All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH v2 0/29] Add additional core driver model features
@ 2014-07-09  3:37 Simon Glass
  2014-07-09  3:37 ` [U-Boot] [PATCH v2 01/29] dm: gpio: Don't use the driver model uclass for SPL Simon Glass
                   ` (28 more replies)
  0 siblings, 29 replies; 44+ messages in thread
From: Simon Glass @ 2014-07-09  3:37 UTC (permalink / raw)
  To: u-boot

This series includes a number of base driver model enhancements, mostly
targeted at pre-relocation and to enable buses to be easily implemented.

With the device tree, child nodes for buses can now be scanned to create
child devices, and bus-related information about each child can be
stored. Children can be numbered as a core driver model feature in U-Boot
(e.g. SPI bus 0 chip select 3).

Driver model now supports operation prior to relocation, assuming a
suitable malloc() implementation is available.

Several changes are added to permit driver model to be available early
after relocation, since we are unable to access any device until driver
model is ready.

This series is available at u-boot-dm.git branch 'working'.

Changes in v2:
- Remove change to board/rbc823/kbd.c, since it has been deleted
- Reformat commit message slightly
- Remove changes to deleted board/netphone/phone_console.c board/rbc823/kbd.c
- Rename struct device to struct udevice
- Update test output in doc/driver-model/README.txt
- Minor reword to comment for dm_init_and_scan()
- Return -ENODEV instead of -1 on error
- Improve wording in commit message
- Improve wording in commit message
- Expand series to include all driver-model-required changes

Simon Glass (29):
  dm: gpio: Don't use the driver model uclass for SPL
  dm: Use an explicit expect value in core tests
  stdio: Remove redundant code around stdio_register() calls
  stdio: Pass device pointer to stdio methods
  dm: Make sure that the root device is probed
  dm: Provide a way to shut down driver model
  sandbox: Remove all drivers before exit
  dm: Allow drivers to be marked 'before relocation'
  dm: Support driver model prior to relocation
  stdio: Provide functions to add/remove devices using stdio_dev
  console: Remove vprintf() optimisation for sandbox
  Add a flag indicating when the serial console is ready
  dm: Move uclass error checking/probing into a function
  fdt: Add a function to get the alias sequence of a node
  dm: Move device display into its own function
  dm: Avoid activating devices in 'dm uclass' command
  dm: Introduce device sequence numbering
  dm: Display the sequence number for each device
  dm: Allow a device to be found by its FDT offset
  dm: Avoid accessing uclasses before they are ready
  fdt: Add a function to get the node offset of an alias
  dm: Tidy up some header file comments
  dm: Provide a function to scan child FDT nodes
  dm: Add functions to access a device's children
  dm: Introduce per-child data for devices
  dm: Add child_pre_probe() and child_post_remove() methods
  dm: Improve errors and warnings in lists_bind_fdt()
  dm: Add dm_scan_other() to locate board-specific devices
  dm: Give the demo uclass a name

 arch/blackfin/cpu/jtag-console.c  |  10 +-
 arch/powerpc/cpu/mpc512x/serial.c |  10 +-
 arch/powerpc/cpu/mpc8xx/video.c   |   6 +-
 arch/sandbox/cpu/cpu.c            |   4 +
 arch/x86/lib/video.c              |   8 +-
 board/bf527-ezkit/video.c         |  10 --
 board/bf548-ezkit/video.c         |  10 --
 board/cm-bf548/video.c            |  10 --
 board/mpl/common/kbd.c            |   6 +-
 board/mpl/common/kbd.h            |   6 +-
 board/mpl/pati/pati.c             |   8 +-
 board/nokia/rx51/rx51.c           |   6 +-
 common/board_f.c                  |  16 +++
 common/board_r.c                  |  25 +---
 common/cmd_log.c                  |  11 +-
 common/console.c                  |  24 ++--
 common/lcd.c                      |  14 ++-
 common/stdio.c                    |  66 ++++++++---
 common/usb_kbd.c                  |   6 +-
 doc/driver-model/README.txt       | 216 +++++++++++++++++++++++++++++++---
 drivers/core/device.c             | 169 +++++++++++++++++++++++++-
 drivers/core/lists.c              |  22 +++-
 drivers/core/root.c               |  79 ++++++++++---
 drivers/core/uclass.c             | 135 ++++++++++++++++++++-
 drivers/demo/demo-uclass.c        |   1 +
 drivers/gpio/Makefile             |   2 +
 drivers/input/cros_ec_keyb.c      |   6 +-
 drivers/input/i8042.c             |   4 +-
 drivers/input/keyboard.c          |   6 +-
 drivers/input/tegra-kbc.c         |   6 +-
 drivers/misc/cbmem_console.c      |   6 +-
 drivers/net/netconsole.c          |  10 +-
 drivers/serial/serial.c           |  55 ++++++++-
 drivers/serial/usbtty.c           |   8 +-
 drivers/video/cfb_console.c       |   8 +-
 include/asm-generic/global_data.h |   4 +-
 include/common.h                  |   5 +
 include/configs/ELPPC.h           |   4 +-
 include/configs/MHPC.h            |   4 +-
 include/configs/jadecpu.h         |   4 +-
 include/configs/nokia_rx51.h      |   5 +-
 include/dm/device-internal.h      |   6 +-
 include/dm/device.h               | 120 ++++++++++++++++++-
 include/dm/lists.h                |   2 +-
 include/dm/platdata.h             |  10 +-
 include/dm/root.h                 |  61 +++++++++-
 include/dm/test.h                 |  22 ++++
 include/dm/uclass-id.h            |   3 +-
 include/dm/uclass-internal.h      |  23 ++++
 include/dm/uclass.h               |  49 +++++++-
 include/fdtdec.h                  |  29 +++++
 include/i8042.h                   |   6 +-
 include/stdio_dev.h               |  17 ++-
 include/video.h                   |   8 +-
 lib/fdtdec.c                      |  61 ++++++++++
 test/dm/Makefile                  |   1 +
 test/dm/bus.c                     | 242 ++++++++++++++++++++++++++++++++++++++
 test/dm/cmd_dm.c                  |  35 ++++--
 test/dm/core.c                    |  64 ++++++++--
 test/dm/test-driver.c             |  11 ++
 test/dm/test-fdt.c                | 164 ++++++++++++++++++++++----
 test/dm/test-main.c               |   4 +-
 test/dm/test.dts                  |  43 ++++++-
 63 files changed, 1714 insertions(+), 282 deletions(-)
 create mode 100644 test/dm/bus.c

-- 
2.0.0.526.g5318336

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 01/29] dm: gpio: Don't use the driver model uclass for SPL
  2014-07-09  3:37 [U-Boot] [PATCH v2 0/29] Add additional core driver model features Simon Glass
@ 2014-07-09  3:37 ` Simon Glass
  2014-07-09  3:37 ` [U-Boot] [PATCH v2 02/29] dm: Use an explicit expect value in core tests Simon Glass
                   ` (27 subsequent siblings)
  28 siblings, 0 replies; 44+ messages in thread
From: Simon Glass @ 2014-07-09  3:37 UTC (permalink / raw)
  To: u-boot

Driver model does not support SPL yet, so we should not use the GPIO
uclass for SPL.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2: None

 drivers/gpio/Makefile | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 4e001e1..fb8dcd9 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -5,7 +5,9 @@
 # SPDX-License-Identifier:	GPL-2.0+
 #
 
+ifndef CONFIG_SPL_BUILD
 obj-$(CONFIG_DM_GPIO)		+= gpio-uclass.o
+endif
 
 obj-$(CONFIG_AT91_GPIO)	+= at91_gpio.o
 obj-$(CONFIG_INTEL_ICH6_GPIO)	+= intel_ich6_gpio.o
-- 
2.0.0.526.g5318336

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 02/29] dm: Use an explicit expect value in core tests
  2014-07-09  3:37 [U-Boot] [PATCH v2 0/29] Add additional core driver model features Simon Glass
  2014-07-09  3:37 ` [U-Boot] [PATCH v2 01/29] dm: gpio: Don't use the driver model uclass for SPL Simon Glass
