From patchwork Sun Feb 2 20:02:26 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sean Anderson X-Patchwork-Id: 235786 List-Id: U-Boot discussion From: seanga2 at gmail.com (Sean Anderson) Date: Sun, 2 Feb 2020 15:02:26 -0500 Subject: [PATCH v3 05/12] dm: Add support for simple-pm-bus In-Reply-To: References: Message-ID: <3b86c607-9616-8e3e-b6af-e4064c7e5782@gmail.com> This type of bus is used in Linux to designate busses which have power domains and/or clocks which need to be enabled before their child devices can be used. Because power domains are automatically enabled before probing in u-boot, we just need to enable any clocks present. Signed-off-by: Sean Anderson Reviewed-by: Bin Meng --- Changes for v3: - New .../bus/simple-pm-bus.txt | 44 ++++++++++++++ drivers/core/simple-bus.c | 57 ++++++++++++++++++- 2 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 doc/device-tree-bindings/bus/simple-pm-bus.txt diff --git a/doc/device-tree-bindings/bus/simple-pm-bus.txt b/doc/device-tree-bindings/bus/simple-pm-bus.txt new file mode 100644 index 0000000000..6f15037131 --- /dev/null +++ b/doc/device-tree-bindings/bus/simple-pm-bus.txt @@ -0,0 +1,44 @@ +Simple Power-Managed Bus +======================== + +A Simple Power-Managed Bus is a transparent bus that doesn't need a real +driver, as it's typically initialized by the boot loader. + +However, its bus controller is part of a PM domain, or under the control of a +functional clock. Hence, the bus controller's PM domain and/or clock must be +enabled for child devices connected to the bus (either on-SoC or externally) +to function. + +While "simple-pm-bus" follows the "simple-bus" set of properties, as specified +in the Devicetree Specification, it is not an extension of "simple-bus". + + +Required properties: + - compatible: Must contain at least "simple-pm-bus". + Must not contain "simple-bus". + It's recommended to let this be preceded by one or more + vendor-specific compatible values. + - #address-cells, #size-cells, ranges: Must describe the mapping between + parent address and child address spaces. + +Optional platform-specific properties for clock or PM domain control (at least +one of them is required): + - clocks: Must contain a reference to the functional clock(s), + - power-domains: Must contain a reference to the PM domain. +Please refer to the binding documentation for the clock and/or PM domain +providers for more details. + + +Example: + + bsc: bus at fec10000 { + compatible = "renesas,bsc-sh73a0", "renesas,bsc", + "simple-pm-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0x20000000>; + reg = <0xfec10000 0x400>; + interrupts = <0 39 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&zb_clk>; + power-domains = <&pd_a4s>; + }; diff --git a/drivers/core/simple-bus.c b/drivers/core/simple-bus.c index 7fc23ef82d..d94567e98d 100644 --- a/drivers/core/simple-bus.c +++ b/drivers/core/simple-bus.c @@ -5,6 +5,11 @@ #include #include +#include + +#define SIMPLE_BUS 0 +#define SIMPLE_MFD 1 +#define SIMPLE_PM_BUS 2 struct simple_bus_plat { u32 base; @@ -50,9 +55,55 @@ UCLASS_DRIVER(simple_bus) = { .per_device_platdata_auto_alloc_size = sizeof(struct simple_bus_plat), }; +static const int generic_simple_bus_probe(struct udevice *dev) +{ +#if CONFIG_IS_ENABLED(CLK) + int ret; + struct clk_bulk *bulk; + ulong type = dev_get_driver_data(dev); + + if (type == SIMPLE_PM_BUS) { + bulk = kzalloc(sizeof(*bulk), GFP_KERNEL); + if (!bulk) + return -ENOMEM; + + ret = clk_get_bulk(dev, bulk); + if (ret) + return ret; + + ret = clk_enable_bulk(bulk); + if (ret && ret != -ENOSYS && ret != -ENOTSUPP) { + clk_release_bulk(bulk); + return ret; + } + dev->priv = bulk; + } +#endif + return 0; +} + +static const int generic_simple_bus_remove(struct udevice *dev) +{ + int ret = 0; +#if CONFIG_IS_ENABLED(CLK) + struct clk_bulk *bulk; + ulong type = dev_get_driver_data(dev); + + if (type == SIMPLE_PM_BUS) { + bulk = dev_get_priv(dev); + ret = clk_release_bulk(bulk); + kfree(bulk); + if (ret == -ENOSYS) + ret = 0; + } +#endif + return ret; +} + static const struct udevice_id generic_simple_bus_ids[] = { - { .compatible = "simple-bus" }, - { .compatible = "simple-mfd" }, + { .compatible = "simple-bus", .data = SIMPLE_BUS }, + { .compatible = "simple-mfd", .data = SIMPLE_MFD }, + { .compatible = "simple-pm-bus", .data = SIMPLE_PM_BUS }, { } }; @@ -60,5 +111,7 @@ U_BOOT_DRIVER(simple_bus_drv) = { .name = "generic_simple_bus", .id = UCLASS_SIMPLE_BUS, .of_match = generic_simple_bus_ids, + .probe = generic_simple_bus_probe, + .remove = generic_simple_bus_remove, .flags = DM_FLAG_PRE_RELOC, };