From 5e8a749c2895377753b8f773b12f6d4090466a33 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 29 Oct 2014 13:08:55 -0600 Subject: dm: at91: Correct text base for snapper9260 The value should be 0x21f00000. Fix it. Signed-off-by: Simon Glass --- include/configs/snapper9260.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/configs/snapper9260.h b/include/configs/snapper9260.h index 1ebee714ba3..6909e995404 100644 --- a/include/configs/snapper9260.h +++ b/include/configs/snapper9260.h @@ -15,7 +15,7 @@ #include #include -#define CONFIG_SYS_TEXT_BASE 0x20000000 +#define CONFIG_SYS_TEXT_BASE 0x21f00000 /* ARM asynchronous clock */ #define CONFIG_SYS_AT91_MAIN_CLOCK 18432000 /* External Crystal, in Hz */ -- cgit v1.3.1 From cd052cd9353cb483e3a4852cedbd6860bfb488c4 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 29 Oct 2014 13:08:56 -0600 Subject: dm: at91: Move snapper9260 to generic baord This works correctly, so switch it over before the deadline. Signed-off-by: Simon Glass --- include/configs/snapper9260.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/configs/snapper9260.h b/include/configs/snapper9260.h index 6909e995404..e2e623ee7f4 100644 --- a/include/configs/snapper9260.h +++ b/include/configs/snapper9260.h @@ -20,6 +20,7 @@ /* ARM asynchronous clock */ #define CONFIG_SYS_AT91_MAIN_CLOCK 18432000 /* External Crystal, in Hz */ #define CONFIG_SYS_AT91_SLOW_CLOCK 32768 +#define CONFIG_SYS_GENERIC_BOARD /* CPU */ #define CONFIG_ARCH_CPU_INIT -- cgit v1.3.1 From 1a1927f3a3c6cf0a0bfb51c0d9b3139ed2cb7a31 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 29 Oct 2014 13:09:01 -0600 Subject: dm: at91: Convert snapper9260 to use driver model MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert this at91sam9260-based board to use driver model. This should serve as an example for other similar boards. Serial and GPIO are supported so far. Signed-off-by: Simon Glass Acked-by: Andreas Bießmann --- board/bluewater/snapper9260/snapper9260.c | 18 ++++++++++++++++-- include/configs/snapper9260.h | 9 ++++++++- 2 files changed, 24 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/board/bluewater/snapper9260/snapper9260.c b/board/bluewater/snapper9260/snapper9260.c index bfde1291a59..95633b0d2e8 100644 --- a/board/bluewater/snapper9260/snapper9260.c +++ b/board/bluewater/snapper9260/snapper9260.c @@ -9,12 +9,15 @@ */ #include +#include #include +#include #include #include #include #include #include +#include #include #include #include @@ -95,10 +98,12 @@ static void nand_hw_init(void) &smc->cs[3].mode); /* Configure RDY/BSY */ - at91_set_gpio_input(CONFIG_SYS_NAND_READY_PIN, 1); + gpio_request(CONFIG_SYS_NAND_READY_PIN, "nand_rdy"); + gpio_direction_input(CONFIG_SYS_NAND_READY_PIN); /* Enable NandFlash */ - at91_set_gpio_output(CONFIG_SYS_NAND_ENABLE_PIN, 1); + gpio_request(CONFIG_SYS_NAND_ENABLE_PIN, "nand_ce"); + gpio_direction_output(CONFIG_SYS_NAND_ENABLE_PIN, 1); } int board_init(void) @@ -140,3 +145,12 @@ int dram_init(void) void reset_phy(void) { } + +static struct atmel_serial_platdata at91sam9260_serial_plat = { + .base_addr = ATMEL_BASE_DBGU, +}; + +U_BOOT_DEVICE(at91sam9260_serial) = { + .name = "serial_atmel", + .platdata = &at91sam9260_serial_plat, +}; diff --git a/include/configs/snapper9260.h b/include/configs/snapper9260.h index e2e623ee7f4..942af2e7f62 100644 --- a/include/configs/snapper9260.h +++ b/include/configs/snapper9260.h @@ -21,6 +21,11 @@ #define CONFIG_SYS_AT91_MAIN_CLOCK 18432000 /* External Crystal, in Hz */ #define CONFIG_SYS_AT91_SLOW_CLOCK 32768 #define CONFIG_SYS_GENERIC_BOARD +#define CONFIG_DM +#define CONFIG_CMD_DM +#define CONFIG_DM_GPIO +#define CONFIG_DM_SERIAL +#define CONFIG_SYS_MALLOC_F_LEN (1 << 10) /* CPU */ #define CONFIG_ARCH_CPU_INIT @@ -85,8 +90,10 @@ /* UARTs/Serial console */ #define CONFIG_ATMEL_USART +#ifndef CONFIG_DM_SERIAL #define CONFIG_USART_BASE ATMEL_BASE_DBGU #define CONFIG_USART_ID ATMEL_ID_SYS +#endif #define CONFIG_BAUDRATE 115200 #define CONFIG_SYS_PROMPT "Snapper> " @@ -160,7 +167,7 @@ #define CONFIG_CMD_DHCP #define CONFIG_CMD_FAT #define CONFIG_CMD_I2C -#undef CONFIG_CMD_GPIO +#define CONFIG_CMD_GPIO #define CONFIG_CMD_USB #define CONFIG_CMD_MII #define CONFIG_CMD_NAND -- cgit v1.3.1 From 9dacbb277255c432047f6df8fe21505b9c8cf485 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 10 Nov 2014 17:16:42 -0700 Subject: dm: tegra: Avoid using arch-specific memcpy() in SPL The faster functions are not actually available in SPL and the code size likely isn't worth it. Use the normal memcpy() in SPL. Signed-off-by: Simon Glass --- include/configs/tegra-common.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/configs/tegra-common.h b/include/configs/tegra-common.h index 5d2b12a11d1..d690045eb04 100644 --- a/include/configs/tegra-common.h +++ b/include/configs/tegra-common.h @@ -118,7 +118,9 @@ #define CONFIG_SYS_MEMTEST_START (NV_PA_SDRC_CS0 + 0x600000) #define CONFIG_SYS_MEMTEST_END (CONFIG_SYS_MEMTEST_START + 0x100000) +#ifndef CONFIG_SPL_BUILD #define CONFIG_USE_ARCH_MEMCPY +#endif /*----------------------------------------------------------------------- * Physical Memory Map -- cgit v1.3.1 From c9356be30741b5192c79038fa4f8a2ac5b5f35c1 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 10 Nov 2014 17:16:43 -0700 Subject: dm: Split the simple malloc() implementation into its own file The simple malloc() implementation is used when memory is tight. It provides a simple buffer with an incrementing pointer. At present the implementation is inside dlmalloc. Move it into its own file so that it is easier to find. Rather than using relocation as a signal that the full malloc() is available, add a special GD_FLG_FULL_MALLOC_INIT flag. This signals that the simple malloc() should no longer be used. In some cases, such as SPL, even the code space used by the full malloc() is wasteful. Add a CONFIG_SYS_MALLOC_SIMPLE option to provide only the simple malloc. In this case the full malloc is not available at all. It saves about 1KB of code space and about 0.5KB of data on Thumb 2. Acked-by: Tom Rini Signed-off-by: Simon Glass --- common/Makefile | 3 ++ common/board_r.c | 3 +- common/dlmalloc.c | 19 ++++--------- common/malloc_simple.c | 39 +++++++++++++++++++++++++ include/asm-generic/global_data.h | 1 + include/malloc.h | 60 ++++++++++++++++++++++++--------------- 6 files changed, 87 insertions(+), 38 deletions(-) create mode 100644 common/malloc_simple.c (limited to 'include') diff --git a/common/Makefile b/common/Makefile index 6cc4de8a73f..7a5c58e41c2 100644 --- a/common/Makefile +++ b/common/Makefile @@ -251,6 +251,9 @@ obj-$(CONFIG_BOUNCE_BUFFER) += bouncebuf.o obj-y += console.o obj-$(CONFIG_CROS_EC) += cros_ec.o obj-y += dlmalloc.o +ifdef CONFIG_SYS_MALLOC_F_LEN +obj-y += malloc_simple.o +endif obj-y += image.o obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o obj-$(CONFIG_OF_LIBFDT) += image-fdt.o diff --git a/common/board_r.c b/common/board_r.c index 7c339008ed2..19c64271ab9 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -99,7 +99,8 @@ static int initr_trace(void) static int initr_reloc(void) { - gd->flags |= GD_FLG_RELOC; /* tell others: relocation done */ + /* tell others: relocation done */ + gd->flags |= GD_FLG_RELOC | GD_FLG_FULL_MALLOC_INIT; bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_R, "board_init_r"); return 0; diff --git a/common/dlmalloc.c b/common/dlmalloc.c index 991229d5f78..6453ee9c259 100644 --- a/common/dlmalloc.c +++ b/common/dlmalloc.c @@ -2184,17 +2184,8 @@ Void_t* mALLOc(bytes) size_t bytes; INTERNAL_SIZE_T nb; #ifdef CONFIG_SYS_MALLOC_F_LEN - if (gd && !(gd->flags & GD_FLG_RELOC)) { - ulong new_ptr; - void *ptr; - - new_ptr = gd->malloc_ptr + bytes; - if (new_ptr > gd->malloc_limit) - panic("Out of pre-reloc memory"); - ptr = map_sysmem(gd->malloc_base + gd->malloc_ptr, bytes); - gd->malloc_ptr = ALIGN(new_ptr, sizeof(new_ptr)); - return ptr; - } + if (gd && !(gd->flags & GD_FLG_FULL_MALLOC_INIT)) + return malloc_simple(bytes); #endif /* check if mem_malloc_init() was run */ @@ -2462,7 +2453,7 @@ void fREe(mem) Void_t* mem; #ifdef CONFIG_SYS_MALLOC_F_LEN /* free() is a no-op - all the memory will be freed on relocation */ - if (!(gd->flags & GD_FLG_RELOC)) + if (!(gd->flags & GD_FLG_FULL_MALLOC_INIT)) return; #endif @@ -2618,7 +2609,7 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes; if (oldmem == NULL) return mALLOc(bytes); #ifdef CONFIG_SYS_MALLOC_F_LEN - if (!(gd->flags & GD_FLG_RELOC)) { + if (!(gd->flags & GD_FLG_FULL_MALLOC_INIT)) { /* This is harder to support and should not be needed */ panic("pre-reloc realloc() is not supported"); } @@ -2970,7 +2961,7 @@ Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size; else { #ifdef CONFIG_SYS_MALLOC_F_LEN - if (!(gd->flags & GD_FLG_RELOC)) { + if (!(gd->flags & GD_FLG_FULL_MALLOC_INIT)) { MALLOC_ZERO(mem, sz); return mem; } diff --git a/common/malloc_simple.c b/common/malloc_simple.c new file mode 100644 index 00000000000..afdacff80d8 --- /dev/null +++ b/common/malloc_simple.c @@ -0,0 +1,39 @@ +/* + * Simple malloc implementation + * + * Copyright (c) 2014 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +void *malloc_simple(size_t bytes) +{ + ulong new_ptr; + void *ptr; + + new_ptr = gd->malloc_ptr + bytes; + if (new_ptr > gd->malloc_limit) + panic("Out of pre-reloc memory"); + ptr = map_sysmem(gd->malloc_base + gd->malloc_ptr, bytes); + gd->malloc_ptr = ALIGN(new_ptr, sizeof(new_ptr)); + return ptr; +} + +#ifdef CONFIG_SYS_MALLOC_SIMPLE +void *calloc(size_t nmemb, size_t elem_size) +{ + size_t size = nmemb * elem_size; + void *ptr; + + ptr = malloc(size); + memset(ptr, '\0', size); + + return ptr; +} +#endif diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index 74df2100336..5e5dc3725a5 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -107,5 +107,6 @@ typedef struct global_data { #define GD_FLG_DISABLE_CONSOLE 0x00040 /* Disable console (in & out) */ #define GD_FLG_ENV_READY 0x00080 /* Env. imported into hash table */ #define GD_FLG_SERIAL_READY 0x00100 /* Pre-reloc serial console ready */ +#define GD_FLG_FULL_MALLOC_INIT 0x00200 /* Full malloc() is ready */ #endif /* __ASM_GENERIC_GBL_DATA_H */ diff --git a/include/malloc.h b/include/malloc.h index c33f3b494eb..5df634873f1 100644 --- a/include/malloc.h +++ b/include/malloc.h @@ -872,33 +872,46 @@ extern Void_t* sbrk(); #else -#ifdef USE_DL_PREFIX -#define cALLOc dlcalloc -#define fREe dlfree -#define mALLOc dlmalloc -#define mEMALIGn dlmemalign -#define rEALLOc dlrealloc -#define vALLOc dlvalloc -#define pvALLOc dlpvalloc -#define mALLINFo dlmallinfo -#define mALLOPt dlmallopt -#else /* USE_DL_PREFIX */ -#define cALLOc calloc -#define fREe free -#define mALLOc malloc -#define mEMALIGn memalign -#define rEALLOc realloc -#define vALLOc valloc -#define pvALLOc pvalloc -#define mALLINFo mallinfo -#define mALLOPt mallopt -#endif /* USE_DL_PREFIX */ +#ifdef CONFIG_SYS_MALLOC_SIMPLE +#define malloc malloc_simple +#define realloc realloc_simple +#define memalign memalign_simple +static inline void free(void *ptr) {} +void *calloc(size_t nmemb, size_t size); +void *memalign_simple(size_t alignment, size_t bytes); +void *realloc_simple(void *ptr, size_t size); +#else + +# ifdef USE_DL_PREFIX +# define cALLOc dlcalloc +# define fREe dlfree +# define mALLOc dlmalloc +# define mEMALIGn dlmemalign +# define rEALLOc dlrealloc +# define vALLOc dlvalloc +# define pvALLOc dlpvalloc +# define mALLINFo dlmallinfo +# define mALLOPt dlmallopt +# else /* USE_DL_PREFIX */ +# define cALLOc calloc +# define fREe free +# define mALLOc malloc +# define mEMALIGn memalign +# define rEALLOc realloc +# define vALLOc valloc +# define pvALLOc pvalloc +# define mALLINFo mallinfo +# define mALLOPt mallopt +# endif /* USE_DL_PREFIX */ #endif /* Public routines */ -#if __STD_C +/* Simple versions which can be used when space is tight */ +void *malloc_simple(size_t size); + +# if __STD_C Void_t* mALLOc(size_t); void fREe(Void_t*); @@ -913,7 +926,7 @@ size_t malloc_usable_size(Void_t*); void malloc_stats(void); int mALLOPt(int, int); struct mallinfo mALLINFo(void); -#else +# else Void_t* mALLOc(); void fREe(); Void_t* rEALLOc(); @@ -927,6 +940,7 @@ size_t malloc_usable_size(); void malloc_stats(); int mALLOPt(); struct mallinfo mALLINFo(); +# endif #endif /* -- cgit v1.3.1 From 3ac435d33a8f6a4e28df6bc068cb0569bc8061ad Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 10 Nov 2014 17:16:47 -0700 Subject: dm: Allow device removal features to be dropped For SPL we don't expect to need to remove a device. Save some code space by dropping this feature. The board config can define CONFIG_DM_DEVICE_REMOVE if this is in fact needed. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- drivers/core/Makefile | 3 +- drivers/core/device-remove.c | 187 +++++++++++++++++++++++++++++++++++++++++++ drivers/core/device.c | 168 -------------------------------------- include/config_defaults.h | 4 + include/dm/device-internal.h | 10 +++ 5 files changed, 203 insertions(+), 169 deletions(-) create mode 100644 drivers/core/device-remove.c (limited to 'include') diff --git a/drivers/core/Makefile b/drivers/core/Makefile index 151c2398a4d..f14695b2d6e 100644 --- a/drivers/core/Makefile +++ b/drivers/core/Makefile @@ -4,5 +4,6 @@ # SPDX-License-Identifier: GPL-2.0+ # -obj-y := device.o lists.o root.o uclass.o util.o +obj-$(CONFIG_DM) += device.o lists.o root.o uclass.o util.o obj-$(CONFIG_OF_CONTROL) += simple-bus.o +obj-$(CONFIG_DM_DEVICE_REMOVE) += device-remove.o diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c new file mode 100644 index 00000000000..8fc6b710842 --- /dev/null +++ b/drivers/core/device-remove.c @@ -0,0 +1,187 @@ +/* + * Device manager + * + * Copyright (c) 2014 Google, Inc + * + * (C) Copyright 2012 + * Pavel Herrmann + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * 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) +{ + struct udevice *pos, *n; + int ret, saved_ret = 0; + + assert(dev); + + list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) { + ret = device_unbind(pos); + if (ret && !saved_ret) + saved_ret = ret; + } + + 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) +{ + struct udevice *pos, *n; + int ret; + + assert(dev); + + list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) { + ret = device_remove(pos); + if (ret) + return ret; + } + + return 0; +} + +int device_unbind(struct udevice *dev) +{ + struct driver *drv; + int ret; + + if (!dev) + return -EINVAL; + + if (dev->flags & DM_FLAG_ACTIVATED) + return -EINVAL; + + drv = dev->driver; + assert(drv); + + if (drv->unbind) { + ret = drv->unbind(dev); + if (ret) + return ret; + } + + ret = device_chld_unbind(dev); + if (ret) + return ret; + + ret = uclass_unbind_device(dev); + if (ret) + return ret; + + if (dev->parent) + list_del(&dev->sibling_node); + free(dev); + + return 0; +} + +/** + * device_free() - Free memory buffers allocated by a device + * @dev: Device that is to be started + */ +void device_free(struct udevice *dev) +{ + int size; + + if (dev->driver->priv_auto_alloc_size) { + free(dev->priv); + dev->priv = NULL; + } + if (dev->flags & DM_FLAG_ALLOC_PDATA) { + free(dev->platdata); + dev->platdata = NULL; + } + size = dev->uclass->uc_drv->per_device_auto_alloc_size; + if (size) { + free(dev->uclass_priv); + dev->uclass_priv = NULL; + } + if (dev->parent) { + size = dev->parent->driver->per_child_auto_alloc_size; + if (size) { + free(dev->parent_priv); + dev->parent_priv = NULL; + } + } +} + +int device_remove(struct udevice *dev) +{ + struct driver *drv; + int ret; + + if (!dev) + return -EINVAL; + + if (!(dev->flags & DM_FLAG_ACTIVATED)) + return 0; + + drv = dev->driver; + assert(drv); + + ret = uclass_pre_remove_device(dev); + if (ret) + return ret; + + ret = device_chld_remove(dev); + if (ret) + goto err; + + if (drv->remove) { + ret = drv->remove(dev); + if (ret) + goto err_remove; + } + + if (dev->parent && dev->parent->driver->child_post_remove) { + ret = dev->parent->driver->child_post_remove(dev); + if (ret) { + dm_warn("%s: Device '%s' failed child_post_remove()", + __func__, dev->name); + } + } + + device_free(dev); + + dev->seq = -1; + dev->flags &= ~DM_FLAG_ACTIVATED; + + return ret; + +err_remove: + /* We can't put the children back */ + dm_warn("%s: Device '%s' failed to remove, but children are gone\n", + __func__, dev->name); +err: + ret = uclass_post_probe_device(dev); + if (ret) { + dm_warn("%s: Device '%s' failed to post_probe on error path\n", + __func__, dev->name); + } + + return ret; +} diff --git a/drivers/core/device.c b/drivers/core/device.c index 49faa29dc1a..576a4f253b8 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -24,52 +24,6 @@ DECLARE_GLOBAL_DATA_PTR; -/** - * 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) -{ - struct udevice *pos, *n; - int ret, saved_ret = 0; - - assert(dev); - - list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) { - ret = device_unbind(pos); - if (ret && !saved_ret) - saved_ret = ret; - } - - 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) -{ - struct udevice *pos, *n; - int ret; - - assert(dev); - - list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) { - ret = device_remove(pos); - if (ret) - return ret; - } - - return 0; -} - int device_bind(struct udevice *parent, struct driver *drv, const char *name, void *platdata, int of_offset, struct udevice **devp) { @@ -167,71 +121,6 @@ int device_bind_by_name(struct udevice *parent, bool pre_reloc_only, -1, devp); } -int device_unbind(struct udevice *dev) -{ - struct driver *drv; - int ret; - - if (!dev) - return -EINVAL; - - if (dev->flags & DM_FLAG_ACTIVATED) - return -EINVAL; - - drv = dev->driver; - assert(drv); - - if (drv->unbind) { - ret = drv->unbind(dev); - if (ret) - return ret; - } - - ret = device_chld_unbind(dev); - if (ret) - return ret; - - ret = uclass_unbind_device(dev); - if (ret) - return ret; - - if (dev->parent) - list_del(&dev->sibling_node); - free(dev); - - return 0; -} - -/** - * device_free() - Free memory buffers allocated by a device - * @dev: Device that is to be started - */ -static void device_free(struct udevice *dev) -{ - int size; - - if (dev->driver->priv_auto_alloc_size) { - free(dev->priv); - dev->priv = NULL; - } - if (dev->flags & DM_FLAG_ALLOC_PDATA) { - free(dev->platdata); - dev->platdata = NULL; - } - size = dev->uclass->uc_drv->per_device_auto_alloc_size; - if (size) { - free(dev->uclass_priv); - dev->uclass_priv = NULL; - } - if (dev->parent) { - size = dev->parent->driver->per_child_auto_alloc_size; - if (size) { - free(dev->parent_priv); - dev->parent_priv = NULL; - } - } -} - int device_probe_child(struct udevice *dev, void *parent_priv) { struct driver *drv; @@ -342,63 +231,6 @@ int device_probe(struct udevice *dev) return device_probe_child(dev, NULL); } -int device_remove(struct udevice *dev) -{ - struct driver *drv; - int ret; - - if (!dev) - return -EINVAL; - - if (!(dev->flags & DM_FLAG_ACTIVATED)) - return 0; - - drv = dev->driver; - assert(drv); - - ret = uclass_pre_remove_device(dev); - if (ret) - return ret; - - ret = device_chld_remove(dev); - if (ret) - goto err; - - if (drv->remove) { - ret = drv->remove(dev); - if (ret) - goto err_remove; - } - - if (dev->parent && dev->parent->driver->child_post_remove) { - ret = dev->parent->driver->child_post_remove(dev); - if (ret) { - dm_warn("%s: Device '%s' failed child_post_remove()", - __func__, dev->name); - } - } - - device_free(dev); - - dev->seq = -1; - dev->flags &= ~DM_FLAG_ACTIVATED; - - return ret; - -err_remove: - /* We can't put the children back */ - dm_warn("%s: Device '%s' failed to remove, but children are gone\n", - __func__, dev->name); -err: - ret = uclass_post_probe_device(dev); - if (ret) { - dm_warn("%s: Device '%s' failed to post_probe on error path\n", - __func__, dev->name); - } - - return ret; -} - void *dev_get_platdata(struct udevice *dev) { if (!dev) { diff --git a/include/config_defaults.h b/include/config_defaults.h index ad08c1d335d..985f055ccef 100644 --- a/include/config_defaults.h +++ b/include/config_defaults.h @@ -20,4 +20,8 @@ #define CONFIG_ZLIB 1 #define CONFIG_PARTITIONS 1 +#ifndef CONFIG_SPL_BUILD +#define CONFIG_DM_DEVICE_REMOVE +#endif + #endif diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h index 44cb7ef93bf..f0cc7947505 100644 --- a/include/dm/device-internal.h +++ b/include/dm/device-internal.h @@ -87,7 +87,11 @@ int device_probe_child(struct udevice *dev, void *parent_priv); * @dev: Pointer to device to remove * @return 0 if OK, -ve on error (an error here is normally a very bad thing) */ +#ifdef CONFIG_DM_DEVICE_REMOVE int device_remove(struct udevice *dev); +#else +static inline int device_remove(struct udevice *dev) { return 0; } +#endif /** * device_unbind() - Unbind a device, destroying it @@ -99,6 +103,12 @@ int device_remove(struct udevice *dev); */ int device_unbind(struct udevice *dev); +#ifdef CONFIG_DM_DEVICE_REMOVE +void device_free(struct udevice *dev); +#else +static inline void device_free(struct udevice *dev) {} +#endif + /* Cast away any volatile pointer */ #define DM_ROOT_NON_CONST (((gd_t *)gd)->dm_root) #define DM_UCLASS_ROOT_NON_CONST (((gd_t *)gd)->uclass_root) -- cgit v1.3.1 From 236f2bd30262f564c0bb71638105e525ddf47b9f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 10 Nov 2014 17:16:48 -0700 Subject: dm: Allow stdio registration to be dropped Provide a CONFIG_DM_STDIO option to enable registering a serial device with the stdio library. This is seldom useful in SPL, so disable it by default when building for SPL. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- drivers/serial/serial-uclass.c | 10 +++++++--- include/config_defaults.h | 1 + 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c index 632933f5cc3..cd5324cfa3b 100644 --- a/drivers/serial/serial-uclass.c +++ b/drivers/serial/serial-uclass.c @@ -163,10 +163,12 @@ void serial_stdio_init(void) { } +#ifdef CONFIG_DM_STDIO static void serial_stub_putc(struct stdio_dev *sdev, const char ch) { _serial_putc(sdev->priv, ch); } +#endif void serial_stub_puts(struct stdio_dev *sdev, const char *str) { @@ -246,9 +248,11 @@ U_BOOT_ENV_CALLBACK(baudrate, on_baudrate); static int serial_post_probe(struct udevice *dev) { - struct stdio_dev sdev; struct dm_serial_ops *ops = serial_get_ops(dev); +#ifdef CONFIG_DM_STDIO struct serial_dev_priv *upriv = dev->uclass_priv; + struct stdio_dev sdev; +#endif int ret; /* Set the baud rate */ @@ -258,9 +262,9 @@ static int serial_post_probe(struct udevice *dev) return ret; } +#ifdef CONFIG_DM_STDIO if (!(gd->flags & GD_FLG_RELOC)) return 0; - memset(&sdev, '\0', sizeof(sdev)); strncpy(sdev.name, dev->name, sizeof(sdev.name)); @@ -271,7 +275,7 @@ static int serial_post_probe(struct udevice *dev) sdev.getc = serial_stub_getc; sdev.tstc = serial_stub_tstc; stdio_register_dev(&sdev, &upriv->sdev); - +#endif return 0; } diff --git a/include/config_defaults.h b/include/config_defaults.h index 985f055ccef..f1b225d670e 100644 --- a/include/config_defaults.h +++ b/include/config_defaults.h @@ -22,6 +22,7 @@ #ifndef CONFIG_SPL_BUILD #define CONFIG_DM_DEVICE_REMOVE +#define CONFIG_DM_STDIO #endif #endif -- cgit v1.3.1 From a94f468fa292c43be7ac9fe35adea5065fbc2a28 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 10 Nov 2014 17:16:49 -0700 Subject: dm: Disable dm_warn() in SPL Since this function can use up quite a bit of space for its strings, disable it by default in SPL. Use CONFIG_DM_WARN to re-enable it. Signed-off-by: Simon Glass Reviewed-by: Tom Rini --- include/config_defaults.h | 1 + include/dm/util.h | 6 ++++++ 2 files changed, 7 insertions(+) (limited to 'include') diff --git a/include/config_defaults.h b/include/config_defaults.h index f1b225d670e..4d493150444 100644 --- a/include/config_defaults.h +++ b/include/config_defaults.h @@ -21,6 +21,7 @@ #define CONFIG_PARTITIONS 1 #ifndef CONFIG_SPL_BUILD +#define CONFIG_DM_WARN #define CONFIG_DM_DEVICE_REMOVE #define CONFIG_DM_STDIO #endif diff --git a/include/dm/util.h b/include/dm/util.h index 6ac3a38ef00..0cec17b52a4 100644 --- a/include/dm/util.h +++ b/include/dm/util.h @@ -7,7 +7,13 @@ #ifndef __DM_UTIL_H #define __DM_UTIL_H +#ifdef CONFIG_DM_WARN void dm_warn(const char *fmt, ...); +#else +static inline void dm_warn(const char *fmt, ...) +{ +} +#endif #ifdef DEBUG void dm_dbg(const char *fmt, ...); -- cgit v1.3.1 From 2ef249b4420818d7ea31a031f48825e5f38ed3ac Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 11 Nov 2014 10:46:18 -0700 Subject: dm: core: Allow access to the device's driver_id data When the device is created from a device tree node, it matches a compatible string. Allow access to that string and the associated data. Signed-off-by: Simon Glass Reviewed-by: Tom Rini Acked-by: Heiko Schocher --- drivers/core/device.c | 5 +++++ drivers/core/lists.c | 20 ++++++++++++++------ include/dm/device.h | 11 +++++++++++ 3 files changed, 30 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/drivers/core/device.c b/drivers/core/device.c index 576a4f253b8..81ddecade28 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -380,3 +380,8 @@ int device_find_next_child(struct udevice **devp) return 0; } + +ulong dev_get_of_data(struct udevice *dev) +{ + return dev->of_id->data; +} diff --git a/drivers/core/lists.c b/drivers/core/lists.c index 3a1ea856544..24d2864924b 100644 --- a/drivers/core/lists.c +++ b/drivers/core/lists.c @@ -83,28 +83,33 @@ int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only) * * @param blob: Device tree pointer * @param offset: Offset of node in device tree - * @param of_matchL List of compatible strings to match + * @param of_match: List of compatible strings to match + * @param of_idp: Returns the match that was found * @return 0 if there is a match, -ENOENT if no match, -ENODEV if the node * does not have a compatible string, other error <0 if there is a device * tree error */ static int driver_check_compatible(const void *blob, int offset, - const struct udevice_id *of_match) + const struct udevice_id *of_match, + const struct udevice_id **of_idp) { int ret; + *of_idp = NULL; if (!of_match) return -ENOENT; while (of_match->compatible) { ret = fdt_node_check_compatible(blob, offset, of_match->compatible); - if (!ret) + if (!ret) { + *of_idp = of_match; return 0; - else if (ret == -FDT_ERR_NOTFOUND) + } else if (ret == -FDT_ERR_NOTFOUND) { return -ENODEV; - else if (ret < 0) + } else if (ret < 0) { return -EINVAL; + } of_match++; } @@ -116,6 +121,7 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset, { struct driver *driver = ll_entry_start(struct driver, driver); const int n_ents = ll_entry_count(struct driver, driver); + const struct udevice_id *id; struct driver *entry; struct udevice *dev; bool found = false; @@ -127,7 +133,8 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset, if (devp) *devp = NULL; for (entry = driver; entry != driver + n_ents; entry++) { - ret = driver_check_compatible(blob, offset, entry->of_match); + ret = driver_check_compatible(blob, offset, entry->of_match, + &id); name = fdt_get_name(blob, offset, NULL); if (ret == -ENOENT) { continue; @@ -147,6 +154,7 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset, dm_warn("Error binding driver '%s'\n", entry->name); return ret; } else { + dev->of_id = id; found = true; if (devp) *devp = dev; diff --git a/include/dm/device.h b/include/dm/device.h index 9ce95a834e7..287504cb270 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -47,6 +47,7 @@ struct driver_info; * @name: Name of device, typically the FDT node name * @platdata: Configuration data for this device * @of_offset: Device tree node offset for this device (- for none) + * @of_id: Pointer to the udevice_id structure which created the device * @parent: Parent of this device, or NULL for the top level device * @priv: Private data for this device * @uclass: Pointer to uclass for this device @@ -65,6 +66,7 @@ struct udevice { const char *name; void *platdata; int of_offset; + const struct udevice_id *of_id; struct udevice *parent; void *priv; struct uclass *uclass; @@ -205,6 +207,15 @@ void *dev_get_parentdata(struct udevice *dev); */ void *dev_get_priv(struct udevice *dev); +/** + * dev_get_of_data() - get the device tree data used to bind a device + * + * When a device is bound using a device tree node, it matches a + * particular compatible string as in struct udevice_id. This function + * returns the associated data value for that compatible string + */ +ulong dev_get_of_data(struct udevice *dev); + /** * device_get_child() - Get the child of a device by index * -- cgit v1.3.1 From 479728cb0c752a121e0fd84c6c6d74e93e086905 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 11 Nov 2014 10:46:19 -0700 Subject: dm: core: Add functions to find parent and OF data Add dev_get_parent() as a convenience to obtain the parent of a device. Signed-off-by: Simon Glass Reviewed-by: Tom Rini Acked-by: Heiko Schocher --- drivers/core/device.c | 5 +++++ include/dm/device.h | 8 ++++++++ 2 files changed, 13 insertions(+) (limited to 'include') diff --git a/drivers/core/device.c b/drivers/core/device.c index 81ddecade28..6793e1c4f94 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -381,6 +381,11 @@ int device_find_next_child(struct udevice **devp) return 0; } +struct udevice *dev_get_parent(struct udevice *child) +{ + return child->parent; +} + ulong dev_get_of_data(struct udevice *dev) { return dev->of_id->data; diff --git a/include/dm/device.h b/include/dm/device.h index 287504cb270..13598a15b68 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -207,6 +207,14 @@ void *dev_get_parentdata(struct udevice *dev); */ void *dev_get_priv(struct udevice *dev); +/** + * struct dev_get_parent() - Get the parent of a device + * + * @child: Child to check + * @return parent of child, or NULL if this is the root device + */ +struct udevice *dev_get_parent(struct udevice *child); + /** * dev_get_of_data() - get the device tree data used to bind a device * -- cgit v1.3.1 From e33dc221f45ca501319f5aebd1c88574238261be Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 11 Nov 2014 10:46:21 -0700 Subject: dm: Add a function to bind a device by driver name In some cases we need to manually bind a device to a particular driver. Add a function to do this. Signed-off-by: Simon Glass Reviewed-by: Jagannadha Sutradharudu Teki Acked-by: Heiko Schocher --- drivers/core/lists.c | 21 +++++++++++++++++++++ include/dm/lists.h | 13 +++++++++++++ 2 files changed, 34 insertions(+) (limited to 'include') diff --git a/drivers/core/lists.c b/drivers/core/lists.c index 24d2864924b..7a1d6604d42 100644 --- a/drivers/core/lists.c +++ b/drivers/core/lists.c @@ -77,6 +77,27 @@ int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only) return result; } +int device_bind_driver(struct udevice *parent, const char *drv_name, + const char *dev_name, struct udevice **devp) +{ + struct driver *drv; + int ret; + + drv = lists_driver_lookup_name(drv_name); + if (!drv) { + printf("Cannot find driver '%s'\n", drv_name); + return -ENOENT; + } + ret = device_bind(parent, drv, dev_name, NULL, -1, devp); + if (ret) { + printf("Cannot create device named '%s' (err=%d)\n", + dev_name, ret); + return ret; + } + + return 0; +} + #ifdef CONFIG_OF_CONTROL /** * driver_check_compatible() - Check if a driver is compatible with this node diff --git a/include/dm/lists.h b/include/dm/lists.h index 704e33e37fb..1b50af9f23c 100644 --- a/include/dm/lists.h +++ b/include/dm/lists.h @@ -60,4 +60,17 @@ int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only); int lists_bind_fdt(struct udevice *parent, const void *blob, int offset, struct udevice **devp); +/** + * device_bind_driver() - bind a device to a driver + * + * This binds a new device to a driver. + * + * @parent: Parent device + * @drv_name: Name of driver to attach to this parent + * @dev_name: Name of the new device thus created + * @devp: Returns the newly bound device + */ +int device_bind_driver(struct udevice *parent, const char *drv_name, + const char *dev_name, struct udevice **devp); + #endif -- cgit v1.3.1 From ff56bba2d6952176a826bddcd9baf84f61b419a3 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 11 Nov 2014 10:46:22 -0700 Subject: dm: spi: Correct handling of SPI chip selects in sandbox This code was not updated when the chip select handling was adjusted. Fix it to call the correct function. Signed-off-by: Simon Glass Reviewed-by: Jagannadha Sutradharudu Teki Acked-by: Heiko Schocher --- drivers/mtd/spi/sandbox.c | 2 +- drivers/spi/spi-uclass.c | 11 +---------- include/spi.h | 10 ++++++++++ 3 files changed, 12 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/drivers/mtd/spi/sandbox.c b/drivers/mtd/spi/sandbox.c index 1cf2f98310a..fecf6d4bc34 100644 --- a/drivers/mtd/spi/sandbox.c +++ b/drivers/mtd/spi/sandbox.c @@ -602,7 +602,7 @@ static int sandbox_sf_bind_bus_cs(struct sandbox_state *state, int busnum, spec, ret); return ret; } - ret = device_find_child_by_seq(bus, cs, true, &slave); + ret = spi_find_chip_select(bus, cs, &slave); if (!ret) { printf("Chip select %d already exists for spec '%s'\n", cs, spec); diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c index 13c6b77d73d..6bfc274956d 100644 --- a/drivers/spi/spi-uclass.c +++ b/drivers/spi/spi-uclass.c @@ -115,16 +115,7 @@ int spi_chip_select(struct udevice *dev) return slave ? slave->cs : -ENOENT; } -/** - * spi_find_chip_select() - Find the slave attached to chip select - * - * @bus: SPI bus to search - * @cs: Chip select to look for - * @devp: Returns the slave device if found - * @return 0 if found, -ENODEV on error - */ -static int spi_find_chip_select(struct udevice *bus, int cs, - struct udevice **devp) +int spi_find_chip_select(struct udevice *bus, int cs, struct udevice **devp) { struct udevice *dev; diff --git a/include/spi.h b/include/spi.h index aa0a48ea627..5975cda8653 100644 --- a/include/spi.h +++ b/include/spi.h @@ -533,6 +533,16 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode, */ int spi_chip_select(struct udevice *slave); +/** + * spi_find_chip_select() - Find the slave attached to chip select + * + * @bus: SPI bus to search + * @cs: Chip select to look for + * @devp: Returns the slave device if found + * @return 0 if found, -ENODEV on error + */ +int spi_find_chip_select(struct udevice *bus, int cs, struct udevice **devp); + /** * spi_bind_device() - bind a device to a bus's chip select * -- cgit v1.3.1 From 6b18656aff0a1aec15528c47cc6108b44b559f7c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 11 Nov 2014 10:46:23 -0700 Subject: dm: spi: Use device_bind_driver() instead of our own function The SPI function does the same thing, so we may as well just use the new generic function. The 'cs' parameter was not actually used, so can be dropped. Signed-off-by: Simon Glass Reviewed-by: Jagannadha Sutradharudu Teki Acked-by: Heiko Schocher --- drivers/mtd/spi/sandbox.c | 2 +- drivers/spi/spi-uclass.c | 23 +---------------------- include/spi.h | 14 -------------- 3 files changed, 2 insertions(+), 37 deletions(-) (limited to 'include') diff --git a/drivers/mtd/spi/sandbox.c b/drivers/mtd/spi/sandbox.c index fecf6d4bc34..c6a5c4b0de5 100644 --- a/drivers/mtd/spi/sandbox.c +++ b/drivers/mtd/spi/sandbox.c @@ -609,7 +609,7 @@ static int sandbox_sf_bind_bus_cs(struct sandbox_state *state, int busnum, return -EEXIST; } - ret = spi_bind_device(bus, cs, "spi_flash_std", spec, &slave); + ret = device_bind_driver(bus, "spi_flash_std", spec, &slave); if (ret) return ret; diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c index 6bfc274956d..64eb1f6b369 100644 --- a/drivers/spi/spi-uclass.c +++ b/drivers/spi/spi-uclass.c @@ -188,27 +188,6 @@ int spi_cs_info(struct udevice *bus, uint cs, struct spi_cs_info *info) return -ENODEV; } -int spi_bind_device(struct udevice *bus, int cs, const char *drv_name, - const char *dev_name, struct udevice **devp) -{ - struct driver *drv; - int ret; - - drv = lists_driver_lookup_name(drv_name); - if (!drv) { - printf("Cannot find driver '%s'\n", drv_name); - return -ENOENT; - } - ret = device_bind(bus, drv, dev_name, NULL, -1, devp); - if (ret) { - printf("Cannot create device named '%s' (err=%d)\n", - dev_name, ret); - return ret; - } - - return 0; -} - int spi_find_bus_and_cs(int busnum, int cs, struct udevice **busp, struct udevice **devp) { @@ -255,7 +234,7 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode, if (ret == -ENODEV && drv_name) { debug("%s: Binding new device '%s', busnum=%d, cs=%d, driver=%s\n", __func__, dev_name, busnum, cs, drv_name); - ret = spi_bind_device(bus, cs, drv_name, dev_name, &dev); + ret = device_bind_driver(bus, drv_name, dev_name, &dev); if (ret) return ret; created = true; diff --git a/include/spi.h b/include/spi.h index 5975cda8653..5b7827113d9 100644 --- a/include/spi.h +++ b/include/spi.h @@ -543,20 +543,6 @@ int spi_chip_select(struct udevice *slave); */ int spi_find_chip_select(struct udevice *bus, int cs, struct udevice **devp); -/** - * spi_bind_device() - bind a device to a bus's chip select - * - * This binds a new device to an given chip select (which must be unused). - * - * @bus: SPI bus to search - * @cs: Chip select to attach to - * @drv_name: Name of driver to attach to this chip select - * @dev_name: Name of the new device thus created - * @devp: Returns the newly bound device - */ -int spi_bind_device(struct udevice *bus, int cs, const char *drv_name, - const char *dev_name, struct udevice **devp); - /** * spi_ofdata_to_platdata() - decode standard SPI platform data * -- cgit v1.3.1