2015-12-09 22:29:49

by Simon Arlott

[permalink] [raw]
Subject: [PATCH linux-next 1/2] power: Add brcm,bcm6358-power-controller device tree binding

The BCM6358 contains power domains controlled with a register. Power
domains are indexed by bits in the register. Power domain bits can be
interleaved with other status bits and clocks in the same register.

Newer SoCs with dedicated power domain registers are active low.

Signed-off-by: Simon Arlott <[email protected]>
---
.../power/brcm,bcm6358-power-controller.txt | 53 ++++++++++++++++++++++
1 file changed, 53 insertions(+)
create mode 100644 Documentation/devicetree/bindings/power/brcm,bcm6358-power-controller.txt

diff --git a/Documentation/devicetree/bindings/power/brcm,bcm6358-power-controller.txt b/Documentation/devicetree/bindings/power/brcm,bcm6358-power-controller.txt
new file mode 100644
index 0000000..556c323
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/brcm,bcm6358-power-controller.txt
@@ -0,0 +1,53 @@
+Broadcom BCM6358 Power domain controller
+
+This binding uses the power domain bindings:
+ Documentation/devicetree/bindings/power/power_domain.txt
+
+The BCM6358 contains power domains controlled with a register. Power
+domains are indexed by bits in the register. Power domain bits can be
+interleaved with other status bits and clocks in the same register.
+
+Newer SoCs with dedicated power domain registers are active low.
+
+Required properties:
+- compatible: Should be "brcm,bcm<soc>-power-controller", "brcm,bcm6358-power-controller"
+- #power-domain-cells: Should be <1>.
+- regmap: The register map phandle
+- offset: Offset in the register map for the power domain register (in bytes)
+- power-domain-indices: The bits in the register used for power domains.
+- power-domain-names: Should be a list of strings of power domain names
+ indexed by the power domain indices.
+
+Optional properties:
+- active-low: Specify that the bits are active low.
+
+Example:
+
+misc_iddq_ctrl: power-controller {
+ compatible = "brcm,bcm63168-power-controller", "brcm,bcm6358-power-controller";
+ regmap = <&misc>;
+ offset = <0x4c>;
+
+ #power-domain-cells = <1>;
+ power-domain-indices =
+ <0>, <1>, <2>, <3>, <4>,
+ <5>, <6>, <7>, <8>, <9>,
+ <10>, <11>, <12>, <13>, <17>,
+ <18>;
+ power-domain-names =
+ "sar", "ipsec", "mips", "dect", "usbh",
+ "usbd", "robosw", "pcm", "periph", "vdsl_phy",
+ "vdsl_mips", "fap", "pcie", "wlan_pads", "gphy",
+ "gmac";
+ active-low;
+};
+
+periph_iddq: power-controller {
+ compatible = "brcm,bcm6368-power-controller", "brcm,bcm6358-power-controller";
+ regmap = <&periph_cntl>;
+ offset = <0x4>;
+
+ #power-domain-cells = <1>;
+ power-domain-indices = <19>;
+ power-domain-names = "usbh";
+};
--
2.1.4

--
Simon Arlott


2015-12-09 22:30:31

by Simon Arlott

[permalink] [raw]
Subject: [PATCH linux-next 2/2] power: bcm6358-power: Add BCM6358 power domain controller support

The BCM6358 contains power domains controlled with a register. Power
domains are indexed by bits in the register. Power domain bits can be
interleaved with other status bits and clocks in the same register.

Newer SoCs with dedicated power domain registers are active low.

Signed-off-by: Simon Arlott <[email protected]>
---
MAINTAINERS | 1 +
drivers/power/Kconfig | 11 +++
drivers/power/Makefile | 1 +
drivers/power/bcm6358-power.c | 198 ++++++++++++++++++++++++++++++++++++++++++
4 files changed, 211 insertions(+)
create mode 100644 drivers/power/bcm6358-power.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 0370aba..5546a53 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2391,6 +2391,7 @@ F: drivers/clk/bcm/clk-bcm6345*
F: drivers/irqchip/irq-bcm63*
F: drivers/irqchip/irq-bcm7*
F: drivers/irqchip/irq-brcmstb*
+F: drivers/power/bcm6358*
F: drivers/reset/bcm/reset-bcm6345*
F: include/linux/bcm63xx_wdt.h

diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 1ddd13c..3d6f842 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -506,3 +506,14 @@ endif # POWER_SUPPLY

