diff options
Diffstat (limited to 'arch/arm/mach-pxa')
-rw-r--r-- | arch/arm/mach-pxa/Kconfig | 4 | ||||
-rw-r--r-- | arch/arm/mach-pxa/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-pxa/devices.h | 22 | ||||
-rw-r--r-- | arch/arm/mach-pxa/em-x270.c | 354 | ||||
-rw-r--r-- | arch/arm/mach-pxa/generic.c | 32 | ||||
-rw-r--r-- | arch/arm/mach-pxa/pm.c | 169 | ||||
-rw-r--r-- | arch/arm/mach-pxa/pxa25x.c | 109 | ||||
-rw-r--r-- | arch/arm/mach-pxa/pxa27x.c | 151 | ||||
-rw-r--r-- | arch/arm/mach-pxa/sleep.S | 112 | ||||
-rw-r--r-- | arch/arm/mach-pxa/time.c | 258 |
10 files changed, 848 insertions, 364 deletions
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig index 5c0a10041cd1..5ebec6d88b51 100644 --- a/arch/arm/mach-pxa/Kconfig +++ b/arch/arm/mach-pxa/Kconfig | |||
@@ -37,6 +37,10 @@ config MACH_TRIZEPS4 | |||
37 | bool "Keith und Koep Trizeps4 DIMM-Module" | 37 | bool "Keith und Koep Trizeps4 DIMM-Module" |
38 | select PXA27x | 38 | select PXA27x |
39 | 39 | ||
40 | config MACH_EM_X270 | ||
41 | bool "CompuLab EM-x270 platform" | ||
42 | select PXA27x | ||
43 | |||
40 | endchoice | 44 | endchoice |
41 | 45 | ||
42 | if PXA_SHARPSL | 46 | if PXA_SHARPSL |
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile index 9093eb1c94eb..7d6ab5c59ab9 100644 --- a/arch/arm/mach-pxa/Makefile +++ b/arch/arm/mach-pxa/Makefile | |||
@@ -18,6 +18,7 @@ obj-$(CONFIG_PXA_SHARP_Cxx00) += spitz.o corgi_ssp.o corgi_lcd.o sharpsl_pm.o sp | |||
18 | obj-$(CONFIG_MACH_AKITA) += akita-ioexp.o | 18 | obj-$(CONFIG_MACH_AKITA) += akita-ioexp.o |
19 | obj-$(CONFIG_MACH_POODLE) += poodle.o corgi_ssp.o | 19 | obj-$(CONFIG_MACH_POODLE) += poodle.o corgi_ssp.o |
20 | obj-$(CONFIG_MACH_TOSA) += tosa.o | 20 | obj-$(CONFIG_MACH_TOSA) += tosa.o |
21 | obj-$(CONFIG_MACH_EM_X270) += em-x270.o | ||
21 | 22 | ||
22 | # Support for blinky lights | 23 | # Support for blinky lights |
23 | led-y := leds.o | 24 | led-y := leds.o |
diff --git a/arch/arm/mach-pxa/devices.h b/arch/arm/mach-pxa/devices.h index 9a6faff8e5a7..636fdb1c049c 100644 --- a/arch/arm/mach-pxa/devices.h +++ b/arch/arm/mach-pxa/devices.h | |||
@@ -1,11 +1,11 @@ | |||
1 | extern struct platform_device pxamci_device; | 1 | extern struct platform_device pxa_device_mci; |
2 | extern struct platform_device pxaudc_device; | 2 | extern struct platform_device pxa_device_udc; |
3 | extern struct platform_device pxafb_device; | 3 | extern struct platform_device pxa_device_fb; |
4 | extern struct platform_device ffuart_device; | 4 | extern struct platform_device pxa_device_ffuart; |
5 | extern struct platform_device btuart_device; | 5 | extern struct platform_device pxa_device_btuart; |
6 | extern struct platform_device stuart_device; | 6 | extern struct platform_device pxa_device_stuart; |
7 | extern struct platform_device hwuart_device; | 7 | extern struct platform_device pxa_device_hwuart; |
8 | extern struct platform_device pxai2c_device; | 8 | extern struct platform_device pxa_device_i2c; |
9 | extern struct platform_device pxai2s_device; | 9 | extern struct platform_device pxa_device_i2s; |
10 | extern struct platform_device pxaficp_device; | 10 | extern struct platform_device pxa_device_ficp; |
11 | extern struct platform_device pxartc_device; | 11 | extern struct platform_device pxa_device_rtc; |
diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c new file mode 100644 index 000000000000..3d0ad5065ee5 --- /dev/null +++ b/arch/arm/mach-pxa/em-x270.c | |||
@@ -0,0 +1,354 @@ | |||
1 | /* | ||
2 | * Support for CompuLab EM-x270 platform | ||
3 | * | ||
4 | * Copyright (C) 2007 CompuLab, Ltd. | ||
5 | * Author: Mike Rapoport <mike@compulab.co.il> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/irq.h> | ||
13 | #include <linux/platform_device.h> | ||
14 | |||
15 | #include <linux/dm9000.h> | ||
16 | #include <linux/rtc-v3020.h> | ||
17 | |||
18 | #include <linux/mtd/nand.h> | ||
19 | #include <linux/mtd/partitions.h> | ||
20 | |||
21 | #include <asm/mach-types.h> | ||
22 | |||
23 | #include <asm/mach/arch.h> | ||
24 | |||
25 | #include <asm/arch/pxa-regs.h> | ||
26 | #include <asm/arch/pxafb.h> | ||
27 | #include <asm/arch/ohci.h> | ||
28 | #include <asm/arch/mmc.h> | ||
29 | #include <asm/arch/bitfield.h> | ||
30 | |||
31 | #include "generic.h" | ||
32 | |||
33 | /* GPIO IRQ usage */ | ||
34 | #define EM_X270_MMC_PD (105) | ||
35 | #define EM_X270_ETHIRQ IRQ_GPIO(41) | ||
36 | #define EM_X270_MMC_IRQ IRQ_GPIO(13) | ||
37 | |||
38 | static struct resource em_x270_dm9k_resource[] = { | ||
39 | [0] = { | ||
40 | .start = PXA_CS2_PHYS, | ||
41 | .end = PXA_CS2_PHYS + 3, | ||
42 | .flags = IORESOURCE_MEM, | ||
43 | }, | ||
44 | [1] = { | ||
45 | .start = PXA_CS2_PHYS + 8, | ||
46 | .end = PXA_CS2_PHYS + 8 + 0x3f, | ||
47 | .flags = IORESOURCE_MEM, | ||
48 | }, | ||
49 | [2] = { | ||
50 | .start = EM_X270_ETHIRQ, | ||
51 | .end = EM_X270_ETHIRQ, | ||
52 | .flags = IORESOURCE_IRQ, | ||
53 | } | ||
54 | }; | ||
55 | |||
56 | /* for the moment we limit ourselves to 32bit IO until some | ||
57 | * better IO routines can be written and tested | ||
58 | */ | ||
59 | static struct dm9000_plat_data em_x270_dm9k_platdata = { | ||
60 | .flags = DM9000_PLATF_32BITONLY, | ||
61 | }; | ||
62 | |||
63 | /* Ethernet device */ | ||
64 | static struct platform_device em_x270_dm9k = { | ||
65 | .name = "dm9000", | ||
66 | .id = 0, | ||
67 | .num_resources = ARRAY_SIZE(em_x270_dm9k_resource), | ||
68 | .resource = em_x270_dm9k_resource, | ||
69 | .dev = { | ||
70 | .platform_data = &em_x270_dm9k_platdata, | ||
71 | } | ||
72 | }; | ||
73 | |||
74 | /* audio device */ | ||
75 | static struct platform_device em_x270_audio = { | ||
76 | .name = "pxa2xx-ac97", | ||
77 | .id = -1, | ||
78 | }; | ||
79 | |||
80 | /* WM9712 touchscreen controller. Hopefully the driver will make it to | ||
81 | * the mainstream sometime */ | ||
82 | static struct platform_device em_x270_ts = { | ||
83 | .name = "wm97xx-ts", | ||
84 | .id = -1, | ||
85 | }; | ||
86 | |||
87 | /* RTC */ | ||
88 | static struct resource em_x270_v3020_resource[] = { | ||
89 | [0] = { | ||
90 | .start = PXA_CS4_PHYS, | ||
91 | .end = PXA_CS4_PHYS + 3, | ||
92 | .flags = IORESOURCE_MEM, | ||
93 | }, | ||
94 | }; | ||
95 | |||
96 | static struct v3020_platform_data em_x270_v3020_platdata = { | ||
97 | .leftshift = 0, | ||
98 | }; | ||
99 | |||
100 | static struct platform_device em_x270_rtc = { | ||
101 | .name = "v3020", | ||
102 | .num_resources = ARRAY_SIZE(em_x270_v3020_resource), | ||
103 | .resource = em_x270_v3020_resource, | ||
104 | .id = -1, | ||
105 | .dev = { | ||
106 | .platform_data = &em_x270_v3020_platdata, | ||
107 | } | ||
108 | }; | ||
109 | |||
110 | /* NAND flash */ | ||
111 | #define GPIO_NAND_CS (11) | ||
112 | #define GPIO_NAND_RB (56) | ||
113 | |||
114 | static inline void nand_cs_on(void) | ||
115 | { | ||
116 | GPCR(GPIO_NAND_CS) = GPIO_bit(GPIO_NAND_CS); | ||
117 | } | ||
118 | |||
119 | static void nand_cs_off(void) | ||
120 | { | ||
121 | dsb(); | ||
122 | |||
123 | GPSR(GPIO_NAND_CS) = GPIO_bit(GPIO_NAND_CS); | ||
124 | } | ||
125 | |||
126 | /* hardware specific access to control-lines */ | ||
127 | static void em_x270_nand_cmd_ctl(struct mtd_info *mtd, int dat, | ||
128 | unsigned int ctrl) | ||
129 | { | ||
130 | struct nand_chip *this = mtd->priv; | ||
131 | unsigned long nandaddr = (unsigned long)this->IO_ADDR_W; | ||
132 | |||
133 | dsb(); | ||
134 | |||
135 | if (ctrl & NAND_CTRL_CHANGE) { | ||
136 | if (ctrl & NAND_ALE) | ||
137 | nandaddr |= (1 << 3); | ||
138 | else | ||
139 | nandaddr &= ~(1 << 3); | ||
140 | if (ctrl & NAND_CLE) | ||
141 | nandaddr |= (1 << 2); | ||
142 | else | ||
143 | nandaddr &= ~(1 << 2); | ||
144 | if (ctrl & NAND_NCE) | ||
145 | nand_cs_on(); | ||
146 | else | ||
147 | nand_cs_off(); | ||
148 | } | ||
149 | |||
150 | dsb(); | ||
151 | this->IO_ADDR_W = (void __iomem *)nandaddr; | ||
152 | if (dat != NAND_CMD_NONE) | ||
153 | writel(dat, this->IO_ADDR_W); | ||
154 | |||
155 | dsb(); | ||
156 | } | ||
157 | |||
158 | /* read device ready pin */ | ||
159 | static int em_x270_nand_device_ready(struct mtd_info *mtd) | ||
160 | { | ||
161 | dsb(); | ||
162 | |||
163 | return GPLR(GPIO_NAND_RB) & GPIO_bit(GPIO_NAND_RB); | ||
164 | } | ||
165 | |||
166 | static struct mtd_partition em_x270_partition_info[] = { | ||
167 | [0] = { | ||
168 | .name = "em_x270-0", | ||
169 | .offset = 0, | ||
170 | .size = SZ_4M, | ||
171 | }, | ||
172 | [1] = { | ||
173 | .name = "em_x270-1", | ||
174 | .offset = MTDPART_OFS_APPEND, | ||
175 | .size = MTDPART_SIZ_FULL | ||
176 | }, | ||
177 | }; | ||
178 | |||
179 | static const char *em_x270_part_probes[] = { "cmdlinepart", NULL }; | ||
180 | |||
181 | struct platform_nand_data em_x270_nand_platdata = { | ||
182 | .chip = { | ||
183 | .nr_chips = 1, | ||
184 | .chip_offset = 0, | ||
185 | .nr_partitions = ARRAY_SIZE(em_x270_partition_info), | ||
186 | .partitions = em_x270_partition_info, | ||
187 | .chip_delay = 20, | ||
188 | .part_probe_types = em_x270_part_probes, | ||
189 | }, | ||
190 | .ctrl = { | ||
191 | .hwcontrol = 0, | ||
192 | .dev_ready = em_x270_nand_device_ready, | ||
193 | .select_chip = 0, | ||
194 | .cmd_ctrl = em_x270_nand_cmd_ctl, | ||
195 | }, | ||
196 | }; | ||
197 | |||
198 | static struct resource em_x270_nand_resource[] = { | ||
199 | [0] = { | ||
200 | .start = PXA_CS1_PHYS, | ||
201 | .end = PXA_CS1_PHYS + 12, | ||
202 | .flags = IORESOURCE_MEM, | ||
203 | }, | ||
204 | }; | ||
205 | |||
206 | static struct platform_device em_x270_nand = { | ||
207 | .name = "gen_nand", | ||
208 | .num_resources = ARRAY_SIZE(em_x270_nand_resource), | ||
209 | .resource = em_x270_nand_resource, | ||
210 | .id = -1, | ||
211 | .dev = { | ||
212 | .platform_data = &em_x270_nand_platdata, | ||
213 | } | ||
214 | }; | ||
215 | |||
216 | /* platform devices */ | ||
217 | static struct platform_device *platform_devices[] __initdata = { | ||
218 | &em_x270_dm9k, | ||
219 | &em_x270_audio, | ||
220 | &em_x270_ts, | ||
221 | &em_x270_rtc, | ||
222 | &em_x270_nand, | ||
223 | }; | ||
224 | |||
225 | |||
226 | /* PXA27x OHCI controller setup */ | ||
227 | static int em_x270_ohci_init(struct device *dev) | ||
228 | { | ||
229 | /* Set the Power Control Polarity Low */ | ||
230 | UHCHR = (UHCHR | UHCHR_PCPL) & | ||
231 | ~(UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSE); | ||
232 | |||
233 | /* enable port 2 transiever */ | ||
234 | UP2OCR = UP2OCR_HXS | UP2OCR_HXOE; | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | static struct pxaohci_platform_data em_x270_ohci_platform_data = { | ||
240 | .port_mode = PMM_PERPORT_MODE, | ||
241 | .init = em_x270_ohci_init, | ||
242 | }; | ||
243 | |||
244 | |||
245 | static int em_x270_mci_init(struct device *dev, | ||
246 | irq_handler_t em_x270_detect_int, | ||
247 | void *data) | ||
248 | { | ||
249 | int err; | ||
250 | |||
251 | /* setup GPIO for PXA27x MMC controller */ | ||
252 | pxa_gpio_mode(GPIO32_MMCCLK_MD); | ||
253 | pxa_gpio_mode(GPIO112_MMCCMD_MD); | ||
254 | pxa_gpio_mode(GPIO92_MMCDAT0_MD); | ||
255 | pxa_gpio_mode(GPIO109_MMCDAT1_MD); | ||
256 | pxa_gpio_mode(GPIO110_MMCDAT2_MD); | ||
257 | pxa_gpio_mode(GPIO111_MMCDAT3_MD); | ||
258 | |||
259 | /* EM-X270 uses GPIO13 as SD power enable */ | ||
260 | pxa_gpio_mode(EM_X270_MMC_PD | GPIO_OUT); | ||
261 | |||
262 | err = request_irq(EM_X270_MMC_IRQ, em_x270_detect_int, | ||
263 | IRQF_DISABLED | IRQF_TRIGGER_FALLING, | ||
264 | "MMC card detect", data); | ||
265 | if (err) { | ||
266 | printk(KERN_ERR "%s: can't request MMC card detect IRQ: %d\n", | ||
267 | __FUNCTION__, err); | ||
268 | return err; | ||
269 | } | ||
270 | |||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | static void em_x270_mci_setpower(struct device *dev, unsigned int vdd) | ||
275 | { | ||
276 | /* | ||
277 | FIXME: current hardware implementation does not allow to | ||
278 | enable/disable MMC power. This will be fixed in next HW releases, | ||
279 | and we'll need to add implmentation here. | ||
280 | */ | ||
281 | return; | ||
282 | } | ||
283 | |||
284 | static void em_x270_mci_exit(struct device *dev, void *data) | ||
285 | { | ||
286 | free_irq(EM_X270_MMC_IRQ, data); | ||
287 | } | ||
288 | |||
289 | static struct pxamci_platform_data em_x270_mci_platform_data = { | ||
290 | .ocr_mask = MMC_VDD_28_29|MMC_VDD_29_30|MMC_VDD_30_31, | ||
291 | .init = em_x270_mci_init, | ||
292 | .setpower = em_x270_mci_setpower, | ||
293 | .exit = em_x270_mci_exit, | ||
294 | }; | ||
295 | |||
296 | /* LCD 480x640 */ | ||
297 | static struct pxafb_mode_info em_x270_lcd_mode = { | ||
298 | .pixclock = 50000, | ||
299 | .bpp = 16, | ||
300 | .xres = 480, | ||
301 | .yres = 640, | ||
302 | .hsync_len = 8, | ||
303 | .vsync_len = 2, | ||
304 | .left_margin = 8, | ||
305 | .upper_margin = 0, | ||
306 | .right_margin = 24, | ||
307 | .lower_margin = 4, | ||
308 | .cmap_greyscale = 0, | ||
309 | }; | ||
310 | |||
311 | static struct pxafb_mach_info em_x270_lcd = { | ||
312 | .modes = &em_x270_lcd_mode, | ||
313 | .num_modes = 1, | ||
314 | .cmap_inverse = 0, | ||
315 | .cmap_static = 0, | ||
316 | .lccr0 = LCCR0_PAS, | ||
317 | .lccr3 = LCCR3_PixClkDiv(0x01) | LCCR3_Acb(0xff), | ||
318 | }; | ||
319 | |||
320 | static void __init em_x270_init(void) | ||
321 | { | ||
322 | /* setup LCD */ | ||
323 | set_pxa_fb_info(&em_x270_lcd); | ||
324 | |||
325 | /* register EM-X270 platform devices */ | ||
326 | platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); | ||
327 | |||
328 | /* set MCI and OHCI platform parameters */ | ||
329 | pxa_set_mci_info(&em_x270_mci_platform_data); | ||
330 | pxa_set_ohci_info(&em_x270_ohci_platform_data); | ||
331 | |||
332 | /* setup STUART GPIOs */ | ||
333 | pxa_gpio_mode(GPIO46_STRXD_MD); | ||
334 | pxa_gpio_mode(GPIO47_STTXD_MD); | ||
335 | |||
336 | /* setup BTUART GPIOs */ | ||
337 | pxa_gpio_mode(GPIO42_BTRXD_MD); | ||
338 | pxa_gpio_mode(GPIO43_BTTXD_MD); | ||
339 | pxa_gpio_mode(GPIO44_BTCTS_MD); | ||
340 | pxa_gpio_mode(GPIO45_BTRTS_MD); | ||
341 | |||
342 | /* Setup interrupt for dm9000 */ | ||
343 | set_irq_type(EM_X270_ETHIRQ, IRQT_RISING); | ||
344 | } | ||
345 | |||
346 | MACHINE_START(EM_X270, "Compulab EM-x270") | ||
347 | .boot_params = 0xa0000100, | ||
348 | .phys_io = 0x40000000, | ||
349 | .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, | ||
350 | .map_io = pxa_map_io, | ||
351 | .init_irq = pxa27x_init_irq, | ||
352 | .timer = &pxa_timer, | ||
353 | .init_machine = em_x270_init, | ||
354 | MACHINE_END | ||
diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c index 296539b6359c..5510f6fdce55 100644 --- a/arch/arm/mach-pxa/generic.c +++ b/arch/arm/mach-pxa/generic.c | |||
@@ -243,7 +243,7 @@ static struct resource pxamci_resources[] = { | |||
243 | 243 | ||
244 | static u64 pxamci_dmamask = 0xffffffffUL; | 244 | static u64 pxamci_dmamask = 0xffffffffUL; |
245 | 245 | ||
246 | struct platform_device pxamci_device = { | 246 | struct platform_device pxa_device_mci = { |
247 | .name = "pxa2xx-mci", | 247 | .name = "pxa2xx-mci", |
248 | .id = -1, | 248 | .id = -1, |
249 | .dev = { | 249 | .dev = { |
@@ -256,7 +256,7 @@ struct platform_device pxamci_device = { | |||
256 | 256 | ||
257 | void __init pxa_set_mci_info(struct pxamci_platform_data *info) | 257 | void __init pxa_set_mci_info(struct pxamci_platform_data *info) |
258 | { | 258 | { |
259 | pxamci_device.dev.platform_data = info; | 259 | pxa_device_mci.dev.platform_data = info; |
260 | } | 260 | } |
261 | 261 | ||
262 | 262 | ||
@@ -282,7 +282,7 @@ static struct resource pxa2xx_udc_resources[] = { | |||
282 | 282 | ||
283 | static u64 udc_dma_mask = ~(u32)0; | 283 | static u64 udc_dma_mask = ~(u32)0; |
284 | 284 | ||
285 | struct platform_device pxaudc_device = { | 285 | struct platform_device pxa_device_udc = { |
286 | .name = "pxa2xx-udc", | 286 | .name = "pxa2xx-udc", |
287 | .id = -1, | 287 | .id = -1, |
288 | .resource = pxa2xx_udc_resources, | 288 | .resource = pxa2xx_udc_resources, |
@@ -308,7 +308,7 @@ static struct resource pxafb_resources[] = { | |||
308 | 308 | ||
309 | static u64 fb_dma_mask = ~(u64)0; | 309 | static u64 fb_dma_mask = ~(u64)0; |
310 | 310 | ||
311 | struct platform_device pxafb_device = { | 311 | struct platform_device pxa_device_fb = { |
312 | .name = "pxa2xx-fb", | 312 | .name = "pxa2xx-fb", |
313 | .id = -1, | 313 | .id = -1, |
314 | .dev = { | 314 | .dev = { |
@@ -321,27 +321,27 @@ struct platform_device pxafb_device = { | |||
321 | 321 | ||
322 | void __init set_pxa_fb_info(struct pxafb_mach_info *info) | 322 | void __init set_pxa_fb_info(struct pxafb_mach_info *info) |
323 | { | 323 | { |
324 | pxafb_device.dev.platform_data = info; | 324 | pxa_device_fb.dev.platform_data = info; |
325 | } | 325 | } |
326 | 326 | ||
327 | void __init set_pxa_fb_parent(struct device *parent_dev) | 327 | void __init set_pxa_fb_parent(struct device *parent_dev) |
328 | { | 328 | { |
329 | pxafb_device.dev.parent = parent_dev; | 329 | pxa_device_fb.dev.parent = parent_dev; |
330 | } | 330 | } |
331 | 331 | ||
332 | struct platform_device ffuart_device = { | 332 | struct platform_device pxa_device_ffuart= { |
333 | .name = "pxa2xx-uart", | 333 | .name = "pxa2xx-uart", |
334 | .id = 0, | 334 | .id = 0, |
335 | }; | 335 | }; |
336 | struct platform_device btuart_device = { | 336 | struct platform_device pxa_device_btuart = { |
337 | .name = "pxa2xx-uart", | 337 | .name = "pxa2xx-uart", |
338 | .id = 1, | 338 | .id = 1, |
339 | }; | 339 | }; |
340 | struct platform_device stuart_device = { | 340 | struct platform_device pxa_device_stuart = { |
341 | .name = "pxa2xx-uart", | 341 | .name = "pxa2xx-uart", |
342 | .id = 2, | 342 | .id = 2, |
343 | }; | 343 | }; |
344 | struct platform_device hwuart_device = { | 344 | struct platform_device pxa_device_hwuart = { |
345 | .name = "pxa2xx-uart", | 345 | .name = "pxa2xx-uart", |
346 | .id = 3, | 346 | .id = 3, |
347 | }; | 347 | }; |
@@ -358,7 +358,7 @@ static struct resource pxai2c_resources[] = { | |||
358 | }, | 358 | }, |
359 | }; | 359 | }; |
360 | 360 | ||
361 | struct platform_device pxai2c_device = { | 361 | struct platform_device pxa_device_i2c = { |
362 | .name = "pxa2xx-i2c", | 362 | .name = "pxa2xx-i2c", |
363 | .id = 0, | 363 | .id = 0, |
364 | .resource = pxai2c_resources, | 364 | .resource = pxai2c_resources, |
@@ -367,7 +367,7 @@ struct platform_device pxai2c_device = { | |||
367 | 367 | ||
368 | void __init pxa_set_i2c_info(struct i2c_pxa_platform_data *info) | 368 | void __init pxa_set_i2c_info(struct i2c_pxa_platform_data *info) |
369 | { | 369 | { |
370 | pxai2c_device.dev.platform_data = info; | 370 | pxa_device_i2c.dev.platform_data = info; |
371 | } | 371 | } |
372 | 372 | ||
373 | static struct resource pxai2s_resources[] = { | 373 | static struct resource pxai2s_resources[] = { |
@@ -382,7 +382,7 @@ static struct resource pxai2s_resources[] = { | |||
382 | }, | 382 | }, |
383 | }; | 383 | }; |
384 | 384 | ||
385 | struct platform_device pxai2s_device = { | 385 | struct platform_device pxa_device_i2s = { |
386 | .name = "pxa2xx-i2s", | 386 | .name = "pxa2xx-i2s", |
387 | .id = -1, | 387 | .id = -1, |
388 | .resource = pxai2s_resources, | 388 | .resource = pxai2s_resources, |
@@ -391,7 +391,7 @@ struct platform_device pxai2s_device = { | |||
391 | 391 | ||
392 | static u64 pxaficp_dmamask = ~(u32)0; | 392 | static u64 pxaficp_dmamask = ~(u32)0; |
393 | 393 | ||
394 | struct platform_device pxaficp_device = { | 394 | struct platform_device pxa_device_ficp = { |
395 | .name = "pxa2xx-ir", | 395 | .name = "pxa2xx-ir", |
396 | .id = -1, | 396 | .id = -1, |
397 | .dev = { | 397 | .dev = { |
@@ -402,10 +402,10 @@ struct platform_device pxaficp_device = { | |||
402 | 402 | ||
403 | void __init pxa_set_ficp_info(struct pxaficp_platform_data *info) | 403 | void __init pxa_set_ficp_info(struct pxaficp_platform_data *info) |
404 | { | 404 | { |
405 | pxaficp_device.dev.platform_data = info; | 405 | pxa_device_ficp.dev.platform_data = info; |
406 | } | 406 | } |
407 | 407 | ||
408 | struct platform_device pxartc_device = { | 408 | struct platform_device pxa_device_rtc = { |
409 | .name = "sa1100-rtc", | 409 | .name = "sa1100-rtc", |
410 | .id = -1, | 410 | .id = -1, |
411 | }; | 411 | }; |
diff --git a/arch/arm/mach-pxa/pm.c b/arch/arm/mach-pxa/pm.c index e66dbc26add1..b59a81a8e7d3 100644 --- a/arch/arm/mach-pxa/pm.c +++ b/arch/arm/mach-pxa/pm.c | |||
@@ -24,61 +24,13 @@ | |||
24 | #include <asm/arch/lubbock.h> | 24 | #include <asm/arch/lubbock.h> |
25 | #include <asm/mach/time.h> | 25 | #include <asm/mach/time.h> |
26 | 26 | ||
27 | 27 | struct pxa_cpu_pm_fns *pxa_cpu_pm_fns; | |
28 | /* | 28 | static unsigned long *sleep_save; |
29 | * Debug macros | ||
30 | */ | ||
31 | #undef DEBUG | ||
32 | |||
33 | #define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x | ||
34 | #define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x] | ||
35 | |||
36 | #define RESTORE_GPLEVEL(n) do { \ | ||
37 | GPSR##n = sleep_save[SLEEP_SAVE_GPLR##n]; \ | ||
38 | GPCR##n = ~sleep_save[SLEEP_SAVE_GPLR##n]; \ | ||
39 | } while (0) | ||
40 | |||
41 | /* | ||
42 | * List of global PXA peripheral registers to preserve. | ||
43 | * More ones like CP and general purpose register values are preserved | ||
44 | * with the stack pointer in sleep.S. | ||
45 | */ | ||
46 | enum { SLEEP_SAVE_START = 0, | ||
47 | |||
48 | SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2, SLEEP_SAVE_GPLR3, | ||
49 | SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2, SLEEP_SAVE_GPDR3, | ||
50 | SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2, SLEEP_SAVE_GRER3, | ||
51 | SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2, SLEEP_SAVE_GFER3, | ||
52 | SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2, SLEEP_SAVE_PGSR3, | ||
53 | |||
54 | SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U, | ||
55 | SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR1_U, | ||
56 | SLEEP_SAVE_GAFR2_L, SLEEP_SAVE_GAFR2_U, | ||
57 | SLEEP_SAVE_GAFR3_L, SLEEP_SAVE_GAFR3_U, | ||
58 | |||
59 | SLEEP_SAVE_PSTR, | ||
60 | |||
61 | SLEEP_SAVE_ICMR, | ||
62 | SLEEP_SAVE_CKEN, | ||
63 | |||
64 | #ifdef CONFIG_PXA27x | ||
65 | SLEEP_SAVE_MDREFR, | ||
66 | SLEEP_SAVE_PWER, SLEEP_SAVE_PCFR, SLEEP_SAVE_PRER, | ||
67 | SLEEP_SAVE_PFER, SLEEP_SAVE_PKWR, | ||
68 | #endif | ||
69 | |||
70 | SLEEP_SAVE_CKSUM, | ||
71 | |||
72 | SLEEP_SAVE_SIZE | ||
73 | }; | ||
74 | |||
75 | 29 | ||
76 | int pxa_pm_enter(suspend_state_t state) | 30 | int pxa_pm_enter(suspend_state_t state) |
77 | { | 31 | { |
78 | unsigned long sleep_save[SLEEP_SAVE_SIZE]; | 32 | unsigned long sleep_save_checksum = 0, checksum = 0; |
79 | unsigned long checksum = 0; | ||
80 | int i; | 33 | int i; |
81 | extern void pxa_cpu_pm_enter(suspend_state_t state); | ||
82 | 34 | ||
83 | #ifdef CONFIG_IWMMXT | 35 | #ifdef CONFIG_IWMMXT |
84 | /* force any iWMMXt context to ram **/ | 36 | /* force any iWMMXt context to ram **/ |
@@ -86,100 +38,35 @@ int pxa_pm_enter(suspend_state_t state) | |||
86 | iwmmxt_task_disable(NULL); | 38 | iwmmxt_task_disable(NULL); |
87 | #endif | 39 | #endif |
88 | 40 | ||
89 | SAVE(GPLR0); SAVE(GPLR1); SAVE(GPLR2); | 41 | pxa_cpu_pm_fns->save(sleep_save); |
90 | SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2); | ||
91 | SAVE(GRER0); SAVE(GRER1); SAVE(GRER2); | ||
92 | SAVE(GFER0); SAVE(GFER1); SAVE(GFER2); | ||
93 | SAVE(PGSR0); SAVE(PGSR1); SAVE(PGSR2); | ||
94 | |||
95 | SAVE(GAFR0_L); SAVE(GAFR0_U); | ||
96 | SAVE(GAFR1_L); SAVE(GAFR1_U); | ||
97 | SAVE(GAFR2_L); SAVE(GAFR2_U); | ||
98 | |||
99 | #ifdef CONFIG_PXA27x | ||
100 | SAVE(MDREFR); | ||
101 | SAVE(GPLR3); SAVE(GPDR3); SAVE(GRER3); SAVE(GFER3); SAVE(PGSR3); | ||
102 | SAVE(GAFR3_L); SAVE(GAFR3_U); | ||
103 | SAVE(PWER); SAVE(PCFR); SAVE(PRER); | ||
104 | SAVE(PFER); SAVE(PKWR); | ||
105 | #endif | ||
106 | |||
107 | SAVE(ICMR); | ||
108 | ICMR = 0; | ||
109 | |||
110 | SAVE(CKEN); | ||
111 | SAVE(PSTR); | ||
112 | |||
113 | /* Note: wake up source are set up in each machine specific files */ | ||
114 | |||
115 | /* clear GPIO transition detect bits */ | ||
116 | GEDR0 = GEDR0; GEDR1 = GEDR1; GEDR2 = GEDR2; | ||
117 | #ifdef CONFIG_PXA27x | ||
118 | GEDR3 = GEDR3; | ||
119 | #endif | ||
120 | 42 | ||
121 | /* Clear sleep reset status */ | 43 | /* Clear sleep reset status */ |
122 | RCSR = RCSR_SMR; | 44 | RCSR = RCSR_SMR; |
123 | 45 | ||
124 | /* before sleeping, calculate and save a checksum */ | 46 | /* before sleeping, calculate and save a checksum */ |
125 | for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++) | 47 | for (i = 0; i < pxa_cpu_pm_fns->save_size - 1; i++) |
126 | checksum += sleep_save[i]; | 48 | sleep_save_checksum += sleep_save[i]; |
127 | sleep_save[SLEEP_SAVE_CKSUM] = checksum; | ||
128 | 49 | ||
129 | /* *** go zzz *** */ | 50 | /* *** go zzz *** */ |
130 | pxa_cpu_pm_enter(state); | 51 | pxa_cpu_pm_fns->enter(state); |
131 | |||
132 | cpu_init(); | 52 | cpu_init(); |
133 | 53 | ||
134 | /* after sleeping, validate the checksum */ | 54 | /* after sleeping, validate the checksum */ |
135 | checksum = 0; | 55 | for (i = 0; i < pxa_cpu_pm_fns->save_size - 1; i++) |
136 | for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++) | ||
137 | checksum += sleep_save[i]; | 56 | checksum += sleep_save[i]; |
138 | 57 | ||
139 | /* if invalid, display message and wait for a hardware reset */ | 58 | /* if invalid, display message and wait for a hardware reset */ |
140 | if (checksum != sleep_save[SLEEP_SAVE_CKSUM]) { | 59 | if (checksum != sleep_save_checksum) { |
141 | #ifdef CONFIG_ARCH_LUBBOCK | 60 | #ifdef CONFIG_ARCH_LUBBOCK |
142 | LUB_HEXLED = 0xbadbadc5; | 61 | LUB_HEXLED = 0xbadbadc5; |
143 | #endif | 62 | #endif |
144 | while (1) | 63 | while (1) |
145 | pxa_cpu_pm_enter(state); | 64 | pxa_cpu_pm_fns->enter(state); |
146 | } | 65 | } |
147 | 66 | ||
148 | /* ensure not to come back here if it wasn't intended */ | 67 | pxa_cpu_pm_fns->restore(sleep_save); |
149 | PSPR = 0; | ||
150 | |||
151 | /* restore registers */ | ||
152 | RESTORE_GPLEVEL(0); RESTORE_GPLEVEL(1); RESTORE_GPLEVEL(2); | ||
153 | RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2); | ||
154 | RESTORE(GAFR0_L); RESTORE(GAFR0_U); | ||
155 | RESTORE(GAFR1_L); RESTORE(GAFR1_U); | ||
156 | RESTORE(GAFR2_L); RESTORE(GAFR2_U); | ||
157 | RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2); | ||
158 | RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2); | ||
159 | RESTORE(PGSR0); RESTORE(PGSR1); RESTORE(PGSR2); | ||
160 | |||
161 | #ifdef CONFIG_PXA27x | ||
162 | RESTORE(MDREFR); | ||
163 | RESTORE_GPLEVEL(3); RESTORE(GPDR3); | ||
164 | RESTORE(GAFR3_L); RESTORE(GAFR3_U); | ||
165 | RESTORE(GRER3); RESTORE(GFER3); RESTORE(PGSR3); | ||
166 | RESTORE(PWER); RESTORE(PCFR); RESTORE(PRER); | ||
167 | RESTORE(PFER); RESTORE(PKWR); | ||
168 | #endif | ||
169 | |||
170 | PSSR = PSSR_RDH | PSSR_PH; | ||
171 | |||
172 | RESTORE(CKEN); | ||
173 | |||
174 | ICLR = 0; | ||
175 | ICCR = 1; | ||
176 | RESTORE(ICMR); | ||
177 | 68 | ||
178 | RESTORE(PSTR); | 69 | pr_debug("*** made it back from resume\n"); |
179 | |||
180 | #ifdef DEBUG | ||
181 | printk(KERN_DEBUG "*** made it back from resume\n"); | ||
182 | #endif | ||
183 | 70 | ||
184 | return 0; | 71 | return 0; |
185 | } | 72 | } |
@@ -190,3 +77,35 @@ unsigned long sleep_phys_sp(void *sp) | |||
190 | { | 77 | { |
191 | return virt_to_phys(sp); | 78 | return virt_to_phys(sp); |
192 | } | 79 | } |
80 | |||
81 | static int pxa_pm_valid(suspend_state_t state) | ||
82 | { | ||
83 | if (pxa_cpu_pm_fns) | ||
84 | return pxa_cpu_pm_fns->valid(state); | ||
85 | |||
86 | return -EINVAL; | ||
87 | } | ||
88 | |||
89 | static struct pm_ops pxa_pm_ops = { | ||
90 | .valid = pxa_pm_valid, | ||
91 | .enter = pxa_pm_enter, | ||
92 | }; | ||
93 | |||
94 | static int __init pxa_pm_init(void) | ||
95 | { | ||
96 | if (!pxa_cpu_pm_fns) { | ||
97 | printk(KERN_ERR "no valid pxa_cpu_pm_fns defined\n"); | ||
98 | return -EINVAL; | ||
99 | } | ||
100 | |||
101 | sleep_save = kmalloc(pxa_cpu_pm_fns->save_size, GFP_KERNEL); | ||
102 | if (!sleep_save) { | ||
103 | printk(KERN_ERR "failed to alloc memory for pm save\n"); | ||
104 | return -ENOMEM; | ||
105 | } | ||
106 | |||
107 | pm_set_ops(&pxa_pm_ops); | ||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | device_initcall(pxa_pm_init); | ||
diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c index f36ca448338e..6dfcca72e90f 100644 --- a/arch/arm/mach-pxa/pxa25x.c +++ b/arch/arm/mach-pxa/pxa25x.c | |||
@@ -110,26 +110,99 @@ EXPORT_SYMBOL(get_lcdclk_frequency_10khz); | |||
110 | 110 | ||
111 | #ifdef CONFIG_PM | 111 | #ifdef CONFIG_PM |
112 | 112 | ||
113 | void pxa_cpu_pm_enter(suspend_state_t state) | 113 | #define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x |
114 | #define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x] | ||
115 | |||
116 | #define RESTORE_GPLEVEL(n) do { \ | ||
117 | GPSR##n = sleep_save[SLEEP_SAVE_GPLR##n]; \ | ||
118 | GPCR##n = ~sleep_save[SLEEP_SAVE_GPLR##n]; \ | ||
119 | } while (0) | ||
120 | |||
121 | /* | ||
122 | * List of global PXA peripheral registers to preserve. | ||
123 | * More ones like CP and general purpose register values are preserved | ||
124 | * with the stack pointer in sleep.S. | ||
125 | */ | ||
126 | enum { SLEEP_SAVE_START = 0, | ||
127 | |||
128 | SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2, | ||
129 | SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2, | ||
130 | SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2, | ||
131 | SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2, | ||
132 | SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2, | ||
133 | |||
134 | SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U, | ||
135 | SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR1_U, | ||
136 | SLEEP_SAVE_GAFR2_L, SLEEP_SAVE_GAFR2_U, | ||
137 | |||
138 | SLEEP_SAVE_PSTR, | ||
139 | |||
140 | SLEEP_SAVE_ICMR, | ||
141 | SLEEP_SAVE_CKEN, | ||
142 | |||
143 | SLEEP_SAVE_SIZE | ||
144 | }; | ||
145 | |||
146 | |||
147 | static void pxa25x_cpu_pm_save(unsigned long *sleep_save) | ||
148 | { | ||
149 | SAVE(GPLR0); SAVE(GPLR1); SAVE(GPLR2); | ||
150 | SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2); | ||
151 | SAVE(GRER0); SAVE(GRER1); SAVE(GRER2); | ||
152 | SAVE(GFER0); SAVE(GFER1); SAVE(GFER2); | ||
153 | SAVE(PGSR0); SAVE(PGSR1); SAVE(PGSR2); | ||
154 | |||
155 | SAVE(GAFR0_L); SAVE(GAFR0_U); | ||
156 | SAVE(GAFR1_L); SAVE(GAFR1_U); | ||
157 | SAVE(GAFR2_L); SAVE(GAFR2_U); | ||
158 | |||
159 | SAVE(ICMR); | ||
160 | SAVE(CKEN); | ||
161 | SAVE(PSTR); | ||
162 | } | ||
163 | |||
164 | static void pxa25x_cpu_pm_restore(unsigned long *sleep_save) | ||
114 | { | 165 | { |
115 | extern void pxa_cpu_suspend(unsigned int); | 166 | /* restore registers */ |
116 | extern void pxa_cpu_resume(void); | 167 | RESTORE_GPLEVEL(0); RESTORE_GPLEVEL(1); RESTORE_GPLEVEL(2); |
168 | RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2); | ||
169 | RESTORE(GAFR0_L); RESTORE(GAFR0_U); | ||
170 | RESTORE(GAFR1_L); RESTORE(GAFR1_U); | ||
171 | RESTORE(GAFR2_L); RESTORE(GAFR2_U); | ||
172 | RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2); | ||
173 | RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2); | ||
174 | RESTORE(PGSR0); RESTORE(PGSR1); RESTORE(PGSR2); | ||
175 | |||
176 | RESTORE(CKEN); | ||
177 | RESTORE(ICMR); | ||
178 | RESTORE(PSTR); | ||
179 | } | ||
117 | 180 | ||
181 | static void pxa25x_cpu_pm_enter(suspend_state_t state) | ||
182 | { | ||
118 | CKEN = 0; | 183 | CKEN = 0; |
119 | 184 | ||
120 | switch (state) { | 185 | switch (state) { |
121 | case PM_SUSPEND_MEM: | 186 | case PM_SUSPEND_MEM: |
122 | /* set resume return address */ | 187 | /* set resume return address */ |
123 | PSPR = virt_to_phys(pxa_cpu_resume); | 188 | PSPR = virt_to_phys(pxa_cpu_resume); |
124 | pxa_cpu_suspend(PWRMODE_SLEEP); | 189 | pxa25x_cpu_suspend(PWRMODE_SLEEP); |
125 | break; | 190 | break; |
126 | } | 191 | } |
127 | } | 192 | } |
128 | 193 | ||
129 | static struct pm_ops pxa25x_pm_ops = { | 194 | static struct pxa_cpu_pm_fns pxa25x_cpu_pm_fns = { |
130 | .enter = pxa_pm_enter, | 195 | .save_size = SLEEP_SAVE_SIZE, |
131 | .valid = pm_valid_only_mem, | 196 | .valid = pm_valid_only_mem, |
197 | .save = pxa25x_cpu_pm_save, | ||
198 | .restore = pxa25x_cpu_pm_restore, | ||
199 | .enter = pxa25x_cpu_pm_enter, | ||
132 | }; | 200 | }; |
201 | |||
202 | static void __init pxa25x_init_pm(void) | ||
203 | { | ||
204 | pxa_cpu_pm_fns = &pxa25x_cpu_pm_fns; | ||
205 | } | ||
133 | #endif | 206 | #endif |
134 | 207 | ||
135 | void __init pxa25x_init_irq(void) | 208 | void __init pxa25x_init_irq(void) |
@@ -139,16 +212,16 @@ void __init pxa25x_init_irq(void) | |||
139 | } | 212 | } |
140 | 213 | ||
141 | static struct platform_device *pxa25x_devices[] __initdata = { | 214 | static struct platform_device *pxa25x_devices[] __initdata = { |
142 | &pxamci_device, | 215 | &pxa_device_mci, |
143 | &pxaudc_device, | 216 | &pxa_device_udc, |
144 | &pxafb_device, | 217 | &pxa_device_fb, |
145 | &ffuart_device, | 218 | &pxa_device_ffuart, |
146 | &btuart_device, | 219 | &pxa_device_btuart, |
147 | &stuart_device, | 220 | &pxa_device_stuart, |
148 | &pxai2c_device, | 221 | &pxa_device_i2c, |
149 | &pxai2s_device, | 222 | &pxa_device_i2s, |
150 | &pxaficp_device, | 223 | &pxa_device_ficp, |
151 | &pxartc_device, | 224 | &pxa_device_rtc, |
152 | }; | 225 | }; |
153 | 226 | ||
154 | static int __init pxa25x_init(void) | 227 | static int __init pxa25x_init(void) |
@@ -159,14 +232,14 @@ static int __init pxa25x_init(void) | |||
159 | if ((ret = pxa_init_dma(16))) | 232 | if ((ret = pxa_init_dma(16))) |
160 | return ret; | 233 | return ret; |
161 | #ifdef CONFIG_PM | 234 | #ifdef CONFIG_PM |
162 | pm_set_ops(&pxa25x_pm_ops); | 235 | pxa25x_init_pm(); |
163 | #endif | 236 | #endif |
164 | ret = platform_add_devices(pxa25x_devices, | 237 | ret = platform_add_devices(pxa25x_devices, |
165 | ARRAY_SIZE(pxa25x_devices)); | 238 | ARRAY_SIZE(pxa25x_devices)); |
166 | } | 239 | } |
167 | /* Only add HWUART for PXA255/26x; PXA210/250/27x do not have it. */ | 240 | /* Only add HWUART for PXA255/26x; PXA210/250/27x do not have it. */ |
168 | if (cpu_is_pxa25x()) | 241 | if (cpu_is_pxa25x()) |
169 | ret = platform_device_register(&hwuart_device); | 242 | ret = platform_device_register(&pxa_device_hwuart); |
170 | 243 | ||
171 | return ret; | 244 | return ret; |
172 | } | 245 | } |
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c index aa5bb02c897b..203371ab19db 100644 --- a/arch/arm/mach-pxa/pxa27x.c +++ b/arch/arm/mach-pxa/pxa27x.c | |||
@@ -126,14 +126,107 @@ EXPORT_SYMBOL(get_lcdclk_frequency_10khz); | |||
126 | 126 | ||
127 | #ifdef CONFIG_PM | 127 | #ifdef CONFIG_PM |
128 | 128 | ||
129 | void pxa_cpu_pm_enter(suspend_state_t state) | 129 | #define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x |
130 | #define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x] | ||
131 | |||
132 | #define RESTORE_GPLEVEL(n) do { \ | ||
133 | GPSR##n = sleep_save[SLEEP_SAVE_GPLR##n]; \ | ||
134 | GPCR##n = ~sleep_save[SLEEP_SAVE_GPLR##n]; \ | ||
135 | } while (0) | ||
136 | |||
137 | /* | ||
138 | * List of global PXA peripheral registers to preserve. | ||
139 | * More ones like CP and general purpose register values are preserved | ||
140 | * with the stack pointer in sleep.S. | ||
141 | */ | ||
142 | enum { SLEEP_SAVE_START = 0, | ||
143 | |||
144 | SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2, SLEEP_SAVE_GPLR3, | ||
145 | SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2, SLEEP_SAVE_GPDR3, | ||
146 | SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2, SLEEP_SAVE_GRER3, | ||
147 | SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2, SLEEP_SAVE_GFER3, | ||
148 | SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2, SLEEP_SAVE_PGSR3, | ||
149 | |||
150 | SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U, | ||
151 | SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR1_U, | ||
152 | SLEEP_SAVE_GAFR2_L, SLEEP_SAVE_GAFR2_U, | ||
153 | SLEEP_SAVE_GAFR3_L, SLEEP_SAVE_GAFR3_U, | ||
154 | |||
155 | SLEEP_SAVE_PSTR, | ||
156 | |||
157 | SLEEP_SAVE_ICMR, | ||
158 | SLEEP_SAVE_CKEN, | ||
159 | |||
160 | SLEEP_SAVE_MDREFR, | ||
161 | SLEEP_SAVE_PWER, SLEEP_SAVE_PCFR, SLEEP_SAVE_PRER, | ||
162 | SLEEP_SAVE_PFER, SLEEP_SAVE_PKWR, | ||
163 | |||
164 | SLEEP_SAVE_SIZE | ||
165 | }; | ||
166 | |||
167 | void pxa27x_cpu_pm_save(unsigned long *sleep_save) | ||
168 | { | ||
169 | SAVE(GPLR0); SAVE(GPLR1); SAVE(GPLR2); SAVE(GPLR3); | ||
170 | SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2); SAVE(GPDR3); | ||
171 | SAVE(GRER0); SAVE(GRER1); SAVE(GRER2); SAVE(GRER3); | ||
172 | SAVE(GFER0); SAVE(GFER1); SAVE(GFER2); SAVE(GFER3); | ||
173 | SAVE(PGSR0); SAVE(PGSR1); SAVE(PGSR2); SAVE(PGSR3); | ||
174 | |||
175 | SAVE(GAFR0_L); SAVE(GAFR0_U); | ||
176 | SAVE(GAFR1_L); SAVE(GAFR1_U); | ||
177 | SAVE(GAFR2_L); SAVE(GAFR2_U); | ||
178 | SAVE(GAFR3_L); SAVE(GAFR3_U); | ||
179 | |||
180 | SAVE(MDREFR); | ||
181 | SAVE(PWER); SAVE(PCFR); SAVE(PRER); | ||
182 | SAVE(PFER); SAVE(PKWR); | ||
183 | |||
184 | SAVE(ICMR); ICMR = 0; | ||
185 | SAVE(CKEN); | ||
186 | SAVE(PSTR); | ||
187 | |||
188 | /* Clear GPIO transition detect bits */ | ||
189 | GEDR0 = GEDR0; GEDR1 = GEDR1; GEDR2 = GEDR2; GEDR3 = GEDR3; | ||
190 | } | ||
191 | |||
192 | void pxa27x_cpu_pm_restore(unsigned long *sleep_save) | ||
193 | { | ||
194 | /* ensure not to come back here if it wasn't intended */ | ||
195 | PSPR = 0; | ||
196 | |||
197 | /* restore registers */ | ||
198 | RESTORE_GPLEVEL(0); RESTORE_GPLEVEL(1); | ||
199 | RESTORE_GPLEVEL(2); RESTORE_GPLEVEL(3); | ||
200 | RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2); RESTORE(GPDR3); | ||
201 | RESTORE(GAFR0_L); RESTORE(GAFR0_U); | ||
202 | RESTORE(GAFR1_L); RESTORE(GAFR1_U); | ||
203 | RESTORE(GAFR2_L); RESTORE(GAFR2_U); | ||
204 | RESTORE(GAFR3_L); RESTORE(GAFR3_U); | ||
205 | RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2); RESTORE(GRER3); | ||
206 | RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2); RESTORE(GFER3); | ||
207 | RESTORE(PGSR0); RESTORE(PGSR1); RESTORE(PGSR2); RESTORE(PGSR3); | ||
208 | |||
209 | RESTORE(MDREFR); | ||
210 | RESTORE(PWER); RESTORE(PCFR); RESTORE(PRER); | ||
211 | RESTORE(PFER); RESTORE(PKWR); | ||
212 | |||
213 | PSSR = PSSR_RDH | PSSR_PH; | ||
214 | |||
215 | RESTORE(CKEN); | ||
216 | |||
217 | ICLR = 0; | ||
218 | ICCR = 1; | ||
219 | RESTORE(ICMR); | ||
220 | RESTORE(PSTR); | ||
221 | } | ||
222 | |||
223 | void pxa27x_cpu_pm_enter(suspend_state_t state) | ||
130 | { | 224 | { |
131 | extern void pxa_cpu_standby(void); | 225 | extern void pxa_cpu_standby(void); |
132 | extern void pxa_cpu_suspend(unsigned int); | ||
133 | extern void pxa_cpu_resume(void); | ||
134 | 226 | ||
135 | if (state == PM_SUSPEND_STANDBY) | 227 | if (state == PM_SUSPEND_STANDBY) |
136 | CKEN = (1 << CKEN_MEMC) | (1 << CKEN_OSTIMER) | (1 << CKEN_LCD) | (1 << CKEN_PWM0); | 228 | CKEN = (1 << CKEN_MEMC) | (1 << CKEN_OSTIMER) | |
229 | (1 << CKEN_LCD) | (1 << CKEN_PWM0); | ||
137 | else | 230 | else |
138 | CKEN = (1 << CKEN_MEMC) | (1 << CKEN_OSTIMER); | 231 | CKEN = (1 << CKEN_MEMC) | (1 << CKEN_OSTIMER); |
139 | 232 | ||
@@ -150,20 +243,28 @@ void pxa_cpu_pm_enter(suspend_state_t state) | |||
150 | case PM_SUSPEND_MEM: | 243 | case PM_SUSPEND_MEM: |
151 | /* set resume return address */ | 244 | /* set resume return address */ |
152 | PSPR = virt_to_phys(pxa_cpu_resume); | 245 | PSPR = virt_to_phys(pxa_cpu_resume); |
153 | pxa_cpu_suspend(PWRMODE_SLEEP); | 246 | pxa27x_cpu_suspend(PWRMODE_SLEEP); |
154 | break; | 247 | break; |
155 | } | 248 | } |
156 | } | 249 | } |
157 | 250 | ||
158 | static int pxa27x_pm_valid(suspend_state_t state) | 251 | static int pxa27x_cpu_pm_valid(suspend_state_t state) |
159 | { | 252 | { |
160 | return state == PM_SUSPEND_MEM || state == PM_SUSPEND_STANDBY; | 253 | return state == PM_SUSPEND_MEM || state == PM_SUSPEND_STANDBY; |
161 | } | 254 | } |
162 | 255 | ||
163 | static struct pm_ops pxa27x_pm_ops = { | 256 | static struct pxa_cpu_pm_fns pxa27x_cpu_pm_fns = { |
164 | .enter = pxa_pm_enter, | 257 | .save_size = SLEEP_SAVE_SIZE, |
165 | .valid = pxa27x_pm_valid, | 258 | .save = pxa27x_cpu_pm_save, |
259 | .restore = pxa27x_cpu_pm_restore, | ||
260 | .valid = pxa27x_cpu_pm_valid, | ||
261 | .enter = pxa27x_cpu_pm_enter, | ||
166 | }; | 262 | }; |
263 | |||
264 | static void __init pxa27x_init_pm(void) | ||
265 | { | ||
266 | pxa_cpu_pm_fns = &pxa27x_cpu_pm_fns; | ||
267 | } | ||
167 | #endif | 268 | #endif |
168 | 269 | ||
169 | /* | 270 | /* |
@@ -185,7 +286,7 @@ static struct resource pxa27x_ohci_resources[] = { | |||
185 | }, | 286 | }, |
186 | }; | 287 | }; |
187 | 288 | ||
188 | static struct platform_device pxaohci_device = { | 289 | static struct platform_device pxa27x_device_ohci = { |
189 | .name = "pxa27x-ohci", | 290 | .name = "pxa27x-ohci", |
190 | .id = -1, | 291 | .id = -1, |
191 | .dev = { | 292 | .dev = { |
@@ -198,7 +299,7 @@ static struct platform_device pxaohci_device = { | |||
198 | 299 | ||
199 | void __init pxa_set_ohci_info(struct pxaohci_platform_data *info) | 300 | void __init pxa_set_ohci_info(struct pxaohci_platform_data *info) |
200 | { | 301 | { |
201 | pxaohci_device.dev.platform_data = info; | 302 | pxa27x_device_ohci.dev.platform_data = info; |
202 | } | 303 | } |
203 | 304 | ||
204 | static struct resource i2c_power_resources[] = { | 305 | static struct resource i2c_power_resources[] = { |
@@ -213,7 +314,7 @@ static struct resource i2c_power_resources[] = { | |||
213 | }, | 314 | }, |
214 | }; | 315 | }; |
215 | 316 | ||
216 | static struct platform_device pxai2c_power_device = { | 317 | static struct platform_device pxa27x_device_i2c_power = { |
217 | .name = "pxa2xx-i2c", | 318 | .name = "pxa2xx-i2c", |
218 | .id = 1, | 319 | .id = 1, |
219 | .resource = i2c_power_resources, | 320 | .resource = i2c_power_resources, |
@@ -221,18 +322,18 @@ static struct platform_device pxai2c_power_device = { | |||
221 | }; | 322 | }; |
222 | 323 | ||
223 | static struct platform_device *devices[] __initdata = { | 324 | static struct platform_device *devices[] __initdata = { |
224 | &pxamci_device, | 325 | &pxa_device_mci, |
225 | &pxaudc_device, | 326 | &pxa_device_udc, |
226 | &pxafb_device, | 327 | &pxa_device_fb, |
227 | &ffuart_device, | 328 | &pxa_device_ffuart, |
228 | &btuart_device, | 329 | &pxa_device_btuart, |
229 | &stuart_device, | 330 | &pxa_device_stuart, |
230 | &pxai2c_device, | 331 | &pxa_device_i2c, |
231 | &pxai2c_power_device, | 332 | &pxa_device_i2s, |
232 | &pxai2s_device, | 333 | &pxa_device_ficp, |
233 | &pxaficp_device, | 334 | &pxa_device_rtc, |
234 | &pxartc_device, | 335 | &pxa27x_device_i2c_power, |
235 | &pxaohci_device, | 336 | &pxa27x_device_ohci, |
236 | }; | 337 | }; |
237 | 338 | ||
238 | void __init pxa27x_init_irq(void) | 339 | void __init pxa27x_init_irq(void) |
@@ -249,7 +350,7 @@ static int __init pxa27x_init(void) | |||
249 | if ((ret = pxa_init_dma(32))) | 350 | if ((ret = pxa_init_dma(32))) |
250 | return ret; | 351 | return ret; |
251 | #ifdef CONFIG_PM | 352 | #ifdef CONFIG_PM |
252 | pm_set_ops(&pxa27x_pm_ops); | 353 | pxa27x_init_pm(); |
253 | #endif | 354 | #endif |
254 | ret = platform_add_devices(devices, ARRAY_SIZE(devices)); | 355 | ret = platform_add_devices(devices, ARRAY_SIZE(devices)); |
255 | } | 356 | } |
diff --git a/arch/arm/mach-pxa/sleep.S b/arch/arm/mach-pxa/sleep.S index 15874b360e51..aff71fec618a 100644 --- a/arch/arm/mach-pxa/sleep.S +++ b/arch/arm/mach-pxa/sleep.S | |||
@@ -17,28 +17,12 @@ | |||
17 | 17 | ||
18 | #include <asm/arch/pxa-regs.h> | 18 | #include <asm/arch/pxa-regs.h> |
19 | 19 | ||
20 | #ifdef CONFIG_PXA27x // workaround for Errata 50 | ||
21 | #define MDREFR_KDIV 0x200a4000 // all banks | 20 | #define MDREFR_KDIV 0x200a4000 // all banks |
22 | #define CCCR_SLEEP 0x00000107 // L=7 2N=2 A=0 PPDIS=0 CPDIS=0 | 21 | #define CCCR_SLEEP 0x00000107 // L=7 2N=2 A=0 PPDIS=0 CPDIS=0 |
23 | #endif | ||
24 | 22 | ||
25 | .text | 23 | .text |
26 | 24 | ||
27 | /* | 25 | pxa_cpu_save_cp: |
28 | * pxa_cpu_suspend() | ||
29 | * | ||
30 | * Forces CPU into sleep state. | ||
31 | * | ||
32 | * r0 = value for PWRMODE M field for desired sleep state | ||
33 | */ | ||
34 | |||
35 | ENTRY(pxa_cpu_suspend) | ||
36 | |||
37 | #ifndef CONFIG_IWMMXT | ||
38 | mra r2, r3, acc0 | ||
39 | #endif | ||
40 | stmfd sp!, {r2 - r12, lr} @ save registers on stack | ||
41 | |||
42 | @ get coprocessor registers | 26 | @ get coprocessor registers |
43 | mrc p14, 0, r3, c6, c0, 0 @ clock configuration, for turbo mode | 27 | mrc p14, 0, r3, c6, c0, 0 @ clock configuration, for turbo mode |
44 | mrc p15, 0, r4, c15, c1, 0 @ CP access reg | 28 | mrc p15, 0, r4, c15, c1, 0 @ CP access reg |
@@ -54,12 +38,36 @@ ENTRY(pxa_cpu_suspend) | |||
54 | mov r10, sp | 38 | mov r10, sp |
55 | stmfd sp!, {r3 - r10} | 39 | stmfd sp!, {r3 - r10} |
56 | 40 | ||
57 | mov r5, r0 @ save sleep mode | 41 | mov pc, lr |
42 | |||
43 | pxa_cpu_save_sp: | ||
58 | @ preserve phys address of stack | 44 | @ preserve phys address of stack |
59 | mov r0, sp | 45 | mov r0, sp |
46 | mov r2, lr | ||
60 | bl sleep_phys_sp | 47 | bl sleep_phys_sp |
61 | ldr r1, =sleep_save_sp | 48 | ldr r1, =sleep_save_sp |
62 | str r0, [r1] | 49 | str r0, [r1] |
50 | mov pc, r2 | ||
51 | |||
52 | /* | ||
53 | * pxa27x_cpu_suspend() | ||
54 | * | ||
55 | * Forces CPU into sleep state. | ||
56 | * | ||
57 | * r0 = value for PWRMODE M field for desired sleep state | ||
58 | */ | ||
59 | |||
60 | ENTRY(pxa27x_cpu_suspend) | ||
61 | |||
62 | #ifndef CONFIG_IWMMXT | ||
63 | mra r2, r3, acc0 | ||
64 | #endif | ||
65 | stmfd sp!, {r2 - r12, lr} @ save registers on stack | ||
66 | |||
67 | bl pxa_cpu_save_cp | ||
68 | |||
69 | mov r5, r0 @ save sleep mode | ||
70 | bl pxa_cpu_save_sp | ||
63 | 71 | ||
64 | @ clean data cache | 72 | @ clean data cache |
65 | bl xscale_flush_kern_cache_all | 73 | bl xscale_flush_kern_cache_all |
@@ -80,13 +88,55 @@ ENTRY(pxa_cpu_suspend) | |||
80 | @ enable SDRAM self-refresh mode | 88 | @ enable SDRAM self-refresh mode |
81 | orr r5, r5, #MDREFR_SLFRSH | 89 | orr r5, r5, #MDREFR_SLFRSH |
82 | 90 | ||
83 | #ifdef CONFIG_PXA27x | ||
84 | @ set SDCLKx divide-by-2 bits (this is part of a workaround for Errata 50) | 91 | @ set SDCLKx divide-by-2 bits (this is part of a workaround for Errata 50) |
85 | ldr r6, =MDREFR_KDIV | 92 | ldr r6, =MDREFR_KDIV |
86 | orr r5, r5, r6 | 93 | orr r5, r5, r6 |
87 | #endif | ||
88 | 94 | ||
89 | #ifdef CONFIG_PXA25x | 95 | @ Intel PXA270 Specification Update notes problems sleeping |
96 | @ with core operating above 91 MHz | ||
97 | @ (see Errata 50, ...processor does not exit from sleep...) | ||
98 | |||
99 | ldr r6, =CCCR | ||
100 | ldr r8, [r6] @ keep original value for resume | ||
101 | |||
102 | ldr r7, =CCCR_SLEEP @ prepare CCCR sleep value | ||
103 | mov r0, #0x2 @ prepare value for CLKCFG | ||
104 | |||
105 | @ align execution to a cache line | ||
106 | b pxa_cpu_do_suspend | ||
107 | |||
108 | /* | ||
109 | * pxa27x_cpu_suspend() | ||
110 | * | ||
111 | * Forces CPU into sleep state. | ||
112 | * | ||
113 | * r0 = value for PWRMODE M field for desired sleep state | ||
114 | */ | ||
115 | |||
116 | ENTRY(pxa25x_cpu_suspend) | ||
117 | stmfd sp!, {r2 - r12, lr} @ save registers on stack | ||
118 | |||
119 | bl pxa_cpu_save_cp | ||
120 | |||
121 | mov r5, r0 @ save sleep mode | ||
122 | bl pxa_cpu_save_sp | ||
123 | |||
124 | @ clean data cache | ||
125 | bl xscale_flush_kern_cache_all | ||
126 | |||
127 | @ prepare value for sleep mode | ||
128 | mov r1, r5 @ sleep mode | ||
129 | |||
130 | @ prepare pointer to physical address 0 (virtual mapping in generic.c) | ||
131 | mov r2, #UNCACHED_PHYS_0 | ||
132 | |||
133 | @ prepare SDRAM refresh settings | ||
134 | ldr r4, =MDREFR | ||
135 | ldr r5, [r4] | ||
136 | |||
137 | @ enable SDRAM self-refresh mode | ||
138 | orr r5, r5, #MDREFR_SLFRSH | ||
139 | |||
90 | @ Intel PXA255 Specification Update notes problems | 140 | @ Intel PXA255 Specification Update notes problems |
91 | @ about suspending with PXBus operating above 133MHz | 141 | @ about suspending with PXBus operating above 133MHz |
92 | @ (see Errata 31, GPIO output signals, ... unpredictable in sleep | 142 | @ (see Errata 31, GPIO output signals, ... unpredictable in sleep |
@@ -118,30 +168,15 @@ ENTRY(pxa_cpu_suspend) | |||
118 | mov r0, #0 | 168 | mov r0, #0 |
119 | mcr p14, 0, r0, c6, c0, 0 | 169 | mcr p14, 0, r0, c6, c0, 0 |
120 | orr r0, r0, #2 @ initiate change bit | 170 | orr r0, r0, #2 @ initiate change bit |
121 | #endif | 171 | b pxa_cpu_do_suspend |
122 | #ifdef CONFIG_PXA27x | ||
123 | @ Intel PXA270 Specification Update notes problems sleeping | ||
124 | @ with core operating above 91 MHz | ||
125 | @ (see Errata 50, ...processor does not exit from sleep...) | ||
126 | |||
127 | ldr r6, =CCCR | ||
128 | ldr r8, [r6] @ keep original value for resume | ||
129 | |||
130 | ldr r7, =CCCR_SLEEP @ prepare CCCR sleep value | ||
131 | mov r0, #0x2 @ prepare value for CLKCFG | ||
132 | #endif | ||
133 | |||
134 | @ align execution to a cache line | ||
135 | b 1f | ||
136 | 172 | ||
137 | .ltorg | 173 | .ltorg |
138 | .align 5 | 174 | .align 5 |
139 | 1: | 175 | pxa_cpu_do_suspend: |
140 | 176 | ||
141 | @ All needed values are now in registers. | 177 | @ All needed values are now in registers. |
142 | @ These last instructions should be in cache | 178 | @ These last instructions should be in cache |
143 | 179 | ||
144 | #if defined(CONFIG_PXA25x) || defined(CONFIG_PXA27x) | ||
145 | @ initiate the frequency change... | 180 | @ initiate the frequency change... |
146 | str r7, [r6] | 181 | str r7, [r6] |
147 | mcr p14, 0, r0, c6, c0, 0 | 182 | mcr p14, 0, r0, c6, c0, 0 |
@@ -155,7 +190,6 @@ ENTRY(pxa_cpu_suspend) | |||
155 | mov r0, #42 | 190 | mov r0, #42 |
156 | 10: subs r0, r0, #1 | 191 | 10: subs r0, r0, #1 |
157 | bne 10b | 192 | bne 10b |
158 | #endif | ||
159 | 193 | ||
160 | @ Do not reorder... | 194 | @ Do not reorder... |
161 | @ Intel PXA270 Specification Update notes problems performing | 195 | @ Intel PXA270 Specification Update notes problems performing |
diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c index 6f91fd2d061a..98d27e646b09 100644 --- a/arch/arm/mach-pxa/time.c +++ b/arch/arm/mach-pxa/time.c | |||
@@ -1,9 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * arch/arm/mach-pxa/time.c | 2 | * arch/arm/mach-pxa/time.c |
3 | * | 3 | * |
4 | * Author: Nicolas Pitre | 4 | * PXA clocksource, clockevents, and OST interrupt handlers. |
5 | * Created: Jun 15, 2001 | 5 | * Copyright (c) 2007 by Bill Gatliff <bgat@billgatliff.com>. |
6 | * Copyright: MontaVista Software Inc. | 6 | * |
7 | * Derived from Nicolas Pitre's PXA timer handler Copyright (c) 2001 | ||
8 | * by MontaVista Software, Inc. (Nico, your code rocks!) | ||
7 | * | 9 | * |
8 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License version 2 as | 11 | * it under the terms of the GNU General Public License version 2 as |
@@ -12,164 +14,160 @@ | |||
12 | 14 | ||
13 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
14 | #include <linux/init.h> | 16 | #include <linux/init.h> |
15 | #include <linux/delay.h> | ||
16 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
17 | #include <linux/time.h> | 18 | #include <linux/clockchips.h> |
18 | #include <linux/signal.h> | 19 | |
19 | #include <linux/errno.h> | ||
20 | #include <linux/sched.h> | ||
21 | #include <linux/clocksource.h> | ||
22 | |||
23 | #include <asm/system.h> | ||
24 | #include <asm/hardware.h> | ||
25 | #include <asm/io.h> | ||
26 | #include <asm/leds.h> | ||
27 | #include <asm/irq.h> | ||
28 | #include <asm/mach/irq.h> | 20 | #include <asm/mach/irq.h> |
29 | #include <asm/mach/time.h> | 21 | #include <asm/mach/time.h> |
30 | #include <asm/arch/pxa-regs.h> | 22 | #include <asm/arch/pxa-regs.h> |
31 | 23 | ||
32 | |||
33 | static int pxa_set_rtc(void) | ||
34 | { | ||
35 | unsigned long current_time = xtime.tv_sec; | ||
36 | |||
37 | if (RTSR & RTSR_ALE) { | ||
38 | /* make sure not to forward the clock over an alarm */ | ||
39 | unsigned long alarm = RTAR; | ||
40 | if (current_time >= alarm && alarm >= RCNR) | ||
41 | return -ERESTARTSYS; | ||
42 | } | ||
43 | RCNR = current_time; | ||
44 | return 0; | ||
45 | } | ||
46 | |||
47 | #ifdef CONFIG_NO_IDLE_HZ | ||
48 | static unsigned long initial_match; | ||
49 | static int match_posponed; | ||
50 | #endif | ||
51 | |||
52 | static irqreturn_t | 24 | static irqreturn_t |
53 | pxa_timer_interrupt(int irq, void *dev_id) | 25 | pxa_ost0_interrupt(int irq, void *dev_id) |
54 | { | 26 | { |
55 | int next_match; | 27 | int next_match; |
56 | 28 | struct clock_event_device *c = dev_id; | |
57 | write_seqlock(&xtime_lock); | 29 | |
58 | 30 | if (c->mode == CLOCK_EVT_MODE_ONESHOT) { | |
59 | #ifdef CONFIG_NO_IDLE_HZ | 31 | /* Disarm the compare/match, signal the event. */ |
60 | if (match_posponed) { | 32 | OIER &= ~OIER_E0; |
61 | match_posponed = 0; | 33 | c->event_handler(c); |
62 | OSMR0 = initial_match; | 34 | } else if (c->mode == CLOCK_EVT_MODE_PERIODIC) { |
63 | } | 35 | /* Call the event handler as many times as necessary |
64 | #endif | 36 | * to recover missed events, if any (if we update |
65 | 37 | * OSMR0 and OSCR0 is still ahead of us, we've missed | |
66 | /* Loop until we get ahead of the free running timer. | 38 | * the event). As we're dealing with that, re-arm the |
67 | * This ensures an exact clock tick count and time accuracy. | 39 | * compare/match for the next event. |
68 | * Since IRQs are disabled at this point, coherence between | 40 | * |
69 | * lost_ticks(updated in do_timer()) and the match reg value is | 41 | * HACK ALERT: |
70 | * ensured, hence we can use do_gettimeofday() from interrupt | 42 | * |
71 | * handlers. | 43 | * There's a latency between the instruction that |
72 | * | 44 | * writes to OSMR0 and the actual commit to the |
73 | * HACK ALERT: it seems that the PXA timer regs aren't updated right | 45 | * physical hardware, because the CPU doesn't (have |
74 | * away in all cases when a write occurs. We therefore compare with | 46 | * to) run at bus speed, there's a write buffer |
75 | * 8 instead of 0 in the while() condition below to avoid missing a | 47 | * between the CPU and the bus, etc. etc. So if the |
76 | * match if OSCR has already reached the next OSMR value. | 48 | * target OSCR0 is "very close", to the OSMR0 load |
77 | * Experience has shown that up to 6 ticks are needed to work around | 49 | * value, the update to OSMR0 might not get to the |
78 | * this problem, but let's use 8 to be conservative. Note that this | 50 | * hardware in time and we'll miss that interrupt. |
79 | * affect things only when the timer IRQ has been delayed by nearly | 51 | * |
80 | * exactly one tick period which should be a pretty rare event. | 52 | * To be safe, if the new OSMR0 is "very close" to the |
53 | * target OSCR0 value, we call the event_handler as | ||
54 | * though the event actually happened. According to | ||
55 | * Nico's comment in the previous version of this | ||
56 | * code, experience has shown that 6 OSCR ticks is | ||
57 | * "very close" but he went with 8. We will use 16, | ||
58 | * based on the results of testing on PXA270. | ||
59 | * | ||
60 | * To be doubly sure, we also tell clkevt via | ||
61 | * clockevents_register_device() not to ask for | ||
62 | * anything that might put us "very close". | ||
81 | */ | 63 | */ |
64 | #define MIN_OSCR_DELTA 16 | ||
82 | do { | 65 | do { |
83 | timer_tick(); | 66 | OSSR = OSSR_M0; |
84 | OSSR = OSSR_M0; /* Clear match on timer 0 */ | ||
85 | next_match = (OSMR0 += LATCH); | 67 | next_match = (OSMR0 += LATCH); |
86 | } while( (signed long)(next_match - OSCR) <= 8 ); | 68 | c->event_handler(c); |
87 | 69 | } while (((signed long)(next_match - OSCR) <= MIN_OSCR_DELTA) | |
88 | write_sequnlock(&xtime_lock); | 70 | && (c->mode == CLOCK_EVT_MODE_PERIODIC)); |
71 | } | ||
89 | 72 | ||
90 | return IRQ_HANDLED; | 73 | return IRQ_HANDLED; |
91 | } | 74 | } |
92 | 75 | ||
93 | static struct irqaction pxa_timer_irq = { | 76 | static int |
94 | .name = "PXA Timer Tick", | 77 | pxa_osmr0_set_next_event(unsigned long delta, struct clock_event_device *dev) |
95 | .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, | 78 | { |
96 | .handler = pxa_timer_interrupt, | 79 | unsigned long irqflags; |
80 | |||
81 | raw_local_irq_save(irqflags); | ||
82 | OSMR0 = OSCR + delta; | ||
83 | OSSR = OSSR_M0; | ||
84 | OIER |= OIER_E0; | ||
85 | raw_local_irq_restore(irqflags); | ||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | static void | ||
90 | pxa_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *dev) | ||
91 | { | ||
92 | unsigned long irqflags; | ||
93 | |||
94 | switch (mode) { | ||
95 | case CLOCK_EVT_MODE_PERIODIC: | ||
96 | raw_local_irq_save(irqflags); | ||
97 | OSMR0 = OSCR + LATCH; | ||
98 | OSSR = OSSR_M0; | ||
99 | OIER |= OIER_E0; | ||
100 | raw_local_irq_restore(irqflags); | ||
101 | break; | ||
102 | |||
103 | case CLOCK_EVT_MODE_ONESHOT: | ||
104 | raw_local_irq_save(irqflags); | ||
105 | OIER &= ~OIER_E0; | ||
106 | raw_local_irq_restore(irqflags); | ||
107 | break; | ||
108 | |||
109 | case CLOCK_EVT_MODE_UNUSED: | ||
110 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
111 | /* initializing, released, or preparing for suspend */ | ||
112 | raw_local_irq_save(irqflags); | ||
113 | OIER &= ~OIER_E0; | ||
114 | raw_local_irq_restore(irqflags); | ||
115 | break; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | static struct clock_event_device ckevt_pxa_osmr0 = { | ||
120 | .name = "osmr0", | ||
121 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | ||
122 | .shift = 32, | ||
123 | .rating = 200, | ||
124 | .cpumask = CPU_MASK_CPU0, | ||
125 | .set_next_event = pxa_osmr0_set_next_event, | ||
126 | .set_mode = pxa_osmr0_set_mode, | ||
97 | }; | 127 | }; |
98 | 128 | ||
99 | static cycle_t pxa_get_cycles(void) | 129 | static cycle_t pxa_read_oscr(void) |
100 | { | 130 | { |
101 | return OSCR; | 131 | return OSCR; |
102 | } | 132 | } |
103 | 133 | ||
104 | static struct clocksource clocksource_pxa = { | 134 | static struct clocksource cksrc_pxa_oscr0 = { |
105 | .name = "pxa_timer", | 135 | .name = "oscr0", |
106 | .rating = 200, | 136 | .rating = 200, |
107 | .read = pxa_get_cycles, | 137 | .read = pxa_read_oscr, |
108 | .mask = CLOCKSOURCE_MASK(32), | 138 | .mask = CLOCKSOURCE_MASK(32), |
109 | .shift = 20, | 139 | .shift = 20, |
110 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | 140 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
111 | }; | 141 | }; |
112 | 142 | ||
143 | static struct irqaction pxa_ost0_irq = { | ||
144 | .name = "ost0", | ||
145 | .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, | ||
146 | .handler = pxa_ost0_interrupt, | ||
147 | .dev_id = &ckevt_pxa_osmr0, | ||
148 | }; | ||
149 | |||
113 | static void __init pxa_timer_init(void) | 150 | static void __init pxa_timer_init(void) |
114 | { | 151 | { |
115 | struct timespec tv; | 152 | OIER = 0; |
116 | unsigned long flags; | 153 | OSSR = OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3; |
117 | 154 | ||
118 | set_rtc = pxa_set_rtc; | 155 | ckevt_pxa_osmr0.mult = |
156 | div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, ckevt_pxa_osmr0.shift); | ||
157 | ckevt_pxa_osmr0.max_delta_ns = | ||
158 | clockevent_delta2ns(0x7fffffff, &ckevt_pxa_osmr0); | ||
159 | ckevt_pxa_osmr0.min_delta_ns = | ||
160 | clockevent_delta2ns(MIN_OSCR_DELTA, &ckevt_pxa_osmr0) + 1; | ||
119 | 161 | ||
120 | OIER = 0; /* disable any timer interrupts */ | 162 | cksrc_pxa_oscr0.mult = |
121 | OSSR = 0xf; /* clear status on all timers */ | 163 | clocksource_hz2mult(CLOCK_TICK_RATE, cksrc_pxa_oscr0.shift); |
122 | setup_irq(IRQ_OST0, &pxa_timer_irq); | ||
123 | local_irq_save(flags); | ||
124 | OIER = OIER_E0; /* enable match on timer 0 to cause interrupts */ | ||
125 | OSMR0 = OSCR + LATCH; /* set initial match */ | ||
126 | local_irq_restore(flags); | ||
127 | |||
128 | /* | ||
129 | * OSCR runs continuously on PXA and is not written to, | ||
130 | * so we can use it as clock source directly. | ||
131 | */ | ||
132 | clocksource_pxa.mult = | ||
133 | clocksource_hz2mult(CLOCK_TICK_RATE, clocksource_pxa.shift); | ||
134 | clocksource_register(&clocksource_pxa); | ||
135 | } | ||
136 | |||
137 | #ifdef CONFIG_NO_IDLE_HZ | ||
138 | static int pxa_dyn_tick_enable_disable(void) | ||
139 | { | ||
140 | /* nothing to do */ | ||
141 | return 0; | ||
142 | } | ||
143 | 164 | ||
144 | static void pxa_dyn_tick_reprogram(unsigned long ticks) | 165 | setup_irq(IRQ_OST0, &pxa_ost0_irq); |
145 | { | ||
146 | if (ticks > 1) { | ||
147 | initial_match = OSMR0; | ||
148 | OSMR0 = initial_match + ticks * LATCH; | ||
149 | match_posponed = 1; | ||
150 | } | ||
151 | } | ||
152 | 166 | ||
153 | static irqreturn_t | 167 | clocksource_register(&cksrc_pxa_oscr0); |
154 | pxa_dyn_tick_handler(int irq, void *dev_id) | 168 | clockevents_register_device(&ckevt_pxa_osmr0); |
155 | { | ||
156 | if (match_posponed) { | ||
157 | match_posponed = 0; | ||
158 | OSMR0 = initial_match; | ||
159 | if ( (signed long)(initial_match - OSCR) <= 8 ) | ||
160 | return pxa_timer_interrupt(irq, dev_id); | ||
161 | } | ||
162 | return IRQ_NONE; | ||
163 | } | 169 | } |
164 | 170 | ||
165 | static struct dyn_tick_timer pxa_dyn_tick = { | ||
166 | .enable = pxa_dyn_tick_enable_disable, | ||
167 | .disable = pxa_dyn_tick_enable_disable, | ||
168 | .reprogram = pxa_dyn_tick_reprogram, | ||
169 | .handler = pxa_dyn_tick_handler, | ||
170 | }; | ||
171 | #endif | ||
172 | |||
173 | #ifdef CONFIG_PM | 171 | #ifdef CONFIG_PM |
174 | static unsigned long osmr[4], oier; | 172 | static unsigned long osmr[4], oier; |
175 | 173 | ||
@@ -191,7 +189,10 @@ static void pxa_timer_resume(void) | |||
191 | OIER = oier; | 189 | OIER = oier; |
192 | 190 | ||
193 | /* | 191 | /* |
194 | * OSMR0 is the system timer: make sure OSCR is sufficiently behind | 192 | * OSCR0 is the system timer, which has to increase |
193 | * monotonically until it rolls over in hardware. The value | ||
194 | * (OSMR0 - LATCH) is OSCR0 at the most recent system tick, | ||
195 | * which is a handy value to restore to OSCR0. | ||
195 | */ | 196 | */ |
196 | OSCR = OSMR0 - LATCH; | 197 | OSCR = OSMR0 - LATCH; |
197 | } | 198 | } |
@@ -204,7 +205,4 @@ struct sys_timer pxa_timer = { | |||
204 | .init = pxa_timer_init, | 205 | .init = pxa_timer_init, |
205 | .suspend = pxa_timer_suspend, | 206 | .suspend = pxa_timer_suspend, |
206 | .resume = pxa_timer_resume, | 207 | .resume = pxa_timer_resume, |
207 | #ifdef CONFIG_NO_IDLE_HZ | ||
208 | .dyn_tick = &pxa_dyn_tick, | ||
209 | #endif | ||
210 | }; | 208 | }; |