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/clock.c | 15 | ||||
-rw-r--r-- | arch/arm/mach-pxa/corgi.c | 7 | ||||
-rw-r--r-- | arch/arm/mach-pxa/devices.h | 11 | ||||
-rw-r--r-- | arch/arm/mach-pxa/dma.c | 44 | ||||
-rw-r--r-- | arch/arm/mach-pxa/em-x270.c | 354 | ||||
-rw-r--r-- | arch/arm/mach-pxa/generic.c | 101 | ||||
-rw-r--r-- | arch/arm/mach-pxa/generic.h | 6 | ||||
-rw-r--r-- | arch/arm/mach-pxa/idp.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-pxa/irq.c | 106 | ||||
-rw-r--r-- | arch/arm/mach-pxa/lpd270.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-pxa/lubbock.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-pxa/mainstone.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-pxa/pm.c | 184 | ||||
-rw-r--r-- | arch/arm/mach-pxa/poodle.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-pxa/pxa25x.c | 137 | ||||
-rw-r--r-- | arch/arm/mach-pxa/pxa27x.c | 183 | ||||
-rw-r--r-- | arch/arm/mach-pxa/sleep.S | 112 | ||||
-rw-r--r-- | arch/arm/mach-pxa/spitz.c | 7 | ||||
-rw-r--r-- | arch/arm/mach-pxa/time.c | 263 | ||||
-rw-r--r-- | arch/arm/mach-pxa/tosa.c | 4 | ||||
-rw-r--r-- | arch/arm/mach-pxa/trizeps4.c | 3 |
23 files changed, 1025 insertions, 532 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 bool "Keith und Koep Trizeps4 DIMM-Module" select PXA27x +config MACH_EM_X270 + bool "CompuLab EM-x270 platform" + select PXA27x + endchoice 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 obj-$(CONFIG_MACH_AKITA) += akita-ioexp.o obj-$(CONFIG_MACH_POODLE) += poodle.o corgi_ssp.o obj-$(CONFIG_MACH_TOSA) += tosa.o +obj-$(CONFIG_MACH_EM_X270) += em-x270.o # Support for blinky lights led-y := leds.o diff --git a/arch/arm/mach-pxa/clock.c b/arch/arm/mach-pxa/clock.c index 8f7c90a0593b..34a31caa6f9d 100644 --- a/arch/arm/mach-pxa/clock.c +++ b/arch/arm/mach-pxa/clock.c @@ -12,7 +12,6 @@ #include <asm/arch/pxa-regs.h> #include <asm/hardware.h> -#include <asm/semaphore.h> struct clk { struct list_head node; @@ -25,21 +24,21 @@ struct clk { }; static LIST_HEAD(clocks); -static DECLARE_MUTEX(clocks_sem); +static DEFINE_MUTEX(clocks_mutex); static DEFINE_SPINLOCK(clocks_lock); struct clk *clk_get(struct device *dev, const char *id) { struct clk *p, *clk = ERR_PTR(-ENOENT); - down(&clocks_sem); + mutex_lock(&clocks_mutex); list_for_each_entry(p, &clocks, node) { if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) { clk = p; break; } } - up(&clocks_sem); + mutex_unlock(&clocks_mutex); return clk; } @@ -101,18 +100,18 @@ static struct clk clk_gpio27 = { int clk_register(struct clk *clk) { - down(&clocks_sem); + mutex_lock(&clocks_mutex); list_add(&clk->node, &clocks); - up(&clocks_sem); + mutex_unlock(&clocks_mutex); return 0; } EXPORT_SYMBOL(clk_register); void clk_unregister(struct clk *clk) { - down(&clocks_sem); + mutex_lock(&clocks_mutex); list_del(&clk->node); - up(&clocks_sem); + mutex_unlock(&clocks_mutex); } EXPORT_SYMBOL(clk_unregister); diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c index a1a900d16665..aab27297b3c6 100644 --- a/arch/arm/mach-pxa/corgi.c +++ b/arch/arm/mach-pxa/corgi.c @@ -44,6 +44,7 @@ #include <asm/hardware/scoop.h> #include "generic.h" +#include "devices.h" #include "sharpsl.h" @@ -368,7 +369,7 @@ MACHINE_START(CORGI, "SHARP Corgi") .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, .fixup = fixup_corgi, .map_io = pxa_map_io, - .init_irq = pxa_init_irq, + .init_irq = pxa25x_init_irq, .init_machine = corgi_init, .timer = &pxa_timer, MACHINE_END @@ -380,7 +381,7 @@ MACHINE_START(SHEPHERD, "SHARP Shepherd") .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, .fixup = fixup_corgi, .map_io = pxa_map_io, - .init_irq = pxa_init_irq, + .init_irq = pxa25x_init_irq, .init_machine = corgi_init, .timer = &pxa_timer, MACHINE_END @@ -392,7 +393,7 @@ MACHINE_START(HUSKY, "SHARP Husky") .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, .fixup = fixup_corgi, .map_io = pxa_map_io, - .init_irq = pxa_init_irq, + .init_irq = pxa25x_init_irq, .init_machine = corgi_init, .timer = &pxa_timer, MACHINE_END diff --git a/arch/arm/mach-pxa/devices.h b/arch/arm/mach-pxa/devices.h new file mode 100644 index 000000000000..636fdb1c049c --- /dev/null +++ b/arch/arm/mach-pxa/devices.h @@ -0,0 +1,11 @@ +extern struct platform_device pxa_device_mci; +extern struct platform_device pxa_device_udc; +extern struct platform_device pxa_device_fb; +extern struct platform_device pxa_device_ffuart; +extern struct platform_device pxa_device_btuart; +extern struct platform_device pxa_device_stuart; +extern struct platform_device pxa_device_hwuart; +extern struct platform_device pxa_device_i2c; +extern struct platform_device pxa_device_i2s; +extern struct platform_device pxa_device_ficp; +extern struct platform_device pxa_device_rtc; diff --git a/arch/arm/mach-pxa/dma.c b/arch/arm/mach-pxa/dma.c index 4440babe7b97..93c4f31f127f 100644 --- a/arch/arm/mach-pxa/dma.c +++ b/arch/arm/mach-pxa/dma.c @@ -25,12 +25,15 @@ #include <asm/arch/pxa-regs.h> -static struct dma_channel { +struct dma_channel { char *name; + pxa_dma_prio prio; void (*irq_handler)(int, void *); void *data; -} dma_channels[PXA_DMA_CHANNELS]; +}; +static struct dma_channel *dma_channels; +static int num_dma_channels; int pxa_request_dma (char *name, pxa_dma_prio prio, void (*irq_handler)(int, void *), @@ -47,8 +50,9 @@ int pxa_request_dma (char *name, pxa_dma_prio prio, do { /* try grabbing a DMA channel with the requested priority */ - pxa_for_each_dma_prio (i, prio) { - if (!dma_channels[i].name) { + for (i = 0; i < num_dma_channels; i++) { + if ((dma_channels[i].prio == prio) && + !dma_channels[i].name) { found = 1; break; } @@ -91,7 +95,7 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id) { int i, dint = DINT; - for (i = 0; i < PXA_DMA_CHANNELS; i++) { + for (i = 0; i < num_dma_channels; i++) { if (dint & (1 << i)) { struct dma_channel *channel = &dma_channels[i]; if (channel->name && channel->irq_handler) { @@ -109,18 +113,32 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } -static int __init pxa_dma_init (void) +int __init pxa_init_dma(int num_ch) { - int ret; + int i, ret; - ret = request_irq (IRQ_DMA, dma_irq_handler, 0, "DMA", NULL); - if (ret) + dma_channels = kzalloc(sizeof(struct dma_channel) * num_ch, GFP_KERNEL); + if (dma_channels == NULL) + return -ENOMEM; + + ret = request_irq(IRQ_DMA, dma_irq_handler, IRQF_DISABLED, "DMA", NULL); + if (ret) { printk (KERN_CRIT "Wow! Can't register IRQ for DMA\n"); - return ret; -} + kfree(dma_channels); + return ret; + } -arch_initcall(pxa_dma_init); + /* dma channel priorities on pxa2xx processors: + * ch 0 - 3, 16 - 19 <--> (0) DMA_PRIO_HIGH + * ch 4 - 7, 20 - 23 <--> (1) DMA_PRIO_MEDIUM + * ch 8 - 15, 24 - 31 <--> (2) DMA_PRIO_LOW + */ + for (i = 0; i < num_ch; i++) + dma_channels[i].prio = min((i & 0xf) >> 2, DMA_PRIO_LOW); + + num_dma_channels = num_ch; + return 0; +} EXPORT_SYMBOL(pxa_request_dma); EXPORT_SYMBOL(pxa_free_dma); - 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 @@ +/* + * Support for CompuLab EM-x270 platform + * + * Copyright (C) 2007 CompuLab, Ltd. + * Author: Mike Rapoport <mike@compulab.co.il> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/irq.h> +#include <linux/platform_device.h> + +#include <linux/dm9000.h> +#include <linux/rtc-v3020.h> + +#include <linux/mtd/nand.h> +#include <linux/mtd/partitions.h> + +#include <asm/mach-types.h> + +#include <asm/mach/arch.h> + +#include <asm/arch/pxa-regs.h> +#include <asm/arch/pxafb.h> +#include <asm/arch/ohci.h> +#include <asm/arch/mmc.h> +#include <asm/arch/bitfield.h> + +#include "generic.h" + +/* GPIO IRQ usage */ +#define EM_X270_MMC_PD (105) +#define EM_X270_ETHIRQ IRQ_GPIO(41) +#define EM_X270_MMC_IRQ IRQ_GPIO(13) + +static struct resource em_x270_dm9k_resource[] = { + [0] = { + .start = PXA_CS2_PHYS, + .end = PXA_CS2_PHYS + 3, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = PXA_CS2_PHYS + 8, + .end = PXA_CS2_PHYS + 8 + 0x3f, + .flags = IORESOURCE_MEM, + }, + [2] = { + .start = EM_X270_ETHIRQ, + .end = EM_X270_ETHIRQ, + .flags = IORESOURCE_IRQ, + } +}; + +/* for the moment we limit ourselves to 32bit IO until some + * better IO routines can be written and tested + */ +static struct dm9000_plat_data em_x270_dm9k_platdata = { + .flags = DM9000_PLATF_32BITONLY, +}; + +/* Ethernet device */ +static struct platform_device em_x270_dm9k = { + .name = "dm9000", + .id = 0, + .num_resources = ARRAY_SIZE(em_x270_dm9k_resource), + .resource = em_x270_dm9k_resource, + .dev = { + .platform_data = &em_x270_dm9k_platdata, + } +}; + +/* audio device */ +static struct platform_device em_x270_audio = { + .name = "pxa2xx-ac97", + .id = -1, +}; + +/* WM9712 touchscreen controller. Hopefully the driver will make it to + * the mainstream sometime */ +static struct platform_device em_x270_ts = { + .name = "wm97xx-ts", + .id = -1, +}; + +/* RTC */ +static struct resource em_x270_v3020_resource[] = { + [0] = { + .start = PXA_CS4_PHYS, + .end = PXA_CS4_PHYS + 3, + .flags = IORESOURCE_MEM, + }, +}; + +static struct v3020_platform_data em_x270_v3020_platdata = { + .leftshift = 0, +}; + +static struct platform_device em_x270_rtc = { + .name = "v3020", + .num_resources = ARRAY_SIZE(em_x270_v3020_resource), + .resource = em_x270_v3020_resource, + .id = -1, + .dev = { + .platform_data = &em_x270_v3020_platdata, + } +}; + +/* NAND flash */ +#define GPIO_NAND_CS (11) +#define GPIO_NAND_RB (56) + +static inline void nand_cs_on(void) +{ + GPCR(GPIO_NAND_CS) = GPIO_bit(GPIO_NAND_CS); +} + +static void nand_cs_off(void) +{ + dsb(); + + GPSR(GPIO_NAND_CS) = GPIO_bit(GPIO_NAND_CS); +} + +/* hardware specific access to control-lines */ +static void em_x270_nand_cmd_ctl(struct mtd_info *mtd, int dat, + unsigned int ctrl) +{ + struct nand_chip *this = mtd->priv; + unsigned long nandaddr = (unsigned long)this->IO_ADDR_W; + + dsb(); + + if (ctrl & NAND_CTRL_CHANGE) { + if (ctrl & NAND_ALE) + nandaddr |= (1 << 3); + else + nandaddr &= ~(1 << 3); + if (ctrl & NAND_CLE) + nandaddr |= (1 << 2); + else + nandaddr &= ~(1 << 2); + if (ctrl & NAND_NCE) + nand_cs_on(); + else + nand_cs_off(); + } + + dsb(); + this->IO_ADDR_W = (void __iomem *)nandaddr; + if (dat != NAND_CMD_NONE) + writel(dat, this->IO_ADDR_W); + + dsb(); +} + +/* read device ready pin */ +static int em_x270_nand_device_ready(struct mtd_info *mtd) +{ + dsb(); + + return GPLR(GPIO_NAND_RB) & GPIO_bit(GPIO_NAND_RB); +} + +static struct mtd_partition em_x270_partition_info[] = { + [0] = { + .name = "em_x270-0", + .offset = 0, + .size = SZ_4M, + }, + [1] = { + .name = "em_x270-1", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL + }, +}; + +static const char *em_x270_part_probes[] = { "cmdlinepart", NULL }; + +struct platform_nand_data em_x270_nand_platdata = { + .chip = { + .nr_chips = 1, + .chip_offset = 0, + .nr_partitions = ARRAY_SIZE(em_x270_partition_info), + .partitions = em_x270_partition_info, + .chip_delay = 20, + .part_probe_types = em_x270_part_probes, + }, + .ctrl = { + .hwcontrol = 0, + .dev_ready = em_x270_nand_device_ready, + .select_chip = 0, + .cmd_ctrl = em_x270_nand_cmd_ctl, + }, +}; + +static struct resource em_x270_nand_resource[] = { + [0] = { + .start = PXA_CS1_PHYS, + .end = PXA_CS1_PHYS + 12, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device em_x270_nand = { + .name = "gen_nand", + .num_resources = ARRAY_SIZE(em_x270_nand_resource), + .resource = em_x270_nand_resource, + .id = -1, + .dev = { + .platform_data = &em_x270_nand_platdata, + } +}; + +/* platform devices */ +static struct platform_device *platform_devices[] __initdata = { + &em_x270_dm9k, + &em_x270_audio, + &em_x270_ts, + &em_x270_rtc, + &em_x270_nand, +}; + + +/* PXA27x OHCI controller setup */ +static int em_x270_ohci_init(struct device *dev) +{ + /* Set the Power Control Polarity Low */ + UHCHR = (UHCHR | UHCHR_PCPL) & + ~(UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSE); + + /* enable port 2 transiever */ + UP2OCR = UP2OCR_HXS | UP2OCR_HXOE; + + return 0; +} + +static struct pxaohci_platform_data em_x270_ohci_platform_data = { + .port_mode = PMM_PERPORT_MODE, + .init = em_x270_ohci_init, +}; + + +static int em_x270_mci_init(struct device *dev, + irq_handler_t em_x270_detect_int, + void *data) +{ + int err; + + /* setup GPIO for PXA27x MMC controller */ + pxa_gpio_mode(GPIO32_MMCCLK_MD); + pxa_gpio_mode(GPIO112_MMCCMD_MD); + pxa_gpio_mode(GPIO92_MMCDAT0_MD); + pxa_gpio_mode(GPIO109_MMCDAT1_MD); + pxa_gpio_mode(GPIO110_MMCDAT2_MD); + pxa_gpio_mode(GPIO111_MMCDAT3_MD); + + /* EM-X270 uses GPIO13 as SD power enable */ + pxa_gpio_mode(EM_X270_MMC_PD | GPIO_OUT); + + err = request_irq(EM_X270_MMC_IRQ, em_x270_detect_int, + IRQF_DISABLED | IRQF_TRIGGER_FALLING, + "MMC card detect", data); + if (err) { + printk(KERN_ERR "%s: can't request MMC card detect IRQ: %d\n", + __FUNCTION__, err); + return err; + } + + return 0; +} + +static void em_x270_mci_setpower(struct device *dev, unsigned int vdd) +{ + /* + FIXME: current hardware implementation does not allow to + enable/disable MMC power. This will be fixed in next HW releases, + and we'll need to add implmentation here. + */ + return; +} + +static void em_x270_mci_exit(struct device *dev, void *data) +{ + free_irq(EM_X270_MMC_IRQ, data); +} + +static struct pxamci_platform_data em_x270_mci_platform_data = { + .ocr_mask = MMC_VDD_28_29|MMC_VDD_29_30|MMC_VDD_30_31, + .init = em_x270_mci_init, + .setpower = em_x270_mci_setpower, + .exit = em_x270_mci_exit, +}; + +/* LCD 480x640 */ +static struct pxafb_mode_info em_x270_lcd_mode = { + .pixclock = 50000, + .bpp = 16, + .xres = 480, + .yres = 640, + .hsync_len = 8, + .vsync_len = 2, + .left_margin = 8, + .upper_margin = 0, + .right_margin = 24, + .lower_margin = 4, + .cmap_greyscale = 0, +}; + +static struct pxafb_mach_info em_x270_lcd = { + .modes = &em_x270_lcd_mode, + .num_modes = 1, + .cmap_inverse = 0, + .cmap_static = 0, + .lccr0 = LCCR0_PAS, + .lccr3 = LCCR3_PixClkDiv(0x01) | LCCR3_Acb(0xff), +}; + +static void __init em_x270_init(void) +{ + /* setup LCD */ + set_pxa_fb_info(&em_x270_lcd); + + /* register EM-X270 platform devices */ + platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); + + /* set MCI and OHCI platform parameters */ + pxa_set_mci_info(&em_x270_mci_platform_data); + pxa_set_ohci_info(&em_x270_ohci_platform_data); + + /* setup STUART GPIOs */ + pxa_gpio_mode(GPIO46_STRXD_MD); + pxa_gpio_mode(GPIO47_STTXD_MD); + + /* setup BTUART GPIOs */ + pxa_gpio_mode(GPIO42_BTRXD_MD); + pxa_gpio_mode(GPIO43_BTTXD_MD); + pxa_gpio_mode(GPIO44_BTCTS_MD); + pxa_gpio_mode(GPIO45_BTRTS_MD); + + /* Setup interrupt for dm9000 */ + set_irq_type(EM_X270_ETHIRQ, IRQT_RISING); +} + +MACHINE_START(EM_X270, "Compulab EM-x270") + .boot_params = 0xa0000100, + .phys_io = 0x40000000, + .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, + .map_io = pxa_map_io, + .init_irq = pxa27x_init_irq, + .timer = &pxa_timer, + .init_machine = em_x270_init, +MACHINE_END diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c index 64b08b744f9f..5510f6fdce55 100644 --- a/arch/arm/mach-pxa/generic.c +++ b/arch/arm/mach-pxa/generic.c @@ -43,6 +43,7 @@ #include <asm/arch/irda.h> #include <asm/arch/i2c.h> +#include "devices.h" #include "generic.h" /* @@ -242,7 +243,7 @@ static struct resource pxamci_resources[] = { static u64 pxamci_dmamask = 0xffffffffUL; -static struct platform_device pxamci_device = { +struct platform_device pxa_device_mci = { .name = "pxa2xx-mci", .id = -1, .dev = { @@ -255,7 +256,7 @@ static struct platform_device pxamci_device = { void __init pxa_set_mci_info(struct pxamci_platform_data *info) { - pxamci_device.dev.platform_data = info; + pxa_device_mci.dev.platform_data = info; } @@ -281,7 +282,7 @@ static struct resource pxa2xx_udc_resources[] = { static u64 udc_dma_mask = ~(u32)0; -static struct platform_device udc_device = { +struct platform_device pxa_device_udc = { .name = "pxa2xx-udc", .id = -1, .resource = pxa2xx_udc_resources, @@ -307,7 +308,7 @@ static struct resource pxafb_resources[] = { static u64 fb_dma_mask = ~(u64)0; -static struct platform_device pxafb_device = { +struct platform_device pxa_device_fb = { .name = "pxa2xx-fb", .id = -1, .dev = { @@ -320,32 +321,32 @@ static struct platform_device pxafb_device = { void __init set_pxa_fb_info(struct pxafb_mach_info *info) { - pxafb_device.dev.platform_data = info; + pxa_device_fb.dev.platform_data = info; } void __init set_pxa_fb_parent(struct device *parent_dev) { - pxafb_device.dev.parent = parent_dev; + pxa_device_fb.dev.parent = parent_dev; } -static struct platform_device ffuart_device = { +struct platform_device pxa_device_ffuart= { .name = "pxa2xx-uart", .id = 0, }; -static struct platform_device btuart_device = { +struct platform_device pxa_device_btuart = { .name = "pxa2xx-uart", .id = 1, }; -static struct platform_device stuart_device = { +struct platform_device pxa_device_stuart = { .name = "pxa2xx-uart", .id = 2, }; -static struct platform_device hwuart_device = { +struct platform_device pxa_device_hwuart = { .name = "pxa2xx-uart", .id = 3, }; -static struct resource i2c_resources[] = { +static struct resource pxai2c_resources[] = { { .start = 0x40301680, .end = 0x403016a3, @@ -357,40 +358,19 @@ static struct resource i2c_resources[] = { }, }; -static struct platform_device i2c_device = { +struct platform_device pxa_device_i2c = { .name = "pxa2xx-i2c", .id = 0, - .resource = i2c_resources, - .num_resources = ARRAY_SIZE(i2c_resources), + .resource = pxai2c_resources, + .num_resources = ARRAY_SIZE(pxai2c_resources), }; -#ifdef CONFIG_PXA27x -static struct resource i2c_power_resources[] = { - { - .start = 0x40f00180, - .end = 0x40f001a3, - .flags = IORESOURCE_MEM, - }, { - .start = IRQ_PWRI2C, - .end = IRQ_PWRI2C, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device i2c_power_device = { - .name = "pxa2xx-i2c", - .id = 1, - .resource = i2c_power_resources, - .num_resources = ARRAY_SIZE(i2c_resources), -}; -#endif - void __init pxa_set_i2c_info(struct i2c_pxa_platform_data *info) { - i2c_device.dev.platform_data = info; + pxa_device_i2c.dev.platform_data = info; } -static struct resource i2s_resources[] = { +static struct resource pxai2s_resources[] = { { .start = 0x40400000, .end = 0x40400083, @@ -402,16 +382,16 @@ static struct resource i2s_resources[] = { }, }; -static struct platform_device i2s_device = { +struct platform_device pxa_device_i2s = { .name = "pxa2xx-i2s", .id = -1, - .resource = i2s_resources, - .num_resources = ARRAY_SIZE(i2s_resources), + .resource = pxai2s_resources, + .num_resources = ARRAY_SIZE(pxai2s_resources), }; static u64 pxaficp_dmamask = ~(u32)0; -static struct platform_device pxaficp_device = { +struct platform_device pxa_device_ficp = { .name = "pxa2xx-ir", .id = -1, .dev = { @@ -422,45 +402,10 @@ static struct platform_device pxaficp_device = { void __init pxa_set_ficp_info(struct pxaficp_platform_data *info) { - pxaficp_device.dev.platform_data = info; + pxa_device_ficp.dev.platform_data = info; } -static struct platform_device pxartc_device = { +struct platform_device pxa_device_rtc = { .name = "sa1100-rtc", .id = -1, }; - -static struct platform_device *devices[] __initdata = { - &pxamci_device, - &udc_device, - &pxafb_device, - &ffuart_device, - &btuart_device, - &stuart_device, - &pxaficp_device, - &i2c_device, -#ifdef CONFIG_PXA27x - &i2c_power_device, -#endif - &i2s_device, - &pxartc_device, -}; - -static int __init pxa_init(void) -{ - int cpuid, ret; - - ret = platform_add_devices(devices, ARRAY_SIZE(devices)); - if (ret) - return ret; - - /* Only add HWUART for PXA255/26x; PXA210/250/27x do not have it. */ - cpuid = read_cpuid(CPUID_ID); - if (((cpuid >> 4) & 0xfff) == 0x2d0 || - ((cpuid >> 4) & 0xfff) == 0x290) - ret = platform_device_register(&hwuart_device); - - return ret; -} - -subsys_initcall(pxa_init); diff --git a/arch/arm/mach-pxa/generic.h b/arch/arm/mach-pxa/generic.h index e54a8dd63c17..91ab2ad8b34b 100644 --- a/arch/arm/mach-pxa/generic.h +++ b/arch/arm/mach-pxa/generic.h @@ -12,8 +12,12 @@ struct sys_timer; extern struct sys_timer pxa_timer; +extern void __init pxa_init_irq_low(void); +extern void __init pxa_init_irq_high(void); +extern void __init pxa_init_irq_gpio(int gpio_nr); +extern void __init pxa25x_init_irq(void); +extern void __init pxa27x_init_irq(void); extern void __init pxa_map_io(void); -extern void __init pxa_init_irq(void); extern unsigned int get_clk_frequency_khz(int info); diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c index 64df44043a65..465108da2851 100644 --- a/arch/arm/mach-pxa/idp.c +++ b/arch/arm/mach-pxa/idp.c @@ -38,6 +38,7 @@ #include <asm/arch/mmc.h> #include "generic.h" +#include "devices.h" /* TODO: * - add pxa2xx_audio_ops_t device structure @@ -152,7 +153,7 @@ static void __init idp_init(void) static void __init idp_init_irq(void) { - pxa_init_irq(); + pxa25x_init_irq(); set_irq_type(TOUCH_PANEL_IRQ, TOUCH_PANEL_IRQ_EDGE); } diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c index 4619d5fe606c..4b867b0789d5 100644 --- a/arch/arm/mach-pxa/irq.c +++ b/arch/arm/mach-pxa/irq.c @@ -30,12 +30,12 @@ static void pxa_mask_low_irq(unsigned int irq) { - ICMR &= ~(1 << (irq + PXA_IRQ_SKIP)); + ICMR &= ~(1 << irq); } static void pxa_unmask_low_irq(unsigned int irq) { - ICMR |= (1 << (irq + PXA_IRQ_SKIP)); + ICMR |= (1 << irq); } static int pxa_set_wake(unsigned int irq, unsigned int on) @@ -67,7 +67,27 @@ static struct irq_chip pxa_internal_chip_low = { .set_wake = pxa_set_wake, }; -#if PXA_INTERNAL_IRQS > 32 +void __init pxa_init_irq_low(void) +{ + int irq; + + /* disable all IRQs */ + ICMR = 0; + + /* all IRQs are IRQ, not FIQ */ + ICLR = 0; + + /* only unmasked interrupts kick us out of idle */ + ICCR = 1; + + for (irq = PXA_IRQ(0); irq <= PXA_IRQ(31); irq++) { + set_irq_chip(irq, &pxa_internal_chip_low); + set_irq_handler(irq, handle_level_irq); + set_irq_flags(irq, IRQF_VALID); + } +} + +#ifdef CONFIG_PXA27x /* * This is for the second set of internal IRQs as found on the PXA27x. @@ -75,12 +95,12 @@ static struct irq_chip pxa_internal_chip_low = { static void pxa_mask_high_irq(unsigned int irq) { - ICMR2 &= ~(1 << (irq - 32 + PXA_IRQ_SKIP)); + ICMR2 &= ~(1 << (irq - 32)); } static void pxa_unmask_high_irq(unsigned int irq) { - ICMR2 |= (1 << (irq - 32 + PXA_IRQ_SKIP)); + ICMR2 |= (1 << (irq - 32)); } static struct irq_chip pxa_internal_chip_high = { @@ -90,6 +110,19 @@ static struct irq_chip pxa_internal_chip_high = { .unmask = pxa_unmask_high_irq, }; +void __init pxa_init_irq_high(void) +{ + int irq; + + ICMR2 = 0; + ICLR2 = 0; + + for (irq = PXA_IRQ(32); irq < PXA_IRQ(64); irq++) { + set_irq_chip(irq, &pxa_internal_chip_high); + set_irq_handler(irq, handle_level_irq); + set_irq_flags(irq, IRQF_VALID); + } +} #endif /* Note that if an input/irq line ever gets changed to an output during @@ -217,7 +250,7 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc) do { loop = 0; - mask = GEDR0 & ~3; + mask = GEDR0 & GPIO_IRQ_mask[0] & ~3; if (mask) { GEDR0 = mask; irq = IRQ_GPIO(2); @@ -233,7 +266,7 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc) loop = 1; } - mask = GEDR1; + mask = GEDR1 & GPIO_IRQ_mask[1]; if (mask) { GEDR1 = mask; irq = IRQ_GPIO(32); @@ -248,7 +281,7 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc) loop = 1; } - mask = GEDR2; + mask = GEDR2 & GPIO_IRQ_mask[2]; if (mask) { GEDR2 = mask; irq = IRQ_GPIO(64); @@ -263,8 +296,7 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc) loop = 1; } -#if PXA_LAST_GPIO >= 96 - mask = GEDR3; + mask = GEDR3 & GPIO_IRQ_mask[3]; if (mask) { GEDR3 = mask; irq = IRQ_GPIO(96); @@ -278,7 +310,6 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc) } while (mask); loop = 1; } -#endif } while (loop); } @@ -314,64 +345,27 @@ static struct irq_chip pxa_muxed_gpio_chip = { .set_wake = pxa_set_gpio_wake, }; - -void __init pxa_init_irq(void) +void __init pxa_init_irq_gpio(int gpio_nr) { - int irq; - - /* disable all IRQs */ - ICMR = 0; - - /* all IRQs are IRQ, not FIQ */ - ICLR = 0; + int irq, i; /* clear all GPIO edge detects */ - GFER0 = 0; - GFER1 = 0; - GFER2 = 0; - GRER0 = 0; - GRER1 = 0; - GRER2 = 0; - GEDR0 = GEDR0; - GEDR1 = GEDR1; - GEDR2 = GEDR2; - -#ifdef CONFIG_PXA27x - /* And similarly for the extra regs on the PXA27x */ - ICMR2 = 0; - ICLR2 = 0; - GFER3 = 0; - GRER3 = 0; - GEDR3 = GEDR3; -#endif - - /* only unmasked interrupts kick us out of idle */ - ICCR = 1; + for (i = 0; i < gpio_nr; i += 32) { + GFER(i) = 0; + GRER(i) = 0; + GEDR(i) = GEDR(i); + } /* GPIO 0 and 1 must have their mask bit always set */ GPIO_IRQ_mask[0] = 3; - for (irq = PXA_IRQ(PXA_IRQ_SKIP); irq <= PXA_IRQ(31); irq++) { - set_irq_chip(irq, &pxa_internal_chip_low); - set_irq_handler(irq, handle_level_irq); - set_irq_flags(irq, IRQF_VALID); - } - -#if PXA_INTERNAL_IRQS > 32 - for (irq = PXA_IRQ(32); irq < PXA_IRQ(PXA_INTERNAL_IRQS); irq++) { - set_irq_chip(irq, &pxa_internal_chip_high); - set_irq_handler(irq, handle_level_irq); - set_irq_flags(irq, IRQF_VALID); - } -#endif - for (irq = IRQ_GPIO0; irq <= IRQ_GPIO1; irq++) { set_irq_chip(irq, &pxa_low_gpio_chip); set_irq_handler(irq, handle_edge_irq); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } - for (irq = IRQ_GPIO(2); irq <= IRQ_GPIO(PXA_LAST_GPIO); irq++) { + for (irq = IRQ_GPIO(2); irq <= IRQ_GPIO(gpio_nr); irq++) { set_irq_chip(irq, &pxa_muxed_gpio_chip); set_irq_handler(irq, handle_edge_irq); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); diff --git a/arch/arm/mach-pxa/lpd270.c b/arch/arm/mach-pxa/lpd270.c index e3097664ffe1..26116440a7c9 100644 --- a/arch/arm/mach-pxa/lpd270.c +++ b/arch/arm/mach-pxa/lpd270.c @@ -46,6 +46,7 @@ #include <asm/arch/ohci.h> #include "generic.h" +#include "devices.h" static unsigned int lpd270_irq_enabled; @@ -97,7 +98,7 @@ static void __init lpd270_init_irq(void) { int irq; - pxa_init_irq(); + pxa27x_init_irq(); __raw_writew(0, LPD270_INT_MASK); __raw_writew(0, LPD270_INT_STATUS); diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c index 6377b2e29ff0..e70048fd00a5 100644 --- a/arch/arm/mach-pxa/lubbock.c +++ b/arch/arm/mach-pxa/lubbock.c @@ -48,6 +48,7 @@ #include <asm/arch/mmc.h> #include "generic.h" +#include "devices.h" #define LUB_MISC_WR __LUB_REG(LUBBOCK_FPGA_PHYS + 0x080) @@ -103,7 +104,7 @@ static void __init lubbock_init_irq(void) { int irq; - pxa_init_irq(); + pxa25x_init_irq(); /* setup extra lubbock irqs */ for (irq = LUBBOCK_IRQ(0); irq <= LUBBOCK_LAST_IRQ; irq++) { diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c index ed99a81b98f3..b02c79c7e6a3 100644 --- a/arch/arm/mach-pxa/mainstone.c +++ b/arch/arm/mach-pxa/mainstone.c @@ -46,6 +46,7 @@ #include <asm/arch/ohci.h> #include "generic.h" +#include "devices.h" static unsigned long mainstone_irq_enabled; @@ -89,7 +90,7 @@ static void __init mainstone_init_irq(void) { int irq; - pxa_init_irq(); + pxa27x_init_irq(); /* setup extra Mainstone irqs */ for(irq = MAINSTONE_IRQ(0); irq <= MAINSTONE_IRQ(15); irq++) { diff --git a/arch/arm/mach-pxa/pm.c b/arch/arm/mach-pxa/pm.c index 6bf15ae73848..b59a81a8e7d3 100644 --- a/arch/arm/mach-pxa/pm.c +++ b/arch/arm/mach-pxa/pm.c @@ -24,62 +24,13 @@ #include <asm/arch/lubbock.h> #include <asm/mach/time.h> - -/* - * Debug macros - */ -#undef DEBUG - -#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x -#define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x] - -#define RESTORE_GPLEVEL(n) do { \ - GPSR##n = sleep_save[SLEEP_SAVE_GPLR##n]; \ - GPCR##n = ~sleep_save[SLEEP_SAVE_GPLR##n]; \ -} while (0) - -/* - * List of global PXA peripheral registers to preserve. - * More ones like CP and general purpose register values are preserved - * with the stack pointer in sleep.S. - */ -enum { SLEEP_SAVE_START = 0, - - SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2, SLEEP_SAVE_GPLR3, - SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2, SLEEP_SAVE_GPDR3, - SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2, SLEEP_SAVE_GRER3, - SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2, SLEEP_SAVE_GFER3, - SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2, SLEEP_SAVE_PGSR3, - - SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U, - SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR1_U, - SLEEP_SAVE_GAFR2_L, SLEEP_SAVE_GAFR2_U, - SLEEP_SAVE_GAFR3_L, SLEEP_SAVE_GAFR3_U, - - SLEEP_SAVE_PSTR, - - SLEEP_SAVE_ICMR, - SLEEP_SAVE_CKEN, - -#ifdef CONFIG_PXA27x - SLEEP_SAVE_MDREFR, - SLEEP_SAVE_PWER, SLEEP_SAVE_PCFR, SLEEP_SAVE_PRER, - SLEEP_SAVE_PFER, SLEEP_SAVE_PKWR, -#endif - - SLEEP_SAVE_CKSUM, - - SLEEP_SAVE_SIZE -}; - +struct pxa_cpu_pm_fns *pxa_cpu_pm_fns; +static unsigned long *sleep_save; int pxa_pm_enter(suspend_state_t state) { - unsigned long sleep_save[SLEEP_SAVE_SIZE]; - unsigned long checksum = 0; - struct timespec delta, rtc; + unsigned long sleep_save_checksum = 0, checksum = 0; int i; - extern void pxa_cpu_pm_enter(suspend_state_t state); #ifdef CONFIG_IWMMXT /* force any iWMMXt context to ram **/ @@ -87,109 +38,35 @@ int pxa_pm_enter(suspend_state_t state) iwmmxt_task_disable(NULL); #endif - /* preserve current time */ - rtc.tv_sec = RCNR; - rtc.tv_nsec = 0; - save_time_delta(&delta, &rtc); - - SAVE(GPLR0); SAVE(GPLR1); SAVE(GPLR2); - SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2); - SAVE(GRER0); SAVE(GRER1); SAVE(GRER2); - SAVE(GFER0); SAVE(GFER1); SAVE(GFER2); - SAVE(PGSR0); SAVE(PGSR1); SAVE(PGSR2); - - SAVE(GAFR0_L); SAVE(GAFR0_U); - SAVE(GAFR1_L); SAVE(GAFR1_U); - SAVE(GAFR2_L); SAVE(GAFR2_U); - -#ifdef CONFIG_PXA27x - SAVE(MDREFR); - SAVE(GPLR3); SAVE(GPDR3); SAVE(GRER3); SAVE(GFER3); SAVE(PGSR3); - SAVE(GAFR3_L); SAVE(GAFR3_U); - SAVE(PWER); SAVE(PCFR); SAVE(PRER); - SAVE(PFER); SAVE(PKWR); -#endif - - SAVE(ICMR); - ICMR = 0; - - SAVE(CKEN); - SAVE(PSTR); - - /* Note: wake up source are set up in each machine specific files */ - - /* clear GPIO transition detect bits */ - GEDR0 = GEDR0; GEDR1 = GEDR1; GEDR2 = GEDR2; -#ifdef CONFIG_PXA27x - GEDR3 = GEDR3; -#endif + pxa_cpu_pm_fns->save(sleep_save); /* Clear sleep reset status */ RCSR = RCSR_SMR; /* before sleeping, calculate and save a checksum */ - for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++) - checksum += sleep_save[i]; - sleep_save[SLEEP_SAVE_CKSUM] = checksum; + for (i = 0; i < pxa_cpu_pm_fns->save_size - 1; i++) + sleep_save_checksum += sleep_save[i]; /* *** go zzz *** */ - pxa_cpu_pm_enter(state); - + pxa_cpu_pm_fns->enter(state); cpu_init(); /* after sleeping, validate the checksum */ - checksum = 0; - for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++) + for (i = 0; i < pxa_cpu_pm_fns->save_size - 1; i++) checksum += sleep_save[i]; /* if invalid, display message and wait for a hardware reset */ - if (checksum != sleep_save[SLEEP_SAVE_CKSUM]) { + if (checksum != sleep_save_checksum) { #ifdef CONFIG_ARCH_LUBBOCK LUB_HEXLED = 0xbadbadc5; #endif while (1) - pxa_cpu_pm_enter(state); + pxa_cpu_pm_fns->enter(state); } - /* ensure not to come back here if it wasn't intended */ - PSPR = 0; - - /* restore registers */ - RESTORE_GPLEVEL(0); RESTORE_GPLEVEL(1); RESTORE_GPLEVEL(2); - RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2); - RESTORE(GAFR0_L); RESTORE(GAFR0_U); - RESTORE(GAFR1_L); RESTORE(GAFR1_U); - RESTORE(GAFR2_L); RESTORE(GAFR2_U); - RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2); - RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2); - RESTORE(PGSR0); RESTORE(PGSR1); RESTORE(PGSR2); - -#ifdef CONFIG_PXA27x - RESTORE(MDREFR); - RESTORE_GPLEVEL(3); RESTORE(GPDR3); - RESTORE(GAFR3_L); RESTORE(GAFR3_U); - RESTORE(GRER3); RESTORE(GFER3); RESTORE(PGSR3); - RESTORE(PWER); RESTORE(PCFR); RESTORE(PRER); - RESTORE(PFER); RESTORE(PKWR); -#endif - - PSSR = PSSR_RDH | PSSR_PH; - - RESTORE(CKEN); - - ICLR = 0; - ICCR = 1; - RESTORE(ICMR); + pxa_cpu_pm_fns->restore(sleep_save); - RESTORE(PSTR); - - /* restore current time */ - rtc.tv_sec = RCNR; - restore_time_delta(&delta, &rtc); - -#ifdef DEBUG - printk(KERN_DEBUG "*** made it back from resume\n"); -#endif + pr_debug("*** made it back from resume\n"); return 0; } @@ -201,37 +78,32 @@ unsigned long sleep_phys_sp(void *sp) return virt_to_phys(sp); } -/* - * Called after processes are frozen, but before we shut down devices. - */ -int pxa_pm_prepare(suspend_state_t state) +static int pxa_pm_valid(suspend_state_t state) { - extern int pxa_cpu_pm_prepare(suspend_state_t state); + if (pxa_cpu_pm_fns) + return pxa_cpu_pm_fns->valid(state); - return pxa_cpu_pm_prepare(state); + return -EINVAL; } -EXPORT_SYMBOL_GPL(pxa_pm_prepare); - -/* - * Called after devices are re-setup, but before processes are thawed. - */ -int pxa_pm_finish(suspend_state_t state) -{ - return 0; -} - -EXPORT_SYMBOL_GPL(pxa_pm_finish); - static struct pm_ops pxa_pm_ops = { - .prepare = pxa_pm_prepare, + .valid = pxa_pm_valid, .enter = pxa_pm_enter, - .finish = pxa_pm_finish, - .valid = pm_valid_only_mem, }; static int __init pxa_pm_init(void) { + if (!pxa_cpu_pm_fns) { + printk(KERN_ERR "no valid pxa_cpu_pm_fns defined\n"); + return -EINVAL; + } + + sleep_save = kmalloc(pxa_cpu_pm_fns->save_size, GFP_KERNEL); + if (!sleep_save) { + printk(KERN_ERR "failed to alloc memory for pm save\n"); + return -ENOMEM; + } + pm_set_ops(&pxa_pm_ops); return 0; } diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c index 34fb80b37023..655668d4d0e9 100644 --- a/arch/arm/mach-pxa/poodle.c +++ b/arch/arm/mach-pxa/poodle.c @@ -45,6 +45,7 @@ #include <asm/mach/sharpsl_param.h> #include "generic.h" +#include "devices.h" #include "sharpsl.h" static struct resource poodle_scoop_resources[] = { @@ -412,7 +413,7 @@ MACHINE_START(POODLE, "SHARP Poodle") .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, .fixup = fixup_poodle, .map_io = pxa_map_io, - .init_irq = pxa_init_irq, + .init_irq = pxa25x_init_irq, .timer = &pxa_timer, .init_machine = poodle_init, MACHINE_END diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c index c1f21739bf71..6dfcca72e90f 100644 --- a/arch/arm/mach-pxa/pxa25x.c +++ b/arch/arm/mach-pxa/pxa25x.c @@ -19,12 +19,17 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> +#include <linux/platform_device.h> #include <linux/pm.h> #include <asm/hardware.h> +#include <asm/arch/irqs.h> #include <asm/arch/pxa-regs.h> +#include <asm/arch/pm.h> +#include <asm/arch/dma.h> #include "generic.h" +#include "devices.h" /* * Various clock factors driven by the CCCR register. @@ -105,32 +110,138 @@ EXPORT_SYMBOL(get_lcdclk_frequency_10khz); #ifdef CONFIG_PM -int pxa_cpu_pm_prepare(suspend_state_t state) -{ - switch (state) { - case PM_SUSPEND_MEM: - break; - default: - return -EINVAL; - } +#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x +#define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x] + +#define RESTORE_GPLEVEL(n) do { \ + GPSR##n = sleep_save[SLEEP_SAVE_GPLR##n]; \ + GPCR##n = ~sleep_save[SLEEP_SAVE_GPLR##n]; \ +} while (0) + +/* + * List of global PXA peripheral registers to preserve. + * More ones like CP and general purpose register values are preserved + * with the stack pointer in sleep.S. + */ +enum { SLEEP_SAVE_START = 0, - return 0; + SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2, + SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2, + SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2, + SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2, + SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2, + + SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U, + SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR1_U, + SLEEP_SAVE_GAFR2_L, SLEEP_SAVE_GAFR2_U, + + SLEEP_SAVE_PSTR, + + SLEEP_SAVE_ICMR, + SLEEP_SAVE_CKEN, + + SLEEP_SAVE_SIZE +}; + + +static void pxa25x_cpu_pm_save(unsigned long *sleep_save) +{ + SAVE(GPLR0); SAVE(GPLR1); SAVE(GPLR2); + SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2); + SAVE(GRER0); SAVE(GRER1); SAVE(GRER2); + SAVE(GFER0); SAVE(GFER1); SAVE(GFER2); + SAVE(PGSR0); SAVE(PGSR1); SAVE(PGSR2); + + SAVE(GAFR0_L); SAVE(GAFR0_U); + SAVE(GAFR1_L); SAVE(GAFR1_U); + SAVE(GAFR2_L); SAVE(GAFR2_U); + + SAVE(ICMR); + SAVE(CKEN); + SAVE(PSTR); } -void pxa_cpu_pm_enter(suspend_state_t state) +static void pxa25x_cpu_pm_restore(unsigned long *sleep_save) { - extern void pxa_cpu_suspend(unsigned int); - extern void pxa_cpu_resume(void); + /* restore registers */ + RESTORE_GPLEVEL(0); RESTORE_GPLEVEL(1); RESTORE_GPLEVEL(2); + RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2); + RESTORE(GAFR0_L); RESTORE(GAFR0_U); + RESTORE(GAFR1_L); RESTORE(GAFR1_U); + RESTORE(GAFR2_L); RESTORE(GAFR2_U); + RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2); + RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2); + RESTORE(PGSR0); RESTORE(PGSR1); RESTORE(PGSR2); + + RESTORE(CKEN); + RESTORE(ICMR); + RESTORE(PSTR); +} +static void pxa25x_cpu_pm_enter(suspend_state_t state) +{ CKEN = 0; switch (state) { case PM_SUSPEND_MEM: /* set resume return address */ PSPR = virt_to_phys(pxa_cpu_resume); - pxa_cpu_suspend(PWRMODE_SLEEP); + pxa25x_cpu_suspend(PWRMODE_SLEEP); break; } } +static struct pxa_cpu_pm_fns pxa25x_cpu_pm_fns = { + .save_size = SLEEP_SAVE_SIZE, + .valid = pm_valid_only_mem, + .save = pxa25x_cpu_pm_save, + .restore = pxa25x_cpu_pm_restore, + .enter = pxa25x_cpu_pm_enter, +}; + +static void __init pxa25x_init_pm(void) +{ + pxa_cpu_pm_fns = &pxa25x_cpu_pm_fns; +} +#endif + +void __init pxa25x_init_irq(void) +{ + pxa_init_irq_low(); + pxa_init_irq_gpio(85); +} + +static struct platform_device *pxa25x_devices[] __initdata = { + &pxa_device_mci, + &pxa_device_udc, + &pxa_device_fb, + &pxa_device_ffuart, + &pxa_device_btuart, + &pxa_device_stuart, + &pxa_device_i2c, + &pxa_device_i2s, + &pxa_device_ficp, + &pxa_device_rtc, +}; + +static int __init pxa25x_init(void) +{ + int ret = 0; + + if (cpu_is_pxa21x() || cpu_is_pxa25x()) { + if ((ret = pxa_init_dma(16))) + return ret; +#ifdef CONFIG_PM + pxa25x_init_pm(); #endif + ret = platform_add_devices(pxa25x_devices, + ARRAY_SIZE(pxa25x_devices)); + } + /* Only add HWUART for PXA255/26x; PXA210/250/27x do not have it. */ + if (cpu_is_pxa25x()) + ret = platform_device_register(&pxa_device_hwuart); + + return ret; +} + +subsys_initcall(pxa25x_init); diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c index 1939acc3f9f7..203371ab19db 100644 --- a/arch/arm/mach-pxa/pxa27x.c +++ b/arch/arm/mach-pxa/pxa27x.c @@ -19,10 +19,14 @@ #include <asm/hardware.h> #include <asm/irq.h> +#include <asm/arch/irqs.h> #include <asm/arch/pxa-regs.h> #include <asm/arch/ohci.h> +#include <asm/arch/pm.h> +#include <asm/arch/dma.h> #include "generic.h" +#include "devices.h" /* Crystal clock: 13MHz */ #define BASE_CLK 13000000 @@ -122,25 +126,107 @@ EXPORT_SYMBOL(get_lcdclk_frequency_10khz); #ifdef CONFIG_PM -int pxa_cpu_pm_prepare(suspend_state_t state) +#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x +#define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x] + +#define RESTORE_GPLEVEL(n) do { \ + GPSR##n = sleep_save[SLEEP_SAVE_GPLR##n]; \ + GPCR##n = ~sleep_save[SLEEP_SAVE_GPLR##n]; \ +} while (0) + +/* + * List of global PXA peripheral registers to preserve. + * More ones like CP and general purpose register values are preserved + * with the stack pointer in sleep.S. + */ +enum { SLEEP_SAVE_START = 0, + + SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2, SLEEP_SAVE_GPLR3, + SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2, SLEEP_SAVE_GPDR3, + SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2, SLEEP_SAVE_GRER3, + SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2, SLEEP_SAVE_GFER3, + SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2, SLEEP_SAVE_PGSR3, + + SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U, + SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR1_U, + SLEEP_SAVE_GAFR2_L, SLEEP_SAVE_GAFR2_U, + SLEEP_SAVE_GAFR3_L, SLEEP_SAVE_GAFR3_U, + + SLEEP_SAVE_PSTR, + + SLEEP_SAVE_ICMR, + SLEEP_SAVE_CKEN, + + SLEEP_SAVE_MDREFR, + SLEEP_SAVE_PWER, SLEEP_SAVE_PCFR, SLEEP_SAVE_PRER, + SLEEP_SAVE_PFER, SLEEP_SAVE_PKWR, + + SLEEP_SAVE_SIZE +}; + +void pxa27x_cpu_pm_save(unsigned long *sleep_save) { - switch (state) { - case PM_SUSPEND_MEM: - case PM_SUSPEND_STANDBY: - return 0; - default: - return -EINVAL; - } + SAVE(GPLR0); SAVE(GPLR1); SAVE(GPLR2); SAVE(GPLR3); + SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2); SAVE(GPDR3); + SAVE(GRER0); SAVE(GRER1); SAVE(GRER2); SAVE(GRER3); + SAVE(GFER0); SAVE(GFER1); SAVE(GFER2); SAVE(GFER3); + SAVE(PGSR0); SAVE(PGSR1); SAVE(PGSR2); SAVE(PGSR3); + + SAVE(GAFR0_L); SAVE(GAFR0_U); + SAVE(GAFR1_L); SAVE(GAFR1_U); + SAVE(GAFR2_L); SAVE(GAFR2_U); + SAVE(GAFR3_L); SAVE(GAFR3_U); + + SAVE(MDREFR); + SAVE(PWER); SAVE(PCFR); SAVE(PRER); + SAVE(PFER); SAVE(PKWR); + + SAVE(ICMR); ICMR = 0; + SAVE(CKEN); + SAVE(PSTR); + + /* Clear GPIO transition detect bits */ + GEDR0 = GEDR0; GEDR1 = GEDR1; GEDR2 = GEDR2; GEDR3 = GEDR3; +} + +void pxa27x_cpu_pm_restore(unsigned long *sleep_save) +{ + /* ensure not to come back here if it wasn't intended */ + PSPR = 0; + + /* restore registers */ + RESTORE_GPLEVEL(0); RESTORE_GPLEVEL(1); + RESTORE_GPLEVEL(2); RESTORE_GPLEVEL(3); + RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2); RESTORE(GPDR3); + RESTORE(GAFR0_L); RESTORE(GAFR0_U); + RESTORE(GAFR1_L); RESTORE(GAFR1_U); + RESTORE(GAFR2_L); RESTORE(GAFR2_U); + RESTORE(GAFR3_L); RESTORE(GAFR3_U); + RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2); RESTORE(GRER3); + RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2); RESTORE(GFER3); + RESTORE(PGSR0); RESTORE(PGSR1); RESTORE(PGSR2); RESTORE(PGSR3); + + RESTORE(MDREFR); + RESTORE(PWER); RESTORE(PCFR); RESTORE(PRER); + RESTORE(PFER); RESTORE(PKWR); + + PSSR = PSSR_RDH | PSSR_PH; + + RESTORE(CKEN); + + ICLR = 0; + ICCR = 1; + RESTORE(ICMR); + RESTORE(PSTR); } -void pxa_cpu_pm_enter(suspend_state_t state) +void pxa27x_cpu_pm_enter(suspend_state_t state) { extern void pxa_cpu_standby(void); - extern void pxa_cpu_suspend(unsigned int); - extern void pxa_cpu_resume(void); if (state == PM_SUSPEND_STANDBY) - CKEN = (1 << CKEN_MEMC) | (1 << CKEN_OSTIMER) | (1 << CKEN_LCD) | (1 << CKEN_PWM0); + CKEN = (1 << CKEN_MEMC) | (1 << CKEN_OSTIMER) | + (1 << CKEN_LCD) | (1 << CKEN_PWM0); else CKEN = (1 << CKEN_MEMC) | (1 << CKEN_OSTIMER); @@ -157,11 +243,28 @@ void pxa_cpu_pm_enter(suspend_state_t state) case PM_SUSPEND_MEM: /* set resume return address */ PSPR = virt_to_phys(pxa_cpu_resume); - pxa_cpu_suspend(PWRMODE_SLEEP); + pxa27x_cpu_suspend(PWRMODE_SLEEP); break; } } +static int pxa27x_cpu_pm_valid(suspend_state_t state) +{ + return state == PM_SUSPEND_MEM || state == PM_SUSPEND_STANDBY; +} + +static struct pxa_cpu_pm_fns pxa27x_cpu_pm_fns = { + .save_size = SLEEP_SAVE_SIZE, + .save = pxa27x_cpu_pm_save, + .restore = pxa27x_cpu_pm_restore, + .valid = pxa27x_cpu_pm_valid, + .enter = pxa27x_cpu_pm_enter, +}; + +static void __init pxa27x_init_pm(void) +{ + pxa_cpu_pm_fns = &pxa27x_cpu_pm_fns; +} #endif /* @@ -183,7 +286,7 @@ static struct resource pxa27x_ohci_resources[] = { }, }; -static struct platform_device ohci_device = { +static struct platform_device pxa27x_device_ohci = { .name = "pxa27x-ohci", .id = -1, .dev = { @@ -196,16 +299,62 @@ static struct platform_device ohci_device = { void __init pxa_set_ohci_info(struct pxaohci_platform_data *info) { - ohci_device.dev.platform_data = info; + pxa27x_device_ohci.dev.platform_data = info; } +static struct resource i2c_power_resources[] = { + { + .start = 0x40f00180, + .end = 0x40f001a3, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_PWRI2C, + .end = IRQ_PWRI2C, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device pxa27x_device_i2c_power = { + .name = "pxa2xx-i2c", + .id = 1, + .resource = i2c_power_resources, + .num_resources = ARRAY_SIZE(i2c_power_resources), +}; + static struct platform_device *devices[] __initdata = { - &ohci_device, + &pxa_device_mci, + &pxa_device_udc, + &pxa_device_fb, + &pxa_device_ffuart, + &pxa_device_btuart, + &pxa_device_stuart, + &pxa_device_i2c, + &pxa_device_i2s, + &pxa_device_ficp, + &pxa_device_rtc, + &pxa27x_device_i2c_power, + &pxa27x_device_ohci, }; +void __init pxa27x_init_irq(void) +{ + pxa_init_irq_low(); + pxa_init_irq_high(); + pxa_init_irq_gpio(128); +} + static int __init pxa27x_init(void) { - return platform_add_devices(devices, ARRAY_SIZE(devices)); + int ret = 0; + if (cpu_is_pxa27x()) { + if ((ret = pxa_init_dma(32))) + return ret; +#ifdef CONFIG_PM + pxa27x_init_pm(); +#endif + ret = platform_add_devices(devices, ARRAY_SIZE(devices)); + } + return ret; } subsys_initcall(pxa27x_init); 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 @@ #include <asm/arch/pxa-regs.h> -#ifdef CONFIG_PXA27x // workaround for Errata 50 #define MDREFR_KDIV 0x200a4000 // all banks #define CCCR_SLEEP 0x00000107 // L=7 2N=2 A=0 PPDIS=0 CPDIS=0 -#endif .text -/* - * pxa_cpu_suspend() - * - * Forces CPU into sleep state. - * - * r0 = value for PWRMODE M field for desired sleep state - */ - -ENTRY(pxa_cpu_suspend) - -#ifndef CONFIG_IWMMXT - mra r2, r3, acc0 -#endif - stmfd sp!, {r2 - r12, lr} @ save registers on stack - +pxa_cpu_save_cp: @ get coprocessor registers mrc p14, 0, r3, c6, c0, 0 @ clock configuration, for turbo mode mrc p15, 0, r4, c15, c1, 0 @ CP access reg @@ -54,12 +38,36 @@ ENTRY(pxa_cpu_suspend) mov r10, sp stmfd sp!, {r3 - r10} - mov r5, r0 @ save sleep mode + mov pc, lr + +pxa_cpu_save_sp: @ preserve phys address of stack mov r0, sp + mov r2, lr bl sleep_phys_sp ldr r1, =sleep_save_sp str r0, [r1] + mov pc, r2 + +/* + * pxa27x_cpu_suspend() + * + * Forces CPU into sleep state. + * + * r0 = value for PWRMODE M field for desired sleep state + */ + +ENTRY(pxa27x_cpu_suspend) + +#ifndef CONFIG_IWMMXT + mra r2, r3, acc0 +#endif + stmfd sp!, {r2 - r12, lr} @ save registers on stack + + bl pxa_cpu_save_cp + + mov r5, r0 @ save sleep mode + bl pxa_cpu_save_sp @ clean data cache bl xscale_flush_kern_cache_all @@ -80,13 +88,55 @@ ENTRY(pxa_cpu_suspend) @ enable SDRAM self-refresh mode orr r5, r5, #MDREFR_SLFRSH -#ifdef CONFIG_PXA27x @ set SDCLKx divide-by-2 bits (this is part of a workaround for Errata 50) ldr r6, =MDREFR_KDIV orr r5, r5, r6 -#endif -#ifdef CONFIG_PXA25x + @ Intel PXA270 Specification Update notes problems sleeping + @ with core operating above 91 MHz + @ (see Errata 50, ...processor does not exit from sleep...) + + ldr r6, =CCCR + ldr r8, [r6] @ keep original value for resume + + ldr r7, =CCCR_SLEEP @ prepare CCCR sleep value + mov r0, #0x2 @ prepare value for CLKCFG + + @ align execution to a cache line + b pxa_cpu_do_suspend + +/* + * pxa27x_cpu_suspend() + * + * Forces CPU into sleep state. + * + * r0 = value for PWRMODE M field for desired sleep state + */ + +ENTRY(pxa25x_cpu_suspend) + stmfd sp!, {r2 - r12, lr} @ save registers on stack + + bl pxa_cpu_save_cp + + mov r5, r0 @ save sleep mode + bl pxa_cpu_save_sp + + @ clean data cache + bl xscale_flush_kern_cache_all + + @ prepare value for sleep mode + mov r1, r5 @ sleep mode + + @ prepare pointer to physical address 0 (virtual mapping in generic.c) + mov r2, #UNCACHED_PHYS_0 + + @ prepare SDRAM refresh settings + ldr r4, =MDREFR + ldr r5, [r4] + + @ enable SDRAM self-refresh mode + orr r5, r5, #MDREFR_SLFRSH + @ Intel PXA255 Specification Update notes problems @ about suspending with PXBus operating above 133MHz @ (see Errata 31, GPIO output signals, ... unpredictable in sleep @@ -118,30 +168,15 @@ ENTRY(pxa_cpu_suspend) mov r0, #0 mcr p14, 0, r0, c6, c0, 0 orr r0, r0, #2 @ initiate change bit -#endif -#ifdef CONFIG_PXA27x - @ Intel PXA270 Specification Update notes problems sleeping - @ with core operating above 91 MHz - @ (see Errata 50, ...processor does not exit from sleep...) - - ldr r6, =CCCR - ldr r8, [r6] @ keep original value for resume - - ldr r7, =CCCR_SLEEP @ prepare CCCR sleep value - mov r0, #0x2 @ prepare value for CLKCFG -#endif - - @ align execution to a cache line - b 1f + b pxa_cpu_do_suspend .ltorg .align 5 -1: +pxa_cpu_do_suspend: @ All needed values are now in registers. @ These last instructions should be in cache -#if defined(CONFIG_PXA25x) || defined(CONFIG_PXA27x) @ initiate the frequency change... str r7, [r6] mcr p14, 0, r0, c6, c0, 0 @@ -155,7 +190,6 @@ ENTRY(pxa_cpu_suspend) mov r0, #42 10: subs r0, r0, #1 bne 10b -#endif @ Do not reorder... @ Intel PXA270 Specification Update notes problems performing diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index 3cbac63bed3c..bae47e145de8 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c @@ -48,6 +48,7 @@ #include <asm/hardware/scoop.h> #include "generic.h" +#include "devices.h" #include "sharpsl.h" /* @@ -560,7 +561,7 @@ MACHINE_START(SPITZ, "SHARP Spitz") .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, .fixup = fixup_spitz, .map_io = pxa_map_io, - .init_irq = pxa_init_irq, + .init_irq = pxa27x_init_irq, .init_machine = spitz_init, .timer = &pxa_timer, MACHINE_END @@ -572,7 +573,7 @@ MACHINE_START(BORZOI, "SHARP Borzoi") .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, .fixup = fixup_spitz, .map_io = pxa_map_io, - .init_irq = pxa_init_irq, + .init_irq = pxa27x_init_irq, .init_machine = spitz_init, .timer = &pxa_timer, MACHINE_END @@ -584,7 +585,7 @@ MACHINE_START(AKITA, "SHARP Akita") .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, .fixup = fixup_spitz, .map_io = pxa_map_io, - .init_irq = pxa_init_irq, + .init_irq = pxa27x_init_irq, .init_machine = akita_init, .timer = &pxa_timer, MACHINE_END diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c index 5248abe334d2..98d27e646b09 100644 --- a/arch/arm/mach-pxa/time.c +++ b/arch/arm/mach-pxa/time.c @@ -1,9 +1,11 @@ /* * arch/arm/mach-pxa/time.c * - * Author: Nicolas Pitre - * Created: Jun 15, 2001 - * Copyright: MontaVista Software Inc. + * PXA clocksource, clockevents, and OST interrupt handlers. + * Copyright (c) 2007 by Bill Gatliff <bgat@billgatliff.com>. + * + * Derived from Nicolas Pitre's PXA timer handler Copyright (c) 2001 + * by MontaVista Software, Inc. (Nico, your code rocks!) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -12,173 +14,160 @@ #include <linux/kernel.h> #include <linux/init.h> -#include <linux/delay.h> #include <linux/interrupt.h> -#include <linux/time.h> -#include <linux/signal.h> -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/clocksource.h> - -#include <asm/system.h> -#include <asm/hardware.h> -#include <asm/io.h> -#include <asm/leds.h> -#include <asm/irq.h> +#include <linux/clockchips.h> + #include <asm/mach/irq.h> #include <asm/mach/time.h> #include <asm/arch/pxa-regs.h> - -static inline unsigned long pxa_get_rtc_time(void) +static irqreturn_t +pxa_ost0_interrupt(int irq, void *dev_id) { - return RCNR; + int next_match; + struct clock_event_device *c = dev_id; + + if (c->mode == CLOCK_EVT_MODE_ONESHOT) { + /* Disarm the compare/match, signal the event. */ + OIER &= ~OIER_E0; + c->event_handler(c); + } else if (c->mode == CLOCK_EVT_MODE_PERIODIC) { + /* Call the event handler as many times as necessary + * to recover missed events, if any (if we update + * OSMR0 and OSCR0 is still ahead of us, we've missed + * the event). As we're dealing with that, re-arm the + * compare/match for the next event. + * + * HACK ALERT: + * + * There's a latency between the instruction that + * writes to OSMR0 and the actual commit to the + * physical hardware, because the CPU doesn't (have + * to) run at bus speed, there's a write buffer + * between the CPU and the bus, etc. etc. So if the + * target OSCR0 is "very close", to the OSMR0 load + * value, the update to OSMR0 might not get to the + * hardware in time and we'll miss that interrupt. + * + * To be safe, if the new OSMR0 is "very close" to the + * target OSCR0 value, we call the event_handler as + * though the event actually happened. According to + * Nico's comment in the previous version of this + * code, experience has shown that 6 OSCR ticks is + * "very close" but he went with 8. We will use 16, + * based on the results of testing on PXA270. + * + * To be doubly sure, we also tell clkevt via + * clockevents_register_device() not to ask for + * anything that might put us "very close". + */ +#define MIN_OSCR_DELTA 16 + do { + OSSR = OSSR_M0; + next_match = (OSMR0 += LATCH); + c->event_handler(c); + } while (((signed long)(next_match - OSCR) <= MIN_OSCR_DELTA) + && (c->mode == CLOCK_EVT_MODE_PERIODIC)); + } + + return IRQ_HANDLED; } -static int pxa_set_rtc(void) +static int +pxa_osmr0_set_next_event(unsigned long delta, struct clock_event_device *dev) { - unsigned long current_time = xtime.tv_sec; + unsigned long irqflags; - if (RTSR & RTSR_ALE) { - /* make sure not to forward the clock over an alarm */ - unsigned long alarm = RTAR; - if (current_time >= alarm && alarm >= RCNR) - return -ERESTARTSYS; - } - RCNR = current_time; + raw_local_irq_save(irqflags); + OSMR0 = OSCR + delta; + OSSR = OSSR_M0; + OIER |= OIER_E0; + raw_local_irq_restore(irqflags); return 0; } -#ifdef CONFIG_NO_IDLE_HZ -static unsigned long initial_match; -static int match_posponed; -#endif - -static irqreturn_t -pxa_timer_interrupt(int irq, void *dev_id) +static void +pxa_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *dev) { - int next_match; - - write_seqlock(&xtime_lock); - -#ifdef CONFIG_NO_IDLE_HZ - if (match_posponed) { - match_posponed = 0; - OSMR0 = initial_match; + unsigned long irqflags; + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + raw_local_irq_save(irqflags); + OSMR0 = OSCR + LATCH; + OSSR = OSSR_M0; + OIER |= OIER_E0; + raw_local_irq_restore(irqflags); + break; + + case CLOCK_EVT_MODE_ONESHOT: + raw_local_irq_save(irqflags); + OIER &= ~OIER_E0; + raw_local_irq_restore(irqflags); + break; + + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + /* initializing, released, or preparing for suspend */ + raw_local_irq_save(irqflags); + OIER &= ~OIER_E0; + raw_local_irq_restore(irqflags); + break; } -#endif - - /* Loop until we get ahead of the free running timer. - * This ensures an exact clock tick count and time accuracy. - * Since IRQs are disabled at this point, coherence between - * lost_ticks(updated in do_timer()) and the match reg value is - * ensured, hence we can use do_gettimeofday() from interrupt - * handlers. - * - * HACK ALERT: it seems that the PXA timer regs aren't updated right - * away in all cases when a write occurs. We therefore compare with - * 8 instead of 0 in the while() condition below to avoid missing a - * match if OSCR has already reached the next OSMR value. - * Experience has shown that up to 6 ticks are needed to work around - * this problem, but let's use 8 to be conservative. Note that this - * affect things only when the timer IRQ has been delayed by nearly - * exactly one tick period which should be a pretty rare event. - */ - do { - timer_tick(); - OSSR = OSSR_M0; /* Clear match on timer 0 */ - next_match = (OSMR0 += LATCH); - } while( (signed long)(next_match - OSCR) <= 8 ); - - write_sequnlock(&xtime_lock); - - return IRQ_HANDLED; } -static struct irqaction pxa_timer_irq = { - .name = "PXA Timer Tick", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, - .handler = pxa_timer_interrupt, +static struct clock_event_device ckevt_pxa_osmr0 = { + .name = "osmr0", + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .shift = 32, + .rating = 200, + .cpumask = CPU_MASK_CPU0, + .set_next_event = pxa_osmr0_set_next_event, + .set_mode = pxa_osmr0_set_mode, }; -static cycle_t pxa_get_cycles(void) +static cycle_t pxa_read_oscr(void) { return OSCR; } -static struct clocksource clocksource_pxa = { - .name = "pxa_timer", +static struct clocksource cksrc_pxa_oscr0 = { + .name = "oscr0", .rating = 200, - .read = pxa_get_cycles, + .read = pxa_read_oscr, .mask = CLOCKSOURCE_MASK(32), .shift = 20, .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; +static struct irqaction pxa_ost0_irq = { + .name = "ost0", + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .handler = pxa_ost0_interrupt, + .dev_id = &ckevt_pxa_osmr0, +}; + static void __init pxa_timer_init(void) { - struct timespec tv; - unsigned long flags; - - set_rtc = pxa_set_rtc; + OIER = 0; + OSSR = OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3; - tv.tv_nsec = 0; - tv.tv_sec = pxa_get_rtc_time(); - do_settimeofday(&tv); + ckevt_pxa_osmr0.mult = + div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, ckevt_pxa_osmr0.shift); + ckevt_pxa_osmr0.max_delta_ns = + clockevent_delta2ns(0x7fffffff, &ckevt_pxa_osmr0); + ckevt_pxa_osmr0.min_delta_ns = + clockevent_delta2ns(MIN_OSCR_DELTA, &ckevt_pxa_osmr0) + 1; - OIER = 0; /* disable any timer interrupts */ - OSSR = 0xf; /* clear status on all timers */ - setup_irq(IRQ_OST0, &pxa_timer_irq); - local_irq_save(flags); - OIER = OIER_E0; /* enable match on timer 0 to cause interrupts */ - OSMR0 = OSCR + LATCH; /* set initial match */ - local_irq_restore(flags); - - /* - * OSCR runs continuously on PXA and is not written to, - * so we can use it as clock source directly. - */ - clocksource_pxa.mult = - clocksource_hz2mult(CLOCK_TICK_RATE, clocksource_pxa.shift); - clocksource_register(&clocksource_pxa); -} - -#ifdef CONFIG_NO_IDLE_HZ -static int pxa_dyn_tick_enable_disable(void) -{ - /* nothing to do */ - return 0; -} + cksrc_pxa_oscr0.mult = + clocksource_hz2mult(CLOCK_TICK_RATE, cksrc_pxa_oscr0.shift); -static void pxa_dyn_tick_reprogram(unsigned long ticks) -{ - if (ticks > 1) { - initial_match = OSMR0; - OSMR0 = initial_match + ticks * LATCH; - match_posponed = 1; - } -} + setup_irq(IRQ_OST0, &pxa_ost0_irq); -static irqreturn_t -pxa_dyn_tick_handler(int irq, void *dev_id) -{ - if (match_posponed) { - match_posponed = 0; - OSMR0 = initial_match; - if ( (signed long)(initial_match - OSCR) <= 8 ) - return pxa_timer_interrupt(irq, dev_id); - } - return IRQ_NONE; + clocksource_register(&cksrc_pxa_oscr0); + clockevents_register_device(&ckevt_pxa_osmr0); } -static struct dyn_tick_timer pxa_dyn_tick = { - .enable = pxa_dyn_tick_enable_disable, - .disable = pxa_dyn_tick_enable_disable, - .reprogram = pxa_dyn_tick_reprogram, - .handler = pxa_dyn_tick_handler, -}; -#endif - #ifdef CONFIG_PM static unsigned long osmr[4], oier; @@ -200,7 +189,10 @@ static void pxa_timer_resume(void) OIER = oier; /* - * OSMR0 is the system timer: make sure OSCR is sufficiently behind + * OSCR0 is the system timer, which has to increase + * monotonically until it rolls over in hardware. The value + * (OSMR0 - LATCH) is OSCR0 at the most recent system tick, + * which is a handy value to restore to OSCR0. */ OSCR = OSMR0 - LATCH; } @@ -213,7 +205,4 @@ struct sys_timer pxa_timer = { .init = pxa_timer_init, .suspend = pxa_timer_suspend, .resume = pxa_timer_resume, -#ifdef CONFIG_NO_IDLE_HZ - .dyn_tick = &pxa_dyn_tick, -#endif }; diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c index 72738771fb57..240fd042083d 100644 --- a/arch/arm/mach-pxa/tosa.c +++ b/arch/arm/mach-pxa/tosa.c @@ -42,7 +42,7 @@ #include <asm/mach/sharpsl_param.h> #include "generic.h" - +#include "devices.h" /* * SCOOP Device @@ -332,7 +332,7 @@ MACHINE_START(TOSA, "SHARP Tosa") .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, .fixup = fixup_tosa, .map_io = pxa_map_io, - .init_irq = pxa_init_irq, + .init_irq = pxa25x_init_irq, .init_machine = tosa_init, .timer = &pxa_timer, MACHINE_END diff --git a/arch/arm/mach-pxa/trizeps4.c b/arch/arm/mach-pxa/trizeps4.c index 28c79bd0a3a0..e4ba43bdf85d 100644 --- a/arch/arm/mach-pxa/trizeps4.c +++ b/arch/arm/mach-pxa/trizeps4.c @@ -49,6 +49,7 @@ #include <asm/arch/ohci.h> #include "generic.h" +#include "devices.h" /******************************************************************************************** * ONBOARD FLASH @@ -503,7 +504,7 @@ MACHINE_START(TRIZEPS4, "Keith und Koep Trizeps IV module") .boot_params = TRIZEPS4_SDRAM_BASE + 0x100, .init_machine = trizeps4_init, .map_io = trizeps4_map_io, - .init_irq = pxa_init_irq, + .init_irq = pxa27x_init_irq, .timer = &pxa_timer, MACHINE_END |