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/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 the
30 * AO-bus as syscon. 0x3a from GX translates to 0x02, 0x3b translates to 0x03
31 * 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 can
471	 * be enabled previously by the bootloader. In this case the VPU
472         * pipeline may be functional but no driver maybe never attach
473         * to this power domain, and if the domain is disabled it could
474         * cause system errors. This is why the pm_domain_always_on_gov
475         * is used here.
476         * For the same reason, the clocks should be enabled in case
477         * we need to power the domain off, otherwise the internal clocks
478         * 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_LICENSE("GPL v2");
652