source "drivers/power/reset/Kconfig"
source "drivers/power/avs/Kconfig"
+
+config BCM6358_POWER
+ bool "BCM6358 power domain support"
+ depends on BMIPS_GENERIC && PM && OF
+ select PM_GENERIC_DOMAINS
+ select PM_GENERIC_DOMAINS_OF
+ default BMIPS_GENERIC
+ help
+ Say Y here to enable support for power domains on the BCM6358.
+ Required to ensure that power is enabled for SoC peripheral
+ devices, and that power is disabled to unused devices.
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 0e4eab5..0b72dd2 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_GENERIC_ADC_BATTERY) += generic-adc-battery.o
obj-$(CONFIG_PDA_POWER) += pda_power.o
obj-$(CONFIG_APM_POWER) += apm_power.o
obj-$(CONFIG_AXP20X_POWER) += axp20x_usb_power.o
+obj-$(CONFIG_BCM6358_POWER) += bcm6358-power.o
obj-$(CONFIG_MAX8925_POWER) += max8925_power.o
obj-$(CONFIG_WM831X_BACKUP) += wm831x_backup.o
obj-$(CONFIG_WM831X_POWER) += wm831x_power.o
diff --git a/drivers/power/bcm6358-power.c b/drivers/power/bcm6358-power.c
new file mode 100644
index 0000000..f4654d7
--- /dev/null
+++ b/drivers/power/bcm6358-power.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2015 Simon Arlott
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/pm_domain.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+
+#define BITS 32
+
+struct bcm6358_power;
+
+struct bcm6358_power_dev {
+ struct generic_pm_domain genpd;
+ struct bcm6358_power *power;
+ u32 bit;
+};
+
+struct bcm6358_power {
+ struct regmap *map;
+ u32 offset;
+ bool active_low;
+
+ struct bcm6358_power_dev dev[BITS];
+ struct genpd_onecell_data genpd_data;
+ struct generic_pm_domain *genpd[BITS];
+};
+
+static int bcm6358_power_get_state(struct bcm6358_power_dev *pmd,
+ bool *is_on)
+{
+ struct bcm6358_power *power = pmd->power;
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(power->map, power->offset, &val);
+ if (ret) {
+ *is_on = false;
+ return ret;
+ }
+
+ if (power->active_low)
+ *is_on = !(val & pmd->bit);
+ else
+ *is_on = (val & pmd->bit);
+ return 0;
+}
+
+static int bcm6358_power_set_state(struct bcm6358_power_dev *pmd,
+ bool on)
+{
+ struct bcm6358_power *power = pmd->power;
+ u32 val;
+
+ if (power->active_low)
+ val = on ? 0 : pmd->bit;
+ else
+ val = on ? pmd->bit : 0;
+
+ return regmap_update_bits(power->map, power->offset, pmd->bit, val);
+}
+
+static int bcm6358_power_power_on(struct generic_pm_domain *genpd)
+{
+ struct bcm6358_power_dev *pmd = container_of(genpd,
+ struct bcm6358_power_dev, genpd);
+
+ return bcm6358_power_set_state(pmd, true);
+}
+
+static int bcm6358_power_power_off(struct generic_pm_domain *genpd)
+{
+ struct bcm6358_power_dev *pmd = container_of(genpd,
+ struct bcm6358_power_dev, genpd);
+
+ return bcm6358_power_set_state(pmd, false);
+}
+
+static int __init bcm6358_power_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct bcm6358_power *power;
+ unsigned int pmdomains = 0;
+ int ret, i;
+
+ power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL);
+ if (!power)
+ return -ENOMEM;
+
+ power->map = syscon_regmap_lookup_by_phandle(np, "regmap");
+ if (IS_ERR(power->map)) {
+ ret = PTR_ERR(power->map);
+ dev_err(dev, "failed to get regmap: %d\n", ret);
+ return ret;
+ }
+
+ if (of_property_read_u32(np, "offset", &power->offset)) {
+ dev_err(dev, "missing register offset\n");
+ return -EINVAL;
+ }
+
+ power->active_low = of_property_read_bool(np, "active-low");
+
+ power->genpd_data.domains = power->genpd;
+ power->genpd_data.num_domains = BITS;
+
+ /* power->genpd_data is sparse, indexed by bit,
+ * maximum pm domains checked using i
+ */
+ for (i = 0; i < power->genpd_data.num_domains; i++) {
+ struct bcm6358_power_dev *pmd = &power->dev[i];
+ u32 bit;
+ bool is_on;
+
+ if (of_property_read_u32_index(np, "power-domain-indices",
+ i, &bit))
+ goto out;
+
+ if (of_property_read_string_index(np, "power-domain-names",
+ i, &pmd->genpd.name))
+ goto out;
+
+ if (bit >= power->genpd_data.num_domains) {
+ dev_err(dev,
+ "power domain bit %u out of range\n", bit);
+ continue;
+ }
+
+ if (power->genpd[bit]) {
+ dev_err(dev,
+ "power domain bit %u already exists\n", bit);
+ continue;
+ }
+
+ pmd->power = power;
+ pmd->bit = BIT(bit);
+
+ ret = bcm6358_power_get_state(pmd, &is_on);
+ if (ret)
+ dev_warn(dev, "unable to get current state for %s\n",
+ pmd->genpd.name);
+
+ pmd->genpd.power_on = bcm6358_power_power_on;
+ pmd->genpd.power_off = bcm6358_power_power_off;
+
+ pm_genpd_init(&pmd->genpd, NULL, !is_on);
+ power->genpd[bit] = &pmd->genpd;
+ pmdomains++;
+ }
+
+out:
+ if (!pmdomains)
+ return -ENODEV;
+
+ ret = of_genpd_add_provider_onecell(np, &power->genpd_data);
+ if (ret) {
+ dev_err(dev, "failed to register genpd driver: %d\n", ret);
+ return ret;
+ }
+
+ dev_info(dev, "registered %u power domains\n", pmdomains);
+ return 0;
+}
+
+static const struct of_device_id bcm6358_power_ids[] __initconst = {
+ { .compatible = "brcm,bcm6358-power-controller" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, bcm6358_power_ids);
+
+static struct platform_driver bcm6358_power_driver __refdata = {
+ .probe = bcm6358_power_probe,
+ .driver = {
+ .name = "bcm6358-power-controller",
+ .of_match_table = bcm6358_power_ids,
+ },
+};
+
+module_platform_driver(bcm6358_power_driver);
+
+MODULE_DESCRIPTION("BCM6358 Power domain controller driver");
+MODULE_AUTHOR("Simon Arlott");
+MODULE_LICENSE("GPL");
--
2.1.4

--
Simon Arlott

2015-12-11 02:58:52

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH linux-next 1/2] power: Add brcm,bcm6358-power-controller device tree binding