@ 2014-07-09  3:37 ` Simon Glass
  2014-07-09  3:37 ` [U-Boot] [PATCH v2 03/29] stdio: Remove redundant code around stdio_register() calls Simon Glass
                   ` (26 subsequent siblings)
  28 siblings, 0 replies; 44+ messages in thread
From: Simon Glass @ 2014-07-09  3:37 UTC (permalink / raw)
  To: u-boot

Rather than reusing the 'reg' property, use an explicit property for the
expected ping value used in testing.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2: None

 test/dm/test-fdt.c | 13 ++++++++-----
 test/dm/test.dts   |  5 ++++-
 2 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c
index 98e3936..0f50537 100644
--- a/test/dm/test-fdt.c
+++ b/test/dm/test-fdt.c
@@ -39,7 +39,8 @@ static int testfdt_ofdata_to_platdata(struct udevice *dev)
 
 	pdata->ping_add = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
 					"ping-add", -1);
-	pdata->base = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
+	pdata->base = fdtdec_get_addr(gd->fdt_blob, dev->of_offset,
+				      "ping-expect");
 
 	return 0;
 }
@@ -127,11 +128,13 @@ static int dm_test_fdt(struct dm_test_state *dms)
 		ut_assert(!ret);
 
 		/*
-		 * Get the 'reg' property, which tells us what the ping add
-		 * should be. We don't use the platdata because we want
-		 * to test the code that sets that up (testfdt_drv_probe()).
+		 * Get the 'ping-expect' property, which tells us what the
+		 * ping add should be. We don't use the platdata because we
+		 * want to test the code that sets that up
+		 * (testfdt_drv_probe()).
 		 */
-		base = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
+		base = fdtdec_get_addr(gd->fdt_blob, dev->of_offset,
+				       "ping-expect");
 		debug("dev=%d, base=%d: %s\n", i, base,
 		      fdt_get_name(gd->fdt_blob, dev->of_offset, NULL));
 
diff --git a/test/dm/test.dts b/test/dm/test.dts
index ec5364f..74d236b 100644
--- a/test/dm/test.dts
+++ b/test/dm/test.dts
@@ -9,6 +9,7 @@
 	a-test {
 		reg = <0>;
 		compatible = "denx,u-boot-fdt-test";
+		ping-expect = <0>;
 		ping-add = <0>;
 	};
 
@@ -24,13 +25,14 @@
 	b-test {
 		reg = <3>;
 		compatible = "denx,u-boot-fdt-test";
+		ping-expect = <3>;
 		ping-add = <3>;
 	};
 
 	some-bus {
 		#address-cells = <1>;
 		#size-cells = <0>;
-		reg = <4>;
+		ping-expect = <4>;
 		ping-add = <4>;
 		c-test {
 			compatible = "denx,u-boot-fdt-test";
@@ -41,6 +43,7 @@
 
 	d-test {
 		reg = <6>;
+		ping-expect = <6>;
 		ping-add = <6>;
 		compatible = "google,another-fdt-test";
 	};
-- 
2.0.0.526.g5318336

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 03/29] stdio: Remove redundant code around stdio_register() calls
  2014-07-09  3:37 [U-Boot] [PATCH v2 0/29] Add additional core driver model features Simon Glass
  2014-07-09  3:37 ` [U-Boot] [PATCH v2 01/29] dm: gpio: Don't use the driver model uclass for SPL Simon Glass
  2014-07-09  3:37 ` [U-Boot] [PATCH v2 02/29] dm: Use an explicit expect value in core tests Simon Glass
@ 2014-07-09  3:37 ` Simon Glass
  2014-07-10 23:23   ` Marek Vasut
  2014-07-09  3:37 ` [U-Boot] [PATCH v2 04/29] stdio: Pass device pointer to stdio methods Simon Glass
                   ` (25 subsequent siblings)
  28 siblings, 1 reply; 44+ messages in thread
From: Simon Glass @ 2014-07-09  3:37 UTC (permalink / raw)
  To: u-boot

There is no point in setting a structure's memory to NULL when it has
already been zeroed with memset().

Also, there is no need to create a stub function for stdio to call - if the
function is NULL it will not be called.

This is a clean-up, with no change in functionality.

Signed-off-by: Simon Glass <sjg@chromium.org>
Acked-by: Marek Vasut <marex@denx.de>
---

Changes in v2:
- Remove change to board/rbc823/kbd.c, since it has been deleted
- Reformat commit message slightly

 arch/x86/lib/video.c        |  4 ----
 board/bf527-ezkit/video.c   | 10 ----------
 board/bf548-ezkit/video.c   | 10 ----------
 board/cm-bf548/video.c      | 10 ----------
 board/mpl/common/kbd.c      |  2 --
 common/usb_kbd.c            |  2 --
 drivers/input/keyboard.c    |  2 --
 drivers/video/cfb_console.c |  2 --
 8 files changed, 42 deletions(-)

diff --git a/arch/x86/lib/video.c b/arch/x86/lib/video.c
index dfd2a84..eb9c595 100644
--- a/arch/x86/lib/video.c
+++ b/arch/x86/lib/video.c
@@ -178,8 +178,6 @@ int video_init(void)
 	vga_dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_SYSTEM;
 	vga_dev.putc  = video_putc;        /* 'putc' function */
 	vga_dev.puts  = video_puts;        /* 'puts' function */
-	vga_dev.tstc  = NULL;              /* 'tstc' function */
-	vga_dev.getc  = NULL;              /* 'getc' function */
 
 	if (stdio_register(&vga_dev) == 0)
 		return 1;
@@ -191,8 +189,6 @@ int video_init(void)
 	strcpy(kbd_dev.name, "kbd");
 	kbd_dev.ext   = 0;
 	kbd_dev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
-	kbd_dev.putc  = NULL;        /* 'putc' function */
-	kbd_dev.puts  = NULL;        /* 'puts' function */
 	kbd_dev.tstc  = i8042_tstc;  /* 'tstc' function */
 	kbd_dev.getc  = i8042_getc;  /* 'getc' function */
 
diff --git a/board/bf527-ezkit/video.c b/board/bf527-ezkit/video.c
index 5d8a091..c2bf145 100644
--- a/board/bf527-ezkit/video.c
+++ b/board/bf527-ezkit/video.c
@@ -391,14 +391,6 @@ void video_stop(void)
 #endif
 }
 
-void video_putc(const char c)
-{
-}
-
-void video_puts(const char *s)
-{
-}
-
 int drv_video_init(void)
 {
 	int error, devices = 1;
@@ -448,8 +440,6 @@ int drv_video_init(void)
 	strcpy(videodev.name, "video");
 	videodev.ext = DEV_EXT_VIDEO;	/* Video extensions */
 	videodev.flags = DEV_FLAGS_SYSTEM;	/* No Output */
-	videodev.putc = video_putc;	/* 'putc' function */
-	videodev.puts = video_puts;	/* 'puts' function */
 
 	error = stdio_register(&videodev);
 
diff --git a/board/bf548-ezkit/video.c b/board/bf548-ezkit/video.c
index 6737ac1..47e68c6 100644
--- a/board/bf548-ezkit/video.c
+++ b/board/bf548-ezkit/video.c
@@ -281,14 +281,6 @@ static void dma_bitblit(void *dst, fastimage_t *logo, int x, int y)
 
 }
 
-void video_putc(const char c)
-{
-}
-
-void video_puts(const char *s)
-{
-}
-
 int drv_video_init(void)
 {
 	int error, devices = 1;
@@ -338,8 +330,6 @@ int drv_video_init(void)
 	strcpy(videodev.name, "video");
 	videodev.ext = DEV_EXT_VIDEO;	/* Video extensions */
 	videodev.flags = DEV_FLAGS_SYSTEM;	/* No Output */
-	videodev.putc = video_putc;	/* 'putc' function */
-	videodev.puts = video_puts;	/* 'puts' function */
 
 	error = stdio_register(&videodev);
 
diff --git a/board/cm-bf548/video.c b/board/cm-bf548/video.c
index c35d285..b098615 100644
--- a/board/cm-bf548/video.c
+++ b/board/cm-bf548/video.c
@@ -283,14 +283,6 @@ static void dma_bitblit(void *dst, fastimage_t *logo, int x, int y)
 
 }
 
-void video_putc(const char c)
-{
-}
-
-void video_puts(const char *s)
-{
-}
-
 int drv_video_init(void)
 {
 	int error, devices = 1;
@@ -342,8 +334,6 @@ int drv_video_init(void)
 	strcpy(videodev.name, "video");
 	videodev.ext = DEV_EXT_VIDEO;	/* Video extensions */
 	videodev.flags = DEV_FLAGS_SYSTEM;	/* No Output */
-	videodev.putc = video_putc;	/* 'putc' function */
-	videodev.puts = video_puts;	/* 'puts' function */
 
 	error = stdio_register(&videodev);
 
diff --git a/board/mpl/common/kbd.c b/board/mpl/common/kbd.c
index 1b5487b..f56545e 100644
--- a/board/mpl/common/kbd.c
+++ b/board/mpl/common/kbd.c
@@ -204,8 +204,6 @@ int drv_isa_kbd_init (void)
 	memset (&kbddev, 0, sizeof(kbddev));
 	strcpy(kbddev.name, DEVNAME);
 	kbddev.flags =  DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
-	kbddev.putc = NULL ;
-	kbddev.puts = NULL ;
 	kbddev.getc = kbd_getc ;
 	kbddev.tstc = kbd_testc ;
 
diff --git a/common/usb_kbd.c b/common/usb_kbd.c
index 0b77c16..371e5bc 100644
--- a/common/usb_kbd.c
+++ b/common/usb_kbd.c
@@ -522,8 +522,6 @@ int drv_usb_kbd_init(void)
 		memset(&usb_kbd_dev, 0, sizeof(struct stdio_dev));
 		strcpy(usb_kbd_dev.name, DEVNAME);
 		usb_kbd_dev.flags =  DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
-		usb_kbd_dev.putc = NULL;
-		usb_kbd_dev.puts = NULL;
 		usb_kbd_dev.getc = usb_kbd_getc;
 		usb_kbd_dev.tstc = usb_kbd_testc;
 		usb_kbd_dev.priv = (void *)dev;
diff --git a/drivers/input/keyboard.c b/drivers/input/keyboard.c
index 614592e..5ef1cc0 100644
--- a/drivers/input/keyboard.c
+++ b/drivers/input/keyboard.c
@@ -275,8 +275,6 @@ int kbd_init (void)
 	memset (&kbddev, 0, sizeof(kbddev));
 	strcpy(kbddev.name, DEVNAME);
 	kbddev.flags =  DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
-	kbddev.putc = NULL ;
-	kbddev.puts = NULL ;
 	kbddev.getc = kbd_getc ;
 	kbddev.tstc = kbd_testc ;
 
diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c
index b52e9ed..1cf8660 100644
--- a/drivers/video/cfb_console.c
+++ b/drivers/video/cfb_console.c
@@ -2279,8 +2279,6 @@ int drv_video_init(void)
 	console_dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_SYSTEM;
 	console_dev.putc = video_putc;	/* 'putc' function */
 	console_dev.puts = video_puts;	/* 'puts' function */
-	console_dev.tstc = NULL;	/* 'tstc' function */
-	console_dev.getc = NULL;	/* 'getc' function */
 
 #if !defined(CONFIG_VGA_AS_SINGLE_DEVICE)
 	/* Also init console device */
-- 
2.0.0.526.g5318336

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 04/29] stdio: Pass device pointer to stdio methods
  2014-07-09  3:37 [U-Boot] [PATCH v2 0/29] Add additional core driver model features Simon Glass
                   ` (2 preceding siblings ...)
  2014-07-09  3:37 ` [U-Boot] [PATCH v2 03/29] stdio: Remove redundant code around stdio_register() calls Simon Glass
@ 2014-07-09  3:37 ` Simon Glass
  2014-07-10 23:26   ` Marek Vasut
  2014-07-09  3:37 ` [U-Boot] [PATCH v2 05/29] dm: Make sure that the root device is probed Simon Glass
                   ` (24 subsequent siblings)
  28 siblings, 1 reply; 44+ messages in thread
From: Simon Glass @ 2014-07-09  3:37 UTC (permalink / raw)
  To: u-boot

At present stdio device functions do not get any clue as to which stdio
device is being acted on. Some implementations go to great lengths to work
around this, such as defining a whole separate set of functions for each
possible device.

For driver model we need to associate a stdio_dev with a device. It doesn't
seem possible to continue with this work-around approach.

Instead, add a stdio_dev pointer to each of the stdio member functions.

Note: The serial drivers have the same problem, but it is not strictly
necessary to fix that to get driver model running. Also, if we convert
serial over to driver model the problem will go away.

Code size increases by 244 bytes for Thumb2 and 428 for PowerPC.

22: stdio: Pass device pointer to stdio methods
       arm: (for 2/2 boards)  all +244.0  bss -4.0  text +248.0
   powerpc: (for 1/1 boards)  all +428.0  text +428.0

Signed-off-by: Simon Glass <sjg@chromium.org>
Acked-by: Marek Vasut <marex@denx.de>
---

Changes in v2:
- Remove changes to deleted board/netphone/phone_console.c board/rbc823/kbd.c

 arch/blackfin/cpu/jtag-console.c  | 10 ++++----
 arch/powerpc/cpu/mpc512x/serial.c | 10 ++++----
 arch/powerpc/cpu/mpc8xx/video.c   |  6 ++---
 arch/x86/lib/video.c              |  4 +--
 board/mpl/common/kbd.c            |  4 +--
 board/mpl/common/kbd.h            |  6 +++--
 board/mpl/pati/pati.c             |  8 +++---
 board/nokia/rx51/rx51.c           |  6 ++---
 common/cmd_log.c                  | 11 ++++----
 common/console.c                  | 18 ++++++-------
 common/lcd.c                      | 14 ++++++++--
 common/stdio.c                    | 34 +++++++++++++++++++-----
 common/usb_kbd.c                  |  4 +--
 drivers/input/cros_ec_keyb.c      |  6 ++---
 drivers/input/i8042.c             |  4 +--
 drivers/input/keyboard.c          |  4 +--
 drivers/input/tegra-kbc.c         |  6 ++---
 drivers/misc/cbmem_console.c      |  6 ++---
 drivers/net/netconsole.c          | 10 ++++----
 drivers/serial/serial.c           | 54 ++++++++++++++++++++++++++++++++++-----
 drivers/serial/usbtty.c           |  8 +++---
 drivers/video/cfb_console.c       |  6 ++---
 include/common.h                  |  5 ++++
 include/configs/ELPPC.h           |  4 +--
 include/configs/MHPC.h            |  4 +--
 include/configs/jadecpu.h         |  4 +--
 include/configs/nokia_rx51.h      |  5 ++--
 include/i8042.h                   |  6 +++--
 include/stdio_dev.h               | 15 ++++++-----
 include/video.h                   |  8 +++---
 30 files changed, 189 insertions(+), 101 deletions(-)

diff --git a/arch/blackfin/cpu/jtag-console.c b/arch/blackfin/cpu/jtag-console.c
index 7cddb85..b8be318 100644
--- a/arch/blackfin/cpu/jtag-console.c
+++ b/arch/blackfin/cpu/jtag-console.c
@@ -112,11 +112,11 @@ static void jtag_send(const char *raw_str, uint32_t len)
 	if (cooked_str != raw_str)
 		free((char *)cooked_str);
 }
-static void jtag_putc(const char c)
+static void jtag_putc(struct stdio_dev *dev, const char c)
 {
 	jtag_send(&c, 1);
 }
-static void jtag_puts(const char *s)
+static void jtag_puts(struct stdio_dev *dev, const char *s)
 {
 	jtag_send(s, strlen(s));
 }
@@ -133,7 +133,7 @@ static int jtag_tstc_dbg(void)
 }
 
 /* Higher layers want to know when any data is available */
-static int jtag_tstc(void)
+static int jtag_tstc(struct stdio_dev *dev)
 {
 	return jtag_tstc_dbg() || leftovers_len;
 }
@@ -142,7 +142,7 @@ static int jtag_tstc(void)
  * [32bit length][actual data]
  */
 static uint32_t leftovers;
-static int jtag_getc(void)
+static int jtag_getc(struct stdio_dev *dev)
 {
 	int ret;
 	uint32_t emudat;
@@ -173,7 +173,7 @@ static int jtag_getc(void)
 		leftovers = emudat;
 	}
 
-	return jtag_getc();
+	return jtag_getc(dev);
 }
 
 int drv_jtag_console_init(void)
diff --git a/arch/powerpc/cpu/mpc512x/serial.c b/arch/powerpc/cpu/mpc512x/serial.c
index 42e0dc9..4105a28 100644
--- a/arch/powerpc/cpu/mpc512x/serial.c
+++ b/arch/powerpc/cpu/mpc512x/serial.c
@@ -384,7 +384,7 @@ struct stdio_dev *open_port(int num, int baudrate)
 		sprintf(env_val, "%d", baudrate);
 		setenv(env_var, env_val);
 
-		if (port->start())
+		if (port->start(port))
 			return NULL;
 
 		set_bit(num, &initialized);
@@ -407,7 +407,7 @@ int close_port(int num)
 	if (!port)
 		return -1;
 
-	ret = port->stop();
+	ret = port->stop(port);
 	clear_bit(num, &initialized);
 
 	return ret;
@@ -418,7 +418,7 @@ int write_port(struct stdio_dev *port, char *buf)
 	if (!port || !buf)
 		return -1;
 
-	port->puts(buf);
+	port->puts(port, buf);
 
 	return 0;
 }
@@ -433,8 +433,8 @@ int read_port(struct stdio_dev *port, char *buf, int size)
 	if (!size)
 		return 0;
 
-	while (port->tstc()) {
-		buf[cnt++] = port->getc();
+	while (port->tstc(port)) {
+		buf[cnt++] = port->getc(port);
 		if (cnt > size)
 			break;
 	}
diff --git a/arch/powerpc/cpu/mpc8xx/video.c b/arch/powerpc/cpu/mpc8xx/video.c
index 2fd5b11..9590bfd 100644
--- a/arch/powerpc/cpu/mpc8xx/video.c
+++ b/arch/powerpc/cpu/mpc8xx/video.c
@@ -948,7 +948,7 @@ static inline void console_newline (void)
 	}
 }
 
-void video_putc (const char c)
+void video_putc(struct stdio_dev *dev, const char c)
 {
 	if (!video_enable) {
 		serial_putc (c);
@@ -985,7 +985,7 @@ void video_putc (const char c)
 	}
 }
 
-void video_puts (const char *s)
+void video_puts(struct stdio_dev *dev, const char *s)
 {
 	int count = strlen (s);
 
@@ -994,7 +994,7 @@ void video_puts (const char *s)
 			serial_putc (*s++);
 	else
 		while (count--)
-			video_putc (*s++);
+			video_putc(dev, *s++);
 }
 
 /************************************************************************/
diff --git a/arch/x86/lib/video.c b/arch/x86/lib/video.c
index eb9c595..975949d 100644
--- a/arch/x86/lib/video.c
+++ b/arch/x86/lib/video.c
@@ -104,7 +104,7 @@ static void __video_putc(const char c, int *x, int *y)
 	}
 }
 
-static void video_putc(const char c)
+static void video_putc(struct stdio_dev *dev, const char c)
 {
 	int x, y, pos;
 
@@ -123,7 +123,7 @@ static void video_putc(const char c)
 	outb_p(0xff & (pos >> 1), vidport+1);
 }
 
-static void video_puts(const char *s)
+static void video_puts(struct stdio_dev *dev, const char *s)
 {
 	int x, y, pos;
 	char c;
diff --git a/board/mpl/common/kbd.c b/board/mpl/common/kbd.c
index f56545e..99de2ca 100644
--- a/board/mpl/common/kbd.c
+++ b/board/mpl/common/kbd.c
@@ -248,7 +248,7 @@ void kbd_put_queue(char data)
 }
 
 /* test if a character is in the queue */
-int kbd_testc(void)
+int kbd_testc(struct stdio_dev *dev)
 {
 	if(in_pointer==out_pointer)
 		return(0); /* no data */
@@ -256,7 +256,7 @@ int kbd_testc(void)
 		return(1);
 }
 /* gets the character from the queue */
-int kbd_getc(void)
+int kbd_getc(struct stdio_dev *dev)
 {
 	char c;
 	while(in_pointer==out_pointer);
diff --git a/board/mpl/common/kbd.h b/board/mpl/common/kbd.h
index 7b19b37..b549e20 100644
--- a/board/mpl/common/kbd.h
+++ b/board/mpl/common/kbd.h
@@ -8,8 +8,10 @@
 #ifndef _KBD_H_
 #define _KBD_H_
 
-extern int kbd_testc(void);
-extern int kbd_getc(void);
+struct stdio_dev;
+
+int kbd_testc(struct stdio_dev *sdev);
+int kbd_getc(struct stdio_dev *sdev);
 extern void kbd_interrupt(void);
 extern char *kbd_initialize(void);
 
diff --git a/board/mpl/pati/pati.c b/board/mpl/pati/pati.c
index 8ca9bb3..5d701a7 100644
--- a/board/mpl/pati/pati.c
+++ b/board/mpl/pati/pati.c
@@ -445,7 +445,7 @@ void pci_con_put_it(const char c)
 	PCICON_SET_REG(PCICON_DBELL_REG,PCIMSG_CON_DATA);
 }
 
-void pci_con_putc(const char c)
+void pci_con_putc(struct stdio_dev *dev, const char c)
 {
 	pci_con_put_it(c);
 	if(c == '\n')
@@ -453,7 +453,7 @@ void pci_con_putc(const char c)
 }
 
 
-int pci_con_getc(void)
+int pci_con_getc(struct stdio_dev *dev)
 {
 	int res;
 	int diff;
@@ -473,14 +473,14 @@ int pci_con_getc(void)
 	return res;
 }
 
-int pci_con_tstc(void)
+int pci_con_tstc(struct stdio_dev *dev)
 {
 	if(r_ptr==(volatile int)w_ptr)
 		return 0;
 	return 1;
 }
 
-void pci_con_puts (const char *s)
+void pci_con_puts(struct stdio_dev *dev, const char *s)
 {
 	while (*s) {
 		pci_con_putc(*s);
diff --git a/board/nokia/rx51/rx51.c b/board/nokia/rx51/rx51.c
index 3e419ef..c2e07db 100644
--- a/board/nokia/rx51/rx51.c
+++ b/board/nokia/rx51/rx51.c
@@ -585,7 +585,7 @@ static void rx51_kp_fill(u8 k, u8 mods)
  * Routine: rx51_kp_tstc
  * Description: Test if key was pressed (from buffer).
  */
-int rx51_kp_tstc(void)
+int rx51_kp_tstc(struct stdio_dev *sdev)
 {
 	u8 c, r, dk, i;
 	u8 intr;
@@ -641,10 +641,10 @@ int rx51_kp_tstc(void)
  * Routine: rx51_kp_getc
  * Description: Get last pressed key (from buffer).
  */
-int rx51_kp_getc(void)
+int rx51_kp_getc(struct stdio_dev *sdev)
 {
 	keybuf_head %= KEYBUF_SIZE;
-	while (!rx51_kp_tstc())
+	while (!rx51_kp_tstc(sdev))
 		WATCHDOG_RESET();
 	return keybuf[keybuf_head++];
 }
diff --git a/common/cmd_log.c b/common/cmd_log.c
index 38d0f5e..873ee40 100644
--- a/common/cmd_log.c
+++ b/common/cmd_log.c
@@ -33,8 +33,8 @@
 DECLARE_GLOBAL_DATA_PTR;
 
 /* Local prototypes */
-static void logbuff_putc(const char c);
-static void logbuff_puts(const char *s);
+static void logbuff_putc(struct stdio_dev *dev, const char c);
+static void logbuff_puts(struct stdio_dev *dev, const char *s);
 static int logbuff_printk(const char *line);
 
 static char buf[1024];
@@ -143,7 +143,7 @@ int drv_logbuff_init(void)
 	return (rc == 0) ? 1 : rc;
 }
 
-static void logbuff_putc(const char c)
+static void logbuff_putc(struct stdio_dev *dev, const char c)
 {
 	char buf[2];
 	buf[0] = c;
@@ -151,7 +151,7 @@ static void logbuff_putc(const char c)
 	logbuff_printk(buf);
 }
 
-static void logbuff_puts(const char *s)
+static void logbuff_puts(struct stdio_dev *dev, const char *s)
 {
 	logbuff_printk (s);
 }
@@ -181,6 +181,7 @@ void logbuff_log(char *msg)
  */
 int do_log(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
+	struct stdio_dev *sdev = NULL;
 	char *s;
 	unsigned long i, start, size;
 
@@ -188,7 +189,7 @@ int do_log(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		/* Log concatenation of all arguments separated by spaces */
 		for (i = 2; i < argc; i++) {
 			logbuff_printk(argv[i]);
-			logbuff_putc((i < argc - 1) ? ' ' : '\n');
+			logbuff_putc(sdev, (i < argc - 1) ? ' ' : '\n');
 		}
 		return 0;
 	}
diff --git a/common/console.c b/common/console.c
index 5453726..11c102a 100644
--- a/common/console.c
+++ b/common/console.c
@@ -109,7 +109,7 @@ static int console_setfile(int file, struct stdio_dev * dev)
 	case stderr:
 		/* Start new device */
 		if (dev->start) {
-			error = dev->start();
+			error = dev->start(dev);
 			/* If it's not started dont use it */
 			if (error < 0)
 				break;
@@ -159,7 +159,7 @@ static int console_getc(int file)
 	unsigned char ret;
 
 	/* This is never called with testcdev == NULL */
-	ret = tstcdev->getc();
+	ret = tstcdev->getc(tstcdev);
 	tstcdev = NULL;
 	return ret;
 }
@@ -173,7 +173,7 @@ static int console_tstc(int file)
 	for (i = 0; i < cd_count[file]; i++) {
 		dev = console_devices[file][i];
 		if (dev->tstc != NULL) {
-			ret = dev->tstc();
+			ret = dev->tstc(dev);
 			if (ret > 0) {
 				tstcdev = dev;
 				disable_ctrlc(0);
@@ -194,7 +194,7 @@ static void console_putc(int file, const char c)
 	for (i = 0; i < cd_count[file]; i++) {
 		dev = console_devices[file][i];
 		if (dev->putc != NULL)
-			dev->putc(c);
+			dev->putc(dev, c);
 	}
 }
 
@@ -206,7 +206,7 @@ static void console_puts(int file, const char *s)
 	for (i = 0; i < cd_count[file]; i++) {
 		dev = console_devices[file][i];
 		if (dev->puts != NULL)
-			dev->puts(s);
+			dev->puts(dev, s);
 	}
 }
 
@@ -222,22 +222,22 @@ static inline void console_doenv(int file, struct stdio_dev *dev)
 #else
 static inline int console_getc(int file)
 {
-	return stdio_devices[file]->getc();
+	return stdio_devices[file]->getc(stdio_devices[file]);
 }
 
 static inline int console_tstc(int file)
 {
-	return stdio_devices[file]->tstc();
+	return stdio_devices[file]->tstc(stdio_devices[file]);
 }
 
 static inline void console_putc(int file, const char c)
 {
-	stdio_devices[file]->putc(c);
+	stdio_devices[file]->putc(stdio_devices[file], c);
 }
 
 static inline void console_puts(int file, const char *s)
 {
-	stdio_devices[file]->puts(s);
+	stdio_devices[file]->puts(stdio_devices[file], s);
 }
 
 static inline void console_printdevs(int file)
diff --git a/common/lcd.c b/common/lcd.c
index 19b86b7..feb913a 100644
--- a/common/lcd.c
+++ b/common/lcd.c
@@ -214,6 +214,11 @@ static inline void console_newline(void)
 
 /*----------------------------------------------------------------------*/
 
+static void lcd_stub_putc(struct stdio_dev *dev, const char c)
+{
+	lcd_putc(c);
+}
+
 void lcd_putc(const char c)
 {
 	if (!lcd_is_enabled) {
@@ -253,6 +258,11 @@ void lcd_putc(const char c)
 
 /*----------------------------------------------------------------------*/
 
+static void lcd_stub_puts(struct stdio_dev *dev, const char *s)
+{
+	lcd_puts(s);
+}
+
 void lcd_puts(const char *s)
 {
 	if (!lcd_is_enabled) {
@@ -426,8 +436,8 @@ int drv_lcd_init(void)
 	strcpy(lcddev.name, "lcd");
 	lcddev.ext   = 0;			/* No extensions */
 	lcddev.flags = DEV_FLAGS_OUTPUT;	/* Output only */
-	lcddev.putc  = lcd_putc;		/* 'putc' function */
-	lcddev.puts  = lcd_puts;		/* 'puts' function */
+	lcddev.putc  = lcd_stub_putc;		/* 'putc' function */
+	lcddev.puts  = lcd_stub_puts;		/* 'puts' function */
 
 	rc = stdio_register(&lcddev);
 
diff --git a/common/stdio.c b/common/stdio.c
index 844f98c..dd402cc 100644
--- a/common/stdio.c
+++ b/common/stdio.c
@@ -35,23 +35,43 @@ char *stdio_names[MAX_FILES] = { "stdin", "stdout", "stderr" };
 
 
 #ifdef CONFIG_SYS_DEVICE_NULLDEV
-void nulldev_putc(const char c)
+void nulldev_putc(struct stdio_dev *dev, const char c)
 {
 	/* nulldev is empty! */
 }
 
-void nulldev_puts(const char *s)
+void nulldev_puts(struct stdio_dev *dev, const char *s)
 {
 	/* nulldev is empty! */
 }
 
-int nulldev_input(void)
+int nulldev_input(struct stdio_dev *dev)
 {
 	/* nulldev is empty! */
 	return 0;
 }
 #endif
 
+void stdio_serial_putc(struct stdio_dev *dev, const char c)
+{
+	serial_putc(c);
+}
+
+void stdio_serial_puts(struct stdio_dev *dev, const char *s)
+{
+	serial_puts(s);
+}
+
+int stdio_serial_getc(struct stdio_dev *dev)
+{
+	return serial_getc();
+}
+
+int stdio_serial_tstc(struct stdio_dev *dev)
+{
+	return serial_tstc();
+}
+
 /**************************************************************************
  * SYSTEM DRIVERS
  **************************************************************************
@@ -65,10 +85,10 @@ static void drv_system_init (void)
 
 	strcpy (dev.name, "serial");
 	dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
-	dev.putc = serial_putc;
-	dev.puts = serial_puts;
-	dev.getc = serial_getc;
-	dev.tstc = serial_tstc;
+	dev.putc = stdio_serial_putc;
+	dev.puts = stdio_serial_puts;
+	dev.getc = stdio_serial_getc;
+	dev.tstc = stdio_serial_tstc;
 	stdio_register (&dev);
 
 #ifdef CONFIG_SYS_DEVICE_NULLDEV
diff --git a/common/usb_kbd.c b/common/usb_kbd.c
index 371e5bc..c34fd5c 100644
--- a/common/usb_kbd.c
+++ b/common/usb_kbd.c
@@ -360,7 +360,7 @@ static inline void usb_kbd_poll_for_event(struct usb_device *dev)
 }
 
 /* test if a character is in the queue */
-static int usb_kbd_testc(void)
+static int usb_kbd_testc(struct stdio_dev *sdev)
 {
 	struct stdio_dev *dev;
 	struct usb_device *usb_kbd_dev;
@@ -386,7 +386,7 @@ static int usb_kbd_testc(void)
 }
 
 /* gets the character from the queue */
-static int usb_kbd_getc(void)
+static int usb_kbd_getc(struct stdio_dev *sdev)
 {
 	struct stdio_dev *dev;
 	struct usb_device *usb_kbd_dev;
diff --git a/drivers/input/cros_ec_keyb.c b/drivers/input/cros_ec_keyb.c
index a2501e0..47502b1 100644
--- a/drivers/input/cros_ec_keyb.c
+++ b/drivers/input/cros_ec_keyb.c
@@ -93,7 +93,7 @@ static int check_for_keys(struct keyb *config,
  *
  * @return 0 if no keys available, 1 if keys are available
  */
-static int kbd_tstc(void)
+static int kbd_tstc(struct stdio_dev *dev)
 {
 	/* Just get input to do this for us */
 	return config.inited ? input_tstc(&config.input) : 0;
@@ -104,7 +104,7 @@ static int kbd_tstc(void)
  *
  * @return ASCII key code, or 0 if no key, or -1 if error
  */
-static int kbd_getc(void)
+static int kbd_getc(struct stdio_dev *dev)
 {
 	/* Just get input to do this for us */
 	return config.inited ? input_getc(&config.input) : 0;
@@ -214,7 +214,7 @@ static int cros_ec_keyb_decode_fdt(const void *blob, int node,
  *
  * @return 0 if ok, -1 on error
  */
-static int cros_ec_init_keyboard(void)
+static int cros_ec_init_keyboard(struct stdio_dev *dev)
 {
 	const void *blob = gd->fdt_blob;
 	int node;
diff --git a/drivers/input/i8042.c b/drivers/input/i8042.c
index 35fa0bb..ca1604c 100644
--- a/drivers/input/i8042.c
+++ b/drivers/input/i8042.c
@@ -398,7 +398,7 @@ int i8042_kbd_init(void)
  * i8042_tstc - test if keyboard input is available
  *		option: cursor blinking if called in a loop
  */
-int i8042_tstc(void)
+int i8042_tstc(struct stdio_dev *dev)
 {
 	unsigned char scan_code = 0;
 
@@ -432,7 +432,7 @@ int i8042_tstc(void)
  * i8042_getc - wait till keyboard input is available
  *		option: turn on/off cursor while waiting
  */
-int i8042_getc(void)
+int i8042_getc(struct stdio_dev *dev)
 {
 	int ret_chr;
 	unsigned char scan_code;
diff --git a/drivers/input/keyboard.c b/drivers/input/keyboard.c
index 5ef1cc0..be0f333 100644
--- a/drivers/input/keyboard.c
+++ b/drivers/input/keyboard.c
@@ -70,7 +70,7 @@ static void kbd_put_queue(char data)
 }
 
 /* test if a character is in the queue */
-static int kbd_testc(void)
+static int kbd_testc(struct stdio_dev *dev)
 {
 #if defined(CONFIG_MPC5xxx) || defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || defined(CONFIG_MPC8555)
 	/* no ISR is used, so received chars must be polled */
@@ -83,7 +83,7 @@ static int kbd_testc(void)
 }
 
 /* gets the character from the queue */
-static int kbd_getc(void)
+static int kbd_getc(struct stdio_dev *dev)
 {
 	char c;
 	while(in_pointer==out_pointer) {
diff --git a/drivers/input/tegra-kbc.c b/drivers/input/tegra-kbc.c
index f137f93..7e36db0 100644
--- a/drivers/input/tegra-kbc.c
+++ b/drivers/input/tegra-kbc.c
@@ -194,7 +194,7 @@ int tegra_kbc_check(struct input_config *input)
  *
  * @return 0 if no keys available, 1 if keys are available
  */
-static int kbd_tstc(void)
+static int kbd_tstc(struct stdio_dev *dev)
 {
 	/* Just get input to do this for us */
 	return input_tstc(&config.input);
@@ -207,7 +207,7 @@ static int kbd_tstc(void)
  *
  * @return ASCII key code, or 0 if no key, or -1 if error
  */
-static int kbd_getc(void)
+static int kbd_getc(struct stdio_dev *dev)
 {
 	/* Just get input to do this for us */
 	return input_getc(&config.input);
@@ -289,7 +289,7 @@ static void tegra_kbc_open(void)
  *
  * @return 0 if ok, -ve on error
  */
-static int init_tegra_keyboard(void)
+static int init_tegra_keyboard(struct stdio_dev *dev)
 {
 	/* check if already created */
 	if (config.created)
diff --git a/drivers/misc/cbmem_console.c b/drivers/misc/cbmem_console.c
index 80a84fd..5f85ccf 100644
--- a/drivers/misc/cbmem_console.c
+++ b/drivers/misc/cbmem_console.c
@@ -31,7 +31,7 @@ struct cbmem_console {
 
 static struct cbmem_console *cbmem_console_p;
 
-void cbmemc_putc(char data)
+void cbmemc_putc(struct stdio_dev *dev, char data)
 {
 	int cursor;
 
@@ -40,12 +40,12 @@ void cbmemc_putc(char data)
 		cbmem_console_p->buffer_body[cursor] = data;
 }
 
-void cbmemc_puts(const char *str)
+void cbmemc_puts(struct stdio_dev *dev, const char *str)
 {
 	char c;
 
 	while ((c = *str++) != 0)
-		cbmemc_putc(c);
+		cbmemc_putc(dev, c);
 }
 
 int cbmemc_init(void)
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 65c747e..623f749 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -215,7 +215,7 @@ static void nc_send_packet(const char *buf, int len)
 	}
 }
 
-static int nc_start(void)
+static int nc_start(struct stdio_dev *dev)
 {
 	int retval;
 
@@ -235,7 +235,7 @@ static int nc_start(void)
 	return 0;
 }
 
-static void nc_putc(char c)
+static void nc_putc(struct stdio_dev *dev, char c)
 {
 	if (output_recursion)
 		return;
@@ -246,7 +246,7 @@ static void nc_putc(char c)
 	output_recursion = 0;
 }
 
-static void nc_puts(const char *s)
+static void nc_puts(struct stdio_dev *dev, const char *s)
 {
 	int len;
 
@@ -265,7 +265,7 @@ static void nc_puts(const char *s)
 	output_recursion = 0;
 }
 
-static int nc_getc(void)
+static int nc_getc(struct stdio_dev *dev)
 {
 	uchar c;
 
@@ -286,7 +286,7 @@ static int nc_getc(void)
 	return c;
 }
 
-static int nc_tstc(void)
+static int nc_tstc(struct stdio_dev *dev)
 {
 	struct eth_device *eth;
 
diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c
index fd61a5e..803d850 100644
--- a/drivers/serial/serial.c
+++ b/drivers/serial/serial.c
@@ -254,6 +254,48 @@ void serial_initialize(void)
 	serial_assign(default_serial_console()->name);
 }
 
+int serial_stub_start(struct stdio_dev *sdev)
+{
+	struct serial_device *dev = sdev->priv;
+
+	return dev->start();
+}
+
+int serial_stub_stop(struct stdio_dev *sdev)
+{
+	struct serial_device *dev = sdev->priv;
+
+	return dev->stop();
+}
+
+void serial_stub_putc(struct stdio_dev *sdev, const char ch)
+{
+	struct serial_device *dev = sdev->priv;
+
+	dev->putc(ch);
+}
+
+void serial_stub_puts(struct stdio_dev *sdev, const char *str)
+{
+	struct serial_device *dev = sdev->priv;
+
+	dev->puts(str);
+}
+
+int serial_stub_getc(struct stdio_dev *sdev)
+{
+	struct serial_device *dev = sdev->priv;
+
+	return dev->getc();
+}
+
+int serial_stub_tstc(struct stdio_dev *sdev)
+{
+	struct serial_device *dev = sdev->priv;
+
+	return dev->tstc();
+}
+
 /**
  * serial_stdio_init() - Register serial ports with STDIO core
  *
@@ -272,12 +314,12 @@ void serial_stdio_init(void)
 		strcpy(dev.name, s->name);
 		dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT;
 
-		dev.start = s->start;
-		dev.stop = s->stop;
-		dev.putc = s->putc;
-		dev.puts = s->puts;
-		dev.getc = s->getc;
-		dev.tstc = s->tstc;
+		dev.start = serial_stub_start;
+		dev.stop = serial_stub_stop;
+		dev.putc = serial_stub_putc;
+		dev.puts = serial_stub_puts;
+		dev.getc = serial_stub_getc;
+		dev.tstc = serial_stub_tstc;
 
 		stdio_register(&dev);
 
diff --git a/drivers/serial/usbtty.c b/drivers/serial/usbtty.c
index 6b912ef..b030526 100644
--- a/drivers/serial/usbtty.c
+++ b/drivers/serial/usbtty.c
@@ -389,7 +389,7 @@ static void str2wide (char *str, u16 * wide)
  * Test whether a character is in the RX buffer
  */
 
-int usbtty_tstc (void)
+int usbtty_tstc(struct stdio_dev *dev)
 {
 	struct usb_endpoint_instance *endpoint =
 		&endpoint_instance[rx_endpoint];
@@ -409,7 +409,7 @@ int usbtty_tstc (void)
  * written into its argument c.
  */
 
-int usbtty_getc (void)
+int usbtty_getc(struct stdio_dev *dev)
 {
 	char c;
 	struct usb_endpoint_instance *endpoint =
@@ -429,7 +429,7 @@ int usbtty_getc (void)
 /*
  * Output a single byte to the usb client port.
  */
-void usbtty_putc (const char c)
+void usbtty_putc(struct stdio_dev *dev, const char c)
 {
 	if (!usbtty_configured ())
 		return;
@@ -484,7 +484,7 @@ static void __usbtty_puts (const char *str, int len)
 	}
 }
 
-void usbtty_puts (const char *str)
+void usbtty_puts(struct stdio_dev *dev, const char *str)
 {
 	int n;
 	int len;
diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c
index 1cf8660..9231927 100644
--- a/drivers/video/cfb_console.c
+++ b/drivers/video/cfb_console.c
@@ -944,7 +944,7 @@ static void parse_putc(const char c)
 		CURSOR_SET;
 }
 
-void video_putc(const char c)
+void video_putc(struct stdio_dev *dev, const char c)
 {
 #ifdef CONFIG_CFB_CONSOLE_ANSI
 	int i;
@@ -1158,12 +1158,12 @@ void video_putc(const char c)
 		flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE);
 }
 
-void video_puts(const char *s)
+void video_puts(struct stdio_dev *dev, const char *s)
 {
 	int count = strlen(s);
 
 	while (count--)
-		video_putc(*s++);
+		video_putc(dev, *s++);
 }
 
 /*
diff --git a/include/common.h b/include/common.h
index 82c0a5a..a75fc25 100644
--- a/include/common.h
+++ b/include/common.h
@@ -639,6 +639,11 @@ void	serial_puts   (const char *);
 int	serial_getc   (void);
 int	serial_tstc   (void);
 
+/* These versions take a stdio_dev pointer */
+struct stdio_dev;
+int serial_stub_getc(struct stdio_dev *sdev);
+int serial_stub_tstc(struct stdio_dev *sdev);
+
 void	_serial_setbrg (const int);
 void	_serial_putc   (const char, const int);
 void	_serial_putc_raw(const char, const int);
diff --git a/include/configs/ELPPC.h b/include/configs/ELPPC.h
index 0ffbd41..debfc36 100644
--- a/include/configs/ELPPC.h
+++ b/include/configs/ELPPC.h
@@ -234,8 +234,8 @@
 #define CONFIG_VIDEO
 #define CONFIG_CFB_CONSOLE
 #define VIDEO_KBD_INIT_FCT    (simple_strtol (getenv("console"), NULL, 10))
-#define VIDEO_TSTC_FCT        serial_tstc
-#define VIDEO_GETC_FCT        serial_getc
+#define VIDEO_TSTC_FCT		serial_stub_tstc
+#define VIDEO_GETC_FCT		serial_stub_getc
 
 #define CONFIG_VIDEO_SMI_LYNXEM
 #define CONFIG_VIDEO_LOGO
diff --git a/include/configs/MHPC.h b/include/configs/MHPC.h
index 6314b53..d45be0f 100644
--- a/include/configs/MHPC.h
+++ b/include/configs/MHPC.h
@@ -96,8 +96,8 @@
 #define CONFIG_VIDEO_LOGO
 
 #define VIDEO_KBD_INIT_FCT	0		/* no KBD dev on MHPC - use serial */
-#define VIDEO_TSTC_FCT		serial_tstc
-#define VIDEO_GETC_FCT		serial_getc
+#define VIDEO_TSTC_FCT		serial_stub_tstc
+#define VIDEO_GETC_FCT		serial_stub_getc
 
 #define CONFIG_BR0_WORKAROUND	1
 
diff --git a/include/configs/jadecpu.h b/include/configs/jadecpu.h
index b34e342..759e112 100644
--- a/include/configs/jadecpu.h
+++ b/include/configs/jadecpu.h
@@ -87,8 +87,8 @@
 #define CONFIG_SYS_VIDEO_LOGO_MAX_SIZE  (800*480 + 256*4 + 10*1024)
 #define VIDEO_FB_16BPP_WORD_SWAP
 #define VIDEO_KBD_INIT_FCT		0
-#define VIDEO_TSTC_FCT			serial_tstc
-#define VIDEO_GETC_FCT			serial_getc
+#define VIDEO_TSTC_FCT		serial_stub_tstc
+#define VIDEO_GETC_FCT		serial_stub_getc
 
 /*
  * BOOTP options
diff --git a/include/configs/nokia_rx51.h b/include/configs/nokia_rx51.h
index e0c0fac..53cb390 100644
--- a/include/configs/nokia_rx51.h
+++ b/include/configs/nokia_rx51.h
@@ -263,9 +263,10 @@
 #define VIDEO_TSTC_FCT			rx51_kp_tstc
 #define VIDEO_GETC_FCT			rx51_kp_getc
 #ifndef __ASSEMBLY__
+struct stdio_dev;
 int rx51_kp_init(void);
-int rx51_kp_tstc(void);
-int rx51_kp_getc(void);
+int rx51_kp_tstc(struct stdio_dev *sdev);
+int rx51_kp_getc(struct stdio_dev *sdev);
 #endif
 
 #ifndef MTDPARTS_DEFAULT
diff --git a/include/i8042.h b/include/i8042.h
index 96306192..58c85ec 100644
--- a/include/i8042.h
+++ b/include/i8042.h
@@ -72,8 +72,10 @@ void i8042_flush(void);
  */
 int i8042_disable(void);
 
+struct stdio_dev;
+
 int i8042_kbd_init(void);
-int i8042_tstc(void);
-int i8042_getc(void);
+int i8042_tstc(struct stdio_dev *dev);
+int i8042_getc(struct stdio_dev *dev);
 
 #endif /* _I8042_H_ */
diff --git a/include/stdio_dev.h b/include/stdio_dev.h
index e6dc12a..4587005 100644
--- a/include/stdio_dev.h
+++ b/include/stdio_dev.h
@@ -27,18 +27,21 @@ struct stdio_dev {
 
 /* GENERAL functions */
 
-	int (*start) (void);		/* To start the device			*/
-	int (*stop) (void);		/* To stop the device			*/
+	int (*start)(struct stdio_dev *dev);	/* To start the device */
+	int (*stop)(struct stdio_dev *dev);	/* To stop the device */
 
 /* OUTPUT functions */
 
-	void (*putc) (const char c);	/* To put a char			*/
-	void (*puts) (const char *s);	/* To put a string (accelerator)	*/
+	/* To put a char */
+	void (*putc)(struct stdio_dev *dev, const char c);
+	/* To put a string (accelerator) */
+	void (*puts)(struct stdio_dev *dev, const char *s);
 
 /* INPUT functions */
 
-	int (*tstc) (void);		/* To test if a char is ready...	*/
-	int (*getc) (void);		/* To get that char			*/
+	/* To test if a char is ready... */
+	int (*tstc)(struct stdio_dev *dev);
+	int (*getc)(struct stdio_dev *dev);	/* To get that char */
 
 /* Other functions */
 
diff --git a/include/video.h b/include/video.h
index 0ff857b..673aa2e 100644
--- a/include/video.h
+++ b/include/video.h
@@ -11,9 +11,11 @@
 
 /* Video functions */
 
-int	video_init	(void *videobase);
-void	video_putc	(const char c);
-void	video_puts	(const char *s);
+struct stdio_dev;
+
+int	video_init(void *videobase);
+void	video_putc(struct stdio_dev *dev, const char c);
+void	video_puts(struct stdio_dev *dev, const char *s);
 
 /**
  * Display a BMP format bitmap on the screen
-- 
2.0.0.526.g5318336

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 05/29] dm: Make sure that the root device is probed
  2014-07-09  3:37 [U-Boot] [PATCH v2 0/29] Add additional core driver model features Simon Glass
                   ` (3 preceding siblings ...)
  2014-07-09  3:37 ` [U-Boot] [PATCH v2 04/29] stdio: Pass device pointer to stdio methods Simon Glass
@ 2014-07-09  3:37 ` Simon Glass
  2014-07-09  3:37 ` [U-Boot] [PATCH v2 06/29] dm: Provide a way to shut down driver model Simon Glass
                   ` (23 subsequent siblings)
  28 siblings, 0 replies; 44+ messages in thread
From: Simon Glass @ 2014-07-09  3:37 UTC (permalink / raw)
  To: u-boot

The root device should be probed just like any other device. The effect of
this is to mark the device as activated, so that it can be removed (along
with its children) if required.

Signed-off-by: Simon Glass <sjg@chromium.org>
Acked-by: Marek Vasut <marex@denx.de>
---

Changes in v2: None

 drivers/core/root.c | 3 +++
 test/dm/core.c      | 2 +-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/core/root.c b/drivers/core/root.c
index 1cbb096..bc76370 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -48,6 +48,9 @@ int dm_init(void)
 	ret = device_bind_by_name(NULL, &root_info, &DM_ROOT_NON_CONST);
 	if (ret)
 		return ret;
+	ret = device_probe(DM_ROOT_NON_CONST);
+	if (ret)
+		return ret;
 
 	return 0;
 }
diff --git a/test/dm/core.c b/test/dm/core.c
index be3646b..8c18780 100644
--- a/test/dm/core.c
+++ b/test/dm/core.c
@@ -106,7 +106,7 @@ static int dm_test_autoprobe(struct dm_test_state *dms)
 	ut_asserteq(0, dm_testdrv_op_count[DM_TEST_OP_POST_PROBE]);
 
 	/* The root device should not be activated until needed */
