soc: bcm: Move power-domain drivers to the genpd dir
authorUlf Hansson <ulf.hansson@linaro.org>
Tue, 4 Jul 2023 22:36:24 +0000 (00:36 +0200)
committerUlf Hansson <ulf.hansson@linaro.org>
Tue, 11 Jul 2023 13:30:09 +0000 (15:30 +0200)
To simplify with maintenance let's move the bcm power-domain drivers to the
new genpd directory. Going forward, patches are intended to be managed
through a separate git tree, according to MAINTAINERS.

While moving the drivers, we end up with a directory for bcm63xx that only
contains a Kconfig file, which seems a bit silly. Let's therefore also move
the Kconfig options into the Kconfig file a directory above, as it allows
us to drop the directory too.

Cc: Florian Fainelli <florian.fainelli@broadcom.com>
Cc: Ray Jui <rjui@broadcom.com>
Cc: Scott Branden <sbranden@broadcom.com>
Cc: <linux-mips@vger.kernel.org>
Cc: <linux-rpi-kernel@lists.infradead.org>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
15 files changed:
MAINTAINERS
drivers/genpd/Makefile
drivers/genpd/bcm/Makefile [new file with mode: 0644]
drivers/genpd/bcm/bcm-pmb.c [new file with mode: 0644]
drivers/genpd/bcm/bcm2835-power.c [new file with mode: 0644]
drivers/genpd/bcm/bcm63xx-power.c [new file with mode: 0644]
drivers/genpd/bcm/raspberrypi-power.c [new file with mode: 0644]
drivers/soc/bcm/Kconfig
drivers/soc/bcm/Makefile
drivers/soc/bcm/bcm2835-power.c [deleted file]
drivers/soc/bcm/bcm63xx/Kconfig [deleted file]
drivers/soc/bcm/bcm63xx/Makefile [deleted file]
drivers/soc/bcm/bcm63xx/bcm-pmb.c [deleted file]
drivers/soc/bcm/bcm63xx/bcm63xx-power.c [deleted file]
drivers/soc/bcm/raspberrypi-power.c [deleted file]

