[U-Boot] [PATCH 00/20] arm: rpi: Enable USB and Ethernet driver model Raspberry Pi

Raspberry Pi uses a DWC2 USB controller and a SMSC USB Ethernet adaptor. Neither of these currently support driver model.
This series does the following: - Move Raspberry Pi to use device tree control (u-boot-dtb.bin instead of u-boot.bin) - Remove GPIO platform data (now uses device tree) - Remove serial platform data (now uses device tree) - Add 'ranges' support to simple-bus - Convert the DWC2 USB driver to support driver model - Convert the SMSC95XX USB Ethernet driver to support driver model - Enable CONFIG_DM_ETH and CONFIG_DM_USB on Raspberry Pi
With Ethernet active the device list looks something like this:
U-Boot> dm tree Class Probed Name ---------------------------------------- root [ + ] root_driver simple_bus [ + ] |-- soc gpio [ ] | |-- gpio@7e200000 serial [ + ] | |-- uart@7e201000 usb [ + ] | `-- usb@7e980000 usb_hub [ + ] | `-- usb_hub usb_hub [ + ] | `-- usb_hub eth [ + ] | `-- smsc95xx_eth simple_bus [ ] `-- clocks
Raspberry Pi 2 is not converted as I do not have one to test at present.
Simon Glass (20): dm: net: Support usbethaddr environment variable dm: usb: Allow USB Ethernet whenever CONFIG_DM_ETH is not defined dm: usb: Add an errno.h header to usb_ether.c dm: usb: Prepare dwc2 driver for driver-model conversion dm: usb: Add driver-model support to dwc2 net: smsc95xx: Sort the include files net: smsc95xx: Rename AX_RX_URB_SIZE to RX_URB_SIZE net: smsc95xx: Correct the error numbers net: smsc95xx: Prepare for conversion to driver model net: smsc95xx: Add driver-model support dm: serial: Update binding for PL01x serial UART dm: Support address translation for simple-bus arm: rpi: Define CONFIG_TFTP_TSIZE to show tftp size info arm: rpi: Bring in kernel device tree files arm: rpi: Device tree modifications for U-Boot arm: rpi: Enable device tree control for Rasberry Pi arm: rpi: Drop the UART console platform data arm: rpi: Drop the GPIO platform data arm: rpi: Move to driver model for USB arm: rpi: Use driver model for Ethernet
arch/arm/dts/Makefile | 2 + arch/arm/dts/bcm2835-rpi-b.dts | 23 ++ arch/arm/dts/bcm2835-rpi.dtsi | 51 ++++ arch/arm/dts/bcm2835.dtsi | 194 ++++++++++++ arch/arm/dts/stv0991.dts | 2 +- arch/arm/mach-bcm283x/include/mach/gpio.h | 2 - board/raspberrypi/rpi/rpi.c | 24 -- common/cmd_usb.c | 7 +- configs/rpi_defconfig | 5 + doc/device-tree-bindings/serial/pl011.txt | 53 ++++ doc/device-tree-bindings/serial/pl01x.txt | 7 - drivers/core/device.c | 17 +- drivers/core/simple-bus.c | 30 ++ drivers/gpio/bcm2835_gpio.c | 20 ++ drivers/serial/serial_pl01x.c | 6 +- drivers/usb/eth/smsc95xx.c | 469 ++++++++++++++++++++---------- drivers/usb/eth/usb_ether.c | 1 + drivers/usb/host/dwc2.c | 247 ++++++++++++---- include/configs/rpi-common.h | 3 +- include/dm/device-internal.h | 12 + include/dt-bindings/pinctrl/bcm2835.h | 27 ++ net/eth.c | 7 +- 22 files changed, 966 insertions(+), 243 deletions(-) create mode 100644 arch/arm/dts/bcm2835-rpi-b.dts create mode 100644 arch/arm/dts/bcm2835-rpi.dtsi create mode 100644 arch/arm/dts/bcm2835.dtsi create mode 100644 doc/device-tree-bindings/serial/pl011.txt delete mode 100644 doc/device-tree-bindings/serial/pl01x.txt create mode 100644 include/dt-bindings/pinctrl/bcm2835.h

For USB Ethernet devices we need to use the usbethaddr environment variable (instead of ethaddr) the Ethernet hardware address. Add this to the uclass so that it happens automatically.
Signed-off-by: Simon Glass sjg@chromium.org ---
net/eth.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/net/eth.c b/net/eth.c index d3ec8d6..1f5e8ee 100644 --- a/net/eth.c +++ b/net/eth.c @@ -519,6 +519,7 @@ static int eth_post_probe(struct udevice *dev) struct eth_device_priv *priv = dev->uclass_priv; struct eth_pdata *pdata = dev->platdata; unsigned char env_enetaddr[6]; + const char *prefix;
priv->state = ETH_STATE_INIT;
@@ -526,7 +527,11 @@ static int eth_post_probe(struct udevice *dev) if (eth_get_ops(dev)->read_rom_hwaddr) eth_get_ops(dev)->read_rom_hwaddr(dev);
- eth_getenv_enetaddr_by_index("eth", dev->seq, env_enetaddr); + prefix = device_get_uclass_id(dev->parent) == UCLASS_USB_HUB ? + "usbeth" : "eth"; + debug("prefix=%s, uclass=%d\n", prefix, + device_get_uclass_id(dev->parent)); + eth_getenv_enetaddr_by_index(prefix, dev->seq, env_enetaddr); if (!is_zero_ethaddr(env_enetaddr)) { if (!is_zero_ethaddr(pdata->enetaddr) && memcmp(pdata->enetaddr, env_enetaddr, 6)) {

Hi Simon,
On Tue, Jul 7, 2015 at 9:53 PM, Simon Glass sjg@chromium.org wrote:
For USB Ethernet devices we need to use the usbethaddr environment variable (instead of ethaddr) the Ethernet hardware address. Add this to the uclass so that it happens automatically.
I have always thought that this approach of having a separate prefix for usbethaddr was a smelly hack. Are we sure we want to propagate it here? Can we not just use dev->seq? It should already be unique in the DM, right? I was really looking forward to that all going away.
Signed-off-by: Simon Glass sjg@chromium.org

+Hans
Hi Joe,
On 7 July 2015 at 22:04, Joe Hershberger joe.hershberger@gmail.com wrote:
Hi Simon,
On Tue, Jul 7, 2015 at 9:53 PM, Simon Glass sjg@chromium.org wrote:
For USB Ethernet devices we need to use the usbethaddr environment variable (instead of ethaddr) the Ethernet hardware address. Add this to the uclass so that it happens automatically.
I have always thought that this approach of having a separate prefix for usbethaddr was a smelly hack. Are we sure we want to propagate it here? Can we not just use dev->seq? It should already be unique in the DM, right? I was really looking forward to that all going away.
Ah, OK, sorry. Do you think we need a way of specifying the eth interface # as we do with aliases at present? We did have one but Han has just removed it :-)
Otherwise we'll just end up counting up from the last 'fixed' ethernet interface. Maybe that is good enough.
Regards, Simon

Hi Simon,
On Wed, Jul 8, 2015 at 3:31 PM, Simon Glass sjg@chromium.org wrote:
+Hans
Hi Joe,
On 7 July 2015 at 22:04, Joe Hershberger joe.hershberger@gmail.com wrote:
Hi Simon,
On Tue, Jul 7, 2015 at 9:53 PM, Simon Glass sjg@chromium.org wrote:
For USB Ethernet devices we need to use the usbethaddr environment variable (instead of ethaddr) the Ethernet hardware address. Add this to the uclass so that it happens automatically.
I have always thought that this approach of having a separate prefix for usbethaddr was a smelly hack. Are we sure we want to propagate it here? Can we not just use dev->seq? It should already be unique in the DM, right? I was really looking forward to that all going away.
Ah, OK, sorry. Do you think we need a way of specifying the eth interface # as we do with aliases at present? We did have one but Han has just removed it :-)
Can you reference where this happened. A quick search didn't turn it up for me.
Otherwise we'll just end up counting up from the last 'fixed' ethernet interface. Maybe that is good enough.
That's probably good enough, but some may prefer more explicit control.
Thanks, -Joe

Hi Joe,
On 8 July 2015 at 14:43, Joe Hershberger joe.hershberger@gmail.com wrote:
Hi Simon,
On Wed, Jul 8, 2015 at 3:31 PM, Simon Glass sjg@chromium.org wrote:
+Hans
Hi Joe,
On 7 July 2015 at 22:04, Joe Hershberger joe.hershberger@gmail.com wrote:
Hi Simon,
On Tue, Jul 7, 2015 at 9:53 PM, Simon Glass sjg@chromium.org wrote:
For USB Ethernet devices we need to use the usbethaddr environment variable (instead of ethaddr) the Ethernet hardware address. Add this to the uclass so that it happens automatically.
I have always thought that this approach of having a separate prefix for usbethaddr was a smelly hack. Are we sure we want to propagate it here? Can we not just use dev->seq? It should already be unique in the DM, right? I was really looking forward to that all going away.
Ah, OK, sorry. Do you think we need a way of specifying the eth interface # as we do with aliases at present? We did have one but Han has just removed it :-)
Can you reference where this happened. A quick search didn't turn it up for me.
Otherwise we'll just end up counting up from the last 'fixed' ethernet interface. Maybe that is good enough.
That's probably good enough, but some may prefer more explicit control.
The thread is here:
http://patchwork.ozlabs.org/patch/485637/
Before, we could I think add USB devices to the device tree and give them a specific number (although I never actually tested it), but that won't work now.
Regards, Simon

Hi Joe,
On 8 July 2015 at 15:07, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 8 July 2015 at 14:43, Joe Hershberger joe.hershberger@gmail.com wrote:
Hi Simon,
On Wed, Jul 8, 2015 at 3:31 PM, Simon Glass sjg@chromium.org wrote:
+Hans
Hi Joe,
On 7 July 2015 at 22:04, Joe Hershberger joe.hershberger@gmail.com wrote:
Hi Simon,
On Tue, Jul 7, 2015 at 9:53 PM, Simon Glass sjg@chromium.org wrote:
For USB Ethernet devices we need to use the usbethaddr environment variable (instead of ethaddr) the Ethernet hardware address. Add this to the uclass so that it happens automatically.
I have always thought that this approach of having a separate prefix for usbethaddr was a smelly hack. Are we sure we want to propagate it here? Can we not just use dev->seq? It should already be unique in the DM, right? I was really looking forward to that all going away.
Ah, OK, sorry. Do you think we need a way of specifying the eth interface # as we do with aliases at present? We did have one but Han has just removed it :-)
Can you reference where this happened. A quick search didn't turn it up for me.
Otherwise we'll just end up counting up from the last 'fixed' ethernet interface. Maybe that is good enough.
That's probably good enough, but some may prefer more explicit control.
The thread is here:
http://patchwork.ozlabs.org/patch/485637/
Before, we could I think add USB devices to the device tree and give them a specific number (although I never actually tested it), but that won't work now.
What are you thoughts on this? I'd like to bring this series in soon (the parts without rpi anyway).
Regards, Simon

Hi Simon,
On Mon, Jul 20, 2015 at 8:56 AM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 8 July 2015 at 15:07, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 8 July 2015 at 14:43, Joe Hershberger joe.hershberger@gmail.com wrote:
Hi Simon,
On Wed, Jul 8, 2015 at 3:31 PM, Simon Glass sjg@chromium.org wrote:
+Hans
Hi Joe,
On 7 July 2015 at 22:04, Joe Hershberger joe.hershberger@gmail.com wrote:
Hi Simon,
On Tue, Jul 7, 2015 at 9:53 PM, Simon Glass sjg@chromium.org wrote:
For USB Ethernet devices we need to use the usbethaddr environment variable (instead of ethaddr) the Ethernet hardware address. Add this to the uclass so that it happens automatically.
I have always thought that this approach of having a separate prefix for usbethaddr was a smelly hack. Are we sure we want to propagate it here? Can we not just use dev->seq? It should already be unique in the DM, right? I was really looking forward to that all going away.
Ah, OK, sorry. Do you think we need a way of specifying the eth interface # as we do with aliases at present? We did have one but Han has just removed it :-)
Can you reference where this happened. A quick search didn't turn it up for me.
Otherwise we'll just end up counting up from the last 'fixed' ethernet interface. Maybe that is good enough.
That's probably good enough, but some may prefer more explicit control.
The thread is here:
http://patchwork.ozlabs.org/patch/485637/
Before, we could I think add USB devices to the device tree and give them a specific number (although I never actually tested it), but that won't work now.
What are you thoughts on this? I'd like to bring this series in soon (the parts without rpi anyway).
I don't mind just having "one past wired Eth" as the starting point. If someone cares about specifying it in the device tree that can be added later without redoing what you are adding here, right?
Thanks, -Joe

Hi Joe,
On 20 July 2015 at 12:10, Joe Hershberger joe.hershberger@gmail.com wrote:
Hi Simon,
On Mon, Jul 20, 2015 at 8:56 AM, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 8 July 2015 at 15:07, Simon Glass sjg@chromium.org wrote:
Hi Joe,
On 8 July 2015 at 14:43, Joe Hershberger joe.hershberger@gmail.com wrote:
Hi Simon,
On Wed, Jul 8, 2015 at 3:31 PM, Simon Glass sjg@chromium.org wrote:
+Hans
Hi Joe,
On 7 July 2015 at 22:04, Joe Hershberger joe.hershberger@gmail.com wrote:
Hi Simon,
On Tue, Jul 7, 2015 at 9:53 PM, Simon Glass sjg@chromium.org wrote: > For USB Ethernet devices we need to use the usbethaddr environment variable > (instead of ethaddr) the Ethernet hardware address. Add this to the uclass > so that it happens automatically.
I have always thought that this approach of having a separate prefix for usbethaddr was a smelly hack. Are we sure we want to propagate it here? Can we not just use dev->seq? It should already be unique in the DM, right? I was really looking forward to that all going away.
Ah, OK, sorry. Do you think we need a way of specifying the eth interface # as we do with aliases at present? We did have one but Han has just removed it :-)
Can you reference where this happened. A quick search didn't turn it up for me.
Otherwise we'll just end up counting up from the last 'fixed' ethernet interface. Maybe that is good enough.
That's probably good enough, but some may prefer more explicit control.
The thread is here:
http://patchwork.ozlabs.org/patch/485637/
Before, we could I think add USB devices to the device tree and give them a specific number (although I never actually tested it), but that won't work now.
What are you thoughts on this? I'd like to bring this series in soon (the parts without rpi anyway).
I don't mind just having "one past wired Eth" as the starting point. If someone cares about specifying it in the device tree that can be added later without redoing what you are adding here, right?
OK I'll go with that,
Regards, Simon

We can support USB Ethernet regardless of the setting of CONFIG_DM_USB. Update the code to reflect this.
Signed-off-by: Simon Glass sjg@chromium.org ---
common/cmd_usb.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/common/cmd_usb.c b/common/cmd_usb.c index b385743..bc45c48 100644 --- a/common/cmd_usb.c +++ b/common/cmd_usb.c @@ -525,7 +525,12 @@ static void do_usb_start(void) return;
/* Driver model will probe the devices as they are found */ -#ifndef CONFIG_DM_USB +#ifdef CONFIG_DM_USB +# ifndef CONFIG_DM_ETH + /* try to recognize ethernet devices immediately */ + usb_ether_curr_dev = usb_host_eth_scan(1); +# endif +#else /* !CONFIG_DM_USB */ # ifdef CONFIG_USB_STORAGE /* try to recognize storage devices immediately */ usb_stor_curr_dev = usb_stor_scan(1);

This is required on some platforms, so add it.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/usb/eth/usb_ether.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/usb/eth/usb_ether.c b/drivers/usb/eth/usb_ether.c index 137eac7..110808d 100644 --- a/drivers/usb/eth/usb_ether.c +++ b/drivers/usb/eth/usb_ether.c @@ -6,6 +6,7 @@
#include <common.h> #include <dm.h> +#include <errno.h> #include <malloc.h> #include <usb.h> #include <dm/device-internal.h>

On 7 July 2015 at 20:53, Simon Glass sjg@chromium.org wrote:
This is required on some platforms, so add it.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/usb/eth/usb_ether.c | 1 + 1 file changed, 1 insertion(+)
Applied to u-boot-dm.

Put all global data in a structure and move (what will be) common code into common functions. This will make the driver-model conversion much easier.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/usb/host/dwc2.c | 150 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 100 insertions(+), 50 deletions(-)
diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c index eee60a2..366e025 100644 --- a/drivers/usb/host/dwc2.c +++ b/drivers/usb/host/dwc2.c @@ -21,18 +21,22 @@ #define DWC2_STATUS_BUF_SIZE 64 #define DWC2_DATA_BUF_SIZE (64 * 1024)
-/* We need doubleword-aligned buffers for DMA transfers */ -DEFINE_ALIGN_BUFFER(uint8_t, aligned_buffer, DWC2_DATA_BUF_SIZE, 8); -DEFINE_ALIGN_BUFFER(uint8_t, status_buffer, DWC2_STATUS_BUF_SIZE, 8); - #define MAX_DEVICE 16 #define MAX_ENDPOINT 16 -static int bulk_data_toggle[MAX_DEVICE][MAX_ENDPOINT];
-static int root_hub_devnum; +struct dwc2_priv { + uint8_t *aligned_buffer; + uint8_t *status_buffer; + int bulk_data_toggle[MAX_DEVICE][MAX_ENDPOINT]; + struct dwc2_core_regs *regs; + int root_hub_devnum; +}; + +/* We need doubleword-aligned buffers for DMA transfers */ +DEFINE_ALIGN_BUFFER(uint8_t, aligned_buffer_addr, DWC2_DATA_BUF_SIZE, 8); +DEFINE_ALIGN_BUFFER(uint8_t, status_buffer_addr, DWC2_STATUS_BUF_SIZE, 8);
-static struct dwc2_core_regs *regs = - (struct dwc2_core_regs *)CONFIG_USB_DWC2_REG_ADDR; +static struct dwc2_priv local;
/* * DWC2 IP interface @@ -428,7 +432,8 @@ static void dwc_otg_hc_init(struct dwc2_core_regs *regs, uint8_t hc_num, * DWC2 to USB API interface */ /* Direction: In ; Request: Status */ -static int dwc_otg_submit_rh_msg_in_status(struct usb_device *dev, void *buffer, +static int dwc_otg_submit_rh_msg_in_status(struct dwc2_core_regs *regs, + struct usb_device *dev, void *buffer, int txlen, struct devrequest *cmd) { uint32_t hprt0 = 0; @@ -602,13 +607,13 @@ static int dwc_otg_submit_rh_msg_in_configuration(struct usb_device *dev, }
/* Direction: In */ -static int dwc_otg_submit_rh_msg_in(struct usb_device *dev, - void *buffer, int txlen, - struct devrequest *cmd) +static int dwc_otg_submit_rh_msg_in(struct dwc2_priv *priv, + struct usb_device *dev, void *buffer, + int txlen, struct devrequest *cmd) { switch (cmd->request) { case USB_REQ_GET_STATUS: - return dwc_otg_submit_rh_msg_in_status(dev, buffer, + return dwc_otg_submit_rh_msg_in_status(priv->regs, dev, buffer, txlen, cmd); case USB_REQ_GET_DESCRIPTOR: return dwc_otg_submit_rh_msg_in_descriptor(dev, buffer, @@ -623,10 +628,12 @@ static int dwc_otg_submit_rh_msg_in(struct usb_device *dev, }
/* Direction: Out */ -static int dwc_otg_submit_rh_msg_out(struct usb_device *dev, - void *buffer, int txlen, - struct devrequest *cmd) +static int dwc_otg_submit_rh_msg_out(struct dwc2_priv *priv, + struct usb_device *dev, + void *buffer, int txlen, + struct devrequest *cmd) { + struct dwc2_core_regs *regs = priv->regs; int len = 0; int stat = 0; uint16_t bmrtype_breq = cmd->requesttype | (cmd->request << 8); @@ -673,7 +680,7 @@ static int dwc_otg_submit_rh_msg_out(struct usb_device *dev, } break; case (USB_REQ_SET_ADDRESS << 8): - root_hub_devnum = wValue; + priv->root_hub_devnum = wValue; break; case (USB_REQ_SET_CONFIGURATION << 8): break; @@ -690,8 +697,8 @@ static int dwc_otg_submit_rh_msg_out(struct usb_device *dev, return stat; }
-static int dwc_otg_submit_rh_msg(struct usb_device *dev, unsigned long pipe, - void *buffer, int txlen, +static int dwc_otg_submit_rh_msg(struct dwc2_priv *priv, struct usb_device *dev, + unsigned long pipe, void *buffer, int txlen, struct devrequest *cmd) { int stat = 0; @@ -702,16 +709,17 @@ static int dwc_otg_submit_rh_msg(struct usb_device *dev, unsigned long pipe, }
if (cmd->requesttype & USB_DIR_IN) - stat = dwc_otg_submit_rh_msg_in(dev, buffer, txlen, cmd); + stat = dwc_otg_submit_rh_msg_in(priv, dev, buffer, txlen, cmd); else - stat = dwc_otg_submit_rh_msg_out(dev, buffer, txlen, cmd); + stat = dwc_otg_submit_rh_msg_out(priv, dev, buffer, txlen, cmd);
mdelay(1);
return stat; }
-int wait_for_chhltd(uint32_t *sub, int *toggle, bool ignore_ack) +int wait_for_chhltd(struct dwc2_core_regs *regs, uint32_t *sub, int *toggle, + bool ignore_ack) { uint32_t hcint_comp_hlt_ack = DWC2_HCINT_XFERCOMP | DWC2_HCINT_CHHLTD; struct dwc2_hc_regs *hc_regs = ®s->hc_regs[DWC2_HC_CHANNEL]; @@ -751,9 +759,11 @@ static int dwc2_eptype[] = { DWC2_HCCHAR_EPTYPE_BULK, };
-int chunk_msg(struct usb_device *dev, unsigned long pipe, int *pid, int in, - void *buffer, int len, bool ignore_ack) +int chunk_msg(struct dwc2_priv *priv, struct usb_device *dev, + unsigned long pipe, int *pid, int in, void *buffer, int len, + bool ignore_ack) { + struct dwc2_core_regs *regs = priv->regs; struct dwc2_hc_regs *hc_regs = ®s->hc_regs[DWC2_HC_CHANNEL]; int devnum = usb_pipedevice(pipe); int ep = usb_pipeendpoint(pipe); @@ -802,10 +812,12 @@ int chunk_msg(struct usb_device *dev, unsigned long pipe, int *pid, int in, (*pid << DWC2_HCTSIZ_PID_OFFSET), &hc_regs->hctsiz);
- if (!in) - memcpy(aligned_buffer, (char *)buffer + done, len); + if (!in) { + memcpy(priv->aligned_buffer, (char *)buffer + done, + len); + }
- writel(phys_to_bus((unsigned long)aligned_buffer), + writel(phys_to_bus((unsigned long)priv->aligned_buffer), &hc_regs->hcdma);
/* Set host channel enable after all other setup is complete. */ @@ -814,13 +826,13 @@ int chunk_msg(struct usb_device *dev, unsigned long pipe, int *pid, int in, (1 << DWC2_HCCHAR_MULTICNT_OFFSET) | DWC2_HCCHAR_CHEN);
- ret = wait_for_chhltd(&sub, pid, ignore_ack); + ret = wait_for_chhltd(regs, &sub, pid, ignore_ack); if (ret) break;
if (in) { xfer_len -= sub; - memcpy(buffer + done, aligned_buffer, xfer_len); + memcpy(buffer + done, priv->aligned_buffer, xfer_len); if (sub) stop_transfer = 1; } @@ -839,43 +851,45 @@ int chunk_msg(struct usb_device *dev, unsigned long pipe, int *pid, int in, }
/* U-Boot USB transmission interface */ -int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, - int len) +int _submit_bulk_msg(struct dwc2_priv *priv, struct usb_device *dev, + unsigned long pipe, void *buffer, int len) { int devnum = usb_pipedevice(pipe); int ep = usb_pipeendpoint(pipe);
- if (devnum == root_hub_devnum) { + if (devnum == priv->root_hub_devnum) { dev->status = 0; return -EINVAL; }
- return chunk_msg(dev, pipe, &bulk_data_toggle[devnum][ep], + return chunk_msg(priv, dev, pipe, &priv->bulk_data_toggle[devnum][ep], usb_pipein(pipe), buffer, len, true); }
-int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, - int len, struct devrequest *setup) +static int _submit_control_msg(struct dwc2_priv *priv, struct usb_device *dev, + unsigned long pipe, void *buffer, int len, + struct devrequest *setup) { int devnum = usb_pipedevice(pipe); int pid, ret, act_len; /* For CONTROL endpoint pid should start with DATA1 */ int status_direction;
- if (devnum == root_hub_devnum) { + if (devnum == priv->root_hub_devnum) { dev->status = 0; dev->speed = USB_SPEED_HIGH; - return dwc_otg_submit_rh_msg(dev, pipe, buffer, len, setup); + return dwc_otg_submit_rh_msg(priv, dev, pipe, buffer, len, + setup); }
pid = DWC2_HC_PID_SETUP; - ret = chunk_msg(dev, pipe, &pid, 0, setup, 8, true); + ret = chunk_msg(priv, dev, pipe, &pid, 0, setup, 8, true); if (ret) return ret;
if (buffer) { pid = DWC2_HC_PID_DATA1; - ret = chunk_msg(dev, pipe, &pid, usb_pipein(pipe), buffer, + ret = chunk_msg(priv, dev, pipe, &pid, usb_pipein(pipe), buffer, len, false); if (ret) return ret; @@ -891,8 +905,8 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, status_direction = 0;
pid = DWC2_HC_PID_DATA1; - ret = chunk_msg(dev, pipe, &pid, status_direction, status_buffer, 0, - false); + ret = chunk_msg(priv, dev, pipe, &pid, status_direction, + priv->status_buffer, 0, false); if (ret) return ret;
@@ -901,8 +915,8 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, return 0; }
-int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, - int len, int interval) +int _submit_int_msg(struct dwc2_priv *priv, struct usb_device *dev, + unsigned long pipe, void *buffer, int len, int interval) { unsigned long timeout; int ret; @@ -915,20 +929,18 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, printf("Timeout poll on interrupt endpoint\n"); return -ETIMEDOUT; } - ret = submit_bulk_msg(dev, pipe, buffer, len); + ret = _submit_bulk_msg(priv, dev, pipe, buffer, len); if (ret != -EAGAIN) return ret; } }
-/* U-Boot USB control interface */ -int usb_lowlevel_init(int index, enum usb_init_type init, void **controller) +static int dwc2_init_common(struct dwc2_priv *priv) { + struct dwc2_core_regs *regs = priv->regs; uint32_t snpsid; int i, j;
- root_hub_devnum = 0; - snpsid = readl(®s->gsnpsid); printf("Core Release: %x.%03x\n", snpsid >> 12 & 0xf, snpsid & 0xfff);
@@ -952,18 +964,56 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
for (i = 0; i < MAX_DEVICE; i++) { for (j = 0; j < MAX_ENDPOINT; j++) - bulk_data_toggle[i][j] = DWC2_HC_PID_DATA0; + priv->bulk_data_toggle[i][j] = DWC2_HC_PID_DATA0; }
return 0; }
-int usb_lowlevel_stop(int index) +static void dwc2_uninit_common(struct dwc2_core_regs *regs) { /* Put everything in reset. */ clrsetbits_le32(®s->hprt0, DWC2_HPRT0_PRTENA | DWC2_HPRT0_PRTCONNDET | DWC2_HPRT0_PRTENCHNG | DWC2_HPRT0_PRTOVRCURRCHNG, DWC2_HPRT0_PRTRST); +} + +int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, + int len, struct devrequest *setup) +{ + return _submit_control_msg(&local, dev, pipe, buffer, len, setup); +} + +int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, + int len) +{ + return _submit_bulk_msg(&local, dev, pipe, buffer, len); +} + +int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, + int len, int interval) +{ + return _submit_int_msg(&local, dev, pipe, buffer, len, interval); +} + +/* U-Boot USB control interface */ +int usb_lowlevel_init(int index, enum usb_init_type init, void **controller) +{ + struct dwc2_priv *priv = &local; + + memset(priv, '\0', sizeof(*priv)); + priv->root_hub_devnum = 0; + priv->regs = (struct dwc2_core_regs *)CONFIG_USB_DWC2_REG_ADDR; + priv->aligned_buffer = aligned_buffer_addr; + priv->status_buffer = status_buffer_addr; + + return dwc2_init_common(priv); +} + +int usb_lowlevel_stop(int index) +{ + dwc2_uninit_common(local.regs); + return 0; }

On 7 July 2015 at 20:53, Simon Glass sjg@chromium.org wrote:
Put all global data in a structure and move (what will be) common code into common functions. This will make the driver-model conversion much easier.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/usb/host/dwc2.c | 150 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 100 insertions(+), 50 deletions(-)
Applied to u-boot-dm.

Add driver model support to this driver so it can be used with the new USB stack.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/usb/host/dwc2.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+)
diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c index 366e025..7b8f5a6 100644 --- a/drivers/usb/host/dwc2.c +++ b/drivers/usb/host/dwc2.c @@ -6,6 +6,7 @@ */
#include <common.h> +#include <dm.h> #include <errno.h> #include <usb.h> #include <malloc.h> @@ -25,18 +26,25 @@ #define MAX_ENDPOINT 16
struct dwc2_priv { +#ifdef CONFIG_DM_USB + uint8_t aligned_buffer[DWC2_DATA_BUF_SIZE] __aligned(8); + uint8_t status_buffer[DWC2_STATUS_BUF_SIZE] __aligned(8); +#else uint8_t *aligned_buffer; uint8_t *status_buffer; +#endif int bulk_data_toggle[MAX_DEVICE][MAX_ENDPOINT]; struct dwc2_core_regs *regs; int root_hub_devnum; };
+#ifndef CONFIG_DM_USB /* We need doubleword-aligned buffers for DMA transfers */ DEFINE_ALIGN_BUFFER(uint8_t, aligned_buffer_addr, DWC2_DATA_BUF_SIZE, 8); DEFINE_ALIGN_BUFFER(uint8_t, status_buffer_addr, DWC2_STATUS_BUF_SIZE, 8);
static struct dwc2_priv local; +#endif
/* * DWC2 IP interface @@ -979,6 +987,7 @@ static void dwc2_uninit_common(struct dwc2_core_regs *regs) DWC2_HPRT0_PRTRST); }
+#ifndef CONFIG_DM_USB int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int len, struct devrequest *setup) { @@ -1017,3 +1026,91 @@ int usb_lowlevel_stop(int index)
return 0; } +#endif + +#ifdef CONFIG_DM_USB +static int dwc2_submit_control_msg(struct udevice *dev, struct usb_device *udev, + unsigned long pipe, void *buffer, int length, + struct devrequest *setup) +{ + struct dwc2_priv *priv = dev_get_priv(dev); + + debug("%s: dev='%s', udev=%p, udev->dev='%s', portnr=%d\n", __func__, + dev->name, udev, udev->dev->name, udev->portnr); + + return _submit_control_msg(priv, udev, pipe, buffer, length, setup); +} + +static int dwc2_submit_bulk_msg(struct udevice *dev, struct usb_device *udev, + unsigned long pipe, void *buffer, int length) +{ + struct dwc2_priv *priv = dev_get_priv(dev); + + debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev); + + return _submit_bulk_msg(priv, udev, pipe, buffer, length); +} + +static int dwc2_submit_int_msg(struct udevice *dev, struct usb_device *udev, + unsigned long pipe, void *buffer, int length, + int interval) +{ + struct dwc2_priv *priv = dev_get_priv(dev); + + debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev); + + return _submit_int_msg(priv, udev, pipe, buffer, length, interval); +} + +static int dwc2_usb_ofdata_to_platdata(struct udevice *dev) +{ + struct dwc2_priv *priv = dev_get_priv(dev); + fdt_addr_t addr; + + addr = dev_get_addr(dev); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + priv->regs = (struct dwc2_core_regs *)addr; + + return 0; +} + +static int dwc2_usb_probe(struct udevice *dev) +{ + struct dwc2_priv *priv = dev_get_priv(dev); + + return dwc2_init_common(priv); +} + +static int dwc2_usb_remove(struct udevice *dev) +{ + struct dwc2_priv *priv = dev_get_priv(dev); + + dwc2_uninit_common(priv->regs); + + return 0; +} + +struct dm_usb_ops dwc2_usb_ops = { + .control = dwc2_submit_control_msg, + .bulk = dwc2_submit_bulk_msg, + .interrupt = dwc2_submit_int_msg, +}; + +static const struct udevice_id dwc2_usb_ids[] = { + { .compatible = "brcm,bcm2835-usb" }, + { } +}; + +U_BOOT_DRIVER(usb_dwc2) = { + .name = "dwc2_exynos", + .id = UCLASS_USB, + .of_match = dwc2_usb_ids, + .ofdata_to_platdata = dwc2_usb_ofdata_to_platdata, + .probe = dwc2_usb_probe, + .remove = dwc2_usb_remove, + .ops = &dwc2_usb_ops, + .priv_auto_alloc_size = sizeof(struct dwc2_priv), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; +#endif

On 7 July 2015 at 20:53, Simon Glass sjg@chromium.org wrote:
Add driver model support to this driver so it can be used with the new USB stack.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/usb/host/dwc2.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+)
Applied to u-boot-dm.

Tidy up the include file order before adding more.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/usb/eth/smsc95xx.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/usb/eth/smsc95xx.c b/drivers/usb/eth/smsc95xx.c index a7e50d6..8ebe4d6 100644 --- a/drivers/usb/eth/smsc95xx.c +++ b/drivers/usb/eth/smsc95xx.c @@ -6,12 +6,13 @@ * SPDX-License-Identifier: GPL-2.0+ */
-#include <asm/unaligned.h> #include <common.h> +#include <errno.h> +#include <malloc.h> #include <usb.h> +#include <asm/unaligned.h> #include <linux/mii.h> #include "usb_ether.h" -#include <malloc.h>
/* SMSC LAN95xx based USB 2.0 Ethernet Devices */

On 7 July 2015 at 20:53, Simon Glass sjg@chromium.org wrote:
Tidy up the include file order before adding more.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/usb/eth/smsc95xx.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
Applied to u-boot-dm.

The AX_ prefix comes from the Asix driver. Since this is not that, we should avoid this confusing prefix.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/usb/eth/smsc95xx.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/usb/eth/smsc95xx.c b/drivers/usb/eth/smsc95xx.c index 8ebe4d6..2d109fb 100644 --- a/drivers/usb/eth/smsc95xx.c +++ b/drivers/usb/eth/smsc95xx.c @@ -132,7 +132,7 @@ #define USB_BULK_SEND_TIMEOUT 5000 #define USB_BULK_RECV_TIMEOUT 5000
-#define AX_RX_URB_SIZE 2048 +#define RX_URB_SIZE 2048 #define PHY_CONNECT_TIMEOUT 5000
#define TURBO_MODE @@ -712,7 +712,7 @@ static int smsc95xx_send(struct eth_device *eth, void* packet, int length) static int smsc95xx_recv(struct eth_device *eth) { struct ueth_data *dev = (struct ueth_data *)eth->priv; - DEFINE_CACHE_ALIGN_BUFFER(unsigned char, recv_buf, AX_RX_URB_SIZE); + DEFINE_CACHE_ALIGN_BUFFER(unsigned char, recv_buf, RX_URB_SIZE); unsigned char *buf_ptr; int err; int actual_len; @@ -723,16 +723,16 @@ static int smsc95xx_recv(struct eth_device *eth) err = usb_bulk_msg(dev->pusb_dev, usb_rcvbulkpipe(dev->pusb_dev, dev->ep_in), (void *)recv_buf, - AX_RX_URB_SIZE, + RX_URB_SIZE, &actual_len, USB_BULK_RECV_TIMEOUT); - debug("Rx: len = %u, actual = %u, err = %d\n", AX_RX_URB_SIZE, + debug("Rx: len = %u, actual = %u, err = %d\n", RX_URB_SIZE, actual_len, err); if (err != 0) { debug("Rx: failed to receive\n"); return -1; } - if (actual_len > AX_RX_URB_SIZE) { + if (actual_len > RX_URB_SIZE) { debug("Rx: received too many bytes %d\n", actual_len); return -1; }

On 7 July 2015 at 20:53, Simon Glass sjg@chromium.org wrote:
The AX_ prefix comes from the Asix driver. Since this is not that, we should avoid this confusing prefix.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/usb/eth/smsc95xx.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
Applied to u-boot-dm.

Instead of returning -1 on error, we should use a proper error number. Fix the code to conform to this.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/usb/eth/smsc95xx.c | 48 +++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 22 deletions(-)
diff --git a/drivers/usb/eth/smsc95xx.c b/drivers/usb/eth/smsc95xx.c index 2d109fb..f0cf7aa 100644 --- a/drivers/usb/eth/smsc95xx.c +++ b/drivers/usb/eth/smsc95xx.c @@ -165,7 +165,7 @@ static int smsc95xx_write_reg(struct ueth_data *dev, u32 index, u32 data) if (len != sizeof(data)) { debug("smsc95xx_write_reg failed: index=%d, data=%d, len=%d", index, data, len); - return -1; + return -EIO; } return 0; } @@ -183,7 +183,7 @@ static int smsc95xx_read_reg(struct ueth_data *dev, u32 index, u32 *data) if (len != sizeof(data)) { debug("smsc95xx_read_reg failed: index=%d, len=%d", index, len); - return -1; + return -EIO; }
le32_to_cpus(data); @@ -202,7 +202,7 @@ static int smsc95xx_phy_wait_not_busy(struct ueth_data *dev) return 0; } while (get_timer(start_time) < 1 * 1000 * 1000);
- return -1; + return -ETIMEDOUT; }
static int smsc95xx_mdio_read(struct ueth_data *dev, int phy_id, int idx) @@ -212,7 +212,7 @@ static int smsc95xx_mdio_read(struct ueth_data *dev, int phy_id, int idx) /* confirm MII not busy */ if (smsc95xx_phy_wait_not_busy(dev)) { debug("MII is busy in smsc95xx_mdio_read\n"); - return -1; + return -ETIMEDOUT; }
/* set the address, index & direction (read from PHY) */ @@ -221,7 +221,7 @@ static int smsc95xx_mdio_read(struct ueth_data *dev, int phy_id, int idx)
if (smsc95xx_phy_wait_not_busy(dev)) { debug("Timed out reading MII reg %02X\n", idx); - return -1; + return -ETIMEDOUT; }
smsc95xx_read_reg(dev, MII_DATA, &val); @@ -264,7 +264,7 @@ static int smsc95xx_eeprom_confirm_not_busy(struct ueth_data *dev) } while (get_timer(start_time) < 1 * 1000 * 1000);
debug("EEPROM is busy\n"); - return -1; + return -ETIMEDOUT; }
static int smsc95xx_wait_eeprom(struct ueth_data *dev) @@ -281,7 +281,7 @@ static int smsc95xx_wait_eeprom(struct ueth_data *dev)
if (val & (E2P_CMD_TIMEOUT_ | E2P_CMD_BUSY_)) { debug("EEPROM read operation timeout\n"); - return -1; + return -ETIMEDOUT; } return 0; } @@ -367,7 +367,9 @@ static int smsc95xx_init_mac_address(struct eth_device *eth, * No eeprom, or eeprom values are invalid. Generating a random MAC * address is not safe. Just return an error. */ - return -1; + debug("Invalid MAC address read from EEPROM\n"); + + return -ENXIO; }
static int smsc95xx_write_hwaddr(struct eth_device *eth) @@ -488,7 +490,7 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd)
if (timeout >= 100) { debug("timeout waiting for completion of Lite Reset\n"); - return -1; + return -ETIMEDOUT; }
write_buf = PM_CTL_PHY_RST_; @@ -506,16 +508,17 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd) } while ((read_buf & PM_CTL_PHY_RST_) && (timeout < 100)); if (timeout >= 100) { debug("timeout waiting for PHY Reset\n"); - return -1; + return -ETIMEDOUT; } if (!priv->have_hwaddr && smsc95xx_init_mac_address(eth, dev) == 0) priv->have_hwaddr = 1; if (!priv->have_hwaddr) { puts("Error: SMSC95xx: No MAC address set - set usbethaddr\n"); - return -1; + return -EADDRNOTAVAIL; } - if (smsc95xx_write_hwaddr(eth) < 0) - return -1; + ret = smsc95xx_write_hwaddr_common(udev, priv, enetaddr); + if (ret < 0) + return ret;
ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); if (ret < 0) @@ -636,8 +639,9 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd) } smsc95xx_set_multicast(dev);
- if (smsc95xx_phy_initialize(dev) < 0) - return -1; + ret = smsc95xx_phy_initialize(dev); + if (ret < 0) + return ret; ret = smsc95xx_read_reg(dev, INT_EP_CTL, &read_buf); if (ret < 0) return ret; @@ -668,7 +672,7 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd) printf("done.\n"); } else { printf("unable to connect.\n"); - return -1; + return -EIO; } return 0; } @@ -685,7 +689,7 @@ static int smsc95xx_send(struct eth_device *eth, void* packet, int length)
debug("** %s(), len %d, buf %#x\n", __func__, length, (int)msg); if (length > PKTSIZE) - return -1; + return -ENOSPC;
tx_cmd_a = (u32)length | TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_; tx_cmd_b = (u32)length; @@ -730,11 +734,11 @@ static int smsc95xx_recv(struct eth_device *eth) actual_len, err); if (err != 0) { debug("Rx: failed to receive\n"); - return -1; + return err; } if (actual_len > RX_URB_SIZE) { debug("Rx: received too many bytes %d\n", actual_len); - return -1; + return -ENOSPC; }
buf_ptr = recv_buf; @@ -745,19 +749,19 @@ static int smsc95xx_recv(struct eth_device *eth) */ if (actual_len < sizeof(packet_len)) { debug("Rx: incomplete packet length\n"); - return -1; + return -EIO; } memcpy(&packet_len, buf_ptr, sizeof(packet_len)); le32_to_cpus(&packet_len); if (packet_len & RX_STS_ES_) { debug("Rx: Error header=%#x", packet_len); - return -1; + return -EIO; } packet_len = ((packet_len & RX_STS_FL_) >> 16);
if (packet_len > actual_len - sizeof(packet_len)) { debug("Rx: too large packet: %d\n", packet_len); - return -1; + return -EIO; }
/* Notify net stack */

On 7 July 2015 at 20:53, Simon Glass sjg@chromium.org wrote:
Instead of returning -1 on error, we should use a proper error number. Fix the code to conform to this.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/usb/eth/smsc95xx.c | 48 +++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 22 deletions(-)
Applied to u-boot-dm.

At present struct eth_device is passed around all over the place. This does not exist with driver model. Add explicit arguments instead, so that with driver model we can pass the correct things.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/usb/eth/smsc95xx.c | 270 +++++++++++++++++++++++++-------------------- 1 file changed, 149 insertions(+), 121 deletions(-)
diff --git a/drivers/usb/eth/smsc95xx.c b/drivers/usb/eth/smsc95xx.c index f0cf7aa..b0c610d 100644 --- a/drivers/usb/eth/smsc95xx.c +++ b/drivers/usb/eth/smsc95xx.c @@ -150,7 +150,7 @@ struct smsc95xx_private { /* * Smsc95xx infrastructure commands */ -static int smsc95xx_write_reg(struct ueth_data *dev, u32 index, u32 data) +static int smsc95xx_write_reg(struct usb_device *udev, u32 index, u32 data) { int len; ALLOC_CACHE_ALIGN_BUFFER(u32, tmpbuf, 1); @@ -158,10 +158,11 @@ static int smsc95xx_write_reg(struct ueth_data *dev, u32 index, u32 data) cpu_to_le32s(&data); tmpbuf[0] = data;
- len = usb_control_msg(dev->pusb_dev, usb_sndctrlpipe(dev->pusb_dev, 0), - USB_VENDOR_REQUEST_WRITE_REGISTER, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 00, index, tmpbuf, sizeof(data), USB_CTRL_SET_TIMEOUT); + len = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + USB_VENDOR_REQUEST_WRITE_REGISTER, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, index, tmpbuf, sizeof(data), + USB_CTRL_SET_TIMEOUT); if (len != sizeof(data)) { debug("smsc95xx_write_reg failed: index=%d, data=%d, len=%d", index, data, len); @@ -170,15 +171,16 @@ static int smsc95xx_write_reg(struct ueth_data *dev, u32 index, u32 data) return 0; }
-static int smsc95xx_read_reg(struct ueth_data *dev, u32 index, u32 *data) +static int smsc95xx_read_reg(struct usb_device *udev, u32 index, u32 *data) { int len; ALLOC_CACHE_ALIGN_BUFFER(u32, tmpbuf, 1);
- len = usb_control_msg(dev->pusb_dev, usb_rcvctrlpipe(dev->pusb_dev, 0), - USB_VENDOR_REQUEST_READ_REGISTER, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 00, index, tmpbuf, sizeof(data), USB_CTRL_GET_TIMEOUT); + len = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + USB_VENDOR_REQUEST_READ_REGISTER, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, index, tmpbuf, sizeof(data), + USB_CTRL_GET_TIMEOUT); *data = tmpbuf[0]; if (len != sizeof(data)) { debug("smsc95xx_read_reg failed: index=%d, len=%d", @@ -191,73 +193,73 @@ static int smsc95xx_read_reg(struct ueth_data *dev, u32 index, u32 *data) }
/* Loop until the read is completed with timeout */ -static int smsc95xx_phy_wait_not_busy(struct ueth_data *dev) +static int smsc95xx_phy_wait_not_busy(struct usb_device *udev) { unsigned long start_time = get_timer(0); u32 val;
do { - smsc95xx_read_reg(dev, MII_ADDR, &val); + smsc95xx_read_reg(udev, MII_ADDR, &val); if (!(val & MII_BUSY_)) return 0; - } while (get_timer(start_time) < 1 * 1000 * 1000); + } while (get_timer(start_time) < 1000);
return -ETIMEDOUT; }
-static int smsc95xx_mdio_read(struct ueth_data *dev, int phy_id, int idx) +static int smsc95xx_mdio_read(struct usb_device *udev, int phy_id, int idx) { u32 val, addr;
/* confirm MII not busy */ - if (smsc95xx_phy_wait_not_busy(dev)) { + if (smsc95xx_phy_wait_not_busy(udev)) { debug("MII is busy in smsc95xx_mdio_read\n"); return -ETIMEDOUT; }
/* set the address, index & direction (read from PHY) */ addr = (phy_id << 11) | (idx << 6) | MII_READ_; - smsc95xx_write_reg(dev, MII_ADDR, addr); + smsc95xx_write_reg(udev, MII_ADDR, addr);
- if (smsc95xx_phy_wait_not_busy(dev)) { + if (smsc95xx_phy_wait_not_busy(udev)) { debug("Timed out reading MII reg %02X\n", idx); return -ETIMEDOUT; }
- smsc95xx_read_reg(dev, MII_DATA, &val); + smsc95xx_read_reg(udev, MII_DATA, &val);
return (u16)(val & 0xFFFF); }
-static void smsc95xx_mdio_write(struct ueth_data *dev, int phy_id, int idx, +static void smsc95xx_mdio_write(struct usb_device *udev, int phy_id, int idx, int regval) { u32 val, addr;
/* confirm MII not busy */ - if (smsc95xx_phy_wait_not_busy(dev)) { + if (smsc95xx_phy_wait_not_busy(udev)) { debug("MII is busy in smsc95xx_mdio_write\n"); return; }
val = regval; - smsc95xx_write_reg(dev, MII_DATA, val); + smsc95xx_write_reg(udev, MII_DATA, val);
/* set the address, index & direction (write to PHY) */ addr = (phy_id << 11) | (idx << 6) | MII_WRITE_; - smsc95xx_write_reg(dev, MII_ADDR, addr); + smsc95xx_write_reg(udev, MII_ADDR, addr);
- if (smsc95xx_phy_wait_not_busy(dev)) + if (smsc95xx_phy_wait_not_busy(udev)) debug("Timed out writing MII reg %02X\n", idx); }
-static int smsc95xx_eeprom_confirm_not_busy(struct ueth_data *dev) +static int smsc95xx_eeprom_confirm_not_busy(struct usb_device *udev) { unsigned long start_time = get_timer(0); u32 val;
do { - smsc95xx_read_reg(dev, E2P_CMD, &val); + smsc95xx_read_reg(udev, E2P_CMD, &val); if (!(val & E2P_CMD_BUSY_)) return 0; udelay(40); @@ -267,13 +269,13 @@ static int smsc95xx_eeprom_confirm_not_busy(struct ueth_data *dev) return -ETIMEDOUT; }
-static int smsc95xx_wait_eeprom(struct ueth_data *dev) +static int smsc95xx_wait_eeprom(struct usb_device *udev) { unsigned long start_time = get_timer(0); u32 val;
do { - smsc95xx_read_reg(dev, E2P_CMD, &val); + smsc95xx_read_reg(udev, E2P_CMD, &val); if (!(val & E2P_CMD_BUSY_) || (val & E2P_CMD_TIMEOUT_)) break; udelay(40); @@ -286,25 +288,25 @@ static int smsc95xx_wait_eeprom(struct ueth_data *dev) return 0; }
-static int smsc95xx_read_eeprom(struct ueth_data *dev, u32 offset, u32 length, +static int smsc95xx_read_eeprom(struct usb_device *udev, u32 offset, u32 length, u8 *data) { u32 val; int i, ret;
- ret = smsc95xx_eeprom_confirm_not_busy(dev); + ret = smsc95xx_eeprom_confirm_not_busy(udev); if (ret) return ret;
for (i = 0; i < length; i++) { val = E2P_CMD_BUSY_ | E2P_CMD_READ_ | (offset & E2P_CMD_ADDR_); - smsc95xx_write_reg(dev, E2P_CMD, val); + smsc95xx_write_reg(udev, E2P_CMD, val);
- ret = smsc95xx_wait_eeprom(dev); + ret = smsc95xx_wait_eeprom(udev); if (ret < 0) return ret;
- smsc95xx_read_reg(dev, E2P_DATA, &val); + smsc95xx_read_reg(udev, E2P_DATA, &val); data[i] = val & 0xFF; offset++; } @@ -316,51 +318,55 @@ static int smsc95xx_read_eeprom(struct ueth_data *dev, u32 offset, u32 length, * * Returns 0 on success, negative on error. */ -static int mii_nway_restart(struct ueth_data *dev) +static int mii_nway_restart(struct usb_device *udev, struct ueth_data *dev) { int bmcr; int r = -1;
/* if autoneg is off, it's an error */ - bmcr = smsc95xx_mdio_read(dev, dev->phy_id, MII_BMCR); + bmcr = smsc95xx_mdio_read(udev, dev->phy_id, MII_BMCR);
if (bmcr & BMCR_ANENABLE) { bmcr |= BMCR_ANRESTART; - smsc95xx_mdio_write(dev, dev->phy_id, MII_BMCR, bmcr); + smsc95xx_mdio_write(udev, dev->phy_id, MII_BMCR, bmcr); r = 0; } return r; }
-static int smsc95xx_phy_initialize(struct ueth_data *dev) +static int smsc95xx_phy_initialize(struct usb_device *udev, + struct ueth_data *dev) { - smsc95xx_mdio_write(dev, dev->phy_id, MII_BMCR, BMCR_RESET); - smsc95xx_mdio_write(dev, dev->phy_id, MII_ADVERTISE, - ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP | - ADVERTISE_PAUSE_ASYM); + smsc95xx_mdio_write(udev, dev->phy_id, MII_BMCR, BMCR_RESET); + smsc95xx_mdio_write(udev, dev->phy_id, MII_ADVERTISE, + ADVERTISE_ALL | ADVERTISE_CSMA | + ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
/* read to clear */ - smsc95xx_mdio_read(dev, dev->phy_id, PHY_INT_SRC); + smsc95xx_mdio_read(udev, dev->phy_id, PHY_INT_SRC);
- smsc95xx_mdio_write(dev, dev->phy_id, PHY_INT_MASK, - PHY_INT_MASK_DEFAULT_); - mii_nway_restart(dev); + smsc95xx_mdio_write(udev, dev->phy_id, PHY_INT_MASK, + PHY_INT_MASK_DEFAULT_); + mii_nway_restart(udev, dev);
debug("phy initialised succesfully\n"); return 0; }
-static int smsc95xx_init_mac_address(struct eth_device *eth, - struct ueth_data *dev) +static int smsc95xx_init_mac_address(unsigned char *enetaddr, + struct usb_device *udev) { + int ret; + /* try reading mac address from EEPROM */ - if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN, - eth->enetaddr) == 0) { - if (is_valid_ethaddr(eth->enetaddr)) { - /* eeprom values are valid so use them */ - debug("MAC address read from EEPROM\n"); - return 0; - } + ret = smsc95xx_read_eeprom(udev, EEPROM_MAC_OFFSET, ETH_ALEN, enetaddr); + if (ret) + return ret; + + if (is_valid_ethaddr(enetaddr)) { + /* eeprom values are valid so use them */ + debug("MAC address read from EEPROM\n"); + return 0; }
/* @@ -372,35 +378,36 @@ static int smsc95xx_init_mac_address(struct eth_device *eth, return -ENXIO; }
-static int smsc95xx_write_hwaddr(struct eth_device *eth) +static int smsc95xx_write_hwaddr_common(struct usb_device *udev, + struct smsc95xx_private *priv, + unsigned char *enetaddr) { - struct ueth_data *dev = (struct ueth_data *)eth->priv; - struct smsc95xx_private *priv = dev->dev_priv; - u32 addr_lo = __get_unaligned_le32(ð->enetaddr[0]); - u32 addr_hi = __get_unaligned_le16(ð->enetaddr[4]); + u32 addr_lo = __get_unaligned_le32(&enetaddr[0]); + u32 addr_hi = __get_unaligned_le16(&enetaddr[4]); int ret;
/* set hardware address */ debug("** %s()\n", __func__); - ret = smsc95xx_write_reg(dev, ADDRL, addr_lo); + ret = smsc95xx_write_reg(udev, ADDRL, addr_lo); if (ret < 0) return ret;
- ret = smsc95xx_write_reg(dev, ADDRH, addr_hi); + ret = smsc95xx_write_reg(udev, ADDRH, addr_hi); if (ret < 0) return ret;
- debug("MAC %pM\n", eth->enetaddr); + debug("MAC %pM\n", enetaddr); priv->have_hwaddr = 1; + return 0; }
/* Enable or disable Tx & Rx checksum offload engines */ -static int smsc95xx_set_csums(struct ueth_data *dev, - int use_tx_csum, int use_rx_csum) +static int smsc95xx_set_csums(struct usb_device *udev, int use_tx_csum, + int use_rx_csum) { u32 read_buf; - int ret = smsc95xx_read_reg(dev, COE_CR, &read_buf); + int ret = smsc95xx_read_reg(udev, COE_CR, &read_buf); if (ret < 0) return ret;
@@ -414,7 +421,7 @@ static int smsc95xx_set_csums(struct ueth_data *dev, else read_buf &= ~Rx_COE_EN_;
- ret = smsc95xx_write_reg(dev, COE_CR, read_buf); + ret = smsc95xx_write_reg(udev, COE_CR, read_buf); if (ret < 0) return ret;
@@ -422,52 +429,45 @@ static int smsc95xx_set_csums(struct ueth_data *dev, return 0; }
-static void smsc95xx_set_multicast(struct ueth_data *dev) +static void smsc95xx_set_multicast(struct smsc95xx_private *priv) { - struct smsc95xx_private *priv = dev->dev_priv; - /* No multicast in u-boot */ priv->mac_cr &= ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_ | MAC_CR_HPFILT_); }
/* starts the TX path */ -static void smsc95xx_start_tx_path(struct ueth_data *dev) +static void smsc95xx_start_tx_path(struct usb_device *udev, + struct smsc95xx_private *priv) { - struct smsc95xx_private *priv = dev->dev_priv; u32 reg_val;
/* Enable Tx at MAC */ priv->mac_cr |= MAC_CR_TXEN_;
- smsc95xx_write_reg(dev, MAC_CR, priv->mac_cr); + smsc95xx_write_reg(udev, MAC_CR, priv->mac_cr);
/* Enable Tx at SCSRs */ reg_val = TX_CFG_ON_; - smsc95xx_write_reg(dev, TX_CFG, reg_val); + smsc95xx_write_reg(udev, TX_CFG, reg_val); }
/* Starts the Receive path */ -static void smsc95xx_start_rx_path(struct ueth_data *dev) +static void smsc95xx_start_rx_path(struct usb_device *udev, + struct smsc95xx_private *priv) { - struct smsc95xx_private *priv = dev->dev_priv; - priv->mac_cr |= MAC_CR_RXEN_; - smsc95xx_write_reg(dev, MAC_CR, priv->mac_cr); + smsc95xx_write_reg(udev, MAC_CR, priv->mac_cr); }
-/* - * Smsc95xx callbacks - */ -static int smsc95xx_init(struct eth_device *eth, bd_t *bd) +static int smsc95xx_init_common(struct usb_device *udev, struct ueth_data *dev, + struct smsc95xx_private *priv, + unsigned char *enetaddr) { int ret; u32 write_buf; u32 read_buf; u32 burst_cap; int timeout; - struct ueth_data *dev = (struct ueth_data *)eth->priv; - struct smsc95xx_private *priv = - (struct smsc95xx_private *)dev->dev_priv; #define TIMEOUT_RESOLUTION 50 /* ms */ int link_detected;
@@ -475,13 +475,13 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd) dev->phy_id = SMSC95XX_INTERNAL_PHY_ID; /* fixed phy id */
write_buf = HW_CFG_LRST_; - ret = smsc95xx_write_reg(dev, HW_CFG, write_buf); + ret = smsc95xx_write_reg(udev, HW_CFG, write_buf); if (ret < 0) return ret;
timeout = 0; do { - ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); + ret = smsc95xx_read_reg(udev, HW_CFG, &read_buf); if (ret < 0) return ret; udelay(10 * 1000); @@ -494,13 +494,13 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd) }
write_buf = PM_CTL_PHY_RST_; - ret = smsc95xx_write_reg(dev, PM_CTRL, write_buf); + ret = smsc95xx_write_reg(udev, PM_CTRL, write_buf); if (ret < 0) return ret;
timeout = 0; do { - ret = smsc95xx_read_reg(dev, PM_CTRL, &read_buf); + ret = smsc95xx_read_reg(udev, PM_CTRL, &read_buf); if (ret < 0) return ret; udelay(10 * 1000); @@ -510,7 +510,8 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd) debug("timeout waiting for PHY Reset\n"); return -ETIMEDOUT; } - if (!priv->have_hwaddr && smsc95xx_init_mac_address(eth, dev) == 0) + if (!priv->have_hwaddr && smsc95xx_init_mac_address(enetaddr, udev) == + 0) priv->have_hwaddr = 1; if (!priv->have_hwaddr) { puts("Error: SMSC95xx: No MAC address set - set usbethaddr\n"); @@ -520,17 +521,17 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd) if (ret < 0) return ret;
- ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); + ret = smsc95xx_read_reg(udev, HW_CFG, &read_buf); if (ret < 0) return ret; debug("Read Value from HW_CFG : 0x%08x\n", read_buf);
read_buf |= HW_CFG_BIR_; - ret = smsc95xx_write_reg(dev, HW_CFG, read_buf); + ret = smsc95xx_write_reg(udev, HW_CFG, read_buf); if (ret < 0) return ret;
- ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); + ret = smsc95xx_read_reg(udev, HW_CFG, &read_buf); if (ret < 0) return ret; debug("Read Value from HW_CFG after writing " @@ -550,27 +551,27 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd) #endif debug("rx_urb_size=%ld\n", (ulong)priv->rx_urb_size);
- ret = smsc95xx_write_reg(dev, BURST_CAP, burst_cap); + ret = smsc95xx_write_reg(udev, BURST_CAP, burst_cap); if (ret < 0) return ret;
- ret = smsc95xx_read_reg(dev, BURST_CAP, &read_buf); + ret = smsc95xx_read_reg(udev, BURST_CAP, &read_buf); if (ret < 0) return ret; debug("Read Value from BURST_CAP after writing: 0x%08x\n", read_buf);
read_buf = DEFAULT_BULK_IN_DELAY; - ret = smsc95xx_write_reg(dev, BULK_IN_DLY, read_buf); + ret = smsc95xx_write_reg(udev, BULK_IN_DLY, read_buf); if (ret < 0) return ret;
- ret = smsc95xx_read_reg(dev, BULK_IN_DLY, &read_buf); + ret = smsc95xx_read_reg(udev, BULK_IN_DLY, &read_buf); if (ret < 0) return ret; debug("Read Value from BULK_IN_DLY after writing: " "0x%08x\n", read_buf);
- ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); + ret = smsc95xx_read_reg(udev, HW_CFG, &read_buf); if (ret < 0) return ret; debug("Read Value from HW_CFG: 0x%08x\n", read_buf); @@ -583,21 +584,21 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd) #define NET_IP_ALIGN 0 read_buf |= NET_IP_ALIGN << 9;
- ret = smsc95xx_write_reg(dev, HW_CFG, read_buf); + ret = smsc95xx_write_reg(udev, HW_CFG, read_buf); if (ret < 0) return ret;
- ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); + ret = smsc95xx_read_reg(udev, HW_CFG, &read_buf); if (ret < 0) return ret; debug("Read Value from HW_CFG after writing: 0x%08x\n", read_buf);
write_buf = 0xFFFFFFFF; - ret = smsc95xx_write_reg(dev, INT_STS, write_buf); + ret = smsc95xx_write_reg(udev, INT_STS, write_buf); if (ret < 0) return ret;
- ret = smsc95xx_read_reg(dev, ID_REV, &read_buf); + ret = smsc95xx_read_reg(udev, ID_REV, &read_buf); if (ret < 0) return ret; debug("ID_REV = 0x%08x\n", read_buf); @@ -605,60 +606,60 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd) /* Configure GPIO pins as LED outputs */ write_buf = LED_GPIO_CFG_SPD_LED | LED_GPIO_CFG_LNK_LED | LED_GPIO_CFG_FDX_LED; - ret = smsc95xx_write_reg(dev, LED_GPIO_CFG, write_buf); + ret = smsc95xx_write_reg(udev, LED_GPIO_CFG, write_buf); if (ret < 0) return ret; debug("LED_GPIO_CFG set\n");
/* Init Tx */ write_buf = 0; - ret = smsc95xx_write_reg(dev, FLOW, write_buf); + ret = smsc95xx_write_reg(udev, FLOW, write_buf); if (ret < 0) return ret;
read_buf = AFC_CFG_DEFAULT; - ret = smsc95xx_write_reg(dev, AFC_CFG, read_buf); + ret = smsc95xx_write_reg(udev, AFC_CFG, read_buf); if (ret < 0) return ret;
- ret = smsc95xx_read_reg(dev, MAC_CR, &priv->mac_cr); + ret = smsc95xx_read_reg(udev, MAC_CR, &priv->mac_cr); if (ret < 0) return ret;
/* Init Rx. Set Vlan */ write_buf = (u32)ETH_P_8021Q; - ret = smsc95xx_write_reg(dev, VLAN1, write_buf); + ret = smsc95xx_write_reg(udev, VLAN1, write_buf); if (ret < 0) return ret;
/* Disable checksum offload engines */ - ret = smsc95xx_set_csums(dev, 0, 0); + ret = smsc95xx_set_csums(udev, 0, 0); if (ret < 0) { debug("Failed to set csum offload: %d\n", ret); return ret; } - smsc95xx_set_multicast(dev); + smsc95xx_set_multicast(priv);
- ret = smsc95xx_phy_initialize(dev); + ret = smsc95xx_phy_initialize(udev, dev); if (ret < 0) return ret; - ret = smsc95xx_read_reg(dev, INT_EP_CTL, &read_buf); + ret = smsc95xx_read_reg(udev, INT_EP_CTL, &read_buf); if (ret < 0) return ret;
/* enable PHY interrupts */ read_buf |= INT_EP_CTL_PHY_INT_;
- ret = smsc95xx_write_reg(dev, INT_EP_CTL, read_buf); + ret = smsc95xx_write_reg(udev, INT_EP_CTL, read_buf); if (ret < 0) return ret;
- smsc95xx_start_tx_path(dev); - smsc95xx_start_rx_path(dev); + smsc95xx_start_tx_path(udev, priv); + smsc95xx_start_rx_path(udev, priv);
timeout = 0; do { - link_detected = smsc95xx_mdio_read(dev, dev->phy_id, MII_BMSR) + link_detected = smsc95xx_mdio_read(udev, dev->phy_id, MII_BMSR) & BMSR_LSTATUS; if (!link_detected) { if (timeout == 0) @@ -677,9 +678,8 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd) return 0; }
-static int smsc95xx_send(struct eth_device *eth, void* packet, int length) +static int smsc95xx_send_common(struct ueth_data *dev, void *packet, int length) { - struct ueth_data *dev = (struct ueth_data *)eth->priv; int err; int actual_len; u32 tx_cmd_a; @@ -710,9 +710,30 @@ static int smsc95xx_send(struct eth_device *eth, void* packet, int length) debug("Tx: len = %u, actual = %u, err = %d\n", length + sizeof(tx_cmd_a) + sizeof(tx_cmd_b), actual_len, err); + return err; }
+/* + * Smsc95xx callbacks + */ +static int smsc95xx_init(struct eth_device *eth, bd_t *bd) +{ + struct ueth_data *dev = (struct ueth_data *)eth->priv; + struct usb_device *udev = dev->pusb_dev; + struct smsc95xx_private *priv = + (struct smsc95xx_private *)dev->dev_priv; + + return smsc95xx_init_common(udev, dev, priv, eth->enetaddr); +} + +static int smsc95xx_send(struct eth_device *eth, void *packet, int length) +{ + struct ueth_data *dev = (struct ueth_data *)eth->priv; + + return smsc95xx_send_common(dev, packet, length); +} + static int smsc95xx_recv(struct eth_device *eth) { struct ueth_data *dev = (struct ueth_data *)eth->priv; @@ -725,16 +746,14 @@ static int smsc95xx_recv(struct eth_device *eth)
debug("** %s()\n", __func__); err = usb_bulk_msg(dev->pusb_dev, - usb_rcvbulkpipe(dev->pusb_dev, dev->ep_in), - (void *)recv_buf, - RX_URB_SIZE, - &actual_len, - USB_BULK_RECV_TIMEOUT); + usb_rcvbulkpipe(dev->pusb_dev, dev->ep_in), + (void *)recv_buf, RX_URB_SIZE, &actual_len, + USB_BULK_RECV_TIMEOUT); debug("Rx: len = %u, actual = %u, err = %d\n", RX_URB_SIZE, actual_len, err); if (err != 0) { debug("Rx: failed to receive\n"); - return err; + return -err; } if (actual_len > RX_URB_SIZE) { debug("Rx: received too many bytes %d\n", actual_len); @@ -788,6 +807,15 @@ static void smsc95xx_halt(struct eth_device *eth) debug("** %s()\n", __func__); }
+static int smsc95xx_write_hwaddr(struct eth_device *eth) +{ + struct ueth_data *dev = eth->priv; + struct usb_device *udev = dev->pusb_dev; + struct smsc95xx_private *priv = dev->dev_priv; + + return smsc95xx_write_hwaddr_common(udev, priv, eth->enetaddr); +} + /* * SMSC probing functions */

On 7 July 2015 at 20:53, Simon Glass sjg@chromium.org wrote:
At present struct eth_device is passed around all over the place. This does not exist with driver model. Add explicit arguments instead, so that with driver model we can pass the correct things.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/usb/eth/smsc95xx.c | 270 +++++++++++++++++++++++++-------------------- 1 file changed, 149 insertions(+), 121 deletions(-)
Applied to u-boot-dm.

Add support for driver model, so that CONFIG_DM_ETH can be defined and used with this driver.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/usb/eth/smsc95xx.c | 142 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+)
diff --git a/drivers/usb/eth/smsc95xx.c b/drivers/usb/eth/smsc95xx.c index b0c610d..1dcd088 100644 --- a/drivers/usb/eth/smsc95xx.c +++ b/drivers/usb/eth/smsc95xx.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2015 Google, Inc * Copyright (c) 2011 The Chromium OS Authors. * Copyright (C) 2009 NVIDIA, Corporation * Copyright (C) 2007-2008 SMSC (Steve Glendinning) @@ -7,6 +8,7 @@ */
#include <common.h> +#include <dm.h> #include <errno.h> #include <malloc.h> #include <usb.h> @@ -137,11 +139,16 @@
#define TURBO_MODE
+#ifndef CONFIG_DM_ETH /* local vars */ static int curr_eth_dev; /* index for name of next device detected */ +#endif
/* driver private */ struct smsc95xx_private { +#ifdef CONFIG_DM_ETH + struct ueth_data ueth; +#endif size_t rx_urb_size; /* maximum USB URB size */ u32 mac_cr; /* MAC control register value */ int have_hwaddr; /* 1 if we have a hardware MAC address */ @@ -714,6 +721,7 @@ static int smsc95xx_send_common(struct ueth_data *dev, void *packet, int length) return err; }
+#ifndef CONFIG_DM_ETH /* * Smsc95xx callbacks */ @@ -931,3 +939,137 @@ int smsc95xx_eth_get_info(struct usb_device *dev, struct ueth_data *ss, eth->priv = ss; return 1; } +#endif /* !CONFIG_DM_ETH */ + +#ifdef CONFIG_DM_ETH +static int smsc95xx_eth_start(struct udevice *dev) +{ + struct usb_device *udev = dev_get_parentdata(dev); + struct smsc95xx_private *priv = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_platdata(dev); + + /* Driver-model Ethernet ensures we have this */ + priv->have_hwaddr = 1; + + return smsc95xx_init_common(udev, &priv->ueth, priv, pdata->enetaddr); +} + +void smsc95xx_eth_stop(struct udevice *dev) +{ + debug("** %s()\n", __func__); +} + +int smsc95xx_eth_send(struct udevice *dev, void *packet, int length) +{ + struct smsc95xx_private *priv = dev_get_priv(dev); + + return smsc95xx_send_common(&priv->ueth, packet, length); +} + +int smsc95xx_eth_recv(struct udevice *dev, int flags, uchar **packetp) +{ + struct smsc95xx_private *priv = dev_get_priv(dev); + struct ueth_data *ueth = &priv->ueth; + uint8_t *ptr; + int ret, len; + u32 packet_len; + + len = usb_ether_get_rx_bytes(ueth, &ptr); + debug("%s: first try, len=%d\n", __func__, len); + if (!len) { + if (!(flags & ETH_RECV_CHECK_DEVICE)) + return -EAGAIN; + ret = usb_ether_receive(ueth, RX_URB_SIZE); + if (ret == -EAGAIN) + return ret; + + len = usb_ether_get_rx_bytes(ueth, &ptr); + debug("%s: second try, len=%d\n", __func__, len); + } + + /* + * 1st 4 bytes contain the length of the actual data plus error info. + * Extract data length. + */ + if (len < sizeof(packet_len)) { + debug("Rx: incomplete packet length\n"); + goto err; + } + memcpy(&packet_len, ptr, sizeof(packet_len)); + le32_to_cpus(&packet_len); + if (packet_len & RX_STS_ES_) { + debug("Rx: Error header=%#x", packet_len); + goto err; + } + packet_len = ((packet_len & RX_STS_FL_) >> 16); + + if (packet_len > len - sizeof(packet_len)) { + debug("Rx: too large packet: %d\n", packet_len); + goto err; + } + + *packetp = ptr + sizeof(packet_len); + return packet_len; + +err: + usb_ether_advance_rxbuf(ueth, -1); + return -EINVAL; +} + +static int smsc95xx_free_pkt(struct udevice *dev, uchar *packet, int packet_len) +{ + struct smsc95xx_private *priv = dev_get_priv(dev); + + packet_len = ALIGN(packet_len, 4); + usb_ether_advance_rxbuf(&priv->ueth, sizeof(u32) + packet_len); + + return 0; +} + +int smsc95xx_write_hwaddr(struct udevice *dev) +{ + struct usb_device *udev = dev_get_parentdata(dev); + struct eth_pdata *pdata = dev_get_platdata(dev); + struct smsc95xx_private *priv = dev_get_priv(dev); + + return smsc95xx_write_hwaddr_common(udev, priv, pdata->enetaddr); +} + +static int smsc95xx_eth_probe(struct udevice *dev) +{ + struct smsc95xx_private *priv = dev_get_priv(dev); + struct ueth_data *ueth = &priv->ueth; + + return usb_ether_register(dev, ueth, RX_URB_SIZE); +} + +static const struct eth_ops smsc95xx_eth_ops = { + .start = smsc95xx_eth_start, + .send = smsc95xx_eth_send, + .recv = smsc95xx_eth_recv, + .free_pkt = smsc95xx_free_pkt, + .stop = smsc95xx_eth_stop, + .write_hwaddr = smsc95xx_write_hwaddr, +}; + +U_BOOT_DRIVER(smsc95xx_eth) = { + .name = "smsc95xx_eth", + .id = UCLASS_ETH, + .probe = smsc95xx_eth_probe, + .ops = &smsc95xx_eth_ops, + .priv_auto_alloc_size = sizeof(struct smsc95xx_private), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +}; + +static const struct usb_device_id smsc95xx_eth_id_table[] = { + { USB_DEVICE(0x05ac, 0x1402) }, + { USB_DEVICE(0x0424, 0xec00) }, /* LAN9512/LAN9514 Ethernet */ + { USB_DEVICE(0x0424, 0x9500) }, /* LAN9500 Ethernet */ + { USB_DEVICE(0x0424, 0x9730) }, /* LAN9730 Ethernet (HSIC) */ + { USB_DEVICE(0x0424, 0x9900) }, /* SMSC9500 USB Ethernet (SAL10) */ + { USB_DEVICE(0x0424, 0x9e00) }, /* LAN9500A Ethernet */ + { } /* Terminating entry */ +}; + +U_BOOT_USB_DEVICE(smsc95xx_eth, smsc95xx_eth_id_table); +#endif

On 7 July 2015 at 20:53, Simon Glass sjg@chromium.org wrote:
Add support for driver model, so that CONFIG_DM_ETH can be defined and used with this driver.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/usb/eth/smsc95xx.c | 142 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+)
Applied to u-boot-dm.

This binding differs from that of Linux. Update it and change existing users.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/arm/dts/stv0991.dts | 2 +- doc/device-tree-bindings/serial/pl011.txt | 53 +++++++++++++++++++++++++++++++ doc/device-tree-bindings/serial/pl01x.txt | 7 ---- drivers/serial/serial_pl01x.c | 6 ++-- 4 files changed, 58 insertions(+), 10 deletions(-) create mode 100644 doc/device-tree-bindings/serial/pl011.txt delete mode 100644 doc/device-tree-bindings/serial/pl01x.txt
diff --git a/arch/arm/dts/stv0991.dts b/arch/arm/dts/stv0991.dts index b25c48b..fd425b4 100644 --- a/arch/arm/dts/stv0991.dts +++ b/arch/arm/dts/stv0991.dts @@ -18,6 +18,6 @@ uart0: serial@0x80406000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x80406000 0x1000>; - clock = <2700000>; + clock-frequency = <2700000>; }; }; diff --git a/doc/device-tree-bindings/serial/pl011.txt b/doc/device-tree-bindings/serial/pl011.txt new file mode 100644 index 0000000..af66272 --- /dev/null +++ b/doc/device-tree-bindings/serial/pl011.txt @@ -0,0 +1,53 @@ +* ARM AMBA Primecell PL011 serial UART + +Required properties: +- compatible: must be "arm,primecell", "arm,pl011" +- reg: exactly one register range with length 0x1000 +- interrupts: exactly one interrupt specifier + +Optional properties: +- pinctrl: + When present, must have one state named "default", + and may contain a second name named "sleep". The former + state sets up pins for ordinary operation whereas + the latter state will put the associated pins to sleep + when the UART is unused +- clocks: + When present, the first clock listed must correspond to + the clock named UARTCLK on the IP block, i.e. the clock + to the external serial line, whereas the second clock + must correspond to the PCLK clocking the internal logic + of the block. Just listing one clock (the first one) is + deprecated. +- clocks-names: + When present, the first clock listed must be named + "uartclk" and the second clock listed must be named + "apb_pclk" +- dmas: + When present, may have one or two dma channels. + The first one must be named "rx", the second one + must be named "tx". +- auto-poll: + Enables polling when using RX DMA. +- poll-rate-ms: + Rate at which poll occurs when auto-poll is set, + default 100ms. +- poll-timeout-ms: + Poll timeout when auto-poll is set, default + 3000ms. +- clock-frequency: + Input clock frequency for UART. + +See also bindings/arm/primecell.txt + +Example: + +uart@80120000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x80120000 0x1000>; + interrupts = <0 11 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&dma 13 0 0x2>, <&dma 13 0 0x0>; + dma-names = "rx", "tx"; + clocks = <&foo_clk>, <&bar_clk>; + clock-names = "uartclk", "apb_pclk"; +}; diff --git a/doc/device-tree-bindings/serial/pl01x.txt b/doc/device-tree-bindings/serial/pl01x.txt deleted file mode 100644 index 61c27d1..0000000 --- a/doc/device-tree-bindings/serial/pl01x.txt +++ /dev/null @@ -1,7 +0,0 @@ -* ARM AMBA Primecell PL011 & PL010 serial UART - -Required properties: -- compatible: must be "arm,primecell", "arm,pl011" or "arm,pl010" -- reg: exactly one register range with length 0x1000 -- clock: input clock frequency for the UART (used to calculate the baud - rate divisor) diff --git a/drivers/serial/serial_pl01x.c b/drivers/serial/serial_pl01x.c index ad503af..ae6fc0e 100644 --- a/drivers/serial/serial_pl01x.c +++ b/drivers/serial/serial_pl01x.c @@ -365,13 +365,15 @@ static int pl01x_serial_ofdata_to_platdata(struct udevice *dev) struct pl01x_serial_platdata *plat = dev_get_platdata(dev); fdt_addr_t addr;
- addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg"); + addr = dev_get_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL;
plat->base = addr; - plat->clock = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "clock", 1); + plat->clock = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + "clock-frequency", 1); plat->type = dev_get_driver_data(dev); + return 0; } #endif

Hi Simon,
-----Original Message----- From: Simon Glass [mailto:sjg@google.com] On Behalf Of Simon Glass Sent: Tuesday, July 07, 2015 7:54 PM To: U-Boot Mailing List Cc: Stephen Warren; Stephen Warren; Joe Hershberger; Masahiro Yamada; Simon Glass; Linus Walleij; Masahiro Yamada; Marek Vasut; Tom Rini; Albert Aribaud; Vikas MANOCHA; Pavel Herrmann Subject: [PATCH 11/20] dm: serial: Update binding for PL01x serial UART
This binding differs from that of Linux. Update it and change existing users.
Signed-off-by: Simon Glass sjg@chromium.org
arch/arm/dts/stv0991.dts | 2 +- doc/device-tree-bindings/serial/pl011.txt | 53 +++++++++++++++++++++++++++++++ doc/device-tree- bindings/serial/pl01x.txt | 7 ---- drivers/serial/serial_pl01x.c | 6 ++-- 4 files changed, 58 insertions(+), 10 deletions(-) create mode 100644 doc/device-tree-bindings/serial/pl011.txt delete mode 100644 doc/device-tree-bindings/serial/pl01x.txt
diff --git a/arch/arm/dts/stv0991.dts b/arch/arm/dts/stv0991.dts index b25c48b..fd425b4 100644 --- a/arch/arm/dts/stv0991.dts +++ b/arch/arm/dts/stv0991.dts @@ -18,6 +18,6 @@ uart0: serial@0x80406000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x80406000 0x1000>;
clock = <2700000>;
clock-frequency = <2700000>;
Clock-frequency is not mentioned in the binding doc.
}; }; diff --git a/doc/device-tree-bindings/serial/pl011.txt b/doc/device-tree- bindings/serial/pl011.txt new file mode 100644 index 0000000..af66272 --- /dev/null +++ b/doc/device-tree-bindings/serial/pl011.txt @@ -0,0 +1,53 @@ +* ARM AMBA Primecell PL011 serial UART
+Required properties: +- compatible: must be "arm,primecell", "arm,pl011" +- reg: exactly one register range with length 0x1000 +- interrupts: exactly one interrupt specifier
+Optional properties: +- pinctrl:
When present, must have one state named "default",
and may contain a second name named "sleep". The former
state sets up pins for ordinary operation whereas
the latter state will put the associated pins to sleep
when the UART is unused
+- clocks:
When present, the first clock listed must correspond to
the clock named UARTCLK on the IP block, i.e. the clock
to the external serial line, whereas the second clock
must correspond to the PCLK clocking the internal logic
of the block. Just listing one clock (the first one) is
deprecated.
+- clocks-names:
When present, the first clock listed must be named
"uartclk" and the second clock listed must be named
"apb_pclk"
+- dmas:
When present, may have one or two dma channels.
The first one must be named "rx", the second one
must be named "tx".
+- auto-poll:
Enables polling when using RX DMA.
+- poll-rate-ms:
Rate at which poll occurs when auto-poll is set,
default 100ms.
+- poll-timeout-ms:
Poll timeout when auto-poll is set, default
3000ms.
+- clock-frequency:
Input clock frequency for UART.
+See also bindings/arm/primecell.txt
+Example:
+uart@80120000 {
- compatible = "arm,pl011", "arm,primecell";
- reg = <0x80120000 0x1000>;
- interrupts = <0 11 IRQ_TYPE_LEVEL_HIGH>;
- dmas = <&dma 13 0 0x2>, <&dma 13 0 0x0>;
- dma-names = "rx", "tx";
- clocks = <&foo_clk>, <&bar_clk>;
- clock-names = "uartclk", "apb_pclk";
+};
PL011 ip is covered in pl01x & we have pl01x driver in u-boot. Linux has only pl011 driver. So binding documents for pl011 in u-boot does not make sense...
diff --git a/doc/device-tree-bindings/serial/pl01x.txt b/doc/device-tree- bindings/serial/pl01x.txt deleted file mode 100644 index 61c27d1..0000000 --- a/doc/device-tree-bindings/serial/pl01x.txt +++ /dev/null @@ -1,7 +0,0 @@ -* ARM AMBA Primecell PL011 & PL010 serial UART
-Required properties: -- compatible: must be "arm,primecell", "arm,pl011" or "arm,pl010" -- reg: exactly one register range with length 0x1000 -- clock: input clock frequency for the UART (used to calculate the baud
- rate divisor)
Removing pl01x.txt.. .you might want to remove it & add kernel pl011.txt binding doc which should be renamed to pl01x.txt in u-boot ? In that case, clock(or clock-frequency) is not optional in u-boot.
Rgds, Vikas
diff --git a/drivers/serial/serial_pl01x.c b/drivers/serial/serial_pl01x.c index ad503af..ae6fc0e 100644 --- a/drivers/serial/serial_pl01x.c +++ b/drivers/serial/serial_pl01x.c @@ -365,13 +365,15 @@ static int pl01x_serial_ofdata_to_platdata(struct udevice *dev) struct pl01x_serial_platdata *plat = dev_get_platdata(dev); fdt_addr_t addr;
- addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
addr = dev_get_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL;
plat->base = addr;
- plat->clock = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "clock",
1);
- plat->clock = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
plat->type = dev_get_driver_data(dev);"clock-frequency", 1);
- return 0;
}
#endif
2.4.3.573.g4eafbef

On Wed, Jul 8, 2015 at 4:53 AM, Simon Glass sjg@chromium.org wrote:
This binding differs from that of Linux. Update it and change existing users.
Signed-off-by: Simon Glass sjg@chromium.org
I'm confused by this. Isn't devicetree@vger.kernel.org the place to discuss device tree bindings? This is sent only to the U-Boot list, does this mean that there will now be *two* ontologies for DT bindings? That sounds like a recepie for ... something not good.
+- clock-frequency:
Input clock frequency for UART.
This is the real trick is it not?
Is the real commit blurb for this patch something like:
"we want a simple way to look up the clock frequency for our serial ports during early boot, and following clocks = <&...> phandles is too much trouble and might imply having to implement a whole clock framework in U-Boot so we just see a lot of trouble, instead provide a default frequency here"
I suggest in that case, instead do this:
- boot-frequency: input clock frequency at boot time, to be used by boot loaders and other early access.
This would be good for early Linux stuff as well I believe and I do not think it's very controversial.
Yours, Linus Walleij

On Wednesday 15 July 2015 11:00:59 Linus Walleij wrote:
On Wed, Jul 8, 2015 at 4:53 AM, Simon Glass sjg@chromium.org wrote:
This binding differs from that of Linux. Update it and change existing users.
Signed-off-by: Simon Glass sjg@chromium.org
I'm confused by this. Isn't devicetree@vger.kernel.org the place to discuss device tree bindings? This is sent only to the U-Boot list, does this mean that there will now be *two* ontologies for DT bindings? That sounds like a recepie for ... something not good.
+- clock-frequency:
Input clock frequency for UART.
This is the real trick is it not?
Is the real commit blurb for this patch something like:
"we want a simple way to look up the clock frequency for our serial ports during early boot, and following clocks = <&...> phandles is too much trouble and might imply having to implement a whole clock framework in U-Boot so we just see a lot of trouble, instead provide a default frequency here"
I suggest in that case, instead do this:
- boot-frequency: input clock frequency at boot time, to be used by boot loaders and other early access.
This would be good for early Linux stuff as well I believe and I do not think it's very controversial.
The CHRP ISA binding defines that a 8250 compatible UART must have this property:
"clock-frequency" S
Standard property, encoded as with encode-int, that shall be the baud-rate generator's clock input frequency (in hertz). Typically, the clock frequency is nominally 1,843,200 Hz. Some devices generate the baud rate input clock by dividing a higher-frequency clock source that is not an exact multiple of 1,843,200 Hz, resulting in a small but acceptable error in the nominal clock frequency. In such cases, the "clock-frequency" shall report the actual nominal frequency. For example, if the baud rate input clock is generated by dividing a 24 MHz clock by 13, the value of the "clock-frequency" property shall be 1846153. Arnd

On Wed, Jul 15, 2015 at 11:38 AM, Arnd Bergmann arnd@arndb.de wrote:
The CHRP ISA binding defines that a 8250 compatible UART must have this property:
"clock-frequency" S
Standard property, encoded as with encode-int, that shall be the baud-rate generator's clock input frequency (in hertz). Typically, the clock frequency is nominally 1,843,200 Hz. Some devices generate the baud rate input clock by dividing a higher-frequency clock source that is not an exact multiple of 1,843,200 Hz, resulting in a small but acceptable error in the nominal clock frequency. In such cases, the "clock-frequency" shall report the actual nominal frequency. For example, if the baud rate input clock is generated by dividing a 24 MHz clock by 13, the value of the "clock-frequency" property shall be 1846153.
Isn't that for the case where the clock frequency will never change at runtime?
The problem (I think) with many systems using PL011 is that they can actually change the serial port clock at runtime (software controlled clock), so providing a "clock-frequency" would imply that they cannot, and the clock frequency is fixed to that value.
I think it's better to use boot-clock-frequency or so to indicate that a richer OS will provide more refined clocks. For example that frequency can typically change if the SoC changes operating point or so, though it would be awkward to handle in the driver, admittedly and I haven't seen a piece of code that actually go and change the UART input frequency.
Still for completion it is better for the UART to tie into the clk framework as the OS gets up, and just providing clock-frequency seems to imply that it need not do that or something. The semantical effect of providing both clock-frequency = and clocks =< &..> must be clarified in any case. Like the latter overrides the former if clock phandles can be handled by the environment. (And this should be stated in the binding.)
Yours, Linus Walleij

On Wednesday 15 July 2015 12:08:05 Linus Walleij wrote:
On Wed, Jul 15, 2015 at 11:38 AM, Arnd Bergmann arnd@arndb.de wrote:
The CHRP ISA binding defines that a 8250 compatible UART must have this property:
"clock-frequency" S
Standard property, encoded as with encode-int, that shall be the baud-rate generator's clock input frequency (in hertz). Typically, the clock frequency is nominally 1,843,200 Hz. Some devices generate the baud rate input clock by dividing a higher-frequency clock source that is not an exact multiple of 1,843,200 Hz, resulting in a small but acceptable error in the nominal clock frequency. In such cases, the "clock-frequency" shall report the actual nominal frequency. For example, if the baud rate input clock is generated by dividing a 24 MHz clock by 13, the value of the "clock-frequency" property shall be 1846153.
Isn't that for the case where the clock frequency will never change at runtime?
The problem (I think) with many systems using PL011 is that they can actually change the serial port clock at runtime (software controlled clock), so providing a "clock-frequency" would imply that they cannot, and the clock frequency is fixed to that value.
I think it's better to use boot-clock-frequency or so to indicate that a richer OS will provide more refined clocks. For example that frequency can typically change if the SoC changes operating point or so, though it would be awkward to handle in the driver, admittedly and I haven't seen a piece of code that actually go and change the UART input frequency.
Still for completion it is better for the UART to tie into the clk framework as the OS gets up, and just providing clock-frequency seems to imply that it need not do that or something. The semantical effect of providing both clock-frequency = and clocks =< &..> must be clarified in any case. Like the latter overrides the former if clock phandles can be handled by the environment. (And this should be stated in the binding.)
Ah right. I don't think that naming is super critical though, as a lot of properties in the DT just describe how things are at boot time.
Arnd

Hi Arnd,
On Wed, Jul 15, 2015 at 12:17 PM, Arnd Bergmann arnd@arndb.de wrote:
On Wednesday 15 July 2015 12:08:05 Linus Walleij wrote:
On Wed, Jul 15, 2015 at 11:38 AM, Arnd Bergmann arnd@arndb.de wrote:
The CHRP ISA binding defines that a 8250 compatible UART must have this property:
"clock-frequency" S
Standard property, encoded as with encode-int, that shall be the baud-rate generator's clock input frequency (in hertz). Typically, the clock frequency is nominally 1,843,200 Hz. Some devices generate the baud rate input clock by dividing a higher-frequency clock source that is not an exact multiple of 1,843,200 Hz, resulting in a small but acceptable error in the nominal clock frequency. In such cases, the "clock-frequency" shall report the actual nominal frequency. For example, if the baud rate input clock is generated by dividing a 24 MHz clock by 13, the value of the "clock-frequency" property shall be 1846153.
Isn't that for the case where the clock frequency will never change at runtime?
The problem (I think) with many systems using PL011 is that they can actually change the serial port clock at runtime (software controlled clock), so providing a "clock-frequency" would imply that they cannot, and the clock frequency is fixed to that value.
I think it's better to use boot-clock-frequency or so to indicate that a richer OS will provide more refined clocks. For example that frequency can typically change if the SoC changes operating point or so, though it would be awkward to handle in the driver, admittedly and I haven't seen a piece of code that actually go and change the UART input frequency.
Still for completion it is better for the UART to tie into the clk framework as the OS gets up, and just providing clock-frequency seems to imply that it need not do that or something. The semantical effect of providing both clock-frequency = and clocks =< &..> must be clarified in any case. Like the latter overrides the former if clock phandles can be handled by the environment. (And this should be stated in the binding.)
Ah right. I don't think that naming is super critical though, as a lot of properties in the DT just describe how things are at boot time.
Hence those don't describe the hardware... Shouldn't they be in /chosen instead?
Gr{oetje,eeting}s,
Geert
-- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds

On Thu, Jul 16, 2015 at 9:41 AM, Geert Uytterhoeven geert@linux-m68k.org wrote:
Ah right. I don't think that naming is super critical though, as a lot of properties in the DT just describe how things are at boot time.
Hence those don't describe the hardware... Shouldn't they be in /chosen instead?
/chosen is used for system-wide things mostly, as alias.
I think this can go in the hardware node.
Simon can you please make a patch to Documentation/devicetree/bindings/serial/pl011.txt in the kernel and post to devicetree@vger.kernel.org *and* linux-doc@vger.kernel.org and Jonathan Corbet corbet@lwn.net so he can merge it if we get some ACKs on it.
Yours, Linus Walleij

The 'ranges' property can be used to specify a translation from the system address to the bus address. Add support for this using the dev_get_addr() function, which devices should use to find their address.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/core/device.c | 17 +++++++++++------ drivers/core/simple-bus.c | 30 ++++++++++++++++++++++++++++++ include/dm/device-internal.h | 12 ++++++++++++ 3 files changed, 53 insertions(+), 6 deletions(-)
diff --git a/drivers/core/device.c b/drivers/core/device.c index eebb53c..d875e8c 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -528,17 +528,22 @@ const char *dev_get_uclass_name(struct udevice *dev) return dev->uclass->uc_drv->name; }
-#ifdef CONFIG_OF_CONTROL fdt_addr_t dev_get_addr(struct udevice *dev) { - return fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg"); -} +#ifdef CONFIG_OF_CONTROL + fdt_addr_t addr; + + addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg"); + if (addr != FDT_ADDR_T_NONE) { + if (device_get_uclass_id(dev->parent) == UCLASS_SIMPLE_BUS) + addr = simple_bus_translate(dev->parent, addr); + } + + return addr; #else -fdt_addr_t dev_get_addr(struct udevice *dev) -{ return FDT_ADDR_T_NONE; -} #endif +}
bool device_has_children(struct udevice *dev) { diff --git a/drivers/core/simple-bus.c b/drivers/core/simple-bus.c index 3ea4d82..913c3cc 100644 --- a/drivers/core/simple-bus.c +++ b/drivers/core/simple-bus.c @@ -10,8 +10,37 @@
DECLARE_GLOBAL_DATA_PTR;
+struct simple_bus_plat { + u32 base; + u32 size; + u32 target; +}; + +fdt_addr_t simple_bus_translate(struct udevice *dev, fdt_addr_t addr) +{ + struct simple_bus_plat *plat = dev_get_uclass_platdata(dev); + + if (addr >= plat->base && addr < plat->base + plat->size) + addr = (addr - plat->base) + plat->target; + + return addr; +} + static int simple_bus_post_bind(struct udevice *dev) { + u32 cell[3]; + int ret; + + ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, "ranges", + cell, ARRAY_SIZE(cell)); + if (!ret) { + struct simple_bus_plat *plat = dev_get_uclass_platdata(dev); + + plat->base = cell[0]; + plat->target = cell[1]; + plat->size = cell[2]; + } + return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false); }
@@ -19,6 +48,7 @@ UCLASS_DRIVER(simple_bus) = { .id = UCLASS_SIMPLE_BUS, .name = "simple_bus", .post_bind = simple_bus_post_bind, + .per_device_platdata_auto_alloc_size = sizeof(struct simple_bus_plat), };
static const struct udevice_id generic_simple_bus_ids[] = { diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h index 687462b..ab1a323 100644 --- a/include/dm/device-internal.h +++ b/include/dm/device-internal.h @@ -113,6 +113,18 @@ void device_free(struct udevice *dev); static inline void device_free(struct udevice *dev) {} #endif
+/** + * simple_bus_translate() - translate a bus address to a system address + * + * This handles the 'ranges' property in a simple bus. It translates the + * device address @addr to a system address using this property. + * + * @dev: Simple bus device (parent of target device) + * @addr: Address to translate + * @return new address + */ +fdt_addr_t simple_bus_translate(struct udevice *dev, fdt_addr_t addr); + /* Cast away any volatile pointer */ #define DM_ROOT_NON_CONST (((gd_t *)gd)->dm_root) #define DM_UCLASS_ROOT_NON_CONST (((gd_t *)gd)->uclass_root)

On 7 July 2015 at 20:53, Simon Glass sjg@chromium.org wrote:
The 'ranges' property can be used to specify a translation from the system address to the bus address. Add support for this using the dev_get_addr() function, which devices should use to find their address.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/core/device.c | 17 +++++++++++------ drivers/core/simple-bus.c | 30 ++++++++++++++++++++++++++++++ include/dm/device-internal.h | 12 ++++++++++++ 3 files changed, 53 insertions(+), 6 deletions(-)
Applied to u-boot-dm.

This shows a proper progress display and the total amount of data transferred. Enable it for Raspberry Pi.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/configs/rpi-common.h | 1 + 1 file changed, 1 insertion(+)
diff --git a/include/configs/rpi-common.h b/include/configs/rpi-common.h index b54cf8b..bfbd32b 100644 --- a/include/configs/rpi-common.h +++ b/include/configs/rpi-common.h @@ -89,6 +89,7 @@ #define CONFIG_USB_STORAGE #define CONFIG_USB_HOST_ETHER #define CONFIG_USB_ETHER_SMSC95XX +#define CONFIG_TFTP_TSIZE #define CONFIG_MISC_INIT_R #endif

Bring in the device tree files from Linux v4.1.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/arm/dts/Makefile | 2 + arch/arm/dts/bcm2835-rpi-b.dts | 23 ++++ arch/arm/dts/bcm2835-rpi.dtsi | 51 +++++++++ arch/arm/dts/bcm2835.dtsi | 192 ++++++++++++++++++++++++++++++++++ include/dt-bindings/pinctrl/bcm2835.h | 27 +++++ 5 files changed, 295 insertions(+) create mode 100644 arch/arm/dts/bcm2835-rpi-b.dts create mode 100644 arch/arm/dts/bcm2835-rpi.dtsi create mode 100644 arch/arm/dts/bcm2835.dtsi create mode 100644 include/dt-bindings/pinctrl/bcm2835.h
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index 9c735c6..b284a2d 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -49,6 +49,8 @@ dtb-$(CONFIG_ARCH_ZYNQ) += zynq-zc702.dtb \ zynq-zc770-xm013.dtb dtb-$(CONFIG_AM33XX) += am335x-boneblack.dtb
+dtb-$(CONFIG_ARCH_BCM283X) += bcm2835-rpi-b.dtb + dtb-$(CONFIG_ARCH_SOCFPGA) += \ socfpga_arria5_socdk.dtb \ socfpga_cyclone5_socdk.dtb \ diff --git a/arch/arm/dts/bcm2835-rpi-b.dts b/arch/arm/dts/bcm2835-rpi-b.dts new file mode 100644 index 0000000..ee89b79 --- /dev/null +++ b/arch/arm/dts/bcm2835-rpi-b.dts @@ -0,0 +1,23 @@ +/dts-v1/; +#include "bcm2835-rpi.dtsi" + +/ { + compatible = "raspberrypi,model-b", "brcm,bcm2835"; + model = "Raspberry Pi Model B"; + + leds { + act { + gpios = <&gpio 16 1>; + }; + }; +}; + +&gpio { + pinctrl-0 = <&gpioout &alt0 &i2s_alt2 &alt3>; + + /* I2S interface */ + i2s_alt2: i2s_alt2 { + brcm,pins = <28 29 30 31>; + brcm,function = <BCM2835_FSEL_ALT2>; + }; +}; diff --git a/arch/arm/dts/bcm2835-rpi.dtsi b/arch/arm/dts/bcm2835-rpi.dtsi new file mode 100644 index 0000000..46780bb --- /dev/null +++ b/arch/arm/dts/bcm2835-rpi.dtsi @@ -0,0 +1,51 @@ +#include "bcm2835.dtsi" + +/ { + memory { + reg = <0 0x10000000>; + }; + + leds { + compatible = "gpio-leds"; + + act { + label = "ACT"; + default-state = "keep"; + linux,default-trigger = "heartbeat"; + }; + }; +}; + +&gpio { + pinctrl-names = "default"; + + gpioout: gpioout { + brcm,pins = <6>; + brcm,function = <BCM2835_FSEL_GPIO_OUT>; + }; + + alt0: alt0 { + brcm,pins = <0 1 2 3 4 5 7 8 9 10 11 14 15 40 45>; + brcm,function = <BCM2835_FSEL_ALT0>; + }; + + alt3: alt3 { + brcm,pins = <48 49 50 51 52 53>; + brcm,function = <BCM2835_FSEL_ALT3>; + }; +}; + +&i2c0 { + status = "okay"; + clock-frequency = <100000>; +}; + +&i2c1 { + status = "okay"; + clock-frequency = <100000>; +}; + +&sdhci { + status = "okay"; + bus-width = <4>; +}; diff --git a/arch/arm/dts/bcm2835.dtsi b/arch/arm/dts/bcm2835.dtsi new file mode 100644 index 0000000..301c73f --- /dev/null +++ b/arch/arm/dts/bcm2835.dtsi @@ -0,0 +1,192 @@ +#include <dt-bindings/pinctrl/bcm2835.h> +#include "skeleton.dtsi" + +/ { + compatible = "brcm,bcm2835"; + model = "BCM2835"; + interrupt-parent = <&intc>; + + chosen { + bootargs = "earlyprintk console=ttyAMA0"; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x7e000000 0x20000000 0x02000000>; + dma-ranges = <0x40000000 0x00000000 0x20000000>; + + timer@7e003000 { + compatible = "brcm,bcm2835-system-timer"; + reg = <0x7e003000 0x1000>; + interrupts = <1 0>, <1 1>, <1 2>, <1 3>; + clock-frequency = <1000000>; + }; + + dma: dma@7e007000 { + compatible = "brcm,bcm2835-dma"; + reg = <0x7e007000 0xf00>; + interrupts = <1 16>, + <1 17>, + <1 18>, + <1 19>, + <1 20>, + <1 21>, + <1 22>, + <1 23>, + <1 24>, + <1 25>, + <1 26>, + <1 27>, + <1 28>; + + #dma-cells = <1>; + brcm,dma-channel-mask = <0x7f35>; + }; + + intc: interrupt-controller@7e00b200 { + compatible = "brcm,bcm2835-armctrl-ic"; + reg = <0x7e00b200 0x200>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + watchdog@7e100000 { + compatible = "brcm,bcm2835-pm-wdt"; + reg = <0x7e100000 0x28>; + }; + + rng@7e104000 { + compatible = "brcm,bcm2835-rng"; + reg = <0x7e104000 0x10>; + }; + + mailbox: mailbox@7e00b800 { + compatible = "brcm,bcm2835-mbox"; + reg = <0x7e00b880 0x40>; + interrupts = <0 1>; + #mbox-cells = <0>; + }; + + gpio: gpio@7e200000 { + compatible = "brcm,bcm2835-gpio"; + reg = <0x7e200000 0xb4>; + /* + * The GPIO IP block is designed for 3 banks of GPIOs. + * Each bank has a GPIO interrupt for itself. + * There is an overall "any bank" interrupt. + * In order, these are GIC interrupts 17, 18, 19, 20. + * Since the BCM2835 only has 2 banks, the 2nd bank + * interrupt output appears to be mirrored onto the + * 3rd bank's interrupt signal. + * So, a bank0 interrupt shows up on 17, 20, and + * a bank1 interrupt shows up on 18, 19, 20! + */ + interrupts = <2 17>, <2 18>, <2 19>, <2 20>; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + uart@7e201000 { + compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell"; + reg = <0x7e201000 0x1000>; + interrupts = <2 25>; + clock-frequency = <3000000>; + arm,primecell-periphid = <0x00241011>; + }; + + i2s: i2s@7e203000 { + compatible = "brcm,bcm2835-i2s"; + reg = <0x7e203000 0x20>, + <0x7e101098 0x02>; + + dmas = <&dma 2>, + <&dma 3>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + spi: spi@7e204000 { + compatible = "brcm,bcm2835-spi"; + reg = <0x7e204000 0x1000>; + interrupts = <2 22>; + clocks = <&clk_spi>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c0: i2c@7e205000 { + compatible = "brcm,bcm2835-i2c"; + reg = <0x7e205000 0x1000>; + interrupts = <2 21>; + clocks = <&clk_i2c>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + sdhci: sdhci@7e300000 { + compatible = "brcm,bcm2835-sdhci"; + reg = <0x7e300000 0x100>; + interrupts = <2 30>; + clocks = <&clk_mmc>; + status = "disabled"; + }; + + i2c1: i2c@7e804000 { + compatible = "brcm,bcm2835-i2c"; + reg = <0x7e804000 0x1000>; + interrupts = <2 21>; + clocks = <&clk_i2c>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + usb@7e980000 { + compatible = "brcm,bcm2835-usb"; + reg = <0x7e980000 0x10000>; + interrupts = <1 9>; + }; + + arm-pmu { + compatible = "arm,arm1176-pmu"; + }; + }; + + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + clk_mmc: clock@0 { + compatible = "fixed-clock"; + reg = <0>; + #clock-cells = <0>; + clock-output-names = "mmc"; + clock-frequency = <100000000>; + }; + + clk_i2c: clock@1 { + compatible = "fixed-clock"; + reg = <1>; + #clock-cells = <0>; + clock-output-names = "i2c"; + clock-frequency = <250000000>; + }; + + clk_spi: clock@2 { + compatible = "fixed-clock"; + reg = <2>; + #clock-cells = <0>; + clock-output-names = "spi"; + clock-frequency = <250000000>; + }; + }; +}; diff --git a/include/dt-bindings/pinctrl/bcm2835.h b/include/dt-bindings/pinctrl/bcm2835.h new file mode 100644 index 0000000..6f0bc37 --- /dev/null +++ b/include/dt-bindings/pinctrl/bcm2835.h @@ -0,0 +1,27 @@ +/* + * Header providing constants for bcm2835 pinctrl bindings. + * + * Copyright (C) 2015 Stefan Wahren stefan.wahren@i2se.com + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#ifndef __DT_BINDINGS_PINCTRL_BCM2835_H__ +#define __DT_BINDINGS_PINCTRL_BCM2835_H__ + +/* brcm,function property */ +#define BCM2835_FSEL_GPIO_IN 0 +#define BCM2835_FSEL_GPIO_OUT 1 +#define BCM2835_FSEL_ALT5 2 +#define BCM2835_FSEL_ALT4 3 +#define BCM2835_FSEL_ALT0 4 +#define BCM2835_FSEL_ALT1 5 +#define BCM2835_FSEL_ALT2 6 +#define BCM2835_FSEL_ALT3 7 + +#endif /* __DT_BINDINGS_PINCTRL_BCM2835_H__ */

This updates the device tree from the kernel version to something suitable for U-Boot:
- Add stdout-path alias for console - Mark the /soc node to be available pre-relocation so that the early serial console works (we need the 'ranges' property to be available)
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/arm/dts/bcm2835.dtsi | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/arch/arm/dts/bcm2835.dtsi b/arch/arm/dts/bcm2835.dtsi index 301c73f..bd6bff6 100644 --- a/arch/arm/dts/bcm2835.dtsi +++ b/arch/arm/dts/bcm2835.dtsi @@ -8,6 +8,7 @@
chosen { bootargs = "earlyprintk console=ttyAMA0"; + stdout-path = &uart; };
soc { @@ -16,6 +17,7 @@ #size-cells = <1>; ranges = <0x7e000000 0x20000000 0x02000000>; dma-ranges = <0x40000000 0x00000000 0x20000000>; + u-boot,dm-pre-reloc;
timer@7e003000 { compatible = "brcm,bcm2835-system-timer"; @@ -92,7 +94,7 @@ #interrupt-cells = <2>; };
- uart@7e201000 { + uart: uart@7e201000 { compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell"; reg = <0x7e201000 0x1000>; interrupts = <2 25>;

Enable device tree control so that we can use driver model fully and avoid using platform data.
Signed-off-by: Simon Glass sjg@chromium.org ---
configs/rpi_defconfig | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/configs/rpi_defconfig b/configs/rpi_defconfig index fc1aef3..94e298b 100644 --- a/configs/rpi_defconfig +++ b/configs/rpi_defconfig @@ -2,3 +2,5 @@ CONFIG_ARM=y CONFIG_ARCH_BCM283X=y CONFIG_TARGET_RPI=y CONFIG_CMD_NET=y +CONFIG_OF_CONTROL=y +CONFIG_DEFAULT_DEVICE_TREE="bcm2835-rpi-b"

We can rely on the device tree to provide the UART information.
Signed-off-by: Simon Glass sjg@chromium.org ---
board/raspberrypi/rpi/rpi.c | 15 --------------- 1 file changed, 15 deletions(-)
diff --git a/board/raspberrypi/rpi/rpi.c b/board/raspberrypi/rpi/rpi.c index 96fe870..7de1921 100644 --- a/board/raspberrypi/rpi/rpi.c +++ b/board/raspberrypi/rpi/rpi.c @@ -28,21 +28,6 @@ U_BOOT_DEVICE(bcm2835_gpios) = { .platdata = &gpio_platdata, };
-static const struct pl01x_serial_platdata serial_platdata = { -#ifdef CONFIG_BCM2836 - .base = 0x3f201000, -#else - .base = 0x20201000, -#endif - .type = TYPE_PL011, - .clock = 3000000, -}; - -U_BOOT_DEVICE(bcm2835_serials) = { - .name = "serial_pl01x", - .platdata = &serial_platdata, -}; - struct msg_get_arm_mem { struct bcm2835_mbox_hdr hdr; struct bcm2835_mbox_tag_get_arm_mem get_arm_mem;

We can rely on the device tree to provide the GPIO information.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/arm/mach-bcm283x/include/mach/gpio.h | 2 -- board/raspberrypi/rpi/rpi.c | 9 --------- drivers/gpio/bcm2835_gpio.c | 20 ++++++++++++++++++++ include/configs/rpi-common.h | 2 -- 4 files changed, 20 insertions(+), 13 deletions(-)
diff --git a/arch/arm/mach-bcm283x/include/mach/gpio.h b/arch/arm/mach-bcm283x/include/mach/gpio.h index c8ef8f5..b020ead 100644 --- a/arch/arm/mach-bcm283x/include/mach/gpio.h +++ b/arch/arm/mach-bcm283x/include/mach/gpio.h @@ -11,8 +11,6 @@
#ifdef CONFIG_BCM2836 #define BCM2835_GPIO_BASE 0x3f200000 -#else -#define BCM2835_GPIO_BASE 0x20200000 #endif #define BCM2835_GPIO_COUNT 54
diff --git a/board/raspberrypi/rpi/rpi.c b/board/raspberrypi/rpi/rpi.c index 7de1921..39f451f 100644 --- a/board/raspberrypi/rpi/rpi.c +++ b/board/raspberrypi/rpi/rpi.c @@ -19,15 +19,6 @@
DECLARE_GLOBAL_DATA_PTR;
-static const struct bcm2835_gpio_platdata gpio_platdata = { - .base = BCM2835_GPIO_BASE, -}; - -U_BOOT_DEVICE(bcm2835_gpios) = { - .name = "gpio_bcm2835", - .platdata = &gpio_platdata, -}; - struct msg_get_arm_mem { struct bcm2835_mbox_hdr hdr; struct bcm2835_mbox_tag_get_arm_mem get_arm_mem; diff --git a/drivers/gpio/bcm2835_gpio.c b/drivers/gpio/bcm2835_gpio.c index fbc641d..f571b0b 100644 --- a/drivers/gpio/bcm2835_gpio.c +++ b/drivers/gpio/bcm2835_gpio.c @@ -114,9 +114,29 @@ static int bcm2835_gpio_probe(struct udevice *dev) return 0; }
+#ifdef CONFIG_OF_CONTROL +static int bcm2835_gpio_ofdata_to_platdata(struct udevice *dev) +{ + struct bcm2835_gpio_platdata *plat = dev_get_platdata(dev); + + plat->base = dev_get_addr(dev); + if (plat->base == FDT_ADDR_T_NONE) + return -EINVAL; + + return 0; +} + +static const struct udevice_id bcm2835_gpio_id[] = { + {.compatible = "brcm,bcm2835-gpio"}, + {} +}; +#endif + U_BOOT_DRIVER(gpio_bcm2835) = { .name = "gpio_bcm2835", .id = UCLASS_GPIO, + .of_match = of_match_ptr(bcm2835_gpio_id), + .ofdata_to_platdata = of_match_ptr(bcm2835_gpio_ofdata_to_platdata), .ops = &gpio_bcm2835_ops, .probe = bcm2835_gpio_probe, .priv_auto_alloc_size = sizeof(struct bcm2835_gpios), diff --git a/include/configs/rpi-common.h b/include/configs/rpi-common.h index bfbd32b..d015a8e 100644 --- a/include/configs/rpi-common.h +++ b/include/configs/rpi-common.h @@ -83,8 +83,6 @@ #define CONFIG_USB_DWC2 #ifdef CONFIG_BCM2836 #define CONFIG_USB_DWC2_REG_ADDR 0x3f980000 -#else -#define CONFIG_USB_DWC2_REG_ADDR 0x20980000 #endif #define CONFIG_USB_STORAGE #define CONFIG_USB_HOST_ETHER

Start using driver model for USB on the Raspberry Pi. The dwc2 supports this now so this is just a config change.
Signed-off-by: Simon Glass sjg@chromium.org ---
configs/rpi_defconfig | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/configs/rpi_defconfig b/configs/rpi_defconfig index 94e298b..f2e8ab1 100644 --- a/configs/rpi_defconfig +++ b/configs/rpi_defconfig @@ -4,3 +4,5 @@ CONFIG_TARGET_RPI=y CONFIG_CMD_NET=y CONFIG_OF_CONTROL=y CONFIG_DEFAULT_DEVICE_TREE="bcm2835-rpi-b" +CONFIG_USB=y +CONFIG_DM_USB=y

Enable CONFIG_DM_ETH so that driver model is used for the USB Ethernet device.
Signed-off-by: Simon Glass sjg@chromium.org ---
configs/rpi_defconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/configs/rpi_defconfig b/configs/rpi_defconfig index f2e8ab1..df2dcee 100644 --- a/configs/rpi_defconfig +++ b/configs/rpi_defconfig @@ -6,3 +6,4 @@ CONFIG_OF_CONTROL=y CONFIG_DEFAULT_DEVICE_TREE="bcm2835-rpi-b" CONFIG_USB=y CONFIG_DM_USB=y +CONFIG_DM_ETH=y

On 07/07/2015 08:53 PM, Simon Glass wrote:
Raspberry Pi uses a DWC2 USB controller and a SMSC USB Ethernet adaptor. Neither of these currently support driver model.
This series does the following:
- Move Raspberry Pi to use device tree control (u-boot-dtb.bin instead of u-boot.bin)
I'd strongly prefer not to do this. For one thing, it means we'd need different U-Boot builds for each of the different RPi models, and we currently don't need that (or perhaps we require users to create their own u-boot-dtb.bin by choosing the right DTB to append). If it absolutely must be done, please note that there are many more RPi models than there are currently DT files for in the upstream kernel. I keep meaning to add a complete set of DT files to the kernel, but haven't gotten around to it yet. Take a look at board/raspberrypi/rpi/rpi.c:models[] for a likely list of the different DTs we'd need.

Hi Stephen,
On 10 July 2015 at 23:34, Stephen Warren swarren@wwwdotorg.org wrote:
On 07/07/2015 08:53 PM, Simon Glass wrote:
Raspberry Pi uses a DWC2 USB controller and a SMSC USB Ethernet adaptor. Neither of these currently support driver model.
This series does the following:
- Move Raspberry Pi to use device tree control (u-boot-dtb.bin instead of u-boot.bin)
I'd strongly prefer not to do this. For one thing, it means we'd need different U-Boot builds for each of the different RPi models, and we currently don't need that (or perhaps we require users to create their own u-boot-dtb.bin by choosing the right DTB to append). If it
Why does device tree change how things work now? The get_board_rev() function currently deals with this. It doesn't look like rpi_board_rev is used anywhere else.
absolutely must be done, please note that there are many more RPi models than there are currently DT files for in the upstream kernel. I keep meaning to add a complete set of DT files to the kernel, but haven't gotten around to it yet. Take a look at board/raspberrypi/rpi/rpi.c:models[] for a likely list of the different DTs we'd need.
I've only added two - one for Raspberry Pi, and one for Raspberry Pi 2 (patches not sent yet, but at u-boot-dm/rpi-working)
Regards, Simon

On 07/11/2015 08:04 AM, Simon Glass wrote:
Hi Stephen,
On 10 July 2015 at 23:34, Stephen Warren swarren@wwwdotorg.org wrote:
On 07/07/2015 08:53 PM, Simon Glass wrote:
Raspberry Pi uses a DWC2 USB controller and a SMSC USB Ethernet adaptor. Neither of these currently support driver model.
This series does the following:
- Move Raspberry Pi to use device tree control (u-boot-dtb.bin instead of u-boot.bin)
I'd strongly prefer not to do this. For one thing, it means we'd need different U-Boot builds for each of the different RPi models, and we currently don't need that (or perhaps we require users to create their own u-boot-dtb.bin by choosing the right DTB to append). If it
Why does device tree change how things work now? The get_board_rev() function currently deals with this. It doesn't look like rpi_board_rev is used anywhere else.
Without a DT, the code is free to make all the board-rev-specific decisions at run-time without external influence.
With a DT, we either have to:
a) Pick the DT for one particular board and use that everywhere, even if it's incorrect for the actual board in use.
b) Build a different U-Boot + DTB image for each board-rev, and put the correct one on the SD card.
Neither of those options seem like a good idea to me.

Hi Stephen,
On 13 July 2015 at 22:52, Stephen Warren swarren@wwwdotorg.org wrote:
On 07/11/2015 08:04 AM, Simon Glass wrote:
Hi Stephen,
On 10 July 2015 at 23:34, Stephen Warren swarren@wwwdotorg.org wrote:
On 07/07/2015 08:53 PM, Simon Glass wrote:
Raspberry Pi uses a DWC2 USB controller and a SMSC USB Ethernet adaptor. Neither of these currently support driver model.
This series does the following:
- Move Raspberry Pi to use device tree control (u-boot-dtb.bin instead of u-boot.bin)
I'd strongly prefer not to do this. For one thing, it means we'd need different U-Boot builds for each of the different RPi models, and we currently don't need that (or perhaps we require users to create their own u-boot-dtb.bin by choosing the right DTB to append). If it
Why does device tree change how things work now? The get_board_rev() function currently deals with this. It doesn't look like rpi_board_rev is used anywhere else.
Without a DT, the code is free to make all the board-rev-specific decisions at run-time without external influence.
With a DT, we either have to:
a) Pick the DT for one particular board and use that everywhere, even if it's incorrect for the actual board in use.
b) Build a different U-Boot + DTB image for each board-rev, and put the correct one on the SD card.
Neither of those options seem like a good idea to me.
How about:
c) Leave the code as is, and not add a whole lot more device tree files.
After all the kernel only has files for rpi and rpi_2. Why should we add one for each variant? If you don't want to do it, why do it?
Regards, Simon

On 07/14/2015 09:44 AM, Simon Glass wrote:
Hi Stephen,
On 13 July 2015 at 22:52, Stephen Warren swarren@wwwdotorg.org wrote:
On 07/11/2015 08:04 AM, Simon Glass wrote:
Hi Stephen,
On 10 July 2015 at 23:34, Stephen Warren swarren@wwwdotorg.org wrote:
On 07/07/2015 08:53 PM, Simon Glass wrote:
Raspberry Pi uses a DWC2 USB controller and a SMSC USB Ethernet adaptor. Neither of these currently support driver model.
This series does the following:
- Move Raspberry Pi to use device tree control (u-boot-dtb.bin instead of u-boot.bin)
I'd strongly prefer not to do this. For one thing, it means we'd need different U-Boot builds for each of the different RPi models, and we currently don't need that (or perhaps we require users to create their own u-boot-dtb.bin by choosing the right DTB to append). If it
Why does device tree change how things work now? The get_board_rev() function currently deals with this. It doesn't look like rpi_board_rev is used anywhere else.
Without a DT, the code is free to make all the board-rev-specific decisions at run-time without external influence.
With a DT, we either have to:
a) Pick the DT for one particular board and use that everywhere, even if it's incorrect for the actual board in use.
b) Build a different U-Boot + DTB image for each board-rev, and put the correct one on the SD card.
Neither of those options seem like a good idea to me.
How about:
c) Leave the code as is, and not add a whole lot more device tree files.
After all the kernel only has files for rpi and rpi_2. Why should we add one for each variant? If you don't want to do it, why do it?
For the kernel I do expect to add a DT file for each variant. That makes sense since we expect a single kernel binary to run unmodified on all HW, parameterize the HW setup via the DTB, and have an infrastructure to pass the different DTs to the kernel easily.
For U-Boot, I'd like to continue to have a single-binary that runs on all RPis (well, one for RPi 1, another for RPi 2). That's a very nice usage model for users. That's not possible if U-Boot pulls everything from DT and we have a different DT for each system (which only makes sense so that we don't lie in the DT, or fail to represent the differences between the models) since a single DT is embedded into the U-Boot binary; there's no infra-structure to passing 1 of n DTBs to U-Boot.

On Thu, Jul 23, 2015 at 10:17:29PM -0600, Stephen Warren wrote:
On 07/14/2015 09:44 AM, Simon Glass wrote:
Hi Stephen,
On 13 July 2015 at 22:52, Stephen Warren swarren@wwwdotorg.org wrote:
On 07/11/2015 08:04 AM, Simon Glass wrote:
Hi Stephen,
On 10 July 2015 at 23:34, Stephen Warren swarren@wwwdotorg.org wrote:
On 07/07/2015 08:53 PM, Simon Glass wrote:
Raspberry Pi uses a DWC2 USB controller and a SMSC USB Ethernet adaptor. Neither of these currently support driver model.
This series does the following:
- Move Raspberry Pi to use device tree control (u-boot-dtb.bin instead of u-boot.bin)
I'd strongly prefer not to do this. For one thing, it means we'd need different U-Boot builds for each of the different RPi models, and we currently don't need that (or perhaps we require users to create their own u-boot-dtb.bin by choosing the right DTB to append). If it
Why does device tree change how things work now? The get_board_rev() function currently deals with this. It doesn't look like rpi_board_rev is used anywhere else.
Without a DT, the code is free to make all the board-rev-specific decisions at run-time without external influence.
With a DT, we either have to:
a) Pick the DT for one particular board and use that everywhere, even if it's incorrect for the actual board in use.
b) Build a different U-Boot + DTB image for each board-rev, and put the correct one on the SD card.
Neither of those options seem like a good idea to me.
How about:
c) Leave the code as is, and not add a whole lot more device tree files.
After all the kernel only has files for rpi and rpi_2. Why should we add one for each variant? If you don't want to do it, why do it?
For the kernel I do expect to add a DT file for each variant. That makes sense since we expect a single kernel binary to run unmodified on all HW, parameterize the HW setup via the DTB, and have an infrastructure to pass the different DTs to the kernel easily.
For U-Boot, I'd like to continue to have a single-binary that runs on all RPis (well, one for RPi 1, another for RPi 2). That's a very nice usage model for users. That's not possible if U-Boot pulls everything from DT and we have a different DT for each system (which only makes sense so that we don't lie in the DT, or fail to represent the differences between the models) since a single DT is embedded into the U-Boot binary; there's no infra-structure to passing 1 of n DTBs to U-Boot.
So my question is, for what U-Boot needs, can we have 1 DT for RPi 1 (that's not lying about what the HW can do) and 1 DT for RPi 2? This is the kind of question I'm frankly strugling with right now on converting more of the TI boards to be DT based as well.

On 07/24/2015 07:44 AM, Tom Rini wrote:
On Thu, Jul 23, 2015 at 10:17:29PM -0600, Stephen Warren wrote:
On 07/14/2015 09:44 AM, Simon Glass wrote:
Hi Stephen,
On 13 July 2015 at 22:52, Stephen Warren swarren@wwwdotorg.org wrote:
On 07/11/2015 08:04 AM, Simon Glass wrote:
Hi Stephen,
On 10 July 2015 at 23:34, Stephen Warren swarren@wwwdotorg.org wrote:
On 07/07/2015 08:53 PM, Simon Glass wrote: > Raspberry Pi uses a DWC2 USB controller and a SMSC USB > Ethernet adaptor. Neither of these currently support > driver model. > > This series does the following: - Move Raspberry Pi to > use device tree control (u-boot-dtb.bin instead of > u-boot.bin)
I'd strongly prefer not to do this. For one thing, it means we'd need different U-Boot builds for each of the different RPi models, and we currently don't need that (or perhaps we require users to create their own u-boot-dtb.bin by choosing the right DTB to append). If it
Why does device tree change how things work now? The get_board_rev() function currently deals with this. It doesn't look like rpi_board_rev is used anywhere else.
Without a DT, the code is free to make all the board-rev-specific decisions at run-time without external influence.
With a DT, we either have to:
a) Pick the DT for one particular board and use that everywhere, even if it's incorrect for the actual board in use.
b) Build a different U-Boot + DTB image for each board-rev, and put the correct one on the SD card.
Neither of those options seem like a good idea to me.
How about:
c) Leave the code as is, and not add a whole lot more device tree files.
After all the kernel only has files for rpi and rpi_2. Why should we add one for each variant? If you don't want to do it, why do it?
For the kernel I do expect to add a DT file for each variant. That makes sense since we expect a single kernel binary to run unmodified on all HW, parameterize the HW setup via the DTB, and have an infrastructure to pass the different DTs to the kernel easily.
For U-Boot, I'd like to continue to have a single-binary that runs on all RPis (well, one for RPi 1, another for RPi 2). That's a very nice usage model for users. That's not possible if U-Boot pulls everything from DT and we have a different DT for each system (which only makes sense so that we don't lie in the DT, or fail to represent the differences between the models) since a single DT is embedded into the U-Boot binary; there's no infra-structure to passing 1 of n DTBs to U-Boot.
So my question is, for what U-Boot needs, can we have 1 DT for RPi 1 (that's not lying about what the HW can do) and 1 DT for RPi 2? This is the kind of question I'm frankly strugling with right now on converting more of the TI boards to be DT based as well.
This would be possible iff all the HW that U-Boot interacts with is identical on all relevant systems and we simply leave out all the other details that U-Boot doesn't care about (or any differences that exist can be probed via standard protocols such as USB).
Right now, I think that's possible on the RPi.
However, this limits U-Boot's ability to support all HW. If we wanted U-Boot to fully support all features of the HW, this limited DT wouldn't be sufficient. Examples of potential issues are:
a) On RPis that contain the USB hub + Ethernet chip, there's a GPIO that feeds into that chip's enable pin. Right now, U-Boot relies on either the HW default being sufficient to turn that pin on, or perhaps the binary FW that runs before U-Boot does this. However, U-Boot really should set the GPIO itself so that it doesn't rely on HW state set up before it runs. It should also do this only on systems with the USB+LAN chip; we don't have the full schematics for all RPi boards so there's no guarantee the same GPIO doesn't do something else on some boards, especially in the future.
b) I2S (digital audio) output is present on some boards. Someone might want U-Boot to play a startup sound, or make a warning beep under certain error conditions. It's not /that/ likely, but similar features have been implemented on other boards. The availability of I2S outputs varies from model to model.
c) If we want to expose the GPIOs on the expansion header, the set of GPIOs that it's useful to expose varies between boards.
We could probably think of other issues too.
To handle all of these, we'd either have to have separate DTs for the different cases, or represent the differences in code. Having multiple DTs has the issues I mentioned previously. By the time we represent part of the HW structure in code, it's far simpler to just represent it all in that one place. C structs are (currently at least) better than DT for representing this information anyway; the C compiler does a lot more error-checking when initializing structs than dtc can do for example, and code-sharing between boards is easier.

On Mon, Jul 27, 2015 at 09:10:32PM -0600, Stephen Warren wrote:
On 07/24/2015 07:44 AM, Tom Rini wrote:
On Thu, Jul 23, 2015 at 10:17:29PM -0600, Stephen Warren wrote:
On 07/14/2015 09:44 AM, Simon Glass wrote:
Hi Stephen,
On 13 July 2015 at 22:52, Stephen Warren swarren@wwwdotorg.org wrote:
On 07/11/2015 08:04 AM, Simon Glass wrote:
Hi Stephen,
On 10 July 2015 at 23:34, Stephen Warren swarren@wwwdotorg.org wrote: > On 07/07/2015 08:53 PM, Simon Glass wrote: >> Raspberry Pi uses a DWC2 USB controller and a SMSC USB >> Ethernet adaptor. Neither of these currently support >> driver model. >> >> This series does the following: - Move Raspberry Pi to >> use device tree control (u-boot-dtb.bin instead of >> u-boot.bin) > > I'd strongly prefer not to do this. For one thing, it > means we'd need different U-Boot builds for each of the > different RPi models, and we currently don't need that > (or perhaps we require users to create their own > u-boot-dtb.bin by choosing the right DTB to append). If > it
Why does device tree change how things work now? The get_board_rev() function currently deals with this. It doesn't look like rpi_board_rev is used anywhere else.
Without a DT, the code is free to make all the board-rev-specific decisions at run-time without external influence.
With a DT, we either have to:
a) Pick the DT for one particular board and use that everywhere, even if it's incorrect for the actual board in use.
b) Build a different U-Boot + DTB image for each board-rev, and put the correct one on the SD card.
Neither of those options seem like a good idea to me.
How about:
c) Leave the code as is, and not add a whole lot more device tree files.
After all the kernel only has files for rpi and rpi_2. Why should we add one for each variant? If you don't want to do it, why do it?
For the kernel I do expect to add a DT file for each variant. That makes sense since we expect a single kernel binary to run unmodified on all HW, parameterize the HW setup via the DTB, and have an infrastructure to pass the different DTs to the kernel easily.
For U-Boot, I'd like to continue to have a single-binary that runs on all RPis (well, one for RPi 1, another for RPi 2). That's a very nice usage model for users. That's not possible if U-Boot pulls everything from DT and we have a different DT for each system (which only makes sense so that we don't lie in the DT, or fail to represent the differences between the models) since a single DT is embedded into the U-Boot binary; there's no infra-structure to passing 1 of n DTBs to U-Boot.
So my question is, for what U-Boot needs, can we have 1 DT for RPi 1 (that's not lying about what the HW can do) and 1 DT for RPi 2? This is the kind of question I'm frankly strugling with right now on converting more of the TI boards to be DT based as well.
This would be possible iff all the HW that U-Boot interacts with is identical on all relevant systems and we simply leave out all the other details that U-Boot doesn't care about (or any differences that exist can be probed via standard protocols such as USB).
Exactly.
Right now, I think that's possible on the RPi.
That's good..
However, this limits U-Boot's ability to support all HW. If we wanted U-Boot to fully support all features of the HW, this limited DT wouldn't be sufficient. Examples of potential issues are:
a) On RPis that contain the USB hub + Ethernet chip, there's a GPIO that feeds into that chip's enable pin. Right now, U-Boot relies on either the HW default being sufficient to turn that pin on, or perhaps the binary FW that runs before U-Boot does this. However, U-Boot really should set the GPIO itself so that it doesn't rely on HW state set up before it runs. It should also do this only on systems with the USB+LAN chip; we don't have the full schematics for all RPi boards so there's no guarantee the same GPIO doesn't do something else on some boards, especially in the future.
b) I2S (digital audio) output is present on some boards. Someone might want U-Boot to play a startup sound, or make a warning beep under certain error conditions. It's not /that/ likely, but similar features have been implemented on other boards. The availability of I2S outputs varies from model to model.
c) If we want to expose the GPIOs on the expansion header, the set of GPIOs that it's useful to expose varies between boards.
We could probably think of other issues too.
To handle all of these, we'd either have to have separate DTs for the different cases, or represent the differences in code. Having multiple DTs has the issues I mentioned previously. By the time we represent part of the HW structure in code, it's far simpler to just represent it all in that one place. C structs are (currently at least) better than DT for representing this information anyway; the C compiler does a lot more error-checking when initializing structs than dtc can do for example, and code-sharing between boards is easier.
Maybe examples like these are why we will need (and want) to keep platform data as a possibility in our DM work. There's value in keeping the DT that we use as minimal as possible (so that it can work as broadly as possible) and then do run-time fixups. The other option here might be something like device tree overlays or at least exposing the running DT (... more readily, I bet you could kludge it today) so that the existing cli infrasturcture can modify it).

+Hans
Hi,
On 28 July 2015 at 07:55, Tom Rini trini@konsulko.com wrote:
On Mon, Jul 27, 2015 at 09:10:32PM -0600, Stephen Warren wrote:
On 07/24/2015 07:44 AM, Tom Rini wrote:
On Thu, Jul 23, 2015 at 10:17:29PM -0600, Stephen Warren wrote:
On 07/14/2015 09:44 AM, Simon Glass wrote:
Hi Stephen,
On 13 July 2015 at 22:52, Stephen Warren swarren@wwwdotorg.org wrote:
On 07/11/2015 08:04 AM, Simon Glass wrote: > Hi Stephen, > > On 10 July 2015 at 23:34, Stephen Warren > swarren@wwwdotorg.org wrote: >> On 07/07/2015 08:53 PM, Simon Glass wrote: >>> Raspberry Pi uses a DWC2 USB controller and a SMSC USB >>> Ethernet adaptor. Neither of these currently support >>> driver model. >>> >>> This series does the following: - Move Raspberry Pi to >>> use device tree control (u-boot-dtb.bin instead of >>> u-boot.bin) >> >> I'd strongly prefer not to do this. For one thing, it >> means we'd need different U-Boot builds for each of the >> different RPi models, and we currently don't need that >> (or perhaps we require users to create their own >> u-boot-dtb.bin by choosing the right DTB to append). If >> it > > Why does device tree change how things work now? The > get_board_rev() function currently deals with this. It > doesn't look like rpi_board_rev is used anywhere else.
Without a DT, the code is free to make all the board-rev-specific decisions at run-time without external influence.
With a DT, we either have to:
a) Pick the DT for one particular board and use that everywhere, even if it's incorrect for the actual board in use.
b) Build a different U-Boot + DTB image for each board-rev, and put the correct one on the SD card.
Neither of those options seem like a good idea to me.
How about:
c) Leave the code as is, and not add a whole lot more device tree files.
After all the kernel only has files for rpi and rpi_2. Why should we add one for each variant? If you don't want to do it, why do it?
For the kernel I do expect to add a DT file for each variant. That makes sense since we expect a single kernel binary to run unmodified on all HW, parameterize the HW setup via the DTB, and have an infrastructure to pass the different DTs to the kernel easily.
For U-Boot, I'd like to continue to have a single-binary that runs on all RPis (well, one for RPi 1, another for RPi 2). That's a very nice usage model for users. That's not possible if U-Boot pulls everything from DT and we have a different DT for each system (which only makes sense so that we don't lie in the DT, or fail to represent the differences between the models) since a single DT is embedded into the U-Boot binary; there's no infra-structure to passing 1 of n DTBs to U-Boot.
So my question is, for what U-Boot needs, can we have 1 DT for RPi 1 (that's not lying about what the HW can do) and 1 DT for RPi 2? This is the kind of question I'm frankly strugling with right now on converting more of the TI boards to be DT based as well.
This would be possible iff all the HW that U-Boot interacts with is identical on all relevant systems and we simply leave out all the other details that U-Boot doesn't care about (or any differences that exist can be probed via standard protocols such as USB).
Exactly.
Right now, I think that's possible on the RPi.
That's good..
However, this limits U-Boot's ability to support all HW. If we wanted U-Boot to fully support all features of the HW, this limited DT wouldn't be sufficient. Examples of potential issues are:
a) On RPis that contain the USB hub + Ethernet chip, there's a GPIO that feeds into that chip's enable pin. Right now, U-Boot relies on either the HW default being sufficient to turn that pin on, or perhaps the binary FW that runs before U-Boot does this. However, U-Boot really should set the GPIO itself so that it doesn't rely on HW state set up before it runs. It should also do this only on systems with the USB+LAN chip; we don't have the full schematics for all RPi boards so there's no guarantee the same GPIO doesn't do something else on some boards, especially in the future.
b) I2S (digital audio) output is present on some boards. Someone might want U-Boot to play a startup sound, or make a warning beep under certain error conditions. It's not /that/ likely, but similar features have been implemented on other boards. The availability of I2S outputs varies from model to model.
c) If we want to expose the GPIOs on the expansion header, the set of GPIOs that it's useful to expose varies between boards.
We could probably think of other issues too.
To handle all of these, we'd either have to have separate DTs for the different cases, or represent the differences in code. Having multiple DTs has the issues I mentioned previously. By the time we represent part of the HW structure in code, it's far simpler to just represent it all in that one place. C structs are (currently at least) better than DT for representing this information anyway; the C compiler does a lot more error-checking when initializing structs than dtc can do for example, and code-sharing between boards is easier.
Maybe examples like these are why we will need (and want) to keep platform data as a possibility in our DM work. There's value in keeping the DT that we use as minimal as possible (so that it can work as broadly as possible) and then do run-time fixups. The other option here might be something like device tree overlays or at least exposing the running DT (... more readily, I bet you could kludge it today) so that the existing cli infrasturcture can modify it).
I really like the idea of keeping the DT minimal rather than slavishing adding a whole lot of detail for every board. If things can be probed then I think it is acceptable to probe them to avoid an explosion of DTs. We can do run-time fix ups even if they are currently not very efficient. The 'fdt' command can modify the running FDT I think, but it currently breaks everything since by then we have devices and have recorded the DT offsets. We could add a DT library to fix this, but for now fix-ups need to be done before relocation.
Re overlays, yes we could do that and probably should. But again we'll need a DT library that turns the DT into a tree.
Hans mentioned he was thinking about this.
But getting back to this series, I feel that for now we can get a long way with just two device trees: rpi1 and rpi2.
Regards, Simon

On 07/28/2015 09:44 AM, Simon Glass wrote:
On 28 July 2015 at 07:55, Tom Rini trini@konsulko.com wrote:
...
Maybe examples like these are why we will need (and want) to keep platform data as a possibility in our DM work. There's value in keeping the DT that we use as minimal as possible (so that it can work as broadly as possible) and then do run-time fixups. The other option here might be something like device tree overlays or at least exposing the running DT (... more readily, I bet you could kludge it today) so that the existing cli infrasturcture can modify it).
I really like the idea of keeping the DT minimal rather than slavishing adding a whole lot of detail for every board. If things can be probed then I think it is acceptable to probe them to avoid an explosion of DTs. We can do run-time fix ups even if they are currently not very efficient. The 'fdt' command can modify the running FDT I think, but it currently breaks everything since by then we have devices and have recorded the DT offsets. We could add a DT library to fix this, but for now fix-ups need to be done before relocation.
There are two cases for probing:
a) Standard buses that are probe-able in a standard way, like USB.
It makes sense to probe these since the probing code is generic across a wide variety of systems and hence the code can be considered generic.
b) Device-specific information sources (such as the RPi firmware etc.).
Code for this isn't at all re-usable across systems. In the kernel, there's been some tendency to push for SW that runs before the kernel to probe these information sources and add the relevant information into the DT (or just include the information statically in DT source files), rather than including system-specific code in the kernel to do the probing. This keeps kernel code size down and avoids lots of non-generic code.
Related, if the kernel knew it booted on nvidia,jetson-tk1, then that information is enough to tell the kernel the entire set of devices that are attached (aside from anything attached to the USB, PCIe, HDMI controllers). We could probe a board file from just the board name:-)
DT schema/content is intended to be identical across all SW stacks so that it can be shared. There's a bit of friction here re: what a bootloader and OS kernel might want in DT vs. what they could/prefer-to probe themselves using device-specific code:-(

On 07/28/2015 07:55 AM, Tom Rini wrote:
On Mon, Jul 27, 2015 at 09:10:32PM -0600, Stephen Warren wrote:
On 07/24/2015 07:44 AM, Tom Rini wrote:
On Thu, Jul 23, 2015 at 10:17:29PM -0600, Stephen Warren wrote:
On 07/14/2015 09:44 AM, Simon Glass wrote:
Hi Stephen,
On 13 July 2015 at 22:52, Stephen Warren swarren@wwwdotorg.org wrote:
On 07/11/2015 08:04 AM, Simon Glass wrote: > Hi Stephen, > > On 10 July 2015 at 23:34, Stephen Warren > swarren@wwwdotorg.org wrote: >> On 07/07/2015 08:53 PM, Simon Glass wrote: >>> Raspberry Pi uses a DWC2 USB controller and a SMSC >>> USB Ethernet adaptor. Neither of these currently >>> support driver model. >>> >>> This series does the following: - Move Raspberry Pi >>> to use device tree control (u-boot-dtb.bin instead >>> of u-boot.bin) >> >> I'd strongly prefer not to do this. For one thing, it >> means we'd need different U-Boot builds for each of >> the different RPi models, and we currently don't need >> that (or perhaps we require users to create their own >> u-boot-dtb.bin by choosing the right DTB to append). >> If it > > Why does device tree change how things work now? The > get_board_rev() function currently deals with this. It > doesn't look like rpi_board_rev is used anywhere > else.
Without a DT, the code is free to make all the board-rev-specific decisions at run-time without external influence.
With a DT, we either have to:
a) Pick the DT for one particular board and use that everywhere, even if it's incorrect for the actual board in use.
b) Build a different U-Boot + DTB image for each board-rev, and put the correct one on the SD card.
Neither of those options seem like a good idea to me.
How about:
c) Leave the code as is, and not add a whole lot more device tree files.
After all the kernel only has files for rpi and rpi_2. Why should we add one for each variant? If you don't want to do it, why do it?
For the kernel I do expect to add a DT file for each variant. That makes sense since we expect a single kernel binary to run unmodified on all HW, parameterize the HW setup via the DTB, and have an infrastructure to pass the different DTs to the kernel easily.
For U-Boot, I'd like to continue to have a single-binary that runs on all RPis (well, one for RPi 1, another for RPi 2). That's a very nice usage model for users. That's not possible if U-Boot pulls everything from DT and we have a different DT for each system (which only makes sense so that we don't lie in the DT, or fail to represent the differences between the models) since a single DT is embedded into the U-Boot binary; there's no infra-structure to passing 1 of n DTBs to U-Boot.
So my question is, for what U-Boot needs, can we have 1 DT for RPi 1 (that's not lying about what the HW can do) and 1 DT for RPi 2? This is the kind of question I'm frankly strugling with right now on converting more of the TI boards to be DT based as well.
This would be possible iff all the HW that U-Boot interacts with is identical on all relevant systems and we simply leave out all the other details that U-Boot doesn't care about (or any differences that exist can be probed via standard protocols such as USB).
Exactly.
Right now, I think that's possible on the RPi.
That's good..
However, this limits U-Boot's ability to support all HW. If we wanted U-Boot to fully support all features of the HW, this limited DT wouldn't be sufficient. Examples of potential issues are:
a) On RPis that contain the USB hub + Ethernet chip, there's a GPIO that feeds into that chip's enable pin. Right now, U-Boot relies on either the HW default being sufficient to turn that pin on, or perhaps the binary FW that runs before U-Boot does this. However, U-Boot really should set the GPIO itself so that it doesn't rely on HW state set up before it runs. It should also do this only on systems with the USB+LAN chip; we don't have the full schematics for all RPi boards so there's no guarantee the same GPIO doesn't do something else on some boards, especially in the future.
b) I2S (digital audio) output is present on some boards. Someone might want U-Boot to play a startup sound, or make a warning beep under certain error conditions. It's not /that/ likely, but similar features have been implemented on other boards. The availability of I2S outputs varies from model to model.
c) If we want to expose the GPIOs on the expansion header, the set of GPIOs that it's useful to expose varies between boards.
We could probably think of other issues too.
To handle all of these, we'd either have to have separate DTs for the different cases, or represent the differences in code. Having multiple DTs has the issues I mentioned previously. By the time we represent part of the HW structure in code, it's far simpler to just represent it all in that one place. C structs are (currently at least) better than DT for representing this information anyway; the C compiler does a lot more error-checking when initializing structs than dtc can do for example, and code-sharing between boards is easier.
Maybe examples like these are why we will need (and want) to keep platform data as a possibility in our DM work. There's value in keeping the DT that we use as minimal as possible (so that it can work as broadly as possible) and then do run-time fixups. The other option here might be something like device tree overlays or at least exposing the running DT (... more readily, I bet you could kludge it today) so that the existing cli infrasturcture can modify it).
I'm still not convinced of the utility of DT /if/ we can't completely get rid of C code alongside it. Representing part of the system in DT and part in C seems to me to be the absolute worst case. If we need C for part of the system config, we should just use it for all of it.

On Mon 2015-07-13 22:52:58, Stephen Warren wrote:
On 07/11/2015 08:04 AM, Simon Glass wrote:
Hi Stephen,
On 10 July 2015 at 23:34, Stephen Warren swarren@wwwdotorg.org wrote:
On 07/07/2015 08:53 PM, Simon Glass wrote:
Raspberry Pi uses a DWC2 USB controller and a SMSC USB Ethernet adaptor. Neither of these currently support driver model.
This series does the following:
- Move Raspberry Pi to use device tree control (u-boot-dtb.bin instead of u-boot.bin)
I'd strongly prefer not to do this. For one thing, it means we'd need different U-Boot builds for each of the different RPi models, and we currently don't need that (or perhaps we require users to create their own u-boot-dtb.bin by choosing the right DTB to append). If it
Why does device tree change how things work now? The get_board_rev() function currently deals with this. It doesn't look like rpi_board_rev is used anywhere else.
Without a DT, the code is free to make all the board-rev-specific decisions at run-time without external influence.
With a DT, we either have to:
a) Pick the DT for one particular board and use that everywhere, even if it's incorrect for the actual board in use.
Is that an option? I mean... if you can tolerate incorrect values for something, perhaps that something should not be in the dtb in the first place?
b) Build a different U-Boot + DTB image for each board-rev, and put the correct one on the SD card.
d) Build U-Boot + set of DTB images, then pick up the right one at the runtime?
Neither of those options seem like a good idea to me.
Stuff that can be autodetected does not belong to the device tree...
Pavel

Hi Stephen,
On 16 July 2015 at 08:10, Pavel Machek pavel@denx.de wrote:
On Mon 2015-07-13 22:52:58, Stephen Warren wrote:
On 07/11/2015 08:04 AM, Simon Glass wrote:
Hi Stephen,
On 10 July 2015 at 23:34, Stephen Warren swarren@wwwdotorg.org wrote:
On 07/07/2015 08:53 PM, Simon Glass wrote:
Raspberry Pi uses a DWC2 USB controller and a SMSC USB Ethernet adaptor. Neither of these currently support driver model.
This series does the following:
- Move Raspberry Pi to use device tree control (u-boot-dtb.bin instead of u-boot.bin)
I'd strongly prefer not to do this. For one thing, it means we'd need different U-Boot builds for each of the different RPi models, and we currently don't need that (or perhaps we require users to create their own u-boot-dtb.bin by choosing the right DTB to append). If it
Why does device tree change how things work now? The get_board_rev() function currently deals with this. It doesn't look like rpi_board_rev is used anywhere else.
Without a DT, the code is free to make all the board-rev-specific decisions at run-time without external influence.
With a DT, we either have to:
a) Pick the DT for one particular board and use that everywhere, even if it's incorrect for the actual board in use.
Is that an option? I mean... if you can tolerate incorrect values for something, perhaps that something should not be in the dtb in the first place?
b) Build a different U-Boot + DTB image for each board-rev, and put the correct one on the SD card.
d) Build U-Boot + set of DTB images, then pick up the right one at the runtime?
Neither of those options seem like a good idea to me.
Stuff that can be autodetected does not belong to the device tree...
Pavel
-- (english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Stephen please can you update here? It seems to me that there is no requirement to add a lot of stuff to the device tree which we already have code to auto-detect.
I'd like to pull in these changes but can hold off on the rpi parts until we figure this out.
Regards, Simon

On 07/16/2015 08:10 AM, Pavel Machek wrote:
On Mon 2015-07-13 22:52:58, Stephen Warren wrote:
On 07/11/2015 08:04 AM, Simon Glass wrote:
Hi Stephen,
On 10 July 2015 at 23:34, Stephen Warren swarren@wwwdotorg.org wrote:
On 07/07/2015 08:53 PM, Simon Glass wrote:
Raspberry Pi uses a DWC2 USB controller and a SMSC USB Ethernet adaptor. Neither of these currently support driver model.
This series does the following:
- Move Raspberry Pi to use device tree control (u-boot-dtb.bin instead of u-boot.bin)
I'd strongly prefer not to do this. For one thing, it means we'd need different U-Boot builds for each of the different RPi models, and we currently don't need that (or perhaps we require users to create their own u-boot-dtb.bin by choosing the right DTB to append). If it
Why does device tree change how things work now? The get_board_rev() function currently deals with this. It doesn't look like rpi_board_rev is used anywhere else.
Without a DT, the code is free to make all the board-rev-specific decisions at run-time without external influence.
With a DT, we either have to:
a) Pick the DT for one particular board and use that everywhere, even if it's incorrect for the actual board in use.
Is that an option? I mean... if you can tolerate incorrect values for something, perhaps that something should not be in the dtb in the first place?
Indeed I would certainly rather not have U-Boot use a DT that contains invalid information.
b) Build a different U-Boot + DTB image for each board-rev, and put the correct one on the SD card.
d) Build U-Boot + set of DTB images, then pick up the right one at the runtime?
Perhaps that'd work.
Neither of those options seem like a good idea to me.
Stuff that can be autodetected does not belong to the device tree...
I tend to agree, but then you need platform-specific code to do the auto-detection, and there's pushback on that since a large benefit of DT is to remove platform-specific code from SW and just represent the information in DT. Put another way, DT seems to end up being "nothing" (DT not used) or "everything" (even representing some auto-probed data). Not great, but.

On Wednesday, July 08, 2015 at 04:53:32 AM, Simon Glass wrote:
Raspberry Pi uses a DWC2 USB controller and a SMSC USB Ethernet adaptor. Neither of these currently support driver model.
This series does the following:
- Move Raspberry Pi to use device tree control (u-boot-dtb.bin instead of u-boot.bin)
- Remove GPIO platform data (now uses device tree)
- Remove serial platform data (now uses device tree)
- Add 'ranges' support to simple-bus
- Convert the DWC2 USB driver to support driver model
- Convert the SMSC95XX USB Ethernet driver to support driver model
- Enable CONFIG_DM_ETH and CONFIG_DM_USB on Raspberry Pi
With Ethernet active the device list looks something like this:
U-Boot> dm tree Class Probed Name
root [ + ] root_driver simple_bus [ + ] |-- soc gpio [ ] | |-- gpio@7e200000 serial [ + ] | |-- uart@7e201000 usb [ + ] | `-- usb@7e980000 usb_hub [ + ] | `-- usb_hub usb_hub [ + ] | `-- usb_hub eth [ + ] | `-- smsc95xx_eth simple_bus [ ] `-- clocks
Raspberry Pi 2 is not converted as I do not have one to test at present.
Simon Glass (20): dm: net: Support usbethaddr environment variable dm: usb: Allow USB Ethernet whenever CONFIG_DM_ETH is not defined dm: usb: Add an errno.h header to usb_ether.c dm: usb: Prepare dwc2 driver for driver-model conversion dm: usb: Add driver-model support to dwc2 net: smsc95xx: Sort the include files net: smsc95xx: Rename AX_RX_URB_SIZE to RX_URB_SIZE net: smsc95xx: Correct the error numbers net: smsc95xx: Prepare for conversion to driver model net: smsc95xx: Add driver-model support dm: serial: Update binding for PL01x serial UART dm: Support address translation for simple-bus arm: rpi: Define CONFIG_TFTP_TSIZE to show tftp size info arm: rpi: Bring in kernel device tree files arm: rpi: Device tree modifications for U-Boot arm: rpi: Enable device tree control for Rasberry Pi arm: rpi: Drop the UART console platform data arm: rpi: Drop the GPIO platform data arm: rpi: Move to driver model for USB arm: rpi: Use driver model for Ethernet
I could really use the DM part of this patchset on SoCFPGA, can you maybe drop the rpi part and repost it, so that part can be mainlined please ?

