Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Copyright (c) 2019 BayLibre, SAS
0004  * Author: Neil Armstrong <narmstrong@baylibre.com>
0005  */
0006 
0007 #include <linux/of_address.h>
0008 #include <linux/platform_device.h>
0009 #include <linux/pm_domain.h>
0010 #include <linux/bitfield.h>
0011 #include <linux/regmap.h>
0012 #include <linux/mfd/syscon.h>
0013 #include <linux/of_device.h>
0014 #include <linux/reset-controller.h>
0015 #include <linux/reset.h>
0016 #include <linux/clk.h>
0017 #include <linux/module.h>
0018 #include <dt-bindings/power/meson8-power.h>
0019 #include <dt-bindings/power/meson-axg-power.h>
0020 #include <dt-bindings/power/meson-g12a-power.h>
0021 #include <dt-bindings/power/meson-gxbb-power.h>
0022 #include <dt-bindings/power/meson-sm1-power.h>
0023 
0024 /* AO Offsets */
0025 
0026 #define GX_AO_RTI_GEN_PWR_SLEEP0    (0x3a << 2)
0027 #define GX_AO_RTI_GEN_PWR_ISO0      (0x3b << 2)
0028 
0029 /*
0030  * Meson8/Meson8b/Meson8m2 only expose the power management registers of the
0031  * AO-bus as syscon. 0x3a from GX translates to 0x02, 0x3b translates to 0x03
0032  * and so on.
0033  */
0034 #define MESON8_AO_RTI_GEN_PWR_SLEEP0    (0x02 << 2)
0035 #define MESON8_AO_RTI_GEN_PWR_ISO0  (0x03 << 2)
0036 
0037 /* HHI Offsets */
0038 
0039 #define HHI_MEM_PD_REG0         (0x40 << 2)
0040 #define HHI_VPU_MEM_PD_REG0     (0x41 << 2)
0041 #define HHI_VPU_MEM_PD_REG1     (0x42 << 2)
0042 #define HHI_VPU_MEM_PD_REG3     (0x43 << 2)
0043 #define HHI_VPU_MEM_PD_REG4     (0x44 << 2)
0044 #define HHI_AUDIO_MEM_PD_REG0       (0x45 << 2)
0045 #define HHI_NANOQ_MEM_PD_REG0       (0x46 << 2)
0046 #define HHI_NANOQ_MEM_PD_REG1       (0x47 << 2)
0047 #define HHI_VPU_MEM_PD_REG2     (0x4d << 2)
0048 
0049 struct meson_ee_pwrc;
0050 struct meson_ee_pwrc_domain;
0051 
0052 struct meson_ee_pwrc_mem_domain {
0053     unsigned int reg;
0054     unsigned int mask;
0055 };
0056 
0057 struct meson_ee_pwrc_top_domain {
0058     unsigned int sleep_reg;
0059     unsigned int sleep_mask;
0060     unsigned int iso_reg;
0061     unsigned int iso_mask;
0062 };
0063 
0064 struct meson_ee_pwrc_domain_desc {
0065     char *name;
0066     unsigned int reset_names_count;
0067     unsigned int clk_names_count;
0068     struct meson_ee_pwrc_top_domain *top_pd;
0069     unsigned int mem_pd_count;
0070     struct meson_ee_pwrc_mem_domain *mem_pd;
0071     bool (*is_powered_off)(struct meson_ee_pwrc_domain *pwrc_domain);
0072 };
0073 
0074 struct meson_ee_pwrc_domain_data {
0075     unsigned int count;
0076     struct meson_ee_pwrc_domain_desc *domains;
0077 };
0078 
0079 /* TOP Power Domains */
0080 
0081 static struct meson_ee_pwrc_top_domain gx_pwrc_vpu = {
0082     .sleep_reg = GX_AO_RTI_GEN_PWR_SLEEP0,
0083     .sleep_mask = BIT(8),
0084     .iso_reg = GX_AO_RTI_GEN_PWR_SLEEP0,
0085     .iso_mask = BIT(9),
0086 };
0087 
0088 static struct meson_ee_pwrc_top_domain meson8_pwrc_vpu = {
0089     .sleep_reg = MESON8_AO_RTI_GEN_PWR_SLEEP0,
0090     .sleep_mask = BIT(8),
0091     .iso_reg = MESON8_AO_RTI_GEN_PWR_SLEEP0,
0092     .iso_mask = BIT(9),
0093 };
0094 
0095 #define SM1_EE_PD(__bit)                    \
0096     {                           \
0097         .sleep_reg = GX_AO_RTI_GEN_PWR_SLEEP0,      \
0098         .sleep_mask = BIT(__bit),           \
0099         .iso_reg = GX_AO_RTI_GEN_PWR_ISO0,      \
0100         .iso_mask = BIT(__bit),             \
0101     }
0102 
0103 static struct meson_ee_pwrc_top_domain sm1_pwrc_vpu = SM1_EE_PD(8);
0104 static struct meson_ee_pwrc_top_domain sm1_pwrc_nna = SM1_EE_PD(16);
0105 static struct meson_ee_pwrc_top_domain sm1_pwrc_usb = SM1_EE_PD(17);
0106 static struct meson_ee_pwrc_top_domain sm1_pwrc_pci = SM1_EE_PD(18);
0107 static struct meson_ee_pwrc_top_domain sm1_pwrc_ge2d = SM1_EE_PD(19);
0108 
0109 /* Memory PD Domains */
0110 
0111 #define VPU_MEMPD(__reg)                    \
0112     { __reg, GENMASK(1, 0) },               \
0113     { __reg, GENMASK(3, 2) },               \
0114     { __reg, GENMASK(5, 4) },               \
0115     { __reg, GENMASK(7, 6) },               \
0116     { __reg, GENMASK(9, 8) },               \
0117     { __reg, GENMASK(11, 10) },             \
0118     { __reg, GENMASK(13, 12) },             \
0119     { __reg, GENMASK(15, 14) },             \
0120     { __reg, GENMASK(17, 16) },             \
0121     { __reg, GENMASK(19, 18) },             \
0122     { __reg, GENMASK(21, 20) },             \
0123     { __reg, GENMASK(23, 22) },             \
0124     { __reg, GENMASK(25, 24) },             \
0125     { __reg, GENMASK(27, 26) },             \
0126     { __reg, GENMASK(29, 28) },             \
0127     { __reg, GENMASK(31, 30) }
0128 
0129 #define VPU_HHI_MEMPD(__reg)                    \
0130     { __reg, BIT(8) },                  \
0131     { __reg, BIT(9) },                  \
0132     { __reg, BIT(10) },                 \
0133     { __reg, BIT(11) },                 \
0134     { __reg, BIT(12) },                 \
0135     { __reg, BIT(13) },                 \
0136     { __reg, BIT(14) },                 \
0137     { __reg, BIT(15) }
0138 
0139 static struct meson_ee_pwrc_mem_domain axg_pwrc_mem_vpu[] = {
0140     VPU_MEMPD(HHI_VPU_MEM_PD_REG0),
0141     VPU_HHI_MEMPD(HHI_MEM_PD_REG0),
0142 };
0143 
0144 static struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_vpu[] = {
0145     VPU_MEMPD(HHI_VPU_MEM_PD_REG0),
0146     VPU_MEMPD(HHI_VPU_MEM_PD_REG1),
0147     VPU_MEMPD(HHI_VPU_MEM_PD_REG2),
0148     VPU_HHI_MEMPD(HHI_MEM_PD_REG0),
0149 };
0150 
0151 static struct meson_ee_pwrc_mem_domain gxbb_pwrc_mem_vpu[] = {
0152     VPU_MEMPD(HHI_VPU_MEM_PD_REG0),
0153     VPU_MEMPD(HHI_VPU_MEM_PD_REG1),
0154     VPU_HHI_MEMPD(HHI_MEM_PD_REG0),
0155 };
0156 
0157 static struct meson_ee_pwrc_mem_domain meson_pwrc_mem_eth[] = {
0158     { HHI_MEM_PD_REG0, GENMASK(3, 2) },
0159 };
0160 
0161 static struct meson_ee_pwrc_mem_domain meson8_pwrc_audio_dsp_mem[] = {
0162     { HHI_MEM_PD_REG0, GENMASK(1, 0) },
0163 };
0164 
0165 static struct meson_ee_pwrc_mem_domain meson8_pwrc_mem_vpu[] = {
0166     VPU_MEMPD(HHI_VPU_MEM_PD_REG0),
0167     VPU_MEMPD(HHI_VPU_MEM_PD_REG1),
0168     VPU_HHI_MEMPD(HHI_MEM_PD_REG0),
0169 };
0170 
0171 static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_vpu[] = {
0172     VPU_MEMPD(HHI_VPU_MEM_PD_REG0),
0173     VPU_MEMPD(HHI_VPU_MEM_PD_REG1),
0174     VPU_MEMPD(HHI_VPU_MEM_PD_REG2),
0175     VPU_MEMPD(HHI_VPU_MEM_PD_REG3),
0176     { HHI_VPU_MEM_PD_REG4, GENMASK(1, 0) },
0177     { HHI_VPU_MEM_PD_REG4, GENMASK(3, 2) },
0178     { HHI_VPU_MEM_PD_REG4, GENMASK(5, 4) },
0179     { HHI_VPU_MEM_PD_REG4, GENMASK(7, 6) },
0180     VPU_HHI_MEMPD(HHI_MEM_PD_REG0),
0181 };
0182 
0183 static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_nna[] = {
0184     { HHI_NANOQ_MEM_PD_REG0, 0xff },
0185     { HHI_NANOQ_MEM_PD_REG1, 0xff },
0186 };
0187 
0188 static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_usb[] = {
0189     { HHI_MEM_PD_REG0, GENMASK(31, 30) },
0190 };
0191 
0192 static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_pcie[] = {
0193     { HHI_MEM_PD_REG0, GENMASK(29, 26) },
0194 };
0195 
0196 static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_ge2d[] = {
0197     { HHI_MEM_PD_REG0, GENMASK(25, 18) },
0198 };
0199 
0200 static struct meson_ee_pwrc_mem_domain axg_pwrc_mem_audio[] = {
0201     { HHI_MEM_PD_REG0, GENMASK(5, 4) },
0202 };
0203 
0204 static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_audio[] = {
0205     { HHI_MEM_PD_REG0, GENMASK(5, 4) },
0206     { HHI_AUDIO_MEM_PD_REG0, GENMASK(1, 0) },
0207     { HHI_AUDIO_MEM_PD_REG0, GENMASK(3, 2) },
0208     { HHI_AUDIO_MEM_PD_REG0, GENMASK(5, 4) },
0209     { HHI_AUDIO_MEM_PD_REG0, GENMASK(7, 6) },
0210     { HHI_AUDIO_MEM_PD_REG0, GENMASK(13, 12) },
0211     { HHI_AUDIO_MEM_PD_REG0, GENMASK(15, 14) },
0212     { HHI_AUDIO_MEM_PD_REG0, GENMASK(17, 16) },
0213     { HHI_AUDIO_MEM_PD_REG0, GENMASK(19, 18) },
0214     { HHI_AUDIO_MEM_PD_REG0, GENMASK(21, 20) },
0215     { HHI_AUDIO_MEM_PD_REG0, GENMASK(23, 22) },
0216     { HHI_AUDIO_MEM_PD_REG0, GENMASK(25, 24) },
0217     { HHI_AUDIO_MEM_PD_REG0, GENMASK(27, 26) },
0218 };
0219 
0220 #define VPU_PD(__name, __top_pd, __mem, __is_pwr_off, __resets, __clks) \
0221     {                               \
0222         .name = __name,                     \
0223         .reset_names_count = __resets,              \
0224         .clk_names_count = __clks,              \
0225         .top_pd = __top_pd,                 \
0226         .mem_pd_count = ARRAY_SIZE(__mem),          \
0227         .mem_pd = __mem,                    \
0228         .is_powered_off = __is_pwr_off,             \
0229     }
0230 
0231 #define TOP_PD(__name, __top_pd, __mem, __is_pwr_off)           \
0232     {                               \
0233         .name = __name,                     \
0234         .top_pd = __top_pd,                 \
0235         .mem_pd_count = ARRAY_SIZE(__mem),          \
0236         .mem_pd = __mem,                    \
0237         .is_powered_off = __is_pwr_off,             \
0238     }
0239 
0240 #define MEM_PD(__name, __mem)                       \
0241     TOP_PD(__name, NULL, __mem, NULL)
0242 
0243 static bool pwrc_ee_is_powered_off(struct meson_ee_pwrc_domain *pwrc_domain);
0244 
0245 static struct meson_ee_pwrc_domain_desc axg_pwrc_domains[] = {
0246     [PWRC_AXG_VPU_ID]  = VPU_PD("VPU", &gx_pwrc_vpu, axg_pwrc_mem_vpu,
0247                      pwrc_ee_is_powered_off, 5, 2),
0248     [PWRC_AXG_ETHERNET_MEM_ID] = MEM_PD("ETH", meson_pwrc_mem_eth),
0249     [PWRC_AXG_AUDIO_ID] = MEM_PD("AUDIO", axg_pwrc_mem_audio),
0250 };
0251 
0252 static struct meson_ee_pwrc_domain_desc g12a_pwrc_domains[] = {
0253     [PWRC_G12A_VPU_ID]  = VPU_PD("VPU", &gx_pwrc_vpu, g12a_pwrc_mem_vpu,
0254                      pwrc_ee_is_powered_off, 11, 2),
0255     [PWRC_G12A_ETH_ID] = MEM_PD("ETH", meson_pwrc_mem_eth),
0256 };
0257 
0258 static struct meson_ee_pwrc_domain_desc gxbb_pwrc_domains[] = {
0259     [PWRC_GXBB_VPU_ID]  = VPU_PD("VPU", &gx_pwrc_vpu, gxbb_pwrc_mem_vpu,
0260                      pwrc_ee_is_powered_off, 12, 2),
0261     [PWRC_GXBB_ETHERNET_MEM_ID] = MEM_PD("ETH", meson_pwrc_mem_eth),
0262 };
0263 
0264 static struct meson_ee_pwrc_domain_desc meson8_pwrc_domains[] = {
0265     [PWRC_MESON8_VPU_ID]  = VPU_PD("VPU", &meson8_pwrc_vpu,
0266                        meson8_pwrc_mem_vpu,
0267                        pwrc_ee_is_powered_off, 0, 1),
0268     [PWRC_MESON8_ETHERNET_MEM_ID] = MEM_PD("ETHERNET_MEM",
0269                            meson_pwrc_mem_eth),
0270     [PWRC_MESON8_AUDIO_DSP_MEM_ID] = MEM_PD("AUDIO_DSP_MEM",
0271                         meson8_pwrc_audio_dsp_mem),
0272 };
0273 
0274 static struct meson_ee_pwrc_domain_desc meson8b_pwrc_domains[] = {
0275     [PWRC_MESON8_VPU_ID]  = VPU_PD("VPU", &meson8_pwrc_vpu,
0276                        meson8_pwrc_mem_vpu,
0277                        pwrc_ee_is_powered_off, 11, 1),
0278     [PWRC_MESON8_ETHERNET_MEM_ID] = MEM_PD("ETHERNET_MEM",
0279                            meson_pwrc_mem_eth),
0280     [PWRC_MESON8_AUDIO_DSP_MEM_ID] = MEM_PD("AUDIO_DSP_MEM",
0281                         meson8_pwrc_audio_dsp_mem),
0282 };
0283 
0284 static struct meson_ee_pwrc_domain_desc sm1_pwrc_domains[] = {
0285     [PWRC_SM1_VPU_ID]  = VPU_PD("VPU", &sm1_pwrc_vpu, sm1_pwrc_mem_vpu,
0286                     pwrc_ee_is_powered_off, 11, 2),
0287     [PWRC_SM1_NNA_ID]  = TOP_PD("NNA", &sm1_pwrc_nna, sm1_pwrc_mem_nna,
0288                     pwrc_ee_is_powered_off),
0289     [PWRC_SM1_USB_ID]  = TOP_PD("USB", &sm1_pwrc_usb, sm1_pwrc_mem_usb,
0290                     pwrc_ee_is_powered_off),
0291     [PWRC_SM1_PCIE_ID] = TOP_PD("PCI", &sm1_pwrc_pci, sm1_pwrc_mem_pcie,
0292                     pwrc_ee_is_powered_off),
0293     [PWRC_SM1_GE2D_ID] = TOP_PD("GE2D", &sm1_pwrc_ge2d, sm1_pwrc_mem_ge2d,
0294                     pwrc_ee_is_powered_off),
0295     [PWRC_SM1_AUDIO_ID] = MEM_PD("AUDIO", sm1_pwrc_mem_audio),
0296     [PWRC_SM1_ETH_ID] = MEM_PD("ETH", meson_pwrc_mem_eth),
0297 };
0298 
0299 struct meson_ee_pwrc_domain {
0300     struct generic_pm_domain base;
0301     bool enabled;
0302     struct meson_ee_pwrc *pwrc;
0303     struct meson_ee_pwrc_domain_desc desc;
0304     struct clk_bulk_data *clks;
0305     int num_clks;
0306     struct reset_control *rstc;
0307     int num_rstc;
0308 };
0309 
0310 struct meson_ee_pwrc {
0311     struct regmap *regmap_ao;
0312     struct regmap *regmap_hhi;
0313     struct meson_ee_pwrc_domain *domains;
0314     struct genpd_onecell_data xlate;
0315 };
0316 
0317 static bool pwrc_ee_is_powered_off(struct meson_ee_pwrc_domain *pwrc_domain)
0318 {
0319     u32 reg;
0320 
0321     regmap_read(pwrc_domain->pwrc->regmap_ao,
0322             pwrc_domain->desc.top_pd->sleep_reg, &reg);
0323 
0324     return (reg & pwrc_domain->desc.top_pd->sleep_mask);
0325 }
0326 
0327 static int meson_ee_pwrc_off(struct generic_pm_domain *domain)
0328 {
0329     struct meson_ee_pwrc_domain *pwrc_domain =
0330         container_of(domain, struct meson_ee_pwrc_domain, base);
0331     int i;
0332 
0333     if (pwrc_domain->desc.top_pd)
0334         regmap_update_bits(pwrc_domain->pwrc->regmap_ao,
0335                    pwrc_domain->desc.top_pd->sleep_reg,
0336                    pwrc_domain->desc.top_pd->sleep_mask,
0337                    pwrc_domain->desc.top_pd->sleep_mask);
0338     udelay(20);
0339 
0340     for (i = 0 ; i < pwrc_domain->desc.mem_pd_count ; ++i)
0341         regmap_update_bits(pwrc_domain->pwrc->regmap_hhi,
0342                    pwrc_domain->desc.mem_pd[i].reg,
0343                    pwrc_domain->desc.mem_pd[i].mask,
0344                    pwrc_domain->desc.mem_pd[i].mask);
0345 
0346     udelay(20);
0347 
0348     if (pwrc_domain->desc.top_pd)
0349         regmap_update_bits(pwrc_domain->pwrc->regmap_ao,
0350                    pwrc_domain->desc.top_pd->iso_reg,
0351                    pwrc_domain->desc.top_pd->iso_mask,
0352                    pwrc_domain->desc.top_pd->iso_mask);
0353 
0354     if (pwrc_domain->num_clks) {
0355         msleep(20);
0356         clk_bulk_disable_unprepare(pwrc_domain->num_clks,
0357                        pwrc_domain->clks);
0358     }
0359 
0360     return 0;
0361 }
0362 
0363 static int meson_ee_pwrc_on(struct generic_pm_domain *domain)
0364 {
0365     struct meson_ee_pwrc_domain *pwrc_domain =
0366         container_of(domain, struct meson_ee_pwrc_domain, base);
0367     int i, ret;
0368 
0369     if (pwrc_domain->desc.top_pd)
0370         regmap_update_bits(pwrc_domain->pwrc->regmap_ao,
0371                    pwrc_domain->desc.top_pd->sleep_reg,
0372                    pwrc_domain->desc.top_pd->sleep_mask, 0);
0373     udelay(20);
0374 
0375     for (i = 0 ; i < pwrc_domain->desc.mem_pd_count ; ++i)
0376         regmap_update_bits(pwrc_domain->pwrc->regmap_hhi,
0377                    pwrc_domain->desc.mem_pd[i].reg,
0378                    pwrc_domain->desc.mem_pd[i].mask, 0);
0379 
0380     udelay(20);
0381 
0382     ret = reset_control_assert(pwrc_domain->rstc);
0383     if (ret)
0384         return ret;
0385 
0386     if (pwrc_domain->desc.top_pd)
0387         regmap_update_bits(pwrc_domain->pwrc->regmap_ao,
0388                    pwrc_domain->desc.top_pd->iso_reg,
0389                    pwrc_domain->desc.top_pd->iso_mask, 0);
0390 
0391     ret = reset_control_deassert(pwrc_domain->rstc);
0392     if (ret)
0393         return ret;
0394 
0395     return clk_bulk_prepare_enable(pwrc_domain->num_clks,
0396                        pwrc_domain->clks);
0397 }
0398 
0399 static int meson_ee_pwrc_init_domain(struct platform_device *pdev,
0400                      struct meson_ee_pwrc *pwrc,
0401                      struct meson_ee_pwrc_domain *dom)
0402 {
0403     int ret;
0404 
0405     dom->pwrc = pwrc;
0406     dom->num_rstc = dom->desc.reset_names_count;
0407     dom->num_clks = dom->desc.clk_names_count;
0408 
0409     if (dom->num_rstc) {
0410         int count = reset_control_get_count(&pdev->dev);
0411 
0412         if (count != dom->num_rstc)
0413             dev_warn(&pdev->dev, "Invalid resets count %d for domain %s\n",
0414                  count, dom->desc.name);
0415 
0416         dom->rstc = devm_reset_control_array_get_exclusive(&pdev->dev);
0417         if (IS_ERR(dom->rstc))
0418             return PTR_ERR(dom->rstc);
0419     }
0420 
0421     if (dom->num_clks) {
0422         int ret = devm_clk_bulk_get_all(&pdev->dev, &dom->clks);
0423         if (ret < 0)
0424             return ret;
0425 
0426         if (dom->num_clks != ret) {
0427             dev_warn(&pdev->dev, "Invalid clocks count %d for domain %s\n",
0428                  ret, dom->desc.name);
0429             dom->num_clks = ret;
0430         }
0431     }
0432 
0433     dom->base.name = dom->desc.name;
0434     dom->base.power_on = meson_ee_pwrc_on;
0435     dom->base.power_off = meson_ee_pwrc_off;
0436 
0437     /*
0438          * TOFIX: This is a special case for the VPU power domain, which can
0439      * be enabled previously by the bootloader. In this case the VPU
0440          * pipeline may be functional but no driver maybe never attach
0441          * to this power domain, and if the domain is disabled it could
0442          * cause system errors. This is why the pm_domain_always_on_gov
0443          * is used here.
0444          * For the same reason, the clocks should be enabled in case
0445          * we need to power the domain off, otherwise the internal clocks
0446          * prepare/enable counters won't be in sync.
0447          */
0448     if (dom->num_clks && dom->desc.is_powered_off && !dom->desc.is_powered_off(dom)) {
0449         ret = clk_bulk_prepare_enable(dom->num_clks, dom->clks);
0450         if (ret)
0451             return ret;
0452 
0453         dom->base.flags = GENPD_FLAG_ALWAYS_ON;
0454         ret = pm_genpd_init(&dom->base, NULL, false);
0455         if (ret)
0456             return ret;
0457     } else {
0458         ret = pm_genpd_init(&dom->base, NULL,
0459                     (dom->desc.is_powered_off ?
0460                      dom->desc.is_powered_off(dom) : true));
0461         if (ret)
0462             return ret;
0463     }
0464 
0465     return 0;
0466 }
0467 
0468 static int meson_ee_pwrc_probe(struct platform_device *pdev)
0469 {
0470     const struct meson_ee_pwrc_domain_data *match;
0471     struct regmap *regmap_ao, *regmap_hhi;
0472     struct meson_ee_pwrc *pwrc;
0473     int i, ret;
0474 
0475     match = of_device_get_match_data(&pdev->dev);
0476     if (!match) {
0477         dev_err(&pdev->dev, "failed to get match data\n");
0478         return -ENODEV;
0479     }
0480 
0481     pwrc = devm_kzalloc(&pdev->dev, sizeof(*pwrc), GFP_KERNEL);
0482     if (!pwrc)
0483         return -ENOMEM;
0484 
0485     pwrc->xlate.domains = devm_kcalloc(&pdev->dev, match->count,
0486                        sizeof(*pwrc->xlate.domains),
0487                        GFP_KERNEL);
0488     if (!pwrc->xlate.domains)
0489         return -ENOMEM;
0490 
0491     pwrc->domains = devm_kcalloc(&pdev->dev, match->count,
0492                      sizeof(*pwrc->domains), GFP_KERNEL);
0493     if (!pwrc->domains)
0494         return -ENOMEM;
0495 
0496     pwrc->xlate.num_domains = match->count;
0497 
0498     regmap_hhi = syscon_node_to_regmap(of_get_parent(pdev->dev.of_node));
0499     if (IS_ERR(regmap_hhi)) {
0500         dev_err(&pdev->dev, "failed to get HHI regmap\n");
0501         return PTR_ERR(regmap_hhi);
0502     }
0503 
0504     regmap_ao = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
0505                             "amlogic,ao-sysctrl");
0506     if (IS_ERR(regmap_ao)) {
0507         dev_err(&pdev->dev, "failed to get AO regmap\n");
0508         return PTR_ERR(regmap_ao);
0509     }
0510 
0511     pwrc->regmap_ao = regmap_ao;
0512     pwrc->regmap_hhi = regmap_hhi;
0513 
0514     platform_set_drvdata(pdev, pwrc);
0515 
0516     for (i = 0 ; i < match->count ; ++i) {
0517         struct meson_ee_pwrc_domain *dom = &pwrc->domains[i];
0518 
0519         memcpy(&dom->desc, &match->domains[i], sizeof(dom->desc));
0520 
0521         ret = meson_ee_pwrc_init_domain(pdev, pwrc, dom);
0522         if (ret)
0523             return ret;
0524 
0525         pwrc->xlate.domains[i] = &dom->base;
0526     }
0527 
0528     return of_genpd_add_provider_onecell(pdev->dev.of_node, &pwrc->xlate);
0529 }
0530 
0531 static void meson_ee_pwrc_shutdown(struct platform_device *pdev)
0532 {
0533     struct meson_ee_pwrc *pwrc = platform_get_drvdata(pdev);
0534     int i;
0535 
0536     for (i = 0 ; i < pwrc->xlate.num_domains ; ++i) {
0537         struct meson_ee_pwrc_domain *dom = &pwrc->domains[i];
0538 
0539         if (dom->desc.is_powered_off && !dom->desc.is_powered_off(dom))
0540             meson_ee_pwrc_off(&dom->base);
0541     }
0542 }
0543 
0544 static struct meson_ee_pwrc_domain_data meson_ee_g12a_pwrc_data = {
0545     .count = ARRAY_SIZE(g12a_pwrc_domains),
0546     .domains = g12a_pwrc_domains,
0547 };
0548 
0549 static struct meson_ee_pwrc_domain_data meson_ee_axg_pwrc_data = {
0550     .count = ARRAY_SIZE(axg_pwrc_domains),
0551     .domains = axg_pwrc_domains,
0552 };
0553 
0554 static struct meson_ee_pwrc_domain_data meson_ee_gxbb_pwrc_data = {
0555     .count = ARRAY_SIZE(gxbb_pwrc_domains),
0556     .domains = gxbb_pwrc_domains,
0557 };
0558 
0559 static struct meson_ee_pwrc_domain_data meson_ee_m8_pwrc_data = {
0560     .count = ARRAY_SIZE(meson8_pwrc_domains),
0561     .domains = meson8_pwrc_domains,
0562 };
0563 
0564 static struct meson_ee_pwrc_domain_data meson_ee_m8b_pwrc_data = {
0565     .count = ARRAY_SIZE(meson8b_pwrc_domains),
0566     .domains = meson8b_pwrc_domains,
0567 };
0568 
0569 static struct meson_ee_pwrc_domain_data meson_ee_sm1_pwrc_data = {
0570     .count = ARRAY_SIZE(sm1_pwrc_domains),
0571     .domains = sm1_pwrc_domains,
0572 };
0573 
0574 static const struct of_device_id meson_ee_pwrc_match_table[] = {
0575     {
0576         .compatible = "amlogic,meson8-pwrc",
0577         .data = &meson_ee_m8_pwrc_data,
0578     },
0579     {
0580         .compatible = "amlogic,meson8b-pwrc",
0581         .data = &meson_ee_m8b_pwrc_data,
0582     },
0583     {
0584         .compatible = "amlogic,meson8m2-pwrc",
0585         .data = &meson_ee_m8b_pwrc_data,
0586     },
0587     {
0588         .compatible = "amlogic,meson-axg-pwrc",
0589         .data = &meson_ee_axg_pwrc_data,
0590     },
0591     {
0592         .compatible = "amlogic,meson-gxbb-pwrc",
0593         .data = &meson_ee_gxbb_pwrc_data,
0594     },
0595     {
0596         .compatible = "amlogic,meson-g12a-pwrc",
0597         .data = &meson_ee_g12a_pwrc_data,
0598     },
0599     {
0600         .compatible = "amlogic,meson-sm1-pwrc",
0601         .data = &meson_ee_sm1_pwrc_data,
0602     },
0603     { /* sentinel */ }
0604 };
0605 MODULE_DEVICE_TABLE(of, meson_ee_pwrc_match_table);
0606 
0607 static struct platform_driver meson_ee_pwrc_driver = {
0608     .probe = meson_ee_pwrc_probe,
0609     .shutdown = meson_ee_pwrc_shutdown,
0610     .driver = {
0611         .name       = "meson_ee_pwrc",
0612         .of_match_table = meson_ee_pwrc_match_table,
0613     },
0614 };
0615 module_platform_driver(meson_ee_pwrc_driver);
0616 MODULE_LICENSE("GPL v2");