]> git.ipfire.org Git - people/ms/u-boot.git/commitdiff
Merge git://git.denx.de/u-boot-marvell
authorTom Rini <trini@konsulko.com>
Thu, 23 Jul 2015 13:02:28 +0000 (09:02 -0400)
committerTom Rini <trini@konsulko.com>
Thu, 23 Jul 2015 13:02:28 +0000 (09:02 -0400)
155 files changed:
Makefile
arch/arm/cpu/u-boot-spl.lds
arch/arm/mach-zynq/clk.c
arch/sandbox/cpu/cpu.c
arch/sandbox/cpu/state.c
arch/sandbox/dts/test.dts
arch/sandbox/include/asm/state.h
arch/sandbox/include/asm/test.h
arch/sandbox/include/asm/u-boot-sandbox.h
arch/x86/include/asm/interrupt.h
common/cmd_tsi148.c
common/cmd_usb.c
common/console.c
common/image.c
common/spl/spl.c
common/spl/spl_mmc.c
common/usb.c
common/usb_hub.c
common/usb_kbd.c
common/usb_storage.c
configs/sandbox_defconfig
doc/device-tree-bindings/leds/common.txt [new file with mode: 0644]
doc/device-tree-bindings/leds/leds-gpio.txt [new file with mode: 0644]
doc/driver-model/README.txt
drivers/Kconfig
drivers/Makefile
drivers/clk/Kconfig [new file with mode: 0644]
drivers/clk/Makefile [new file with mode: 0644]
drivers/clk/clk-uclass.c [new file with mode: 0644]
drivers/clk/clk_sandbox.c [new file with mode: 0644]
drivers/core/Kconfig
drivers/core/Makefile
drivers/core/device-remove.c
drivers/core/device.c
drivers/core/dump.c [new file with mode: 0644]
drivers/core/lists.c
drivers/core/regmap.c [new file with mode: 0644]
drivers/core/syscon-uclass.c [new file with mode: 0644]
drivers/core/uclass.c
drivers/gpio/Makefile
drivers/gpio/gpio-uclass.c
drivers/led/Kconfig [new file with mode: 0644]
drivers/led/Makefile [new file with mode: 0644]
drivers/led/led-uclass.c [new file with mode: 0644]
drivers/led/led_gpio.c [new file with mode: 0644]
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/reset-uclass.c [new file with mode: 0644]
drivers/misc/reset_sandbox.c [new file with mode: 0644]
drivers/misc/syscon_sandbox.c [new file with mode: 0644]
drivers/mmc/Kconfig
drivers/mmc/Makefile
drivers/mmc/mmc-uclass.c [new file with mode: 0644]
drivers/mmc/mmc.c
drivers/mmc/sandbox_mmc.c [new file with mode: 0644]
drivers/net/designware.c
drivers/net/rtl8169.c
drivers/net/sandbox-raw.c
drivers/net/sandbox.c
drivers/net/sunxi_emac.c
drivers/pci/pci-uclass.c
drivers/pci/pci_compat.c
drivers/power/pmic/pmic-uclass.c
drivers/power/regulator/regulator-uclass.c
drivers/ram/Kconfig [new file with mode: 0644]
drivers/ram/Makefile [new file with mode: 0644]
drivers/ram/ram-uclass.c [new file with mode: 0644]
drivers/ram/sandbox_ram.c [new file with mode: 0644]
drivers/serial/ns16550.c
drivers/spi/spi-uclass.c
drivers/usb/Kconfig
drivers/usb/eth/asix.c
drivers/usb/eth/usb_ether.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-pci.c
drivers/usb/host/ehci.h
drivers/usb/host/r8a66597-hcd.c
drivers/usb/host/r8a66597.h
drivers/usb/host/usb-uclass.c
drivers/usb/musb-new/am35x.c
drivers/usb/musb-new/musb_core.c
drivers/usb/musb-new/musb_core.h
drivers/usb/musb-new/musb_dsps.c
drivers/usb/musb-new/musb_gadget_ep0.c
drivers/usb/musb-new/musb_host.c
drivers/usb/musb-new/musb_uboot.c
drivers/usb/musb-new/musb_uboot.h [new file with mode: 0644]
drivers/usb/musb-new/omap2430.c
drivers/usb/musb-new/sunxi.c
drivers/usb/musb-new/usb-compat.h
dts/Kconfig
include/asm-generic/global_data.h
include/asm-generic/gpio.h
include/clk.h
include/common.h
include/configs/minnowmax.h
include/debug_uart.h
include/dm/device-internal.h
include/dm/device.h
include/dm/platdata.h
include/dm/uclass-id.h
include/dm/util.h
include/dwmmc.h
include/image.h
include/led.h [new file with mode: 0644]
include/libfdt.h
include/linux/compat.h
include/mmc.h
include/net.h
include/pci.h
include/power/pmic.h
include/power/regulator.h
include/power/sandbox_pmic.h
include/ram.h [new file with mode: 0644]
include/rc4.h [new file with mode: 0644]
include/regmap.h [new file with mode: 0644]
include/reset.h [new file with mode: 0644]
include/spl.h
include/syscon.h [new file with mode: 0644]
include/test/ut.h
include/usb.h
include/usb_ether.h
include/vsprintf.h
lib/Kconfig
lib/Makefile
lib/dhry/Kconfig [new file with mode: 0644]
lib/dhry/Makefile [new file with mode: 0644]
lib/dhry/cmd_dhry.c [new file with mode: 0644]
lib/dhry/dhry.h [new file with mode: 0644]
lib/dhry/dhry_1.c [new file with mode: 0644]
lib/dhry/dhry_2.c [new file with mode: 0644]
lib/fdtdec.c
lib/libfdt/Makefile
lib/libfdt/fdt_region.c [new file with mode: 0644]
lib/libfdt/fdt_rw.c
lib/linux_compat.c
lib/rc4.c [new file with mode: 0644]
lib/vsprintf.c
net/eth.c
scripts/Makefile.spl
test/dm/Makefile
test/dm/clk.c [new file with mode: 0644]
test/dm/cmd_dm.c
test/dm/led.c [new file with mode: 0644]
test/dm/mmc.c [new file with mode: 0644]
test/dm/ram.c [new file with mode: 0644]
test/dm/regmap.c [new file with mode: 0644]
test/dm/regulator.c
test/dm/reset.c [new file with mode: 0644]
test/dm/syscon.c [new file with mode: 0644]
test/dm/test-main.c
tools/Makefile
tools/fdtgrep.c [new file with mode: 0644]
tools/imagetool.h
tools/mkimage.c

index 9ca0a56949d98281b2748ce48290ebfd9f310e57..54ef2cd1a04c6f15f423cdb50ea7dc173cde68f6 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1259,7 +1259,7 @@ u-boot.lds: $(LDSCRIPT) prepare FORCE
 
 spl/u-boot-spl.bin: spl/u-boot-spl
        @:
-spl/u-boot-spl: tools prepare
+spl/u-boot-spl: tools prepare $(if $(CONFIG_OF_SEPARATE),dts/dt.dtb)
        $(Q)$(MAKE) obj=spl -f $(srctree)/scripts/Makefile.spl all
 
 spl/sunxi-spl.bin: spl/u-boot-spl
index a8be204038f94a937289f1e433aff5a02d21f293..c5b4f7ce5e9e4091a1d7d51e40ac9969a5a3b8c3 100644 (file)
@@ -32,17 +32,17 @@ SECTIONS
        }
 
        . = ALIGN(4);
-       .u_boot_list : {
-               KEEP(*(SORT(.u_boot_list*_i2c_*)));
-       }
-
-       . = .;
 #ifdef CONFIG_SPL_DM
        .u_boot_list : {
                KEEP(*(SORT(.u_boot_list_*_driver_*)));
                KEEP(*(SORT(.u_boot_list_*_uclass_*)));
        }
 #endif
+       . = .;
+       .u_boot_list : {
+               KEEP(*(SORT(.u_boot_list*_i2c_*)));
+       }
+
        . = ALIGN(4);
 
        __image_copy_end = .;
@@ -66,7 +66,7 @@ SECTIONS
                 . = ALIGN(4);
                __bss_end = .;
        }
-
+       __bss_size = __bss_end - __bss_start;
        .dynsym _image_binary_end : { *(.dynsym) }
        .dynbss : { *(.dynbss) }
        .dynstr : { *(.dynstr*) }
index d2885dc2b9e3e9d6444684ed103b1e1962b2b929..6444be8f032573c06e5b219ce6a930c93353b0a8 100644 (file)
@@ -48,11 +48,11 @@ DECLARE_GLOBAL_DATA_PTR;
 struct clk;
 
 /**
- * struct clk_ops:
+ * struct zynq_clk_ops:
  * @set_rate:  Function pointer to set_rate() implementation
  * @get_rate:  Function pointer to get_rate() implementation
  */
-struct clk_ops {
+struct zynq_clk_ops {
        int (*set_rate)(struct clk *clk, unsigned long rate);
        unsigned long (*get_rate)(struct clk *clk);
 };
@@ -72,7 +72,7 @@ struct clk {
        enum zynq_clk   parent;
        unsigned int    flags;
        u32             *reg;
-       struct clk_ops  ops;
+       struct zynq_clk_ops     ops;
 };
 #define ZYNQ_CLK_FLAGS_HAS_2_DIVS      1
 
index e6ddb17a140381b59abd7d8b0c597eff8a18a57e..3a7f5a004b0fa341dfec557f20fa087d41674327 100644 (file)
@@ -20,7 +20,7 @@ static struct udevice *map_dev;
 unsigned long map_len;
 #endif
 
-void reset_cpu(ulong ignored)
+void sandbox_exit(void)
 {
        /* Do this here while it still has an effect */
        os_fd_restore();
@@ -34,13 +34,6 @@ void reset_cpu(ulong ignored)
        os_exit(0);
 }
 
-int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
-{
-       reset_cpu(0);
-
-       return 0;
-}
-
 /* delay x useconds */
 void __udelay(unsigned long usec)
 {
index cae731c8f16ede3e01b193fad1c438fced894121..7e5d03e8460bf945b40577bd40c4b9cb3fd85fbf 100644 (file)
@@ -345,6 +345,10 @@ int state_init(void)
        state->ram_buf = os_malloc(state->ram_size);
        assert(state->ram_buf);
 
+       /* No reset yet, so mark it as such. Always allow power reset */
+       state->last_reset = RESET_COUNT;
+       state->reset_allowed[RESET_POWER] = true;
+
        /*
         * Example of how to use GPIOs:
         *
index c25614ab8806aef6b908a5f616d2dd47492fe528..c948df8c864bc3fae1fa6b30fd5f9658fb2064bf 100644 (file)
@@ -4,7 +4,7 @@
        model = "sandbox";
        compatible = "sandbox";
        #address-cells = <1>;
-       #size-cells = <0>;
+       #size-cells = <1>;
 
        aliases {
                console = &uart0;
@@ -28,7 +28,7 @@
        };
 
        a-test {
-               reg = <0>;
+               reg = <0 1>;
                compatible = "denx,u-boot-fdt-test";
                ping-expect = <0>;
                ping-add = <0>;
        };
 
        junk {
-               reg = <1>;
+               reg = <1 1>;
                compatible = "not,compatible";
        };
 
        no-compatible {
-               reg = <2>;
+               reg = <2 1>;
        };
 
        b-test {
-               reg = <3>;
+               reg = <3 1>;
                compatible = "denx,u-boot-fdt-test";
                ping-expect = <3>;
                ping-add = <3>;
@@ -60,7 +60,7 @@
                #address-cells = <1>;
                #size-cells = <0>;
                compatible = "denx,u-boot-test-bus";
-               reg = <3>;
+               reg = <3 1>;
                ping-expect = <4>;
                ping-add = <4>;
                c-test@5 {
        };
 
        d-test {
-               reg = <3>;
+               reg = <3 1>;
                ping-expect = <6>;
                ping-add = <6>;
                compatible = "google,another-fdt-test";
        };
 
        e-test {
-               reg = <3>;
+               reg = <3 1>;
                ping-expect = <6>;
                ping-add = <6>;
                compatible = "google,another-fdt-test";
                compatible = "denx,u-boot-fdt-test";
        };
 
+       clk@0 {
+               compatible = "sandbox,clk";
+       };
+
        eth@10002000 {
                compatible = "sandbox,eth";
                reg = <0x10002000 0x1000>;
        i2c@0 {
                #address-cells = <1>;
                #size-cells = <0>;
-               reg = <0>;
+               reg = <0 1>;
                compatible = "sandbox,i2c";
                clock-frequency = <100000>;
                eeprom@2c {
                };
        };
 
+       leds {
+               compatible = "gpio-leds";
+
+               iracibble {
+                       gpios = <&gpio_a 1 0>;
+                       label = "sandbox:red";
+               };
+
+               martinet {
+                       gpios = <&gpio_a 2 0>;
+                       label = "sandbox:green";
+               };
+       };
+
+       mmc {
+               compatible = "sandbox,mmc";
+       };
+
        pci: pci-controller {
                compatible = "sandbox,pci";
                device_type = "pci";
                };
        };
 
+       ram {
+               compatible = "sandbox,ram";
+       };
+
+       reset@0 {
+               compatible = "sandbox,warm-reset";
+       };
+
+       reset@1 {
+               compatible = "sandbox,reset";
+       };
+
        spi@0 {
                #address-cells = <1>;
                #size-cells = <0>;
-               reg = <0>;
+               reg = <0 1>;
                compatible = "sandbox,spi";
                cs-gpios = <0>, <&gpio_a 0>;
                spi.bin@0 {
                };
        };
 
+       syscon@0 {
+               compatible = "sandbox,syscon0";
+               reg = <0x10 4>;
+       };
+
+       syscon@1 {
+               compatible = "sandbox,syscon1";
+               reg = <0x20 5
+                       0x28 6
+                       0x30 7
+                       0x38 8>;
+       };
+
        uart0: serial {
                compatible = "sandbox,serial";
                u-boot,dm-pre-reloc;
index a57480a996f33bf9b5b419e50235fdd44f4305f7..2bd28f6b1c1739b5857407d1e055676698330435 100644 (file)
@@ -7,6 +7,7 @@
 #define __SANDBOX_STATE_H
 
 #include <config.h>
+#include <reset.h>
 #include <stdbool.h>
 #include <linux/stringify.h>
 
@@ -59,6 +60,8 @@ struct sandbox_state {
        bool write_state;               /* Write sandbox state on exit */
        bool ignore_missing_state_on_read;      /* No error if state missing */
        bool show_lcd;                  /* Show LCD on start-up */
+       enum reset_t last_reset;        /* Last reset type */
+       bool reset_allowed[RESET_COUNT];        /* Allowed reset types */
        enum state_terminal_raw term_raw;       /* Terminal raw/cooked */
 
        /* Pointer to information for each SPI bus/cs */
index 91a5c79ad2fb14767e239c921594934f2e8810bd..d3c7851bb50c427f2296face2a38e1701d35f842 100644 (file)
 #define SANDBOX_PCI_CLASS_CODE         PCI_CLASS_CODE_COMM
 #define SANDBOX_PCI_CLASS_SUB_CODE     PCI_CLASS_SUB_CODE_COMM_SERIAL
 
+#define SANDBOX_CLK_RATE               32768
+
+enum {
+       PERIPH_ID_FIRST = 0,
+       PERIPH_ID_SPI = PERIPH_ID_FIRST,
+       PERIPH_ID_I2C,
+       PERIPH_ID_PCI,
+
+       PERIPH_ID_COUNT,
+};
+
+/* System controller driver data */
+enum {
+       SYSCON0         = 32,
+       SYSCON1,
+
+       SYSCON_COUNT
+};
+
 /**
  * sandbox_i2c_set_test_mode() - set test mode for running unit tests
  *
index da87cc304067f85ac4e829ef3111901d49de1999..2f3c3f90f2aa814c17bbcd9eb78661e03f1f17cf 100644 (file)
@@ -83,4 +83,7 @@ void sandbox_set_enable_pci_map(int enable);
  */
 int sandbox_read_fdt_from_file(void);
 
+/* Exit sandbox (quit U-Boot) */
+void sandbox_exit(void);
+
 #endif /* _U_BOOT_SANDBOX_H_ */
index 0a75f89d9561b530ed04aec19729c63e94838dd0..00cbe07ed186381c2d63f9e1d73f6b6a0743d022 100644 (file)
 /* arch/x86/cpu/interrupts.c */
 void set_vector(u8 intnum, void *routine);
 
-/* arch/x86/lib/interrupts.c */
-void disable_irq(int irq);
-void enable_irq(int irq);
-
 /* Architecture specific functions */
 void mask_irq(int irq);
 void unmask_irq(int irq);
index dc488b2b3e5705d307eea7914b6a8471296f6caa..ea96d0ffb0a56d9bcd352fb325e87cdfd8593f73 100644 (file)
@@ -16,8 +16,8 @@
 
 #include <tsi148.h>
 
-#define PCI_VENDOR PCI_VENDOR_ID_TUNDRA
-#define PCI_DEVICE PCI_DEVICE_ID_TUNDRA_TSI148
+#define LPCI_VENDOR PCI_VENDOR_ID_TUNDRA
+#define LPCI_DEVICE PCI_DEVICE_ID_TUNDRA_TSI148
 
 typedef struct _TSI148_DEV TSI148_DEV;
 
@@ -41,7 +41,7 @@ int tsi148_init(void)
        pci_dev_t busdevfn;
        unsigned int val;
 
-       busdevfn = pci_find_device(PCI_VENDOR, PCI_DEVICE, 0);
+       busdevfn = pci_find_device(LPCI_VENDOR, LPCI_DEVICE, 0);
        if (busdevfn == -1) {
                puts("Tsi148: No Tundra Tsi148 found!\n");
                return -1;
@@ -68,7 +68,7 @@ int tsi148_init(void)
        /* check mapping */
        debug("Tsi148: Read via mapping, PCI_ID = %08X\n",
              readl(&dev->uregs->pci_id));
-       if (((PCI_DEVICE << 16) | PCI_VENDOR) != readl(&dev->uregs->pci_id)) {
+       if (((LPCI_DEVICE << 16) | LPCI_VENDOR) != readl(&dev->uregs->pci_id)) {
                printf("Tsi148: Cannot read PCI-ID via Mapping: %08x\n",
                       readl(&dev->uregs->pci_id));
                result = -1;
index eab55cd6743b25fe00e3b869c570ea30d6478aae..0ade7759f08e68b6cdffb5f9466016df09cc84d6 100644 (file)
@@ -22,8 +22,8 @@
 #ifdef CONFIG_USB_STORAGE
 static int usb_stor_curr_dev = -1; /* current device */
 #endif
-#ifdef CONFIG_USB_HOST_ETHER
-static int usb_ether_curr_dev = -1; /* current ethernet device */
+#if defined(CONFIG_USB_HOST_ETHER) && !defined(CONFIG_DM_ETH)
+static int __maybe_unused usb_ether_curr_dev = -1; /* current ethernet device */
 #endif
 
 /* some display routines (info command) */
@@ -355,12 +355,12 @@ static void usb_show_tree_graph(struct usb_device *dev, char *pre)
 #endif
        /* check if we are the last one */
 #ifdef CONFIG_DM_USB
-       last_child = device_is_last_sibling(dev->dev);
+       /* Not the root of the usb tree? */
+       if (device_get_uclass_id(dev->dev->parent) != UCLASS_USB) {
+               last_child = device_is_last_sibling(dev->dev);
 #else
-       last_child = (dev->parent != NULL);
-#endif
-       if (last_child) {
-#ifndef CONFIG_DM_USB
+       if (dev->parent != NULL) { /* not root? */
+               last_child = 1;
                for (i = 0; i < dev->parent->maxchild; i++) {
                        /* search for children */
                        if (dev->parent->children[i] == dev) {
@@ -530,11 +530,14 @@ static void do_usb_start(void)
        /* try to recognize storage devices immediately */
        usb_stor_curr_dev = usb_stor_scan(1);
 #endif
-#endif
 #ifdef CONFIG_USB_HOST_ETHER
+# ifdef CONFIG_DM_ETH
+#  error "You must use CONFIG_DM_USB if you want to use CONFIG_USB_HOST_ETHER with CONFIG_DM_ETH"
+# endif
        /* try to recognize ethernet devices immediately */
        usb_ether_curr_dev = usb_host_eth_scan(1);
 #endif
+#endif
 #ifdef CONFIG_USB_KEYBOARD
        drv_usb_kbd_init();
 #endif
@@ -630,12 +633,11 @@ static int do_usb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
                     bus;
                     uclass_next_device(&bus)) {
                        struct usb_device *udev;
-                       struct udevice *hub;
+                       struct udevice *dev;
 
-                       device_find_first_child(bus, &hub);
-                       if (device_get_uclass_id(hub) == UCLASS_USB_HUB &&
-                           device_active(hub)) {
-                               udev = dev_get_parentdata(hub);
+                       device_find_first_child(bus, &dev);
+                       if (dev && device_active(dev)) {
+                               udev = dev_get_parentdata(dev);
                                usb_show_tree(udev);
                        }
                }
index 00582224d463272b43647af31f8dcba519b2c61c..ace206ca4ff5dd87651c32da857fae762916f41c 100644 (file)
@@ -6,6 +6,7 @@
  */
 
 #include <common.h>
+#include <debug_uart.h>
 #include <stdarg.h>
 #include <iomux.h>
 #include <malloc.h>
@@ -455,11 +456,19 @@ static inline void print_pre_console_buffer(int flushpoint) {}
 void putc(const char c)
 {
 #ifdef CONFIG_SANDBOX
+       /* sandbox can send characters to stdout before it has a console */
        if (!gd || !(gd->flags & GD_FLG_SERIAL_READY)) {
                os_putc(c);
                return;
        }
 #endif
+#ifdef CONFIG_DEBUG_UART
+       /* if we don't have a console yet, use the debug UART */
+       if (!gd || !(gd->flags & GD_FLG_SERIAL_READY)) {
+               printch(c);
+               return;
+       }
+#endif
 #ifdef CONFIG_SILENT_CONSOLE
        if (gd->flags & GD_FLG_SILENT)
                return;
@@ -491,7 +500,18 @@ void puts(const char *s)
                return;
        }
 #endif
+#ifdef CONFIG_DEBUG_UART
+       if (!gd || !(gd->flags & GD_FLG_SERIAL_READY)) {
+               while (*s) {
+                       int ch = *s++;
 
+                       printch(ch);
+                       if (ch == '\n')
+                               printch('\r');
+               }
+               return;
+       }
+#endif
 #ifdef CONFIG_SILENT_CONSOLE
        if (gd->flags & GD_FLG_SILENT)
                return;
@@ -521,11 +541,6 @@ int printf(const char *fmt, ...)
        uint i;
        char printbuffer[CONFIG_SYS_PBSIZE];
 
-#if !defined(CONFIG_SANDBOX) && !defined(CONFIG_PRE_CONSOLE_BUFFER)
-       if (!gd->have_console)
-               return 0;
-#endif
-
        va_start(args, fmt);
 
        /* For this to work, printbuffer must be larger than
index f0f01351fe5b378dc8a98235d70a99e9bdd42ced..9efacf8b89ecb36b0f2c43dd5cd5fa373b648ebe 100644 (file)
@@ -543,6 +543,15 @@ void genimg_print_time(time_t timestamp)
 }
 #endif
 
+const table_entry_t *get_table_entry(const table_entry_t *table, int id)
+{
+       for (; table->id >= 0; ++table) {
+               if (table->id == id)
+                       return table;
+       }
+       return NULL;
+}
+
 /**
  * get_table_entry_name - translate entry id to long name
  * @table: pointer to a translation table for entries of a specific type
@@ -559,15 +568,14 @@ void genimg_print_time(time_t timestamp)
  */
 char *get_table_entry_name(const table_entry_t *table, char *msg, int id)
 {
-       for (; table->id >= 0; ++table) {
-               if (table->id == id)
+       table = get_table_entry(table, id);
+       if (!table)
+               return msg;
 #if defined(USE_HOSTCC) || !defined(CONFIG_NEEDS_MANUAL_RELOC)
-                       return table->lname;
+       return table->lname;
 #else
-                       return table->lname + gd->reloc_off;
+       return table->lname + gd->reloc_off;
 #endif
-       }
-       return (msg);
 }
 
 const char *genimg_get_os_name(uint8_t os)
@@ -586,6 +594,20 @@ const char *genimg_get_type_name(uint8_t type)
        return (get_table_entry_name(uimage_type, "Unknown Image", type));
 }
 
+const char *genimg_get_type_short_name(uint8_t type)
+{
+       const table_entry_t *table;
+
+       table = get_table_entry(uimage_type, type);
+       if (!table)
+               return "unknown";
+#if defined(USE_HOSTCC) || !defined(CONFIG_NEEDS_MANUAL_RELOC)
+       return table->sname;
+#else
+       return table->sname + gd->reloc_off;
+#endif
+}
+
 const char *genimg_get_comp_name(uint8_t comp)
 {
        return (get_table_entry_name(uimage_comp, "Unknown Compression",
@@ -610,34 +632,18 @@ int get_table_entry_id(const table_entry_t *table,
                const char *table_name, const char *name)
 {
        const table_entry_t *t;
-#ifdef USE_HOSTCC
-       int first = 1;
-
-       for (t = table; t->id >= 0; ++t) {
-               if (t->sname && strcasecmp(t->sname, name) == 0)
-                       return(t->id);
-       }
 
-       fprintf(stderr, "\nInvalid %s Type - valid names are", table_name);
-       for (t = table; t->id >= 0; ++t) {
-               if (t->sname == NULL)
-                       continue;
-               fprintf(stderr, "%c %s", (first) ? ':' : ',', t->sname);
-               first = 0;
-       }
-       fprintf(stderr, "\n");
-#else
        for (t = table; t->id >= 0; ++t) {
 #ifdef CONFIG_NEEDS_MANUAL_RELOC
-               if (t->sname && strcmp(t->sname + gd->reloc_off, name) == 0)
+               if (t->sname && strcasecmp(t->sname + gd->reloc_off, name) == 0)
 #else
-               if (t->sname && strcmp(t->sname, name) == 0)
+               if (t->sname && strcasecmp(t->sname, name) == 0)
 #endif
                        return (t->id);
        }
        debug("Invalid %s Type: %s\n", table_name, name);
-#endif /* USE_HOSTCC */
-       return (-1);
+
+       return -1;
 }
 
 int genimg_get_os_id(const char *name)
index aeb0645eda47d668f64a083f2b65de9bb8064ed7..94b01da56ce92bdef79eb5ed8cbd043271a2a17b 100644 (file)
@@ -148,18 +148,12 @@ static void spl_ram_load_image(void)
 }
 #endif
 
-void board_init_r(gd_t *dummy1, ulong dummy2)
+int spl_init(void)
 {
-       u32 boot_device;
        int ret;
 
-       debug(">>spl:board_init_r()\n");
-
-#if defined(CONFIG_SYS_SPL_MALLOC_START)
-       mem_malloc_init(CONFIG_SYS_SPL_MALLOC_START,
-                       CONFIG_SYS_SPL_MALLOC_SIZE);
-       gd->flags |= GD_FLG_FULL_MALLOC_INIT;
-#elif defined(CONFIG_SYS_MALLOC_F_LEN)
+       debug("spl_init()\n");
+#if defined(CONFIG_SYS_MALLOC_F_LEN)
        gd->malloc_limit = CONFIG_SYS_MALLOC_F_LEN;
        gd->malloc_ptr = 0;
 #endif
@@ -168,17 +162,36 @@ void board_init_r(gd_t *dummy1, ulong dummy2)
                ret = fdtdec_setup();
                if (ret) {
                        debug("fdtdec_setup() returned error %d\n", ret);
-                       hang();
+                       return ret;
                }
        }
        if (IS_ENABLED(CONFIG_SPL_DM)) {
                ret = dm_init_and_scan(true);
                if (ret) {
                        debug("dm_init_and_scan() returned error %d\n", ret);
-                       hang();
+                       return ret;
                }
        }
+       gd->flags |= GD_FLG_SPL_INIT;
+
+       return 0;
+}
 
+void board_init_r(gd_t *dummy1, ulong dummy2)
+{
+       u32 boot_device;
+
+       debug(">>spl:board_init_r()\n");
+
+#if defined(CONFIG_SYS_SPL_MALLOC_START)
+       mem_malloc_init(CONFIG_SYS_SPL_MALLOC_START,
+                       CONFIG_SYS_SPL_MALLOC_SIZE);
+       gd->flags |= GD_FLG_FULL_MALLOC_INIT;
+#endif
+       if (!(gd->flags & GD_FLG_SPL_INIT)) {
+               if (spl_init())
+                       hang();
+       }
 #ifndef CONFIG_PPC
        /*
         * timer_init() does not exist on PPC systems. The timer is initialized
@@ -285,6 +298,7 @@ void board_init_r(gd_t *dummy1, ulong dummy2)
              gd->malloc_ptr / 1024);
 #endif
 
+       debug("loaded - jumping to U-Boot...");
        jump_to_image_no_args(&spl_image);
 }
 
index 552f80d1e3dd761dd3101e66f6d01d97bf683004..5f1cfbf98e97daf107d0e07a649534534d153423 100644 (file)
@@ -7,6 +7,7 @@
  * SPDX-License-Identifier:    GPL-2.0+
  */
 #include <common.h>
+#include <dm.h>
 #include <spl.h>
 #include <linux/compiler.h>
 #include <asm/u-boot.h>
@@ -26,11 +27,14 @@ static int mmc_load_image_raw_sector(struct mmc *mmc, unsigned long sector)
 
        /* read image header to find the image size & load address */
        count = mmc->block_dev.block_read(0, sector, 1, header);
+       debug("read sector %lx, count=%lu\n", sector, count);
        if (count == 0)
                goto end;
 
-       if (image_get_magic(header) != IH_MAGIC)
+       if (image_get_magic(header) != IH_MAGIC) {
+               puts("bad magic\n");
                return -1;
+       }
 
        spl_parse_image_header(header);
 
@@ -40,7 +44,9 @@ static int mmc_load_image_raw_sector(struct mmc *mmc, unsigned long sector)
 
        /* Read the header too to avoid extra memcpy */
        count = mmc->block_dev.block_read(0, sector, image_size_sectors,
-                                         (void *) spl_image.load_addr);
+                                         (void *)spl_image.load_addr);
+       debug("read %x sectors to %x\n", image_size_sectors,
+             spl_image.load_addr);
 
 end:
        if (count == 0) {
@@ -96,9 +102,18 @@ void spl_mmc_load_image(void)
 {
        struct mmc *mmc;
        u32 boot_mode;
-       int err;
+       int err = 0;
        __maybe_unused int part;
 
+#ifdef CONFIG_DM_MMC
+       struct udevice *dev;
+
+       mmc_initialize(NULL);
+       err = uclass_get_device(UCLASS_MMC, 0, &dev);
+       mmc = NULL;
+       if (!err)
+               mmc = mmc_get_mmc_dev(dev);
+#else
        mmc_initialize(gd->bd);
 
        /* We register only one device. So, the dev id is always 0 */
@@ -109,8 +124,11 @@ void spl_mmc_load_image(void)
 #endif
                hang();
        }
+#endif
+
+       if (!err)
+               err = mmc_init(mmc);
 
-       err = mmc_init(mmc);
        if (err) {
 #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
                printf("spl: mmc init failed with error: %d\n", err);
index 7ff8ac5df364f6cb78ec3e522948402c969f3104..fbaf8ecbe232ce63170228727df1ed7fa23b060f 100644 (file)
@@ -911,26 +911,24 @@ __weak int usb_alloc_device(struct usb_device *udev)
 }
 #endif /* !CONFIG_DM_USB */
 
-#ifndef CONFIG_DM_USB
-int usb_legacy_port_reset(struct usb_device *hub, int portnr)
+static int usb_hub_port_reset(struct usb_device *dev, struct usb_device *hub)
 {
        if (hub) {
                unsigned short portstatus;
                int err;
 
                /* reset the port for the second time */
-               err = legacy_hub_port_reset(hub, portnr - 1, &portstatus);
+               err = legacy_hub_port_reset(hub, dev->portnr - 1, &portstatus);
                if (err < 0) {
-                       printf("\n     Couldn't reset port %i\n", portnr);
+                       printf("\n     Couldn't reset port %i\n", dev->portnr);
                        return err;
                }
        } else {
-               usb_reset_root_port();
+               usb_reset_root_port(dev);
        }
 
        return 0;
 }
-#endif
 
 static int get_descriptor_len(struct usb_device *dev, int len, int expect_len)
 {
@@ -1032,7 +1030,7 @@ static int usb_setup_descriptor(struct usb_device *dev, bool do_read)
 }
 
 static int usb_prepare_device(struct usb_device *dev, int addr, bool do_read,
-                             struct usb_device *parent, int portnr)
+                             struct usb_device *parent)
 {
        int err;
 
@@ -1050,7 +1048,7 @@ static int usb_prepare_device(struct usb_device *dev, int addr, bool do_read,
        err = usb_setup_descriptor(dev, do_read);
        if (err)
                return err;
-       err = usb_legacy_port_reset(parent, portnr);
+       err = usb_hub_port_reset(dev, parent);
        if (err)
                return err;
 
@@ -1128,7 +1126,7 @@ int usb_select_config(struct usb_device *dev)
 }
 
 int usb_setup_device(struct usb_device *dev, bool do_read,
-                    struct usb_device *parent, int portnr)
+                    struct usb_device *parent)
 {
        int addr;
        int ret;
@@ -1137,7 +1135,7 @@ int usb_setup_device(struct usb_device *dev, bool do_read,
        addr = dev->devnum;
        dev->devnum = 0;
 
-       ret = usb_prepare_device(dev, addr, do_read, parent, portnr);
+       ret = usb_prepare_device(dev, addr, do_read, parent);
        if (ret)
                return ret;
        ret = usb_select_config(dev);
@@ -1167,7 +1165,7 @@ int usb_new_device(struct usb_device *dev)
 #ifdef CONFIG_USB_XHCI
        do_read = false;
 #endif
-       err = usb_setup_device(dev, do_read, dev->parent, dev->portnr);
+       err = usb_setup_device(dev, do_read, dev->parent);
        if (err)
                return err;
 
index be01f4f257d9a1ec3ae2f9294d39e734ba683cc4..f621ddb9ab5debe7c6b65514f2b04ee408167bfc 100644 (file)
@@ -652,6 +652,6 @@ static const struct usb_device_id hub_id_table[] = {
        { }     /* Terminating entry */
 };
 
-USB_DEVICE(usb_generic_hub, hub_id_table);
+U_BOOT_USB_DEVICE(usb_generic_hub, hub_id_table);
 
 #endif
index e2af67d2f0a783c13709f57bd15d1b9d87f5f7ce..0227024441710041a4cbcb2fd5c30920ad9078a6 100644 (file)
@@ -540,8 +540,8 @@ int drv_usb_kbd_init(void)
        debug("%s: Probing for keyboard\n", __func__);
 #ifdef CONFIG_DM_USB
        /*
-        * TODO: We should add USB_DEVICE() declarations to each USB ethernet
-        * driver and then most of this file can be removed.
+        * TODO: We should add U_BOOT_USB_DEVICE() declarations to each USB
+        * keyboard driver and then most of this file can be removed.
         */
        struct udevice *bus;
        struct uclass *uc;
index cc9b3e37a1cbec27ce9acbab1bbb7f9e973f5374..b9784304086ecdc7ec7beaaeedb853af513824de 100644 (file)
@@ -1442,6 +1442,6 @@ static const struct usb_device_id mass_storage_id_table[] = {
        { }             /* Terminating entry */
 };
 
-USB_DEVICE(usb_mass_storage, mass_storage_id_table);
+U_BOOT_USB_DEVICE(usb_mass_storage, mass_storage_id_table);
 
 #endif
index 598519dbb2fc35e279c2efbf4f0215680b3f98ac..553574682dcd165d06e892e321fda110725f0554 100644 (file)
@@ -18,6 +18,7 @@ CONFIG_PCI_SANDBOX=y
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_SANDBOX=y
 CONFIG_CMD_CROS_EC=y
+CONFIG_CMD_DHRYSTONE=y
 CONFIG_CROS_EC=y
 CONFIG_CROS_EC_SANDBOX=y
 CONFIG_DM_ETH=y
@@ -44,3 +45,10 @@ CONFIG_UNIT_TEST=y
 CONFIG_UT_TIME=y
 CONFIG_UT_DM=y
 CONFIG_UT_ENV=y
+CONFIG_CLK=y
+CONFIG_RESET=y
+CONFIG_RAM=y
+CONFIG_DM_MMC=y
+CONFIG_LED=y
+CONFIG_LED_GPIO=y
+CONFIG_SYSCON=y
diff --git a/doc/device-tree-bindings/leds/common.txt b/doc/device-tree-bindings/leds/common.txt
new file mode 100644 (file)
index 0000000..2d88816
--- /dev/null
@@ -0,0 +1,23 @@
+Common leds properties.
+
+Optional properties for child nodes:
+- label : The label for this LED.  If omitted, the label is
+  taken from the node name (excluding the unit address).
+
+- linux,default-trigger :  This parameter, if present, is a
+    string defining the trigger assigned to the LED.  Current triggers are:
+     "backlight" - LED will act as a back-light, controlled by the framebuffer
+                  system
+     "default-on" - LED will turn on (but for leds-gpio see "default-state"
+                   property in Documentation/devicetree/bindings/gpio/led.txt)
+     "heartbeat" - LED "double" flashes at a load average based rate
+     "ide-disk" - LED indicates disk activity
+     "timer" - LED flashes at a fixed, configurable rate
+
+Examples:
+
+system-status {
+       label = "Status";
+       linux,default-trigger = "heartbeat";
+       ...
+};
diff --git a/doc/device-tree-bindings/leds/leds-gpio.txt b/doc/device-tree-bindings/leds/leds-gpio.txt
new file mode 100644 (file)
index 0000000..df1b308
--- /dev/null
@@ -0,0 +1,52 @@
+LEDs connected to GPIO lines
+
+Required properties:
+- compatible : should be "gpio-leds".
+
+Each LED is represented as a sub-node of the gpio-leds device.  Each
+node's name represents the name of the corresponding LED.
+
+LED sub-node properties:
+- gpios :  Should specify the LED's GPIO, see "gpios property" in
+  Documentation/devicetree/bindings/gpio/gpio.txt.  Active low LEDs should be
+  indicated using flags in the GPIO specifier.
+- label :  (optional)
+  see Documentation/devicetree/bindings/leds/common.txt
+- linux,default-trigger :  (optional)
+  see Documentation/devicetree/bindings/leds/common.txt
+- default-state:  (optional) The initial state of the LED.  Valid
+  values are "on", "off", and "keep".  If the LED is already on or off
+  and the default-state property is set the to same value, then no
+  glitch should be produced where the LED momentarily turns off (or
+  on).  The "keep" setting will keep the LED at whatever its current
+  state is, without producing a glitch.  The default is off if this
+  property is not present.
+
+Examples:
+
+leds {
+       compatible = "gpio-leds";
+       hdd {
+               label = "IDE Activity";
+               gpios = <&mcu_pio 0 1>; /* Active low */
+               linux,default-trigger = "ide-disk";
+       };
+
+       fault {
+               gpios = <&mcu_pio 1 0>;
+               /* Keep LED on if BIOS detected hardware fault */
+               default-state = "keep";
+       };
+};
+
+run-control {
+       compatible = "gpio-leds";
+       red {
+               gpios = <&mpc8572 6 0>;
+               default-state = "off";
+       };
+       green {
+               gpios = <&mpc8572 7 0>;
+               default-state = "on";
+       };
+};
index f0276b1b46fe6135f549cf37f7fe5e28c4efd4fe..b891e8459d85f2c6dd946939658e7d72e485a84d 100644 (file)
@@ -301,6 +301,15 @@ device tree) and probe.
 Platform Data
 -------------
 
+*** Note: platform data is the old way of doing things. It is
+*** basically a C structure which is passed to drivers to tell them about
+*** platform-specific settings like the address of its registers, bus
+*** speed, etc. Device tree is now the preferred way of handling this.
+*** Unless you have a good reason not to use device tree (the main one
+*** being you need serial support in SPL and don't have enough SRAM for
+*** the cut-down device tree and libfdt libraries) you should stay away
+*** from platform data.
+
 Platform data is like Linux platform data, if you are familiar with that.
 It provides the board-specific information to start up a device.
 
@@ -366,8 +375,12 @@ Device Tree
 -----------
 
 While platdata is useful, a more flexible way of providing device data is
-by using device tree. With device tree we replace the above code with the
-following device tree fragment:
+by using device tree. In U-Boot you should use this where possible. Avoid
+sending patches which make use of the U_BOOT_DEVICE() macro unless strictly
+necessary.
+
+With device tree we replace the above code with the following device tree
+fragment:
 
        red-square {
                compatible = "demo-shape";
index c7e526cc8a7f5c0a62e97993f2048e4c21caa03e..092bc02b304ef6dc9f8cfd6230a5c1ebbf653618 100644 (file)
@@ -1,5 +1,7 @@
 menu "Device Drivers"
 
+source "drivers/clk/Kconfig"
+
 source "drivers/core/Kconfig"
 
 source "drivers/cpu/Kconfig"
@@ -20,6 +22,8 @@ source "drivers/net/Kconfig"
 
 source "drivers/input/Kconfig"
 
+source "drivers/led/Kconfig"
+
 source "drivers/serial/Kconfig"
 
 source "drivers/tpm/Kconfig"
@@ -32,6 +36,8 @@ source "drivers/gpio/Kconfig"
 
 source "drivers/power/Kconfig"
 
+source "drivers/ram/Kconfig"
+
 source "drivers/hwmon/Kconfig"
 
 source "drivers/watchdog/Kconfig"
index 405b64b26873ce5076b56047128a4f62de565e73..5a35148ead10237b81e570cc68ddc8b078c66b6c 100644 (file)
@@ -1,3 +1,4 @@
+obj-$(CONFIG_CLK) += clk/
 obj-$(CONFIG_DM) += core/
 obj-$(CONFIG_DM_DEMO) += demo/
 obj-$(CONFIG_BIOSEMU) += bios_emulator/
@@ -7,9 +8,11 @@ obj-$(CONFIG_CPU) += cpu/
 obj-y += crypto/
 obj-$(CONFIG_FPGA) += fpga/
 obj-y += hwmon/
+obj-$(CONFIG_LED) += led/
 obj-y += misc/
 obj-y += pcmcia/
 obj-y += dfu/
+obj-$(CONFIG_RAM) += ram/
 obj-y += rtc/
 obj-y += sound/
 obj-y += tpm/
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
new file mode 100644 (file)
index 0000000..07eb54c
--- /dev/null
@@ -0,0 +1,19 @@
+config CLK
+       bool "Enable clock driver support"
+       depends on DM
+       help
+         This allows drivers to be provided for clock generators, including
+         oscillators and PLLs. Devices can use a common clock API to request
+         a particular clock rate and check on available clocks. Clocks can
+         feed into other clocks in a tree structure, with multiplexers to
+         choose the source for each clock.
+
+config SPL_CLK_SUPPORT
+       bool "Enable clock support in SPL"
+       depends on CLK
+       help
+         The clock subsystem adds a small amount of overhead to the image.
+         If this is acceptable and you have a need to use clock drivers in
+         SPL, enable this option. It might provide a cleaner interface to
+         setting up clocks within SPL, and allows the same drivers to be
+         used as U-Boot proper.
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
new file mode 100644 (file)
index 0000000..bb89fb9
--- /dev/null
@@ -0,0 +1,9 @@
+#
+# Copyright (c) 2015 Google, Inc
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# SPDX-License-Identifier:      GPL-2.0+
+#
+
+obj-$(CONFIG_CLK) += clk-uclass.o
+obj-$(CONFIG_SANDBOX) += clk_sandbox.o
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
new file mode 100644 (file)
index 0000000..73dfd7d
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <errno.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+
+ulong clk_get_rate(struct udevice *dev)
+{
+       struct clk_ops *ops = clk_get_ops(dev);
+
+       if (!ops->get_rate)
+               return -ENOSYS;
+
+       return ops->get_rate(dev);
+}
+
+ulong clk_set_rate(struct udevice *dev, ulong rate)
+{
+       struct clk_ops *ops = clk_get_ops(dev);
+
+       if (!ops->set_rate)
+               return -ENOSYS;
+
+       return ops->set_rate(dev, rate);
+}
+
+ulong clk_get_periph_rate(struct udevice *dev, int periph)
+{
+       struct clk_ops *ops = clk_get_ops(dev);
+
+       if (!ops->get_periph_rate)
+               return -ENOSYS;
+
+       return ops->get_periph_rate(dev, periph);
+}
+
+ulong clk_set_periph_rate(struct udevice *dev, int periph, ulong rate)
+{
+       struct clk_ops *ops = clk_get_ops(dev);
+
+       if (!ops->set_periph_rate)
+               return -ENOSYS;
+
+       return ops->set_periph_rate(dev, periph, rate);
+}
+
+UCLASS_DRIVER(clk) = {
+       .id             = UCLASS_CLK,
+       .name           = "clk",
+};
diff --git a/drivers/clk/clk_sandbox.c b/drivers/clk/clk_sandbox.c
new file mode 100644 (file)
index 0000000..058225a
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * (C) Copyright 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/test.h>
+
+struct sandbox_clk_priv {
+       ulong rate;
+       ulong periph_rate[PERIPH_ID_COUNT];
+};
+
+static ulong sandbox_clk_get_rate(struct udevice *dev)
+{
+       struct sandbox_clk_priv *priv = dev_get_priv(dev);
+
+       return priv->rate;
+}
+
+static ulong sandbox_clk_set_rate(struct udevice *dev, ulong rate)
+{
+       struct sandbox_clk_priv *priv = dev_get_priv(dev);
+
+       if (!rate)
+               return -EINVAL;
+       priv->rate = rate;
+       return 0;
+}
+
+ulong sandbox_get_periph_rate(struct udevice *dev, int periph)
+{
+       struct sandbox_clk_priv *priv = dev_get_priv(dev);
+
+       if (periph < PERIPH_ID_FIRST || periph >= PERIPH_ID_COUNT)
+               return -EINVAL;
+       return priv->periph_rate[periph];
+}
+
+ulong sandbox_set_periph_rate(struct udevice *dev, int periph, ulong rate)
+{
+       struct sandbox_clk_priv *priv = dev_get_priv(dev);
+       ulong old_rate;
+
+       if (periph < PERIPH_ID_FIRST || periph >= PERIPH_ID_COUNT)
+               return -EINVAL;
+       old_rate = priv->periph_rate[periph];
+       priv->periph_rate[periph] = rate;
+
+       return old_rate;
+}
+
+static int sandbox_clk_probe(struct udevice *dev)
+{
+       struct sandbox_clk_priv *priv = dev_get_priv(dev);
+
+       priv->rate = SANDBOX_CLK_RATE;
+
+       return 0;
+}
+
+static struct clk_ops sandbox_clk_ops = {
+       .get_rate       = sandbox_clk_get_rate,
+       .set_rate       = sandbox_clk_set_rate,
+       .get_periph_rate = sandbox_get_periph_rate,
+       .set_periph_rate = sandbox_set_periph_rate,
+};
+
+static const struct udevice_id sandbox_clk_ids[] = {
+       { .compatible = "sandbox,clk" },
+       { }
+};
+
+U_BOOT_DRIVER(clk_sandbox) = {
+       .name           = "clk_sandbox",
+       .id             = UCLASS_CLK,
+       .of_match       = sandbox_clk_ids,
+       .ops            = &sandbox_clk_ops,
+       .priv_auto_alloc_size = sizeof(struct sandbox_clk_priv),
+       .probe          = sandbox_clk_probe,
+};
index 2861b4307955854ef1b0b5f51b7beedffd7e4fa9..e40372dd753c9c6e140d6037c3189bc824818b66 100644 (file)
@@ -38,6 +38,10 @@ config DM_DEVICE_REMOVE
          device. This is not normally required in SPL, so by default this
          option is disabled for SPL.
 
+         Note that this may have undesirable results in the USB subsystem as
+         it causes unplugged devices to linger around in the dm-tree, and it
+         causes USB host controllers to not be stopped when booting the OS.
+
 config DM_STDIO
        bool "Support stdio registration"
        depends on DM
index a3fec3850395512d3fdb177feb49ebb1381ca224..5c2ead870b00412bf0ebc5532a21b4ebdfd82974 100644 (file)
@@ -4,8 +4,11 @@
 # SPDX-License-Identifier:     GPL-2.0+
 #
 
-obj-$(CONFIG_DM)       += device.o lists.o root.o uclass.o util.o
+obj-y  += device.o lists.o root.o uclass.o util.o
 ifndef CONFIG_SPL_BUILD
 obj-$(CONFIG_OF_CONTROL) += simple-bus.o
 endif
 obj-$(CONFIG_DM_DEVICE_REMOVE) += device-remove.o
+obj-$(CONFIG_DM)       += dump.o
+obj-$(CONFIG_OF_CONTROL)       += regmap.o
+obj-$(CONFIG_OF_CONTROL)       += syscon-uclass.o
index 6a16b4f690fd9392eb7637799ac777b3befc2e1f..6b87f865e40377fc1a2e179fa4f4d394d8124abf 100644 (file)
 #include <dm/uclass-internal.h>
 #include <dm/util.h>
 
-/**
- * device_chld_unbind() - Unbind all device's children from the device
- *
- * On error, the function continues to unbind all children, and reports the
- * first error.
- *
- * @dev:       The device that is to be stripped of its children
- * @return 0 on success, -ve on error
- */
-static int device_chld_unbind(struct udevice *dev)
+int device_unbind_children(struct udevice *dev)
 {
        struct udevice *pos, *n;
        int ret, saved_ret = 0;
@@ -43,12 +34,7 @@ static int device_chld_unbind(struct udevice *dev)
        return saved_ret;
 }
 
-/**
- * device_chld_remove() - Stop all device's children
- * @dev:       The device whose children are to be removed
- * @return 0 on success, -ve on error
- */
-static int device_chld_remove(struct udevice *dev)
+int device_remove_children(struct udevice *dev)
 {
        struct udevice *pos, *n;
        int ret;
@@ -84,7 +70,7 @@ int device_unbind(struct udevice *dev)
                        return ret;
        }
 
-       ret = device_chld_unbind(dev);
+       ret = device_unbind_children(dev);
        if (ret)
                return ret;
 
@@ -159,7 +145,7 @@ int device_remove(struct udevice *dev)
        if (ret)
                return ret;
 
-       ret = device_chld_remove(dev);
+       ret = device_remove_children(dev);
        if (ret)
                goto err;
 
index 85fd1fc7350331d48721539cbb42ca5ae33f8206..51b1b44e5b0a0834942fbce69e74a0ff9592fcec 100644 (file)
@@ -284,7 +284,6 @@ int device_probe_child(struct udevice *dev, void *parent_priv)
                        goto fail;
        }
 
-       dev->flags |= DM_FLAG_ACTIVATED;
        if (drv->probe) {
                ret = drv->probe(dev);
                if (ret) {
@@ -330,7 +329,7 @@ void *dev_get_platdata(struct udevice *dev)
 void *dev_get_parent_platdata(struct udevice *dev)
 {
        if (!dev) {
-               dm_warn("%s: null device", __func__);
+               dm_warn("%s: null device\n", __func__);
                return NULL;
        }
 
@@ -340,7 +339,7 @@ void *dev_get_parent_platdata(struct udevice *dev)
 void *dev_get_uclass_platdata(struct udevice *dev)
 {
        if (!dev) {
-               dm_warn("%s: null device", __func__);
+               dm_warn("%s: null device\n", __func__);
                return NULL;
        }
 
@@ -459,17 +458,42 @@ int device_find_child_by_of_offset(struct udevice *parent, int of_offset,
        return -ENODEV;
 }
 
-int device_get_child_by_of_offset(struct udevice *parent, int seq,
+int device_get_child_by_of_offset(struct udevice *parent, int node,
                                  struct udevice **devp)
 {
        struct udevice *dev;
        int ret;
 
        *devp = NULL;
-       ret = device_find_child_by_of_offset(parent, seq, &dev);
+       ret = device_find_child_by_of_offset(parent, node, &dev);
        return device_get_device_tail(dev, ret, devp);
 }
 
+static struct udevice *_device_find_global_by_of_offset(struct udevice *parent,
+                                                       int of_offset)
+{
+       struct udevice *dev, *found;
+
+       if (parent->of_offset == of_offset)
+               return parent;
+
+       list_for_each_entry(dev, &parent->child_head, sibling_node) {
+               found = _device_find_global_by_of_offset(dev, of_offset);
+               if (found)
+                       return found;
+       }
+
+       return NULL;
+}
+
+int device_get_global_by_of_offset(int of_offset, struct udevice **devp)
+{
+       struct udevice *dev;
+
+       dev = _device_find_global_by_of_offset(gd->dm_root, of_offset);
+       return device_get_device_tail(dev, dev ? 0 : -ENOENT, devp);
+}
+
 int device_find_first_child(struct udevice *parent, struct udevice **devp)
 {
        if (list_empty(&parent->child_head)) {
diff --git a/drivers/core/dump.c b/drivers/core/dump.c
new file mode 100644 (file)
index 0000000..fd4596e
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <mapmem.h>
+#include <dm/root.h>
+
+static void show_devices(struct udevice *dev, int depth, int last_flag)
+{
+       int i, is_last;
+       struct udevice *child;
+       char class_name[12];
+
+       /* print the first 11 characters to not break the tree-format. */
+       strlcpy(class_name, dev->uclass->uc_drv->name, sizeof(class_name));
+       printf(" %-11s [ %c ]    ", class_name,
+              dev->flags & DM_FLAG_ACTIVATED ? '+' : ' ');
+
+       for (i = depth; i >= 0; i--) {
+               is_last = (last_flag >> i) & 1;
+               if (i) {
+                       if (is_last)
+                               printf("    ");
+                       else
+                               printf("|   ");
+               } else {
+                       if (is_last)
+                               printf("`-- ");
+                       else
+                               printf("|-- ");
+               }
+       }
+
+       printf("%s\n", dev->name);
+
+       list_for_each_entry(child, &dev->child_head, sibling_node) {
+               is_last = list_is_last(&child->sibling_node, &dev->child_head);
+               show_devices(child, depth + 1, (last_flag << 1) | is_last);
+       }
+}
+
+void dm_dump_all(void)
+{
+       struct udevice *root;
+
+       root = dm_root();
+       if (root) {
+               printf(" Class       Probed   Name\n");
+               printf("----------------------------------------\n");
+               show_devices(root, -1, 0);
+       }
+}
+
+/**
+ * dm_display_line() - Display information about a single device
+ *
+ * Displays a single line of information with an option prefix
+ *
+ * @dev:       Device to display
+ */
+static void dm_display_line(struct udevice *dev)
+{
+       printf("- %c %s @ %08lx",
+              dev->flags & DM_FLAG_ACTIVATED ? '*' : ' ',
+              dev->name, (ulong)map_to_sysmem(dev));
+       if (dev->seq != -1 || dev->req_seq != -1)
+               printf(", seq %d, (req %d)", dev->seq, dev->req_seq);
+       puts("\n");
+}
+
+void dm_dump_uclass(void)
+{
+       struct uclass *uc;
+       int ret;
+       int id;
+
+       for (id = 0; id < UCLASS_COUNT; id++) {
+               struct udevice *dev;
+
+               ret = uclass_get(id, &uc);
+               if (ret)
+                       continue;
+
+               printf("uclass %d: %s\n", id, uc->uc_drv->name);
+               if (list_empty(&uc->dev_head))
+                       continue;
+               list_for_each_entry(dev, &uc->dev_head, uclass_node) {
+                       dm_display_line(dev);
+               }
+               puts("\n");
+       }
+}
index 0c49d99f47edce622ee70df459191746ae1ee789..2e52500ef25c7ee145c22240cae67356b212bf99 100644 (file)
@@ -86,13 +86,13 @@ int device_bind_driver_to_node(struct udevice *parent, const char *drv_name,
 
        drv = lists_driver_lookup_name(drv_name);
        if (!drv) {
-               printf("Cannot find driver '%s'\n", drv_name);
+               debug("Cannot find driver '%s'\n", drv_name);
                return -ENOENT;
        }
        ret = device_bind(parent, drv, dev_name, NULL, node, devp);
        if (ret) {
-               printf("Cannot create device named '%s' (err=%d)\n",
-                      dev_name, ret);
+               debug("Cannot create device named '%s' (err=%d)\n",
+                     dev_name, ret);
                return ret;
        }
 
diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c
new file mode 100644 (file)
index 0000000..519832f
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <libfdt.h>
+#include <malloc.h>
+#include <mapmem.h>
+#include <regmap.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int regmap_init_mem(struct udevice *dev, struct regmap **mapp)
+{
+       const void *blob = gd->fdt_blob;
+       struct regmap_range *range;
+       const fdt32_t *cell;
+       struct regmap *map;
+       int count;
+       int addr_len, size_len, both_len;
+       int parent;
+       int len;
+
+       parent = dev->parent->of_offset;
+       addr_len = fdt_address_cells(blob, parent);
+       size_len = fdt_size_cells(blob, parent);
+       both_len = addr_len + size_len;
+
+       cell = fdt_getprop(blob, dev->of_offset, "reg", &len);
+       len /= sizeof(*cell);
+       count = len / both_len;
+       if (!cell || !count)
+               return -EINVAL;
+
+       map = malloc(sizeof(struct regmap));
+       if (!map)
+               return -ENOMEM;
+
+       if (count <= 1) {
+               map->range = &map->base_range;
+       } else {
+               map->range = malloc(count * sizeof(struct regmap_range));
+               if (!map->range) {
+                       free(map);
+                       return -ENOMEM;
+               }
+       }
+
+       map->base = fdtdec_get_number(cell, addr_len);
+       map->range_count = count;
+
+       for (range = map->range; count > 0;
+            count--, cell += both_len, range++) {
+               range->start = fdtdec_get_number(cell, addr_len);
+               range->size = fdtdec_get_number(cell + addr_len, size_len);
+       }
+
+       *mapp = map;
+
+       return 0;
+}
+
+void *regmap_get_range(struct regmap *map, unsigned int range_num)
+{
+       struct regmap_range *range;
+
+       if (range_num >= map->range_count)
+               return NULL;
+       range = &map->range[range_num];
+
+       return map_sysmem(range->start, range->size);
+}
+
+int regmap_uninit(struct regmap *map)
+{
+       if (map->range_count > 1)
+               free(map->range);
+       free(map);
+
+       return 0;
+}
diff --git a/drivers/core/syscon-uclass.c b/drivers/core/syscon-uclass.c
new file mode 100644 (file)
index 0000000..686c320
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <syscon.h>
+#include <dm.h>
+#include <errno.h>
+#include <regmap.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+#include <linux/err.h>
+
+struct regmap *syscon_get_regmap(struct udevice *dev)
+{
+       struct syscon_uc_info *priv;
+
+       if (device_get_uclass_id(dev) != UCLASS_SYSCON)
+               return ERR_PTR(-ENOEXEC);
+       priv = dev_get_uclass_priv(dev);
+       return priv->regmap;
+}
+
+static int syscon_pre_probe(struct udevice *dev)
+{
+       struct syscon_uc_info *priv = dev_get_uclass_priv(dev);
+
+       return regmap_init_mem(dev, &priv->regmap);
+}
+
+struct regmap *syscon_get_regmap_by_driver_data(ulong driver_data)
+{
+       struct udevice *dev;
+       struct uclass *uc;
+       int ret;
+
+       ret = uclass_get(UCLASS_SYSCON, &uc);
+       if (ret)
+               return ERR_PTR(ret);
+       uclass_foreach_dev(dev, uc) {
+               if (dev->driver_data == driver_data) {
+                       struct syscon_uc_info *priv;
+                       int ret;
+
+                       ret = device_probe(dev);
+                       if (ret)
+                               return ERR_PTR(ret);
+                       priv = dev_get_uclass_priv(dev);
+
+                       return priv->regmap;
+               }
+       }
+
+       return ERR_PTR(-ENODEV);
+}
+
+void *syscon_get_first_range(ulong driver_data)
+{
+       struct regmap *map;
+
+       map = syscon_get_regmap_by_driver_data(driver_data);
+       if (IS_ERR(map))
+               return map;
+       return regmap_get_range(map, 0);
+}
+
+UCLASS_DRIVER(syscon) = {
+       .id             = UCLASS_SYSCON,
+       .name           = "syscon",
+       .per_device_auto_alloc_size = sizeof(struct syscon_uc_info),
+       .pre_probe = syscon_pre_probe,
+};
index 7de817324b90fe22e99a2948f34a11926eaee2f7..aba98801fd4505b269f3aecf6ac454c3f21bff86 100644 (file)
@@ -56,8 +56,8 @@ static int uclass_add(enum uclass_id id, struct uclass **ucp)
        *ucp = NULL;
        uc_drv = lists_uclass_lookup(id);
        if (!uc_drv) {
-               dm_warn("Cannot find uclass for id %d: please add the UCLASS_DRIVER() declaration for this UCLASS_... id\n",
-                       id);
+               debug("Cannot find uclass for id %d: please add the UCLASS_DRIVER() declaration for this UCLASS_... id\n",
+                     id);
                return -ENOENT;
        }
        uc = calloc(1, sizeof(*uc));
index 586485055db68afdfb463f3eb3c9114a7c4f15f7..67c6374d4736451843ed8906958bcc753e52fb91 100644 (file)
@@ -6,13 +6,9 @@
 #
 
 ifndef CONFIG_SPL_BUILD
-obj-$(CONFIG_DM_GPIO)          += gpio-uclass.o
 obj-$(CONFIG_AXP_GPIO)         += axp_gpio.o
 endif
-/* TODO(sjg@chromium.org): Only tegra supports driver model in SPL */
-ifdef CONFIG_TEGRA_GPIO
 obj-$(CONFIG_DM_GPIO)          += gpio-uclass.o
-endif
 
 obj-$(CONFIG_AT91_GPIO)        += at91_gpio.o
 obj-$(CONFIG_INTEL_ICH6_GPIO)  += intel_ich6_gpio.o
index bf982b9d193143a9aed74eaed867f4267771d702..4efda311a49e81c8470a23d88f62a09b07f0f5bc 100644 (file)
@@ -48,8 +48,7 @@ static int gpio_to_device(unsigned int gpio, struct gpio_desc *desc)
        return ret ? ret : -ENOENT;
 }
 
-int gpio_lookup_name(const char *name, struct udevice **devp,
-                    unsigned int *offsetp, unsigned int *gpiop)
+int dm_gpio_lookup_name(const char *name, struct gpio_desc *desc)
 {
        struct gpio_dev_priv *uc_priv = NULL;
        struct udevice *dev;
@@ -57,8 +56,6 @@ int gpio_lookup_name(const char *name, struct udevice **devp,
        int numeric;
        int ret;
 
-       if (devp)
-               *devp = NULL;
        numeric = isdigit(*name) ? simple_strtoul(name, NULL, 10) : -1;
        for (ret = uclass_first_device(UCLASS_GPIO, &dev);
             dev;
@@ -84,12 +81,33 @@ int gpio_lookup_name(const char *name, struct udevice **devp,
        if (!dev)
                return ret ? ret : -EINVAL;
 
+       desc->dev = dev;
+       desc->offset = offset;
+
+       return 0;
+}
+
+int gpio_lookup_name(const char *name, struct udevice **devp,
+                    unsigned int *offsetp, unsigned int *gpiop)
+{
+       struct gpio_desc desc;
+       int ret;
+
+       if (devp)
+               *devp = NULL;
+       ret = dm_gpio_lookup_name(name, &desc);
+       if (ret)
+               return ret;
+
        if (devp)
-               *devp = dev;
+               *devp = desc.dev;
        if (offsetp)
-               *offsetp = offset;
-       if (gpiop)
-               *gpiop = uc_priv->gpio_base + offset;
+               *offsetp = desc.offset;
+       if (gpiop) {
+               struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(desc.dev);
+
+               *gpiop = uc_priv->gpio_base + desc.offset;
+       }
 
        return 0;
 }
@@ -109,7 +127,7 @@ static int gpio_find_and_xlate(struct gpio_desc *desc,
        return ops->xlate ? ops->xlate(desc->dev, desc, args) : 0;
 }
 
-static int dm_gpio_request(struct gpio_desc *desc, const char *label)
+int dm_gpio_request(struct gpio_desc *desc, const char *label)
 {
        struct udevice *dev = desc->dev;
        struct gpio_dev_priv *uc_priv;
diff --git a/drivers/led/Kconfig b/drivers/led/Kconfig
new file mode 100644 (file)
index 0000000..de5feea
--- /dev/null
@@ -0,0 +1,26 @@
+config LED
+       bool "Enable LED support"
+       depends on DM
+       help
+         Many boards have LEDs which can be used to signal status or alerts.
+         U-Boot provides a uclass API to implement this feature. LED drivers
+         can provide access to board-specific LEDs. Use of the device tree
+         for configuration is encouraged.
+
+config SPL_LED_SUPPORT
+       bool "Enable LED support in SPL"
+       depends on LED
+       help
+         The LED subsystem adds a small amount of overhead to the image.
+         If this is acceptable and you have a need to use LEDs in SPL,
+         enable this option. You will need to enable device tree in SPL
+         for this to work.
+
+config LED_GPIO
+       bool "LED support for GPIO-connected LEDs"
+       depends on LED && DM_GPIO
+       help
+         Enable support for LEDs which are connected to GPIO lines. These
+         GPIOs may be on the SoC or some other device which provides GPIOs.
+         The GPIO driver must used driver model. LEDs are configured using
+         the device tree.
diff --git a/drivers/led/Makefile b/drivers/led/Makefile
new file mode 100644 (file)
index 0000000..990129e
--- /dev/null
@@ -0,0 +1,9 @@
+#
+# Copyright (c) 2015 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+# SPDX-License-Identifier:     GPL-2.0+
+#
+
+obj-$(CONFIG_LED) += led-uclass.o
+obj-$(CONFIG_LED_GPIO) += led_gpio.o
diff --git a/drivers/led/led-uclass.c b/drivers/led/led-uclass.c
new file mode 100644 (file)
index 0000000..784ac87
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <led.h>
+#include <dm/root.h>
+#include <dm/uclass-internal.h>
+
+int led_get_by_label(const char *label, struct udevice **devp)
+{
+       struct udevice *dev;
+       struct uclass *uc;
+       int ret;
+
+       ret = uclass_get(UCLASS_LED, &uc);
+       if (ret)
+               return ret;
+       uclass_foreach_dev(dev, uc) {
+               struct led_uclass_plat *uc_plat = dev_get_uclass_platdata(dev);
+
+               /* Ignore the top-level LED node */
+               if (uc_plat->label && !strcmp(label, uc_plat->label))
+                       return uclass_get_device_tail(dev, 0, devp);
+       }
+
+       return -ENODEV;
+}
+
+int led_set_on(struct udevice *dev, int on)
+{
+       struct led_ops *ops = led_get_ops(dev);
+
+       if (!ops->set_on)
+               return -ENOSYS;
+
+       return ops->set_on(dev, on);
+}
+
+UCLASS_DRIVER(led) = {
+       .id             = UCLASS_LED,
+       .name           = "led",
+       .per_device_platdata_auto_alloc_size = sizeof(struct led_uclass_plat),
+};
diff --git a/drivers/led/led_gpio.c b/drivers/led/led_gpio.c
new file mode 100644 (file)
index 0000000..cb6e996
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <led.h>
+#include <asm/gpio.h>
+#include <dm/lists.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct led_gpio_priv {
+       struct gpio_desc gpio;
+};
+
+static int gpio_led_set_on(struct udevice *dev, int on)
+{
+       struct led_gpio_priv *priv = dev_get_priv(dev);
+
+       if (!dm_gpio_is_valid(&priv->gpio))
+               return -EREMOTEIO;
+
+       return dm_gpio_set_value(&priv->gpio, on);
+}
+
+static int led_gpio_probe(struct udevice *dev)
+{
+       struct led_uclass_plat *uc_plat = dev_get_uclass_platdata(dev);
+       struct led_gpio_priv *priv = dev_get_priv(dev);
+
+       /* Ignore the top-level LED node */
+       if (!uc_plat->label)
+               return 0;
+       return gpio_request_by_name(dev, "gpios", 0, &priv->gpio, GPIOD_IS_OUT);
+}
+
+static int led_gpio_remove(struct udevice *dev)
+{
+       /*
+        * The GPIO driver may have already been removed. We will need to
+        * address this more generally.
+        */
+#ifndef CONFIG_SANDBOX
+       struct led_gpio_priv *priv = dev_get_priv(dev);
+
+       if (dm_gpio_is_valid(&priv->gpio))
+               dm_gpio_free(dev, &priv->gpio);
+#endif
+
+       return 0;
+}
+
+static int led_gpio_bind(struct udevice *parent)
+{
+       const void *blob = gd->fdt_blob;
+       struct udevice *dev;
+       int node;
+       int ret;
+
+       for (node = fdt_first_subnode(blob, parent->of_offset);
+            node > 0;
+            node = fdt_next_subnode(blob, node)) {
+               struct led_uclass_plat *uc_plat;
+               const char *label;
+
+               label = fdt_getprop(blob, node, "label", NULL);
+               if (!label) {
+                       debug("%s: node %s has no label\n", __func__,
+                             fdt_get_name(blob, node, NULL));
+                       return -EINVAL;
+               }
+               ret = device_bind_driver_to_node(parent, "gpio_led",
+                                                fdt_get_name(blob, node, NULL),
+                                                node, &dev);
+               if (ret)
+                       return ret;
+               uc_plat = dev_get_uclass_platdata(dev);
+               uc_plat->label = label;
+       }
+
+       return 0;
+}
+
+static const struct led_ops gpio_led_ops = {
+       .set_on         = gpio_led_set_on,
+};
+
+static const struct udevice_id led_gpio_ids[] = {
+       { .compatible = "gpio-leds" },
+       { }
+};
+
+U_BOOT_DRIVER(led_gpio) = {
+       .name   = "gpio_led",
+       .id     = UCLASS_LED,
+       .of_match = led_gpio_ids,
+       .ops    = &gpio_led_ops,
+       .priv_auto_alloc_size = sizeof(struct led_gpio_priv),
+       .bind   = led_gpio_bind,
+       .probe  = led_gpio_probe,
+       .remove = led_gpio_remove,
+};
index 64b07a30155b6622349e611c9d6eaecd443fb244..3b7f76ab78753c9ca6f2252b6130f536ffe3b961 100644 (file)
@@ -73,3 +73,12 @@ config PCA9551_I2C_ADDR
        default 0x60
        help
          The I2C address of the PCA9551 LED controller.
+
+config RESET
+       bool "Enable support for reset drivers"
+       depends on DM
+       help
+         Enable reset drivers which can be used to reset the CPU or board.
+         Each driver can provide a reset method which will be called to
+         effect a reset. The uclass will try all available drivers when
+         reset_walk() is called.
index 120babc4b5d87e2ac344f96d1f4849f6de80ce54..5218b91c0baf8a957b11aaca86f5403fb25f4e82 100644 (file)
@@ -22,13 +22,16 @@ obj-$(CONFIG_MXC_OCOTP) += mxc_ocotp.o
 obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o
 obj-$(CONFIG_NS87308) += ns87308.o
 obj-$(CONFIG_PDSP188x) += pdsp188x.o
+obj-$(CONFIG_SANDBOX) += reset_sandbox.o
 ifdef CONFIG_DM_I2C
 obj-$(CONFIG_SANDBOX) += i2c_eeprom_emul.o
 endif
 obj-$(CONFIG_SMSC_LPC47M) += smsc_lpc47m.o
 obj-$(CONFIG_STATUS_LED) += status_led.o
 obj-$(CONFIG_SANDBOX) += swap_case.o
+obj-$(CONFIG_SANDBOX) += syscon_sandbox.o
 obj-$(CONFIG_TWL4030_LED) += twl4030_led.o
 obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
 obj-$(CONFIG_FSL_SEC_MON) += fsl_sec_mon.o
 obj-$(CONFIG_PCA9551_LED) += pca9551_led.o
+obj-$(CONFIG_RESET) += reset-uclass.o
diff --git a/drivers/misc/reset-uclass.c b/drivers/misc/reset-uclass.c
new file mode 100644 (file)
index 0000000..fdb5c6f
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <reset.h>
+#include <dm.h>
+#include <errno.h>
+#include <regmap.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+#include <linux/err.h>
+
+int reset_request(struct udevice *dev, enum reset_t type)
+{
+       struct reset_ops *ops = reset_get_ops(dev);
+
+       if (!ops->request)
+               return -ENOSYS;
+
+       return ops->request(dev, type);
+}
+
+int reset_walk(enum reset_t type)
+{
+       struct udevice *dev;
+       int ret = -ENOSYS;
+
+       while (ret != -EINPROGRESS && type < RESET_COUNT) {
+               for (uclass_first_device(UCLASS_RESET, &dev);
+                    dev;
+                    uclass_next_device(&dev)) {
+                       ret = reset_request(dev, type);
+                       if (ret == -EINPROGRESS)
+                               break;
+               }
+               type++;
+       }
+
+       return ret;
+}
+
+void reset_walk_halt(enum reset_t type)
+{
+       int ret;
+
+       ret = reset_walk(type);
+
+       /* Wait for the reset to take effect */
+       if (ret == -EINPROGRESS)
+               mdelay(100);
+
+       /* Still no reset? Give up */
+       printf("Reset not supported on this platform\n");
+       hang();
+}
+
+/**
+ * reset_cpu() - calls reset_walk(RESET_WARM)
+ */
+void reset_cpu(ulong addr)
+{
+       reset_walk_halt(RESET_WARM);
+}
+
+
+int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       reset_walk_halt(RESET_WARM);
+
+       return 0;
+}
+
+UCLASS_DRIVER(reset) = {
+       .id             = UCLASS_RESET,
+       .name           = "reset",
+};
diff --git a/drivers/misc/reset_sandbox.c b/drivers/misc/reset_sandbox.c
new file mode 100644 (file)
index 0000000..917121b
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <reset.h>
+#include <asm/state.h>
+#include <asm/test.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int sandbox_warm_reset_request(struct udevice *dev, enum reset_t type)
+{
+       struct sandbox_state *state = state_get_current();
+
+       switch (type) {
+       case RESET_WARM:
+               state->last_reset = type;
+               break;
+       default:
+               return -ENOSYS;
+       }
+       if (!state->reset_allowed[type])
+               return -EACCES;
+
+       return -EINPROGRESS;
+}
+
+static int sandbox_reset_request(struct udevice *dev, enum reset_t type)
+{
+       struct sandbox_state *state = state_get_current();
+
+       /*
+        * If we have a device tree, the device we created from platform data
+        * (see the U_BOOT_DEVICE() declaration below) should not do anything.
+        * If we are that device, return an error.
+        */
+       if (gd->fdt_blob && dev->of_offset == -1)
+               return -ENODEV;
+
+       switch (type) {
+       case RESET_COLD:
+               state->last_reset = type;
+               break;
+       case RESET_POWER:
+               state->last_reset = type;
+               if (!state->reset_allowed[type])
+                       return -EACCES;
+               sandbox_exit();
+               break;
+       default:
+               return -ENOSYS;
+       }
+       if (!state->reset_allowed[type])
+               return -EACCES;
+
+       return -EINPROGRESS;
+}
+
+static struct reset_ops sandbox_reset_ops = {
+       .request        = sandbox_reset_request,
+};
+
+static const struct udevice_id sandbox_reset_ids[] = {
+       { .compatible = "sandbox,reset" },
+       { }
+};
+
+U_BOOT_DRIVER(reset_sandbox) = {
+       .name           = "reset_sandbox",
+       .id             = UCLASS_RESET,
+       .of_match       = sandbox_reset_ids,
+       .ops            = &sandbox_reset_ops,
+};
+
+static struct reset_ops sandbox_warm_reset_ops = {
+       .request        = sandbox_warm_reset_request,
+};
+
+static const struct udevice_id sandbox_warm_reset_ids[] = {
+       { .compatible = "sandbox,warm-reset" },
+       { }
+};
+
+U_BOOT_DRIVER(warm_reset_sandbox) = {
+       .name           = "warm_reset_sandbox",
+       .id             = UCLASS_RESET,
+       .of_match       = sandbox_warm_reset_ids,
+       .ops            = &sandbox_warm_reset_ops,
+};
+
+/* This is here in case we don't have a device tree */
+U_BOOT_DEVICE(reset_sandbox_non_fdt) = {
+       .name = "reset_sandbox",
+};
diff --git a/drivers/misc/syscon_sandbox.c b/drivers/misc/syscon_sandbox.c
new file mode 100644 (file)
index 0000000..ccfab3e
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <syscon.h>
+#include <asm/test.h>
+#include <dm/lists.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const struct udevice_id sandbox_syscon_ids[] = {
+       { .compatible = "sandbox,syscon0", .data = SYSCON0 },
+       { .compatible = "sandbox,syscon1", .data = SYSCON1 },
+       { }
+};
+
+U_BOOT_DRIVER(sandbox_syscon) = {
+       .name   = "sandbox_syscon",
+       .id     = UCLASS_SYSCON,
+       .of_match = sandbox_syscon_ids,
+};
index 7ba85a2b62c45b5f968dbddc1994d7f174163e9a..3e835f7bca0b6c374e94a7b0f09c7d51654fad2e 100644 (file)
@@ -1,5 +1,15 @@
 menu "MMC Host controller Support"
 
+config DM_MMC
+       bool "Enable MMC controllers using Driver Model"
+       depends on DM
+       help
+         This enables the MultiMediaCard (MMC) uclass which suports MMC and
+         Secure Digital I/O (SDIO) cards. Both removable (SD, micro-SD, etc.)
+         and non-removable (e.g. eMMC chip) devices are supported. These
+         appear as block devices in U-Boot and can support filesystems such
+         as EXT4 and FAT.
+
 config SH_SDHI
        bool "SuperH/Renesas ARM SoCs on-chip SDHI host controller support"
        depends on RMOBILE
index ed7368773516753e994e1c60300b96c6f5620b87..286df2fc7d360f1e615dddaab8c04a62014fbbbb 100644 (file)
@@ -5,6 +5,8 @@
 # SPDX-License-Identifier:     GPL-2.0+
 #
 
+obj-$(CONFIG_DM_MMC) += mmc-uclass.o
+
 obj-$(CONFIG_ARM_PL180_MMCI) += arm_pl180_mmci.o
 obj-$(CONFIG_BCM2835_SDHCI) += bcm2835_sdhci.o
 obj-$(CONFIG_BFIN_SDH) += bfin_sdh.o
@@ -29,6 +31,7 @@ obj-$(CONFIG_PXA_MMC_GENERIC) += pxa_mmc_gen.o
 obj-$(CONFIG_SUPPORT_EMMC_RPMB) += rpmb.o
 obj-$(CONFIG_S3C_SDI) += s3c_sdi.o
 obj-$(CONFIG_S5P_SDHCI) += s5p_sdhci.o
+obj-$(CONFIG_SANDBOX) += sandbox_mmc.o
 obj-$(CONFIG_SDHCI) += sdhci.o
 obj-$(CONFIG_SH_MMCIF) += sh_mmcif.o
 obj-$(CONFIG_SH_SDHI) += sh_sdhi.o
diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c
new file mode 100644 (file)
index 0000000..777489f
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <mmc.h>
+#include <dm.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+
+struct mmc *mmc_get_mmc_dev(struct udevice *dev)
+{
+       struct mmc_uclass_priv *upriv;
+
+       if (!device_active(dev))
+               return NULL;
+       upriv = dev_get_uclass_priv(dev);
+       return upriv->mmc;
+}
+
+U_BOOT_DRIVER(mmc) = {
+       .name   = "mmc",
+       .id     = UCLASS_MMC,
+};
+
+UCLASS_DRIVER(mmc) = {
+       .id             = UCLASS_MMC,
+       .name           = "mmc",
+       .flags          = DM_UC_FLAG_SEQ_ALIAS,
+       .per_device_auto_alloc_size = sizeof(struct mmc_uclass_priv),
+};
index 79e6feeb13aca8a3ac55f92478307bf8dbfc8319..da47037a3066260a5596d35c1cf033f7102c2afe 100644 (file)
@@ -250,14 +250,18 @@ static ulong mmc_bread(int dev_num, lbaint_t start, lbaint_t blkcnt, void *dst)
                return 0;
        }
 
-       if (mmc_set_blocklen(mmc, mmc->read_bl_len))
+       if (mmc_set_blocklen(mmc, mmc->read_bl_len)) {
+               debug("%s: Failed to set blocklen\n", __func__);
                return 0;
+       }
 
        do {
                cur = (blocks_todo > mmc->cfg->b_max) ?
                        mmc->cfg->b_max : blocks_todo;
-               if(mmc_read_blocks(mmc, dst, start, cur) != cur)
+               if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
+                       debug("%s: Failed to read blocks\n", __func__);
                        return 0;
+               }
                blocks_todo -= cur;
                start += cur;
                dst += cur * mmc->read_bl_len;
@@ -1761,8 +1765,10 @@ int mmc_initialize(bd_t *bis)
        INIT_LIST_HEAD (&mmc_devices);
        cur_dev_num = 0;
 
+#ifndef CONFIG_DM_MMC
        if (board_mmc_init(bis) < 0)
                cpu_mmc_init(bis);
+#endif
 
 #ifndef CONFIG_SPL_BUILD
        print_mmc_devices(',');
diff --git a/drivers/mmc/sandbox_mmc.c b/drivers/mmc/sandbox_mmc.c
new file mode 100644 (file)
index 0000000..f4646a8
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <mmc.h>
+#include <asm/test.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const struct udevice_id sandbox_mmc_ids[] = {
+       { .compatible = "sandbox,mmc" },
+       { }
+};
+
+U_BOOT_DRIVER(warm_mmc_sandbox) = {
+       .name           = "mmc_sandbox",
+       .id             = UCLASS_MMC,
+       .of_match       = sandbox_mmc_ids,
+};
index 645ca6427cf41843f90a8fdcf3c941ae144e83c9..bcae842389aae9de0f2f8e0425c6f9b27dba2775 100644 (file)
@@ -528,7 +528,7 @@ static int designware_eth_send(struct udevice *dev, void *packet, int length)
        return _dw_eth_send(priv, packet, length);
 }
 
-static int designware_eth_recv(struct udevice *dev, uchar **packetp)
+static int designware_eth_recv(struct udevice *dev, int flags, uchar **packetp)
 {
        struct dw_eth_dev *priv = dev_get_priv(dev);
 
index 958488c19a1c56d7a2f5353a544ca3e1a2d8b561..7b6e20f30fbfe3ee4f0413be7dce4f4f645be219 100644 (file)
  * Modified to use le32_to_cpu and cpu_to_le32 properly
  */
 #include <common.h>
+#include <dm.h>
 #include <errno.h>
 #include <malloc.h>
 #include <net.h>
+#ifndef CONFIG_DM_ETH
 #include <netdev.h>
+#endif
 #include <asm/io.h>
 #include <pci.h>
 
@@ -281,6 +284,8 @@ struct RxDesc {
        u32 buf_Haddr;
 };
 
+static unsigned char rxdata[RX_BUF_LEN];
+
 #define RTL8169_DESC_SIZE 16
 
 #if ARCH_DMA_MINALIGN > 256
@@ -299,7 +304,8 @@ struct RxDesc {
  * the driver to allocate descriptors from a pool of non-cached memory.
  */
 #if RTL8169_DESC_SIZE < ARCH_DMA_MINALIGN
-#if !defined(CONFIG_SYS_NONCACHED_MEMORY) && !defined(CONFIG_SYS_DCACHE_OFF)
+#if !defined(CONFIG_SYS_NONCACHED_MEMORY) && \
+       !defined(CONFIG_SYS_DCACHE_OFF) && !defined(CONFIG_X86)
 #warning cache-line size is larger than descriptor size
 #endif
 #endif
@@ -317,6 +323,7 @@ DEFINE_ALIGN_BUFFER(u8, txb, NUM_TX_DESC * RX_BUF_SIZE, RTL8169_ALIGN);
 DEFINE_ALIGN_BUFFER(u8, rxb, NUM_RX_DESC * RX_BUF_SIZE, RTL8169_ALIGN);
 
 struct rtl8169_private {
+       ulong iobase;
        void *mmio_addr;        /* memory map physical address */
        int chipset;
        unsigned long cur_rx;   /* Index into the Rx descriptor buffer of next Rx pkt. */
@@ -338,9 +345,9 @@ static const unsigned int rtl8169_rx_config =
     (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);
 
 static struct pci_device_id supported[] = {
-       {PCI_VENDOR_ID_REALTEK, 0x8167},
-       {PCI_VENDOR_ID_REALTEK, 0x8168},
-       {PCI_VENDOR_ID_REALTEK, 0x8169},
+       { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167) },
+       { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168) },
+       { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169) },
        {}
 };
 
@@ -380,7 +387,7 @@ int mdio_read(int RegAddr)
        return value;
 }
 
-static int rtl8169_init_board(struct eth_device *dev)
+static int rtl8169_init_board(unsigned long dev_iobase, const char *name)
 {
        int i;
        u32 tmp;
@@ -388,7 +395,7 @@ static int rtl8169_init_board(struct eth_device *dev)
 #ifdef DEBUG_RTL8169
        printf ("%s\n", __FUNCTION__);
 #endif
-       ioaddr = dev->iobase;
+       ioaddr = dev_iobase;
 
        /* Soft reset the chip. */
        RTL_W8(ChipCmd, CmdReset);
@@ -412,7 +419,8 @@ static int rtl8169_init_board(struct eth_device *dev)
        }
 
        /* if unknown chip, assume array element #0, original RTL-8169 in this case */
-       printf("PCI device %s: unknown chip version, assuming RTL-8169\n", dev->name);
+       printf("PCI device %s: unknown chip version, assuming RTL-8169\n",
+              name);
        printf("PCI device: TxConfig = 0x%lX\n", (unsigned long) RTL_R32(TxConfig));
        tpc->chipset = 0;
 
@@ -504,7 +512,8 @@ static void rtl_flush_buffer(void *buf, size_t size)
 /**************************************************************************
 RECV - Receive a frame
 ***************************************************************************/
-static int rtl_recv(struct eth_device *dev)
+static int rtl_recv_common(pci_dev_t bdf, unsigned long dev_iobase,
+                          uchar **packetp)
 {
        /* return true if there's an ethernet packet ready to read */
        /* nic->packet should contain data on return */
@@ -515,7 +524,7 @@ static int rtl_recv(struct eth_device *dev)
 #ifdef DEBUG_RTL8169_RX
        printf ("%s\n", __FUNCTION__);
 #endif
-       ioaddr = dev->iobase;
+       ioaddr = dev_iobase;
 
        cur_rx = tpc->cur_rx;
 
@@ -523,7 +532,6 @@ static int rtl_recv(struct eth_device *dev)
 
        if ((le32_to_cpu(tpc->RxDescArray[cur_rx].status) & OWNbit) == 0) {
                if (!(le32_to_cpu(tpc->RxDescArray[cur_rx].status) & RxRES)) {
-                       unsigned char rxdata[RX_BUF_LEN];
                        length = (int) (le32_to_cpu(tpc->RxDescArray[cur_rx].
                                                status) & 0x00001FFF) - 4;
 
@@ -536,17 +544,22 @@ static int rtl_recv(struct eth_device *dev)
                        else
                                tpc->RxDescArray[cur_rx].status =
                                        cpu_to_le32(OWNbit + RX_BUF_SIZE);
-                       tpc->RxDescArray[cur_rx].buf_addr =
-                               cpu_to_le32(bus_to_phys(tpc->RxBufferRing[cur_rx]));
+                       tpc->RxDescArray[cur_rx].buf_addr = cpu_to_le32(
+                               pci_mem_to_phys(bdf, (pci_addr_t)(unsigned long)
+                               tpc->RxBufferRing[cur_rx]));
                        rtl_flush_rx_desc(&tpc->RxDescArray[cur_rx]);
-
+#ifdef CONFIG_DM_ETH
+                       *packetp = rxdata;
+#else
                        net_process_received_packet(rxdata, length);
+#endif
                } else {
                        puts("Error Rx");
+                       length = -EIO;
                }
                cur_rx = (cur_rx + 1) % NUM_RX_DESC;
                tpc->cur_rx = cur_rx;
-               return 1;
+               return length;
 
        } else {
                ushort sts = RTL_R8(IntrStatus);
@@ -557,11 +570,26 @@ static int rtl_recv(struct eth_device *dev)
        return (0);             /* initially as this is called to flush the input */
 }
 
+#ifdef CONFIG_DM_ETH
+int rtl8169_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+       struct rtl8169_private *priv = dev_get_priv(dev);
+
+       return rtl_recv_common(pci_get_bdf(dev), priv->iobase, packetp);
+}
+#else
+static int rtl_recv(struct eth_device *dev)
+{
+       return rtl_recv_common((pci_dev_t)dev->priv, dev->iobase, NULL);
+}
+#endif /* nCONFIG_DM_ETH */
+
 #define HZ 1000
 /**************************************************************************
 SEND - Transmit a frame
 ***************************************************************************/
-static int rtl_send(struct eth_device *dev, void *packet, int length)
+static int rtl_send_common(pci_dev_t bdf, unsigned long dev_iobase,
+                          void *packet, int length)
 {
        /* send the packet to destination */
 
@@ -577,7 +605,7 @@ static int rtl_send(struct eth_device *dev, void *packet, int length)
        printf("sending %d bytes\n", len);
 #endif
 
-       ioaddr = dev->iobase;
+       ioaddr = dev_iobase;
 
        /* point to the current txb incase multiple tx_rings are used */
        ptxb = tpc->Tx_skbuff[entry * MAX_ETH_FRAME_SIZE];
@@ -588,7 +616,8 @@ static int rtl_send(struct eth_device *dev, void *packet, int length)
                ptxb[len++] = '\0';
 
        tpc->TxDescArray[entry].buf_Haddr = 0;
-       tpc->TxDescArray[entry].buf_addr = cpu_to_le32(bus_to_phys(ptxb));
+       tpc->TxDescArray[entry].buf_addr = cpu_to_le32(
+               pci_mem_to_phys(bdf, (pci_addr_t)(unsigned long)ptxb));
        if (entry != (NUM_TX_DESC - 1)) {
                tpc->TxDescArray[entry].status =
                        cpu_to_le32((OWNbit | FSbit | LSbit) |
@@ -625,7 +654,23 @@ static int rtl_send(struct eth_device *dev, void *packet, int length)
        return ret;
 }
 
-static void rtl8169_set_rx_mode(struct eth_device *dev)
+#ifdef CONFIG_DM_ETH
+int rtl8169_eth_send(struct udevice *dev, void *packet, int length)
+{
+       struct rtl8169_private *priv = dev_get_priv(dev);
+
+       return rtl_send_common(pci_get_bdf(dev), priv->iobase, packet, length);
+}
+
+#else
+static int rtl_send(struct eth_device *dev, void *packet, int length)
+{
+       return rtl_send_common((pci_dev_t)dev->priv, dev->iobase, packet,
+                              length);
+}
+#endif
+
+static void rtl8169_set_rx_mode(void)
 {
        u32 mc_filter[2];       /* Multicast hash filter */
        int rx_mode;
@@ -648,7 +693,7 @@ static void rtl8169_set_rx_mode(struct eth_device *dev)
        RTL_W32(MAR0 + 4, mc_filter[1]);
 }
 
-static void rtl8169_hw_start(struct eth_device *dev)
+static void rtl8169_hw_start(pci_dev_t bdf)
 {
        u32 i;
 
@@ -693,9 +738,11 @@ static void rtl8169_hw_start(struct eth_device *dev)
 
        tpc->cur_rx = 0;
 
-       RTL_W32(TxDescStartAddrLow, bus_to_phys(tpc->TxDescArray));
+       RTL_W32(TxDescStartAddrLow, pci_mem_to_phys(bdf,
+                       (pci_addr_t)(unsigned long)tpc->TxDescArray));
        RTL_W32(TxDescStartAddrHigh, (unsigned long)0);
-       RTL_W32(RxDescStartAddrLow, bus_to_phys(tpc->RxDescArray));
+       RTL_W32(RxDescStartAddrLow, pci_mem_to_phys(
+                       bdf, (pci_addr_t)(unsigned long)tpc->RxDescArray));
        RTL_W32(RxDescStartAddrHigh, (unsigned long)0);
 
        /* RTL-8169sc/8110sc or later version */
@@ -707,7 +754,7 @@ static void rtl8169_hw_start(struct eth_device *dev)
 
        RTL_W32(RxMissed, 0);
 
-       rtl8169_set_rx_mode(dev);
+       rtl8169_set_rx_mode();
 
        /* no early-rx interrupts */
        RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
@@ -717,7 +764,7 @@ static void rtl8169_hw_start(struct eth_device *dev)
 #endif
 }
 
-static void rtl8169_init_ring(struct eth_device *dev)
+static void rtl8169_init_ring(pci_dev_t bdf)
 {
        int i;
 
@@ -745,8 +792,8 @@ static void rtl8169_init_ring(struct eth_device *dev)
                                cpu_to_le32(OWNbit + RX_BUF_SIZE);
 
                tpc->RxBufferRing[i] = &rxb[i * RX_BUF_SIZE];
-               tpc->RxDescArray[i].buf_addr =
-                       cpu_to_le32(bus_to_phys(tpc->RxBufferRing[i]));
+               tpc->RxDescArray[i].buf_addr = cpu_to_le32(pci_mem_to_phys(
+                       bdf, (pci_addr_t)(unsigned long)tpc->RxBufferRing[i]));
                rtl_flush_rx_desc(&tpc->RxDescArray[i]);
        }
 
@@ -755,10 +802,7 @@ static void rtl8169_init_ring(struct eth_device *dev)
 #endif
 }
 
-/**************************************************************************
-RESET - Finish setting up the ethernet interface
-***************************************************************************/
-static int rtl_reset(struct eth_device *dev, bd_t *bis)
+static void rtl8169_common_start(pci_dev_t bdf, unsigned char *enetaddr)
 {
        int i;
 
@@ -767,30 +811,47 @@ static int rtl_reset(struct eth_device *dev, bd_t *bis)
        printf ("%s\n", __FUNCTION__);
 #endif
 
-       rtl8169_init_ring(dev);
-       rtl8169_hw_start(dev);
+       rtl8169_init_ring(bdf);
+       rtl8169_hw_start(bdf);
        /* Construct a perfect filter frame with the mac address as first match
         * and broadcast for all others */
        for (i = 0; i < 192; i++)
                txb[i] = 0xFF;
 
-       txb[0] = dev->enetaddr[0];
-       txb[1] = dev->enetaddr[1];
-       txb[2] = dev->enetaddr[2];
-       txb[3] = dev->enetaddr[3];
-       txb[4] = dev->enetaddr[4];
-       txb[5] = dev->enetaddr[5];
+       txb[0] = enetaddr[0];
+       txb[1] = enetaddr[1];
+       txb[2] = enetaddr[2];
+       txb[3] = enetaddr[3];
+       txb[4] = enetaddr[4];
+       txb[5] = enetaddr[5];
 
 #ifdef DEBUG_RTL8169
        printf("%s elapsed time : %lu\n", __func__, currticks()-stime);
 #endif
-       return 0;
 }
 
+#ifdef CONFIG_DM_ETH
+static int rtl8169_eth_start(struct udevice *dev)
+{
+       struct eth_pdata *plat = dev_get_platdata(dev);
+
+       rtl8169_common_start(pci_get_bdf(dev), plat->enetaddr);
+
+       return 0;
+}
+#else
 /**************************************************************************
-HALT - Turn off ethernet interface
+RESET - Finish setting up the ethernet interface
 ***************************************************************************/
-static void rtl_halt(struct eth_device *dev)
+static int rtl_reset(struct eth_device *dev, bd_t *bis)
+{
+       rtl8169_common_start((pci_dev_t)dev->priv, dev->enetaddr);
+
+       return 0;
+}
+#endif /* nCONFIG_DM_ETH */
+
+static void rtl_halt_common(unsigned long dev_iobase)
 {
        int i;
 
@@ -798,7 +859,7 @@ static void rtl_halt(struct eth_device *dev)
        printf ("%s\n", __FUNCTION__);
 #endif
 
-       ioaddr = dev->iobase;
+       ioaddr = dev_iobase;
 
        /* Stop the chip's Tx and Rx DMA processes. */
        RTL_W8(ChipCmd, 0x00);
@@ -813,13 +874,31 @@ static void rtl_halt(struct eth_device *dev)
        }
 }
 
+#ifdef CONFIG_DM_ETH
+void rtl8169_eth_stop(struct udevice *dev)
+{
+       struct rtl8169_private *priv = dev_get_priv(dev);
+
+       rtl_halt_common(priv->iobase);
+}
+#else
+/**************************************************************************
+HALT - Turn off ethernet interface
+***************************************************************************/
+static void rtl_halt(struct eth_device *dev)
+{
+       rtl_halt_common(dev->iobase);
+}
+#endif
+
 /**************************************************************************
 INIT - Look for an adapter, this routine's visible to the outside
 ***************************************************************************/
 
 #define board_found 1
 #define valid_link 0
-static int rtl_init(struct eth_device *dev, bd_t *bis)
+static int rtl_init(unsigned long dev_ioaddr, const char *name,
+                   unsigned char *enetaddr)
 {
        static int board_idx = -1;
        int i, rc;
@@ -828,33 +907,32 @@ static int rtl_init(struct eth_device *dev, bd_t *bis)
 #ifdef DEBUG_RTL8169
        printf ("%s\n", __FUNCTION__);
 #endif
-
-       ioaddr = dev->iobase;
+       ioaddr = dev_ioaddr;
 
        board_idx++;
 
        /* point to private storage */
        tpc = &tpx;
 
-       rc = rtl8169_init_board(dev);
+       rc = rtl8169_init_board(ioaddr, name);
        if (rc)
                return rc;
 
        /* Get MAC address.  FIXME: read EEPROM */
        for (i = 0; i < MAC_ADDR_LEN; i++)
-               dev->enetaddr[i] = RTL_R8(MAC0 + i);
+               enetaddr[i] = RTL_R8(MAC0 + i);
 
 #ifdef DEBUG_RTL8169
        printf("chipset = %d\n", tpc->chipset);
        printf("MAC Address");
        for (i = 0; i < MAC_ADDR_LEN; i++)
-               printf(":%02x", dev->enetaddr[i]);
+               printf(":%02x", enetaddr[i]);
        putc('\n');
 #endif
 
 #ifdef DEBUG_RTL8169
        /* Print out some hardware info */
-       printf("%s: at ioaddr 0x%lx\n", dev->name, ioaddr);
+       printf("%s: at ioaddr 0x%lx\n", name, ioaddr);
 #endif
 
        /* if TBI is not endbled */
@@ -964,6 +1042,7 @@ static int rtl_init(struct eth_device *dev, bd_t *bis)
        return 0;
 }
 
+#ifndef CONFIG_DM_ETH
 int rtl8169_initialize(bd_t *bis)
 {
        pci_dev_t devno;
@@ -1014,7 +1093,7 @@ int rtl8169_initialize(bd_t *bis)
                dev->send = rtl_send;
                dev->recv = rtl_recv;
 
-               err = rtl_init(dev, bis);
+               err = rtl_init(dev->iobase, dev->name, dev->enetaddr);
                if (err < 0) {
                        printf(pr_fmt("failed to initialize card: %d\n"), err);
                        free(dev);
@@ -1027,3 +1106,62 @@ int rtl8169_initialize(bd_t *bis)
        }
        return card_number;
 }
+#endif
+
+#ifdef CONFIG_DM_ETH
+static int rtl8169_eth_probe(struct udevice *dev)
+{
+       struct pci_child_platdata *pplat = dev_get_parent_platdata(dev);
+       struct rtl8169_private *priv = dev_get_priv(dev);
+       struct eth_pdata *plat = dev_get_platdata(dev);
+       u32 iobase;
+       int region;
+       int ret;
+
+       debug("rtl8169: REALTEK RTL8169 @0x%x\n", iobase);
+       switch (pplat->device) {
+       case 0x8168:
+               region = 2;
+               break;
+       default:
+               region = 1;
+               break;
+       }
+       pci_read_config32(pci_get_bdf(dev), PCI_BASE_ADDRESS_0 + region * 4,
+                         &iobase);
+       iobase &= ~0xf;
+       priv->iobase = (int)pci_mem_to_phys(pci_get_bdf(dev), iobase);
+
+       ret = rtl_init(priv->iobase, dev->name, plat->enetaddr);
+       if (ret < 0) {
+               printf(pr_fmt("failed to initialize card: %d\n"), ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct eth_ops rtl8169_eth_ops = {
+       .start  = rtl8169_eth_start,
+       .send   = rtl8169_eth_send,
+       .recv   = rtl8169_eth_recv,
+       .stop   = rtl8169_eth_stop,
+};
+
+static const struct udevice_id rtl8169_eth_ids[] = {
+       { .compatible = "realtek,rtl8169" },
+       { }
+};
+
+U_BOOT_DRIVER(eth_rtl8169) = {
+       .name   = "eth_rtl8169",
+       .id     = UCLASS_ETH,
+       .of_match = rtl8169_eth_ids,
+       .probe  = rtl8169_eth_probe,
+       .ops    = &rtl8169_eth_ops,
+       .priv_auto_alloc_size = sizeof(struct rtl8169_private),
+       .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+};
+
+U_BOOT_PCI_DEVICE(eth_rtl8169, supported);
+#endif
index 45c3b18bdf33ccfe8d4f224e5d6e10f6c2e385ab..591242797e26dfff301888f1022f62ce8fa5f88d 100644 (file)
@@ -65,7 +65,7 @@ static int sb_eth_raw_send(struct udevice *dev, void *packet, int length)
        return sandbox_eth_raw_os_send(packet, length, priv);
 }
 
-static int sb_eth_raw_recv(struct udevice *dev, uchar **packetp)
+static int sb_eth_raw_recv(struct udevice *dev, int flags, uchar **packetp)
 {
        struct eth_pdata *pdata = dev_get_platdata(dev);
        struct eth_sandbox_raw_priv *priv = dev_get_priv(dev);
index 4e083d32ae6fe7aad839b84c5875ed98bbc4d627..6763a248f28d0b327c8b14ff757206cf10a26432 100644 (file)
@@ -152,7 +152,7 @@ static int sb_eth_send(struct udevice *dev, void *packet, int length)
        return 0;
 }
 
-static int sb_eth_recv(struct udevice *dev, uchar **packetp)
+static int sb_eth_recv(struct udevice *dev, int flags, uchar **packetp)
 {
        struct eth_sandbox_priv *priv = dev_get_priv(dev);
 
index e939bf2108a3fbde2c23cd01bdb09f815a4be53c..11cd0ea06888ba8e271b0c10376306df5291a3e2 100644 (file)
@@ -527,7 +527,7 @@ static int sunxi_emac_eth_send(struct udevice *dev, void *packet, int length)
        return _sunxi_emac_eth_send(priv, packet, length);
 }
 
-static int sunxi_emac_eth_recv(struct udevice *dev, uchar **packetp)
+static int sunxi_emac_eth_recv(struct udevice *dev, int flags, uchar **packetp)
 {
        struct emac_eth_dev *priv = dev_get_priv(dev);
        int rx_len;
index 5b91fe3dcecfdbdb783e0824ec820a80d524081e..3be76c99ee471646dc5307164c6817d69563f793 100644 (file)
@@ -30,6 +30,14 @@ struct pci_controller *pci_bus_to_hose(int busnum)
        return dev_get_uclass_priv(bus);
 }
 
+pci_dev_t pci_get_bdf(struct udevice *dev)
+{
+       struct pci_child_platdata *pplat = dev_get_parent_platdata(dev);
+       struct udevice *bus = dev->parent;
+
+       return PCI_ADD_BUS(bus->seq, pplat->devfn);
+}
+
 /**
  * pci_get_bus_max() - returns the bus number of the last active bus
  *
@@ -295,19 +303,14 @@ int pci_auto_config_devices(struct udevice *bus)
        for (ret = device_find_first_child(bus, &dev);
             !ret && dev;
             ret = device_find_next_child(&dev)) {
-               struct pci_child_platdata *pplat;
                struct pci_controller *ctlr_hose;
-
-               pplat = dev_get_parent_platdata(dev);
                unsigned int max_bus;
-               pci_dev_t bdf;
 
-               bdf = PCI_ADD_BUS(bus->seq, pplat->devfn);
                debug("%s: device %s\n", __func__, dev->name);
 
                /* The root controller has the region information */
                ctlr_hose = hose->ctlr->uclass_priv;
-               max_bus = pciauto_config_device(ctlr_hose, bdf);
+               max_bus = pciauto_config_device(ctlr_hose, pci_get_bdf(dev));
                sub_bus = max(sub_bus, max_bus);
        }
        debug("%s: done\n", __func__);
@@ -353,6 +356,101 @@ int dm_pci_hose_probe_bus(struct pci_controller *hose, pci_dev_t bdf)
        return sub_bus;
 }
 
+/**
+ * pci_match_one_device - Tell if a PCI device structure has a matching
+ *                        PCI device id structure
+ * @id: single PCI device id structure to match
+ * @dev: the PCI device structure to match against
+ *
+ * Returns the matching pci_device_id structure or %NULL if there is no match.
+ */
+static bool pci_match_one_id(const struct pci_device_id *id,
+                            const struct pci_device_id *find)
+{
+       if ((id->vendor == PCI_ANY_ID || id->vendor == find->vendor) &&
+           (id->device == PCI_ANY_ID || id->device == find->device) &&
+           (id->subvendor == PCI_ANY_ID || id->subvendor == find->subvendor) &&
+           (id->subdevice == PCI_ANY_ID || id->subdevice == find->subdevice) &&
+           !((id->class ^ find->class) & id->class_mask))
+               return true;
+
+       return false;
+}
+
+/**
+ * pci_find_and_bind_driver() - Find and bind the right PCI driver
+ *
+ * This only looks at certain fields in the descriptor.
+ */
+static int pci_find_and_bind_driver(struct udevice *parent,
+                                   struct pci_device_id *find_id, int devfn,
+                                   struct udevice **devp)
+{
+       struct pci_driver_entry *start, *entry;
+       const char *drv;
+       int n_ents;
+       int ret;
+       char name[30], *str;
+
+       *devp = NULL;
+
+       debug("%s: Searching for driver: vendor=%x, device=%x\n", __func__,
+             find_id->vendor, find_id->device);
+       start = ll_entry_start(struct pci_driver_entry, pci_driver_entry);
+       n_ents = ll_entry_count(struct pci_driver_entry, pci_driver_entry);
+       for (entry = start; entry != start + n_ents; entry++) {
+               const struct pci_device_id *id;
+               struct udevice *dev;
+               const struct driver *drv;
+
+               for (id = entry->match;
+                    id->vendor || id->subvendor || id->class_mask;
+                    id++) {
+                       if (!pci_match_one_id(id, find_id))
+                               continue;
+
+                       drv = entry->driver;
+                       /*
+                        * We could pass the descriptor to the driver as
+                        * platdata (instead of NULL) and allow its bind()
+                        * method to return -ENOENT if it doesn't support this
+                        * device. That way we could continue the search to
+                        * find another driver. For now this doesn't seem
+                        * necesssary, so just bind the first match.
+                        */
+                       ret = device_bind(parent, drv, drv->name, NULL, -1,
+                                         &dev);
+                       if (ret)
+                               goto error;
+                       debug("%s: Match found: %s\n", __func__, drv->name);
+                       dev->driver_data = find_id->driver_data;
+                       *devp = dev;
+                       return 0;
+               }
+       }
+
+       /* Bind a generic driver so that the device can be used */
+       sprintf(name, "pci_%x:%x.%x", parent->seq, PCI_DEV(devfn),
+               PCI_FUNC(devfn));
+       str = strdup(name);
+       if (!str)
+               return -ENOMEM;
+       drv = (find_id->class >> 8) == PCI_CLASS_BRIDGE_PCI ? "pci_bridge_drv" :
+                       "pci_generic_drv";
+       ret = device_bind_driver(parent, drv, str, devp);
+       if (ret) {
+               debug("%s: Failed to bind generic driver: %d", __func__, ret);
+               return ret;
+       }
+       debug("%s: No match found: bound generic driver instead\n", __func__);
+
+       return 0;
+
+error:
+       debug("%s: No match found: error %d\n", __func__, ret);
+       return ret;
+}
+
 int pci_bind_bus_devices(struct udevice *bus)
 {
        ulong vendor, device;
@@ -387,25 +485,33 @@ int pci_bind_bus_devices(struct udevice *bus)
                      bus->seq, bus->name, PCI_DEV(devfn), PCI_FUNC(devfn));
                pci_bus_read_config(bus, devfn, PCI_DEVICE_ID, &device,
                                    PCI_SIZE_16);
-               pci_bus_read_config(bus, devfn, PCI_CLASS_DEVICE, &class,
-                                   PCI_SIZE_16);
+               pci_bus_read_config(bus, devfn, PCI_CLASS_REVISION, &class,
+                                   PCI_SIZE_32);
+               class >>= 8;
 
                /* Find this device in the device tree */
                ret = pci_bus_find_devfn(bus, devfn, &dev);
 
+               /* Search for a driver */
+
                /* If nothing in the device tree, bind a generic device */
                if (ret == -ENODEV) {
-                       char name[30], *str;
-                       const char *drv;
-
-                       sprintf(name, "pci_%x:%x.%x", bus->seq,
-                               PCI_DEV(devfn), PCI_FUNC(devfn));
-                       str = strdup(name);
-                       if (!str)
-                               return -ENOMEM;
-                       drv = class == PCI_CLASS_BRIDGE_PCI ?
-                               "pci_bridge_drv" : "pci_generic_drv";
-                       ret = device_bind_driver(bus, drv, str, &dev);
+                       struct pci_device_id find_id;
+                       ulong val;
+
+                       memset(&find_id, '\0', sizeof(find_id));
+                       find_id.vendor = vendor;
+                       find_id.device = device;
+                       find_id.class = class;
+                       if ((header_type & 0x7f) == PCI_HEADER_TYPE_NORMAL) {
+                               pci_bus_read_config(bus, devfn,
+                                                   PCI_SUBSYSTEM_VENDOR_ID,
+                                                   &val, PCI_SIZE_32);
+                               find_id.subvendor = val & 0xffff;
+                               find_id.subdevice = val >> 16;
+                       }
+                       ret = pci_find_and_bind_driver(bus, &find_id, devfn,
+                                                      &dev);
                }
                if (ret)
                        return ret;
index d6938c198f70a79b1d8662209df128c4eaa108af..05c35105ab421568e4441c2f8f5d5edccefc5d80 100644 (file)
@@ -31,13 +31,9 @@ PCI_HOSE_OP(write, dword, 32, u32)
 
 pci_dev_t pci_find_devices(struct pci_device_id *ids, int index)
 {
-       struct pci_child_platdata *pplat;
-       struct udevice *bus, *dev;
+       struct udevice *dev;
 
        if (pci_find_device_id(ids, index, &dev))
                return -1;
-       bus = dev->parent;
-       pplat = dev_get_parent_platdata(dev);
-
-       return PCI_ADD_BUS(bus->seq, pplat->devfn);
+       return pci_get_bdf(dev);
 }
index 812ac13baa314d50cc8f00b11464f8258c60637f..d99cb9aadaa9c37f0994454df4454f4e55fdd59b 100644 (file)
@@ -9,6 +9,7 @@
 #include <fdtdec.h>
 #include <errno.h>
 #include <dm.h>
+#include <vsprintf.h>
 #include <dm/lists.h>
 #include <dm/device-internal.h>
 #include <dm/uclass-internal.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
-static ulong str_get_num(const char *ptr, const char *maxptr)
-{
-       if (!ptr || !maxptr)
-               return 0;
-
-       while (!isdigit(*ptr) && ptr++ < maxptr);
-
-       return simple_strtoul(ptr, NULL, 0);
-}
-
 int pmic_bind_children(struct udevice *pmic, int offset,
                       const struct pmic_child_info *child_info)
 {
@@ -35,7 +26,6 @@ int pmic_bind_children(struct udevice *pmic, int offset,
        struct driver *drv;
        struct udevice *child;
        const char *node_name;
-       int node_name_len;
        int bind_count = 0;
        int node;
        int prefix_len;
@@ -47,19 +37,19 @@ int pmic_bind_children(struct udevice *pmic, int offset,
        for (node = fdt_first_subnode(blob, offset);
             node > 0;
             node = fdt_next_subnode(blob, node)) {
-               node_name = fdt_get_name(blob, node, &node_name_len);
+               node_name = fdt_get_name(blob, node, NULL);
 
                debug("* Found child node: '%s' at offset:%d\n", node_name,
                                                                 node);
 
                child = NULL;
                for (info = child_info; info->prefix && info->driver; info++) {
+                       debug("  - compatible prefix: '%s'\n", info->prefix);
+
                        prefix_len = strlen(info->prefix);
-                       if (strncasecmp(info->prefix, node_name, prefix_len))
+                       if (strncmp(info->prefix, node_name, prefix_len))
                                continue;
 
-                       debug("  - compatible prefix: '%s'\n", info->prefix);
-
                        drv = lists_driver_lookup_name(info->driver);
                        if (!drv) {
                                debug("  - driver: '%s' not found!\n",
@@ -78,10 +68,7 @@ int pmic_bind_children(struct udevice *pmic, int offset,
 
                        debug("  - bound child device: '%s'\n", child->name);
 
-                       child->driver_data = str_get_num(node_name +
-                                                        prefix_len,
-                                                        node_name +
-                                                        node_name_len);
+                       child->driver_data = trailing_strtol(node_name);
 
                        debug("  - set 'child->driver_data': %lu\n",
                              child->driver_data);
@@ -139,6 +126,38 @@ int pmic_write(struct udevice *dev, uint reg, const uint8_t *buffer, int len)
        return ops->write(dev, reg, buffer, len);
 }
 
+int pmic_reg_read(struct udevice *dev, uint reg)
+{
+       u8 byte;
+       int ret;
+
+       ret = pmic_read(dev, reg, &byte, 1);
+       debug("%s: reg=%x, value=%x\n", __func__, reg, byte);
+
+       return ret ? ret : byte;
+}
+
+int pmic_reg_write(struct udevice *dev, uint reg, uint value)
+{
+       u8 byte = value;
+
+       debug("%s: reg=%x, value=%x\n", __func__, reg, value);
+       return pmic_read(dev, reg, &byte, 1);
+}
+
+int pmic_clrsetbits(struct udevice *dev, uint reg, uint clr, uint set)
+{
+       u8 byte;
+       int ret;
+
+       ret = pmic_reg_read(dev, reg);
+       if (ret < 0)
+               return ret;
+       byte = (ret & ~clr) | set;
+
+       return pmic_reg_write(dev, reg, byte);
+}
+
 UCLASS_DRIVER(pmic) = {
        .id             = UCLASS_PMIC,
        .name           = "pmic",
index 31ffd44454cf30e5d0b51b3c57799b4c21a8e802..12e141b4adedbda7b2d44b1f3ddfd913eaa9ffb1 100644 (file)
@@ -138,87 +138,57 @@ int regulator_get_by_devname(const char *devname, struct udevice **devp)
        return uclass_get_device_by_name(UCLASS_REGULATOR, devname, devp);
 }
 
-static int failed(int ret, bool verbose, const char *fmt, ...)
+int regulator_autoset(struct udevice *dev)
 {
-       va_list args;
-       char buf[64];
-
-       if (verbose == false)
-               return ret;
+       struct dm_regulator_uclass_platdata *uc_pdata;
+       int ret = 0;
 
-       va_start(args, fmt);
-       vscnprintf(buf, sizeof(buf), fmt, args);
-       va_end(args);
+       uc_pdata = dev_get_uclass_platdata(dev);
+       if (!uc_pdata->always_on && !uc_pdata->boot_on)
+               return -EMEDIUMTYPE;
 
-       printf(buf);
+       if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UV)
+               ret = regulator_set_value(dev, uc_pdata->min_uV);
+       if (!ret && (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UA))
+               ret = regulator_set_current(dev, uc_pdata->min_uA);
 
        if (!ret)
-               return 0;
-
-       printf(" (ret: %d)", ret);
+               ret = regulator_set_enable(dev, true);
 
        return ret;
 }
 
-int regulator_autoset(const char *platname,
-                     struct udevice **devp,
-                     bool verbose)
+static void regulator_show(struct udevice *dev, int ret)
 {
        struct dm_regulator_uclass_platdata *uc_pdata;
-       struct udevice *dev;
-       int ret;
-
-       if (devp)
-               *devp = NULL;
-
-       ret = regulator_get_by_platname(platname, &dev);
-       if (ret) {
-               error("Can get the regulator: %s!", platname);
-               return ret;
-       }
 
        uc_pdata = dev_get_uclass_platdata(dev);
-       if (!uc_pdata) {
-               error("Can get the regulator %s uclass platdata!", platname);
-               return -ENXIO;
-       }
 
-       if (!uc_pdata->always_on && !uc_pdata->boot_on)
-               goto retdev;
-
-       if (verbose)
-               printf("%s@%s: ", dev->name, uc_pdata->name);
-
-       /* Those values are optional (-ENODATA if unset) */
-       if ((uc_pdata->min_uV != -ENODATA) &&
-           (uc_pdata->max_uV != -ENODATA) &&
-           (uc_pdata->min_uV == uc_pdata->max_uV)) {
-               ret = regulator_set_value(dev, uc_pdata->min_uV);
-               if (failed(ret, verbose, "set %d uV", uc_pdata->min_uV))
-                       goto exit;
-       }
-
-       /* Those values are optional (-ENODATA if unset) */
-       if ((uc_pdata->min_uA != -ENODATA) &&
-           (uc_pdata->max_uA != -ENODATA) &&
-           (uc_pdata->min_uA == uc_pdata->max_uA)) {
-               ret = regulator_set_current(dev, uc_pdata->min_uA);
-               if (failed(ret, verbose, "; set %d uA", uc_pdata->min_uA))
-                       goto exit;
-       }
+       printf("%s@%s: ", dev->name, uc_pdata->name);
+       if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UV)
+               printf("set %d uV", uc_pdata->min_uV);
+       if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UA)
+               printf("; set %d uA", uc_pdata->min_uA);
+       printf("; enabling");
+       if (ret)
+               printf(" (ret: %d)\n", ret);
+       printf("\n");
+}
 
-       ret = regulator_set_enable(dev, true);
-       if (failed(ret, verbose, "; enabling", uc_pdata->min_uA))
-               goto exit;
+int regulator_autoset_by_name(const char *platname, struct udevice **devp)
+{
+       struct udevice *dev;
+       int ret;
 
-retdev:
+       ret = regulator_get_by_platname(platname, &dev);
        if (devp)
                *devp = dev;
-exit:
-       if (verbose)
-               printf("\n");
+       if (ret) {
+               debug("Can get the regulator: %s!", platname);
+               return ret;
+       }
 
-       return ret;
+       return regulator_autoset(dev);
 }
 
 int regulator_list_autoset(const char *list_platname[],
@@ -229,7 +199,9 @@ int regulator_list_autoset(const char *list_platname[],
        int error = 0, i = 0, ret;
 
        while (list_platname[i]) {
-               ret = regulator_autoset(list_platname[i], &dev, verbose);
+               ret = regulator_autoset_by_name(list_platname[i], &dev);
+               if (ret != -EMEDIUMTYPE && verbose)
+                       regulator_show(dev, ret);
                if (ret & !error)
                        error = ret;
 
@@ -290,7 +262,7 @@ static int regulator_post_bind(struct udevice *dev)
        if (regulator_name_is_unique(dev, uc_pdata->name))
                return 0;
 
-       error("\"%s\" of dev: \"%s\", has nonunique value: \"%s\"",
+       debug("\"%s\" of dev: \"%s\", has nonunique value: \"%s\"",
              property, dev->name, uc_pdata->name);
 
        return -EINVAL;
@@ -319,9 +291,43 @@ static int regulator_pre_probe(struct udevice *dev)
        uc_pdata->boot_on = fdtdec_get_bool(gd->fdt_blob, offset,
                                            "regulator-boot-on");
 
+       /* Those values are optional (-ENODATA if unset) */
+       if ((uc_pdata->min_uV != -ENODATA) &&
+           (uc_pdata->max_uV != -ENODATA) &&
+           (uc_pdata->min_uV == uc_pdata->max_uV))
+               uc_pdata->flags |= REGULATOR_FLAG_AUTOSET_UV;
+
+       /* Those values are optional (-ENODATA if unset) */
+       if ((uc_pdata->min_uA != -ENODATA) &&
+           (uc_pdata->max_uA != -ENODATA) &&
+           (uc_pdata->min_uA == uc_pdata->max_uA))
+               uc_pdata->flags |= REGULATOR_FLAG_AUTOSET_UA;
+
        return 0;
 }
 
+int regulators_enable_boot_on(bool verbose)
+{
+       struct udevice *dev;
+       struct uclass *uc;
+       int ret;
+
+       ret = uclass_get(UCLASS_REGULATOR, &uc);
+       if (ret)
+               return ret;
+       for (uclass_first_device(UCLASS_REGULATOR, &dev);
+            dev && !ret;
+            uclass_next_device(&dev)) {
+               ret = regulator_autoset(dev);
+               if (ret == -EMEDIUMTYPE)
+                       continue;
+               if (verbose)
+                       regulator_show(dev, ret);
+       }
+
+       return ret;
+}
+
 UCLASS_DRIVER(regulator) = {
        .id             = UCLASS_REGULATOR,
        .name           = "regulator",
diff --git a/drivers/ram/Kconfig b/drivers/ram/Kconfig
new file mode 100644 (file)
index 0000000..642a2d8
--- /dev/null
@@ -0,0 +1,18 @@
+config RAM
+       bool "Enable RAM drivers using Driver Model"
+       depends on DM
+       help
+         This allows drivers to be provided for SDRAM and other RAM
+         controllers and their type to be specified in the board's device
+         tree. Generally some parameters are required to set up the RAM and
+         the RAM size can either be statically defined or dynamically
+         detected.
+
+config SPL_RAM_SUPPORT
+       bool "Enable RAM support in SPL"
+       depends on RAM
+       help
+         The RAM subsystem adds a small amount of overhead to the image.
+         If this is acceptable and you have a need to use RAM drivers in
+         SPL, enable this option. It might provide a cleaner interface to
+         setting up RAM (e.g. SDRAM / DDR) within SPL.
diff --git a/drivers/ram/Makefile b/drivers/ram/Makefile
new file mode 100644 (file)
index 0000000..0e10249
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# Copyright (c) 2015 Google, Inc
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# SPDX-License-Identifier:      GPL-2.0+
+#
+obj-$(CONFIG_RAM) += ram-uclass.o
+obj-$(CONFIG_SANDBOX) += sandbox_ram.o
diff --git a/drivers/ram/ram-uclass.c b/drivers/ram/ram-uclass.c
new file mode 100644 (file)
index 0000000..2f1fbe7
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <ram.h>
+#include <dm.h>
+#include <errno.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+
+int ram_get_info(struct udevice *dev, struct ram_info *info)
+{
+       struct ram_ops *ops = ram_get_ops(dev);
+
+       if (!ops->get_info)
+               return -ENOSYS;
+
+       return ops->get_info(dev, info);
+}
+
+UCLASS_DRIVER(ram) = {
+       .id             = UCLASS_RAM,
+       .name           = "ram",
+};
diff --git a/drivers/ram/sandbox_ram.c b/drivers/ram/sandbox_ram.c
new file mode 100644 (file)
index 0000000..06bf3ec
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <ram.h>
+#include <asm/test.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int sandbox_get_info(struct udevice *dev, struct ram_info *info)
+{
+       info->base = 0;
+       info->size = gd->ram_size;
+
+       return 0;
+}
+
+static const struct ram_ops sandbox_ram_ops = {
+       .get_info       = sandbox_get_info,
+};
+
+static const struct udevice_id sandbox_ram_ids[] = {
+       { .compatible = "sandbox,ram" },
+       { }
+};
+
+U_BOOT_DRIVER(warm_ram_sandbox) = {
+       .name           = "ram_sandbox",
+       .id             = UCLASS_RAM,
+       .of_match       = sandbox_ram_ids,
+       .ops            = &sandbox_ram_ops,
+};
index 9b044a37da500f3deabfde65d1b9684e2f03957c..c8a77e295e9ee9d3c2f1108d1b86014bb6d46bd2 100644 (file)
@@ -246,6 +246,17 @@ int NS16550_tstc(NS16550_t com_port)
 
 #include <debug_uart.h>
 
+#define serial_dout(reg, value)        \
+       serial_out_shift((char *)com_port + \
+               ((char *)reg - (char *)com_port) * \
+                       (1 << CONFIG_DEBUG_UART_SHIFT), \
+               CONFIG_DEBUG_UART_SHIFT, value)
+#define serial_din(reg) \
+       serial_in_shift((char *)com_port + \
+               ((char *)reg - (char *)com_port) * \
+                       (1 << CONFIG_DEBUG_UART_SHIFT), \
+               CONFIG_DEBUG_UART_SHIFT)
+
 void debug_uart_init(void)
 {
        struct NS16550 *com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE;
@@ -259,28 +270,23 @@ void debug_uart_init(void)
         */
        baud_divisor = calc_divisor(com_port, CONFIG_DEBUG_UART_CLOCK,
                                    CONFIG_BAUDRATE);
-       serial_out_shift(&com_port->ier, CONFIG_DEBUG_UART_SHIFT,
-                        CONFIG_SYS_NS16550_IER);
-       serial_out_shift(&com_port->mcr, CONFIG_DEBUG_UART_SHIFT, UART_MCRVAL);
-       serial_out_shift(&com_port->fcr, CONFIG_DEBUG_UART_SHIFT, UART_FCRVAL);
-
-       serial_out_shift(&com_port->lcr, CONFIG_DEBUG_UART_SHIFT,
-                        UART_LCR_BKSE | UART_LCRVAL);
-       serial_out_shift(&com_port->dll, CONFIG_DEBUG_UART_SHIFT,
-                        baud_divisor & 0xff);
-       serial_out_shift(&com_port->dlm, CONFIG_DEBUG_UART_SHIFT,
-                        (baud_divisor >> 8) & 0xff);
-       serial_out_shift(&com_port->lcr, CONFIG_DEBUG_UART_SHIFT,
-                        UART_LCRVAL);
+       serial_dout(&com_port->ier, CONFIG_SYS_NS16550_IER);
+       serial_dout(&com_port->mcr, UART_MCRVAL);
+       serial_dout(&com_port->fcr, UART_FCRVAL);
+
+       serial_dout(&com_port->lcr, UART_LCR_BKSE | UART_LCRVAL);
+       serial_dout(&com_port->dll, baud_divisor & 0xff);
+       serial_dout(&com_port->dlm, (baud_divisor >> 8) & 0xff);
+       serial_dout(&com_port->lcr, UART_LCRVAL);
 }
 
 static inline void _debug_uart_putc(int ch)
 {
        struct NS16550 *com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE;
 
-       while (!(serial_in_shift(&com_port->lsr, 0) & UART_LSR_THRE))
+       while (!(serial_din(&com_port->lsr) & UART_LSR_THRE))
                ;
-       serial_out_shift(&com_port->thr, CONFIG_DEBUG_UART_SHIFT, ch);
+       serial_dout(&com_port->thr, ch);
 }
 
 DEBUG_UART_FUNCS
index 737ae64052acace832e332ba16ea69e3ddc8adc6..d666272e39ced97c99b4156741cb51e49abfa3c7 100644 (file)
@@ -95,13 +95,13 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
        return spi_get_ops(bus)->xfer(dev, bitlen, dout, din, flags);
 }
 
-int spi_post_bind(struct udevice *dev)
+static int spi_post_bind(struct udevice *dev)
 {
        /* Scan the bus for devices */
        return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
 }
 
-int spi_child_post_bind(struct udevice *dev)
+static int spi_child_post_bind(struct udevice *dev)
 {
        struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev);
 
@@ -111,7 +111,7 @@ int spi_child_post_bind(struct udevice *dev)
        return spi_slave_ofdata_to_platdata(gd->fdt_blob, dev->of_offset, plat);
 }
 
-int spi_post_probe(struct udevice *bus)
+static int spi_post_probe(struct udevice *bus)
 {
        struct dm_spi_bus *spi = dev_get_uclass_priv(bus);
 
@@ -121,7 +121,7 @@ int spi_post_probe(struct udevice *bus)
        return 0;
 }
 
-int spi_child_pre_probe(struct udevice *dev)
+static int spi_child_pre_probe(struct udevice *dev)
 {
        struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev);
        struct spi_slave *slave = dev_get_parentdata(dev);
index 637ef3d567e88c348d8c362d6a145cf1d074c733..3fa5b2e37e81c86171e35a8167116c2a469a9e6e 100644 (file)
@@ -46,8 +46,8 @@ config DM_USB
 
          Much of the code is shared but with this option enabled the USB
          uclass takes care of device enumeration. USB devices can be
-         declared with the USB_DEVICE() macro and will be automatically
-         probed when found on the bus.
+         declared with the U_BOOT_USB_DEVICE() macro and will be
+         automatically probed when found on the bus.
 
 source "drivers/usb/host/Kconfig"
 
index c8697ae78dbc719220144174b5ebd83fa193b7b8..72ec41ea896b1059af802b1172cb6f1796425fe2 100644 (file)
@@ -5,11 +5,11 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <usb.h>
+#include <malloc.h>
 #include <linux/mii.h>
 #include "usb_ether.h"
-#include <malloc.h>
-
 
 /* ASIX AX8817X based USB 2.0 Ethernet Devices */
 
 #define FLAG_TYPE_AX88772B     (1U << 2)
 #define FLAG_EEPROM_MAC                (1U << 3) /* initial mac address in eeprom */
 
-/* local vars */
-static int curr_eth_dev; /* index for name of next device detected */
 
 /* driver private */
 struct asix_private {
        int flags;
+#ifdef CONFIG_DM_ETH
+       struct ueth_data ueth;
+#endif
 };
 
+#ifndef CONFIG_DM_ETH
+/* local vars */
+static int curr_eth_dev; /* index for name of next device detected */
+#endif
+
 /*
  * Asix infrastructure commands
  */
@@ -284,13 +290,12 @@ static int asix_write_gpio(struct ueth_data *dev, u16 value, int sleep)
        return ret;
 }
 
-static int asix_write_hwaddr(struct eth_device *eth)
+static int asix_write_hwaddr_common(struct ueth_data *dev, uint8_t *enetaddr)
 {
-       struct ueth_data *dev = (struct ueth_data *)eth->priv;
        int ret;
        ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buf, ETH_ALEN);
 
-       memcpy(buf, eth->enetaddr, ETH_ALEN);
+       memcpy(buf, enetaddr, ETH_ALEN);
 
        ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, buf);
        if (ret < 0)
@@ -325,12 +330,11 @@ static int mii_nway_restart(struct ueth_data *dev)
        return r;
 }
 
-static int asix_read_mac(struct eth_device *eth)
+static int asix_read_mac_common(struct ueth_data *dev,
+                               struct asix_private *priv, uint8_t *enetaddr)
 {
-       struct ueth_data *dev = (struct ueth_data *)eth->priv;
-       struct asix_private *priv = (struct asix_private *)dev->dev_priv;
-       int i;
        ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buf, ETH_ALEN);
+       int i;
 
        if (priv->flags & FLAG_EEPROM_MAC) {
                for (i = 0; i < (ETH_ALEN >> 1); i++) {
@@ -339,7 +343,7 @@ static int asix_read_mac(struct eth_device *eth)
                                debug("Failed to read SROM address 04h.\n");
                                return -1;
                        }
-                       memcpy((eth->enetaddr + i * 2), buf, 2);
+                       memcpy(enetaddr + i * 2, buf, 2);
                }
        } else {
                if (asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf)
@@ -347,7 +351,7 @@ static int asix_read_mac(struct eth_device *eth)
                        debug("Failed to read MAC address.\n");
                        return -1;
                }
-               memcpy(eth->enetaddr, buf, ETH_ALEN);
+               memcpy(enetaddr, buf, ETH_ALEN);
        }
 
        return 0;
@@ -414,12 +418,8 @@ static int asix_basic_reset(struct ueth_data *dev)
        return 0;
 }
 
-/*
- * Asix callbacks
- */
-static int asix_init(struct eth_device *eth, bd_t *bd)
+static int asix_init_common(struct ueth_data *dev)
 {
-       struct ueth_data        *dev = (struct ueth_data *)eth->priv;
        int timeout = 0;
 #define TIMEOUT_RESOLUTION 50  /* ms */
        int link_detected;
@@ -452,9 +452,8 @@ out_err:
        return -1;
 }
 
-static int asix_send(struct eth_device *eth, void *packet, int length)
+static int asix_send_common(struct ueth_data *dev, void *packet, int length)
 {
-       struct ueth_data *dev = (struct ueth_data *)eth->priv;
        int err;
        u32 packet_len;
        int actual_len;
@@ -481,6 +480,24 @@ static int asix_send(struct eth_device *eth, void *packet, int length)
        return err;
 }
 
+#ifndef CONFIG_DM_ETH
+/*
+ * Asix callbacks
+ */
+static int asix_init(struct eth_device *eth, bd_t *bd)
+{
+       struct ueth_data *dev = (struct ueth_data *)eth->priv;
+
+       return asix_init_common(dev);
+}
+
+static int asix_send(struct eth_device *eth, void *packet, int length)
+{
+       struct ueth_data *dev = (struct ueth_data *)eth->priv;
+
+       return asix_send_common(dev, packet, length);
+}
+
 static int asix_recv(struct eth_device *eth)
 {
        struct ueth_data *dev = (struct ueth_data *)eth->priv;
@@ -552,6 +569,13 @@ static void asix_halt(struct eth_device *eth)
        debug("** %s()\n", __func__);
 }
 
+static int asix_write_hwaddr(struct eth_device *eth)
+{
+       struct ueth_data *dev = (struct ueth_data *)eth->priv;
+
+       return asix_write_hwaddr_common(dev, eth->enetaddr);
+}
+
 /*
  * Asix probing functions
  */
@@ -694,9 +718,180 @@ int asix_eth_get_info(struct usb_device *dev, struct ueth_data *ss,
                return 0;
 
        /* Get the MAC address */
-       if (asix_read_mac(eth))
+       if (asix_read_mac_common(ss, priv, eth->enetaddr))
                return 0;
        debug("MAC %pM\n", eth->enetaddr);
 
        return 1;
 }
+#endif
+
+#ifdef CONFIG_DM_ETH
+static int asix_eth_start(struct udevice *dev)
+{
+       struct asix_private *priv = dev_get_priv(dev);
+
+       return asix_init_common(&priv->ueth);
+}
+
+void asix_eth_stop(struct udevice *dev)
+{
+       debug("** %s()\n", __func__);
+}
+
+int asix_eth_send(struct udevice *dev, void *packet, int length)
+{
+       struct asix_private *priv = dev_get_priv(dev);
+
+       return asix_send_common(&priv->ueth, packet, length);
+}
+
+int asix_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+       struct asix_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, AX_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 as two
+        * complementary 16-bit words. Extract the length of the data.
+        */
+       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 >> 16) & 0x7ff) != (packet_len & 0x7ff)) {
+               debug("Rx: malformed packet length: %#x (%#x:%#x)\n",
+                     packet_len, (~packet_len >> 16) & 0x7ff,
+                     packet_len & 0x7ff);
+               goto err;
+       }
+       packet_len = packet_len & 0x7ff;
+       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 asix_free_pkt(struct udevice *dev, uchar *packet, int packet_len)
+{
+       struct asix_private *priv = dev_get_priv(dev);
+
+       if (packet_len & 1)
+               packet_len++;
+       usb_ether_advance_rxbuf(&priv->ueth, sizeof(u32) + packet_len);
+
+       return 0;
+}
+
+int asix_write_hwaddr(struct udevice *dev)
+{
+       struct eth_pdata *pdata = dev_get_platdata(dev);
+       struct asix_private *priv = dev_get_priv(dev);
+
+       if (priv->flags & FLAG_TYPE_AX88172)
+               return -ENOSYS;
+
+       return asix_write_hwaddr_common(&priv->ueth, pdata->enetaddr);
+}
+
+static int asix_eth_probe(struct udevice *dev)
+{
+       struct eth_pdata *pdata = dev_get_platdata(dev);
+       struct asix_private *priv = dev_get_priv(dev);
+       struct ueth_data *ss = &priv->ueth;
+       int ret;
+
+       priv->flags = dev->driver_data;
+       ret = usb_ether_register(dev, ss, AX_RX_URB_SIZE);
+       if (ret)
+               return ret;
+
+       ret = asix_basic_reset(ss);
+       if (ret)
+               goto err;
+
+       /* Get the MAC address */
+       ret = asix_read_mac_common(ss, priv, pdata->enetaddr);
+       if (ret)
+               goto err;
+       debug("MAC %pM\n", pdata->enetaddr);
+
+       return 0;
+
+err:
+       return usb_ether_deregister(ss);
+}
+
+static const struct eth_ops asix_eth_ops = {
+       .start  = asix_eth_start,
+       .send   = asix_eth_send,
+       .recv   = asix_eth_recv,
+       .free_pkt = asix_free_pkt,
+       .stop   = asix_eth_stop,
+       .write_hwaddr = asix_write_hwaddr,
+};
+
+U_BOOT_DRIVER(asix_eth) = {
+       .name   = "asix_eth",
+       .id     = UCLASS_ETH,
+       .probe = asix_eth_probe,
+       .ops    = &asix_eth_ops,
+       .priv_auto_alloc_size = sizeof(struct asix_private),
+       .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+};
+
+static const struct usb_device_id asix_eth_id_table[] = {
+       /* Apple USB Ethernet Adapter */
+       { USB_DEVICE(0x05ac, 0x1402), .driver_info = FLAG_TYPE_AX88772 },
+       /* D-Link DUB-E100 H/W Ver B1 */
+       { USB_DEVICE(0x07d1, 0x3c05), .driver_info = FLAG_TYPE_AX88772 },
+       /* D-Link DUB-E100 H/W Ver C1 */
+       { USB_DEVICE(0x2001, 0x1a02), .driver_info = FLAG_TYPE_AX88772 },
+       /* Cables-to-Go USB Ethernet Adapter */
+       { USB_DEVICE(0x0b95, 0x772a), .driver_info = FLAG_TYPE_AX88772 },
+       /* Trendnet TU2-ET100 V3.0R */
+       { USB_DEVICE(0x0b95, 0x7720), .driver_info = FLAG_TYPE_AX88772 },
+       /* SMC */
+       { USB_DEVICE(0x0b95, 0x1720), .driver_info = FLAG_TYPE_AX88172 },
+       /* MSI - ASIX 88772a */
+       { USB_DEVICE(0x0db0, 0xa877), .driver_info = FLAG_TYPE_AX88772 },
+       /* Linksys 200M v2.1 */
+       { USB_DEVICE(0x13b1, 0x0018), .driver_info = FLAG_TYPE_AX88172 },
+       /* 0Q0 cable ethernet */
+       { USB_DEVICE(0x1557, 0x7720), .driver_info = FLAG_TYPE_AX88772 },
+       /* DLink DUB-E100 H/W Ver B1 Alternate */
+       { USB_DEVICE(0x2001, 0x3c05), .driver_info = FLAG_TYPE_AX88772 },
+       /* ASIX 88772B */
+       { USB_DEVICE(0x0b95, 0x772b),
+               .driver_info = FLAG_TYPE_AX88772B | FLAG_EEPROM_MAC },
+       { USB_DEVICE(0x0b95, 0x7e2b), .driver_info = FLAG_TYPE_AX88772B },
+       { }             /* Terminating entry */
+};
+
+U_BOOT_USB_DEVICE(asix_eth, asix_eth_id_table);
+#endif
index c72b7e47c488bf31cd837a8b6964f5375d6f59f8..63785a9c598195cbb9d9465154622c059ba24ff4 100644 (file)
 
 #include <common.h>
 #include <dm.h>
+#include <malloc.h>
 #include <usb.h>
 #include <dm/device-internal.h>
 
 #include "usb_ether.h"
 
+#ifdef CONFIG_DM_ETH
+
+#define USB_BULK_RECV_TIMEOUT 500
+
+int usb_ether_register(struct udevice *dev, struct ueth_data *ueth, int rxsize)
+{
+       struct usb_device *udev = dev_get_parentdata(dev);
+       struct usb_interface_descriptor *iface_desc;
+       bool ep_in_found = false, ep_out_found = false;
+       struct usb_interface *iface;
+       const int ifnum = 0; /* Always use interface 0 */
+       int ret, i;
+
+       iface = &udev->config.if_desc[ifnum];
+       iface_desc = &udev->config.if_desc[ifnum].desc;
+
+       /* Initialize the ueth_data structure with some useful info */
+       ueth->ifnum = ifnum;
+       ueth->subclass = iface_desc->bInterfaceSubClass;
+       ueth->protocol = iface_desc->bInterfaceProtocol;
+
+       /*
+        * We are expecting a minimum of 3 endpoints - in, out (bulk), and int.
+        * We will ignore any others.
+        */
+       for (i = 0; i < iface_desc->bNumEndpoints; i++) {
+               int ep_addr = iface->ep_desc[i].bEndpointAddress;
+
+               /* is it an BULK endpoint? */
+               if ((iface->ep_desc[i].bmAttributes &
+                    USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
+                       if (ep_addr & USB_DIR_IN && !ep_in_found) {
+                               ueth->ep_in = ep_addr &
+                                       USB_ENDPOINT_NUMBER_MASK;
+                               ep_in_found = true;
+                       } else if (!(ep_addr & USB_DIR_IN) && !ep_out_found) {
+                               ueth->ep_out = ep_addr &
+                                       USB_ENDPOINT_NUMBER_MASK;
+                               ep_out_found = true;
+                       }
+               }
+
+               /* is it an interrupt endpoint? */
+               if ((iface->ep_desc[i].bmAttributes &
+                   USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
+                       ueth->ep_int = iface->ep_desc[i].bEndpointAddress &
+                               USB_ENDPOINT_NUMBER_MASK;
+                       ueth->irqinterval = iface->ep_desc[i].bInterval;
+               }
+       }
+       debug("Endpoints In %d Out %d Int %d\n", ueth->ep_in, ueth->ep_out,
+             ueth->ep_int);
+
+       /* Do some basic sanity checks, and bail if we find a problem */
+       if (!ueth->ep_in || !ueth->ep_out || !ueth->ep_int) {
+               debug("%s: %s: Cannot find endpoints\n", __func__, dev->name);
+               return -ENXIO;
+       }
+
+       ueth->rxsize = rxsize;
+       ueth->rxbuf = memalign(rxsize, ARCH_DMA_MINALIGN);
+       if (!ueth->rxbuf)
+               return -ENOMEM;
+
+       ret = usb_set_interface(udev, iface_desc->bInterfaceNumber, ifnum);
+       if (ret) {
+               debug("%s: %s: Cannot set interface: %d\n", __func__, dev->name,
+                     ret);
+               return ret;
+       }
+       ueth->pusb_dev = udev;
+
+       return 0;
+}
+
+int usb_ether_deregister(struct ueth_data *ueth)
+{
+       return 0;
+}
+
+int usb_ether_receive(struct ueth_data *ueth, int rxsize)
+{
+       int actual_len;
+       int ret;
+
+       if (rxsize > ueth->rxsize)
+               return -EINVAL;
+       ret = usb_bulk_msg(ueth->pusb_dev,
+                          usb_rcvbulkpipe(ueth->pusb_dev, ueth->ep_in),
+                          ueth->rxbuf, rxsize, &actual_len,
+                          USB_BULK_RECV_TIMEOUT);
+       debug("Rx: len = %u, actual = %u, err = %d\n", rxsize, actual_len, ret);
+       if (ret) {
+               printf("Rx: failed to receive: %d\n", ret);
+               return ret;
+       }
+       if (actual_len > rxsize) {
+               debug("Rx: received too many bytes %d\n", actual_len);
+               return -ENOSPC;
+       }
+       ueth->rxlen = actual_len;
+       ueth->rxptr = 0;
+
+       return actual_len ? 0 : -EAGAIN;
+}
+
+void usb_ether_advance_rxbuf(struct ueth_data *ueth, int num_bytes)
+{
+       ueth->rxptr += num_bytes;
+       if (num_bytes < 0 || ueth->rxptr >= ueth->rxlen)
+               ueth->rxlen = 0;
+}
+
+int usb_ether_get_rx_bytes(struct ueth_data *ueth, uint8_t **ptrp)
+{
+       if (!ueth->rxlen)
+               return 0;
+
+       *ptrp = &ueth->rxbuf[ueth->rxptr];
+
+       return ueth->rxlen - ueth->rxptr;
+}
+
+#else
+
 typedef void (*usb_eth_before_probe)(void);
 typedef int (*usb_eth_probe)(struct usb_device *dev, unsigned int ifnum,
                        struct ueth_data *ss);
@@ -140,8 +266,8 @@ int usb_host_eth_scan(int mode)
        usb_max_eth_dev = 0;
 #ifdef CONFIG_DM_USB
        /*
-        * TODO: We should add USB_DEVICE() declarations to each USB ethernet
-        * driver and then most of this file can be removed.
+        * TODO: We should add U_BOOT_USB_DEVICE() declarations to each USB
+        * Ethernet driver and then most of this file can be removed.
         */
        struct udevice *bus;
        struct uclass *uc;
@@ -197,3 +323,4 @@ int usb_host_eth_scan(int mode)
                return 0;
        return -1;
 }
+#endif
index bf02221c9f0f5308399acacd1385c60a102ce825..3a0d32ee2ba1f0e3c9d49500e4570103e0f70487 100644 (file)
@@ -5,20 +5,7 @@
  *
  * All rights reserved.
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2 of
- * the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier:    GPL-2.0
  */
 #include <common.h>
 #include <dm.h>
@@ -321,7 +308,7 @@ static void ehci_update_endpt2_dev_n_port(struct usb_device *udev,
                struct udevice *dev = parent;
 
                if (device_get_uclass_id(dev->parent) != UCLASS_USB_HUB) {
-                       printf("ehci: Error cannot find high speed parent of usb-1 device\n");
+                       printf("ehci: Error cannot find high-speed parent of usb-1 device\n");
                        return;
                }
 
index b9eabc55936a2aa47574c543b5f0db68019c03c7..0cb9fcc166dcc59f428cd4333ed58e06878b687d 100644 (file)
@@ -2,29 +2,49 @@
  * Copyright (c) 2007-2008, Juniper Networks, Inc.
  * All rights reserved.
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2 of
- * the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier:    GPL-2.0
  */
 
 #include <common.h>
+#include <dm.h>
 #include <errno.h>
 #include <pci.h>
 #include <usb.h>
 
 #include "ehci.h"
 
+/* Information about a USB port */
+struct ehci_pci_priv {
+       struct ehci_ctrl ehci;
+};
+
+static void ehci_pci_common_init(pci_dev_t pdev, struct ehci_hccr **ret_hccr,
+                                struct ehci_hcor **ret_hcor)
+{
+       struct ehci_hccr *hccr;
+       struct ehci_hcor *hcor;
+       uint32_t cmd;
+
+       hccr = (struct ehci_hccr *)pci_map_bar(pdev,
+                       PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
+       hcor = (struct ehci_hcor *)((uint32_t) hccr +
+                       HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+       debug("EHCI-PCI init hccr 0x%x and hcor 0x%x hc_length %d\n",
+             (uint32_t)hccr, (uint32_t)hcor,
+             (uint32_t)HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+       *ret_hccr = hccr;
+       *ret_hcor = hcor;
+
+       /* enable busmaster */
+       pci_read_config_dword(pdev, PCI_COMMAND, &cmd);
+       cmd |= PCI_COMMAND_MASTER;
+       pci_write_config_dword(pdev, PCI_COMMAND, cmd);
+}
+
+#ifndef CONFIG_DM_USB
+
 #ifdef CONFIG_PCI_EHCI_DEVICE
 static struct pci_device_id ehci_pci_ids[] = {
        /* Please add supported PCI EHCI controller ids here */
@@ -33,7 +53,6 @@ static struct pci_device_id ehci_pci_ids[] = {
        {0x12D8, 0x400F},       /* Pericom */
        {0, 0}
 };
-#else
 #endif
 
 /*
@@ -44,9 +63,6 @@ int ehci_hcd_init(int index, enum usb_init_type init,
                struct ehci_hccr **ret_hccr, struct ehci_hcor **ret_hcor)
 {
        pci_dev_t pdev;
-       uint32_t cmd;
-       struct ehci_hccr *hccr;
-       struct ehci_hcor *hcor;
 
 #ifdef CONFIG_PCI_EHCI_DEVICE
        pdev = pci_find_devices(ehci_pci_ids, CONFIG_PCI_EHCI_DEVICE);
@@ -57,23 +73,8 @@ int ehci_hcd_init(int index, enum usb_init_type init,
                printf("EHCI host controller not found\n");
                return -1;
        }
+       ehci_pci_common_init(pdev, ret_hccr, ret_hcor);
 
-       hccr = (struct ehci_hccr *)pci_map_bar(pdev,
-                       PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
-       hcor = (struct ehci_hcor *)((uint32_t) hccr +
-                       HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
-
-       debug("EHCI-PCI init hccr 0x%x and hcor 0x%x hc_length %d\n",
-                       (uint32_t)hccr, (uint32_t)hcor,
-                       (uint32_t)HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
-
-       *ret_hccr = hccr;
-       *ret_hcor = hcor;
-
-       /* enable busmaster */
-       pci_read_config_dword(pdev, PCI_COMMAND, &cmd);
-       cmd |= PCI_COMMAND_MASTER;
-       pci_write_config_dword(pdev, PCI_COMMAND, cmd);
        return 0;
 }
 
@@ -85,3 +86,46 @@ int ehci_hcd_stop(int index)
 {
        return 0;
 }
+#endif /* nCONFIG_DM_USB */
+
+#ifdef CONFIG_DM_USB
+static int ehci_pci_probe(struct udevice *dev)
+{
+       struct ehci_hccr *hccr;
+       struct ehci_hcor *hcor;
+
+       ehci_pci_common_init(pci_get_bdf(dev), &hccr, &hcor);
+
+       return ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST);
+}
+
+static int ehci_pci_remove(struct udevice *dev)
+{
+       int ret;
+
+       ret = ehci_deregister(dev);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+U_BOOT_DRIVER(ehci_pci) = {
+       .name   = "ehci_pci",
+       .id     = UCLASS_USB,
+       .probe = ehci_pci_probe,
+       .remove = ehci_pci_remove,
+       .ops    = &ehci_usb_ops,
+       .platdata_auto_alloc_size = sizeof(struct usb_platdata),
+       .priv_auto_alloc_size = sizeof(struct ehci_pci_priv),
+       .flags  = DM_FLAG_ALLOC_PRIV_DMA,
+};
+
+static struct pci_device_id ehci_pci_supported[] = {
+       { PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_EHCI, ~0) },
+       {},
+};
+
+U_BOOT_PCI_DEVICE(ehci_pci, ehci_pci_supported);
+
+#endif /* CONFIG_DM_USB */
index 774282d28706df0d8621bfd1597d4f65cb153c5b..3379c293c4dfafa310c2f933eba0bce6d846a000 100644 (file)
@@ -3,20 +3,7 @@
  * Copyright (c) 2008, Michael Trimarchi <trimarchimichael@yahoo.it>
  * All rights reserved.
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2 of
- * the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier:    GPL-2.0
  */
 
 #ifndef USB_EHCI_H
index 6f33456c90d0130fe6be40e2265bf21954a6e050..373e04cbe5e09c0cc33f70edccef8c423cdb4cf2 100644 (file)
@@ -3,19 +3,7 @@
  *
  * Copyright (C) 2008  Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
+ * SPDX-License-Identifier:    GPL-2.0
  */
 
 #include <common.h>
index ca1b67155ea8ad80eeb2cebbf235d210a8f3f7aa..67dc3c4588ee015533bb6ddc3720f97d208958dd 100644 (file)
@@ -3,19 +3,7 @@
  *
  * Copyright (C) 2008  Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
+ * SPDX-License-Identifier:    GPL-2.0
  */
 
 #ifndef __R8A66597_H__
index 6e86f4a24a48ff26e19013ed7746d60212a66705..c5d1e7feb9d0e5da7e31ae2d3abe4c00a6b86350 100644 (file)
@@ -128,6 +128,17 @@ int usb_alloc_device(struct usb_device *udev)
        return ops->alloc_device(bus, udev);
 }
 
+int usb_reset_root_port(struct usb_device *udev)
+{
+       struct udevice *bus = udev->controller_dev;
+       struct dm_usb_ops *ops = usb_get_ops(bus);
+
+       if (!ops->reset_root_port)
+               return -ENOSYS;
+
+       return ops->reset_root_port(bus, udev);
+}
+
 int usb_stop(void)
 {
        struct udevice *bus;
@@ -146,6 +157,9 @@ int usb_stop(void)
                ret = device_remove(bus);
                if (ret && !err)
                        err = ret;
+               ret = device_unbind_children(bus);
+               if (ret && !err)
+                       err = ret;
        }
 
 #ifdef CONFIG_SANDBOX
@@ -265,11 +279,6 @@ int usb_init(void)
        return usb_started ? 0 : -1;
 }
 
-int usb_reset_root_port(void)
-{
-       return -ENOSYS;
-}
-
 static struct usb_device *find_child_devnum(struct udevice *parent, int devnum)
 {
        struct usb_device *udev;
@@ -294,14 +303,14 @@ static struct usb_device *find_child_devnum(struct udevice *parent, int devnum)
 
 struct usb_device *usb_get_dev_index(struct udevice *bus, int index)
 {
-       struct udevice *hub;
+       struct udevice *dev;
        int devnum = index + 1; /* Addresses are allocated from 1 on USB */
 
-       device_find_first_child(bus, &hub);
-       if (device_get_uclass_id(hub) == UCLASS_USB_HUB)
-               return find_child_devnum(hub, devnum);
+       device_find_first_child(bus, &dev);
+       if (!dev)
+               return NULL;
 
-       return NULL;
+       return find_child_devnum(dev, devnum);
 }
 
 int usb_post_bind(struct udevice *dev)
@@ -310,35 +319,6 @@ int usb_post_bind(struct udevice *dev)
        return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
 }
 
-int usb_port_reset(struct usb_device *parent, int portnr)
-{
-       unsigned short portstatus;
-       int ret;
-
-       debug("%s: start\n", __func__);
-
-       if (parent) {
-               /* reset the port for the second time */
-               assert(portnr > 0);
-               debug("%s: reset %d\n", __func__, portnr - 1);
-               ret = legacy_hub_port_reset(parent, portnr - 1, &portstatus);
-               if (ret < 0) {
-                       printf("\n     Couldn't reset port %i\n", portnr);
-                       return ret;
-               }
-       } else {
-               debug("%s: reset root\n", __func__);
-               usb_reset_root_port();
-       }
-
-       return 0;
-}
-
-int usb_legacy_port_reset(struct usb_device *parent, int portnr)
-{
-       return usb_port_reset(parent, portnr);
-}
-
 int usb_setup_ehci_gadget(struct ehci_ctrl **ctlrp)
 {
        struct usb_platdata *plat;
@@ -511,15 +491,14 @@ error:
 }
 
 /**
- * usb_find_child() - Find an existing device which matches our needs
- *
- *
+ * usb_find_emul_child() - Find an existing device for emulated devices
  */
-static int usb_find_child(struct udevice *parent,
-                         struct usb_device_descriptor *desc,
-                         struct usb_interface_descriptor *iface,
-                         struct udevice **devp)
+static int usb_find_emul_child(struct udevice *parent,
+                              struct usb_device_descriptor *desc,
+                              struct usb_interface_descriptor *iface,
+                              struct udevice **devp)
 {
+#ifdef CONFIG_SANDBOX
        struct udevice *dev;
 
        *devp = NULL;
@@ -538,7 +517,7 @@ static int usb_find_child(struct udevice *parent,
                        return 0;
                }
        }
-
+#endif
        return -ENOENT;
 }
 
@@ -594,12 +573,12 @@ int usb_scan_device(struct udevice *parent, int port,
        debug("Calling usb_setup_device(), portnr=%d\n", udev->portnr);
        parent_udev = device_get_uclass_id(parent) == UCLASS_USB_HUB ?
                dev_get_parentdata(parent) : NULL;
-       ret = usb_setup_device(udev, priv->desc_before_addr, parent_udev, port);
+       ret = usb_setup_device(udev, priv->desc_before_addr, parent_udev);
        debug("read_descriptor for '%s': ret=%d\n", parent->name, ret);
        if (ret)
                return ret;
-       ret = usb_find_child(parent, &udev->descriptor, iface, &dev);
-       debug("** usb_find_child returns %d\n", ret);
+       ret = usb_find_emul_child(parent, &udev->descriptor, iface, &dev);
+       debug("** usb_find_emul_child returns %d\n", ret);
        if (ret) {
                if (ret != -ENOENT)
                        return ret;
index 857d7eb0cce451c5d6d750cd8265867e114dd37e..d158454a086bbc2adbadc5656f228360c5f7d451 100644 (file)
@@ -100,7 +100,11 @@ struct am35x_glue {
 /*
  * am35x_musb_enable - enable interrupts
  */
+#ifndef __UBOOT__
 static void am35x_musb_enable(struct musb *musb)
+#else
+static int am35x_musb_enable(struct musb *musb)
+#endif
 {
        void __iomem *reg_base = musb->ctrl_base;
        u32 epmask;
@@ -116,6 +120,9 @@ static void am35x_musb_enable(struct musb *musb)
        if (is_otg_enabled(musb))
                musb_writel(reg_base, CORE_INTR_SRC_SET_REG,
                            AM35X_INTR_DRVVBUS << AM35X_INTR_USB_SHIFT);
+#ifdef __UBOOT__
+       return 0;
+#endif
 }
 
 /*
index 242cc30b1c2d07e4d81d8213a8352b03450208c3..f530af4fb73c4e5cb41f84e4b15e1ae6ec0dee90 100644 (file)
@@ -926,10 +926,17 @@ b_host:
 /*
 * Program the HDRC to start (enable interrupts, dma, etc.).
 */
+#ifndef __UBOOT__
 void musb_start(struct musb *musb)
+#else
+int musb_start(struct musb *musb)
+#endif
 {
        void __iomem    *regs = musb->mregs;
        u8              devctl = musb_readb(regs, MUSB_DEVCTL);
+#ifdef __UBOOT__
+       int ret;
+#endif
 
        dev_dbg(musb->controller, "<== devctl %02x\n", devctl);
 
@@ -972,8 +979,21 @@ void musb_start(struct musb *musb)
                if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS)
                        musb->is_active = 1;
        }
+
+#ifndef __UBOOT__
        musb_platform_enable(musb);
+#else
+       ret = musb_platform_enable(musb);
+       if (ret) {
+               musb->is_active = 0;
+               return ret;
+       }
+#endif
        musb_writeb(regs, MUSB_DEVCTL, devctl);
+
+#ifdef __UBOOT__
+       return 0;
+#endif
 }
 
 
index 26957420981774ff4858ec71cc396202a50b5dce..8727f6415e7bc81f5f2273eb4d44afaf2524f6b6 100644 (file)
@@ -231,7 +231,11 @@ struct musb_platform_ops {
        int     (*init)(struct musb *musb);
        int     (*exit)(struct musb *musb);
 
+#ifndef __UBOOT__
        void    (*enable)(struct musb *musb);
+#else
+       int     (*enable)(struct musb *musb);
+#endif
        void    (*disable)(struct musb *musb);
 
        int     (*set_mode)(struct musb *musb, u8 mode);
@@ -546,7 +550,11 @@ static inline void musb_configure_ep0(struct musb *musb)
 
 extern const char musb_driver_name[];
 
+#ifndef __UBOOT__
 extern void musb_start(struct musb *musb);
+#else
+extern int musb_start(struct musb *musb);
+#endif
 extern void musb_stop(struct musb *musb);
 
 extern void musb_write_fifo(struct musb_hw_ep *ep, u16 len, const u8 *src);
@@ -564,11 +572,21 @@ static inline void musb_platform_set_vbus(struct musb *musb, int is_on)
                musb->ops->set_vbus(musb, is_on);
 }
 
+#ifndef __UBOOT__
 static inline void musb_platform_enable(struct musb *musb)
 {
        if (musb->ops->enable)
                musb->ops->enable(musb);
 }
+#else
+static inline int musb_platform_enable(struct musb *musb)
+{
+       if (!musb->ops->enable)
+               return 0;
+
+       return musb->ops->enable(musb);
+}
+#endif
 
 static inline void musb_platform_disable(struct musb *musb)
 {
index 17ed224488f3c924c2c5873e74bd49c8f880120c..895939773a7cdb389ea06551a70e54afb8831c02 100644 (file)
@@ -156,7 +156,11 @@ struct dsps_glue {
 /**
  * dsps_musb_enable - enable interrupts
  */
+#ifndef __UBOOT__
 static void dsps_musb_enable(struct musb *musb)
+#else
+static int dsps_musb_enable(struct musb *musb)
+#endif
 {
 #ifndef __UBOOT__
        struct device *dev = musb->controller;
@@ -181,6 +185,8 @@ static void dsps_musb_enable(struct musb *musb)
        if (is_otg_enabled(musb))
                dsps_writel(reg_base, wrp->coreintr_set,
                            (1 << wrp->drvvbus) << wrp->usb_shift);
+#else
+       return 0;
 #endif
 }
 
index 5a715013a2315e945c0b3a2ab354a4fe533f7f46..415a9f21a9c6c13187511486c016c8693ff5b6ac 100644 (file)
@@ -43,6 +43,7 @@
 #else
 #include <common.h>
 #include "linux-compat.h"
+#include <asm/processor.h>
 #endif
 
 #include "musb_core.h"
index 437309ceb44a380bfed9b05d73d6f9828db08210..40b9c66af89bfea4be21ddffec5b6af2f0a445d2 100644 (file)
@@ -2067,7 +2067,11 @@ int musb_urb_enqueue(
 
        /* precompute addressing for external hub/tt ports */
        if (musb->is_multipoint) {
+#ifndef __UBOOT__
                struct usb_device       *parent = urb->dev->parent;
+#else
+               struct usb_device       *parent = usb_dev_get_parent(urb->dev);
+#endif
 
 #ifndef __UBOOT__
                if (parent != hcd->self.root_hub) {
index d1ee5f8d0651eac8532fcda026e3ce2cc64d5054..9b56e904e44ba0b7de2ba5530f616971f445cfe4 100644 (file)
@@ -13,6 +13,7 @@
 #include "musb_core.h"
 #include "musb_host.h"
 #include "musb_gadget.h"
+#include "musb_uboot.h"
 
 #ifdef CONFIG_MUSB_HOST
 struct int_queue {
@@ -20,9 +21,9 @@ struct int_queue {
        struct urb urb;
 };
 
-static struct musb *host;
-static struct usb_hcd hcd;
-static enum usb_device_speed host_speed;
+#ifndef CONFIG_DM_USB
+struct musb_host_data musb_host;
+#endif
 
 static void musb_host_complete_urb(struct urb *urb)
 {
@@ -30,9 +31,6 @@ static void musb_host_complete_urb(struct urb *urb)
        urb->dev->act_len = urb->actual_length;
 }
 
-static struct usb_host_endpoint hep;
-static struct urb urb;
-
 static void construct_urb(struct urb *urb, struct usb_host_endpoint *hep,
                          struct usb_device *dev, int endpoint_type,
                          unsigned long pipe, void *buffer, int len,
@@ -90,38 +88,40 @@ static int submit_urb(struct usb_hcd *hcd, struct urb *urb)
        return urb->status;
 }
 
-int submit_control_msg(struct usb_device *dev, unsigned long pipe,
-                       void *buffer, int len, struct devrequest *setup)
+static int _musb_submit_control_msg(struct musb_host_data *host,
+       struct usb_device *dev, unsigned long pipe,
+       void *buffer, int len, struct devrequest *setup)
 {
-       construct_urb(&urb, &hep, dev, USB_ENDPOINT_XFER_CONTROL, pipe,
-                     buffer, len, setup, 0);
+       construct_urb(&host->urb, &host->hep, dev, USB_ENDPOINT_XFER_CONTROL,
+                     pipe, buffer, len, setup, 0);
 
        /* Fix speed for non hub-attached devices */
-       if (!dev->parent)
-               dev->speed = host_speed;
+       if (!usb_dev_get_parent(dev))
+               dev->speed = host->host_speed;
 
-       return submit_urb(&hcd, &urb);
+       return submit_urb(&host->hcd, &host->urb);
 }
 
-
-int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
-                                       void *buffer, int len)
+static int _musb_submit_bulk_msg(struct musb_host_data *host,
+       struct usb_device *dev, unsigned long pipe, void *buffer, int len)
 {
-       construct_urb(&urb, &hep, dev, USB_ENDPOINT_XFER_BULK, pipe,
-                     buffer, len, NULL, 0);
-       return submit_urb(&hcd, &urb);
+       construct_urb(&host->urb, &host->hep, dev, USB_ENDPOINT_XFER_BULK,
+                     pipe, buffer, len, NULL, 0);
+       return submit_urb(&host->hcd, &host->urb);
 }
 
-int submit_int_msg(struct usb_device *dev, unsigned long pipe,
-                               void *buffer, int len, int interval)
+static int _musb_submit_int_msg(struct musb_host_data *host,
+       struct usb_device *dev, unsigned long pipe,
+       void *buffer, int len, int interval)
 {
-       construct_urb(&urb, &hep, dev, USB_ENDPOINT_XFER_INT, pipe,
+       construct_urb(&host->urb, &host->hep, dev, USB_ENDPOINT_XFER_INT, pipe,
                      buffer, len, NULL, interval);
-       return submit_urb(&hcd, &urb);
+       return submit_urb(&host->hcd, &host->urb);
 }
 
-struct int_queue *create_int_queue(struct usb_device *dev, unsigned long pipe,
-       int queuesize, int elementsize, void *buffer, int interval)
+static struct int_queue *_musb_create_int_queue(struct musb_host_data *host,
+       struct usb_device *dev, unsigned long pipe, int queuesize,
+       int elementsize, void *buffer, int interval)
 {
        struct int_queue *queue;
        int ret, index = usb_pipein(pipe) * 16 + usb_pipeendpoint(pipe);
@@ -143,7 +143,7 @@ struct int_queue *create_int_queue(struct usb_device *dev, unsigned long pipe,
        construct_urb(&queue->urb, &queue->hep, dev, USB_ENDPOINT_XFER_INT,
                      pipe, buffer, elementsize, NULL, interval);
 
-       ret = musb_urb_enqueue(&hcd, &queue->urb, 0);
+       ret = musb_urb_enqueue(&host->hcd, &queue->urb, 0);
        if (ret < 0) {
                printf("Failed to enqueue URB to controller\n");
                free(queue);
@@ -154,25 +154,27 @@ struct int_queue *create_int_queue(struct usb_device *dev, unsigned long pipe,
        return queue;
 }
 
-int destroy_int_queue(struct usb_device *dev, struct int_queue *queue)
+static int _musb_destroy_int_queue(struct musb_host_data *host,
+       struct usb_device *dev, struct int_queue *queue)
 {
        int index = usb_pipein(queue->urb.pipe) * 16 + 
                    usb_pipeendpoint(queue->urb.pipe);
 
        if (queue->urb.status == -EINPROGRESS)
-               musb_urb_dequeue(&hcd, &queue->urb, -ETIME);
+               musb_urb_dequeue(&host->hcd, &queue->urb, -ETIME);
 
        dev->int_pending &= ~(1 << index);
        free(queue);
        return 0;
 }
 
-void *poll_int_queue(struct usb_device *dev, struct int_queue *queue)
+static void *_musb_poll_int_queue(struct musb_host_data *host,
+       struct usb_device *dev, struct int_queue *queue)
 {
        if (queue->urb.status != -EINPROGRESS)
                return NULL; /* URB has already completed in a prev. poll */
 
-       host->isr(0, host);
+       host->host->isr(0, host->host);
 
        if (queue->urb.status != -EINPROGRESS)
                return queue->urb.transfer_buffer; /* Done */
@@ -180,9 +182,10 @@ void *poll_int_queue(struct usb_device *dev, struct int_queue *queue)
        return NULL; /* URB still pending */
 }
 
-int usb_reset_root_port(void)
+static int _musb_reset_root_port(struct musb_host_data *host,
+       struct usb_device *dev)
 {
-       void *mbase = host->mregs;
+       void *mbase = host->host->mregs;
        u8 power;
 
        power = musb_readb(mbase, MUSB_POWER);
@@ -202,29 +205,33 @@ int usb_reset_root_port(void)
 #ifdef CONFIG_ARCH_SUNXI
        sunxi_usb_phy_enable_squelch_detect(0, 1);
 #endif
-       host->isr(0, host);
-       host_speed = (musb_readb(mbase, MUSB_POWER) & MUSB_POWER_HSMODE) ?
+       host->host->isr(0, host->host);
+       host->host_speed = (musb_readb(mbase, MUSB_POWER) & MUSB_POWER_HSMODE) ?
                        USB_SPEED_HIGH :
                        (musb_readb(mbase, MUSB_DEVCTL) & MUSB_DEVCTL_FSDEV) ?
                        USB_SPEED_FULL : USB_SPEED_LOW;
-       mdelay((host_speed == USB_SPEED_LOW) ? 200 : 50);
+       mdelay((host->host_speed == USB_SPEED_LOW) ? 200 : 50);
 
        return 0;
 }
 
-int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
+int musb_lowlevel_init(struct musb_host_data *host)
 {
        void *mbase;
        /* USB spec says it may take up to 1 second for a device to connect */
        unsigned long timeout = get_timer(0) + 1000;
+       int ret;
 
-       if (!host) {
+       if (!host->host) {
                printf("MUSB host is not registered\n");
                return -ENODEV;
        }
 
-       musb_start(host);
-       mbase = host->mregs;
+       ret = musb_start(host->host);
+       if (ret)
+               return ret;
+
+       mbase = host->host->mregs;
        do {
                if (musb_readb(mbase, MUSB_DEVCTL) & MUSB_DEVCTL_HM)
                        break;
@@ -232,23 +239,135 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
        if (get_timer(0) >= timeout)
                return -ENODEV;
 
-       usb_reset_root_port();
-       host->is_active = 1;
-       hcd.hcd_priv = host;
+       _musb_reset_root_port(host, NULL);
+       host->host->is_active = 1;
+       host->hcd.hcd_priv = host->host;
 
        return 0;
 }
 
+#ifndef CONFIG_DM_USB
 int usb_lowlevel_stop(int index)
 {
-       if (!host) {
+       if (!musb_host.host) {
                printf("MUSB host is not registered\n");
                return -ENODEV;
        }
 
-       musb_stop(host);
+       musb_stop(musb_host.host);
        return 0;
 }
+
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
+                           void *buffer, int length)
+{
+       return _musb_submit_bulk_msg(&musb_host, dev, pipe, buffer, length);
+}
+
+int submit_control_msg(struct usb_device *dev, unsigned long pipe,
+                      void *buffer, int length, struct devrequest *setup)
+{
+       return _musb_submit_control_msg(&musb_host, dev, pipe, buffer, length, setup);
+}
+
+int submit_int_msg(struct usb_device *dev, unsigned long pipe,
+                  void *buffer, int length, int interval)
+{
+       return _musb_submit_int_msg(&musb_host, dev, pipe, buffer, length, interval);
+}
+
+struct int_queue *create_int_queue(struct usb_device *dev,
+               unsigned long pipe, int queuesize, int elementsize,
+               void *buffer, int interval)
+{
+       return _musb_create_int_queue(&musb_host, dev, pipe, queuesize, elementsize,
+                                     buffer, interval);
+}
+
+void *poll_int_queue(struct usb_device *dev, struct int_queue *queue)
+{
+       return _musb_poll_int_queue(&musb_host, dev, queue);
+}
+
+int destroy_int_queue(struct usb_device *dev, struct int_queue *queue)
+{
+       return _musb_destroy_int_queue(&musb_host, dev, queue);
+}
+
+int usb_reset_root_port(struct usb_device *dev)
+{
+       return _musb_reset_root_port(&musb_host, dev);
+}
+
+int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
+{
+       return musb_lowlevel_init(&musb_host);
+}
+#endif /* !CONFIG_DM_USB */
+
+#ifdef CONFIG_DM_USB
+static int musb_submit_control_msg(struct udevice *dev, struct usb_device *udev,
+                                  unsigned long pipe, void *buffer, int length,
+                                  struct devrequest *setup)
+{
+       struct musb_host_data *host = dev_get_priv(dev);
+       return _musb_submit_control_msg(host, udev, pipe, buffer, length, setup);
+}
+
+static int musb_submit_bulk_msg(struct udevice *dev, struct usb_device *udev,
+                               unsigned long pipe, void *buffer, int length)
+{
+       struct musb_host_data *host = dev_get_priv(dev);
+       return _musb_submit_bulk_msg(host, udev, pipe, buffer, length);
+}
+
+static int musb_submit_int_msg(struct udevice *dev, struct usb_device *udev,
+                              unsigned long pipe, void *buffer, int length,
+                              int interval)
+{
+       struct musb_host_data *host = dev_get_priv(dev);
+       return _musb_submit_int_msg(host, udev, pipe, buffer, length, interval);
+}
+
+static struct int_queue *musb_create_int_queue(struct udevice *dev,
+               struct usb_device *udev, unsigned long pipe, int queuesize,
+               int elementsize, void *buffer, int interval)
+{
+       struct musb_host_data *host = dev_get_priv(dev);
+       return _musb_create_int_queue(host, udev, pipe, queuesize, elementsize,
+                                     buffer, interval);
+}
+
+static void *musb_poll_int_queue(struct udevice *dev, struct usb_device *udev,
+                                struct int_queue *queue)
+{
+       struct musb_host_data *host = dev_get_priv(dev);
+       return _musb_poll_int_queue(host, udev, queue);
+}
+
+static int musb_destroy_int_queue(struct udevice *dev, struct usb_device *udev,
+                                 struct int_queue *queue)
+{
+       struct musb_host_data *host = dev_get_priv(dev);
+       return _musb_destroy_int_queue(host, udev, queue);
+}
+
+static int musb_reset_root_port(struct udevice *dev, struct usb_device *udev)
+{
+       struct musb_host_data *host = dev_get_priv(dev);
+       return _musb_reset_root_port(host, udev);
+}
+
+struct dm_usb_ops musb_usb_ops = {
+       .control = musb_submit_control_msg,
+       .bulk = musb_submit_bulk_msg,
+       .interrupt = musb_submit_int_msg,
+       .create_int_queue = musb_create_int_queue,
+       .poll_int_queue = musb_poll_int_queue,
+       .destroy_int_queue = musb_destroy_int_queue,
+       .reset_root_port = musb_reset_root_port,
+};
+#endif /* CONFIG_DM_USB */
 #endif /* CONFIG_MUSB_HOST */
 
 #ifdef CONFIG_MUSB_GADGET
@@ -309,9 +428,9 @@ int musb_register(struct musb_hdrc_platform_data *plat, void *bdata,
        struct musb **musbp;
 
        switch (plat->mode) {
-#ifdef CONFIG_MUSB_HOST
+#if defined(CONFIG_MUSB_HOST) && !defined(CONFIG_DM_USB)
        case MUSB_HOST:
-               musbp = &host;
+               musbp = &musb_host.host;
                break;
 #endif
 #ifdef CONFIG_MUSB_GADGET
diff --git a/drivers/usb/musb-new/musb_uboot.h b/drivers/usb/musb-new/musb_uboot.h
new file mode 100644 (file)
index 0000000..6312cd2
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * MUSB OTG driver u-boot specific functions
+ *
+ * Copyright Â© 2015 Hans de Goede <hdegoede@redhat.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+#ifndef __MUSB_UBOOT_H__
+#define __MUSB_UBOOT_H__
+
+#include <usb.h>
+#include "linux-compat.h"
+#include "usb-compat.h"
+#include "musb_core.h"
+
+struct musb_host_data {
+       struct musb *host;
+       struct usb_hcd hcd;
+       enum usb_device_speed host_speed;
+       struct usb_host_endpoint hep;
+       struct urb urb;
+};
+
+extern struct dm_usb_ops musb_usb_ops;
+
+int musb_lowlevel_init(struct musb_host_data *host);
+
+#endif
index 31a280edba0e51f1a3c59ee0ada5d79b79cf4bfb..77273a49a31e47edb27d05437d4c7faf17e21965 100644 (file)
@@ -400,7 +400,11 @@ err1:
        return status;
 }
 
+#ifndef __UBOOT__
 static void omap2430_musb_enable(struct musb *musb)
+#else
+static int omap2430_musb_enable(struct musb *musb)
+#endif
 {
 #ifndef __UBOOT__
        u8              devctl;
@@ -445,6 +449,7 @@ static void omap2430_musb_enable(struct musb *musb)
                                __PRETTY_FUNCTION__);
        }
 #endif
+       return 0;
 #endif
 }
 
index 052e0657d03d22261f9951a13c9295cc119c395b..c123d61af2c3d274b76d7395b9e4460b257624ec 100644 (file)
@@ -199,12 +199,12 @@ static irqreturn_t sunxi_musb_interrupt(int irq, void *__hci)
 /* musb_core does not call enable / disable in a balanced manner <sigh> */
 static bool enabled = false;
 
-static void sunxi_musb_enable(struct musb *musb)
+static int sunxi_musb_enable(struct musb *musb)
 {
        pr_debug("%s():\n", __func__);
 
        if (enabled)
-               return;
+               return 0;
 
        /* select PIO mode */
        musb_writeb(musb->mregs, USBC_REG_o_VEND0, 0);
@@ -215,6 +215,7 @@ static void sunxi_musb_enable(struct musb *musb)
        USBC_ForceVbusValidToHigh(musb->mregs);
 
        enabled = true;
+       return 0;
 }
 
 static void sunxi_musb_disable(struct musb *musb)
index 50bad378c5de95c6527cc1016021a790d4daa087..53fe4ff3c4535490a16b755b587892bf437ef926 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef __USB_COMPAT_H__
 #define __USB_COMPAT_H__
 
+#include <dm.h>
 #include "usb.h"
 
 struct usb_hcd {
@@ -66,6 +67,68 @@ static inline int usb_hcd_unmap_urb_for_dma(struct usb_hcd *hcd,
        return 0;
 }
 
+#ifdef CONFIG_DM_USB
+static inline u16 find_tt(struct usb_device *udev)
+{
+       struct udevice *parent;
+       struct usb_device *uparent, *ttdev;
+
+       /*
+        * When called from usb-uclass.c: usb_scan_device() udev->dev points
+        * to the parent udevice, not the actual udevice belonging to the
+        * udev as the device is not instantiated yet. So when searching
+        * for the first usb-2 parent start with udev->dev not
+        * udev->dev->parent .
+        */
+       ttdev = udev;
+       parent = udev->dev;
+       uparent = dev_get_parentdata(parent);
+
+       while (uparent->speed != USB_SPEED_HIGH) {
+               struct udevice *dev = parent;
+
+               if (device_get_uclass_id(dev->parent) != UCLASS_USB_HUB) {
+                       printf("musb: Error cannot find high speed parent of usb-1 device\n");
+                       return 0;
+               }
+
+               ttdev = dev_get_parentdata(dev);
+               parent = dev->parent;
+               uparent = dev_get_parentdata(parent);
+       }
+
+       return (uparent->devnum << 8) | (ttdev->portnr - 1);
+}
+
+static inline struct usb_device *usb_dev_get_parent(struct usb_device *udev)
+{
+       struct udevice *parent = udev->dev->parent;
+
+       /*
+        * When called from usb-uclass.c: usb_scan_device() udev->dev points
+        * to the parent udevice, not the actual udevice belonging to the
+        * udev as the device is not instantiated yet.
+        *
+        * If dev is an usb-bus, then we are called from usb_scan_device() for
+        * an usb-device plugged directly into the root port, return NULL.
+        */
+       if (device_get_uclass_id(udev->dev) == UCLASS_USB)
+               return NULL;
+
+       /*
+        * If these 2 are not the same we are being called from
+        * usb_scan_device() and udev itself is the parent.
+        */
+       if (dev_get_parentdata(udev->dev) != udev)
+               return udev;
+
+       /* We are being called normally, use the parent pointer */
+       if (device_get_uclass_id(parent) == UCLASS_USB_HUB)
+               return dev_get_parentdata(parent);
+
+       return NULL;
+}
+#else
 static inline u16 find_tt(struct usb_device *dev)
 {
        u8 chid;
@@ -86,4 +149,11 @@ static inline u16 find_tt(struct usb_device *dev)
 
        return (hub << 8) | chid;
 }
+
+static inline struct usb_device *usb_dev_get_parent(struct usb_device *dev)
+{
+       return dev->parent;
+}
+#endif
+
 #endif /* __USB_COMPAT_H__ */
index 957f5c7ffad2a2ab6637024169f84bfdc6489f75..09cfefbd35358adb5335fea0f2dc53eda94be99e 100644 (file)
@@ -56,4 +56,16 @@ config DEFAULT_DEVICE_TREE
          It can be overridden from the command line:
          $ make DEVICE_TREE=<device-tree-name>
 
+config OF_SPL_REMOVE_PROPS
+       string "List of device tree properties to drop for SPL"
+       depends on OF_CONTROL && SPL
+       default "pinctrl-0 pinctrl-names clocks clock-names interrupt-parent"
+       help
+         Since SPL normally runs in a reduced memory space, the device tree
+         is cut down to only what is needed to load and start U-Boot. Only
+         nodes marked with the property "u-boot,dm-pre-reloc" will be
+         included. In addition, some properties are not used by U-Boot and
+         can be discarded. This option defines the list of properties to
+         discard.
+
 endmenu
index db0550b67cb44bad712e49851e3b1ad7101a22ea..7ef3e259b46b501b5dd0053e47a13e9c03684a0c 100644 (file)
@@ -116,5 +116,6 @@ typedef struct global_data {
 #define GD_FLG_ENV_READY       0x00080 /* Env. imported into hash table   */
 #define GD_FLG_SERIAL_READY    0x00100 /* Pre-reloc serial console ready  */
 #define GD_FLG_FULL_MALLOC_INIT        0x00200 /* Full malloc() is ready          */
+#define GD_FLG_SPL_INIT                0x00400 /* spl_init() has been called      */
 
 #endif /* __ASM_GENERIC_GBL_DATA_H */
index de91e57efcd672a4e61e06434a6d0c042a3c0b07..0af599f86df5bee53efa1745a833d386df6665a6 100644 (file)
@@ -321,6 +321,19 @@ struct gpio_dev_priv {
  */
 const char *gpio_get_bank_info(struct udevice *dev, int *offset_count);
 
+/**
+ * dm_gpio_lookup_name() - Look up a named GPIO and return its description
+ *
+ * The name of a GPIO is typically its bank name followed by a number from 0.
+ * For example A0 is the first GPIO in bank A. Each bank is a separate driver
+ * model device.
+ *
+ * @name:      Name to look up
+ * @desc:      Returns description, on success
+ * @return 0 if OK, -ve on error
+ */
+int dm_gpio_lookup_name(const char *name, struct gpio_desc *desc);
+
 /**
  * gpio_lookup_name - Look up a GPIO name and return its details
  *
@@ -420,6 +433,18 @@ int gpio_request_list_by_name(struct udevice *dev, const char *list_name,
                              struct gpio_desc *desc_list, int max_count,
                              int flags);
 
+/**
+ * dm_gpio_request() - manually request a GPIO
+ *
+ * Note: This function should only be used for testing / debugging. Instead.
+ * use gpio_request_by_name() to pull GPIOs from the device tree.
+ *
+ * @desc:      GPIO description of GPIO to request (see dm_gpio_lookup_name())
+ * @label:     Label to attach to the GPIO while claimed
+ * @return 0 if OK, -ve on error
+ */
+int dm_gpio_request(struct gpio_desc *desc, const char *label);
+
 /**
  * gpio_get_list_count() - Returns the number of GPIOs in a list
  *
index df4570c6f54abb0f5e6aac166b8096c19becdf69..254ad2b8761bf4acef3a5b4b06b3c6bc4c11ac11 100644 (file)
@@ -1,6 +1,86 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
 #ifndef _CLK_H_
 #define _CLK_H_
 
 int soc_clk_dump(void);
 
+struct clk_ops {
+       /**
+        * get_rate() - Get current clock rate
+        *
+        * @dev:        Device to check (UCLASS_CLK)
+        * @return clock rate in Hz, or -ve error code
+        */
+       ulong (*get_rate)(struct udevice *dev);
+
+       /**
+        * set_rate() - Set current clock rate
+        *
+        * @dev:        Device to adjust
+        * @rate:       New clock rate in Hz
+        * @return new rate, or -ve error code
+        */
+       ulong (*set_rate)(struct udevice *dev, ulong rate);
+
+       /**
+       * clk_set_periph_rate() - Set clock rate for a peripheral
+       *
+       * @dev: Device to adjust (UCLASS_CLK)
+       * @rate:        New clock rate in Hz
+       * @return new clock rate in Hz, or -ve error code
+       */
+       ulong (*get_periph_rate)(struct udevice *dev, int periph);
+
+       /**
+        * clk_set_periph_rate() - Set current clock rate for a peripheral
+        *
+        * @dev:        Device to update (UCLASS_CLK)
+        * @periph:     Peripheral ID to cupdate
+        * @return new clock rate in Hz, or -ve error code
+        */
+       ulong (*set_periph_rate)(struct udevice *dev, int periph, ulong rate);
+};
+
+#define clk_get_ops(dev)       ((struct clk_ops *)(dev)->driver->ops)
+
+/**
+ * clk_get_rate() - Get current clock rate
+ *
+ * @dev:       Device to check (UCLASS_CLK)
+ * @return clock rate in Hz, or -ve error code
+ */
+ulong clk_get_rate(struct udevice *dev);
+
+/**
+ * set_rate() - Set current clock rate
+ *
+ * @dev:       Device to adjust
+ * @rate:      New clock rate in Hz
+ * @return new rate, or -ve error code
+ */
+ulong clk_set_rate(struct udevice *dev, ulong rate);
+
+/**
+ * clk_get_periph_rate() - Get current clock rate for a peripheral
+ *
+ * @dev:       Device to check (UCLASS_CLK)
+ * @return clock rate in Hz, -ve error code
+ */
+ulong clk_get_periph_rate(struct udevice *dev, int periph);
+
+/**
+ * clk_set_periph_rate() - Set current clock rate for a peripheral
+ *
+ * @dev:       Device to update (UCLASS_CLK)
+ * @periph:    Peripheral ID to cupdate
+ * @return new clock rate in Hz, or -ve error code
+ */
+ulong clk_set_periph_rate(struct udevice *dev, int periph, ulong rate);
+
 #endif /* _CLK_H_ */
index 8f4b2ec21277d82977f59f4e50749eaa578cdfa7..4566bd11111c97061856a4386e883fa53f784bab 100644 (file)
@@ -1010,6 +1010,17 @@ int cpu_release(int nr, int argc, char * const argv[]);
 #define DEFINE_CACHE_ALIGN_BUFFER(type, name, size)                    \
        DEFINE_ALIGN_BUFFER(type, name, size, ARCH_DMA_MINALIGN)
 
+/*
+ * check_member() - Check the offset of a structure member
+ *
+ * @structure: Name of structure (e.g. global_data)
+ * @member:    Name of member (e.g. baudrate)
+ * @offset:    Expected offset in bytes
+ */
+#define check_member(structure, member, offset) _Static_assert( \
+       offsetof(struct structure, member) == offset, \
+       "`struct " #structure "` offset for `" #member "` is not " #offset)
+
 /* Pull in stuff for the build system */
 #ifdef DO_DEPS_ONLY
 # include <environment.h>
index af36ac5cafe48b9ac2aa4e6e7687d39b111051c2..4781e792f9bc899572bd405889381c2d16ef50e7 100644 (file)
@@ -60,9 +60,6 @@
 #define CONFIG_FIT_SIGNATURE
 #define CONFIG_RSA
 
-/* Avoid a warning in the Realtek Ethernet driver */
-#define CONFIG_SYS_CACHELINE_SIZE 16
-
 #define CONFIG_ENV_SECT_SIZE           0x1000
 #define CONFIG_ENV_OFFSET              0x007fe000
 
index f56797b72f4f98f5f87f549fd198b2c7863ddc96..a75e377dc0fab36a48bffbe0972b3388dc626941 100644 (file)
@@ -10,8 +10,6 @@
 #ifndef _DEBUG_UART_H
 #define _DEBUG_UART_H
 
-#include <linux/linkage.h>
-
 /*
  * The debug UART is intended for use very early in U-Boot to debug problems
  * when an ICE or other debug mechanism is not available.
@@ -64,46 +62,46 @@ void debug_uart_init(void);
  *
  * @ch:                Character to output
  */
-asmlinkage void printch(int ch);
+void printch(int ch);
 
 /**
  * printascii() - Output an ASCII string to the debug UART
  *
  * @str:       String to output
  */
-asmlinkage void printascii(const char *str);
+void printascii(const char *str);
 
 /**
  * printhex2() - Output a 2-digit hex value
  *
  * @value:     Value to output
  */
-asmlinkage void printhex2(uint value);
+void printhex2(uint value);
 
 /**
  * printhex4() - Output a 4-digit hex value
  *
  * @value:     Value to output
  */
-asmlinkage void printhex4(uint value);
+void printhex4(uint value);
 
 /**
  * printhex8() - Output a 8-digit hex value
  *
  * @value:     Value to output
  */
-asmlinkage void printhex8(uint value);
+void printhex8(uint value);
 
 /*
  * Now define some functions - this should be inserted into the serial driver
  */
 #define DEBUG_UART_FUNCS \
-       asmlinkage void printch(int ch) \
+       void printch(int ch) \
        { \
                _debug_uart_putc(ch); \
        } \
 \
-       asmlinkage void printascii(const char *str) \
+       void printascii(const char *str) \
        { \
                while (*str) \
                        _debug_uart_putc(*str++); \
@@ -121,17 +119,17 @@ asmlinkage void printhex8(uint value);
                        printhex1(value >> (4 * digits)); \
        } \
 \
-       asmlinkage void printhex2(uint value) \
+       void printhex2(uint value) \
        { \
                printhex(value, 2); \
        } \
 \
-       asmlinkage void printhex4(uint value) \
+       void printhex4(uint value) \
        { \
                printhex(value, 4); \
        } \
 \
-       asmlinkage void printhex8(uint value) \
+       void printhex8(uint value) \
        { \
                printhex(value, 8); \
        }
index 687462b093424a9e3706df839fa3846ef82dbe37..402304f19efa1e5efc297bef78b9b47982f9f6ab 100644 (file)
@@ -107,6 +107,32 @@ int device_unbind(struct udevice *dev);
 static inline int device_unbind(struct udevice *dev) { return 0; }
 #endif
 
+/**
+ * device_remove_children() - Stop all device's children
+ * @dev:       The device whose children are to be removed
+ * @return 0 on success, -ve on error
+ */
+#ifdef CONFIG_DM_DEVICE_REMOVE
+int device_remove_children(struct udevice *dev);
+#else
+static inline int device_remove_children(struct udevice *dev) { return 0; }
+#endif
+
+/**
+ * device_unbind_children() - Unbind all device's children from the device
+ *
+ * On error, the function continues to unbind all children, and reports the
+ * first error.
+ *
+ * @dev:       The device that is to be stripped of its children
+ * @return 0 on success, -ve on error
+ */
+#ifdef CONFIG_DM_DEVICE_REMOVE
+int device_unbind_children(struct udevice *dev);
+#else
+static inline int device_unbind_children(struct udevice *dev) { return 0; }
+#endif
+
 #ifdef CONFIG_DM_DEVICE_REMOVE
 void device_free(struct udevice *dev);
 #else
index 18296bb68614b9aeae25c46b5ff3c8306e8a36d1..9fa0048bd0a4448b481071d5aae8b14c7d063898 100644 (file)
@@ -386,9 +386,23 @@ int device_find_child_by_of_offset(struct udevice *parent, int of_offset,
  * @devp: Returns pointer to device if found, otherwise this is set to NULL
  * @return 0 if OK, -ve on error
  */
-int device_get_child_by_of_offset(struct udevice *parent, int seq,
+int device_get_child_by_of_offset(struct udevice *parent, int of_offset,
                                  struct udevice **devp);
 
+/**
+ * device_get_global_by_of_offset() - Get a device based on FDT offset
+ *
+ * Locates a device by its device tree offset, searching globally throughout
+ * the all driver model devices.
+ *
+ * The device is probed to activate it ready for use.
+ *
+ * @of_offset: Device tree offset to find
+ * @devp: Returns pointer to device if found, otherwise this is set to NULL
+ * @return 0 if OK, -ve on error
+ */
+int device_get_global_by_of_offset(int of_offset, struct udevice **devp);
+
 /**
  * device_find_first_child() - Find the first child of a device
  *
index fbc8a6b3adda18424bd485a0ea39df981143f55e..6f4f00140e5690f404b3169e2dce4e2c0133e735 100644 (file)
 /**
  * struct driver_info - Information required to instantiate a device
  *
+ * NOTE: Avoid using this except in extreme circumstances, where device tree
+ * is not feasible (e.g. serial driver in SPL where <8KB of SRAM is
+ * available). U-Boot's driver model uses device tree for configuration.
+ *
  * @name:      Driver name
  * @platdata:  Driver-specific platform data
  */
@@ -24,6 +28,11 @@ struct driver_info {
        const void *platdata;
 };
 
+/**
+ * NOTE: Avoid using these except in extreme circumstances, where device tree
+ * is not feasible (e.g. serial driver in SPL where <8KB of SRAM is
+ * available). U-Boot's driver model uses device tree for configuration.
+ */
 #define U_BOOT_DEVICE(__name)                                          \
        ll_entry_declare(struct driver_info, __name, driver_info)
 
index c7310d7ca04f23300385fe7e025ebe719ee6bb16..bc057d7adf05aa769f811bada96771a3b6a4f7e1 100644 (file)
@@ -25,27 +25,33 @@ enum uclass_id {
        UCLASS_SIMPLE_BUS,      /* bus with child devices */
 
        /* U-Boot uclasses start here - in alphabetical order */
+       UCLASS_CLK,             /* Clock source, e.g. used by peripherals */
        UCLASS_CPU,             /* CPU, typically part of an SoC */
        UCLASS_CROS_EC,         /* Chrome OS EC */
        UCLASS_DISPLAY_PORT,    /* Display port video */
+       UCLASS_RAM,             /* RAM controller */
        UCLASS_ETH,             /* Ethernet device */
        UCLASS_GPIO,            /* Bank of general-purpose I/O pins */
        UCLASS_I2C,             /* I2C bus */
        UCLASS_I2C_EEPROM,      /* I2C EEPROM device */
        UCLASS_I2C_GENERIC,     /* Generic I2C device */
+       UCLASS_LED,             /* Light-emitting diode (LED) */
        UCLASS_LPC,             /* x86 'low pin count' interface */
        UCLASS_MASS_STORAGE,    /* Mass storage device */
+       UCLASS_MMC,             /* SD / MMC card or chip */
        UCLASS_MOD_EXP,         /* RSA Mod Exp device */
        UCLASS_PCH,             /* x86 platform controller hub */
        UCLASS_PCI,             /* PCI bus */
        UCLASS_PCI_GENERIC,     /* Generic PCI bus device */
        UCLASS_PMIC,            /* PMIC I/O device */
        UCLASS_REGULATOR,       /* Regulator device */
+       UCLASS_RESET,           /* Reset device */
        UCLASS_RTC,             /* Real time clock device */
        UCLASS_SERIAL,          /* Serial UART */
        UCLASS_SPI,             /* SPI bus */
        UCLASS_SPI_FLASH,       /* SPI flash */
        UCLASS_SPI_GENERIC,     /* Generic SPI flash target */
+       UCLASS_SYSCON,          /* System configuration device */
        UCLASS_THERMAL,         /* Thermal sensor */
        UCLASS_USB,             /* USB bus */
        UCLASS_USB_DEV_GENERIC, /* USB generic device */
index 0cec17b52a413e8631bd0cc54c08d226e049515b..7dbed6793f887dd38b50a8ef92f23b677e00ae3c 100644 (file)
@@ -33,4 +33,10 @@ struct list_head;
  */
 int list_count_items(struct list_head *head);
 
+/* Dump out a tree of all devices */
+void dm_dump_all(void);
+
+/* Dump out a list of uclasses and their devices */
+void dm_dump_uclass(void);
+
 #endif
index 86a54918f90fb6af8632f3af7da36595e0111fb0..7a7555a73ab2c7a5291b5b2f5ee5e263998d4eae 100644 (file)
 /* quirks */
 #define DWMCI_QUIRK_DISABLE_SMU                (1 << 0)
 
+/**
+ * struct dwmci_host - Information about a designware MMC host
+ *
+ * @name:      Device name
+ * @ioaddr:    Base I/O address of controller
+ * @quirks:    Quick flags - see DWMCI_QUIRK_...
+ * @caps:      Capabilities - see MMC_MODE_...
+ * @bus_hz:    Bus speed in Hz, if @get_mmc_clk() is NULL
+ * @div:       Arbitrary clock divider value for use by controller
+ * @dev_index: Arbitrary device index for use by controller
+ * @dev_id:    Arbitrary device ID for use by controller
+ * @buswidth:  Bus width in bits (8 or 4)
+ * @fifoth_val:        Value for FIFOTH register (or 0 to leave unset)
+ * @mmc:       Pointer to generic MMC structure for this device
+ * @priv:      Private pointer for use by controller
+ */
 struct dwmci_host {
-       char *name;
+       const char *name;
        void *ioaddr;
        unsigned int quirks;
        unsigned int caps;
index b6eb57e18783dd4302ed65e2285eeb3e4f55889c..63c3d37f20fa4dac33c43975693801a505b94a3e 100644 (file)
@@ -246,6 +246,8 @@ struct lmb;
 #define IH_TYPE_LPC32XXIMAGE   21      /* x86 setup.bin Image          */
 #define IH_TYPE_LOADABLE       22      /* A list of typeless images    */
 
+#define IH_TYPE_COUNT          23      /* Number of image types */
+
 /*
  * Compression Types
  */
@@ -411,6 +413,15 @@ char *get_table_entry_name(const table_entry_t *table, char *msg, int id);
 const char *genimg_get_os_name(uint8_t os);
 const char *genimg_get_arch_name(uint8_t arch);
 const char *genimg_get_type_name(uint8_t type);
+
+/**
+ * genimg_get_type_short_name() - get the short name for an image type
+ *
+ * @param type Image type (IH_TYPE_...)
+ * @return image short name, or "unknown" if unknown
+ */
+const char *genimg_get_type_short_name(uint8_t type);
+
 const char *genimg_get_comp_name(uint8_t comp);
 int genimg_get_os_id(const char *name);
 int genimg_get_arch_id(const char *name);
diff --git a/include/led.h b/include/led.h
new file mode 100644 (file)
index 0000000..b929d0c
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __LED_H
+#define __LED_H
+
+/**
+ * struct led_uclass_plat - Platform data the uclass stores about each device
+ *
+ * @label:     LED label
+ */
+struct led_uclass_plat {
+       const char *label;
+};
+
+struct led_ops {
+       /**
+        * set_on() - set the state of an LED
+        *
+        * @dev:        LED device to change
+        * @on:         1 to turn the LED on, 0 to turn it off
+        * @return 0 if OK, -ve on error
+        */
+       int (*set_on)(struct udevice *dev, int on);
+};
+
+#define led_get_ops(dev)       ((struct led_ops *)(dev)->driver->ops)
+
+/**
+ * led_get_by_label() - Find an LED device by label
+ *
+ * @label:     LED label to look up
+ * @devp:      Returns the associated device, if found
+ * @return 0 if found, -ENODEV if not found, other -ve on error
+ */
+int led_get_by_label(const char *label, struct udevice **devp);
+
+/**
+ * led_set_on() - set the state of an LED
+ *
+ * @dev:       LED device to change
+ * @on:                1 to turn the LED on, 0 to turn it off
+ * @return 0 if OK, -ve on error
+ */
+int led_set_on(struct udevice *dev, int on);
+
+#endif
index 421d64fd8b6328f0241bf32762febd2b958b049e..e48c21aced0288a4fca14b3dd6ac3e797691d676 100644 (file)
        /* FDT_ERR_BADNCELLS: Device tree has a #address-cells, #size-cells
         * or similar property with a bad format or value */
 
-#define FDT_ERR_MAX            14
+#define FDT_ERR_TOODEEP                15
+       /* FDT_ERR_TOODEEP: The depth of a node has exceeded the internal
+        * libfdt limit. This can happen if you have more than
+        * FDT_MAX_DEPTH nested nodes. */
+
+#define FDT_ERR_MAX            15
 
 /**********************************************************************/
 /* Low-level functions (you probably don't need these)                */
@@ -1646,11 +1651,99 @@ int fdt_del_node(void *fdt, int nodeoffset);
 
 const char *fdt_strerror(int errval);
 
+/**
+ * fdt_remove_unused_strings() - Remove any unused strings from an FDT
+ *
+ * This creates a new device tree in @new with unused strings removed. The
+ * called can then use fdt_pack() to minimise the space consumed.
+ *
+ * @old:       Old device tree blog
+ * @new:       Place to put new device tree blob, which must be as large as
+ *             @old
+ * @return
+ *     0, on success
+ *     -FDT_ERR_BADOFFSET, corrupt device tree
+ *     -FDT_ERR_NOSPACE, out of space, which should not happen unless there
+ *             is something very wrong with the device tree input
+ */
+int fdt_remove_unused_strings(const void *old, void *new);
+
 struct fdt_region {
        int offset;
        int size;
 };
 
+/*
+ * Flags for fdt_find_regions()
+ *
+ * Add a region for the string table (always the last region)
+ */
+#define FDT_REG_ADD_STRING_TAB         (1 << 0)
+
+/*
+ * Add all supernodes of a matching node/property, useful for creating a
+ * valid subset tree
+ */
+#define FDT_REG_SUPERNODES             (1 << 1)
+
+/* Add the FDT_BEGIN_NODE tags of subnodes, including their names */
+#define FDT_REG_DIRECT_SUBNODES        (1 << 2)
+
+/* Add all subnodes of a matching node */
+#define FDT_REG_ALL_SUBNODES           (1 << 3)
+
+/* Add a region for the mem_rsvmap table (always the first region) */
+#define FDT_REG_ADD_MEM_RSVMAP         (1 << 4)
+
+/* Indicates what an fdt part is (node, property, value) */
+#define FDT_IS_NODE                    (1 << 0)
+#define FDT_IS_PROP                    (1 << 1)
+#define FDT_IS_VALUE                   (1 << 2)        /* not supported */
+#define FDT_IS_COMPAT                  (1 << 3)        /* used internally */
+#define FDT_NODE_HAS_PROP              (1 << 4)        /* node contains prop */
+
+#define FDT_ANY_GLOBAL         (FDT_IS_NODE | FDT_IS_PROP | FDT_IS_VALUE | \
+                                       FDT_IS_COMPAT)
+#define FDT_IS_ANY                     0x1f            /* all the above */
+
+/* We set a reasonable limit on the number of nested nodes */
+#define FDT_MAX_DEPTH                  32
+
+/* Decribes what we want to include from the current tag */
+enum want_t {
+       WANT_NOTHING,
+       WANT_NODES_ONLY,                /* No properties */
+       WANT_NODES_AND_PROPS,           /* Everything for one level */
+       WANT_ALL_NODES_AND_PROPS        /* Everything for all levels */
+};
+
+/* Keeps track of the state at parent nodes */
+struct fdt_subnode_stack {
+       int offset;             /* Offset of node */
+       enum want_t want;       /* The 'want' value here */
+       int included;           /* 1 if we included this node, 0 if not */
+};
+
+struct fdt_region_ptrs {
+       int depth;                      /* Current tree depth */
+       int done;                       /* What we have completed scanning */
+       enum want_t want;               /* What we are currently including */
+       char *end;                      /* Pointer to end of full node path */
+       int nextoffset;                 /* Next node offset to check */
+};
+
+/* The state of our finding algortihm */
+struct fdt_region_state {
+       struct fdt_subnode_stack stack[FDT_MAX_DEPTH];  /* node stack */
+       struct fdt_region *region;      /* Contains list of regions found */
+       int count;                      /* Numnber of regions found */
+       const void *fdt;                /* FDT blob */
+       int max_regions;                /* Maximum regions to find */
+       int can_merge;          /* 1 if we can merge with previous region */
+       int start;                      /* Start position of current region */
+       struct fdt_region_ptrs ptrs;    /* Pointers for what we are up to */
+};
+
 /**
  * fdt_find_regions() - find regions in device tree
  *
@@ -1710,4 +1803,165 @@ int fdt_find_regions(const void *fdt, char * const inc[], int inc_count,
                     struct fdt_region region[], int max_regions,
                     char *path, int path_len, int add_string_tab);
 
+/**
+ * fdt_first_region() - find regions in device tree
+ *
+ * Given a nodes and properties to include and properties to exclude, find
+ * the regions of the device tree which describe those included parts.
+ *
+ * The use for this function is twofold. Firstly it provides a convenient
+ * way of performing a structure-aware grep of the tree. For example it is
+ * possible to grep for a node and get all the properties associated with
+ * that node. Trees can be subsetted easily, by specifying the nodes that
+ * are required, and then writing out the regions returned by this function.
+ * This is useful for small resource-constrained systems, such as boot
+ * loaders, which want to use an FDT but do not need to know about all of
+ * it.
+ *
+ * Secondly it makes it easy to hash parts of the tree and detect changes.
+ * The intent is to get a list of regions which will be invariant provided
+ * those parts are invariant. For example, if you request a list of regions
+ * for all nodes but exclude the property "data", then you will get the
+ * same region contents regardless of any change to "data" properties.
+ *
+ * This function can be used to produce a byte-stream to send to a hashing
+ * function to verify that critical parts of the FDT have not changed.
+ * Note that semantically null changes in order could still cause false
+ * hash misses. Such reordering might happen if the tree is regenerated
+ * from source, and nodes are reordered (the bytes-stream will be emitted
+ * in a different order and mnay hash functions will detect this). However
+ * if an existing tree is modified using libfdt functions, such as
+ * fdt_add_subnode() and fdt_setprop(), then this problem is avoided.
+ *
+ * The nodes/properties to include/exclude are defined by a function
+ * provided by the caller. This function is called for each node and
+ * property, and must return:
+ *
+ *    0 - to exclude this part
+ *    1 - to include this part
+ *   -1 - for FDT_IS_PROP only: no information is available, so include
+ *             if its containing node is included
+ *
+ * The last case is only used to deal with properties. Often a property is
+ * included if its containing node is included - this is the case where
+ * -1 is returned.. However if the property is specifically required to be
+ * included/excluded, then 0 or 1 can be returned. Note that including a
+ * property when the FDT_REG_SUPERNODES flag is given will force its
+ * containing node to be included since it is not valid to have a property
+ * that is not in a node.
+ *
+ * Using the information provided, the inclusion of a node can be controlled
+ * either by a node name or its compatible string, or any other property
+ * that the function can determine.
+ *
+ * As an example, including node "/" means to include the root node and all
+ * root properties. A flag provides a way of also including supernodes (of
+ * which there is none for the root node), and another flag includes
+ * immediate subnodes, so in this case we would get the FDT_BEGIN_NODE and
+ * FDT_END_NODE of all subnodes of /.
+ *
+ * The subnode feature helps in a hashing situation since it prevents the
+ * root node from changing at all. Any change to non-excluded properties,
+ * names of subnodes or number of subnodes would be detected.
+ *
+ * When used with FITs this provides the ability to hash and sign parts of
+ * the FIT based on different configurations in the FIT. Then it is
+ * impossible to change anything about that configuration (include images
+ * attached to the configuration), but it may be possible to add new
+ * configurations, new images or new signatures within the existing
+ * framework.
+ *
+ * Adding new properties to a device tree may result in the string table
+ * being extended (if the new property names are different from those
+ * already added). This function can optionally include a region for
+ * the string table so that this can be part of the hash too. This is always
+ * the last region.
+ *
+ * The FDT also has a mem_rsvmap table which can also be included, and is
+ * always the first region if so.
+ *
+ * The device tree header is not included in the region list. Since the
+ * contents of the FDT are changing (shrinking, often), the caller will need
+ * to regenerate the header anyway.
+ *
+ * @fdt:       Device tree to check
+ * @h_include: Function to call to determine whether to include a part or
+ *             not:
+ *
+ *             @priv: Private pointer as passed to fdt_find_regions()
+ *             @fdt: Pointer to FDT blob
+ *             @offset: Offset of this node / property
+ *             @type: Type of this part, FDT_IS_...
+ *             @data: Pointer to data (node name, property name, compatible
+ *                     string, value (not yet supported)
+ *             @size: Size of data, or 0 if none
+ *             @return 0 to exclude, 1 to include, -1 if no information is
+ *             available
+ * @priv:      Private pointer passed to h_include
+ * @region:    Returns list of regions, sorted by offset
+ * @max_regions: Maximum length of region list
+ * @path:      Pointer to a temporary string for the function to use for
+ *             building path names
+ * @path_len:  Length of path, must be large enough to hold the longest
+ *             path in the tree
+ * @flags:     Various flags that control the region algortihm, see
+ *             FDT_REG_...
+ * @return number of regions in list. If this is >max_regions then the
+ * region array was exhausted. You should increase max_regions and try
+ * the call again. Only the first max_regions elements are available in the
+ * array.
+ *
+ * On error a -ve value is return, which can be:
+ *
+ *     -FDT_ERR_BADSTRUCTURE (too deep or more END tags than BEGIN tags
+ *     -FDT_ERR_BADLAYOUT
+ *     -FDT_ERR_NOSPACE (path area is too small)
+ */
+int fdt_first_region(const void *fdt,
+               int (*h_include)(void *priv, const void *fdt, int offset,
+                                int type, const char *data, int size),
+               void *priv, struct fdt_region *region,
+               char *path, int path_len, int flags,
+               struct fdt_region_state *info);
+
+/** fdt_next_region() - find next region
+ *
+ * See fdt_first_region() for full description. This function finds the
+ * next region according to the provided parameters, which must be the same
+ * as passed to fdt_first_region().
+ *
+ * This function can additionally return -FDT_ERR_NOTFOUND when there are no
+ * more regions
+ */
+int fdt_next_region(const void *fdt,
+               int (*h_include)(void *priv, const void *fdt, int offset,
+                                int type, const char *data, int size),
+               void *priv, struct fdt_region *region,
+               char *path, int path_len, int flags,
+               struct fdt_region_state *info);
+
+/**
+ * fdt_add_alias_regions() - find aliases that point to existing regions
+ *
+ * Once a device tree grep is complete some of the nodes will be present
+ * and some will have been dropped. This function checks all the alias nodes
+ * to figure out which points point to nodes which are still present. These
+ * aliases need to be kept, along with the nodes they reference.
+ *
+ * Given a list of regions function finds the aliases that still apply and
+ * adds more regions to the list for these. This function is called after
+ * fdt_next_region() has finished returning regions and requires the same
+ * state.
+ *
+ * @fdt:       Device tree file to reference
+ * @region:    List of regions that will be kept
+ * @count:     Number of regions
+ * @max_regions: Number of entries that can fit in @region
+ * @info:      Region state as returned from fdt_next_region()
+ * @return new number of regions in @region (i.e. count + the number added)
+ * or -FDT_ERR_NOSPACE if there was not enough space.
+ */
+int fdt_add_alias_regions(const void *fdt, struct fdt_region *region, int count,
+                         int max_regions, struct fdt_region_state *info);
+
 #endif /* _LIBFDT_H */
index 6ff3915216814e81d0f46fd1ba04e969290ed9a7..fbebf910addd994d265d21c4fbaa0a2f48f4ccb1 100644 (file)
@@ -36,10 +36,25 @@ extern struct p_current *current;
 #define KERN_INFO
 #define KERN_DEBUG
 
+#define GFP_ATOMIC ((gfp_t) 0)
+#define GFP_KERNEL ((gfp_t) 0)
+#define GFP_NOFS ((gfp_t) 0)
+#define GFP_USER ((gfp_t) 0)
+#define __GFP_NOWARN ((gfp_t) 0)
+#define __GFP_ZERO     ((__force gfp_t)0x8000u)        /* Return zeroed page on success */
+
 void *kmalloc(size_t size, int flags);
-void *kzalloc(size_t size, int flags);
+
+static inline void *kzalloc(size_t size, gfp_t flags)
+{
+       return kmalloc(size, flags | __GFP_ZERO);
+}
 #define vmalloc(size)  kmalloc(size, 0)
 #define __vmalloc(size, flags, pgsz)   kmalloc(size, flags)
+static inline void *vzalloc(unsigned long size)
+{
+       return kzalloc(size, 0);
+}
 #define kfree(ptr)     free(ptr)
 #define vfree(ptr)     free(ptr)
 
@@ -73,13 +88,6 @@ void *kmem_cache_alloc(struct kmem_cache *obj, int flag);
 /* drivers/char/random.c */
 #define get_random_bytes(...)
 
-/* idr.c */
-#define GFP_ATOMIC ((gfp_t) 0)
-#define GFP_KERNEL ((gfp_t) 0)
-#define GFP_NOFS ((gfp_t) 0)
-#define GFP_USER ((gfp_t) 0)
-#define __GFP_NOWARN ((gfp_t) 0)
-
 /* include/linux/leds.h */
 struct led_trigger {};
 
@@ -189,8 +197,6 @@ struct work_struct {};
 unsigned long copy_from_user(void *dest, const void *src,
                             unsigned long count);
 
-void *vzalloc(unsigned long size);
-
 typedef unused_t spinlock_t;
 typedef int    wait_queue_head_t;
 
@@ -315,8 +321,6 @@ struct notifier_block {};
 
 typedef unsigned long dmaaddr_t;
 
-#define cpu_relax() do {} while (0)
-
 #define pm_runtime_get_sync(dev) do {} while (0)
 #define pm_runtime_put(dev) do {} while (0)
 #define pm_runtime_put_sync(dev) do {} while (0)
index dd98b3b8acfe1cd98c8f3a68a4534d8f262af949..cda9a19ce0aab545faf5bc70ced71e34f0a48ad3 100644 (file)
 #define MMC_NUM_BOOT_PARTITION 2
 #define MMC_PART_RPMB           3       /* RPMB partition number */
 
+/* Driver model support */
+
+/**
+ * struct mmc_uclass_priv - Holds information about a device used by the uclass
+ */
+struct mmc_uclass_priv {
+       struct mmc *mmc;
+};
+
+/**
+ * mmc_get_mmc_dev() - get the MMC struct pointer for a device
+ *
+ * Provided that the device is already probed and ready for use, this value
+ * will be available.
+ *
+ * @dev:       Device
+ * @return associated mmc struct pointer if available, else NULL
+ */
+struct mmc *mmc_get_mmc_dev(struct udevice *dev);
+
+/* End of driver model support */
+
 struct mmc_cid {
        unsigned long psn;
        unsigned short oid;
index d17173d818a4fb9160aa8fed65a6f56ab263c457..d09bec9de1560e8c2443269fb2045f95ea84e7f7 100644 (file)
@@ -93,6 +93,14 @@ struct eth_pdata {
        int phy_interface;
 };
 
+enum eth_recv_flags {
+       /*
+        * Check hardware device for new packets (otherwise only return those
+        * which are already in the memory buffer ready to process)
+        */
+       ETH_RECV_CHECK_DEVICE           = 1 << 0,
+};
+
 /**
  * struct eth_ops - functions of Ethernet MAC controllers
  *
@@ -111,7 +119,9 @@ struct eth_pdata {
  * mcast: Join or leave a multicast group (for TFTP) - optional
  * write_hwaddr: Write a MAC address to the hardware (used to pass it to Linux
  *              on some platforms like ARM). This function expects the
- *              eth_pdata::enetaddr field to be populated - optional
+ *              eth_pdata::enetaddr field to be populated. The method can
+ *              return -ENOSYS to indicate that this is not implemented for
+                this hardware - optional.
  * read_rom_hwaddr: Some devices have a backup of the MAC address stored in a
  *                 ROM on the board. This is how the driver should expose it
  *                 to the network stack. This function should fill in the
@@ -120,7 +130,7 @@ struct eth_pdata {
 struct eth_ops {
        int (*start)(struct udevice *dev);
        int (*send)(struct udevice *dev, void *packet, int length);
-       int (*recv)(struct udevice *dev, uchar **packetp);
+       int (*recv)(struct udevice *dev, int flags, uchar **packetp);
        int (*free_pkt)(struct udevice *dev, uchar *packet, int length);
        void (*stop)(struct udevice *dev);
 #ifdef CONFIG_MCAST_TFTP
index 542e68bceb97b8d54609aef657a77da708a8cb65..94bca9751248d13fae0df6a9060751c0483ae9e2 100644 (file)
@@ -468,7 +468,10 @@ typedef int pci_dev_t;
 #define PCI_ANY_ID             (~0)
 
 struct pci_device_id {
-       unsigned int vendor, device;            /* Vendor and device ID or PCI_ANY_ID */
+       unsigned int vendor, device;    /* Vendor and device ID or PCI_ANY_ID */
+       unsigned int subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */
+       unsigned int class, class_mask; /* (class,subclass,prog-if) triplet */
+       unsigned long driver_data;      /* Data private to the driver */
 };
 
 struct pci_controller;
@@ -804,6 +807,14 @@ struct dm_pci_ops {
 /* Get access to a PCI bus' operations */
 #define pci_get_ops(dev)       ((struct dm_pci_ops *)(dev)->driver->ops)
 
+/**
+ * pci_get_bdf() - Get the BDF value for a device
+ *
+ * @dev:       Device to check
+ * @return bus/device/function value (see PCI_BDF())
+ */
+pci_dev_t pci_get_bdf(struct udevice *dev);
+
 /**
  * pci_bind_bus_devices() - scan a PCI bus and bind devices
  *
@@ -1101,7 +1112,79 @@ struct dm_pci_emul_ops {
 int sandbox_pci_get_emul(struct udevice *bus, pci_dev_t find_devfn,
                         struct udevice **emulp);
 
-#endif
+#endif /* CONFIG_DM_PCI */
+
+/**
+ * PCI_DEVICE - macro used to describe a specific pci device
+ * @vend: the 16 bit PCI Vendor ID
+ * @dev: the 16 bit PCI Device ID
+ *
+ * This macro is used to create a struct pci_device_id that matches a
+ * specific device.  The subvendor and subdevice fields will be set to
+ * PCI_ANY_ID.
+ */
+#define PCI_DEVICE(vend, dev) \
+       .vendor = (vend), .device = (dev), \
+       .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
+
+/**
+ * PCI_DEVICE_SUB - macro used to describe a specific pci device with subsystem
+ * @vend: the 16 bit PCI Vendor ID
+ * @dev: the 16 bit PCI Device ID
+ * @subvend: the 16 bit PCI Subvendor ID
+ * @subdev: the 16 bit PCI Subdevice ID
+ *
+ * This macro is used to create a struct pci_device_id that matches a
+ * specific device with subsystem information.
+ */
+#define PCI_DEVICE_SUB(vend, dev, subvend, subdev) \
+       .vendor = (vend), .device = (dev), \
+       .subvendor = (subvend), .subdevice = (subdev)
+
+/**
+ * PCI_DEVICE_CLASS - macro used to describe a specific pci device class
+ * @dev_class: the class, subclass, prog-if triple for this device
+ * @dev_class_mask: the class mask for this device
+ *
+ * This macro is used to create a struct pci_device_id that matches a
+ * specific PCI class.  The vendor, device, subvendor, and subdevice
+ * fields will be set to PCI_ANY_ID.
+ */
+#define PCI_DEVICE_CLASS(dev_class, dev_class_mask) \
+       .class = (dev_class), .class_mask = (dev_class_mask), \
+       .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, \
+       .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
+
+/**
+ * PCI_VDEVICE - macro used to describe a specific pci device in short form
+ * @vend: the vendor name
+ * @dev: the 16 bit PCI Device ID
+ *
+ * This macro is used to create a struct pci_device_id that matches a
+ * specific PCI device.  The subvendor, and subdevice fields will be set
+ * to PCI_ANY_ID. The macro allows the next field to follow as the device
+ * private data.
+ */
+
+#define PCI_VDEVICE(vend, dev) \
+       .vendor = PCI_VENDOR_ID_##vend, .device = (dev), \
+       .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, 0, 0
+
+/**
+ * struct pci_driver_entry - Matches a driver to its pci_device_id list
+ * @driver: Driver to use
+ * @match: List of match records for this driver, terminated by {}
+ */
+struct pci_driver_entry {
+       struct driver *driver;
+       const struct pci_device_id *match;
+};
+
+#define U_BOOT_PCI_DEVICE(__name, __match)                             \
+       ll_entry_declare(struct pci_driver_entry, __name, pci_driver_entry) = {\
+               .driver = llsym(struct driver, __name, driver), \
+               .match = __match, \
+               }
 
 #endif /* __ASSEMBLY__ */
 #endif /* _PCI_H */
index eb152ef4926dc9311faf69c80c38c6a1394a1dc5..6ba4b6ecd6073f943b866b69ce7f16bcab562ae1 100644 (file)
@@ -264,6 +264,40 @@ int pmic_reg_count(struct udevice *dev);
  */
 int pmic_read(struct udevice *dev, uint reg, uint8_t *buffer, int len);
 int pmic_write(struct udevice *dev, uint reg, const uint8_t *buffer, int len);
+
+/**
+ * pmic_reg_read() - read a PMIC register value
+ *
+ * @dev:       PMIC device to read
+ * @reg:       Register to read
+ * @return value read on success or negative value of errno.
+ */
+int pmic_reg_read(struct udevice *dev, uint reg);
+
+/**
+ * pmic_reg_write() - write a PMIC register value
+ *
+ * @dev:       PMIC device to write
+ * @reg:       Register to write
+ * @value:     Value to write
+ * @return 0 on success or negative value of errno.
+ */
+int pmic_reg_write(struct udevice *dev, uint reg, uint value);
+
+/**
+ * pmic_clrsetbits() - clear and set bits in a PMIC register
+ *
+ * This reads a register, optionally clears some bits, optionally sets some
+ * bits, then writes the register.
+ *
+ * @dev:       PMIC device to update
+ * @reg:       Register to update
+ * @clr:       Bit mask to clear (set those bits that you want cleared)
+ * @set:       Bit mask to set (set those bits that you want set)
+ * @return 0 on success or negative value of errno.
+ */
+int pmic_clrsetbits(struct udevice *dev, uint reg, uint clr, uint set);
+
 #endif /* CONFIG_DM_PMIC */
 
 #ifdef CONFIG_POWER
index 03a2cefcd61bc4a56d7070d9756c41623b6244a3..015229027c874eeb860b91000eda11accf604e51 100644 (file)
@@ -128,6 +128,11 @@ struct dm_regulator_mode {
        const char *name;
 };
 
+enum regulator_flag {
+       REGULATOR_FLAG_AUTOSET_UV       = 1 << 0,
+       REGULATOR_FLAG_AUTOSET_UA       = 1 << 1,
+};
+
 /**
  * struct dm_regulator_uclass_platdata - pointed by dev->uclass_platdata, and
  * allocated on each regulator bind. This structure holds an information
@@ -143,6 +148,8 @@ struct dm_regulator_mode {
  * @max_uA*    - maximum amperage (micro Amps)
  * @always_on* - bool type, true or false
  * @boot_on*   - bool type, true or false
+ * TODO(sjg@chromium.org): Consider putting the above two into @flags
+ * @flags:     - flags value (see REGULATOR_FLAG_...)
  * @name**     - fdt regulator name - should be taken from the device tree
  *
  * Note:
@@ -162,6 +169,7 @@ struct dm_regulator_uclass_platdata {
        bool always_on;
        bool boot_on;
        const char *name;
+       int flags;
 };
 
 /* Regulator device operations */
@@ -308,9 +316,39 @@ int regulator_get_mode(struct udevice *dev);
 int regulator_set_mode(struct udevice *dev, int mode_id);
 
 /**
- * regulator_autoset: setup the regulator given by its uclass's platform data
- * name field. The setup depends on constraints found in device's uclass's
- * platform data (struct dm_regulator_uclass_platdata):
+ * regulators_enable_boot_on() - enable regulators needed for boot
+ *
+ * This enables all regulators which are marked to be on at boot time. This
+ * only works for regulators which don't have a range for voltage/current,
+ * since in that case it is not possible to know which value to use.
+ *
+ * This effectively calls regulator_autoset() for every regulator.
+ */
+int regulators_enable_boot_on(bool verbose);
+
+/**
+ * regulator_autoset: setup the voltage/current on a regulator
+ *
+ * The setup depends on constraints found in device's uclass's platform data
+ * (struct dm_regulator_uclass_platdata):
+ *
+ * - Enable - will set - if any of: 'always_on' or 'boot_on' is set to true,
+ *   or if both are unset, then the function returns
+ * - Voltage value - will set - if '.min_uV' and '.max_uV' values are equal
+ * - Current limit - will set - if '.min_uA' and '.max_uA' values are equal
+ *
+ * The function returns on the first-encountered error.
+ *
+ * @platname - expected string for dm_regulator_uclass_platdata .name field
+ * @devp     - returned pointer to the regulator device - if non-NULL passed
+ * @return: 0 on success or negative value of errno.
+ */
+int regulator_autoset(struct udevice *dev);
+
+/**
+ * regulator_autoset_by_name: setup the regulator given by its uclass's
+ * platform data name field. The setup depends on constraints found in device's
+ * uclass's platform data (struct dm_regulator_uclass_platdata):
  * - Enable - will set - if any of: 'always_on' or 'boot_on' is set to true,
  *   or if both are unset, then the function returns
  * - Voltage value - will set - if '.min_uV' and '.max_uV' values are equal
@@ -320,21 +358,18 @@ int regulator_set_mode(struct udevice *dev, int mode_id);
  *
  * @platname - expected string for dm_regulator_uclass_platdata .name field
  * @devp     - returned pointer to the regulator device - if non-NULL passed
- * @verbose  - (true/false) print regulator setup info, or be quiet
  * @return: 0 on success or negative value of errno.
  *
  * The returned 'regulator' device can be used with:
  * - regulator_get/set_*
  */
-int regulator_autoset(const char *platname,
-                     struct udevice **devp,
-                     bool verbose);
+int regulator_autoset_by_name(const char *platname, struct udevice **devp);
 
 /**
  * regulator_list_autoset: setup the regulators given by list of their uclass's
  * platform data name field. The setup depends on constraints found in device's
  * uclass's platform data. The function loops with calls to:
- * regulator_autoset() for each name from the list.
+ * regulator_autoset_by_name() for each name from the list.
  *
  * @list_platname - an array of expected strings for .name field of each
  *                  regulator's uclass platdata
@@ -375,7 +410,7 @@ int regulator_get_by_devname(const char *devname, struct udevice **devp);
  * Search by name, found in regulator uclass platdata.
  *
  * @platname - expected string for uc_pdata->name of regulator uclass platdata
- * @devp     - returned pointer to the regulator device
+ * @devp     - returns pointer to the regulator device or NULL on error
  * @return 0 on success or negative value of errno.
  *
  * The returned 'regulator' device is probed and can be used with:
index ae142921e53b86a6f5866f3d98a18a0e934a5702..854767497145f4a1a1670a807e4e4b5ac5c99030 100644 (file)
@@ -117,11 +117,11 @@ enum {
 
 /*
  * Expected regulators setup after call of:
- * - regulator_autoset()
+ * - regulator_autoset_by_name()
  * - regulator_list_autoset()
  */
 
-/* BUCK1: for testing regulator_autoset() */
+/* BUCK1: for testing regulator_autoset_by_name() */
 #define SANDBOX_BUCK1_AUTOSET_EXPECTED_UV      1200000
 #define SANDBOX_BUCK1_AUTOSET_EXPECTED_UA      200000
 #define SANDBOX_BUCK1_AUTOSET_EXPECTED_ENABLE  true
diff --git a/include/ram.h b/include/ram.h
new file mode 100644 (file)
index 0000000..e2172a8
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __RAM_H
+#define __RAM_H
+
+struct ram_info {
+       phys_addr_t base;
+       size_t size;
+};
+
+struct ram_ops {
+       /**
+        * get_info() - Get basic memory info
+        *
+        * @dev:        Device to check (UCLASS_RAM)
+        * @info:       Place to put info
+        * @return 0 if OK, -ve on error
+        */
+       int (*get_info)(struct udevice *dev, struct ram_info *info);
+};
+
+#define ram_get_ops(dev)        ((struct ram_ops *)(dev)->driver->ops)
+
+/**
+ * ram_get_info() - Get information about a RAM device
+ *
+ * @dev:       Device to check (UCLASS_RAM)
+ * @info:      Returns RAM info
+ * @return 0 if OK, -ve on error
+ */
+int ram_get_info(struct udevice *dev, struct ram_info *info);
+
+#endif
diff --git a/include/rc4.h b/include/rc4.h
new file mode 100644 (file)
index 0000000..ea409c2
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * (C) Copyright 2015 Google, Inc
+ *
+ * (C) Copyright 2008-2014 Rockchip Electronics
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __RC4_H
+#define __RC4_H
+
+/**
+ * rc4_encode() - encode a buf with the RC4 cipher
+ *
+ * @buf:       Buffer to encode (it is overwrite in the process
+ * @len:       Length of buffer in bytes
+ * @key:       16-byte key to use
+ */
+void rc4_encode(unsigned char *buf, unsigned int len, unsigned char key[16]);
+
+#endif
diff --git a/include/regmap.h b/include/regmap.h
new file mode 100644 (file)
index 0000000..eccf770
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __REGMAP_H
+#define __REGMAP_H
+
+/**
+ * struct regmap_range - a register map range
+ *
+ * @start:     Start address
+ * @size:      Size in bytes
+ */
+struct regmap_range {
+       ulong start;
+       ulong size;
+};
+
+/**
+ * struct regmap - a way of accessing hardware/bus registers
+ *
+ * @base:      Base address of register map
+ * @range_count: Number of ranges available within the map
+ * @range:     Pointer to the list of ranges, allocated if @range_count > 1
+ * @base_range:        If @range_count is <= 1, @range points here
+ */
+struct regmap {
+       phys_addr_t base;
+       int range_count;
+       struct regmap_range *range, base_range;
+};
+
+/*
+ * Interface to provide access to registers either through a direct memory
+ * bus or through a peripheral bus like I2C, SPI.
+ */
+int regmap_write(struct regmap *map, uint offset, uint val);
+int regmap_read(struct regmap *map, uint offset, uint *valp);
+
+#define regmap_write32(map, ptr, member, val) \
+       regmap_write(map, (uint32_t *)(ptr)->member - (uint32_t *)(ptr), val)
+
+#define regmap_read32(map, ptr, member, valp) \
+       regmap_read(map, (uint32_t *)(ptr)->member - (uint32_t *)(ptr), valp)
+
+/**
+ * regmap_init_mem() - Set up a new register map that uses memory access
+ *
+ * Use regmap_uninit() to free it.
+ *
+ * @dev:       Device that uses this map
+ * @mapp:      Returns allocated map
+ */
+int regmap_init_mem(struct udevice *dev, struct regmap **mapp);
+
+/**
+ * regmap_get_range() - Obtain the base memory address of a regmap range
+ *
+ * @map:       Regmap to query
+ * @range_num: Range to look up
+ */
+void *regmap_get_range(struct regmap *map, unsigned int range_num);
+
+/**
+ * regmap_uninit() - free a previously inited regmap
+ */
+int regmap_uninit(struct regmap *map);
+
+#endif
diff --git a/include/reset.h b/include/reset.h
new file mode 100644 (file)
index 0000000..383761e
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __RESET_H
+#define __RESET_H
+
+enum reset_t {
+       RESET_WARM,     /* Reset CPU, keep GPIOs active */
+       RESET_COLD,     /* Reset CPU and GPIOs */
+       RESET_POWER,    /* Reset PMIC (remove and restore power) */
+
+       RESET_COUNT,
+};
+
+struct reset_ops {
+       /**
+        * request() - request a reset of the given type
+        *
+        * Note that this function may return before the reset takes effect.
+        *
+        * @type:       Reset type to request
+        * @return -EINPROGRESS if the reset has been started and
+        *              will complete soon, -EPROTONOSUPPORT if not supported
+        *              by this device, 0 if the reset has already happened
+        *              (in which case this method will not actually return)
+        */
+       int (*request)(struct udevice *dev, enum reset_t type);
+};
+
+#define reset_get_ops(dev)        ((struct reset_ops *)(dev)->driver->ops)
+
+/**
+ * reset_request() - request a reset
+ *
+ * @type:      Reset type to request
+ * @return 0 if OK, -EPROTONOSUPPORT if not supported by this device
+ */
+int reset_request(struct udevice *dev, enum reset_t type);
+
+/**
+ * reset_walk() - cause a reset
+ *
+ * This works through the available reset devices until it finds one that can
+ * perform a reset. If the provided reset type is not available, the next one
+ * will be tried.
+ *
+ * If this function fails to reset, it will display a message and halt
+ *
+ * @type:      Reset type to request
+ * @return -EINPROGRESS if a reset is in progress, -ENOSYS if not available
+ */
+int reset_walk(enum reset_t type);
+
+/**
+ * reset_walk_halt() - try to reset, otherwise halt
+ *
+ * This calls reset_walk(). If it returns, indicating that reset is not
+ * supported, it prints a message and halts.
+ */
+void reset_walk_halt(enum reset_t type);
+
+/**
+ * reset_cpu() - calls reset_walk(RESET_WARM)
+ */
+void reset_cpu(ulong addr);
+
+#endif
index d19940f2a33a4ec52079873dbacbfe62ecdd34be..8e5342614249da93bba4b61f5d343bd048993fcd 100644 (file)
@@ -81,6 +81,18 @@ void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image);
 int spl_load_image_ext(block_dev_desc_t *block_dev, int partition, const char *filename);
 int spl_load_image_ext_os(block_dev_desc_t *block_dev, int partition);
 
+/**
+ * spl_init() - Set up device tree and driver model in SPL if enabled
+ *
+ * Call this function in board_init_f() if you want to use device tree and
+ * driver model early, before board_init_r() is called. This function will
+ * be called from board_init_r() if not called earlier.
+ *
+ * If this is not called, then driver model will be inactive in SPL's
+ * board_init_f(), and no device tree will be available.
+ */
+int spl_init(void);
+
 #ifdef CONFIG_SPL_BOARD_INIT
 void spl_board_init(void);
 #endif
diff --git a/include/syscon.h b/include/syscon.h
new file mode 100644 (file)
index 0000000..c62ccd6
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __SYSCON_H
+#define __SYSCON_H
+
+/**
+ * struct syscon_uc_info - Information stored by the syscon UCLASS_UCLASS
+ *
+ * @regmap:    Register map for this controller
+ */
+struct syscon_uc_info {
+       struct regmap *regmap;
+};
+
+/* So far there are no ops so this is a placeholder */
+struct syscon_ops {
+};
+
+#define syscon_get_ops(dev)        ((struct syscon_ops *)(dev)->driver->ops)
+
+/**
+ * syscon_get_regmap() - Get access to a register map
+ *
+ * @dev:       Device to check (UCLASS_SCON)
+ * @info:      Returns regmap for the device
+ * @return 0 if OK, -ve on error
+ */
+struct regmap *syscon_get_regmap(struct udevice *dev);
+
+/**
+ * syscon_get_regmap_by_driver_data() - Look up a controller by its ID
+ *
+ * Each system controller can be accessed by its driver data, which is
+ * assumed to be unique through the scope of all system controllers that
+ * are in use. This function looks up the regmap given this driver data.
+ *
+ * @driver_data:       Driver data value to look up
+ * @return register map correponding to @driver_data, or -ve error code
+ */
+struct regmap *syscon_get_regmap_by_driver_data(ulong driver_data);
+
+/**
+ * syscon_get_first_range() - get the first memory range from a syscon regmap
+ *
+ * @driver_data:       Driver data value to look up
+ * @return first region of register map correponding to @driver_data, or
+ *                     -ve error code
+ */
+void *syscon_get_first_range(ulong driver_data);
+
+#endif
index 5e5aa6ce41c3ac7cdafbfc566be8e987805f4575..da7c1a9d265b4820582315ebbe04eddfb1172c6b 100644 (file)
@@ -9,6 +9,8 @@
 #ifndef __TEST_UT_H
 #define __TEST_UT_H
 
+#include <linux/err.h>
+
 struct unit_test_state;
 
 /**
@@ -101,6 +103,19 @@ void ut_failf(struct unit_test_state *uts, const char *fname, int line,
        }                                                               \
 }
 
+/* Assert that a pointer is not an error pointer */
+#define ut_assertok_ptr(expr) {                                        \
+       const void *val = (expr);                                       \
+                                                                       \
+       if (IS_ERR(val)) {                                              \
+               ut_failf(uts, __FILE__, __LINE__, __func__,             \
+                        #expr " = NULL",                               \
+                        "Expected pointer, got error %ld",             \
+                        PTR_ERR(val));                                 \
+               return CMD_RET_FAILURE;                                 \
+       }                                                               \
+}
+
 /* Assert that an operation succeeds (returns 0) */
 #define ut_assertok(cond)      ut_asserteq(0, cond)
 
index dca512d394b8445c13d616699d099ca3c23107e7..cf00ffdf53234a83d2981d582c04e23ca7b6e76b 100644 (file)
@@ -175,9 +175,9 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller);
 int usb_lowlevel_stop(int index);
 
 #if defined(CONFIG_MUSB_HOST) || defined(CONFIG_DM_USB)
-int usb_reset_root_port(void);
+int usb_reset_root_port(struct usb_device *dev);
 #else
-#define usb_reset_root_port()
+#define usb_reset_root_port(dev)
 #endif
 
 int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
@@ -493,15 +493,31 @@ struct usb_device_id {
 
 /**
  * struct usb_driver_entry - Matches a driver to its usb_device_ids
- * @compatible: Compatible string
- * @data: Data for this compatible string
+ * @driver: Driver to use
+ * @match: List of match records for this driver, terminated by {}
  */
 struct usb_driver_entry {
        struct driver *driver;
        const struct usb_device_id *match;
 };
 
-#define USB_DEVICE(__name, __match)                                    \
+#define USB_DEVICE_ID_MATCH_DEVICE \
+               (USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT)
+
+/**
+ * USB_DEVICE - macro used to describe a specific usb device
+ * @vend: the 16 bit USB Vendor ID
+ * @prod: the 16 bit USB Product ID
+ *
+ * This macro is used to create a struct usb_device_id that matches a
+ * specific device.
+ */
+#define USB_DEVICE(vend, prod) \
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE, \
+       .idVendor = (vend), \
+       .idProduct = (prod)
+
+#define U_BOOT_USB_DEVICE(__name, __match) \
        ll_entry_declare(struct usb_driver_entry, __name, usb_driver_entry) = {\
                .driver = llsym(struct driver, __name, driver), \
                .match = __match, \
@@ -705,15 +721,16 @@ struct dm_usb_ops {
         * is read). This should be NULL for EHCI, which does not need this.
         */
        int (*alloc_device)(struct udevice *bus, struct usb_device *udev);
+
+       /**
+        * reset_root_port() - Reset usb root port
+        */
+       int (*reset_root_port)(struct udevice *bus, struct usb_device *udev);
 };
 
 #define usb_get_ops(dev)       ((struct dm_usb_ops *)(dev)->driver->ops)
 #define usb_get_emul_ops(dev)  ((struct dm_usb_ops *)(dev)->driver->ops)
 
-#ifdef CONFIG_MUSB_HOST
-int usb_reset_root_port(void);
-#endif
-
 /**
  * usb_get_dev_index() - look up a device index number
  *
@@ -729,27 +746,19 @@ int usb_reset_root_port(void);
  */
 struct usb_device *usb_get_dev_index(struct udevice *bus, int index);
 
-/**
- * usb_legacy_port_reset() - Legacy function to reset a hub port
- *
- * @hub:       Hub device
- * @portnr:    Port number (1=first)
- */
-int usb_legacy_port_reset(struct usb_device *hub, int portnr);
-
 /**
  * usb_setup_device() - set up a device ready for use
  *
  * @dev:       USB device pointer. This need not be a real device - it is
  *             common for it to just be a local variable with its ->dev
- *             member (i.e. @dev->dev) set to the parent device
+ *             member (i.e. @dev->dev) set to the parent device and
+ *             dev->portnr set to the port number on the hub (1=first)
  * @do_read:   true to read the device descriptor before an address is set
  *             (should be false for XHCI buses, true otherwise)
  * @parent:    Parent device (either UCLASS_USB or UCLASS_USB_HUB)
- * @portnr:    Port number on hub (1=first) or 0 for none
  * @return 0 if OK, -ve on error */
 int usb_setup_device(struct usb_device *dev, bool do_read,
-                    struct usb_device *parent, int portnr);
+                    struct usb_device *parent);
 
 /**
  * usb_hub_scan() - Scan a hub and find its devices
index 23507e19e6024918e7617a4a4a98f87e69c774f9..c6d1416048a113c37d529d503bb255f47dffa197 100644 (file)
 #define ETH_DATA_LEN   1500            /* Max. octets in payload        */
 #define ETH_FRAME_LEN  PKTSIZE_ALIGN   /* Max. octets in frame sans FCS */
 
+/* TODO(sjg@chromium.org): Remove @pusb_dev when all boards use CONFIG_DM_ETH */
 struct ueth_data {
        /* eth info */
-       struct eth_device eth_dev;              /* used with eth_register */
-       int phy_id;                                             /* mii phy id */
+#ifdef CONFIG_DM_ETH
+       uint8_t *rxbuf;
+       int rxsize;
+       int rxlen;                      /* Total bytes available in rxbuf */
+       int rxptr;                      /* Current position in rxbuf */
+#else
+       struct eth_device eth_dev;      /* used with eth_register */
+       /* driver private */
+       void *dev_priv;
+#endif
+       int phy_id;                     /* mii phy id */
 
        /* usb info */
        struct usb_device *pusb_dev;    /* this usb_device */
-       unsigned char   ifnum;                  /* interface number */
-       unsigned char   ep_in;                  /* in endpoint */
-       unsigned char   ep_out;                 /* out ....... */
-       unsigned char   ep_int;                 /* interrupt . */
-       unsigned char   subclass;               /* as in overview */
-       unsigned char   protocol;               /* .............. */
+       unsigned char   ifnum;          /* interface number */
+       unsigned char   ep_in;          /* in endpoint */
+       unsigned char   ep_out;         /* out ....... */
+       unsigned char   ep_int;         /* interrupt . */
+       unsigned char   subclass;       /* as in overview */
+       unsigned char   protocol;       /* .............. */
        unsigned char   irqinterval;    /* Intervall for IRQ Pipe */
-
-       /* driver private */
-       void *dev_priv;
 };
 
+#ifdef CONFIG_DM_ETH
+/**
+ * usb_ether_register() - register a new USB ethernet device
+ *
+ * This selects the correct USB interface and figures out the endpoints to use.
+ *
+ * @dev:       USB device
+ * @ss:                Place to put USB ethernet data
+ * @rxsize:    Maximum size to allocate for the receive buffer
+ * @return 0 if OK, -ve on error
+ */
+int usb_ether_register(struct udevice *dev, struct ueth_data *ueth, int rxsize);
+
+/**
+ * usb_ether_deregister() - deregister a USB ethernet device
+ *
+ * @ueth:      USB Ethernet device
+ * @return 0
+ */
+int usb_ether_deregister(struct ueth_data *ueth);
+
+/**
+ * usb_ether_receive() - recieve a packet from the bulk in endpoint
+ *
+ * The packet is stored in the internal buffer ready for processing.
+ *
+ * @ueth:      USB Ethernet device
+ * @rxsize:    Maximum size to receive
+ * @return 0 if a packet was received, -EAGAIN if not, -ENOSPC if @rxsize is
+ * larger than the size passed ot usb_ether_register(), other -ve on error
+ */
+int usb_ether_receive(struct ueth_data *ueth, int rxsize);
+
+/**
+ * usb_ether_get_rx_bytes() - obtain bytes from the internal packet buffer
+ *
+ * This should be called repeatedly to obtain packet data until it returns 0.
+ * After each packet is processed, call usb_ether_advance_rxbuf() to move to
+ * the next one.
+ *
+ * @ueth:      USB Ethernet device
+ * @ptrp:      Returns a pointer to the start of the next packet if there is
+ *             one available
+ * @return number of bytes available, or 0 if none
+ */
+int usb_ether_get_rx_bytes(struct ueth_data *ueth, uint8_t **ptrp);
+
+/**
+ * usb_ether_advance_rxbuf() - Advance to the next packet in the internal buffer
+ *
+ * After processing the data returned by usb_ether_get_rx_bytes(), call this
+ * function to move to the next packet. You must specify the number of bytes
+ * you have processed in @num_bytes.
+ *
+ * @ueth:      USB Ethernet device
+ * @num_bytes: Number of bytes to skip, or -1 to skip all bytes
+ */
+void usb_ether_advance_rxbuf(struct ueth_data *ueth, int num_bytes);
+#else
 /*
  * Function definitions for each USB ethernet driver go here
  * (declaration is unconditional, compilation is conditional)
@@ -65,5 +131,6 @@ int smsc95xx_eth_probe(struct usb_device *dev, unsigned int ifnum,
                        struct ueth_data *ss);
 int smsc95xx_eth_get_info(struct usb_device *dev, struct ueth_data *ss,
                        struct eth_device *eth);
+#endif
 
 #endif /* __USB_ETHER_H__ */
index d2fcca3f5a78e7f63ec4cfabaeb2c4cc3654092a..b5bc9c1d95fab6c09d6cf637202b10ae57e9f85f 100644 (file)
@@ -40,6 +40,32 @@ unsigned long long simple_strtoull(const char *cp, char **endp,
                                        unsigned int base);
 long simple_strtol(const char *cp, char **endp, unsigned int base);
 
+/**
+ * trailing_strtol() - extract a trailing integer from a string
+ *
+ * Given a string this finds a trailing number on the string and returns it.
+ * For example, "abc123" would return 123.
+ *
+ * @str:       String to exxamine
+ * @return training number if found, else -1
+ */
+long trailing_strtol(const char *str);
+
+/**
+ * trailing_strtoln() - extract a trailing integer from a fixed-length string
+ *
+ * Given a fixed-length string this finds a trailing number on the string
+ * and returns it. For example, "abc123" would return 123. Only the
+ * characters between @str and @end - 1 are examined. If @end is NULL, it is
+ * set to str + strlen(str).
+ *
+ * @str:       String to exxamine
+ * @end:       Pointer to end of string to examine, or NULL to use the
+ *             whole string
+ * @return training number if found, else -1
+ */
+long trailing_strtoln(const char *str, const char *end);
+
 /**
  * panic() - Print a message and reset/hang
  *
index c98d3997b7dec85e51a2461601fe85fb20a2c22a..972ac1793daa3353a0ebf8bc12a9e2a901e37117 100644 (file)
@@ -50,6 +50,8 @@ config LIB_RAND
        help
          This library provides pseudo-random number generator functions.
 
+source lib/dhry/Kconfig
+
 source lib/rsa/Kconfig
 
 menu "Hashing Support"
index 97ed398ade42f1b0eb6ef233202b56fa3068a668..fd106b91c80f0335fbdeb66a8bb4d53fb07c0900 100644 (file)
@@ -15,12 +15,15 @@ obj-$(CONFIG_BZIP2) += bzip2/
 obj-$(CONFIG_TIZEN) += tizen/
 obj-$(CONFIG_OF_LIBFDT) += libfdt/
 obj-$(CONFIG_FIT) += libfdt/
+obj-$(CONFIG_FIT) += libfdt/
+obj-$(CONFIG_CMD_DHRYSTONE) += dhry/
 
 obj-$(CONFIG_AES) += aes.o
 obj-$(CONFIG_USB_TTY) += circbuf.o
 obj-y += crc7.o
 obj-y += crc8.o
 obj-y += crc16.o
+obj-$(CONFIG_ERRNO_STR) += errno_str.o
 obj-$(CONFIG_FIT) += fdtdec_common.o
 obj-$(CONFIG_OF_CONTROL) += fdtdec_common.o
 obj-$(CONFIG_OF_CONTROL) += fdtdec.o
@@ -34,6 +37,7 @@ obj-$(CONFIG_MD5) += md5.o
 obj-y += net_utils.o
 obj-$(CONFIG_PHYSMEM) += physmem.o
 obj-y += qsort.o
+obj-y += rc4.o
 obj-$(CONFIG_SHA1) += sha1.o
 obj-$(CONFIG_SUPPORT_EMMC_RPMB) += sha256.o
 obj-$(CONFIG_SHA256) += sha256.o
@@ -57,7 +61,6 @@ endif
 obj-$(CONFIG_ADDR_MAP) += addr_map.o
 obj-y += hashtable.o
 obj-y += errno.o
-obj-$(CONFIG_ERRNO_STR) += errno_str.o
 obj-y += display_options.o
 obj-$(CONFIG_BCH) += bch.o
 obj-y += crc32.o
diff --git a/lib/dhry/Kconfig b/lib/dhry/Kconfig
new file mode 100644 (file)
index 0000000..641b806
--- /dev/null
@@ -0,0 +1,7 @@
+config CMD_DHRYSTONE
+       bool "Support the 'dhry' command to run the dhrystone benchmark"
+       help
+         Dhrystone is an old benchmark in the public domain that gives a
+         rough idea of CPU performance. This enables a 'dhry' command
+         which runs this benchmark within U-Boot and reports the performance.
+         The number of 'Dhrystone MIPS' is also reported.
diff --git a/lib/dhry/Makefile b/lib/dhry/Makefile
new file mode 100644 (file)
index 0000000..926c0d6
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Copyright (c) 2015 Google, Inc
+#
+# SPDX-License-Identifier:     GPL-2.0+
+#
+
+obj-y += cmd_dhry.o dhry_1.o dhry_2.o
diff --git a/lib/dhry/cmd_dhry.c b/lib/dhry/cmd_dhry.c
new file mode 100644 (file)
index 0000000..5dc191e
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * (C) Copyright 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include "dhry.h"
+
+static int do_dhry(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       ulong start, duration, dhry_per_sec, vax_mips;
+       int iterations = 1000000;
+
+       if (argc > 1)
+               iterations = simple_strtoul(argv[1], NULL, 10);
+
+       start = get_timer(0);
+       dhry(iterations);
+       duration = get_timer(start);
+       dhry_per_sec = iterations * 1000 / duration;
+       vax_mips = dhry_per_sec / 1757;
+       printf("%d iterations in %lu ms: %lu/s, %lu DMIPS\n", iterations,
+              duration, dhry_per_sec, vax_mips);
+
+       return 0;
+}
+
+U_BOOT_CMD(
+       dhry,   2,      1,      do_dhry,
+       "[iterations] - run dhrystone benchmark",
+       "\n    - run the Dhrystone 2.1 benchmark, a rough measure of CPU speed\n"
+);
diff --git a/lib/dhry/dhry.h b/lib/dhry/dhry.h
new file mode 100644 (file)
index 0000000..49d4223
--- /dev/null
@@ -0,0 +1,442 @@
+/*
+ * (C) Copyright 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ *
+ * Dhrystone is widely available in the public domain. A GPL license is
+ * chosen for U-Boot.
+ */
+
+/*****************************************************************************
+ *  The BYTE UNIX Benchmarks - Release 3
+ *          Module: dhry.h   SID: 3.4 5/15/91 19:30:21
+ *          
+ *****************************************************************************
+ * Bug reports, patches, comments, suggestions should be sent to:
+ *
+ *     Ben Smith, Rick Grehan or Tom Yager
+ *     ben@bytepb.byte.com   rick_g@bytepb.byte.com   tyager@bytepb.byte.com
+ *
+ *****************************************************************************
+ *  Modification Log:
+ *  addapted from:
+ *
+ *
+ *                   "DHRYSTONE" Benchmark Program
+ *                   -----------------------------
+ *                                                                            
+ *  Version:    C, Version 2.1
+ *                                                                            
+ *  File:       dhry.h (part 1 of 3)
+ *
+ *  Date:       May 25, 1988
+ *
+ *  Author:     Reinhold P. Weicker
+ *                      Siemens AG, AUT E 51
+ *                      Postfach 3220
+ *                      8520 Erlangen
+ *                      Germany (West)
+ *                              Phone:  [+49]-9131-7-20330
+ *                                      (8-17 Central European Time)
+ *                              Usenet: ..!mcvax!unido!estevax!weicker
+ *
+ *              Original Version (in Ada) published in
+ *              "Communications of the ACM" vol. 27., no. 10 (Oct. 1984),
+ *              pp. 1013 - 1030, together with the statistics
+ *              on which the distribution of statements etc. is based.
+ *
+ *              In this C version, the following C library functions are used:
+ *              - strcpy, strcmp (inside the measurement loop)
+ *              - printf, scanf (outside the measurement loop)
+ *              In addition, Berkeley UNIX system calls "times ()" or "time ()"
+ *              are used for execution time measurement. For measurements
+ *              on other systems, these calls have to be changed.
+ *
+ *  Collection of Results:
+ *              Reinhold Weicker (address see above) and
+ *              
+ *              Rick Richardson
+ *              PC Research. Inc.
+ *              94 Apple Orchard Drive
+ *              Tinton Falls, NJ 07724
+ *                      Phone:  (201) 834-1378 (9-17 EST)               
+ *                      Usenet: ...!seismo!uunet!pcrat!rick
+ *
+ *      Please send results to Rick Richardson and/or Reinhold Weicker.
+ *      Complete information should be given on hardware and software used.
+ *      Hardware information includes: Machine type, CPU, type and size
+ *      of caches; for microprocessors: clock frequency, memory speed
+ *      (number of wait states).
+ *      Software information includes: Compiler (and runtime library)
+ *      manufacturer and version, compilation switches, OS version.
+ *      The Operating System version may give an indication about the
+ *      compiler; Dhrystone itself performs no OS calls in the measurement loop.
+ *
+ *      The complete output generated by the program should be mailed
+ *      such that at least some checks for correctness can be made.
+ *
+ ***************************************************************************
+ *
+ *  History:    This version C/2.1 has been made for two reasons:
+ *
+ *              1) There is an obvious need for a common C version of
+ *              Dhrystone, since C is at present the most popular system
+ *              programming language for the class of processors
+ *              (microcomputers, minicomputers) where Dhrystone is used most.
+ *              There should be, as far as possible, only one C version of
+ *              Dhrystone such that results can be compared without
+ *              restrictions. In the past, the C versions distributed
+ *              by Rick Richardson (Version 1.1) and by Reinhold Weicker
+ *              had small (though not significant) differences.
+ *
+ *              2) As far as it is possible without changes to the Dhrystone
+ *              statistics, optimizing compilers should be prevented from
+ *              removing significant statements.
+ *
+ *              This C version has been developed in cooperation with
+ *              Rick Richardson (Tinton Falls, NJ), it incorporates many
+ *              ideas from the "Version 1.1" distributed previously by
+ *              him over the UNIX network Usenet.
+ *              I also thank Chaim Benedelac (National Semiconductor),
+ *              David Ditzel (SUN), Earl Killian and John Mashey (MIPS),
+ *              Alan Smith and Rafael Saavedra-Barrera (UC at Berkeley)
+ *              for their help with comments on earlier versions of the
+ *              benchmark.
+ *
+ *  Changes:    In the initialization part, this version follows mostly
+ *              Rick Richardson's version distributed via Usenet, not the
+ *              version distributed earlier via floppy disk by Reinhold Weicker.
+ *              As a concession to older compilers, names have been made
+ *              unique within the first 8 characters.
+ *              Inside the measurement loop, this version follows the
+ *              version previously distributed by Reinhold Weicker.
+ *
+ *              At several places in the benchmark, code has been added,
+ *              but within the measurement loop only in branches that 
+ *              are not executed. The intention is that optimizing compilers
+ *              should be prevented from moving code out of the measurement
+ *              loop, or from removing code altogether. Since the statements
+ *              that are executed within the measurement loop have NOT been
+ *              changed, the numbers defining the "Dhrystone distribution"
+ *              (distribution of statements, operand types and locality)
+ *              still hold. Except for sophisticated optimizing compilers,
+ *              execution times for this version should be the same as
+ *              for previous versions.
+ *              
+ *              Since it has proven difficult to subtract the time for the
+ *              measurement loop overhead in a correct way, the loop check
+ *              has been made a part of the benchmark. This does have
+ *              an impact - though a very minor one - on the distribution
+ *              statistics which have been updated for this version.
+ *
+ *              All changes within the measurement loop are described
+ *              and discussed in the companion paper "Rationale for
+ *              Dhrystone version 2".
+ *
+ *              Because of the self-imposed limitation that the order and
+ *              distribution of the executed statements should not be
+ *              changed, there are still cases where optimizing compilers
+ *              may not generate code for some statements. To a certain
+ *              degree, this is unavoidable for small synthetic benchmarks.
+ *              Users of the benchmark are advised to check code listings
+ *              whether code is generated for all statements of Dhrystone.
+ *
+ *              Version 2.1 is identical to version 2.0 distributed via
+ *              the UNIX network Usenet in March 1988 except that it corrects
+ *              some minor deficiencies that were found by users of version 2.0.
+ *              The only change within the measurement loop is that a
+ *              non-executed "else" part was added to the "if" statement in
+ *              Func_3, and a non-executed "else" part removed from Proc_3.
+ *
+ ***************************************************************************
+ *
+ * Defines:     The following "Defines" are possible:
+ *              -DREG=register          (default: Not defined)
+ *                      As an approximation to what an average C programmer
+ *                      might do, the "register" storage class is applied
+ *                      (if enabled by -DREG=register)
+ *                      - for local variables, if they are used (dynamically)
+ *                        five or more times
+ *                      - for parameters if they are used (dynamically)
+ *                        six or more times
+ *                      Note that an optimal "register" strategy is
+ *                      compiler-dependent, and that "register" declarations
+ *                      do not necessarily lead to faster execution.
+ *              -DNOSTRUCTASSIGN        (default: Not defined)
+ *                      Define if the C compiler does not support
+ *                      assignment of structures.
+ *              -DNOENUMS               (default: Not defined)
+ *                      Define if the C compiler does not support
+ *                      enumeration types.
+ *              -DTIMES                 (default)
+ *              -DTIME
+ *                      The "times" function of UNIX (returning process times)
+ *                      or the "time" function (returning wallclock time)
+ *                      is used for measurement. 
+ *                      For single user machines, "time ()" is adequate. For
+ *                      multi-user machines where you cannot get single-user
+ *                      access, use the "times ()" function. If you have
+ *                      neither, use a stopwatch in the dead of night.
+ *                      "printf"s are provided marking the points "Start Timer"
+ *                      and "Stop Timer". DO NOT use the UNIX "time(1)"
+ *                      command, as this will measure the total time to
+ *                      run this program, which will (erroneously) include
+ *                      the time to allocate storage (malloc) and to perform
+ *                      the initialization.
+ *              -DHZ=nnn
+ *                      In Berkeley UNIX, the function "times" returns process
+ *                      time in 1/HZ seconds, with HZ = 60 for most systems.
+ *                      CHECK YOUR SYSTEM DESCRIPTION BEFORE YOU JUST APPLY
+ *                      A VALUE.
+ *
+ ***************************************************************************
+ *
+ *  Compilation model and measurement (IMPORTANT):
+ *
+ *  This C version of Dhrystone consists of three files:
+ *  - dhry.h (this file, containing global definitions and comments)
+ *  - dhry_1.c (containing the code corresponding to Ada package Pack_1)
+ *  - dhry_2.c (containing the code corresponding to Ada package Pack_2)
+ *
+ *  The following "ground rules" apply for measurements:
+ *  - Separate compilation
+ *  - No procedure merging
+ *  - Otherwise, compiler optimizations are allowed but should be indicated
+ *  - Default results are those without register declarations
+ *  See the companion paper "Rationale for Dhrystone Version 2" for a more
+ *  detailed discussion of these ground rules.
+ *
+ *  For 16-Bit processors (e.g. 80186, 80286), times for all compilation
+ *  models ("small", "medium", "large" etc.) should be given if possible,
+ *  together with a definition of these models for the compiler system used.
+ *
+ **************************************************************************
+ *
+ *  Dhrystone (C version) statistics:
+ *
+ *  [Comment from the first distribution, updated for version 2.
+ *   Note that because of language differences, the numbers are slightly
+ *   different from the Ada version.]
+ *
+ *  The following program contains statements of a high level programming
+ *  language (here: C) in a distribution considered representative:           
+ *
+ *    assignments                  52 (51.0 %)
+ *    control statements           33 (32.4 %)
+ *    procedure, function calls    17 (16.7 %)
+ *
+ *  103 statements are dynamically executed. The program is balanced with
+ *  respect to the three aspects:                                             
+ *
+ *    - statement type
+ *    - operand type
+ *    - operand locality
+ *         operand global, local, parameter, or constant.                     
+ *
+ *  The combination of these three aspects is balanced only approximately.    
+ *
+ *  1. Statement Type:                                                        
+ *  -----------------             number
+ *
+ *     V1 = V2                     9
+ *       (incl. V1 = F(..)
+ *     V = Constant               12
+ *     Assignment,                 7
+ *       with array element
+ *     Assignment,                 6
+ *       with record component
+ *                                --
+ *                                34       34
+ *
+ *     X = Y +|-|"&&"|"|" Z        5
+ *     X = Y +|-|"==" Constant     6
+ *     X = X +|- 1                 3
+ *     X = Y *|/ Z                 2
+ *     X = Expression,             1
+ *           two operators
+ *     X = Expression,             1
+ *           three operators
+ *                                --
+ *                                18       18
+ *
+ *     if ....                    14
+ *       with "else"      7
+ *       without "else"   7
+ *           executed        3
+ *           not executed    4
+ *     for ...                     7  |  counted every time
+ *     while ...                   4  |  the loop condition
+ *     do ... while                1  |  is evaluated
+ *     switch ...                  1
+ *     break                       1
+ *     declaration with            1
+ *       initialization
+ *                                --
+ *                                34       34
+ *
+ *     P (...)  procedure call    11
+ *       user procedure      10
+ *       library procedure    1
+ *     X = F (...)
+ *             function  call      6
+ *       user function        5                                         
+ *       library function     1                                               
+ *                                --                                          
+ *                                17       17
+ *                                        ---
+ *                                        103
+ *
+ *    The average number of parameters in procedure or function calls
+ *    is 1.82 (not counting the function values as implicit parameters).
+ *
+ *
+ *  2. Operators
+ *  ------------
+ *                          number    approximate
+ *                                    percentage
+ *
+ *    Arithmetic             32          50.8                                 
+ *
+ *       +                     21          33.3                              
+ *       -                      7          11.1                              
+ *       *                      3           4.8
+ *       / (int div)            1           1.6
+ *
+ *    Comparison             27           42.8
+ *
+ *       ==                     9           14.3
+ *       /=                     4            6.3
+ *       >                      1            1.6
+ *       <                      3            4.8
+ *       >=                     1            1.6
+ *       <=                     9           14.3
+ *
+ *    Logic                   4            6.3
+ *
+ *       && (AND-THEN)          1            1.6
+ *       |  (OR)                1            1.6
+ *       !  (NOT)               2            3.2
+ * 
+ *                           --          -----
+ *                           63          100.1
+ *
+ *
+ *  3. Operand Type (counted once per operand reference):
+ *  ---------------
+ *                          number    approximate
+ *                                    percentage
+ *
+ *     Integer               175        72.3 %
+ *     Character              45        18.6 %
+ *     Pointer                12         5.0 %
+ *     String30                6         2.5 %
+ *     Array                   2         0.8 %
+ *     Record                  2         0.8 %
+ *                           ---       -------
+ *                           242       100.0 %
+ *
+ *  When there is an access path leading to the final operand (e.g. a record
+ *  component), only the final data type on the access path is counted.       
+ *
+ *
+ *  4. Operand Locality:                                                      
+ *  -------------------
+ *                                number    approximate
+ *                                          percentage
+ *
+ *     local variable              114        47.1 %
+ *     global variable              22         9.1 %
+ *     parameter                    45        18.6 %
+ *        value                        23         9.5 %
+ *        reference                    22         9.1 %
+ *     function result               6         2.5 %
+ *     constant                     55        22.7 %
+ *                                 ---       -------
+ *                                 242       100.0 %
+ *
+ *
+ *  The program does not compute anything meaningful, but it is syntactically
+ *  and semantically correct. All variables have a value assigned to them
+ *  before they are used as a source operand.
+ *
+ *  There has been no explicit effort to account for the effects of a
+ *  cache, or to balance the use of long or short displacements for code or
+ *  data.
+ *
+ ***************************************************************************
+ */
+
+
+/* Compiler and system dependent definitions: */
+
+#ifndef TIME
+#define TIMES
+#endif
+                /* Use times(2) time function unless    */
+                /* explicitly defined otherwise         */
+
+#define Mic_secs_Per_Second     1000000.0
+                /* Berkeley UNIX C returns process times in seconds/HZ */
+
+#ifdef  NOSTRUCTASSIGN
+#define structassign(d, s)      memcpy(&(d), &(s), sizeof(d))
+#else
+#define structassign(d, s)      d = s
+#endif
+
+#ifdef  NOENUM
+#define Ident_1 0
+#define Ident_2 1
+#define Ident_3 2
+#define Ident_4 3
+#define Ident_5 4
+  typedef int   Enumeration;
+#else
+  typedef       enum    {Ident_1, Ident_2, Ident_3, Ident_4, Ident_5}
+                Enumeration;
+#endif
+        /* for boolean and enumeration types in Ada, Pascal */
+
+/* General definitions: */
+
+#define Null 0 
+                /* Value of a Null pointer */
+#define true  1
+#define false 0
+
+typedef int     One_Thirty;
+typedef int     One_Fifty;
+typedef char    Capital_Letter;
+typedef int     Boolean;
+typedef char    Str_30 [31];
+typedef int     Arr_1_Dim [50];
+typedef int     Arr_2_Dim [50] [50];
+
+typedef struct record 
+    {
+    struct record *Ptr_Comp;
+    Enumeration    Discr;
+    union {
+          struct {
+                  Enumeration Enum_Comp;
+                  int         Int_Comp;
+                  char        Str_Comp [31];
+                  } var_1;
+          struct {
+                  Enumeration E_Comp_2;
+                  char        Str_2_Comp [31];
+                  } var_2;
+          struct {
+                  char        Ch_1_Comp;
+                  char        Ch_2_Comp;
+                  } var_3;
+          } variant;
+      } Rec_Type, *Rec_Pointer;
+
+
+/*
+ * dhry() - run dhrystone for a given number of iterations
+ *
+ * @iterations:        Number of iterations to run
+ */
+void dhry(int iterations);
diff --git a/lib/dhry/dhry_1.c b/lib/dhry/dhry_1.c
new file mode 100644 (file)
index 0000000..be63710
--- /dev/null
@@ -0,0 +1,421 @@
+/*
+ * (C) Copyright 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ *
+ * Dhrystone is widely available in the public domain. A GPL license is
+ * chosen for U-Boot.
+ */
+
+/*****************************************************************************
+ *  The BYTE UNIX Benchmarks - Release 3
+ *          Module: dhry_1.c   SID: 3.4 5/15/91 19:30:21
+ *          
+ *****************************************************************************
+ * Bug reports, patches, comments, suggestions should be sent to:
+ *
+ *     Ben Smith, Rick Grehan or Tom Yager
+ *     ben@bytepb.byte.com   rick_g@bytepb.byte.com   tyager@bytepb.byte.com
+ *
+ *****************************************************************************
+ *
+ * *** WARNING ****  With BYTE's modifications applied, results obtained with
+ *     *******       this version of the Dhrystone program may not be applicable
+ *                   to other versions.
+ *                  
+ *  Modification Log:
+ *  10/22/97 - code cleanup to remove ANSI C compiler warnings
+ *             Andy Kahn <kahn@zk3.dec.com>
+ *
+ *  Adapted from:
+ *
+ *                   "DHRYSTONE" Benchmark Program
+ *                   -----------------------------
+ *                                                                            
+ *  Version:    C, Version 2.1
+ *                                                                            
+ *  File:       dhry_1.c (part 2 of 3)
+ *
+ *  Date:       May 25, 1988
+ *
+ *  Author:     Reinhold P. Weicker
+ *
+ ***************************************************************************/
+char SCCSid[] = "@(#) @(#)dhry_1.c:3.4 -- 5/15/91 19:30:21";
+
+#include <common.h>
+#include <malloc.h>
+
+#include "dhry.h"
+
+unsigned long Run_Index;
+
+void report(void)
+{
+       printf("%ld loops\n", Run_Index);
+}
+
+/* Global Variables: */
+
+Rec_Pointer     Ptr_Glob,
+                Next_Ptr_Glob;
+int             Int_Glob;
+Boolean         Bool_Glob;
+char            Ch_1_Glob,
+                Ch_2_Glob;
+int             Arr_1_Glob [50];
+int             Arr_2_Glob [50] [50];
+
+Enumeration     Func_1 (Capital_Letter Ch_1_Par_Val, Capital_Letter Ch_2_Par_Val);
+  /* forward declaration necessary since Enumeration may not simply be int */
+
+#ifndef REG
+        Boolean Reg = false;
+#define REG
+        /* REG becomes defined as empty */
+        /* i.e. no register variables   */
+#else
+        Boolean Reg = true;
+#endif
+
+/* variables for time measurement: */
+
+#ifdef TIMES
+#define Too_Small_Time 120
+                /* Measurements should last at least about 2 seconds */
+#endif
+#ifdef TIME
+extern long     time();
+                /* see library function "time"  */
+#define Too_Small_Time 2
+                /* Measurements should last at least 2 seconds */
+#endif
+
+long            Begin_Time,
+                End_Time,
+                User_Time;
+
+/* end of variables for time measurement */
+
+void Proc_1 (REG Rec_Pointer Ptr_Val_Par);
+void Proc_2 (One_Fifty   *Int_Par_Ref);
+void Proc_3 (Rec_Pointer *Ptr_Ref_Par);
+void Proc_4 (void);
+void Proc_5 (void);
+
+
+extern Boolean Func_2(Str_30, Str_30);
+extern void Proc_6(Enumeration, Enumeration *);
+extern void Proc_7(One_Fifty, One_Fifty, One_Fifty *);
+extern void Proc_8(Arr_1_Dim, Arr_2_Dim, int, int);
+
+void dhry(int Number_Of_Runs)
+  /* main program, corresponds to procedures        */
+  /* Main and Proc_0 in the Ada version             */
+{
+        One_Fifty       Int_1_Loc;
+  REG   One_Fifty       Int_2_Loc;
+        One_Fifty       Int_3_Loc;
+  REG   char            Ch_Index;
+        Enumeration     Enum_Loc;
+        Str_30          Str_1_Loc;
+        Str_30          Str_2_Loc;
+
+  /* Initializations */
+
+  Next_Ptr_Glob = (Rec_Pointer) malloc (sizeof (Rec_Type));
+  Ptr_Glob = (Rec_Pointer) malloc (sizeof (Rec_Type));
+
+  Ptr_Glob->Ptr_Comp                    = Next_Ptr_Glob;
+  Ptr_Glob->Discr                       = Ident_1;
+  Ptr_Glob->variant.var_1.Enum_Comp     = Ident_3;
+  Ptr_Glob->variant.var_1.Int_Comp      = 40;
+  strcpy (Ptr_Glob->variant.var_1.Str_Comp, 
+          "DHRYSTONE PROGRAM, SOME STRING");
+  strcpy (Str_1_Loc, "DHRYSTONE PROGRAM, 1'ST STRING");
+
+  Arr_2_Glob [8][7] = 10;
+        /* Was missing in published program. Without this statement,    */
+        /* Arr_2_Glob [8][7] would have an undefined value.             */
+        /* Warning: With 16-Bit processors and Number_Of_Runs > 32000,  */
+        /* overflow may occur for this array element.                   */
+
+#ifdef PRATTLE
+  printf ("\n");
+  printf ("Dhrystone Benchmark, Version 2.1 (Language: C)\n");
+  printf ("\n");
+  if (Reg)
+  {
+    printf ("Program compiled with 'register' attribute\n");
+    printf ("\n");
+  }
+  else
+  {
+    printf ("Program compiled without 'register' attribute\n");
+    printf ("\n");
+  }
+  printf ("Please give the number of runs through the benchmark: ");
+  {
+    int n;
+    scanf ("%d", &n);
+    Number_Of_Runs = n;
+  }
+  printf ("\n");
+
+  printf ("Execution starts, %d runs through Dhrystone\n", Number_Of_Runs);
+#endif /* PRATTLE */
+
+  Run_Index = 0;
+
+  /***************/
+  /* Start timer */
+  /***************/
+#ifdef SELF_TIMED
+#ifdef TIMES
+  times (&time_info);
+  Begin_Time = (long) time_info.tms_utime;
+#endif
+#ifdef TIME
+  Begin_Time = time ( (long *) 0);
+#endif
+#endif /* SELF_TIMED */
+
+  for (Run_Index = 1; Run_Index < Number_Of_Runs; ++Run_Index)
+  {
+
+    Proc_5();
+    Proc_4();
+      /* Ch_1_Glob == 'A', Ch_2_Glob == 'B', Bool_Glob == true */
+    Int_1_Loc = 2;
+    Int_2_Loc = 3;
+    strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 2'ND STRING");
+    Enum_Loc = Ident_2;
+    Bool_Glob = ! Func_2 (Str_1_Loc, Str_2_Loc);
+      /* Bool_Glob == 1 */
+    while (Int_1_Loc < Int_2_Loc)  /* loop body executed once */
+    {
+      Int_3_Loc = 5 * Int_1_Loc - Int_2_Loc;
+        /* Int_3_Loc == 7 */
+      Proc_7 (Int_1_Loc, Int_2_Loc, &Int_3_Loc);
+        /* Int_3_Loc == 7 */
+      Int_1_Loc += 1;
+    } /* while */
+      /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */
+    Proc_8 (Arr_1_Glob, Arr_2_Glob, Int_1_Loc, Int_3_Loc);
+      /* Int_Glob == 5 */
+    Proc_1 (Ptr_Glob);
+    for (Ch_Index = 'A'; Ch_Index <= Ch_2_Glob; ++Ch_Index)
+                             /* loop body executed twice */
+    {
+      if (Enum_Loc == Func_1 (Ch_Index, 'C'))
+          /* then, not executed */
+        {
+        Proc_6 (Ident_1, &Enum_Loc);
+        strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 3'RD STRING");
+        Int_2_Loc = Run_Index;
+        Int_Glob = Run_Index;
+        }
+    }
+      /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */
+    Int_2_Loc = Int_2_Loc * Int_1_Loc;
+    Int_1_Loc = Int_2_Loc / Int_3_Loc;
+    Int_2_Loc = 7 * (Int_2_Loc - Int_3_Loc) - Int_1_Loc;
+      /* Int_1_Loc == 1, Int_2_Loc == 13, Int_3_Loc == 7 */
+    Proc_2 (&Int_1_Loc);
+      /* Int_1_Loc == 5 */
+
+  } /* loop "for Run_Index" */
+
+  /**************/
+  /* Stop timer */
+  /**************/
+#ifdef SELF_TIMED 
+#ifdef TIMES
+  times (&time_info);
+  End_Time = (long) time_info.tms_utime;
+#endif
+#ifdef TIME
+  End_Time = time ( (long *) 0);
+#endif
+#endif /* SELF_TIMED */
+
+  /* BYTE version never executes this stuff */
+#ifdef SELF_TIMED
+  printf ("Execution ends\n");
+  printf ("\n");
+  printf ("Final values of the variables used in the benchmark:\n");
+  printf ("\n");
+  printf ("Int_Glob:            %d\n", Int_Glob);
+  printf ("        should be:   %d\n", 5);
+  printf ("Bool_Glob:           %d\n", Bool_Glob);
+  printf ("        should be:   %d\n", 1);
+  printf ("Ch_1_Glob:           %c\n", Ch_1_Glob);
+  printf ("        should be:   %c\n", 'A');
+  printf ("Ch_2_Glob:           %c\n", Ch_2_Glob);
+  printf ("        should be:   %c\n", 'B');
+  printf ("Arr_1_Glob[8]:       %d\n", Arr_1_Glob[8]);
+  printf ("        should be:   %d\n", 7);
+  printf ("Arr_2_Glob[8][7]:    %d\n", Arr_2_Glob[8][7]);
+  printf ("        should be:   Number_Of_Runs + 10\n");
+  printf ("Ptr_Glob->\n");
+  printf ("  Ptr_Comp:          %d\n", (int) Ptr_Glob->Ptr_Comp);
+  printf ("        should be:   (implementation-dependent)\n");
+  printf ("  Discr:             %d\n", Ptr_Glob->Discr);
+  printf ("        should be:   %d\n", 0);
+  printf ("  Enum_Comp:         %d\n", Ptr_Glob->variant.var_1.Enum_Comp);
+  printf ("        should be:   %d\n", 2);
+  printf ("  Int_Comp:          %d\n", Ptr_Glob->variant.var_1.Int_Comp);
+  printf ("        should be:   %d\n", 17);
+  printf ("  Str_Comp:          %s\n", Ptr_Glob->variant.var_1.Str_Comp);
+  printf ("        should be:   DHRYSTONE PROGRAM, SOME STRING\n");
+  printf ("Next_Ptr_Glob->\n");
+  printf ("  Ptr_Comp:          %d\n", (int) Next_Ptr_Glob->Ptr_Comp);
+  printf ("        should be:   (implementation-dependent), same as above\n");
+  printf ("  Discr:             %d\n", Next_Ptr_Glob->Discr);
+  printf ("        should be:   %d\n", 0);
+  printf ("  Enum_Comp:         %d\n", Next_Ptr_Glob->variant.var_1.Enum_Comp);
+  printf ("        should be:   %d\n", 1);
+  printf ("  Int_Comp:          %d\n", Next_Ptr_Glob->variant.var_1.Int_Comp);
+  printf ("        should be:   %d\n", 18);
+  printf ("  Str_Comp:          %s\n",
+                                Next_Ptr_Glob->variant.var_1.Str_Comp);
+  printf ("        should be:   DHRYSTONE PROGRAM, SOME STRING\n");
+  printf ("Int_1_Loc:           %d\n", Int_1_Loc);
+  printf ("        should be:   %d\n", 5);
+  printf ("Int_2_Loc:           %d\n", Int_2_Loc);
+  printf ("        should be:   %d\n", 13);
+  printf ("Int_3_Loc:           %d\n", Int_3_Loc);
+  printf ("        should be:   %d\n", 7);
+  printf ("Enum_Loc:            %d\n", Enum_Loc);
+  printf ("        should be:   %d\n", 1);
+  printf ("Str_1_Loc:           %s\n", Str_1_Loc);
+  printf ("        should be:   DHRYSTONE PROGRAM, 1'ST STRING\n");
+  printf ("Str_2_Loc:           %s\n", Str_2_Loc);
+  printf ("        should be:   DHRYSTONE PROGRAM, 2'ND STRING\n");
+  printf ("\n");
+
+  User_Time = End_Time - Begin_Time;
+
+  if (User_Time < Too_Small_Time)
+  {
+    printf ("Measured time too small to obtain meaningful results\n");
+    printf ("Please increase number of runs\n");
+    printf ("\n");
+  }
+  else
+  {
+#ifdef TIME
+    Microseconds = (float) User_Time * Mic_secs_Per_Second
+                        / (float) Number_Of_Runs;
+    Dhrystones_Per_Second = (float) Number_Of_Runs / (float) User_Time;
+#else
+    Microseconds = (float) User_Time * Mic_secs_Per_Second
+                        / ((float) HZ * ((float) Number_Of_Runs));
+    Dhrystones_Per_Second = ((float) HZ * (float) Number_Of_Runs)
+                        / (float) User_Time;
+#endif
+    printf ("Microseconds for one run through Dhrystone: ");
+    printf ("%6.1f \n", Microseconds);
+    printf ("Dhrystones per Second:                      ");
+    printf ("%6.1f \n", Dhrystones_Per_Second);
+    printf ("\n");
+  }
+#endif /* SELF_TIMED */
+}
+
+
+void Proc_1 (REG Rec_Pointer Ptr_Val_Par)
+    /* executed once */
+{
+  REG Rec_Pointer Next_Record = Ptr_Val_Par->Ptr_Comp;  
+                                        /* == Ptr_Glob_Next */
+  /* Local variable, initialized with Ptr_Val_Par->Ptr_Comp,    */
+  /* corresponds to "rename" in Ada, "with" in Pascal           */
+  
+  structassign (*Ptr_Val_Par->Ptr_Comp, *Ptr_Glob); 
+  Ptr_Val_Par->variant.var_1.Int_Comp = 5;
+  Next_Record->variant.var_1.Int_Comp 
+        = Ptr_Val_Par->variant.var_1.Int_Comp;
+  Next_Record->Ptr_Comp = Ptr_Val_Par->Ptr_Comp;
+  Proc_3 (&Next_Record->Ptr_Comp);
+    /* Ptr_Val_Par->Ptr_Comp->Ptr_Comp 
+                        == Ptr_Glob->Ptr_Comp */
+  if (Next_Record->Discr == Ident_1)
+    /* then, executed */
+  {
+    Next_Record->variant.var_1.Int_Comp = 6;
+    Proc_6 (Ptr_Val_Par->variant.var_1.Enum_Comp, 
+           &Next_Record->variant.var_1.Enum_Comp);
+    Next_Record->Ptr_Comp = Ptr_Glob->Ptr_Comp;
+    Proc_7 (Next_Record->variant.var_1.Int_Comp, 10, 
+           &Next_Record->variant.var_1.Int_Comp);
+  }
+  else /* not executed */
+    structassign (*Ptr_Val_Par, *Ptr_Val_Par->Ptr_Comp);
+} /* Proc_1 */
+
+
+void Proc_2 (One_Fifty   *Int_Par_Ref)
+    /* executed once */
+    /* *Int_Par_Ref == 1, becomes 4 */
+{
+  One_Fifty  Int_Loc;  
+  Enumeration   Enum_Loc;
+
+  Enum_Loc = 0;
+
+  Int_Loc = *Int_Par_Ref + 10;
+  do /* executed once */
+    if (Ch_1_Glob == 'A')
+      /* then, executed */
+    {
+      Int_Loc -= 1;
+      *Int_Par_Ref = Int_Loc - Int_Glob;
+      Enum_Loc = Ident_1;
+    } /* if */
+  while (Enum_Loc != Ident_1); /* true */
+} /* Proc_2 */
+
+
+void Proc_3 (Rec_Pointer *Ptr_Ref_Par)
+    /* executed once */
+    /* Ptr_Ref_Par becomes Ptr_Glob */
+{
+  if (Ptr_Glob != Null)
+    /* then, executed */
+    *Ptr_Ref_Par = Ptr_Glob->Ptr_Comp;
+  Proc_7 (10, Int_Glob, &Ptr_Glob->variant.var_1.Int_Comp);
+} /* Proc_3 */
+
+
+void Proc_4 (void) /* without parameters */
+    /* executed once */
+{
+  Boolean Bool_Loc;
+
+  Bool_Loc = Ch_1_Glob == 'A';
+  Bool_Glob = Bool_Loc | Bool_Glob;
+  Ch_2_Glob = 'B';
+} /* Proc_4 */
+
+void Proc_5 (void) /* without parameters */
+/*******/
+    /* executed once */
+{
+  Ch_1_Glob = 'A';
+  Bool_Glob = false;
+} /* Proc_5 */
+
+
+        /* Procedure for the assignment of structures,          */
+        /* if the C compiler doesn't support this feature       */
+#ifdef  NOSTRUCTASSIGN
+memcpy (d, s, l)
+register char   *d;
+register char   *s;
+register int    l;
+{
+        while (l--) *d++ = *s++;
+}
+#endif
diff --git a/lib/dhry/dhry_2.c b/lib/dhry/dhry_2.c
new file mode 100644 (file)
index 0000000..59aa458
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * (C) Copyright 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ *
+ * Dhrystone is widely available in the public domain. A GPL license is
+ * chosen for U-Boot.
+ */
+
+/*****************************************************************************
+ *  The BYTE UNIX Benchmarks - Release 3
+ *          Module: dhry_2.c   SID: 3.4 5/15/91 19:30:22
+ *          
+ *****************************************************************************
+ * Bug reports, patches, comments, suggestions should be sent to:
+ *
+ *     Ben Smith, Rick Grehan or Tom Yager
+ *     ben@bytepb.byte.com   rick_g@bytepb.byte.com   tyager@bytepb.byte.com
+ *
+ *****************************************************************************
+ *  Modification Log:
+ *  10/22/97 - code cleanup to remove ANSI C compiler warnings
+ *             Andy Kahn <kahn@zk3.dec.com>
+ *
+ *  Adapted from:
+ *
+ *                   "DHRYSTONE" Benchmark Program
+ *                   -----------------------------
+ *
+ * **** WARNING **** See warning in n.dhry_1.c
+ *                                                                            
+ *  Version:    C, Version 2.1
+ *                                                                            
+ *  File:       dhry_2.c (part 3 of 3)
+ *
+ *  Date:       May 25, 1988
+ *
+ *  Author:     Reinhold P. Weicker
+ *
+ ****************************************************************************/
+/* SCCSid is defined in dhry_1.c */
+
+#include <common.h>
+#include "dhry.h"
+
+#ifndef REG
+#define REG
+        /* REG becomes defined as empty */
+        /* i.e. no register variables   */
+#endif
+
+extern  int     Int_Glob;
+extern  char    Ch_1_Glob;
+
+void Proc_6(Enumeration, Enumeration *);
+void Proc_7(One_Fifty, One_Fifty, One_Fifty *);
+void Proc_8(Arr_1_Dim, Arr_2_Dim, int, int);
+Enumeration Func_1(Capital_Letter, Capital_Letter);
+Boolean Func_2(Str_30, Str_30);
+Boolean Func_3(Enumeration);
+
+void Proc_6 (Enumeration Enum_Val_Par, Enumeration *Enum_Ref_Par)
+    /* executed once */
+    /* Enum_Val_Par == Ident_3, Enum_Ref_Par becomes Ident_2 */
+{
+  *Enum_Ref_Par = Enum_Val_Par;
+  if (! Func_3 (Enum_Val_Par))
+    /* then, not executed */
+    *Enum_Ref_Par = Ident_4;
+  switch (Enum_Val_Par)
+  {
+    case Ident_1: 
+      *Enum_Ref_Par = Ident_1;
+      break;
+    case Ident_2: 
+      if (Int_Glob > 100)
+        /* then */
+      *Enum_Ref_Par = Ident_1;
+      else *Enum_Ref_Par = Ident_4;
+      break;
+    case Ident_3: /* executed */
+      *Enum_Ref_Par = Ident_2;
+      break;
+    case Ident_4: break;
+    case Ident_5: 
+      *Enum_Ref_Par = Ident_3;
+      break;
+  } /* switch */
+} /* Proc_6 */
+
+void Proc_7 (Int_1_Par_Val, Int_2_Par_Val, Int_Par_Ref)
+One_Fifty       Int_1_Par_Val;
+One_Fifty       Int_2_Par_Val;
+One_Fifty      *Int_Par_Ref;
+/**********************************************/
+    /* executed three times                                      */ 
+    /* first call:      Int_1_Par_Val == 2, Int_2_Par_Val == 3,  */
+    /*                  Int_Par_Ref becomes 7                    */
+    /* second call:     Int_1_Par_Val == 10, Int_2_Par_Val == 5, */
+    /*                  Int_Par_Ref becomes 17                   */
+    /* third call:      Int_1_Par_Val == 6, Int_2_Par_Val == 10, */
+    /*                  Int_Par_Ref becomes 18                   */
+{
+  One_Fifty Int_Loc;
+
+  Int_Loc = Int_1_Par_Val + 2;
+  *Int_Par_Ref = Int_2_Par_Val + Int_Loc;
+} /* Proc_7 */
+
+
+void Proc_8 (Arr_1_Par_Ref, Arr_2_Par_Ref, Int_1_Par_Val, Int_2_Par_Val)
+/*********************************************************************/
+    /* executed once      */
+    /* Int_Par_Val_1 == 3 */
+    /* Int_Par_Val_2 == 7 */
+Arr_1_Dim       Arr_1_Par_Ref;
+Arr_2_Dim       Arr_2_Par_Ref;
+int             Int_1_Par_Val;
+int             Int_2_Par_Val;
+{
+  REG One_Fifty Int_Index;
+  REG One_Fifty Int_Loc;
+
+  Int_Loc = Int_1_Par_Val + 5;
+  Arr_1_Par_Ref [Int_Loc] = Int_2_Par_Val;
+  Arr_1_Par_Ref [Int_Loc+1] = Arr_1_Par_Ref [Int_Loc];
+  Arr_1_Par_Ref [Int_Loc+30] = Int_Loc;
+  for (Int_Index = Int_Loc; Int_Index <= Int_Loc+1; ++Int_Index)
+    Arr_2_Par_Ref [Int_Loc] [Int_Index] = Int_Loc;
+  Arr_2_Par_Ref [Int_Loc] [Int_Loc-1] += 1;
+  Arr_2_Par_Ref [Int_Loc+20] [Int_Loc] = Arr_1_Par_Ref [Int_Loc];
+  Int_Glob = 5;
+} /* Proc_8 */
+
+
+Enumeration Func_1 (Capital_Letter Ch_1_Par_Val, Capital_Letter Ch_2_Par_Val)
+/*************************************************/
+    /* executed three times                                         */
+    /* first call:      Ch_1_Par_Val == 'H', Ch_2_Par_Val == 'R'    */
+    /* second call:     Ch_1_Par_Val == 'A', Ch_2_Par_Val == 'C'    */
+    /* third call:      Ch_1_Par_Val == 'B', Ch_2_Par_Val == 'C'    */
+{
+  Capital_Letter        Ch_1_Loc;
+  Capital_Letter        Ch_2_Loc;
+
+  Ch_1_Loc = Ch_1_Par_Val;
+  Ch_2_Loc = Ch_1_Loc;
+  if (Ch_2_Loc != Ch_2_Par_Val)
+    /* then, executed */
+    return (Ident_1);
+  else  /* not executed */
+  {
+    Ch_1_Glob = Ch_1_Loc;
+    return (Ident_2);
+   }
+} /* Func_1 */
+
+
+
+Boolean Func_2 (Str_1_Par_Ref, Str_2_Par_Ref)
+/*************************************************/
+    /* executed once */
+    /* Str_1_Par_Ref == "DHRYSTONE PROGRAM, 1'ST STRING" */
+    /* Str_2_Par_Ref == "DHRYSTONE PROGRAM, 2'ND STRING" */
+
+Str_30  Str_1_Par_Ref;
+Str_30  Str_2_Par_Ref;
+{
+  REG One_Thirty        Int_Loc;
+      Capital_Letter    Ch_Loc;
+
+  Ch_Loc = 'A';
+  Int_Loc = 2;
+  while (Int_Loc <= 2) /* loop body executed once */
+    if (Func_1 (Str_1_Par_Ref[Int_Loc],
+                Str_2_Par_Ref[Int_Loc+1]) == Ident_1)
+      /* then, executed */
+    {
+      Ch_Loc = 'A';
+      Int_Loc += 1;
+    } /* if, while */
+  if (Ch_Loc >= 'W' && Ch_Loc < 'Z')
+    /* then, not executed */
+    Int_Loc = 7;
+  if (Ch_Loc == 'R')
+    /* then, not executed */
+    return (true);
+  else /* executed */
+  {
+    if (strcmp (Str_1_Par_Ref, Str_2_Par_Ref) > 0)
+      /* then, not executed */
+    {
+      Int_Loc += 7;
+      Int_Glob = Int_Loc;
+      return (true);
+    }
+    else /* executed */
+      return (false);
+  } /* if Ch_Loc */
+} /* Func_2 */
+
+
+Boolean Func_3 (Enum_Par_Val)
+/***************************/
+    /* executed once        */
+    /* Enum_Par_Val == Ident_3 */
+Enumeration Enum_Par_Val;
+{
+  Enumeration Enum_Loc;
+
+  Enum_Loc = Enum_Par_Val;
+  if (Enum_Loc == Ident_3)
+    /* then, executed */
+    return (true);
+  else /* not executed */
+    return (false);
+} /* Func_3 */
index 9c6b3619da24cd9ad5c4894d848298ff380d3419..232ca7471215aa08e47fd52b7b9d472b57f25cb7 100644 (file)
@@ -505,8 +505,7 @@ int fdtdec_get_alias_seq(const void *blob, const char *base, int offset,
                const char *prop;
                const char *name;
                const char *slash;
-               const char *p;
-               int len;
+               int len, val;
 
                prop = fdt_getprop_by_offset(blob, prop_offset, &name, &len);
                debug("   - %s, %s\n", name, prop);
@@ -517,12 +516,11 @@ int fdtdec_get_alias_seq(const void *blob, const char *base, int offset,
                slash = strrchr(prop, '/');
                if (strcmp(slash + 1, find_name))
                        continue;
-               for (p = name + strlen(name) - 1; p > name; p--) {
-                       if (!isdigit(*p)) {
-                               *seqp = simple_strtoul(p + 1, NULL, 10);
-                               debug("Found seq %d\n", *seqp);
-                               return 0;
-                       }
+               val = trailing_strtol(name);
+               if (val != -1) {
+                       *seqp = val;
+                       debug("Found seq %d\n", *seqp);
+                       return 0;
                }
        }
 
@@ -570,6 +568,13 @@ int fdtdec_prepare_fdt(void)
                puts("Missing DTB\n");
 #else
                puts("No valid device tree binary found - please append one to U-Boot binary, use u-boot-dtb.bin or define CONFIG_OF_EMBED. For sandbox, use -d <file.dtb>\n");
+# ifdef DEBUG
+               if (gd->fdt_blob) {
+                       printf("fdt_blob=%p\n", gd->fdt_blob);
+                       print_buffer((ulong)gd->fdt_blob, gd->fdt_blob, 4,
+                                    32, 0);
+               }
+# endif
 #endif
                return -1;
        }
index 2f5413f90d6797122875dfc9d8c547dee5162406..934d6142c3e9115bb5963d3c04e46563c8b72c3b 100644 (file)
@@ -6,4 +6,4 @@
 #
 
 obj-y += fdt.o fdt_ro.o fdt_rw.o fdt_strerror.o fdt_sw.o fdt_wip.o \
-       fdt_empty_tree.o fdt_addresses.o
+       fdt_empty_tree.o fdt_addresses.o fdt_region.o
diff --git a/lib/libfdt/fdt_region.c b/lib/libfdt/fdt_region.c
new file mode 100644 (file)
index 0000000..9fea775
--- /dev/null
@@ -0,0 +1,492 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2013 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ * SPDX-License-Identifier:    GPL-2.0+ BSD-2-Clause
+ */
+
+#include "libfdt_env.h"
+
+#ifndef USE_HOSTCC
+#include <fdt.h>
+#include <libfdt.h>
+#else
+#include "fdt_host.h"
+#endif
+
+#include "libfdt_internal.h"
+
+/**
+ * fdt_add_region() - Add a new region to our list
+ *
+ * The region is added if there is space, but in any case we increment the
+ * count. If permitted, and the new region overlaps the last one, we merge
+ * them.
+ *
+ * @info: State information
+ * @offset: Start offset of region
+ * @size: Size of region
+ */
+static int fdt_add_region(struct fdt_region_state *info, int offset, int size)
+{
+       struct fdt_region *reg;
+
+       reg = info->region ? &info->region[info->count - 1] : NULL;
+       if (info->can_merge && info->count &&
+           info->count <= info->max_regions &&
+           reg && offset <= reg->offset + reg->size) {
+               reg->size = offset + size - reg->offset;
+       } else if (info->count++ < info->max_regions) {
+               if (reg) {
+                       reg++;
+                       reg->offset = offset;
+                       reg->size = size;
+               }
+       } else {
+               return -1;
+       }
+
+       return 0;
+}
+
+static int region_list_contains_offset(struct fdt_region_state *info,
+                                      const void *fdt, int target)
+{
+       struct fdt_region *reg;
+       int num;
+
+       target += fdt_off_dt_struct(fdt);
+       for (reg = info->region, num = 0; num < info->count; reg++, num++) {
+               if (target >= reg->offset && target < reg->offset + reg->size)
+                       return 1;
+       }
+
+       return 0;
+}
+
+int fdt_add_alias_regions(const void *fdt, struct fdt_region *region, int count,
+                         int max_regions, struct fdt_region_state *info)
+{
+       int base = fdt_off_dt_struct(fdt);
+       int node, node_end, offset;
+       int did_alias_header;
+
+       node = fdt_subnode_offset(fdt, 0, "aliases");
+       if (node < 0)
+               return -FDT_ERR_NOTFOUND;
+
+       /* The aliases node must come before the others */
+       node_end = fdt_next_subnode(fdt, node);
+       if (node_end <= 0)
+               return -FDT_ERR_BADLAYOUT;
+       node_end -= sizeof(fdt32_t);
+
+       did_alias_header = 0;
+       info->region = region;
+       info->count = count;
+       info->can_merge = 0;
+       info->max_regions = max_regions;
+
+       for (offset = fdt_first_property_offset(fdt, node);
+            offset >= 0;
+            offset = fdt_next_property_offset(fdt, offset)) {
+               const struct fdt_property *prop;
+               const char *name;
+               int target, next;
+
+               prop = fdt_get_property_by_offset(fdt, offset, NULL);
+               name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
+               target = fdt_path_offset(fdt, name);
+               if (!region_list_contains_offset(info, fdt, target))
+                       continue;
+               next = fdt_next_property_offset(fdt, offset);
+               if (next < 0)
+                       next = node_end - sizeof(fdt32_t);
+
+               if (!did_alias_header) {
+                       fdt_add_region(info, base + node, 12);
+                       did_alias_header = 1;
+               }
+               fdt_add_region(info, base + offset, next - offset);
+       }
+
+       /* Add the 'end' tag */
+       if (did_alias_header)
+               fdt_add_region(info, base + node_end, sizeof(fdt32_t));
+
+       return info->count < max_regions ? info->count : -FDT_ERR_NOSPACE;
+}
+
+/**
+ * fdt_include_supernodes() - Include supernodes required by this node
+ *
+ * When we decided to include a node or property which is not at the top
+ * level, this function forces the inclusion of higher level nodes. For
+ * example, given this tree:
+ *
+ * / {
+ *     testing {
+ *     }
+ * }
+ *
+ * If we decide to include testing then we need the root node to have a valid
+ * tree. This function adds those regions.
+ *
+ * @info: State information
+ * @depth: Current stack depth
+ */
+static int fdt_include_supernodes(struct fdt_region_state *info, int depth)
+{
+       int base = fdt_off_dt_struct(info->fdt);
+       int start, stop_at;
+       int i;
+
+       /*
+        * Work down the stack looking for supernodes that we didn't include.
+        * The algortihm here is actually pretty simple, since we know that
+        * no previous subnode had to include these nodes, or if it did, we
+        * marked them as included (on the stack) already.
+        */
+       for (i = 0; i <= depth; i++) {
+               if (!info->stack[i].included) {
+                       start = info->stack[i].offset;
+
+                       /* Add the FDT_BEGIN_NODE tag of this supernode */
+                       fdt_next_tag(info->fdt, start, &stop_at);
+                       if (fdt_add_region(info, base + start, stop_at - start))
+                               return -1;
+
+                       /* Remember that this supernode is now included */
+                       info->stack[i].included = 1;
+                       info->can_merge = 1;
+               }
+
+               /* Force (later) generation of the FDT_END_NODE tag */
+               if (!info->stack[i].want)
+                       info->stack[i].want = WANT_NODES_ONLY;
+       }
+
+       return 0;
+}
+
+enum {
+       FDT_DONE_NOTHING,
+       FDT_DONE_MEM_RSVMAP,
+       FDT_DONE_STRUCT,
+       FDT_DONE_END,
+       FDT_DONE_STRINGS,
+       FDT_DONE_ALL,
+};
+
+int fdt_first_region(const void *fdt,
+               int (*h_include)(void *priv, const void *fdt, int offset,
+                                int type, const char *data, int size),
+               void *priv, struct fdt_region *region,
+               char *path, int path_len, int flags,
+               struct fdt_region_state *info)
+{
+       struct fdt_region_ptrs *p = &info->ptrs;
+
+       /* Set up our state */
+       info->fdt = fdt;
+       info->can_merge = 1;
+       info->max_regions = 1;
+       info->start = -1;
+       p->want = WANT_NOTHING;
+       p->end = path;
+       *p->end = '\0';
+       p->nextoffset = 0;
+       p->depth = -1;
+       p->done = FDT_DONE_NOTHING;
+
+       return fdt_next_region(fdt, h_include, priv, region,
+                              path, path_len, flags, info);
+}
+
+/*
+ * Theory of operation
+ *
+ *
+ *
+
+Note: in this description 'included' means that a node (or other part of
+the tree) should be included in the region list, i.e. it will have a region
+which covers its part of the tree.
+
+This function maintains some state from the last time it is called. It
+checks the next part of the tree that it is supposed to look at
+(p.nextoffset) to see if that should be included or not. When it finds
+something to include, it sets info->start to its offset. This marks the
+start of the region we want to include.
+
+Once info->start is set to the start (i.e. not -1), we continue scanning
+until we find something that we don't want included. This will be the end
+of a region. At this point we can close off the region and add it to the
+list. So we do so, and reset info->start to -1.
+
+One complication here is that we want to merge regions. So when we come to
+add another region later, we may in fact merge it with the previous one if
+one ends where the other starts.
+
+The function fdt_add_region() will return -1 if it fails to add the region,
+because we already have a region ready to be returned, and the new one
+cannot be merged in with it. In this case, we must return the region we
+found, and wait for another call to this function. When it comes, we will
+repeat the processing of the tag and again try to add a region. This time it
+will succeed.
+
+The current state of the pointers (stack, offset, etc.) is maintained in
+a ptrs member. At the start of every loop iteration we make a copy of it.
+The copy is then updated as the tag is processed. Only if we get to the end
+of the loop iteration (and successfully call fdt_add_region() if we need
+to) can we commit the changes we have made to these pointers. For example,
+if we see an FDT_END_NODE tag we will decrement the depth value. But if we
+need to add a region for this tag (let's say because the previous tag is
+included and this FDT_END_NODE tag is not included) then we will only commit
+the result if we were able to add the region. That allows us to retry again
+next time.
+
+We keep track of a variable called 'want' which tells us what we want to
+include when there is no specific information provided by the h_include
+function for a particular property. This basically handles the inclusion of
+properties which are pulled in by virtue of the node they are in. So if you
+include a node, its properties are also included. In this case 'want' will
+be WANT_NODES_AND_PROPS. The FDT_REG_DIRECT_SUBNODES feature also makes use
+of 'want'. While we are inside the subnode, 'want' will be set to
+WANT_NODES_ONLY, so that only the subnode's FDT_BEGIN_NODE and FDT_END_NODE
+tags will be included, and properties will be skipped. If WANT_NOTHING is
+selected, then we will just rely on what the h_include() function tells us.
+
+Using 'want' we work out 'include', which tells us whether this current tag
+should be included or not. As you can imagine, if the value of 'include'
+changes, that means we are on a boundary between nodes to include and nodes
+to exclude. At this point we either close off a previous region and add it
+to the list, or mark the start of a new region.
+
+Apart from the nodes, we have mem_rsvmap, the FDT_END tag and the string
+list. Each of these dealt with as a whole (i.e. we create a region for each
+if it is to be included). For mem_rsvmap we don't allow it to merge with
+the first struct region. For the stringlist we don't allow it to merge with
+the last struct region (which contains at minimum the FDT_END tag).
+*/
+int fdt_next_region(const void *fdt,
+               int (*h_include)(void *priv, const void *fdt, int offset,
+                                int type, const char *data, int size),
+               void *priv, struct fdt_region *region,
+               char *path, int path_len, int flags,
+               struct fdt_region_state *info)
+{
+       int base = fdt_off_dt_struct(fdt);
+       int last_node = 0;
+       const char *str;
+
+       info->region = region;
+       info->count = 0;
+       if (info->ptrs.done < FDT_DONE_MEM_RSVMAP &&
+           (flags & FDT_REG_ADD_MEM_RSVMAP)) {
+               /* Add the memory reserve map into its own region */
+               if (fdt_add_region(info, fdt_off_mem_rsvmap(fdt),
+                                  fdt_off_dt_struct(fdt) -
+                                  fdt_off_mem_rsvmap(fdt)))
+                       return 0;
+               info->can_merge = 0;    /* Don't allow merging with this */
+               info->ptrs.done = FDT_DONE_MEM_RSVMAP;
+       }
+
+       /*
+        * Work through the tags one by one, deciding whether each needs to
+        * be included or not. We set the variable 'include' to indicate our
+        * decision. 'want' is used to track what we want to include - it
+        * allows us to pick up all the properties (and/or subnode tags) of
+        * a node.
+        */
+       while (info->ptrs.done < FDT_DONE_STRUCT) {
+               const struct fdt_property *prop;
+               struct fdt_region_ptrs p;
+               const char *name;
+               int include = 0;
+               int stop_at = 0;
+               uint32_t tag;
+               int offset;
+               int val;
+               int len;
+
+               /*
+                * Make a copy of our pointers. If we make it to the end of
+                * this block then we will commit them back to info->ptrs.
+                * Otherwise we can try again from the same starting state
+                * next time we are called.
+                */
+               p = info->ptrs;
+
+               /*
+                * Find the tag, and the offset of the next one. If we need to
+                * stop including tags, then by default we stop *after*
+                * including the current tag
+                */
+               offset = p.nextoffset;
+               tag = fdt_next_tag(fdt, offset, &p.nextoffset);
+               stop_at = p.nextoffset;
+
+               switch (tag) {
+               case FDT_PROP:
+                       stop_at = offset;
+                       prop = fdt_get_property_by_offset(fdt, offset, NULL);
+                       str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
+                       val = h_include(priv, fdt, last_node, FDT_IS_PROP, str,
+                                           strlen(str) + 1);
+                       if (val == -1) {
+                               include = p.want >= WANT_NODES_AND_PROPS;
+                       } else {
+                               include = val;
+                               /*
+                                * Make sure we include the } for this block.
+                                * It might be more correct to have this done
+                                * by the call to fdt_include_supernodes() in
+                                * the case where it adds the node we are
+                                * currently in, but this is equivalent.
+                                */
+                               if ((flags & FDT_REG_SUPERNODES) && val &&
+                                   !p.want)
+                                       p.want = WANT_NODES_ONLY;
+                       }
+
+                       /* Value grepping is not yet supported */
+                       break;
+
+               case FDT_NOP:
+                       include = p.want >= WANT_NODES_AND_PROPS;
+                       stop_at = offset;
+                       break;
+
+               case FDT_BEGIN_NODE:
+                       last_node = offset;
+                       p.depth++;
+                       if (p.depth == FDT_MAX_DEPTH)
+                               return -FDT_ERR_TOODEEP;
+                       name = fdt_get_name(fdt, offset, &len);
+                       if (p.end - path + 2 + len >= path_len)
+                               return -FDT_ERR_NOSPACE;
+
+                       /* Build the full path of this node */
+                       if (p.end != path + 1)
+                               *p.end++ = '/';
+                       strcpy(p.end, name);
+                       p.end += len;
+                       info->stack[p.depth].want = p.want;
+                       info->stack[p.depth].offset = offset;
+
+                       /*
+                        * If we are not intending to include this node unless
+                        * it matches, make sure we stop *before* its tag.
+                        */
+                       if (p.want == WANT_NODES_ONLY ||
+                           !(flags & (FDT_REG_DIRECT_SUBNODES |
+                                      FDT_REG_ALL_SUBNODES))) {
+                               stop_at = offset;
+                               p.want = WANT_NOTHING;
+                       }
+                       val = h_include(priv, fdt, offset, FDT_IS_NODE, path,
+                                       p.end - path + 1);
+
+                       /* Include this if requested */
+                       if (val) {
+                               p.want = (flags & FDT_REG_ALL_SUBNODES) ?
+                                       WANT_ALL_NODES_AND_PROPS :
+                                       WANT_NODES_AND_PROPS;
+                       }
+
+                       /* If not requested, decay our 'p.want' value */
+                       else if (p.want) {
+                               if (p.want != WANT_ALL_NODES_AND_PROPS)
+                                       p.want--;
+
+                       /* Not including this tag, so stop now */
+                       } else {
+                               stop_at = offset;
+                       }
+
+                       /*
+                        * Decide whether to include this tag, and update our
+                        * stack with the state for this node
+                        */
+                       include = p.want;
+                       info->stack[p.depth].included = include;
+                       break;
+
+               case FDT_END_NODE:
+                       include = p.want;
+                       if (p.depth < 0)
+                               return -FDT_ERR_BADSTRUCTURE;
+
+                       /*
+                        * If we don't want this node, stop right away, unless
+                        * we are including subnodes
+                        */
+                       if (!p.want && !(flags & FDT_REG_DIRECT_SUBNODES))
+                               stop_at = offset;
+                       p.want = info->stack[p.depth].want;
+                       p.depth--;
+                       while (p.end > path && *--p.end != '/')
+                               ;
+                       *p.end = '\0';
+                       break;
+
+               case FDT_END:
+                       /* We always include the end tag */
+                       include = 1;
+                       p.done = FDT_DONE_STRUCT;
+                       break;
+               }
+
+               /* If this tag is to be included, mark it as region start */
+               if (include && info->start == -1) {
+                       /* Include any supernodes required by this one */
+                       if (flags & FDT_REG_SUPERNODES) {
+                               if (fdt_include_supernodes(info, p.depth))
+                                       return 0;
+                       }
+                       info->start = offset;
+               }
+
+               /*
+                * If this tag is not to be included, finish up the current
+                * region.
+                */
+               if (!include && info->start != -1) {
+                       if (fdt_add_region(info, base + info->start,
+                                          stop_at - info->start))
+                               return 0;
+                       info->start = -1;
+                       info->can_merge = 1;
+               }
+
+               /* If we have made it this far, we can commit our pointers */
+               info->ptrs = p;
+       }
+
+       /* Add a region for the END tag and a separate one for string table */
+       if (info->ptrs.done < FDT_DONE_END) {
+               if (info->ptrs.nextoffset != fdt_size_dt_struct(fdt))
+                       return -FDT_ERR_BADSTRUCTURE;
+
+               if (fdt_add_region(info, base + info->start,
+                                  info->ptrs.nextoffset - info->start))
+                       return 0;
+               info->ptrs.done++;
+       }
+       if (info->ptrs.done < FDT_DONE_STRINGS) {
+               if (flags & FDT_REG_ADD_STRING_TAB) {
+                       info->can_merge = 0;
+                       if (fdt_off_dt_strings(fdt) <
+                           base + info->ptrs.nextoffset)
+                               return -FDT_ERR_BADLAYOUT;
+                       if (fdt_add_region(info, fdt_off_dt_strings(fdt),
+                                          fdt_size_dt_strings(fdt)))
+                               return 0;
+               }
+               info->ptrs.done++;
+       }
+
+       return info->count > 0 ? 0 : -FDT_ERR_NOTFOUND;
+}
index bec8b8ad891846e5240c476cf3b15e34eb3f66e8..1a358a8ca0a6f59e8652a8d92fd712d53bf96408 100644 (file)
@@ -449,3 +449,35 @@ int fdt_pack(void *fdt)
 
        return 0;
 }
+
+int fdt_remove_unused_strings(const void *old, void *new)
+{
+       const struct fdt_property *old_prop;
+       struct fdt_property *new_prop;
+       int size = fdt_totalsize(old);
+       int next_offset, offset;
+       const char *str;
+       int ret;
+       int tag = FDT_PROP;
+
+       /* Make a copy and remove the strings */
+       memcpy(new, old, size);
+       fdt_set_size_dt_strings(new, 0);
+
+       /* Add every property name back into the new string table */
+       for (offset = 0; tag != FDT_END; offset = next_offset) {
+               tag = fdt_next_tag(old, offset, &next_offset);
+               if (tag != FDT_PROP)
+                       continue;
+               old_prop = fdt_get_property_by_offset(old, offset, NULL);
+               new_prop = (struct fdt_property *)(unsigned long)
+                       fdt_get_property_by_offset(new, offset, NULL);
+               str = fdt_string(old, fdt32_to_cpu(old_prop->nameoff));
+               ret = _fdt_find_add_string(new, str);
+               if (ret < 0)
+                       return ret;
+               new_prop->nameoff = cpu_to_fdt32(ret);
+       }
+
+       return 0;
+}
index a3d4675f7ed98cc2d7c05cb460138717abf7c470..a936a7eac21437fd4ac0d24d32b71e418345ac03 100644 (file)
@@ -16,19 +16,13 @@ unsigned long copy_from_user(void *dest, const void *src,
 
 void *kmalloc(size_t size, int flags)
 {
-       return memalign(ARCH_DMA_MINALIGN, size);
-}
+       void *p;
 
-void *kzalloc(size_t size, int flags)
-{
-       void *ptr = kmalloc(size, flags);
-       memset(ptr, 0, size);
-       return ptr;
-}
+       p = memalign(ARCH_DMA_MINALIGN, size);
+       if (flags & __GFP_ZERO)
+               memset(p, 0, size);
 
-void *vzalloc(unsigned long size)
-{
-       return kzalloc(size, 0);
+       return p;
 }
 
 struct kmem_cache *get_mem(int element_sz)
diff --git a/lib/rc4.c b/lib/rc4.c
new file mode 100644 (file)
index 0000000..89d15f3
--- /dev/null
+++ b/lib/rc4.c
@@ -0,0 +1,49 @@
+/*
+ * (C) Copyright 2015 Google, Inc
+ *
+ * (C) Copyright 2008-2014 Rockchip Electronics
+ *
+ * Rivest Cipher 4 (RC4) implementation
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef USE_HOSTCC
+#include <common.h>
+#endif
+#include <rc4.h>
+
+void rc4_encode(unsigned char *buf, unsigned int len, unsigned char key[16])
+{
+       unsigned char s[256], k[256], temp;
+       unsigned short i, j, t;
+       int ptr;
+
+       j = 0;
+       for (i = 0; i < 256; i++) {
+               s[i] = (unsigned char)i;
+               j &= 0x0f;
+               k[i] = key[j];
+               j++;
+       }
+
+       j = 0;
+       for (i = 0; i < 256; i++) {
+               j = (j + s[i] + k[i]) % 256;
+               temp = s[i];
+               s[i] = s[j];
+               s[j] = temp;
+       }
+
+       i = 0;
+       j = 0;
+       for (ptr = 0; ptr < len; ptr++) {
+               i = (i + 1) % 256;
+               j = (j + s[i]) % 256;
+               temp = s[i];
+               s[i] = s[j];
+               s[j] = temp;
+               t = (s[i] + (s[j] % 256)) % 256;
+               buf[ptr] = buf[ptr] ^ s[t];
+       }
+}
index a9b8a3ae67fa0817deefa3f1d5d559b97056eeb7..4c82837cc41e8e55899d945e8f27d399a0b0be71 100644 (file)
@@ -166,6 +166,25 @@ unsigned long long simple_strtoull(const char *cp, char **endp,
        return result;
 }
 
+long trailing_strtoln(const char *str, const char *end)
+{
+       const char *p;
+
+       if (!end)
+               end = str + strlen(str);
+       for (p = end - 1; p > str; p--) {
+               if (!isdigit(*p))
+                       return simple_strtoul(p + 1, NULL, 10);
+       }
+
+       return -1;
+}
+
+long trailing_strtol(const char *str)
+{
+       return trailing_strtoln(str, NULL);
+}
+
 /* we use this so that we can do without the ctype library */
 #define is_digit(c)    ((c) >= '0' && (c) <= '9')
 
index 953b7310bd5cf66362bf04534a552b08eaa3c830..d3ec8d64d596d3a8e51336617b8de0032c87812b 100644 (file)
--- a/net/eth.c
+++ b/net/eth.c
@@ -287,7 +287,13 @@ static int eth_write_hwaddr(struct udevice *dev)
                        return -EINVAL;
                }
 
+               /*
+                * Drivers are allowed to decide not to implement this at
+                * run-time. E.g. Some devices may use it and some may not.
+                */
                ret = eth_get_ops(dev)->write_hwaddr(dev);
+               if (ret == -ENOSYS)
+                       ret = 0;
                if (ret)
                        printf("\nWarning: %s failed to set MAC address\n",
                               dev->name);
@@ -404,6 +410,7 @@ int eth_rx(void)
 {
        struct udevice *current;
        uchar *packet;
+       int flags;
        int ret;
        int i;
 
@@ -415,8 +422,10 @@ int eth_rx(void)
                return -EINVAL;
 
        /* Process up to 32 packets at one time */
+       flags = ETH_RECV_CHECK_DEVICE;
        for (i = 0; i < 32; i++) {
-               ret = eth_get_ops(current)->recv(current, &packet);
+               ret = eth_get_ops(current)->recv(current, flags, &packet);
+               flags = 0;
                if (ret > 0)
                        net_process_received_packet(packet, ret);
                if (ret >= 0 && eth_get_ops(current)->free_pkt)
index 481ee5ea02b25c518a86a37a976abe143e4217b5..b1047b5d09ffc74c67c3c4df44627383e3f55b6f 100644 (file)
@@ -54,6 +54,7 @@ libs-$(HAVE_VENDOR_COMMON_LIB) += board/$(VENDOR)/common/
 libs-$(CONFIG_SPL_FRAMEWORK) += common/spl/
 libs-$(CONFIG_SPL_LIBCOMMON_SUPPORT) += common/
 libs-$(CONFIG_SPL_LIBDISK_SUPPORT) += disk/
+libs-$(CONFIG_SPL_CLK_SUPPORT) += drivers/clk/
 libs-$(CONFIG_SPL_DM) += drivers/core/
 libs-$(CONFIG_SPL_I2C_SUPPORT) += drivers/i2c/
 libs-$(CONFIG_SPL_GPIO_SUPPORT) += drivers/gpio/
@@ -65,8 +66,10 @@ libs-$(CONFIG_SPL_SERIAL_SUPPORT) += drivers/serial/
 libs-$(CONFIG_SPL_SPI_FLASH_SUPPORT) += drivers/mtd/spi/
 libs-$(CONFIG_SPL_SPI_SUPPORT) += drivers/spi/
 libs-y += fs/
+libs-$(CONFIG_SPL_LED_SUPPORT) += drivers/led/
 libs-$(CONFIG_SPL_LIBGENERIC_SUPPORT) += lib/
 libs-$(CONFIG_SPL_POWER_SUPPORT) += drivers/power/ drivers/power/pmic/
+libs-$(CONFIG_SPL_POWER_SUPPORT) += drivers/power/regulator/
 libs-$(CONFIG_SPL_MTD_SUPPORT) += drivers/mtd/
 libs-$(CONFIG_SPL_NAND_SUPPORT) += drivers/mtd/nand/
 libs-$(CONFIG_SPL_DRIVERS_MISC_SUPPORT) += drivers/misc/
@@ -77,6 +80,7 @@ libs-$(CONFIG_SPL_NET_SUPPORT) += net/
 libs-$(CONFIG_SPL_ETH_SUPPORT) += drivers/net/
 libs-$(CONFIG_SPL_ETH_SUPPORT) += drivers/net/phy/
 libs-$(CONFIG_SPL_USBETH_SUPPORT) += drivers/net/phy/
+libs-$(CONFIG_SPL_RAM_SUPPORT) += drivers/ram/
 libs-$(CONFIG_SPL_MUSB_NEW_SUPPORT) += drivers/usb/musb-new/
 libs-$(CONFIG_SPL_USBETH_SUPPORT) += drivers/usb/gadget/
 libs-$(CONFIG_SPL_WATCHDOG_SUPPORT) += drivers/watchdog/
@@ -152,6 +156,8 @@ boot.bin: $(obj)/u-boot-spl.bin
 
 ALL-y  += $(obj)/$(SPL_BIN).bin $(obj)/$(SPL_BIN).cfg
 
+ALL-$(CONFIG_OF_SEPARATE) += $(obj)/$(SPL_BIN)-pad.bin $(obj)/$(SPL_BIN)-dtb.bin
+
 ifdef CONFIG_SAMSUNG
 ALL-y  += $(obj)/$(BOARD)-spl.bin
 endif
@@ -166,6 +172,32 @@ endif
 
 all:   $(ALL-y)
 
+quiet_cmd_cat = CAT     $@
+cmd_cat = cat $(filter-out $(PHONY), $^) > $@
+
+$(obj)/$(SPL_BIN)-dtb.bin: $(obj)/$(SPL_BIN).bin $(obj)/$(SPL_BIN)-pad.bin \
+               $(obj)/$(SPL_BIN).dtb FORCE
+       $(call if_changed,cat)
+
+# Create a file that pads from the end of u-boot-spl.bin to bss_end
+$(obj)/$(SPL_BIN)-pad.bin: $(obj)/$(SPL_BIN)
+       @bss_size_str=$(shell $(NM) $< | awk 'BEGIN {size = 0} /__bss_size/ {size = $$1} END {print "ibase=16; " toupper(size)}' | bc); \
+       dd if=/dev/zero of=$@ bs=1 count=$${bss_size_str} 2>/dev/null;
+
+# Pass the original device tree file through fdtgrep twice. The first pass
+# removes any unwanted nodes (i.e. those which don't have the
+# 'u-boot,dm-pre-reloc' property and thus are not needed by SPL. The second
+# pass removes various unused properties from the remaining nodes.
+# The output is typically a much smaller device tree file.
+quiet_cmd_fdtgrep = FDTGREP $@
+      cmd_fdtgrep = $(objtree)/tools/fdtgrep -b u-boot,dm-pre-reloc -RT $< \
+               -n /chosen -O dtb | \
+       $(objtree)/tools/fdtgrep -r -O dtb - -o $@ \
+               $(addprefix -P ,$(subst $\",,$(CONFIG_OF_SPL_REMOVE_PROPS)))
+
+$(obj)/$(SPL_BIN).dtb: dts/dt.dtb
+       $(call cmd,fdtgrep)
+
 quiet_cmd_cpp_cfg = CFG     $@
 cmd_cpp_cfg = $(CPP) -Wp,-MD,$(depfile) $(cpp_flags) $(LDPPFLAGS) -ansi \
        -DDO_DEPS_ONLY -D__ASSEMBLY__ -x assembler-with-cpp -P -dM -E -o $@ $<
index 19ad2fb99f660ec25c622d4447d44f1b07adf039..eda964318593918930fd8a90dd7d31875455e470 100644 (file)
@@ -15,13 +15,20 @@ obj-$(CONFIG_UT_DM) += test-uclass.o
 # subsystem you must add sandbox tests here.
 obj-$(CONFIG_UT_DM) += core.o
 ifneq ($(CONFIG_SANDBOX),)
+obj-$(CONFIG_CLK) += clk.o
 obj-$(CONFIG_DM_ETH) += eth.o
 obj-$(CONFIG_DM_GPIO) += gpio.o
 obj-$(CONFIG_DM_I2C) += i2c.o
+obj-$(CONFIG_LED) += led.o
+obj-$(CONFIG_DM_MMC) += mmc.o
 obj-$(CONFIG_DM_PCI) += pci.o
+obj-$(CONFIG_RAM) += ram.o
+obj-y += regmap.o
+obj-$(CONFIG_RESET) += reset.o
 obj-$(CONFIG_DM_RTC) += rtc.o
 obj-$(CONFIG_DM_SPI_FLASH) += sf.o
 obj-$(CONFIG_DM_SPI) += spi.o
+obj-y += syscon.o
 obj-$(CONFIG_DM_USB) += usb.o
 obj-$(CONFIG_DM_PMIC) += pmic.o
 obj-$(CONFIG_DM_REGULATOR) += regulator.o
diff --git a/test/dm/clk.c b/test/dm/clk.c
new file mode 100644 (file)
index 0000000..9ff6d95
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <asm/test.h>
+#include <dm/test.h>
+#include <linux/err.h>
+#include <test/ut.h>
+
+/* Test that we can find and adjust clocks */
+static int dm_test_clk_base(struct unit_test_state *uts)
+{
+       struct udevice *clk;
+       ulong rate;
+
+       ut_assertok(uclass_get_device(UCLASS_CLK, 0, &clk));
+       rate = clk_get_rate(clk);
+       ut_asserteq(SANDBOX_CLK_RATE, rate);
+       ut_asserteq(-EINVAL, clk_set_rate(clk, 0));
+       ut_assertok(clk_set_rate(clk, rate * 2));
+       ut_asserteq(SANDBOX_CLK_RATE * 2, clk_get_rate(clk));
+
+       return 0;
+}
+DM_TEST(dm_test_clk_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test that peripheral clocks work as expected */
+static int dm_test_clk_periph(struct unit_test_state *uts)
+{
+       struct udevice *clk;
+       ulong rate;
+
+       ut_assertok(uclass_get_device(UCLASS_CLK, 0, &clk));
+       rate = clk_set_periph_rate(clk, PERIPH_ID_COUNT, 123);
+       ut_asserteq(-EINVAL, rate);
+       ut_asserteq(1, IS_ERR_VALUE(rate));
+
+       rate = clk_set_periph_rate(clk, PERIPH_ID_SPI, 123);
+       ut_asserteq(0, rate);
+       ut_asserteq(123, clk_get_periph_rate(clk, PERIPH_ID_SPI));
+
+       rate = clk_set_periph_rate(clk, PERIPH_ID_SPI, 1234);
+       ut_asserteq(123, rate);
+
+       rate = clk_set_periph_rate(clk, PERIPH_ID_I2C, 567);
+
+       rate = clk_set_periph_rate(clk, PERIPH_ID_SPI, 1234);
+       ut_asserteq(1234, rate);
+
+       ut_asserteq(567, clk_get_periph_rate(clk, PERIPH_ID_I2C));
+
+       return 0;
+}
+DM_TEST(dm_test_clk_periph, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
index 5bb2a99c8f0b5f207e61aea6ae990b2902eff524..5c501ec2541b85756b59f8038dd0f89c5c2add0c 100644 (file)
 #include <errno.h>
 #include <asm/io.h>
 #include <dm/root.h>
-#include <dm/uclass-internal.h>
-
-static void show_devices(struct udevice *dev, int depth, int last_flag)
-{
-       int i, is_last;
-       struct udevice *child;
-       char class_name[12];
-
-       /* print the first 11 characters to not break the tree-format. */
-       strlcpy(class_name, dev->uclass->uc_drv->name, sizeof(class_name));
-       printf(" %-11s [ %c ]    ", class_name,
-              dev->flags & DM_FLAG_ACTIVATED ? '+' : ' ');
-
-       for (i = depth; i >= 0; i--) {
-               is_last = (last_flag >> i) & 1;
-               if (i) {
-                       if (is_last)
-                               printf("    ");
-                       else
-                               printf("|   ");
-               } else {
-                       if (is_last)
-                               printf("`-- ");
-                       else
-                               printf("|-- ");
-               }
-       }
-
-       printf("%s\n", dev->name);
-
-       list_for_each_entry(child, &dev->child_head, sibling_node) {
-               is_last = list_is_last(&child->sibling_node, &dev->child_head);
-               show_devices(child, depth + 1, (last_flag << 1) | is_last);
-       }
-}
+#include <dm/util.h>
 
 static int do_dm_dump_all(cmd_tbl_t *cmdtp, int flag, int argc,
                          char * const argv[])
 {
-       struct udevice *root;
-
-       root = dm_root();
-       if (root) {
-               printf(" Class       Probed   Name\n");
-               printf("----------------------------------------\n");
-               show_devices(root, -1, 0);
-       }
+       dm_dump_all();
 
        return 0;
 }
 
-/**
- * dm_display_line() - Display information about a single device
- *
- * Displays a single line of information with an option prefix
- *
- * @dev:       Device to display
- */
-static void dm_display_line(struct udevice *dev)
-{
-       printf("- %c %s @ %08lx",
-              dev->flags & DM_FLAG_ACTIVATED ? '*' : ' ',
-              dev->name, (ulong)map_to_sysmem(dev));
-       if (dev->seq != -1 || dev->req_seq != -1)
-               printf(", seq %d, (req %d)", dev->seq, dev->req_seq);
-       puts("\n");
-}
-
 static int do_dm_dump_uclass(cmd_tbl_t *cmdtp, int flag, int argc,
                             char * const argv[])
 {
-       struct uclass *uc;
-       int ret;
-       int id;
-
-       for (id = 0; id < UCLASS_COUNT; id++) {
-               struct udevice *dev;
-
-               ret = uclass_get(id, &uc);
-               if (ret)
-                       continue;
-
-               printf("uclass %d: %s\n", id, uc->uc_drv->name);
-               if (list_empty(&uc->dev_head))
-                       continue;
-               list_for_each_entry(dev, &uc->dev_head, uclass_node) {
-                       dm_display_line(dev);
-               }
-               puts("\n");
-       }
+       dm_dump_uclass();
 
        return 0;
 }
diff --git a/test/dm/led.c b/test/dm/led.c
new file mode 100644 (file)
index 0000000..8ee075c
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <led.h>
+#include <asm/gpio.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Base test of the led uclass */
+static int dm_test_led_base(struct unit_test_state *uts)
+{
+       struct udevice *dev;
+
+       /* Get the top-level device */
+       ut_assertok(uclass_get_device(UCLASS_LED, 0, &dev));
+       ut_assertok(uclass_get_device(UCLASS_LED, 1, &dev));
+       ut_assertok(uclass_get_device(UCLASS_LED, 2, &dev));
+       ut_asserteq(-ENODEV, uclass_get_device(UCLASS_LED, 3, &dev));
+
+       return 0;
+}
+DM_TEST(dm_test_led_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test of the led uclass using the led_gpio driver */
+static int dm_test_led_gpio(struct unit_test_state *uts)
+{
+       const int offset = 1;
+       struct udevice *dev, *gpio;
+
+       /*
+        * Check that we can manipulate an LED. LED 1 is connected to GPIO
+        * bank gpio_a, offset 1.
+        */
+       ut_assertok(uclass_get_device(UCLASS_LED, 1, &dev));
+       ut_assertok(uclass_get_device(UCLASS_GPIO, 1, &gpio));
+       ut_asserteq(0, sandbox_gpio_get_value(gpio, offset));
+       led_set_on(dev, 1);
+       ut_asserteq(1, sandbox_gpio_get_value(gpio, offset));
+       led_set_on(dev, 0);
+       ut_asserteq(0, sandbox_gpio_get_value(gpio, offset));
+
+       return 0;
+}
+DM_TEST(dm_test_led_gpio, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test obtaining an LED by label */
+static int dm_test_led_label(struct unit_test_state *uts)
+{
+       struct udevice *dev, *cmp;
+
+       ut_assertok(led_get_by_label("sandbox:red", &dev));
+       ut_asserteq(1, device_active(dev));
+       ut_assertok(uclass_get_device(UCLASS_LED, 1, &cmp));
+       ut_asserteq_ptr(dev, cmp);
+
+       ut_assertok(led_get_by_label("sandbox:green", &dev));
+       ut_asserteq(1, device_active(dev));
+       ut_assertok(uclass_get_device(UCLASS_LED, 2, &cmp));
+       ut_asserteq_ptr(dev, cmp);
+
+       ut_asserteq(-ENODEV, led_get_by_label("sandbox:blue", &dev));
+
+       return 0;
+}
+DM_TEST(dm_test_led_label, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/mmc.c b/test/dm/mmc.c
new file mode 100644 (file)
index 0000000..0461423
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <mmc.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Basic test of the mmc uclass. We could expand this by implementing an MMC
+ * stack for sandbox, or at least implementing the basic operation.
+ */
+static int dm_test_mmc_base(struct unit_test_state *uts)
+{
+       struct udevice *dev;
+
+       ut_assertok(uclass_get_device(UCLASS_MMC, 0, &dev));
+
+       return 0;
+}
+DM_TEST(dm_test_mmc_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/ram.c b/test/dm/ram.c
new file mode 100644 (file)
index 0000000..3a7c5ff
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <ram.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Basic test of the ram uclass */
+static int dm_test_ram_base(struct unit_test_state *uts)
+{
+       struct udevice *dev;
+       struct ram_info info;
+
+       ut_assertok(uclass_get_device(UCLASS_RAM, 0, &dev));
+       ut_assertok(ram_get_info(dev, &info));
+       ut_asserteq(0, info.base);
+       ut_asserteq(gd->ram_size, info.size);
+
+       return 0;
+}
+DM_TEST(dm_test_ram_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/regmap.c b/test/dm/regmap.c
new file mode 100644 (file)
index 0000000..7f66058
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+2 *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <mapmem.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <asm/test.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Base test of register maps */
+static int dm_test_regmap_base(struct unit_test_state *uts)
+{
+       struct udevice *dev;
+       struct regmap *map;
+       int i;
+
+       ut_assertok(uclass_get_device(UCLASS_SYSCON, 0, &dev));
+       map = syscon_get_regmap(dev);
+       ut_assertok_ptr(map);
+       ut_asserteq(1, map->range_count);
+       ut_asserteq(0x10, map->base);
+       ut_asserteq(0x10, map->range->start);
+       ut_asserteq(4, map->range->size);
+       ut_asserteq_ptr(&map->base_range, map->range);
+       ut_asserteq(0x10, map_to_sysmem(regmap_get_range(map, 0)));
+
+       ut_assertok(uclass_get_device(UCLASS_SYSCON, 1, &dev));
+       map = syscon_get_regmap(dev);
+       ut_assertok_ptr(map);
+       ut_asserteq(4, map->range_count);
+       ut_asserteq(0x20, map->base);
+       ut_assert(&map->base_range != map->range);
+       for (i = 0; i < 4; i++) {
+               const unsigned long addr = 0x20 + 8 * i;
+
+               ut_asserteq(addr, map->range[i].start);
+               ut_asserteq(5 + i, map->range[i].size);
+               ut_asserteq(addr, map_to_sysmem(regmap_get_range(map, i)));
+       }
+
+       /* Check that we can't pretend a different device is a syscon */
+       ut_assertok(uclass_get_device(UCLASS_I2C, 0, &dev));
+       map = syscon_get_regmap(dev);
+       ut_asserteq_ptr(ERR_PTR(-ENOEXEC), map);
+
+       return 0;
+}
+DM_TEST(dm_test_regmap_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test we can access a regmap through syscon */
+static int dm_test_regmap_syscon(struct unit_test_state *uts)
+{
+       struct regmap *map;
+
+       map = syscon_get_regmap_by_driver_data(SYSCON0);
+       ut_assertok_ptr(map);
+       ut_asserteq(1, map->range_count);
+
+       map = syscon_get_regmap_by_driver_data(SYSCON1);
+       ut_assertok_ptr(map);
+       ut_asserteq(4, map->range_count);
+
+       map = syscon_get_regmap_by_driver_data(SYSCON_COUNT);
+       ut_asserteq_ptr(ERR_PTR(-ENODEV), map);
+
+       ut_asserteq(0x10, map_to_sysmem(syscon_get_first_range(SYSCON0)));
+       ut_asserteq(0x20, map_to_sysmem(syscon_get_first_range(SYSCON1)));
+       ut_asserteq_ptr(ERR_PTR(-ENODEV),
+                       syscon_get_first_range(SYSCON_COUNT));
+
+       return 0;
+}
+
+DM_TEST(dm_test_regmap_syscon, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
index d279c04c840c415352716c96c4cf02c69c0f4233..3d0056f2dc7bf13049d4d2c13e711bedf9aa8f77 100644 (file)
@@ -210,7 +210,7 @@ static int dm_test_power_regulator_autoset(struct unit_test_state *uts)
         * Expected output state: uV=1200000; uA=200000; output enabled
         */
        platname = regulator_names[BUCK1][PLATNAME];
-       ut_assertok(regulator_autoset(platname, &dev_autoset, false));
+       ut_assertok(regulator_autoset_by_name(platname, &dev_autoset));
 
        /* Check, that the returned device is proper */
        ut_assertok(regulator_get_by_platname(platname, &dev));
diff --git a/test/dm/reset.c b/test/dm/reset.c
new file mode 100644 (file)
index 0000000..5d53f25
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <reset.h>
+#include <asm/state.h>
+#include <asm/test.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+/* Test that we can use particular reset devices */
+static int dm_test_reset_base(struct unit_test_state *uts)
+{
+       struct sandbox_state *state = state_get_current();
+       struct udevice *dev;
+
+       /* Device 0 is the platform data device - it should never respond */
+       ut_assertok(uclass_get_device(UCLASS_RESET, 0, &dev));
+       ut_asserteq(-ENODEV, reset_request(dev, RESET_WARM));
+       ut_asserteq(-ENODEV, reset_request(dev, RESET_COLD));
+       ut_asserteq(-ENODEV, reset_request(dev, RESET_POWER));
+
+       /* Device 1 is the warm reset device */
+       ut_assertok(uclass_get_device(UCLASS_RESET, 1, &dev));
+       ut_asserteq(-EACCES, reset_request(dev, RESET_WARM));
+       ut_asserteq(-ENOSYS, reset_request(dev, RESET_COLD));
+       ut_asserteq(-ENOSYS, reset_request(dev, RESET_POWER));
+
+       state->reset_allowed[RESET_WARM] = true;
+       ut_asserteq(-EINPROGRESS, reset_request(dev, RESET_WARM));
+       state->reset_allowed[RESET_WARM] = false;
+
+       /* Device 2 is the cold reset device */
+       ut_assertok(uclass_get_device(UCLASS_RESET, 2, &dev));
+       ut_asserteq(-ENOSYS, reset_request(dev, RESET_WARM));
+       ut_asserteq(-EACCES, reset_request(dev, RESET_COLD));
+       state->reset_allowed[RESET_POWER] = false;
+       ut_asserteq(-EACCES, reset_request(dev, RESET_POWER));
+       state->reset_allowed[RESET_POWER] = true;
+
+       return 0;
+}
+DM_TEST(dm_test_reset_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test that we can walk through the reset devices */
+static int dm_test_reset_walk(struct unit_test_state *uts)
+{
+       struct sandbox_state *state = state_get_current();
+
+       /* If we generate a power reset, we will exit sandbox! */
+       state->reset_allowed[RESET_POWER] = false;
+       ut_asserteq(-EACCES, reset_walk(RESET_WARM));
+       ut_asserteq(-EACCES, reset_walk(RESET_COLD));
+       ut_asserteq(-EACCES, reset_walk(RESET_POWER));
+
+       /*
+        * Enable cold reset - this should make cold reset work, plus a warm
+        * reset should be promoted to cold, since this is the next step
+        * along.
+        */
+       state->reset_allowed[RESET_COLD] = true;
+       ut_asserteq(-EINPROGRESS, reset_walk(RESET_WARM));
+       ut_asserteq(-EINPROGRESS, reset_walk(RESET_COLD));
+       ut_asserteq(-EACCES, reset_walk(RESET_POWER));
+       state->reset_allowed[RESET_COLD] = false;
+       state->reset_allowed[RESET_POWER] = true;
+
+       return 0;
+}
+DM_TEST(dm_test_reset_walk, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/syscon.c b/test/dm/syscon.c
new file mode 100644 (file)
index 0000000..3642481
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <syscon.h>
+#include <asm/test.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Base test of system controllers */
+static int dm_test_syscon_base(struct unit_test_state *uts)
+{
+       struct udevice *dev;
+
+       ut_assertok(uclass_get_device(UCLASS_SYSCON, 0, &dev));
+       ut_asserteq(SYSCON0, dev->driver_data);
+
+       ut_assertok(uclass_get_device(UCLASS_SYSCON, 1, &dev));
+       ut_asserteq(SYSCON1, dev->driver_data);
+
+       ut_asserteq(-ENODEV, uclass_get_device(UCLASS_SYSCON, 2, &dev));
+
+       return 0;
+}
+DM_TEST(dm_test_syscon_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
index 0477d2fa735d423d880fcfc2da8042db38344f38..0e43ab95480485240fece43126d76941b2915f91 100644 (file)
@@ -76,6 +76,7 @@ static int dm_test_main(const char *test_name)
        struct unit_test_state *uts = &global_dm_test_state;
        uts->priv = &_global_priv_dm_test_state;
        struct unit_test *test;
+       int run_count;
 
        /*
         * If we have no device tree, or it only has a root node, then these
@@ -90,10 +91,17 @@ static int dm_test_main(const char *test_name)
        if (!test_name)
                printf("Running %d driver model tests\n", n_ents);
 
+       run_count = 0;
        for (test = tests; test < tests + n_ents; test++) {
-               if (test_name && strcmp(test_name, test->name))
+               const char *name = test->name;
+
+               /* All tests have this prefix */
+               if (!strncmp(name, "dm_test_", 8))
+                       name += 8;
+               if (test_name && strcmp(test_name, name))
                        continue;
                printf("Test: %s\n", test->name);
+               run_count++;
                ut_assertok(dm_test_init(uts));
 
                uts->start = mallinfo();
@@ -109,7 +117,10 @@ static int dm_test_main(const char *test_name)
                ut_assertok(dm_test_destroy(uts));
        }
 
-       printf("Failures: %d\n", uts->fail_count);
+       if (test_name && !run_count)
+               printf("Test '%s' not found\n", test_name);
+       else
+               printf("Failures: %d\n", uts->fail_count);
 
        gd->dm_root = NULL;
        ut_assertok(dm_init());
index 8ff9c2e1082335c41629aa294e8392b2075e3985..98414f736a75f3b33a8bc90fadcb6ea64f4b3dc4 100644 (file)
@@ -58,7 +58,8 @@ hostprogs-$(CONFIG_FIT_SIGNATURE) += fit_info fit_check_sign
 FIT_SIG_OBJS-$(CONFIG_FIT_SIGNATURE) := common/image-sig.o
 # Flattened device tree objects
 LIBFDT_OBJS := $(addprefix lib/libfdt/, \
-                       fdt.o fdt_ro.o fdt_rw.o fdt_strerror.o fdt_wip.o)
+                       fdt.o fdt_ro.o fdt_rw.o fdt_strerror.o fdt_wip.o \
+                       fdt_region.o)
 RSA_OBJS-$(CONFIG_FIT_SIGNATURE) := $(addprefix lib/rsa/, \
                                        rsa-sign.o rsa-verify.o rsa-checksum.o \
                                        rsa-mod-exp.o)
@@ -155,6 +156,9 @@ hostprogs-$(CONFIG_ARMADA_XP) += kwboot
 hostprogs-y += proftool
 hostprogs-$(CONFIG_STATIC_RELA) += relocate-rela
 
+hostprogs-y += fdtgrep
+fdtgrep-objs += $(LIBFDT_OBJS) fdtgrep.o
+
 # We build some files with extra pedantic flags to try to minimize things
 # that won't build on some weird host compiler -- though there are lots of
 # exceptions for files that aren't complaint.
diff --git a/tools/fdtgrep.c b/tools/fdtgrep.c
new file mode 100644 (file)
index 0000000..caaf600
--- /dev/null
@@ -0,0 +1,1234 @@
+/*
+ * Copyright (c) 2013, Google Inc.
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ *
+ * Perform a grep of an FDT either displaying the source subset or producing
+ * a new .dtb subset which can be used as required.
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <../include/libfdt.h>
+#include <libfdt_internal.h>
+
+/* Define DEBUG to get some debugging output on stderr */
+#ifdef DEBUG
+#define debug(a, b...) fprintf(stderr, a, ## b)
+#else
+#define debug(a, b...)
+#endif
+
+/* A linked list of values we are grepping for */
+struct value_node {
+       int type;               /* Types this value matches (FDT_IS... mask) */
+       int include;            /* 1 to include matches, 0 to exclude */
+       const char *string;     /* String to match */
+       struct value_node *next;        /* Pointer to next node, or NULL */
+};
+
+/* Output formats we support */
+enum output_t {
+       OUT_DTS,                /* Device tree source */
+       OUT_DTB,                /* Valid device tree binary */
+       OUT_BIN,                /* Fragment of .dtb, for hashing */
+};
+
+/* Holds information which controls our output and options */
+struct display_info {
+       enum output_t output;   /* Output format */
+       int add_aliases;        /* Add aliases node to output */
+       int all;                /* Display all properties/nodes */
+       int colour;             /* Display output in ANSI colour */
+       int region_list;        /* Output a region list */
+       int flags;              /* Flags (FDT_REG_...) */
+       int list_strings;       /* List strings in string table */
+       int show_offset;        /* Show offset */
+       int show_addr;          /* Show address */
+       int header;             /* Output an FDT header */
+       int diff;               /* Show +/- diff markers */
+       int include_root;       /* Include the root node and all properties */
+       int remove_strings;     /* Remove unused strings */
+       int show_dts_version;   /* Put '/dts-v1/;' on the first line */
+       int types_inc;          /* Mask of types that we include (FDT_IS...) */
+       int types_exc;          /* Mask of types that we exclude (FDT_IS...) */
+       int invert;             /* Invert polarity of match */
+       struct value_node *value_head;  /* List of values to match */
+       const char *output_fname;       /* Output filename */
+       FILE *fout;             /* File to write dts/dtb output */
+};
+
+static void report_error(const char *where, int err)
+{
+       fprintf(stderr, "Error at '%s': %s\n", where, fdt_strerror(err));
+}
+
+/* Supported ANSI colours */
+enum {
+       COL_BLACK,
+       COL_RED,
+       COL_GREEN,
+       COL_YELLOW,
+       COL_BLUE,
+       COL_MAGENTA,
+       COL_CYAN,
+       COL_WHITE,
+
+       COL_NONE = -1,
+};
+
+/**
+ * print_ansi_colour() - Print out the ANSI sequence for a colour
+ *
+ * @fout:      Output file
+ * @col:       Colour to output (COL_...), or COL_NONE to reset colour
+ */
+static void print_ansi_colour(FILE *fout, int col)
+{
+       if (col == COL_NONE)
+               fprintf(fout, "\033[0m");
+       else
+               fprintf(fout, "\033[1;%dm", col + 30);
+}
+
+
+/**
+ * value_add() - Add a new value to our list of things to grep for
+ *
+ * @disp:      Display structure, holding info about our options
+ * @headp:     Pointer to header pointer of list
+ * @type:      Type of this value (FDT_IS_...)
+ * @include:   1 if we want to include matches, 0 to exclude
+ * @str:       String value to match
+ */
+static int value_add(struct display_info *disp, struct value_node **headp,
+                    int type, int include, const char *str)
+{
+       struct value_node *node;
+
+       /*
+        * Keep track of which types we are excluding/including. We don't
+        * allow both including and excluding things, because it doesn't make
+        * sense. 'Including' means that everything not mentioned is
+        * excluded. 'Excluding' means that everything not mentioned is
+        * included. So using the two together would be meaningless.
+        */
+       if (include)
+               disp->types_inc |= type;
+       else
+               disp->types_exc |= type;
+       if (disp->types_inc & disp->types_exc & type) {
+               fprintf(stderr,
+                       "Cannot use both include and exclude for '%s'\n", str);
+               return -1;
+       }
+
+       str = strdup(str);
+       node = malloc(sizeof(*node));
+       if (!str || !node) {
+               fprintf(stderr, "Out of memory\n");
+               return -1;
+       }
+       node->next = *headp;
+       node->type = type;
+       node->include = include;
+       node->string = str;
+       *headp = node;
+
+       return 0;
+}
+
+static bool util_is_printable_string(const void *data, int len)
+{
+       const char *s = data;
+       const char *ss, *se;
+
+       /* zero length is not */
+       if (len == 0)
+               return 0;
+
+       /* must terminate with zero */
+       if (s[len - 1] != '\0')
+               return 0;
+
+       se = s + len;
+
+       while (s < se) {
+               ss = s;
+               while (s < se && *s && isprint((unsigned char)*s))
+                       s++;
+
+               /* not zero, or not done yet */
+               if (*s != '\0' || s == ss)
+                       return 0;
+
+               s++;
+       }
+
+       return 1;
+}
+
+static void utilfdt_print_data(const char *data, int len)
+{
+       int i;
+       const char *p = data;
+       const char *s;
+
+       /* no data, don't print */
+       if (len == 0)
+               return;
+
+       if (util_is_printable_string(data, len)) {
+               printf(" = ");
+
+               s = data;
+               do {
+                       printf("\"%s\"", s);
+                       s += strlen(s) + 1;
+                       if (s < data + len)
+                               printf(", ");
+               } while (s < data + len);
+
+       } else if ((len % 4) == 0) {
+               const uint32_t *cell = (const uint32_t *)data;
+
+               printf(" = <");
+               for (i = 0, len /= 4; i < len; i++)
+                       printf("0x%08x%s", fdt32_to_cpu(cell[i]),
+                              i < (len - 1) ? " " : "");
+               printf(">");
+       } else {
+               printf(" = [");
+               for (i = 0; i < len; i++)
+                       printf("%02x%s", *p++, i < len - 1 ? " " : "");
+               printf("]");
+       }
+}
+
+/**
+ * display_fdt_by_regions() - Display regions of an FDT source
+ *
+ * This dumps an FDT as source, but only certain regions of it. This is the
+ * final stage of the grep - we have a list of regions we want to display,
+ * and this function displays them.
+ *
+ * @disp:      Display structure, holding info about our options
+ * @blob:      FDT blob to display
+ * @region:    List of regions to display
+ * @count:     Number of regions
+ */
+static int display_fdt_by_regions(struct display_info *disp, const void *blob,
+               struct fdt_region region[], int count)
+{
+       struct fdt_region *reg = region, *reg_end = region + count;
+       uint32_t off_mem_rsvmap = fdt_off_mem_rsvmap(blob);
+       int base = fdt_off_dt_struct(blob);
+       int version = fdt_version(blob);
+       int offset, nextoffset;
+       int tag, depth, shift;
+       FILE *f = disp->fout;
+       uint64_t addr, size;
+       int in_region;
+       int file_ofs;
+       int i;
+
+       if (disp->show_dts_version)
+               fprintf(f, "/dts-v1/;\n");
+
+       if (disp->header) {
+               fprintf(f, "// magic:\t\t0x%x\n", fdt_magic(blob));
+               fprintf(f, "// totalsize:\t\t0x%x (%d)\n", fdt_totalsize(blob),
+                       fdt_totalsize(blob));
+               fprintf(f, "// off_dt_struct:\t0x%x\n",
+                       fdt_off_dt_struct(blob));
+               fprintf(f, "// off_dt_strings:\t0x%x\n",
+                       fdt_off_dt_strings(blob));
+               fprintf(f, "// off_mem_rsvmap:\t0x%x\n", off_mem_rsvmap);
+               fprintf(f, "// version:\t\t%d\n", version);
+               fprintf(f, "// last_comp_version:\t%d\n",
+                       fdt_last_comp_version(blob));
+               if (version >= 2) {
+                       fprintf(f, "// boot_cpuid_phys:\t0x%x\n",
+                               fdt_boot_cpuid_phys(blob));
+               }
+               if (version >= 3) {
+                       fprintf(f, "// size_dt_strings:\t0x%x\n",
+                               fdt_size_dt_strings(blob));
+               }
+               if (version >= 17) {
+                       fprintf(f, "// size_dt_struct:\t0x%x\n",
+                               fdt_size_dt_struct(blob));
+               }
+               fprintf(f, "\n");
+       }
+
+       if (disp->flags & FDT_REG_ADD_MEM_RSVMAP) {
+               const struct fdt_reserve_entry *p_rsvmap;
+
+               p_rsvmap = (const struct fdt_reserve_entry *)
+                               ((const char *)blob + off_mem_rsvmap);
+               for (i = 0; ; i++) {
+                       addr = fdt64_to_cpu(p_rsvmap[i].address);
+                       size = fdt64_to_cpu(p_rsvmap[i].size);
+                       if (addr == 0 && size == 0)
+                               break;
+
+                       fprintf(f, "/memreserve/ %llx %llx;\n",
+                               (unsigned long long)addr,
+                               (unsigned long long)size);
+               }
+       }
+
+       depth = 0;
+       nextoffset = 0;
+       shift = 4;      /* 4 spaces per indent */
+       do {
+               const struct fdt_property *prop;
+               const char *name;
+               int show;
+               int len;
+
+               offset = nextoffset;
+
+               /*
+                * Work out the file offset of this offset, and decide
+                * whether it is in the region list or not
+                */
+               file_ofs = base + offset;
+               if (reg < reg_end && file_ofs >= reg->offset + reg->size)
+                       reg++;
+               in_region = reg < reg_end && file_ofs >= reg->offset &&
+                               file_ofs < reg->offset + reg->size;
+               tag = fdt_next_tag(blob, offset, &nextoffset);
+
+               if (tag == FDT_END)
+                       break;
+               show = in_region || disp->all;
+               if (show && disp->diff)
+                       fprintf(f, "%c", in_region ? '+' : '-');
+
+               if (!show) {
+                       /* Do this here to avoid 'if (show)' in every 'case' */
+                       if (tag == FDT_BEGIN_NODE)
+                               depth++;
+                       else if (tag == FDT_END_NODE)
+                               depth--;
+                       continue;
+               }
+               if (tag != FDT_END) {
+                       if (disp->show_addr)
+                               fprintf(f, "%4x: ", file_ofs);
+                       if (disp->show_offset)
+                               fprintf(f, "%4x: ", file_ofs - base);
+               }
+
+               /* Green means included, red means excluded */
+               if (disp->colour)
+                       print_ansi_colour(f, in_region ? COL_GREEN : COL_RED);
+
+               switch (tag) {
+               case FDT_PROP:
+                       prop = fdt_get_property_by_offset(blob, offset, NULL);
+                       name = fdt_string(blob, fdt32_to_cpu(prop->nameoff));
+                       fprintf(f, "%*s%s", depth * shift, "", name);
+                       utilfdt_print_data(prop->data,
+                                          fdt32_to_cpu(prop->len));
+                       fprintf(f, ";");
+                       break;
+
+               case FDT_NOP:
+                       fprintf(f, "%*s// [NOP]", depth * shift, "");
+                       break;
+
+               case FDT_BEGIN_NODE:
+                       name = fdt_get_name(blob, offset, &len);
+                       fprintf(f, "%*s%s {", depth++ * shift, "",
+                               *name ? name : "/");
+                       break;
+
+               case FDT_END_NODE:
+                       fprintf(f, "%*s};", --depth * shift, "");
+                       break;
+               }
+
+               /* Reset colour back to normal before end of line */
+               if (disp->colour)
+                       print_ansi_colour(f, COL_NONE);
+               fprintf(f, "\n");
+       } while (1);
+
+       /* Print a list of strings if requested */
+       if (disp->list_strings) {
+               const char *str;
+               int str_base = fdt_off_dt_strings(blob);
+
+               for (offset = 0; offset < fdt_size_dt_strings(blob);
+                               offset += strlen(str) + 1) {
+                       str = fdt_string(blob, offset);
+                       int len = strlen(str) + 1;
+                       int show;
+
+                       /* Only print strings that are in the region */
+                       file_ofs = str_base + offset;
+                       in_region = reg < reg_end &&
+                                       file_ofs >= reg->offset &&
+                                       file_ofs + len < reg->offset +
+                                               reg->size;
+                       show = in_region || disp->all;
+                       if (show && disp->diff)
+                               printf("%c", in_region ? '+' : '-');
+                       if (disp->show_addr)
+                               printf("%4x: ", file_ofs);
+                       if (disp->show_offset)
+                               printf("%4x: ", offset);
+                       printf("%s\n", str);
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * dump_fdt_regions() - Dump regions of an FDT as binary data
+ *
+ * This dumps an FDT as binary, but only certain regions of it. This is the
+ * final stage of the grep - we have a list of regions we want to dump,
+ * and this function dumps them.
+ *
+ * The output of this function may or may not be a valid FDT. To ensure it
+ * is, these disp->flags must be set:
+ *
+ *   FDT_REG_SUPERNODES: ensures that subnodes are preceeded by their
+ *             parents. Without this option, fragments of subnode data may be
+ *             output without the supernodes above them. This is useful for
+ *             hashing but cannot produce a valid FDT.
+ *   FDT_REG_ADD_STRING_TAB: Adds a string table to the end of the FDT.
+ *             Without this none of the properties will have names
+ *   FDT_REG_ADD_MEM_RSVMAP: Adds a mem_rsvmap table - an FDT is invalid
+ *             without this.
+ *
+ * @disp:      Display structure, holding info about our options
+ * @blob:      FDT blob to display
+ * @region:    List of regions to display
+ * @count:     Number of regions
+ * @out:       Output destination
+ */
+static int dump_fdt_regions(struct display_info *disp, const void *blob,
+               struct fdt_region region[], int count, char *out)
+{
+       struct fdt_header *fdt;
+       int size, struct_start;
+       int ptr;
+       int i;
+
+       /* Set up a basic header (even if we don't actually write it) */
+       fdt = (struct fdt_header *)out;
+       memset(fdt, '\0', sizeof(*fdt));
+       fdt_set_magic(fdt, FDT_MAGIC);
+       struct_start = FDT_ALIGN(sizeof(struct fdt_header),
+                                       sizeof(struct fdt_reserve_entry));
+       fdt_set_off_mem_rsvmap(fdt, struct_start);
+       fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
+       fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
+
+       /*
+        * Calculate the total size of the regions we are writing out. The
+        * first will be the mem_rsvmap if the FDT_REG_ADD_MEM_RSVMAP flag
+        * is set. The last will be the string table if FDT_REG_ADD_STRING_TAB
+        * is set.
+        */
+       for (i = size = 0; i < count; i++)
+               size += region[i].size;
+
+       /* Bring in the mem_rsvmap section from the old file if requested */
+       if (count > 0 && (disp->flags & FDT_REG_ADD_MEM_RSVMAP)) {
+               struct_start += region[0].size;
+               size -= region[0].size;
+       }
+       fdt_set_off_dt_struct(fdt, struct_start);
+
+       /* Update the header to have the correct offsets/sizes */
+       if (count >= 2 && (disp->flags & FDT_REG_ADD_STRING_TAB)) {
+               int str_size;
+
+               str_size = region[count - 1].size;
+               fdt_set_size_dt_struct(fdt, size - str_size);
+               fdt_set_off_dt_strings(fdt, struct_start + size - str_size);
+               fdt_set_size_dt_strings(fdt, str_size);
+               fdt_set_totalsize(fdt, struct_start + size);
+       }
+
+       /* Write the header if required */
+       ptr = 0;
+       if (disp->header) {
+               ptr = sizeof(*fdt);
+               while (ptr < fdt_off_mem_rsvmap(fdt))
+                       out[ptr++] = '\0';
+       }
+
+       /* Output all the nodes including any mem_rsvmap/string table */
+       for (i = 0; i < count; i++) {
+               struct fdt_region *reg = &region[i];
+
+               memcpy(out + ptr, (const char *)blob + reg->offset, reg->size);
+               ptr += reg->size;
+       }
+
+       return ptr;
+}
+
+/**
+ * show_region_list() - Print out a list of regions
+ *
+ * The list includes the region offset (absolute offset from start of FDT
+ * blob in bytes) and size
+ *
+ * @reg:       List of regions to print
+ * @count:     Number of regions
+ */
+static void show_region_list(struct fdt_region *reg, int count)
+{
+       int i;
+
+       printf("Regions: %d\n", count);
+       for (i = 0; i < count; i++, reg++) {
+               printf("%d:  %-10x  %-10x\n", i, reg->offset,
+                      reg->offset + reg->size);
+       }
+}
+
+static int check_type_include(void *priv, int type, const char *data, int size)
+{
+       struct display_info *disp = priv;
+       struct value_node *val;
+       int match, none_match = FDT_IS_ANY;
+
+       /* If none of our conditions mention this type, we know nothing */
+       debug("type=%x, data=%s\n", type, data ? data : "(null)");
+       if (!((disp->types_inc | disp->types_exc) & type)) {
+               debug("   - not in any condition\n");
+               return -1;
+       }
+
+       /*
+        * Go through the list of conditions. For inclusive conditions, we
+        * return 1 at the first match. For exclusive conditions, we must
+        * check that there are no matches.
+        */
+       for (val = disp->value_head; val; val = val->next) {
+               if (!(type & val->type))
+                       continue;
+               match = fdt_stringlist_contains(data, size, val->string);
+               debug("      - val->type=%x, str='%s', match=%d\n",
+                     val->type, val->string, match);
+               if (match && val->include) {
+                       debug("   - match inc %s\n", val->string);
+                       return 1;
+               }
+               if (match)
+                       none_match &= ~val->type;
+       }
+
+       /*
+        * If this is an exclusive condition, and nothing matches, then we
+        * should return 1.
+        */
+       if ((type & disp->types_exc) && (none_match & type)) {
+               debug("   - match exc\n");
+               /*
+                * Allow FDT_IS_COMPAT to make the final decision in the
+                * case where there is no specific type
+                */
+               if (type == FDT_IS_NODE && disp->types_exc == FDT_ANY_GLOBAL) {
+                       debug("   - supressed exc node\n");
+                       return -1;
+               }
+               return 1;
+       }
+
+       /*
+        * Allow FDT_IS_COMPAT to make the final decision in the
+        * case where there is no specific type (inclusive)
+        */
+       if (type == FDT_IS_NODE && disp->types_inc == FDT_ANY_GLOBAL)
+               return -1;
+
+       debug("   - no match, types_inc=%x, types_exc=%x, none_match=%x\n",
+             disp->types_inc, disp->types_exc, none_match);
+
+       return 0;
+}
+
+/**
+ * h_include() - Include handler function for fdt_find_regions()
+ *
+ * This function decides whether to include or exclude a node, property or
+ * compatible string. The function is defined by fdt_find_regions().
+ *
+ * The algorithm is documented in the code - disp->invert is 0 for normal
+ * operation, and 1 to invert the sense of all matches.
+ *
+ * See
+ */
+static int h_include(void *priv, const void *fdt, int offset, int type,
+                    const char *data, int size)
+{
+       struct display_info *disp = priv;
+       int inc, len;
+
+       inc = check_type_include(priv, type, data, size);
+       if (disp->include_root && type == FDT_IS_PROP && offset == 0 && inc)
+               return 1;
+
+       /*
+        * If the node name does not tell us anything, check the
+        * compatible string
+        */
+       if (inc == -1 && type == FDT_IS_NODE) {
+               debug("   - checking compatible2\n");
+               data = fdt_getprop(fdt, offset, "compatible", &len);
+               inc = check_type_include(priv, FDT_IS_COMPAT, data, len);
+       }
+
+       /* If we still have no idea, check for properties in the node */
+       if (inc != 1 && type == FDT_IS_NODE &&
+           (disp->types_inc & FDT_NODE_HAS_PROP)) {
+               debug("   - checking node '%s'\n",
+                     fdt_get_name(fdt, offset, NULL));
+               for (offset = fdt_first_property_offset(fdt, offset);
+                    offset > 0 && inc != 1;
+                    offset = fdt_next_property_offset(fdt, offset)) {
+                       const struct fdt_property *prop;
+                       const char *str;
+
+                       prop = fdt_get_property_by_offset(fdt, offset, NULL);
+                       if (!prop)
+                               continue;
+                       str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
+                       inc = check_type_include(priv, FDT_NODE_HAS_PROP, str,
+                                                strlen(str));
+               }
+               if (inc == -1)
+                       inc = 0;
+       }
+
+       switch (inc) {
+       case 1:
+               inc = !disp->invert;
+               break;
+       case 0:
+               inc = disp->invert;
+               break;
+       }
+       debug("   - returning %d\n", inc);
+
+       return inc;
+}
+
+static int h_cmp_region(const void *v1, const void *v2)
+{
+       const struct fdt_region *region1 = v1, *region2 = v2;
+
+       return region1->offset - region2->offset;
+}
+
+static int fdtgrep_find_regions(const void *fdt,
+               int (*include_func)(void *priv, const void *fdt, int offset,
+                                int type, const char *data, int size),
+               struct display_info *disp, struct fdt_region *region,
+               int max_regions, char *path, int path_len, int flags)
+{
+       struct fdt_region_state state;
+       int count;
+       int ret;
+
+       count = 0;
+       ret = fdt_first_region(fdt, include_func, disp,
+                       &region[count++], path, path_len,
+                       disp->flags, &state);
+       while (ret == 0) {
+               ret = fdt_next_region(fdt, include_func, disp,
+                               count < max_regions ? &region[count] : NULL,
+                               path, path_len, disp->flags, &state);
+               if (!ret)
+                       count++;
+       }
+
+       /* Find all the aliases and add those regions back in */
+       if (disp->add_aliases && count < max_regions) {
+               int new_count;
+
+               new_count = fdt_add_alias_regions(fdt, region, count,
+                                                 max_regions, &state);
+               if (new_count > max_regions) {
+                       region = malloc(new_count * sizeof(struct fdt_region));
+                       if (!region) {
+                               fprintf(stderr,
+                                       "Out of memory for %d regions\n",
+                                       count);
+                               return -1;
+                       }
+                       memcpy(region, state.region,
+                              count * sizeof(struct fdt_region));
+                       free(state.region);
+                       new_count = fdt_add_alias_regions(fdt, region, count,
+                                                         max_regions, &state);
+               }
+
+               /*
+                * The alias regions will now be at the end of the list. Sort
+                * the regions by offset to get things into the right order
+                */
+               qsort(region, new_count, sizeof(struct fdt_region),
+                     h_cmp_region);
+               count = new_count;
+       }
+
+       if (ret != -FDT_ERR_NOTFOUND)
+               return ret;
+
+       return count;
+}
+
+int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len)
+{
+       int fd = 0;     /* assume stdin */
+       char *buf = NULL;
+       off_t bufsize = 1024, offset = 0;
+       int ret = 0;
+
+       *buffp = NULL;
+       if (strcmp(filename, "-") != 0) {
+               fd = open(filename, O_RDONLY);
+               if (fd < 0)
+                       return errno;
+       }
+
+       /* Loop until we have read everything */
+       buf = malloc(bufsize);
+       if (!buf)
+               return -ENOMEM;
+       do {
+               /* Expand the buffer to hold the next chunk */
+               if (offset == bufsize) {
+                       bufsize *= 2;
+                       buf = realloc(buf, bufsize);
+                       if (!buf)
+                               return -ENOMEM;
+               }
+
+               ret = read(fd, &buf[offset], bufsize - offset);
+               if (ret < 0) {
+                       ret = errno;
+                       break;
+               }
+               offset += ret;
+       } while (ret != 0);
+
+       /* Clean up, including closing stdin; return errno on error */
+       close(fd);
+       if (ret)
+               free(buf);
+       else
+               *buffp = buf;
+       *len = bufsize;
+       return ret;
+}
+
+int utilfdt_read_err(const char *filename, char **buffp)
+{
+       off_t len;
+       return utilfdt_read_err_len(filename, buffp, &len);
+}
+
+char *utilfdt_read_len(const char *filename, off_t *len)
+{
+       char *buff;
+       int ret = utilfdt_read_err_len(filename, &buff, len);
+
+       if (ret) {
+               fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename,
+                       strerror(ret));
+               return NULL;
+       }
+       /* Successful read */
+       return buff;
+}
+
+char *utilfdt_read(const char *filename)
+{
+       off_t len;
+       return utilfdt_read_len(filename, &len);
+}
+
+/**
+ * Run the main fdtgrep operation, given a filename and valid arguments
+ *
+ * @param disp         Display information / options
+ * @param filename     Filename of blob file
+ * @param return 0 if ok, -ve on error
+ */
+static int do_fdtgrep(struct display_info *disp, const char *filename)
+{
+       struct fdt_region *region;
+       int max_regions;
+       int count = 100;
+       char path[1024];
+       char *blob;
+       int i, ret;
+
+       blob = utilfdt_read(filename);
+       if (!blob)
+               return -1;
+       ret = fdt_check_header(blob);
+       if (ret) {
+               fprintf(stderr, "Error: %s\n", fdt_strerror(ret));
+               return ret;
+       }
+
+       /* Allow old files, but they are untested */
+       if (fdt_version(blob) < 17 && disp->value_head) {
+               fprintf(stderr,
+                       "Warning: fdtgrep does not fully support version %d files\n",
+                       fdt_version(blob));
+       }
+
+       /*
+        * We do two passes, since we don't know how many regions we need.
+        * The first pass will count the regions, but if it is too many,
+        * we do another pass to actually record them.
+        */
+       for (i = 0; i < 2; i++) {
+               region = malloc(count * sizeof(struct fdt_region));
+               if (!region) {
+                       fprintf(stderr, "Out of memory for %d regions\n",
+                               count);
+                       return -1;
+               }
+               max_regions = count;
+               count = fdtgrep_find_regions(blob,
+                               h_include, disp,
+                               region, max_regions, path, sizeof(path),
+                               disp->flags);
+               if (count < 0) {
+                       report_error("fdt_find_regions", count);
+                       return -1;
+               }
+               if (count <= max_regions)
+                       break;
+               free(region);
+       }
+
+       /* Optionally print a list of regions */
+       if (disp->region_list)
+               show_region_list(region, count);
+
+       /* Output either source .dts or binary .dtb */
+       if (disp->output == OUT_DTS) {
+               ret = display_fdt_by_regions(disp, blob, region, count);
+       } else {
+               void *fdt;
+               /* Allow reserved memory section to expand slightly */
+               int size = fdt_totalsize(blob) + 16;
+
+               fdt = malloc(size);
+               if (!fdt) {
+                       fprintf(stderr, "Out_of_memory\n");
+                       ret = -1;
+                       goto err;
+               }
+               size = dump_fdt_regions(disp, blob, region, count, fdt);
+               if (disp->remove_strings) {
+                       void *out;
+
+                       out = malloc(size);
+                       if (!out) {
+                               fprintf(stderr, "Out_of_memory\n");
+                               ret = -1;
+                               goto err;
+                       }
+                       ret = fdt_remove_unused_strings(fdt, out);
+                       if (ret < 0) {
+                               fprintf(stderr,
+                                       "Failed to remove unused strings: err=%d\n",
+                                       ret);
+                               goto err;
+                       }
+                       free(fdt);
+                       fdt = out;
+                       ret = fdt_pack(fdt);
+                       if (ret < 0) {
+                               fprintf(stderr, "Failed to pack: err=%d\n",
+                                       ret);
+                               goto err;
+                       }
+                       size = fdt_totalsize(fdt);
+               }
+
+               if (size != fwrite(fdt, 1, size, disp->fout)) {
+                       fprintf(stderr, "Write failure, %d bytes\n", size);
+                       free(fdt);
+                       ret = 1;
+                       goto err;
+               }
+               free(fdt);
+       }
+err:
+       free(blob);
+       free(region);
+
+       return ret;
+}
+
+static const char usage_synopsis[] =
+       "fdtgrep - extract portions from device tree\n"
+       "\n"
+       "Usage:\n"
+       "       fdtgrep <options> <dt file>|-\n\n"
+       "Output formats are:\n"
+       "\tdts - device tree soure text\n"
+       "\tdtb - device tree blob (sets -Hmt automatically)\n"
+       "\tbin - device tree fragment (may not be a valid .dtb)";
+
+/* Helper for usage_short_opts string constant */
+#define USAGE_COMMON_SHORT_OPTS "hV"
+
+/* Helper for aligning long_opts array */
+#define a_argument required_argument
+
+/* Helper for usage_long_opts option array */
+#define USAGE_COMMON_LONG_OPTS \
+       {"help",      no_argument, NULL, 'h'}, \
+       {"version",   no_argument, NULL, 'V'}, \
+       {NULL,        no_argument, NULL, 0x0}
+
+/* Helper for usage_opts_help array */
+#define USAGE_COMMON_OPTS_HELP \
+       "Print this help and exit", \
+       "Print version and exit", \
+       NULL
+
+/* Helper for getopt case statements */
+#define case_USAGE_COMMON_FLAGS \
+       case 'h': usage(NULL); \
+       case 'V': util_version(); \
+       case '?': usage("unknown option");
+
+static const char usage_short_opts[] =
+               "haAc:b:C:defg:G:HIlLmn:N:o:O:p:P:rRsStTv"
+               USAGE_COMMON_SHORT_OPTS;
+static struct option const usage_long_opts[] = {
+       {"show-address",        no_argument, NULL, 'a'},
+       {"colour",              no_argument, NULL, 'A'},
+       {"include-node-with-prop", a_argument, NULL, 'b'},
+       {"include-compat",      a_argument, NULL, 'c'},
+       {"exclude-compat",      a_argument, NULL, 'C'},
+       {"diff",                no_argument, NULL, 'd'},
+       {"enter-node",          no_argument, NULL, 'e'},
+       {"show-offset",         no_argument, NULL, 'f'},
+       {"include-match",       a_argument, NULL, 'g'},
+       {"exclude-match",       a_argument, NULL, 'G'},
+       {"show-header",         no_argument, NULL, 'H'},
+       {"show-version",        no_argument, NULL, 'I'},
+       {"list-regions",        no_argument, NULL, 'l'},
+       {"list-strings",        no_argument, NULL, 'L'},
+       {"include-mem",         no_argument, NULL, 'm'},
+       {"include-node",        a_argument, NULL, 'n'},
+       {"exclude-node",        a_argument, NULL, 'N'},
+       {"include-prop",        a_argument, NULL, 'p'},
+       {"exclude-prop",        a_argument, NULL, 'P'},
+       {"remove-strings",      no_argument, NULL, 'r'},
+       {"include-root",        no_argument, NULL, 'R'},
+       {"show-subnodes",       no_argument, NULL, 's'},
+       {"skip-supernodes",     no_argument, NULL, 'S'},
+       {"show-stringtab",      no_argument, NULL, 't'},
+       {"show-aliases",        no_argument, NULL, 'T'},
+       {"out",                 a_argument, NULL, 'o'},
+       {"out-format",          a_argument, NULL, 'O'},
+       {"invert-match",        no_argument, NULL, 'v'},
+       USAGE_COMMON_LONG_OPTS,
+};
+static const char * const usage_opts_help[] = {
+       "Display address",
+       "Show all nodes/tags, colour those that match",
+       "Include contains containing property",
+       "Compatible nodes to include in grep",
+       "Compatible nodes to exclude in grep",
+       "Diff: Mark matching nodes with +, others with -",
+       "Enter direct subnode names of matching nodes",
+       "Display offset",
+       "Node/property/compatible string to include in grep",
+       "Node/property/compatible string to exclude in grep",
+       "Output a header",
+       "Put \"/dts-v1/;\" on first line of dts output",
+       "Output a region list",
+       "List strings in string table",
+       "Include mem_rsvmap section in binary output",
+       "Node to include in grep",
+       "Node to exclude in grep",
+       "Property to include in grep",
+       "Property to exclude in grep",
+       "Remove unused strings from string table",
+       "Include root node and all properties",
+       "Show all subnodes matching nodes",
+       "Don't include supernodes of matching nodes",
+       "Include string table in binary output",
+       "Include matching aliases in output",
+       "-o <output file>",
+       "-O <output format>",
+       "Invert the sense of matching (select non-matching lines)",
+       USAGE_COMMON_OPTS_HELP
+};
+
+/**
+ * Call getopt_long() with standard options
+ *
+ * Since all util code runs getopt in the same way, provide a helper.
+ */
+#define util_getopt_long() getopt_long(argc, argv, usage_short_opts, \
+                                      usage_long_opts, NULL)
+
+void util_usage(const char *errmsg, const char *synopsis,
+               const char *short_opts, struct option const long_opts[],
+               const char * const opts_help[])
+{
+       FILE *fp = errmsg ? stderr : stdout;
+       const char a_arg[] = "<arg>";
+       size_t a_arg_len = strlen(a_arg) + 1;
+       size_t i;
+       int optlen;
+
+       fprintf(fp,
+               "Usage: %s\n"
+               "\n"
+               "Options: -[%s]\n", synopsis, short_opts);
+
+       /* prescan the --long opt length to auto-align */
+       optlen = 0;
+       for (i = 0; long_opts[i].name; ++i) {
+               /* +1 is for space between --opt and help text */
+               int l = strlen(long_opts[i].name) + 1;
+               if (long_opts[i].has_arg == a_argument)
+                       l += a_arg_len;
+               if (optlen < l)
+                       optlen = l;
+       }
+
+       for (i = 0; long_opts[i].name; ++i) {
+               /* helps when adding new applets or options */
+               assert(opts_help[i] != NULL);
+
+               /* first output the short flag if it has one */
+               if (long_opts[i].val > '~')
+                       fprintf(fp, "      ");
+               else
+                       fprintf(fp, "  -%c, ", long_opts[i].val);
+
+               /* then the long flag */
+               if (long_opts[i].has_arg == no_argument) {
+                       fprintf(fp, "--%-*s", optlen, long_opts[i].name);
+               } else {
+                       fprintf(fp, "--%s %s%*s", long_opts[i].name, a_arg,
+                               (int)(optlen - strlen(long_opts[i].name) -
+                               a_arg_len), "");
+               }
+
+               /* finally the help text */
+               fprintf(fp, "%s\n", opts_help[i]);
+       }
+
+       if (errmsg) {
+               fprintf(fp, "\nError: %s\n", errmsg);
+               exit(EXIT_FAILURE);
+       } else {
+               exit(EXIT_SUCCESS);
+       }
+}
+
+/**
+ * Show usage and exit
+ *
+ * If you name all your usage variables with usage_xxx, then you can call this
+ * help macro rather than expanding all arguments yourself.
+ *
+ * @param errmsg       If non-NULL, an error message to display
+ */
+#define usage(errmsg) \
+       util_usage(errmsg, usage_synopsis, usage_short_opts, \
+                  usage_long_opts, usage_opts_help)
+
+void util_version(void)
+{
+       printf("Version: %s\n", "(U-Boot)");
+       exit(0);
+}
+
+static void scan_args(struct display_info *disp, int argc, char *argv[])
+{
+       int opt;
+
+       while ((opt = util_getopt_long()) != EOF) {
+               int type = 0;
+               int inc = 1;
+
+               switch (opt) {
+               case_USAGE_COMMON_FLAGS
+               case 'a':
+                       disp->show_addr = 1;
+                       break;
+               case 'A':
+                       disp->all = 1;
+                       break;
+               case 'b':
+                       type = FDT_NODE_HAS_PROP;
+                       break;
+               case 'C':
+                       inc = 0;
+                       /* no break */
+               case 'c':
+                       type = FDT_IS_COMPAT;
+                       break;
+               case 'd':
+                       disp->diff = 1;
+                       break;
+               case 'e':
+                       disp->flags |= FDT_REG_DIRECT_SUBNODES;
+                       break;
+               case 'f':
+                       disp->show_offset = 1;
+                       break;
+               case 'G':
+                       inc = 0;
+                       /* no break */
+               case 'g':
+                       type = FDT_ANY_GLOBAL;
+                       break;
+               case 'H':
+                       disp->header = 1;
+                       break;
+               case 'l':
+                       disp->region_list = 1;
+                       break;
+               case 'L':
+                       disp->list_strings = 1;
+                       break;
+               case 'm':
+                       disp->flags |= FDT_REG_ADD_MEM_RSVMAP;
+                       break;
+               case 'N':
+                       inc = 0;
+                       /* no break */
+               case 'n':
+                       type = FDT_IS_NODE;
+                       break;
+               case 'o':
+                       disp->output_fname = optarg;
+                       break;
+               case 'O':
+                       if (!strcmp(optarg, "dtb"))
+                               disp->output = OUT_DTB;
+                       else if (!strcmp(optarg, "dts"))
+                               disp->output = OUT_DTS;
+                       else if (!strcmp(optarg, "bin"))
+                               disp->output = OUT_BIN;
+                       else
+                               usage("Unknown output format");
+                       break;
+               case 'P':
+                       inc = 0;
+                       /* no break */
+               case 'p':
+                       type = FDT_IS_PROP;
+                       break;
+               case 'r':
+                       disp->remove_strings = 1;
+                       break;
+               case 'R':
+                       disp->include_root = 1;
+                       break;
+               case 's':
+                       disp->flags |= FDT_REG_ALL_SUBNODES;
+                       break;
+               case 'S':
+                       disp->flags &= ~FDT_REG_SUPERNODES;
+                       break;
+               case 't':
+                       disp->flags |= FDT_REG_ADD_STRING_TAB;
+                       break;
+               case 'T':
+                       disp->add_aliases = 1;
+                       break;
+               case 'v':
+                       disp->invert = 1;
+                       break;
+               case 'I':
+                       disp->show_dts_version = 1;
+                       break;
+               }
+
+               if (type && value_add(disp, &disp->value_head, type, inc,
+                                     optarg))
+                       usage("Cannot add value");
+       }
+
+       if (disp->invert && disp->types_exc)
+               usage("-v has no meaning when used with 'exclude' conditions");
+}
+
+int main(int argc, char *argv[])
+{
+       char *filename = NULL;
+       struct display_info disp;
+       int ret;
+
+       /* set defaults */
+       memset(&disp, '\0', sizeof(disp));
+       disp.flags = FDT_REG_SUPERNODES;        /* Default flags */
+
+       scan_args(&disp, argc, argv);
+
+       /* Show matched lines in colour if we can */
+       disp.colour = disp.all && isatty(0);
+
+       /* Any additional arguments can match anything, just like -g */
+       while (optind < argc - 1) {
+               if (value_add(&disp, &disp.value_head, FDT_IS_ANY, 1,
+                             argv[optind++]))
+                       usage("Cannot add value");
+       }
+
+       if (optind < argc)
+               filename = argv[optind++];
+       if (!filename)
+               usage("Missing filename");
+
+       /* If a valid .dtb is required, set flags to ensure we get one */
+       if (disp.output == OUT_DTB) {
+               disp.header = 1;
+               disp.flags |= FDT_REG_ADD_MEM_RSVMAP | FDT_REG_ADD_STRING_TAB;
+       }
+
+       if (disp.output_fname) {
+               disp.fout = fopen(disp.output_fname, "w");
+               if (!disp.fout)
+                       usage("Cannot open output file");
+       } else {
+               disp.fout = stdout;
+       }
+
+       /* Run the grep and output the results */
+       ret = do_fdtgrep(&disp, filename);
+       if (disp.output_fname)
+               fclose(disp.fout);
+       if (ret)
+               return 1;
+
+       return 0;
+}
index b7874f47cd228f0a6aaf93f9098979f36a7ca5ca..99bbf2f459e5ae2d66bb69a25b55011a990b84c3 100644 (file)
@@ -59,6 +59,7 @@ struct image_tool_params {
        const char *keydest;    /* Destination .dtb for public key */
        const char *comment;    /* Comment to add to signature node */
        int require_keys;       /* 1 to mark signing keys as 'required' */
+       int file_size;          /* Total size of output file */
 };
 
 /*
index 5ccd951048cef587686d264575aae6ea7623e90f..e81d4550835c6763bcab21e0b2b8ab2bf46baba3 100644 (file)
@@ -26,8 +26,48 @@ struct image_tool_params params = {
        .imagename2 = "",
 };
 
-int
-main (int argc, char **argv)
+static int h_compare_image_name(const void *vtype1, const void *vtype2)
+{
+       const int *type1 = vtype1;
+       const int *type2 = vtype2;
+       const char *name1 = genimg_get_type_short_name(*type1);
+       const char *name2 = genimg_get_type_short_name(*type2);
+
+       return strcmp(name1, name2);
+}
+
+/* Show all image types supported by mkimage */
+static void show_image_types(void)
+{
+       struct image_type_params *tparams;
+       int order[IH_TYPE_COUNT];
+       int count;
+       int type;
+       int i;
+
+       /* Sort the names in order of short name for easier reading */
+       memset(order, '\0', sizeof(order));
+       for (count = 0, type = 0; type < IH_TYPE_COUNT; type++) {
+               tparams = imagetool_get_type(type);
+               if (tparams)
+                       order[count++] = type;
+       }
+       qsort(order, count, sizeof(int), h_compare_image_name);
+
+       fprintf(stderr, "\nInvalid image type. Supported image types:\n");
+       for (i = 0; i < count; i++) {
+               type = order[i];
+               tparams = imagetool_get_type(type);
+               if (tparams) {
+                       fprintf(stderr, "\t%-15s  %s\n",
+                               genimg_get_type_short_name(type),
+                               genimg_get_type_name(type));
+               }
+       }
+       fprintf(stderr, "\n");
+}
+
+int main(int argc, char **argv)
 {
        int ifd = -1;
        struct stat sbuf;
@@ -35,6 +75,7 @@ main (int argc, char **argv)
        int retval = 0;
        struct image_type_params *tparams = NULL;
        int pad_len = 0;
+       int dfd;
 
        params.cmdname = *argv;
        params.addr = params.ep = 0;
@@ -75,12 +116,16 @@ main (int argc, char **argv)
                                        usage ();
                                goto NXTARG;
                        case 'T':
-                               if ((--argc <= 0) ||
-                                       (params.type =
-                                       genimg_get_type_id (*++argv)) < 0)
-                                       usage ();
+                               params.type = -1;
+                               if (--argc >= 0 && argv[1]) {
+                                       params.type =
+                                               genimg_get_type_id(*++argv);
+                               }
+                               if (params.type < 0) {
+                                       show_image_types();
+                                       usage();
+                               }
                                goto NXTARG;
-
                        case 'a':
                                if (--argc <= 0)
                                        usage ();
@@ -266,6 +311,22 @@ NXTARG:            ;
                exit (retval);
        }
 
+       dfd = open(params.datafile, O_RDONLY | O_BINARY);
+       if (dfd < 0) {
+               fprintf(stderr, "%s: Can't open %s: %s\n",
+                       params.cmdname, params.datafile, strerror(errno));
+               exit(EXIT_FAILURE);
+       }
+
+       if (fstat(dfd, &sbuf) < 0) {
+               fprintf(stderr, "%s: Can't stat %s: %s\n",
+                       params.cmdname, params.datafile, strerror(errno));
+               exit(EXIT_FAILURE);
+       }
+
+       params.file_size = sbuf.st_size + tparams->header_size;
+       close(dfd);
+
        /*
         * In case there an header with a variable
         * length will be added, the corresponding
@@ -365,6 +426,7 @@ NXTARG:             ;
                        params.cmdname, params.imagefile, strerror(errno));
                exit (EXIT_FAILURE);
        }
+       params.file_size = sbuf.st_size;
 
        ptr = mmap(0, sbuf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, ifd, 0);
        if (ptr == MAP_FAILED) {
@@ -546,6 +608,7 @@ static void usage(void)
 #endif
        fprintf (stderr, "       %s -V ==> print version information and exit\n",
                params.cmdname);
+       fprintf(stderr, "Use -T to see a list of available image types\n");
 
        exit (EXIT_FAILURE);
 }