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