On Wed, Dec 09, 2015 at 10:29:35PM +0000, Simon Arlott wrote:
> The BCM6358 contains power domains controlled with a register. Power
> domains are indexed by bits in the register. Power domain bits can be
> interleaved with other status bits and clocks in the same register.
>
> Newer SoCs with dedicated power domain registers are active low.
>
> Signed-off-by: Simon Arlott <[email protected]>
> ---
> .../power/brcm,bcm6358-power-controller.txt | 53 ++++++++++++++++++++++
> 1 file changed, 53 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/power/brcm,bcm6358-power-controller.txt
>
> diff --git a/Documentation/devicetree/bindings/power/brcm,bcm6358-power-controller.txt b/Documentation/devicetree/bindings/power/brcm,bcm6358-power-controller.txt
> new file mode 100644
> index 0000000..556c323
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/power/brcm,bcm6358-power-controller.txt
> @@ -0,0 +1,53 @@
> +Broadcom BCM6358 Power domain controller
> +
> +This binding uses the power domain bindings:
> + Documentation/devicetree/bindings/power/power_domain.txt
> +
> +The BCM6358 contains power domains controlled with a register. Power
> +domains are indexed by bits in the register. Power domain bits can be
> +interleaved with other status bits and clocks in the same register.
> +
> +Newer SoCs with dedicated power domain registers are active low.
> +
> +Required properties:
> +- compatible: Should be "brcm,bcm<soc>-power-controller", "brcm,bcm6358-power-controller"
> +- #power-domain-cells: Should be <1>.
> +- regmap: The register map phandle
> +- offset: Offset in the register map for the power domain register (in bytes)
> +- power-domain-indices: The bits in the register used for power domains.

You should drop this and make the cell values be the register offsets.

> +- power-domain-names: Should be a list of strings of power domain names
> + indexed by the power domain indices.

This isn't really needed anyway.

> +
> +Optional properties:
> +- active-low: Specify that the bits are active low.

This should be implied by the compatible property.

Rob

2015-12-11 20:36:44

by Simon Arlott

[permalink] [raw]
Subject: Re: [PATCH linux-next 1/2] power: Add brcm,bcm6358-power-controller device tree binding

