1 /*
2  * r8a7779 Power management support
3  *
4  * Copyright (C) 2011  Renesas Solutions Corp.
5  * Copyright (C) 2011  Magnus Damm
6  *
7  * This file is subject to the terms and conditions of the GNU General Public
8  * License.  See the file "COPYING" in the main directory of this archive
9  * for more details.
10  */
11 
12 #include <linux/pm.h>
13 #include <linux/suspend.h>
14 #include <linux/err.h>
15 #include <linux/pm_clock.h>
16 #include <linux/platform_device.h>
17 #include <linux/delay.h>
18 #include <linux/irq.h>
19 #include <linux/interrupt.h>
20 #include <linux/console.h>
21 #include <asm/system.h>
22 #include <asm/io.h>
23 #include <mach/common.h>
24 #include <mach/r8a7779.h>
25 
26 static void __iomem *r8a7779_sysc_base;
27 
28 /* SYSC */
29 #define SYSCSR 0x00
30 #define SYSCISR 0x04
31 #define SYSCISCR 0x08
32 #define SYSCIER 0x0c
33 #define SYSCIMR 0x10
34 #define PWRSR0 0x40
35 #define PWRSR1 0x80
36 #define PWRSR2 0xc0
37 #define PWRSR3 0x100
38 #define PWRSR4 0x140
39 
40 #define PWRSR_OFFS 0x00
41 #define PWROFFCR_OFFS 0x04
42 #define PWRONCR_OFFS 0x0c
43 #define PWRER_OFFS 0x14
44 
45 #define SYSCSR_RETRIES 100
46 #define SYSCSR_DELAY_US 1
47 
48 #define SYSCISR_RETRIES 1000
49 #define SYSCISR_DELAY_US 1
50 
51 #if defined(CONFIG_PM) || defined(CONFIG_SMP)
52 
53 static DEFINE_SPINLOCK(r8a7779_sysc_lock); /* SMP CPUs + I/O devices */
54 
r8a7779_sysc_pwr_on_off(struct r8a7779_pm_ch * r8a7779_ch,int sr_bit,int reg_offs)55 static int r8a7779_sysc_pwr_on_off(struct r8a7779_pm_ch *r8a7779_ch,
56 				   int sr_bit, int reg_offs)
57 {
58 	int k;
59 
60 	for (k = 0; k < SYSCSR_RETRIES; k++) {
61 		if (ioread32(r8a7779_sysc_base + SYSCSR) & (1 << sr_bit))
62 			break;
63 		udelay(SYSCSR_DELAY_US);
64 	}
65 
66 	if (k == SYSCSR_RETRIES)
67 		return -EAGAIN;
68 
69 	iowrite32(1 << r8a7779_ch->chan_bit,
70 		  r8a7779_sysc_base + r8a7779_ch->chan_offs + reg_offs);
71 
72 	return 0;
73 }
74 
r8a7779_sysc_pwr_off(struct r8a7779_pm_ch * r8a7779_ch)75 static int r8a7779_sysc_pwr_off(struct r8a7779_pm_ch *r8a7779_ch)
76 {
77 	return r8a7779_sysc_pwr_on_off(r8a7779_ch, 0, PWROFFCR_OFFS);
78 }
79 
r8a7779_sysc_pwr_on(struct r8a7779_pm_ch * r8a7779_ch)80 static int r8a7779_sysc_pwr_on(struct r8a7779_pm_ch *r8a7779_ch)
81 {
82 	return r8a7779_sysc_pwr_on_off(r8a7779_ch, 1, PWRONCR_OFFS);
83 }
84 
r8a7779_sysc_update(struct r8a7779_pm_ch * r8a7779_ch,int (* on_off_fn)(struct r8a7779_pm_ch *))85 static int r8a7779_sysc_update(struct r8a7779_pm_ch *r8a7779_ch,
86 			       int (*on_off_fn)(struct r8a7779_pm_ch *))
87 {
88 	unsigned int isr_mask = 1 << r8a7779_ch->isr_bit;
89 	unsigned int chan_mask = 1 << r8a7779_ch->chan_bit;
90 	unsigned int status;
91 	unsigned long flags;
92 	int ret = 0;
93 	int k;
94 
95 	spin_lock_irqsave(&r8a7779_sysc_lock, flags);
96 
97 	iowrite32(isr_mask, r8a7779_sysc_base + SYSCISCR);
98 
99 	do {
100 		ret = on_off_fn(r8a7779_ch);
101 		if (ret)
102 			goto out;
103 
104 		status = ioread32(r8a7779_sysc_base +
105 				  r8a7779_ch->chan_offs + PWRER_OFFS);
106 	} while (status & chan_mask);
107 
108 	for (k = 0; k < SYSCISR_RETRIES; k++) {
109 		if (ioread32(r8a7779_sysc_base + SYSCISR) & isr_mask)
110 			break;
111 		udelay(SYSCISR_DELAY_US);
112 	}
113 
114 	if (k == SYSCISR_RETRIES)
115 		ret = -EIO;
116 
117 	iowrite32(isr_mask, r8a7779_sysc_base + SYSCISCR);
118 
119  out:
120 	spin_unlock_irqrestore(&r8a7779_sysc_lock, flags);
121 
122 	pr_debug("r8a7779 power domain %d: %02x %02x %02x %02x %02x -> %d\n",
123 		 r8a7779_ch->isr_bit, ioread32(r8a7779_sysc_base + PWRSR0),
124 		 ioread32(r8a7779_sysc_base + PWRSR1),
125 		 ioread32(r8a7779_sysc_base + PWRSR2),
126 		 ioread32(r8a7779_sysc_base + PWRSR3),
127 		 ioread32(r8a7779_sysc_base + PWRSR4), ret);
128 	return ret;
129 }
130 
r8a7779_sysc_power_down(struct r8a7779_pm_ch * r8a7779_ch)131 int r8a7779_sysc_power_down(struct r8a7779_pm_ch *r8a7779_ch)
132 {
133 	return r8a7779_sysc_update(r8a7779_ch, r8a7779_sysc_pwr_off);
134 }
135 
r8a7779_sysc_power_up(struct r8a7779_pm_ch * r8a7779_ch)136 int r8a7779_sysc_power_up(struct r8a7779_pm_ch *r8a7779_ch)
137 {
138 	return r8a7779_sysc_update(r8a7779_ch, r8a7779_sysc_pwr_on);
139 }
140 
r8a7779_sysc_init(void)141 static void __init r8a7779_sysc_init(void)
142 {
143 	r8a7779_sysc_base = ioremap_nocache(0xffd85000, PAGE_SIZE);
144 	if (!r8a7779_sysc_base)
145 		panic("unable to ioremap r8a7779 SYSC hardware block\n");
146 
147 	/* enable all interrupt sources, but do not use interrupt handler */
148 	iowrite32(0x0131000e, r8a7779_sysc_base + SYSCIER);
149 	iowrite32(0, r8a7779_sysc_base + SYSCIMR);
150 }
151 
152 #else /* CONFIG_PM || CONFIG_SMP */
153 
r8a7779_sysc_init(void)154 static inline void r8a7779_sysc_init(void) {}
155 
156 #endif /* CONFIG_PM || CONFIG_SMP */
157 
158 #ifdef CONFIG_PM
159 
pd_power_down(struct generic_pm_domain * genpd)160 static int pd_power_down(struct generic_pm_domain *genpd)
161 {
162 	return r8a7779_sysc_power_down(to_r8a7779_ch(genpd));
163 }
164 
pd_power_up(struct generic_pm_domain * genpd)165 static int pd_power_up(struct generic_pm_domain *genpd)
166 {
167 	return r8a7779_sysc_power_up(to_r8a7779_ch(genpd));
168 }
169 
pd_is_off(struct generic_pm_domain * genpd)170 static bool pd_is_off(struct generic_pm_domain *genpd)
171 {
172 	struct r8a7779_pm_ch *r8a7779_ch = to_r8a7779_ch(genpd);
173 	unsigned int st;
174 
175 	st = ioread32(r8a7779_sysc_base + r8a7779_ch->chan_offs + PWRSR_OFFS);
176 	if (st & (1 << r8a7779_ch->chan_bit))
177 		return true;
178 
179 	return false;
180 }
181 
pd_active_wakeup(struct device * dev)182 static bool pd_active_wakeup(struct device *dev)
183 {
184 	return true;
185 }
186 
r8a7779_init_pm_domain(struct r8a7779_pm_domain * r8a7779_pd)187 void r8a7779_init_pm_domain(struct r8a7779_pm_domain *r8a7779_pd)
188 {
189 	struct generic_pm_domain *genpd = &r8a7779_pd->genpd;
190 
191 	pm_genpd_init(genpd, NULL, false);
192 	genpd->dev_ops.stop = pm_clk_suspend;
193 	genpd->dev_ops.start = pm_clk_resume;
194 	genpd->dev_ops.active_wakeup = pd_active_wakeup;
195 	genpd->dev_irq_safe = true;
196 	genpd->power_off = pd_power_down;
197 	genpd->power_on = pd_power_up;
198 
199 	if (pd_is_off(&r8a7779_pd->genpd))
200 		pd_power_up(&r8a7779_pd->genpd);
201 }
202 
r8a7779_add_device_to_domain(struct r8a7779_pm_domain * r8a7779_pd,struct platform_device * pdev)203 void r8a7779_add_device_to_domain(struct r8a7779_pm_domain *r8a7779_pd,
204 				 struct platform_device *pdev)
205 {
206 	struct device *dev = &pdev->dev;
207 
208 	pm_genpd_add_device(&r8a7779_pd->genpd, dev);
209 	if (pm_clk_no_clocks(dev))
210 		pm_clk_add(dev, NULL);
211 }
212 
213 struct r8a7779_pm_domain r8a7779_sh4a = {
214 	.ch = {
215 		.chan_offs = 0x80, /* PWRSR1 .. PWRER1 */
216 		.isr_bit = 16, /* SH4A */
217 	}
218 };
219 
220 struct r8a7779_pm_domain r8a7779_sgx = {
221 	.ch = {
222 		.chan_offs = 0xc0, /* PWRSR2 .. PWRER2 */
223 		.isr_bit = 20, /* SGX */
224 	}
225 };
226 
227 struct r8a7779_pm_domain r8a7779_vdp1 = {
228 	.ch = {
229 		.chan_offs = 0x100, /* PWRSR3 .. PWRER3 */
230 		.isr_bit = 21, /* VDP */
231 	}
232 };
233 
234 struct r8a7779_pm_domain r8a7779_impx3 = {
235 	.ch = {
236 		.chan_offs = 0x140, /* PWRSR4 .. PWRER4 */
237 		.isr_bit = 24, /* IMP */
238 	}
239 };
240 
241 #endif /* CONFIG_PM */
242 
r8a7779_pm_init(void)243 void __init r8a7779_pm_init(void)
244 {
245 	static int once;
246 
247 	if (!once++)
248 		r8a7779_sysc_init();
249 }
250