-	ut_assert(!(dms->root->flags & DM_FLAG_ACTIVATED));
+	ut_assert(dms->root->flags & DM_FLAG_ACTIVATED);
 
 	/*
 	 * We should be able to find the three test devices, and they should
-- 
2.0.0.526.g5318336

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 06/29] dm: Provide a way to shut down driver model
  2014-07-09  3:37 [U-Boot] [PATCH v2 0/29] Add additional core driver model features Simon Glass
                   ` (4 preceding siblings ...)
  2014-07-09  3:37 ` [U-Boot] [PATCH v2 05/29] dm: Make sure that the root device is probed Simon Glass
@ 2014-07-09  3:37 ` Simon Glass
  2014-07-09  3:37 ` [U-Boot] [PATCH v2 07/29] sandbox: Remove all drivers before exit Simon Glass
                   ` (22 subsequent siblings)
  28 siblings, 0 replies; 44+ messages in thread
From: Simon Glass @ 2014-07-09  3:37 UTC (permalink / raw)
  To: u-boot

Add a new method which removes and unbinds all drivers.

Signed-off-by: Simon Glass <sjg@chromium.org>
Acked-by: Marek Vasut <marex@denx.de>
---

Changes in v2: None

 drivers/core/root.c | 8 ++++++++
 include/dm/root.h   | 8 ++++++++
 2 files changed, 16 insertions(+)

diff --git a/drivers/core/root.c b/drivers/core/root.c
index bc76370..1fa24c4 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -55,6 +55,14 @@ int dm_init(void)
 	return 0;
 }
 
+int dm_uninit(void)
+{
+	device_remove(dm_root());
+	device_unbind(dm_root());
+
+	return 0;
+}
+
 int dm_scan_platdata(void)
 {
 	int ret;
diff --git a/include/dm/root.h b/include/dm/root.h
index a4826a6..35818b1 100644
--- a/include/dm/root.h
+++ b/include/dm/root.h
@@ -50,4 +50,12 @@ int dm_scan_fdt(const void *blob);
  */
 int dm_init(void);
 
+/**
+ * dm_uninit - Uninitialise Driver Model structures
+ *
+ * All devices will be removed and unbound
+ * @return 0 if OK, -ve on error
+ */
+int dm_uninit(void);
+
 #endif
-- 
2.0.0.526.g5318336

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 07/29] sandbox: Remove all drivers before exit
  2014-07-09  3:37 [U-Boot] [PATCH v2 0/29] Add additional core driver model features Simon Glass
                   ` (5 preceding siblings ...)
  2014-07-09  3:37 ` [U-Boot] [PATCH v2 06/29] dm: Provide a way to shut down driver model Simon Glass
@ 2014-07-09  3:37 ` Simon Glass
  2014-07-09  3:37 ` [U-Boot] [PATCH v2 08/29] dm: Allow drivers to be marked 'before relocation' Simon Glass
                   ` (21 subsequent siblings)
  28 siblings, 0 replies; 44+ messages in thread
From: Simon Glass @ 2014-07-09  3:37 UTC (permalink / raw)
  To: u-boot

Drivers are supposed to be able to close down cleanly. To set a good example,
make sandbox shut down its driver model drivers and remove them before exit.

It may be desirable to do the same more generally once driver model is more
widely-used. This could be done during bootm, before U-Boot jumps to the OS.
It seems far too early to make this change.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2: None

 arch/sandbox/cpu/cpu.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/sandbox/cpu/cpu.c b/arch/sandbox/cpu/cpu.c
index 3f4005b..1aa397c 100644
--- a/arch/sandbox/cpu/cpu.c
+++ b/arch/sandbox/cpu/cpu.c
@@ -4,6 +4,7 @@
  */
 
 #include <common.h>
+#include <dm/root.h>
 #include <os.h>
 #include <asm/state.h>
 
@@ -14,6 +15,9 @@ void reset_cpu(ulong ignored)
 	if (state_uninit())
 		os_exit(2);
 
+	if (dm_uninit())
+		os_exit(2);
+
 	/* This is considered normal termination for now */
 	os_exit(0);
 }
-- 
2.0.0.526.g5318336

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 08/29] dm: Allow drivers to be marked 'before relocation'
  2014-07-09  3:37 [U-Boot] [PATCH v2 0/29] Add additional core driver model features Simon Glass
                   ` (6 preceding siblings ...)
  2014-07-09  3:37 ` [U-Boot] [PATCH v2 07/29] sandbox: Remove all drivers before exit Simon Glass
@ 2014-07-09  3:37 ` Simon Glass
  2014-07-10 23:29   ` Marek Vasut
  2014-07-09  3:37 ` [U-Boot] [PATCH v2 09/29] dm: Support driver model prior to relocation Simon Glass
                   ` (20 subsequent siblings)
  28 siblings, 1 reply; 44+ messages in thread
From: Simon Glass @ 2014-07-09  3:37 UTC (permalink / raw)
  To: u-boot

Driver model currently only operates after relocation is complete. In this
state U-Boot typically has a small amount of memory available. In adding
support for driver model prior to relocation we must try to use as little
memory as possible.

In addition, on some machines the memory has not be inited and/or the CPU
is not running at full speed or the data cache is off. These can reduce
execution performance, so the less initialisation that is done before
relocation the better.

An immediately-obvious improvement is to only initialise drivers which are
actually going to be used before relocation. On many boards the only such
driver is a serial UART, so this provides a very large potential benefit.

Allow drivers to mark themselves as 'pre-reloc' which means that they will
be initialised prior to relocation. This can be done either with a driver
flag or with a 'dm,pre-reloc' device tree property.

To support this, the various dm scanning function now take a 'pre_reloc_only'
parameter which indicates that only drivers marked pre-reloc should be
bound.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2:
- Rename struct device to struct udevice
- Update test output in doc/driver-model/README.txt

 common/board_r.c             |  4 ++--
 doc/driver-model/README.txt  | 31 +++++++++++++++++-----------
 drivers/core/device.c        |  6 ++++--
 drivers/core/lists.c         |  6 +++---
 drivers/core/root.c          | 11 ++++++----
 include/dm/device-internal.h |  6 ++++--
 include/dm/device.h          |  5 +++++
 include/dm/lists.h           |  2 +-
 include/dm/root.h            |  8 ++++++--
 test/dm/core.c               | 48 +++++++++++++++++++++++++++++++++++---------
 test/dm/test-driver.c        | 11 ++++++++++
 test/dm/test-fdt.c           | 20 +++++++++++++++++-
 test/dm/test-main.c          |  4 ++--
 test/dm/test.dts             | 11 ++++++++++
 14 files changed, 132 insertions(+), 41 deletions(-)

diff --git a/common/board_r.c b/common/board_r.c
index 86424a0..e43a318 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -280,13 +280,13 @@ static int initr_dm(void)
 		debug("dm_init() failed: %d\n", ret);
 		return ret;
 	}
-	ret = dm_scan_platdata();
+	ret = dm_scan_platdata(false);
 	if (ret) {
 		debug("dm_scan_platdata() failed: %d\n", ret);
 		return ret;
 	}
 #ifdef CONFIG_OF_CONTROL
-	ret = dm_scan_fdt(gd->fdt_blob);
+	ret = dm_scan_fdt(gd->fdt_blob, false);
 	if (ret) {
 		debug("dm_scan_fdt() failed: %d\n", ret);
 		return ret;
diff --git a/doc/driver-model/README.txt b/doc/driver-model/README.txt
index 22c3fcb..4858281 100644
--- a/doc/driver-model/README.txt
+++ b/doc/driver-model/README.txt
@@ -95,26 +95,24 @@ are provided in test/dm. To run them, try:
 You should see something like this:
 
     <...U-Boot banner...>
-    Running 12 driver model tests
+    Running 14 driver model tests
     Test: dm_test_autobind
     Test: dm_test_autoprobe
     Test: dm_test_children
     Test: dm_test_fdt
+    Test: dm_test_fdt_pre_reloc
     Test: dm_test_gpio
     sandbox_gpio: sb_gpio_get_value: error: offset 4 not reserved
     Test: dm_test_leak
-    Warning: Please add '#define DEBUG' to the top of common/dlmalloc.c
-    Warning: Please add '#define DEBUG' to the top of common/dlmalloc.c
     Test: dm_test_lifecycle
     Test: dm_test_operations
     Test: dm_test_ordering
     Test: dm_test_platdata
+    Test: dm_test_pre_reloc
     Test: dm_test_remove
     Test: dm_test_uclass
     Failures: 0
 
-(You can add '#define DEBUG' as suggested to check for memory leaks)
-
 
 What is going on?
 -----------------
@@ -538,26 +536,35 @@ dealing with this might not be worth it.
 - Implemented a GPIO system, trying to keep it simple
 
 
+Pre-Relocation Support
+----------------------
+
+For pre-relocation we simply call the driver model init function. Only
+drivers marked with DM_FLAG_PRE_RELOC or the device tree 'dm,pre-reloc'
+flag are initialised prior to relocation. This helps to reduce the driver
+model overhead.
+
+Then post relocation we throw that away and re-init driver model again.
+For drivers which require some sort of continuity between pre- and
+post-relocation devices, we can provide access to the pre-relocation
+device pointers, but this is not currently implemented (the root device
+pointer is saved but not made available through the driver model API).
+
+
 Things to punt for later
 ------------------------
 
 - SPL support - this will have to be present before many drivers can be
 converted, but it seems like we can add it once we are happy with the
 core implementation.
-- Pre-relocation support - similar story
 
-That is not to say that no thinking has gone into these - in fact there
+That is not to say that no thinking has gone into this - in fact there
 is quite a lot there. However, getting these right is non-trivial and
 there is a high cost associated with going down the wrong path.
 
 For SPL, it may be possible to fit in a simplified driver model with only
 bind and probe methods, to reduce size.
 
-For pre-relocation we can simply call the driver model init function. Then
-post relocation we throw that away and re-init driver model again. For drivers
-which require some sort of continuity between pre- and post-relocation
-devices, we can provide access to the pre-relocation device pointers.
-
 Uclasses are statically numbered at compile time. It would be possible to
 change this to dynamic numbering, but then we would require some sort of
 lookup service, perhaps searching by name. This is slightly less efficient
diff --git a/drivers/core/device.c b/drivers/core/device.c
index c73c339..86b9ff8 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -129,14 +129,16 @@ fail_bind:
 	return ret;
 }
 
-int device_bind_by_name(struct udevice *parent, const struct driver_info *info,
-			struct udevice **devp)
+int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
+			const struct driver_info *info, struct udevice **devp)
 {
 	struct driver *drv;
 
 	drv = lists_driver_lookup_name(info->name);
 	if (!drv)
 		return -ENOENT;
+	if (pre_reloc_only && !(drv->flags & DM_FLAG_PRE_RELOC))
+		return -EPERM;
 
 	return device_bind(parent, drv, info->name, (void *)info->platdata,
 			   -1, devp);
diff --git a/drivers/core/lists.c b/drivers/core/lists.c
index afb59d1..a8d3aa1 100644
--- a/drivers/core/lists.c
+++ b/drivers/core/lists.c
@@ -61,7 +61,7 @@ struct uclass_driver *lists_uclass_lookup(enum uclass_id id)
 	return NULL;
 }
 
-int lists_bind_drivers(struct udevice *parent)
+int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only)
 {
 	struct driver_info *info =
 		ll_entry_start(struct driver_info, driver_info);
@@ -72,8 +72,8 @@ int lists_bind_drivers(struct udevice *parent)
 	int ret;
 
 	for (entry = info; entry != info + n_ents; entry++) {
-		ret = device_bind_by_name(parent, entry, &dev);
-		if (ret) {
+		ret = device_bind_by_name(parent, pre_reloc_only, entry, &dev);
+		if (ret && ret != -EPERM) {
 			dm_warn("No match for driver '%s'\n", entry->name);
 			if (!result || ret != -ENOENT)
 				result = ret;
diff --git a/drivers/core/root.c b/drivers/core/root.c
index 1fa24c4..c75b60f 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -45,7 +45,7 @@ int dm_init(void)
 	}
 	INIT_LIST_HEAD(&DM_UCLASS_ROOT_NON_CONST);
 
-	ret = device_bind_by_name(NULL, &root_info, &DM_ROOT_NON_CONST);
+	ret = device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST);
 	if (ret)
 		return ret;
 	ret = device_probe(DM_ROOT_NON_CONST);
@@ -63,11 +63,11 @@ int dm_uninit(void)
 	return 0;
 }
 
-int dm_scan_platdata(void)
+int dm_scan_platdata(bool pre_reloc_only)
 {
 	int ret;
 
-	ret = lists_bind_drivers(DM_ROOT_NON_CONST);
+	ret = lists_bind_drivers(DM_ROOT_NON_CONST, pre_reloc_only);
 	if (ret == -ENOENT) {
 		dm_warn("Some drivers were not found\n");
 		ret = 0;
@@ -79,7 +79,7 @@ int dm_scan_platdata(void)
 }
 
 #ifdef CONFIG_OF_CONTROL
-int dm_scan_fdt(const void *blob)
+int dm_scan_fdt(const void *blob, bool pre_reloc_only)
 {
 	int offset = 0;
 	int ret = 0, err;
@@ -88,6 +88,9 @@ int dm_scan_fdt(const void *blob)
 	do {
 		offset = fdt_next_node(blob, offset, &depth);
 		if (offset > 0 && depth == 1) {
+			if (pre_reloc_only &&
+			    !fdt_getprop(blob, offset, "dm,pre-reloc", NULL))
+				continue;
 			err = lists_bind_fdt(gd->dm_root, blob, offset);
 			if (err && !ret)
 				ret = err;
diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h
index 26e5cf5..7005d03 100644
--- a/include/dm/device-internal.h
+++ b/include/dm/device-internal.h
@@ -45,12 +45,14 @@ int device_bind(struct udevice *parent, struct driver *drv,
  * tree.
  *
  * @parent: Pointer to device's parent
+ * @pre_reloc_only: If true, bind the driver only if its DM_INIT_F flag is set.
+ * If false bind the driver always.
  * @info: Name and platdata for this device
  * @devp: Returns a pointer to the bound device
  * @return 0 if OK, -ve on error
  */
-int device_bind_by_name(struct udevice *parent, const struct driver_info *info,
-			struct udevice **devp);
+int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
+			const struct driver_info *info, struct udevice **devp);
 
 /**
  * device_probe() - Probe a device, activating it
diff --git a/include/dm/device.h b/include/dm/device.h
index ae75a3f..4679979 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -23,6 +23,9 @@ struct driver_info;
 /* DM is responsible for allocating and freeing platdata */
 #define DM_FLAG_ALLOC_PDATA	(1 << 1)
 
+/* DM should init this device prior to relocation */
+#define DM_FLAG_PRE_RELOC	(1 << 2)
+
 /**
  * struct udevice - An instance of a driver
  *
@@ -117,6 +120,7 @@ struct udevice_id {
  * ops: Driver-specific operations. This is typically a list of function
  * pointers defined by the driver, to implement driver functions required by
  * the uclass.
+ * @flags: driver flags - see DM_FLAGS_...
  */
 struct driver {
 	char *name;
@@ -130,6 +134,7 @@ struct driver {
 	int priv_auto_alloc_size;
 	int platdata_auto_alloc_size;
 	const void *ops;	/* driver-specific operations */
+	uint32_t flags;
 };
 
 /* Declare a new U-Boot driver */
diff --git a/include/dm/lists.h b/include/dm/lists.h
index 49d87e6..87a3af5 100644
--- a/include/dm/lists.h
+++ b/include/dm/lists.h
@@ -42,7 +42,7 @@ struct uclass_driver *lists_uclass_lookup(enum uclass_id id);
  * @early_only: If true, bind only drivers with the DM_INIT_F flag. If false
  * bind all drivers.
  */
-int lists_bind_drivers(struct udevice *parent);
+int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only);
 
 /**
  * lists_bind_fdt() - bind a device tree node
diff --git a/include/dm/root.h b/include/dm/root.h
index 35818b1..d37b452 100644
--- a/include/dm/root.h
+++ b/include/dm/root.h
@@ -26,9 +26,11 @@ struct udevice *dm_root(void);
  *
  * This scans all available platdata and creates drivers for each
  *
+ * @pre_reloc_only: If true, bind only drivers with the DM_FLAG_PRE_RELOC
+ * flag. If false bind all drivers.
  * @return 0 if OK, -ve on error
  */
-int dm_scan_platdata(void);
+int dm_scan_platdata(bool pre_reloc_only);
 
 /**
  * dm_scan_fdt() - Scan the device tree and bind drivers
@@ -36,9 +38,11 @@ int dm_scan_platdata(void);
  * This scans the device tree and creates a driver for each node
  *
  * @blob: Pointer to device tree blob
+ * @pre_reloc_only: If true, bind only drivers with the DM_FLAG_PRE_RELOC
+ * flag. If false bind all drivers.
  * @return 0 if OK, -ve on error
  */
-int dm_scan_fdt(const void *blob);
+int dm_scan_fdt(const void *blob, bool pre_reloc_only);
 
 /**
  * dm_init() - Initialise Driver Model structures
diff --git a/test/dm/core.c b/test/dm/core.c
index 8c18780..24e0b6b 100644
--- a/test/dm/core.c
+++ b/test/dm/core.c
@@ -25,6 +25,7 @@ enum {
 	TEST_INTVAL2		= 3,
 	TEST_INTVAL3		= 6,
 	TEST_INTVAL_MANUAL	= 101112,
+	TEST_INTVAL_PRE_RELOC	= 7,
 };
 
 static const struct dm_test_pdata test_pdata[] = {
@@ -37,6 +38,10 @@ static const struct dm_test_pdata test_pdata_manual = {
 	.ping_add		= TEST_INTVAL_MANUAL,
 };
 
+static const struct dm_test_pdata test_pdata_pre_reloc = {
+	.ping_add		= TEST_INTVAL_PRE_RELOC,
+};
+
 U_BOOT_DEVICE(dm_test_info1) = {
 	.name = "test_drv",
 	.platdata = &test_pdata[0],
@@ -57,6 +62,11 @@ static struct driver_info driver_info_manual = {
 	.platdata = &test_pdata_manual,
 };
 
+static struct driver_info driver_info_pre_reloc = {
+	.name = "test_pre_reloc_drv",
+	.platdata = &test_pdata_manual,
+};
+
 /* Test that binding with platdata occurs correctly */
 static int dm_test_autobind(struct dm_test_state *dms)
 {
@@ -71,7 +81,7 @@ static int dm_test_autobind(struct dm_test_state *dms)
 	ut_asserteq(0, list_count_items(&gd->dm_root->child_head));
 	ut_asserteq(0, dm_testdrv_op_count[DM_TEST_OP_POST_BIND]);
 
-	ut_assertok(dm_scan_platdata());
+	ut_assertok(dm_scan_platdata(false));
 
 	/* We should have our test class now at least, plus more children */
 	ut_assert(1 < list_count_items(&gd->uclass_root));
@@ -181,7 +191,7 @@ static int dm_test_lifecycle(struct dm_test_state *dms)
 
 	memcpy(op_count, dm_testdrv_op_count, sizeof(op_count));
 
-	ut_assertok(device_bind_by_name(dms->root, &driver_info_manual,
+	ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual,
 					&dev));
 	ut_assert(dev);
 	ut_assert(dm_testdrv_op_count[DM_TEST_OP_BIND]
@@ -232,15 +242,15 @@ static int dm_test_ordering(struct dm_test_state *dms)
 	struct udevice *dev, *dev_penultimate, *dev_last, *test_dev;
 	int pingret;
 
-	ut_assertok(device_bind_by_name(dms->root, &driver_info_manual,
+	ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual,
 					&dev));
 	ut_assert(dev);
 
 	/* Bind two new devices (numbers 4 and 5) */
-	ut_assertok(device_bind_by_name(dms->root, &driver_info_manual,
+	ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual,
 					&dev_penultimate));
 	ut_assert(dev_penultimate);
-	ut_assertok(device_bind_by_name(dms->root, &driver_info_manual,
+	ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual,
 					&dev_last));
 	ut_assert(dev_last);
 
@@ -255,7 +265,8 @@ static int dm_test_ordering(struct dm_test_state *dms)
 	ut_assert(dev_last == test_dev);
 
 	/* Add back the original device 3, now in position 5 */
-	ut_assertok(device_bind_by_name(dms->root, &driver_info_manual, &dev));
+	ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual,
+					&dev));
 	ut_assert(dev);
 
 	/* Try ping */
@@ -375,8 +386,8 @@ static int dm_test_leak(struct dm_test_state *dms)
 		if (!start.uordblks)
 			puts("Warning: Please add '#define DEBUG' to the top of common/dlmalloc.c\n");
 
-		ut_assertok(dm_scan_platdata());
-		ut_assertok(dm_scan_fdt(gd->fdt_blob));
+		ut_assertok(dm_scan_platdata(false));
+		ut_assertok(dm_scan_fdt(gd->fdt_blob, false));
 
 		/* Scanning the uclass is enough to probe all the devices */
 		for (id = UCLASS_ROOT; id < UCLASS_COUNT; id++) {
@@ -444,8 +455,8 @@ static int create_children(struct dm_test_state *dms, struct udevice *parent,
 	for (i = 0; i < count; i++) {
 		struct dm_test_pdata *pdata;
 
-		ut_assertok(device_bind_by_name(parent, &driver_info_manual,
-						&dev));
+		ut_assertok(device_bind_by_name(parent, false,
+						&driver_info_manual, &dev));
 		pdata = calloc(1, sizeof(*pdata));
 		pdata->ping_add = key + i;
 		dev->platdata = pdata;
@@ -542,3 +553,20 @@ static int dm_test_children(struct dm_test_state *dms)
 	return 0;
 }
 DM_TEST(dm_test_children, 0);
+
+/* Test that pre-relocation devices work as expected */
+static int dm_test_pre_reloc(struct dm_test_state *dms)
+{
+	struct udevice *dev;
+
+	/* The normal driver should refuse to bind before relocation */
+	ut_asserteq(-EPERM, device_bind_by_name(dms->root, true,
+						&driver_info_manual, &dev));
+
+	/* But this one is marked pre-reloc */
+	ut_assertok(device_bind_by_name(dms->root, true,
+					&driver_info_pre_reloc, &dev));
+
+	return 0;
+}
+DM_TEST(dm_test_pre_reloc, 0);
diff --git a/test/dm/test-driver.c b/test/dm/test-driver.c
index 0f1a37b..bc6a6e7 100644
--- a/test/dm/test-driver.c
+++ b/test/dm/test-driver.c
@@ -144,3 +144,14 @@ U_BOOT_DRIVER(test_manual_drv) = {
 	.remove	= test_manual_remove,
 	.unbind	= test_manual_unbind,
 };
+
+U_BOOT_DRIVER(test_pre_reloc_drv) = {
+	.name	= "test_pre_reloc_drv",
+	.id	= UCLASS_TEST,
+	.ops	= &test_manual_ops,
+	.bind	= test_manual_bind,
+	.probe	= test_manual_probe,
+	.remove	= test_manual_remove,
+	.unbind	= test_manual_unbind,
+	.flags	= DM_FLAG_PRE_RELOC,
+};
diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c
index 0f50537..d284f7f 100644
--- a/test/dm/test-fdt.c
+++ b/test/dm/test-fdt.c
@@ -100,7 +100,7 @@ static int dm_test_fdt(struct dm_test_state *dms)
 	int ret;
 	int i;
 
-	ret = dm_scan_fdt(gd->fdt_blob);
+	ret = dm_scan_fdt(gd->fdt_blob, false);
 	ut_assert(!ret);
 
 	ret = uclass_get(UCLASS_TEST_FDT, &uc);
@@ -145,3 +145,21 @@ static int dm_test_fdt(struct dm_test_state *dms)
 	return 0;
 }
 DM_TEST(dm_test_fdt, 0);
+
+static int dm_test_fdt_pre_reloc(struct dm_test_state *dms)
+{
+	struct uclass *uc;
+	int ret;
+
+	ret = dm_scan_fdt(gd->fdt_blob, true);
+	ut_assert(!ret);
+
+	ret = uclass_get(UCLASS_TEST_FDT, &uc);
+	ut_assert(!ret);
+
+	/* These is only one pre-reloc device */
+	ut_asserteq(1, list_count_items(&uc->dev_head));
+
+	return 0;
+}
+DM_TEST(dm_test_fdt_pre_reloc, 0);
diff --git a/test/dm/test-main.c b/test/dm/test-main.c
index fbdae68..94ce72a 100644
--- a/test/dm/test-main.c
+++ b/test/dm/test-main.c
@@ -89,11 +89,11 @@ int dm_test_main(void)
 		ut_assertok(dm_test_init(dms));
 
 		if (test->flags & DM_TESTF_SCAN_PDATA)
-			ut_assertok(dm_scan_platdata());
+			ut_assertok(dm_scan_platdata(false));
 		if (test->flags & DM_TESTF_PROBE_TEST)
 			ut_assertok(do_autoprobe(dms));
 		if (test->flags & DM_TESTF_SCAN_FDT)
-			ut_assertok(dm_scan_fdt(gd->fdt_blob));
+			ut_assertok(dm_scan_fdt(gd->fdt_blob, false));
 
 		if (test->func(dms))
 			break;
diff --git a/test/dm/test.dts b/test/dm/test.dts
index 74d236b..17c0439 100644
--- a/test/dm/test.dts
+++ b/test/dm/test.dts
@@ -6,11 +6,22 @@
 	#address-cells = <1>;
 	#size-cells = <0>;
 
+	aliases {
+		console = &uart0;
+	};
+
+	uart0: serial {
+		compatible = "sandbox,serial";
+		dm,pre-reloc;
+		//text-colour = "cyan";
+	};
+
 	a-test {
 		reg = <0>;
 		compatible = "denx,u-boot-fdt-test";
 		ping-expect = <0>;
 		ping-add = <0>;
+		dm,pre-reloc;
 	};
 
 	junk {
-- 
2.0.0.526.g5318336

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 09/29] dm: Support driver model prior to relocation
  2014-07-09  3:37 [U-Boot] [PATCH v2 0/29] Add additional core driver model features Simon Glass
                   ` (7 preceding siblings ...)
  2014-07-09  3:37 ` [U-Boot] [PATCH v2 08/29] dm: Allow drivers to be marked 'before relocation' Simon Glass
@ 2014-07-09  3:37 ` Simon Glass
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 10/29] stdio: Provide functions to add/remove devices using stdio_dev Simon Glass
                   ` (19 subsequent siblings)
  28 siblings, 0 replies; 44+ messages in thread
From: Simon Glass @ 2014-07-09  3:37 UTC (permalink / raw)
  To: u-boot

Initialise devices marked 'pre-reloc' and make them available prior to
relocation. Note that this requires pre-reloc malloc() to be available.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2:
- Minor reword to comment for dm_init_and_scan()

 common/board_f.c                  | 16 ++++++++++++++++
 common/board_r.c                  | 25 ++++---------------------
 drivers/core/root.c               | 25 +++++++++++++++++++++++++
 include/asm-generic/global_data.h |  3 ++-
 include/dm/root.h                 | 13 +++++++++++++
 5 files changed, 60 insertions(+), 22 deletions(-)

diff --git a/common/board_f.c b/common/board_f.c
index b5e2031..8782c43 100644
--- a/common/board_f.c
+++ b/common/board_f.c
@@ -14,6 +14,7 @@
 #include <linux/compiler.h>
 #include <version.h>
 #include <environment.h>
+#include <dm.h>
 #include <fdtdec.h>
 #include <fs.h>
 #if defined(CONFIG_CMD_IDE)
@@ -52,6 +53,7 @@
 #ifdef CONFIG_SANDBOX
 #include <asm/state.h>
 #endif
+#include <dm/root.h>
 #include <linux/compiler.h>
 
 /*
@@ -787,6 +789,19 @@ static int initf_malloc(void)
 	return 0;
 }
 
+static int initf_dm(void)
+{
+#if defined(CONFIG_DM) && defined(CONFIG_SYS_MALLOC_F_LEN)
+	int ret;
+
+	ret = dm_init_and_scan(true);
+	if (ret)
+		return ret;
+#endif
+
+	return 0;
+}
+
 static init_fnc_t init_sequence_f[] = {
 #ifdef CONFIG_SANDBOX
 	setup_ram_buf,
@@ -845,6 +860,7 @@ static init_fnc_t init_sequence_f[] = {
 	init_timebase,
 #endif
 	initf_malloc,
+	initf_dm,
 	init_baud_rate,		/* initialze baudrate settings */
 	serial_init,		/* serial communications setup */
 	console_init_f,		/* stage 1 init of console */
diff --git a/common/board_r.c b/common/board_r.c
index e43a318..a35ffa5 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -273,27 +273,10 @@ static int initr_malloc(void)
 #ifdef CONFIG_DM
 static int initr_dm(void)
 {
-	int ret;
-
-	ret = dm_init();
-	if (ret) {
-		debug("dm_init() failed: %d\n", ret);
-		return ret;
-	}
-	ret = dm_scan_platdata(false);
-	if (ret) {
-		debug("dm_scan_platdata() failed: %d\n", ret);
-		return ret;
-	}
-#ifdef CONFIG_OF_CONTROL
-	ret = dm_scan_fdt(gd->fdt_blob, false);
-	if (ret) {
-		debug("dm_scan_fdt() failed: %d\n", ret);
-		return ret;
-	}
-#endif
-
-	return 0;
+	/* Save the pre-reloc driver model and start a new one */
+	gd->dm_root_f = gd->dm_root;
+	gd->dm_root = NULL;
+	return dm_init_and_scan(false);
 }
 #endif
 
diff --git a/drivers/core/root.c b/drivers/core/root.c
index c75b60f..9a7df11 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -104,6 +104,31 @@ int dm_scan_fdt(const void *blob, bool pre_reloc_only)
 }
 #endif
 
+int dm_init_and_scan(bool pre_reloc_only)
+{
+	int ret;
+
+	ret = dm_init();
+	if (ret) {
+		debug("dm_init() failed: %d\n", ret);
+		return ret;
+	}
+	ret = dm_scan_platdata(pre_reloc_only);
+	if (ret) {
+		debug("dm_scan_platdata() failed: %d\n", ret);
+		return ret;
+	}
+#ifdef CONFIG_OF_CONTROL
+	ret = dm_scan_fdt(gd->fdt_blob, pre_reloc_only);
+	if (ret) {
+		debug("dm_scan_fdt() failed: %d\n", ret);
+		return ret;
+	}
+#endif
+
+	return 0;
+}
+
 /* This is the root driver - all drivers are children of this */
 U_BOOT_DRIVER(root_driver) = {
 	.name	= "root_driver",
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h
index f6a2a20..edde9d7 100644
--- a/include/asm-generic/global_data.h
+++ b/include/asm-generic/global_data.h
@@ -65,7 +65,8 @@ typedef struct global_data {
 	struct global_data *new_gd;	/* relocated global data */
 
 #ifdef CONFIG_DM
-	struct udevice	*dm_root;/* Root instance for Driver Model */
+	struct udevice	*dm_root;	/* Root instance for Driver Model */
+	struct udevice	*dm_root_f;	/* Pre-relocation root instance */
 	struct list_head uclass_root;	/* Head of core tree */
 #endif
 
diff --git a/include/dm/root.h b/include/dm/root.h
index d37b452..09f9303 100644
--- a/include/dm/root.h
+++ b/include/dm/root.h
@@ -45,6 +45,19 @@ int dm_scan_platdata(bool pre_reloc_only);
 int dm_scan_fdt(const void *blob, bool pre_reloc_only);
 
 /**
+ * dm_init_and_scan() - Initialise Driver Model structures and scan for devices
+ *
+ * This function initialises the roots of the driver tree and uclass trees,
+ * then scans and binds available devices from platform data and the FDT.
+ * This calls dm_init() to set up Driver Model structures.
+ *
+ * @pre_reloc_only: If true, bind only drivers with the DM_FLAG_PRE_RELOC
+ * flag. If false bind all drivers.
+ * @return 0 if OK, -ve on error
+ */
+int dm_init_and_scan(bool pre_reloc_only);
+
+/**
  * dm_init() - Initialise Driver Model structures
  *
  * This function will initialize roots of driver tree and class tree.
-- 
2.0.0.526.g5318336

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 10/29] stdio: Provide functions to add/remove devices using stdio_dev
  2014-07-09  3:37 [U-Boot] [PATCH v2 0/29] Add additional core driver model features Simon Glass
                   ` (8 preceding siblings ...)
  2014-07-09  3:37 ` [U-Boot] [PATCH v2 09/29] dm: Support driver model prior to relocation Simon Glass
@ 2014-07-09  3:38 ` Simon Glass
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 11/29] console: Remove vprintf() optimisation for sandbox Simon Glass
                   ` (18 subsequent siblings)
  28 siblings, 0 replies; 44+ messages in thread
From: Simon Glass @ 2014-07-09  3:38 UTC (permalink / raw)
  To: u-boot

The current functions for adding and removing devices require a device name.
This is not convenient for driver model, which wants to store a pointer to
the relevant device. Add new functions which provide this feature and adjust
the old ones to call these.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2:
- Return -ENODEV instead of -1 on error

 common/stdio.c      | 32 ++++++++++++++++++++++++--------
 include/stdio_dev.h |  2 ++
 2 files changed, 26 insertions(+), 8 deletions(-)

diff --git a/common/stdio.c b/common/stdio.c
index dd402cc..692ca7f 100644
--- a/common/stdio.c
+++ b/common/stdio.c
@@ -11,6 +11,7 @@
 
 #include <config.h>
 #include <common.h>
+#include <errno.h>
 #include <stdarg.h>
 #include <malloc.h>
 #include <stdio_dev.h>
@@ -148,32 +149,35 @@ struct stdio_dev* stdio_clone(struct stdio_dev *dev)
 	return _dev;
 }
 
-int stdio_register (struct stdio_dev * dev)
+int stdio_register_dev(struct stdio_dev *dev, struct stdio_dev **devp)
 {
 	struct stdio_dev *_dev;
 
 	_dev = stdio_clone(dev);
 	if(!_dev)
-		return -1;
+		return -ENODEV;
 	list_add_tail(&(_dev->list), &(devs.list));
+	if (devp)
+		*devp = _dev;
+
 	return 0;
 }
 
+int stdio_register(struct stdio_dev *dev)
+{
+	return stdio_register_dev(dev, NULL);
+}
+
 /* deregister the device "devname".
  * returns 0 if success, -1 if device is assigned and 1 if devname not found
  */
 #ifdef	CONFIG_SYS_STDIO_DEREGISTER
-int stdio_deregister(const char *devname)
+int stdio_deregister_dev(struct stdio_dev *dev)
 {
 	int l;
 	struct list_head *pos;
-	struct stdio_dev *dev;
 	char temp_names[3][16];
 
-	dev = stdio_get_by_name(devname);
-
-	if(!dev) /* device not found */
-		return -1;
 	/* get stdio devices (ListRemoveItem changes the dev list) */
 	for (l=0 ; l< MAX_FILES; l++) {
 		if (stdio_devices[l] == dev) {
@@ -197,6 +201,18 @@ int stdio_deregister(const char *devname)
 	}
 	return 0;
 }
+
+int stdio_deregister(const char *devname)
+{
+	struct stdio_dev *dev;
+
+	dev = stdio_get_by_name(devname);
+
+	if (!dev) /* device not found */
+		return -ENODEV;
+
+	return stdio_deregister_dev(dev);
+}
 #endif	/* CONFIG_SYS_STDIO_DEREGISTER */
 
 int stdio_init (void)
diff --git a/include/stdio_dev.h b/include/stdio_dev.h
index 4587005..a7d0825 100644
--- a/include/stdio_dev.h
+++ b/include/stdio_dev.h
@@ -77,10 +77,12 @@ extern char *stdio_names[MAX_FILES];
  * PROTOTYPES
  */
 int	stdio_register (struct stdio_dev * dev);
+int stdio_register_dev(struct stdio_dev *dev, struct stdio_dev **devp);
 int	stdio_init (void);
 void	stdio_print_current_devices(void);
 #ifdef CONFIG_SYS_STDIO_DEREGISTER
 int	stdio_deregister(const char *devname);
+int stdio_deregister_dev(struct stdio_dev *dev);
 #endif
 struct list_head* stdio_get_list(void);
 struct stdio_dev* stdio_get_by_name(const char* name);
-- 
2.0.0.526.g5318336

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 11/29] console: Remove vprintf() optimisation for sandbox
  2014-07-09  3:37 [U-Boot] [PATCH v2 0/29] Add additional core driver model features Simon Glass
                   ` (9 preceding siblings ...)
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 10/29] stdio: Provide functions to add/remove devices using stdio_dev Simon Glass
@ 2014-07-09  3:38 ` Simon Glass
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 12/29] Add a flag indicating when the serial console is ready Simon Glass
                   ` (17 subsequent siblings)
  28 siblings, 0 replies; 44+ messages in thread