index caa221fd0c11f24c9954cd9fdf04b1fc7f175820..77629ab4a5f0adf1fbfa4096dbf95db5dc9a6fef 100644 (file)
@@ -4009,7 +4009,7 @@ F:        arch/mips/kernel/*bmips*
 F:     drivers/irqchip/irq-bcm63*
 F:     drivers/irqchip/irq-bcm7*
 F:     drivers/irqchip/irq-brcmstb*
-F:     drivers/soc/bcm/bcm63xx
+F:     drivers/genpd/bcm/bcm63xx-power.c
 F:     include/linux/bcm963xx_nvram.h
 F:     include/linux/bcm963xx_tag.h
 
@@ -4224,7 +4224,7 @@ R:        Broadcom internal kernel review list <bcm-kernel-feedback-list@broadcom.com>
 L:     linux-pm@vger.kernel.org
 S:     Maintained
 T:     git https://github.com/broadcom/stblinux.git
-F:     drivers/soc/bcm/bcm63xx/bcm-pmb.c
+F:     drivers/genpd/bcm/bcm-pmb.c
 F:     include/dt-bindings/soc/bcm-pmb.h
 
 BROADCOM SPECIFIC AMBA DRIVER (BCMA)
index 91d4a3808981dec4a8fa7b7a5ac9ac4e5a85aeb9..6b9e9fe907f37a873a305d99edf7f425f72cdc7d 100644 (file)
@@ -2,3 +2,4 @@
 obj-y                                  += actions/
 obj-y                                  += amlogic/
 obj-y                                  += apple/
+obj-y                                  += bcm/
diff --git a/drivers/genpd/bcm/Makefile b/drivers/genpd/bcm/Makefile
new file mode 100644 (file)
index 0000000..6bfbe4e
--- /dev/null
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_BCM_PMB)                  += bcm-pmb.o
+obj-$(CONFIG_BCM2835_POWER)            += bcm2835-power.o
+obj-$(CONFIG_BCM63XX_POWER)            += bcm63xx-power.o
+obj-$(CONFIG_RASPBERRYPI_POWER)                += raspberrypi-power.o
diff --git a/drivers/genpd/bcm/bcm-pmb.c b/drivers/genpd/bcm/bcm-pmb.c
new file mode 100644 (file)
index 0000000..9407cac
--- /dev/null
@@ -0,0 +1,364 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2013 Broadcom
+ * Copyright (C) 2020 Rafał Miłecki <rafal@milecki.pl>
+ */
+
+#include <dt-bindings/soc/bcm-pmb.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/reset/bcm63xx_pmb.h>
+
+#define BPCM_ID_REG                                    0x00
+#define BPCM_CAPABILITIES                              0x04
+#define  BPCM_CAP_NUM_ZONES                            0x000000ff
+#define  BPCM_CAP_SR_REG_BITS                          0x0000ff00
+#define  BPCM_CAP_PLLTYPE                              0x00030000
+#define  BPCM_CAP_UBUS                                 0x00080000
+#define BPCM_CONTROL                                   0x08
+#define BPCM_STATUS                                    0x0c
+#define BPCM_ROSC_CONTROL                              0x10
+#define BPCM_ROSC_THRESH_H                             0x14
+#define BPCM_ROSC_THRESHOLD_BCM6838                    0x14
+#define BPCM_ROSC_THRESH_S                             0x18
+#define BPCM_ROSC_COUNT_BCM6838                                0x18
+#define BPCM_ROSC_COUNT                                        0x1c
+#define BPCM_PWD_CONTROL_BCM6838                       0x1c
+#define BPCM_PWD_CONTROL                               0x20
+#define BPCM_SR_CONTROL_BCM6838                                0x20
+#define BPCM_PWD_ACCUM_CONTROL                         0x24
+#define BPCM_SR_CONTROL                                        0x28
+#define BPCM_GLOBAL_CONTROL                            0x2c
+#define BPCM_MISC_CONTROL                              0x30
+#define BPCM_MISC_CONTROL2                             0x34
+#define BPCM_SGPHY_CNTL                                        0x38
+#define BPCM_SGPHY_STATUS                              0x3c
+#define BPCM_ZONE0                                     0x40
+#define  BPCM_ZONE_CONTROL                             0x00
+#define   BPCM_ZONE_CONTROL_MANUAL_CLK_EN              0x00000001
+#define   BPCM_ZONE_CONTROL_MANUAL_RESET_CTL           0x00000002
+#define   BPCM_ZONE_CONTROL_FREQ_SCALE_USED            0x00000004      /* R/O */
+#define   BPCM_ZONE_CONTROL_DPG_CAPABLE                        0x00000008      /* R/O */
+#define   BPCM_ZONE_CONTROL_MANUAL_MEM_PWR             0x00000030
+#define   BPCM_ZONE_CONTROL_MANUAL_ISO_CTL             0x00000040
+#define   BPCM_ZONE_CONTROL_MANUAL_CTL                 0x00000080
+#define   BPCM_ZONE_CONTROL_DPG_CTL_EN                 0x00000100
+#define   BPCM_ZONE_CONTROL_PWR_DN_REQ                 0x00000200
+#define   BPCM_ZONE_CONTROL_PWR_UP_REQ                 0x00000400
+#define   BPCM_ZONE_CONTROL_MEM_PWR_CTL_EN             0x00000800
+#define   BPCM_ZONE_CONTROL_BLK_RESET_ASSERT           0x00001000
+#define   BPCM_ZONE_CONTROL_MEM_STBY                   0x00002000
+#define   BPCM_ZONE_CONTROL_RESERVED                   0x0007c000
+#define   BPCM_ZONE_CONTROL_PWR_CNTL_STATE             0x00f80000
+#define   BPCM_ZONE_CONTROL_FREQ_SCALAR_DYN_SEL                0x01000000      /* R/O */
+#define   BPCM_ZONE_CONTROL_PWR_OFF_STATE              0x02000000      /* R/O */
+#define   BPCM_ZONE_CONTROL_PWR_ON_STATE               0x04000000      /* R/O */
+#define   BPCM_ZONE_CONTROL_PWR_GOOD                   0x08000000      /* R/O */
+#define   BPCM_ZONE_CONTROL_DPG_PWR_STATE              0x10000000      /* R/O */
+#define   BPCM_ZONE_CONTROL_MEM_PWR_STATE              0x20000000      /* R/O */
+#define   BPCM_ZONE_CONTROL_ISO_STATE                  0x40000000      /* R/O */
+#define   BPCM_ZONE_CONTROL_RESET_STATE                        0x80000000      /* R/O */
+#define  BPCM_ZONE_CONFIG1                             0x04
+#define  BPCM_ZONE_CONFIG2                             0x08
+#define  BPCM_ZONE_FREQ_SCALAR_CONTROL                 0x0c
+#define  BPCM_ZONE_SIZE                                        0x10
+
+struct bcm_pmb {
+       struct device *dev;
+       void __iomem *base;
+       spinlock_t lock;
+       bool little_endian;
+       struct genpd_onecell_data genpd_onecell_data;
+};
+
+struct bcm_pmb_pd_data {
+       const char * const name;
+       int id;
+       u8 bus;
+       u8 device;
+};
+
+struct bcm_pmb_pm_domain {
+       struct bcm_pmb *pmb;
+       const struct bcm_pmb_pd_data *data;
+       struct generic_pm_domain genpd;
+};
+
+static int bcm_pmb_bpcm_read(struct bcm_pmb *pmb, int bus, u8 device,
+                            int offset, u32 *val)
+{
+       void __iomem *base = pmb->base + bus * 0x20;
+       unsigned long flags;
+       int err;
+
+       spin_lock_irqsave(&pmb->lock, flags);
+       err = bpcm_rd(base, device, offset, val);
+       spin_unlock_irqrestore(&pmb->lock, flags);
+
+       if (!err)
+               *val = pmb->little_endian ? le32_to_cpu(*val) : be32_to_cpu(*val);
+
+       return err;
+}
+
+static int bcm_pmb_bpcm_write(struct bcm_pmb *pmb, int bus, u8 device,
+                             int offset, u32 val)
+{
+       void __iomem *base = pmb->base + bus * 0x20;
+       unsigned long flags;
+       int err;
+
+       val = pmb->little_endian ? cpu_to_le32(val) : cpu_to_be32(val);
+
+       spin_lock_irqsave(&pmb->lock, flags);
+       err = bpcm_wr(base, device, offset, val);
+       spin_unlock_irqrestore(&pmb->lock, flags);
+
+       return err;
+}
+
+static int bcm_pmb_power_off_zone(struct bcm_pmb *pmb, int bus, u8 device,
+                                 int zone)
+{
+       int offset;
+       u32 val;
+       int err;
+
+       offset = BPCM_ZONE0 + zone * BPCM_ZONE_SIZE + BPCM_ZONE_CONTROL;
+
+       err = bcm_pmb_bpcm_read(pmb, bus, device, offset, &val);
+       if (err)
+               return err;
+
+       val |= BPCM_ZONE_CONTROL_PWR_DN_REQ;
+       val &= ~BPCM_ZONE_CONTROL_PWR_UP_REQ;
+
+       err = bcm_pmb_bpcm_write(pmb, bus, device, offset, val);
+
+       return err;
+}
+
+static int bcm_pmb_power_on_zone(struct bcm_pmb *pmb, int bus, u8 device,
+                                int zone)
+{
+       int offset;
+       u32 val;
+       int err;
+
+       offset = BPCM_ZONE0 + zone * BPCM_ZONE_SIZE + BPCM_ZONE_CONTROL;
+
+       err = bcm_pmb_bpcm_read(pmb, bus, device, offset, &val);
+       if (err)
+               return err;
+
+       if (!(val & BPCM_ZONE_CONTROL_PWR_ON_STATE)) {
+               val &= ~BPCM_ZONE_CONTROL_PWR_DN_REQ;
+               val |= BPCM_ZONE_CONTROL_DPG_CTL_EN;
+               val |= BPCM_ZONE_CONTROL_PWR_UP_REQ;
+               val |= BPCM_ZONE_CONTROL_MEM_PWR_CTL_EN;
+               val |= BPCM_ZONE_CONTROL_BLK_RESET_ASSERT;
+
+               err = bcm_pmb_bpcm_write(pmb, bus, device, offset, val);
+       }
+
+       return err;
+}
+
+static int bcm_pmb_power_off_device(struct bcm_pmb *pmb, int bus, u8 device)
+{
+       int offset;
+       u32 val;
+       int err;
+
+       /* Entire device can be powered off by powering off the 0th zone */
+       offset = BPCM_ZONE0 + BPCM_ZONE_CONTROL;
+
+       err = bcm_pmb_bpcm_read(pmb, bus, device, offset, &val);
+       if (err)
+               return err;
+
+       if (!(val & BPCM_ZONE_CONTROL_PWR_OFF_STATE)) {
+               val = BPCM_ZONE_CONTROL_PWR_DN_REQ;
+
+               err = bcm_pmb_bpcm_write(pmb, bus, device, offset, val);
+       }
+
+       return err;
+}
+
+static int bcm_pmb_power_on_device(struct bcm_pmb *pmb, int bus, u8 device)
+{
+       u32 val;
+       int err;
+       int i;
+
+       err = bcm_pmb_bpcm_read(pmb, bus, device, BPCM_CAPABILITIES, &val);
+       if (err)
+               return err;
+
+       for (i = 0; i < (val & BPCM_CAP_NUM_ZONES); i++) {
+               err = bcm_pmb_power_on_zone(pmb, bus, device, i);
+               if (err)
+                       return err;
+       }
+
+       return err;
+}
+
+static int bcm_pmb_power_on_sata(struct bcm_pmb *pmb, int bus, u8 device)
+{
+       int err;
+
+       err = bcm_pmb_power_on_zone(pmb, bus, device, 0);
+       if (err)
+               return err;
+
+       /* Does not apply to the BCM963158 */
+       err = bcm_pmb_bpcm_write(pmb, bus, device, BPCM_MISC_CONTROL, 0);
+       if (err)
+               return err;
+
+       err = bcm_pmb_bpcm_write(pmb, bus, device, BPCM_SR_CONTROL, 0xffffffff);
+       if (err)
+               return err;
+
+       err = bcm_pmb_bpcm_write(pmb, bus, device, BPCM_SR_CONTROL, 0);
+
+       return err;
+}
+
+static int bcm_pmb_power_on(struct generic_pm_domain *genpd)
+{
+       struct bcm_pmb_pm_domain *pd = container_of(genpd, struct bcm_pmb_pm_domain, genpd);
+       const struct bcm_pmb_pd_data *data = pd->data;
+       struct bcm_pmb *pmb = pd->pmb;
+
+       switch (data->id) {
+       case BCM_PMB_PCIE0:
+       case BCM_PMB_PCIE1:
+       case BCM_PMB_PCIE2:
+               return bcm_pmb_power_on_zone(pmb, data->bus, data->device, 0);
+       case BCM_PMB_HOST_USB:
+               return bcm_pmb_power_on_device(pmb, data->bus, data->device);
+       case BCM_PMB_SATA:
+               return bcm_pmb_power_on_sata(pmb, data->bus, data->device);
+       default:
+               dev_err(pmb->dev, "unsupported device id: %d\n", data->id);
+               return -EINVAL;
+       }
+}
+
+static int bcm_pmb_power_off(struct generic_pm_domain *genpd)
+{
+       struct bcm_pmb_pm_domain *pd = container_of(genpd, struct bcm_pmb_pm_domain, genpd);
+       const struct bcm_pmb_pd_data *data = pd->data;
+       struct bcm_pmb *pmb = pd->pmb;
+
+       switch (data->id) {
+       case BCM_PMB_PCIE0:
+       case BCM_PMB_PCIE1:
+       case BCM_PMB_PCIE2:
+               return bcm_pmb_power_off_zone(pmb, data->bus, data->device, 0);
+       case BCM_PMB_HOST_USB:
+               return bcm_pmb_power_off_device(pmb, data->bus, data->device);
+       default:
+               dev_err(pmb->dev, "unsupported device id: %d\n", data->id);
+               return -EINVAL;
+       }
+}
+
+static int bcm_pmb_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       const struct bcm_pmb_pd_data *table;
+       const struct bcm_pmb_pd_data *e;
+       struct bcm_pmb *pmb;
+       int max_id;
+       int err;
+
+       pmb = devm_kzalloc(dev, sizeof(*pmb), GFP_KERNEL);
+       if (!pmb)
+               return -ENOMEM;
+
+       pmb->dev = dev;
+
+       pmb->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(pmb->base))
+               return PTR_ERR(pmb->base);
+
+       spin_lock_init(&pmb->lock);
+
+       pmb->little_endian = !of_device_is_big_endian(dev->of_node);
+
+       table = of_device_get_match_data(dev);
+       if (!table)
+               return -EINVAL;
+
+       max_id = 0;
+       for (e = table; e->name; e++)
+               max_id = max(max_id, e->id);
+
+       pmb->genpd_onecell_data.num_domains = max_id + 1;
+       pmb->genpd_onecell_data.domains =
+               devm_kcalloc(dev, pmb->genpd_onecell_data.num_domains,
+                            sizeof(struct generic_pm_domain *), GFP_KERNEL);
+       if (!pmb->genpd_onecell_data.domains)
+               return -ENOMEM;
+
+       for (e = table; e->name; e++) {
+               struct bcm_pmb_pm_domain *pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
+
+               if (!pd)
+                       return -ENOMEM;
+
+               pd->pmb = pmb;
+               pd->data = e;
+               pd->genpd.name = e->name;
+               pd->genpd.power_on = bcm_pmb_power_on;
+               pd->genpd.power_off = bcm_pmb_power_off;
+
+               pm_genpd_init(&pd->genpd, NULL, true);
+               pmb->genpd_onecell_data.domains[e->id] = &pd->genpd;
+       }
+
+       err = of_genpd_add_provider_onecell(dev->of_node, &pmb->genpd_onecell_data);
+       if (err) {
+               dev_err(dev, "failed to add genpd provider: %d\n", err);
+               return err;
+       }
+
+       return 0;
+}
+
+static const struct bcm_pmb_pd_data bcm_pmb_bcm4908_data[] = {
+       { .name = "pcie2", .id = BCM_PMB_PCIE2, .bus = 0, .device = 2, },
+       { .name = "pcie0", .id = BCM_PMB_PCIE0, .bus = 1, .device = 14, },
+       { .name = "pcie1", .id = BCM_PMB_PCIE1, .bus = 1, .device = 15, },
+       { .name = "usb", .id = BCM_PMB_HOST_USB, .bus = 1, .device = 17, },
+       { },
+};
+
+static const struct bcm_pmb_pd_data bcm_pmb_bcm63138_data[] = {
+       { .name = "sata", .id = BCM_PMB_SATA, .bus = 0, .device = 3, },
+       { },
+};
+
+static const struct of_device_id bcm_pmb_of_match[] = {
+       { .compatible = "brcm,bcm4908-pmb", .data = &bcm_pmb_bcm4908_data, },
+       { .compatible = "brcm,bcm63138-pmb", .data = &bcm_pmb_bcm63138_data, },
+       { },
+};
+
+static struct platform_driver bcm_pmb_driver = {
+       .driver = {
+               .name = "bcm-pmb",
+               .of_match_table = bcm_pmb_of_match,
+       },
+       .probe  = bcm_pmb_probe,
+};
+
+builtin_platform_driver(bcm_pmb_driver);
diff --git a/drivers/genpd/bcm/bcm2835-power.c b/drivers/genpd/bcm/bcm2835-power.c
new file mode 100644 (file)
index 0000000..1a179d4
--- /dev/null
@@ -0,0 +1,713 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Power domain driver for Broadcom BCM2835
+ *
+ * Copyright (C) 2018 Broadcom
+ */
+
+#include <dt-bindings/soc/bcm2835-pm.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/mfd/bcm2835-pm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/reset-controller.h>
+#include <linux/types.h>
+
+#define PM_GNRIC                        0x00
+#define PM_AUDIO                        0x04
+#define PM_STATUS                       0x18
+#define PM_RSTC                                0x1c
+#define PM_RSTS                                0x20
+#define PM_WDOG                                0x24
+#define PM_PADS0                       0x28
+#define PM_PADS2                       0x2c
+#define PM_PADS3                       0x30
+#define PM_PADS4                       0x34
+#define PM_PADS5                       0x38
+#define PM_PADS6                       0x3c
+#define PM_CAM0                                0x44
+#define PM_CAM0_LDOHPEN                        BIT(2)
+#define PM_CAM0_LDOLPEN                        BIT(1)
+#define PM_CAM0_CTRLEN                 BIT(0)
+
+#define PM_CAM1                                0x48
+#define PM_CAM1_LDOHPEN                        BIT(2)
+#define PM_CAM1_LDOLPEN                        BIT(1)
+#define PM_CAM1_CTRLEN                 BIT(0)
+
+#define PM_CCP2TX                      0x4c
+#define PM_CCP2TX_LDOEN                        BIT(1)
+#define PM_CCP2TX_CTRLEN               BIT(0)
+
+#define PM_DSI0                                0x50
+#define PM_DSI0_LDOHPEN                        BIT(2)
+#define PM_DSI0_LDOLPEN                        BIT(1)
+#define PM_DSI0_CTRLEN                 BIT(0)
+
+#define PM_DSI1                                0x54
+#define PM_DSI1_LDOHPEN                        BIT(2)
+#define PM_DSI1_LDOLPEN                        BIT(1)
+#define PM_DSI1_CTRLEN                 BIT(0)
+
+#define PM_HDMI                                0x58
+#define PM_HDMI_RSTDR                  BIT(19)
+#define PM_HDMI_LDOPD                  BIT(1)
+#define PM_HDMI_CTRLEN                 BIT(0)
+
+#define PM_USB                         0x5c
+/* The power gates must be enabled with this bit before enabling the LDO in the
+ * USB block.
+ */
+#define PM_USB_CTRLEN                  BIT(0)
+
+#define PM_PXLDO                       0x60
+#define PM_PXBG                                0x64
+#define PM_DFT                         0x68
+#define PM_SMPS                                0x6c
+#define PM_XOSC                                0x70
+#define PM_SPAREW                      0x74
+#define PM_SPARER                      0x78
+#define PM_AVS_RSTDR                   0x7c
+#define PM_AVS_STAT                    0x80
+#define PM_AVS_EVENT                   0x84
+#define PM_AVS_INTEN                   0x88
+#define PM_DUMMY                       0xfc
+
+#define PM_IMAGE                       0x108
+#define PM_GRAFX                       0x10c
+#define PM_PROC                                0x110
+#define PM_ENAB                                BIT(12)
+#define PM_ISPRSTN                     BIT(8)
+#define PM_H264RSTN                    BIT(7)
+#define PM_PERIRSTN                    BIT(6)
+#define PM_V3DRSTN                     BIT(6)
+#define PM_ISFUNC                      BIT(5)
+#define PM_MRDONE                      BIT(4)
+#define PM_MEMREP                      BIT(3)
+#define PM_ISPOW                       BIT(2)
+#define PM_POWOK                       BIT(1)
+#define PM_POWUP                       BIT(0)
+#define PM_INRUSH_SHIFT                        13
+#define PM_INRUSH_3_5_MA               0
+#define PM_INRUSH_5_MA                 1
+#define PM_INRUSH_10_MA                        2
+#define PM_INRUSH_20_MA                        3
+#define PM_INRUSH_MASK                 (3 << PM_INRUSH_SHIFT)
+
+#define PM_PASSWORD                    0x5a000000
+
+#define PM_WDOG_TIME_SET               0x000fffff
+#define PM_RSTC_WRCFG_CLR              0xffffffcf
+#define PM_RSTS_HADWRH_SET             0x00000040
+#define PM_RSTC_WRCFG_SET              0x00000030
+#define PM_RSTC_WRCFG_FULL_RESET       0x00000020
+#define PM_RSTC_RESET                  0x00000102
+
+#define PM_READ(reg) readl(power->base + (reg))
+#define PM_WRITE(reg, val) writel(PM_PASSWORD | (val), power->base + (reg))
+
+#define ASB_BRDG_VERSION                0x00
+#define ASB_CPR_CTRL                    0x04
+
+#define ASB_V3D_S_CTRL                 0x08
+#define ASB_V3D_M_CTRL                 0x0c
+#define ASB_ISP_S_CTRL                 0x10
+#define ASB_ISP_M_CTRL                 0x14
+#define ASB_H264_S_CTRL                        0x18
+#define ASB_H264_M_CTRL                        0x1c
+
+#define ASB_REQ_STOP                    BIT(0)
+#define ASB_ACK                         BIT(1)
+#define ASB_EMPTY                       BIT(2)
+#define ASB_FULL                        BIT(3)
+
+#define ASB_AXI_BRDG_ID                        0x20
+
+#define BCM2835_BRDG_ID                        0x62726467
+
+struct bcm2835_power_domain {
+       struct generic_pm_domain base;
+       struct bcm2835_power *power;
+       u32 domain;
+       struct clk *clk;
+};
+
+struct bcm2835_power {
+       struct device           *dev;
+       /* PM registers. */
+       void __iomem            *base;
+       /* AXI Async bridge registers. */
+       void __iomem            *asb;
+       /* RPiVid bridge registers. */
+       void __iomem            *rpivid_asb;
+
+       struct genpd_onecell_data pd_xlate;
+       struct bcm2835_power_domain domains[BCM2835_POWER_DOMAIN_COUNT];
+       struct reset_controller_dev reset;
+};
+
+static int bcm2835_asb_control(struct bcm2835_power *power, u32 reg, bool enable)
+{
+       void __iomem *base = power->asb;
+       u64 start;
+       u32 val;
+
+       switch (reg) {
+       case 0:
+               return 0;
+       case ASB_V3D_S_CTRL:
+       case ASB_V3D_M_CTRL:
+               if (power->rpivid_asb)
+                       base = power->rpivid_asb;
+               break;
+       }
+
+       start = ktime_get_ns();
+
+       /* Enable the module's async AXI bridges. */
+       if (enable) {
+               val = readl(base + reg) & ~ASB_REQ_STOP;
+       } else {
+               val = readl(base + reg) | ASB_REQ_STOP;
+       }
+       writel(PM_PASSWORD | val, base + reg);
+
+       while (readl(base + reg) & ASB_ACK) {
+               cpu_relax();
+               if (ktime_get_ns() - start >= 1000)
+                       return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static int bcm2835_asb_enable(struct bcm2835_power *power, u32 reg)
+{
+       return bcm2835_asb_control(power, reg, true);
+}
+
+static int bcm2835_asb_disable(struct bcm2835_power *power, u32 reg)
+{
+       return bcm2835_asb_control(power, reg, false);
+}
+
+static int bcm2835_power_power_off(struct bcm2835_power_domain *pd, u32 pm_reg)
+{
+       struct bcm2835_power *power = pd->power;
+
+       /* We don't run this on BCM2711 */
+       if (power->rpivid_asb)
+               return 0;
+
+       /* Enable functional isolation */
+       PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISFUNC);
+
+       /* Enable electrical isolation */
+       PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISPOW);
+
+       /* Open the power switches. */
+       PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_POWUP);
+
+       return 0;
+}
+
+static int bcm2835_power_power_on(struct bcm2835_power_domain *pd, u32 pm_reg)
+{
+       struct bcm2835_power *power = pd->power;
+       struct device *dev = power->dev;
+       u64 start;
+       int ret;
+       int inrush;
+       bool powok;
+
+       /* We don't run this on BCM2711 */
+       if (power->rpivid_asb)
+               return 0;
+
+       /* If it was already powered on by the fw, leave it that way. */
+       if (PM_READ(pm_reg) & PM_POWUP)
+               return 0;
+
+       /* Enable power.  Allowing too much current at once may result
+        * in POWOK never getting set, so start low and ramp it up as
+        * necessary to succeed.
+        */
+       powok = false;
+       for (inrush = PM_INRUSH_3_5_MA; inrush <= PM_INRUSH_20_MA; inrush++) {
+               PM_WRITE(pm_reg,
+                        (PM_READ(pm_reg) & ~PM_INRUSH_MASK) |
+                        (inrush << PM_INRUSH_SHIFT) |
+                        PM_POWUP);
+
+               start = ktime_get_ns();
+               while (!(powok = !!(PM_READ(pm_reg) & PM_POWOK))) {
+                       cpu_relax();
+                       if (ktime_get_ns() - start >= 3000)
+                               break;
+               }
+       }
+       if (!powok) {
+               dev_err(dev, "Timeout waiting for %s power OK\n",
+                       pd->base.name);
+               ret = -ETIMEDOUT;
+               goto err_disable_powup;
+       }
+
+       /* Disable electrical isolation */
+       PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_ISPOW);
+
+       /* Repair memory */
+       PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_MEMREP);
+       start = ktime_get_ns();
+       while (!(PM_READ(pm_reg) & PM_MRDONE)) {
+               cpu_relax();
+               if (ktime_get_ns() - start >= 1000) {
+                       dev_err(dev, "Timeout waiting for %s memory repair\n",
+                               pd->base.name);
+                       ret = -ETIMEDOUT;
+                       goto err_disable_ispow;
+               }
+       }
+
+       /* Disable functional isolation */
+       PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_ISFUNC);
+
+       return 0;
+
+err_disable_ispow:
+       PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISPOW);
+err_disable_powup:
+       PM_WRITE(pm_reg, PM_READ(pm_reg) & ~(PM_POWUP | PM_INRUSH_MASK));
+       return ret;
+}
+
+static int bcm2835_asb_power_on(struct bcm2835_power_domain *pd,
+                               u32 pm_reg,
+                               u32 asb_m_reg,
+                               u32 asb_s_reg,
+                               u32 reset_flags)
+{
+       struct bcm2835_power *power = pd->power;
+       int ret;
+
+       ret = clk_prepare_enable(pd->clk);
+       if (ret) {
+               dev_err(power->dev, "Failed to enable clock for %s\n",
+                       pd->base.name);
+               return ret;
+       }
+
+       /* Wait 32 clocks for reset to propagate, 1 us will be enough */
+       udelay(1);
+
+       clk_disable_unprepare(pd->clk);
+
+       /* Deassert the resets. */
+       PM_WRITE(pm_reg, PM_READ(pm_reg) | reset_flags);
+
+       ret = clk_prepare_enable(pd->clk);
+       if (ret) {
+               dev_err(power->dev, "Failed to enable clock for %s\n",
+                       pd->base.name);
+               goto err_enable_resets;
+       }
+
+       ret = bcm2835_asb_enable(power, asb_m_reg);
+       if (ret) {
+               dev_err(power->dev, "Failed to enable ASB master for %s\n",
+                       pd->base.name);
+               goto err_disable_clk;
+       }
+       ret = bcm2835_asb_enable(power, asb_s_reg);
+       if (ret) {
+               dev_err(power->dev, "Failed to enable ASB slave for %s\n",
+                       pd->base.name);
+               goto err_disable_asb_master;
+       }
+
+       return 0;
+
+err_disable_asb_master:
+       bcm2835_asb_disable(power, asb_m_reg);
+err_disable_clk:
+       clk_disable_unprepare(pd->clk);
+err_enable_resets:
+       PM_WRITE(pm_reg, PM_READ(pm_reg) & ~reset_flags);
+       return ret;
+}
+
+static int bcm2835_asb_power_off(struct bcm2835_power_domain *pd,
+                                u32 pm_reg,
+                                u32 asb_m_reg,
+                                u32 asb_s_reg,
+                                u32 reset_flags)
+{
+       struct bcm2835_power *power = pd->power;
+       int ret;
+
+       ret = bcm2835_asb_disable(power, asb_s_reg);
+       if (ret) {
+               dev_warn(power->dev, "Failed to disable ASB slave for %s\n",
+                        pd->base.name);
+               return ret;
+       }
+       ret = bcm2835_asb_disable(power, asb_m_reg);
+       if (ret) {
+               dev_warn(power->dev, "Failed to disable ASB master for %s\n",
+                        pd->base.name);
+               bcm2835_asb_enable(power, asb_s_reg);
+               return ret;
+       }
+
+       clk_disable_unprepare(pd->clk);
+
+       /* Assert the resets. */
+       PM_WRITE(pm_reg, PM_READ(pm_reg) & ~reset_flags);
+
+       return 0;
+}
+
+static int bcm2835_power_pd_power_on(struct generic_pm_domain *domain)
+{
+       struct bcm2835_power_domain *pd =
+               container_of(domain, struct bcm2835_power_domain, base);
+       struct bcm2835_power *power = pd->power;
+
+       switch (pd->domain) {
+       case BCM2835_POWER_DOMAIN_GRAFX:
+               return bcm2835_power_power_on(pd, PM_GRAFX);
+
+       case BCM2835_POWER_DOMAIN_GRAFX_V3D:
+               return bcm2835_asb_power_on(pd, PM_GRAFX,
+                                           ASB_V3D_M_CTRL, ASB_V3D_S_CTRL,
+                                           PM_V3DRSTN);
+
+       case BCM2835_POWER_DOMAIN_IMAGE:
+               return bcm2835_power_power_on(pd, PM_IMAGE);
+
+       case BCM2835_POWER_DOMAIN_IMAGE_PERI:
+               return bcm2835_asb_power_on(pd, PM_IMAGE,
+                                           0, 0,
+                                           PM_PERIRSTN);
+
+       case BCM2835_POWER_DOMAIN_IMAGE_ISP:
+               return bcm2835_asb_power_on(pd, PM_IMAGE,
+                                           ASB_ISP_M_CTRL, ASB_ISP_S_CTRL,
+                                           PM_ISPRSTN);
+
+       case BCM2835_POWER_DOMAIN_IMAGE_H264:
+               return bcm2835_asb_power_on(pd, PM_IMAGE,
+                                           ASB_H264_M_CTRL, ASB_H264_S_CTRL,
+                                           PM_H264RSTN);
+
+       case BCM2835_POWER_DOMAIN_USB:
+               PM_WRITE(PM_USB, PM_USB_CTRLEN);
+               return 0;
+
+       case BCM2835_POWER_DOMAIN_DSI0:
+               PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN);
+               PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN | PM_DSI0_LDOHPEN);
+               return 0;
+
+       case BCM2835_POWER_DOMAIN_DSI1:
+               PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN);
+               PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN | PM_DSI1_LDOHPEN);
+               return 0;
+
+       case BCM2835_POWER_DOMAIN_CCP2TX:
+               PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN);
+               PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN | PM_CCP2TX_LDOEN);
+               return 0;
+
+       case BCM2835_POWER_DOMAIN_HDMI:
+               PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_RSTDR);
+               PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_CTRLEN);
+               PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_LDOPD);
+               usleep_range(100, 200);
+               PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_RSTDR);
+               return 0;
+
+       default:
+               dev_err(power->dev, "Invalid domain %d\n", pd->domain);
+               return -EINVAL;
+       }
+}
+
+static int bcm2835_power_pd_power_off(struct generic_pm_domain *domain)
+{
+       struct bcm2835_power_domain *pd =
+               container_of(domain, struct bcm2835_power_domain, base);
+       struct bcm2835_power *power = pd->power;
+
+       switch (pd->domain) {
+       case BCM2835_POWER_DOMAIN_GRAFX:
+               return bcm2835_power_power_off(pd, PM_GRAFX);
+
+       case BCM2835_POWER_DOMAIN_GRAFX_V3D:
+               return bcm2835_asb_power_off(pd, PM_GRAFX,
+                                            ASB_V3D_M_CTRL, ASB_V3D_S_CTRL,
+                                            PM_V3DRSTN);
+
+       case BCM2835_POWER_DOMAIN_IMAGE:
+               return bcm2835_power_power_off(pd, PM_IMAGE);
+
+       case BCM2835_POWER_DOMAIN_IMAGE_PERI:
+               return bcm2835_asb_power_off(pd, PM_IMAGE,
+                                            0, 0,
+                                            PM_PERIRSTN);
+
+       case BCM2835_POWER_DOMAIN_IMAGE_ISP:
+               return bcm2835_asb_power_off(pd, PM_IMAGE,
+                                            ASB_ISP_M_CTRL, ASB_ISP_S_CTRL,
+                                            PM_ISPRSTN);
+
+       case BCM2835_POWER_DOMAIN_IMAGE_H264:
+               return bcm2835_asb_power_off(pd, PM_IMAGE,
+                                            ASB_H264_M_CTRL, ASB_H264_S_CTRL,
+                                            PM_H264RSTN);
+
+       case BCM2835_POWER_DOMAIN_USB:
+               PM_WRITE(PM_USB, 0);
+               return 0;
+
+       case BCM2835_POWER_DOMAIN_DSI0:
+               PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN);
+               PM_WRITE(PM_DSI0, 0);
+               return 0;
+
+       case BCM2835_POWER_DOMAIN_DSI1:
+               PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN);
+               PM_WRITE(PM_DSI1, 0);
+               return 0;
+
+       case BCM2835_POWER_DOMAIN_CCP2TX:
+               PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN);
+               PM_WRITE(PM_CCP2TX, 0);
+               return 0;
+
+       case BCM2835_POWER_DOMAIN_HDMI:
+               PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_LDOPD);
+               PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_CTRLEN);
+               return 0;
+
+       default:
+               dev_err(power->dev, "Invalid domain %d\n", pd->domain);
+               return -EINVAL;
+       }
+}
+
+static int
+bcm2835_init_power_domain(struct bcm2835_power *power,
+                         int pd_xlate_index, const char *name)
+{
+       struct device *dev = power->dev;
+       struct bcm2835_power_domain *dom = &power->domains[pd_xlate_index];
+
+       dom->clk = devm_clk_get(dev->parent, name);
+       if (IS_ERR(dom->clk)) {
+               int ret = PTR_ERR(dom->clk);
+
+               if (ret == -EPROBE_DEFER)
+                       return ret;
+
+               /* Some domains don't have a clk, so make sure that we
+                * don't deref an error pointer later.
+                */
+               dom->clk = NULL;
+       }
+
+       dom->base.name = name;
+       dom->base.power_on = bcm2835_power_pd_power_on;
+       dom->base.power_off = bcm2835_power_pd_power_off;
+
+       dom->domain = pd_xlate_index;
+       dom->power = power;
+
+       /* XXX: on/off at boot? */
+       pm_genpd_init(&dom->base, NULL, true);
+
+       power->pd_xlate.domains[pd_xlate_index] = &dom->base;
+
+       return 0;
+}
+
+/** bcm2835_reset_reset - Resets a block that has a reset line in the
+ * PM block.
+ *
+ * The consumer of the reset controller must have the power domain up
+ * -- there's no reset ability with the power domain down.  To reset
+ * the sub-block, we just disable its access to memory through the
+ * ASB, reset, and re-enable.
+ */
+static int bcm2835_reset_reset(struct reset_controller_dev *rcdev,
+                              unsigned long id)
+{
+       struct bcm2835_power *power = container_of(rcdev, struct bcm2835_power,
+                                                  reset);
+       struct bcm2835_power_domain *pd;
+       int ret;
+
+       switch (id) {
+       case BCM2835_RESET_V3D:
+               pd = &power->domains[BCM2835_POWER_DOMAIN_GRAFX_V3D];
+               break;
+       case BCM2835_RESET_H264:
+               pd = &power->domains[BCM2835_POWER_DOMAIN_IMAGE_H264];
+               break;
+       case BCM2835_RESET_ISP:
+               pd = &power->domains[BCM2835_POWER_DOMAIN_IMAGE_ISP];
+               break;
+       default:
+               dev_err(power->dev, "Bad reset id %ld\n", id);
+               return -EINVAL;
+       }
+
+       ret = bcm2835_power_pd_power_off(&pd->base);
+       if (ret)
+               return ret;
+
+       return bcm2835_power_pd_power_on(&pd->base);
+}
+
+static int bcm2835_reset_status(struct reset_controller_dev *rcdev,
+                               unsigned long id)
+{
+       struct bcm2835_power *power = container_of(rcdev, struct bcm2835_power,
+                                                  reset);
+
+       switch (id) {
+       case BCM2835_RESET_V3D:
+               return !PM_READ(PM_GRAFX & PM_V3DRSTN);
+       case BCM2835_RESET_H264:
+               return !PM_READ(PM_IMAGE & PM_H264RSTN);
+       case BCM2835_RESET_ISP:
+               return !PM_READ(PM_IMAGE & PM_ISPRSTN);
+       default:
+               return -EINVAL;
+       }
+}
+
+static const struct reset_control_ops bcm2835_reset_ops = {
+       .reset = bcm2835_reset_reset,
+       .status = bcm2835_reset_status,
+};
+
+static const char *const power_domain_names[] = {
+       [BCM2835_POWER_DOMAIN_GRAFX] = "grafx",
+       [BCM2835_POWER_DOMAIN_GRAFX_V3D] = "v3d",
+
+       [BCM2835_POWER_DOMAIN_IMAGE] = "image",
+       [BCM2835_POWER_DOMAIN_IMAGE_PERI] = "peri_image",
+       [BCM2835_POWER_DOMAIN_IMAGE_H264] = "h264",
+       [BCM2835_POWER_DOMAIN_IMAGE_ISP] = "isp",
+
+       [BCM2835_POWER_DOMAIN_USB] = "usb",
+       [BCM2835_POWER_DOMAIN_DSI0] = "dsi0",
+       [BCM2835_POWER_DOMAIN_DSI1] = "dsi1",
+       [BCM2835_POWER_DOMAIN_CAM0] = "cam0",
+       [BCM2835_POWER_DOMAIN_CAM1] = "cam1",
+       [BCM2835_POWER_DOMAIN_CCP2TX] = "ccp2tx",
+       [BCM2835_POWER_DOMAIN_HDMI] = "hdmi",
+};
+
+static int bcm2835_power_probe(struct platform_device *pdev)
+{
+       struct bcm2835_pm *pm = dev_get_drvdata(pdev->dev.parent);
+       struct device *dev = &pdev->dev;
+       struct bcm2835_power *power;
+       static const struct {
+               int parent, child;
+       } domain_deps[] = {
+               { BCM2835_POWER_DOMAIN_GRAFX, BCM2835_POWER_DOMAIN_GRAFX_V3D },
+               { BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_PERI },
+               { BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_H264 },
+               { BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_ISP },
+               { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_USB },
+               { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM0 },
+               { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM1 },
+       };
+       int ret = 0, i;
+       u32 id;
+
+       power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL);
+       if (!power)
+               return -ENOMEM;
+       platform_set_drvdata(pdev, power);
+
+       power->dev = dev;
+       power->base = pm->base;
+       power->asb = pm->asb;
+       power->rpivid_asb = pm->rpivid_asb;
+
+       id = readl(power->asb + ASB_AXI_BRDG_ID);
+       if (id != BCM2835_BRDG_ID /* "BRDG" */) {
+               dev_err(dev, "ASB register ID returned 0x%08x\n", id);
+               return -ENODEV;
+       }
+
+       if (power->rpivid_asb) {
+               id = readl(power->rpivid_asb + ASB_AXI_BRDG_ID);
+               if (id != BCM2835_BRDG_ID /* "BRDG" */) {
+                       dev_err(dev, "RPiVid ASB register ID returned 0x%08x\n",
+                                    id);
+                       return -ENODEV;
+               }
+       }
+
+       power->pd_xlate.domains = devm_kcalloc(dev,
+                                              ARRAY_SIZE(power_domain_names),
+                                              sizeof(*power->pd_xlate.domains),
+                                              GFP_KERNEL);
+       if (!power->pd_xlate.domains)
+               return -ENOMEM;
+
+       power->pd_xlate.num_domains = ARRAY_SIZE(power_domain_names);
+
+       for (i = 0; i < ARRAY_SIZE(power_domain_names); i++) {
+               ret = bcm2835_init_power_domain(power, i, power_domain_names[i]);
+               if (ret)
+                       goto fail;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(domain_deps); i++) {
+               pm_genpd_add_subdomain(&power->domains[domain_deps[i].parent].base,
+                                      &power->domains[domain_deps[i].child].base);
+       }
+
+       power->reset.owner = THIS_MODULE;
+       power->reset.nr_resets = BCM2835_RESET_COUNT;
+       power->reset.ops = &bcm2835_reset_ops;
+       power->reset.of_node = dev->parent->of_node;
+
+       ret = devm_reset_controller_register(dev, &power->reset);
+       if (ret)
+               goto fail;
+
+       of_genpd_add_provider_onecell(dev->parent->of_node, &power->pd_xlate);
+
+       dev_info(dev, "Broadcom BCM2835 power domains driver");
+       return 0;
+
+fail:
+       for (i = 0; i < ARRAY_SIZE(power_domain_names); i++) {
+               struct generic_pm_domain *dom = &power->domains[i].base;
+
+               if (dom->name)
+                       pm_genpd_remove(dom);
+       }
+       return ret;
+}
+
+static struct platform_driver bcm2835_power_driver = {
+       .probe          = bcm2835_power_probe,
+       .driver = {
+               .name = "bcm2835-power",
+       },
+};
+module_platform_driver(bcm2835_power_driver);
+
+MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
+MODULE_DESCRIPTION("Driver for Broadcom BCM2835 PM power domains and reset");
diff --git a/drivers/genpd/bcm/bcm63xx-power.c b/drivers/genpd/bcm/bcm63xx-power.c
new file mode 100644 (file)
index 0000000..aa72e13
--- /dev/null
@@ -0,0 +1,376 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * BCM63xx Power Domain Controller Driver
+ *
+ * Copyright (C) 2020 Álvaro Fernández Rojas <noltari@gmail.com>
+ */
+
+#include <dt-bindings/soc/bcm6318-pm.h>
+#include <dt-bindings/soc/bcm6328-pm.h>
+#include <dt-bindings/soc/bcm6362-pm.h>
+#include <dt-bindings/soc/bcm63268-pm.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+struct bcm63xx_power_dev {
+       struct generic_pm_domain genpd;
+       struct bcm63xx_power *power;
+       uint32_t mask;
+};
+
+struct bcm63xx_power {
+       void __iomem *base;
+       spinlock_t lock;
+       struct bcm63xx_power_dev *dev;
+       struct genpd_onecell_data genpd_data;
+       struct generic_pm_domain **genpd;
+};
+
+struct bcm63xx_power_data {
+       const char * const name;
+       uint8_t bit;
+       unsigned int flags;
+};
+
+static int bcm63xx_power_get_state(struct bcm63xx_power_dev *pmd, bool *is_on)
+{
+       struct bcm63xx_power *power = pmd->power;
+
+       if (!pmd->mask) {
+               *is_on = false;
+               return -EINVAL;
+       }
+
+       *is_on = !(__raw_readl(power->base) & pmd->mask);
+
+       return 0;
+}
+
+static int bcm63xx_power_set_state(struct bcm63xx_power_dev *pmd, bool on)
+{
+       struct bcm63xx_power *power = pmd->power;
+       unsigned long flags;
+       uint32_t val;
+
+       if (!pmd->mask)
+               return -EINVAL;
+
+       spin_lock_irqsave(&power->lock, flags);
+       val = __raw_readl(power->base);
+       if (on)
+               val &= ~pmd->mask;
+       else
+               val |= pmd->mask;
+       __raw_writel(val, power->base);
+       spin_unlock_irqrestore(&power->lock, flags);
+
+       return 0;
+}
+
+static int bcm63xx_power_on(struct generic_pm_domain *genpd)
+{
+       struct bcm63xx_power_dev *pmd = container_of(genpd,
+               struct bcm63xx_power_dev, genpd);
+
+       return bcm63xx_power_set_state(pmd, true);
+}
+
+static int bcm63xx_power_off(struct generic_pm_domain *genpd)
+{
+       struct bcm63xx_power_dev *pmd = container_of(genpd,
+               struct bcm63xx_power_dev, genpd);
+
+       return bcm63xx_power_set_state(pmd, false);
+}
+
+static int bcm63xx_power_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       const struct bcm63xx_power_data *entry, *table;
+       struct bcm63xx_power *power;
+       unsigned int ndom;
+       uint8_t max_bit = 0;
+       int ret;
+
+       power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL);
+       if (!power)
+               return -ENOMEM;
+
+       power->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(power->base))
+               return PTR_ERR(power->base);
+
+       table = of_device_get_match_data(dev);
+       if (!table)
+               return -EINVAL;
+
+       power->genpd_data.num_domains = 0;
+       ndom = 0;
+       for (entry = table; entry->name; entry++) {
+               max_bit = max(max_bit, entry->bit);
+               ndom++;
+       }
+
+       if (!ndom)
+               return -ENODEV;
+
+       power->genpd_data.num_domains = max_bit + 1;
+
+       power->dev = devm_kcalloc(dev, power->genpd_data.num_domains,
+                                 sizeof(struct bcm63xx_power_dev),
+                                 GFP_KERNEL);
+       if (!power->dev)
+               return -ENOMEM;
+
+       power->genpd = devm_kcalloc(dev, power->genpd_data.num_domains,
+                                   sizeof(struct generic_pm_domain *),
+                                   GFP_KERNEL);
+       if (!power->genpd)
+               return -ENOMEM;
+
+       power->genpd_data.domains = power->genpd;
+
+       ndom = 0;
+       for (entry = table; entry->name; entry++) {
+               struct bcm63xx_power_dev *pmd = &power->dev[ndom];
+               bool is_on;
+
+               pmd->power = power;
+               pmd->mask = BIT(entry->bit);
+               pmd->genpd.name = entry->name;
+               pmd->genpd.flags = entry->flags;
+
+               ret = bcm63xx_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 = bcm63xx_power_on;
+               pmd->genpd.power_off = bcm63xx_power_off;
+
+               pm_genpd_init(&pmd->genpd, NULL, !is_on);
+               power->genpd[entry->bit] = &pmd->genpd;
+
+               ndom++;
+       }
+
+       spin_lock_init(&power->lock);
+
+       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", ndom);
+
+       return 0;
+}
+
+static const struct bcm63xx_power_data bcm6318_power_domains[] = {
+       {
+               .name = "pcie",
+               .bit = BCM6318_POWER_DOMAIN_PCIE,
+       }, {
+               .name = "usb",
+               .bit = BCM6318_POWER_DOMAIN_USB,
+       }, {
+               .name = "ephy0",
+               .bit = BCM6318_POWER_DOMAIN_EPHY0,
+       }, {
+               .name = "ephy1",
+               .bit = BCM6318_POWER_DOMAIN_EPHY1,
+       }, {
+               .name = "ephy2",
+               .bit = BCM6318_POWER_DOMAIN_EPHY2,
+       }, {
+               .name = "ephy3",
+               .bit = BCM6318_POWER_DOMAIN_EPHY3,
+       }, {
+               .name = "ldo2p5",
+               .bit = BCM6318_POWER_DOMAIN_LDO2P5,
+               .flags = GENPD_FLAG_ALWAYS_ON,
+       }, {
+               .name = "ldo2p9",
+               .bit = BCM6318_POWER_DOMAIN_LDO2P9,
+               .flags = GENPD_FLAG_ALWAYS_ON,
+       }, {
+               .name = "sw1p0",
+               .bit = BCM6318_POWER_DOMAIN_SW1P0,
+               .flags = GENPD_FLAG_ALWAYS_ON,
+       }, {
+               .name = "pad",
+               .bit = BCM6318_POWER_DOMAIN_PAD,
+               .flags = GENPD_FLAG_ALWAYS_ON,
+       }, {
+               /* sentinel */
+       },
+};
+
+static const struct bcm63xx_power_data bcm6328_power_domains[] = {
+       {
+               .name = "adsl2-mips",
+               .bit = BCM6328_POWER_DOMAIN_ADSL2_MIPS,
+       }, {
+               .name = "adsl2-phy",
+               .bit = BCM6328_POWER_DOMAIN_ADSL2_PHY,
+       }, {
+               .name = "adsl2-afe",
+               .bit = BCM6328_POWER_DOMAIN_ADSL2_AFE,
+       }, {
+               .name = "sar",
+               .bit = BCM6328_POWER_DOMAIN_SAR,
+       }, {
+               .name = "pcm",
+               .bit = BCM6328_POWER_DOMAIN_PCM,
+       }, {
+               .name = "usbd",
+               .bit = BCM6328_POWER_DOMAIN_USBD,
+       }, {
+               .name = "usbh",
+               .bit = BCM6328_POWER_DOMAIN_USBH,
+       }, {
+               .name = "pcie",
+               .bit = BCM6328_POWER_DOMAIN_PCIE,
+       }, {
+               .name = "robosw",
+               .bit = BCM6328_POWER_DOMAIN_ROBOSW,
+       }, {
+               .name = "ephy",
+               .bit = BCM6328_POWER_DOMAIN_EPHY,
+       }, {
+               /* sentinel */
+       },
+};
+
+static const struct bcm63xx_power_data bcm6362_power_domains[] = {
+       {
+               .name = "sar",
+               .bit = BCM6362_POWER_DOMAIN_SAR,
+       }, {
+               .name = "ipsec",
+               .bit = BCM6362_POWER_DOMAIN_IPSEC,
+       }, {
+               .name = "mips",
+               .bit = BCM6362_POWER_DOMAIN_MIPS,
+               .flags = GENPD_FLAG_ALWAYS_ON,
+       }, {
+               .name = "dect",
+               .bit = BCM6362_POWER_DOMAIN_DECT,
+       }, {
+               .name = "usbh",
+               .bit = BCM6362_POWER_DOMAIN_USBH,
+       }, {
+               .name = "usbd",
+               .bit = BCM6362_POWER_DOMAIN_USBD,
+       }, {
+               .name = "robosw",
+               .bit = BCM6362_POWER_DOMAIN_ROBOSW,
+       }, {
+               .name = "pcm",
+               .bit = BCM6362_POWER_DOMAIN_PCM,
+       }, {
+               .name = "periph",
+               .bit = BCM6362_POWER_DOMAIN_PERIPH,
+               .flags = GENPD_FLAG_ALWAYS_ON,
+       }, {
+               .name = "adsl-phy",
+               .bit = BCM6362_POWER_DOMAIN_ADSL_PHY,
+       }, {
+               .name = "gmii-pads",
+               .bit = BCM6362_POWER_DOMAIN_GMII_PADS,
+       }, {
+               .name = "fap",
+               .bit = BCM6362_POWER_DOMAIN_FAP,
+       }, {
+               .name = "pcie",
+               .bit = BCM6362_POWER_DOMAIN_PCIE,
+       }, {
+               .name = "wlan-pads",
+               .bit = BCM6362_POWER_DOMAIN_WLAN_PADS,
+       }, {
+               /* sentinel */
+       },
+};
+
+static const struct bcm63xx_power_data bcm63268_power_domains[] = {
+       {
+               .name = "sar",
+               .bit = BCM63268_POWER_DOMAIN_SAR,
+       }, {
+               .name = "ipsec",
+               .bit = BCM63268_POWER_DOMAIN_IPSEC,
+       }, {
+               .name = "mips",
+               .bit = BCM63268_POWER_DOMAIN_MIPS,
+               .flags = GENPD_FLAG_ALWAYS_ON,
+       }, {
+               .name = "dect",
+               .bit = BCM63268_POWER_DOMAIN_DECT,
+       }, {
+               .name = "usbh",
+               .bit = BCM63268_POWER_DOMAIN_USBH,
+       }, {
+               .name = "usbd",
+               .bit = BCM63268_POWER_DOMAIN_USBD,
+       }, {
+               .name = "robosw",
+               .bit = BCM63268_POWER_DOMAIN_ROBOSW,
+       }, {
+               .name = "pcm",
+               .bit = BCM63268_POWER_DOMAIN_PCM,
+       }, {
+               .name = "periph",
+               .bit = BCM63268_POWER_DOMAIN_PERIPH,
+               .flags = GENPD_FLAG_ALWAYS_ON,
+       }, {
+               .name = "vdsl-phy",
+               .bit = BCM63268_POWER_DOMAIN_VDSL_PHY,
+       }, {
+               .name = "vdsl-mips",
+               .bit = BCM63268_POWER_DOMAIN_VDSL_MIPS,
+       }, {
+               .name = "fap",
+               .bit = BCM63268_POWER_DOMAIN_FAP,
+       }, {
+               .name = "pcie",
+               .bit = BCM63268_POWER_DOMAIN_PCIE,
+       }, {
+               .name = "wlan-pads",
+               .bit = BCM63268_POWER_DOMAIN_WLAN_PADS,
+       }, {
+               /* sentinel */
+       },
+};
+
+static const struct of_device_id bcm63xx_power_of_match[] = {
+       {
+               .compatible = "brcm,bcm6318-power-controller",
+               .data = &bcm6318_power_domains,
+       }, {
+               .compatible = "brcm,bcm6328-power-controller",
+               .data = &bcm6328_power_domains,
+       }, {
+               .compatible = "brcm,bcm6362-power-controller",
+               .data = &bcm6362_power_domains,
+       }, {
+               .compatible = "brcm,bcm63268-power-controller",
+               .data = &bcm63268_power_domains,
+       }, {
+               /* sentinel */
+       }
+};
+
+static struct platform_driver bcm63xx_power_driver = {
+       .driver = {
+               .name = "bcm63xx-power-controller",
+               .of_match_table = bcm63xx_power_of_match,
+       },
+       .probe  = bcm63xx_power_probe,
+};
+builtin_platform_driver(bcm63xx_power_driver);
diff --git a/drivers/genpd/bcm/raspberrypi-power.c b/drivers/genpd/bcm/raspberrypi-power.c
new file mode 100644 (file)
index 0000000..58175af
--- /dev/null
@@ -0,0 +1,245 @@
+// SPDX-License-Identifier: GPL-2.0
+/* (C) 2015 Pengutronix, Alexander Aring <aar@pengutronix.de>
+ *
+ * Authors:
+ * Alexander Aring <aar@pengutronix.de>
+ * Eric Anholt <eric@anholt.net>
+ */
+
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <dt-bindings/power/raspberrypi-power.h>
+#include <soc/bcm2835/raspberrypi-firmware.h>
+
+/*
+ * Firmware indices for the old power domains interface.  Only a few
+ * of them were actually implemented.
+ */
+#define RPI_OLD_POWER_DOMAIN_USB               3
+#define RPI_OLD_POWER_DOMAIN_V3D               10
+
+struct rpi_power_domain {
+       u32 domain;
+       bool enabled;
+       bool old_interface;
+       struct generic_pm_domain base;
+       struct rpi_firmware *fw;
+};
+
+struct rpi_power_domains {
+       bool has_new_interface;
+       struct genpd_onecell_data xlate;
+       struct rpi_firmware *fw;
+       struct rpi_power_domain domains[RPI_POWER_DOMAIN_COUNT];
+};
+
+/*
+ * Packet definition used by RPI_FIRMWARE_SET_POWER_STATE and
+ * RPI_FIRMWARE_SET_DOMAIN_STATE
+ */
+struct rpi_power_domain_packet {
+       u32 domain;
+       u32 on;
+};
+
+/*
+ * Asks the firmware to enable or disable power on a specific power
+ * domain.
+ */
+static int rpi_firmware_set_power(struct rpi_power_domain *rpi_domain, bool on)
+{
+       struct rpi_power_domain_packet packet;
+
+       packet.domain = rpi_domain->domain;
+       packet.on = on;
+       return rpi_firmware_property(rpi_domain->fw,
+                                    rpi_domain->old_interface ?
+                                    RPI_FIRMWARE_SET_POWER_STATE :
+                                    RPI_FIRMWARE_SET_DOMAIN_STATE,
+                                    &packet, sizeof(packet));
+}
+
+static int rpi_domain_off(struct generic_pm_domain *domain)
+{
+       struct rpi_power_domain *rpi_domain =
+               container_of(domain, struct rpi_power_domain, base);
+
+       return rpi_firmware_set_power(rpi_domain, false);
+}
+
+static int rpi_domain_on(struct generic_pm_domain *domain)
+{
+       struct rpi_power_domain *rpi_domain =
+               container_of(domain, struct rpi_power_domain, base);
+
+       return rpi_firmware_set_power(rpi_domain, true);
+}
+
+static void rpi_common_init_power_domain(struct rpi_power_domains *rpi_domains,
+                                        int xlate_index, const char *name)
+{
+       struct rpi_power_domain *dom = &rpi_domains->domains[xlate_index];
+
+       dom->fw = rpi_domains->fw;
+
+       dom->base.name = name;
+       dom->base.power_on = rpi_domain_on;
+       dom->base.power_off = rpi_domain_off;
+
+       /*
+        * Treat all power domains as off at boot.
+        *
+        * The firmware itself may be keeping some domains on, but
+        * from Linux's perspective all we control is the refcounts
+        * that we give to the firmware, and we can't ask the firmware
+        * to turn off something that we haven't ourselves turned on.
+        */
+       pm_genpd_init(&dom->base, NULL, true);
+
+       rpi_domains->xlate.domains[xlate_index] = &dom->base;
+}
+
+static void rpi_init_power_domain(struct rpi_power_domains *rpi_domains,
+                                 int xlate_index, const char *name)
+{
+       struct rpi_power_domain *dom = &rpi_domains->domains[xlate_index];
+
+       if (!rpi_domains->has_new_interface)
+               return;
+
+       /* The DT binding index is the firmware's domain index minus one. */
+       dom->domain = xlate_index + 1;
+
+       rpi_common_init_power_domain(rpi_domains, xlate_index, name);
+}
+
+static void rpi_init_old_power_domain(struct rpi_power_domains *rpi_domains,
+                                     int xlate_index, int domain,
+                                     const char *name)
+{
+       struct rpi_power_domain *dom = &rpi_domains->domains[xlate_index];
+
+       dom->old_interface = true;
+       dom->domain = domain;
+
+       rpi_common_init_power_domain(rpi_domains, xlate_index, name);
+}
+
+/*
+ * Detects whether the firmware supports the new power domains interface.
+ *
+ * The firmware doesn't actually return an error on an unknown tag,
+ * and just skips over it, so we do the detection by putting an
+ * unexpected value in the return field and checking if it was
+ * unchanged.
+ */
+static bool
+rpi_has_new_domain_support(struct rpi_power_domains *rpi_domains)
+{
+       struct rpi_power_domain_packet packet;
+       int ret;
+
+       packet.domain = RPI_POWER_DOMAIN_ARM;
+       packet.on = ~0;
+
+       ret = rpi_firmware_property(rpi_domains->fw,
+                                   RPI_FIRMWARE_GET_DOMAIN_STATE,
+                                   &packet, sizeof(packet));
+
+       return ret == 0 && packet.on != ~0;
+}
+
+static int rpi_power_probe(struct platform_device *pdev)
+{
+       struct device_node *fw_np;
+       struct device *dev = &pdev->dev;
+       struct rpi_power_domains *rpi_domains;
+
+       rpi_domains = devm_kzalloc(dev, sizeof(*rpi_domains), GFP_KERNEL);
+       if (!rpi_domains)
+               return -ENOMEM;
+
+       rpi_domains->xlate.domains =
+               devm_kcalloc(dev,
+                            RPI_POWER_DOMAIN_COUNT,
+                            sizeof(*rpi_domains->xlate.domains),
+                            GFP_KERNEL);
+       if (!rpi_domains->xlate.domains)
+               return -ENOMEM;
+
+       rpi_domains->xlate.num_domains = RPI_POWER_DOMAIN_COUNT;
+
+       fw_np = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
+       if (!fw_np) {
+               dev_err(&pdev->dev, "no firmware node\n");
+               return -ENODEV;
+       }
+
+       rpi_domains->fw = devm_rpi_firmware_get(&pdev->dev, fw_np);
+       of_node_put(fw_np);
+       if (!rpi_domains->fw)
+               return -EPROBE_DEFER;
+
+       rpi_domains->has_new_interface =
+               rpi_has_new_domain_support(rpi_domains);
+
+       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_I2C0, "I2C0");
+       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_I2C1, "I2C1");
+       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_I2C2, "I2C2");
+       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_VIDEO_SCALER,
+                             "VIDEO_SCALER");
+       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_VPU1, "VPU1");
+       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_HDMI, "HDMI");
+
+       /*
+        * Use the old firmware interface for USB power, so that we
+        * can turn it on even if the firmware hasn't been updated.
+        */
+       rpi_init_old_power_domain(rpi_domains, RPI_POWER_DOMAIN_USB,
+                                 RPI_OLD_POWER_DOMAIN_USB, "USB");
+
+       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_VEC, "VEC");
+       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_JPEG, "JPEG");
+       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_H264, "H264");
+       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_V3D, "V3D");
+       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_ISP, "ISP");
+       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_UNICAM0, "UNICAM0");
+       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_UNICAM1, "UNICAM1");
+       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CCP2RX, "CCP2RX");
+       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CSI2, "CSI2");
+       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CPI, "CPI");
+       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_DSI0, "DSI0");
+       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_DSI1, "DSI1");
+       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_TRANSPOSER,
+                             "TRANSPOSER");
+       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CCP2TX, "CCP2TX");
+       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CDP, "CDP");
+       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_ARM, "ARM");
+
+       of_genpd_add_provider_onecell(dev->of_node, &rpi_domains->xlate);
+
+       platform_set_drvdata(pdev, rpi_domains);
+
+       return 0;
+}
+
+static const struct of_device_id rpi_power_of_match[] = {
+       { .compatible = "raspberrypi,bcm2835-power", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, rpi_power_of_match);
+
+static struct platform_driver rpi_power_driver = {
+       .driver = {
+               .name = "raspberrypi-power",
+               .of_match_table = rpi_power_of_match,
+       },
+       .probe          = rpi_power_probe,
+};
+builtin_platform_driver(rpi_power_driver);
+
+MODULE_AUTHOR("Alexander Aring <aar@pengutronix.de>");
+MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
+MODULE_DESCRIPTION("Raspberry Pi power domain driver");
index 24f92a6e882afcc5505f53bc0205befa0d382c15..f96906795fa6dd69a9e6c0ddd988ce2c36fbbbd8 100644 (file)
@@ -42,7 +42,27 @@ config SOC_BRCMSTB
 
          If unsure, say N.
 
-source "drivers/soc/bcm/bcm63xx/Kconfig"
+config BCM_PMB
+       bool "Broadcom PMB (Power Management Bus) driver"
+       depends on ARCH_BCMBCA || (COMPILE_TEST && OF)
+       default ARCH_BCMBCA
+       select PM_GENERIC_DOMAINS if PM
+       help
+         This enables support for the Broadcom's PMB (Power Management Bus) that
+         is used for disabling and enabling SoC devices.
+
+if SOC_BCM63XX
+
+config BCM63XX_POWER
+       bool "BCM63xx power domain driver"
+       depends on BMIPS_GENERIC || (COMPILE_TEST && OF)
+       select PM_GENERIC_DOMAINS if PM
+       help
+         This enables support for the BCM63xx power domains controller on
+         BCM6318, BCM6328, BCM6362 and BCM63268 SoCs.
+
+endif # SOC_BCM63XX
+
 source "drivers/soc/bcm/brcmstb/Kconfig"
 
 endmenu
index 0f0efa28d92b7fb6f3bdd9bf00506396113c8497..32424b1032c7ba10be5a7898db9da8c48aa65649 100644 (file)
@@ -1,5 +1,2 @@
 # SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_BCM2835_POWER)    += bcm2835-power.o
-obj-$(CONFIG_RASPBERRYPI_POWER)        += raspberrypi-power.o
-obj-y                          += bcm63xx/
 obj-$(CONFIG_SOC_BRCMSTB)      += brcmstb/
diff --git a/drivers/soc/bcm/bcm2835-power.c b/drivers/soc/bcm/bcm2835-power.c
deleted file mode 100644 (file)
index 1a179d4..0000000
+++ /dev/null
@@ -1,713 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Power domain driver for Broadcom BCM2835
- *
- * Copyright (C) 2018 Broadcom
- */
-
-#include <dt-bindings/soc/bcm2835-pm.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/mfd/bcm2835-pm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/pm_domain.h>
-#include <linux/reset-controller.h>
-#include <linux/types.h>
-
-#define PM_GNRIC                        0x00
-#define PM_AUDIO                        0x04
-#define PM_STATUS                       0x18
-#define PM_RSTC                                0x1c
-#define PM_RSTS                                0x20
-#define PM_WDOG                                0x24
-#define PM_PADS0                       0x28
-#define PM_PADS2                       0x2c
-#define PM_PADS3                       0x30
-#define PM_PADS4                       0x34
-#define PM_PADS5                       0x38
-#define PM_PADS6                       0x3c
-#define PM_CAM0                                0x44
-#define PM_CAM0_LDOHPEN                        BIT(2)
-#define PM_CAM0_LDOLPEN                        BIT(1)
-#define PM_CAM0_CTRLEN                 BIT(0)
-
-#define PM_CAM1                                0x48
-#define PM_CAM1_LDOHPEN                        BIT(2)
-#define PM_CAM1_LDOLPEN                        BIT(1)
-#define PM_CAM1_CTRLEN                 BIT(0)
-
-#define PM_CCP2TX                      0x4c
-#define PM_CCP2TX_LDOEN                        BIT(1)
-#define PM_CCP2TX_CTRLEN               BIT(0)
-
-#define PM_DSI0                                0x50
-#define PM_DSI0_LDOHPEN                        BIT(2)
-#define PM_DSI0_LDOLPEN                        BIT(1)
-#define PM_DSI0_CTRLEN                 BIT(0)
-
-#define PM_DSI1                                0x54
-#define PM_DSI1_LDOHPEN                        BIT(2)
-#define PM_DSI1_LDOLPEN                        BIT(1)
-#define PM_DSI1_CTRLEN                 BIT(0)
-
-#define PM_HDMI                                0x58
-#define PM_HDMI_RSTDR                  BIT(19)
-#define PM_HDMI_LDOPD                  BIT(1)
-#define PM_HDMI_CTRLEN                 BIT(0)
-
-#define PM_USB                         0x5c
-/* The power gates must be enabled with this bit before enabling the LDO in the
- * USB block.
- */
-#define PM_USB_CTRLEN                  BIT(0)
-
-#define PM_PXLDO                       0x60
-#define PM_PXBG                                0x64
-#define PM_DFT                         0x68
-#define PM_SMPS                                0x6c
-#define PM_XOSC                                0x70
-#define PM_SPAREW                      0x74
-#define PM_SPARER                      0x78
-#define PM_AVS_RSTDR                   0x7c
-#define PM_AVS_STAT                    0x80
-#define PM_AVS_EVENT                   0x84
-#define PM_AVS_INTEN                   0x88
-#define PM_DUMMY                       0xfc
-
-#define PM_IMAGE                       0x108
-#define PM_GRAFX                       0x10c
-#define PM_PROC                                0x110
-#define PM_ENAB                                BIT(12)
-#define PM_ISPRSTN                     BIT(8)
-#define PM_H264RSTN                    BIT(7)
-#define PM_PERIRSTN                    BIT(6)
-#define PM_V3DRSTN                     BIT(6)
-#define PM_ISFUNC                      BIT(5)
-#define PM_MRDONE                      BIT(4)
-#define PM_MEMREP                      BIT(3)
-#define PM_ISPOW                       BIT(2)
-#define PM_POWOK                       BIT(1)
-#define PM_POWUP                       BIT(0)
-#define PM_INRUSH_SHIFT                        13
-#define PM_INRUSH_3_5_MA               0
-#define PM_INRUSH_5_MA                 1
-#define PM_INRUSH_10_MA                        2
-#define PM_INRUSH_20_MA                        3
-#define PM_INRUSH_MASK                 (3 << PM_INRUSH_SHIFT)
-
-#define PM_PASSWORD                    0x5a000000
-
-#define PM_WDOG_TIME_SET               0x000fffff
-#define PM_RSTC_WRCFG_CLR              0xffffffcf
-#define PM_RSTS_HADWRH_SET             0x00000040
-#define PM_RSTC_WRCFG_SET              0x00000030
-#define PM_RSTC_WRCFG_FULL_RESET       0x00000020
-#define PM_RSTC_RESET                  0x00000102
-
-#define PM_READ(reg) readl(power->base + (reg))
-#define PM_WRITE(reg, val) writel(PM_PASSWORD | (val), power->base + (reg))
-
-#define ASB_BRDG_VERSION                0x00
-#define ASB_CPR_CTRL                    0x04
-
-#define ASB_V3D_S_CTRL                 0x08
-#define ASB_V3D_M_CTRL                 0x0c
-#define ASB_ISP_S_CTRL                 0x10
-#define ASB_ISP_M_CTRL                 0x14
-#define ASB_H264_S_CTRL                        0x18
-#define ASB_H264_M_CTRL                        0x1c
-
-#define ASB_REQ_STOP                    BIT(0)
-#define ASB_ACK                         BIT(1)
-#define ASB_EMPTY                       BIT(2)
-#define ASB_FULL                        BIT(3)
-
-#define ASB_AXI_BRDG_ID                        0x20
-
-#define BCM2835_BRDG_ID                        0x62726467
-
-struct bcm2835_power_domain {
-       struct generic_pm_domain base;
-       struct bcm2835_power *power;
-       u32 domain;
-       struct clk *clk;
-};
-
-struct bcm2835_power {
-       struct device           *dev;
-       /* PM registers. */
-       void __iomem            *base;
-       /* AXI Async bridge registers. */
-       void __iomem            *asb;
-       /* RPiVid bridge registers. */
-       void __iomem            *rpivid_asb;
-
-       struct genpd_onecell_data pd_xlate;
-       struct bcm2835_power_domain domains[BCM2835_POWER_DOMAIN_COUNT];
-       struct reset_controller_dev reset;
-};
-
-static int bcm2835_asb_control(struct bcm2835_power *power, u32 reg, bool enable)
-{
-       void __iomem *base = power->asb;
-       u64 start;
-       u32 val;
-
-       switch (reg) {
-       case 0:
-               return 0;
-       case ASB_V3D_S_CTRL:
-       case ASB_V3D_M_CTRL:
-               if (power->rpivid_asb)
-                       base = power->rpivid_asb;
-               break;
-       }
-
-       start = ktime_get_ns();
-
-       /* Enable the module's async AXI bridges. */
-       if (enable) {
-               val = readl(base + reg) & ~ASB_REQ_STOP;
-       } else {
-               val = readl(base + reg) | ASB_REQ_STOP;
-       }
-       writel(PM_PASSWORD | val, base + reg);
-
-       while (readl(base + reg) & ASB_ACK) {
-               cpu_relax();
-               if (ktime_get_ns() - start >= 1000)
-                       return -ETIMEDOUT;
-       }
-
-       return 0;
-}
-
-static int bcm2835_asb_enable(struct bcm2835_power *power, u32 reg)
-{
-       return bcm2835_asb_control(power, reg, true);
-}
-
-static int bcm2835_asb_disable(struct bcm2835_power *power, u32 reg)
-{
-       return bcm2835_asb_control(power, reg, false);
-}
-
-static int bcm2835_power_power_off(struct bcm2835_power_domain *pd, u32 pm_reg)
-{
-       struct bcm2835_power *power = pd->power;
-
-       /* We don't run this on BCM2711 */
-       if (power->rpivid_asb)
-               return 0;
-
-       /* Enable functional isolation */
-       PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISFUNC);
-
-       /* Enable electrical isolation */
-       PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISPOW);
-
-       /* Open the power switches. */
-       PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_POWUP);
-
-       return 0;
-}
-
-static int bcm2835_power_power_on(struct bcm2835_power_domain *pd, u32 pm_reg)
-{
-       struct bcm2835_power *power = pd->power;
-       struct device *dev = power->dev;
-       u64 start;
-       int ret;
-       int inrush;
-       bool powok;
-
-       /* We don't run this on BCM2711 */
-       if (power->rpivid_asb)
-               return 0;
-
-       /* If it was already powered on by the fw, leave it that way. */
-       if (PM_READ(pm_reg) & PM_POWUP)
-               return 0;
-
-       /* Enable power.  Allowing too much current at once may result
-        * in POWOK never getting set, so start low and ramp it up as
-        * necessary to succeed.
-        */
-       powok = false;
-       for (inrush = PM_INRUSH_3_5_MA; inrush <= PM_INRUSH_20_MA; inrush++) {
-               PM_WRITE(pm_reg,
-                        (PM_READ(pm_reg) & ~PM_INRUSH_MASK) |
-                        (inrush << PM_INRUSH_SHIFT) |
-                        PM_POWUP);
-
-               start = ktime_get_ns();
-               while (!(powok = !!(PM_READ(pm_reg) & PM_POWOK))) {
-                       cpu_relax();
-                       if (ktime_get_ns() - start >= 3000)
-                               break;
-               }
-       }
-       if (!powok) {
-               dev_err(dev, "Timeout waiting for %s power OK\n",
-                       pd->base.name);
-               ret = -ETIMEDOUT;
-               goto err_disable_powup;
-       }
-
-       /* Disable electrical isolation */
-       PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_ISPOW);
-
-       /* Repair memory */
-       PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_MEMREP);
-       start = ktime_get_ns();
-       while (!(PM_READ(pm_reg) & PM_MRDONE)) {
-               cpu_relax();
-               if (ktime_get_ns() - start >= 1000) {
-                       dev_err(dev, "Timeout waiting for %s memory repair\n",
-                               pd->base.name);
-                       ret = -ETIMEDOUT;
-                       goto err_disable_ispow;
-               }
-       }
-
-       /* Disable functional isolation */
-       PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_ISFUNC);
-
-       return 0;
-
-err_disable_ispow:
-       PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISPOW);
-err_disable_powup:
-       PM_WRITE(pm_reg, PM_READ(pm_reg) & ~(PM_POWUP | PM_INRUSH_MASK));
-       return ret;
-}
-
-static int bcm2835_asb_power_on(struct bcm2835_power_domain *pd,
-                               u32 pm_reg,
-                               u32 asb_m_reg,
-                               u32 asb_s_reg,
-                               u32 reset_flags)
-{
-       struct bcm2835_power *power = pd->power;
-       int ret;
-
-       ret = clk_prepare_enable(pd->clk);
-       if (ret) {
-               dev_err(power->dev, "Failed to enable clock for %s\n",
-                       pd->base.name);
-               return ret;
-       }
-
-       /* Wait 32 clocks for reset to propagate, 1 us will be enough */
-       udelay(1);
-
-       clk_disable_unprepare(pd->clk);
-
-       /* Deassert the resets. */
-       PM_WRITE(pm_reg, PM_READ(pm_reg) | reset_flags);
-
-       ret = clk_prepare_enable(pd->clk);
-       if (ret) {
-               dev_err(power->dev, "Failed to enable clock for %s\n",
-                       pd->base.name);
-               goto err_enable_resets;
-       }
-
-       ret = bcm2835_asb_enable(power, asb_m_reg);
-       if (ret) {
-               dev_err(power->dev, "Failed to enable ASB master for %s\n",
-                       pd->base.name);
-               goto err_disable_clk;
-       }
-       ret = bcm2835_asb_enable(power, asb_s_reg);
-       if (ret) {
-               dev_err(power->dev, "Failed to enable ASB slave for %s\n",
-                       pd->base.name);
-               goto err_disable_asb_master;
-       }
-
-       return 0;
-
-err_disable_asb_master:
-       bcm2835_asb_disable(power, asb_m_reg);
-err_disable_clk:
-       clk_disable_unprepare(pd->clk);
-err_enable_resets:
-       PM_WRITE(pm_reg, PM_READ(pm_reg) & ~reset_flags);
-       return ret;
-}
-
-static int bcm2835_asb_power_off(struct bcm2835_power_domain *pd,
-                                u32 pm_reg,
-                                u32 asb_m_reg,
-                                u32 asb_s_reg,
-                                u32 reset_flags)
-{
-       struct bcm2835_power *power = pd->power;
-       int ret;
-
-       ret = bcm2835_asb_disable(power, asb_s_reg);
-       if (ret) {
-               dev_warn(power->dev, "Failed to disable ASB slave for %s\n",
-                        pd->base.name);
-               return ret;
-       }
-       ret = bcm2835_asb_disable(power, asb_m_reg);
-       if (ret) {
-               dev_warn(power->dev, "Failed to disable ASB master for %s\n",
-                        pd->base.name);
-               bcm2835_asb_enable(power, asb_s_reg);
-               return ret;
-       }
-
-       clk_disable_unprepare(pd->clk);
-
-       /* Assert the resets. */
-       PM_WRITE(pm_reg, PM_READ(pm_reg) & ~reset_flags);
-
-       return 0;
-}
-
-static int bcm2835_power_pd_power_on(struct generic_pm_domain *domain)
-{
-       struct bcm2835_power_domain *pd =
-               container_of(domain, struct bcm2835_power_domain, base);
-       struct bcm2835_power *power = pd->power;
-
-       switch (pd->domain) {
-       case BCM2835_POWER_DOMAIN_GRAFX:
-               return bcm2835_power_power_on(pd, PM_GRAFX);
-
-       case BCM2835_POWER_DOMAIN_GRAFX_V3D:
-               return bcm2835_asb_power_on(pd, PM_GRAFX,
-                                           ASB_V3D_M_CTRL, ASB_V3D_S_CTRL,
-                                           PM_V3DRSTN);
-
-       case BCM2835_POWER_DOMAIN_IMAGE:
-               return bcm2835_power_power_on(pd, PM_IMAGE);
-
-       case BCM2835_POWER_DOMAIN_IMAGE_PERI:
-               return bcm2835_asb_power_on(pd, PM_IMAGE,
-                                           0, 0,
-                                           PM_PERIRSTN);
-
-       case BCM2835_POWER_DOMAIN_IMAGE_ISP:
-               return bcm2835_asb_power_on(pd, PM_IMAGE,
-                                           ASB_ISP_M_CTRL, ASB_ISP_S_CTRL,
-                                           PM_ISPRSTN);
-
-       case BCM2835_POWER_DOMAIN_IMAGE_H264:
-               return bcm2835_asb_power_on(pd, PM_IMAGE,
-                                           ASB_H264_M_CTRL, ASB_H264_S_CTRL,
-                                           PM_H264RSTN);
-
-       case BCM2835_POWER_DOMAIN_USB:
-               PM_WRITE(PM_USB, PM_USB_CTRLEN);
-               return 0;
-
-       case BCM2835_POWER_DOMAIN_DSI0:
-               PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN);
-               PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN | PM_DSI0_LDOHPEN);
-               return 0;
-
-       case BCM2835_POWER_DOMAIN_DSI1:
-               PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN);
-               PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN | PM_DSI1_LDOHPEN);
-               return 0;
-
-       case BCM2835_POWER_DOMAIN_CCP2TX:
-               PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN);
-               PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN | PM_CCP2TX_LDOEN);
-               return 0;
-
-       case BCM2835_POWER_DOMAIN_HDMI:
-               PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_RSTDR);
-               PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_CTRLEN);
-               PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_LDOPD);
-               usleep_range(100, 200);
-               PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_RSTDR);
-               return 0;
-
-       default:
-               dev_err(power->dev, "Invalid domain %d\n", pd->domain);
-               return -EINVAL;
-       }
-}
-
-static int bcm2835_power_pd_power_off(struct generic_pm_domain *domain)
-{
-       struct bcm2835_power_domain *pd =
-               container_of(domain, struct bcm2835_power_domain, base);
-       struct bcm2835_power *power = pd->power;
-
-       switch (pd->domain) {
-       case BCM2835_POWER_DOMAIN_GRAFX:
-               return bcm2835_power_power_off(pd, PM_GRAFX);
-
-       case BCM2835_POWER_DOMAIN_GRAFX_V3D:
-               return bcm2835_asb_power_off(pd, PM_GRAFX,
-                                            ASB_V3D_M_CTRL, ASB_V3D_S_CTRL,
-                                            PM_V3DRSTN);
-
-       case BCM2835_POWER_DOMAIN_IMAGE:
-               return bcm2835_power_power_off(pd, PM_IMAGE);
-
-       case BCM2835_POWER_DOMAIN_IMAGE_PERI:
-               return bcm2835_asb_power_off(pd, PM_IMAGE,
-                                            0, 0,
-                                            PM_PERIRSTN);
-
-       case BCM2835_POWER_DOMAIN_IMAGE_ISP:
-               return bcm2835_asb_power_off(pd, PM_IMAGE,
-                                            ASB_ISP_M_CTRL, ASB_ISP_S_CTRL,
-                                            PM_ISPRSTN);
-
-       case BCM2835_POWER_DOMAIN_IMAGE_H264:
-               return bcm2835_asb_power_off(pd, PM_IMAGE,
-                                            ASB_H264_M_CTRL, ASB_H264_S_CTRL,
-                                            PM_H264RSTN);
-
-       case BCM2835_POWER_DOMAIN_USB:
-               PM_WRITE(PM_USB, 0);
-               return 0;
-
-       case BCM2835_POWER_DOMAIN_DSI0:
-               PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN);
-               PM_WRITE(PM_DSI0, 0);
-               return 0;
-
-       case BCM2835_POWER_DOMAIN_DSI1:
-               PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN);
-               PM_WRITE(PM_DSI1, 0);
-               return 0;
-
-       case BCM2835_POWER_DOMAIN_CCP2TX:
-               PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN);
-               PM_WRITE(PM_CCP2TX, 0);
-               return 0;
-
-       case BCM2835_POWER_DOMAIN_HDMI:
-               PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_LDOPD);
-               PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_CTRLEN);
-               return 0;
-
-       default:
-               dev_err(power->dev, "Invalid domain %d\n", pd->domain);
-               return -EINVAL;
-       }
-}
-
-static int
-bcm2835_init_power_domain(struct bcm2835_power *power,
-                         int pd_xlate_index, const char *name)
-{
-       struct device *dev = power->dev;
-       struct bcm2835_power_domain *dom = &power->domains[pd_xlate_index];
-
-       dom->clk = devm_clk_get(dev->parent, name);
-       if (IS_ERR(dom->clk)) {
-               int ret = PTR_ERR(dom->clk);
-
-               if (ret == -EPROBE_DEFER)
-                       return ret;
-
-               /* Some domains don't have a clk, so make sure that we
-                * don't deref an error pointer later.
-                */
-               dom->clk = NULL;
-       }
-
-       dom->base.name = name;
-       dom->base.power_on = bcm2835_power_pd_power_on;
-       dom->base.power_off = bcm2835_power_pd_power_off;
-
-       dom->domain = pd_xlate_index;
-       dom->power = power;
-
-       /* XXX: on/off at boot? */
-       pm_genpd_init(&dom->base, NULL, true);
-
-       power->pd_xlate.domains[pd_xlate_index] = &dom->base;
-
-       return 0;
-}
-
-/** bcm2835_reset_reset - Resets a block that has a reset line in the
- * PM block.
- *
- * The consumer of the reset controller must have the power domain up
- * -- there's no reset ability with the power domain down.  To reset
- * the sub-block, we just disable its access to memory through the
- * ASB, reset, and re-enable.
- */
-static int bcm2835_reset_reset(struct reset_controller_dev *rcdev,
-                              unsigned long id)
-{
-       struct bcm2835_power *power = container_of(rcdev, struct bcm2835_power,
-                                                  reset);
-       struct bcm2835_power_domain *pd;
-       int ret;
-
-       switch (id) {
-       case BCM2835_RESET_V3D:
-               pd = &power->domains[BCM2835_POWER_DOMAIN_GRAFX_V3D];
-               break;
-       case BCM2835_RESET_H264:
-               pd = &power->domains[BCM2835_POWER_DOMAIN_IMAGE_H264];
-               break;
-       case BCM2835_RESET_ISP:
-               pd = &power->domains[BCM2835_POWER_DOMAIN_IMAGE_ISP];
-               break;
-       default:
-               dev_err(power->dev, "Bad reset id %ld\n", id);
-               return -EINVAL;
-       }
-
-       ret = bcm2835_power_pd_power_off(&pd->base);
-       if (ret)
-               return ret;
-
-       return bcm2835_power_pd_power_on(&pd->base);
-}
-
-static int bcm2835_reset_status(struct reset_controller_dev *rcdev,
-                               unsigned long id)
-{
-       struct bcm2835_power *power = container_of(rcdev, struct bcm2835_power,
-                                                  reset);
-
-       switch (id) {
-       case BCM2835_RESET_V3D:
-               return !PM_READ(PM_GRAFX & PM_V3DRSTN);
-       case BCM2835_RESET_H264:
-               return !PM_READ(PM_IMAGE & PM_H264RSTN);
-       case BCM2835_RESET_ISP:
-               return !PM_READ(PM_IMAGE & PM_ISPRSTN);
-       default:
-               return -EINVAL;
-       }
-}
-
-static const struct reset_control_ops bcm2835_reset_ops = {
-       .reset = bcm2835_reset_reset,
-       .status = bcm2835_reset_status,
-};
-
-static const char *const power_domain_names[] = {
-       [BCM2835_POWER_DOMAIN_GRAFX] = "grafx",
-       [BCM2835_POWER_DOMAIN_GRAFX_V3D] = "v3d",
-
-       [BCM2835_POWER_DOMAIN_IMAGE] = "image",
-       [BCM2835_POWER_DOMAIN_IMAGE_PERI] = "peri_image",
-       [BCM2835_POWER_DOMAIN_IMAGE_H264] = "h264",
-       [BCM2835_POWER_DOMAIN_IMAGE_ISP] = "isp",
-
-       [BCM2835_POWER_DOMAIN_USB] = "usb",
-       [BCM2835_POWER_DOMAIN_DSI0] = "dsi0",
-       [BCM2835_POWER_DOMAIN_DSI1] = "dsi1",
-       [BCM2835_POWER_DOMAIN_CAM0] = "cam0",
-       [BCM2835_POWER_DOMAIN_CAM1] = "cam1",
-       [BCM2835_POWER_DOMAIN_CCP2TX] = "ccp2tx",
-       [BCM2835_POWER_DOMAIN_HDMI] = "hdmi",
-};
-
-static int bcm2835_power_probe(struct platform_device *pdev)
-{
-       struct bcm2835_pm *pm = dev_get_drvdata(pdev->dev.parent);
-       struct device *dev = &pdev->dev;
-       struct bcm2835_power *power;
-       static const struct {
-               int parent, child;
-       } domain_deps[] = {
-               { BCM2835_POWER_DOMAIN_GRAFX, BCM2835_POWER_DOMAIN_GRAFX_V3D },
-               { BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_PERI },
-               { BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_H264 },
-               { BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_ISP },
-               { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_USB },
-               { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM0 },
-               { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM1 },
-       };
-       int ret = 0, i;
-       u32 id;
-
-       power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL);
-       if (!power)
-               return -ENOMEM;
-       platform_set_drvdata(pdev, power);
-
-       power->dev = dev;
-       power->base = pm->base;
-       power->asb = pm->asb;
-       power->rpivid_asb = pm->rpivid_asb;
-
-       id = readl(power->asb + ASB_AXI_BRDG_ID);
-       if (id != BCM2835_BRDG_ID /* "BRDG" */) {
-               dev_err(dev, "ASB register ID returned 0x%08x\n", id);
-               return -ENODEV;
-       }
-
-       if (power->rpivid_asb) {
-               id = readl(power->rpivid_asb + ASB_AXI_BRDG_ID);
-               if (id != BCM2835_BRDG_ID /* "BRDG" */) {
-                       dev_err(dev, "RPiVid ASB register ID returned 0x%08x\n",
-                                    id);
-                       return -ENODEV;
-               }
-       }
-
-       power->pd_xlate.domains = devm_kcalloc(dev,
-                                              ARRAY_SIZE(power_domain_names),
-                                              sizeof(*power->pd_xlate.domains),
-                                              GFP_KERNEL);
-       if (!power->pd_xlate.domains)
-               return -ENOMEM;
-
-       power->pd_xlate.num_domains = ARRAY_SIZE(power_domain_names);
-
-       for (i = 0; i < ARRAY_SIZE(power_domain_names); i++) {
-               ret = bcm2835_init_power_domain(power, i, power_domain_names[i]);
-               if (ret)
-                       goto fail;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(domain_deps); i++) {
-               pm_genpd_add_subdomain(&power->domains[domain_deps[i].parent].base,
-                                      &power->domains[domain_deps[i].child].base);
-       }
-
-       power->reset.owner = THIS_MODULE;
-       power->reset.nr_resets = BCM2835_RESET_COUNT;
-       power->reset.ops = &bcm2835_reset_ops;
-       power->reset.of_node = dev->parent->of_node;
-
-       ret = devm_reset_controller_register(dev, &power->reset);
-       if (ret)
-               goto fail;
-
-       of_genpd_add_provider_onecell(dev->parent->of_node, &power->pd_xlate);
-
-       dev_info(dev, "Broadcom BCM2835 power domains driver");
-       return 0;
-
-fail:
-       for (i = 0; i < ARRAY_SIZE(power_domain_names); i++) {
-               struct generic_pm_domain *dom = &power->domains[i].base;
-
-               if (dom->name)
-                       pm_genpd_remove(dom);
-       }
-       return ret;
-}
-
-static struct platform_driver bcm2835_power_driver = {
-       .probe          = bcm2835_power_probe,
-       .driver = {
-               .name = "bcm2835-power",
-       },
-};
-module_platform_driver(bcm2835_power_driver);
-
-MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
-MODULE_DESCRIPTION("Driver for Broadcom BCM2835 PM power domains and reset");
diff --git a/drivers/soc/bcm/bcm63xx/Kconfig b/drivers/soc/bcm/bcm63xx/Kconfig
deleted file mode 100644 (file)
index 355c344..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-if SOC_BCM63XX
-
-config BCM63XX_POWER
-       bool "BCM63xx power domain driver"
-       depends on BMIPS_GENERIC || (COMPILE_TEST && OF)
-       select PM_GENERIC_DOMAINS if PM
-       help
-         This enables support for the BCM63xx power domains controller on
-         BCM6318, BCM6328, BCM6362 and BCM63268 SoCs.
-
-endif # SOC_BCM63XX
-
-config BCM_PMB
-       bool "Broadcom PMB (Power Management Bus) driver"
-       depends on ARCH_BCMBCA || (COMPILE_TEST && OF)
-       default ARCH_BCMBCA
-       select PM_GENERIC_DOMAINS if PM
-       help
-         This enables support for the Broadcom's PMB (Power Management Bus) that
-         is used for disabling and enabling SoC devices.
diff --git a/drivers/soc/bcm/bcm63xx/Makefile b/drivers/soc/bcm/bcm63xx/Makefile
deleted file mode 100644 (file)
index 557eed3..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_BCM63XX_POWER) += bcm63xx-power.o
-obj-$(CONFIG_BCM_PMB)          += bcm-pmb.o
diff --git a/drivers/soc/bcm/bcm63xx/bcm-pmb.c b/drivers/soc/bcm/bcm63xx/bcm-pmb.c
deleted file mode 100644 (file)
index 9407cac..0000000
+++ /dev/null
@@ -1,364 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (c) 2013 Broadcom
- * Copyright (C) 2020 Rafał Miłecki <rafal@milecki.pl>
- */
-
-#include <dt-bindings/soc/bcm-pmb.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/pm_domain.h>
-#include <linux/reset/bcm63xx_pmb.h>
-
-#define BPCM_ID_REG                                    0x00
-#define BPCM_CAPABILITIES                              0x04
-#define  BPCM_CAP_NUM_ZONES                            0x000000ff
-#define  BPCM_CAP_SR_REG_BITS                          0x0000ff00
-#define  BPCM_CAP_PLLTYPE                              0x00030000
-#define  BPCM_CAP_UBUS                                 0x00080000
-#define BPCM_CONTROL                                   0x08
-#define BPCM_STATUS                                    0x0c
-#define BPCM_ROSC_CONTROL                              0x10
-#define BPCM_ROSC_THRESH_H                             0x14
-#define BPCM_ROSC_THRESHOLD_BCM6838                    0x14
-#define BPCM_ROSC_THRESH_S                             0x18
-#define BPCM_ROSC_COUNT_BCM6838                                0x18
-#define BPCM_ROSC_COUNT                                        0x1c
-#define BPCM_PWD_CONTROL_BCM6838                       0x1c
-#define BPCM_PWD_CONTROL                               0x20
-#define BPCM_SR_CONTROL_BCM6838                                0x20
-#define BPCM_PWD_ACCUM_CONTROL                         0x24
-#define BPCM_SR_CONTROL                                        0x28
-#define BPCM_GLOBAL_CONTROL                            0x2c
-#define BPCM_MISC_CONTROL                              0x30
-#define BPCM_MISC_CONTROL2                             0x34
-#define BPCM_SGPHY_CNTL                                        0x38
-#define BPCM_SGPHY_STATUS                              0x3c
-#define BPCM_ZONE0                                     0x40
-#define  BPCM_ZONE_CONTROL                             0x00
-#define   BPCM_ZONE_CONTROL_MANUAL_CLK_EN              0x00000001
-#define   BPCM_ZONE_CONTROL_MANUAL_RESET_CTL           0x00000002
-#define   BPCM_ZONE_CONTROL_FREQ_SCALE_USED            0x00000004      /* R/O */
-#define   BPCM_ZONE_CONTROL_DPG_CAPABLE                        0x00000008      /* R/O */
-#define   BPCM_ZONE_CONTROL_MANUAL_MEM_PWR             0x00000030
-#define   BPCM_ZONE_CONTROL_MANUAL_ISO_CTL             0x00000040
-#define   BPCM_ZONE_CONTROL_MANUAL_CTL                 0x00000080
-#define   BPCM_ZONE_CONTROL_DPG_CTL_EN                 0x00000100
-#define   BPCM_ZONE_CONTROL_PWR_DN_REQ                 0x00000200
-#define   BPCM_ZONE_CONTROL_PWR_UP_REQ                 0x00000400
-#define   BPCM_ZONE_CONTROL_MEM_PWR_CTL_EN             0x00000800
-#define   BPCM_ZONE_CONTROL_BLK_RESET_ASSERT           0x00001000
-#define   BPCM_ZONE_CONTROL_MEM_STBY                   0x00002000
-#define   BPCM_ZONE_CONTROL_RESERVED                   0x0007c000
-#define   BPCM_ZONE_CONTROL_PWR_CNTL_STATE             0x00f80000
-#define   BPCM_ZONE_CONTROL_FREQ_SCALAR_DYN_SEL                0x01000000      /* R/O */
-#define   BPCM_ZONE_CONTROL_PWR_OFF_STATE              0x02000000      /* R/O */
-#define   BPCM_ZONE_CONTROL_PWR_ON_STATE               0x04000000      /* R/O */
-#define   BPCM_ZONE_CONTROL_PWR_GOOD                   0x08000000      /* R/O */
-#define   BPCM_ZONE_CONTROL_DPG_PWR_STATE              0x10000000      /* R/O */
-#define   BPCM_ZONE_CONTROL_MEM_PWR_STATE              0x20000000      /* R/O */
-#define   BPCM_ZONE_CONTROL_ISO_STATE                  0x40000000      /* R/O */
-#define   BPCM_ZONE_CONTROL_RESET_STATE                        0x80000000      /* R/O */
-#define  BPCM_ZONE_CONFIG1                             0x04
-#define  BPCM_ZONE_CONFIG2                             0x08
-#define  BPCM_ZONE_FREQ_SCALAR_CONTROL                 0x0c
-#define  BPCM_ZONE_SIZE                                        0x10
-
-struct bcm_pmb {
-       struct device *dev;
-       void __iomem *base;
-       spinlock_t lock;
-       bool little_endian;
-       struct genpd_onecell_data genpd_onecell_data;
-};
-
-struct bcm_pmb_pd_data {
-       const char * const name;
-       int id;
-       u8 bus;
-       u8 device;
-};
-
-struct bcm_pmb_pm_domain {
-       struct bcm_pmb *pmb;
-       const struct bcm_pmb_pd_data *data;
-       struct generic_pm_domain genpd;
-};
-
-static int bcm_pmb_bpcm_read(struct bcm_pmb *pmb, int bus, u8 device,
-                            int offset, u32 *val)
-{
-       void __iomem *base = pmb->base + bus * 0x20;
-       unsigned long flags;
-       int err;
-
-       spin_lock_irqsave(&pmb->lock, flags);
-       err = bpcm_rd(base, device, offset, val);
-       spin_unlock_irqrestore(&pmb->lock, flags);
-
-       if (!err)
-               *val = pmb->little_endian ? le32_to_cpu(*val) : be32_to_cpu(*val);
-
-       return err;
-}
-
-static int bcm_pmb_bpcm_write(struct bcm_pmb *pmb, int bus, u8 device,
-                             int offset, u32 val)
-{
-       void __iomem *base = pmb->base + bus * 0x20;
-       unsigned long flags;
-       int err;
-
-       val = pmb->little_endian ? cpu_to_le32(val) : cpu_to_be32(val);
-
-       spin_lock_irqsave(&pmb->lock, flags);
-       err = bpcm_wr(base, device, offset, val);
-       spin_unlock_irqrestore(&pmb->lock, flags);
-
-       return err;
-}
-
-static int bcm_pmb_power_off_zone(struct bcm_pmb *pmb, int bus, u8 device,
-                                 int zone)
-{
-       int offset;
-       u32 val;
-       int err;
-
-       offset = BPCM_ZONE0 + zone * BPCM_ZONE_SIZE + BPCM_ZONE_CONTROL;
-
-       err = bcm_pmb_bpcm_read(pmb, bus, device, offset, &val);
-       if (err)
-               return err;
-
-       val |= BPCM_ZONE_CONTROL_PWR_DN_REQ;
-       val &= ~BPCM_ZONE_CONTROL_PWR_UP_REQ;
-
-       err = bcm_pmb_bpcm_write(pmb, bus, device, offset, val);
-
-       return err;
-}
-
-static int bcm_pmb_power_on_zone(struct bcm_pmb *pmb, int bus, u8 device,
-                                int zone)
-{
-       int offset;
-       u32 val;
-       int err;
-
-       offset = BPCM_ZONE0 + zone * BPCM_ZONE_SIZE + BPCM_ZONE_CONTROL;
-
-       err = bcm_pmb_bpcm_read(pmb, bus, device, offset, &val);
-       if (err)
-               return err;
-
-       if (!(val & BPCM_ZONE_CONTROL_PWR_ON_STATE)) {
-               val &= ~BPCM_ZONE_CONTROL_PWR_DN_REQ;
-               val |= BPCM_ZONE_CONTROL_DPG_CTL_EN;
-               val |= BPCM_ZONE_CONTROL_PWR_UP_REQ;
-               val |= BPCM_ZONE_CONTROL_MEM_PWR_CTL_EN;
-               val |= BPCM_ZONE_CONTROL_BLK_RESET_ASSERT;
-
-               err = bcm_pmb_bpcm_write(pmb, bus, device, offset, val);
-       }
-
-       return err;
-}
-
-static int bcm_pmb_power_off_device(struct bcm_pmb *pmb, int bus, u8 device)
-{
-       int offset;
-       u32 val;
-       int err;
-
-       /* Entire device can be powered off by powering off the 0th zone */
-       offset = BPCM_ZONE0 + BPCM_ZONE_CONTROL;
-
-       err = bcm_pmb_bpcm_read(pmb, bus, device, offset, &val);
-       if (err)
-               return err;
-
-       if (!(val & BPCM_ZONE_CONTROL_PWR_OFF_STATE)) {
-               val = BPCM_ZONE_CONTROL_PWR_DN_REQ;
-
-               err = bcm_pmb_bpcm_write(pmb, bus, device, offset, val);
-       }
-
-       return err;
-}
-
-static int bcm_pmb_power_on_device(struct bcm_pmb *pmb, int bus, u8 device)
-{
-       u32 val;
-       int err;
-       int i;
-
-       err = bcm_pmb_bpcm_read(pmb, bus, device, BPCM_CAPABILITIES, &val);
-       if (err)
-               return err;
-
-       for (i = 0; i < (val & BPCM_CAP_NUM_ZONES); i++) {
-               err = bcm_pmb_power_on_zone(pmb, bus, device, i);
-               if (err)
-                       return err;
-       }
-
-       return err;
-}
-
-static int bcm_pmb_power_on_sata(struct bcm_pmb *pmb, int bus, u8 device)
-{
-       int err;
-
-       err = bcm_pmb_power_on_zone(pmb, bus, device, 0);
-       if (err)
-               return err;
-
-       /* Does not apply to the BCM963158 */
-       err = bcm_pmb_bpcm_write(pmb, bus, device, BPCM_MISC_CONTROL, 0);
-       if (err)
-               return err;
-
-       err = bcm_pmb_bpcm_write(pmb, bus, device, BPCM_SR_CONTROL, 0xffffffff);
-       if (err)
-               return err;
-
-       err = bcm_pmb_bpcm_write(pmb, bus, device, BPCM_SR_CONTROL, 0);
-
-       return err;
-}
-
-static int bcm_pmb_power_on(struct generic_pm_domain *genpd)
-{
-       struct bcm_pmb_pm_domain *pd = container_of(genpd, struct bcm_pmb_pm_domain, genpd);
-       const struct bcm_pmb_pd_data *data = pd->data;
-       struct bcm_pmb *pmb = pd->pmb;
-
-       switch (data->id) {
-       case BCM_PMB_PCIE0:
-       case BCM_PMB_PCIE1:
-       case BCM_PMB_PCIE2:
-               return bcm_pmb_power_on_zone(pmb, data->bus, data->device, 0);
-       case BCM_PMB_HOST_USB:
-               return bcm_pmb_power_on_device(pmb, data->bus, data->device);
-       case BCM_PMB_SATA:
-               return bcm_pmb_power_on_sata(pmb, data->bus, data->device);
-       default:
-               dev_err(pmb->dev, "unsupported device id: %d\n", data->id);
-               return -EINVAL;
-       }
-}
-
-static int bcm_pmb_power_off(struct generic_pm_domain *genpd)
-{
-       struct bcm_pmb_pm_domain *pd = container_of(genpd, struct bcm_pmb_pm_domain, genpd);
-       const struct bcm_pmb_pd_data *data = pd->data;
-       struct bcm_pmb *pmb = pd->pmb;
-
-       switch (data->id) {
-       case BCM_PMB_PCIE0:
-       case BCM_PMB_PCIE1:
-       case BCM_PMB_PCIE2:
-               return bcm_pmb_power_off_zone(pmb, data->bus, data->device, 0);
-       case BCM_PMB_HOST_USB:
-               return bcm_pmb_power_off_device(pmb, data->bus, data->device);
-       default:
-               dev_err(pmb->dev, "unsupported device id: %d\n", data->id);
-               return -EINVAL;
-       }
-}
-
-static int bcm_pmb_probe(struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-       const struct bcm_pmb_pd_data *table;
-       const struct bcm_pmb_pd_data *e;
-       struct bcm_pmb *pmb;
-       int max_id;
-       int err;
-
-       pmb = devm_kzalloc(dev, sizeof(*pmb), GFP_KERNEL);
-       if (!pmb)
-               return -ENOMEM;
-
-       pmb->dev = dev;
-
-       pmb->base = devm_platform_ioremap_resource(pdev, 0);
-       if (IS_ERR(pmb->base))
-               return PTR_ERR(pmb->base);
-
-       spin_lock_init(&pmb->lock);
-
-       pmb->little_endian = !of_device_is_big_endian(dev->of_node);
-
-       table = of_device_get_match_data(dev);
-       if (!table)
-               return -EINVAL;
-
-       max_id = 0;
-       for (e = table; e->name; e++)
-               max_id = max(max_id, e->id);
-
-       pmb->genpd_onecell_data.num_domains = max_id + 1;
-       pmb->genpd_onecell_data.domains =
-               devm_kcalloc(dev, pmb->genpd_onecell_data.num_domains,
-                            sizeof(struct generic_pm_domain *), GFP_KERNEL);
-       if (!pmb->genpd_onecell_data.domains)
-               return -ENOMEM;
-
-       for (e = table; e->name; e++) {
-               struct bcm_pmb_pm_domain *pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
-
-               if (!pd)
-                       return -ENOMEM;
-
-               pd->pmb = pmb;
-               pd->data = e;
-               pd->genpd.name = e->name;
-               pd->genpd.power_on = bcm_pmb_power_on;
-               pd->genpd.power_off = bcm_pmb_power_off;
-
-               pm_genpd_init(&pd->genpd, NULL, true);
-               pmb->genpd_onecell_data.domains[e->id] = &pd->genpd;
-       }
-
-       err = of_genpd_add_provider_onecell(dev->of_node, &pmb->genpd_onecell_data);
-       if (err) {
-               dev_err(dev, "failed to add genpd provider: %d\n", err);
-               return err;
-       }
-
-       return 0;
-}
-
-static const struct bcm_pmb_pd_data bcm_pmb_bcm4908_data[] = {
-       { .name = "pcie2", .id = BCM_PMB_PCIE2, .bus = 0, .device = 2, },
-       { .name = "pcie0", .id = BCM_PMB_PCIE0, .bus = 1, .device = 14, },
-       { .name = "pcie1", .id = BCM_PMB_PCIE1, .bus = 1, .device = 15, },
-       { .name = "usb", .id = BCM_PMB_HOST_USB, .bus = 1, .device = 17, },
-       { },
-};
-
-static const struct bcm_pmb_pd_data bcm_pmb_bcm63138_data[] = {
-       { .name = "sata", .id = BCM_PMB_SATA, .bus = 0, .device = 3, },
-       { },
-};
-
-static const struct of_device_id bcm_pmb_of_match[] = {
-       { .compatible = "brcm,bcm4908-pmb", .data = &bcm_pmb_bcm4908_data, },
-       { .compatible = "brcm,bcm63138-pmb", .data = &bcm_pmb_bcm63138_data, },
-       { },
-};
-
-static struct platform_driver bcm_pmb_driver = {
-       .driver = {
-               .name = "bcm-pmb",
-               .of_match_table = bcm_pmb_of_match,
-       },
-       .probe  = bcm_pmb_probe,
-};
-
-builtin_platform_driver(bcm_pmb_driver);
diff --git a/drivers/soc/bcm/bcm63xx/bcm63xx-power.c b/drivers/soc/bcm/bcm63xx/bcm63xx-power.c
deleted file mode 100644 (file)
index aa72e13..0000000
+++ /dev/null
@@ -1,376 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * BCM63xx Power Domain Controller Driver
- *
- * Copyright (C) 2020 Álvaro Fernández Rojas <noltari@gmail.com>
- */
-
-#include <dt-bindings/soc/bcm6318-pm.h>
-#include <dt-bindings/soc/bcm6328-pm.h>
-#include <dt-bindings/soc/bcm6362-pm.h>
-#include <dt-bindings/soc/bcm63268-pm.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/pm_domain.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-
-struct bcm63xx_power_dev {
-       struct generic_pm_domain genpd;
-       struct bcm63xx_power *power;
-       uint32_t mask;
-};
-
-struct bcm63xx_power {
-       void __iomem *base;
-       spinlock_t lock;
-       struct bcm63xx_power_dev *dev;
-       struct genpd_onecell_data genpd_data;
-       struct generic_pm_domain **genpd;
-};
-
-struct bcm63xx_power_data {
-       const char * const name;
-       uint8_t bit;
-       unsigned int flags;
-};
-
-static int bcm63xx_power_get_state(struct bcm63xx_power_dev *pmd, bool *is_on)
-{
-       struct bcm63xx_power *power = pmd->power;
-
-       if (!pmd->mask) {
-               *is_on = false;
-               return -EINVAL;
-       }
-
-       *is_on = !(__raw_readl(power->base) & pmd->mask);
-
-       return 0;
-}
-
-static int bcm63xx_power_set_state(struct bcm63xx_power_dev *pmd, bool on)
-{
-       struct bcm63xx_power *power = pmd->power;
-       unsigned long flags;
-       uint32_t val;
-
-       if (!pmd->mask)
-               return -EINVAL;
-
-       spin_lock_irqsave(&power->lock, flags);
-       val = __raw_readl(power->base);
-       if (on)
-               val &= ~pmd->mask;
-       else
-               val |= pmd->mask;
-       __raw_writel(val, power->base);
-       spin_unlock_irqrestore(&power->lock, flags);
-
-       return 0;
-}
-
-static int bcm63xx_power_on(struct generic_pm_domain *genpd)
-{
-       struct bcm63xx_power_dev *pmd = container_of(genpd,
-               struct bcm63xx_power_dev, genpd);
-
-       return bcm63xx_power_set_state(pmd, true);
-}
-
-static int bcm63xx_power_off(struct generic_pm_domain *genpd)
-{
-       struct bcm63xx_power_dev *pmd = container_of(genpd,
-               struct bcm63xx_power_dev, genpd);
-
-       return bcm63xx_power_set_state(pmd, false);
-}
-
-static int bcm63xx_power_probe(struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-       struct device_node *np = dev->of_node;
-       const struct bcm63xx_power_data *entry, *table;
-       struct bcm63xx_power *power;
-       unsigned int ndom;
-       uint8_t max_bit = 0;
-       int ret;
-
-       power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL);
-       if (!power)
-               return -ENOMEM;
-
-       power->base = devm_platform_ioremap_resource(pdev, 0);
-       if (IS_ERR(power->base))
-               return PTR_ERR(power->base);
-
-       table = of_device_get_match_data(dev);
-       if (!table)
-               return -EINVAL;
-
-       power->genpd_data.num_domains = 0;
-       ndom = 0;
-       for (entry = table; entry->name; entry++) {
-               max_bit = max(max_bit, entry->bit);
-               ndom++;
-       }
-
-       if (!ndom)
-               return -ENODEV;
-
-       power->genpd_data.num_domains = max_bit + 1;
-
-       power->dev = devm_kcalloc(dev, power->genpd_data.num_domains,
-                                 sizeof(struct bcm63xx_power_dev),
-                                 GFP_KERNEL);
-       if (!power->dev)
-               return -ENOMEM;
-
-       power->genpd = devm_kcalloc(dev, power->genpd_data.num_domains,
-                                   sizeof(struct generic_pm_domain *),
-                                   GFP_KERNEL);
-       if (!power->genpd)
-               return -ENOMEM;
-
-       power->genpd_data.domains = power->genpd;
-
-       ndom = 0;
-       for (entry = table; entry->name; entry++) {
-               struct bcm63xx_power_dev *pmd = &power->dev[ndom];
-               bool is_on;
-
-               pmd->power = power;
-               pmd->mask = BIT(entry->bit);
-               pmd->genpd.name = entry->name;
-               pmd->genpd.flags = entry->flags;
-
-               ret = bcm63xx_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 = bcm63xx_power_on;
-               pmd->genpd.power_off = bcm63xx_power_off;
-
-               pm_genpd_init(&pmd->genpd, NULL, !is_on);
-               power->genpd[entry->bit] = &pmd->genpd;
-
-               ndom++;
-       }
-
-       spin_lock_init(&power->lock);
-
-       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", ndom);
-
-       return 0;
-}
-
-static const struct bcm63xx_power_data bcm6318_power_domains[] = {
-       {
-               .name = "pcie",
-               .bit = BCM6318_POWER_DOMAIN_PCIE,
-       }, {
-               .name = "usb",
-               .bit = BCM6318_POWER_DOMAIN_USB,
-       }, {
-               .name = "ephy0",
-               .bit = BCM6318_POWER_DOMAIN_EPHY0,
-       }, {
-               .name = "ephy1",
-               .bit = BCM6318_POWER_DOMAIN_EPHY1,
-       }, {
-               .name = "ephy2",
-               .bit = BCM6318_POWER_DOMAIN_EPHY2,
-       }, {
-               .name = "ephy3",
-               .bit = BCM6318_POWER_DOMAIN_EPHY3,
-       }, {
-               .name = "ldo2p5",
-               .bit = BCM6318_POWER_DOMAIN_LDO2P5,
-               .flags = GENPD_FLAG_ALWAYS_ON,
-       }, {
-               .name = "ldo2p9",
-               .bit = BCM6318_POWER_DOMAIN_LDO2P9,
-               .flags = GENPD_FLAG_ALWAYS_ON,
-       }, {
-               .name = "sw1p0",
-               .bit = BCM6318_POWER_DOMAIN_SW1P0,
-               .flags = GENPD_FLAG_ALWAYS_ON,
-       }, {
-               .name = "pad",
-               .bit = BCM6318_POWER_DOMAIN_PAD,
-               .flags = GENPD_FLAG_ALWAYS_ON,
-       }, {
-               /* sentinel */
-       },
-};
-
-static const struct bcm63xx_power_data bcm6328_power_domains[] = {
-       {
-               .name = "adsl2-mips",
-               .bit = BCM6328_POWER_DOMAIN_ADSL2_MIPS,
-       }, {
-               .name = "adsl2-phy",
-               .bit = BCM6328_POWER_DOMAIN_ADSL2_PHY,
-       }, {
-               .name = "adsl2-afe",
-               .bit = BCM6328_POWER_DOMAIN_ADSL2_AFE,
-       }, {
-               .name = "sar",
-               .bit = BCM6328_POWER_DOMAIN_SAR,
-       }, {
-               .name = "pcm",
-               .bit = BCM6328_POWER_DOMAIN_PCM,
-       }, {
-               .name = "usbd",
-               .bit = BCM6328_POWER_DOMAIN_USBD,
-       }, {
-               .name = "usbh",
-               .bit = BCM6328_POWER_DOMAIN_USBH,
-       }, {
-               .name = "pcie",
-               .bit = BCM6328_POWER_DOMAIN_PCIE,
-       }, {
-               .name = "robosw",
-               .bit = BCM6328_POWER_DOMAIN_ROBOSW,
-       }, {
-               .name = "ephy",
-               .bit = BCM6328_POWER_DOMAIN_EPHY,
-       }, {
-               /* sentinel */
-       },
-};
-
-static const struct bcm63xx_power_data bcm6362_power_domains[] = {
-       {
-               .name = "sar",
-               .bit = BCM6362_POWER_DOMAIN_SAR,
-       }, {
-               .name = "ipsec",
-               .bit = BCM6362_POWER_DOMAIN_IPSEC,
-       }, {
-               .name = "mips",
-               .bit = BCM6362_POWER_DOMAIN_MIPS,
-               .flags = GENPD_FLAG_ALWAYS_ON,
-       }, {
-               .name = "dect",
-               .bit = BCM6362_POWER_DOMAIN_DECT,
-       }, {
-               .name = "usbh",
-               .bit = BCM6362_POWER_DOMAIN_USBH,
-       }, {
-               .name = "usbd",
-               .bit = BCM6362_POWER_DOMAIN_USBD,
-       }, {
-               .name = "robosw",
-               .bit = BCM6362_POWER_DOMAIN_ROBOSW,
-       }, {
-               .name = "pcm",
-               .bit = BCM6362_POWER_DOMAIN_PCM,
-       }, {
-               .name = "periph",
-               .bit = BCM6362_POWER_DOMAIN_PERIPH,
-               .flags = GENPD_FLAG_ALWAYS_ON,
-       }, {
-               .name = "adsl-phy",
-               .bit = BCM6362_POWER_DOMAIN_ADSL_PHY,
-       }, {
-               .name = "gmii-pads",
-               .bit = BCM6362_POWER_DOMAIN_GMII_PADS,
-       }, {
-               .name = "fap",
-               .bit = BCM6362_POWER_DOMAIN_FAP,
-       }, {
-               .name = "pcie",
-               .bit = BCM6362_POWER_DOMAIN_PCIE,
-       }, {
-               .name = "wlan-pads",
-               .bit = BCM6362_POWER_DOMAIN_WLAN_PADS,
-       }, {
-               /* sentinel */
-       },
-};
-
-static const struct bcm63xx_power_data bcm63268_power_domains[] = {
-       {
-               .name = "sar",
-               .bit = BCM63268_POWER_DOMAIN_SAR,
-       }, {
-               .name = "ipsec",
-               .bit = BCM63268_POWER_DOMAIN_IPSEC,
-       }, {
-               .name = "mips",
-               .bit = BCM63268_POWER_DOMAIN_MIPS,
-               .flags = GENPD_FLAG_ALWAYS_ON,
-       }, {
-               .name = "dect",
-               .bit = BCM63268_POWER_DOMAIN_DECT,
-       }, {
-               .name = "usbh",
-               .bit = BCM63268_POWER_DOMAIN_USBH,
-       }, {
-               .name = "usbd",
-               .bit = BCM63268_POWER_DOMAIN_USBD,
-       }, {
-               .name = "robosw",
-               .bit = BCM63268_POWER_DOMAIN_ROBOSW,
-       }, {
-               .name = "pcm",
-               .bit = BCM63268_POWER_DOMAIN_PCM,
-       }, {
-               .name = "periph",
-               .bit = BCM63268_POWER_DOMAIN_PERIPH,
-               .flags = GENPD_FLAG_ALWAYS_ON,
-       }, {
-               .name = "vdsl-phy",
-               .bit = BCM63268_POWER_DOMAIN_VDSL_PHY,
-       }, {
-               .name = "vdsl-mips",
-               .bit = BCM63268_POWER_DOMAIN_VDSL_MIPS,
-       }, {
-               .name = "fap",
-               .bit = BCM63268_POWER_DOMAIN_FAP,
-       }, {
-               .name = "pcie",
-               .bit = BCM63268_POWER_DOMAIN_PCIE,
-       }, {
-               .name = "wlan-pads",
-               .bit = BCM63268_POWER_DOMAIN_WLAN_PADS,
-       }, {
-               /* sentinel */
-       },
-};
-
-static const struct of_device_id bcm63xx_power_of_match[] = {
-       {
-               .compatible = "brcm,bcm6318-power-controller",
-               .data = &bcm6318_power_domains,
-       }, {
-               .compatible = "brcm,bcm6328-power-controller",
-               .data = &bcm6328_power_domains,
-       }, {
-               .compatible = "brcm,bcm6362-power-controller",
-               .data = &bcm6362_power_domains,
-       }, {
-               .compatible = "brcm,bcm63268-power-controller",
-               .data = &bcm63268_power_domains,
-       }, {
-               /* sentinel */
-       }
-};
-
-static struct platform_driver bcm63xx_power_driver = {
-       .driver = {
-               .name = "bcm63xx-power-controller",
-               .of_match_table = bcm63xx_power_of_match,
-       },
-       .probe  = bcm63xx_power_probe,
-};
-builtin_platform_driver(bcm63xx_power_driver);
diff --git a/drivers/soc/bcm/raspberrypi-power.c b/drivers/soc/bcm/raspberrypi-power.c
deleted file mode 100644 (file)
index 58175af..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* (C) 2015 Pengutronix, Alexander Aring <aar@pengutronix.de>
- *
- * Authors:
- * Alexander Aring <aar@pengutronix.de>
- * Eric Anholt <eric@anholt.net>
- */
-
-#include <linux/module.h>
-#include <linux/of_platform.h>
-#include <linux/platform_device.h>
-#include <linux/pm_domain.h>
-#include <dt-bindings/power/raspberrypi-power.h>
-#include <soc/bcm2835/raspberrypi-firmware.h>
-
-/*
- * Firmware indices for the old power domains interface.  Only a few
- * of them were actually implemented.
- */
-#define RPI_OLD_POWER_DOMAIN_USB               3
-#define RPI_OLD_POWER_DOMAIN_V3D               10
-
-struct rpi_power_domain {
-       u32 domain;
-       bool enabled;
-       bool old_interface;
-       struct generic_pm_domain base;
-       struct rpi_firmware *fw;
-};
-
-struct rpi_power_domains {
-       bool has_new_interface;
-       struct genpd_onecell_data xlate;
-       struct rpi_firmware *fw;
-       struct rpi_power_domain domains[RPI_POWER_DOMAIN_COUNT];
-};
-
-/*
- * Packet definition used by RPI_FIRMWARE_SET_POWER_STATE and
- * RPI_FIRMWARE_SET_DOMAIN_STATE
- */
-struct rpi_power_domain_packet {
-       u32 domain;
-       u32 on;
-};
-
-/*
- * Asks the firmware to enable or disable power on a specific power
- * domain.
- */
-static int rpi_firmware_set_power(struct rpi_power_domain *rpi_domain, bool on)
-{
-       struct rpi_power_domain_packet packet;
-
-       packet.domain = rpi_domain->domain;
-       packet.on = on;
-       return rpi_firmware_property(rpi_domain->fw,
-                                    rpi_domain->old_interface ?
-                                    RPI_FIRMWARE_SET_POWER_STATE :
-                                    RPI_FIRMWARE_SET_DOMAIN_STATE,
-                                    &packet, sizeof(packet));
-}
-
-static int rpi_domain_off(struct generic_pm_domain *domain)
-{
-       struct rpi_power_domain *rpi_domain =
-               container_of(domain, struct rpi_power_domain, base);
-
-       return rpi_firmware_set_power(rpi_domain, false);
-}
-
-static int rpi_domain_on(struct generic_pm_domain *domain)
-{
-       struct rpi_power_domain *rpi_domain =
-               container_of(domain, struct rpi_power_domain, base);
-
-       return rpi_firmware_set_power(rpi_domain, true);
-}
-
-static void rpi_common_init_power_domain(struct rpi_power_domains *rpi_domains,
-                                        int xlate_index, const char *name)
-{
-       struct rpi_power_domain *dom = &rpi_domains->domains[xlate_index];
-
-       dom->fw = rpi_domains->fw;
-
-       dom->base.name = name;
-       dom->base.power_on = rpi_domain_on;
-       dom->base.power_off = rpi_domain_off;
-
-       /*
-        * Treat all power domains as off at boot.
-        *
-        * The firmware itself may be keeping some domains on, but
-        * from Linux's perspective all we control is the refcounts
-        * that we give to the firmware, and we can't ask the firmware
-        * to turn off something that we haven't ourselves turned on.
-        */
-       pm_genpd_init(&dom->base, NULL, true);
-
-       rpi_domains->xlate.domains[xlate_index] = &dom->base;
-}
-
-static void rpi_init_power_domain(struct rpi_power_domains *rpi_domains,
-                                 int xlate_index, const char *name)
-{
-       struct rpi_power_domain *dom = &rpi_domains->domains[xlate_index];
-
-       if (!rpi_domains->has_new_interface)
-               return;
-
-       /* The DT binding index is the firmware's domain index minus one. */
-       dom->domain = xlate_index + 1;
-
-       rpi_common_init_power_domain(rpi_domains, xlate_index, name);
-}
-
-static void rpi_init_old_power_domain(struct rpi_power_domains *rpi_domains,
-                                     int xlate_index, int domain,
-                                     const char *name)
-{
-       struct rpi_power_domain *dom = &rpi_domains->domains[xlate_index];
-
-       dom->old_interface = true;
-       dom->domain = domain;
-
-       rpi_common_init_power_domain(rpi_domains, xlate_index, name);
-}
-
-/*
- * Detects whether the firmware supports the new power domains interface.
- *
- * The firmware doesn't actually return an error on an unknown tag,
- * and just skips over it, so we do the detection by putting an
- * unexpected value in the return field and checking if it was
- * unchanged.
- */
-static bool
-rpi_has_new_domain_support(struct rpi_power_domains *rpi_domains)
-{
-       struct rpi_power_domain_packet packet;
-       int ret;
-
-       packet.domain = RPI_POWER_DOMAIN_ARM;
-       packet.on = ~0;
-
-       ret = rpi_firmware_property(rpi_domains->fw,
-                                   RPI_FIRMWARE_GET_DOMAIN_STATE,
-                                   &packet, sizeof(packet));
-
-       return ret == 0 && packet.on != ~0;
-}
-
-static int rpi_power_probe(struct platform_device *pdev)
-{
-       struct device_node *fw_np;
-       struct device *dev = &pdev->dev;
-       struct rpi_power_domains *rpi_domains;
-
-       rpi_domains = devm_kzalloc(dev, sizeof(*rpi_domains), GFP_KERNEL);
-       if (!rpi_domains)
-               return -ENOMEM;
-
-       rpi_domains->xlate.domains =
-               devm_kcalloc(dev,
-                            RPI_POWER_DOMAIN_COUNT,
-                            sizeof(*rpi_domains->xlate.domains),
-                            GFP_KERNEL);
-       if (!rpi_domains->xlate.domains)
-               return -ENOMEM;
-
-       rpi_domains->xlate.num_domains = RPI_POWER_DOMAIN_COUNT;
-
-       fw_np = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
-       if (!fw_np) {
-               dev_err(&pdev->dev, "no firmware node\n");
-               return -ENODEV;
-       }
-
-       rpi_domains->fw = devm_rpi_firmware_get(&pdev->dev, fw_np);
-       of_node_put(fw_np);
-       if (!rpi_domains->fw)
-               return -EPROBE_DEFER;
-
-       rpi_domains->has_new_interface =
-               rpi_has_new_domain_support(rpi_domains);
-
-       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_I2C0, "I2C0");
-       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_I2C1, "I2C1");
-       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_I2C2, "I2C2");
-       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_VIDEO_SCALER,
-                             "VIDEO_SCALER");
-       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_VPU1, "VPU1");
-       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_HDMI, "HDMI");
-
-       /*
-        * Use the old firmware interface for USB power, so that we
-        * can turn it on even if the firmware hasn't been updated.
-        */
-       rpi_init_old_power_domain(rpi_domains, RPI_POWER_DOMAIN_USB,
-                                 RPI_OLD_POWER_DOMAIN_USB, "USB");
-
-       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_VEC, "VEC");
-       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_JPEG, "JPEG");
-       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_H264, "H264");
-       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_V3D, "V3D");
-       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_ISP, "ISP");
-       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_UNICAM0, "UNICAM0");
-       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_UNICAM1, "UNICAM1");
-       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CCP2RX, "CCP2RX");
-       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CSI2, "CSI2");
-       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CPI, "CPI");
-       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_DSI0, "DSI0");
-       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_DSI1, "DSI1");
-       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_TRANSPOSER,
-                             "TRANSPOSER");
-       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CCP2TX, "CCP2TX");
-       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_CDP, "CDP");
-       rpi_init_power_domain(rpi_domains, RPI_POWER_DOMAIN_ARM, "ARM");
-
-       of_genpd_add_provider_onecell(dev->of_node, &rpi_domains->xlate);
-
-       platform_set_drvdata(pdev, rpi_domains);
-
-       return 0;
-}
-
-static const struct of_device_id rpi_power_of_match[] = {
-       { .compatible = "raspberrypi,bcm2835-power", },
-       {},
-};
-MODULE_DEVICE_TABLE(of, rpi_power_of_match);
-
-static struct platform_driver rpi_power_driver = {
-       .driver = {
-               .name = "raspberrypi-power",
-               .of_match_table = rpi_power_of_match,
-       },
-       .probe          = rpi_power_probe,
-};
-builtin_platform_driver(rpi_power_driver);
-
-MODULE_AUTHOR("Alexander Aring <aar@pengutronix.de>");
-MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
-MODULE_DESCRIPTION("Raspberry Pi power domain driver");