On 11/12/15 02:58, Rob Herring wrote:
> On Wed, Dec 09, 2015 at 10:29:35PM +0000, Simon Arlott wrote:
>> The BCM6358 contains power domains controlled with a register. Power
>> domains are indexed by bits in the register. Power domain bits can be
>> interleaved with other status bits and clocks in the same register.
>>
>> Newer SoCs with dedicated power domain registers are active low.
>>
>> Signed-off-by: Simon Arlott <[email protected]>
>> ---
>> .../power/brcm,bcm6358-power-controller.txt | 53 ++++++++++++++++++++++
>> 1 file changed, 53 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/power/brcm,bcm6358-power-controller.txt
>>
>> diff --git a/Documentation/devicetree/bindings/power/brcm,bcm6358-power-controller.txt b/Documentation/devicetree/bindings/power/brcm,bcm6358-power-controller.txt
>> new file mode 100644
>> index 0000000..556c323
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/power/brcm,bcm6358-power-controller.txt
>> @@ -0,0 +1,53 @@
>> +Broadcom BCM6358 Power domain controller
>> +
>> +This binding uses the power domain bindings:
>> + Documentation/devicetree/bindings/power/power_domain.txt
>> +
>> +The BCM6358 contains power domains controlled with a register. Power
>> +domains are indexed by bits in the register. Power domain bits can be
>> +interleaved with other status bits and clocks in the same register.
>> +
>> +Newer SoCs with dedicated power domain registers are active low.
>> +
>> +Required properties:
>> +- compatible: Should be "brcm,bcm<soc>-power-controller", "brcm,bcm6358-power-controller"
>> +- #power-domain-cells: Should be <1>.
>> +- regmap: The register map phandle
>> +- offset: Offset in the register map for the power domain register (in bytes)
>> +- power-domain-indices: The bits in the register used for power domains.
>
> You should drop this and make the cell values be the register offsets.

I need to register every power domain in order to get the kernel to turn
off those that are unused. Even if I could enumerate all device tree
devices that reference the power-controller node, not all of them have
bindings to allow them to be specified in the device tree file.

I can't register all 32 bits because that won't work on the BCM6358 that
only has 1 power domain bit in the register and several clock bits. On
the BCM63268 there are power domain bits that have no device that I
don't want the kernel to disable (like the memory controller).

How should I determine which bits to register a power domain for?

misc_iddq_ctrl: power-controller@1000184c {
compatible = "brcm,bcm6358-power-controller";
regmap = <&misc>;
offset = <0x4c>;

mask = <0x1043fff>;

#power-domain-cells = <1>;
};

or

misc_iddq_ctrl: power-controller@1000184c {
compatible = "brcm,bcm6358-power-controller";
regmap = <&misc>;
offset = <0x4c>;

#address-cells = <1>;
#size-cells = <0>;

sar: power-controller@0 {
reg = <0>;
#power-domain-cells = <0>;
};

ipsec: power-controller@1 {
reg = <1>;
#power-domain-cells = <0>;
};

...
};

or something else?

>> +- power-domain-names: Should be a list of strings of power domain names
>> + indexed by the power domain indices.
>
> This isn't really needed anyway.

If I remove this then I'll have to use the same node name for each
struct generic_pm_domain "name" field that I register, although these
names don't appear to be exported anywhere.

>> +
>> +Optional properties:
>> +- active-low: Specify that the bits are active low.
>
> This should be implied by the compatible property.

Ok, I'll create "brcm,bcm6358-power-controller" that's active high and
"brcm,bcm6328-power-controller" that's active low. This appear to be
the earliest chips that introduced or changed "iddq" register bits.

--
Simon Arlott

2015-12-15 23:23:07

by Sebastian Reichel

[permalink] [raw]
Subject: Re: [PATCH linux-next 1/2] power: Add brcm,bcm6358-power-controller device tree binding

Hi,

On Wed, Dec 09, 2015 at 10:29:35PM +0000, Simon Arlott wrote:
> The BCM6358 contains power domains controlled with a register. Power
> domains are indexed by bits in the register. Power domain bits can be
> interleaved with other status bits and clocks in the same register.
>
> Newer SoCs with dedicated power domain registers are active low.

That's neither a power supply driver (like a battery charger or a
fuel gauge), nor a reboot/poweroff driver, so does not really fit
into my tree. I will add generic PM maintainers to the discussion.

-- Sebastian


Attachments:
(No filename) (564.00 B)
signature.asc (819.00 B)
Download all attachments