From: Simon Glass @ 2014-07-09  3:38 UTC (permalink / raw)
  To: u-boot

If the console is not present, we try to reduce overhead by stopping any
output in vprintf(), before it gets to putc(). This is of dubious merit
in general, but in the case of sandbox it is incorrect since we have a
fallback console which reports errors very early in U-Boot. If this is
defeated U-Boot can hang or exit with no indication of what is wrong.

Remove the optimisation for sandbox.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2:
- Improve wording in commit message

 common/console.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/common/console.c b/common/console.c
index 11c102a..5576dfd 100644
--- a/common/console.c
+++ b/common/console.c
@@ -504,7 +504,7 @@ int vprintf(const char *fmt, va_list args)
 	uint i;
 	char printbuffer[CONFIG_SYS_PBSIZE];
 
-#ifndef CONFIG_PRE_CONSOLE_BUFFER
+#if defined(CONFIG_PRE_CONSOLE_BUFFER) && !defined(CONFIG_SANDBOX)
 	if (!gd->have_console)
 		return 0;
 #endif
-- 
2.0.0.526.g5318336

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 12/29] Add a flag indicating when the serial console is ready
  2014-07-09  3:37 [U-Boot] [PATCH v2 0/29] Add additional core driver model features Simon Glass
                   ` (10 preceding siblings ...)
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 11/29] console: Remove vprintf() optimisation for sandbox Simon Glass
@ 2014-07-09  3:38 ` Simon Glass
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 13/29] dm: Move uclass error checking/probing into a function Simon Glass
                   ` (16 subsequent siblings)
  28 siblings, 0 replies; 44+ messages in thread
From: Simon Glass @ 2014-07-09  3:38 UTC (permalink / raw)
  To: u-boot

For sandbox we have a fallback console which is used very early in
U-Boot, before serial drivers are available. Rather than try to guess
when to switch to the real console, add a flag so we can be sure. This
makes sure that sandbox can always output a panic() message, for example,
and avoids silent failure (which is very annoying in sandbox).

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2:
- Improve wording in commit message

 common/console.c                  | 4 ++--
 drivers/serial/serial.c           | 1 +
 include/asm-generic/global_data.h | 1 +
 3 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/common/console.c b/common/console.c
index 5576dfd..898da39 100644
--- a/common/console.c
+++ b/common/console.c
@@ -417,7 +417,7 @@ static inline void print_pre_console_buffer(void) {}
 void putc(const char c)
 {
 #ifdef CONFIG_SANDBOX
-	if (!gd) {
+	if (!gd || !(gd->flags & GD_FLG_SERIAL_READY)) {
 		os_putc(c);
 		return;
 	}
@@ -447,7 +447,7 @@ void putc(const char c)
 void puts(const char *s)
 {
 #ifdef CONFIG_SANDBOX
-	if (!gd) {
+	if (!gd || !(gd->flags & GD_FLG_SERIAL_READY)) {
 		os_puts(s);
 		return;
 	}
diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c
index 803d850..d2eb752 100644
--- a/drivers/serial/serial.c
+++ b/drivers/serial/serial.c
@@ -418,6 +418,7 @@ static struct serial_device *get_current(void)
  */
 int serial_init(void)
 {
+	gd->flags |= GD_FLG_SERIAL_READY;
 	return get_current()->start();
 }
 
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h
index edde9d7..74df210 100644
--- a/include/asm-generic/global_data.h
+++ b/include/asm-generic/global_data.h
@@ -106,5 +106,6 @@ typedef struct global_data {
 #define GD_FLG_LOGINIT		0x00020	/* Log Buffer has been initialized */
 #define GD_FLG_DISABLE_CONSOLE	0x00040	/* Disable console (in & out)	   */
 #define GD_FLG_ENV_READY	0x00080	/* Env. imported into hash table   */
+#define GD_FLG_SERIAL_READY	0x00100	/* Pre-reloc serial console ready  */
 
 #endif /* __ASM_GENERIC_GBL_DATA_H */
-- 
2.0.0.526.g5318336

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 13/29] dm: Move uclass error checking/probing into a function
  2014-07-09  3:37 [U-Boot] [PATCH v2 0/29] Add additional core driver model features Simon Glass
                   ` (11 preceding siblings ...)
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 12/29] Add a flag indicating when the serial console is ready Simon Glass
@ 2014-07-09  3:38 ` Simon Glass
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 14/29] fdt: Add a function to get the alias sequence of a node Simon Glass
                   ` (15 subsequent siblings)
  28 siblings, 0 replies; 44+ messages in thread
From: Simon Glass @ 2014-07-09  3:38 UTC (permalink / raw)
  To: u-boot

Several functions will use this same pattern, so bring it into a function.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2: None

 drivers/core/uclass.c | 28 ++++++++++++++++++++++------
 1 file changed, 22 insertions(+), 6 deletions(-)

diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index 34723ec..db91526 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -158,13 +158,19 @@ int uclass_find_device(enum uclass_id id, int index, struct udevice **devp)
 	return -ENODEV;
 }
 
-int uclass_get_device(enum uclass_id id, int index, struct udevice **devp)
+/**
+ * uclass_get_device_tail() - handle the end of a get_device call
+ *
+ * This handles returning an error or probing a device as needed.
+ *
+ * @dev: Device that needs to be probed
+ * @ret: Error to return. If non-zero then the device is not probed
+ * @devp: Returns the value of 'dev' if there is no error
+ * @return ret, if non-zero, else the result of the device_probe() call
+ */
+static int uclass_get_device_tail(struct udevice *dev, int ret,
+				  struct udevice **devp)
 {
-	struct udevice *dev;
-	int ret;
-
-	*devp = NULL;
-	ret = uclass_find_device(id, index, &dev);
 	if (ret)
 		return ret;
 
@@ -177,6 +183,16 @@ int uclass_get_device(enum uclass_id id, int index, struct udevice **devp)
 	return 0;
 }
 
+int uclass_get_device(enum uclass_id id, int index, struct udevice **devp)
+{
+	struct udevice *dev;
+	int ret;
+
+	*devp = NULL;
+	ret = uclass_find_device(id, index, &dev);
+	return uclass_get_device_tail(dev, ret, devp);
+}
+
 int uclass_first_device(enum uclass_id id, struct udevice **devp)
 {
 	struct uclass *uc;
-- 
2.0.0.526.g5318336

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 14/29] fdt: Add a function to get the alias sequence of a node
  2014-07-09  3:37 [U-Boot] [PATCH v2 0/29] Add additional core driver model features Simon Glass
                   ` (12 preceding siblings ...)
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 13/29] dm: Move uclass error checking/probing into a function Simon Glass
@ 2014-07-09  3:38 ` Simon Glass
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 15/29] dm: Move device display into its own function Simon Glass
                   ` (14 subsequent siblings)
  28 siblings, 0 replies; 44+ messages in thread
From: Simon Glass @ 2014-07-09  3:38 UTC (permalink / raw)
  To: u-boot

Aliases are used to provide U-Boot's numbering of devices, such as:

aliases {
	spi0 = "/spi at 12330000";
}

spi at 12330000 {
	...
}

This tells us that the SPI controller at 12330000 is considered to be the
first SPI controller (SPI 0). So we have a numbering for the SPI node.

Add a function that returns the numbering for a node assume that it exists
in the list of aliases.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2: None

 include/fdtdec.h | 18 ++++++++++++++++++
 lib/fdtdec.c     | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 64 insertions(+)

diff --git a/include/fdtdec.h b/include/fdtdec.h
index a7e6ee7..f454f7e 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -345,6 +345,24 @@ int fdtdec_find_aliases_for_id(const void *blob, const char *name,
 int fdtdec_add_aliases_for_id(const void *blob, const char *name,
 			enum fdt_compat_id id, int *node_list, int maxcount);
 
+/**
+ * Get the alias sequence number of a node
+ *
+ * This works out whether a node is pointed to by an alias, and if so, the
+ * sequence number of that alias. Aliases are of the form <base><num> where
+ * <num> is the sequence number. For example spi2 would be sequence number
+ * 2.
+ *
+ * @param blob		Device tree blob (if NULL, then error is returned)
+ * @param base		Base name for alias (before the underscore)
+ * @param node		Node to look up
+ * @param seqp		This is set to the sequence number if one is found,
+ *			but otherwise the value is left alone
+ * @return 0 if a sequence was found, -ve if not
+ */
+int fdtdec_get_alias_seq(const void *blob, const char *base, int node,
+			 int *seqp);
+
 /*
  * Get the name for a compatible ID
  *
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index aaa6620..1b4ae9f 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -5,9 +5,11 @@
 
 #ifndef USE_HOSTCC
 #include <common.h>
+#include <errno.h>
 #include <serial.h>
 #include <libfdt.h>
 #include <fdtdec.h>
+#include <linux/ctype.h>
 
 #include <asm/gpio.h>
 
@@ -319,6 +321,50 @@ int fdtdec_add_aliases_for_id(const void *blob, const char *name,
 	return num_found;
 }
 
+int fdtdec_get_alias_seq(const void *blob, const char *base, int offset,
+			 int *seqp)
+{
+	int base_len = strlen(base);
+	const char *find_name;
+	int find_namelen;
+	int prop_offset;
+	int aliases;
+
+	find_name = fdt_get_name(blob, offset, &find_namelen);
+	debug("Looking for '%s' at %d, name %s\n", base, offset, find_name);
+
+	aliases = fdt_path_offset(blob, "/aliases");
+	for (prop_offset = fdt_first_property_offset(blob, aliases);
+	     prop_offset > 0;
+	     prop_offset = fdt_next_property_offset(blob, prop_offset)) {
+		const char *prop;
+		const char *name;
+		const char *slash;
+		const char *p;
+		int len;
+
+		prop = fdt_getprop_by_offset(blob, prop_offset, &name, &len);
+		debug("   - %s, %s\n", name, prop);
+		if (len < find_namelen || *prop != '/' || prop[len - 1] ||
+		    strncmp(name, base, base_len))
+			continue;
+
+		slash = strrchr(prop, '/');
+		if (strcmp(slash + 1, find_name))
+			continue;
+		for (p = name; *p; p++) {
+			if (isdigit(*p)) {
+				*seqp = simple_strtoul(p, NULL, 10);
+				debug("Found seq %d\n", *seqp);
+				return 0;
+			}
+		}
+	}
+
+	debug("Not found\n");
+	return -ENOENT;
+}
+
 int fdtdec_check_fdt(void)
 {
 	/*
-- 
2.0.0.526.g5318336

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 15/29] dm: Move device display into its own function
  2014-07-09  3:37 [U-Boot] [PATCH v2 0/29] Add additional core driver model features Simon Glass
                   ` (13 preceding siblings ...)
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 14/29] fdt: Add a function to get the alias sequence of a node Simon Glass
@ 2014-07-09  3:38 ` Simon Glass
  2014-07-10 23:33   ` Marek Vasut
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 16/29] dm: Avoid activating devices in 'dm uclass' command Simon Glass
                   ` (13 subsequent siblings)
  28 siblings, 1 reply; 44+ messages in thread
From: Simon Glass @ 2014-07-09  3:38 UTC (permalink / raw)
  To: u-boot

The device display for 'dm tree' and 'dm uclass' is mostly the same, so
move it into a common function.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2: None

 test/dm/cmd_dm.c | 27 +++++++++++++++++++--------
 1 file changed, 19 insertions(+), 8 deletions(-)

diff --git a/test/dm/cmd_dm.c b/test/dm/cmd_dm.c
index 96f10f3..9b77a7f 100644
--- a/test/dm/cmd_dm.c
+++ b/test/dm/cmd_dm.c
@@ -16,6 +16,22 @@
 #include <dm/test.h>
 #include <dm/uclass-internal.h>
 
+/**
+ * dm_display_line() - Display information about a single device
+ *
+ * Displays a single line of information with an option prefix
+ *
+ * @dev:	Device to display
+ * @buf:	Prefix to display at the start of the line
+ */
+static void dm_display_line(struct udevice *dev, char *buf)
+{
+	printf("%s- %c %s @ %08lx", buf,
+	       dev->flags & DM_FLAG_ACTIVATED ? '*' : ' ',
+	       dev->name, (ulong)map_to_sysmem(dev));
+	puts("\n");
+}
+
 static int display_succ(struct udevice *in, char *buf)
 {
 	int len;
@@ -23,10 +39,7 @@ static int display_succ(struct udevice *in, char *buf)
 	char local[16];
 	struct udevice *pos, *n, *prev = NULL;
 
-	printf("%s- %c %s @ %08lx", buf,
-	       in->flags & DM_FLAG_ACTIVATED ? '*' : ' ',
-	       in->name, (ulong)map_to_sysmem(in));
-	puts("\n");
+	dm_display_line(in, buf);
 
 	if (list_empty(&in->child_head))
 		return 0;
@@ -84,9 +97,7 @@ static int do_dm_dump_uclass(cmd_tbl_t *cmdtp, int flag, int argc,
 		for (ret = uclass_first_device(id, &dev);
 		     dev;
 		     ret = uclass_next_device(&dev)) {
-			printf("  %c %s @ %08lx:\n",
-			       dev->flags & DM_FLAG_ACTIVATED ? '*' : ' ',
-			       dev->name, (ulong)map_to_sysmem(dev));
+			dm_display_line(dev, "");
 		}
 		puts("\n");
 	}
@@ -135,7 +146,7 @@ static int do_dm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 U_BOOT_CMD(
 	dm,	2,	1,	do_dm,
 	"Driver model low level access",
-	"tree         Dump driver model tree\n"
+	"tree         Dump driver model tree ('*' = activated)\n"
 	"dm uclass        Dump list of instances for each uclass"
 	TEST_HELP
 );
-- 
2.0.0.526.g5318336

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 16/29] dm: Avoid activating devices in 'dm uclass' command
  2014-07-09  3:37 [U-Boot] [PATCH v2 0/29] Add additional core driver model features Simon Glass
                   ` (14 preceding siblings ...)
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 15/29] dm: Move device display into its own function Simon Glass
@ 2014-07-09  3:38 ` Simon Glass
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 17/29] dm: Introduce device sequence numbering Simon Glass
                   ` (12 subsequent siblings)
  28 siblings, 0 replies; 44+ messages in thread
From: Simon Glass @ 2014-07-09  3:38 UTC (permalink / raw)
  To: u-boot

This command currently activates devices as it lists them. This is not
desirable since it changes the system state. Fix it and avoid printing
a newline if there are no devices in a uclass.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2: None

 test/dm/cmd_dm.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/test/dm/cmd_dm.c b/test/dm/cmd_dm.c
index 9b77a7f..93e5255 100644
--- a/test/dm/cmd_dm.c
+++ b/test/dm/cmd_dm.c
@@ -94,9 +94,9 @@ static int do_dm_dump_uclass(cmd_tbl_t *cmdtp, int flag, int argc,
 			continue;
 
 		printf("uclass %d: %s\n", id, uc->uc_drv->name);
-		for (ret = uclass_first_device(id, &dev);
-		     dev;
-		     ret = uclass_next_device(&dev)) {
+		if (list_empty(&uc->dev_head))
+			continue;
+		list_for_each_entry(dev, &uc->dev_head, uclass_node) {
 			dm_display_line(dev, "");
 		}
 		puts("\n");
-- 
2.0.0.526.g5318336

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 17/29] dm: Introduce device sequence numbering
  2014-07-09  3:37 [U-Boot] [PATCH v2 0/29] Add additional core driver model features Simon Glass
                   ` (15 preceding siblings ...)
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 16/29] dm: Avoid activating devices in 'dm uclass' command Simon Glass
@ 2014-07-09  3:38 ` Simon Glass
  2014-07-09 13:53   ` Jon Loeliger
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 18/29] dm: Display the sequence number for each device Simon Glass
                   ` (11 subsequent siblings)
  28 siblings, 1 reply; 44+ messages in thread
From: Simon Glass @ 2014-07-09  3:38 UTC (permalink / raw)
  To: u-boot

In U-Boot it is pretty common to number devices from 0 and access them
on the command line using this numbering. While it may come to pass that
we will move away from this numbering, the possibility seems remote at
present.

Given that devices within a uclass will have an implied numbering, it
makes sense to build this into driver model as a core feature. The cost
is fairly small in terms of code and data space.

With each uclass having numbered devices we can ask for SPI port 0 or
serial port 1 and receive a single device.

Devices typically request a sequence number using aliases in the device
tree. These are resolved when the device is probed, to deal with conflicts.
Sequence numbers need not be sequential and holes are permitted.

At present there is no support for sequence numbers using static platform
data. It could easily be added to 'struct driver_info' if needed, but it
seems better to add features as we find a use for them, and the use of -1
to mean 'no sequence' makes the default value somewhat painful.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2: None

 doc/driver-model/README.txt  | 101 ++++++++++++++++++++++++++++++++++++++++---
 drivers/core/device.c        |  28 ++++++++++++
 drivers/core/uclass.c        |  78 +++++++++++++++++++++++++++++++++
 include/dm/device.h          |  29 +++++++++++++
 include/dm/uclass-internal.h |  23 ++++++++++
 include/dm/uclass.h          |  31 +++++++++++++
 test/dm/test-fdt.c           |  54 ++++++++++++++++++++++-
 test/dm/test.dts             |  11 ++++-
 8 files changed, 347 insertions(+), 8 deletions(-)

diff --git a/doc/driver-model/README.txt b/doc/driver-model/README.txt
index 4858281..4ac6287 100644
--- a/doc/driver-model/README.txt
+++ b/doc/driver-model/README.txt
@@ -95,12 +95,16 @@ are provided in test/dm. To run them, try:
 You should see something like this:
 
     <...U-Boot banner...>
-    Running 14 driver model tests
+    Running 15 driver model tests
     Test: dm_test_autobind
     Test: dm_test_autoprobe
     Test: dm_test_children
     Test: dm_test_fdt
+    Device 'd-test': seq 3 is in use by 'b-test'
     Test: dm_test_fdt_pre_reloc
+    Test: dm_test_fdt_uclass_seq
+    Device 'd-test': seq 3 is in use by 'b-test'
+    Device 'a-test': seq 0 is in use by 'd-test'
     Test: dm_test_gpio
     sandbox_gpio: sb_gpio_get_value: error: offset 4 not reserved
     Test: dm_test_leak
@@ -339,6 +343,80 @@ numbering comes from include/dm/uclass.h. To add a new uclass, add to the
 end of the enum there, then declare your uclass as above.
 
 
+Device Sequence Numbers
+-----------------------
+
+U-Boot numbers devices from 0 in many situations, such as in the command
+line for I2C and SPI buses, and the device names for serial ports (serial0,
+serial1, ...). Driver model supports this numbering and permits devices
+to be locating by their 'sequence'.
+
+Sequence numbers start from 0 but gaps are permitted. For example, a board
+may have I2C buses 0, 1, 4, 5 but no 2 or 3. The choice of how devices are
+numbered is up to a particular board, and may be set by the SoC in some
+cases. While it might be tempting to automatically renumber the devices
+where there are gaps in the sequence, this can lead to confusion and is
+not the way that U-Boot works.
+
+Each device can request a sequence number. If none is required then the
+device will be automatically allocated the next available sequence number.
+
+To specify the sequence number in the device tree an alias is typically
+used.
+
+aliases {
+	serial2 = "/serial at 22230000";
+};
+
+This indicates that in the uclass called "serial", the named node
+("/serial at 22230000") will be given sequence number 2. Any command or driver
+which requests serial device 2 will obtain this device.
+
+Some devices represent buses where the devices on the bus are numbered or
+addressed. For example, SPI typically numbers its slaves from 0, and I2C
+uses a 7-bit address. In these cases the 'reg' property of the subnode is
+used, for example:
+
+{
+	aliases {
+		spi2 = "/spi at 22300000";
+	};
+
+	spi at 22300000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		spi-flash at 0 {
+			reg = <0>;
+			...
+		}
+		eeprom at 1 {
+			reg = <1>;
+		};
+	};
+
+In this case we have a SPI bus with two slaves at 0 and 1. The SPI bus
+itself is numbered 2. So we might access the SPI flash with:
+
+	sf probe 2:0
+
+and the eeprom with
+
+	sspi 2:1 32 ef
+
+These commands simply need to look up the 2nd device in the SPI uclass to
+find the right SPI bus. Then, they look at the children of that bus for the
+right sequence number (0 or 1 in this case).
+
+Typically the alias method is used for top-level nodes and the 'reg' method
+is used only for buses.
+
+Device sequence numbers are resolved when a device is probed. Before then
+the sequence number is only a request which may or may not be honoured,
+depending on what other devices have been probed. However the numbering is
+entirely under the control of the board author so a conflict is generally
+an error.
+
+
 Driver Lifecycle
 ----------------
 
@@ -409,7 +487,11 @@ steps (see device_probe()):
    This means (for example) that an I2C driver will require that its bus
    be activated.
 
-   e. If the driver provides an ofdata_to_platdata() method, then this is
+   e. The device's sequence number is assigned, either the requested one
+   (assuming no conflicts) or the next available one if there is a conflict
+   or nothing particular is requested.
+
+   f. If the driver provides an ofdata_to_platdata() method, then this is
    called to convert the device tree data into platform data. This should
    do various calls like fdtdec_get_int(gd->fdt_blob, dev->of_offset, ...)
    to access the node and store the resulting information into dev->platdata.
@@ -425,7 +507,7 @@ steps (see device_probe()):
    data, one day it is possible that U-Boot will cache platformat data for
    devices which are regularly de/activated).
 
-   f. The device's probe() method is called. This should do anything that
+   g. The device's probe() method is called. This should do anything that
    is required by the device to get it going. This could include checking
    that the hardware is actually present, setting up clocks for the
    hardware and setting up hardware registers to initial values. The code
@@ -440,9 +522,9 @@ steps (see device_probe()):
    allocate the priv space here yourself. The same applies also to
    platdata_auto_alloc_size. Remember to free them in the remove() method.
 
-   g. The device is marked 'activated'
+   h. The device is marked 'activated'
 
-   h. The uclass's post_probe() method is called, if one exists. This may
+   i. The uclass's post_probe() method is called, if one exists. This may
    cause the uclass to do some housekeeping to record the device as
    activated and 'known' by the uclass.
 
@@ -488,7 +570,14 @@ remove it. This performs the probe steps in reverse:
       or preferably ofdata_to_platdata()) and the deallocation in remove()
       are the responsibility of the driver author.
 
