summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--arch/arm/cpu/u-boot-spl.lds12
-rw-r--r--arch/arm/mach-zynq/clk.c6
-rw-r--r--arch/sandbox/cpu/cpu.c9
-rw-r--r--arch/sandbox/cpu/state.c4
-rw-r--r--arch/sandbox/dts/test.dts67
-rw-r--r--arch/sandbox/include/asm/state.h3
-rw-r--r--arch/sandbox/include/asm/test.h19
-rw-r--r--arch/sandbox/include/asm/u-boot-sandbox.h3
-rw-r--r--arch/x86/include/asm/interrupt.h4
-rw-r--r--common/cmd_tsi148.c8
-rw-r--r--common/cmd_usb.c28
-rw-r--r--common/console.c25
-rw-r--r--common/image.c58
-rw-r--r--common/spl/spl.c36
-rw-r--r--common/spl/spl_mmc.c26
-rw-r--r--common/usb.c20
-rw-r--r--common/usb_hub.c2
-rw-r--r--common/usb_kbd.c4
-rw-r--r--common/usb_storage.c2
-rw-r--r--configs/sandbox_defconfig8
-rw-r--r--doc/device-tree-bindings/leds/common.txt23
-rw-r--r--doc/device-tree-bindings/leds/leds-gpio.txt52
-rw-r--r--doc/driver-model/README.txt17
-rw-r--r--drivers/Kconfig6
-rw-r--r--drivers/Makefile3
-rw-r--r--drivers/clk/Kconfig19
-rw-r--r--drivers/clk/Makefile9
-rw-r--r--drivers/clk/clk-uclass.c58
-rw-r--r--drivers/clk/clk_sandbox.c85
-rw-r--r--drivers/core/Kconfig4
-rw-r--r--drivers/core/Makefile5
-rw-r--r--drivers/core/device-remove.c22
-rw-r--r--drivers/core/device.c34
-rw-r--r--drivers/core/dump.c96
-rw-r--r--drivers/core/lists.c6
-rw-r--r--drivers/core/regmap.c86
-rw-r--r--drivers/core/syscon-uclass.c76
-rw-r--r--drivers/core/uclass.c4
-rw-r--r--drivers/gpio/Makefile4
-rw-r--r--drivers/gpio/gpio-uclass.c36
-rw-r--r--drivers/led/Kconfig26
-rw-r--r--drivers/led/Makefile9
-rw-r--r--drivers/led/led-uclass.c49
-rw-r--r--drivers/led/led_gpio.c107
-rw-r--r--drivers/misc/Kconfig9
-rw-r--r--drivers/misc/Makefile3
-rw-r--r--drivers/misc/reset-uclass.c81
-rw-r--r--drivers/misc/reset_sandbox.c100
-rw-r--r--drivers/misc/syscon_sandbox.c27
-rw-r--r--drivers/mmc/Kconfig10
-rw-r--r--drivers/mmc/Makefile3
-rw-r--r--drivers/mmc/mmc-uclass.c34
-rw-r--r--drivers/mmc/mmc.c10
-rw-r--r--drivers/mmc/sandbox_mmc.c25
-rw-r--r--drivers/net/designware.c2
-rw-r--r--drivers/net/rtl8169.c236
-rw-r--r--drivers/net/sandbox-raw.c2
-rw-r--r--drivers/net/sandbox.c2
-rw-r--r--drivers/net/sunxi_emac.c2
-rw-r--r--drivers/pci/pci-uclass.c144
-rw-r--r--drivers/pci/pci_compat.c8
-rw-r--r--drivers/power/pmic/pmic-uclass.c57
-rw-r--r--drivers/power/regulator/regulator-uclass.c134
-rw-r--r--drivers/ram/Kconfig18
-rw-r--r--drivers/ram/Makefile8
-rw-r--r--drivers/ram/ram-uclass.c28
-rw-r--r--drivers/ram/sandbox_ram.c38
-rw-r--r--drivers/serial/ns16550.c36
-rw-r--r--drivers/spi/spi-uclass.c8
-rw-r--r--drivers/usb/Kconfig4
-rw-r--r--drivers/usb/eth/asix.c237
-rw-r--r--drivers/usb/eth/usb_ether.c131
-rw-r--r--drivers/usb/host/ehci-hcd.c17
-rw-r--r--drivers/usb/host/ehci-pci.c112
-rw-r--r--drivers/usb/host/ehci.h15
-rw-r--r--drivers/usb/host/r8a66597-hcd.c14
-rw-r--r--drivers/usb/host/r8a66597.h14
-rw-r--r--drivers/usb/host/usb-uclass.c79
-rw-r--r--drivers/usb/musb-new/am35x.c7
-rw-r--r--drivers/usb/musb-new/musb_core.c20
-rw-r--r--drivers/usb/musb-new/musb_core.h18
-rw-r--r--drivers/usb/musb-new/musb_dsps.c6
-rw-r--r--drivers/usb/musb-new/musb_gadget_ep0.c1
-rw-r--r--drivers/usb/musb-new/musb_host.c4
-rw-r--r--drivers/usb/musb-new/musb_uboot.c211
-rw-r--r--drivers/usb/musb-new/musb_uboot.h28
-rw-r--r--drivers/usb/musb-new/omap2430.c5
-rw-r--r--drivers/usb/musb-new/sunxi.c5
-rw-r--r--drivers/usb/musb-new/usb-compat.h70
-rw-r--r--dts/Kconfig12
-rw-r--r--include/asm-generic/global_data.h1
-rw-r--r--include/asm-generic/gpio.h25
-rw-r--r--include/clk.h80
-rw-r--r--include/common.h11
-rw-r--r--include/configs/minnowmax.h3
-rw-r--r--include/debug_uart.h22
-rw-r--r--include/dm/device-internal.h26
-rw-r--r--include/dm/device.h16
-rw-r--r--include/dm/platdata.h9
-rw-r--r--include/dm/uclass-id.h6
-rw-r--r--include/dm/util.h6
-rw-r--r--include/dwmmc.h18
-rw-r--r--include/image.h11
-rw-r--r--include/led.h51
-rw-r--r--include/libfdt.h256
-rw-r--r--include/linux/compat.h28
-rw-r--r--include/mmc.h22
-rw-r--r--include/net.h14
-rw-r--r--include/pci.h87
-rw-r--r--include/power/pmic.h34
-rw-r--r--include/power/regulator.h53
-rw-r--r--include/power/sandbox_pmic.h4
-rw-r--r--include/ram.h38
-rw-r--r--include/rc4.h21
-rw-r--r--include/regmap.h72
-rw-r--r--include/reset.h71
-rw-r--r--include/spl.h12
-rw-r--r--include/syscon.h56
-rw-r--r--include/test/ut.h15
-rw-r--r--include/usb.h49
-rw-r--r--include/usb_ether.h89
-rw-r--r--include/vsprintf.h26
-rw-r--r--lib/Kconfig2
-rw-r--r--lib/Makefile5
-rw-r--r--lib/dhry/Kconfig7
-rw-r--r--lib/dhry/Makefile7
-rw-r--r--lib/dhry/cmd_dhry.c34
-rw-r--r--lib/dhry/dhry.h442
-rw-r--r--lib/dhry/dhry_1.c421
-rw-r--r--lib/dhry/dhry_2.c217
-rw-r--r--lib/fdtdec.c21
-rw-r--r--lib/libfdt/Makefile2
-rw-r--r--lib/libfdt/fdt_region.c492
-rw-r--r--lib/libfdt/fdt_rw.c32
-rw-r--r--lib/linux_compat.c16
-rw-r--r--lib/rc4.c49
-rw-r--r--lib/vsprintf.c19
-rw-r--r--net/eth.c11
-rw-r--r--scripts/Makefile.spl32
-rw-r--r--test/dm/Makefile7
-rw-r--r--test/dm/clk.c59
-rw-r--r--test/dm/cmd_dm.c82
-rw-r--r--test/dm/led.c72
-rw-r--r--test/dm/mmc.c27
-rw-r--r--test/dm/ram.c28
-rw-r--r--test/dm/regmap.c82
-rw-r--r--test/dm/regulator.c2
-rw-r--r--test/dm/reset.c74
-rw-r--r--test/dm/syscon.c31
-rw-r--r--test/dm/test-main.c15
-rw-r--r--tools/Makefile6
-rw-r--r--tools/fdtgrep.c1234
-rw-r--r--tools/imagetool.h1
-rw-r--r--tools/mkimage.c77
155 files changed, 7319 insertions, 736 deletions
diff --git a/Makefile b/Makefile
index 9ca0a56949..54ef2cd1a0 100644
--- 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
diff --git a/arch/arm/cpu/u-boot-spl.lds b/arch/arm/cpu/u-boot-spl.lds
index a8be204038..c5b4f7ce5e 100644
--- a/arch/arm/cpu/u-boot-spl.lds
+++ b/arch/arm/cpu/u-boot-spl.lds
@@ -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*) }
diff --git a/arch/arm/mach-zynq/clk.c b/arch/arm/mach-zynq/clk.c
index d2885dc2b9..6444be8f03 100644
--- a/arch/arm/mach-zynq/clk.c
+++ b/arch/arm/mach-zynq/clk.c
@@ -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
diff --git a/arch/sandbox/cpu/cpu.c b/arch/sandbox/cpu/cpu.c
index e6ddb17a14..3a7f5a004b 100644
--- a/arch/sandbox/cpu/cpu.c
+++ b/arch/sandbox/cpu/cpu.c
@@ -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)
{
diff --git a/arch/sandbox/cpu/state.c b/arch/sandbox/cpu/state.c
index cae731c8f1..7e5d03e846 100644
--- a/arch/sandbox/cpu/state.c
+++ b/arch/sandbox/cpu/state.c
@@ -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:
*
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index c25614ab88..c948df8c86 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -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>;
@@ -41,16 +41,16 @@
};
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 {
@@ -84,14 +84,14 @@
};
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";
@@ -105,6 +105,10 @@
compatible = "denx,u-boot-fdt-test";
};
+ clk@0 {
+ compatible = "sandbox,clk";
+ };
+
eth@10002000 {
compatible = "sandbox,eth";
reg = <0x10002000 0x1000>;
@@ -142,7 +146,7 @@
i2c@0 {
#address-cells = <1>;
#size-cells = <0>;
- reg = <0>;
+ reg = <0 1>;
compatible = "sandbox,i2c";
clock-frequency = <100000>;
eeprom@2c {
@@ -176,6 +180,24 @@
};
};
+ 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";
@@ -192,10 +214,22 @@
};
};
+ 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 {
@@ -206,6 +240,19 @@
};
};
+ 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;
diff --git a/arch/sandbox/include/asm/state.h b/arch/sandbox/include/asm/state.h
index a57480a996..2bd28f6b1c 100644
--- a/arch/sandbox/include/asm/state.h
+++ b/arch/sandbox/include/asm/state.h
@@ -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 */
diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h
index 91a5c79ad2..d3c7851bb5 100644
--- a/arch/sandbox/include/asm/test.h
+++ b/arch/sandbox/include/asm/test.h
@@ -17,6 +17,25 @@
#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
*
diff --git a/arch/sandbox/include/asm/u-boot-sandbox.h b/arch/sandbox/include/asm/u-boot-sandbox.h
index da87cc3040..2f3c3f90f2 100644
--- a/arch/sandbox/include/asm/u-boot-sandbox.h
+++ b/arch/sandbox/include/asm/u-boot-sandbox.h
@@ -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_ */
diff --git a/arch/x86/include/asm/interrupt.h b/arch/x86/include/asm/interrupt.h
index 0a75f89d95..00cbe07ed1 100644
--- a/arch/x86/include/asm/interrupt.h
+++ b/arch/x86/include/asm/interrupt.h
@@ -16,10 +16,6 @@
/* 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);
diff --git a/common/cmd_tsi148.c b/common/cmd_tsi148.c
index dc488b2b3e..ea96d0ffb0 100644
--- a/common/cmd_tsi148.c
+++ b/common/cmd_tsi148.c
@@ -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;
diff --git a/common/cmd_usb.c b/common/cmd_usb.c
index eab55cd674..0ade7759f0 100644
--- a/common/cmd_usb.c
+++ b/common/cmd_usb.c
@@ -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);
}
}
diff --git a/common/console.c b/common/console.c
index 00582224d4..ace206ca4f 100644
--- a/common/console.c
+++ b/common/console.c
@@ -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
diff --git a/common/image.c b/common/image.c
index f0f01351fe..9efacf8b89 100644
--- a/common/image.c
+++ b/common/image.c
@@ -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)
diff --git a/common/spl/spl.c b/common/spl/spl.c
index aeb0645eda..94b01da56c 100644
--- a/common/spl/spl.c
+++ b/common/spl/spl.c
@@ -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);
}
diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c
index 552f80d1e3..5f1cfbf98e 100644
--- a/common/spl/spl_mmc.c
+++ b/common/spl/spl_mmc.c
@@ -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);
diff --git a/common/usb.c b/common/usb.c
index 7ff8ac5df3..fbaf8ecbe2 100644
--- a/common/usb.c
+++ b/common/usb.c
@@ -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;
diff --git a/common/usb_hub.c b/common/usb_hub.c
index be01f4f257..f621ddb9ab 100644
--- a/common/usb_hub.c
+++ b/common/usb_hub.c
@@ -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
diff --git a/common/usb_kbd.c b/common/usb_kbd.c
index e2af67d2f0..0227024441 100644
--- a/common/usb_kbd.c
+++ b/common/usb_kbd.c
@@ -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;
diff --git a/common/usb_storage.c b/common/usb_storage.c
index cc9b3e37a1..b978430408 100644
--- a/common/usb_storage.c
+++ b/common/usb_storage.c
@@ -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
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 598519dbb2..553574682d 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -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
index 0000000000..2d88816dd5
--- /dev/null
+++ b/doc/device-tree-bindings/leds/common.txt
@@ -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
index 0000000000..df1b3080f6
--- /dev/null
+++ b/doc/device-tree-bindings/leds/leds-gpio.txt
@@ -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";
+ };
+};
diff --git a/doc/driver-model/README.txt b/doc/driver-model/README.txt
index f0276b1b46..b891e8459d 100644
--- a/doc/driver-model/README.txt
+++ b/doc/driver-model/README.txt
@@ -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";
diff --git a/drivers/Kconfig b/drivers/Kconfig
index c7e526cc8a..092bc02b30 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -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"
diff --git a/drivers/Makefile b/drivers/Makefile
index 405b64b268..5a35148ead 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -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
index 0000000000..07eb54c597
--- /dev/null
+++ b/drivers/clk/Kconfig
@@ -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
index 0000000000..bb89fb918b
--- /dev/null
+++ b/drivers/clk/Makefile
@@ -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
index 0000000000..73dfd7d016
--- /dev/null
+++ b/drivers/clk/clk-uclass.c
@@ -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
index 0000000000..058225a766
--- /dev/null
+++ b/drivers/clk/clk_sandbox.c
@@ -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,
+};
diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
index 2861b43079..e40372dd75 100644
--- a/drivers/core/Kconfig
+++ b/drivers/core/Kconfig
@@ -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
diff --git a/drivers/core/Makefile b/drivers/core/Makefile
index a3fec38503..5c2ead870b 100644
--- a/drivers/core/Makefile
+++ b/drivers/core/Makefile
@@ -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
diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c
index 6a16b4f690..6b87f865e4 100644
--- a/drivers/core/device-remove.c
+++ b/drivers/core/device-remove.c
@@ -18,16 +18,7 @@
#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;
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 85fd1fc735..51b1b44e5b 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -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
index 0000000000..fd4596ee68
--- /dev/null
+++ b/drivers/core/dump.c
@@ -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");
+ }
+}
diff --git a/drivers/core/lists.c b/drivers/core/lists.c
index 0c49d99f47..2e52500ef2 100644
--- a/drivers/core/lists.c
+++ b/drivers/core/lists.c
@@ -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
index 0000000000..519832f173
--- /dev/null
+++ b/drivers/core/regmap.c
@@ -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
index 0000000000..686c32056e
--- /dev/null
+++ b/drivers/core/syscon-uclass.c
@@ -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,
+};
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index 7de817324b..aba98801fd 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -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));
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 586485055d..67c6374d47 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -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
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index bf982b9d19..4efda311a4 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -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
index 0000000000..de5feea8dd
--- /dev/null
+++ b/drivers/led/Kconfig
@@ -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
index 0000000000..990129e08d
--- /dev/null
+++ b/drivers/led/Makefile
@@ -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
index 0000000000..784ac870e2
--- /dev/null
+++ b/drivers/led/led-uclass.c
@@ -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
index 0000000000..cb6e996931
--- /dev/null
+++ b/drivers/led/led_gpio.c
@@ -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,
+};
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 64b07a3015..3b7f76ab78 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -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.
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 120babc4b5..5218b91c0b 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -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
index 0000000000..fdb5c6fcff
--- /dev/null
+++ b/drivers/misc/reset-uclass.c
@@ -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
index 0000000000..917121bc5e
--- /dev/null
+++ b/drivers/misc/reset_sandbox.c
@@ -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
index 0000000000..ccfab3ef98
--- /dev/null
+++ b/drivers/misc/syscon_sandbox.c
@@ -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,
+};
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 7ba85a2b62..3e835f7bca 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -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
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index ed73687735..286df2fc7d 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -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
index 0000000000..777489f5d8
--- /dev/null
+++ b/drivers/mmc/mmc-uclass.c
@@ -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),
+};
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 79e6feeb13..da47037a30 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -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
index 0000000000..f4646a824f
--- /dev/null
+++ b/drivers/mmc/sandbox_mmc.c
@@ -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,
+};
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index 645ca6427c..bcae842389 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -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);
diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c
index 958488c19a..7b6e20f30f 100644
--- a/drivers/net/rtl8169.c
+++ b/drivers/net/rtl8169.c
@@ -41,10 +41,13 @@
* 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
diff --git a/drivers/net/sandbox-raw.c b/drivers/net/sandbox-raw.c
index 45c3b18bdf..591242797e 100644
--- a/drivers/net/sandbox-raw.c
+++ b/drivers/net/sandbox-raw.c
@@ -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);
diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c
index 4e083d32ae..6763a248f2 100644
--- a/drivers/net/sandbox.c
+++ b/drivers/net/sandbox.c
@@ -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);
diff --git a/drivers/net/sunxi_emac.c b/drivers/net/sunxi_emac.c
index e939bf2108..11cd0ea068 100644
--- a/drivers/net/sunxi_emac.c
+++ b/drivers/net/sunxi_emac.c
@@ -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;
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c
index 5b91fe3dce..3be76c99ee 100644
--- a/drivers/pci/pci-uclass.c
+++ b/drivers/pci/pci-uclass.c
@@ -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;
diff --git a/drivers/pci/pci_compat.c b/drivers/pci/pci_compat.c
index d6938c198f..05c35105ab 100644
--- a/drivers/pci/pci_compat.c
+++ b/drivers/pci/pci_compat.c
@@ -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);
}
diff --git a/drivers/power/pmic/pmic-uclass.c b/drivers/power/pmic/pmic-uclass.c
index 812ac13baa..d99cb9aada 100644
--- a/drivers/power/pmic/pmic-uclass.c
+++ b/drivers/power/pmic/pmic-uclass.c
@@ -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>
@@ -17,16 +18,6 @@
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",
diff --git a/drivers/power/regulator/regulator-uclass.c b/drivers/power/regulator/regulator-uclass.c
index 31ffd44454..12e141b4ad 100644
--- a/drivers/power/regulator/regulator-uclass.c
+++ b/drivers/power/regulator/regulator-uclass.c
@@ -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
index 0000000000..642a2d8948
--- /dev/null
+++ b/drivers/ram/Kconfig
@@ -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
index 0000000000..0e102491a4
--- /dev/null
+++ b/drivers/ram/Makefile
@@ -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
index 0000000000..2f1fbe7c97
--- /dev/null
+++ b/drivers/ram/ram-uclass.c
@@ -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
index 0000000000..06bf3ece2c
--- /dev/null
+++ b/drivers/ram/sandbox_ram.c
@@ -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,
+};
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c
index 9b044a37da..c8a77e295e 100644
--- a/drivers/serial/ns16550.c
+++ b/drivers/serial/ns16550.c
@@ -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
diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c
index 737ae64052..d666272e39 100644
--- a/drivers/spi/spi-uclass.c
+++ b/drivers/spi/spi-uclass.c
@@ -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);
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 637ef3d567..3fa5b2e37e 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -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"
diff --git a/drivers/usb/eth/asix.c b/drivers/usb/eth/asix.c
index c8697ae78d..72ec41ea89 100644
--- a/drivers/usb/eth/asix.c
+++ b/drivers/usb/eth/asix.c
@@ -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 */
@@ -92,14 +92,20 @@
#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
diff --git a/drivers/usb/eth/usb_ether.c b/drivers/usb/eth/usb_ether.c
index c72b7e47c4..63785a9c59 100644
--- a/drivers/usb/eth/usb_ether.c
+++ b/drivers/usb/eth/usb_ether.c
@@ -6,11 +6,137 @@
#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
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index bf02221c9f..3a0d32ee2b 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -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;
}
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index b9eabc5593..0cb9fcc166 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -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 */
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 774282d287..3379c293c4 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -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
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index 6f33456c90..373e04cbe5 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -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>
diff --git a/drivers/usb/host/r8a66597.h b/drivers/usb/host/r8a66597.h
index ca1b67155e..67dc3c4588 100644
--- a/drivers/usb/host/r8a66597.h
+++ b/drivers/usb/host/r8a66597.h
@@ -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__
diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c
index 6e86f4a24a..c5d1e7feb9 100644
--- a/drivers/usb/host/usb-uclass.c
+++ b/drivers/usb/host/usb-uclass.c
@@ -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;
diff --git a/drivers/usb/musb-new/am35x.c b/drivers/usb/musb-new/am35x.c
index 857d7eb0cc..d158454a08 100644
--- a/drivers/usb/musb-new/am35x.c
+++ b/drivers/usb/musb-new/am35x.c
@@ -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
}
/*
diff --git a/drivers/usb/musb-new/musb_core.c b/drivers/usb/musb-new/musb_core.c
index 242cc30b1c..f530af4fb7 100644
--- a/drivers/usb/musb-new/musb_core.c
+++ b/drivers/usb/musb-new/musb_core.c
@@ -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
}
diff --git a/drivers/usb/musb-new/musb_core.h b/drivers/usb/musb-new/musb_core.h
index 2695742098..8727f6415e 100644
--- a/drivers/usb/musb-new/musb_core.h
+++ b/drivers/usb/musb-new/musb_core.h
@@ -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)
{
diff --git a/drivers/usb/musb-new/musb_dsps.c b/drivers/usb/musb-new/musb_dsps.c
index 17ed224488..895939773a 100644
--- a/drivers/usb/musb-new/musb_dsps.c
+++ b/drivers/usb/musb-new/musb_dsps.c
@@ -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
}
diff --git a/drivers/usb/musb-new/musb_gadget_ep0.c b/drivers/usb/musb-new/musb_gadget_ep0.c
index 5a715013a2..415a9f21a9 100644
--- a/drivers/usb/musb-new/musb_gadget_ep0.c
+++ b/drivers/usb/musb-new/musb_gadget_ep0.c
@@ -43,6 +43,7 @@
#else
#include <common.h>
#include "linux-compat.h"
+#include <asm/processor.h>
#endif
#include "musb_core.h"
diff --git a/drivers/usb/musb-new/musb_host.c b/drivers/usb/musb-new/musb_host.c
index 437309ceb4..40b9c66af8 100644
--- a/drivers/usb/musb-new/musb_host.c
+++ b/drivers/usb/musb-new/musb_host.c
@@ -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) {
diff --git a/drivers/usb/musb-new/musb_uboot.c b/drivers/usb/musb-new/musb_uboot.c
index d1ee5f8d06..9b56e904e4 100644
--- a/drivers/usb/musb-new/musb_uboot.c
+++ b/drivers/usb/musb-new/musb_uboot.c
@@ -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
index 0000000000..6312cd2148
--- /dev/null
+++ b/drivers/usb/musb-new/musb_uboot.h
@@ -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
diff --git a/drivers/usb/musb-new/omap2430.c b/drivers/usb/musb-new/omap2430.c
index 31a280edba..77273a49a3 100644
--- a/drivers/usb/musb-new/omap2430.c
+++ b/drivers/usb/musb-new/omap2430.c
@@ -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
}
diff --git a/drivers/usb/musb-new/sunxi.c b/drivers/usb/musb-new/sunxi.c
index 052e0657d0..c123d61af2 100644
--- a/drivers/usb/musb-new/sunxi.c
+++ b/drivers/usb/musb-new/sunxi.c
@@ -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)
diff --git a/drivers/usb/musb-new/usb-compat.h b/drivers/usb/musb-new/usb-compat.h
index 50bad378c5..53fe4ff3c4 100644
--- a/drivers/usb/musb-new/usb-compat.h
+++ b/drivers/usb/musb-new/usb-compat.h
@@ -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__ */
diff --git a/dts/Kconfig b/dts/Kconfig
index 957f5c7ffa..09cfefbd35 100644
--- a/dts/Kconfig
+++ b/dts/Kconfig
@@ -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
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h
index db0550b67c..7ef3e259b4 100644
--- a/include/asm-generic/global_data.h
+++ b/include/asm-generic/global_data.h
@@ -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 */
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index de91e57efc..0af599f86d 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -322,6 +322,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
*
* This is used to convert a named GPIO into a device, offset and GPIO
@@ -421,6 +434,18 @@ int gpio_request_list_by_name(struct udevice *dev, const char *list_name,
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
*
* Counts the GPIOs in a list. See gpio_request_by_name() for additional
diff --git a/include/clk.h b/include/clk.h
index df4570c6f5..254ad2b876 100644
--- a/include/clk.h
+++ b/include/clk.h
@@ -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_ */
diff --git a/include/common.h b/include/common.h
index 8f4b2ec212..4566bd1111 100644
--- a/include/common.h
+++ b/include/common.h
@@ -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>
diff --git a/include/configs/minnowmax.h b/include/configs/minnowmax.h
index af36ac5caf..4781e792f9 100644
--- a/include/configs/minnowmax.h
+++ b/include/configs/minnowmax.h
@@ -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
diff --git a/include/debug_uart.h b/include/debug_uart.h
index f56797b72f..a75e377dc0 100644
--- a/include/debug_uart.h
+++ b/include/debug_uart.h
@@ -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); \
}
diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h
index 687462b093..402304f19e 100644
--- a/include/dm/device-internal.h
+++ b/include/dm/device-internal.h
@@ -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
diff --git a/include/dm/device.h b/include/dm/device.h
index 18296bb686..9fa0048bd0 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -386,10 +386,24 @@ 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
*
* @parent: Parent device to search
diff --git a/include/dm/platdata.h b/include/dm/platdata.h
index fbc8a6b3ad..6f4f00140e 100644
--- a/include/dm/platdata.h
+++ b/include/dm/platdata.h
@@ -16,6 +16,10 @@
/**
* 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)
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index c7310d7ca0..bc057d7adf 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -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 */
diff --git a/include/dm/util.h b/include/dm/util.h
index 0cec17b52a..7dbed6793f 100644
--- a/include/dm/util.h
+++ b/include/dm/util.h
@@ -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
diff --git a/include/dwmmc.h b/include/dwmmc.h
index 86a54918f9..7a7555a73a 100644
--- a/include/dwmmc.h
+++ b/include/dwmmc.h
@@ -129,8 +129,24 @@
/* 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;
diff --git a/include/image.h b/include/image.h
index b6eb57e187..63c3d37f20 100644
--- a/include/image.h
+++ b/include/image.h
@@ -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
index 0000000000..b929d0ca3c
--- /dev/null
+++ b/include/led.h
@@ -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
diff --git a/include/libfdt.h b/include/libfdt.h
index 421d64fd8b..e48c21aced 100644
--- a/include/libfdt.h
+++ b/include/libfdt.h
@@ -121,7 +121,12 @@
/* 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 */
diff --git a/include/linux/compat.h b/include/linux/compat.h
index 6ff3915216..fbebf910ad 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -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)
diff --git a/include/mmc.h b/include/mmc.h
index dd98b3b8ac..cda9a19ce0 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -266,6 +266,28 @@
#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;
diff --git a/include/net.h b/include/net.h
index d17173d818..d09bec9de1 100644
--- a/include/net.h
+++ b/include/net.h
@@ -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
diff --git a/include/pci.h b/include/pci.h
index 542e68bceb..94bca97512 100644
--- a/include/pci.h
+++ b/include/pci.h
@@ -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;
@@ -805,6 +808,14 @@ struct dm_pci_ops {
#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
*
* Scan a PCI bus looking for devices. Bind each one that is found. If
@@ -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 */
diff --git a/include/power/pmic.h b/include/power/pmic.h
index eb152ef492..6ba4b6ecd6 100644
--- a/include/power/pmic.h
+++ b/include/power/pmic.h
@@ -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
diff --git a/include/power/regulator.h b/include/power/regulator.h
index 03a2cefcd6..015229027c 100644
--- a/include/power/regulator.h
+++ b/include/power/regulator.h
@@ -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:
diff --git a/include/power/sandbox_pmic.h b/include/power/sandbox_pmic.h
index ae142921e5..8547674971 100644
--- a/include/power/sandbox_pmic.h
+++ b/include/power/sandbox_pmic.h
@@ -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
index 0000000000..e2172a8741
--- /dev/null
+++ b/include/ram.h
@@ -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
index 0000000000..ea409c2f3e
--- /dev/null
+++ b/include/rc4.h
@@ -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
index 0000000000..eccf7707f4
--- /dev/null
+++ b/include/regmap.h
@@ -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
index 0000000000..383761eb1f
--- /dev/null
+++ b/include/reset.h
@@ -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
diff --git a/include/spl.h b/include/spl.h
index d19940f2a3..8e53426142 100644
--- a/include/spl.h
+++ b/include/spl.h
@@ -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
index 0000000000..c62ccd61b3
--- /dev/null
+++ b/include/syscon.h
@@ -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
diff --git a/include/test/ut.h b/include/test/ut.h
index 5e5aa6ce41..da7c1a9d26 100644
--- a/include/test/ut.h
+++ b/include/test/ut.h
@@ -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)
diff --git a/include/usb.h b/include/usb.h
index dca512d394..cf00ffdf53 100644
--- a/include/usb.h
+++ b/include/usb.h
@@ -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
*
@@ -730,26 +747,18 @@ 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
diff --git a/include/usb_ether.h b/include/usb_ether.h
index 23507e19e6..c6d1416048 100644
--- a/include/usb_ether.h
+++ b/include/usb_ether.h
@@ -19,25 +19,91 @@
#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__ */
diff --git a/include/vsprintf.h b/include/vsprintf.h
index d2fcca3f5a..b5bc9c1d95 100644
--- a/include/vsprintf.h
+++ b/include/vsprintf.h
@@ -41,6 +41,32 @@ unsigned long long simple_strtoull(const char *cp, char **endp,
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
*
* Prints a message on the console(s) and then resets. If CONFIG_PANIC_HANG is
diff --git a/lib/Kconfig b/lib/Kconfig
index c98d3997b7..972ac1793d 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -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"
diff --git a/lib/Makefile b/lib/Makefile
index 97ed398ade..fd106b91c8 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -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
index 0000000000..641b8064c1
--- /dev/null
+++ b/lib/dhry/Kconfig
@@ -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
index 0000000000..926c0d6192
--- /dev/null
+++ b/lib/dhry/Makefile
@@ -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
index 0000000000..5dc191ea62
--- /dev/null
+++ b/lib/dhry/cmd_dhry.c
@@ -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
index 0000000000..49d4223956
--- /dev/null
+++ b/lib/dhry/dhry.h
@@ -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
index 0000000000..be6371053f
--- /dev/null
+++ b/lib/dhry/dhry_1.c
@@ -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
index 0000000000..59aa458a34
--- /dev/null
+++ b/lib/dhry/dhry_2.c
@@ -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 */
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 9c6b3619da..232ca74712 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -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;
}
diff --git a/lib/libfdt/Makefile b/lib/libfdt/Makefile
index 2f5413f90d..934d6142c3 100644
--- a/lib/libfdt/Makefile
+++ b/lib/libfdt/Makefile
@@ -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
index 0000000000..9fea775a97
--- /dev/null
+++ b/lib/libfdt/fdt_region.c
@@ -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;
+}
diff --git a/lib/libfdt/fdt_rw.c b/lib/libfdt/fdt_rw.c
index bec8b8ad89..1a358a8ca0 100644
--- a/lib/libfdt/fdt_rw.c
+++ b/lib/libfdt/fdt_rw.c
@@ -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;
+}
diff --git a/lib/linux_compat.c b/lib/linux_compat.c
index a3d4675f7e..a936a7eac2 100644
--- a/lib/linux_compat.c
+++ b/lib/linux_compat.c
@@ -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
index 0000000000..89d15f3c82
--- /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];
+ }
+}
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index a9b8a3ae67..4c82837cc4 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -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')
diff --git a/net/eth.c b/net/eth.c
index 953b7310bd..d3ec8d64d5 100644
--- 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)
diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl
index 481ee5ea02..b1047b5d09 100644
--- a/scripts/Makefile.spl
+++ b/scripts/Makefile.spl
@@ -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 $@ $<
diff --git a/test/dm/Makefile b/test/dm/Makefile
index 19ad2fb99f..eda9643185 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -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
index 0000000000..9ff6d95103
--- /dev/null
+++ b/test/dm/clk.c
@@ -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);
diff --git a/test/dm/cmd_dm.c b/test/dm/cmd_dm.c
index 5bb2a99c8f..5c501ec254 100644
--- a/test/dm/cmd_dm.c
+++ b/test/dm/cmd_dm.c
@@ -14,96 +14,20 @@
#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
index 0000000000..8ee075cf1c
--- /dev/null
+++ b/test/dm/led.c
@@ -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
index 0000000000..046142322d
--- /dev/null
+++ b/test/dm/mmc.c
@@ -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
index 0000000000..3a7c5fffdd
--- /dev/null
+++ b/test/dm/ram.c
@@ -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
index 0000000000..7f66058735
--- /dev/null
+++ b/test/dm/regmap.c
@@ -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);
diff --git a/test/dm/regulator.c b/test/dm/regulator.c
index d279c04c84..3d0056f2dc 100644
--- a/test/dm/regulator.c
+++ b/test/dm/regulator.c
@@ -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
index 0000000000..5d53f252bb
--- /dev/null
+++ b/test/dm/reset.c
@@ -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
index 0000000000..36424816b8
--- /dev/null
+++ b/test/dm/syscon.c
@@ -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);
diff --git a/test/dm/test-main.c b/test/dm/test-main.c
index 0477d2fa73..0e43ab9548 100644
--- a/test/dm/test-main.c
+++ b/test/dm/test-main.c
@@ -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());
diff --git a/tools/Makefile b/tools/Makefile
index 8ff9c2e108..98414f736a 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -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
index 0000000000..caaf6006a5
--- /dev/null
+++ b/tools/fdtgrep.c
@@ -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;
+}
diff --git a/tools/imagetool.h b/tools/imagetool.h
index b7874f47cd..99bbf2f459 100644
--- a/tools/imagetool.h
+++ b/tools/imagetool.h
@@ -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 */
};
/*
diff --git a/tools/mkimage.c b/tools/mkimage.c
index 5ccd951048..e81d455083 100644
--- a/tools/mkimage.c
+++ b/tools/mkimage.c
@@ -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);
}
OpenPOWER on IntegriCloud