1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  *  linux/arch/unicore32/kernel/puv3-core.c
4  *
5  * Code specific to PKUnity SoC and UniCore ISA
6  *
7  *	Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
8  *	Copyright (C) 2001-2010 Guan Xuetao
9  */
10 
11 #include <linux/init.h>
12 #include <linux/device.h>
13 #include <linux/amba/bus.h>
14 #include <linux/platform_device.h>
15 #include <linux/io.h>
16 #include <linux/cnt32_to_63.h>
17 #include <linux/usb/musb.h>
18 
19 #include <asm/irq.h>
20 #include <mach/hardware.h>
21 #include <mach/pm.h>
22 
23 /*
24  * This is the PKUnity sched_clock implementation.  This has
25  * a resolution of 271ns, and a maximum value of 32025597s (370 days).
26  *
27  * The return value is guaranteed to be monotonic in that range as
28  * long as there is always less than 582 seconds between successive
29  * calls to this function.
30  *
31  *  ( * 1E9 / CLOCK_TICK_RATE ) -> about 2235/32
32  */
sched_clock(void)33 unsigned long long sched_clock(void)
34 {
35 	unsigned long long v = cnt32_to_63(readl(OST_OSCR));
36 
37 	/* original conservative method, but overflow frequently
38 	 * v *= NSEC_PER_SEC >> 12;
39 	 * do_div(v, CLOCK_TICK_RATE >> 12);
40 	 */
41 	v = ((v & 0x7fffffffffffffffULL) * 2235) >> 5;
42 
43 	return v;
44 }
45 
46 static struct resource puv3_usb_resources[] = {
47 	/* order is significant! */
48 	{
49 		.start		= io_v2p(PKUNITY_USB_BASE),
50 		.end		= io_v2p(PKUNITY_USB_BASE) + 0x3ff,
51 		.flags		= IORESOURCE_MEM,
52 	}, {
53 		.start		= IRQ_USB,
54 		.flags		= IORESOURCE_IRQ,
55 	}, {
56 		.start		= IRQ_USB,
57 		.flags		= IORESOURCE_IRQ,
58 	},
59 };
60 
61 static struct musb_hdrc_config	puv3_usb_config[] = {
62 	{
63 		.num_eps = 16,
64 		.multipoint = 1,
65 #ifdef CONFIG_USB_INVENTRA_DMA
66 		.dma = 1,
67 		.dma_channels = 8,
68 #endif
69 	},
70 };
71 
72 static struct musb_hdrc_platform_data puv3_usb_plat = {
73 	.mode		= MUSB_HOST,
74 	.min_power	= 100,
75 	.clock		= 0,
76 	.config		= puv3_usb_config,
77 };
78 
79 static struct resource puv3_mmc_resources[] = {
80 	[0] = {
81 		.start	= io_v2p(PKUNITY_SDC_BASE),
82 		.end	= io_v2p(PKUNITY_SDC_BASE) + 0xfff,
83 		.flags	= IORESOURCE_MEM,
84 	},
85 	[1] = {
86 		.start	= IRQ_SDC,
87 		.end	= IRQ_SDC,
88 		.flags	= IORESOURCE_IRQ,
89 	},
90 };
91 
92 static struct resource puv3_unigfx_resources[] = {
93 	[0] = {
94 		.start	= io_v2p(PKUNITY_UNIGFX_BASE),
95 		.end	= io_v2p(PKUNITY_UNIGFX_BASE) + 0xfff,
96 		.flags	= IORESOURCE_MEM,
97 	},
98 };
99 
100 static struct resource puv3_rtc_resources[] = {
101 	[0] = {
102 		.start = io_v2p(PKUNITY_RTC_BASE),
103 		.end   = io_v2p(PKUNITY_RTC_BASE) + 0xff,
104 		.flags = IORESOURCE_MEM,
105 	},
106 	[1] = {
107 		.start = IRQ_RTCAlarm,
108 		.end   = IRQ_RTCAlarm,
109 		.flags = IORESOURCE_IRQ,
110 	},
111 	[2] = {
112 		.start = IRQ_RTC,
113 		.end   = IRQ_RTC,
114 		.flags = IORESOURCE_IRQ
115 	}
116 };
117 
118 static struct resource puv3_pwm_resources[] = {
119 	[0] = {
120 		.start	= io_v2p(PKUNITY_OST_BASE) + 0x80,
121 		.end	= io_v2p(PKUNITY_OST_BASE) + 0xff,
122 		.flags	= IORESOURCE_MEM,
123 	},
124 };
125 
126 static struct resource puv3_uart0_resources[] = {
127 	[0] = {
128 		.start = io_v2p(PKUNITY_UART0_BASE),
129 		.end   = io_v2p(PKUNITY_UART0_BASE) + 0xff,
130 		.flags = IORESOURCE_MEM,
131 	},
132 	[1] = {
133 		.start = IRQ_UART0,
134 		.end   = IRQ_UART0,
135 		.flags = IORESOURCE_IRQ
136 	}
137 };
138 
139 static struct resource puv3_uart1_resources[] = {
140 	[0] = {
141 		.start = io_v2p(PKUNITY_UART1_BASE),
142 		.end   = io_v2p(PKUNITY_UART1_BASE) + 0xff,
143 		.flags = IORESOURCE_MEM,
144 	},
145 	[1] = {
146 		.start = IRQ_UART1,
147 		.end   = IRQ_UART1,
148 		.flags = IORESOURCE_IRQ
149 	}
150 };
151 
152 static struct resource puv3_umal_resources[] = {
153 	[0] = {
154 		.start = io_v2p(PKUNITY_UMAL_BASE),
155 		.end   = io_v2p(PKUNITY_UMAL_BASE) + 0x1fff,
156 		.flags = IORESOURCE_MEM,
157 	},
158 	[1] = {
159 		.start = IRQ_UMAL,
160 		.end   = IRQ_UMAL,
161 		.flags = IORESOURCE_IRQ
162 	}
163 };
164 
165 #ifdef CONFIG_PUV3_PM
166 
167 #define SAVE(x)		sleep_save[SLEEP_SAVE_##x] = x
168 #define RESTORE(x)	x = sleep_save[SLEEP_SAVE_##x]
169 
170 /*
171  * List of global PXA peripheral registers to preserve.
172  * More ones like CP and general purpose register values are preserved
173  * with the stack pointer in sleep.S.
174  */
175 enum {
176 	SLEEP_SAVE_PM_PLLDDRCFG,
177 	SLEEP_SAVE_COUNT
178 };
179 
180 
puv3_cpu_pm_save(unsigned long * sleep_save)181 static void puv3_cpu_pm_save(unsigned long *sleep_save)
182 {
183 /*	SAVE(PM_PLLDDRCFG); */
184 }
185 
puv3_cpu_pm_restore(unsigned long * sleep_save)186 static void puv3_cpu_pm_restore(unsigned long *sleep_save)
187 {
188 /*	RESTORE(PM_PLLDDRCFG); */
189 }
190 
puv3_cpu_pm_prepare(void)191 static int puv3_cpu_pm_prepare(void)
192 {
193 	/* set resume return address */
194 	writel(virt_to_phys(puv3_cpu_resume), PM_DIVCFG);
195 	return 0;
196 }
197 
puv3_cpu_pm_enter(suspend_state_t state)198 static void puv3_cpu_pm_enter(suspend_state_t state)
199 {
200 	/* Clear reset status */
201 	writel(RESETC_RSSR_HWR | RESETC_RSSR_WDR
202 			| RESETC_RSSR_SMR | RESETC_RSSR_SWR, RESETC_RSSR);
203 
204 	switch (state) {
205 /*	case PM_SUSPEND_ON:
206 		puv3_cpu_idle();
207 		break; */
208 	case PM_SUSPEND_MEM:
209 		puv3_cpu_pm_prepare();
210 		puv3_cpu_suspend(PM_PMCR_SFB);
211 		break;
212 	}
213 }
214 
puv3_cpu_pm_valid(suspend_state_t state)215 static int puv3_cpu_pm_valid(suspend_state_t state)
216 {
217 	return state == PM_SUSPEND_MEM;
218 }
219 
puv3_cpu_pm_finish(void)220 static void puv3_cpu_pm_finish(void)
221 {
222 	/* ensure not to come back here if it wasn't intended */
223 	/* PSPR = 0; */
224 }
225 
226 static struct puv3_cpu_pm_fns puv3_cpu_pm_fnss = {
227 	.save_count	= SLEEP_SAVE_COUNT,
228 	.valid		= puv3_cpu_pm_valid,
229 	.save		= puv3_cpu_pm_save,
230 	.restore	= puv3_cpu_pm_restore,
231 	.enter		= puv3_cpu_pm_enter,
232 	.prepare	= puv3_cpu_pm_prepare,
233 	.finish		= puv3_cpu_pm_finish,
234 };
235 
puv3_init_pm(void)236 static void __init puv3_init_pm(void)
237 {
238 	puv3_cpu_pm_fns = &puv3_cpu_pm_fnss;
239 }
240 #else
puv3_init_pm(void)241 static inline void puv3_init_pm(void) {}
242 #endif
243 
puv3_ps2_init(void)244 void puv3_ps2_init(void)
245 {
246 	struct clk *bclk32;
247 
248 	bclk32 = clk_get(NULL, "BUS32_CLK");
249 	writel(clk_get_rate(bclk32) / 200000, PS2_CNT); /* should > 5us */
250 }
251 
puv3_core_init(void)252 void __init puv3_core_init(void)
253 {
254 	puv3_init_pm();
255 	puv3_ps2_init();
256 
257 	platform_device_register_simple("PKUnity-v3-RTC", -1,
258 			puv3_rtc_resources, ARRAY_SIZE(puv3_rtc_resources));
259 	platform_device_register_simple("PKUnity-v3-UMAL", -1,
260 			puv3_umal_resources, ARRAY_SIZE(puv3_umal_resources));
261 	platform_device_register_simple("PKUnity-v3-MMC", -1,
262 			puv3_mmc_resources, ARRAY_SIZE(puv3_mmc_resources));
263 	platform_device_register_simple("PKUnity-v3-UNIGFX", -1,
264 			puv3_unigfx_resources, ARRAY_SIZE(puv3_unigfx_resources));
265 	platform_device_register_simple("PKUnity-v3-PWM", -1,
266 			puv3_pwm_resources, ARRAY_SIZE(puv3_pwm_resources));
267 	platform_device_register_simple("PKUnity-v3-UART", 0,
268 			puv3_uart0_resources, ARRAY_SIZE(puv3_uart0_resources));
269 	platform_device_register_simple("PKUnity-v3-UART", 1,
270 			puv3_uart1_resources, ARRAY_SIZE(puv3_uart1_resources));
271 	platform_device_register_simple("PKUnity-v3-AC97", -1, NULL, 0);
272 	platform_device_register_resndata(NULL, "musb_hdrc", -1,
273 			puv3_usb_resources, ARRAY_SIZE(puv3_usb_resources),
274 			&puv3_usb_plat, sizeof(puv3_usb_plat));
275 }
276 
277