653 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Copyright (c) 2019 BayLibre, SAS4 * Author: Neil Armstrong <narmstrong@baylibre.com>5 */6 7#include <linux/platform_device.h>8#include <linux/pm_domain.h>9#include <linux/bitfield.h>10#include <linux/regmap.h>11#include <linux/mfd/syscon.h>12#include <linux/of.h>13#include <linux/reset-controller.h>14#include <linux/reset.h>15#include <linux/clk.h>16#include <linux/module.h>17#include <dt-bindings/power/meson8-power.h>18#include <dt-bindings/power/meson-axg-power.h>19#include <dt-bindings/power/meson-g12a-power.h>20#include <dt-bindings/power/meson-gxbb-power.h>21#include <dt-bindings/power/meson-sm1-power.h>22 23/* AO Offsets */24 25#define GX_AO_RTI_GEN_PWR_SLEEP0 (0x3a << 2)26#define GX_AO_RTI_GEN_PWR_ISO0 (0x3b << 2)27 28/*29 * Meson8/Meson8b/Meson8m2 only expose the power management registers of the30 * AO-bus as syscon. 0x3a from GX translates to 0x02, 0x3b translates to 0x0331 * and so on.32 */33#define MESON8_AO_RTI_GEN_PWR_SLEEP0 (0x02 << 2)34#define MESON8_AO_RTI_GEN_PWR_ISO0 (0x03 << 2)35 36/* HHI Offsets */37 38#define HHI_MEM_PD_REG0 (0x40 << 2)39#define HHI_VPU_MEM_PD_REG0 (0x41 << 2)40#define HHI_VPU_MEM_PD_REG1 (0x42 << 2)41#define HHI_VPU_MEM_PD_REG3 (0x43 << 2)42#define HHI_VPU_MEM_PD_REG4 (0x44 << 2)43#define HHI_AUDIO_MEM_PD_REG0 (0x45 << 2)44#define HHI_NANOQ_MEM_PD_REG0 (0x46 << 2)45#define HHI_NANOQ_MEM_PD_REG1 (0x47 << 2)46#define HHI_VPU_MEM_PD_REG2 (0x4d << 2)47 48#define G12A_HHI_NANOQ_MEM_PD_REG0 (0x43 << 2)49#define G12A_HHI_NANOQ_MEM_PD_REG1 (0x44 << 2)50#define G12A_HHI_ISP_MEM_PD_REG0 (0x45 << 2)51#define G12A_HHI_ISP_MEM_PD_REG1 (0x46 << 2)52 53struct meson_ee_pwrc;54struct meson_ee_pwrc_domain;55 56struct meson_ee_pwrc_mem_domain {57 unsigned int reg;58 unsigned int mask;59};60 61struct meson_ee_pwrc_top_domain {62 unsigned int sleep_reg;63 unsigned int sleep_mask;64 unsigned int iso_reg;65 unsigned int iso_mask;66};67 68struct meson_ee_pwrc_domain_desc {69 char *name;70 unsigned int reset_names_count;71 unsigned int clk_names_count;72 struct meson_ee_pwrc_top_domain *top_pd;73 unsigned int mem_pd_count;74 struct meson_ee_pwrc_mem_domain *mem_pd;75 bool (*is_powered_off)(struct meson_ee_pwrc_domain *pwrc_domain);76};77 78struct meson_ee_pwrc_domain_data {79 unsigned int count;80 struct meson_ee_pwrc_domain_desc *domains;81};82 83/* TOP Power Domains */84 85static struct meson_ee_pwrc_top_domain gx_pwrc_vpu = {86 .sleep_reg = GX_AO_RTI_GEN_PWR_SLEEP0,87 .sleep_mask = BIT(8),88 .iso_reg = GX_AO_RTI_GEN_PWR_SLEEP0,89 .iso_mask = BIT(9),90};91 92static struct meson_ee_pwrc_top_domain meson8_pwrc_vpu = {93 .sleep_reg = MESON8_AO_RTI_GEN_PWR_SLEEP0,94 .sleep_mask = BIT(8),95 .iso_reg = MESON8_AO_RTI_GEN_PWR_SLEEP0,96 .iso_mask = BIT(9),97};98 99#define SM1_EE_PD(__bit) \100 { \101 .sleep_reg = GX_AO_RTI_GEN_PWR_SLEEP0, \102 .sleep_mask = BIT(__bit), \103 .iso_reg = GX_AO_RTI_GEN_PWR_ISO0, \104 .iso_mask = BIT(__bit), \105 }106 107static struct meson_ee_pwrc_top_domain sm1_pwrc_vpu = SM1_EE_PD(8);108static struct meson_ee_pwrc_top_domain sm1_pwrc_nna = SM1_EE_PD(16);109static struct meson_ee_pwrc_top_domain sm1_pwrc_usb = SM1_EE_PD(17);110static struct meson_ee_pwrc_top_domain sm1_pwrc_pci = SM1_EE_PD(18);111static struct meson_ee_pwrc_top_domain sm1_pwrc_ge2d = SM1_EE_PD(19);112 113static struct meson_ee_pwrc_top_domain g12a_pwrc_nna = {114 .sleep_reg = GX_AO_RTI_GEN_PWR_SLEEP0,115 .sleep_mask = BIT(16) | BIT(17),116 .iso_reg = GX_AO_RTI_GEN_PWR_ISO0,117 .iso_mask = BIT(16) | BIT(17),118};119 120static struct meson_ee_pwrc_top_domain g12a_pwrc_isp = {121 .sleep_reg = GX_AO_RTI_GEN_PWR_SLEEP0,122 .sleep_mask = BIT(18) | BIT(19),123 .iso_reg = GX_AO_RTI_GEN_PWR_ISO0,124 .iso_mask = BIT(18) | BIT(19),125};126 127/* Memory PD Domains */128 129#define VPU_MEMPD(__reg) \130 { __reg, GENMASK(1, 0) }, \131 { __reg, GENMASK(3, 2) }, \132 { __reg, GENMASK(5, 4) }, \133 { __reg, GENMASK(7, 6) }, \134 { __reg, GENMASK(9, 8) }, \135 { __reg, GENMASK(11, 10) }, \136 { __reg, GENMASK(13, 12) }, \137 { __reg, GENMASK(15, 14) }, \138 { __reg, GENMASK(17, 16) }, \139 { __reg, GENMASK(19, 18) }, \140 { __reg, GENMASK(21, 20) }, \141 { __reg, GENMASK(23, 22) }, \142 { __reg, GENMASK(25, 24) }, \143 { __reg, GENMASK(27, 26) }, \144 { __reg, GENMASK(29, 28) }, \145 { __reg, GENMASK(31, 30) }146 147#define VPU_HHI_MEMPD(__reg) \148 { __reg, BIT(8) }, \149 { __reg, BIT(9) }, \150 { __reg, BIT(10) }, \151 { __reg, BIT(11) }, \152 { __reg, BIT(12) }, \153 { __reg, BIT(13) }, \154 { __reg, BIT(14) }, \155 { __reg, BIT(15) }156 157static struct meson_ee_pwrc_mem_domain axg_pwrc_mem_vpu[] = {158 VPU_MEMPD(HHI_VPU_MEM_PD_REG0),159 VPU_HHI_MEMPD(HHI_MEM_PD_REG0),160};161 162static struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_vpu[] = {163 VPU_MEMPD(HHI_VPU_MEM_PD_REG0),164 VPU_MEMPD(HHI_VPU_MEM_PD_REG1),165 VPU_MEMPD(HHI_VPU_MEM_PD_REG2),166 VPU_HHI_MEMPD(HHI_MEM_PD_REG0),167};168 169static struct meson_ee_pwrc_mem_domain gxbb_pwrc_mem_vpu[] = {170 VPU_MEMPD(HHI_VPU_MEM_PD_REG0),171 VPU_MEMPD(HHI_VPU_MEM_PD_REG1),172 VPU_HHI_MEMPD(HHI_MEM_PD_REG0),173};174 175static struct meson_ee_pwrc_mem_domain meson_pwrc_mem_eth[] = {176 { HHI_MEM_PD_REG0, GENMASK(3, 2) },177};178 179static struct meson_ee_pwrc_mem_domain meson8_pwrc_audio_dsp_mem[] = {180 { HHI_MEM_PD_REG0, GENMASK(1, 0) },181};182 183static struct meson_ee_pwrc_mem_domain meson8_pwrc_mem_vpu[] = {184 VPU_MEMPD(HHI_VPU_MEM_PD_REG0),185 VPU_MEMPD(HHI_VPU_MEM_PD_REG1),186 VPU_HHI_MEMPD(HHI_MEM_PD_REG0),187};188 189static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_vpu[] = {190 VPU_MEMPD(HHI_VPU_MEM_PD_REG0),191 VPU_MEMPD(HHI_VPU_MEM_PD_REG1),192 VPU_MEMPD(HHI_VPU_MEM_PD_REG2),193 VPU_MEMPD(HHI_VPU_MEM_PD_REG3),194 { HHI_VPU_MEM_PD_REG4, GENMASK(1, 0) },195 { HHI_VPU_MEM_PD_REG4, GENMASK(3, 2) },196 { HHI_VPU_MEM_PD_REG4, GENMASK(5, 4) },197 { HHI_VPU_MEM_PD_REG4, GENMASK(7, 6) },198 VPU_HHI_MEMPD(HHI_MEM_PD_REG0),199};200 201static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_nna[] = {202 { HHI_NANOQ_MEM_PD_REG0, 0xff },203 { HHI_NANOQ_MEM_PD_REG1, 0xff },204};205 206static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_usb[] = {207 { HHI_MEM_PD_REG0, GENMASK(31, 30) },208};209 210static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_pcie[] = {211 { HHI_MEM_PD_REG0, GENMASK(29, 26) },212};213 214static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_ge2d[] = {215 { HHI_MEM_PD_REG0, GENMASK(25, 18) },216};217 218static struct meson_ee_pwrc_mem_domain axg_pwrc_mem_audio[] = {219 { HHI_MEM_PD_REG0, GENMASK(5, 4) },220};221 222static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_audio[] = {223 { HHI_MEM_PD_REG0, GENMASK(5, 4) },224 { HHI_AUDIO_MEM_PD_REG0, GENMASK(1, 0) },225 { HHI_AUDIO_MEM_PD_REG0, GENMASK(3, 2) },226 { HHI_AUDIO_MEM_PD_REG0, GENMASK(5, 4) },227 { HHI_AUDIO_MEM_PD_REG0, GENMASK(7, 6) },228 { HHI_AUDIO_MEM_PD_REG0, GENMASK(13, 12) },229 { HHI_AUDIO_MEM_PD_REG0, GENMASK(15, 14) },230 { HHI_AUDIO_MEM_PD_REG0, GENMASK(17, 16) },231 { HHI_AUDIO_MEM_PD_REG0, GENMASK(19, 18) },232 { HHI_AUDIO_MEM_PD_REG0, GENMASK(21, 20) },233 { HHI_AUDIO_MEM_PD_REG0, GENMASK(23, 22) },234 { HHI_AUDIO_MEM_PD_REG0, GENMASK(25, 24) },235 { HHI_AUDIO_MEM_PD_REG0, GENMASK(27, 26) },236};237 238static struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_nna[] = {239 { G12A_HHI_NANOQ_MEM_PD_REG0, GENMASK(31, 0) },240 { G12A_HHI_NANOQ_MEM_PD_REG1, GENMASK(31, 0) },241};242 243static struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_isp[] = {244 { G12A_HHI_ISP_MEM_PD_REG0, GENMASK(31, 0) },245 { G12A_HHI_ISP_MEM_PD_REG1, GENMASK(31, 0) },246};247 248#define VPU_PD(__name, __top_pd, __mem, __is_pwr_off, __resets, __clks) \249 { \250 .name = __name, \251 .reset_names_count = __resets, \252 .clk_names_count = __clks, \253 .top_pd = __top_pd, \254 .mem_pd_count = ARRAY_SIZE(__mem), \255 .mem_pd = __mem, \256 .is_powered_off = __is_pwr_off, \257 }258 259#define TOP_PD(__name, __top_pd, __mem, __is_pwr_off) \260 { \261 .name = __name, \262 .top_pd = __top_pd, \263 .mem_pd_count = ARRAY_SIZE(__mem), \264 .mem_pd = __mem, \265 .is_powered_off = __is_pwr_off, \266 }267 268#define MEM_PD(__name, __mem) \269 TOP_PD(__name, NULL, __mem, NULL)270 271static bool pwrc_ee_is_powered_off(struct meson_ee_pwrc_domain *pwrc_domain);272 273static struct meson_ee_pwrc_domain_desc axg_pwrc_domains[] = {274 [PWRC_AXG_VPU_ID] = VPU_PD("VPU", &gx_pwrc_vpu, axg_pwrc_mem_vpu,275 pwrc_ee_is_powered_off, 5, 2),276 [PWRC_AXG_ETHERNET_MEM_ID] = MEM_PD("ETH", meson_pwrc_mem_eth),277 [PWRC_AXG_AUDIO_ID] = MEM_PD("AUDIO", axg_pwrc_mem_audio),278};279 280static struct meson_ee_pwrc_domain_desc g12a_pwrc_domains[] = {281 [PWRC_G12A_VPU_ID] = VPU_PD("VPU", &gx_pwrc_vpu, g12a_pwrc_mem_vpu,282 pwrc_ee_is_powered_off, 11, 2),283 [PWRC_G12A_ETH_ID] = MEM_PD("ETH", meson_pwrc_mem_eth),284 [PWRC_G12A_NNA_ID] = TOP_PD("NNA", &g12a_pwrc_nna, g12a_pwrc_mem_nna,285 pwrc_ee_is_powered_off),286 [PWRC_G12A_ISP_ID] = TOP_PD("ISP", &g12a_pwrc_isp, g12a_pwrc_mem_isp,287 pwrc_ee_is_powered_off),288};289 290static struct meson_ee_pwrc_domain_desc gxbb_pwrc_domains[] = {291 [PWRC_GXBB_VPU_ID] = VPU_PD("VPU", &gx_pwrc_vpu, gxbb_pwrc_mem_vpu,292 pwrc_ee_is_powered_off, 12, 2),293 [PWRC_GXBB_ETHERNET_MEM_ID] = MEM_PD("ETH", meson_pwrc_mem_eth),294};295 296static struct meson_ee_pwrc_domain_desc meson8_pwrc_domains[] = {297 [PWRC_MESON8_VPU_ID] = VPU_PD("VPU", &meson8_pwrc_vpu,298 meson8_pwrc_mem_vpu,299 pwrc_ee_is_powered_off, 0, 1),300 [PWRC_MESON8_ETHERNET_MEM_ID] = MEM_PD("ETHERNET_MEM",301 meson_pwrc_mem_eth),302 [PWRC_MESON8_AUDIO_DSP_MEM_ID] = MEM_PD("AUDIO_DSP_MEM",303 meson8_pwrc_audio_dsp_mem),304};305 306static struct meson_ee_pwrc_domain_desc meson8b_pwrc_domains[] = {307 [PWRC_MESON8_VPU_ID] = VPU_PD("VPU", &meson8_pwrc_vpu,308 meson8_pwrc_mem_vpu,309 pwrc_ee_is_powered_off, 11, 1),310 [PWRC_MESON8_ETHERNET_MEM_ID] = MEM_PD("ETHERNET_MEM",311 meson_pwrc_mem_eth),312 [PWRC_MESON8_AUDIO_DSP_MEM_ID] = MEM_PD("AUDIO_DSP_MEM",313 meson8_pwrc_audio_dsp_mem),314};315 316static struct meson_ee_pwrc_domain_desc sm1_pwrc_domains[] = {317 [PWRC_SM1_VPU_ID] = VPU_PD("VPU", &sm1_pwrc_vpu, sm1_pwrc_mem_vpu,318 pwrc_ee_is_powered_off, 11, 2),319 [PWRC_SM1_NNA_ID] = TOP_PD("NNA", &sm1_pwrc_nna, sm1_pwrc_mem_nna,320 pwrc_ee_is_powered_off),321 [PWRC_SM1_USB_ID] = TOP_PD("USB", &sm1_pwrc_usb, sm1_pwrc_mem_usb,322 pwrc_ee_is_powered_off),323 [PWRC_SM1_PCIE_ID] = TOP_PD("PCI", &sm1_pwrc_pci, sm1_pwrc_mem_pcie,324 pwrc_ee_is_powered_off),325 [PWRC_SM1_GE2D_ID] = TOP_PD("GE2D", &sm1_pwrc_ge2d, sm1_pwrc_mem_ge2d,326 pwrc_ee_is_powered_off),327 [PWRC_SM1_AUDIO_ID] = MEM_PD("AUDIO", sm1_pwrc_mem_audio),328 [PWRC_SM1_ETH_ID] = MEM_PD("ETH", meson_pwrc_mem_eth),329};330 331struct meson_ee_pwrc_domain {332 struct generic_pm_domain base;333 bool enabled;334 struct meson_ee_pwrc *pwrc;335 struct meson_ee_pwrc_domain_desc desc;336 struct clk_bulk_data *clks;337 int num_clks;338 struct reset_control *rstc;339 int num_rstc;340};341 342struct meson_ee_pwrc {343 struct regmap *regmap_ao;344 struct regmap *regmap_hhi;345 struct meson_ee_pwrc_domain *domains;346 struct genpd_onecell_data xlate;347};348 349static bool pwrc_ee_is_powered_off(struct meson_ee_pwrc_domain *pwrc_domain)350{351 u32 reg;352 353 regmap_read(pwrc_domain->pwrc->regmap_ao,354 pwrc_domain->desc.top_pd->sleep_reg, ®);355 356 return (reg & pwrc_domain->desc.top_pd->sleep_mask);357}358 359static int meson_ee_pwrc_off(struct generic_pm_domain *domain)360{361 struct meson_ee_pwrc_domain *pwrc_domain =362 container_of(domain, struct meson_ee_pwrc_domain, base);363 int i;364 365 if (pwrc_domain->desc.top_pd)366 regmap_update_bits(pwrc_domain->pwrc->regmap_ao,367 pwrc_domain->desc.top_pd->sleep_reg,368 pwrc_domain->desc.top_pd->sleep_mask,369 pwrc_domain->desc.top_pd->sleep_mask);370 udelay(20);371 372 for (i = 0 ; i < pwrc_domain->desc.mem_pd_count ; ++i)373 regmap_update_bits(pwrc_domain->pwrc->regmap_hhi,374 pwrc_domain->desc.mem_pd[i].reg,375 pwrc_domain->desc.mem_pd[i].mask,376 pwrc_domain->desc.mem_pd[i].mask);377 378 udelay(20);379 380 if (pwrc_domain->desc.top_pd)381 regmap_update_bits(pwrc_domain->pwrc->regmap_ao,382 pwrc_domain->desc.top_pd->iso_reg,383 pwrc_domain->desc.top_pd->iso_mask,384 pwrc_domain->desc.top_pd->iso_mask);385 386 if (pwrc_domain->num_clks) {387 msleep(20);388 clk_bulk_disable_unprepare(pwrc_domain->num_clks,389 pwrc_domain->clks);390 }391 392 return 0;393}394 395static int meson_ee_pwrc_on(struct generic_pm_domain *domain)396{397 struct meson_ee_pwrc_domain *pwrc_domain =398 container_of(domain, struct meson_ee_pwrc_domain, base);399 int i, ret;400 401 if (pwrc_domain->desc.top_pd)402 regmap_update_bits(pwrc_domain->pwrc->regmap_ao,403 pwrc_domain->desc.top_pd->sleep_reg,404 pwrc_domain->desc.top_pd->sleep_mask, 0);405 udelay(20);406 407 for (i = 0 ; i < pwrc_domain->desc.mem_pd_count ; ++i)408 regmap_update_bits(pwrc_domain->pwrc->regmap_hhi,409 pwrc_domain->desc.mem_pd[i].reg,410 pwrc_domain->desc.mem_pd[i].mask, 0);411 412 udelay(20);413 414 ret = reset_control_assert(pwrc_domain->rstc);415 if (ret)416 return ret;417 418 if (pwrc_domain->desc.top_pd)419 regmap_update_bits(pwrc_domain->pwrc->regmap_ao,420 pwrc_domain->desc.top_pd->iso_reg,421 pwrc_domain->desc.top_pd->iso_mask, 0);422 423 ret = reset_control_deassert(pwrc_domain->rstc);424 if (ret)425 return ret;426 427 return clk_bulk_prepare_enable(pwrc_domain->num_clks,428 pwrc_domain->clks);429}430 431static int meson_ee_pwrc_init_domain(struct platform_device *pdev,432 struct meson_ee_pwrc *pwrc,433 struct meson_ee_pwrc_domain *dom)434{435 int ret;436 437 dom->pwrc = pwrc;438 dom->num_rstc = dom->desc.reset_names_count;439 dom->num_clks = dom->desc.clk_names_count;440 441 if (dom->num_rstc) {442 int count = reset_control_get_count(&pdev->dev);443 444 if (count != dom->num_rstc)445 dev_warn(&pdev->dev, "Invalid resets count %d for domain %s\n",446 count, dom->desc.name);447 448 dom->rstc = devm_reset_control_array_get_exclusive(&pdev->dev);449 if (IS_ERR(dom->rstc))450 return PTR_ERR(dom->rstc);451 }452 453 if (dom->num_clks) {454 int ret = devm_clk_bulk_get_all(&pdev->dev, &dom->clks);455 if (ret < 0)456 return ret;457 458 if (dom->num_clks != ret) {459 dev_warn(&pdev->dev, "Invalid clocks count %d for domain %s\n",460 ret, dom->desc.name);461 dom->num_clks = ret;462 }463 }464 465 dom->base.name = dom->desc.name;466 dom->base.power_on = meson_ee_pwrc_on;467 dom->base.power_off = meson_ee_pwrc_off;468 469 /*470 * TOFIX: This is a special case for the VPU power domain, which can471 * be enabled previously by the bootloader. In this case the VPU472 * pipeline may be functional but no driver maybe never attach473 * to this power domain, and if the domain is disabled it could474 * cause system errors. This is why the pm_domain_always_on_gov475 * is used here.476 * For the same reason, the clocks should be enabled in case477 * we need to power the domain off, otherwise the internal clocks478 * prepare/enable counters won't be in sync.479 */480 if (dom->num_clks && dom->desc.is_powered_off && !dom->desc.is_powered_off(dom)) {481 ret = clk_bulk_prepare_enable(dom->num_clks, dom->clks);482 if (ret)483 return ret;484 485 dom->base.flags = GENPD_FLAG_ALWAYS_ON;486 ret = pm_genpd_init(&dom->base, NULL, false);487 if (ret)488 return ret;489 } else {490 ret = pm_genpd_init(&dom->base, NULL,491 (dom->desc.is_powered_off ?492 dom->desc.is_powered_off(dom) : true));493 if (ret)494 return ret;495 }496 497 return 0;498}499 500static int meson_ee_pwrc_probe(struct platform_device *pdev)501{502 const struct meson_ee_pwrc_domain_data *match;503 struct regmap *regmap_ao, *regmap_hhi;504 struct device_node *parent_np;505 struct meson_ee_pwrc *pwrc;506 int i, ret;507 508 match = of_device_get_match_data(&pdev->dev);509 if (!match) {510 dev_err(&pdev->dev, "failed to get match data\n");511 return -ENODEV;512 }513 514 pwrc = devm_kzalloc(&pdev->dev, sizeof(*pwrc), GFP_KERNEL);515 if (!pwrc)516 return -ENOMEM;517 518 pwrc->xlate.domains = devm_kcalloc(&pdev->dev, match->count,519 sizeof(*pwrc->xlate.domains),520 GFP_KERNEL);521 if (!pwrc->xlate.domains)522 return -ENOMEM;523 524 pwrc->domains = devm_kcalloc(&pdev->dev, match->count,525 sizeof(*pwrc->domains), GFP_KERNEL);526 if (!pwrc->domains)527 return -ENOMEM;528 529 pwrc->xlate.num_domains = match->count;530 531 parent_np = of_get_parent(pdev->dev.of_node);532 regmap_hhi = syscon_node_to_regmap(parent_np);533 of_node_put(parent_np);534 if (IS_ERR(regmap_hhi)) {535 dev_err(&pdev->dev, "failed to get HHI regmap\n");536 return PTR_ERR(regmap_hhi);537 }538 539 regmap_ao = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,540 "amlogic,ao-sysctrl");541 if (IS_ERR(regmap_ao)) {542 dev_err(&pdev->dev, "failed to get AO regmap\n");543 return PTR_ERR(regmap_ao);544 }545 546 pwrc->regmap_ao = regmap_ao;547 pwrc->regmap_hhi = regmap_hhi;548 549 platform_set_drvdata(pdev, pwrc);550 551 for (i = 0 ; i < match->count ; ++i) {552 struct meson_ee_pwrc_domain *dom = &pwrc->domains[i];553 554 memcpy(&dom->desc, &match->domains[i], sizeof(dom->desc));555 556 ret = meson_ee_pwrc_init_domain(pdev, pwrc, dom);557 if (ret)558 return ret;559 560 pwrc->xlate.domains[i] = &dom->base;561 }562 563 return of_genpd_add_provider_onecell(pdev->dev.of_node, &pwrc->xlate);564}565 566static void meson_ee_pwrc_shutdown(struct platform_device *pdev)567{568 struct meson_ee_pwrc *pwrc = platform_get_drvdata(pdev);569 int i;570 571 for (i = 0 ; i < pwrc->xlate.num_domains ; ++i) {572 struct meson_ee_pwrc_domain *dom = &pwrc->domains[i];573 574 if (dom->desc.is_powered_off && !dom->desc.is_powered_off(dom))575 meson_ee_pwrc_off(&dom->base);576 }577}578 579static struct meson_ee_pwrc_domain_data meson_ee_g12a_pwrc_data = {580 .count = ARRAY_SIZE(g12a_pwrc_domains),581 .domains = g12a_pwrc_domains,582};583 584static struct meson_ee_pwrc_domain_data meson_ee_axg_pwrc_data = {585 .count = ARRAY_SIZE(axg_pwrc_domains),586 .domains = axg_pwrc_domains,587};588 589static struct meson_ee_pwrc_domain_data meson_ee_gxbb_pwrc_data = {590 .count = ARRAY_SIZE(gxbb_pwrc_domains),591 .domains = gxbb_pwrc_domains,592};593 594static struct meson_ee_pwrc_domain_data meson_ee_m8_pwrc_data = {595 .count = ARRAY_SIZE(meson8_pwrc_domains),596 .domains = meson8_pwrc_domains,597};598 599static struct meson_ee_pwrc_domain_data meson_ee_m8b_pwrc_data = {600 .count = ARRAY_SIZE(meson8b_pwrc_domains),601 .domains = meson8b_pwrc_domains,602};603 604static struct meson_ee_pwrc_domain_data meson_ee_sm1_pwrc_data = {605 .count = ARRAY_SIZE(sm1_pwrc_domains),606 .domains = sm1_pwrc_domains,607};608 609static const struct of_device_id meson_ee_pwrc_match_table[] = {610 {611 .compatible = "amlogic,meson8-pwrc",612 .data = &meson_ee_m8_pwrc_data,613 },614 {615 .compatible = "amlogic,meson8b-pwrc",616 .data = &meson_ee_m8b_pwrc_data,617 },618 {619 .compatible = "amlogic,meson8m2-pwrc",620 .data = &meson_ee_m8b_pwrc_data,621 },622 {623 .compatible = "amlogic,meson-axg-pwrc",624 .data = &meson_ee_axg_pwrc_data,625 },626 {627 .compatible = "amlogic,meson-gxbb-pwrc",628 .data = &meson_ee_gxbb_pwrc_data,629 },630 {631 .compatible = "amlogic,meson-g12a-pwrc",632 .data = &meson_ee_g12a_pwrc_data,633 },634 {635 .compatible = "amlogic,meson-sm1-pwrc",636 .data = &meson_ee_sm1_pwrc_data,637 },638 { /* sentinel */ }639};640MODULE_DEVICE_TABLE(of, meson_ee_pwrc_match_table);641 642static struct platform_driver meson_ee_pwrc_driver = {643 .probe = meson_ee_pwrc_probe,644 .shutdown = meson_ee_pwrc_shutdown,645 .driver = {646 .name = "meson_ee_pwrc",647 .of_match_table = meson_ee_pwrc_match_table,648 },649};650module_platform_driver(meson_ee_pwrc_driver);651MODULE_DESCRIPTION("Amlogic Meson Everything-Else Power Domains driver");652MODULE_LICENSE("GPL v2");653