xref: /linux/drivers/pmdomain/bcm/bcm2835-power.c (revision c715f13bb30f9f4d1bd8888667ef32e43b6fedc1)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Power domain driver for Broadcom BCM2835
4  *
5  * Copyright (C) 2018 Broadcom
6  */
7 
8 #include <dt-bindings/soc/bcm2835-pm.h>
9 #include <linux/clk.h>
10 #include <linux/delay.h>
11 #include <linux/io.h>
12 #include <linux/iopoll.h>
13 #include <linux/mfd/bcm2835-pm.h>
14 #include <linux/module.h>
15 #include <linux/platform_device.h>
16 #include <linux/pm_domain.h>
17 #include <linux/reset-controller.h>
18 #include <linux/types.h>
19 
20 #define PM_GNRIC                        0x00
21 #define PM_AUDIO                        0x04
22 #define PM_STATUS                       0x18
23 #define PM_RSTC				0x1c
24 #define PM_RSTS				0x20
25 #define PM_WDOG				0x24
26 #define PM_PADS0			0x28
27 #define PM_PADS2			0x2c
28 #define PM_PADS3			0x30
29 #define PM_PADS4			0x34
30 #define PM_PADS5			0x38
31 #define PM_PADS6			0x3c
32 #define PM_CAM0				0x44
33 #define PM_CAM0_LDOHPEN			BIT(2)
34 #define PM_CAM0_LDOLPEN			BIT(1)
35 #define PM_CAM0_CTRLEN			BIT(0)
36 
37 #define PM_CAM1				0x48
38 #define PM_CAM1_LDOHPEN			BIT(2)
39 #define PM_CAM1_LDOLPEN			BIT(1)
40 #define PM_CAM1_CTRLEN			BIT(0)
41 
42 #define PM_CCP2TX			0x4c
43 #define PM_CCP2TX_LDOEN			BIT(1)
44 #define PM_CCP2TX_CTRLEN		BIT(0)
45 
46 #define PM_DSI0				0x50
47 #define PM_DSI0_LDOHPEN			BIT(2)
48 #define PM_DSI0_LDOLPEN			BIT(1)
49 #define PM_DSI0_CTRLEN			BIT(0)
50 
51 #define PM_DSI1				0x54
52 #define PM_DSI1_LDOHPEN			BIT(2)
53 #define PM_DSI1_LDOLPEN			BIT(1)
54 #define PM_DSI1_CTRLEN			BIT(0)
55 
56 #define PM_HDMI				0x58
57 #define PM_HDMI_RSTDR			BIT(19)
58 #define PM_HDMI_LDOPD			BIT(1)
59 #define PM_HDMI_CTRLEN			BIT(0)
60 
61 #define PM_USB				0x5c
62 /* The power gates must be enabled with this bit before enabling the LDO in the
63  * USB block.
64  */
65 #define PM_USB_CTRLEN			BIT(0)
66 
67 #define PM_PXLDO			0x60
68 #define PM_PXBG				0x64
69 #define PM_DFT				0x68
70 #define PM_SMPS				0x6c
71 #define PM_XOSC				0x70
72 #define PM_SPAREW			0x74
73 #define PM_SPARER			0x78
74 #define PM_AVS_RSTDR			0x7c
75 #define PM_AVS_STAT			0x80
76 #define PM_AVS_EVENT			0x84
77 #define PM_AVS_INTEN			0x88
78 #define PM_DUMMY			0xfc
79 
80 #define PM_IMAGE			0x108
81 #define PM_GRAFX			0x10c
82 #define PM_PROC				0x110
83 #define PM_GRAFX_2712			0x304
84 #define PM_ENAB				BIT(12)
85 #define PM_ISPRSTN			BIT(8)
86 #define PM_H264RSTN			BIT(7)
87 #define PM_PERIRSTN			BIT(6)
88 #define PM_V3DRSTN			BIT(6)
89 #define PM_ISFUNC			BIT(5)
90 #define PM_MRDONE			BIT(4)
91 #define PM_MEMREP			BIT(3)
92 #define PM_ISPOW			BIT(2)
93 #define PM_POWOK			BIT(1)
94 #define PM_POWUP			BIT(0)
95 #define PM_INRUSH_SHIFT			13
96 #define PM_INRUSH_3_5_MA		0
97 #define PM_INRUSH_5_MA			1
98 #define PM_INRUSH_10_MA			2
99 #define PM_INRUSH_20_MA			3
100 #define PM_INRUSH_MASK			(3 << PM_INRUSH_SHIFT)
101 
102 #define PM_PASSWORD			0x5a000000
103 
104 #define PM_WDOG_TIME_SET		0x000fffff
105 #define PM_RSTC_WRCFG_CLR		0xffffffcf
106 #define PM_RSTS_HADWRH_SET		0x00000040
107 #define PM_RSTC_WRCFG_SET		0x00000030
108 #define PM_RSTC_WRCFG_FULL_RESET	0x00000020
109 #define PM_RSTC_RESET			0x00000102
110 
111 #define PM_READ(reg) readl(power->base + (reg))
112 #define PM_WRITE(reg, val) writel(PM_PASSWORD | (val), power->base + (reg))
113 
114 #define ASB_BRDG_VERSION                0x00
115 #define ASB_CPR_CTRL                    0x04
116 
117 #define ASB_V3D_S_CTRL			0x08
118 #define ASB_V3D_M_CTRL			0x0c
119 #define ASB_ISP_S_CTRL			0x10
120 #define ASB_ISP_M_CTRL			0x14
121 #define ASB_H264_S_CTRL			0x18
122 #define ASB_H264_M_CTRL			0x1c
123 
124 #define ASB_REQ_STOP                    BIT(0)
125 #define ASB_ACK                         BIT(1)
126 #define ASB_EMPTY                       BIT(2)
127 #define ASB_FULL                        BIT(3)
128 
129 #define ASB_AXI_BRDG_ID			0x20
130 
131 #define BCM2835_BRDG_ID			0x62726467
132 
133 struct bcm2835_power_domain {
134 	struct generic_pm_domain base;
135 	struct bcm2835_power *power;
136 	u32 domain;
137 	struct clk *clk;
138 };
139 
140 struct bcm2835_power {
141 	struct device		*dev;
142 	/* PM registers. */
143 	void __iomem		*base;
144 	/* AXI Async bridge registers. */
145 	void __iomem		*asb;
146 	/* RPiVid bridge registers. */
147 	void __iomem		*rpivid_asb;
148 
149 	struct genpd_onecell_data pd_xlate;
150 	struct bcm2835_power_domain domains[BCM2835_POWER_DOMAIN_COUNT];
151 	struct reset_controller_dev reset;
152 };
153 
bcm2835_asb_control(struct bcm2835_power * power,u32 reg,bool enable)154 static int bcm2835_asb_control(struct bcm2835_power *power, u32 reg, bool enable)
155 {
156 	void __iomem *base = power->asb;
157 	u32 val;
158 
159 	switch (reg) {
160 	case 0:
161 		return 0;
162 	case ASB_V3D_S_CTRL:
163 	case ASB_V3D_M_CTRL:
164 		if (power->rpivid_asb)
165 			base = power->rpivid_asb;
166 		break;
167 	}
168 
169 	/* Enable the module's async AXI bridges. */
170 	if (enable) {
171 		val = readl(base + reg) & ~ASB_REQ_STOP;
172 	} else {
173 		val = readl(base + reg) | ASB_REQ_STOP;
174 	}
175 	writel(PM_PASSWORD | val, base + reg);
176 
177 	if (readl_poll_timeout_atomic(base + reg, val,
178 				      !!(val & ASB_ACK) != enable, 0, 5))
179 		return -ETIMEDOUT;
180 
181 	return 0;
182 }
183 
bcm2835_asb_enable(struct bcm2835_power * power,u32 reg)184 static int bcm2835_asb_enable(struct bcm2835_power *power, u32 reg)
185 {
186 	return bcm2835_asb_control(power, reg, true);
187 }
188 
bcm2835_asb_disable(struct bcm2835_power * power,u32 reg)189 static int bcm2835_asb_disable(struct bcm2835_power *power, u32 reg)
190 {
191 	return bcm2835_asb_control(power, reg, false);
192 }
193 
bcm2835_power_power_off(struct bcm2835_power_domain * pd,u32 pm_reg)194 static int bcm2835_power_power_off(struct bcm2835_power_domain *pd, u32 pm_reg)
195 {
196 	struct bcm2835_power *power = pd->power;
197 
198 	/* We don't run this on BCM2711 */
199 	if (power->rpivid_asb)
200 		return 0;
201 
202 	/* Enable functional isolation */
203 	PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISFUNC);
204 
205 	/* Enable electrical isolation */
206 	PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISPOW);
207 
208 	/* Open the power switches. */
209 	PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_POWUP);
210 
211 	return 0;
212 }
213 
bcm2835_power_power_on(struct bcm2835_power_domain * pd,u32 pm_reg)214 static int bcm2835_power_power_on(struct bcm2835_power_domain *pd, u32 pm_reg)
215 {
216 	struct bcm2835_power *power = pd->power;
217 	struct device *dev = power->dev;
218 	u64 start;
219 	int ret;
220 	int inrush;
221 	bool powok;
222 
223 	/* We don't run this on BCM2711 */
224 	if (power->rpivid_asb)
225 		return 0;
226 
227 	/* If it was already powered on by the fw, leave it that way. */
228 	if (PM_READ(pm_reg) & PM_POWUP)
229 		return 0;
230 
231 	/* Enable power.  Allowing too much current at once may result
232 	 * in POWOK never getting set, so start low and ramp it up as
233 	 * necessary to succeed.
234 	 */
235 	powok = false;
236 	for (inrush = PM_INRUSH_3_5_MA; inrush <= PM_INRUSH_20_MA; inrush++) {
237 		PM_WRITE(pm_reg,
238 			 (PM_READ(pm_reg) & ~PM_INRUSH_MASK) |
239 			 (inrush << PM_INRUSH_SHIFT) |
240 			 PM_POWUP);
241 
242 		start = ktime_get_ns();
243 		while (!(powok = !!(PM_READ(pm_reg) & PM_POWOK))) {
244 			cpu_relax();
245 			if (ktime_get_ns() - start >= 3000)
246 				break;
247 		}
248 	}
249 	if (!powok) {
250 		dev_err(dev, "Timeout waiting for %s power OK\n",
251 			pd->base.name);
252 		ret = -ETIMEDOUT;
253 		goto err_disable_powup;
254 	}
255 
256 	/* Disable electrical isolation */
257 	PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_ISPOW);
258 
259 	/* Repair memory */
260 	PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_MEMREP);
261 	start = ktime_get_ns();
262 	while (!(PM_READ(pm_reg) & PM_MRDONE)) {
263 		cpu_relax();
264 		if (ktime_get_ns() - start >= 1000) {
265 			dev_err(dev, "Timeout waiting for %s memory repair\n",
266 				pd->base.name);
267 			ret = -ETIMEDOUT;
268 			goto err_disable_ispow;
269 		}
270 	}
271 
272 	/* Disable functional isolation */
273 	PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_ISFUNC);
274 
275 	return 0;
276 
277 err_disable_ispow:
278 	PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISPOW);
279 err_disable_powup:
280 	PM_WRITE(pm_reg, PM_READ(pm_reg) & ~(PM_POWUP | PM_INRUSH_MASK));
281 	return ret;
282 }
283 
bcm2835_asb_power_on(struct bcm2835_power_domain * pd,u32 pm_reg,u32 asb_m_reg,u32 asb_s_reg,u32 reset_flags)284 static int bcm2835_asb_power_on(struct bcm2835_power_domain *pd,
285 				u32 pm_reg,
286 				u32 asb_m_reg,
287 				u32 asb_s_reg,
288 				u32 reset_flags)
289 {
290 	struct bcm2835_power *power = pd->power;
291 	int ret;
292 
293 	ret = clk_prepare_enable(pd->clk);
294 	if (ret) {
295 		dev_err(power->dev, "Failed to enable clock for %s\n",
296 			pd->base.name);
297 		return ret;
298 	}
299 
300 	/* Wait 32 clocks for reset to propagate, 1 us will be enough */
301 	udelay(1);
302 
303 	clk_disable_unprepare(pd->clk);
304 
305 	/* Deassert the resets. */
306 	PM_WRITE(pm_reg, PM_READ(pm_reg) | reset_flags);
307 
308 	ret = clk_prepare_enable(pd->clk);
309 	if (ret) {
310 		dev_err(power->dev, "Failed to enable clock for %s\n",
311 			pd->base.name);
312 		goto err_enable_resets;
313 	}
314 
315 	ret = bcm2835_asb_enable(power, asb_m_reg);
316 	if (ret) {
317 		dev_err(power->dev, "Failed to enable ASB master for %s\n",
318 			pd->base.name);
319 		goto err_disable_clk;
320 	}
321 	ret = bcm2835_asb_enable(power, asb_s_reg);
322 	if (ret) {
323 		dev_err(power->dev, "Failed to enable ASB slave for %s\n",
324 			pd->base.name);
325 		goto err_disable_asb_master;
326 	}
327 
328 	return 0;
329 
330 err_disable_asb_master:
331 	bcm2835_asb_disable(power, asb_m_reg);
332 err_disable_clk:
333 	clk_disable_unprepare(pd->clk);
334 err_enable_resets:
335 	PM_WRITE(pm_reg, PM_READ(pm_reg) & ~reset_flags);
336 	return ret;
337 }
338 
bcm2835_asb_power_off(struct bcm2835_power_domain * pd,u32 pm_reg,u32 asb_m_reg,u32 asb_s_reg,u32 reset_flags)339 static int bcm2835_asb_power_off(struct bcm2835_power_domain *pd,
340 				 u32 pm_reg,
341 				 u32 asb_m_reg,
342 				 u32 asb_s_reg,
343 				 u32 reset_flags)
344 {
345 	struct bcm2835_power *power = pd->power;
346 	int ret;
347 
348 	ret = bcm2835_asb_disable(power, asb_s_reg);
349 	if (ret) {
350 		dev_warn(power->dev, "Failed to disable ASB slave for %s\n",
351 			 pd->base.name);
352 		return ret;
353 	}
354 	ret = bcm2835_asb_disable(power, asb_m_reg);
355 	if (ret) {
356 		dev_warn(power->dev, "Failed to disable ASB master for %s\n",
357 			 pd->base.name);
358 		bcm2835_asb_enable(power, asb_s_reg);
359 		return ret;
360 	}
361 
362 	clk_disable_unprepare(pd->clk);
363 
364 	/* Assert the resets. */
365 	PM_WRITE(pm_reg, PM_READ(pm_reg) & ~reset_flags);
366 
367 	return 0;
368 }
369 
bcm2835_power_pd_power_on(struct generic_pm_domain * domain)370 static int bcm2835_power_pd_power_on(struct generic_pm_domain *domain)
371 {
372 	struct bcm2835_power_domain *pd =
373 		container_of(domain, struct bcm2835_power_domain, base);
374 	struct bcm2835_power *power = pd->power;
375 
376 	switch (pd->domain) {
377 	case BCM2835_POWER_DOMAIN_GRAFX:
378 		return bcm2835_power_power_on(pd, PM_GRAFX);
379 
380 	case BCM2835_POWER_DOMAIN_GRAFX_V3D:
381 		if (!power->asb)
382 			return bcm2835_asb_power_on(pd, PM_GRAFX_2712,
383 						    0, 0, PM_V3DRSTN);
384 		return bcm2835_asb_power_on(pd, PM_GRAFX,
385 					    ASB_V3D_M_CTRL, ASB_V3D_S_CTRL,
386 					    PM_V3DRSTN);
387 
388 	case BCM2835_POWER_DOMAIN_IMAGE:
389 		return bcm2835_power_power_on(pd, PM_IMAGE);
390 
391 	case BCM2835_POWER_DOMAIN_IMAGE_PERI:
392 		return bcm2835_asb_power_on(pd, PM_IMAGE,
393 					    0, 0,
394 					    PM_PERIRSTN);
395 
396 	case BCM2835_POWER_DOMAIN_IMAGE_ISP:
397 		return bcm2835_asb_power_on(pd, PM_IMAGE,
398 					    ASB_ISP_M_CTRL, ASB_ISP_S_CTRL,
399 					    PM_ISPRSTN);
400 
401 	case BCM2835_POWER_DOMAIN_IMAGE_H264:
402 		return bcm2835_asb_power_on(pd, PM_IMAGE,
403 					    ASB_H264_M_CTRL, ASB_H264_S_CTRL,
404 					    PM_H264RSTN);
405 
406 	case BCM2835_POWER_DOMAIN_USB:
407 		PM_WRITE(PM_USB, PM_USB_CTRLEN);
408 		return 0;
409 
410 	case BCM2835_POWER_DOMAIN_DSI0:
411 		PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN);
412 		PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN | PM_DSI0_LDOHPEN);
413 		return 0;
414 
415 	case BCM2835_POWER_DOMAIN_DSI1:
416 		PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN);
417 		PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN | PM_DSI1_LDOHPEN);
418 		return 0;
419 
420 	case BCM2835_POWER_DOMAIN_CCP2TX:
421 		PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN);
422 		PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN | PM_CCP2TX_LDOEN);
423 		return 0;
424 
425 	case BCM2835_POWER_DOMAIN_HDMI:
426 		PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_RSTDR);
427 		PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_CTRLEN);
428 		PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_LDOPD);
429 		usleep_range(100, 200);
430 		PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_RSTDR);
431 		return 0;
432 
433 	default:
434 		dev_err(power->dev, "Invalid domain %d\n", pd->domain);
435 		return -EINVAL;
436 	}
437 }
438 
bcm2835_power_pd_power_off(struct generic_pm_domain * domain)439 static int bcm2835_power_pd_power_off(struct generic_pm_domain *domain)
440 {
441 	struct bcm2835_power_domain *pd =
442 		container_of(domain, struct bcm2835_power_domain, base);
443 	struct bcm2835_power *power = pd->power;
444 
445 	switch (pd->domain) {
446 	case BCM2835_POWER_DOMAIN_GRAFX:
447 		return bcm2835_power_power_off(pd, PM_GRAFX);
448 
449 	case BCM2835_POWER_DOMAIN_GRAFX_V3D:
450 		if (!power->asb)
451 			return bcm2835_asb_power_off(pd, PM_GRAFX_2712,
452 						     0, 0, PM_V3DRSTN);
453 		return bcm2835_asb_power_off(pd, PM_GRAFX,
454 					     ASB_V3D_M_CTRL, ASB_V3D_S_CTRL,
455 					     PM_V3DRSTN);
456 
457 	case BCM2835_POWER_DOMAIN_IMAGE:
458 		return bcm2835_power_power_off(pd, PM_IMAGE);
459 
460 	case BCM2835_POWER_DOMAIN_IMAGE_PERI:
461 		return bcm2835_asb_power_off(pd, PM_IMAGE,
462 					     0, 0,
463 					     PM_PERIRSTN);
464 
465 	case BCM2835_POWER_DOMAIN_IMAGE_ISP:
466 		return bcm2835_asb_power_off(pd, PM_IMAGE,
467 					     ASB_ISP_M_CTRL, ASB_ISP_S_CTRL,
468 					     PM_ISPRSTN);
469 
470 	case BCM2835_POWER_DOMAIN_IMAGE_H264:
471 		return bcm2835_asb_power_off(pd, PM_IMAGE,
472 					     ASB_H264_M_CTRL, ASB_H264_S_CTRL,
473 					     PM_H264RSTN);
474 
475 	case BCM2835_POWER_DOMAIN_USB:
476 		PM_WRITE(PM_USB, 0);
477 		return 0;
478 
479 	case BCM2835_POWER_DOMAIN_DSI0:
480 		PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN);
481 		PM_WRITE(PM_DSI0, 0);
482 		return 0;
483 
484 	case BCM2835_POWER_DOMAIN_DSI1:
485 		PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN);
486 		PM_WRITE(PM_DSI1, 0);
487 		return 0;
488 
489 	case BCM2835_POWER_DOMAIN_CCP2TX:
490 		PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN);
491 		PM_WRITE(PM_CCP2TX, 0);
492 		return 0;
493 
494 	case BCM2835_POWER_DOMAIN_HDMI:
495 		PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_LDOPD);
496 		PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_CTRLEN);
497 		return 0;
498 
499 	default:
500 		dev_err(power->dev, "Invalid domain %d\n", pd->domain);
501 		return -EINVAL;
502 	}
503 }
504 
505 static int
bcm2835_init_power_domain(struct bcm2835_power * power,int pd_xlate_index,const char * name)506 bcm2835_init_power_domain(struct bcm2835_power *power,
507 			  int pd_xlate_index, const char *name)
508 {
509 	struct device *dev = power->dev;
510 	struct bcm2835_power_domain *dom = &power->domains[pd_xlate_index];
511 
512 	dom->clk = devm_clk_get_optional(dev->parent, name);
513 	if (IS_ERR(dom->clk))
514 		return dev_err_probe(dev, PTR_ERR(dom->clk), "Failed to get clock %s\n",
515 							     name);
516 
517 	dom->base.name = name;
518 	dom->base.flags = GENPD_FLAG_ACTIVE_WAKEUP;
519 	dom->base.power_on = bcm2835_power_pd_power_on;
520 	dom->base.power_off = bcm2835_power_pd_power_off;
521 
522 	dom->domain = pd_xlate_index;
523 	dom->power = power;
524 
525 	/* XXX: on/off at boot? */
526 	pm_genpd_init(&dom->base, NULL, true);
527 
528 	power->pd_xlate.domains[pd_xlate_index] = &dom->base;
529 
530 	return 0;
531 }
532 
533 /** bcm2835_reset_reset - Resets a block that has a reset line in the
534  * PM block.
535  *
536  * The consumer of the reset controller must have the power domain up
537  * -- there's no reset ability with the power domain down.  To reset
538  * the sub-block, we just disable its access to memory through the
539  * ASB, reset, and re-enable.
540  */
bcm2835_reset_reset(struct reset_controller_dev * rcdev,unsigned long id)541 static int bcm2835_reset_reset(struct reset_controller_dev *rcdev,
542 			       unsigned long id)
543 {
544 	struct bcm2835_power *power = container_of(rcdev, struct bcm2835_power,
545 						   reset);
546 	struct bcm2835_power_domain *pd;
547 	int ret;
548 
549 	switch (id) {
550 	case BCM2835_RESET_V3D:
551 		pd = &power->domains[BCM2835_POWER_DOMAIN_GRAFX_V3D];
552 		break;
553 	case BCM2835_RESET_H264:
554 		pd = &power->domains[BCM2835_POWER_DOMAIN_IMAGE_H264];
555 		break;
556 	case BCM2835_RESET_ISP:
557 		pd = &power->domains[BCM2835_POWER_DOMAIN_IMAGE_ISP];
558 		break;
559 	default:
560 		dev_err(power->dev, "Bad reset id %ld\n", id);
561 		return -EINVAL;
562 	}
563 
564 	ret = bcm2835_power_pd_power_off(&pd->base);
565 	if (ret)
566 		return ret;
567 
568 	return bcm2835_power_pd_power_on(&pd->base);
569 }
570 
bcm2835_reset_status(struct reset_controller_dev * rcdev,unsigned long id)571 static int bcm2835_reset_status(struct reset_controller_dev *rcdev,
572 				unsigned long id)
573 {
574 	struct bcm2835_power *power = container_of(rcdev, struct bcm2835_power,
575 						   reset);
576 
577 	switch (id) {
578 	case BCM2835_RESET_V3D:
579 		return !(PM_READ(PM_GRAFX) & PM_V3DRSTN);
580 	case BCM2835_RESET_H264:
581 		return !(PM_READ(PM_IMAGE) & PM_H264RSTN);
582 	case BCM2835_RESET_ISP:
583 		return !(PM_READ(PM_IMAGE) & PM_ISPRSTN);
584 	default:
585 		return -EINVAL;
586 	}
587 }
588 
589 static const struct reset_control_ops bcm2835_reset_ops = {
590 	.reset = bcm2835_reset_reset,
591 	.status = bcm2835_reset_status,
592 };
593 
594 static const char *const power_domain_names[] = {
595 	[BCM2835_POWER_DOMAIN_GRAFX] = "grafx",
596 	[BCM2835_POWER_DOMAIN_GRAFX_V3D] = "v3d",
597 
598 	[BCM2835_POWER_DOMAIN_IMAGE] = "image",
599 	[BCM2835_POWER_DOMAIN_IMAGE_PERI] = "peri_image",
600 	[BCM2835_POWER_DOMAIN_IMAGE_H264] = "h264",
601 	[BCM2835_POWER_DOMAIN_IMAGE_ISP] = "isp",
602 
603 	[BCM2835_POWER_DOMAIN_USB] = "usb",
604 	[BCM2835_POWER_DOMAIN_DSI0] = "dsi0",
605 	[BCM2835_POWER_DOMAIN_DSI1] = "dsi1",
606 	[BCM2835_POWER_DOMAIN_CAM0] = "cam0",
607 	[BCM2835_POWER_DOMAIN_CAM1] = "cam1",
608 	[BCM2835_POWER_DOMAIN_CCP2TX] = "ccp2tx",
609 	[BCM2835_POWER_DOMAIN_HDMI] = "hdmi",
610 };
611 
bcm2835_power_probe(struct platform_device * pdev)612 static int bcm2835_power_probe(struct platform_device *pdev)
613 {
614 	struct bcm2835_pm *pm = dev_get_drvdata(pdev->dev.parent);
615 	struct device *dev = &pdev->dev;
616 	struct bcm2835_power *power;
617 	static const struct {
618 		int parent, child;
619 	} domain_deps[] = {
620 		{ BCM2835_POWER_DOMAIN_GRAFX, BCM2835_POWER_DOMAIN_GRAFX_V3D },
621 		{ BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_PERI },
622 		{ BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_H264 },
623 		{ BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_ISP },
624 		{ BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_USB },
625 		{ BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM0 },
626 		{ BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM1 },
627 	};
628 	int ret = 0, i;
629 	u32 id;
630 
631 	power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL);
632 	if (!power)
633 		return -ENOMEM;
634 	platform_set_drvdata(pdev, power);
635 
636 	power->dev = dev;
637 	power->base = pm->base;
638 	power->asb = pm->asb;
639 	power->rpivid_asb = pm->rpivid_asb;
640 
641 	if (power->asb) {
642 		id = readl(power->asb + ASB_AXI_BRDG_ID);
643 		if (id != BCM2835_BRDG_ID /* "BRDG" */) {
644 			dev_err(dev, "ASB register ID returned 0x%08x\n", id);
645 			return -ENODEV;
646 		}
647 	}
648 
649 	if (power->rpivid_asb) {
650 		id = readl(power->rpivid_asb + ASB_AXI_BRDG_ID);
651 		if (id != BCM2835_BRDG_ID /* "BRDG" */) {
652 			dev_err(dev, "RPiVid ASB register ID returned 0x%08x\n",
653 				     id);
654 			return -ENODEV;
655 		}
656 	}
657 
658 	power->pd_xlate.domains = devm_kcalloc(dev,
659 					       ARRAY_SIZE(power_domain_names),
660 					       sizeof(*power->pd_xlate.domains),
661 					       GFP_KERNEL);
662 	if (!power->pd_xlate.domains)
663 		return -ENOMEM;
664 
665 	power->pd_xlate.num_domains = ARRAY_SIZE(power_domain_names);
666 
667 	for (i = 0; i < ARRAY_SIZE(power_domain_names); i++) {
668 		ret = bcm2835_init_power_domain(power, i, power_domain_names[i]);
669 		if (ret)
670 			goto fail;
671 	}
672 
673 	for (i = 0; i < ARRAY_SIZE(domain_deps); i++) {
674 		pm_genpd_add_subdomain(&power->domains[domain_deps[i].parent].base,
675 				       &power->domains[domain_deps[i].child].base);
676 	}
677 
678 	power->reset.owner = THIS_MODULE;
679 	power->reset.nr_resets = BCM2835_RESET_COUNT;
680 	power->reset.ops = &bcm2835_reset_ops;
681 	power->reset.of_node = dev->parent->of_node;
682 
683 	ret = devm_reset_controller_register(dev, &power->reset);
684 	if (ret)
685 		goto fail;
686 
687 	of_genpd_add_provider_onecell(dev->parent->of_node, &power->pd_xlate);
688 
689 	dev_info(dev, "Broadcom BCM2835 power domains driver");
690 	return 0;
691 
692 fail:
693 	for (i = 0; i < ARRAY_SIZE(power_domain_names); i++) {
694 		struct generic_pm_domain *dom = &power->domains[i].base;
695 
696 		if (dom->name)
697 			pm_genpd_remove(dom);
698 	}
699 	return ret;
700 }
701 
702 static struct platform_driver bcm2835_power_driver = {
703 	.probe		= bcm2835_power_probe,
704 	.driver = {
705 		.name =	"bcm2835-power",
706 	},
707 };
708 module_platform_driver(bcm2835_power_driver);
709 
710 MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
711 MODULE_DESCRIPTION("Driver for Broadcom BCM2835 PM power domains and reset");
712