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