-   e. The device is marked inactive. Note that it is still bound, so the
+   e. The device sequence number is set to -1, meaning that it no longer
+   has an allocated sequence. If the device is later reactivated and that
+   sequence number is still free, it may well receive the name sequence
+   number again. But from this point, the sequence number previously used
+   by this device will no longer exist (think of SPI bus 2 being removed
+   and bus 2 is no longer available for use).
+
+   f. The device is marked inactive. Note that it is still bound, so the
    device structure itself is not freed at this point. Should the device be
    activated again, then the cycle starts again at step 2 above.
 
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 86b9ff8..848ce3b 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -10,6 +10,7 @@
  */
 
 #include <common.h>
+#include <fdtdec.h>
 #include <malloc.h>
 #include <dm/device.h>
 #include <dm/device-internal.h>
@@ -21,6 +22,8 @@
 #include <linux/err.h>
 #include <linux/list.h>
 
+DECLARE_GLOBAL_DATA_PTR;
+
 /**
  * device_chld_unbind() - Unbind all device's children from the device
  *
@@ -95,6 +98,21 @@ int device_bind(struct udevice *parent, struct driver *drv, const char *name,
 	dev->parent = parent;
 	dev->driver = drv;
 	dev->uclass = uc;
+
+	/*
+	 * For some devices, such as a SPI or I2C bus, the 'reg' property
+	 * is a reasonable indicator of the sequence number. But if there is
+	 * an alias, we use that in preference. In any case, this is just
+	 * a 'requested' sequence, and will be resolved (and ->seq updated)
+	 * when the device is probed.
+	 */
+	dev->req_seq = fdtdec_get_int(gd->fdt_blob, of_offset, "reg", -1);
+	dev->seq = -1;
+	if (uc->uc_drv->name && of_offset != -1) {
+		fdtdec_get_alias_seq(gd->fdt_blob, uc->uc_drv->name, of_offset,
+				     &dev->req_seq);
+	}
+
 	if (!dev->platdata && drv->platdata_auto_alloc_size)
 		dev->flags |= DM_FLAG_ALLOC_PDATA;
 
@@ -207,6 +225,7 @@ int device_probe(struct udevice *dev)
 	struct driver *drv;
 	int size = 0;
 	int ret;
+	int seq;
 
 	if (!dev)
 		return -EINVAL;
@@ -249,6 +268,13 @@ int device_probe(struct udevice *dev)
 			goto fail;
 	}
 
+	seq = uclass_resolve_seq(dev);
+	if (seq < 0) {
+		ret = seq;
+		goto fail;
+	}
+	dev->seq = seq;
+
 	if (drv->ofdata_to_platdata && dev->of_offset >= 0) {
 		ret = drv->ofdata_to_platdata(dev);
 		if (ret)
@@ -276,6 +302,7 @@ fail_uclass:
 			__func__, dev->name);
 	}
 fail:
+	dev->seq = -1;
 	device_free(dev);
 
 	return ret;
@@ -311,6 +338,7 @@ int device_remove(struct udevice *dev)
 
 	device_free(dev);
 
+	dev->seq = -1;
 	dev->flags &= ~DM_FLAG_ACTIVATED;
 
 	return 0;
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index db91526..c28cf67 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -158,6 +158,35 @@ int uclass_find_device(enum uclass_id id, int index, struct udevice **devp)
 	return -ENODEV;
 }
 
+int uclass_find_device_by_seq(enum uclass_id id, int seq_or_req_seq,
+			      bool find_req_seq, struct udevice **devp)
+{
+	struct uclass *uc;
+	struct udevice *dev;
+	int ret;
+
+	*devp = NULL;
+	debug("%s: %d %d\n", __func__, find_req_seq, seq_or_req_seq);
+	if (seq_or_req_seq == -1)
+		return -ENODEV;
+	ret = uclass_get(id, &uc);
+	if (ret)
+		return ret;
+
+	list_for_each_entry(dev, &uc->dev_head, uclass_node) {
+		debug("   - %d %d\n", dev->req_seq, dev->seq);
+		if ((find_req_seq ? dev->req_seq : dev->seq) ==
+				seq_or_req_seq) {
+			*devp = dev;
+			debug("   - found\n");
+			return 0;
+		}
+	}
+	debug("   - not found\n");
+
+	return -ENODEV;
+}
+
 /**
  * uclass_get_device_tail() - handle the end of a get_device call
  *
@@ -193,6 +222,23 @@ int uclass_get_device(enum uclass_id id, int index, struct udevice **devp)
 	return uclass_get_device_tail(dev, ret, devp);
 }
 
+int uclass_get_device_by_seq(enum uclass_id id, int seq, struct udevice **devp)
+{
+	struct udevice *dev;
+	int ret;
+
+	*devp = NULL;
+	ret = uclass_find_device_by_seq(id, seq, false, &dev);
+	if (ret == -ENODEV) {
+		/*
+		 * We didn't find it in probed devices. See if there is one
+		 * that will request this seq if probed.
+		 */
+		ret = uclass_find_device_by_seq(id, seq, true, &dev);
+	}
+	return uclass_get_device_tail(dev, ret, devp);
+}
+
 int uclass_first_device(enum uclass_id id, struct udevice **devp)
 {
 	struct uclass *uc;
@@ -270,6 +316,37 @@ int uclass_unbind_device(struct udevice *dev)
 	return 0;
 }
 
+int uclass_resolve_seq(struct udevice *dev)
+{
+	struct udevice *dup;
+	int seq;
+	int ret;
+
+	assert(dev->seq == -1);
+	ret = uclass_find_device_by_seq(dev->uclass->uc_drv->id, dev->req_seq,
+					false, &dup);
+	if (!ret) {
+		dm_warn("Device '%s': seq %d is in use by '%s'\n",
+			dev->name, dev->req_seq, dup->name);
+	} else if (ret == -ENODEV) {
+		/* Our requested sequence number is available */
+		if (dev->req_seq != -1)
+			return dev->req_seq;
+	} else {
+		return ret;
+	}
+
+	for (seq = 0; seq < DM_MAX_SEQ; seq++) {
+		ret = uclass_find_device_by_seq(dev->uclass->uc_drv->id, seq,
+						false, &dup);
+		if (ret == -ENODEV)
+			break;
+		if (ret)
+			return ret;
+	}
+	return seq;
+}
+
 int uclass_post_probe_device(struct udevice *dev)
 {
 	struct uclass_driver *uc_drv = dev->uclass->uc_drv;
@@ -297,6 +374,7 @@ int uclass_pre_remove_device(struct udevice *dev)
 		free(dev->uclass_priv);
 		dev->uclass_priv = NULL;
 	}
+	dev->seq = -1;
 
 	return 0;
 }
diff --git a/include/dm/device.h b/include/dm/device.h
index 4679979..6005e7e 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -55,6 +55,8 @@ struct driver_info;
  * @child_head: List of children of this device
  * @sibling_node: Next device in list of all devices
  * @flags: Flags for this device DM_FLAG_...
+ * @req_seq: Requested sequence number for this device (-1 = any)
+ * @seq: Allocated sequence number for this device (-1 = none)
  */
 struct udevice {
 	struct driver *driver;
@@ -69,8 +71,13 @@ struct udevice {
 	struct list_head child_head;
 	struct list_head sibling_node;
 	uint32_t flags;
+	int req_seq;
+	int seq;
 };
 
+/* Maximum sequence number supported */
+#define DM_MAX_SEQ	999
+
 /* Returns the operations for a device */
 #define device_get_ops(dev)	(dev->driver->ops)
 
@@ -161,4 +168,26 @@ void *dev_get_platdata(struct udevice *dev);
  */
 void *dev_get_priv(struct udevice *dev);
 
+/**
+ * device_find_child_by_seq() - Find a child device based on a sequence
+ *
+ * This searches for a device with the given seq or req_seq.
+ *
+ * For seq, if an active device has this sequence it will be returned.
+ * If there is no such device then this will return -ENODEV.
+ *
+ * For req_seq, if a device (whether activated or not) has this req_seq
+ * value, that device will be returned. This is a strong indication that
+ * the device will receive that sequence when activated.
+ *
+ * @parent: Parent device
+ * @seq_or_req_seq: Sequence number to find (0=first)
+ * @find_req_seq: true to find req_seq, false to find seq
+ * @devp: Returns pointer to device (there is only one per for each seq).
+ * Set to NULL if none is found
+ * @return 0 if OK, -ve on error
+ */
+int device_find_child_by_seq(struct udevice *parent, int seq_or_req_seq,
+			     bool find_req_seq, struct udevice **devp);
+
 #endif
diff --git a/include/dm/uclass-internal.h b/include/dm/uclass-internal.h
index 1434db3..f718f37 100644
--- a/include/dm/uclass-internal.h
+++ b/include/dm/uclass-internal.h
@@ -82,4 +82,27 @@ struct uclass *uclass_find(enum uclass_id key);
  */
 int uclass_destroy(struct uclass *uc);
 
+/**
+ * uclass_find_device_by_seq() - Find uclass device based on ID and sequence
+ *
+ * This searches for a device with the given seq or req_seq.
+ *
+ * For seq, if an active device has this sequence it will be returned.
+ * If there is no such device then this will return -ENODEV.
+ *
+ * For req_seq, if a device (whether activated or not) has this req_seq
+ * value, that device will be returned. This is a strong indication that
+ * the device will receive that sequence when activated.
+ *
+ * The device is NOT probed, it is merely returned.
+ *
+ * @id: ID to look up
+ * @seq_or_req_seq: Sequence number to find (0=first)
+ * @find_req_seq: true to find req_seq, false to find seq
+ * @devp: Returns pointer to device (there is only one per for each seq)
+ * @return 0 if OK, -ve on error
+ */
+int uclass_find_device_by_seq(enum uclass_id id, int seq_or_req_seq,
+			      bool find_req_seq, struct udevice **devp);
+
 #endif
diff --git a/include/dm/uclass.h b/include/dm/uclass.h
index afd9923..48ae242 100644
--- a/include/dm/uclass.h
+++ b/include/dm/uclass.h
@@ -106,6 +106,22 @@ int uclass_get(enum uclass_id key, struct uclass **ucp);
 int uclass_get_device(enum uclass_id id, int index, struct udevice **devp);
 
 /**
+ * uclass_get_device_by_seq() - Get a uclass device based on an ID and sequence
+ *
+ * If an active device has this sequence it will be returned. If there is no
+ * such device then this will check for a device that is requesting this
+ * sequence.
+ *
+ * The device is probed to activate it ready for use.
+ *
+ * @id: ID to look up
+ * @seq: Sequence number to find (0=first)
+ * @devp: Returns pointer to device (there is only one for each seq)
+ * @return 0 if OK, -ve on error
+ */
+int uclass_get_device_by_seq(enum uclass_id id, int seq, struct udevice **devp);
+
+/**
  * uclass_first_device() - Get the first device in a uclass
  *
  * @id: Uclass ID to look up
@@ -124,6 +140,21 @@ int uclass_first_device(enum uclass_id id, struct udevice **devp);
 int uclass_next_device(struct udevice **devp);
 
 /**
+ * uclass_resolve_seq() - Resolve a device's sequence number
+ *
+ * On entry dev->seq is -1, and dev->req_seq may be -1 (to allocate a
+ * sequence number automatically, or >= 0 to select a particular number.
+ * If the requested sequence number is in use, then this device will
+ * be allocated another one.
+ *
+ * Note that the device's seq value is not changed by this function.
+ *
+ * @dev: Device for which to allocate sequence number
+ * @return sequence number allocated, or -ve on error
+ */
+int uclass_resolve_seq(struct udevice *dev);
+
+/**
  * uclass_foreach_dev() - Helper function to iteration through devices
  *
  * This creates a for() loop which works through the available devices in
diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c
index d284f7f..d8e94d8 100644
--- a/test/dm/test-fdt.c
+++ b/test/dm/test-fdt.c
@@ -94,7 +94,7 @@ UCLASS_DRIVER(testfdt) = {
 /* Test that FDT-based binding works correctly */
 static int dm_test_fdt(struct dm_test_state *dms)
 {
-	const int num_drivers = 3;
+	const int num_drivers = 4;
 	struct udevice *dev;
 	struct uclass *uc;
 	int ret;
@@ -163,3 +163,55 @@ static int dm_test_fdt_pre_reloc(struct dm_test_state *dms)
 	return 0;
 }
 DM_TEST(dm_test_fdt_pre_reloc, 0);
+
+/* Test that sequence numbers are allocated properly */
+static int dm_test_fdt_uclass_seq(struct dm_test_state *dms)
+{
+	struct udevice *dev;
+
+	/* A few basic santiy tests */
+	ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_FDT, 3, true, &dev));
+	ut_asserteq_str("b-test", dev->name);
+
+	ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_FDT, 0, true, &dev));
+	ut_asserteq_str("a-test", dev->name);
+
+	ut_asserteq(-ENODEV, uclass_find_device_by_seq(UCLASS_TEST_FDT, 5,
+						       true, &dev));
+	ut_asserteq_ptr(NULL, dev);
+
+	/* Test aliases */
+	ut_assertok(uclass_get_device_by_seq(UCLASS_TEST_FDT, 6, &dev));
+	ut_asserteq_str("e-test", dev->name);
+
+	ut_asserteq(-ENODEV, uclass_find_device_by_seq(UCLASS_TEST_FDT, 7,
+						       true, &dev));
+
+	/* Note that c-test is not probed since it is not a top-level node */
+	ut_assertok(uclass_get_device_by_seq(UCLASS_TEST_FDT, 3, &dev));
+	ut_asserteq_str("b-test", dev->name);
+
+	/*
+	 * d-test wants sequence number 3 also, but it can't have it because
+	 * b-test gets it first.
+	 */
+	ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 2, &dev));
+	ut_asserteq_str("d-test", dev->name);
+
+	/* d-test actually gets 0 */
+	ut_assertok(uclass_get_device_by_seq(UCLASS_TEST_FDT, 0, &dev));
+	ut_asserteq_str("d-test", dev->name);
+
+	/* initially no one wants seq 1 */
+	ut_asserteq(-ENODEV, uclass_get_device_by_seq(UCLASS_TEST_FDT, 1,
+						      &dev));
+	ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
+	ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 1, &dev));
+
+	/* But now that it is probed, we can find it */
+	ut_assertok(uclass_get_device_by_seq(UCLASS_TEST_FDT, 1, &dev));
+	ut_asserteq_str("a-test", dev->name);
+
+	return 0;
+}
+DM_TEST(dm_test_fdt_uclass_seq, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/test.dts b/test/dm/test.dts
index 17c0439..d8d7e0f 100644
--- a/test/dm/test.dts
+++ b/test/dm/test.dts
@@ -8,6 +8,7 @@
 
 	aliases {
 		console = &uart0;
+		testfdt6 = "/e-test";
 	};
 
 	uart0: serial {
@@ -43,6 +44,7 @@
 	some-bus {
 		#address-cells = <1>;
 		#size-cells = <0>;
+		reg = <3>;
 		ping-expect = <4>;
 		ping-add = <4>;
 		c-test {
@@ -53,7 +55,14 @@
 	};
 
 	d-test {
-		reg = <6>;
+		reg = <3>;
+		ping-expect = <6>;
+		ping-add = <6>;
+		compatible = "google,another-fdt-test";
+	};
+
+	e-test {
+		reg = <3>;
 		ping-expect = <6>;
 		ping-add = <6>;
 		compatible = "google,another-fdt-test";
-- 
2.0.0.526.g5318336

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 18/29] dm: Display the sequence number for each device
  2014-07-09  3:37 [U-Boot] [PATCH v2 0/29] Add additional core driver model features Simon Glass
                   ` (16 preceding siblings ...)
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 17/29] dm: Introduce device sequence numbering Simon Glass
@ 2014-07-09  3:38 ` Simon Glass
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 19/29] dm: Allow a device to be found by its FDT offset Simon Glass
                   ` (10 subsequent siblings)
  28 siblings, 0 replies; 44+ messages in thread
From: Simon Glass @ 2014-07-09  3:38 UTC (permalink / raw)
  To: u-boot

Add this information to 'dm tree' and 'dm uclass' commands.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2: None

 test/dm/cmd_dm.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/test/dm/cmd_dm.c b/test/dm/cmd_dm.c
index 93e5255..26980d2 100644
--- a/test/dm/cmd_dm.c
+++ b/test/dm/cmd_dm.c
@@ -29,6 +29,8 @@ static void dm_display_line(struct udevice *dev, char *buf)
 	printf("%s- %c %s @ %08lx", buf,
 	       dev->flags & DM_FLAG_ACTIVATED ? '*' : ' ',
 	       dev->name, (ulong)map_to_sysmem(dev));
+	if (dev->req_seq != -1)
+		printf(", %d", dev->req_seq);
 	puts("\n");
 }
 
-- 
2.0.0.526.g5318336

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 19/29] dm: Allow a device to be found by its FDT offset
  2014-07-09  3:37 [U-Boot] [PATCH v2 0/29] Add additional core driver model features Simon Glass
                   ` (17 preceding siblings ...)
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 18/29] dm: Display the sequence number for each device Simon Glass
@ 2014-07-09  3:38 ` Simon Glass
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 20/29] dm: Avoid accessing uclasses before they are ready Simon Glass
                   ` (9 subsequent siblings)
  28 siblings, 0 replies; 44+ messages in thread
From: Simon Glass @ 2014-07-09  3:38 UTC (permalink / raw)
  To: u-boot

Each device that was bound from a device tree has an node that caused it to
be bound. Add functions that find and return a device based on a device tree
offset.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2: None

 doc/driver-model/README.txt |  3 ++-
 drivers/core/uclass.c       | 35 +++++++++++++++++++++++++++++++++++
 include/dm/uclass.h         | 16 ++++++++++++++++
 test/dm/test-fdt.c          | 30 ++++++++++++++++++++++++++++++
 4 files changed, 83 insertions(+), 1 deletion(-)

diff --git a/doc/driver-model/README.txt b/doc/driver-model/README.txt
index 4ac6287..fad6284 100644
--- a/doc/driver-model/README.txt
+++ b/doc/driver-model/README.txt
@@ -95,12 +95,13 @@ are provided in test/dm. To run them, try:
 You should see something like this:
 
     <...U-Boot banner...>
-    Running 15 driver model tests
+    Running 16 driver model tests
     Test: dm_test_autobind
     Test: dm_test_autoprobe
     Test: dm_test_children
     Test: dm_test_fdt
     Device 'd-test': seq 3 is in use by 'b-test'
+    Test: dm_test_fdt_offset
     Test: dm_test_fdt_pre_reloc
     Test: dm_test_fdt_uclass_seq
     Device 'd-test': seq 3 is in use by 'b-test'
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index c28cf67..a27f3d5 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -187,6 +187,30 @@ int uclass_find_device_by_seq(enum uclass_id id, int seq_or_req_seq,
 	return -ENODEV;
 }
 
+static int uclass_find_device_by_of_offset(enum uclass_id id, int node,
+					   struct udevice **devp)
+{
+	struct uclass *uc;
+	struct udevice *dev;
+	int ret;
+
+	*devp = NULL;
+	if (node < 0)
+		return -ENODEV;
+	ret = uclass_get(id, &uc);
+	if (ret)
+		return ret;
+
+	list_for_each_entry(dev, &uc->dev_head, uclass_node) {
+		if (dev->of_offset == node) {
+			*devp = dev;
+			return 0;
+		}
+	}
+
+	return -ENODEV;
+}
+
 /**
  * uclass_get_device_tail() - handle the end of a get_device call
  *
@@ -239,6 +263,17 @@ int uclass_get_device_by_seq(enum uclass_id id, int seq, struct udevice **devp)
 	return uclass_get_device_tail(dev, ret, devp);
 }
 
+int uclass_get_device_by_of_offset(enum uclass_id id, int node,
+				   struct udevice **devp)
+{
+	struct udevice *dev;
+	int ret;
+
+	*devp = NULL;
+	ret = uclass_find_device_by_of_offset(id, node, &dev);
+	return uclass_get_device_tail(dev, ret, devp);
+}
+
 int uclass_first_device(enum uclass_id id, struct udevice **devp)
 {
 	struct uclass *uc;
diff --git a/include/dm/uclass.h b/include/dm/uclass.h
index 48ae242..0b5ade6 100644
--- a/include/dm/uclass.h
+++ b/include/dm/uclass.h
@@ -122,6 +122,22 @@ int uclass_get_device(enum uclass_id id, int index, struct udevice **devp);
 int uclass_get_device_by_seq(enum uclass_id id, int seq, struct udevice **devp);
 
 /**
+ * uclass_get_device_by_of_offset() - Get a uclass device by device tree node
+ *
+ * This searches the devices in the uclass for one attached to the given
+ * device tree node.
+ *
+ * The device is probed to activate it ready for use.
+ *
+ * @id: ID to look up
+ * @node: Device tree offset to search for (if -ve then -ENODEV is returned)
+ * @devp: Returns pointer to device (there is only one for each node)
+ * @return 0 if OK, -ve on error
+ */
+int uclass_get_device_by_of_offset(enum uclass_id id, int node,
+				   struct udevice **devp);
+
+/**
  * uclass_first_device() - Get the first device in a uclass
  *
  * @id: Uclass ID to look up
diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c
index d8e94d8..7980a68 100644
--- a/test/dm/test-fdt.c
+++ b/test/dm/test-fdt.c
@@ -215,3 +215,33 @@ static int dm_test_fdt_uclass_seq(struct dm_test_state *dms)
 	return 0;
 }
 DM_TEST(dm_test_fdt_uclass_seq, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test that we can find a device by device tree offset */
+static int dm_test_fdt_offset(struct dm_test_state *dms)
+{
+	const void *blob = gd->fdt_blob;
+	struct udevice *dev;
+	int node;
+
+	node = fdt_path_offset(blob, "/e-test");
+	ut_assert(node > 0);
+	ut_assertok(uclass_get_device_by_of_offset(UCLASS_TEST_FDT, node,
+						   &dev));
+	ut_asserteq_str("e-test", dev->name);
+
+	/* This node should not be bound */
+	node = fdt_path_offset(blob, "/junk");
+	ut_assert(node > 0);
+	ut_asserteq(-ENODEV, uclass_get_device_by_of_offset(UCLASS_TEST_FDT,
+							    node, &dev));
+
+	/* This is not a top level node so should not be probed */
+	node = fdt_path_offset(blob, "/some-bus/c-test");
+	ut_assert(node > 0);
+	ut_asserteq(-ENODEV, uclass_get_device_by_of_offset(UCLASS_TEST_FDT,
+							    node, &dev));
+
+	return 0;
+}
+
+DM_TEST(dm_test_fdt_offset, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-- 
2.0.0.526.g5318336

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 20/29] dm: Avoid accessing uclasses before they are ready
  2014-07-09  3:37 [U-Boot] [PATCH v2 0/29] Add additional core driver model features Simon Glass
                   ` (18 preceding siblings ...)
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 19/29] dm: Allow a device to be found by its FDT offset Simon Glass
@ 2014-07-09  3:38 ` Simon Glass
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 21/29] fdt: Add a function to get the node offset of an alias Simon Glass
                   ` (8 subsequent siblings)
  28 siblings, 0 replies; 44+ messages in thread
From: Simon Glass @ 2014-07-09  3:38 UTC (permalink / raw)
  To: u-boot

Don't allow access to uclasses before they have been initialised.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2: None

 doc/driver-model/README.txt |  3 ++-
 drivers/core/uclass.c       |  2 ++
 test/dm/core.c              | 14 ++++++++++++++
 3 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/doc/driver-model/README.txt b/doc/driver-model/README.txt
index fad6284..33f077c 100644
--- a/doc/driver-model/README.txt
+++ b/doc/driver-model/README.txt
@@ -95,7 +95,7 @@ are provided in test/dm. To run them, try:
 You should see something like this:
 
     <...U-Boot banner...>
-    Running 16 driver model tests
+    Running 17 driver model tests
     Test: dm_test_autobind
     Test: dm_test_autoprobe
     Test: dm_test_children
@@ -116,6 +116,7 @@ You should see something like this:
     Test: dm_test_pre_reloc
     Test: dm_test_remove
     Test: dm_test_uclass
+    Test: dm_test_uclass_before_ready
     Failures: 0
 
 
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index a27f3d5..61ca17e 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -23,6 +23,8 @@ struct uclass *uclass_find(enum uclass_id key)
 {
 	struct uclass *uc;
 
+	if (!gd->dm_root)
+		return NULL;
 	/*
 	 * TODO(sjg at chromium.org): Optimise this, perhaps moving the found
 	 * node to the start of the list, or creating a linear array mapping
diff --git a/test/dm/core.c b/test/dm/core.c
index 24e0b6b..b0cfb42 100644
--- a/test/dm/core.c
+++ b/test/dm/core.c
@@ -570,3 +570,17 @@ static int dm_test_pre_reloc(struct dm_test_state *dms)
 	return 0;
 }
 DM_TEST(dm_test_pre_reloc, 0);
+
+static int dm_test_uclass_before_ready(struct dm_test_state *dms)
+{
+	struct uclass *uc;
+
+	ut_assertok(uclass_get(UCLASS_TEST, &uc));
+
+	memset(gd, '\0', sizeof(*gd));
+	ut_asserteq_ptr(NULL, uclass_find(UCLASS_TEST));
+
+	return 0;
+}
+
+DM_TEST(dm_test_uclass_before_ready, 0);
-- 
2.0.0.526.g5318336

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 21/29] fdt: Add a function to get the node offset of an alias
  2014-07-09  3:37 [U-Boot] [PATCH v2 0/29] Add additional core driver model features Simon Glass
                   ` (19 preceding siblings ...)
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 20/29] dm: Avoid accessing uclasses before they are ready Simon Glass
@ 2014-07-09  3:38 ` Simon Glass
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 22/29] dm: Tidy up some header file comments Simon Glass
                   ` (7 subsequent siblings)
  28 siblings, 0 replies; 44+ messages in thread
From: Simon Glass @ 2014-07-09  3:38 UTC (permalink / raw)
  To: u-boot

This simple function returns the node offset of a named alias.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2: None

 include/fdtdec.h | 11 +++++++++++
 lib/fdtdec.c     | 15 +++++++++++++++
 2 files changed, 26 insertions(+)