Hi Marek,
On 3 August 2015 at 17:45, Marek Vasut marex@denx.de wrote:
On Wednesday, July 08, 2015 at 04:53:32 AM, Simon Glass wrote:
Raspberry Pi uses a DWC2 USB controller and a SMSC USB Ethernet adaptor. Neither of these currently support driver model.
This series does the following:
- Move Raspberry Pi to use device tree control (u-boot-dtb.bin instead of u-boot.bin)
- Remove GPIO platform data (now uses device tree)
- Remove serial platform data (now uses device tree)
- Add 'ranges' support to simple-bus
- Convert the DWC2 USB driver to support driver model
- Convert the SMSC95XX USB Ethernet driver to support driver model
- Enable CONFIG_DM_ETH and CONFIG_DM_USB on Raspberry Pi
With Ethernet active the device list looks something like this:
U-Boot> dm tree Class Probed Name
root [ + ] root_driver simple_bus [ + ] |-- soc gpio [ ] | |-- gpio@7e200000 serial [ + ] | |-- uart@7e201000 usb [ + ] | `-- usb@7e980000 usb_hub [ + ] | `-- usb_hub usb_hub [ + ] | `-- usb_hub eth [ + ] | `-- smsc95xx_eth simple_bus [ ] `-- clocks
Raspberry Pi 2 is not converted as I do not have one to test at present.
Simon Glass (20): dm: net: Support usbethaddr environment variable dm: usb: Allow USB Ethernet whenever CONFIG_DM_ETH is not defined dm: usb: Add an errno.h header to usb_ether.c dm: usb: Prepare dwc2 driver for driver-model conversion dm: usb: Add driver-model support to dwc2 net: smsc95xx: Sort the include files net: smsc95xx: Rename AX_RX_URB_SIZE to RX_URB_SIZE net: smsc95xx: Correct the error numbers net: smsc95xx: Prepare for conversion to driver model net: smsc95xx: Add driver-model support dm: serial: Update binding for PL01x serial UART dm: Support address translation for simple-bus arm: rpi: Define CONFIG_TFTP_TSIZE to show tftp size info arm: rpi: Bring in kernel device tree files arm: rpi: Device tree modifications for U-Boot arm: rpi: Enable device tree control for Rasberry Pi arm: rpi: Drop the UART console platform data arm: rpi: Drop the GPIO platform data arm: rpi: Move to driver model for USB arm: rpi: Use driver model for Ethernet
I could really use the DM part of this patchset on SoCFPGA, can you maybe drop the rpi part and repost it, so that part can be mainlined please ?
Half of this series in in dm/master - please rebase on top of that. I hope to get a pull request out by Friday,
Regards, Simon

On Tuesday, August 04, 2015 at 02:07:41 AM, Simon Glass wrote:
Hi Marek,
Hi!
On 3 August 2015 at 17:45, Marek Vasut marex@denx.de wrote:
On Wednesday, July 08, 2015 at 04:53:32 AM, Simon Glass wrote:
Raspberry Pi uses a DWC2 USB controller and a SMSC USB Ethernet adaptor. Neither of these currently support driver model.
This series does the following:
- Move Raspberry Pi to use device tree control (u-boot-dtb.bin instead
of
u-boot.bin)
- Remove GPIO platform data (now uses device tree)
- Remove serial platform data (now uses device tree)
- Add 'ranges' support to simple-bus
- Convert the DWC2 USB driver to support driver model
- Convert the SMSC95XX USB Ethernet driver to support driver model
- Enable CONFIG_DM_ETH and CONFIG_DM_USB on Raspberry Pi
With Ethernet active the device list looks something like this:
U-Boot> dm tree
Class Probed Name
root [ + ] root_driver simple_bus [ + ] |-- soc gpio [ ] | |-- gpio@7e200000 serial [ + ] | |-- uart@7e201000 usb [ + ] | `-- usb@7e980000 usb_hub [ + ] | `-- usb_hub usb_hub [ + ] | `-- usb_hub eth [ + ] | `-- smsc95xx_eth simple_bus [ ] `-- clocks
Raspberry Pi 2 is not converted as I do not have one to test at present.
Simon Glass (20): dm: net: Support usbethaddr environment variable dm: usb: Allow USB Ethernet whenever CONFIG_DM_ETH is not defined dm: usb: Add an errno.h header to usb_ether.c dm: usb: Prepare dwc2 driver for driver-model conversion dm: usb: Add driver-model support to dwc2 net: smsc95xx: Sort the include files net: smsc95xx: Rename AX_RX_URB_SIZE to RX_URB_SIZE net: smsc95xx: Correct the error numbers net: smsc95xx: Prepare for conversion to driver model net: smsc95xx: Add driver-model support dm: serial: Update binding for PL01x serial UART dm: Support address translation for simple-bus arm: rpi: Define CONFIG_TFTP_TSIZE to show tftp size info arm: rpi: Bring in kernel device tree files arm: rpi: Device tree modifications for U-Boot arm: rpi: Enable device tree control for Rasberry Pi arm: rpi: Drop the UART console platform data arm: rpi: Drop the GPIO platform data arm: rpi: Move to driver model for USB arm: rpi: Use driver model for Ethernet
I could really use the DM part of this patchset on SoCFPGA, can you maybe drop the rpi part and repost it, so that part can be mainlined please ?
Half of this series in in dm/master - please rebase on top of that.
You asking people to rebased on top of dm/master has become quite common recently ;-)
I hope to get a pull request out by Friday,
Excellent, I'll wait until this stuff hits u-boot/master . Thanks!
participants (10)
-
Arnd Bergmann
-
Geert Uytterhoeven
-
Joe Hershberger
-
Linus Walleij
-
Marek Vasut
-
Pavel Machek
-
Simon Glass
-
Stephen Warren
-
Tom Rini
-
Vikas MANOCHA