From daac3bfee57247013cb8373683e9babb191abd75 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 11 May 2016 15:26:24 -0600 Subject: [PATCH 01/25] dm: allow setting driver_data before/during bind This will allow a driver's bind function to use the driver data. One example is the Tegra186 GPIO driver, which instantiates child devices for each of its GPIO ports, yet supports two different HW instances each with a different set of ports, and identified by the udevice_id .data field. Signed-off-by: Stephen Warren Acked-by: Simon Glass --- doc/driver-model/README.txt | 23 ++++++++++++++--------- drivers/core/device.c | 25 ++++++++++++++++++++++--- drivers/core/lists.c | 4 ++-- include/dm/device-internal.h | 24 ++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 14 deletions(-) diff --git a/doc/driver-model/README.txt b/doc/driver-model/README.txt index 7a24552560..1b5ccec4b2 100644 --- a/doc/driver-model/README.txt +++ b/doc/driver-model/README.txt @@ -606,19 +606,24 @@ methods actually defined. 1. Bind stage -A device and its driver are bound using one of these two methods: +U-Boot discovers devices using one of these two methods: - - Scan the U_BOOT_DEVICE() definitions. U-Boot It looks up the -name specified by each, to find the appropriate driver. It then calls -device_bind() to create a new device and bind' it to its driver. This will -call the device's bind() method. + - Scan the U_BOOT_DEVICE() definitions. U-Boot looks up the name specified +by each, to find the appropriate U_BOOT_DRIVER() definition. In this case, +there is no path by which driver_data may be provided, but the U_BOOT_DEVICE() +may provide platdata. - Scan through the device tree definitions. U-Boot looks at top-level nodes in the the device tree. It looks at the compatible string in each node -and uses the of_match part of the U_BOOT_DRIVER() structure to find the -right driver for each node. It then calls device_bind() to bind the -newly-created device to its driver (thereby creating a device structure). -This will also call the device's bind() method. +and uses the of_match table of the U_BOOT_DRIVER() structure to find the +right driver for each node. In this case, the of_match table may provide a +driver_data value, but platdata cannot be provided until later. + +For each device that is discovered, U-Boot then calls device_bind() to create a +new device, initializes various core fields of the device object such as name, +uclass & driver, initializes any optional fields of the device object that are +applicable such as of_offset, driver_data & platdata, and finally calls the +driver's bind() method if one is defined. At this point all the devices are known, and bound to their drivers. There is a 'struct udevice' allocated for all devices. However, nothing has been diff --git a/drivers/core/device.c b/drivers/core/device.c index 45d5e3e12c..eb75b1734f 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -26,9 +26,10 @@ DECLARE_GLOBAL_DATA_PTR; -int device_bind(struct udevice *parent, const struct driver *drv, - const char *name, void *platdata, int of_offset, - struct udevice **devp) +static int device_bind_common(struct udevice *parent, const struct driver *drv, + const char *name, void *platdata, + ulong driver_data, int of_offset, + struct udevice **devp) { struct udevice *dev; struct uclass *uc; @@ -56,6 +57,7 @@ int device_bind(struct udevice *parent, const struct driver *drv, INIT_LIST_HEAD(&dev->devres_head); #endif dev->platdata = platdata; + dev->driver_data = driver_data; dev->name = name; dev->of_offset = of_offset; dev->parent = parent; @@ -193,6 +195,23 @@ fail_alloc1: return ret; } +int device_bind_with_driver_data(struct udevice *parent, + const struct driver *drv, const char *name, + ulong driver_data, int of_offset, + struct udevice **devp) +{ + return device_bind_common(parent, drv, name, NULL, driver_data, + of_offset, devp); +} + +int device_bind(struct udevice *parent, const struct driver *drv, + const char *name, void *platdata, int of_offset, + struct udevice **devp) +{ + return device_bind_common(parent, drv, name, platdata, 0, of_offset, + devp); +} + int device_bind_by_name(struct udevice *parent, bool pre_reloc_only, const struct driver_info *info, struct udevice **devp) { diff --git a/drivers/core/lists.c b/drivers/core/lists.c index a72db13a11..0c27717790 100644 --- a/drivers/core/lists.c +++ b/drivers/core/lists.c @@ -170,7 +170,8 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset, } dm_dbg(" - found match at '%s'\n", entry->name); - ret = device_bind(parent, entry, name, NULL, offset, &dev); + ret = device_bind_with_driver_data(parent, entry, name, + id->data, offset, &dev); if (ret == -ENODEV) { dm_dbg("Driver '%s' refuses to bind\n", entry->name); continue; @@ -180,7 +181,6 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset, ret); return ret; } else { - dev->driver_data = id->data; found = true; if (devp) *devp = dev; diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h index b348ad5231..0bf8707493 100644 --- a/include/dm/device-internal.h +++ b/include/dm/device-internal.h @@ -38,6 +38,30 @@ int device_bind(struct udevice *parent, const struct driver *drv, const char *name, void *platdata, int of_offset, struct udevice **devp); +/** + * device_bind_with_driver_data() - Create a device and bind it to a driver + * + * Called to set up a new device attached to a driver, in the case where the + * driver was matched to the device by means of a match table that provides + * driver_data. + * + * Once bound a device exists but is not yet active until device_probe() is + * called. + * + * @parent: Pointer to device's parent, under which this driver will exist + * @drv: Device's driver + * @name: Name of device (e.g. device tree node name) + * @driver_data: The driver_data field from the driver's match table. + * @of_offset: Offset of device tree node for this device. This is -1 for + * devices which don't use device tree. + * @devp: if non-NULL, returns a pointer to the bound device + * @return 0 if OK, -ve on error + */ +int device_bind_with_driver_data(struct udevice *parent, + const struct driver *drv, const char *name, + ulong driver_data, int of_offset, + struct udevice **devp); + /** * device_bind_by_name: Create a device and bind it to a driver * From 6f82fac2f278173f5afe5b4b5dbc269646d11c0b Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 11 May 2016 15:26:25 -0600 Subject: [PATCH 02/25] sunxi: gpio: convert bind() to use driver data Now that the DM core sets driver_data before calling bind(), this driver can make use of driver_data to determine the set of child devices to create, rather than manually re-implementing the matching logic in code. Cc: Hans de Goede Signed-off-by: Stephen Warren Reviewed-by: Simon Glass Reviewed-by: Hans de Goede --- drivers/gpio/sunxi_gpio.c | 90 ++++++++++++++++++++++----------------- 1 file changed, 50 insertions(+), 40 deletions(-) diff --git a/drivers/gpio/sunxi_gpio.c b/drivers/gpio/sunxi_gpio.c index a7cec18d57..94abbeb39a 100644 --- a/drivers/gpio/sunxi_gpio.c +++ b/drivers/gpio/sunxi_gpio.c @@ -258,43 +258,30 @@ static int gpio_sunxi_probe(struct udevice *dev) return 0; } + +struct sunxi_gpio_soc_data { + int start; + int no_banks; +}; + /** * We have a top-level GPIO device with no actual GPIOs. It has a child * device for each Sunxi bank. */ static int gpio_sunxi_bind(struct udevice *parent) { + struct sunxi_gpio_soc_data *soc_data = + (struct sunxi_gpio_soc_data *)dev_get_driver_data(parent); struct sunxi_gpio_platdata *plat = parent->platdata; struct sunxi_gpio_reg *ctlr; - int bank, no_banks, ret, start; + int bank, ret; /* If this is a child device, there is nothing to do here */ if (plat) return 0; - if (fdt_node_check_compatible(gd->fdt_blob, parent->of_offset, - "allwinner,sun6i-a31-r-pinctrl") == 0) { - start = 'L' - 'A'; - no_banks = 2; /* L & M */ - } else if (fdt_node_check_compatible(gd->fdt_blob, parent->of_offset, - "allwinner,sun8i-a23-r-pinctrl") == 0 || - fdt_node_check_compatible(gd->fdt_blob, parent->of_offset, - "allwinner,sun8i-a83t-r-pinctrl") == 0 || - fdt_node_check_compatible(gd->fdt_blob, parent->of_offset, - "allwinner,sun8i-h3-r-pinctrl") == 0) { - start = 'L' - 'A'; - no_banks = 1; /* L only */ - } else if (fdt_node_check_compatible(gd->fdt_blob, parent->of_offset, - "allwinner,sun9i-a80-r-pinctrl") == 0) { - start = 'L' - 'A'; - no_banks = 3; /* L, M & N */ - } else { - start = 0; - no_banks = SUNXI_GPIO_BANKS; - } - ctlr = (struct sunxi_gpio_reg *)dev_get_addr(parent); - for (bank = 0; bank < no_banks; bank++) { + for (bank = 0; bank < soc_data->no_banks; bank++) { struct sunxi_gpio_platdata *plat; struct udevice *dev; @@ -302,7 +289,7 @@ static int gpio_sunxi_bind(struct udevice *parent) if (!plat) return -ENOMEM; plat->regs = &ctlr->gpio_bank[bank]; - plat->bank_name = gpio_bank_name(start + bank); + plat->bank_name = gpio_bank_name(soc_data->start + bank); plat->gpio_count = SUNXI_GPIOS_PER_BANK; ret = device_bind(parent, parent->driver, @@ -315,23 +302,46 @@ static int gpio_sunxi_bind(struct udevice *parent) return 0; } +static const struct sunxi_gpio_soc_data soc_data_a_all = { + .start = 0, + .no_banks = SUNXI_GPIO_BANKS, +}; + +static const struct sunxi_gpio_soc_data soc_data_l_1 = { + .start = 'L' - 'A', + .no_banks = 1, +}; + +static const struct sunxi_gpio_soc_data soc_data_l_2 = { + .start = 'L' - 'A', + .no_banks = 2, +}; + +static const struct sunxi_gpio_soc_data soc_data_l_3 = { + .start = 'L' - 'A', + .no_banks = 3, +}; + +#define ID(_compat_, _soc_data_) \ + { .compatible = _compat_, .data = (ulong)&soc_data_##_soc_data_ } + static const struct udevice_id sunxi_gpio_ids[] = { - { .compatible = "allwinner,sun4i-a10-pinctrl" }, - { .compatible = "allwinner,sun5i-a10s-pinctrl" }, - { .compatible = "allwinner,sun5i-a13-pinctrl" }, - { .compatible = "allwinner,sun6i-a31-pinctrl" }, - { .compatible = "allwinner,sun6i-a31s-pinctrl" }, - { .compatible = "allwinner,sun7i-a20-pinctrl" }, - { .compatible = "allwinner,sun8i-a23-pinctrl" }, - { .compatible = "allwinner,sun8i-a33-pinctrl" }, - { .compatible = "allwinner,sun8i-a83t-pinctrl", }, - { .compatible = "allwinner,sun8i-h3-pinctrl" }, - { .compatible = "allwinner,sun9i-a80-pinctrl" }, - { .compatible = "allwinner,sun6i-a31-r-pinctrl" }, - { .compatible = "allwinner,sun8i-a23-r-pinctrl" }, - { .compatible = "allwinner,sun8i-a83t-r-pinctrl" }, - { .compatible = "allwinner,sun8i-h3-r-pinctrl", }, - { .compatible = "allwinner,sun9i-a80-r-pinctrl", }, + ID("allwinner,sun4i-a10-pinctrl", a_all), + ID("allwinner,sun5i-a10s-pinctrl", a_all), + ID("allwinner,sun5i-a13-pinctrl", a_all), + ID("allwinner,sun6i-a31-pinctrl", a_all), + ID("allwinner,sun6i-a31s-pinctrl", a_all), + ID("allwinner,sun7i-a20-pinctrl", a_all), + ID("allwinner,sun8i-a23-pinctrl", a_all), + ID("allwinner,sun8i-a33-pinctrl", a_all), + ID("allwinner,sun8i-a83t-pinctrl", a_all), + ID("allwinner,sun8i-h3-pinctrl", a_all), + ID("allwinner,sun9i-a80-pinctrl", a_all), + ID("allwinner,sun6i-a31-r-pinctrl", l_2), + ID("allwinner,sun8i-a23-r-pinctrl", l_1), + ID("allwinner,sun8i-a83t-r-pinctrl", l_1), + ID("allwinner,sun8i-h3-r-pinctrl", l_1), + ID("allwinner,sun9i-a80-r-pinctrl", l_3), { } }; From 11636258981a083957c19f3979796fde5e7e8080 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Thu, 12 May 2016 12:03:35 -0600 Subject: [PATCH 03/25] Rename reset to sysreset The current reset API implements a method to reset the entire system. In the near future, I'd like to introduce code that implements the device tree reset bindings; i.e. the equivalent of the Linux kernel's reset API. This controls resets to individual HW blocks or external chips with reset signals. It doesn't make sense to merge the two APIs into one since they have different semantic purposes. Resolve the naming conflict by renaming the existing reset API to sysreset instead, so the new reset API can be called just reset. Signed-off-by: Stephen Warren Acked-by: Simon Glass --- arch/arm/lib/Makefile | 2 +- arch/arm/mach-rockchip/rk3036/reset_rk3036.c | 20 ++-- arch/arm/mach-rockchip/rk3288/reset_rk3288.c | 20 ++-- arch/arm/mach-snapdragon/reset.c | 18 ++-- arch/sandbox/cpu/state.c | 4 +- arch/sandbox/include/asm/state.h | 6 +- configs/chromebook_jerry_defconfig | 2 +- configs/dragonboard410c_defconfig | 2 +- configs/evb-rk3036_defconfig | 2 +- configs/firefly-rk3288_defconfig | 2 +- configs/kylin-rk3036_defconfig | 2 +- configs/rock2_defconfig | 2 +- configs/sandbox_defconfig | 2 +- configs/sandbox_noblk_defconfig | 2 +- drivers/clk/clk_rk3036.c | 2 +- drivers/clk/clk_rk3288.c | 2 +- drivers/misc/Kconfig | 10 +- drivers/misc/Makefile | 4 +- drivers/misc/reset_sandbox.c | 100 ----------------- .../{reset-uclass.c => sysreset-uclass.c} | 32 +++--- drivers/misc/sysreset_sandbox.c | 101 ++++++++++++++++++ include/dm/uclass-id.h | 2 +- include/reset.h | 71 ------------ include/sysreset.h | 71 ++++++++++++ test/dm/Makefile | 2 +- test/dm/reset.c | 74 ------------- test/dm/sysreset.c | 74 +++++++++++++ 27 files changed, 316 insertions(+), 315 deletions(-) delete mode 100644 drivers/misc/reset_sandbox.c rename drivers/misc/{reset-uclass.c => sysreset-uclass.c} (55%) create mode 100644 drivers/misc/sysreset_sandbox.c delete mode 100644 include/reset.h create mode 100644 include/sysreset.h delete mode 100644 test/dm/reset.c create mode 100644 test/dm/sysreset.c diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile index 7a0fb5862e..b535dbef49 100644 --- a/arch/arm/lib/Makefile +++ b/arch/arm/lib/Makefile @@ -46,7 +46,7 @@ obj-y += interrupts_64.o else obj-y += interrupts.o endif -ifndef CONFIG_RESET +ifndef CONFIG_SYSRESET obj-y += reset.o endif diff --git a/arch/arm/mach-rockchip/rk3036/reset_rk3036.c b/arch/arm/mach-rockchip/rk3036/reset_rk3036.c index fefb568f7a..b3d2113239 100644 --- a/arch/arm/mach-rockchip/rk3036/reset_rk3036.c +++ b/arch/arm/mach-rockchip/rk3036/reset_rk3036.c @@ -7,24 +7,24 @@ #include #include #include -#include +#include #include #include #include #include #include -int rk3036_reset_request(struct udevice *dev, enum reset_t type) +int rk3036_sysreset_request(struct udevice *dev, enum sysreset_t type) { struct rk3036_cru *cru = rockchip_get_cru(); if (IS_ERR(cru)) return PTR_ERR(cru); switch (type) { - case RESET_WARM: + case SYSRESET_WARM: writel(0xeca8, &cru->cru_glb_srst_snd_value); break; - case RESET_COLD: + case SYSRESET_COLD: writel(0xfdb9, &cru->cru_glb_srst_fst_value); break; default: @@ -34,12 +34,12 @@ int rk3036_reset_request(struct udevice *dev, enum reset_t type) return -EINPROGRESS; } -static struct reset_ops rk3036_reset = { - .request = rk3036_reset_request, +static struct sysreset_ops rk3036_sysreset = { + .request = rk3036_sysreset_request, }; -U_BOOT_DRIVER(reset_rk3036) = { - .name = "rk3036_reset", - .id = UCLASS_RESET, - .ops = &rk3036_reset, +U_BOOT_DRIVER(sysreset_rk3036) = { + .name = "rk3036_sysreset", + .id = UCLASS_SYSRESET, + .ops = &rk3036_sysreset, }; diff --git a/arch/arm/mach-rockchip/rk3288/reset_rk3288.c b/arch/arm/mach-rockchip/rk3288/reset_rk3288.c index bf7540a5d2..0aad1c2160 100644 --- a/arch/arm/mach-rockchip/rk3288/reset_rk3288.c +++ b/arch/arm/mach-rockchip/rk3288/reset_rk3288.c @@ -7,25 +7,25 @@ #include #include #include -#include +#include #include #include #include #include #include -int rk3288_reset_request(struct udevice *dev, enum reset_t type) +int rk3288_sysreset_request(struct udevice *dev, enum sysreset_t type) { struct rk3288_cru *cru = rockchip_get_cru(); if (IS_ERR(cru)) return PTR_ERR(cru); switch (type) { - case RESET_WARM: + case SYSRESET_WARM: rk_clrreg(&cru->cru_mode_con, 0xffff); writel(0xeca8, &cru->cru_glb_srst_snd_value); break; - case RESET_COLD: + case SYSRESET_COLD: rk_clrreg(&cru->cru_mode_con, 0xffff); writel(0xfdb9, &cru->cru_glb_srst_fst_value); break; @@ -36,12 +36,12 @@ int rk3288_reset_request(struct udevice *dev, enum reset_t type) return -EINPROGRESS; } -static struct reset_ops rk3288_reset = { - .request = rk3288_reset_request, +static struct sysreset_ops rk3288_sysreset = { + .request = rk3288_sysreset_request, }; -U_BOOT_DRIVER(reset_rk3288) = { - .name = "rk3288_reset", - .id = UCLASS_RESET, - .ops = &rk3288_reset, +U_BOOT_DRIVER(sysreset_rk3288) = { + .name = "rk3288_sysreset", + .id = UCLASS_SYSRESET, + .ops = &rk3288_sysreset, }; diff --git a/arch/arm/mach-snapdragon/reset.c b/arch/arm/mach-snapdragon/reset.c index 2627eec181..a6cabfb8b0 100644 --- a/arch/arm/mach-snapdragon/reset.c +++ b/arch/arm/mach-snapdragon/reset.c @@ -9,12 +9,12 @@ #include #include #include -#include +#include #include DECLARE_GLOBAL_DATA_PTR; -static int msm_reset_request(struct udevice *dev, enum reset_t type) +static int msm_sysreset_request(struct udevice *dev, enum sysreset_t type) { phys_addr_t addr = dev_get_addr(dev); if (!addr) @@ -23,18 +23,18 @@ static int msm_reset_request(struct udevice *dev, enum reset_t type) return -EINPROGRESS; } -static struct reset_ops msm_reset_ops = { - .request = msm_reset_request, +static struct sysreset_ops msm_sysreset_ops = { + .request = msm_sysreset_request, }; -static const struct udevice_id msm_reset_ids[] = { +static const struct udevice_id msm_sysreset_ids[] = { { .compatible = "qcom,pshold" }, { } }; U_BOOT_DRIVER(msm_reset) = { - .name = "msm_reset", - .id = UCLASS_RESET, - .of_match = msm_reset_ids, - .ops = &msm_reset_ops, + .name = "msm_sysreset", + .id = UCLASS_SYSRESET, + .of_match = msm_sysreset_ids, + .ops = &msm_sysreset_ops, }; diff --git a/arch/sandbox/cpu/state.c b/arch/sandbox/cpu/state.c index d2a7dc9b45..2b4dbd341f 100644 --- a/arch/sandbox/cpu/state.c +++ b/arch/sandbox/cpu/state.c @@ -360,8 +360,8 @@ int state_init(void) 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; + state->last_sysreset = SYSRESET_COUNT; + state->sysreset_allowed[SYSRESET_POWER] = true; /* * Example of how to use GPIOs: diff --git a/arch/sandbox/include/asm/state.h b/arch/sandbox/include/asm/state.h index 11856c2fed..149f28d873 100644 --- a/arch/sandbox/include/asm/state.h +++ b/arch/sandbox/include/asm/state.h @@ -7,7 +7,7 @@ #define __SANDBOX_STATE_H #include -#include +#include #include #include @@ -60,8 +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 sysreset_t last_sysreset; /* Last system reset type */ + bool sysreset_allowed[SYSRESET_COUNT]; /* Allowed system reset types */ enum state_terminal_raw term_raw; /* Terminal raw/cooked */ bool skip_delays; /* Ignore any time delays (for test) */ bool show_test_output; /* Don't suppress stdout in tests */ diff --git a/configs/chromebook_jerry_defconfig b/configs/chromebook_jerry_defconfig index 25ead92778..d5bc5153b1 100644 --- a/configs/chromebook_jerry_defconfig +++ b/configs/chromebook_jerry_defconfig @@ -47,7 +47,7 @@ CONFIG_CMD_CROS_EC=y CONFIG_CROS_EC=y CONFIG_CROS_EC_SPI=y CONFIG_PWRSEQ=y -CONFIG_RESET=y +CONFIG_SYSRESET=y CONFIG_DM_MMC=y CONFIG_ROCKCHIP_DWMMC=y CONFIG_PINCTRL=y diff --git a/configs/dragonboard410c_defconfig b/configs/dragonboard410c_defconfig index 2566ded58a..37c5ea7761 100644 --- a/configs/dragonboard410c_defconfig +++ b/configs/dragonboard410c_defconfig @@ -23,7 +23,7 @@ CONFIG_MSM_GPIO=y CONFIG_PM8916_GPIO=y CONFIG_LED=y CONFIG_LED_GPIO=y -CONFIG_RESET=y +CONFIG_SYSRESET=y CONFIG_DM_MMC=y CONFIG_MSM_SDHCI=y CONFIG_DM_PMIC=y diff --git a/configs/evb-rk3036_defconfig b/configs/evb-rk3036_defconfig index 4dd4586243..9894fffcca 100644 --- a/configs/evb-rk3036_defconfig +++ b/configs/evb-rk3036_defconfig @@ -28,7 +28,7 @@ CONFIG_CLK=y CONFIG_ROCKCHIP_GPIO=y CONFIG_SYS_I2C_ROCKCHIP=y CONFIG_LED=y -CONFIG_RESET=y +CONFIG_SYSRESET=y CONFIG_DM_MMC=y CONFIG_ROCKCHIP_DWMMC=y CONFIG_PINCTRL=y diff --git a/configs/firefly-rk3288_defconfig b/configs/firefly-rk3288_defconfig index 0995f9b329..0cbc539848 100644 --- a/configs/firefly-rk3288_defconfig +++ b/configs/firefly-rk3288_defconfig @@ -40,7 +40,7 @@ CONFIG_ROCKCHIP_GPIO=y CONFIG_SYS_I2C_ROCKCHIP=y CONFIG_LED=y CONFIG_LED_GPIO=y -CONFIG_RESET=y +CONFIG_SYSRESET=y CONFIG_DM_MMC=y CONFIG_ROCKCHIP_DWMMC=y CONFIG_PINCTRL=y diff --git a/configs/kylin-rk3036_defconfig b/configs/kylin-rk3036_defconfig index 50fbe654bf..0ff6c6b9a4 100644 --- a/configs/kylin-rk3036_defconfig +++ b/configs/kylin-rk3036_defconfig @@ -28,7 +28,7 @@ CONFIG_CLK=y CONFIG_ROCKCHIP_GPIO=y CONFIG_SYS_I2C_ROCKCHIP=y CONFIG_LED=y -CONFIG_RESET=y +CONFIG_SYSRESET=y CONFIG_DM_MMC=y CONFIG_ROCKCHIP_DWMMC=y CONFIG_PINCTRL=y diff --git a/configs/rock2_defconfig b/configs/rock2_defconfig index fd32fb521e..3e16b805ca 100644 --- a/configs/rock2_defconfig +++ b/configs/rock2_defconfig @@ -38,7 +38,7 @@ CONFIG_CLK=y CONFIG_SPL_CLK=y CONFIG_ROCKCHIP_GPIO=y CONFIG_SYS_I2C_ROCKCHIP=y -CONFIG_RESET=y +CONFIG_SYSRESET=y CONFIG_DM_MMC=y CONFIG_ROCKCHIP_DWMMC=y CONFIG_PINCTRL=y diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 9e4a92dd6c..6e30c5df8b 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -97,7 +97,7 @@ CONFIG_CROS_EC_SANDBOX=y CONFIG_CROS_EC_SPI=y CONFIG_PWRSEQ=y CONFIG_SPL_PWRSEQ=y -CONFIG_RESET=y +CONFIG_SYSRESET=y CONFIG_DM_MMC=y CONFIG_SANDBOX_MMC=y CONFIG_SPI_FLASH_SANDBOX=y diff --git a/configs/sandbox_noblk_defconfig b/configs/sandbox_noblk_defconfig index 93167c2f65..60c73398db 100644 --- a/configs/sandbox_noblk_defconfig +++ b/configs/sandbox_noblk_defconfig @@ -94,7 +94,7 @@ CONFIG_CROS_EC_SANDBOX=y CONFIG_CROS_EC_SPI=y CONFIG_PWRSEQ=y CONFIG_SPL_PWRSEQ=y -CONFIG_RESET=y +CONFIG_SYSRESET=y CONFIG_DM_MMC=y CONFIG_SPI_FLASH_SANDBOX=y CONFIG_SPI_FLASH=y diff --git a/drivers/clk/clk_rk3036.c b/drivers/clk/clk_rk3036.c index bd5f22a753..7ec65bdff0 100644 --- a/drivers/clk/clk_rk3036.c +++ b/drivers/clk/clk_rk3036.c @@ -407,7 +407,7 @@ static int rk3036_clk_bind(struct udevice *dev) } /* The reset driver does not have a device node, so bind it here */ - ret = device_bind_driver(gd->dm_root, "rk3036_reset", "reset", &dev); + ret = device_bind_driver(gd->dm_root, "rk3036_sysreset", "reset", &dev); if (ret) debug("Warning: No RK3036 reset driver: ret=%d\n", ret); diff --git a/drivers/clk/clk_rk3288.c b/drivers/clk/clk_rk3288.c index 2a85e93a6c..e763a1c8e9 100644 --- a/drivers/clk/clk_rk3288.c +++ b/drivers/clk/clk_rk3288.c @@ -877,7 +877,7 @@ static int rk3288_clk_bind(struct udevice *dev) } /* The reset driver does not have a device node, so bind it here */ - ret = device_bind_driver(gd->dm_root, "rk3288_reset", "reset", &dev); + ret = device_bind_driver(gd->dm_root, "rk3288_sysreset", "reset", &dev); if (ret) debug("Warning: No RK3288 reset driver: ret=%d\n", ret); diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index c40f6b577f..2373037685 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -121,13 +121,13 @@ config PCA9551_I2C_ADDR help The I2C address of the PCA9551 LED controller. -config RESET - bool "Enable support for reset drivers" +config SYSRESET + bool "Enable support for system 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 + Enable system 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. config WINBOND_W83627 diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 98704f2085..066639ba1f 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -27,7 +27,7 @@ obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o obj-$(CONFIG_NS87308) += ns87308.o obj-$(CONFIG_PDSP188x) += pdsp188x.o obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o -obj-$(CONFIG_SANDBOX) += reset_sandbox.o +obj-$(CONFIG_SANDBOX) += sysreset_sandbox.o ifdef CONFIG_DM_I2C obj-$(CONFIG_SANDBOX) += i2c_eeprom_emul.o endif @@ -40,7 +40,7 @@ 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 +obj-$(CONFIG_SYSRESET) += sysreset-uclass.o obj-$(CONFIG_FSL_DEVICE_DISABLE) += fsl_devdis.o obj-$(CONFIG_WINBOND_W83627) += winbond_w83627.o obj-$(CONFIG_QFW) += qfw.o diff --git a/drivers/misc/reset_sandbox.c b/drivers/misc/reset_sandbox.c deleted file mode 100644 index 2691bb031a..0000000000 --- a/drivers/misc/reset_sandbox.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2015 Google, Inc - * Written by Simon Glass - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include -#include -#include - -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 (state->fdt_fname && 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/reset-uclass.c b/drivers/misc/sysreset-uclass.c similarity index 55% rename from drivers/misc/reset-uclass.c rename to drivers/misc/sysreset-uclass.c index fdb5c6fcff..e41efcaca6 100644 --- a/drivers/misc/reset-uclass.c +++ b/drivers/misc/sysreset-uclass.c @@ -6,7 +6,7 @@ */ #include -#include +#include #include #include #include @@ -15,9 +15,9 @@ #include #include -int reset_request(struct udevice *dev, enum reset_t type) +int sysreset_request(struct udevice *dev, enum sysreset_t type) { - struct reset_ops *ops = reset_get_ops(dev); + struct sysreset_ops *ops = sysreset_get_ops(dev); if (!ops->request) return -ENOSYS; @@ -25,16 +25,16 @@ int reset_request(struct udevice *dev, enum reset_t type) return ops->request(dev, type); } -int reset_walk(enum reset_t type) +int sysreset_walk(enum sysreset_t type) { struct udevice *dev; int ret = -ENOSYS; - while (ret != -EINPROGRESS && type < RESET_COUNT) { - for (uclass_first_device(UCLASS_RESET, &dev); + while (ret != -EINPROGRESS && type < SYSRESET_COUNT) { + for (uclass_first_device(UCLASS_SYSRESET, &dev); dev; uclass_next_device(&dev)) { - ret = reset_request(dev, type); + ret = sysreset_request(dev, type); if (ret == -EINPROGRESS) break; } @@ -44,38 +44,38 @@ int reset_walk(enum reset_t type) return ret; } -void reset_walk_halt(enum reset_t type) +void sysreset_walk_halt(enum sysreset_t type) { int ret; - ret = reset_walk(type); + ret = sysreset_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"); + printf("System reset not supported on this platform\n"); hang(); } /** - * reset_cpu() - calls reset_walk(RESET_WARM) + * reset_cpu() - calls sysreset_walk(SYSRESET_WARM) */ void reset_cpu(ulong addr) { - reset_walk_halt(RESET_WARM); + sysreset_walk_halt(SYSRESET_WARM); } int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { - reset_walk_halt(RESET_WARM); + sysreset_walk_halt(SYSRESET_WARM); return 0; } -UCLASS_DRIVER(reset) = { - .id = UCLASS_RESET, - .name = "reset", +UCLASS_DRIVER(sysreset) = { + .id = UCLASS_SYSRESET, + .name = "sysreset", }; diff --git a/drivers/misc/sysreset_sandbox.c b/drivers/misc/sysreset_sandbox.c new file mode 100644 index 0000000000..7ae7f386ee --- /dev/null +++ b/drivers/misc/sysreset_sandbox.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2015 Google, Inc + * Written by Simon Glass + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +static int sandbox_warm_sysreset_request(struct udevice *dev, + enum sysreset_t type) +{ + struct sandbox_state *state = state_get_current(); + + switch (type) { + case SYSRESET_WARM: + state->last_sysreset = type; + break; + default: + return -ENOSYS; + } + if (!state->sysreset_allowed[type]) + return -EACCES; + + return -EINPROGRESS; +} + +static int sandbox_sysreset_request(struct udevice *dev, enum sysreset_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 (state->fdt_fname && dev->of_offset == -1) + return -ENODEV; + + switch (type) { + case SYSRESET_COLD: + state->last_sysreset = type; + break; + case SYSRESET_POWER: + state->last_sysreset = type; + if (!state->sysreset_allowed[type]) + return -EACCES; + sandbox_exit(); + break; + default: + return -ENOSYS; + } + if (!state->sysreset_allowed[type]) + return -EACCES; + + return -EINPROGRESS; +} + +static struct sysreset_ops sandbox_sysreset_ops = { + .request = sandbox_sysreset_request, +}; + +static const struct udevice_id sandbox_sysreset_ids[] = { + { .compatible = "sandbox,reset" }, + { } +}; + +U_BOOT_DRIVER(sysreset_sandbox) = { + .name = "sysreset_sandbox", + .id = UCLASS_SYSRESET, + .of_match = sandbox_sysreset_ids, + .ops = &sandbox_sysreset_ops, +}; + +static struct sysreset_ops sandbox_warm_sysreset_ops = { + .request = sandbox_warm_sysreset_request, +}; + +static const struct udevice_id sandbox_warm_sysreset_ids[] = { + { .compatible = "sandbox,warm-reset" }, + { } +}; + +U_BOOT_DRIVER(warm_sysreset_sandbox) = { + .name = "warm_sysreset_sandbox", + .id = UCLASS_SYSRESET, + .of_match = sandbox_warm_sysreset_ids, + .ops = &sandbox_warm_sysreset_ops, +}; + +/* This is here in case we don't have a device tree */ +U_BOOT_DEVICE(sysreset_sandbox_non_fdt) = { + .name = "sysreset_sandbox", +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index a5cf6e201c..f9ff45e010 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -61,7 +61,6 @@ enum uclass_id { UCLASS_PWM, /* Pulse-width modulator */ UCLASS_PWRSEQ, /* Power sequence device */ UCLASS_REGULATOR, /* Regulator device */ - UCLASS_RESET, /* Reset device */ UCLASS_REMOTEPROC, /* Remote Processor device */ UCLASS_RTC, /* Real time clock device */ UCLASS_SERIAL, /* Serial UART */ @@ -70,6 +69,7 @@ enum uclass_id { UCLASS_SPI_FLASH, /* SPI flash */ UCLASS_SPI_GENERIC, /* Generic SPI flash target */ UCLASS_SYSCON, /* System configuration device */ + UCLASS_SYSRESET, /* System reset device */ UCLASS_THERMAL, /* Thermal sensor */ UCLASS_TIMER, /* Timer device */ UCLASS_TPM, /* Trusted Platform Module TIS interface */ diff --git a/include/reset.h b/include/reset.h deleted file mode 100644 index 383761eb1f..0000000000 --- a/include/reset.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2015 Google, Inc - * Written by Simon Glass - * - * 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/sysreset.h b/include/sysreset.h new file mode 100644 index 0000000000..393c7be3d8 --- /dev/null +++ b/include/sysreset.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2015 Google, Inc + * Written by Simon Glass + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __SYSRESET_H +#define __SYSRESET_H + +enum sysreset_t { + SYSRESET_WARM, /* Reset CPU, keep GPIOs active */ + SYSRESET_COLD, /* Reset CPU and GPIOs */ + SYSRESET_POWER, /* Reset PMIC (remove and restore power) */ + + SYSRESET_COUNT, +}; + +struct sysreset_ops { + /** + * request() - request a sysreset 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 sysreset_t type); +}; + +#define sysreset_get_ops(dev) ((struct sysreset_ops *)(dev)->driver->ops) + +/** + * sysreset_request() - request a sysreset + * + * @type: Reset type to request + * @return 0 if OK, -EPROTONOSUPPORT if not supported by this device + */ +int sysreset_request(struct udevice *dev, enum sysreset_t type); + +/** + * sysreset_walk() - cause a system reset + * + * This works through the available sysreset devices until it finds one that can + * perform a reset. If the provided sysreset 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 sysreset_walk(enum sysreset_t type); + +/** + * sysreset_walk_halt() - try to reset, otherwise halt + * + * This calls sysreset_walk(). If it returns, indicating that reset is not + * supported, it prints a message and halts. + */ +void sysreset_walk_halt(enum sysreset_t type); + +/** + * reset_cpu() - calls sysreset_walk(SYSRESET_WARM) + */ +void reset_cpu(ulong addr); + +#endif diff --git a/test/dm/Makefile b/test/dm/Makefile index 9a11ae0a14..fd781e82cf 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -26,7 +26,7 @@ obj-$(CONFIG_DM_PCI) += pci.o obj-$(CONFIG_RAM) += ram.o obj-y += regmap.o obj-$(CONFIG_REMOTEPROC) += remoteproc.o -obj-$(CONFIG_RESET) += reset.o +obj-$(CONFIG_SYSRESET) += sysreset.o obj-$(CONFIG_DM_RTC) += rtc.o obj-$(CONFIG_DM_SPI_FLASH) += sf.o obj-$(CONFIG_DM_SPI) += spi.o diff --git a/test/dm/reset.c b/test/dm/reset.c deleted file mode 100644 index 5d53f252bb..0000000000 --- a/test/dm/reset.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2015 Google, Inc - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include -#include -#include -#include - -/* 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/sysreset.c b/test/dm/sysreset.c new file mode 100644 index 0000000000..5e94c072b6 --- /dev/null +++ b/test/dm/sysreset.c @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include + +/* Test that we can use particular sysreset devices */ +static int dm_test_sysreset_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_SYSRESET, 0, &dev)); + ut_asserteq(-ENODEV, sysreset_request(dev, SYSRESET_WARM)); + ut_asserteq(-ENODEV, sysreset_request(dev, SYSRESET_COLD)); + ut_asserteq(-ENODEV, sysreset_request(dev, SYSRESET_POWER)); + + /* Device 1 is the warm sysreset device */ + ut_assertok(uclass_get_device(UCLASS_SYSRESET, 1, &dev)); + ut_asserteq(-EACCES, sysreset_request(dev, SYSRESET_WARM)); + ut_asserteq(-ENOSYS, sysreset_request(dev, SYSRESET_COLD)); + ut_asserteq(-ENOSYS, sysreset_request(dev, SYSRESET_POWER)); + + state->sysreset_allowed[SYSRESET_WARM] = true; + ut_asserteq(-EINPROGRESS, sysreset_request(dev, SYSRESET_WARM)); + state->sysreset_allowed[SYSRESET_WARM] = false; + + /* Device 2 is the cold sysreset device */ + ut_assertok(uclass_get_device(UCLASS_SYSRESET, 2, &dev)); + ut_asserteq(-ENOSYS, sysreset_request(dev, SYSRESET_WARM)); + ut_asserteq(-EACCES, sysreset_request(dev, SYSRESET_COLD)); + state->sysreset_allowed[SYSRESET_POWER] = false; + ut_asserteq(-EACCES, sysreset_request(dev, SYSRESET_POWER)); + state->sysreset_allowed[SYSRESET_POWER] = true; + + return 0; +} +DM_TEST(dm_test_sysreset_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/* Test that we can walk through the sysreset devices */ +static int dm_test_sysreset_walk(struct unit_test_state *uts) +{ + struct sandbox_state *state = state_get_current(); + + /* If we generate a power sysreset, we will exit sandbox! */ + state->sysreset_allowed[SYSRESET_POWER] = false; + ut_asserteq(-EACCES, sysreset_walk(SYSRESET_WARM)); + ut_asserteq(-EACCES, sysreset_walk(SYSRESET_COLD)); + ut_asserteq(-EACCES, sysreset_walk(SYSRESET_POWER)); + + /* + * Enable cold system reset - this should make cold system reset work, + * plus a warm system reset should be promoted to cold, since this is + * the next step along. + */ + state->sysreset_allowed[SYSRESET_COLD] = true; + ut_asserteq(-EINPROGRESS, sysreset_walk(SYSRESET_WARM)); + ut_asserteq(-EINPROGRESS, sysreset_walk(SYSRESET_COLD)); + ut_asserteq(-EACCES, sysreset_walk(SYSRESET_POWER)); + state->sysreset_allowed[SYSRESET_COLD] = false; + state->sysreset_allowed[SYSRESET_POWER] = true; + + return 0; +} +DM_TEST(dm_test_sysreset_walk, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); From 6238935d018042d332aa7e90eae3addfeb11abdc Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 13 May 2016 15:50:29 -0600 Subject: [PATCH 04/25] Add a mailbox driver framework/uclass A mailbox is a hardware mechanism for transferring small message and/or notifications between the CPU on which U-Boot runs and some other device such as an auxilliary CPU running firmware or a hardware module. This patch defines a standard API that connects mailbox clients to mailbox providers (drivers). Initially, DT is the only supported method for connecting the two. The DT binding specification (mailbox.txt) was taken from Linux kernel v4.5's Documentation/devicetree/bindings/mailbox/mailbox.txt. Signed-off-by: Stephen Warren Acked-by: Simon Glass --- doc/device-tree-bindings/mailbox/mailbox.txt | 32 ++++ drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/mailbox/Kconfig | 13 ++ drivers/mailbox/Makefile | 5 + drivers/mailbox/mailbox-uclass.c | 145 ++++++++++++++++++ include/dm/uclass-id.h | 1 + include/mailbox_client.h | 149 +++++++++++++++++++ include/mailbox_uclass.h | 83 +++++++++++ 9 files changed, 431 insertions(+) create mode 100644 doc/device-tree-bindings/mailbox/mailbox.txt create mode 100644 drivers/mailbox/Kconfig create mode 100644 drivers/mailbox/Makefile create mode 100644 drivers/mailbox/mailbox-uclass.c create mode 100644 include/mailbox_client.h create mode 100644 include/mailbox_uclass.h diff --git a/doc/device-tree-bindings/mailbox/mailbox.txt b/doc/device-tree-bindings/mailbox/mailbox.txt new file mode 100644 index 0000000000..be05b9746c --- /dev/null +++ b/doc/device-tree-bindings/mailbox/mailbox.txt @@ -0,0 +1,32 @@ +* Generic Mailbox Controller and client driver bindings + +Generic binding to provide a way for Mailbox controller drivers to +assign appropriate mailbox channel to client drivers. + +* Mailbox Controller + +Required property: +- #mbox-cells: Must be at least 1. Number of cells in a mailbox + specifier. + +Example: + mailbox: mailbox { + ... + #mbox-cells = <1>; + }; + + +* Mailbox Client + +Required property: +- mboxes: List of phandle and mailbox channel specifiers. + +Optional property: +- mbox-names: List of identifier strings for each mailbox channel. + +Example: + pwr_cntrl: power { + ... + mbox-names = "pwr-ctrl", "rpc"; + mboxes = <&mailbox 0 &mailbox 1>; + }; diff --git a/drivers/Kconfig b/drivers/Kconfig index 118b66ed0e..f2a137ad87 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -30,6 +30,8 @@ source "drivers/input/Kconfig" source "drivers/led/Kconfig" +source "drivers/mailbox/Kconfig" + source "drivers/memory/Kconfig" source "drivers/misc/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 99dd07fc76..f6295d285e 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -64,6 +64,7 @@ obj-y += video/ obj-y += watchdog/ obj-$(CONFIG_QE) += qe/ obj-$(CONFIG_U_QE) += qe/ +obj-y += mailbox/ obj-y += memory/ obj-y += pwm/ obj-y += input/ diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig new file mode 100644 index 0000000000..295e6db0f2 --- /dev/null +++ b/drivers/mailbox/Kconfig @@ -0,0 +1,13 @@ +menu "Mailbox Controller Support" + +config DM_MAILBOX + bool "Enable mailbox controllers using Driver Model" + depends on DM && OF_CONTROL + help + Enable support for the mailbox driver class. Mailboxes provide the + ability to transfer small messages and/or notifications from one + CPU to another CPU, or sometimes to dedicated HW modules. They form + the basis of a variety of inter-process/inter-CPU communication + protocols. + +endmenu diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile new file mode 100644 index 0000000000..a2d96a4e3b --- /dev/null +++ b/drivers/mailbox/Makefile @@ -0,0 +1,5 @@ +# Copyright (c) 2016, NVIDIA CORPORATION. +# +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_DM_MAILBOX) += mailbox-uclass.o diff --git a/drivers/mailbox/mailbox-uclass.c b/drivers/mailbox/mailbox-uclass.c new file mode 100644 index 0000000000..73fa32874a --- /dev/null +++ b/drivers/mailbox/mailbox-uclass.c @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +static inline struct mbox_ops *mbox_dev_ops(struct udevice *dev) +{ + return (struct mbox_ops *)dev->driver->ops; +} + +static int mbox_of_xlate_default(struct mbox_chan *chan, + struct fdtdec_phandle_args *args) +{ + debug("%s(chan=%p)\n", __func__, chan); + + if (args->args_count != 1) { + debug("Invaild args_count: %d\n", args->args_count); + return -EINVAL; + } + + chan->id = args->args[0]; + + return 0; +} + +int mbox_get_by_index(struct udevice *dev, int index, struct mbox_chan *chan) +{ + struct fdtdec_phandle_args args; + int ret; + struct udevice *dev_mbox; + struct mbox_ops *ops; + + debug("%s(dev=%p, index=%d, chan=%p)\n", __func__, dev, index, chan); + + ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev->of_offset, + "mboxes", "#mbox-cells", 0, + index, &args); + if (ret) { + debug("%s: fdtdec_parse_phandle_with_args failed: %d\n", + __func__, ret); + return ret; + } + + ret = uclass_get_device_by_of_offset(UCLASS_MAILBOX, args.node, + &dev_mbox); + if (ret) { + debug("%s: uclass_get_device_by_of_offset failed: %d\n", + __func__, ret); + return ret; + } + ops = mbox_dev_ops(dev_mbox); + + chan->dev = dev_mbox; + if (ops->of_xlate) + ret = ops->of_xlate(chan, &args); + else + ret = mbox_of_xlate_default(chan, &args); + if (ret) { + debug("of_xlate() failed: %d\n", ret); + return ret; + } + + ret = ops->request(chan); + if (ret) { + debug("ops->request() failed: %d\n", ret); + return ret; + } + + return 0; +} + +int mbox_get_by_name(struct udevice *dev, const char *name, + struct mbox_chan *chan) +{ + int index; + + debug("%s(dev=%p, name=%s, chan=%p)\n", __func__, dev, name, chan); + + index = fdt_find_string(gd->fdt_blob, dev->of_offset, "mbox-names", + name); + if (index < 0) { + debug("fdt_find_string() failed: %d\n", index); + return index; + } + + return mbox_get_by_index(dev, index, chan); +} + +int mbox_free(struct mbox_chan *chan) +{ + struct mbox_ops *ops = mbox_dev_ops(chan->dev); + + debug("%s(chan=%p)\n", __func__, chan); + + return ops->free(chan); +} + +int mbox_send(struct mbox_chan *chan, const void *data) +{ + struct mbox_ops *ops = mbox_dev_ops(chan->dev); + + debug("%s(chan=%p, data=%p)\n", __func__, chan, data); + + return ops->send(chan, data); +} + +int mbox_recv(struct mbox_chan *chan, void *data, ulong timeout_us) +{ + struct mbox_ops *ops = mbox_dev_ops(chan->dev); + ulong start_time; + int ret; + + debug("%s(chan=%p, data=%p, timeout_us=%ld)\n", __func__, chan, data, + timeout_us); + + start_time = timer_get_us(); + /* + * Account for partial us ticks, but if timeout_us is 0, ensure we + * still don't wait at all. + */ + if (timeout_us) + timeout_us++; + + for (;;) { + ret = ops->recv(chan, data); + if (ret != -ENODATA) + return ret; + if ((timer_get_us() - start_time) >= timeout_us) + return -ETIMEDOUT; + } +} + +UCLASS_DRIVER(mailbox) = { + .id = UCLASS_MAILBOX, + .name = "mailbox", +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index f9ff45e010..0777cbe27e 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -44,6 +44,7 @@ enum uclass_id { UCLASS_KEYBOARD, /* Keyboard input device */ UCLASS_LED, /* Light-emitting diode (LED) */ UCLASS_LPC, /* x86 'low pin count' interface */ + UCLASS_MAILBOX, /* Mailbox controller */ UCLASS_MASS_STORAGE, /* Mass storage device */ UCLASS_MISC, /* Miscellaneous device */ UCLASS_MMC, /* SD / MMC card or chip */ diff --git a/include/mailbox_client.h b/include/mailbox_client.h new file mode 100644 index 0000000000..8345ea0bf1 --- /dev/null +++ b/include/mailbox_client.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _MAILBOX_CLIENT_H +#define _MAILBOX_CLIENT_H + +/** + * A mailbox is a hardware mechanism for transferring small fixed-size messages + * and/or notifications between the CPU on which U-Boot runs and some other + * device such as an auxiliary CPU running firmware or a hardware module. + * + * Data transfer is optional; a mailbox may consist solely of a notification + * mechanism. When data transfer is implemented, it is via HW registers or + * FIFOs, rather than via RAM-based buffers. The mailbox API generally + * implements any communication protocol enforced solely by hardware, and + * leaves any higher-level protocols to other layers. + * + * A mailbox channel is a bi-directional mechanism that can send a message or + * notification to a single specific remote entity, and receive messages or + * notifications from that entity. The size, content, and format of such + * messages is defined by the mailbox implementation, or the remote entity with + * which it communicates; there is no general standard at this API level. + * + * A driver that implements UCLASS_MAILBOX is a mailbox provider. A provider + * will often implement multiple separate mailbox channels, since the hardware + * it manages often has this capability. mailbox_uclass.h describes the + * interface which mailbox providers must implement. + * + * Mailbox consumers/clients generate and send, or receive and process, + * messages. This header file describes the API used by clients. + */ + +struct udevice; + +/** + * struct mbox_chan - A handle to a single mailbox channel. + * + * Clients provide storage for channels. The content of the channel structure + * is managed solely by the mailbox API and mailbox drivers. A mailbox channel + * is initialized by "get"ing the mailbox. The channel struct is passed to all + * other mailbox APIs to identify which mailbox to operate upon. + * + * @dev: The device which implements the mailbox. + * @id: The mailbox channel ID within the provider. + * + * Currently, the mailbox API assumes that a single integer ID is enough to + * identify and configure any mailbox channel for any mailbox provider. If this + * assumption becomes invalid in the future, the struct could be expanded to + * either (a) add more fields to allow mailbox providers to store additional + * information, or (b) replace the id field with an opaque pointer, which the + * provider would dynamically allocated during its .of_xlate op, and process + * during is .request op. This may require the addition of an extra op to clean + * up the allocation. + */ +struct mbox_chan { + struct udevice *dev; + /* + * Written by of_xlate. We assume a single id is enough for now. In the + * future, we might add more fields here. + */ + unsigned long id; +}; + +/** + * mbox_get_by_index - Get/request a mailbox by integer index + * + * This looks up and requests a mailbox channel. The index is relative to the + * client device; each device is assumed to have n mailbox channels associated + * with it somehow, and this function finds and requests one of them. The + * mapping of client device channel indices to provider channels may be via + * device-tree properties, board-provided mapping tables, or some other + * mechanism. + * + * @dev: The client device. + * @index: The index of the mailbox channel to request, within the + * client's list of channels. + * @chan A pointer to a channel object to initialize. + * @return 0 if OK, or a negative error code. + */ +int mbox_get_by_index(struct udevice *dev, int index, struct mbox_chan *chan); + +/** + * mbox_get_by_name - Get/request a mailbox by name + * + * This looks up and requests a mailbox channel. The name is relative to the + * client device; each device is assumed to have n mailbox channels associated + * with it somehow, and this function finds and requests one of them. The + * mapping of client device channel names to provider channels may be via + * device-tree properties, board-provided mapping tables, or some other + * mechanism. + * + * @dev: The client device. + * @name: The name of the mailbox channel to request, within the client's + * list of channels. + * @chan A pointer to a channel object to initialize. + * @return 0 if OK, or a negative error code. + */ +int mbox_get_by_name(struct udevice *dev, const char *name, + struct mbox_chan *chan); + +/** + * mbox_free - Free a previously requested mailbox channel. + * + * @chan: A channel object that was previously successfully requested by + * calling mbox_get_by_*(). + * @return 0 if OK, or a negative error code. + */ +int mbox_free(struct mbox_chan *chan); + +/** + * mbox_send - Send a message over a mailbox channel + * + * This function will send a message to the remote entity. It may return before + * the remote entity has received and/or processed the message. + * + * @chan: A channel object that was previously successfully requested by + * calling mbox_get_by_*(). + * @data: A pointer to the message to transfer. The format and size of + * the memory region pointed at by @data is determined by the + * mailbox provider. Providers that solely transfer notifications + * will ignore this parameter. + * @return 0 if OK, or a negative error code. + */ +int mbox_send(struct mbox_chan *chan, const void *data); + +/** + * mbox_recv - Receive any available message from a mailbox channel + * + * This function will wait (up to the specified @timeout_us) for a message to + * be sent by the remote entity, and write the content of any such message + * into a caller-provided buffer. + * + * @chan: A channel object that was previously successfully requested by + * calling mbox_get_by_*(). + * @data: A pointer to the buffer to receive the message. The format and + * size of the memory region pointed at by @data is determined by + * the mailbox provider. Providers that solely transfer + * notifications will ignore this parameter. + * @timeout_us: The maximum time to wait for a message to be available, in + * micro-seconds. A value of 0 does not wait at all. + * @return 0 if OK, -ENODATA if no message was available, or a negative error + * code. + */ +int mbox_recv(struct mbox_chan *chan, void *data, ulong timeout_us); + +#endif diff --git a/include/mailbox_uclass.h b/include/mailbox_uclass.h new file mode 100644 index 0000000000..6a2994c34c --- /dev/null +++ b/include/mailbox_uclass.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _MAILBOX_UCLASS_H +#define _MAILBOX_UCLASS_H + +/* See mailbox_client.h for background documentation. */ + +#include + +struct udevice; + +/** + * struct mbox_ops - The functions that a mailbox driver must implement. + */ +struct mbox_ops { + /** + * of_xlate - Translate a client's device-tree (OF) mailbox specifier. + * + * The mailbox core calls this function as the first step in + * implementing a client's mbox_get_by_*() call. + * + * If this function pointer is set to NULL, the mailbox core will use + * a default implementation, which assumes #mbox-cells = <1>, and that + * the DT cell contains a simple integer channel ID. + * + * At present, the mailbox API solely supports device-tree. If this + * changes, other xxx_xlate() functions may be added to support those + * other mechanisms. + * + * @chan: The channel to hold the translation result. + * @args: The mailbox specifier values from device tree. + * @return 0 if OK, or a negative error code. + */ + int (*of_xlate)(struct mbox_chan *chan, + struct fdtdec_phandle_args *args); + /** + * request - Request a translated channel. + * + * The mailbox core calls this function as the second step in + * implementing a client's mbox_get_by_*() call, following a successful + * xxx_xlate() call. + * + * @chan: The channel to request; this has been filled in by a + * previoux xxx_xlate() function call. + * @return 0 if OK, or a negative error code. + */ + int (*request)(struct mbox_chan *chan); + /** + * free - Free a previously requested channel. + * + * This is the implementation of the client mbox_free() API. + * + * @chan: The channel to free. + * @return 0 if OK, or a negative error code. + */ + int (*free)(struct mbox_chan *chan); + /** + * send - Send a message over a mailbox channel + * + * @chan: The channel to send to the message to. + * @data: A pointer to the message to send. + * @return 0 if OK, or a negative error code. + */ + int (*send)(struct mbox_chan *chan, const void *data); + /** + * recv - Receive any available message from the channel. + * + * This function does not block. If not message is immediately + * available, the function should return an error. + * + * @chan: The channel to receive to the message from. + * @data: A pointer to the buffer to hold the received message. + * @return 0 if OK, -ENODATA if no message was available, or a negative + * error code. + */ + int (*recv)(struct mbox_chan *chan, void *data); +}; + +#endif From 8961b524240f40ac2fefcdee0818af10899832f2 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Mon, 16 May 2016 17:41:37 -0600 Subject: [PATCH 05/25] mailbox: implement a sandbox test This adds a sandbox mailbox implementation (provider), a test client device, instantiates them both from Sandbox's DT, and adds a DM test that excercises everything. Signed-off-by: Stephen Warren Acked-by: Simon Glass # v1 --- arch/sandbox/dts/test.dts | 11 +++ arch/sandbox/include/asm/mbox.h | 21 ++++++ configs/sandbox_defconfig | 3 + drivers/mailbox/Kconfig | 7 ++ drivers/mailbox/Makefile | 2 + drivers/mailbox/sandbox-mbox-test.c | 54 +++++++++++++++ drivers/mailbox/sandbox-mbox.c | 104 ++++++++++++++++++++++++++++ test/dm/Makefile | 1 + test/dm/mailbox.c | 31 +++++++++ 9 files changed, 234 insertions(+) create mode 100644 arch/sandbox/include/asm/mbox.h create mode 100644 drivers/mailbox/sandbox-mbox-test.c create mode 100644 drivers/mailbox/sandbox-mbox.c create mode 100644 test/dm/mailbox.c diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 89300096a5..686c215aea 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -216,6 +216,17 @@ }; }; + mbox: mbox { + compatible = "sandbox,mbox"; + #mbox-cells = <1>; + }; + + mbox-test { + compatible = "sandbox,mbox-test"; + mboxes = <&mbox 100>, <&mbox 1>; + mbox-names = "other", "test"; + }; + mmc { compatible = "sandbox,mmc"; }; diff --git a/arch/sandbox/include/asm/mbox.h b/arch/sandbox/include/asm/mbox.h new file mode 100644 index 0000000000..2d7b7d03e5 --- /dev/null +++ b/arch/sandbox/include/asm/mbox.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __SANDBOX_MBOX_H +#define __SANDBOX_MBOX_H + +#include + +#define SANDBOX_MBOX_PING_XOR 0x12345678 + +struct udevice; + +int sandbox_mbox_test_get(struct udevice *dev); +int sandbox_mbox_test_send(struct udevice *dev, uint32_t msg); +int sandbox_mbox_test_recv(struct udevice *dev, uint32_t *msg); +int sandbox_mbox_test_free(struct udevice *dev); + +#endif diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 6e30c5df8b..4eb3c224fd 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -170,3 +170,6 @@ CONFIG_UNIT_TEST=y CONFIG_UT_TIME=y CONFIG_UT_DM=y CONFIG_UT_ENV=y +CONFIG_MISC=y +CONFIG_DM_MAILBOX=y +CONFIG_SANDBOX_MBOX=y diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index 295e6db0f2..9087512390 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -10,4 +10,11 @@ config DM_MAILBOX the basis of a variety of inter-process/inter-CPU communication protocols. +config SANDBOX_MBOX + bool "Enable the sandbox mailbox test driver" + depends on DM_MAILBOX && SANDBOX + help + Enable support for a test mailbox implementation, which simply echos + back a modified version of any message that is sent. + endmenu diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index a2d96a4e3b..bbae4def6d 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -3,3 +3,5 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_DM_MAILBOX) += mailbox-uclass.o +obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox.o +obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox-test.o diff --git a/drivers/mailbox/sandbox-mbox-test.c b/drivers/mailbox/sandbox-mbox-test.c new file mode 100644 index 0000000000..02d161aada --- /dev/null +++ b/drivers/mailbox/sandbox-mbox-test.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include + +struct sandbox_mbox_test { + struct mbox_chan chan; +}; + +int sandbox_mbox_test_get(struct udevice *dev) +{ + struct sandbox_mbox_test *sbmt = dev_get_priv(dev); + + return mbox_get_by_name(dev, "test", &sbmt->chan); +} + +int sandbox_mbox_test_send(struct udevice *dev, uint32_t msg) +{ + struct sandbox_mbox_test *sbmt = dev_get_priv(dev); + + return mbox_send(&sbmt->chan, &msg); +} + +int sandbox_mbox_test_recv(struct udevice *dev, uint32_t *msg) +{ + struct sandbox_mbox_test *sbmt = dev_get_priv(dev); + + return mbox_recv(&sbmt->chan, msg, 100); +} + +int sandbox_mbox_test_free(struct udevice *dev) +{ + struct sandbox_mbox_test *sbmt = dev_get_priv(dev); + + return mbox_free(&sbmt->chan); +} + +static const struct udevice_id sandbox_mbox_test_ids[] = { + { .compatible = "sandbox,mbox-test" }, + { } +}; + +U_BOOT_DRIVER(sandbox_mbox_test) = { + .name = "sandbox_mbox_test", + .id = UCLASS_MISC, + .of_match = sandbox_mbox_test_ids, + .priv_auto_alloc_size = sizeof(struct sandbox_mbox_test), +}; diff --git a/drivers/mailbox/sandbox-mbox.c b/drivers/mailbox/sandbox-mbox.c new file mode 100644 index 0000000000..1b7ac231cb --- /dev/null +++ b/drivers/mailbox/sandbox-mbox.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include + +#define SANDBOX_MBOX_CHANNELS 2 + +struct sandbox_mbox_chan { + bool rx_msg_valid; + uint32_t rx_msg; +}; + +struct sandbox_mbox { + struct sandbox_mbox_chan chans[SANDBOX_MBOX_CHANNELS]; +}; + +static int sandbox_mbox_request(struct mbox_chan *chan) +{ + debug("%s(chan=%p)\n", __func__, chan); + + if (chan->id >= SANDBOX_MBOX_CHANNELS) + return -EINVAL; + + return 0; +} + +static int sandbox_mbox_free(struct mbox_chan *chan) +{ + debug("%s(chan=%p)\n", __func__, chan); + + return 0; +} + +static int sandbox_mbox_send(struct mbox_chan *chan, const void *data) +{ + struct sandbox_mbox *sbm = dev_get_priv(chan->dev); + const uint32_t *pmsg = data; + + debug("%s(chan=%p, data=%p)\n", __func__, chan, data); + + sbm->chans[chan->id].rx_msg = *pmsg ^ SANDBOX_MBOX_PING_XOR; + sbm->chans[chan->id].rx_msg_valid = true; + + return 0; +} + +static int sandbox_mbox_recv(struct mbox_chan *chan, void *data) +{ + struct sandbox_mbox *sbm = dev_get_priv(chan->dev); + uint32_t *pmsg = data; + + debug("%s(chan=%p, data=%p)\n", __func__, chan, data); + + if (!sbm->chans[chan->id].rx_msg_valid) + return -ENODATA; + + *pmsg = sbm->chans[chan->id].rx_msg; + sbm->chans[chan->id].rx_msg_valid = false; + + return 0; +} + +static int sandbox_mbox_bind(struct udevice *dev) +{ + debug("%s(dev=%p)\n", __func__, dev); + + return 0; +} + +static int sandbox_mbox_probe(struct udevice *dev) +{ + debug("%s(dev=%p)\n", __func__, dev); + + return 0; +} + +static const struct udevice_id sandbox_mbox_ids[] = { + { .compatible = "sandbox,mbox" }, + { } +}; + +struct mbox_ops sandbox_mbox_mbox_ops = { + .request = sandbox_mbox_request, + .free = sandbox_mbox_free, + .send = sandbox_mbox_send, + .recv = sandbox_mbox_recv, +}; + +U_BOOT_DRIVER(sandbox_mbox) = { + .name = "sandbox_mbox", + .id = UCLASS_MAILBOX, + .of_match = sandbox_mbox_ids, + .bind = sandbox_mbox_bind, + .probe = sandbox_mbox_probe, + .priv_auto_alloc_size = sizeof(struct sandbox_mbox), + .ops = &sandbox_mbox_mbox_ops, +}; diff --git a/test/dm/Makefile b/test/dm/Makefile index fd781e82cf..9eaf04b9ba 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -21,6 +21,7 @@ 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_MAILBOX) += mailbox.o obj-$(CONFIG_DM_MMC) += mmc.o obj-$(CONFIG_DM_PCI) += pci.o obj-$(CONFIG_RAM) += ram.o diff --git a/test/dm/mailbox.c b/test/dm/mailbox.c new file mode 100644 index 0000000000..be7bd6de06 --- /dev/null +++ b/test/dm/mailbox.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include + +static int dm_test_mailbox(struct unit_test_state *uts) +{ + struct udevice *dev; + uint32_t msg; + + ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "mbox-test", &dev)); + ut_assertok(sandbox_mbox_test_get(dev)); + + ut_asserteq(-ETIMEDOUT, sandbox_mbox_test_recv(dev, &msg)); + ut_assertok(sandbox_mbox_test_send(dev, 0xaaff9955UL)); + ut_assertok(sandbox_mbox_test_recv(dev, &msg)); + ut_asserteq(msg, 0xaaff9955UL ^ SANDBOX_MBOX_PING_XOR); + ut_asserteq(-ETIMEDOUT, sandbox_mbox_test_recv(dev, &msg)); + + ut_assertok(sandbox_mbox_test_free(dev)); + + return 0; +} +DM_TEST(dm_test_mailbox, DM_TESTF_SCAN_FDT); From d0375f3cc55ce740836f9ba6fe081ed0fdc19a3c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 7 Aug 2015 07:42:22 -0600 Subject: [PATCH 06/25] arm: rpi: Define CONFIG_TFTP_TSIZE to show tftp size info This shows a proper progress display and the total amount of data transferred. Enable it for Raspberry Pi. Signed-off-by: Simon Glass Acked-by: Stephen Warren --- include/configs/rpi.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/configs/rpi.h b/include/configs/rpi.h index af58182e7b..9ef5eae304 100644 --- a/include/configs/rpi.h +++ b/include/configs/rpi.h @@ -106,6 +106,7 @@ #define CONFIG_USB_STORAGE #define CONFIG_USB_HOST_ETHER #define CONFIG_USB_ETHER_SMSC95XX +#define CONFIG_TFTP_TSIZE #define CONFIG_MISC_INIT_R #define CONFIG_USB_KEYBOARD #define CONFIG_SYS_USB_EVENT_POLL From 1fb67608b309bd7f49842fbdfb1dc2b18a250965 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 14 May 2016 14:02:52 -0600 Subject: [PATCH 07/25] tiny-printf: Tidy up a few nits - Rename 'w' to 'width' to make it more obvious what it is used for - Use bool and int types instead of char to avoid register-masking on 32-bit machines Signed-off-by: Simon Glass Reviewed-by: Stefan Roese --- lib/tiny-printf.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/tiny-printf.c b/lib/tiny-printf.c index a06abed495..fbd5368c0b 100644 --- a/lib/tiny-printf.c +++ b/lib/tiny-printf.c @@ -52,8 +52,8 @@ int vprintf(const char *fmt, va_list va) if (ch != '%') { putc(ch); } else { - char lz = 0; - char w = 0; + bool lz = false; + int width = 0; ch = *(fmt++); if (ch == '0') { @@ -62,9 +62,9 @@ int vprintf(const char *fmt, va_list va) } if (ch >= '0' && ch <= '9') { - w = 0; + width = 0; while (ch >= '0' && ch <= '9') { - w = (w * 10) + ch - '0'; + width = (width * 10) + ch - '0'; ch = *fmt++; } } @@ -73,7 +73,7 @@ int vprintf(const char *fmt, va_list va) zs = 0; switch (ch) { - case 0: + case '\0': goto abort; case 'u': case 'd': @@ -112,9 +112,9 @@ int vprintf(const char *fmt, va_list va) *bf = 0; bf = p; - while (*bf++ && w > 0) - w--; - while (w-- > 0) + while (*bf++ && width > 0) + width--; + while (width-- > 0) putc(lz ? '0' : ' '); if (p) { while ((ch = *p++)) From 5c411d88be8df5f6a8a1ea0c961f7c35ba82c064 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 14 May 2016 14:02:53 -0600 Subject: [PATCH 08/25] tiny-printf: Support snprintf() Add a simple version of this function for SPL. It does not check the buffer size as this would add to the code size. Signed-off-by: Simon Glass Reviewed-by: Stefan Roese --- lib/tiny-printf.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/lib/tiny-printf.c b/lib/tiny-printf.c index fbd5368c0b..4b70263df7 100644 --- a/lib/tiny-printf.c +++ b/lib/tiny-printf.c @@ -16,6 +16,9 @@ static char *bf; static char zs; +/* Current position in sprintf() output string */ +static char *outstr; + static void out(char c) { *bf++ = c; @@ -40,7 +43,7 @@ static void div_out(unsigned int *num, unsigned int div) out_dgt(dgt); } -int vprintf(const char *fmt, va_list va) +int _vprintf(const char *fmt, va_list va, void (*putc)(const char ch)) { char ch; char *p; @@ -133,8 +136,28 @@ int printf(const char *fmt, ...) int ret; va_start(va, fmt); - ret = vprintf(fmt, va); + ret = _vprintf(fmt, va, putc); va_end(va); return ret; } + +static void putc_outstr(char ch) +{ + *outstr++ = ch; +} + +/* Note that size is ignored */ +int snprintf(char *buf, size_t size, const char *fmt, ...) +{ + va_list va; + int ret; + + va_start(va, fmt); + outstr = buf; + ret = _vprintf(fmt, va, putc_outstr); + va_end(va); + *outstr = '\0'; + + return ret; +} From 5c0862155c883b9e134fae72d25f1b5a93260510 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 14 May 2016 14:02:54 -0600 Subject: [PATCH 09/25] reset: Drop the reset failure message This adds to code size and is not needed, since hang() will print a message. Signed-off-by: Simon Glass --- drivers/misc/sysreset-uclass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/sysreset-uclass.c b/drivers/misc/sysreset-uclass.c index e41efcaca6..3566d17fb1 100644 --- a/drivers/misc/sysreset-uclass.c +++ b/drivers/misc/sysreset-uclass.c @@ -55,7 +55,7 @@ void sysreset_walk_halt(enum sysreset_t type) mdelay(100); /* Still no reset? Give up */ - printf("System reset not supported on this platform\n"); + debug("System reset not supported on this platform\n"); hang(); } From e98dd20ccec30311dddd165f945c7ce0dedef6db Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 14 May 2016 14:02:55 -0600 Subject: [PATCH 10/25] mmc: Drop mmc_register() This function is no longer used. Signed-off-by: Simon Glass --- drivers/mmc/mmc.c | 9 --------- include/mmc.h | 1 - 2 files changed, 10 deletions(-) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 74b3d68f87..1ddeff4ace 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1531,15 +1531,6 @@ static int mmc_send_if_cond(struct mmc *mmc) return 0; } -/* not used any more */ -int __deprecated mmc_register(struct mmc *mmc) -{ -#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) - printf("%s is deprecated! use mmc_create() instead.\n", __func__); -#endif - return -1; -} - #ifdef CONFIG_BLK int mmc_bind(struct udevice *dev, struct mmc *mmc, const struct mmc_config *cfg) { diff --git a/include/mmc.h b/include/mmc.h index a5c6573ddd..056296e908 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -411,7 +411,6 @@ enum mmc_hwpart_conf_mode { MMC_HWPART_CONF_COMPLETE, }; -int mmc_register(struct mmc *mmc); struct mmc *mmc_create(const struct mmc_config *cfg, void *priv); /** From 9cf7b1a74c8c17145e39d34893cce763e098efd2 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 14 May 2016 14:02:56 -0600 Subject: [PATCH 11/25] mmc: Drop dead mmc code for non-generic MMC All boards that use MMC define CONFIG_GENERIC_MMC now, so we can drop this old code. Signed-off-by: Simon Glass --- cmd/mmc.c | 62 --------------------------------------------------- include/mmc.h | 4 ---- 2 files changed, 66 deletions(-) diff --git a/cmd/mmc.c b/cmd/mmc.c index eb4a547a97..b2761e934b 100644 --- a/cmd/mmc.c +++ b/cmd/mmc.c @@ -11,66 +11,6 @@ #include static int curr_device = -1; -#ifndef CONFIG_GENERIC_MMC -int do_mmc (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) -{ - int dev; - - if (argc < 2) - return CMD_RET_USAGE; - - if (strcmp(argv[1], "init") == 0) { - if (argc == 2) { - if (curr_device < 0) - dev = 1; - else - dev = curr_device; - } else if (argc == 3) { - dev = (int)simple_strtoul(argv[2], NULL, 10); - } else { - return CMD_RET_USAGE; - } - - if (mmc_legacy_init(dev) != 0) { - puts("No MMC card found\n"); - return 1; - } - - curr_device = dev; - printf("mmc%d is available\n", curr_device); - } else if (strcmp(argv[1], "device") == 0) { - if (argc == 2) { - if (curr_device < 0) { - puts("No MMC device available\n"); - return 1; - } - } else if (argc == 3) { - dev = (int)simple_strtoul(argv[2], NULL, 10); - -#ifdef CONFIG_SYS_MMC_SET_DEV - if (mmc_set_dev(dev) != 0) - return 1; -#endif - curr_device = dev; - } else { - return CMD_RET_USAGE; - } - - printf("mmc%d is current device\n", curr_device); - } else { - return CMD_RET_USAGE; - } - - return 0; -} - -U_BOOT_CMD( - mmc, 3, 1, do_mmc, - "MMC sub-system", - "init [dev] - init MMC sub system\n" - "mmc device [dev] - show or set current device" -); -#else /* !CONFIG_GENERIC_MMC */ static void print_mmcinfo(struct mmc *mmc) { @@ -881,5 +821,3 @@ U_BOOT_CMD( "display MMC info", "- display info of the current MMC device" ); - -#endif /* !CONFIG_GENERIC_MMC */ diff --git a/include/mmc.h b/include/mmc.h index 056296e908..7fdfc324fe 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -491,16 +491,12 @@ int mmc_start_init(struct mmc *mmc); */ void mmc_set_preinit(struct mmc *mmc, int preinit); -#ifdef CONFIG_GENERIC_MMC #ifdef CONFIG_MMC_SPI #define mmc_host_is_spi(mmc) ((mmc)->cfg->host_caps & MMC_MODE_SPI) #else #define mmc_host_is_spi(mmc) 0 #endif struct mmc *mmc_spi_init(uint bus, uint cs, uint speed, uint mode); -#else -int mmc_legacy_init(int verbose); -#endif void board_mmc_power_init(void); int board_mmc_init(bd_t *bis); From 61fe076f0fceaa00bcbb8901504aedf1d1096293 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 14 May 2016 14:02:57 -0600 Subject: [PATCH 12/25] mmc: Use byte array for multipliers We don't need an int since no value is over 80. This saves a small amount of SPL space (about 44 bytes). Signed-off-by: Simon Glass --- drivers/mmc/mmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 1ddeff4ace..b7c936c720 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -984,7 +984,7 @@ static const int fbase[] = { /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice * to platforms without floating point. */ -static const int multipliers[] = { +static const u8 multipliers[] = { 0, /* reserved */ 10, 12, From 9217d93bc45668815ebaab0ad9280ace166b7348 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 14 May 2016 14:02:59 -0600 Subject: [PATCH 13/25] rockchip: Check image name for the rksd image We need a correct name (rk3288, rk3036) so check this to avoid a crash later. Signed-off-by: Simon Glass --- tools/rkimage.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/tools/rkimage.c b/tools/rkimage.c index f9fdcfa712..ef31cb6944 100644 --- a/tools/rkimage.c +++ b/tools/rkimage.c @@ -13,11 +13,6 @@ static uint32_t header; -static int rkimage_check_params(struct image_tool_params *params) -{ - return 0; -} - static int rkimage_verify_header(unsigned char *buf, int size, struct image_tool_params *params) { @@ -56,7 +51,7 @@ U_BOOT_IMAGE_TYPE( "Rockchip Boot Image support", 4, &header, - rkimage_check_params, + rkcommon_check_params, rkimage_verify_header, rkimage_print_header, rkimage_set_header, From 56d6977121732e4efe6cd48872e874e40f4916a0 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 14 May 2016 14:03:00 -0600 Subject: [PATCH 14/25] rockchip: Drop unnecessary SPL properties While we consider whether to drop use of DT in SPL, remove some unwanted properties. This reduces SPL size by about 250 bytes. Signed-off-by: Simon Glass --- configs/firefly-rk3288_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/firefly-rk3288_defconfig b/configs/firefly-rk3288_defconfig index 0cbc539848..4af91206dc 100644 --- a/configs/firefly-rk3288_defconfig +++ b/configs/firefly-rk3288_defconfig @@ -28,7 +28,7 @@ CONFIG_CMD_EXT4=y CONFIG_CMD_FAT=y CONFIG_CMD_FS_GENERIC=y CONFIG_SPL_OF_CONTROL=y -CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names clock-names interrupt-parent" +CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names clock-names interrupt-parent assigned-clocks assigned-clock-rates assigned-clock-parents" CONFIG_REGMAP=y CONFIG_SPL_REGMAP=y CONFIG_SYSCON=y From b55e04a021ee256aaba118a547f13a4722538623 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 14 May 2016 14:03:01 -0600 Subject: [PATCH 15/25] rockchip: video: Flush the cache when the display is updated Enable this option to correct display artifacts when a write-back cache is in use. Signed-off-by: Simon Glass --- drivers/video/rockchip/rk_vop.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/video/rockchip/rk_vop.c b/drivers/video/rockchip/rk_vop.c index a54af172ec..db09d9a41d 100644 --- a/drivers/video/rockchip/rk_vop.c +++ b/drivers/video/rockchip/rk_vop.c @@ -326,6 +326,7 @@ static int rk_vop_probe(struct udevice *dev) if (!ret) break; } + video_set_flush_dcache(dev, 1); return ret; } From 3c2d75269cb4c94c445be2f77adcbca4add70893 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 14 May 2016 14:03:02 -0600 Subject: [PATCH 16/25] rockchip: Drop SPL GPIO support for rk3288 This is not currently used and saves a little over 1KB of SPL image size. Signed-off-by: Simon Glass --- include/configs/rk3288_common.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/configs/rk3288_common.h b/include/configs/rk3288_common.h index 8a81397290..9d50d834db 100644 --- a/include/configs/rk3288_common.h +++ b/include/configs/rk3288_common.h @@ -69,7 +69,6 @@ #define CONFIG_SPL_FS_LOAD_PAYLOAD_NAME "u-boot.img" #define CONFIG_SPL_PINCTRL_SUPPORT -#define CONFIG_SPL_GPIO_SUPPORT #define CONFIG_SPL_RAM_SUPPORT #define CONFIG_SPL_DRIVERS_MISC_SUPPORT From 5461acba44b7da8292ba2cbeaf961279d9b8c187 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 14 May 2016 14:03:03 -0600 Subject: [PATCH 17/25] dm: env: mmc: Convert env_mmc to support CONFIG_BLK Update the MMC environment code so that it works with driver-model enabled for block devices. Signed-off-by: Simon Glass --- common/env_mmc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common/env_mmc.c b/common/env_mmc.c index c7fef188cd..16f6a17514 100644 --- a/common/env_mmc.c +++ b/common/env_mmc.c @@ -128,12 +128,12 @@ static inline int write_env(struct mmc *mmc, unsigned long size, unsigned long offset, const void *buffer) { uint blk_start, blk_cnt, n; + struct blk_desc *desc = mmc_get_blk_desc(mmc); blk_start = ALIGN(offset, mmc->write_bl_len) / mmc->write_bl_len; blk_cnt = ALIGN(size, mmc->write_bl_len) / mmc->write_bl_len; - n = mmc->block_dev.block_write(&mmc->block_dev, blk_start, - blk_cnt, (u_char *)buffer); + n = blk_dwrite(desc, blk_start, blk_cnt, (u_char *)buffer); return (n == blk_cnt) ? 0 : -1; } @@ -197,12 +197,12 @@ static inline int read_env(struct mmc *mmc, unsigned long size, unsigned long offset, const void *buffer) { uint blk_start, blk_cnt, n; + struct blk_desc *desc = mmc_get_blk_desc(mmc); blk_start = ALIGN(offset, mmc->read_bl_len) / mmc->read_bl_len; blk_cnt = ALIGN(size, mmc->read_bl_len) / mmc->read_bl_len; - n = mmc->block_dev.block_read(&mmc->block_dev, blk_start, blk_cnt, - (uchar *)buffer); + n = blk_dread(desc, blk_start, blk_cnt, (uchar *)buffer); return (n == blk_cnt) ? 0 : -1; } From 19d2e34237d5c077b2dc395522a1559e4b5c62df Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 14 May 2016 14:03:04 -0600 Subject: [PATCH 18/25] dm: mmc: Convert sdhci to support CONFIG_BLK Update sdhci.c so that it works with driver model enabled for block devices. Signed-off-by: Simon Glass --- drivers/mmc/sdhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index ef7e6150f9..5c71ab8d05 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -137,7 +137,7 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, int trans_bytes = 0, is_aligned = 1; u32 mask, flags, mode; unsigned int time = 0, start_addr = 0; - int mmc_dev = mmc->block_dev.devnum; + int mmc_dev = mmc_get_blk_desc(mmc)->devnum; unsigned start = get_timer(0); /* Timeout unit - ms */ From 487d756f78629f5e9465c7ace2c14ef51401bc3b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 14 May 2016 14:03:05 -0600 Subject: [PATCH 19/25] dm: efi: Update for CONFIG_BLK This code does not currently build with driver model enabled for block devices. Update it to correct this. Signed-off-by: Simon Glass Reviewed-by: Alexander Graf --- include/efi_loader.h | 2 +- lib/efi_loader/efi_disk.c | 61 +++++++++++++++++++++++++++++---------- 2 files changed, 47 insertions(+), 16 deletions(-) diff --git a/include/efi_loader.h b/include/efi_loader.h index 88b8149b14..44a950f484 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -134,7 +134,7 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type, int efi_memory_init(void); /* Convert strings from normal C strings to uEFI strings */ -static inline void ascii2unicode(u16 *unicode, char *ascii) +static inline void ascii2unicode(u16 *unicode, const char *ascii) { while (*ascii) *(unicode++) = *(ascii++); diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index 075fd34014..3095bcfa2b 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -96,9 +97,9 @@ static efi_status_t EFIAPI efi_disk_rw_blocks(struct efi_block_io *this, return EFI_EXIT(EFI_DEVICE_ERROR); if (direction == EFI_DISK_READ) - n = desc->block_read(desc, lba, blocks, buffer); + n = blk_dread(desc, lba, blocks, buffer); else - n = desc->block_write(desc, lba, blocks, buffer); + n = blk_dwrite(desc, lba, blocks, buffer); /* We don't do interrupts, so check for timers cooperatively */ efi_timer_check(); @@ -142,8 +143,8 @@ static const struct efi_block_io block_io_disk_template = { .flush_blocks = &efi_disk_flush_blocks, }; -static void efi_disk_add_dev(char *name, - const struct blk_driver *cur_drvr, +static void efi_disk_add_dev(const char *name, + const char *if_typename, const struct blk_desc *desc, int dev_index, lbaint_t offset) @@ -161,7 +162,7 @@ static void efi_disk_add_dev(char *name, diskobj->parent.protocols[1].open = efi_disk_open_dp; diskobj->parent.handle = diskobj; diskobj->ops = block_io_disk_template; - diskobj->ifname = cur_drvr->if_typename; + diskobj->ifname = if_typename; diskobj->dev_index = dev_index; diskobj->offset = offset; @@ -190,7 +191,7 @@ static void efi_disk_add_dev(char *name, } static int efi_disk_create_eltorito(struct blk_desc *desc, - const struct blk_driver *cur_drvr, + const char *if_typename, int diskid) { int disks = 0; @@ -203,9 +204,10 @@ static int efi_disk_create_eltorito(struct blk_desc *desc, return 0; while (!part_get_info(desc, part, &info)) { - snprintf(devname, sizeof(devname), "%s%d:%d", - cur_drvr->if_typename, diskid, part); - efi_disk_add_dev(devname, cur_drvr, desc, diskid, info.start); + snprintf(devname, sizeof(devname), "%s%d:%d", if_typename, + diskid, part); + efi_disk_add_dev(devname, if_typename, desc, diskid, + info.start); part++; disks++; } @@ -219,21 +221,49 @@ static int efi_disk_create_eltorito(struct blk_desc *desc, * EFI payload, we scan through all of the potentially available ones and * store them in our object pool. * + * TODO(sjg@chromium.org): Actually with CONFIG_BLK, U-Boot does have this. + * Consider converting the code to look up devices as needed. The EFI device + * could be a child of the UCLASS_BLK block device, perhaps. + * * This gets called from do_bootefi_exec(). */ int efi_disk_register(void) { - const struct blk_driver *cur_drvr; - int i, if_type; int disks = 0; +#ifdef CONFIG_BLK + struct udevice *dev; + + for (uclass_first_device(UCLASS_BLK, &dev); + dev; + uclass_next_device(&dev)) { + struct blk_desc *desc = dev_get_uclass_platdata(dev); + const char *if_typename = dev->driver->name; + + printf("Scanning disk %s...\n", dev->name); + efi_disk_add_dev(dev->name, if_typename, desc, desc->devnum, 0); + disks++; + + /* + * El Torito images show up as block devices in an EFI world, + * so let's create them here + */ + disks += efi_disk_create_eltorito(desc, if_typename, + desc->devnum); + } +#else + int i, if_type; /* Search for all available disk devices */ for (if_type = 0; if_type < IF_TYPE_COUNT; if_type++) { + const struct blk_driver *cur_drvr; + const char *if_typename; + cur_drvr = blk_driver_lookup_type(if_type); if (!cur_drvr) continue; - printf("Scanning disks on %s...\n", cur_drvr->if_typename); + if_typename = cur_drvr->if_typename; + printf("Scanning disks on %s...\n", if_typename); for (i = 0; i < 4; i++) { struct blk_desc *desc; char devname[32] = { 0 }; /* dp->str is u16[32] long */ @@ -245,17 +275,18 @@ int efi_disk_register(void) continue; snprintf(devname, sizeof(devname), "%s%d", - cur_drvr->if_typename, i); - efi_disk_add_dev(devname, cur_drvr, desc, i, 0); + if_typename, i); + efi_disk_add_dev(devname, if_typename, desc, i, 0); disks++; /* * El Torito images show up as block devices * in an EFI world, so let's create them here */ - disks += efi_disk_create_eltorito(desc, cur_drvr, i); + disks += efi_disk_create_eltorito(desc, if_typename, i); } } +#endif printf("Found %d disks\n", disks); return 0; From ef5609c33fc6a8323613a296f08c8efa3161d77f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 14 May 2016 14:03:06 -0600 Subject: [PATCH 20/25] dm: mmc: spl: Add support for CONFIG_BLK Allow driver model to be used for block devices in SPL. Signed-off-by: Simon Glass --- common/spl/spl_mmc.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c index 5676acdde3..6adfc9b8e5 100644 --- a/common/spl/spl_mmc.c +++ b/common/spl/spl_mmc.c @@ -34,9 +34,8 @@ static int mmc_load_legacy(struct mmc *mmc, ulong sector, mmc->read_bl_len; /* Read the header too to avoid extra memcpy */ - count = mmc->block_dev.block_read(&mmc->block_dev, sector, - image_size_sectors, - (void *)(ulong)spl_image.load_addr); + count = blk_dread(mmc_get_blk_desc(mmc), sector, image_size_sectors, + (void *)(ulong)spl_image.load_addr); debug("read %x sectors to %x\n", image_size_sectors, spl_image.load_addr); if (count != image_size_sectors) @@ -50,7 +49,7 @@ static ulong h_spl_load_read(struct spl_load_info *load, ulong sector, { struct mmc *mmc = load->dev; - return mmc->block_dev.block_read(&mmc->block_dev, sector, count, buf); + return blk_dread(mmc_get_blk_desc(mmc), sector, count, buf); } static int mmc_load_image_raw_sector(struct mmc *mmc, unsigned long sector) @@ -63,7 +62,7 @@ static int mmc_load_image_raw_sector(struct mmc *mmc, unsigned long sector) sizeof(struct image_header)); /* read image header to find the image size & load address */ - count = mmc->block_dev.block_read(&mmc->block_dev, sector, 1, header); + count = blk_dread(mmc_get_blk_desc(mmc), sector, 1, header); debug("hdr read sector %lx, count=%lu\n", sector, count); if (count == 0) { ret = -EIO; From 5e6ff810c3bfeec2e81cc1117a2c1514416d947d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 14 May 2016 14:03:07 -0600 Subject: [PATCH 21/25] dm: mmc: dwmmc: Support CONFIG_BLK Add support for using driver model for block devices in this driver. Signed-off-by: Simon Glass --- drivers/mmc/dw_mmc.c | 52 ++++++++++++++++++++++++++++---------------- include/dwmmc.h | 7 +++++- 2 files changed, 39 insertions(+), 20 deletions(-) diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index 7329f40d34..74a2663c8b 100644 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -454,27 +454,40 @@ static const struct mmc_ops dwmci_ops = { .init = dwmci_init, }; +void dwmci_setup_cfg(struct mmc_config *cfg, const char *name, int buswidth, + uint caps, u32 max_clk, u32 min_clk) +{ + cfg->name = name; + cfg->ops = &dwmci_ops; + cfg->f_min = min_clk; + cfg->f_max = max_clk; + + cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; + + cfg->host_caps = caps; + + if (buswidth == 8) { + cfg->host_caps |= MMC_MODE_8BIT; + cfg->host_caps &= ~MMC_MODE_4BIT; + } else { + cfg->host_caps |= MMC_MODE_4BIT; + cfg->host_caps &= ~MMC_MODE_8BIT; + } + cfg->host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz; + + cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; +} + +#ifdef CONFIG_BLK +int dwmci_bind(struct udevice *dev, struct mmc *mmc, struct mmc_config *cfg) +{ + return mmc_bind(dev, mmc, cfg); +} +#else int add_dwmci(struct dwmci_host *host, u32 max_clk, u32 min_clk) { - host->cfg.name = host->name; - host->cfg.ops = &dwmci_ops; - host->cfg.f_min = min_clk; - host->cfg.f_max = max_clk; - - host->cfg.voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; - - host->cfg.host_caps = host->caps; - - if (host->buswidth == 8) { - host->cfg.host_caps |= MMC_MODE_8BIT; - host->cfg.host_caps &= ~MMC_MODE_4BIT; - } else { - host->cfg.host_caps |= MMC_MODE_4BIT; - host->cfg.host_caps &= ~MMC_MODE_8BIT; - } - host->cfg.host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz; - - host->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; + dwmci_setup_cfg(&host->cfg, host->name, host->buswidth, host->caps, + max_clk, min_clk); host->mmc = mmc_create(&host->cfg, host); if (host->mmc == NULL) @@ -482,3 +495,4 @@ int add_dwmci(struct dwmci_host *host, u32 max_clk, u32 min_clk) return 0; } +#endif diff --git a/include/dwmmc.h b/include/dwmmc.h index 05b0817fe1..335af51fdf 100644 --- a/include/dwmmc.h +++ b/include/dwmmc.h @@ -180,8 +180,9 @@ struct dwmci_host { * @freq: Frequency the host is trying to achieve */ unsigned int (*get_mmc_clk)(struct dwmci_host *host, uint freq); - +#ifndef CONFIG_BLK struct mmc_config cfg; +#endif /* use fifo mode to read and write data */ bool fifo_mode; @@ -223,5 +224,9 @@ static inline u8 dwmci_readb(struct dwmci_host *host, int reg) return readb(host->ioaddr + reg); } +void dwmci_setup_cfg(struct mmc_config *cfg, const char *name, int buswidth, + uint caps, u32 max_clk, u32 min_clk); +int dwmci_bind(struct udevice *dev, struct mmc *mmc, struct mmc_config *cfg); + int add_dwmci(struct dwmci_host *host, u32 max_clk, u32 min_clk); #endif /* __DWMMC_HW_H */ From f6e41d17ababd72479d2dfdb40be63beb359de1d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 14 May 2016 14:03:08 -0600 Subject: [PATCH 22/25] dm: rockchip: mmc: Allow use of CONFIG_BLK Allow driver model to be used for block devices in the rockchip mmc driver. Signed-off-by: Simon Glass --- drivers/mmc/rockchip_dw_mmc.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c index 0a261c51a8..750ab9f8c5 100644 --- a/drivers/mmc/rockchip_dw_mmc.c +++ b/drivers/mmc/rockchip_dw_mmc.c @@ -18,6 +18,11 @@ DECLARE_GLOBAL_DATA_PTR; +struct rockchip_mmc_plat { + struct mmc_config cfg; + struct mmc mmc; +}; + struct rockchip_dwmmc_priv { struct udevice *clk; int periph; @@ -62,6 +67,9 @@ static int rockchip_dwmmc_ofdata_to_platdata(struct udevice *dev) static int rockchip_dwmmc_probe(struct udevice *dev) { +#ifdef CONFIG_BLK + struct rockchip_mmc_plat *plat = dev_get_platdata(dev); +#endif struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); struct rockchip_dwmmc_priv *priv = dev_get_priv(dev); struct dwmci_host *host = &priv->host; @@ -100,16 +108,37 @@ static int rockchip_dwmmc_probe(struct udevice *dev) return ret; } #endif +#ifdef CONFIG_BLK + dwmci_setup_cfg(&plat->cfg, dev->name, host->buswidth, host->caps, + minmax[1], minmax[0]); + host->mmc = &plat->mmc; +#else ret = add_dwmci(host, minmax[1], minmax[0]); if (ret) return ret; +#endif + host->mmc->priv = &priv->host; host->mmc->dev = dev; upriv->mmc = host->mmc; return 0; } +static int rockchip_dwmmc_bind(struct udevice *dev) +{ +#ifdef CONFIG_BLK + struct rockchip_mmc_plat *plat = dev_get_platdata(dev); + int ret; + + ret = dwmci_bind(dev, &plat->mmc, &plat->cfg); + if (ret) + return ret; +#endif + + return 0; +} + static const struct udevice_id rockchip_dwmmc_ids[] = { { .compatible = "rockchip,rk3288-dw-mshc" }, { } @@ -120,8 +149,10 @@ U_BOOT_DRIVER(rockchip_dwmmc_drv) = { .id = UCLASS_MMC, .of_match = rockchip_dwmmc_ids, .ofdata_to_platdata = rockchip_dwmmc_ofdata_to_platdata, + .bind = rockchip_dwmmc_bind, .probe = rockchip_dwmmc_probe, .priv_auto_alloc_size = sizeof(struct rockchip_dwmmc_priv), + .platdata_auto_alloc_size = sizeof(struct rockchip_mmc_plat), }; #ifdef CONFIG_PWRSEQ From e419a3ec1aa3f094268976b6c10e9b636a97c64d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 14 May 2016 14:03:09 -0600 Subject: [PATCH 23/25] dm: mmc: Fix up mmc_bread/bwrite() prototypes for SPL When these functions are not compiled in, we still need to declare the correct function signature to avoid a build warnings in SPL. Fix this. Signed-off-by: Simon Glass --- drivers/mmc/mmc_private.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/mmc/mmc_private.h b/drivers/mmc/mmc_private.h index 27b9e5f56f..9f0d5c2384 100644 --- a/drivers/mmc/mmc_private.h +++ b/drivers/mmc/mmc_private.h @@ -37,6 +37,19 @@ ulong mmc_bwrite(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, /* SPL will never write or erase, declare dummies to reduce code size. */ +#ifdef CONFIG_BLK +static inline unsigned long mmc_berase(struct udevice *dev, + lbaint_t start, lbaint_t blkcnt) +{ + return 0; +} + +static inline ulong mmc_bwrite(struct udevice *dev, lbaint_t start, + lbaint_t blkcnt, const void *src) +{ + return 0; +} +#else static inline unsigned long mmc_berase(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt) { @@ -48,6 +61,7 @@ static inline ulong mmc_bwrite(struct blk_desc *block_dev, lbaint_t start, { return 0; } +#endif #endif /* CONFIG_SPL_BUILD */ From e6c28073f94be357d8e55beefd67ccf0c925c90e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 14 May 2016 14:03:10 -0600 Subject: [PATCH 24/25] dm: mmc: Use cfg directly in mmc_bind() This small change tidies up the code slightly. Signed-off-by: Simon Glass --- drivers/mmc/mmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index b7c936c720..94f19ade3e 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1557,7 +1557,7 @@ int mmc_bind(struct udevice *dev, struct mmc *mmc, const struct mmc_config *cfg) bdesc->removable = 1; /* setup initial part type */ - bdesc->part_type = mmc->cfg->part_type; + bdesc->part_type = cfg->part_type; mmc->dev = dev; return 0; From 3c27b6ad540828c44a62d209030df5ba86896df0 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 14 May 2016 14:03:11 -0600 Subject: [PATCH 25/25] dm: rockchip: Enable CONFIG_BLK Enable CONFIG_BLK to move to using driver model for block devices. This affects MMC booting in SPL, as well as MMC access in U-Boot proper. Signed-off-by: Simon Glass --- arch/arm/mach-rockchip/Kconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig index d3bddb726a..2a8afac5e1 100644 --- a/arch/arm/mach-rockchip/Kconfig +++ b/arch/arm/mach-rockchip/Kconfig @@ -41,6 +41,9 @@ config DM_I2C config DM_GPIO default y +config BLK + default y + source "arch/arm/mach-rockchip/rk3288/Kconfig" source "arch/arm/mach-rockchip/rk3036/Kconfig" endif