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(NULL, "musb_hdrc", -1, 276 puv3_usb_resources, ARRAY_SIZE(puv3_usb_resources), 277 &puv3_usb_plat, sizeof(puv3_usb_plat)); 278} 279 280