cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

meson-ee-pwrc.c (17837B)


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