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