diff --git a/include/fdtdec.h b/include/fdtdec.h
index f454f7e..856e6cf 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -363,6 +363,17 @@ int fdtdec_add_aliases_for_id(const void *blob, const char *name,
 int fdtdec_get_alias_seq(const void *blob, const char *base, int node,
 			 int *seqp);
 
+/**
+ * Get the offset of the given alias node
+ *
+ * This looks up an alias in /aliases then finds the offset of that node.
+ *
+ * @param blob		Device tree blob (if NULL, then error is returned)
+ * @param name		Alias name, e.g. "console"
+ * @return Node offset referred to by that alias, or -ve FDT_ERR_...
+ */
+int fdtdec_get_alias_node(const void *blob, const char *name);
+
 /*
  * Get the name for a compatible ID
  *
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 1b4ae9f..eb5aa20 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -365,6 +365,21 @@ int fdtdec_get_alias_seq(const void *blob, const char *base, int offset,
 	return -ENOENT;
 }
 
+int fdtdec_get_alias_node(const void *blob, const char *name)
+{
+	const char *prop;
+	int alias_node;
+	int len;
+
+	if (!blob)
+		return -FDT_ERR_NOTFOUND;
+	alias_node = fdt_path_offset(blob, "/aliases");
+	prop = fdt_getprop(blob, alias_node, name, &len);
+	if (!prop)
+		return -FDT_ERR_NOTFOUND;
+	return fdt_path_offset(blob, prop);
+}
+
 int fdtdec_check_fdt(void)
 {
 	/*
-- 
2.0.0.526.g5318336

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 22/29] dm: Tidy up some header file comments
  2014-07-09  3:37 [U-Boot] [PATCH v2 0/29] Add additional core driver model features Simon Glass
                   ` (20 preceding siblings ...)
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 21/29] fdt: Add a function to get the node offset of an alias Simon Glass
@ 2014-07-09  3:38 ` Simon Glass
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 23/29] dm: Provide a function to scan child FDT nodes Simon Glass
                   ` (6 subsequent siblings)
  28 siblings, 0 replies; 44+ messages in thread
From: Simon Glass @ 2014-07-09  3:38 UTC (permalink / raw)
  To: u-boot

Fix up the style of a few comments and add/clarify a few others.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2: None

 include/dm/device.h    |  2 +-
 include/dm/platdata.h  | 10 ++++++++--
 include/dm/root.h      |  3 ++-
 include/dm/uclass-id.h |  2 +-
 include/dm/uclass.h    |  2 +-
 5 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/include/dm/device.h b/include/dm/device.h
index 6005e7e..9077490 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -124,7 +124,7 @@ struct udevice_id {
  * This is typically only useful for device-tree-aware drivers (those with
  * an of_match), since drivers which use platdata will have the data
  * provided in the U_BOOT_DEVICE() instantiation.
- * ops: Driver-specific operations. This is typically a list of function
+ * @ops: Driver-specific operations. This is typically a list of function
  * pointers defined by the driver, to implement driver functions required by
  * the uclass.
  * @flags: driver flags - see DM_FLAGS_...
diff --git a/include/dm/platdata.h b/include/dm/platdata.h
index 0ef3353..2bc8b14 100644
--- a/include/dm/platdata.h
+++ b/include/dm/platdata.h
@@ -11,9 +11,15 @@
 #ifndef _DM_PLATDATA_H
 #define _DM_PLATDATA_H
 
+/**
+ * struct driver_info - Information required to instantiate a device
+ *
+ * @name:	Device name
+ * @platdata:	Driver-specific platform data
+ */
 struct driver_info {
-	const char	*name;
-	const void	*platdata;
+	const char *name;
+	const void *platdata;
 };
 
 #define U_BOOT_DEVICE(__name)						\
diff --git a/include/dm/root.h b/include/dm/root.h
index 09f9303..02c7788 100644
--- a/include/dm/root.h
+++ b/include/dm/root.h
@@ -35,7 +35,8 @@ int dm_scan_platdata(bool pre_reloc_only);
 /**
  * dm_scan_fdt() - Scan the device tree and bind drivers
  *
- * This scans the device tree and creates a driver for each node
+ * This scans the device tree and creates a driver for each node. Only
+ * the top-level subnodes are examined.
  *
  * @blob: Pointer to device tree blob
  * @pre_reloc_only: If true, bind only drivers with the DM_FLAG_PRE_RELOC
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index f0e691c..77ff9ea 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -19,7 +19,7 @@ enum uclass_id {
 	UCLASS_TEST_FDT,
 
 	/* U-Boot uclasses start here */
-	UCLASS_GPIO,
+	UCLASS_GPIO,		/* Bank of general-purpose I/O pins */
 
 	UCLASS_COUNT,
 	UCLASS_INVALID = -1,
diff --git a/include/dm/uclass.h b/include/dm/uclass.h
index 0b5ade6..8d09ecf 100644
--- a/include/dm/uclass.h
+++ b/include/dm/uclass.h
@@ -98,7 +98,7 @@ int uclass_get(enum uclass_id key, struct uclass **ucp);
  *
  * The device is probed to activate it ready for use.
  *
- * id: ID to look up
+ * @id: ID to look up
  * @index: Device number within that uclass (0=first)
  * @devp: Returns pointer to device (there is only one per for each ID)
  * @return 0 if OK, -ve on error
-- 
2.0.0.526.g5318336

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 23/29] dm: Provide a function to scan child FDT nodes
  2014-07-09  3:37 [U-Boot] [PATCH v2 0/29] Add additional core driver model features Simon Glass
                   ` (21 preceding siblings ...)
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 22/29] dm: Tidy up some header file comments Simon Glass
@ 2014-07-09  3:38 ` Simon Glass
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 24/29] dm: Add functions to access a device's children Simon Glass
                   ` (5 subsequent siblings)
  28 siblings, 0 replies; 44+ messages in thread
From: Simon Glass @ 2014-07-09  3:38 UTC (permalink / raw)
  To: u-boot

At present only root nodes in the device tree are scanned for devices.
But some devices can have children. For example a SPI bus may have
several children for each of its chip selects.

Add a function which scans subnodes and binds devices for each one. This
can be used for the root node scan also, so change it.

A device can call this function in its bind() or probe() methods to bind
its children.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2: None

 doc/driver-model/README.txt |  6 ++++-
 drivers/core/root.c         | 34 +++++++++++++-----------
 include/dm/root.h           | 16 ++++++++++++
 include/dm/test.h           |  9 +++++++
 include/dm/uclass-id.h      |  1 +
 test/dm/Makefile            |  1 +
 test/dm/bus.c               | 63 +++++++++++++++++++++++++++++++++++++++++++++
 test/dm/test-fdt.c          | 63 +++++++++++++++++++++++++++------------------
 test/dm/test.dts            | 16 +++++++++++-
 9 files changed, 167 insertions(+), 42 deletions(-)
 create mode 100644 test/dm/bus.c

diff --git a/doc/driver-model/README.txt b/doc/driver-model/README.txt
index 33f077c..a191f47 100644
--- a/doc/driver-model/README.txt
+++ b/doc/driver-model/README.txt
@@ -95,9 +95,13 @@ are provided in test/dm. To run them, try:
 You should see something like this:
 
     <...U-Boot banner...>
-    Running 17 driver model tests
+    Running 18 driver model tests
     Test: dm_test_autobind
     Test: dm_test_autoprobe
+    Test: dm_test_bus_children
+    Device 'd-test': seq 3 is in use by 'b-test'
+    Device 'c-test at 0': seq 0 is in use by 'a-test'
+    Device 'c-test at 1': seq 1 is in use by 'd-test'
     Test: dm_test_children
     Test: dm_test_fdt
     Device 'd-test': seq 3 is in use by 'b-test'
diff --git a/drivers/core/root.c b/drivers/core/root.c
index 9a7df11..bb535e0 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -15,6 +15,7 @@
 #include <dm/device-internal.h>
 #include <dm/lists.h>
 #include <dm/platdata.h>
+#include <dm/root.h>
 #include <dm/uclass.h>
 #include <dm/util.h>
 #include <linux/list.h>
@@ -79,29 +80,32 @@ int dm_scan_platdata(bool pre_reloc_only)
 }
 
 #ifdef CONFIG_OF_CONTROL
-int dm_scan_fdt(const void *blob, bool pre_reloc_only)
+int dm_scan_fdt_node(struct udevice *parent, const void *blob, int offset,
+		     bool pre_reloc_only)
 {
-	int offset = 0;
 	int ret = 0, err;
-	int depth = 0;
-
-	do {
-		offset = fdt_next_node(blob, offset, &depth);
-		if (offset > 0 && depth == 1) {
-			if (pre_reloc_only &&
-			    !fdt_getprop(blob, offset, "dm,pre-reloc", NULL))
-				continue;
-			err = lists_bind_fdt(gd->dm_root, blob, offset);
-			if (err && !ret)
-				ret = err;
-		}
-	} while (offset > 0);
+
+	for (offset = fdt_first_subnode(blob, offset);
+	     offset > 0;
+	     offset = fdt_next_subnode(blob, offset)) {
+		if (pre_reloc_only &&
+		    !fdt_getprop(blob, offset, "dm,pre-reloc", NULL))
+			continue;
+		err = lists_bind_fdt(parent, blob, offset);
+		if (err && !ret)
+			ret = err;
+	}
 
 	if (ret)
 		dm_warn("Some drivers failed to bind\n");
 
 	return ret;
 }
+
+int dm_scan_fdt(const void *blob, bool pre_reloc_only)
+{
+	return dm_scan_fdt_node(gd->dm_root, blob, 0, pre_reloc_only);
+}
 #endif
 
 int dm_init_and_scan(bool pre_reloc_only)
diff --git a/include/dm/root.h b/include/dm/root.h
index 02c7788..33f951b 100644
--- a/include/dm/root.h
+++ b/include/dm/root.h
@@ -46,6 +46,22 @@ int dm_scan_platdata(bool pre_reloc_only);
 int dm_scan_fdt(const void *blob, bool pre_reloc_only);
 
 /**
+ * dm_scan_fdt_node() - Scan the device tree and bind drivers for a node
+ *
+ * This scans the subnodes of a device tree node and and creates a driver
+ * for each one.
+ *
+ * @parent: Parent device for the devices that will be created
+ * @blob: Pointer to device tree blob
+ * @offset: Offset of node to scan
+ * @pre_reloc_only: If true, bind only drivers with the DM_FLAG_PRE_RELOC
+ * flag. If false bind all drivers.
+ * @return 0 if OK, -ve on error
+ */
+int dm_scan_fdt_node(struct udevice *parent, const void *blob, int offset,
+		     bool pre_reloc_only);
+
+/**
  * dm_init_and_scan() - Initialise Driver Model structures and scan for devices
  *
  * This function initialises the roots of the driver tree and uclass trees,
diff --git a/include/dm/test.h b/include/dm/test.h
index 409f1a3..e8e1c0b 100644
--- a/include/dm/test.h
+++ b/include/dm/test.h
@@ -156,6 +156,15 @@ int dm_check_operations(struct dm_test_state *dms, struct udevice *dev,
 			uint32_t base, struct dm_test_priv *priv);
 
 /**
+ * dm_check_devices() - check the devices respond to operations correctly
+ *
+ * @dms: Overall test state
+ * @num_devices: Number of test devices to check
+ * @return 0 if OK, -ve on error
+ */
+int dm_check_devices(struct dm_test_state *dms, int num_devices);
+
+/**
  * dm_test_main() - Run all the tests
  *
  * This runs all available driver model tests
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 77ff9ea..dd95fca 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -17,6 +17,7 @@ enum uclass_id {
 	UCLASS_DEMO,
 	UCLASS_TEST,
 	UCLASS_TEST_FDT,
+	UCLASS_TEST_BUS,
 
 	/* U-Boot uclasses start here */
 	UCLASS_GPIO,		/* Bank of general-purpose I/O pins */
diff --git a/test/dm/Makefile b/test/dm/Makefile
index c0f2135..5c2415e 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -5,6 +5,7 @@
 #
 
 obj-$(CONFIG_CMD_DM) += cmd_dm.o
+obj-$(CONFIG_DM_TEST) += bus.o
 obj-$(CONFIG_DM_TEST) += test-driver.o
 obj-$(CONFIG_DM_TEST) += test-fdt.o
 obj-$(CONFIG_DM_TEST) += test-main.o
diff --git a/test/dm/bus.c b/test/dm/bus.c
new file mode 100644
index 0000000..cfb9934
--- /dev/null
+++ b/test/dm/bus.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/root.h>
+#include <dm/test.h>
+#include <dm/ut.h>
+#include <dm/util.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int testbus_drv_probe(struct udevice *dev)
+{
+	return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
+}
+
+static const struct udevice_id testbus_ids[] = {
+	{
+		.compatible = "denx,u-boot-test-bus",
+		.data = DM_TEST_TYPE_FIRST },
+	{ }
+};
+
+U_BOOT_DRIVER(testbus_drv) = {
+	.name	= "testbus_drv",
+	.of_match	= testbus_ids,
+	.id	= UCLASS_TEST_BUS,
+	.probe	= testbus_drv_probe,
+	.priv_auto_alloc_size = sizeof(struct dm_test_priv),
+	.platdata_auto_alloc_size = sizeof(struct dm_test_pdata),
+};
+
+UCLASS_DRIVER(testbus) = {
+	.name		= "testbus",
+	.id		= UCLASS_TEST_BUS,
+};
+
+/* Test that we can probe for children */
+static int dm_test_bus_children(struct dm_test_state *dms)
+{
+	int num_devices = 4;
+	struct udevice *bus;
+	struct uclass *uc;
+
+	ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
+	ut_asserteq(num_devices, list_count_items(&uc->dev_head));
+
+	/* Probe the bus, which should yield 3 more devices */
+	ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
+	num_devices += 3;
+
+	ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
+	ut_asserteq(num_devices, list_count_items(&uc->dev_head));
+
+	ut_assert(!dm_check_devices(dms, num_devices));
+
+	return 0;
+}
+DM_TEST(dm_test_bus_children, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c
index 7980a68..cd2c389 100644
--- a/test/dm/test-fdt.c
+++ b/test/dm/test-fdt.c
@@ -91,37 +91,17 @@ UCLASS_DRIVER(testfdt) = {
 	.id		= UCLASS_TEST_FDT,
 };
 
-/* Test that FDT-based binding works correctly */
-static int dm_test_fdt(struct dm_test_state *dms)
+int dm_check_devices(struct dm_test_state *dms, int num_devices)
 {
-	const int num_drivers = 4;
 	struct udevice *dev;
-	struct uclass *uc;
 	int ret;
 	int i;
 
-	ret = dm_scan_fdt(gd->fdt_blob, false);
-	ut_assert(!ret);
-
-	ret = uclass_get(UCLASS_TEST_FDT, &uc);
-	ut_assert(!ret);
-
-	/* These are num_drivers compatible root-level device tree nodes */
-	ut_asserteq(num_drivers, list_count_items(&uc->dev_head));
-
-	/* Each should have no platdata / priv */
-	for (i = 0; i < num_drivers; i++) {
-		ret = uclass_find_device(UCLASS_TEST_FDT, i, &dev);
-		ut_assert(!ret);
-		ut_assert(!dev_get_priv(dev));
-		ut_assert(!dev->platdata);
-	}
-
 	/*
 	 * Now check that the ping adds are what we expect. This is using the
 	 * ping-add property in each node.
 	 */
-	for (i = 0; i < num_drivers; i++) {
+	for (i = 0; i < num_devices; i++) {
 		uint32_t base;
 
 		ret = uclass_get_device(UCLASS_TEST_FDT, i, &dev);
@@ -144,6 +124,37 @@ static int dm_test_fdt(struct dm_test_state *dms)
 
 	return 0;
 }
+
+/* Test that FDT-based binding works correctly */
+static int dm_test_fdt(struct dm_test_state *dms)
+{
+	const int num_devices = 4;
+	struct udevice *dev;
+	struct uclass *uc;
+	int ret;
+	int i;
+
+	ret = dm_scan_fdt(gd->fdt_blob, false);
+	ut_assert(!ret);
+
+	ret = uclass_get(UCLASS_TEST_FDT, &uc);
+	ut_assert(!ret);
+
+	/* These are num_devices compatible root-level device tree nodes */
+	ut_asserteq(num_devices, list_count_items(&uc->dev_head));
+
+	/* Each should have no platdata / priv */
+	for (i = 0; i < num_devices; i++) {
+		ret = uclass_find_device(UCLASS_TEST_FDT, i, &dev);
+		ut_assert(!ret);
+		ut_assert(!dev_get_priv(dev));
+		ut_assert(!dev->platdata);
+	}
+
+	ut_assertok(dm_check_devices(dms, num_devices));
+
+	return 0;
+}
 DM_TEST(dm_test_fdt, 0);
 
 static int dm_test_fdt_pre_reloc(struct dm_test_state *dms)
@@ -187,7 +198,10 @@ static int dm_test_fdt_uclass_seq(struct dm_test_state *dms)
 	ut_asserteq(-ENODEV, uclass_find_device_by_seq(UCLASS_TEST_FDT, 7,
 						       true, &dev));
 
-	/* Note that c-test is not probed since it is not a top-level node */
+	/*
+	 * Note that c-test nodes are not probed since it is not a top-level
+	 * node
+	 */
 	ut_assertok(uclass_get_device_by_seq(UCLASS_TEST_FDT, 3, &dev));
 	ut_asserteq_str("b-test", dev->name);
 
@@ -236,12 +250,11 @@ static int dm_test_fdt_offset(struct dm_test_state *dms)
 							    node, &dev));
 
 	/* This is not a top level node so should not be probed */
-	node = fdt_path_offset(blob, "/some-bus/c-test");
+	node = fdt_path_offset(blob, "/some-bus/c-test at 5");
 	ut_assert(node > 0);
 	ut_asserteq(-ENODEV, uclass_get_device_by_of_offset(UCLASS_TEST_FDT,
 							    node, &dev));
 
 	return 0;
 }
-
 DM_TEST(dm_test_fdt_offset, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/test.dts b/test/dm/test.dts
index d8d7e0f..141d82c 100644
--- a/test/dm/test.dts
+++ b/test/dm/test.dts
@@ -44,14 +44,28 @@
 	some-bus {
 		#address-cells = <1>;
 		#size-cells = <0>;
+		compatible = "denx,u-boot-test-bus";
 		reg = <3>;
 		ping-expect = <4>;
 		ping-add = <4>;
-		c-test {
+		c-test at 5 {
 			compatible = "denx,u-boot-fdt-test";
 			reg = <5>;
+			ping-expect = <5>;
 			ping-add = <5>;
 		};
+		c-test at 0 {
+			compatible = "denx,u-boot-fdt-test";
+			reg = <0>;
+			ping-expect = <6>;
+			ping-add = <6>;
+		};
+		c-test at 1 {
+			compatible = "denx,u-boot-fdt-test";
+			reg = <1>;
+			ping-expect = <7>;
+			ping-add = <7>;
+		};
 	};
 
 	d-test {
-- 
2.0.0.526.g5318336

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 24/29] dm: Add functions to access a device's children
  2014-07-09  3:37 [U-Boot] [PATCH v2 0/29] Add additional core driver model features Simon Glass
                   ` (22 preceding siblings ...)
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 23/29] dm: Provide a function to scan child FDT nodes Simon Glass
@ 2014-07-09  3:38 ` Simon Glass
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 25/29] dm: Introduce per-child data for devices Simon Glass
                   ` (4 subsequent siblings)
  28 siblings, 0 replies; 44+ messages in thread
From: Simon Glass @ 2014-07-09  3:38 UTC (permalink / raw)
  To: u-boot

Devices can have childen that can be addressed by a simple index, the
sequence number or a device tree offset. Add functions to access a child
in each of these ways.

The index is typically used as a fallback when the sequence number is not
available. For example we may use a serial UART with sequence number 0 as
the console, but if no UART has sequence number 0, then we can fall back
to just using the first UART (index 0).

The device tree offset function is useful for buses, where they want to
locate one of their children. The device tree can be scanned to find the
offset of each child, and that offset can then find the device.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2: None

 doc/driver-model/README.txt |  3 +-
 drivers/core/device.c       | 93 +++++++++++++++++++++++++++++++++++++++++++++
 include/dm/device.h         | 58 ++++++++++++++++++++++++++++
 test/dm/bus.c               | 46 ++++++++++++++++++++++
 4 files changed, 199 insertions(+), 1 deletion(-)

diff --git a/doc/driver-model/README.txt b/doc/driver-model/README.txt
index a191f47..b29a79f 100644
--- a/doc/driver-model/README.txt
+++ b/doc/driver-model/README.txt
@@ -95,13 +95,14 @@ are provided in test/dm. To run them, try:
 You should see something like this:
 
     <...U-Boot banner...>
-    Running 18 driver model tests
+    Running 19 driver model tests
     Test: dm_test_autobind
     Test: dm_test_autoprobe
     Test: dm_test_bus_children
     Device 'd-test': seq 3 is in use by 'b-test'
     Device 'c-test at 0': seq 0 is in use by 'a-test'
     Device 'c-test at 1': seq 1 is in use by 'd-test'
+    Test: dm_test_bus_children_funcs
     Test: dm_test_children
     Test: dm_test_fdt
     Device 'd-test': seq 3 is in use by 'b-test'
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 848ce3b..74bb5f0 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -376,3 +376,96 @@ void *dev_get_priv(struct udevice *dev)
 
 	return dev->priv;
 }
+
+static int device_get_device_tail(struct udevice *dev, int ret,
+				  struct udevice **devp)
+{
+	if (ret)
+		return ret;
+
+	ret = device_probe(dev);
+	if (ret)
+		return ret;
+
+	*devp = dev;
+
+	return 0;
+}
+
+int device_get_child(struct udevice *parent, int index, struct udevice **devp)
+{
+	struct udevice *dev;
+
+	list_for_each_entry(dev, &parent->child_head, sibling_node) {
+		if (!index--)
+			return device_get_device_tail(dev, 0, devp);
+	}
+
+	return -ENODEV;
+}
+
+int device_find_child_by_seq(struct udevice *parent, int seq_or_req_seq,
+			     bool find_req_seq, struct udevice **devp)
+{
+	struct udevice *dev;
+
+	*devp = NULL;
+	if (seq_or_req_seq == -1)
+		return -ENODEV;
+
+	list_for_each_entry(dev, &parent->child_head, sibling_node) {
+		if ((find_req_seq ? dev->req_seq : dev->seq) ==
+				seq_or_req_seq) {
+			*devp = dev;
+			return 0;
+		}
+	}
+
+	return -ENODEV;
+}
+
+int device_get_child_by_seq(struct udevice *parent, int seq,
+			    struct udevice **devp)
+{
+	struct udevice *dev;
+	int ret;
+
+	*devp = NULL;
+	ret = device_find_child_by_seq(parent, seq, false, &dev);
+	if (ret == -ENODEV) {
+		/*
+		 * We didn't find it in probed devices. See if there is one
+		 * that will request this seq if probed.
+		 */
+		ret = device_find_child_by_seq(parent, seq, true, &dev);
+	}
+	return device_get_device_tail(dev, ret, devp);
+}
+
+int device_find_child_by_of_offset(struct udevice *parent, int of_offset,
+				   struct udevice **devp)
+{
+	struct udevice *dev;
+
+	*devp = NULL;
+
+	list_for_each_entry(dev, &parent->child_head, sibling_node) {
+		if (dev->of_offset == of_offset) {
+			*devp = dev;
+			return 0;
+		}
+	}
+
+	return -ENODEV;
+}
+
+int device_get_child_by_of_offset(struct udevice *parent, int seq,
+				  struct udevice **devp)
+{
+	struct udevice *dev;
+	int ret;
+
+	*devp = NULL;
+	ret = device_find_child_by_of_offset(parent, seq, &dev);
+	return device_get_device_tail(dev, ret, devp);
+}
diff --git a/include/dm/device.h b/include/dm/device.h
index 9077490..3f0f711 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -169,6 +169,18 @@ void *dev_get_platdata(struct udevice *dev);
 void *dev_get_priv(struct udevice *dev);
 
 /**
+ * device_get_child() - Get the child of a device by index
+ *
+ * Returns the numbered child, 0 being the first. This does not use
+ * sequence numbers, only the natural order.
+ *
+ * @dev:	Parent device to check
+ * @index:	Child index
+ * @devp:	Returns pointer to device
+ */
+int device_get_child(struct udevice *parent, int index, struct udevice **devp);
+
+/**
  * device_find_child_by_seq() - Find a child device based on a sequence
  *
  * This searches for a device with the given seq or req_seq.
@@ -190,4 +202,50 @@ void *dev_get_priv(struct udevice *dev);
 int device_find_child_by_seq(struct udevice *parent, int seq_or_req_seq,
 			     bool find_req_seq, struct udevice **devp);
 
+/**
+ * device_get_child_by_seq() - Get a child device based on a sequence
+ *
+ * If an active device has this sequence it will be returned. If there is no
+ * such device then this will check for a device that is requesting this
+ * sequence.
+ *
+ * The device is probed to activate it ready for use.
+ *
+ * @parent: Parent device
+ * @seq: Sequence number to find (0=first)
+ * @devp: Returns pointer to device (there is only one per for each seq)
+ * Set to NULL if none is found
+ * @return 0 if OK, -ve on error
+ */
+int device_get_child_by_seq(struct udevice *parent, int seq,
+			    struct udevice **devp);
+
+/**
+ * device_find_child_by_of_offset() - Find a child device based on FDT offset
+ *
+ * Locates a child device by its device tree offset.
+ *
+ * @parent: Parent device
+ * @of_offset: Device tree offset to find
+ * @devp: Returns pointer to device if found, otherwise this is set to NULL
+ * @return 0 if OK, -ve on error
+ */
+int device_find_child_by_of_offset(struct udevice *parent, int of_offset,
+				   struct udevice **devp);
+
+/**
+ * device_get_child_by_of_offset() - Get a child device based on FDT offset
+ *
+ * Locates a child device by its device tree offset.
+ *
+ * The device is probed to activate it ready for use.
+ *
+ * @parent: Parent device
+ * @of_offset: Device tree offset to find
+ * @devp: Returns pointer to device if found, otherwise this is set to NULL
+ * @return 0 if OK, -ve on error
+ */
+int device_get_child_by_of_offset(struct udevice *parent, int seq,
+				  struct udevice **devp);
+
 #endif
