diff --git a/Makefile b/Makefile index bccfbaa11d..99cc8cf2f7 100644 --- a/Makefile +++ b/Makefile @@ -638,6 +638,7 @@ libs-y += drivers/net/ libs-y += drivers/net/phy/ libs-y += drivers/pci/ libs-y += drivers/power/ \ + drivers/power/domain/ \ drivers/power/fuel_gauge/ \ drivers/power/mfd/ \ drivers/power/pmic/ \ diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 4a62d4b108..6de734f8f2 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -657,10 +657,13 @@ config ARCH_ZYNQ select DM_GPIO select SPL_DM if SPL select DM_MMC + select DM_MMC_OPS select DM_SPI select DM_SERIAL select DM_SPI_FLASH select SPL_SEPARATE_BSS if SPL + select DM_USB if USB + select BLK config ARCH_ZYNQMP bool "Support Xilinx ZynqMP Platform" @@ -671,6 +674,10 @@ config ARCH_ZYNQMP select SUPPORT_SPL select CLK select SPL_CLK + select DM_USB if USB + select DM_MMC + select DM_MMC_OPS + select BLK config TEGRA bool "NVIDIA Tegra" diff --git a/arch/arm/cpu/armv8/zynqmp/Kconfig b/arch/arm/cpu/armv8/zynqmp/Kconfig index 6c71d7840e..ed3305d718 100644 --- a/arch/arm/cpu/armv8/zynqmp/Kconfig +++ b/arch/arm/cpu/armv8/zynqmp/Kconfig @@ -20,4 +20,8 @@ config SYS_CONFIG_NAME config ZYNQMP_USB bool "Configure ZynqMP USB" +config SYS_MALLOC_F_LEN + default 0x600 + + endif diff --git a/arch/arm/mach-zynq/Kconfig b/arch/arm/mach-zynq/Kconfig index db3c579293..a98232097b 100644 --- a/arch/arm/mach-zynq/Kconfig +++ b/arch/arm/mach-zynq/Kconfig @@ -17,4 +17,7 @@ config SYS_CONFIG_NAME Based on this option include/configs/.h header will be used for board configuration. +config SYS_MALLOC_F_LEN + default 0x600 + endif diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 9e46f9e815..fff175d1b7 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -262,6 +262,16 @@ }; }; + pwrdom: power-domain { + compatible = "sandbox,power-domain"; + #power-domain-cells = <1>; + }; + + power-domain-test { + compatible = "sandbox,power-domain-test"; + power-domains = <&pwrdom 2>; + }; + ram { compatible = "sandbox,ram"; }; diff --git a/arch/sandbox/include/asm/power-domain.h b/arch/sandbox/include/asm/power-domain.h new file mode 100644 index 0000000000..cad388549e --- /dev/null +++ b/arch/sandbox/include/asm/power-domain.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __SANDBOX_POWER_DOMAIN_H +#define __SANDBOX_POWER_DOMAIN_H + +#include + +struct udevice; + +int sandbox_power_domain_query(struct udevice *dev, unsigned long id); + +int sandbox_power_domain_test_get(struct udevice *dev); +int sandbox_power_domain_test_on(struct udevice *dev); +int sandbox_power_domain_test_off(struct udevice *dev); +int sandbox_power_domain_test_free(struct udevice *dev); + +#endif diff --git a/arch/x86/lib/lpc-uclass.c b/arch/x86/lib/lpc-uclass.c index c6e8f73d22..eb033e6b3f 100644 --- a/arch/x86/lib/lpc-uclass.c +++ b/arch/x86/lib/lpc-uclass.c @@ -7,24 +7,11 @@ #include #include -#include DECLARE_GLOBAL_DATA_PTR; -static int lpc_uclass_post_bind(struct udevice *bus) -{ - /* - * Scan the device tree for devices - * - * Before relocation, only bind devices marked for pre-relocation - * use. - */ - return dm_scan_fdt_node(bus, gd->fdt_blob, bus->of_offset, - gd->flags & GD_FLG_RELOC ? false : true); -} - UCLASS_DRIVER(lpc) = { .id = UCLASS_LPC, .name = "lpc", - .post_bind = lpc_uclass_post_bind, + .post_bind = dm_scan_fdt_dev, }; diff --git a/cmd/bdinfo.c b/cmd/bdinfo.c index f2435ab7e5..1fb66c4917 100644 --- a/cmd/bdinfo.c +++ b/cmd/bdinfo.c @@ -416,6 +416,11 @@ static int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, #ifdef CONFIG_BOARD_TYPES printf("Board Type = %ld\n", gd->board_type); #endif +#ifdef CONFIG_SYS_MALLOC_F + printf("Early malloc usage: %lx / %x\n", gd->malloc_ptr, + CONFIG_SYS_MALLOC_F_LEN); +#endif + return 0; } diff --git a/cmd/usb_mass_storage.c b/cmd/usb_mass_storage.c index b05913ac34..86398fc24e 100644 --- a/cmd/usb_mass_storage.c +++ b/cmd/usb_mass_storage.c @@ -22,7 +22,7 @@ static int ums_read_sector(struct ums *ums_dev, struct blk_desc *block_dev = &ums_dev->block_dev; lbaint_t blkstart = start + ums_dev->start_sector; - return block_dev->block_read(block_dev, blkstart, blkcnt, buf); + return blk_dread(block_dev, blkstart, blkcnt, buf); } static int ums_write_sector(struct ums *ums_dev, @@ -31,7 +31,7 @@ static int ums_write_sector(struct ums *ums_dev, struct blk_desc *block_dev = &ums_dev->block_dev; lbaint_t blkstart = start + ums_dev->start_sector; - return block_dev->block_write(block_dev, blkstart, blkcnt, buf); + return blk_dwrite(block_dev, blkstart, blkcnt, buf); } static struct ums *ums; diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c index 6b3e9e4a17..7c7f32959b 100644 --- a/common/spl/spl_mmc.c +++ b/common/spl/spl_mmc.c @@ -155,7 +155,7 @@ static int mmc_load_image_raw_partition(struct mmc *mmc, int partition) disk_partition_t info; int err; - err = part_get_info(&mmc->block_dev, partition, &info); + err = part_get_info(mmc_get_blk_desc(mmc), partition, &info); if (err) { #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT puts("spl: partition error\n"); diff --git a/common/usb_hub.c b/common/usb_hub.c index 0f39c9faf7..ff9cd50eab 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -36,7 +36,6 @@ #include #endif #include -#include DECLARE_GLOBAL_DATA_PTR; @@ -755,12 +754,6 @@ int usb_hub_scan(struct udevice *hub) return usb_hub_configure(udev); } -static int usb_hub_post_bind(struct udevice *dev) -{ - /* Scan the bus for devices */ - return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false); -} - static int usb_hub_post_probe(struct udevice *dev) { debug("%s\n", __func__); @@ -782,7 +775,7 @@ U_BOOT_DRIVER(usb_generic_hub) = { UCLASS_DRIVER(usb_hub) = { .id = UCLASS_USB_HUB, .name = "usb_hub", - .post_bind = usb_hub_post_bind, + .post_bind = dm_scan_fdt_dev, .post_probe = usb_hub_post_probe, .child_pre_probe = usb_child_pre_probe, .per_child_auto_alloc_size = sizeof(struct usb_device), diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 29e6d85bd4..887d83acfd 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -176,3 +176,5 @@ CONFIG_UNIT_TEST=y CONFIG_UT_TIME=y CONFIG_UT_DM=y CONFIG_UT_ENV=y +CONFIG_POWER_DOMAIN=y +CONFIG_SANDBOX_POWER_DOMAIN=y diff --git a/drivers/core/root.c b/drivers/core/root.c index 158702406e..33dc9c0b2d 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -218,6 +218,15 @@ int dm_scan_fdt_node(struct udevice *parent, const void *blob, int offset, return ret; } +int dm_scan_fdt_dev(struct udevice *dev) +{ + if (dev->of_offset == -1) + return 0; + + return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, + gd->flags & GD_FLG_RELOC ? false : true); +} + int dm_scan_fdt(const void *blob, bool pre_reloc_only) { return dm_scan_fdt_node(gd->dm_root, blob, 0, pre_reloc_only); diff --git a/drivers/core/simple-bus.c b/drivers/core/simple-bus.c index 1a9c864ef3..5c955da334 100644 --- a/drivers/core/simple-bus.c +++ b/drivers/core/simple-bus.c @@ -6,7 +6,6 @@ #include #include -#include DECLARE_GLOBAL_DATA_PTR; @@ -41,7 +40,7 @@ static int simple_bus_post_bind(struct udevice *dev) plat->size = cell[2]; } - return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false); + return dm_scan_fdt_dev(dev); } UCLASS_DRIVER(simple_bus) = { diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c index 20b30ffbeb..dbd3789747 100644 --- a/drivers/i2c/i2c-uclass.c +++ b/drivers/i2c/i2c-uclass.c @@ -12,7 +12,6 @@ #include #include #include -#include DECLARE_GLOBAL_DATA_PTR; @@ -499,16 +498,6 @@ static int i2c_post_probe(struct udevice *dev) #endif } -static int i2c_post_bind(struct udevice *dev) -{ -#if CONFIG_IS_ENABLED(OF_CONTROL) - /* Scan the bus for devices */ - return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false); -#else - return 0; -#endif -} - static int i2c_child_post_bind(struct udevice *dev) { #if CONFIG_IS_ENABLED(OF_CONTROL) @@ -527,7 +516,9 @@ UCLASS_DRIVER(i2c) = { .id = UCLASS_I2C, .name = "i2c", .flags = DM_UC_FLAG_SEQ_ALIAS, - .post_bind = i2c_post_bind, +#if CONFIG_IS_ENABLED(OF_CONTROL) + .post_bind = dm_scan_fdt_dev, +#endif .post_probe = i2c_post_probe, .per_device_auto_alloc_size = sizeof(struct dm_i2c_bus), .per_child_platdata_auto_alloc_size = sizeof(struct dm_i2c_chip), diff --git a/drivers/i2c/sandbox_i2c.c b/drivers/i2c/sandbox_i2c.c index 2c84c41643..4696a1ae62 100644 --- a/drivers/i2c/sandbox_i2c.c +++ b/drivers/i2c/sandbox_i2c.c @@ -14,7 +14,6 @@ #include #include #include -#include DECLARE_GLOBAL_DATA_PTR; @@ -33,8 +32,7 @@ static int get_emul(struct udevice *dev, struct udevice **devp, *opsp = NULL; plat = dev_get_parent_platdata(dev); if (!plat->emul) { - ret = dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, - false); + ret = dm_scan_fdt_dev(dev); if (ret) return ret; diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index e3229efed0..aea8d61f34 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #ifdef DEBUG_TRACE @@ -1450,12 +1449,6 @@ static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return ret; } -int cros_ec_post_bind(struct udevice *dev) -{ - /* Scan for available EC devices (e.g. I2C tunnel) */ - return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false); -} - U_BOOT_CMD( crosec, 6, 1, do_cros_ec, "CROS-EC utility command", @@ -1482,5 +1475,5 @@ UCLASS_DRIVER(cros_ec) = { .id = UCLASS_CROS_EC, .name = "cros_ec", .per_device_auto_alloc_size = sizeof(struct cros_ec_dev), - .post_bind = cros_ec_post_bind, + .post_bind = dm_scan_fdt_dev, }; diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index 2cf7bae792..b58c282416 100644 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -182,7 +182,7 @@ static int dwmci_set_transfer_mode(struct dwmci_host *host, } #ifdef CONFIG_DM_MMC_OPS -int dwmci_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, +static int dwmci_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, struct mmc_data *data) { struct mmc *mmc = mmc_get_mmc_dev(dev); @@ -195,7 +195,7 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, ALLOC_CACHE_ALIGN_BUFFER(struct dwmci_idmac, cur_idmac, data ? DIV_ROUND_UP(data->blocks, 8) : 0); int ret = 0, flags = 0, i; - unsigned int timeout = 100000; + unsigned int timeout = 500; u32 retry = 100000; u32 mask, ctrl; ulong start = get_timer(0); @@ -381,7 +381,7 @@ static int dwmci_setup_bus(struct dwmci_host *host, u32 freq) } #ifdef CONFIG_DM_MMC_OPS -int dwmci_set_ios(struct udevice *dev) +static int dwmci_set_ios(struct udevice *dev) { struct mmc *mmc = mmc_get_mmc_dev(dev); #else diff --git a/drivers/mmc/socfpga_dw_mmc.c b/drivers/mmc/socfpga_dw_mmc.c index 6a0e9719b8..8a9630208c 100644 --- a/drivers/mmc/socfpga_dw_mmc.c +++ b/drivers/mmc/socfpga_dw_mmc.c @@ -22,6 +22,11 @@ static const struct socfpga_clock_manager *clock_manager_base = static const struct socfpga_system_manager *system_manager_base = (void *)SOCFPGA_SYSMGR_ADDRESS; +struct socfpga_dwmci_plat { + struct mmc_config cfg; + struct mmc mmc; +}; + /* socfpga implmentation specific driver private data */ struct dwmci_socfpga_priv_data { struct dwmci_host host; @@ -98,21 +103,45 @@ static int socfpga_dwmmc_ofdata_to_platdata(struct udevice *dev) static int socfpga_dwmmc_probe(struct udevice *dev) { +#ifdef CONFIG_BLK + struct socfpga_dwmci_plat *plat = dev_get_platdata(dev); +#endif struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); struct dwmci_socfpga_priv_data *priv = dev_get_priv(dev); struct dwmci_host *host = &priv->host; + +#ifdef CONFIG_BLK + dwmci_setup_cfg(&plat->cfg, dev->name, host->buswidth, host->caps, + host->bus_hz, 400000); + host->mmc = &plat->mmc; +#else int ret; ret = add_dwmci(host, host->bus_hz, 400000); if (ret) return ret; - +#endif + host->mmc->priv = &priv->host; upriv->mmc = host->mmc; host->mmc->dev = dev; return 0; } +static int socfpga_dwmmc_bind(struct udevice *dev) +{ +#ifdef CONFIG_BLK + struct socfpga_dwmci_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 socfpga_dwmmc_ids[] = { { .compatible = "altr,socfpga-dw-mshc" }, { } @@ -123,6 +152,7 @@ U_BOOT_DRIVER(socfpga_dwmmc_drv) = { .id = UCLASS_MMC, .of_match = socfpga_dwmmc_ids, .ofdata_to_platdata = socfpga_dwmmc_ofdata_to_platdata, + .bind = socfpga_dwmmc_bind, .probe = socfpga_dwmmc_probe, .priv_auto_alloc_size = sizeof(struct dwmci_socfpga_priv_data), }; diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index d405929b64..bcd154a707 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -17,10 +17,18 @@ # define CONFIG_ZYNQ_SDHCI_MIN_FREQ 0 #endif +struct arasan_sdhci_plat { + struct mmc_config cfg; + struct mmc mmc; +}; + static int arasan_sdhci_probe(struct udevice *dev) { + struct arasan_sdhci_plat *plat = dev_get_platdata(dev); struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); struct sdhci_host *host = dev_get_priv(dev); + u32 caps; + int ret; host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_BROKEN_R1B; @@ -31,13 +39,19 @@ static int arasan_sdhci_probe(struct udevice *dev) host->version = sdhci_readw(host, SDHCI_HOST_VERSION); - add_sdhci(host, CONFIG_ZYNQ_SDHCI_MAX_FREQ, - CONFIG_ZYNQ_SDHCI_MIN_FREQ); - - upriv->mmc = host->mmc; + caps = sdhci_readl(host, SDHCI_CAPABILITIES); + ret = sdhci_setup_cfg(&plat->cfg, dev->name, host->bus_width, + caps, CONFIG_ZYNQ_SDHCI_MAX_FREQ, + CONFIG_ZYNQ_SDHCI_MIN_FREQ, host->version, + host->quirks, 0); + host->mmc = &plat->mmc; + if (ret) + return ret; + host->mmc->priv = host; host->mmc->dev = dev; + upriv->mmc = host->mmc; - return 0; + return sdhci_probe(dev); } static int arasan_sdhci_ofdata_to_platdata(struct udevice *dev) @@ -50,6 +64,18 @@ static int arasan_sdhci_ofdata_to_platdata(struct udevice *dev) return 0; } +static int arasan_sdhci_bind(struct udevice *dev) +{ + struct arasan_sdhci_plat *plat = dev_get_platdata(dev); + int ret; + + ret = sdhci_bind(dev, &plat->mmc, &plat->cfg); + if (ret) + return ret; + + return 0; +} + static const struct udevice_id arasan_sdhci_ids[] = { { .compatible = "arasan,sdhci-8.9a" }, { } @@ -60,6 +86,9 @@ U_BOOT_DRIVER(arasan_sdhci_drv) = { .id = UCLASS_MMC, .of_match = arasan_sdhci_ids, .ofdata_to_platdata = arasan_sdhci_ofdata_to_platdata, + .ops = &sdhci_ops, + .bind = arasan_sdhci_bind, .probe = arasan_sdhci_probe, .priv_auto_alloc_size = sizeof(struct sdhci_host), + .platdata_auto_alloc_size = sizeof(struct arasan_sdhci_plat), }; diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 58d287bb07..4eeb0f6ede 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -8,6 +8,7 @@ */ #include #include +#include #include #define PHY_AUTONEGOTIATE_TIMEOUT 5000 diff --git a/drivers/pch/pch-uclass.c b/drivers/pch/pch-uclass.c index 7216660a24..af794eb5a1 100644 --- a/drivers/pch/pch-uclass.c +++ b/drivers/pch/pch-uclass.c @@ -8,7 +8,6 @@ #include #include #include -#include DECLARE_GLOBAL_DATA_PTR; @@ -55,20 +54,8 @@ int pch_get_io_base(struct udevice *dev, u32 *iobasep) return ops->get_io_base(dev, iobasep); } -static int pch_uclass_post_bind(struct udevice *bus) -{ - /* - * Scan the device tree for devices - * - * Before relocation, only bind devices marked for pre-relocation - * use. - */ - return dm_scan_fdt_node(bus, gd->fdt_blob, bus->of_offset, - gd->flags & GD_FLG_RELOC ? false : true); -} - UCLASS_DRIVER(pch) = { .id = UCLASS_PCH, .name = "pch", - .post_bind = pch_uclass_post_bind, + .post_bind = dm_scan_fdt_dev, }; diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 32590ce498..342b78c0c4 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #if defined(CONFIG_X86) && defined(CONFIG_HAVE_FSP) #include @@ -753,27 +752,6 @@ error: return ret; } -static int pci_uclass_post_bind(struct udevice *bus) -{ - /* - * If there is no pci device listed in the device tree, - * don't bother scanning the device tree. - */ - if (bus->of_offset == -1) - return 0; - - /* - * Scan the device tree for devices. This does not probe the PCI bus, - * as this is not permitted while binding. It just finds devices - * mentioned in the device tree. - * - * Before relocation, only bind devices marked for pre-relocation - * use. - */ - return dm_scan_fdt_node(bus, gd->fdt_blob, bus->of_offset, - gd->flags & GD_FLG_RELOC ? false : true); -} - static int decode_regions(struct pci_controller *hose, const void *blob, int parent_node, int node) { @@ -1254,7 +1232,7 @@ UCLASS_DRIVER(pci) = { .id = UCLASS_PCI, .name = "pci", .flags = DM_UC_FLAG_SEQ_ALIAS, - .post_bind = pci_uclass_post_bind, + .post_bind = dm_scan_fdt_dev, .pre_probe = pci_uclass_pre_probe, .post_probe = pci_uclass_post_probe, .child_post_bind = pci_uclass_child_post_bind, diff --git a/drivers/pci/pci_sandbox.c b/drivers/pci/pci_sandbox.c index 6de5130c2a..6a84ee386d 100644 --- a/drivers/pci/pci_sandbox.c +++ b/drivers/pci/pci_sandbox.c @@ -10,7 +10,6 @@ #include #include #include -#include DECLARE_GLOBAL_DATA_PTR; @@ -52,12 +51,6 @@ static int sandbox_pci_read_config(struct udevice *bus, pci_dev_t devfn, return ops->read_config(emul, offset, valuep, size); } -static int sandbox_pci_child_post_bind(struct udevice *dev) -{ - /* Attach an emulator if we can */ - return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false); -} - static const struct dm_pci_ops sandbox_pci_ops = { .read_config = sandbox_pci_read_config, .write_config = sandbox_pci_write_config, @@ -73,7 +66,9 @@ U_BOOT_DRIVER(pci_sandbox) = { .id = UCLASS_PCI, .of_match = sandbox_pci_ids, .ops = &sandbox_pci_ops, - .child_post_bind = sandbox_pci_child_post_bind, + + /* Attach an emulator if we can */ + .child_post_bind = dm_scan_fdt_dev, .per_child_platdata_auto_alloc_size = sizeof(struct pci_child_platdata), }; diff --git a/drivers/pinctrl/pinctrl_pic32.c b/drivers/pinctrl/pinctrl_pic32.c index 5cf97ecec8..9acac29133 100644 --- a/drivers/pinctrl/pinctrl_pic32.c +++ b/drivers/pinctrl/pinctrl_pic32.c @@ -10,7 +10,6 @@ #include #include #include -#include #include DECLARE_GLOBAL_DATA_PTR; @@ -341,12 +340,6 @@ static int pic32_pinctrl_probe(struct udevice *dev) return 0; } -static int pic32_pinctrl_bind(struct udevice *dev) -{ - /* scan child GPIO banks */ - return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false); -} - static const struct udevice_id pic32_pinctrl_ids[] = { { .compatible = "microchip,pic32mzda-pinctrl" }, { } @@ -358,6 +351,6 @@ U_BOOT_DRIVER(pinctrl_pic32) = { .of_match = pic32_pinctrl_ids, .ops = &pic32_pinctrl_ops, .probe = pic32_pinctrl_probe, - .bind = pic32_pinctrl_bind, + .bind = dm_scan_fdt_dev, .priv_auto_alloc_size = sizeof(struct pic32_pinctrl_priv), }; diff --git a/drivers/pinctrl/rockchip/pinctrl_rk3036.c b/drivers/pinctrl/rockchip/pinctrl_rk3036.c index 1f78bf862d..6aea856aa6 100644 --- a/drivers/pinctrl/rockchip/pinctrl_rk3036.c +++ b/drivers/pinctrl/rockchip/pinctrl_rk3036.c @@ -15,7 +15,6 @@ #include #include #include -#include DECLARE_GLOBAL_DATA_PTR; @@ -253,12 +252,6 @@ static struct pinctrl_ops rk3036_pinctrl_ops = { .get_periph_id = rk3036_pinctrl_get_periph_id, }; -static int rk3036_pinctrl_bind(struct udevice *dev) -{ - /* scan child GPIO banks */ - return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false); -} - static int rk3036_pinctrl_probe(struct udevice *dev) { struct rk3036_pinctrl_priv *priv = dev_get_priv(dev); @@ -279,6 +272,6 @@ U_BOOT_DRIVER(pinctrl_rk3036) = { .of_match = rk3036_pinctrl_ids, .priv_auto_alloc_size = sizeof(struct rk3036_pinctrl_priv), .ops = &rk3036_pinctrl_ops, - .bind = rk3036_pinctrl_bind, + .bind = dm_scan_fdt_dev, .probe = rk3036_pinctrl_probe, }; diff --git a/drivers/pinctrl/rockchip/pinctrl_rk3288.c b/drivers/pinctrl/rockchip/pinctrl_rk3288.c index 8cb3b8228e..ae8a4f1fde 100644 --- a/drivers/pinctrl/rockchip/pinctrl_rk3288.c +++ b/drivers/pinctrl/rockchip/pinctrl_rk3288.c @@ -17,7 +17,6 @@ #include #include #include -#include DECLARE_GLOBAL_DATA_PTR; @@ -664,16 +663,6 @@ static struct pinctrl_ops rk3288_pinctrl_ops = { .get_periph_id = rk3288_pinctrl_get_periph_id, }; -static int rk3288_pinctrl_bind(struct udevice *dev) -{ -#if CONFIG_IS_ENABLED(OF_PLATDATA) - return 0; -#else - /* scan child GPIO banks */ - return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false); -#endif -} - #ifndef CONFIG_SPL_BUILD static int rk3288_pinctrl_parse_tables(struct rk3288_pinctrl_priv *priv, struct rockchip_pin_bank *banks, @@ -730,6 +719,8 @@ U_BOOT_DRIVER(pinctrl_rk3288) = { .of_match = rk3288_pinctrl_ids, .priv_auto_alloc_size = sizeof(struct rk3288_pinctrl_priv), .ops = &rk3288_pinctrl_ops, - .bind = rk3288_pinctrl_bind, +#if !CONFIG_IS_ENABLED(OF_PLATDATA) + .bind = dm_scan_fdt_dev, +#endif .probe = rk3288_pinctrl_probe, }; diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 3c44167805..b422703126 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -1,5 +1,7 @@ menu "Power" +source "drivers/power/domain/Kconfig" + source "drivers/power/pmic/Kconfig" source "drivers/power/regulator/Kconfig" diff --git a/drivers/power/domain/Kconfig b/drivers/power/domain/Kconfig new file mode 100644 index 0000000000..b904097433 --- /dev/null +++ b/drivers/power/domain/Kconfig @@ -0,0 +1,20 @@ +menu "Power Domain Support" + +config POWER_DOMAIN + bool "Enable power domain support using Driver Model" + depends on DM && OF_CONTROL + help + Enable support for the power domain driver class. Many SoCs allow + power to be applied to or removed from portions of the SoC (power + domains). This may be used to save power. This API provides the + means to control such power management hardware. + +config SANDBOX_POWER_DOMAIN + bool "Enable the sandbox power domain test driver" + depends on POWER_DOMAIN && SANDBOX + help + Enable support for a test power domain driver implementation, which + simply accepts requests to power on/off various HW modules without + actually doing anything beyond a little error checking. + +endmenu diff --git a/drivers/power/domain/Makefile b/drivers/power/domain/Makefile new file mode 100644 index 0000000000..c18292f0ec --- /dev/null +++ b/drivers/power/domain/Makefile @@ -0,0 +1,7 @@ +# Copyright (c) 2016, NVIDIA CORPORATION. +# +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_POWER_DOMAIN) += power-domain-uclass.o +obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain.o +obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain-test.o diff --git a/drivers/power/domain/power-domain-uclass.c b/drivers/power/domain/power-domain-uclass.c new file mode 100644 index 0000000000..1bb6262fa1 --- /dev/null +++ b/drivers/power/domain/power-domain-uclass.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +static inline struct power_domain_ops *power_domain_dev_ops(struct udevice *dev) +{ + return (struct power_domain_ops *)dev->driver->ops; +} + +static int power_domain_of_xlate_default(struct power_domain *power_domain, + struct fdtdec_phandle_args *args) +{ + debug("%s(power_domain=%p)\n", __func__, power_domain); + + if (args->args_count != 1) { + debug("Invalid args_count: %d\n", args->args_count); + return -EINVAL; + } + + power_domain->id = args->args[0]; + + return 0; +} + +int power_domain_get(struct udevice *dev, struct power_domain *power_domain) +{ + struct fdtdec_phandle_args args; + int ret; + struct udevice *dev_power_domain; + struct power_domain_ops *ops; + + debug("%s(dev=%p, power_domain=%p)\n", __func__, dev, power_domain); + + ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev->of_offset, + "power-domains", + "#power-domain-cells", 0, 0, + &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_POWER_DOMAIN, args.node, + &dev_power_domain); + if (ret) { + debug("%s: uclass_get_device_by_of_offset failed: %d\n", + __func__, ret); + return ret; + } + ops = power_domain_dev_ops(dev_power_domain); + + power_domain->dev = dev_power_domain; + if (ops->of_xlate) + ret = ops->of_xlate(power_domain, &args); + else + ret = power_domain_of_xlate_default(power_domain, &args); + if (ret) { + debug("of_xlate() failed: %d\n", ret); + return ret; + } + + ret = ops->request(power_domain); + if (ret) { + debug("ops->request() failed: %d\n", ret); + return ret; + } + + return 0; +} + +int power_domain_free(struct power_domain *power_domain) +{ + struct power_domain_ops *ops = power_domain_dev_ops(power_domain->dev); + + debug("%s(power_domain=%p)\n", __func__, power_domain); + + return ops->free(power_domain); +} + +int power_domain_on(struct power_domain *power_domain) +{ + struct power_domain_ops *ops = power_domain_dev_ops(power_domain->dev); + + debug("%s(power_domain=%p)\n", __func__, power_domain); + + return ops->on(power_domain); +} + +int power_domain_off(struct power_domain *power_domain) +{ + struct power_domain_ops *ops = power_domain_dev_ops(power_domain->dev); + + debug("%s(power_domain=%p)\n", __func__, power_domain); + + return ops->off(power_domain); +} + +UCLASS_DRIVER(power_domain) = { + .id = UCLASS_POWER_DOMAIN, + .name = "power_domain", +}; diff --git a/drivers/power/domain/sandbox-power-domain-test.c b/drivers/power/domain/sandbox-power-domain-test.c new file mode 100644 index 0000000000..92a3a2a527 --- /dev/null +++ b/drivers/power/domain/sandbox-power-domain-test.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include + +struct sandbox_power_domain_test { + struct power_domain pd; +}; + +int sandbox_power_domain_test_get(struct udevice *dev) +{ + struct sandbox_power_domain_test *sbrt = dev_get_priv(dev); + + return power_domain_get(dev, &sbrt->pd); +} + +int sandbox_power_domain_test_on(struct udevice *dev) +{ + struct sandbox_power_domain_test *sbrt = dev_get_priv(dev); + + return power_domain_on(&sbrt->pd); +} + +int sandbox_power_domain_test_off(struct udevice *dev) +{ + struct sandbox_power_domain_test *sbrt = dev_get_priv(dev); + + return power_domain_off(&sbrt->pd); +} + +int sandbox_power_domain_test_free(struct udevice *dev) +{ + struct sandbox_power_domain_test *sbrt = dev_get_priv(dev); + + return power_domain_free(&sbrt->pd); +} + +static const struct udevice_id sandbox_power_domain_test_ids[] = { + { .compatible = "sandbox,power-domain-test" }, + { } +}; + +U_BOOT_DRIVER(sandbox_power_domain_test) = { + .name = "sandbox_power_domain_test", + .id = UCLASS_MISC, + .of_match = sandbox_power_domain_test_ids, + .priv_auto_alloc_size = sizeof(struct sandbox_power_domain_test), +}; diff --git a/drivers/power/domain/sandbox-power-domain.c b/drivers/power/domain/sandbox-power-domain.c new file mode 100644 index 0000000000..9071346f98 --- /dev/null +++ b/drivers/power/domain/sandbox-power-domain.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include + +#define SANDBOX_POWER_DOMAINS 3 + +struct sandbox_power_domain { + bool on[SANDBOX_POWER_DOMAINS]; +}; + +static int sandbox_power_domain_request(struct power_domain *power_domain) +{ + debug("%s(power_domain=%p)\n", __func__, power_domain); + + if (power_domain->id >= SANDBOX_POWER_DOMAINS) + return -EINVAL; + + return 0; +} + +static int sandbox_power_domain_free(struct power_domain *power_domain) +{ + debug("%s(power_domain=%p)\n", __func__, power_domain); + + return 0; +} + +static int sandbox_power_domain_on(struct power_domain *power_domain) +{ + struct sandbox_power_domain *sbr = dev_get_priv(power_domain->dev); + + debug("%s(power_domain=%p)\n", __func__, power_domain); + + sbr->on[power_domain->id] = true; + + return 0; +} + +static int sandbox_power_domain_off(struct power_domain *power_domain) +{ + struct sandbox_power_domain *sbr = dev_get_priv(power_domain->dev); + + debug("%s(power_domain=%p)\n", __func__, power_domain); + + sbr->on[power_domain->id] = false; + + return 0; +} + +static int sandbox_power_domain_bind(struct udevice *dev) +{ + debug("%s(dev=%p)\n", __func__, dev); + + return 0; +} + +static int sandbox_power_domain_probe(struct udevice *dev) +{ + debug("%s(dev=%p)\n", __func__, dev); + + return 0; +} + +static const struct udevice_id sandbox_power_domain_ids[] = { + { .compatible = "sandbox,power-domain" }, + { } +}; + +struct power_domain_ops sandbox_power_domain_ops = { + .request = sandbox_power_domain_request, + .free = sandbox_power_domain_free, + .on = sandbox_power_domain_on, + .off = sandbox_power_domain_off, +}; + +U_BOOT_DRIVER(sandbox_power_domain) = { + .name = "sandbox_power_domain", + .id = UCLASS_POWER_DOMAIN, + .of_match = sandbox_power_domain_ids, + .bind = sandbox_power_domain_bind, + .probe = sandbox_power_domain_probe, + .priv_auto_alloc_size = sizeof(struct sandbox_power_domain), + .ops = &sandbox_power_domain_ops, +}; + +int sandbox_power_domain_query(struct udevice *dev, unsigned long id) +{ + struct sandbox_power_domain *sbr = dev_get_priv(dev); + + debug("%s(dev=%p, id=%ld)\n", __func__, dev, id); + + if (id >= SANDBOX_POWER_DOMAINS) + return -EINVAL; + + return sbr->on[id]; +} diff --git a/drivers/power/pmic/pm8916.c b/drivers/power/pmic/pm8916.c index d4c7d4adff..2b65c697ec 100644 --- a/drivers/power/pmic/pm8916.c +++ b/drivers/power/pmic/pm8916.c @@ -7,7 +7,6 @@ */ #include #include -#include #include #include @@ -79,17 +78,11 @@ static int pm8916_probe(struct udevice *dev) return 0; } - -static int pm8916_bind(struct udevice *dev) -{ - return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false); -} - U_BOOT_DRIVER(pmic_pm8916) = { .name = "pmic_pm8916", .id = UCLASS_PMIC, .of_match = pm8916_ids, - .bind = pm8916_bind, + .bind = dm_scan_fdt_dev, .probe = pm8916_probe, .ops = &pm8916_ops, .priv_auto_alloc_size = sizeof(struct pm8916_priv), diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig index 465ff3fda6..17f22dda2b 100644 --- a/drivers/power/regulator/Kconfig +++ b/drivers/power/regulator/Kconfig @@ -13,7 +13,7 @@ config DM_REGULATOR - 'drivers/power/pmic/regulator-uclass.c' It's important to call the device_bind() with the proper node offset, when binding the regulator devices. The pmic_bind_childs() can be used - for this purpose if PMIC I/O driver is implemented or dm_scan_fdt_node() + for this purpose if PMIC I/O driver is implemented or dm_scan_fdt_dev() otherwise. Detailed information can be found in the header file. config SPL_DM_REGULATOR diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c index 8003f9bfc8..247abfa72b 100644 --- a/drivers/spi/spi-uclass.c +++ b/drivers/spi/spi-uclass.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include @@ -109,12 +108,6 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, return dm_spi_xfer(slave->dev, bitlen, dout, din, flags); } -static int spi_post_bind(struct udevice *dev) -{ - /* Scan the bus for devices */ - return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false); -} - static int spi_child_post_bind(struct udevice *dev) { struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev); @@ -446,7 +439,7 @@ UCLASS_DRIVER(spi) = { .id = UCLASS_SPI, .name = "spi", .flags = DM_UC_FLAG_SEQ_ALIAS, - .post_bind = spi_post_bind, + .post_bind = dm_scan_fdt_dev, .post_probe = spi_post_probe, .child_pre_probe = spi_child_pre_probe, .per_device_auto_alloc_size = sizeof(struct dm_spi_bus), diff --git a/drivers/spmi/spmi-uclass.c b/drivers/spmi/spmi-uclass.c index 4ddd51b556..6edece23d8 100644 --- a/drivers/spmi/spmi-uclass.c +++ b/drivers/spmi/spmi-uclass.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include @@ -36,13 +35,8 @@ int spmi_reg_write(struct udevice *dev, int usid, int pid, int reg, return ops->write(dev, usid, pid, reg, value); } -static int spmi_post_bind(struct udevice *dev) -{ - return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false); -} - UCLASS_DRIVER(spmi) = { .id = UCLASS_SPMI, .name = "spmi", - .post_bind = spmi_post_bind, + .post_bind = dm_scan_fdt_dev, }; diff --git a/drivers/usb/emul/usb-emul-uclass.c b/drivers/usb/emul/usb-emul-uclass.c index ee7ea5ad91..6e03c1e0d9 100644 --- a/drivers/usb/emul/usb-emul-uclass.c +++ b/drivers/usb/emul/usb-emul-uclass.c @@ -8,7 +8,6 @@ #include #include #include -#include #include DECLARE_GLOBAL_DATA_PTR; @@ -265,12 +264,6 @@ int usb_emul_setup_device(struct udevice *dev, int maxpacketsize, return 0; } -int usb_emul_post_bind(struct udevice *dev) -{ - /* Scan the bus for devices */ - return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false); -} - void usb_emul_reset(struct udevice *dev) { struct usb_dev_platdata *plat = dev_get_parent_platdata(dev); @@ -282,7 +275,7 @@ void usb_emul_reset(struct udevice *dev) UCLASS_DRIVER(usb_emul) = { .id = UCLASS_USB_EMUL, .name = "usb_emul", - .post_bind = usb_emul_post_bind, + .post_bind = dm_scan_fdt_dev, .per_child_auto_alloc_size = sizeof(struct usb_device), .per_child_platdata_auto_alloc_size = sizeof(struct usb_dev_platdata), }; diff --git a/drivers/usb/host/ehci-zynq.c b/drivers/usb/host/ehci-zynq.c index 37a7935b43..76642cdad7 100644 --- a/drivers/usb/host/ehci-zynq.c +++ b/drivers/usb/host/ehci-zynq.c @@ -7,55 +7,48 @@ */ #include +#include +#include #include #include #include -#include #include #include #include "ehci.h" -#define ZYNQ_USB_USBCMD_RST 0x0000002 -#define ZYNQ_USB_USBCMD_STOP 0x0000000 -#define ZYNQ_USB_NUM_MIO 12 - -/* - * Create the appropriate control structures to manage - * a new EHCI host controller. - */ -int ehci_hcd_init(int index, enum usb_init_type init, struct ehci_hccr **hccr, - struct ehci_hcor **hcor) -{ +struct zynq_ehci_priv { + struct ehci_ctrl ehcictrl; struct usb_ehci *ehci; +}; + +static int ehci_zynq_ofdata_to_platdata(struct udevice *dev) +{ + struct zynq_ehci_priv *priv = dev_get_priv(dev); + + priv->ehci = (struct usb_ehci *)dev_get_addr_ptr(dev); + if (!priv->ehci) + return -EINVAL; + + return 0; +} + +static int ehci_zynq_probe(struct udevice *dev) +{ + struct usb_platdata *plat = dev_get_platdata(dev); + struct zynq_ehci_priv *priv = dev_get_priv(dev); + struct ehci_hccr *hccr; + struct ehci_hcor *hcor; struct ulpi_viewport ulpi_vp; - int ret, mio_usb; /* Used for writing the ULPI data address */ struct ulpi_regs *ulpi = (struct ulpi_regs *)0; + int ret; - if (!index) { - mio_usb = zynq_slcr_get_mio_pin_status("usb0"); - if (mio_usb != ZYNQ_USB_NUM_MIO) { - printf("usb0 wrong num MIO: %d, Index %d\n", mio_usb, - index); - return -1; - } - ehci = (struct usb_ehci *)ZYNQ_USB_BASEADDR0; - } else { - mio_usb = zynq_slcr_get_mio_pin_status("usb1"); - if (mio_usb != ZYNQ_USB_NUM_MIO) { - printf("usb1 wrong num MIO: %d, Index %d\n", mio_usb, - index); - return -1; - } - ehci = (struct usb_ehci *)ZYNQ_USB_BASEADDR1; - } + hccr = (struct ehci_hccr *)((uint32_t)&priv->ehci->caplength); + hcor = (struct ehci_hcor *)((uint32_t) hccr + + HC_LENGTH(ehci_readl(&hccr->cr_capbase))); - *hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength); - *hcor = (struct ehci_hcor *)((uint32_t) *hccr + - HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); - - ulpi_vp.viewport_addr = (u32)&ehci->ulpi_viewpoint; + ulpi_vp.viewport_addr = (u32)&priv->ehci->ulpi_viewpoint; ulpi_vp.port_num = 0; ret = ulpi_init(&ulpi_vp); @@ -77,28 +70,34 @@ int ehci_hcd_init(int index, enum usb_init_type init, struct ehci_hccr **hccr, ulpi_write(&ulpi_vp, &ulpi->otg_ctrl_set, ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT); - return 0; + return ehci_register(dev, hccr, hcor, NULL, 0, plat->init_type); } -/* - * Destroy the appropriate control structures corresponding - * the the EHCI host controller. - */ -int ehci_hcd_stop(int index) +static int ehci_zynq_remove(struct udevice *dev) { - struct usb_ehci *ehci; + int ret; - if (!index) - ehci = (struct usb_ehci *)ZYNQ_USB_BASEADDR0; - else - ehci = (struct usb_ehci *)ZYNQ_USB_BASEADDR1; - - /* Stop controller */ - writel(ZYNQ_USB_USBCMD_STOP, &ehci->usbcmd); - udelay(1000); - - /* Initiate controller reset */ - writel(ZYNQ_USB_USBCMD_RST, &ehci->usbcmd); + ret = ehci_deregister(dev); + if (ret) + return ret; return 0; } + +static const struct udevice_id ehci_zynq_ids[] = { + { .compatible = "xlnx,zynq-usb-2.20a" }, + { } +}; + +U_BOOT_DRIVER(ehci_zynq) = { + .name = "ehci_zynq", + .id = UCLASS_USB, + .of_match = ehci_zynq_ids, + .ofdata_to_platdata = ehci_zynq_ofdata_to_platdata, + .probe = ehci_zynq_probe, + .remove = ehci_zynq_remove, + .ops = &ehci_usb_ops, + .platdata_auto_alloc_size = sizeof(struct usb_platdata), + .priv_auto_alloc_size = sizeof(struct zynq_ehci_priv), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c index 69c9a504eb..be114fc077 100644 --- a/drivers/usb/host/usb-uclass.c +++ b/drivers/usb/host/usb-uclass.c @@ -14,7 +14,6 @@ #include #include #include -#include #include DECLARE_GLOBAL_DATA_PTR; @@ -349,12 +348,6 @@ struct usb_device *usb_get_dev_index(struct udevice *bus, int index) } #endif -int usb_post_bind(struct udevice *dev) -{ - /* Scan the bus for devices */ - return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false); -} - int usb_setup_ehci_gadget(struct ehci_ctrl **ctlrp) { struct usb_platdata *plat; @@ -768,7 +761,7 @@ UCLASS_DRIVER(usb) = { .id = UCLASS_USB, .name = "usb", .flags = DM_UC_FLAG_SEQ_ALIAS, - .post_bind = usb_post_bind, + .post_bind = dm_scan_fdt_dev, .priv_auto_alloc_size = sizeof(struct usb_uclass_priv), .per_child_auto_alloc_size = sizeof(struct usb_device), .per_device_auto_alloc_size = sizeof(struct usb_bus_priv), diff --git a/include/dm/device.h b/include/dm/device.h index 705849b228..babf8ac8f0 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -612,6 +612,22 @@ static inline bool device_is_on_pci_bus(struct udevice *dev) #define device_foreach_child_safe(pos, next, parent) \ list_for_each_entry_safe(pos, next, &parent->child_head, sibling_node) +/** + * dm_scan_fdt_dev() - Bind child device in a the device tree + * + * This handles device which have sub-nodes in the device tree. It scans all + * sub-nodes and binds drivers for each node where a driver can be found. + * + * If this is called prior to relocation, only pre-relocation devices will be + * bound (those marked with u-boot,dm-pre-reloc in the device tree, or where + * the driver has the DM_FLAG_PRE_RELOC flag set). Otherwise, all devices will + * be bound. + * + * @dev: Device to scan + * @return 0 if OK, -ve on error + */ +int dm_scan_fdt_dev(struct udevice *dev); + /* device resource management */ typedef void (*dr_release_t)(struct udevice *dev, void *res); typedef int (*dr_match_t)(struct udevice *dev, void *res, void *match_data); diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index c5cdfc79d1..eb78c4dac4 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -59,6 +59,7 @@ enum uclass_id { UCLASS_PINCTRL, /* Pinctrl (pin muxing/configuration) device */ UCLASS_PMIC, /* PMIC I/O device */ UCLASS_PWM, /* Pulse-width modulator */ + UCLASS_POWER_DOMAIN, /* (SoC) Power domains */ UCLASS_PWRSEQ, /* Power sequence device */ UCLASS_RAM, /* RAM controller */ UCLASS_REGULATOR, /* Regulator device */ diff --git a/include/dwmmc.h b/include/dwmmc.h index 6aebe96b97..d18ec8463b 100644 --- a/include/dwmmc.h +++ b/include/dwmmc.h @@ -256,8 +256,8 @@ static inline u8 dwmci_readb(struct dwmci_host *host, int reg) * @name: Device name (normally dev->name) * @buswidth: Bus width (in bits, such as 4 or 8) * @caps: Host capabilities (MMC_MODE_...) - * @max_clk: Maximum supported clock speed in HZ (e.g. 400000) - * @min_clk: Minimum supported clock speed in HZ (e.g. 150000000) + * @max_clk: Maximum supported clock speed in HZ (e.g. 150000000) + * @min_clk: Minimum supported clock speed in HZ (e.g. 400000) */ void dwmci_setup_cfg(struct mmc_config *cfg, const char *name, int buswidth, uint caps, u32 max_clk, u32 min_clk); @@ -286,8 +286,8 @@ int dwmci_bind(struct udevice *dev, struct mmc *mmc, struct mmc_config *cfg); * This is used when you are not using CONFIG_BLK. Convert your driver over! * * @host: DWMMC host structure - * @max_clk: Maximum supported clock speed in HZ (e.g. 400000) - * @min_clk: Minimum supported clock speed in HZ (e.g. 150000000) + * @max_clk: Maximum supported clock speed in HZ (e.g. 150000000) + * @min_clk: Minimum supported clock speed in HZ (e.g. 400000) * @return 0 if OK, -ve on error */ int add_dwmci(struct dwmci_host *host, u32 max_clk, u32 min_clk); @@ -295,9 +295,6 @@ int add_dwmci(struct dwmci_host *host, u32 max_clk, u32 min_clk); #ifdef CONFIG_DM_MMC_OPS /* Export the operations to drivers */ -int dwmci_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, - struct mmc_data *data); -int dwmci_set_ios(struct udevice *dev); int dwmci_probe(struct udevice *dev); extern const struct dm_mmc_ops dm_dwmci_ops; #endif diff --git a/include/power-domain-uclass.h b/include/power-domain-uclass.h new file mode 100644 index 0000000000..5878021e32 --- /dev/null +++ b/include/power-domain-uclass.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _POWER_DOMAIN_UCLASS_H +#define _POWER_DOMAIN_UCLASS_H + +/* See power-domain.h for background documentation. */ + +#include + +struct udevice; + +/** + * struct power_domain_ops - The functions that a power domain controller driver + * must implement. + */ +struct power_domain_ops { + /** + * of_xlate - Translate a client's device-tree (OF) power domain + * specifier. + * + * The power domain core calls this function as the first step in + * implementing a client's power_domain_get() call. + * + * If this function pointer is set to NULL, the power domain core will + * use a default implementation, which assumes #power-domain-cells = + * <1>, and that the DT cell contains a simple integer power domain ID. + * + * At present, the power domain API solely supports device-tree. If + * this changes, other xxx_xlate() functions may be added to support + * those other mechanisms. + * + * @power_domain: The power domain struct to hold the + * translation result. + * @args: The power domain specifier values from device + * tree. + * @return 0 if OK, or a negative error code. + */ + int (*of_xlate)(struct power_domain *power_domain, + struct fdtdec_phandle_args *args); + /** + * request - Request a translated power domain. + * + * The power domain core calls this function as the second step in + * implementing a client's power_domain_get() call, following a + * successful xxx_xlate() call. + * + * @power_domain: The power domain to request; this has been + * filled in by a previous xxx_xlate() function + * call. + * @return 0 if OK, or a negative error code. + */ + int (*request)(struct power_domain *power_domain); + /** + * free - Free a previously requested power domain. + * + * This is the implementation of the client power_domain_free() API. + * + * @power_domain: The power domain to free. + * @return 0 if OK, or a negative error code. + */ + int (*free)(struct power_domain *power_domain); + /** + * on - Power on a power domain. + * + * @power_domain: The power domain to turn on. + * @return 0 if OK, or a negative error code. + */ + int (*on)(struct power_domain *power_domain); + /** + * off - Power off a power domain. + * + * @power_domain: The power domain to turn off. + * @return 0 if OK, or a negative error code. + */ + int (*off)(struct power_domain *power_domain); +}; + +#endif diff --git a/include/power-domain.h b/include/power-domain.h new file mode 100644 index 0000000000..10999790b5 --- /dev/null +++ b/include/power-domain.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _POWER_DOMAIN_H +#define _POWER_DOMAIN_H + +/** + * A power domain is a portion of an SoC or chip that is powered by a + * switchable source of power. In many cases, software has control over the + * power domain, and can turn the power source on or off. This is typically + * done to save power by powering off unused devices, or to enable software + * sequencing of initial powerup at boot. This API provides a means for + * drivers to turn power domains on and off. + * + * A driver that implements UCLASS_POWER_DOMAIN is a power domain controller or + * provider. A controller will often implement multiple separate power domains, + * since the hardware it manages often has this capability. + * power-domain-uclass.h describes the interface which power domain controllers + * must implement. + * + * Depending on the power domain controller hardware, changing the state of a + * power domain may require performing related operations on other resources. + * For example, some power domains may require certain clocks to be enabled + * whenever the power domain is powered on, or during the time when the power + * domain is transitioning state. These details are implementation-specific + * and should ideally be encapsulated entirely within the provider driver, or + * configured through mechanisms (e.g. device tree) that do not require client + * drivers to provide extra configuration information. + * + * Power domain consumers/clients are the drivers for HW modules within the + * power domain. This header file describes the API used by those drivers. + * + * In many cases, a single complex IO controller (e.g. a PCIe controller) will + * be the sole logic contained within a power domain. In such cases, it is + * logical for the relevant device driver to directly control that power + * domain. In other cases, multiple controllers, each with their own driver, + * may be contained in a single power domain. Any logic require to co-ordinate + * between drivers for these multiple controllers is beyond the scope of this + * API at present. Equally, this API does not define or implement any policy + * by which power domains are managed. + */ + +struct udevice; + +/** + * struct power_domain - A handle to (allowing control of) a single power domain. + * + * Clients provide storage for power domain handles. The content of the + * structure is managed solely by the power domain API and power domain + * drivers. A power domain struct is initialized by "get"ing the power domain + * struct. The power domain struct is passed to all other power domain APIs to + * identify which power domain to operate upon. + * + * @dev: The device which implements the power domain. + * @id: The power domain ID within the provider. + * + * Currently, the power domain API assumes that a single integer ID is enough + * to identify and configure any power domain for any power domain provider. If + * this assumption becomes invalid in the future, the struct could be expanded + * to either (a) add more fields to allow power domain providers to store + * additional information, or (b) replace the id field with an opaque pointer, + * which the provider would dynamically allocate 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 power_domain { + 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; +}; + +/** + * power_domain_get - Get/request the power domain for a device. + * + * This looks up and requests a power domain. Each device is assumed to have + * a single (or, at least one) power domain associated with it somehow, and + * that domain, or the first/default domain. The mapping of client device to + * provider power domain may be via device-tree properties, board-provided + * mapping tables, or some other mechanism. + * + * @dev: The client device. + * @power_domain A pointer to a power domain struct to initialize. + * @return 0 if OK, or a negative error code. + */ +int power_domain_get(struct udevice *dev, struct power_domain *power_domain); + +/** + * power_domain_free - Free a previously requested power domain. + * + * @power_domain: A power domain struct that was previously successfully + * requested by power_domain_get(). + * @return 0 if OK, or a negative error code. + */ +int power_domain_free(struct power_domain *power_domain); + +/** + * power_domain_on - Enable power to a power domain. + * + * @power_domain: A power domain struct that was previously successfully + * requested by power_domain_get(). + * @return 0 if OK, or a negative error code. + */ +int power_domain_on(struct power_domain *power_domain); + +/** + * power_domain_off - Disable power ot a power domain. + * + * @power_domain: A power domain struct that was previously successfully + * requested by power_domain_get(). + * @return 0 if OK, or a negative error code. + */ +int power_domain_off(struct power_domain *power_domain); + +#endif diff --git a/include/power/regulator.h b/include/power/regulator.h index 63c0814fe8..9bcd728120 100644 --- a/include/power/regulator.h +++ b/include/power/regulator.h @@ -54,7 +54,7 @@ * which does the scan on the device node, for the 'regulator-name' constraint. * If the parent is not a PMIC device, and the child is not bind by function: * 'pmic_bind_childs()', then it's recommended to bind the device by call to - * dm_scan_fdt_node() - this is usually done automatically for bus devices, + * dm_scan_fdt_dev() - this is usually done automatically for bus devices, * as a post bind method. * * Regulator get: diff --git a/test/dm/Makefile b/test/dm/Makefile index cad3374e43..1885e17c38 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -24,6 +24,7 @@ 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_POWER_DOMAIN) += power-domain.o obj-$(CONFIG_RAM) += ram.o obj-y += regmap.o obj-$(CONFIG_REMOTEPROC) += remoteproc.o diff --git a/test/dm/bus.c b/test/dm/bus.c index 3b5a23b934..d94dcf7a60 100644 --- a/test/dm/bus.c +++ b/test/dm/bus.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -30,7 +29,7 @@ static struct dm_test_state *test_state; static int testbus_drv_probe(struct udevice *dev) { - return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false); + return dm_scan_fdt_dev(dev); } static int testbus_child_post_bind(struct udevice *dev) diff --git a/test/dm/i2c.c b/test/dm/i2c.c index 23d612eb81..e2688bfbe9 100644 --- a/test/dm/i2c.c +++ b/test/dm/i2c.c @@ -31,8 +31,8 @@ static int dm_test_i2c_find(struct unit_test_state *uts) false, &bus)); /* - * i2c_post_bind() will bind devices to chip selects. Check this then - * remove the emulation and the slave device. + * The post_bind() method will bind devices to chip selects. Check + * this then remove the emulation and the slave device. */ ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus)); ut_assertok(dm_i2c_probe(bus, chip, 0, &dev)); diff --git a/test/dm/power-domain.c b/test/dm/power-domain.c new file mode 100644 index 0000000000..379a8fa3d6 --- /dev/null +++ b/test/dm/power-domain.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include + +/* This must match the specifier for power-domains in the DT node */ +#define TEST_POWER_DOMAIN 2 + +static int dm_test_power_domain(struct unit_test_state *uts) +{ + struct udevice *dev_power_domain; + struct udevice *dev_test; + + ut_assertok(uclass_get_device_by_name(UCLASS_POWER_DOMAIN, + "power-domain", + &dev_power_domain)); + ut_asserteq(0, sandbox_power_domain_query(dev_power_domain, 0)); + ut_asserteq(0, sandbox_power_domain_query(dev_power_domain, + TEST_POWER_DOMAIN)); + + ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "power-domain-test", + &dev_test)); + ut_assertok(sandbox_power_domain_test_get(dev_test)); + + ut_assertok(sandbox_power_domain_test_on(dev_test)); + ut_asserteq(0, sandbox_power_domain_query(dev_power_domain, 0)); + ut_asserteq(1, sandbox_power_domain_query(dev_power_domain, + TEST_POWER_DOMAIN)); + + ut_assertok(sandbox_power_domain_test_off(dev_test)); + ut_asserteq(0, sandbox_power_domain_query(dev_power_domain, 0)); + ut_asserteq(0, sandbox_power_domain_query(dev_power_domain, + TEST_POWER_DOMAIN)); + + ut_assertok(sandbox_power_domain_test_free(dev_test)); + + return 0; +} +DM_TEST(dm_test_power_domain, DM_TESTF_SCAN_FDT); diff --git a/test/dm/spi.c b/test/dm/spi.c index 2e27da72d5..5733096066 100644 --- a/test/dm/spi.c +++ b/test/dm/spi.c @@ -30,8 +30,8 @@ static int dm_test_spi_find(struct unit_test_state *uts) false, &bus)); /* - * spi_post_bind() will bind devices to chip selects. Check this then - * remove the emulation and the slave device. + * The post_bind() method will bind devices to chip selects. Check + * this then remove the emulation and the slave device. */ ut_asserteq(0, uclass_get_device_by_seq(UCLASS_SPI, busnum, &bus)); ut_assertok(spi_cs_info(bus, cs, &info));