brintos

brintos / linux-shallow public Read only

0
0
Text · 18.6 KiB · fbb2b41 Raw
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, &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