diff --git a/test/dm/bus.c b/test/dm/bus.c
index cfb9934..08a4725 100644
--- a/test/dm/bus.c
+++ b/test/dm/bus.c
@@ -61,3 +61,49 @@ static int dm_test_bus_children(struct dm_test_state *dms)
 	return 0;
 }
 DM_TEST(dm_test_bus_children, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test our functions for accessing children */
+static int dm_test_bus_children_funcs(struct dm_test_state *dms)
+{
+	const void *blob = gd->fdt_blob;
+	struct udevice *bus, *dev;
+	int node;
+
+	ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
+
+	/* device_get_child() */
+	ut_assertok(device_get_child(bus, 0, &dev));
+	ut_asserteq(-ENODEV, device_get_child(bus, 4, &dev));
+	ut_assertok(device_get_child_by_seq(bus, 5, &dev));
+	ut_assert(dev->flags & DM_FLAG_ACTIVATED);
+	ut_asserteq_str("c-test at 5", dev->name);
+
+	/* Device with sequence number 0 should be accessible */
+	ut_asserteq(-ENODEV, device_find_child_by_seq(bus, -1, true, &dev));
+	ut_assertok(device_find_child_by_seq(bus, 0, true, &dev));
+	ut_assert(!(dev->flags & DM_FLAG_ACTIVATED));
+	ut_asserteq(-ENODEV, device_find_child_by_seq(bus, 0, false, &dev));
+	ut_assertok(device_get_child_by_seq(bus, 0, &dev));
+	ut_assert(dev->flags & DM_FLAG_ACTIVATED);
+
+	/* There is no device with sequence number 2 */
+	ut_asserteq(-ENODEV, device_find_child_by_seq(bus, 2, false, &dev));
+	ut_asserteq(-ENODEV, device_find_child_by_seq(bus, 2, true, &dev));
+	ut_asserteq(-ENODEV, device_get_child_by_seq(bus, 2, &dev));
+
+	/* Looking for something that is not a child */
+	node = fdt_path_offset(blob, "/junk");
+	ut_asserteq(-ENODEV, device_find_child_by_of_offset(bus, node, &dev));
+	node = fdt_path_offset(blob, "/d-test");
+	ut_asserteq(-ENODEV, device_find_child_by_of_offset(bus, node, &dev));
+
+	/* Find a valid child */
+	node = fdt_path_offset(blob, "/some-bus/c-test at 1");
+	ut_assertok(device_find_child_by_of_offset(bus, node, &dev));
+	ut_assert(!(dev->flags & DM_FLAG_ACTIVATED));
+	ut_assertok(device_get_child_by_of_offset(bus, node, &dev));
+	ut_assert(dev->flags & DM_FLAG_ACTIVATED);
+
+	return 0;
+}
+DM_TEST(dm_test_bus_children_funcs, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-- 
2.0.0.526.g5318336

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 25/29] dm: Introduce per-child data for devices
  2014-07-09  3:37 [U-Boot] [PATCH v2 0/29] Add additional core driver model features Simon Glass
                   ` (23 preceding siblings ...)
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 24/29] dm: Add functions to access a device's children Simon Glass
@ 2014-07-09  3:38 ` Simon Glass
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 26/29] dm: Add child_pre_probe() and child_post_remove() methods Simon Glass
                   ` (3 subsequent siblings)
  28 siblings, 0 replies; 44+ messages in thread
From: Simon Glass @ 2014-07-09  3:38 UTC (permalink / raw)
  To: u-boot

Some device types can have child devices and want to store information
about them. For example a USB flash stick attached to a USB host
controller would likely use this space. The controller can hold
information about the USB state of each of its children.

The data is stored attached to the child device in the 'parent_priv'
member. It can be auto-allocated by dm when the child is probed. To
do this, add a per_child_auto_alloc_size value to the parent driver.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2: None

 doc/driver-model/README.txt | 25 +++++++++++------
 drivers/core/device.c       | 26 ++++++++++++++++++
 include/dm/device.h         | 20 ++++++++++++++
 include/dm/test.h           |  9 +++++++
 test/dm/bus.c               | 65 +++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 137 insertions(+), 8 deletions(-)

diff --git a/doc/driver-model/README.txt b/doc/driver-model/README.txt
index b29a79f..cb6b8fd 100644
--- a/doc/driver-model/README.txt
+++ b/doc/driver-model/README.txt
@@ -95,7 +95,7 @@ are provided in test/dm. To run them, try:
 You should see something like this:
 
     <...U-Boot banner...>
-    Running 19 driver model tests
+    Running 20 driver model tests
     Test: dm_test_autobind
     Test: dm_test_autoprobe
     Test: dm_test_bus_children
@@ -103,6 +103,7 @@ You should see something like this:
     Device 'c-test at 0': seq 0 is in use by 'a-test'
     Device 'c-test at 1': seq 1 is in use by 'd-test'
     Test: dm_test_bus_children_funcs
+    Test: dm_test_bus_parent_data
     Test: dm_test_children
     Test: dm_test_fdt
     Device 'd-test': seq 3 is in use by 'b-test'
@@ -489,16 +490,23 @@ steps (see device_probe()):
    stored in the device, but it is uclass data. owned by the uclass driver.
    It is possible for the device to access it.
 
-   d. All parent devices are probed. It is not possible to activate a device
+   d. If the device's immediate parent specifies a per_child_auto_alloc_size
+   then this space is allocated. This is intended for use by the parent
+   device to keep track of things related to the child. For example a USB
+   flash stick attached to a USB host controller would likely use this
+   space. The controller can hold information about the USB state of each
+   of its children.
+
+   e. All parent devices are probed. It is not possible to activate a device
    unless its predecessors (all the way up to the root device) are activated.
    This means (for example) that an I2C driver will require that its bus
    be activated.
 
-   e. The device's sequence number is assigned, either the requested one
+   f. The device's sequence number is assigned, either the requested one
    (assuming no conflicts) or the next available one if there is a conflict
    or nothing particular is requested.
 
-   f. If the driver provides an ofdata_to_platdata() method, then this is
+   g. If the driver provides an ofdata_to_platdata() method, then this is
    called to convert the device tree data into platform data. This should
    do various calls like fdtdec_get_int(gd->fdt_blob, dev->of_offset, ...)
    to access the node and store the resulting information into dev->platdata.
@@ -514,7 +522,7 @@ steps (see device_probe()):
    data, one day it is possible that U-Boot will cache platformat data for
    devices which are regularly de/activated).
 
-   g. The device's probe() method is called. This should do anything that
+   h. The device's probe() method is called. This should do anything that
    is required by the device to get it going. This could include checking
    that the hardware is actually present, setting up clocks for the
    hardware and setting up hardware registers to initial values. The code
@@ -529,9 +537,9 @@ steps (see device_probe()):
    allocate the priv space here yourself. The same applies also to
    platdata_auto_alloc_size. Remember to free them in the remove() method.
 
-   h. The device is marked 'activated'
+   i. The device is marked 'activated'
 
-   i. The uclass's post_probe() method is called, if one exists. This may
+   j. The uclass's post_probe() method is called, if one exists. This may
    cause the uclass to do some housekeeping to record the device as
    activated and 'known' by the uclass.
 
@@ -562,7 +570,8 @@ remove it. This performs the probe steps in reverse:
    to be sure that no hardware is running, it should be enough to remove
    all devices.
 
-   d. The device memory is freed (platform data, private data, uclass data).
+   d. The device memory is freed (platform data, private data, uclass data,
+   parent data).
 
    Note: Because the platform data for a U_BOOT_DEVICE() is defined with a
    static pointer, it is not de-allocated during the remove() method. For
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 74bb5f0..42d250f 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -218,6 +218,13 @@ static void device_free(struct udevice *dev)
 		free(dev->uclass_priv);
 		dev->uclass_priv = NULL;
 	}
+	if (dev->parent) {
+		size = dev->parent->driver->per_child_auto_alloc_size;
+		if (size) {
+			free(dev->parent_priv);
+			dev->parent_priv = NULL;
+		}
+	}
 }
 
 int device_probe(struct udevice *dev)
@@ -263,6 +270,15 @@ int device_probe(struct udevice *dev)
 
 	/* Ensure all parents are probed */
 	if (dev->parent) {
+		size = dev->parent->driver->per_child_auto_alloc_size;
+		if (size) {
+			dev->parent_priv = calloc(1, size);
+			if (!dev->parent_priv) {
+				ret = -ENOMEM;
+				goto fail;
+			}
+		}
+
 		ret = device_probe(dev->parent);
 		if (ret)
 			goto fail;
@@ -377,6 +393,16 @@ void *dev_get_priv(struct udevice *dev)
 	return dev->priv;
 }
 
+void *dev_get_parentdata(struct udevice *dev)
+{
+	if (!dev) {
+		dm_warn("%s: null device", __func__);
+		return NULL;
+	}
+
+	return dev->parent_priv;
+}
+
 static int device_get_device_tail(struct udevice *dev, int ret,
 				  struct udevice **devp)
 {
diff --git a/include/dm/device.h b/include/dm/device.h
index 3f0f711..20207ce 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -51,6 +51,7 @@ struct driver_info;
  * @priv: Private data for this device
  * @uclass: Pointer to uclass for this device
  * @uclass_priv: The uclass's private data for this device
+ * @parent_priv: The parent's private data for this device
  * @uclass_node: Used by uclass to link its devices
  * @child_head: List of children of this device
  * @sibling_node: Next device in list of all devices
@@ -67,6 +68,7 @@ struct udevice {
 	void *priv;
 	struct uclass *uclass;
 	void *uclass_priv;
+	void *parent_priv;
 	struct list_head uclass_node;
 	struct list_head child_head;
 	struct list_head sibling_node;
@@ -124,6 +126,9 @@ struct udevice_id {
  * This is typically only useful for device-tree-aware drivers (those with
  * an of_match), since drivers which use platdata will have the data
  * provided in the U_BOOT_DEVICE() instantiation.
+ * @per_child_auto_alloc_size: Each device can hold private data owned by
+ * its parent. If required this will be automatically allocated if this
+ * value is non-zero.
  * @ops: Driver-specific operations. This is typically a list of function
  * pointers defined by the driver, to implement driver functions required by
  * the uclass.
@@ -140,6 +145,7 @@ struct driver {
 	int (*ofdata_to_platdata)(struct udevice *dev);
 	int priv_auto_alloc_size;
 	int platdata_auto_alloc_size;
+	int per_child_auto_alloc_size;
 	const void *ops;	/* driver-specific operations */
 	uint32_t flags;
 };
@@ -159,6 +165,20 @@ struct driver {
 void *dev_get_platdata(struct udevice *dev);
 
 /**
+ * dev_get_parentdata() - Get the parent data for a device
+ *
+ * The parent data is data stored in the device but owned by the parent.
+ * For example, a USB device may have parent data which contains information
+ * about how to talk to the device over USB.
+ *
+ * This checks that dev is not NULL, but no other checks for now
+ *
+ * @dev		Device to check
+ * @return parent data, or NULL if none
+ */
+void *dev_get_parentdata(struct udevice *dev);
+
+/**
  * dev_get_priv() - Get the private data for a device
  *
  * This checks that dev is not NULL, but no other checks for now
diff --git a/include/dm/test.h b/include/dm/test.h
index e8e1c0b..7b04850 100644
--- a/include/dm/test.h
+++ b/include/dm/test.h
@@ -82,6 +82,15 @@ struct dm_test_uclass_priv {
 	int total_add;
 };
 
+/**
+ * struct dm_test_parent_data - parent's information on each child
+ *
+ * @sum: Test value used to check parent data works correctly
+ */
+struct dm_test_parent_data {
+	int sum;
+};
+
 /*
  * Operation counts for the test driver, used to check that each method is
  * called correctly
diff --git a/test/dm/bus.c b/test/dm/bus.c
index 08a4725..df8edcb3 100644
--- a/test/dm/bus.c
+++ b/test/dm/bus.c
@@ -6,6 +6,7 @@
 
 #include <common.h>
 #include <dm.h>
+#include <dm/device-internal.h>
 #include <dm/root.h>
 #include <dm/test.h>
 #include <dm/ut.h>
@@ -32,6 +33,7 @@ U_BOOT_DRIVER(testbus_drv) = {
 	.probe	= testbus_drv_probe,
 	.priv_auto_alloc_size = sizeof(struct dm_test_priv),
 	.platdata_auto_alloc_size = sizeof(struct dm_test_pdata),
+	.per_child_auto_alloc_size = sizeof(struct dm_test_parent_data),
 };
 
 UCLASS_DRIVER(testbus) = {
@@ -107,3 +109,66 @@ static int dm_test_bus_children_funcs(struct dm_test_state *dms)
 	return 0;
 }
 DM_TEST(dm_test_bus_children_funcs, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test that the bus can store data about each child */
+static int dm_test_bus_parent_data(struct dm_test_state *dms)
+{
+	struct dm_test_parent_data *parent_data;
+	struct udevice *bus, *dev;
+	struct uclass *uc;
+	int value;
+
+	ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
+
+	/* Check that parent data is allocated */
+	ut_assertok(device_find_child_by_seq(bus, 0, true, &dev));
+	ut_asserteq_ptr(NULL, dev_get_parentdata(dev));
+	ut_assertok(device_get_child_by_seq(bus, 0, &dev));
+	parent_data = dev_get_parentdata(dev);
+	ut_assert(NULL != parent_data);
+
+	/* Check that it starts at 0 and goes away when device is removed */
+	parent_data->sum += 5;
+	ut_asserteq(5, parent_data->sum);
+	device_remove(dev);
+	ut_asserteq_ptr(NULL, dev_get_parentdata(dev));
+
+	/* Check that we can do this twice */
+	ut_assertok(device_get_child_by_seq(bus, 0, &dev));
+	parent_data = dev_get_parentdata(dev);
+	ut_assert(NULL != parent_data);
+	parent_data->sum += 5;
+	ut_asserteq(5, parent_data->sum);
+
+	/* Add parent data to all children */
+	ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
+	value = 5;
+	uclass_foreach_dev(dev, uc) {
+		/* Ignore these if they are not on this bus */
+		if (dev->parent != bus) {
+			ut_asserteq_ptr(NULL, dev_get_parentdata(dev));
+			continue;
+		}
+		ut_assertok(device_probe(dev));
+		parent_data = dev_get_parentdata(dev);
+
+		parent_data->sum = value;
+		value += 5;
+	}
+
+	/* Check it is still there */
+	value = 5;
+	uclass_foreach_dev(dev, uc) {
+		/* Ignore these if they are not on this bus */
+		if (dev->parent != bus)
+			continue;
+		parent_data = dev_get_parentdata(dev);
+
+		ut_asserteq(value, parent_data->sum);
+		value += 5;
+	}
+
+	return 0;
+}
+
+DM_TEST(dm_test_bus_parent_data, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-- 
2.0.0.526.g5318336

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 26/29] dm: Add child_pre_probe() and child_post_remove() methods
  2014-07-09  3:37 [U-Boot] [PATCH v2 0/29] Add additional core driver model features Simon Glass
                   ` (24 preceding siblings ...)
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 25/29] dm: Introduce per-child data for devices Simon Glass
@ 2014-07-09  3:38 ` Simon Glass
  2014-07-15  8:26   ` Pavel Herrmann
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 27/29] dm: Improve errors and warnings in lists_bind_fdt() Simon Glass
                   ` (2 subsequent siblings)
  28 siblings, 1 reply; 44+ messages in thread
From: Simon Glass @ 2014-07-09  3:38 UTC (permalink / raw)
  To: u-boot

Some devices (particularly bus devices) must track their children, knowing
when a new child is added so that it can be set up for communication on the
bus.

Add a child_pre_probe() method to provide this feature, and a corresponding
child_post_remove() method.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2: None

 doc/driver-model/README.txt | 68 ++++++++++++++++++++++++++++++++++++++++++++-
 drivers/core/device.c       | 16 ++++++++++-
 include/dm/device.h         |  6 ++++
 include/dm/test.h           |  4 +++
 test/dm/bus.c               | 68 +++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 160 insertions(+), 2 deletions(-)

diff --git a/doc/driver-model/README.txt b/doc/driver-model/README.txt
index cb6b8fd..742b7c8 100644
--- a/doc/driver-model/README.txt
+++ b/doc/driver-model/README.txt
@@ -95,7 +95,7 @@ are provided in test/dm. To run them, try:
 You should see something like this:
 
     <...U-Boot banner...>
-    Running 20 driver model tests
+    Running 21 driver model tests
     Test: dm_test_autobind
     Test: dm_test_autoprobe
     Test: dm_test_bus_children
@@ -104,6 +104,7 @@ You should see something like this:
     Device 'c-test at 1': seq 1 is in use by 'd-test'
     Test: dm_test_bus_children_funcs
     Test: dm_test_bus_parent_data
+    Test: dm_test_bus_parent_ops
     Test: dm_test_children
     Test: dm_test_fdt
     Device 'd-test': seq 3 is in use by 'b-test'
@@ -425,6 +426,71 @@ entirely under the control of the board author so a conflict is generally
 an error.
 
 
+Bus Drivers
+-----------
+
+A common use of driver model is to implement a bus, a device which provides
+access to other devices. Example of buses include SPI and I2C. Typically
+the bus provides some sort of transport or translation that makes it
+possible to talk to the devices on the bus.
+
+Driver model provides a few useful features to help with implementing
+buses. Firstly, a bus can request that its children store some 'parent
+data' which can be used to keep track of child state. Secondly, the bus can
+define methods which are called when a child is probed or removed. This is
+similar to the methods the uclass driver provides.
+
+Here an explanation of how a bus fits with a uclass may be useful. Consider
+a USB bus with several devices attached to it, each from a different (made
+up) uclass:
+
+   xhci_usb (UCLASS_USB)
+      eth (UCLASS_ETHERNET)
+      camera (UCLASS_CAMERA)
+      flash (UCLASS_FLASH_STORAGE)
+
+Each of the devices is connected to a different address on the USB bus.
+The bus device wants to store this address and some other information such
+as the bus speed for each device.
+
+To achieve this, the bus device can use dev->parent_priv in each of its
+three children. This can be auto-allocated if the bus driver has a non-zero
+value for per_child_auto_alloc_size. If not, then the bus device can
+allocate the space itself before the child device is probed.
+
+Also the bus driver can define the child_pre_probe() and child_post_remove()
+methods to allow it to do some processing before the child is activated or
+after it is deactivated.
+
+Note that the information that controls this behaviour is in the bus's
+driver, not the child's. In fact it is possible that child has no knowledge
+that it is connected to a bus. The same child device may even be used on two
+different bus types. As an example. the 'flash' device shown above may also
+be connected on a SATA bus or standalone with no bus:
+
+   xhci_usb (UCLASS_USB)
+      flash (UCLASS_FLASH_STORAGE)  - parent data/methods defined by USB bus
+
+   sata (UCLASS_SATA)
+      flash (UCLASS_FLASH_STORAGE)  - parent data/methods defined by SATA bus
+
+   flash (UCLASS_FLASH_STORAGE)  - no parent data/methods (not on a bus)
+
+Above you can see that the driver for xhci_usb/sata controls the child's
+bus methods. In the third example the device is not on a bus, and therefore
+will not have these methods at all. Consider the case where the flash
+device defines child methods. These would be used for *its* children, and
+would be quite separate from the methods defined by the driver for the bus
+that the flash device is connetced to. The act of attaching a device to a
+parent device which is a bus, causes the device to start behaving like a
+bus device, regardless of its own views on the matter.
+
+The uclass for the device can also contain data private to that uclass.
+But note that each device on the bus may be a memeber of a different
+uclass, and this data has nothing to do with the child data for each child
+on the bus.
+
+
 Driver Lifecycle
 ----------------
 
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 42d250f..166b073 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -291,6 +291,12 @@ int device_probe(struct udevice *dev)
 	}
 	dev->seq = seq;
 
+	if (dev->parent && dev->parent->driver->child_pre_probe) {
+		ret = dev->parent->driver->child_pre_probe(dev);
+		if (ret)
+			goto fail;
+	}
+
 	if (drv->ofdata_to_platdata && dev->of_offset >= 0) {
 		ret = drv->ofdata_to_platdata(dev);
 		if (ret)
@@ -352,12 +358,20 @@ int device_remove(struct udevice *dev)
 			goto err_remove;
 	}
 
+	if (dev->parent && dev->parent->driver->child_post_remove) {
+		ret = dev->parent->driver->child_post_remove(dev);
+		if (ret) {
+			dm_warn("%s: Device '%s' failed child_post_remove()",
+				__func__, dev->name);
+		}
+	}
+
 	device_free(dev);
 
 	dev->seq = -1;
 	dev->flags &= ~DM_FLAG_ACTIVATED;
 
-	return 0;
+	return ret;
 
 err_remove:
 	/* We can't put the children back */
diff --git a/include/dm/device.h b/include/dm/device.h
index 20207ce..c8a4072 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -118,6 +118,10 @@ struct udevice_id {
  * @remove: Called to remove a device, i.e. de-activate it
  * @unbind: Called to unbind a device from its driver
  * @ofdata_to_platdata: Called before probe to decode device tree data
+ * @child_pre_probe: Called before a child device is probed. The device has
+ * memory allocated but it has not yet been probed.
+ * @child_post_remove: Called after a child device is removed. The device
+ * has memory allocated but its device_remove() method has been called.
  * @priv_auto_alloc_size: If non-zero this is the size of the private data
  * to be allocated in the device's ->priv pointer. If zero, then the driver
  * is responsible for allocating any data required.
@@ -143,6 +147,8 @@ struct driver {
 	int (*remove)(struct udevice *dev);
 	int (*unbind)(struct udevice *dev);
 	int (*ofdata_to_platdata)(struct udevice *dev);
+	int (*child_pre_probe)(struct udevice *dev);
+	int (*child_post_remove)(struct udevice *dev);
 	int priv_auto_alloc_size;
 	int platdata_auto_alloc_size;
 	int per_child_auto_alloc_size;
diff --git a/include/dm/test.h b/include/dm/test.h
index 7b04850..235d728 100644
--- a/include/dm/test.h
+++ b/include/dm/test.h
@@ -86,9 +86,11 @@ struct dm_test_uclass_priv {
  * struct dm_test_parent_data - parent's information on each child
  *
  * @sum: Test value used to check parent data works correctly
+ * @flag: Used to track calling of parent operations
  */
 struct dm_test_parent_data {
 	int sum;
+	int flag;
 };
 
 /*
@@ -109,6 +111,7 @@ extern struct dm_test_state global_test_state;
  * @fail_count: Number of tests that failed
  * @force_fail_alloc: Force all memory allocs to fail
  * @skip_post_probe: Skip uclass post-probe processing
+ * @removed: Used to keep track of a device that was removed
  */
 struct dm_test_state {
 	struct udevice *root;
@@ -116,6 +119,7 @@ struct dm_test_state {
 	int fail_count;
 	int force_fail_alloc;
 	int skip_post_probe;
+	struct udevice *removed;
 };
 
 /* Test flags for each test */
diff --git a/test/dm/bus.c b/test/dm/bus.c
index df8edcb3..873d64e 100644
--- a/test/dm/bus.c
+++ b/test/dm/bus.c
@@ -14,11 +14,39 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+enum {
+	FLAG_CHILD_PROBED	= 10,
+	FLAG_CHILD_REMOVED	= -7,
+};
+
+static struct dm_test_state *test_state;
+
 static int testbus_drv_probe(struct udevice *dev)
 {
 	return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
 }
 
+static int testbus_child_pre_probe(struct udevice *dev)
+{
+	struct dm_test_parent_data *parent_data = dev_get_parentdata(dev);
+
+	parent_data->flag += FLAG_CHILD_PROBED;
+
+	return 0;
+}
+
+static int testbus_child_post_remove(struct udevice *dev)
+{
+	struct dm_test_parent_data *parent_data = dev_get_parentdata(dev);
+	struct dm_test_state *dms = test_state;
+
+	parent_data->flag += FLAG_CHILD_REMOVED;
+	if (dms)
+		dms->removed = dev;
+
+	return 0;
+}
+
 static const struct udevice_id testbus_ids[] = {
 	{
 		.compatible = "denx,u-boot-test-bus",
@@ -34,6 +62,8 @@ U_BOOT_DRIVER(testbus_drv) = {
 	.priv_auto_alloc_size = sizeof(struct dm_test_priv),
 	.platdata_auto_alloc_size = sizeof(struct dm_test_pdata),
 	.per_child_auto_alloc_size = sizeof(struct dm_test_parent_data),
+	.child_pre_probe = testbus_child_pre_probe,
+	.child_post_remove = testbus_child_post_remove,
 };
 
 UCLASS_DRIVER(testbus) = {
@@ -172,3 +202,41 @@ static int dm_test_bus_parent_data(struct dm_test_state *dms)
 }
 
 DM_TEST(dm_test_bus_parent_data, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test that the bus ops are called when a child is probed/removed */
+static int dm_test_bus_parent_ops(struct dm_test_state *dms)
+{
+	struct dm_test_parent_data *parent_data;
+	struct udevice *bus, *dev;
+	struct uclass *uc;
+
+	test_state = dms;
+	ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
+	ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
+
+	uclass_foreach_dev(dev, uc) {
+		/* Ignore these if they are not on this bus */
+		if (dev->parent != bus)
+			continue;
+		ut_asserteq_ptr(NULL, dev_get_parentdata(dev));
+
+		ut_assertok(device_probe(dev));
+		parent_data = dev_get_parentdata(dev);
+		ut_asserteq(FLAG_CHILD_PROBED, parent_data->flag);
+	}
+
+	uclass_foreach_dev(dev, uc) {
+		/* Ignore these if they are not on this bus */
+		if (dev->parent != bus)
+			continue;
+		parent_data = dev_get_parentdata(dev);
+		ut_asserteq(FLAG_CHILD_PROBED, parent_data->flag);
+		ut_assertok(device_remove(dev));
+		ut_asserteq_ptr(NULL, dev_get_parentdata(dev));
+		ut_asserteq_ptr(dms->removed, dev);
+	}
+	test_state = NULL;
+
+	return 0;
+}
+DM_TEST(dm_test_bus_parent_ops, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-- 
2.0.0.526.g5318336

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 27/29] dm: Improve errors and warnings in lists_bind_fdt()
  2014-07-09  3:37 [U-Boot] [PATCH v2 0/29] Add additional core driver model features Simon Glass
                   ` (25 preceding siblings ...)
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 26/29] dm: Add child_pre_probe() and child_post_remove() methods Simon Glass
@ 2014-07-09  3:38 ` Simon Glass
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 28/29] dm: Add dm_scan_other() to locate board-specific devices Simon Glass
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 29/29] dm: Give the demo uclass a name Simon Glass
  28 siblings, 0 replies; 44+ messages in thread
From: Simon Glass @ 2014-07-09  3:38 UTC (permalink / raw)
  To: u-boot

Add a debug message for when a device tree node has no driver. Also reword
the warning when a device fails to bind, which was misleading.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2: None

 drivers/core/lists.c | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/drivers/core/lists.c b/drivers/core/lists.c
index a8d3aa1..8c0a548 100644
--- a/drivers/core/lists.c
+++ b/drivers/core/lists.c
@@ -123,16 +123,19 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset)
 	const int n_ents = ll_entry_count(struct driver, driver);
 	struct driver *entry;
 	struct udevice *dev;
+	bool found = false;
 	const char *name;
 	int result = 0;
-	int ret;
+	int ret = 0;
 
 	dm_dbg("bind node %s\n", fdt_get_name(blob, offset, NULL));
 	for (entry = driver; entry != driver + n_ents; entry++) {
 		ret = driver_check_compatible(blob, offset, entry->of_match);
+		name = fdt_get_name(blob, offset, NULL);
 		if (ret == -ENOENT) {
 			continue;
 		} else if (ret == -ENODEV) {
+			dm_dbg("Device '%s' has no compatible string\n", name);
 			break;
 		} else if (ret) {
 			dm_warn("Device tree error at offset %d\n", offset);
@@ -141,14 +144,21 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset)
 			break;
 		}
 
-		name = fdt_get_name(blob, offset, NULL);
 		dm_dbg("   - found match at '%s'\n", entry->name);
 		ret = device_bind(parent, entry, name, NULL, offset, &dev);
 		if (ret) {
-			dm_warn("No match for driver '%s'\n", entry->name);
+			dm_warn("Error binding driver '%s'\n", entry->name);
 			if (!result || ret != -ENOENT)
 				result = ret;
+		} else {
+			found = true;
 		}
+		break;
+	}
+
+	if (!found && !result && ret != -ENODEV) {
+		dm_dbg("No match for node '%s'\n",
+		       fdt_get_name(blob, offset, NULL));
 	}
 
 	return result;
-- 
2.0.0.526.g5318336

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 28/29] dm: Add dm_scan_other() to locate board-specific devices
  2014-07-09  3:37 [U-Boot] [PATCH v2 0/29] Add additional core driver model features Simon Glass
                   ` (26 preceding siblings ...)
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 27/29] dm: Improve errors and warnings in lists_bind_fdt() Simon Glass
@ 2014-07-09  3:38 ` Simon Glass
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 29/29] dm: Give the demo uclass a name Simon Glass
  28 siblings, 0 replies; 44+ messages in thread
From: Simon Glass @ 2014-07-09  3:38 UTC (permalink / raw)
  To: u-boot

Some boards will have devices which are not in the device tree and do not
have platform data. They may be programnatically created, for example.
Add a hook which boards can use to bind those devices early in boot.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2: None

 drivers/core/root.c |  8 ++++++++
 include/dm/root.h   | 13 +++++++++++++
 2 files changed, 21 insertions(+)

diff --git a/drivers/core/root.c b/drivers/core/root.c
index bb535e0..1ad6c54 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -108,6 +108,11 @@ int dm_scan_fdt(const void *blob, bool pre_reloc_only)
 }
 #endif
 
+__weak int dm_scan_other(bool pre_reloc_only)
+{
+	return 0;
+}
+
 int dm_init_and_scan(bool pre_reloc_only)
 {
 	int ret;
@@ -129,6 +134,9 @@ int dm_init_and_scan(bool pre_reloc_only)
 		return ret;
 	}
 #endif
+	ret = dm_scan_other(pre_reloc_only);
+	if (ret)
+		return ret;
 
 	return 0;
 }
diff --git a/include/dm/root.h b/include/dm/root.h
index 33f951b..c7f0c1d 100644
--- a/include/dm/root.h
+++ b/include/dm/root.h
@@ -62,6 +62,19 @@ int dm_scan_fdt_node(struct udevice *parent, const void *blob, int offset,
 		     bool pre_reloc_only);
 
 /**
+ * dm_scan_other() - Scan for other devices
+ *
+ * Some devices may not be visible to Driver Model. This weak function can
+ * be provided by boards which wish to create their own devices
+ * programmaticaly. They should do this by calling device_bind() on each
+ * device.
+ *
+ * @pre_reloc_only: If true, bind only drivers with the DM_FLAG_PRE_RELOC
+ * flag. If false bind all drivers.
+ */
+int dm_scan_other(bool pre_reloc_only);
+
+/**
  * dm_init_and_scan() - Initialise Driver Model structures and scan for devices
  *
  * This function initialises the roots of the driver tree and uclass trees,
-- 
2.0.0.526.g5318336

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 29/29] dm: Give the demo uclass a name
  2014-07-09  3:37 [U-Boot] [PATCH v2 0/29] Add additional core driver model features Simon Glass
                   ` (27 preceding siblings ...)
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 28/29] dm: Add dm_scan_other() to locate board-specific devices Simon Glass
@ 2014-07-09  3:38 ` Simon Glass
  28 siblings, 0 replies; 44+ messages in thread
From: Simon Glass @ 2014-07-09  3:38 UTC (permalink / raw)
  To: u-boot

Uclasses should be named, so add a name for the demo uclass.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v2:
- Expand series to include all driver-model-required changes

 drivers/demo/demo-uclass.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/demo/demo-uclass.c b/drivers/demo/demo-uclass.c
index 636fd88..f6510d6 100644
--- a/drivers/demo/demo-uclass.c
+++ b/drivers/demo/demo-uclass.c
@@ -19,6 +19,7 @@
 DECLARE_GLOBAL_DATA_PTR;
 
 UCLASS_DRIVER(demo) = {
+	.name		= "demo",
 	.id		= UCLASS_DEMO,
 };
 
-- 
2.0.0.526.g5318336

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 17/29] dm: Introduce device sequence numbering
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 17/29] dm: Introduce device sequence numbering Simon Glass
@ 2014-07-09 13:53   ` Jon Loeliger
  2014-07-19  3:22     ` Simon Glass
  0 siblings, 1 reply; 44+ messages in thread
From: Jon Loeliger @ 2014-07-09 13:53 UTC (permalink / raw)
  To: u-boot

HI Simon,

On Tue, Jul 8, 2014 at 10:38 PM, Simon Glass <sjg@chromium.org> wrote:
> In U-Boot it is pretty common to number devices from 0 and access them
> on the command line using this numbering. While it may come to pass that
> we will move away from this numbering, the possibility seems remote at
> present.
>
> Given that devices within a uclass will have an implied numbering, it
> makes sense to build this into driver model as a core feature. The cost
> is fairly small in terms of code and data space.

Hmmm.  I'm not entirely in agreement here.  I think this is the wrong
long-term approach, and this just reinforces the status quo rather than
allowing a migration to a better approach.

> With each uclass having numbered devices we can ask for SPI port 0 or
> serial port 1 and receive a single device.

That's nice, but we should allow them to be named by their actual
names as found in the device tree too.

> Devices typically request a sequence number using aliases in the device
> tree. These are resolved when the device is probed, to deal with conflicts.
> Sequence numbers need not be sequential and holes are permitted.

So they are unreliably unpredictable, unless you also happen
to have the DTS decoder ring in hand too?


> +This indicates that in the uclass called "serial", the named node
> +("/serial at 22230000") will be given sequence number 2. Any command or driver
> +which requests serial device 2 will obtain this device.
> +
> +Some devices represent buses where the devices on the bus are numbered or
> +addressed. For example, SPI typically numbers its slaves from 0, and I2C
> +uses a 7-bit address. In these cases the 'reg' property of the subnode is
> +used, for example:
> +
> +{
> +       aliases {
> +               spi2 = "/spi at 22300000";
> +       };
> +
> +       spi at 22300000 {
> +               #address-cells = <1>;
> +               #size-cells = <1>;
> +               spi-flash at 0 {
> +                       reg = <0>;
> +                       ...
> +               }
> +               eeprom at 1 {
> +                       reg = <1>;
> +               };
> +       };

And not everyone agrees that this is the best approach, even in Linux land.
Specifically, we should be in agreement with Linux, and we should not
have our DTS stray from the definitions that Linux will accept for the same
devices.  And this approach won't be bought by the Linux crowd.  (Yes,
there are some that use  a "reg = <0>;" approach here, but there are many
that do not too.  It's not a universally accepted approach.)

This concept is crucial.

I've said it before, and I will say it again if needed.

So:  Sure, put this approach in, but make it be the backward compatible
approach.  Also please put in a correct naming approach so that we can
move forward with a better longer term solution too.

Thanks,
jdl

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 03/29] stdio: Remove redundant code around stdio_register() calls
  2014-07-09  3:37 ` [U-Boot] [PATCH v2 03/29] stdio: Remove redundant code around stdio_register() calls Simon Glass
