Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (c) 2013 Broadcom
0004  * Copyright (C) 2020 Rafał Miłecki <rafal@milecki.pl>
0005  */
0006 
0007 #include <dt-bindings/soc/bcm-pmb.h>
0008 #include <linux/io.h>
0009 #include <linux/module.h>
0010 #include <linux/of.h>
0011 #include <linux/of_device.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/pm_domain.h>
0014 #include <linux/reset/bcm63xx_pmb.h>
0015 
0016 #define BPCM_ID_REG                 0x00
0017 #define BPCM_CAPABILITIES               0x04
0018 #define  BPCM_CAP_NUM_ZONES             0x000000ff
0019 #define  BPCM_CAP_SR_REG_BITS               0x0000ff00
0020 #define  BPCM_CAP_PLLTYPE               0x00030000
0021 #define  BPCM_CAP_UBUS                  0x00080000
0022 #define BPCM_CONTROL                    0x08
0023 #define BPCM_STATUS                 0x0c
0024 #define BPCM_ROSC_CONTROL               0x10
0025 #define BPCM_ROSC_THRESH_H              0x14
0026 #define BPCM_ROSC_THRESHOLD_BCM6838         0x14
0027 #define BPCM_ROSC_THRESH_S              0x18
0028 #define BPCM_ROSC_COUNT_BCM6838             0x18
0029 #define BPCM_ROSC_COUNT                 0x1c
0030 #define BPCM_PWD_CONTROL_BCM6838            0x1c
0031 #define BPCM_PWD_CONTROL                0x20
0032 #define BPCM_SR_CONTROL_BCM6838             0x20
0033 #define BPCM_PWD_ACCUM_CONTROL              0x24
0034 #define BPCM_SR_CONTROL                 0x28
0035 #define BPCM_GLOBAL_CONTROL             0x2c
0036 #define BPCM_MISC_CONTROL               0x30
0037 #define BPCM_MISC_CONTROL2              0x34
0038 #define BPCM_SGPHY_CNTL                 0x38
0039 #define BPCM_SGPHY_STATUS               0x3c
0040 #define BPCM_ZONE0                  0x40
0041 #define  BPCM_ZONE_CONTROL              0x00
0042 #define   BPCM_ZONE_CONTROL_MANUAL_CLK_EN       0x00000001
0043 #define   BPCM_ZONE_CONTROL_MANUAL_RESET_CTL        0x00000002
0044 #define   BPCM_ZONE_CONTROL_FREQ_SCALE_USED     0x00000004  /* R/O */
0045 #define   BPCM_ZONE_CONTROL_DPG_CAPABLE         0x00000008  /* R/O */
0046 #define   BPCM_ZONE_CONTROL_MANUAL_MEM_PWR      0x00000030
0047 #define   BPCM_ZONE_CONTROL_MANUAL_ISO_CTL      0x00000040
0048 #define   BPCM_ZONE_CONTROL_MANUAL_CTL          0x00000080
0049 #define   BPCM_ZONE_CONTROL_DPG_CTL_EN          0x00000100
0050 #define   BPCM_ZONE_CONTROL_PWR_DN_REQ          0x00000200
0051 #define   BPCM_ZONE_CONTROL_PWR_UP_REQ          0x00000400
0052 #define   BPCM_ZONE_CONTROL_MEM_PWR_CTL_EN      0x00000800
0053 #define   BPCM_ZONE_CONTROL_BLK_RESET_ASSERT        0x00001000
0054 #define   BPCM_ZONE_CONTROL_MEM_STBY            0x00002000
0055 #define   BPCM_ZONE_CONTROL_RESERVED            0x0007c000
0056 #define   BPCM_ZONE_CONTROL_PWR_CNTL_STATE      0x00f80000
0057 #define   BPCM_ZONE_CONTROL_FREQ_SCALAR_DYN_SEL     0x01000000  /* R/O */
0058 #define   BPCM_ZONE_CONTROL_PWR_OFF_STATE       0x02000000  /* R/O */
0059 #define   BPCM_ZONE_CONTROL_PWR_ON_STATE        0x04000000  /* R/O */
0060 #define   BPCM_ZONE_CONTROL_PWR_GOOD            0x08000000  /* R/O */
0061 #define   BPCM_ZONE_CONTROL_DPG_PWR_STATE       0x10000000  /* R/O */
0062 #define   BPCM_ZONE_CONTROL_MEM_PWR_STATE       0x20000000  /* R/O */
0063 #define   BPCM_ZONE_CONTROL_ISO_STATE           0x40000000  /* R/O */
0064 #define   BPCM_ZONE_CONTROL_RESET_STATE         0x80000000  /* R/O */
0065 #define  BPCM_ZONE_CONFIG1              0x04
0066 #define  BPCM_ZONE_CONFIG2              0x08
0067 #define  BPCM_ZONE_FREQ_SCALAR_CONTROL          0x0c
0068 #define  BPCM_ZONE_SIZE                 0x10
0069 
0070 struct bcm_pmb {
0071     struct device *dev;
0072     void __iomem *base;
0073     spinlock_t lock;
0074     bool little_endian;
0075     struct genpd_onecell_data genpd_onecell_data;
0076 };
0077 
0078 struct bcm_pmb_pd_data {
0079     const char * const name;
0080     int id;
0081     u8 bus;
0082     u8 device;
0083 };
0084 
0085 struct bcm_pmb_pm_domain {
0086     struct bcm_pmb *pmb;
0087     const struct bcm_pmb_pd_data *data;
0088     struct generic_pm_domain genpd;
0089 };
0090 
0091 static int bcm_pmb_bpcm_read(struct bcm_pmb *pmb, int bus, u8 device,
0092                  int offset, u32 *val)
0093 {
0094     void __iomem *base = pmb->base + bus * 0x20;
0095     unsigned long flags;
0096     int err;
0097 
0098     spin_lock_irqsave(&pmb->lock, flags);
0099     err = bpcm_rd(base, device, offset, val);
0100     spin_unlock_irqrestore(&pmb->lock, flags);
0101 
0102     if (!err)
0103         *val = pmb->little_endian ? le32_to_cpu(*val) : be32_to_cpu(*val);
0104 
0105     return err;
0106 }
0107 
0108 static int bcm_pmb_bpcm_write(struct bcm_pmb *pmb, int bus, u8 device,
0109                   int offset, u32 val)
0110 {
0111     void __iomem *base = pmb->base + bus * 0x20;
0112     unsigned long flags;
0113     int err;
0114 
0115     val = pmb->little_endian ? cpu_to_le32(val) : cpu_to_be32(val);
0116 
0117     spin_lock_irqsave(&pmb->lock, flags);
0118     err = bpcm_wr(base, device, offset, val);
0119     spin_unlock_irqrestore(&pmb->lock, flags);
0120 
0121     return err;
0122 }
0123 
0124 static int bcm_pmb_power_off_zone(struct bcm_pmb *pmb, int bus, u8 device,
0125                   int zone)
0126 {
0127     int offset;
0128     u32 val;
0129     int err;
0130 
0131     offset = BPCM_ZONE0 + zone * BPCM_ZONE_SIZE + BPCM_ZONE_CONTROL;
0132 
0133     err = bcm_pmb_bpcm_read(pmb, bus, device, offset, &val);
0134     if (err)
0135         return err;
0136 
0137     val |= BPCM_ZONE_CONTROL_PWR_DN_REQ;
0138     val &= ~BPCM_ZONE_CONTROL_PWR_UP_REQ;
0139 
0140     err = bcm_pmb_bpcm_write(pmb, bus, device, offset, val);
0141 
0142     return err;
0143 }
0144 
0145 static int bcm_pmb_power_on_zone(struct bcm_pmb *pmb, int bus, u8 device,
0146                  int zone)
0147 {
0148     int offset;
0149     u32 val;
0150     int err;
0151 
0152     offset = BPCM_ZONE0 + zone * BPCM_ZONE_SIZE + BPCM_ZONE_CONTROL;
0153 
0154     err = bcm_pmb_bpcm_read(pmb, bus, device, offset, &val);
0155     if (err)
0156         return err;
0157 
0158     if (!(val & BPCM_ZONE_CONTROL_PWR_ON_STATE)) {
0159         val &= ~BPCM_ZONE_CONTROL_PWR_DN_REQ;
0160         val |= BPCM_ZONE_CONTROL_DPG_CTL_EN;
0161         val |= BPCM_ZONE_CONTROL_PWR_UP_REQ;
0162         val |= BPCM_ZONE_CONTROL_MEM_PWR_CTL_EN;
0163         val |= BPCM_ZONE_CONTROL_BLK_RESET_ASSERT;
0164 
0165         err = bcm_pmb_bpcm_write(pmb, bus, device, offset, val);
0166     }
0167 
0168     return err;
0169 }
0170 
0171 static int bcm_pmb_power_off_device(struct bcm_pmb *pmb, int bus, u8 device)
0172 {
0173     int offset;
0174     u32 val;
0175     int err;
0176 
0177     /* Entire device can be powered off by powering off the 0th zone */
0178     offset = BPCM_ZONE0 + BPCM_ZONE_CONTROL;
0179 
0180     err = bcm_pmb_bpcm_read(pmb, bus, device, offset, &val);
0181     if (err)
0182         return err;
0183 
0184     if (!(val & BPCM_ZONE_CONTROL_PWR_OFF_STATE)) {
0185         val = BPCM_ZONE_CONTROL_PWR_DN_REQ;
0186 
0187         err = bcm_pmb_bpcm_write(pmb, bus, device, offset, val);
0188     }
0189 
0190     return err;
0191 }
0192 
0193 static int bcm_pmb_power_on_device(struct bcm_pmb *pmb, int bus, u8 device)
0194 {
0195     u32 val;
0196     int err;
0197     int i;
0198 
0199     err = bcm_pmb_bpcm_read(pmb, bus, device, BPCM_CAPABILITIES, &val);
0200     if (err)
0201         return err;
0202 
0203     for (i = 0; i < (val & BPCM_CAP_NUM_ZONES); i++) {
0204         err = bcm_pmb_power_on_zone(pmb, bus, device, i);
0205         if (err)
0206             return err;
0207     }
0208 
0209     return err;
0210 }
0211 
0212 static int bcm_pmb_power_on_sata(struct bcm_pmb *pmb, int bus, u8 device)
0213 {
0214     int err;
0215 
0216     err = bcm_pmb_power_on_zone(pmb, bus, device, 0);
0217     if (err)
0218         return err;
0219 
0220     /* Does not apply to the BCM963158 */
0221     err = bcm_pmb_bpcm_write(pmb, bus, device, BPCM_MISC_CONTROL, 0);
0222     if (err)
0223         return err;
0224 
0225     err = bcm_pmb_bpcm_write(pmb, bus, device, BPCM_SR_CONTROL, 0xffffffff);
0226     if (err)
0227         return err;
0228 
0229     err = bcm_pmb_bpcm_write(pmb, bus, device, BPCM_SR_CONTROL, 0);
0230 
0231     return err;
0232 }
0233 
0234 static int bcm_pmb_power_on(struct generic_pm_domain *genpd)
0235 {
0236     struct bcm_pmb_pm_domain *pd = container_of(genpd, struct bcm_pmb_pm_domain, genpd);
0237     const struct bcm_pmb_pd_data *data = pd->data;
0238     struct bcm_pmb *pmb = pd->pmb;
0239 
0240     switch (data->id) {
0241     case BCM_PMB_PCIE0:
0242     case BCM_PMB_PCIE1:
0243     case BCM_PMB_PCIE2:
0244         return bcm_pmb_power_on_zone(pmb, data->bus, data->device, 0);
0245     case BCM_PMB_HOST_USB:
0246         return bcm_pmb_power_on_device(pmb, data->bus, data->device);
0247     case BCM_PMB_SATA:
0248         return bcm_pmb_power_on_sata(pmb, data->bus, data->device);
0249     default:
0250         dev_err(pmb->dev, "unsupported device id: %d\n", data->id);
0251         return -EINVAL;
0252     }
0253 }
0254 
0255 static int bcm_pmb_power_off(struct generic_pm_domain *genpd)
0256 {
0257     struct bcm_pmb_pm_domain *pd = container_of(genpd, struct bcm_pmb_pm_domain, genpd);
0258     const struct bcm_pmb_pd_data *data = pd->data;
0259     struct bcm_pmb *pmb = pd->pmb;
0260 
0261     switch (data->id) {
0262     case BCM_PMB_PCIE0:
0263     case BCM_PMB_PCIE1:
0264     case BCM_PMB_PCIE2:
0265         return bcm_pmb_power_off_zone(pmb, data->bus, data->device, 0);
0266     case BCM_PMB_HOST_USB:
0267         return bcm_pmb_power_off_device(pmb, data->bus, data->device);
0268     default:
0269         dev_err(pmb->dev, "unsupported device id: %d\n", data->id);
0270         return -EINVAL;
0271     }
0272 }
0273 
0274 static int bcm_pmb_probe(struct platform_device *pdev)
0275 {
0276     struct device *dev = &pdev->dev;
0277     const struct bcm_pmb_pd_data *table;
0278     const struct bcm_pmb_pd_data *e;
0279     struct bcm_pmb *pmb;
0280     int max_id;
0281     int err;
0282 
0283     pmb = devm_kzalloc(dev, sizeof(*pmb), GFP_KERNEL);
0284     if (!pmb)
0285         return -ENOMEM;
0286 
0287     pmb->dev = dev;
0288 
0289     pmb->base = devm_platform_ioremap_resource(pdev, 0);
0290     if (IS_ERR(pmb->base))
0291         return PTR_ERR(pmb->base);
0292 
0293     spin_lock_init(&pmb->lock);
0294 
0295     pmb->little_endian = !of_device_is_big_endian(dev->of_node);
0296 
0297     table = of_device_get_match_data(dev);
0298     if (!table)
0299         return -EINVAL;
0300 
0301     max_id = 0;
0302     for (e = table; e->name; e++)
0303         max_id = max(max_id, e->id);
0304 
0305     pmb->genpd_onecell_data.num_domains = max_id + 1;
0306     pmb->genpd_onecell_data.domains =
0307         devm_kcalloc(dev, pmb->genpd_onecell_data.num_domains,
0308                  sizeof(struct generic_pm_domain *), GFP_KERNEL);
0309     if (!pmb->genpd_onecell_data.domains)
0310         return -ENOMEM;
0311 
0312     for (e = table; e->name; e++) {
0313         struct bcm_pmb_pm_domain *pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
0314 
0315         if (!pd)
0316             return -ENOMEM;
0317 
0318         pd->pmb = pmb;
0319         pd->data = e;
0320         pd->genpd.name = e->name;
0321         pd->genpd.power_on = bcm_pmb_power_on;
0322         pd->genpd.power_off = bcm_pmb_power_off;
0323 
0324         pm_genpd_init(&pd->genpd, NULL, true);
0325         pmb->genpd_onecell_data.domains[e->id] = &pd->genpd;
0326     }
0327 
0328     err = of_genpd_add_provider_onecell(dev->of_node, &pmb->genpd_onecell_data);
0329     if (err) {
0330         dev_err(dev, "failed to add genpd provider: %d\n", err);
0331         return err;
0332     }
0333 
0334     return 0;
0335 }
0336 
0337 static const struct bcm_pmb_pd_data bcm_pmb_bcm4908_data[] = {
0338     { .name = "pcie2", .id = BCM_PMB_PCIE2, .bus = 0, .device = 2, },
0339     { .name = "pcie0", .id = BCM_PMB_PCIE0, .bus = 1, .device = 14, },
0340     { .name = "pcie1", .id = BCM_PMB_PCIE1, .bus = 1, .device = 15, },
0341     { .name = "usb", .id = BCM_PMB_HOST_USB, .bus = 1, .device = 17, },
0342     { },
0343 };
0344 
0345 static const struct bcm_pmb_pd_data bcm_pmb_bcm63138_data[] = {
0346     { .name = "sata", .id = BCM_PMB_SATA, .bus = 0, .device = 3, },
0347     { },
0348 };
0349 
0350 static const struct of_device_id bcm_pmb_of_match[] = {
0351     { .compatible = "brcm,bcm4908-pmb", .data = &bcm_pmb_bcm4908_data, },
0352     { .compatible = "brcm,bcm63138-pmb", .data = &bcm_pmb_bcm63138_data, },
0353     { },
0354 };
0355 
0356 static struct platform_driver bcm_pmb_driver = {
0357     .driver = {
0358         .name = "bcm-pmb",
0359         .of_match_table = bcm_pmb_of_match,
0360     },
0361     .probe  = bcm_pmb_probe,
0362 };
0363 
0364 builtin_platform_driver(bcm_pmb_driver);