@ 2014-07-10 23:23   ` Marek Vasut
  2014-07-13 16:13     ` Simon Glass
  0 siblings, 1 reply; 44+ messages in thread
From: Marek Vasut @ 2014-07-10 23:23 UTC (permalink / raw)
  To: u-boot

On Wednesday, July 09, 2014 at 05:37:53 AM, Simon Glass wrote:
> There is no point in setting a structure's memory to NULL when it has
> already been zeroed with memset().
> 
> Also, there is no need to create a stub function for stdio to call - if the
> function is NULL it will not be called.
> 
> This is a clean-up, with no change in functionality.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> Acked-by: Marek Vasut <marex@denx.de>
> ---

Acked-by: Marek Vasut <marex@denx.de>

Some of those implementations really make my head spin ... *sigh* . Thank you 
for cleaning this up a bit !

Best regards,
Marek Vasut

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 04/29] stdio: Pass device pointer to stdio methods
  2014-07-09  3:37 ` [U-Boot] [PATCH v2 04/29] stdio: Pass device pointer to stdio methods Simon Glass
@ 2014-07-10 23:26   ` Marek Vasut
  2014-07-11  4:29     ` Simon Glass
  0 siblings, 1 reply; 44+ messages in thread
From: Marek Vasut @ 2014-07-10 23:26 UTC (permalink / raw)
  To: u-boot

On Wednesday, July 09, 2014 at 05:37:54 AM, Simon Glass wrote:
> At present stdio device functions do not get any clue as to which stdio
> device is being acted on. Some implementations go to great lengths to work
> around this, such as defining a whole separate set of functions for each
> possible device.
> 
> For driver model we need to associate a stdio_dev with a device. It doesn't
> seem possible to continue with this work-around approach.
> 
> Instead, add a stdio_dev pointer to each of the stdio member functions.
> 
> Note: The serial drivers have the same problem, but it is not strictly
> necessary to fix that to get driver model running. Also, if we convert
> serial over to driver model the problem will go away.
> 
> Code size increases by 244 bytes for Thumb2 and 428 for PowerPC.
> 
> 22: stdio: Pass device pointer to stdio methods
>        arm: (for 2/2 boards)  all +244.0  bss -4.0  text +248.0
>    powerpc: (for 1/1 boards)  all +428.0  text +428.0
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> Acked-by: Marek Vasut <marex@denx.de>

[...]

> diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c
> index fd61a5e..803d850 100644
> --- a/drivers/serial/serial.c
> +++ b/drivers/serial/serial.c
> @@ -254,6 +254,48 @@ void serial_initialize(void)
>  	serial_assign(default_serial_console()->name);
>  }
> 
> +int serial_stub_start(struct stdio_dev *sdev)
> +{
> +	struct serial_device *dev = sdev->priv;

Are you sure this pointer derefference won't blow if $sdev is ever NULL? Can 
$sdev be NULL (in some early stage for example) ?

> +	return dev->start();
> +}

Reviewed-by: Marek Vasut <marex@denx.de>

I really like where this is going.

Best regards,
Marek Vasut

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 08/29] dm: Allow drivers to be marked 'before relocation'
  2014-07-09  3:37 ` [U-Boot] [PATCH v2 08/29] dm: Allow drivers to be marked 'before relocation' Simon Glass
@ 2014-07-10 23:29   ` Marek Vasut
  2014-07-13 18:38     ` Simon Glass
  0 siblings, 1 reply; 44+ messages in thread
From: Marek Vasut @ 2014-07-10 23:29 UTC (permalink / raw)
  To: u-boot

On Wednesday, July 09, 2014 at 05:37:58 AM, Simon Glass wrote:
> Driver model currently only operates after relocation is complete. In this
> state U-Boot typically has a small amount of memory available. In adding
> support for driver model prior to relocation we must try to use as little
> memory as possible.
> 
> In addition, on some machines the memory has not be inited and/or the CPU
> is not running at full speed or the data cache is off. These can reduce
> execution performance, so the less initialisation that is done before
> relocation the better.
> 
> An immediately-obvious improvement is to only initialise drivers which are
> actually going to be used before relocation. On many boards the only such
> driver is a serial UART, so this provides a very large potential benefit.
> 
> Allow drivers to mark themselves as 'pre-reloc' which means that they will
> be initialised prior to relocation. This can be done either with a driver
> flag or with a 'dm,pre-reloc' device tree property.

I think we should start marking those DT props something like 'u-boot,dm-pre-
reloc' instead . The same way as Linux marks it's own linux-specific DT props.
[...]
Best regards,
Marek Vasut

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 15/29] dm: Move device display into its own function
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 15/29] dm: Move device display into its own function Simon Glass
@ 2014-07-10 23:33   ` Marek Vasut
  2014-07-11  4:27     ` Simon Glass
  0 siblings, 1 reply; 44+ messages in thread
From: Marek Vasut @ 2014-07-10 23:33 UTC (permalink / raw)
  To: u-boot

On Wednesday, July 09, 2014 at 05:38:05 AM, Simon Glass wrote:
> The device display for 'dm tree' and 'dm uclass' is mostly the same, so
> move it into a common function.

Is this going to become a dev_{info/warn/err/crit/...}() kind of output function 
eventually ?

Best regards,
Marek Vasut

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 15/29] dm: Move device display into its own function
  2014-07-10 23:33   ` Marek Vasut
@ 2014-07-11  4:27     ` Simon Glass
  0 siblings, 0 replies; 44+ messages in thread
From: Simon Glass @ 2014-07-11  4:27 UTC (permalink / raw)
  To: u-boot

Hi Marek,

On 10 July 2014 17:33, Marek Vasut <marex@denx.de> wrote:
> On Wednesday, July 09, 2014 at 05:38:05 AM, Simon Glass wrote:
>> The device display for 'dm tree' and 'dm uclass' is mostly the same, so
>> move it into a common function.
>
> Is this going to become a dev_{info/warn/err/crit/...}() kind of output function
> eventually ?

dm_display_line() is just for the 'dm' command - we can certainly add
those functions for devices to use. I haven't really got that far yet.

Regards,
Simon

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 04/29] stdio: Pass device pointer to stdio methods
  2014-07-10 23:26   ` Marek Vasut
@ 2014-07-11  4:29     ` Simon Glass
  0 siblings, 0 replies; 44+ messages in thread
From: Simon Glass @ 2014-07-11  4:29 UTC (permalink / raw)
  To: u-boot

Hi Marek,

On 10 July 2014 17:26, Marek Vasut <marex@denx.de> wrote:
> On Wednesday, July 09, 2014 at 05:37:54 AM, Simon Glass wrote:
>> At present stdio device functions do not get any clue as to which stdio
>> device is being acted on. Some implementations go to great lengths to work
>> around this, such as defining a whole separate set of functions for each
>> possible device.
>>
>> For driver model we need to associate a stdio_dev with a device. It doesn't
>> seem possible to continue with this work-around approach.
>>
>> Instead, add a stdio_dev pointer to each of the stdio member functions.
>>
>> Note: The serial drivers have the same problem, but it is not strictly
>> necessary to fix that to get driver model running. Also, if we convert
>> serial over to driver model the problem will go away.
>>
>> Code size increases by 244 bytes for Thumb2 and 428 for PowerPC.
>>
>> 22: stdio: Pass device pointer to stdio methods
>>        arm: (for 2/2 boards)  all +244.0  bss -4.0  text +248.0
>>    powerpc: (for 1/1 boards)  all +428.0  text +428.0
>>
>> Signed-off-by: Simon Glass <sjg@chromium.org>
>> Acked-by: Marek Vasut <marex@denx.de>
>
> [...]
>
>> diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c
>> index fd61a5e..803d850 100644
>> --- a/drivers/serial/serial.c
>> +++ b/drivers/serial/serial.c
>> @@ -254,6 +254,48 @@ void serial_initialize(void)
>>       serial_assign(default_serial_console()->name);
>>  }
>>
>> +int serial_stub_start(struct stdio_dev *sdev)
>> +{
>> +     struct serial_device *dev = sdev->priv;
>
> Are you sure this pointer derefference won't blow if $sdev is ever NULL? Can
> $sdev be NULL (in some early stage for example) ?

Not that I can think of. It should never be NULL.

>
>> +     return dev->start();
>> +}
>
> Reviewed-by: Marek Vasut <marex@denx.de>
>
> I really like where this is going.
>
> Best regards,
> Marek Vasut

Regards,
Simon

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 03/29] stdio: Remove redundant code around stdio_register() calls
  2014-07-10 23:23   ` Marek Vasut
@ 2014-07-13 16:13     ` Simon Glass
  0 siblings, 0 replies; 44+ messages in thread
From: Simon Glass @ 2014-07-13 16:13 UTC (permalink / raw)
  To: u-boot

Hi Marek,

On 10 July 2014 17:23, Marek Vasut <marex@denx.de> wrote:
>
> On Wednesday, July 09, 2014 at 05:37:53 AM, Simon Glass wrote:
> > There is no point in setting a structure's memory to NULL when it has
> > already been zeroed with memset().
> >
> > Also, there is no need to create a stub function for stdio to call - if the
> > function is NULL it will not be called.
> >
> > This is a clean-up, with no change in functionality.
> >
> > Signed-off-by: Simon Glass <sjg@chromium.org>
> > Acked-by: Marek Vasut <marex@denx.de>
> > ---
>
> Acked-by: Marek Vasut <marex@denx.de>
>
> Some of those implementations really make my head spin ... *sigh* . Thank you
> for cleaning this up a bit !

I think it will be good to get this tidied up. I'm doing things
incrementally as I think that is the best approach given the
complexity and interaction with driver model work, etc.

Regards,
Simon

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 08/29] dm: Allow drivers to be marked 'before relocation'
  2014-07-10 23:29   ` Marek Vasut
@ 2014-07-13 18:38     ` Simon Glass
  0 siblings, 0 replies; 44+ messages in thread
From: Simon Glass @ 2014-07-13 18:38 UTC (permalink / raw)
  To: u-boot

Hi Marek,

On 10 July 2014 17:29, Marek Vasut <marex@denx.de> wrote:
> On Wednesday, July 09, 2014 at 05:37:58 AM, Simon Glass wrote:
>> Driver model currently only operates after relocation is complete. In this
>> state U-Boot typically has a small amount of memory available. In adding
>> support for driver model prior to relocation we must try to use as little
>> memory as possible.
>>
>> In addition, on some machines the memory has not be inited and/or the CPU
>> is not running at full speed or the data cache is off. These can reduce
>> execution performance, so the less initialisation that is done before
>> relocation the better.
>>
>> An immediately-obvious improvement is to only initialise drivers which are
>> actually going to be used before relocation. On many boards the only such
>> driver is a serial UART, so this provides a very large potential benefit.
>>
>> Allow drivers to mark themselves as 'pre-reloc' which means that they will
>> be initialised prior to relocation. This can be done either with a driver
>> flag or with a 'dm,pre-reloc' device tree property.
>
> I think we should start marking those DT props something like 'u-boot,dm-pre-
> reloc' instead . The same way as Linux marks it's own linux-specific DT props.

Yes good idea, I'll fix that.

Regards,
Simon

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 26/29] dm: Add child_pre_probe() and child_post_remove() methods
  2014-07-09  3:38 ` [U-Boot] [PATCH v2 26/29] dm: Add child_pre_probe() and child_post_remove() methods Simon Glass
@ 2014-07-15  8:26   ` Pavel Herrmann
  2014-07-17  5:41     ` Simon Glass
  0 siblings, 1 reply; 44+ messages in thread
From: Pavel Herrmann @ 2014-07-15  8:26 UTC (permalink / raw)
  To: u-boot

Hi

On Tuesday 08 of July 2014 21:38:16 Simon Glass wrote:
> ...
> +
> +Note that the information that controls this behaviour is in the bus's
> +driver, not the child's. In fact it is possible that child has no knowledge
> +that it is connected to a bus. The same child device may even be used on
> two +different bus types. As an example. the 'flash' device shown above may
> also +be connected on a SATA bus or standalone with no bus:
> +
> +   xhci_usb (UCLASS_USB)
> +      flash (UCLASS_FLASH_STORAGE)  - parent data/methods defined by USB
> bus +
> +   sata (UCLASS_SATA)
> +      flash (UCLASS_FLASH_STORAGE)  - parent data/methods defined by SATA
> bus +
> +   flash (UCLASS_FLASH_STORAGE)  - no parent data/methods (not on a bus)

this is not the best example, since the driver actually needs to have an idea 
what parent bus it is connected to, as it should use the parents driver.ops to 
communicate with the device.

the better (more realistic) version would show that the same device would 
operate under various xhci_usb, ohci_usb and ehci_usb busses, which might very 
well have different parent_priv structure (for example, ohci_usb would probably 
not store maximum speed supported by the device, since the bus only has the 
basic one)

as a side note, flash is a bit tricky here, since USB and SATA do not provide 
you with "flash-like" interface even for flash-based devices, but instead have a 
disk-like interface, which is simpler (does not give you the ability to 
control bad block management, among other things).


regards
Pavel Herrmann

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 26/29] dm: Add child_pre_probe() and child_post_remove() methods
  2014-07-15  8:26   ` Pavel Herrmann
@ 2014-07-17  5:41     ` Simon Glass
  2014-07-17  7:09       ` Pavel Herrmann
  0 siblings, 1 reply; 44+ messages in thread
From: Simon Glass @ 2014-07-17  5:41 UTC (permalink / raw)
  To: u-boot

Hi Pavel,

On 15 July 2014 02:26, Pavel Herrmann <morpheus.ibis@gmail.com> wrote:
> Hi
>
> On Tuesday 08 of July 2014 21:38:16 Simon Glass wrote:
>> ...
>> +
>> +Note that the information that controls this behaviour is in the bus's
>> +driver, not the child's. In fact it is possible that child has no knowledge
>> +that it is connected to a bus. The same child device may even be used on
>> two +different bus types. As an example. the 'flash' device shown above may
>> also +be connected on a SATA bus or standalone with no bus:
>> +
>> +   xhci_usb (UCLASS_USB)
>> +      flash (UCLASS_FLASH_STORAGE)  - parent data/methods defined by USB
>> bus +
>> +   sata (UCLASS_SATA)
>> +      flash (UCLASS_FLASH_STORAGE)  - parent data/methods defined by SATA
>> bus +
>> +   flash (UCLASS_FLASH_STORAGE)  - no parent data/methods (not on a bus)
>
> this is not the best example, since the driver actually needs to have an idea
> what parent bus it is connected to, as it should use the parents driver.ops to
> communicate with the device.

Yes, it's not a good example.

>
> the better (more realistic) version would show that the same device would
> operate under various xhci_usb, ohci_usb and ehci_usb busses, which might very
> well have different parent_priv structure (for example, ohci_usb would probably
> not store maximum speed supported by the device, since the bus only has the
> basic one)

They still use the parent driver ops, but now they are all the same?
Do you mean that the uclass would be the same for each bus?

>
> as a side note, flash is a bit tricky here, since USB and SATA do not provide
> you with "flash-like" interface even for flash-based devices, but instead have a
> disk-like interface, which is simpler (does not give you the ability to
> control bad block management, among other things).

Another reason why the example is poor - I was more thinking of flash
as a disk than a raw NAND device.

Regards,
Simon

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 26/29] dm: Add child_pre_probe() and child_post_remove() methods
  2014-07-17  5:41     ` Simon Glass
@ 2014-07-17  7:09       ` Pavel Herrmann
  2014-07-17 15:20         ` Simon Glass
  0 siblings, 1 reply; 44+ messages in thread
From: Pavel Herrmann @ 2014-07-17  7:09 UTC (permalink / raw)
  To: u-boot

On Wednesday 16 of July 2014 23:41:57 Simon Glass wrote:
> Hi Pavel,
> 
> On 15 July 2014 02:26, Pavel Herrmann <morpheus.ibis@gmail.com> wrote:
> > Hi
> > 
> > On Tuesday 08 of July 2014 21:38:16 Simon Glass wrote:
> >> ...
> >> +
> >> +Note that the information that controls this behaviour is in the bus's
> >> +driver, not the child's. In fact it is possible that child has no
> >> knowledge +that it is connected to a bus. The same child device may even
> >> be used on two +different bus types. As an example. the 'flash' device
> >> shown above may also +be connected on a SATA bus or standalone with no
> >> bus:
> >> +
> >> +   xhci_usb (UCLASS_USB)
> >> +      flash (UCLASS_FLASH_STORAGE)  - parent data/methods defined by USB
> >> bus +
> >> +   sata (UCLASS_SATA)
> >> +      flash (UCLASS_FLASH_STORAGE)  - parent data/methods defined by
> >> SATA
> >> bus +
> >> +   flash (UCLASS_FLASH_STORAGE)  - no parent data/methods (not on a bus)
> > 
> > this is not the best example, since the driver actually needs to have an
> > idea what parent bus it is connected to, as it should use the parents
> > driver.ops to communicate with the device.
> 
> Yes, it's not a good example.
> 
> > the better (more realistic) version would show that the same device would
> > operate under various xhci_usb, ohci_usb and ehci_usb busses, which might
> > very well have different parent_priv structure (for example, ohci_usb
> > would probably not store maximum speed supported by the device, since the
> > bus only has the basic one)
> 
> They still use the parent driver ops, but now they are all the same?
> Do you mean that the uclass would be the same for each bus?

Yes, I imagine the uclass for USB host controller would the same, not 
depending on the speed of the controller.

> > as a side note, flash is a bit tricky here, since USB and SATA do not
> > provide you with "flash-like" interface even for flash-based devices, but
> > instead have a disk-like interface, which is simpler (does not give you
> > the ability to control bad block management, among other things).
> 
> Another reason why the example is poor - I was more thinking of flash
> as a disk than a raw NAND device.
> 
> Regards,
> Simon

regards
Pavel Herrmann

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 26/29] dm: Add child_pre_probe() and child_post_remove() methods
  2014-07-17  7:09       ` Pavel Herrmann
@ 2014-07-17 15:20         ` Simon Glass
  0 siblings, 0 replies; 44+ messages in thread
From: Simon Glass @ 2014-07-17 15:20 UTC (permalink / raw)
  To: u-boot

Hi Pavel,

On 17 July 2014 01:09, Pavel Herrmann <morpheus.ibis@gmail.com> wrote:
>
> On Wednesday 16 of July 2014 23:41:57 Simon Glass wrote:
> > Hi Pavel,
> >
> > On 15 July 2014 02:26, Pavel Herrmann <morpheus.ibis@gmail.com> wrote:
> > > Hi
> > >
> > > On Tuesday 08 of July 2014 21:38:16 Simon Glass wrote:
> > >> ...
> > >> +
> > >> +Note that the information that controls this behaviour is in the bus's
> > >> +driver, not the child's. In fact it is possible that child has no
> > >> knowledge +that it is connected to a bus. The same child device may even
> > >> be used on two +different bus types. As an example. the 'flash' device
> > >> shown above may also +be connected on a SATA bus or standalone with no
> > >> bus:
> > >> +
> > >> +   xhci_usb (UCLASS_USB)
> > >> +      flash (UCLASS_FLASH_STORAGE)  - parent data/methods defined by USB
> > >> bus +
> > >> +   sata (UCLASS_SATA)
> > >> +      flash (UCLASS_FLASH_STORAGE)  - parent data/methods defined by
> > >> SATA
> > >> bus +
> > >> +   flash (UCLASS_FLASH_STORAGE)  - no parent data/methods (not on a bus)
> > >
> > > this is not the best example, since the driver actually needs to have an
> > > idea what parent bus it is connected to, as it should use the parents
> > > driver.ops to communicate with the device.
> >
> > Yes, it's not a good example.
> >
> > > the better (more realistic) version would show that the same device would
> > > operate under various xhci_usb, ohci_usb and ehci_usb busses, which might
> > > very well have different parent_priv structure (for example, ohci_usb
> > > would probably not store maximum speed supported by the device, since the
> > > bus only has the basic one)
> >
> > They still use the parent driver ops, but now they are all the same?
> > Do you mean that the uclass would be the same for each bus?
>
> Yes, I imagine the uclass for USB host controller would the same, not
> depending on the speed of the controller.

OK, but there is no requirement for the child data to be the same for
each USB device. Each device has its own child data structure - this
is not defined by the uclass but by the udevice.

Regards,
Simon

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH v2 17/29] dm: Introduce device sequence numbering
  2014-07-09 13:53   ` Jon Loeliger
@ 2014-07-19  3:22     ` Simon Glass
  0 siblings, 0 replies; 44+ messages in thread
From: Simon Glass @ 2014-07-19  3:22 UTC (permalink / raw)
  To: u-boot

Hi Jon,

On 9 July 2014 07:53, Jon Loeliger <loeliger@gmail.com> wrote:
> HI Simon,
>
> On Tue, Jul 8, 2014 at 10:38 PM, Simon Glass <sjg@chromium.org> wrote:
>> In U-Boot it is pretty common to number devices from 0 and access them
>> on the command line using this numbering. While it may come to pass that
>> we will move away from this numbering, the possibility seems remote at
>> present.
>>
>> Given that devices within a uclass will have an implied numbering, it
>> makes sense to build this into driver model as a core feature. The cost
>> is fairly small in terms of code and data space.
>
> Hmmm.  I'm not entirely in agreement here.  I think this is the wrong
> long-term approach, and this just reinforces the status quo rather than
> allowing a migration to a better approach.

If we don't add numbering to driver model, then it will be done badly
(and ad-hoc) in support code. I can't even quite imagine how we might
do it. Also while U-Boot's numbering may not be the right long-term
approach, that would involve a large discussion and long change-over
to an as-yet unknown method. So I think we need to have realistic
expectations of driver mode's place in the world. It can enable new
methods, but not mandate them.

>
>> With each uclass having numbered devices we can ask for SPI port 0 or
>> serial port 1 and receive a single device.
>
> That's nice, but we should allow them to be named by their actual
> names as found in the device tree too.

There's nothing in this patch that precludes that. It would require
changes to U-Boot's command processing, probably best done as a
separate series sometime in the future.

>
>> Devices typically request a sequence number using aliases in the device
>> tree. These are resolved when the device is probed, to deal with conflicts.
>> Sequence numbers need not be sequential and holes are permitted.
>
> So they are unreliably unpredictable, unless you also happen
> to have the DTS decoder ring in hand too?

If you compare with how things are now, we only support a single
driver for each class. For example, if you are using SPI, you can only
have one SPI driver - perhaps with multiple ports. If you are not
using DT, then the U_BOOT_DEVICE() macros will all appear in that
driver or the board file (TBD at this stage), and will be parsed in
order. I believe we can honour the numbering in that case, albeit I
don't want to implement something before it is needed.

>
>
>> +This indicates that in the uclass called "serial", the named node
>> +("/serial at 22230000") will be given sequence number 2. Any command or driver
>> +which requests serial device 2 will obtain this device.
>> +
>> +Some devices represent buses where the devices on the bus are numbered or
>> +addressed. For example, SPI typically numbers its slaves from 0, and I2C
>> +uses a 7-bit address. In these cases the 'reg' property of the subnode is
>> +used, for example:
>> +
>> +{
>> +       aliases {
>> +               spi2 = "/spi at 22300000";
>> +       };
>> +
>> +       spi at 22300000 {
>> +               #address-cells = <1>;
>> +               #size-cells = <1>;
>> +               spi-flash at 0 {
>> +                       reg = <0>;
>> +                       ...
>> +               }
>> +               eeprom at 1 {
>> +                       reg = <1>;
>> +               };
>> +       };
>
> And not everyone agrees that this is the best approach, even in Linux land.
> Specifically, we should be in agreement with Linux, and we should not
> have our DTS stray from the definitions that Linux will accept for the same
> devices.  And this approach won't be bought by the Linux crowd.  (Yes,
> there are some that use  a "reg = <0>;" approach here, but there are many
> that do not too.  It's not a universally accepted approach.)
>
> This concept is crucial.
>
> I've said it before, and I will say it again if needed.
>
> So:  Sure, put this approach in, but make it be the backward compatible
> approach.  Also please put in a correct naming approach so that we can
> move forward with a better longer term solution too.

I think you are saying that something like:

sf probe spi1:flash

should be possible instead of

sf probe 1:0

It feels right to me too, but it doesn't belong in this patch, needs
further discussion and the command parsing aspect needs more general
thought. It would be great to figure this out and get it agreed, and
driver model can certainly support it.

Regards,
Simon

^ permalink raw reply	[flat|nested] 44+ messages in thread

end of thread, other threads:[~2014-07-19  3:22 UTC | newest]

Thread overview: 44+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-07-09  3:37 [U-Boot] [PATCH v2 0/29] Add additional core driver model features Simon Glass
2014-07-09  3:37 ` [U-Boot] [PATCH v2 01/29] dm: gpio: Don't use the driver model uclass for SPL Simon Glass
2014-07-09  3:37 ` [U-Boot] [PATCH v2 02/29] dm: Use an explicit expect value in core tests Simon Glass
2014-07-09  3:37 ` [U-Boot] [PATCH v2 03/29] stdio: Remove redundant code around stdio_register() calls Simon Glass
2014-07-10 23:23   ` Marek Vasut
2014-07-13 16:13     ` Simon Glass
2014-07-09  3:37 ` [U-Boot] [PATCH v2 04/29] stdio: Pass device pointer to stdio methods Simon Glass
2014-07-10 23:26   ` Marek Vasut
2014-07-11  4:29     ` Simon Glass
2014-07-09  3:37 ` [U-Boot] [PATCH v2 05/29] dm: Make sure that the root device is probed Simon Glass
2014-07-09  3:37 ` [U-Boot] [PATCH v2 06/29] dm: Provide a way to shut down driver model Simon Glass
2014-07-09  3:37 ` [U-Boot] [PATCH v2 07/29] sandbox: Remove all drivers before exit Simon Glass
2014-07-09  3:37 ` [U-Boot] [PATCH v2 08/29] dm: Allow drivers to be marked 'before relocation' Simon Glass
2014-07-10 23:29   ` Marek Vasut
2014-07-13 18:38     ` Simon Glass
2014-07-09  3:37 ` [U-Boot] [PATCH v2 09/29] dm: Support driver model prior to relocation Simon Glass
2014-07-09  3:38 ` [U-Boot] [PATCH v2 10/29] stdio: Provide functions to add/remove devices using stdio_dev Simon Glass
2014-07-09  3:38 ` [U-Boot] [PATCH v2 11/29] console: Remove vprintf() optimisation for sandbox Simon Glass
2014-07-09  3:38 ` [U-Boot] [PATCH v2 12/29] Add a flag indicating when the serial console is ready Simon Glass
2014-07-09  3:38 ` [U-Boot] [PATCH v2 13/29] dm: Move uclass error checking/probing into a function Simon Glass
2014-07-09  3:38 ` [U-Boot] [PATCH v2 14/29] fdt: Add a function to get the alias sequence of a node Simon Glass
2014-07-09  3:38 ` [U-Boot] [PATCH v2 15/29] dm: Move device display into its own function Simon Glass
2014-07-10 23:33   ` Marek Vasut
2014-07-11  4:27     ` Simon Glass
2014-07-09  3:38 ` [U-Boot] [PATCH v2 16/29] dm: Avoid activating devices in 'dm uclass' command Simon Glass
2014-07-09  3:38 ` [U-Boot] [PATCH v2 17/29] dm: Introduce device sequence numbering Simon Glass
2014-07-09 13:53   ` Jon Loeliger
2014-07-19  3:22     ` Simon Glass
2014-07-09  3:38 ` [U-Boot] [PATCH v2 18/29] dm: Display the sequence number for each device Simon Glass
2014-07-09  3:38 ` [U-Boot] [PATCH v2 19/29] dm: Allow a device to be found by its FDT offset Simon Glass
2014-07-09  3:38 ` [U-Boot] [PATCH v2 20/29] dm: Avoid accessing uclasses before they are ready Simon Glass
2014-07-09  3:38 ` [U-Boot] [PATCH v2 21/29] fdt: Add a function to get the node offset of an alias Simon Glass
2014-07-09  3:38 ` [U-Boot] [PATCH v2 22/29] dm: Tidy up some header file comments Simon Glass
2014-07-09  3:38 ` [U-Boot] [PATCH v2 23/29] dm: Provide a function to scan child FDT nodes Simon Glass
2014-07-09  3:38 ` [U-Boot] [PATCH v2 24/29] dm: Add functions to access a device's children Simon Glass
2014-07-09  3:38 ` [U-Boot] [PATCH v2 25/29] dm: Introduce per-child data for devices Simon Glass
2014-07-09  3:38 ` [U-Boot] [PATCH v2 26/29] dm: Add child_pre_probe() and child_post_remove() methods Simon Glass
2014-07-15  8:26   ` Pavel Herrmann
2014-07-17  5:41     ` Simon Glass
2014-07-17  7:09       ` Pavel Herrmann
2014-07-17 15:20         ` Simon Glass
2014-07-09  3:38 ` [U-Boot] [PATCH v2 27/29] dm: Improve errors and warnings in lists_bind_fdt() Simon Glass
2014-07-09  3:38 ` [U-Boot] [PATCH v2 28/29] dm: Add dm_scan_other() to locate board-specific devices Simon Glass
2014-07-09  3:38 ` [U-Boot] [PATCH v2 29/29] dm: Give the demo uclass a name Simon Glass

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.