From 7876284178b386ab6e97f96733ccbc19eda743a3 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 26 Jun 2006 16:15:59 -0700 Subject: ARM: OMAP: Mistral board updates (spi, ...) This adds the OSK/Mistral specific glue for the omap_uwire driver and its ADS 7846 touchscreen. It also moves the lcd and keypad setup so it's grouped with the other Mistral-specific setup code, and provides comments about which switch maps to which reported key. Signed-off-by: David Brownell Signed-off-by: Tony Lindgren --- arch/arm/mach-omap1/board-osk.c | 142 +++++++++++++++++++++++++--------------- 1 file changed, 89 insertions(+), 53 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c index 1160093e8ef..8f8f50b7058 100644 --- a/arch/arm/mach-omap1/board-osk.c +++ b/arch/arm/mach-omap1/board-osk.c @@ -33,7 +33,6 @@ #include #include -#include #include #include @@ -45,25 +44,10 @@ #include #include #include -#include #include #include #include -static int osk_keymap[] = { - KEY(0, 0, KEY_F1), - KEY(0, 3, KEY_UP), - KEY(1, 1, KEY_LEFTCTRL), - KEY(1, 2, KEY_LEFT), - KEY(2, 0, KEY_SPACE), - KEY(2, 1, KEY_ESC), - KEY(2, 2, KEY_DOWN), - KEY(3, 2, KEY_ENTER), - KEY(3, 3, KEY_RIGHT), - 0 -}; - - static struct mtd_partition osk_partitions[] = { /* bootloader (U-Boot, etc) in first sector */ { @@ -181,48 +165,17 @@ static struct omap_alsa_codec_config alsa_config = { static struct platform_device osk5912_mcbsp1_device = { .name = "omap_alsa_mcbsp", - .id = 1, + .id = 1, .dev = { .platform_data = &alsa_config, }, }; -static struct resource osk5912_kp_resources[] = { - [0] = { - .start = INT_KEYBOARD, - .end = INT_KEYBOARD, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct omap_kp_platform_data osk_kp_data = { - .rows = 8, - .cols = 8, - .keymap = osk_keymap, -}; - -static struct platform_device osk5912_kp_device = { - .name = "omap-keypad", - .id = -1, - .dev = { - .platform_data = &osk_kp_data, - }, - .num_resources = ARRAY_SIZE(osk5912_kp_resources), - .resource = osk5912_kp_resources, -}; - -static struct platform_device osk5912_lcd_device = { - .name = "lcd_osk", - .id = -1, -}; - static struct platform_device *osk5912_devices[] __initdata = { &osk5912_flash_device, &osk5912_smc91x_device, &osk5912_cf_device, &osk5912_mcbsp1_device, - &osk5912_kp_device, - &osk5912_lcd_device, }; static void __init osk_init_smc91x(void) @@ -276,18 +229,95 @@ static struct omap_uart_config osk_uart_config __initdata = { .enabled_uarts = (1 << 0), }; +#ifdef CONFIG_OMAP_OSK_MISTRAL static struct omap_lcd_config osk_lcd_config __initdata = { .ctrl_name = "internal", }; +#endif static struct omap_board_config_kernel osk_config[] = { { OMAP_TAG_USB, &osk_usb_config }, { OMAP_TAG_UART, &osk_uart_config }, +#ifdef CONFIG_OMAP_OSK_MISTRAL { OMAP_TAG_LCD, &osk_lcd_config }, +#endif }; #ifdef CONFIG_OMAP_OSK_MISTRAL +#include +#include +#include + +#include + +static const int osk_keymap[] = { + /* KEY(col, row, code) */ + KEY(0, 0, KEY_F1), /* SW4 */ + KEY(0, 3, KEY_UP), /* (sw2/up) */ + KEY(1, 1, KEY_LEFTCTRL), /* SW5 */ + KEY(1, 2, KEY_LEFT), /* (sw2/left) */ + KEY(2, 0, KEY_SPACE), /* SW3 */ + KEY(2, 1, KEY_ESC), /* SW6 */ + KEY(2, 2, KEY_DOWN), /* (sw2/down) */ + KEY(3, 2, KEY_ENTER), /* (sw2/select) */ + KEY(3, 3, KEY_RIGHT), /* (sw2/right) */ + 0 +}; + +static struct omap_kp_platform_data osk_kp_data = { + .rows = 8, + .cols = 8, + .keymap = (int *) osk_keymap, +}; + +static struct resource osk5912_kp_resources[] = { + [0] = { + .start = INT_KEYBOARD, + .end = INT_KEYBOARD, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device osk5912_kp_device = { + .name = "omap-keypad", + .id = -1, + .dev = { + .platform_data = &osk_kp_data, + }, + .num_resources = ARRAY_SIZE(osk5912_kp_resources), + .resource = osk5912_kp_resources, +}; + +static struct platform_device osk5912_lcd_device = { + .name = "lcd_osk", + .id = -1, +}; + +static struct platform_device *mistral_devices[] __initdata = { + &osk5912_kp_device, + &osk5912_lcd_device, +}; + +static const struct ads7846_platform_data mistral_ts_info = { + .model = 7846, + .vref_delay_usecs = 100, /* internal, no capacitor */ + .x_plate_ohms = 419, + .y_plate_ohms = 486, + // .{x,y,pressure}_{min,max} +}; + +static struct spi_board_info __initdata mistral_boardinfo[] = { { + /* MicroWire (bus 2) CS0 has an ads7846e */ + .modalias = "ads7846", + .platform_data = &mistral_ts_info, + .irq = OMAP_GPIO_IRQ(4), + .max_speed_hz = 120000 /* max sample rate at 3V */ + * 26 /* command + data + overhead */, + .bus_num = 2, + .chip_select = 0, +} }; + #ifdef CONFIG_PM static irqreturn_t osk_mistral_wake_interrupt(int irq, void *ignored, struct pt_regs *regs) @@ -298,14 +328,18 @@ osk_mistral_wake_interrupt(int irq, void *ignored, struct pt_regs *regs) static void __init osk_mistral_init(void) { - /* FIXME here's where to feed in framebuffer, touchpad, and - * keyboard setup ... not in the drivers for those devices! - * - * NOTE: we could actually tell if there's a Mistral board + /* NOTE: we could actually tell if there's a Mistral board * attached, e.g. by trying to read something from the ads7846. - * But this is too early for that... + * But this arch_init() code is too early for that, since we + * can't talk to the ads or even the i2c eeprom. */ + // omap_cfg_reg(P19_1610_GPIO6); // BUSY + omap_cfg_reg(P20_1610_GPIO4); // PENIRQ + set_irq_type(OMAP_GPIO_IRQ(4), IRQT_FALLING); + spi_register_board_info(mistral_boardinfo, + ARRAY_SIZE(mistral_boardinfo)); + /* the sideways button (SW1) is for use as a "wakeup" button */ omap_cfg_reg(N15_1610_MPUIO2); if (omap_request_gpio(OMAP_MPUIO(2)) == 0) { @@ -329,6 +363,8 @@ static void __init osk_mistral_init(void) #endif } else printk(KERN_ERR "OSK+Mistral: wakeup button is awol\n"); + + platform_add_devices(mistral_devices, ARRAY_SIZE(mistral_devices)); } #else static void __init osk_mistral_init(void) { } -- cgit v1.2.3 From ea6dedd7fbd0f760ebf37eb0bcc8c64856475a13 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 26 Jun 2006 16:16:00 -0700 Subject: ARM: OMAP: GPIO IRQ lazy IRQ disable fix - The current OMAP GPIO IRQ framework doesn't use the do_edge_IRQ, do_level_IRQ handlers, but instead calls do_simple_IRQ. This doesn't handle disabled interrupts properly, so drivers will still get interrupts after calling disable_irq. The patch solves this by respecting the irq_desc.disable_depth and irq_desc.running counters. When one of these is non-zero the handler is not called, the interrupt is masked and marked as pending. The pending interrupt will be serviced when the running handler returns. This is according to the same semantics as the standard do_edge_IRQ and do_level_IRQ handlers have, so one day we should use them instead of do_simple_IRQ. - Process only interrupts that are not masked. The ISR may contain pending interrupts that are masked these shouldn't be processed. - Move the bank IRQ unmasking out of the IRQ dispatch loop. If there are further iterations we shouldn't unmask it if there are level triggered interrupts pending. Signed-off-by: Imre Deak Signed-off-by: Juha Yrjola Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/gpio.c | 88 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 79 insertions(+), 9 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index d3c8ea7eecf..cd1e508f90c 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c @@ -537,6 +537,34 @@ static inline void _clear_gpio_irqstatus(struct gpio_bank *bank, int gpio) _clear_gpio_irqbank(bank, 1 << get_gpio_index(gpio)); } +static u32 _get_gpio_irqbank_mask(struct gpio_bank *bank) +{ + void __iomem *reg = bank->base; + + switch (bank->method) { + case METHOD_MPUIO: + reg += OMAP_MPUIO_GPIO_MASKIT; + break; + case METHOD_GPIO_1510: + reg += OMAP1510_GPIO_INT_MASK; + break; + case METHOD_GPIO_1610: + reg += OMAP1610_GPIO_IRQENABLE1; + break; + case METHOD_GPIO_730: + reg += OMAP730_GPIO_INT_MASK; + break; + case METHOD_GPIO_24XX: + reg += OMAP24XX_GPIO_IRQENABLE1; + break; + default: + BUG(); + return 0; + } + + return __raw_readl(reg); +} + static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enable) { void __iomem *reg = bank->base; @@ -736,6 +764,8 @@ static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc, u32 isr; unsigned int gpio_irq; struct gpio_bank *bank; + u32 retrigger = 0; + int unmasked = 0; desc->chip->ack(irq); @@ -760,18 +790,22 @@ static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc, #endif while(1) { u32 isr_saved, level_mask = 0; + u32 enabled; - isr_saved = isr = __raw_readl(isr_reg); + enabled = _get_gpio_irqbank_mask(bank); + isr_saved = isr = __raw_readl(isr_reg) & enabled; if (cpu_is_omap15xx() && (bank->method == METHOD_MPUIO)) isr &= 0x0000ffff; - if (cpu_is_omap24xx()) + if (cpu_is_omap24xx()) { level_mask = __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0) | __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1); + level_mask &= enabled; + } /* clear edge sensitive interrupts before handler(s) are called so that we don't miss any interrupt occurred while @@ -782,19 +816,54 @@ static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc, /* if there is only edge sensitive GPIO pin interrupts configured, we could unmask GPIO bank interrupt immediately */ - if (!level_mask) + if (!level_mask && !unmasked) { + unmasked = 1; desc->chip->unmask(irq); + } + isr |= retrigger; + retrigger = 0; if (!isr) break; gpio_irq = bank->virtual_irq_start; for (; isr != 0; isr >>= 1, gpio_irq++) { struct irqdesc *d; + int irq_mask; if (!(isr & 1)) continue; d = irq_desc + gpio_irq; + /* Don't run the handler if it's already running + * or was disabled lazely. + */ + if (unlikely((d->disable_depth || d->running))) { + irq_mask = 1 << + (gpio_irq - bank->virtual_irq_start); + /* The unmasking will be done by + * enable_irq in case it is disabled or + * after returning from the handler if + * it's already running. + */ + _enable_gpio_irqbank(bank, irq_mask, 0); + if (!d->disable_depth) { + /* Level triggered interrupts + * won't ever be reentered + */ + BUG_ON(level_mask & irq_mask); + d->pending = 1; + } + continue; + } + d->running = 1; desc_handle_irq(gpio_irq, d, regs); + d->running = 0; + if (unlikely(d->pending && !d->disable_depth)) { + irq_mask = 1 << + (gpio_irq - bank->virtual_irq_start); + d->pending = 0; + _enable_gpio_irqbank(bank, irq_mask, 1); + retrigger |= irq_mask; + } } if (cpu_is_omap24xx()) { @@ -804,13 +873,14 @@ static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc, _enable_gpio_irqbank(bank, isr_saved & level_mask, 1); } - /* if bank has any level sensitive GPIO pin interrupt - configured, we must unmask the bank interrupt only after - handler(s) are executed in order to avoid spurious bank - interrupt */ - if (level_mask) - desc->chip->unmask(irq); } + /* if bank has any level sensitive GPIO pin interrupt + configured, we must unmask the bank interrupt only after + handler(s) are executed in order to avoid spurious bank + interrupt */ + if (!unmasked) + desc->chip->unmask(irq); + } static void gpio_ack_irq(unsigned int irq) -- cgit v1.2.3 From 0711615290510bfba11c3f4eabcde6ac92c0766e Mon Sep 17 00:00:00 2001 From: Jonathan McDowell Date: Mon, 26 Jun 2006 16:16:01 -0700 Subject: ARM: OMAP: Readd Amstrad Delta USB support One of the recent merges from mainline removed the Amstrad Delta USB support. This patch adds it back in; it's the same as was in 2.6.16-omap2. Signed-off-by: Jonathan McDowell Signed-off-by: Tony Lindgren --- arch/arm/mach-omap1/board-ams-delta.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap1/board-ams-delta.c b/arch/arm/mach-omap1/board-ams-delta.c index 73df32aac4c..8437d065ada 100644 --- a/arch/arm/mach-omap1/board-ams-delta.c +++ b/arch/arm/mach-omap1/board-ams-delta.c @@ -80,8 +80,15 @@ static struct omap_uart_config ams_delta_uart_config __initdata = { .enabled_uarts = 1, }; +static struct omap_usb_config ams_delta_usb_config __initdata = { + .register_host = 1, + .hmc_mode = 16, + .pins[0] = 2, +}; + static struct omap_board_config_kernel ams_delta_config[] = { { OMAP_TAG_UART, &ams_delta_uart_config }, + { OMAP_TAG_USB, &ams_delta_usb_config }, }; static struct platform_device ams_delta_led_device = { -- cgit v1.2.3 From ffb7a80f932550590ef54791b60db7e6ffce63f3 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 26 Jun 2006 16:16:02 -0700 Subject: ARM: OMAP: Fix gpt2_ick clock bit CM_ICLKEN1_CORE bit should be 4, not 0 as noted by Richard Woodruff. Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/clock.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index 6c78d471fab..2781dfbc516 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -1062,7 +1062,7 @@ static struct clk gpt2_ick = { .parent = &l4_ck, .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, /* Bit4 */ - .enable_bit = 0, + .enable_bit = 4, .recalc = &omap2_followparent_recalc, }; -- cgit v1.2.3 From 495f71db30e279a5a696fa6622fc75451caa8366 Mon Sep 17 00:00:00 2001 From: Brian Swetland Date: Mon, 26 Jun 2006 16:16:03 -0700 Subject: ARM: OMAP: Add core fsample support This patch adds core support for the TI F-Sample Board (OMAP 850). Signed-off-by: Brian Swetland Signed-off-by: Tony Lindgren --- arch/arm/mach-omap1/Kconfig | 7 + arch/arm/mach-omap1/Makefile | 1 + arch/arm/mach-omap1/board-fsample.c | 319 ++++++++++++++++++++++++++++++++++++ arch/arm/mach-omap1/clock.c | 18 +- arch/arm/mach-omap1/pm.c | 7 +- arch/arm/mach-omap1/time.c | 2 +- arch/arm/plat-omap/devices.c | 2 +- 7 files changed, 348 insertions(+), 8 deletions(-) create mode 100644 arch/arm/mach-omap1/board-fsample.c (limited to 'arch/arm') diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig index f8d716ccc1d..d135568dc9e 100644 --- a/arch/arm/mach-omap1/Kconfig +++ b/arch/arm/mach-omap1/Kconfig @@ -62,6 +62,13 @@ config MACH_OMAP_PERSEUS2 Support for TI OMAP 730 Perseus2 board. Say Y here if you have such a board. +config MACH_OMAP_FSAMPLE + bool "TI F-Sample" + depends on ARCH_OMAP1 && ARCH_OMAP730 + help + Support for TI OMAP 850 F-Sample board. Say Y here if you have such + a board. + config MACH_VOICEBLUE bool "Voiceblue" depends on ARCH_OMAP1 && ARCH_OMAP15XX diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile index 9ea719550ad..7165f74f78d 100644 --- a/arch/arm/mach-omap1/Makefile +++ b/arch/arm/mach-omap1/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_MACH_OMAP_H2) += board-h2.o obj-$(CONFIG_MACH_OMAP_INNOVATOR) += board-innovator.o obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o obj-$(CONFIG_MACH_OMAP_PERSEUS2) += board-perseus2.o +obj-$(CONFIG_MACH_OMAP_FSAMPLE) += board-fsample.o obj-$(CONFIG_MACH_OMAP_OSK) += board-osk.o obj-$(CONFIG_MACH_OMAP_H3) += board-h3.o obj-$(CONFIG_MACH_VOICEBLUE) += board-voiceblue.o diff --git a/arch/arm/mach-omap1/board-fsample.c b/arch/arm/mach-omap1/board-fsample.c new file mode 100644 index 00000000000..c753a3c5aad --- /dev/null +++ b/arch/arm/mach-omap1/board-fsample.c @@ -0,0 +1,319 @@ +/* + * linux/arch/arm/mach-omap1/board-fsample.c + * + * Modified from board-perseus2.c + * + * Original OMAP730 support by Jean Pihet + * Updated for 2.6 by Kevin Hilman + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +static int fsample_keymap[] = { + KEY(0,0,KEY_UP), + KEY(0,1,KEY_RIGHT), + KEY(0,2,KEY_LEFT), + KEY(0,3,KEY_DOWN), + KEY(0,4,KEY_CENTER), + KEY(0,5,KEY_0_5), + KEY(1,0,KEY_SOFT2), + KEY(1,1,KEY_SEND), + KEY(1,2,KEY_END), + KEY(1,3,KEY_VOLUMEDOWN), + KEY(1,4,KEY_VOLUMEUP), + KEY(1,5,KEY_RECORD), + KEY(2,0,KEY_SOFT1), + KEY(2,1,KEY_3), + KEY(2,2,KEY_6), + KEY(2,3,KEY_9), + KEY(2,4,KEY_SHARP), + KEY(2,5,KEY_2_5), + KEY(3,0,KEY_BACK), + KEY(3,1,KEY_2), + KEY(3,2,KEY_5), + KEY(3,3,KEY_8), + KEY(3,4,KEY_0), + KEY(3,5,KEY_HEADSETHOOK), + KEY(4,0,KEY_HOME), + KEY(4,1,KEY_1), + KEY(4,2,KEY_4), + KEY(4,3,KEY_7), + KEY(4,4,KEY_STAR), + KEY(4,5,KEY_POWER), + 0 +}; + +static struct resource smc91x_resources[] = { + [0] = { + .start = H2P2_DBG_FPGA_ETHR_START, /* Physical */ + .end = H2P2_DBG_FPGA_ETHR_START + 0xf, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = INT_730_MPU_EXT_NIRQ, + .end = 0, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct mtd_partition nor_partitions[] = { + /* bootloader (U-Boot, etc) in first sector */ + { + .name = "bootloader", + .offset = 0, + .size = SZ_128K, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + /* bootloader params in the next sector */ + { + .name = "params", + .offset = MTDPART_OFS_APPEND, + .size = SZ_128K, + .mask_flags = 0, + }, + /* kernel */ + { + .name = "kernel", + .offset = MTDPART_OFS_APPEND, + .size = SZ_2M, + .mask_flags = 0 + }, + /* rest of flash is a file system */ + { + .name = "rootfs", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + .mask_flags = 0 + }, +}; + +static struct flash_platform_data nor_data = { + .map_name = "cfi_probe", + .width = 2, + .parts = nor_partitions, + .nr_parts = ARRAY_SIZE(nor_partitions), +}; + +static struct resource nor_resource = { + .start = OMAP_CS0_PHYS, + .end = OMAP_CS0_PHYS + SZ_32M - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device nor_device = { + .name = "omapflash", + .id = 0, + .dev = { + .platform_data = &nor_data, + }, + .num_resources = 1, + .resource = &nor_resource, +}; + +static struct nand_platform_data nand_data = { + .options = NAND_SAMSUNG_LP_OPTIONS, +}; + +static struct resource nand_resource = { + .start = OMAP_CS3_PHYS, + .end = OMAP_CS3_PHYS + SZ_4K - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device nand_device = { + .name = "omapnand", + .id = 0, + .dev = { + .platform_data = &nand_data, + }, + .num_resources = 1, + .resource = &nand_resource, +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; + +static struct resource kp_resources[] = { + [0] = { + .start = INT_730_MPUIO_KEYPAD, + .end = INT_730_MPUIO_KEYPAD, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct omap_kp_platform_data kp_data = { + .rows = 8, + .cols = 8, + .keymap = fsample_keymap, +}; + +static struct platform_device kp_device = { + .name = "omap-keypad", + .id = -1, + .dev = { + .platform_data = &kp_data, + }, + .num_resources = ARRAY_SIZE(kp_resources), + .resource = kp_resources, +}; + +static struct platform_device lcd_device = { + .name = "lcd_p2", + .id = -1, +}; + +static struct platform_device *devices[] __initdata = { + &nor_device, + &nand_device, + &smc91x_device, + &kp_device, + &lcd_device, +}; + +#define P2_NAND_RB_GPIO_PIN 62 + +static int nand_dev_ready(struct nand_platform_data *data) +{ + return omap_get_gpio_datain(P2_NAND_RB_GPIO_PIN); +} + +static struct omap_uart_config fsample_uart_config __initdata = { + .enabled_uarts = ((1 << 0) | (1 << 1)), +}; + +static struct omap_lcd_config fsample_lcd_config __initdata = { + .ctrl_name = "internal", +}; + +static struct omap_board_config_kernel fsample_config[] = { + { OMAP_TAG_UART, &fsample_uart_config }, + { OMAP_TAG_LCD, &fsample_lcd_config }, +}; + +static void __init omap_fsample_init(void) +{ + if (!(omap_request_gpio(P2_NAND_RB_GPIO_PIN))) + nand_data.dev_ready = nand_dev_ready; + + omap_cfg_reg(L3_1610_FLASH_CS2B_OE); + omap_cfg_reg(M8_1610_FLASH_CS2B_WE); + + platform_add_devices(devices, ARRAY_SIZE(devices)); + + omap_board_config = fsample_config; + omap_board_config_size = ARRAY_SIZE(fsample_config); + omap_serial_init(); +} + +static void __init fsample_init_smc91x(void) +{ + fpga_write(1, H2P2_DBG_FPGA_LAN_RESET); + mdelay(50); + fpga_write(fpga_read(H2P2_DBG_FPGA_LAN_RESET) & ~1, + H2P2_DBG_FPGA_LAN_RESET); + mdelay(50); +} + +void omap_fsample_init_irq(void) +{ + omap1_init_common_hw(); + omap_init_irq(); + omap_gpio_init(); + fsample_init_smc91x(); +} + +/* Only FPGA needs to be mapped here. All others are done with ioremap */ +static struct map_desc omap_fsample_io_desc[] __initdata = { + { + .virtual = H2P2_DBG_FPGA_BASE, + .pfn = __phys_to_pfn(H2P2_DBG_FPGA_START), + .length = H2P2_DBG_FPGA_SIZE, + .type = MT_DEVICE + }, + { + .virtual = FSAMPLE_CPLD_BASE, + .pfn = __phys_to_pfn(FSAMPLE_CPLD_START), + .length = FSAMPLE_CPLD_SIZE, + .type = MT_DEVICE + } +}; + +static void __init omap_fsample_map_io(void) +{ + omap1_map_common_io(); + iotable_init(omap_fsample_io_desc, + ARRAY_SIZE(omap_fsample_io_desc)); + + /* Early, board-dependent init */ + + /* + * Hold GSM Reset until needed + */ + omap_writew(omap_readw(OMAP730_DSP_M_CTL) & ~1, OMAP730_DSP_M_CTL); + + /* + * UARTs -> done automagically by 8250 driver + */ + + /* + * CSx timings, GPIO Mux ... setup + */ + + /* Flash: CS0 timings setup */ + omap_writel(0x0000fff3, OMAP730_FLASH_CFG_0); + omap_writel(0x00000088, OMAP730_FLASH_ACFG_0); + + /* + * Ethernet support through the debug board + * CS1 timings setup + */ + omap_writel(0x0000fff3, OMAP730_FLASH_CFG_1); + omap_writel(0x00000000, OMAP730_FLASH_ACFG_1); + + /* + * Configure MPU_EXT_NIRQ IO in IO_CONF9 register, + * It is used as the Ethernet controller interrupt + */ + omap_writel(omap_readl(OMAP730_IO_CONF_9) & 0x1FFFFFFF, OMAP730_IO_CONF_9); +} + +MACHINE_START(OMAP_FSAMPLE, "OMAP730 F-Sample") +/* Maintainer: Brian Swetland */ + .phys_io = 0xfff00000, + .io_pg_offst = ((0xfef00000) >> 18) & 0xfffc, + .boot_params = 0x10000100, + .map_io = omap_fsample_map_io, + .init_irq = omap_fsample_init_irq, + .init_machine = omap_fsample_init, + .timer = &omap_timer, +MACHINE_END diff --git a/arch/arm/mach-omap1/clock.c b/arch/arm/mach-omap1/clock.c index 619db18144e..f1958e882e8 100644 --- a/arch/arm/mach-omap1/clock.c +++ b/arch/arm/mach-omap1/clock.c @@ -1,3 +1,4 @@ +//kernel/linux-omap-fsample/arch/arm/mach-omap1/clock.c#2 - edit change 3808 (text) /* * linux/arch/arm/mach-omap1/clock.c * @@ -20,6 +21,7 @@ #include +#include #include #include #include @@ -270,8 +272,12 @@ static int omap1_select_table_rate(struct clk * clk, unsigned long rate) /* * In most cases we should not need to reprogram DPLL. * Reprogramming the DPLL is tricky, it must be done from SRAM. + * (on 730, bit 13 must always be 1) */ - omap_sram_reprogram_clock(ptr->dpllctl_val, ptr->ckctl_val); + if (cpu_is_omap730()) + omap_sram_reprogram_clock(ptr->dpllctl_val, ptr->ckctl_val | 0x2000); + else + omap_sram_reprogram_clock(ptr->dpllctl_val, ptr->ckctl_val); ck_dpll1.rate = ptr->pll_rate; propagate_rate(&ck_dpll1); @@ -748,7 +754,7 @@ int __init omap1_clk_init(void) printk(KERN_ERR "System frequencies not set. Check your config.\n"); /* Guess sane values (60MHz) */ omap_writew(0x2290, DPLL_CTL); - omap_writew(0x1005, ARM_CKCTL); + omap_writew(cpu_is_omap730() ? 0x3005 : 0x1005, ARM_CKCTL); ck_dpll1.rate = 60000000; propagate_rate(&ck_dpll1); } @@ -761,13 +767,17 @@ int __init omap1_clk_init(void) ck_dpll1.rate / 1000000, (ck_dpll1.rate / 100000) % 10, arm_ck.rate / 1000000, (arm_ck.rate / 100000) % 10); -#ifdef CONFIG_MACH_OMAP_PERSEUS2 +#if defined(CONFIG_MACH_OMAP_PERSEUS2) || defined(CONFIG_MACH_OMAP_FSAMPLE) /* Select slicer output as OMAP input clock */ omap_writew(omap_readw(OMAP730_PCC_UPLD_CTRL) & ~0x1, OMAP730_PCC_UPLD_CTRL); #endif /* Turn off DSP and ARM_TIMXO. Make sure ARM_INTHCK is not divided */ - omap_writew(omap_readw(ARM_CKCTL) & 0x0fff, ARM_CKCTL); + /* (on 730, bit 13 must not be cleared) */ + if (cpu_is_omap730()) + omap_writew(omap_readw(ARM_CKCTL) & 0x2fff, ARM_CKCTL); + else + omap_writew(omap_readw(ARM_CKCTL) & 0x0fff, ARM_CKCTL); /* Put DSP/MPUI into reset until needed */ omap_writew(0, ARM_RSTCT1); diff --git a/arch/arm/mach-omap1/pm.c b/arch/arm/mach-omap1/pm.c index ddf6b07dc9c..1b4e1d57afb 100644 --- a/arch/arm/mach-omap1/pm.c +++ b/arch/arm/mach-omap1/pm.c @@ -1,3 +1,4 @@ +//kernel/linux-omap-fsample/arch/arm/mach-omap1/pm.c#3 - integrate change 4545 (text) /* * linux/arch/arm/mach-omap1/pm.c * @@ -50,6 +51,7 @@ #include #include +#include #include #include #include @@ -326,8 +328,9 @@ void omap_pm_suspend(void) /* stop DSP */ omap_writew(omap_readw(ARM_RSTCT1) & ~(1 << DSP_EN), ARM_RSTCT1); - /* shut down dsp_ck */ - omap_writew(omap_readw(ARM_CKCTL) & ~(1 << EN_DSPCK), ARM_CKCTL); + /* shut down dsp_ck */ + if (!cpu_is_omap730()) + omap_writew(omap_readw(ARM_CKCTL) & ~(1 << EN_DSPCK), ARM_CKCTL); /* temporarily enabling api_ck to access DSP registers */ omap_writew(omap_readw(ARM_IDLECT2) | 1 << EN_APICK, ARM_IDLECT2); diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c index a85fe6066bc..64c2d69c615 100644 --- a/arch/arm/mach-omap1/time.c +++ b/arch/arm/mach-omap1/time.c @@ -94,7 +94,7 @@ static inline unsigned long long cycles_2_ns(unsigned long long cyc) * will break. On P2, the timer count rate is 6.5 MHz after programming PTV * with 0. This divides the 13MHz input by 2, and is undocumented. */ -#ifdef CONFIG_MACH_OMAP_PERSEUS2 +#if defined(CONFIG_MACH_OMAP_PERSEUS2) || defined(CONFIG_MACH_OMAP_FSAMPLE) /* REVISIT: This ifdef construct should be replaced by a query to clock * framework to see if timer base frequency is 12.0, 13.0 or 19.2 MHz. */ diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c index 5d5d6eb222d..ee15b408912 100644 --- a/arch/arm/plat-omap/devices.c +++ b/arch/arm/plat-omap/devices.c @@ -105,7 +105,7 @@ static void omap_init_kp(void) omap_cfg_reg(E20_1610_KBR3); omap_cfg_reg(E19_1610_KBR4); omap_cfg_reg(N19_1610_KBR5); - } else if (machine_is_omap_perseus2()) { + } else if (machine_is_omap_perseus2() || machine_is_omap_fsample()) { omap_cfg_reg(E2_730_KBR0); omap_cfg_reg(J7_730_KBR1); omap_cfg_reg(E1_730_KBR2); -- cgit v1.2.3 From e8cdf7bdf3efbb1e285fd82a86a3f8fae5ae2665 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 26 Jun 2006 16:16:04 -0700 Subject: ARM: OMAP: Mistral ads7846 pendown state Syncing the ads7846 code with mainstream means that the Mistral support needs to include a callback to read the pendown state. Signed-off-by: David Brownell Signed-off-by: Tony Lindgren --- arch/arm/mach-omap1/board-osk.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c index 8f8f50b7058..e0711d23a6b 100644 --- a/arch/arm/mach-omap1/board-osk.c +++ b/arch/arm/mach-omap1/board-osk.c @@ -299,12 +299,17 @@ static struct platform_device *mistral_devices[] __initdata = { &osk5912_lcd_device, }; +static int mistral_get_pendown_state(void) +{ + return !omap_get_gpio_datain(4); +} + static const struct ads7846_platform_data mistral_ts_info = { .model = 7846, .vref_delay_usecs = 100, /* internal, no capacitor */ .x_plate_ohms = 419, .y_plate_ohms = 486, - // .{x,y,pressure}_{min,max} + .get_pendown_state = mistral_get_pendown_state, }; static struct spi_board_info __initdata mistral_boardinfo[] = { { -- cgit v1.2.3 From eca9e56eb8dfcf2b8b966c1c49e4622196f0586d Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 26 Jun 2006 16:16:06 -0700 Subject: ARM: OMAP: DMA transfer parameter configuration fix Fix for re-using OMAP DMA channel with different transfer parameters. Bits in the CCR register need to be cleaned as well in some cases. Signed-off-by: Peter Ujfalusi Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/dma.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'arch/arm') diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c index 5dac4230360..aa1cf79f954 100644 --- a/arch/arm/plat-omap/dma.c +++ b/arch/arm/plat-omap/dma.c @@ -166,18 +166,24 @@ void omap_set_dma_transfer_params(int lch, int data_type, int elem_count, if (cpu_is_omap24xx() && dma_trigger) { u32 val = OMAP_DMA_CCR_REG(lch); + val &= ~(3 << 19); if (dma_trigger > 63) val |= 1 << 20; if (dma_trigger > 31) val |= 1 << 19; + val &= ~(0x1f); val |= (dma_trigger & 0x1f); if (sync_mode & OMAP_DMA_SYNC_FRAME) val |= 1 << 5; + else + val &= ~(1 << 5); if (sync_mode & OMAP_DMA_SYNC_BLOCK) val |= 1 << 18; + else + val &= ~(1 << 18); if (src_or_dst_synch) val |= 1 << 24; /* source synch */ -- cgit v1.2.3 From 99c477074de4a91a388aff863646dc3e2eb783e2 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 26 Jun 2006 16:16:07 -0700 Subject: ARM: OMAP: Fix GPIO IRQ mask handling The GPIO IRQ mask was retrieved incorrectly in cases where we have a mask register instead of an enable register. Also we should only return the valid bits depending on the bank size. This fixes a bug on 1510/1610 based OMAPs where GPIO IRQs are not delivered. Signed-off-by: Imre Deak Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/gpio.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'arch/arm') diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index cd1e508f90c..e75a2ca70ba 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c @@ -540,29 +540,44 @@ static inline void _clear_gpio_irqstatus(struct gpio_bank *bank, int gpio) static u32 _get_gpio_irqbank_mask(struct gpio_bank *bank) { void __iomem *reg = bank->base; + int inv = 0; + u32 l; + u32 mask; switch (bank->method) { case METHOD_MPUIO: reg += OMAP_MPUIO_GPIO_MASKIT; + mask = 0xffff; + inv = 1; break; case METHOD_GPIO_1510: reg += OMAP1510_GPIO_INT_MASK; + mask = 0xffff; + inv = 1; break; case METHOD_GPIO_1610: reg += OMAP1610_GPIO_IRQENABLE1; + mask = 0xffff; break; case METHOD_GPIO_730: reg += OMAP730_GPIO_INT_MASK; + mask = 0xffffffff; + inv = 1; break; case METHOD_GPIO_24XX: reg += OMAP24XX_GPIO_IRQENABLE1; + mask = 0xffffffff; break; default: BUG(); return 0; } - return __raw_readl(reg); + l = __raw_readl(reg); + if (inv) + l = ~l; + l &= mask; + return l; } static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enable) -- cgit v1.2.3 From 284185c73d3156f4438d5599ae69793b44d825ab Mon Sep 17 00:00:00 2001 From: lamikr Date: Mon, 26 Jun 2006 16:16:08 -0700 Subject: ARM: OMAP: Aic23 alsa platform driver code for board-innovator Add platform driver init-code required by the aic23-alsa driver to omap-innovator. Signed-off-by: Mika Laitio Signed-off-by: Tony Lindgren --- arch/arm/mach-omap1/board-innovator.c | 39 +++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c index e90c137a4cf..43260aa20f8 100644 --- a/arch/arm/mach-omap1/board-innovator.c +++ b/arch/arm/mach-omap1/board-innovator.c @@ -37,6 +37,8 @@ #include #include #include +#include +#include static int innovator_keymap[] = { KEY(0, 0, KEY_F1), @@ -112,6 +114,42 @@ static struct platform_device innovator_flash_device = { .resource = &innovator_flash_resource, }; +#define DEFAULT_BITPERSAMPLE 16 + +static struct omap_mcbsp_reg_cfg mcbsp_regs = { + .spcr2 = FREE | FRST | GRST | XRST | XINTM(3), + .spcr1 = RINTM(3) | RRST, + .rcr2 = RPHASE | RFRLEN2(OMAP_MCBSP_WORD_8) | + RWDLEN2(OMAP_MCBSP_WORD_16) | RDATDLY(0), + .rcr1 = RFRLEN1(OMAP_MCBSP_WORD_8) | RWDLEN1(OMAP_MCBSP_WORD_16), + .xcr2 = XPHASE | XFRLEN2(OMAP_MCBSP_WORD_8) | + XWDLEN2(OMAP_MCBSP_WORD_16) | XDATDLY(0) | XFIG, + .xcr1 = XFRLEN1(OMAP_MCBSP_WORD_8) | XWDLEN1(OMAP_MCBSP_WORD_16), + .srgr1 = FWID(DEFAULT_BITPERSAMPLE - 1), + .srgr2 = GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1), + /*.pcr0 = FSXM | FSRM | CLKXM | CLKRM | CLKXP | CLKRP,*/ /* mcbsp: master */ + .pcr0 = CLKXP | CLKRP, /* mcbsp: slave */ +}; + +static struct omap_alsa_codec_config alsa_config = { + .name = "OMAP Innovator AIC23", + .mcbsp_regs_alsa = &mcbsp_regs, + .codec_configure_dev = NULL, // aic23_configure, + .codec_set_samplerate = NULL, // aic23_set_samplerate, + .codec_clock_setup = NULL, // aic23_clock_setup, + .codec_clock_on = NULL, // aic23_clock_on, + .codec_clock_off = NULL, // aic23_clock_off, + .get_default_samplerate = NULL, // aic23_get_default_samplerate, +}; + +static struct platform_device innovator_mcbsp1_device = { + .name = "omap_alsa_mcbsp", + .id = 1, + .dev = { + .platform_data = &alsa_config, + }, +}; + static struct resource innovator_kp_resources[] = { [0] = { .start = INT_KEYBOARD, @@ -177,6 +215,7 @@ static struct platform_device innovator1510_lcd_device = { static struct platform_device *innovator1510_devices[] __initdata = { &innovator_flash_device, &innovator1510_smc91x_device, + &innovator_mcbsp1_device, &innovator_kp_device, &innovator1510_lcd_device, }; -- cgit v1.2.3 From c15e5d10b160ca0fe71f5865c771bf4ad0e7ed85 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 26 Jun 2006 16:16:09 -0700 Subject: ARM: OMAP: Add bitbank SPI driver for Innovator 1510 touchscreen Add bitbang SPI driver for Innovator 1510 touchscreen, using the new framework. Compile-tested only. Signed-off-by: David Brownell Signed-off-by: Tony Lindgren --- arch/arm/mach-omap1/board-innovator.c | 36 +++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c index 43260aa20f8..4cbc62db5b5 100644 --- a/arch/arm/mach-omap1/board-innovator.c +++ b/arch/arm/mach-omap1/board-innovator.c @@ -177,6 +177,10 @@ static struct platform_device innovator_kp_device = { #ifdef CONFIG_ARCH_OMAP15XX +#include +#include + + /* Only FPGA needs to be mapped here. All others are done with ioremap */ static struct map_desc innovator1510_io_desc[] __initdata = { { @@ -212,14 +216,44 @@ static struct platform_device innovator1510_lcd_device = { .id = -1, }; +static struct platform_device innovator1510_spi_device = { + .name = "spi_inn1510", + .id = -1, +}; + static struct platform_device *innovator1510_devices[] __initdata = { &innovator_flash_device, &innovator1510_smc91x_device, &innovator_mcbsp1_device, &innovator_kp_device, &innovator1510_lcd_device, + &innovator1510_spi_device, }; +static int innovator_get_pendown_state(void) +{ + return !(fpga_read(OMAP1510_FPGA_TOUCHSCREEN) & (1 << 5)); +} + +static const struct ads7846_platform_data innovator1510_ts_info = { + .model = 7846, + .vref_delay_usecs = 100, /* internal, no capacitor */ + .x_plate_ohms = 419, + .y_plate_ohms = 486, + .get_pendown_state = innovator_get_pendown_state, +}; + +static struct spi_board_info __initdata innovator1510_boardinfo[] = { { + /* FPGA (bus "10") CS0 has an ads7846e */ + .modalias = "ads7846", + .platform_data = &innovator1510_ts_info, + .irq = OMAP1510_INT_FPGA_TS, + .max_speed_hz = 120000 /* max sample rate at 3V */ + * 26 /* command + data + overhead */, + .bus_num = 10, + .chip_select = 0, +} }; + #endif /* CONFIG_ARCH_OMAP15XX */ #ifdef CONFIG_ARCH_OMAP16XX @@ -350,6 +384,8 @@ static void __init innovator_init(void) #ifdef CONFIG_ARCH_OMAP15XX if (cpu_is_omap1510()) { platform_add_devices(innovator1510_devices, ARRAY_SIZE(innovator1510_devices)); + spi_register_board_info(innovator1510_boardinfo, + ARRAY_SIZE(innovator1510_boardinfo)); } #endif #ifdef CONFIG_ARCH_OMAP16XX -- cgit v1.2.3 From ed7eb9d90a24bbe93fa47e19b61528bd5cfe584c Mon Sep 17 00:00:00 2001 From: Juha Yrjola Date: Mon, 26 Jun 2006 16:16:10 -0700 Subject: ARM: OMAP: Register the 24xx McSPI device Register the 24xx McSPI device as an OMAP2 platform device. The driver module and Kconfig option were merged already some time ago. Signed-off-by: Juha Yrjola Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/devices.c | 46 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index fb7f91da1aa..5139677e426 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c @@ -105,6 +105,51 @@ static inline void omap_init_sti(void) static inline void omap_init_sti(void) {} #endif +#if defined(CONFIG_SPI_OMAP24XX) + +#include + +#define OMAP2_MCSPI1_BASE 0x48098000 +#define OMAP2_MCSPI2_BASE 0x4809a000 + +/* FIXME: use resources instead */ + +static struct omap2_mcspi_platform_config omap2_mcspi1_config = { + .base = io_p2v(OMAP2_MCSPI1_BASE), + .num_cs = 4, +}; + +struct platform_device omap2_mcspi1 = { + .name = "omap2_mcspi", + .id = 1, + .dev = { + .platform_data = &omap2_mcspi1_config, + }, +}; + +static struct omap2_mcspi_platform_config omap2_mcspi2_config = { + .base = io_p2v(OMAP2_MCSPI2_BASE), + .num_cs = 2, +}; + +struct platform_device omap2_mcspi2 = { + .name = "omap2_mcspi", + .id = 2, + .dev = { + .platform_data = &omap2_mcspi2_config, + }, +}; + +static void omap_init_mcspi(void) +{ + platform_device_register(&omap2_mcspi1); + platform_device_register(&omap2_mcspi2); +} + +#else +static inline void omap_init_mcspi(void) {} +#endif + /*-------------------------------------------------------------------------*/ static int __init omap2_init_devices(void) @@ -113,6 +158,7 @@ static int __init omap2_init_devices(void) * in alphabetical order so they're easier to sort through. */ omap_init_i2c(); + omap_init_mcspi(); omap_init_sti(); return 0; -- cgit v1.2.3 From 6e711ec6d249c0d3f8bc225066738d064ed90032 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 26 Jun 2006 16:16:11 -0700 Subject: ARM: OMAP: Correct two bugs in arch/arm/mach-omap2/clock.c omap2_clk_set_rate: dif_off must use clk->rate_offset, not clk->src_off. omap2_get_src_field: for the case CM_SYSCLKOUT_SEL1, val must be 2 for 96MHz and 3 for 54MHz. Signed-off-by: Jarkko Nikula Signed-off-by: Juha Yrjola Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/clock.c | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index 72eb4bf571a..242d8f925e9 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -660,26 +660,35 @@ static int omap2_clk_set_rate(struct clk *clk, unsigned long rate) /* Isolate control register */ div_sel = (SRC_RATE_SEL_MASK & clk->flags); - div_off = clk->src_offset; + div_off = clk->rate_offset; validrate = omap2_clksel_round_rate(clk, rate, &new_div); - if(validrate != rate) + if (validrate != rate) return(ret); field_val = omap2_get_clksel(&div_sel, &field_mask, clk); if (div_sel == 0) return ret; - if(clk->flags & CM_SYSCLKOUT_SEL1){ - switch(new_div){ - case 16: field_val = 4; break; - case 8: field_val = 3; break; - case 4: field_val = 2; break; - case 2: field_val = 1; break; - case 1: field_val = 0; break; + if (clk->flags & CM_SYSCLKOUT_SEL1) { + switch (new_div) { + case 16: + field_val = 4; + break; + case 8: + field_val = 3; + break; + case 4: + field_val = 2; + break; + case 2: + field_val = 1; + break; + case 1: + field_val = 0; + break; } - } - else + } else field_val = new_div; reg = (void __iomem *)div_sel; @@ -784,9 +793,9 @@ static u32 omap2_get_src_field(u32 *type_to_addr, u32 reg_offset, val = 0; if (src_clk == &sys_ck) val = 1; - if (src_clk == &func_54m_ck) - val = 2; if (src_clk == &func_96m_ck) + val = 2; + if (src_clk == &func_54m_ck) val = 3; break; } -- cgit v1.2.3 From 77900a2fc3bfb1eb6eaa6d43eef4591e1f7c600d Mon Sep 17 00:00:00 2001 From: Timo Teras Date: Mon, 26 Jun 2006 16:16:12 -0700 Subject: ARM: OMAP: Port dmtimers to OMAP2 and implement PWM support Port dmtimer framework to OMAP2. Modify the dmtimers API to support setting of PWM configuration and prescaler. Convert 32 kHz timer and GP timer to use the dmtimer framework. Signed-off-by: Timo Teras Signed-off-by: Juha Yrjola Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/Kconfig | 1 + arch/arm/mach-omap2/timer-gp.c | 86 ++------- arch/arm/plat-omap/Kconfig | 2 +- arch/arm/plat-omap/dmtimer.c | 413 +++++++++++++++++++++++++++++------------ arch/arm/plat-omap/timer32k.c | 121 ++++++------ 5 files changed, 367 insertions(+), 256 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 537dd2e6d38..aab97ccf1e6 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -8,6 +8,7 @@ config ARCH_OMAP24XX config ARCH_OMAP2420 bool "OMAP2420 support" depends on ARCH_OMAP24XX + select OMAP_DM_TIMER comment "OMAP Board Type" depends on ARCH_OMAP2 diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c index 1d2f5ac2f69..3358c0d47b1 100644 --- a/arch/arm/mach-omap2/timer-gp.c +++ b/arch/arm/mach-omap2/timer-gp.c @@ -6,6 +6,7 @@ * Copyright (C) 2005 Nokia Corporation * Author: Paul Mundt * Juha Yrjölä + * OMAP Dual-mode timer framework support by Timo Teras * * Some parts based off of TI's 24xx code: * @@ -22,54 +23,18 @@ #include #include #include +#include #include -#include -#include +#include -#define OMAP2_GP_TIMER1_BASE 0x48028000 -#define OMAP2_GP_TIMER2_BASE 0x4802a000 -#define OMAP2_GP_TIMER3_BASE 0x48078000 -#define OMAP2_GP_TIMER4_BASE 0x4807a000 +static struct omap_dm_timer *gptimer; -#define GP_TIMER_TIDR 0x00 -#define GP_TIMER_TISR 0x18 -#define GP_TIMER_TIER 0x1c -#define GP_TIMER_TCLR 0x24 -#define GP_TIMER_TCRR 0x28 -#define GP_TIMER_TLDR 0x2c -#define GP_TIMER_TSICR 0x40 - -#define OS_TIMER_NR 1 /* GP timer 2 */ - -static unsigned long timer_base[] = { - IO_ADDRESS(OMAP2_GP_TIMER1_BASE), - IO_ADDRESS(OMAP2_GP_TIMER2_BASE), - IO_ADDRESS(OMAP2_GP_TIMER3_BASE), - IO_ADDRESS(OMAP2_GP_TIMER4_BASE), -}; - -static inline unsigned int timer_read_reg(int nr, unsigned int reg) -{ - return __raw_readl(timer_base[nr] + reg); -} - -static inline void timer_write_reg(int nr, unsigned int reg, unsigned int val) -{ - __raw_writel(val, timer_base[nr] + reg); -} - -/* Note that we always enable the clock prescale divider bit */ -static inline void omap2_gp_timer_start(int nr, unsigned long load_val) +static inline void omap2_gp_timer_start(unsigned long load_val) { - unsigned int tmp; - - tmp = 0xffffffff - load_val; - - timer_write_reg(nr, GP_TIMER_TLDR, tmp); - timer_write_reg(nr, GP_TIMER_TCRR, tmp); - timer_write_reg(nr, GP_TIMER_TIER, 1 << 1); - timer_write_reg(nr, GP_TIMER_TCLR, (1 << 5) | (1 << 1) | 1); + omap_dm_timer_set_load(gptimer, 1, 0xffffffff - load_val); + omap_dm_timer_set_int_enable(gptimer, OMAP_TIMER_INT_OVERFLOW); + omap_dm_timer_start(gptimer); } static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id, @@ -77,7 +42,7 @@ static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id, { write_seqlock(&xtime_lock); - timer_write_reg(OS_TIMER_NR, GP_TIMER_TISR, 1 << 1); + omap_dm_timer_write_status(gptimer, OMAP_TIMER_INT_OVERFLOW); timer_tick(regs); write_sequnlock(&xtime_lock); @@ -87,41 +52,26 @@ static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id, static struct irqaction omap2_gp_timer_irq = { .name = "gp timer", - .flags = SA_INTERRUPT, + .flags = SA_INTERRUPT | SA_TIMER, .handler = omap2_gp_timer_interrupt, }; static void __init omap2_gp_timer_init(void) { - struct clk * sys_ck; - u32 tick_period = 120000; - u32 l; + u32 tick_period; - /* Reset clock and prescale value */ - timer_write_reg(OS_TIMER_NR, GP_TIMER_TCLR, 0); + omap_dm_timer_init(); + gptimer = omap_dm_timer_request_specific(2); + BUG_ON(gptimer == NULL); - sys_ck = clk_get(NULL, "sys_ck"); - if (IS_ERR(sys_ck)) - printk(KERN_ERR "Could not get sys_ck\n"); - else { - clk_enable(sys_ck); - tick_period = clk_get_rate(sys_ck) / 100; - clk_put(sys_ck); - } - - tick_period /= 2; /* Minimum prescale divider is 2 */ + omap_dm_timer_set_source(gptimer, OMAP_TIMER_SRC_SYS_CLK); + tick_period = clk_get_rate(omap_dm_timer_get_fclk(gptimer)) / 100; tick_period -= 1; - l = timer_read_reg(OS_TIMER_NR, GP_TIMER_TIDR); - printk(KERN_INFO "OMAP2 GP timer (HW version %d.%d)\n", - (l >> 4) & 0x0f, l & 0x0f); - - setup_irq(38, &omap2_gp_timer_irq); - - omap2_gp_timer_start(OS_TIMER_NR, tick_period); + setup_irq(omap_dm_timer_get_irq(gptimer), &omap2_gp_timer_irq); + omap2_gp_timer_start(tick_period); } struct sys_timer omap_timer = { .init = omap2_gp_timer_init, }; - diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index ec49495e651..ec752e16d61 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -91,7 +91,7 @@ config OMAP_32K_TIMER_HZ config OMAP_DM_TIMER bool "Use dual-mode timer" - depends on ARCH_OMAP16XX + depends on ARCH_OMAP16XX || ARCH_OMAP24XX help Select this option if you want to use OMAP Dual-Mode timers. diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index eba3cb52ad8..c25a1a6d2b0 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -4,7 +4,8 @@ * OMAP Dual-Mode Timers * * Copyright (C) 2005 Nokia Corporation - * Author: Lauri Leukkunen + * OMAP2 support by Juha Yrjola + * API improvements and OMAP2 clock framework support by Timo Teras * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -26,15 +27,17 @@ */ #include +#include +#include +#include +#include +#include #include #include #include #include -#include -#include - -#define OMAP_TIMER_COUNT 8 +/* register offsets */ #define OMAP_TIMER_ID_REG 0x00 #define OMAP_TIMER_OCP_CFG_REG 0x10 #define OMAP_TIMER_SYS_STAT_REG 0x14 @@ -50,52 +53,184 @@ #define OMAP_TIMER_CAPTURE_REG 0x3c #define OMAP_TIMER_IF_CTRL_REG 0x40 +/* timer control reg bits */ +#define OMAP_TIMER_CTRL_GPOCFG (1 << 14) +#define OMAP_TIMER_CTRL_CAPTMODE (1 << 13) +#define OMAP_TIMER_CTRL_PT (1 << 12) +#define OMAP_TIMER_CTRL_TCM_LOWTOHIGH (0x1 << 8) +#define OMAP_TIMER_CTRL_TCM_HIGHTOLOW (0x2 << 8) +#define OMAP_TIMER_CTRL_TCM_BOTHEDGES (0x3 << 8) +#define OMAP_TIMER_CTRL_SCPWM (1 << 7) +#define OMAP_TIMER_CTRL_CE (1 << 6) /* compare enable */ +#define OMAP_TIMER_CTRL_PRE (1 << 5) /* prescaler enable */ +#define OMAP_TIMER_CTRL_PTV_SHIFT 2 /* how much to shift the prescaler value */ +#define OMAP_TIMER_CTRL_AR (1 << 1) /* auto-reload enable */ +#define OMAP_TIMER_CTRL_ST (1 << 0) /* start timer */ + +struct omap_dm_timer { + unsigned long phys_base; + int irq; +#ifdef CONFIG_ARCH_OMAP2 + struct clk *iclk, *fclk; +#endif + void __iomem *io_base; + unsigned reserved:1; +}; + +#ifdef CONFIG_ARCH_OMAP1 + +static struct omap_dm_timer dm_timers[] = { + { .phys_base = 0xfffb1400, .irq = INT_1610_GPTIMER1 }, + { .phys_base = 0xfffb1c00, .irq = INT_1610_GPTIMER2 }, + { .phys_base = 0xfffb2400, .irq = INT_1610_GPTIMER3 }, + { .phys_base = 0xfffb2c00, .irq = INT_1610_GPTIMER4 }, + { .phys_base = 0xfffb3400, .irq = INT_1610_GPTIMER5 }, + { .phys_base = 0xfffb3c00, .irq = INT_1610_GPTIMER6 }, + { .phys_base = 0xfffb4400, .irq = INT_1610_GPTIMER7 }, + { .phys_base = 0xfffb4c00, .irq = INT_1610_GPTIMER8 }, +}; -static struct dmtimer_info_struct { - struct list_head unused_timers; - struct list_head reserved_timers; -} dm_timer_info; +#elif defined(CONFIG_ARCH_OMAP2) static struct omap_dm_timer dm_timers[] = { - { .base=0xfffb1400, .irq=INT_1610_GPTIMER1 }, - { .base=0xfffb1c00, .irq=INT_1610_GPTIMER2 }, - { .base=0xfffb2400, .irq=INT_1610_GPTIMER3 }, - { .base=0xfffb2c00, .irq=INT_1610_GPTIMER4 }, - { .base=0xfffb3400, .irq=INT_1610_GPTIMER5 }, - { .base=0xfffb3c00, .irq=INT_1610_GPTIMER6 }, - { .base=0xfffb4400, .irq=INT_1610_GPTIMER7 }, - { .base=0xfffb4c00, .irq=INT_1610_GPTIMER8 }, - { .base=0x0 }, + { .phys_base = 0x48028000, .irq = INT_24XX_GPTIMER1 }, + { .phys_base = 0x4802a000, .irq = INT_24XX_GPTIMER2 }, + { .phys_base = 0x48078000, .irq = INT_24XX_GPTIMER3 }, + { .phys_base = 0x4807a000, .irq = INT_24XX_GPTIMER4 }, + { .phys_base = 0x4807c000, .irq = INT_24XX_GPTIMER5 }, + { .phys_base = 0x4807e000, .irq = INT_24XX_GPTIMER6 }, + { .phys_base = 0x48080000, .irq = INT_24XX_GPTIMER7 }, + { .phys_base = 0x48082000, .irq = INT_24XX_GPTIMER8 }, + { .phys_base = 0x48084000, .irq = INT_24XX_GPTIMER9 }, + { .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 }, + { .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 }, + { .phys_base = 0x4808a000, .irq = INT_24XX_GPTIMER12 }, }; +#else + +#error OMAP architecture not supported! + +#endif + +static const int dm_timer_count = ARRAY_SIZE(dm_timers); static spinlock_t dm_timer_lock; +static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg) +{ + return readl(timer->io_base + reg); +} -inline void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value) +static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value) { - omap_writel(value, timer->base + reg); + writel(value, timer->io_base + reg); while (omap_dm_timer_read_reg(timer, OMAP_TIMER_WRITE_PEND_REG)) ; } -u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg) +static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer) { - return omap_readl(timer->base + reg); + int c; + + c = 0; + while (!(omap_dm_timer_read_reg(timer, OMAP_TIMER_SYS_STAT_REG) & 1)) { + c++; + if (c > 100000) { + printk(KERN_ERR "Timer failed to reset\n"); + return; + } + } } -int omap_dm_timers_active(void) +static void omap_dm_timer_reset(struct omap_dm_timer *timer) +{ + u32 l; + + omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06); + omap_dm_timer_wait_for_reset(timer); + + omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_SYS_CLK); + + /* Set to smart-idle mode */ + l = omap_dm_timer_read_reg(timer, OMAP_TIMER_OCP_CFG_REG); + l |= 0x02 << 3; + omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, l); +} + +static void omap_dm_timer_reserve(struct omap_dm_timer *timer) +{ + timer->reserved = 1; +#ifdef CONFIG_ARCH_OMAP2 + clk_enable(timer->iclk); + clk_enable(timer->fclk); +#endif + omap_dm_timer_reset(timer); +} + +struct omap_dm_timer *omap_dm_timer_request(void) +{ + struct omap_dm_timer *timer = NULL; + unsigned long flags; + int i; + + spin_lock_irqsave(&dm_timer_lock, flags); + for (i = 0; i < dm_timer_count; i++) { + if (dm_timers[i].reserved) + continue; + + timer = &dm_timers[i]; + omap_dm_timer_reserve(timer); + break; + } + spin_unlock_irqrestore(&dm_timer_lock, flags); + + return timer; +} + +struct omap_dm_timer *omap_dm_timer_request_specific(int id) { struct omap_dm_timer *timer; + unsigned long flags; - for (timer = &dm_timers[0]; timer->base; ++timer) - if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) & - OMAP_TIMER_CTRL_ST) - return 1; + spin_lock_irqsave(&dm_timer_lock, flags); + if (id <= 0 || id > dm_timer_count || dm_timers[id-1].reserved) { + spin_unlock_irqrestore(&dm_timer_lock, flags); + printk("BUG: warning at %s:%d/%s(): unable to get timer %d\n", + __FILE__, __LINE__, __FUNCTION__, id); + dump_stack(); + return NULL; + } - return 0; + timer = &dm_timers[id-1]; + omap_dm_timer_reserve(timer); + spin_unlock_irqrestore(&dm_timer_lock, flags); + + return timer; } +void omap_dm_timer_free(struct omap_dm_timer *timer) +{ + omap_dm_timer_reset(timer); +#ifdef CONFIG_ARCH_OMAP2 + clk_disable(timer->iclk); + clk_disable(timer->fclk); +#endif + WARN_ON(!timer->reserved); + timer->reserved = 0; +} + +int omap_dm_timer_get_irq(struct omap_dm_timer *timer) +{ + return timer->irq; +} + +#if defined(CONFIG_ARCH_OMAP1) + +struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer) +{ + BUG(); +} /** * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR @@ -103,184 +238,226 @@ int omap_dm_timers_active(void) */ __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask) { - int n; + int i; /* If ARMXOR cannot be idled this function call is unnecessary */ if (!(inputmask & (1 << 1))) return inputmask; /* If any active timer is using ARMXOR return modified mask */ - for (n = 0; dm_timers[n].base; ++n) - if (omap_dm_timer_read_reg(&dm_timers[n], OMAP_TIMER_CTRL_REG)& - OMAP_TIMER_CTRL_ST) { - if (((omap_readl(MOD_CONF_CTRL_1)>>(n*2)) & 0x03) == 0) + for (i = 0; i < dm_timer_count; i++) { + u32 l; + + l = omap_dm_timer_read_reg(&dm_timers[n], OMAP_TIMER_CTRL_REG); + if (l & OMAP_TIMER_CTRL_ST) { + if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0) inputmask &= ~(1 << 1); else inputmask &= ~(1 << 2); } + } return inputmask; } +#elif defined(CONFIG_ARCH_OMAP2) -void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) +struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer) { - int n = (timer - dm_timers) << 1; - u32 l; + return timer->fclk; +} - l = omap_readl(MOD_CONF_CTRL_1) & ~(0x03 << n); - l |= source << n; - omap_writel(l, MOD_CONF_CTRL_1); +__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask) +{ + BUG(); } +#endif -static void omap_dm_timer_reset(struct omap_dm_timer *timer) +void omap_dm_timer_trigger(struct omap_dm_timer *timer) { - /* Reset and set posted mode */ - omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06); - omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, 0x02); - - omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_ARMXOR); + omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0); } +void omap_dm_timer_start(struct omap_dm_timer *timer) +{ + u32 l; + l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); + if (!(l & OMAP_TIMER_CTRL_ST)) { + l |= OMAP_TIMER_CTRL_ST; + omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); + } +} -struct omap_dm_timer * omap_dm_timer_request(void) +void omap_dm_timer_stop(struct omap_dm_timer *timer) { - struct omap_dm_timer *timer = NULL; - unsigned long flags; + u32 l; - spin_lock_irqsave(&dm_timer_lock, flags); - if (!list_empty(&dm_timer_info.unused_timers)) { - timer = (struct omap_dm_timer *) - dm_timer_info.unused_timers.next; - list_move_tail((struct list_head *)timer, - &dm_timer_info.reserved_timers); + l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); + if (l & OMAP_TIMER_CTRL_ST) { + l &= ~0x1; + omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); } - spin_unlock_irqrestore(&dm_timer_lock, flags); - - return timer; } +#ifdef CONFIG_ARCH_OMAP1 -void omap_dm_timer_free(struct omap_dm_timer *timer) +void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) { - unsigned long flags; - - omap_dm_timer_reset(timer); + int n = (timer - dm_timers) << 1; + u32 l; - spin_lock_irqsave(&dm_timer_lock, flags); - list_move_tail((struct list_head *)timer, &dm_timer_info.unused_timers); - spin_unlock_irqrestore(&dm_timer_lock, flags); + l = omap_readl(MOD_CONF_CTRL_1) & ~(0x03 << n); + l |= source << n; + omap_writel(l, MOD_CONF_CTRL_1); } -void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, - unsigned int value) -{ - omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_EN_REG, value); -} +#else -unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer) +void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) { - return omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG); + static const char *source_timers[] = { + "sys_ck", + "func_32k_ck", + "alt_ck" + }; + struct clk *parent; + + if (source < 0 || source >= 3) + return; + + parent = clk_get(NULL, source_timers[source]); + clk_disable(timer->fclk); + clk_set_parent(timer->fclk, parent); + clk_enable(timer->fclk); + clk_put(parent); + + /* When the functional clock disappears, too quick writes seem to + * cause an abort. */ + udelay(50); } -void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value) -{ - omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG, value); -} +#endif -void omap_dm_timer_enable_autoreload(struct omap_dm_timer *timer) +void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, + unsigned int load) { u32 l; + l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); - l |= OMAP_TIMER_CTRL_AR; + if (autoreload) + l |= OMAP_TIMER_CTRL_AR; + else + l &= ~OMAP_TIMER_CTRL_AR; omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); + omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load); + omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0); } -void omap_dm_timer_trigger(struct omap_dm_timer *timer) -{ - omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 1); -} - -void omap_dm_timer_set_trigger(struct omap_dm_timer *timer, unsigned int value) +void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable, + unsigned int match) { u32 l; l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); - l |= value & 0x3; + if (enable) + l |= OMAP_TIMER_CTRL_CE; + else + l &= ~OMAP_TIMER_CTRL_CE; omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); + omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match); } -void omap_dm_timer_start(struct omap_dm_timer *timer) + +void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, + int toggle, int trigger) { u32 l; l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); - l |= OMAP_TIMER_CTRL_ST; + l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM | + OMAP_TIMER_CTRL_PT | (0x03 << 10)); + if (def_on) + l |= OMAP_TIMER_CTRL_SCPWM; + if (toggle) + l |= OMAP_TIMER_CTRL_PT; + l |= trigger << 10; omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); } -void omap_dm_timer_stop(struct omap_dm_timer *timer) +void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler) { u32 l; l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); - l &= ~0x1; + l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2)); + if (prescaler >= 0x00 && prescaler <= 0x07) { + l |= OMAP_TIMER_CTRL_PRE; + l |= prescaler << 2; + } omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); } -unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer) +void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, + unsigned int value) { - return omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG); + omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_EN_REG, value); } -void omap_dm_timer_reset_counter(struct omap_dm_timer *timer) +unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer) { - omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, 0); + return omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG); } -void omap_dm_timer_set_load(struct omap_dm_timer *timer, unsigned int load) +void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value) { - omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load); + omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG, value); } -void omap_dm_timer_set_match(struct omap_dm_timer *timer, unsigned int match) +unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer) { - omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match); + return omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG); } -void omap_dm_timer_enable_compare(struct omap_dm_timer *timer) +int omap_dm_timers_active(void) { - u32 l; + int i; - l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); - l |= OMAP_TIMER_CTRL_CE; - omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); -} + for (i = 0; i < dm_timer_count; i++) { + struct omap_dm_timer *timer; + timer = &dm_timers[i]; + if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) & + OMAP_TIMER_CTRL_ST) + return 1; + } + return 0; +} -static inline void __dm_timer_init(void) +int omap_dm_timer_init(void) { struct omap_dm_timer *timer; + int i; + + if (!(cpu_is_omap16xx() || cpu_is_omap24xx())) + return -ENODEV; spin_lock_init(&dm_timer_lock); - INIT_LIST_HEAD(&dm_timer_info.unused_timers); - INIT_LIST_HEAD(&dm_timer_info.reserved_timers); - - timer = &dm_timers[0]; - while (timer->base) { - list_add_tail((struct list_head *)timer, &dm_timer_info.unused_timers); - omap_dm_timer_reset(timer); - timer++; + for (i = 0; i < dm_timer_count; i++) { +#ifdef CONFIG_ARCH_OMAP2 + char clk_name[16]; +#endif + + timer = &dm_timers[i]; + timer->io_base = (void __iomem *) io_p2v(timer->phys_base); +#ifdef CONFIG_ARCH_OMAP2 + sprintf(clk_name, "gpt%d_ick", i + 1); + timer->iclk = clk_get(NULL, clk_name); + sprintf(clk_name, "gpt%d_fck", i + 1); + timer->fclk = clk_get(NULL, clk_name); +#endif } -} -static int __init omap_dm_timer_init(void) -{ - if (cpu_is_omap16xx()) - __dm_timer_init(); return 0; } - -arch_initcall(omap_dm_timer_init); diff --git a/arch/arm/plat-omap/timer32k.c b/arch/arm/plat-omap/timer32k.c index 3461a6c9665..f028e182215 100644 --- a/arch/arm/plat-omap/timer32k.c +++ b/arch/arm/plat-omap/timer32k.c @@ -7,6 +7,7 @@ * Partial timer rewrite and additional dynamic tick timer support by * Tony Lindgen and * Tuukka Tikkanen + * OMAP Dual-mode timer framework support by Timo Teras * * MPU timer code based on the older MPU timer code for OMAP * Copyright (C) 2000 RidgeRun, Inc. @@ -79,18 +80,6 @@ struct sys_timer omap_timer; #define OMAP1_32K_TIMER_TVR 0x00 #define OMAP1_32K_TIMER_TCR 0x04 -/* 24xx specific defines */ -#define OMAP2_GP_TIMER_BASE 0x48028000 -#define CM_CLKSEL_WKUP 0x48008440 -#define GP_TIMER_TIDR 0x00 -#define GP_TIMER_TISR 0x18 -#define GP_TIMER_TIER 0x1c -#define GP_TIMER_TCLR 0x24 -#define GP_TIMER_TCRR 0x28 -#define GP_TIMER_TLDR 0x2c -#define GP_TIMER_TTGR 0x30 -#define GP_TIMER_TSICR 0x40 - #define OMAP_32K_TICKS_PER_HZ (32768 / HZ) /* @@ -102,54 +91,64 @@ struct sys_timer omap_timer; #define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate) \ (((nr_jiffies) * (clock_rate)) / HZ) +#if defined(CONFIG_ARCH_OMAP1) + static inline void omap_32k_timer_write(int val, int reg) { - if (cpu_class_is_omap1()) - omap_writew(val, OMAP1_32K_TIMER_BASE + reg); - - if (cpu_is_omap24xx()) - omap_writel(val, OMAP2_GP_TIMER_BASE + reg); + omap_writew(val, OMAP1_32K_TIMER_BASE + reg); } static inline unsigned long omap_32k_timer_read(int reg) { - if (cpu_class_is_omap1()) - return omap_readl(OMAP1_32K_TIMER_BASE + reg) & 0xffffff; + return omap_readl(OMAP1_32K_TIMER_BASE + reg) & 0xffffff; +} - if (cpu_is_omap24xx()) - return omap_readl(OMAP2_GP_TIMER_BASE + reg); +static inline void omap_32k_timer_start(unsigned long load_val) +{ + omap_32k_timer_write(load_val, OMAP1_32K_TIMER_TVR); + omap_32k_timer_write(0x0f, OMAP1_32K_TIMER_CR); } -/* - * The 32KHz synchronized timer is an additional timer on 16xx. - * It is always running. - */ -static inline unsigned long omap_32k_sync_timer_read(void) +static inline void omap_32k_timer_stop(void) { - return omap_readl(TIMER_32K_SYNCHRONIZED); + omap_32k_timer_write(0x0, OMAP1_32K_TIMER_CR); } +#define omap_32k_timer_ack_irq() + +#elif defined(CONFIG_ARCH_OMAP2) + +#include + +static struct omap_dm_timer *gptimer; + static inline void omap_32k_timer_start(unsigned long load_val) { - if (cpu_class_is_omap1()) { - omap_32k_timer_write(load_val, OMAP1_32K_TIMER_TVR); - omap_32k_timer_write(0x0f, OMAP1_32K_TIMER_CR); - } - - if (cpu_is_omap24xx()) { - omap_32k_timer_write(0xffffffff - load_val, GP_TIMER_TCRR); - omap_32k_timer_write((1 << 1), GP_TIMER_TIER); - omap_32k_timer_write((1 << 1) | 1, GP_TIMER_TCLR); - } + omap_dm_timer_set_load(gptimer, 1, 0xffffffff - load_val); + omap_dm_timer_set_int_enable(gptimer, OMAP_TIMER_INT_OVERFLOW); + omap_dm_timer_start(gptimer); } static inline void omap_32k_timer_stop(void) { - if (cpu_class_is_omap1()) - omap_32k_timer_write(0x0, OMAP1_32K_TIMER_CR); + omap_dm_timer_stop(gptimer); +} - if (cpu_is_omap24xx()) - omap_32k_timer_write(0x0, GP_TIMER_TCLR); +static inline void omap_32k_timer_ack_irq(void) +{ + u32 status = omap_dm_timer_read_status(gptimer); + omap_dm_timer_write_status(gptimer, status); +} + +#endif + +/* + * The 32KHz synchronized timer is an additional timer on 16xx. + * It is always running. + */ +static inline unsigned long omap_32k_sync_timer_read(void) +{ + return omap_readl(TIMER_32K_SYNCHRONIZED); } /* @@ -203,11 +202,7 @@ static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id, write_seqlock_irqsave(&xtime_lock, flags); - if (cpu_is_omap24xx()) { - u32 status = omap_32k_timer_read(GP_TIMER_TISR); - omap_32k_timer_write(status, GP_TIMER_TISR); - } - + omap_32k_timer_ack_irq(); now = omap_32k_sync_timer_read(); while ((signed long)(now - omap_32k_last_tick) @@ -269,9 +264,6 @@ static struct irqaction omap_32k_timer_irq = { .handler = omap_32k_timer_interrupt, }; -static struct clk * gpt1_ick; -static struct clk * gpt1_fck; - static __init void omap_init_32k_timer(void) { #ifdef CONFIG_NO_IDLE_HZ @@ -280,31 +272,19 @@ static __init void omap_init_32k_timer(void) if (cpu_class_is_omap1()) setup_irq(INT_OS_TIMER, &omap_32k_timer_irq); - if (cpu_is_omap24xx()) - setup_irq(37, &omap_32k_timer_irq); omap_timer.offset = omap_32k_timer_gettimeoffset; omap_32k_last_tick = omap_32k_sync_timer_read(); /* REVISIT: Check 24xx TIOCP_CFG settings after idle works */ if (cpu_is_omap24xx()) { - omap_32k_timer_write(0, GP_TIMER_TCLR); - omap_writel(0, CM_CLKSEL_WKUP); /* 32KHz clock source */ - - gpt1_ick = clk_get(NULL, "gpt1_ick"); - if (IS_ERR(gpt1_ick)) - printk(KERN_ERR "Could not get gpt1_ick\n"); - else - clk_enable(gpt1_ick); - - gpt1_fck = clk_get(NULL, "gpt1_fck"); - if (IS_ERR(gpt1_fck)) - printk(KERN_ERR "Could not get gpt1_fck\n"); - else - clk_enable(gpt1_fck); - - mdelay(100); /* Wait for clocks to stabilize */ - - omap_32k_timer_write(0x7, GP_TIMER_TISR); + gptimer = omap_dm_timer_request_specific(1); + BUG_ON(gptimer == NULL); + + omap_dm_timer_set_source(gptimer, OMAP_TIMER_SRC_32_KHZ); + setup_irq(omap_dm_timer_get_irq(gptimer), &omap_32k_timer_irq); + omap_dm_timer_set_int_enable(gptimer, + OMAP_TIMER_INT_CAPTURE | OMAP_TIMER_INT_OVERFLOW | + OMAP_TIMER_INT_MATCH); } omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD); @@ -317,6 +297,9 @@ static __init void omap_init_32k_timer(void) */ static void __init omap_timer_init(void) { +#ifdef CONFIG_OMAP_DM_TIMER + omap_dm_timer_init(); +#endif omap_init_32k_timer(); } -- cgit v1.2.3 From e32f7ec2e8bf00756c74a5e6a80bc59e949dd81d Mon Sep 17 00:00:00 2001 From: Timo Teras Date: Mon, 26 Jun 2006 16:16:13 -0700 Subject: ARM: OMAP: Fix 32 kHz timer and modify GP timer to use GPT1 The dmtimer framework update broke 32 kHz timer as udelay() does not work before system timer is started (and GPT1 should not be reset). This also makes the GP timer use GPT1. This requires a fix in clock framework. Signed-off-by: Timo Teras Signed-off-by: Juha Yrjola Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/clock.c | 2 +- arch/arm/mach-omap2/timer-gp.c | 2 +- arch/arm/plat-omap/dmtimer.c | 9 +++++---- 3 files changed, 7 insertions(+), 6 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index 242d8f925e9..6789dd4029a 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -753,7 +753,7 @@ static u32 omap2_get_src_field(u32 *type_to_addr, u32 reg_offset, val = 0x2; break; case CM_WKUP_SEL1: - src_reg_addr = (u32)&CM_CLKSEL2_CORE; + src_reg_addr = (u32)&CM_CLKSEL_WKUP; mask = 0x3; if (src_clk == &func_32k_ck) val = 0x0; diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c index 3358c0d47b1..cf78e6c5a27 100644 --- a/arch/arm/mach-omap2/timer-gp.c +++ b/arch/arm/mach-omap2/timer-gp.c @@ -61,7 +61,7 @@ static void __init omap2_gp_timer_init(void) u32 tick_period; omap_dm_timer_init(); - gptimer = omap_dm_timer_request_specific(2); + gptimer = omap_dm_timer_request_specific(1); BUG_ON(gptimer == NULL); omap_dm_timer_set_source(gptimer, OMAP_TIMER_SRC_SYS_CLK); diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index c25a1a6d2b0..bfccebc7751 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -147,9 +147,10 @@ static void omap_dm_timer_reset(struct omap_dm_timer *timer) { u32 l; - omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06); - omap_dm_timer_wait_for_reset(timer); - + if (timer != &dm_timers[0]) { + omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06); + omap_dm_timer_wait_for_reset(timer); + } omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_SYS_CLK); /* Set to smart-idle mode */ @@ -335,7 +336,7 @@ void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) /* When the functional clock disappears, too quick writes seem to * cause an abort. */ - udelay(50); + __delay(15000); } #endif -- cgit v1.2.3 From 6dc3c8f20159530d5553d0f8decc9454916d7495 Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Mon, 26 Jun 2006 16:16:14 -0700 Subject: ARM: OMAP: OMAP2 DMA burst support OMAP2 DMA burst setting support Signed-off-by: Kyungmin Park Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/dma.c | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c index aa1cf79f954..8e7c33656b5 100644 --- a/arch/arm/plat-omap/dma.c +++ b/arch/arm/plat-omap/dma.c @@ -292,22 +292,39 @@ void omap_set_dma_src_data_pack(int lch, int enable) void omap_set_dma_src_burst_mode(int lch, enum omap_dma_burst_mode burst_mode) { + unsigned int burst = 0; OMAP_DMA_CSDP_REG(lch) &= ~(0x03 << 7); switch (burst_mode) { case OMAP_DMA_DATA_BURST_DIS: break; case OMAP_DMA_DATA_BURST_4: - OMAP_DMA_CSDP_REG(lch) |= (0x02 << 7); + if (cpu_is_omap24xx()) + burst = 0x1; + else + burst = 0x2; break; case OMAP_DMA_DATA_BURST_8: - /* not supported by current hardware + if (cpu_is_omap24xx()) { + burst = 0x2; + break; + } + /* not supported by current hardware on OMAP1 * w |= (0x03 << 7); * fall through */ + case OMAP_DMA_DATA_BURST_16: + if (cpu_is_omap24xx()) { + burst = 0x3; + break; + } + /* OMAP1 don't support burst 16 + * fall through + */ default: BUG(); } + OMAP_DMA_CSDP_REG(lch) |= (burst << 7); } /* Note that dest_port is only for OMAP1 */ @@ -354,22 +371,38 @@ void omap_set_dma_dest_data_pack(int lch, int enable) void omap_set_dma_dest_burst_mode(int lch, enum omap_dma_burst_mode burst_mode) { + unsigned int burst = 0; OMAP_DMA_CSDP_REG(lch) &= ~(0x03 << 14); switch (burst_mode) { case OMAP_DMA_DATA_BURST_DIS: break; case OMAP_DMA_DATA_BURST_4: - OMAP_DMA_CSDP_REG(lch) |= (0x02 << 14); + if (cpu_is_omap24xx()) + burst = 0x1; + else + burst = 0x2; break; case OMAP_DMA_DATA_BURST_8: - OMAP_DMA_CSDP_REG(lch) |= (0x03 << 14); + if (cpu_is_omap24xx()) + burst = 0x2; + else + burst = 0x3; break; + case OMAP_DMA_DATA_BURST_16: + if (cpu_is_omap24xx()) { + burst = 0x3; + break; + } + /* OMAP1 don't support burst 16 + * fall through + */ default: printk(KERN_ERR "Invalid DMA burst mode\n"); BUG(); return; } + OMAP_DMA_CSDP_REG(lch) |= (burst << 14); } static inline void omap_enable_channel_irq(int lch) -- cgit v1.2.3 From 7ff879dbcd2083c95933a56bce65ae45ecab3f35 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 26 Jun 2006 16:16:15 -0700 Subject: ARM: OMAP: Fix DMA channel irq handling for omap24xx - DMA CSR register is cleared by reading on omap1, but on omap2 it is cleard by writing to it. - DMA TOUT interrupt does not exist on omap24xx, rename it - Add SECURE and MISALIGNED errors by default for omap24xx - Add defines for external DMA request lines Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/dma.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c index 8e7c33656b5..c5d0214ef19 100644 --- a/arch/arm/plat-omap/dma.c +++ b/arch/arm/plat-omap/dma.c @@ -43,6 +43,7 @@ #define OMAP_DMA_ACTIVE 0x01 #define OMAP_DMA_CCR_EN (1 << 7) +#define OMAP2_DMA_CSR_CLEAR_MASK 0xffe #define OMAP_FUNC_MUX_ARM_BASE (0xfffe1000 + 0xec) @@ -409,8 +410,11 @@ static inline void omap_enable_channel_irq(int lch) { u32 status; - /* Read CSR to make sure it's cleared. */ - status = OMAP_DMA_CSR_REG(lch); + /* Clear CSR */ + if (cpu_class_is_omap1()) + status = OMAP_DMA_CSR_REG(lch); + else if (cpu_is_omap24xx()) + OMAP_DMA_CSR_REG(lch) = OMAP2_DMA_CSR_CLEAR_MASK; /* Enable some nice interrupts. */ OMAP_DMA_CICR_REG(lch) = dma_chan[lch].enabled_irqs; @@ -509,11 +513,13 @@ int omap_request_dma(int dev_id, const char *dev_name, chan->dev_name = dev_name; chan->callback = callback; chan->data = data; - chan->enabled_irqs = OMAP_DMA_TOUT_IRQ | OMAP_DMA_DROP_IRQ | - OMAP_DMA_BLOCK_IRQ; + chan->enabled_irqs = OMAP_DMA_DROP_IRQ | OMAP_DMA_BLOCK_IRQ; - if (cpu_is_omap24xx()) - chan->enabled_irqs |= OMAP2_DMA_TRANS_ERR_IRQ; + if (cpu_class_is_omap1()) + chan->enabled_irqs |= OMAP1_DMA_TOUT_IRQ; + else if (cpu_is_omap24xx()) + chan->enabled_irqs |= OMAP2_DMA_MISALIGNED_ERR_IRQ | + OMAP2_DMA_TRANS_ERR_IRQ; if (cpu_is_omap16xx()) { /* If the sync device is set, configure it dynamically. */ @@ -533,7 +539,7 @@ int omap_request_dma(int dev_id, const char *dev_name, omap_enable_channel_irq(free_ch); /* Clear the CSR register and IRQ status register */ - OMAP_DMA_CSR_REG(free_ch) = 0x0; + OMAP_DMA_CSR_REG(free_ch) = OMAP2_DMA_CSR_CLEAR_MASK; omap_writel(~0x0, OMAP_DMA4_IRQSTATUS_L0); } @@ -573,7 +579,7 @@ void omap_free_dma(int lch) omap_writel(val, OMAP_DMA4_IRQENABLE_L0); /* Clear the CSR register and IRQ status register */ - OMAP_DMA_CSR_REG(lch) = 0x0; + OMAP_DMA_CSR_REG(lch) = OMAP2_DMA_CSR_CLEAR_MASK; val = omap_readl(OMAP_DMA4_IRQSTATUS_L0); val |= 1 << lch; @@ -837,7 +843,7 @@ static int omap1_dma_handle_ch(int ch) "%d (CSR %04x)\n", ch, csr); return 0; } - if (unlikely(csr & OMAP_DMA_TOUT_IRQ)) + if (unlikely(csr & OMAP1_DMA_TOUT_IRQ)) printk(KERN_WARNING "DMA timeout with device %d\n", dma_chan[ch].dev_id); if (unlikely(csr & OMAP_DMA_DROP_IRQ)) @@ -885,20 +891,21 @@ static int omap2_dma_handle_ch(int ch) return 0; if (unlikely(dma_chan[ch].dev_id == -1)) return 0; - /* REVISIT: According to 24xx TRM, there's no TOUT_IE */ - if (unlikely(status & OMAP_DMA_TOUT_IRQ)) - printk(KERN_INFO "DMA timeout with device %d\n", - dma_chan[ch].dev_id); if (unlikely(status & OMAP_DMA_DROP_IRQ)) printk(KERN_INFO "DMA synchronization event drop occurred with device " "%d\n", dma_chan[ch].dev_id); - if (unlikely(status & OMAP2_DMA_TRANS_ERR_IRQ)) printk(KERN_INFO "DMA transaction error with device %d\n", dma_chan[ch].dev_id); + if (unlikely(status & OMAP2_DMA_SECURE_ERR_IRQ)) + printk(KERN_INFO "DMA secure error with device %d\n", + dma_chan[ch].dev_id); + if (unlikely(status & OMAP2_DMA_MISALIGNED_ERR_IRQ)) + printk(KERN_INFO "DMA misaligned error with device %d\n", + dma_chan[ch].dev_id); - OMAP_DMA_CSR_REG(ch) = 0x20; + OMAP_DMA_CSR_REG(ch) = OMAP2_DMA_CSR_CLEAR_MASK; val = omap_readl(OMAP_DMA4_IRQSTATUS_L0); /* ch in this function is from 0-31 while in register it is 1-32 */ -- cgit v1.2.3 From 4bbbc1adc2095c6504a556819dd8842135df300b Mon Sep 17 00:00:00 2001 From: Juha Yrjola Date: Mon, 26 Jun 2006 16:16:16 -0700 Subject: ARM: OMAP: Add GPMC support for OMAP2 Implement basic support for General-Purpose Memory Controller as found on OMAP2420. Dynamic CS address space allocation still needs to be done. Signed-off-by: Juha Yrjola Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/Makefile | 3 +- arch/arm/mach-omap2/gpmc.c | 209 +++++++++++++++++++++++++++++++++++++++++++ arch/arm/mach-omap2/io.c | 2 + 3 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-omap2/gpmc.c (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 111eaa64258..7a8edd6cd19 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -3,7 +3,8 @@ # # Common support -obj-y := irq.o id.o io.o sram-fn.o memory.o prcm.o clock.o mux.o devices.o serial.o +obj-y := irq.o id.o io.o sram-fn.o memory.o prcm.o clock.o mux.o devices.o \ + serial.o gpmc.o obj-$(CONFIG_OMAP_MPU_TIMER) += timer-gp.o diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c new file mode 100644 index 00000000000..4aeaa4e7958 --- /dev/null +++ b/arch/arm/mach-omap2/gpmc.c @@ -0,0 +1,209 @@ +/* + * GPMC support functions + * + * Copyright (C) 2005-2006 Nokia Corporation + * + * Author: Juha Yrjola + * + * 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 +#include +#include +#include + +#include +#include + +#undef DEBUG + +#define GPMC_BASE 0x6800a000 +#define GPMC_REVISION 0x00 +#define GPMC_SYSCONFIG 0x10 +#define GPMC_SYSSTATUS 0x14 +#define GPMC_IRQSTATUS 0x18 +#define GPMC_IRQENABLE 0x1c +#define GPMC_TIMEOUT_CONTROL 0x40 +#define GPMC_ERR_ADDRESS 0x44 +#define GPMC_ERR_TYPE 0x48 +#define GPMC_CONFIG 0x50 +#define GPMC_STATUS 0x54 +#define GPMC_PREFETCH_CONFIG1 0x1e0 +#define GPMC_PREFETCH_CONFIG2 0x1e4 +#define GPMC_PREFETCH_CONTROL 0x1e8 +#define GPMC_PREFETCH_STATUS 0x1f0 +#define GPMC_ECC_CONFIG 0x1f4 +#define GPMC_ECC_CONTROL 0x1f8 +#define GPMC_ECC_SIZE_CONFIG 0x1fc + +#define GPMC_CS0 0x60 +#define GPMC_CS_SIZE 0x30 + +static void __iomem *gpmc_base = + (void __iomem *) IO_ADDRESS(GPMC_BASE); +static void __iomem *gpmc_cs_base = + (void __iomem *) IO_ADDRESS(GPMC_BASE) + GPMC_CS0; + +static struct clk *gpmc_l3_clk; + +static void gpmc_write_reg(int idx, u32 val) +{ + __raw_writel(val, gpmc_base + idx); +} + +static u32 gpmc_read_reg(int idx) +{ + return __raw_readl(gpmc_base + idx); +} + +void gpmc_cs_write_reg(int cs, int idx, u32 val) +{ + void __iomem *reg_addr; + + reg_addr = gpmc_cs_base + (cs * GPMC_CS_SIZE) + idx; + __raw_writel(val, reg_addr); +} + +u32 gpmc_cs_read_reg(int cs, int idx) +{ + return __raw_readl(gpmc_cs_base + (cs * GPMC_CS_SIZE) + idx); +} + +/* TODO: Add support for gpmc_fck to clock framework and use it */ +static unsigned long gpmc_get_fclk_period(void) +{ + /* In picoseconds */ + return 1000000000 / ((clk_get_rate(gpmc_l3_clk)) / 1000); +} + +unsigned int gpmc_ns_to_ticks(unsigned int time_ns) +{ + unsigned long tick_ps; + + /* Calculate in picosecs to yield more exact results */ + tick_ps = gpmc_get_fclk_period(); + + return (time_ns * 1000 + tick_ps - 1) / tick_ps; +} + +#ifdef DEBUG +static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit, + int time, int div, const char *name) +#else +static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit, + int time) +#endif +{ + u32 l; + int ticks, mask, nr_bits; + + if (time == 0) + ticks = 0; + else + ticks = gpmc_ns_to_ticks(time); + nr_bits = end_bit - st_bit + 1; + if (ticks >= 1 << nr_bits) + return -1; + + mask = (1 << nr_bits) - 1; + l = gpmc_cs_read_reg(cs, reg); +#ifdef DEBUG + printk(KERN_INFO "GPMC CS%d: %-10s: %d ticks, %3lu ns (was %i ticks)\n", + cs, name, ticks, gpmc_get_clk_period(div) * ticks / 1000, + (l >> st_bit) & mask); +#endif + l &= ~(mask << st_bit); + l |= ticks << st_bit; + gpmc_cs_write_reg(cs, reg, l); + + return 0; +} + +#ifdef DEBUG +#define GPMC_SET_ONE(reg, st, end, field) \ + if (set_gpmc_timing_reg(cs, (reg), (st), (end), \ + t->field, #field) < 0) \ + return -1 +#else +#define GPMC_SET_ONE(reg, st, end, field) \ + if (set_gpmc_timing_reg(cs, (reg), (st), (end), t->field) < 0) \ + return -1 +#endif + +int gpmc_cs_calc_divider(int cs, unsigned int sync_clk) +{ + int div; + u32 l; + + l = sync_clk * 1000 + (gpmc_get_fclk_period() - 1); + div = l / gpmc_get_fclk_period(); + if (div > 4) + return -1; + if (div < 0) + div = 1; + + return div; +} + +int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t) +{ + int div; + u32 l; + + div = gpmc_cs_calc_divider(cs, t->sync_clk); + if (div < 0) + return -1; + + GPMC_SET_ONE(GPMC_CS_CONFIG2, 0, 3, cs_on); + GPMC_SET_ONE(GPMC_CS_CONFIG2, 8, 12, cs_rd_off); + GPMC_SET_ONE(GPMC_CS_CONFIG2, 16, 20, cs_wr_off); + + GPMC_SET_ONE(GPMC_CS_CONFIG3, 0, 3, adv_on); + GPMC_SET_ONE(GPMC_CS_CONFIG3, 8, 12, adv_rd_off); + GPMC_SET_ONE(GPMC_CS_CONFIG3, 16, 20, adv_wr_off); + + GPMC_SET_ONE(GPMC_CS_CONFIG4, 0, 3, oe_on); + GPMC_SET_ONE(GPMC_CS_CONFIG4, 8, 12, oe_off); + GPMC_SET_ONE(GPMC_CS_CONFIG4, 16, 19, we_on); + GPMC_SET_ONE(GPMC_CS_CONFIG4, 24, 28, we_off); + + GPMC_SET_ONE(GPMC_CS_CONFIG5, 0, 4, rd_cycle); + GPMC_SET_ONE(GPMC_CS_CONFIG5, 8, 12, wr_cycle); + GPMC_SET_ONE(GPMC_CS_CONFIG5, 16, 20, access); + + GPMC_SET_ONE(GPMC_CS_CONFIG5, 24, 27, page_burst_access); + +#ifdef DEBUG + printk(KERN_INFO "GPMC CLK period is %d (div %d)\n", + cs, get_gpmc_clk_period(div), div); +#endif + + l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1); + l &= ~0x03; + l |= (div - 1); + + return 0; +} + +unsigned long gpmc_cs_get_base_addr(int cs) +{ + return (gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7) & 0x1f) << 24; +} + +void __init gpmc_init(void) +{ + u32 l; + + gpmc_l3_clk = clk_get(NULL, "core_l3_ck"); + BUG_ON(IS_ERR(gpmc_l3_clk)); + + l = gpmc_read_reg(GPMC_REVISION); + printk(KERN_INFO "GPMC revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f); + /* Set smart idle mode and automatic L3 clock gating */ + l = gpmc_read_reg(GPMC_SYSCONFIG); + l &= 0x03 << 3; + l |= (0x02 << 3) | (1 << 0); + gpmc_write_reg(GPMC_SYSCONFIG, l); +} diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 7d5711611f2..68456b79a0a 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -27,6 +27,7 @@ extern void omap_sram_init(void); extern int omap2_clk_init(void); extern void omap2_check_revision(void); +extern void gpmc_init(void); /* * The machine specific code may provide the extra mapping besides the @@ -67,4 +68,5 @@ void __init omap2_init_common_hw(void) { omap2_mux_init(); omap2_clk_init(); + gpmc_init(); } -- cgit v1.2.3 From a7ca9d2b0199f79480800e18f643328bb43f521d Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 26 Jun 2006 16:16:17 -0700 Subject: ARM: OMAP: Update cpufreq support for 24xx Update cpufreq support for 24xx Signed-off-by: Tony Lindgren --- arch/arm/Kconfig | 2 +- arch/arm/plat-omap/cpu-omap.c | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 3d1a3fb7d5f..30dede5a38b 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -669,7 +669,7 @@ config XIP_PHYS_ADDR endmenu -if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP1) +if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP) menu "CPU Frequency scaling" diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c index 98edc9fdd6d..a0c71dca237 100644 --- a/arch/arm/plat-omap/cpu-omap.c +++ b/arch/arm/plat-omap/cpu-omap.c @@ -25,6 +25,14 @@ #include #include +#define VERY_HI_RATE 900000000 + +#ifdef CONFIG_ARCH_OMAP1 +#define MPU_CLK "mpu" +#else +#define MPU_CLK "virt_prcm_set" +#endif + /* TODO: Add support for SDRAM timing changes */ int omap_verify_speed(struct cpufreq_policy *policy) @@ -36,7 +44,7 @@ int omap_verify_speed(struct cpufreq_policy *policy) cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, policy->cpuinfo.max_freq); - mpu_clk = clk_get(NULL, "mpu"); + mpu_clk = clk_get(NULL, MPU_CLK); if (IS_ERR(mpu_clk)) return PTR_ERR(mpu_clk); policy->min = clk_round_rate(mpu_clk, policy->min * 1000) / 1000; @@ -56,7 +64,7 @@ unsigned int omap_getspeed(unsigned int cpu) if (cpu) return 0; - mpu_clk = clk_get(NULL, "mpu"); + mpu_clk = clk_get(NULL, MPU_CLK); if (IS_ERR(mpu_clk)) return 0; rate = clk_get_rate(mpu_clk) / 1000; @@ -73,7 +81,7 @@ static int omap_target(struct cpufreq_policy *policy, struct cpufreq_freqs freqs; int ret = 0; - mpu_clk = clk_get(NULL, "mpu"); + mpu_clk = clk_get(NULL, MPU_CLK); if (IS_ERR(mpu_clk)) return PTR_ERR(mpu_clk); @@ -93,7 +101,7 @@ static int __init omap_cpu_init(struct cpufreq_policy *policy) { struct clk * mpu_clk; - mpu_clk = clk_get(NULL, "mpu"); + mpu_clk = clk_get(NULL, MPU_CLK); if (IS_ERR(mpu_clk)) return PTR_ERR(mpu_clk); @@ -102,7 +110,7 @@ static int __init omap_cpu_init(struct cpufreq_policy *policy) policy->cur = policy->min = policy->max = omap_getspeed(0); policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000; - policy->cpuinfo.max_freq = clk_round_rate(mpu_clk, 216000000) / 1000; + policy->cpuinfo.max_freq = clk_round_rate(mpu_clk, VERY_HI_RATE) / 1000; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; clk_put(mpu_clk); -- cgit v1.2.3 From 22a16f39e36e62f7bd221e5b279ea02fb3c43425 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 26 Jun 2006 16:16:18 -0700 Subject: ARM: OMAP: Add initial 24xx suspend support This patch adds support for omap24xx power domains and allows suspend to work. Please note that for some reason core power domain still does not seem to idle. Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/Makefile | 2 +- arch/arm/mach-omap2/pm-domain.c | 300 ++++++++++++++++++++++++++++++++++++++++ arch/arm/mach-omap2/pm.c | 271 +++++++++++++++++++++++++++++++++++- 3 files changed, 566 insertions(+), 7 deletions(-) create mode 100644 arch/arm/mach-omap2/pm-domain.c (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 7a8edd6cd19..266d88e77bd 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -9,7 +9,7 @@ obj-y := irq.o id.o io.o sram-fn.o memory.o prcm.o clock.o mux.o devices.o \ obj-$(CONFIG_OMAP_MPU_TIMER) += timer-gp.o # Power Management -obj-$(CONFIG_PM) += pm.o sleep.o +obj-$(CONFIG_PM) += pm.o pm-domain.o sleep.o # Specific board support obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o diff --git a/arch/arm/mach-omap2/pm-domain.c b/arch/arm/mach-omap2/pm-domain.c new file mode 100644 index 00000000000..5e20e740cde --- /dev/null +++ b/arch/arm/mach-omap2/pm-domain.c @@ -0,0 +1,300 @@ +/* + * linux/arch/arm/mach-omap2/pm-domain.c + * + * Power domain functions for OMAP2 + * + * Copyright (C) 2006 Nokia Corporation + * Tony Lindgren + * + * Some code based on earlier OMAP2 sample PM code + * Copyright (C) 2005 Texas Instruments, Inc. + * Richard Woodruff + * + * 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 +#include +#include +#include + +#include + +#include "prcm-regs.h" + +/* Power domain offsets */ +#define PM_MPU_OFFSET 0x100 +#define PM_CORE_OFFSET 0x200 +#define PM_GFX_OFFSET 0x300 +#define PM_WKUP_OFFSET 0x400 /* Autoidle only */ +#define PM_PLL_OFFSET 0x500 /* Autoidle only */ +#define PM_DSP_OFFSET 0x800 +#define PM_MDM_OFFSET 0xc00 + +/* Power domain wake-up dependency control register */ +#define PM_WKDEP_OFFSET 0xc8 +#define EN_MDM (1 << 5) +#define EN_WKUP (1 << 4) +#define EN_GFX (1 << 3) +#define EN_DSP (1 << 2) +#define EN_MPU (1 << 1) +#define EN_CORE (1 << 0) + +/* Core power domain state transition control register */ +#define PM_PWSTCTRL_OFFSET 0xe0 +#define FORCESTATE (1 << 18) /* Only for DSP & GFX */ +#define MEM4RETSTATE (1 << 6) +#define MEM3RETSTATE (1 << 5) +#define MEM2RETSTATE (1 << 4) +#define MEM1RETSTATE (1 << 3) +#define LOGICRETSTATE (1 << 2) /* Logic is retained */ +#define POWERSTATE_OFF 0x3 +#define POWERSTATE_RETENTION 0x1 +#define POWERSTATE_ON 0x0 + +/* Power domain state register */ +#define PM_PWSTST_OFFSET 0xe4 + +/* Hardware supervised state transition control register */ +#define CM_CLKSTCTRL_OFFSET 0x48 +#define AUTOSTAT_MPU (1 << 0) /* MPU */ +#define AUTOSTAT_DSS (1 << 2) /* Core */ +#define AUTOSTAT_L4 (1 << 1) /* Core */ +#define AUTOSTAT_L3 (1 << 0) /* Core */ +#define AUTOSTAT_GFX (1 << 0) /* GFX */ +#define AUTOSTAT_IVA (1 << 8) /* 2420 IVA in DSP domain */ +#define AUTOSTAT_DSP (1 << 0) /* DSP */ +#define AUTOSTAT_MDM (1 << 0) /* MDM */ + +/* Automatic control of interface clock idling */ +#define CM_AUTOIDLE1_OFFSET 0x30 +#define CM_AUTOIDLE2_OFFSET 0x34 /* Core only */ +#define CM_AUTOIDLE3_OFFSET 0x38 /* Core only */ +#define CM_AUTOIDLE4_OFFSET 0x3c /* Core only */ +#define AUTO_54M(x) (((x) & 0x3) << 6) +#define AUTO_96M(x) (((x) & 0x3) << 2) +#define AUTO_DPLL(x) (((x) & 0x3) << 0) +#define AUTO_STOPPED 0x3 +#define AUTO_BYPASS_FAST 0x2 /* DPLL only */ +#define AUTO_BYPASS_LOW_POWER 0x1 /* DPLL only */ +#define AUTO_DISABLED 0x0 + +/* Voltage control PRCM_VOLTCTRL bits */ +#define AUTO_EXTVOLT (1 << 15) +#define FORCE_EXTVOLT (1 << 14) +#define SETOFF_LEVEL(x) (((x) & 0x3) << 12) +#define MEMRETCTRL (1 << 8) +#define SETRET_LEVEL(x) (((x) & 0x3) << 6) +#define VOLT_LEVEL(x) (((x) & 0x3) << 0) + +#define OMAP24XX_PRCM_VBASE IO_ADDRESS(OMAP24XX_PRCM_BASE) +#define prcm_readl(r) __raw_readl(OMAP24XX_PRCM_VBASE + (r)) +#define prcm_writel(v, r) __raw_writel((v), OMAP24XX_PRCM_VBASE + (r)) + +static u32 pmdomain_get_wakeup_dependencies(int domain_offset) +{ + return prcm_readl(domain_offset + PM_WKDEP_OFFSET); +} + +static void pmdomain_set_wakeup_dependencies(u32 state, int domain_offset) +{ + prcm_writel(state, domain_offset + PM_WKDEP_OFFSET); +} + +static u32 pmdomain_get_powerstate(int domain_offset) +{ + return prcm_readl(domain_offset + PM_PWSTCTRL_OFFSET); +} + +static void pmdomain_set_powerstate(u32 state, int domain_offset) +{ + prcm_writel(state, domain_offset + PM_PWSTCTRL_OFFSET); +} + +static u32 pmdomain_get_clock_autocontrol(int domain_offset) +{ + return prcm_readl(domain_offset + CM_CLKSTCTRL_OFFSET); +} + +static void pmdomain_set_clock_autocontrol(u32 state, int domain_offset) +{ + prcm_writel(state, domain_offset + CM_CLKSTCTRL_OFFSET); +} + +static u32 pmdomain_get_clock_autoidle1(int domain_offset) +{ + return prcm_readl(domain_offset + CM_AUTOIDLE1_OFFSET); +} + +/* Core domain only */ +static u32 pmdomain_get_clock_autoidle2(int domain_offset) +{ + return prcm_readl(domain_offset + CM_AUTOIDLE2_OFFSET); +} + +/* Core domain only */ +static u32 pmdomain_get_clock_autoidle3(int domain_offset) +{ + return prcm_readl(domain_offset + CM_AUTOIDLE3_OFFSET); +} + +/* Core domain only */ +static u32 pmdomain_get_clock_autoidle4(int domain_offset) +{ + return prcm_readl(domain_offset + CM_AUTOIDLE4_OFFSET); +} + +static void pmdomain_set_clock_autoidle1(u32 state, int domain_offset) +{ + prcm_writel(state, CM_AUTOIDLE1_OFFSET + domain_offset); +} + +/* Core domain only */ +static void pmdomain_set_clock_autoidle2(u32 state, int domain_offset) +{ + prcm_writel(state, CM_AUTOIDLE2_OFFSET + domain_offset); +} + +/* Core domain only */ +static void pmdomain_set_clock_autoidle3(u32 state, int domain_offset) +{ + prcm_writel(state, CM_AUTOIDLE3_OFFSET + domain_offset); +} + +/* Core domain only */ +static void pmdomain_set_clock_autoidle4(u32 state, int domain_offset) +{ + prcm_writel(state, CM_AUTOIDLE4_OFFSET + domain_offset); +} + +/* + * Configures power management domains to idle clocks automatically. + */ +void pmdomain_set_autoidle(void) +{ + u32 val; + + /* Set PLL auto stop for 54M, 96M & DPLL */ + pmdomain_set_clock_autoidle1(AUTO_54M(AUTO_STOPPED) | + AUTO_96M(AUTO_STOPPED) | + AUTO_DPLL(AUTO_STOPPED), PM_PLL_OFFSET); + + /* External clock input control + * REVISIT: Should this be in clock framework? + */ + PRCM_CLKSRC_CTRL |= (0x3 << 3); + + /* Configure number of 32KHz clock cycles for sys_clk */ + PRCM_CLKSSETUP = 0x00ff; + + /* Configure automatic voltage transition */ + PRCM_VOLTSETUP = 0; + val = PRCM_VOLTCTRL; + val &= ~(SETOFF_LEVEL(0x3) | VOLT_LEVEL(0x3)); + val |= SETOFF_LEVEL(1) | VOLT_LEVEL(1) | AUTO_EXTVOLT; + PRCM_VOLTCTRL = val; + + /* Disable emulation tools functional clock */ + PRCM_CLKEMUL_CTRL = 0x0; + + /* Set core memory retention state */ + val = pmdomain_get_powerstate(PM_CORE_OFFSET); + if (cpu_is_omap2420()) { + val &= ~(0x7 << 3); + val |= (MEM3RETSTATE | MEM2RETSTATE | MEM1RETSTATE); + } else { + val &= ~(0xf << 3); + val |= (MEM4RETSTATE | MEM3RETSTATE | MEM2RETSTATE | + MEM1RETSTATE); + } + pmdomain_set_powerstate(val, PM_CORE_OFFSET); + + /* OCP interface smart idle. REVISIT: Enable autoidle bit0 ? */ + val = SMS_SYSCONFIG; + val &= ~(0x3 << 3); + val |= (0x2 << 3) | (1 << 0); + SMS_SYSCONFIG |= val; + + val = SDRC_SYSCONFIG; + val &= ~(0x3 << 3); + val |= (0x2 << 3); + SDRC_SYSCONFIG = val; + + /* Configure L3 interface for smart idle. + * REVISIT: Enable autoidle bit0 ? + */ + val = GPMC_SYSCONFIG; + val &= ~(0x3 << 3); + val |= (0x2 << 3) | (1 << 0); + GPMC_SYSCONFIG = val; + + pmdomain_set_powerstate(LOGICRETSTATE | POWERSTATE_RETENTION, + PM_MPU_OFFSET); + pmdomain_set_powerstate(POWERSTATE_RETENTION, PM_CORE_OFFSET); + if (!cpu_is_omap2420()) + pmdomain_set_powerstate(POWERSTATE_RETENTION, PM_MDM_OFFSET); + + /* Assume suspend function has saved the state for DSP and GFX */ + pmdomain_set_powerstate(FORCESTATE | POWERSTATE_OFF, PM_DSP_OFFSET); + pmdomain_set_powerstate(FORCESTATE | POWERSTATE_OFF, PM_GFX_OFFSET); + +#if 0 + /* REVISIT: Internal USB needs special handling */ + force_standby_usb(); + if (cpu_is_omap2430()) + force_hsmmc(); + sdram_self_refresh_on_idle_req(1); +#endif + + /* Enable clock auto control for all domains. + * Note that CORE domain includes also DSS, L4 & L3. + */ + pmdomain_set_clock_autocontrol(AUTOSTAT_MPU, PM_MPU_OFFSET); + pmdomain_set_clock_autocontrol(AUTOSTAT_GFX, PM_GFX_OFFSET); + pmdomain_set_clock_autocontrol(AUTOSTAT_DSS | AUTOSTAT_L4 | AUTOSTAT_L3, + PM_CORE_OFFSET); + if (cpu_is_omap2420()) + pmdomain_set_clock_autocontrol(AUTOSTAT_IVA | AUTOSTAT_DSP, + PM_DSP_OFFSET); + else { + pmdomain_set_clock_autocontrol(AUTOSTAT_DSP, PM_DSP_OFFSET); + pmdomain_set_clock_autocontrol(AUTOSTAT_MDM, PM_MDM_OFFSET); + } + + /* Enable clock autoidle for all domains */ + pmdomain_set_clock_autoidle1(0x2, PM_DSP_OFFSET); + if (cpu_is_omap2420()) { + pmdomain_set_clock_autoidle1(0xfffffff9, PM_CORE_OFFSET); + pmdomain_set_clock_autoidle2(0x7, PM_CORE_OFFSET); + pmdomain_set_clock_autoidle1(0x3f, PM_WKUP_OFFSET); + } else { + pmdomain_set_clock_autoidle1(0xeafffff1, PM_CORE_OFFSET); + pmdomain_set_clock_autoidle2(0xfff, PM_CORE_OFFSET); + pmdomain_set_clock_autoidle1(0x7f, PM_WKUP_OFFSET); + pmdomain_set_clock_autoidle1(0x3, PM_MDM_OFFSET); + } + pmdomain_set_clock_autoidle3(0x7, PM_CORE_OFFSET); + pmdomain_set_clock_autoidle4(0x1f, PM_CORE_OFFSET); +} + +/* + * Initializes power domains by removing wake-up dependencies and powering + * down DSP and GFX. Gets called from PM init. Note that DSP and IVA code + * must re-enable DSP and GFX when used. + */ +void __init pmdomain_init(void) +{ + /* Remove all domain wakeup dependencies */ + pmdomain_set_wakeup_dependencies(EN_WKUP | EN_CORE, PM_MPU_OFFSET); + pmdomain_set_wakeup_dependencies(0, PM_DSP_OFFSET); + pmdomain_set_wakeup_dependencies(0, PM_GFX_OFFSET); + pmdomain_set_wakeup_dependencies(EN_WKUP | EN_MPU, PM_CORE_OFFSET); + if (cpu_is_omap2430()) + pmdomain_set_wakeup_dependencies(0, PM_MDM_OFFSET); + + /* Power down DSP and GFX */ + pmdomain_set_powerstate(POWERSTATE_OFF | FORCESTATE, PM_DSP_OFFSET); + pmdomain_set_powerstate(POWERSTATE_OFF | FORCESTATE, PM_GFX_OFFSET); +} diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index 562168fa2b1..d7eee99b7e3 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -36,11 +37,18 @@ #include #include +#include "prcm-regs.h" + static struct clk *vclk; static void (*omap2_sram_idle)(void); static void (*omap2_sram_suspend)(int dllctrl, int cpu_rev); static void (*saved_idle)(void); +extern void __init pmdomain_init(void); +extern void pmdomain_set_autoidle(void); + +static unsigned int omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_SIZE]; + void omap2_pm_idle(void) { local_irq_disable(); @@ -87,23 +95,272 @@ static int omap2_pm_prepare(suspend_state_t state) return error; } +#define INT0_WAKE_MASK (OMAP_IRQ_BIT(INT_24XX_GPIO_BANK1) | \ + OMAP_IRQ_BIT(INT_24XX_GPIO_BANK2) | \ + OMAP_IRQ_BIT(INT_24XX_GPIO_BANK3)) + +#define INT1_WAKE_MASK (OMAP_IRQ_BIT(INT_24XX_GPIO_BANK4)) + +#define INT2_WAKE_MASK (OMAP_IRQ_BIT(INT_24XX_UART1_IRQ) | \ + OMAP_IRQ_BIT(INT_24XX_UART2_IRQ) | \ + OMAP_IRQ_BIT(INT_24XX_UART3_IRQ)) + +#define preg(reg) printk("%s\t(0x%p):\t0x%08x\n", #reg, ®, reg); + +static void omap2_pm_debug(char * desc) +{ + printk("%s:\n", desc); + + preg(CM_CLKSTCTRL_MPU); + preg(CM_CLKSTCTRL_CORE); + preg(CM_CLKSTCTRL_GFX); + preg(CM_CLKSTCTRL_DSP); + preg(CM_CLKSTCTRL_MDM); + + preg(PM_PWSTCTRL_MPU); + preg(PM_PWSTCTRL_CORE); + preg(PM_PWSTCTRL_GFX); + preg(PM_PWSTCTRL_DSP); + preg(PM_PWSTCTRL_MDM); + + preg(PM_PWSTST_MPU); + preg(PM_PWSTST_CORE); + preg(PM_PWSTST_GFX); + preg(PM_PWSTST_DSP); + preg(PM_PWSTST_MDM); + + preg(CM_AUTOIDLE1_CORE); + preg(CM_AUTOIDLE2_CORE); + preg(CM_AUTOIDLE3_CORE); + preg(CM_AUTOIDLE4_CORE); + preg(CM_AUTOIDLE_WKUP); + preg(CM_AUTOIDLE_PLL); + preg(CM_AUTOIDLE_DSP); + preg(CM_AUTOIDLE_MDM); + + preg(CM_ICLKEN1_CORE); + preg(CM_ICLKEN2_CORE); + preg(CM_ICLKEN3_CORE); + preg(CM_ICLKEN4_CORE); + preg(CM_ICLKEN_GFX); + preg(CM_ICLKEN_WKUP); + preg(CM_ICLKEN_DSP); + preg(CM_ICLKEN_MDM); + + preg(CM_IDLEST1_CORE); + preg(CM_IDLEST2_CORE); + preg(CM_IDLEST3_CORE); + preg(CM_IDLEST4_CORE); + preg(CM_IDLEST_GFX); + preg(CM_IDLEST_WKUP); + preg(CM_IDLEST_CKGEN); + preg(CM_IDLEST_DSP); + preg(CM_IDLEST_MDM); + + preg(RM_RSTST_MPU); + preg(RM_RSTST_GFX); + preg(RM_RSTST_WKUP); + preg(RM_RSTST_DSP); + preg(RM_RSTST_MDM); + + preg(PM_WKDEP_MPU); + preg(PM_WKDEP_CORE); + preg(PM_WKDEP_GFX); + preg(PM_WKDEP_DSP); + preg(PM_WKDEP_MDM); + + preg(CM_FCLKEN_WKUP); + preg(CM_ICLKEN_WKUP); + preg(CM_IDLEST_WKUP); + preg(CM_AUTOIDLE_WKUP); + preg(CM_CLKSEL_WKUP); + + preg(PM_WKEN_WKUP); + preg(PM_WKST_WKUP); +} + +static inline void omap2_pm_save_registers(void) +{ + /* Save interrupt registers */ + OMAP24XX_SAVE(INTC_MIR0); + OMAP24XX_SAVE(INTC_MIR1); + OMAP24XX_SAVE(INTC_MIR2); + + /* Save power control registers */ + OMAP24XX_SAVE(CM_CLKSTCTRL_MPU); + OMAP24XX_SAVE(CM_CLKSTCTRL_CORE); + OMAP24XX_SAVE(CM_CLKSTCTRL_GFX); + OMAP24XX_SAVE(CM_CLKSTCTRL_DSP); + OMAP24XX_SAVE(CM_CLKSTCTRL_MDM); + + /* Save power state registers */ + OMAP24XX_SAVE(PM_PWSTCTRL_MPU); + OMAP24XX_SAVE(PM_PWSTCTRL_CORE); + OMAP24XX_SAVE(PM_PWSTCTRL_GFX); + OMAP24XX_SAVE(PM_PWSTCTRL_DSP); + OMAP24XX_SAVE(PM_PWSTCTRL_MDM); + + /* Save autoidle registers */ + OMAP24XX_SAVE(CM_AUTOIDLE1_CORE); + OMAP24XX_SAVE(CM_AUTOIDLE2_CORE); + OMAP24XX_SAVE(CM_AUTOIDLE3_CORE); + OMAP24XX_SAVE(CM_AUTOIDLE4_CORE); + OMAP24XX_SAVE(CM_AUTOIDLE_WKUP); + OMAP24XX_SAVE(CM_AUTOIDLE_PLL); + OMAP24XX_SAVE(CM_AUTOIDLE_DSP); + OMAP24XX_SAVE(CM_AUTOIDLE_MDM); + + /* Save idle state registers */ + OMAP24XX_SAVE(CM_IDLEST1_CORE); + OMAP24XX_SAVE(CM_IDLEST2_CORE); + OMAP24XX_SAVE(CM_IDLEST3_CORE); + OMAP24XX_SAVE(CM_IDLEST4_CORE); + OMAP24XX_SAVE(CM_IDLEST_GFX); + OMAP24XX_SAVE(CM_IDLEST_WKUP); + OMAP24XX_SAVE(CM_IDLEST_CKGEN); + OMAP24XX_SAVE(CM_IDLEST_DSP); + OMAP24XX_SAVE(CM_IDLEST_MDM); + + /* Save clock registers */ + OMAP24XX_SAVE(CM_FCLKEN1_CORE); + OMAP24XX_SAVE(CM_FCLKEN2_CORE); + OMAP24XX_SAVE(CM_ICLKEN1_CORE); + OMAP24XX_SAVE(CM_ICLKEN2_CORE); + OMAP24XX_SAVE(CM_ICLKEN3_CORE); + OMAP24XX_SAVE(CM_ICLKEN4_CORE); +} + +static inline void omap2_pm_restore_registers(void) +{ + /* Restore clock state registers */ + OMAP24XX_RESTORE(CM_CLKSTCTRL_MPU); + OMAP24XX_RESTORE(CM_CLKSTCTRL_CORE); + OMAP24XX_RESTORE(CM_CLKSTCTRL_GFX); + OMAP24XX_RESTORE(CM_CLKSTCTRL_DSP); + OMAP24XX_RESTORE(CM_CLKSTCTRL_MDM); + + /* Restore power state registers */ + OMAP24XX_RESTORE(PM_PWSTCTRL_MPU); + OMAP24XX_RESTORE(PM_PWSTCTRL_CORE); + OMAP24XX_RESTORE(PM_PWSTCTRL_GFX); + OMAP24XX_RESTORE(PM_PWSTCTRL_DSP); + OMAP24XX_RESTORE(PM_PWSTCTRL_MDM); + + /* Restore idle state registers */ + OMAP24XX_RESTORE(CM_IDLEST1_CORE); + OMAP24XX_RESTORE(CM_IDLEST2_CORE); + OMAP24XX_RESTORE(CM_IDLEST3_CORE); + OMAP24XX_RESTORE(CM_IDLEST4_CORE); + OMAP24XX_RESTORE(CM_IDLEST_GFX); + OMAP24XX_RESTORE(CM_IDLEST_WKUP); + OMAP24XX_RESTORE(CM_IDLEST_CKGEN); + OMAP24XX_RESTORE(CM_IDLEST_DSP); + OMAP24XX_RESTORE(CM_IDLEST_MDM); + + /* Restore autoidle registers */ + OMAP24XX_RESTORE(CM_AUTOIDLE1_CORE); + OMAP24XX_RESTORE(CM_AUTOIDLE2_CORE); + OMAP24XX_RESTORE(CM_AUTOIDLE3_CORE); + OMAP24XX_RESTORE(CM_AUTOIDLE4_CORE); + OMAP24XX_RESTORE(CM_AUTOIDLE_WKUP); + OMAP24XX_RESTORE(CM_AUTOIDLE_PLL); + OMAP24XX_RESTORE(CM_AUTOIDLE_DSP); + OMAP24XX_RESTORE(CM_AUTOIDLE_MDM); + + /* Restore clock registers */ + OMAP24XX_RESTORE(CM_FCLKEN1_CORE); + OMAP24XX_RESTORE(CM_FCLKEN2_CORE); + OMAP24XX_RESTORE(CM_ICLKEN1_CORE); + OMAP24XX_RESTORE(CM_ICLKEN2_CORE); + OMAP24XX_RESTORE(CM_ICLKEN3_CORE); + OMAP24XX_RESTORE(CM_ICLKEN4_CORE); + + /* REVISIT: Clear interrupts here */ + + /* Restore interrupt registers */ + OMAP24XX_RESTORE(INTC_MIR0); + OMAP24XX_RESTORE(INTC_MIR1); + OMAP24XX_RESTORE(INTC_MIR2); +} + +static int omap2_pm_suspend(void) +{ + int processor_type = 0; + + /* REVISIT: 0x21 or 0x26? */ + if (cpu_is_omap2420()) + processor_type = 0x21; + + if (!processor_type) + return -ENOTSUPP; + + local_irq_disable(); + local_fiq_disable(); + + omap2_pm_save_registers(); + + /* Disable interrupts except for the wake events */ + INTC_MIR_SET0 = 0xffffffff & ~INT0_WAKE_MASK; + INTC_MIR_SET1 = 0xffffffff & ~INT1_WAKE_MASK; + INTC_MIR_SET2 = 0xffffffff & ~INT2_WAKE_MASK; + + pmdomain_set_autoidle(); + + /* Clear old wake-up events */ + PM_WKST1_CORE = 0; + PM_WKST2_CORE = 0; + PM_WKST_WKUP = 0; + + /* Enable wake-up events */ + PM_WKEN1_CORE = (1 << 22) | (1 << 21); /* UART1 & 2 */ + PM_WKEN2_CORE = (1 << 2); /* UART3 */ + PM_WKEN_WKUP = (1 << 2) | (1 << 0); /* GPIO & GPT1 */ + + /* Disable clocks except for CM_ICLKEN2_CORE. It gets disabled + * in the SRAM suspend code */ + CM_FCLKEN1_CORE = 0; + CM_FCLKEN2_CORE = 0; + CM_ICLKEN1_CORE = 0; + CM_ICLKEN3_CORE = 0; + CM_ICLKEN4_CORE = 0; + + omap2_pm_debug("Status before suspend"); + + /* Must wait for serial buffers to clear */ + mdelay(200); + + /* Jump to SRAM suspend code + * REVISIT: When is this SDRC_DLLB_CTRL? + */ + omap2_sram_suspend(SDRC_DLLA_CTRL, processor_type); + + /* Back from sleep */ + omap2_pm_restore_registers(); + + local_fiq_enable(); + local_irq_enable(); + + return 0; +} + static int omap2_pm_enter(suspend_state_t state) { + int ret = 0; + switch (state) { case PM_SUSPEND_STANDBY: case PM_SUSPEND_MEM: - /* FIXME: Add suspend */ + ret = omap2_pm_suspend(); break; - case PM_SUSPEND_DISK: - return -ENOTSUPP; - + ret = -ENOTSUPP; + break; default: - return -EINVAL; + ret = -EINVAL; } - return 0; + return ret; } static int omap2_pm_finish(suspend_state_t state) @@ -143,6 +400,8 @@ int __init omap2_pm_init(void) pm_set_ops(&omap_pm_ops); pm_idle = omap2_pm_idle; + pmdomain_init(); + return 0; } -- cgit v1.2.3 From 5ac4215349163baa66c9a26a94e220dcb6c44050 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 26 Jun 2006 16:16:20 -0700 Subject: ARM: OMAP: Mux updates for external DMA and GPIO Mux updates for external DMA and GPIO. GPIO updates by Igor Stoppa. Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/mux.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c index 1197dc38c20..fa9000ed0b5 100644 --- a/arch/arm/mach-omap2/mux.c +++ b/arch/arm/mach-omap2/mux.c @@ -60,18 +60,38 @@ MUX_CFG_24XX("W15_24XX_MCBSP2_DR", 0x126, 1, 1, 0, 1) MUX_CFG_24XX("V15_24XX_MCBSP2_DX", 0x127, 1, 1, 0, 1) /* 24xx GPIO */ -MUX_CFG_24XX("M21_242X_GPIO11", 0x0c9, 3, 1, 1, 1) +MUX_CFG_24XX("M21_242X_GPIO11", 0x0c9, 3, 1, 1, 1) MUX_CFG_24XX("AA10_242X_GPIO13", 0x0e5, 3, 0, 0, 1) -MUX_CFG_24XX("AA6_242X_GPIO14", 0x0e6, 3, 0, 0, 1) -MUX_CFG_24XX("AA4_242X_GPIO15", 0x0e7, 3, 0, 0, 1) -MUX_CFG_24XX("Y11_242X_GPIO16", 0x0e8, 3, 0, 0, 1) +MUX_CFG_24XX("AA6_242X_GPIO14", 0x0e6, 3, 0, 0, 1) +MUX_CFG_24XX("AA4_242X_GPIO15", 0x0e7, 3, 0, 0, 1) +MUX_CFG_24XX("Y11_242X_GPIO16", 0x0e8, 3, 0, 0, 1) MUX_CFG_24XX("AA12_242X_GPIO17", 0x0e9, 3, 0, 0, 1) -MUX_CFG_24XX("AA8_242X_GPIO58", 0x0ea, 3, 0, 0, 1) +MUX_CFG_24XX("AA8_242X_GPIO58", 0x0ea, 3, 0, 0, 1) MUX_CFG_24XX("Y20_24XX_GPIO60", 0x12c, 3, 0, 0, 1) -MUX_CFG_24XX("W4__24XX_GPIO74", 0x0f2, 3, 0, 0, 1) +MUX_CFG_24XX("W4__24XX_GPIO74", 0x0f2, 3, 0, 0, 1) MUX_CFG_24XX("M15_24XX_GPIO92", 0x10a, 3, 0, 0, 1) MUX_CFG_24XX("V14_24XX_GPIO117", 0x128, 3, 1, 0, 1) +/* 242x DBG GPIO */ +MUX_CFG_24XX("V4_242X_GPIO49", 0xd3, 3, 0, 0, 1) +MUX_CFG_24XX("W2_242X_GPIO50", 0xd4, 3, 0, 0, 1) +MUX_CFG_24XX("U4_242X_GPIO51", 0xd5, 3, 0, 0, 1) +MUX_CFG_24XX("V3_242X_GPIO52", 0xd6, 3, 0, 0, 1) +MUX_CFG_24XX("V2_242X_GPIO53", 0xd7, 3, 0, 0, 1) +MUX_CFG_24XX("V6_242X_GPIO53", 0xcf, 3, 0, 0, 1) +MUX_CFG_24XX("T4_242X_GPIO54", 0xd8, 3, 0, 0, 1) +MUX_CFG_24XX("Y4_242X_GPIO54", 0xd0, 3, 0, 0, 1) +MUX_CFG_24XX("T3_242X_GPIO55", 0xd9, 3, 0, 0, 1) +MUX_CFG_24XX("U2_242X_GPIO56", 0xda, 3, 0, 0, 1) + +/* 24xx external DMA requests */ +MUX_CFG_24XX("AA10_242X_DMAREQ0", 0x0e5, 2, 0, 0, 1) +MUX_CFG_24XX("AA6_242X_DMAREQ1", 0x0e6, 2, 0, 0, 1) +MUX_CFG_24XX("E4_242X_DMAREQ2", 0x074, 2, 0, 0, 1) +MUX_CFG_24XX("G4_242X_DMAREQ3", 0x073, 2, 0, 0, 1) +MUX_CFG_24XX("D3_242X_DMAREQ4", 0x072, 2, 0, 0, 1) +MUX_CFG_24XX("E3_242X_DMAREQ5", 0x071, 2, 0, 0, 1) + /* TSC IRQ */ MUX_CFG_24XX("P20_24XX_TSC_IRQ", 0x108, 0, 0, 0, 1) -- cgit v1.2.3 From 2aab6468b7f88df60828f8e07cfdf8c87338ed8d Mon Sep 17 00:00:00 2001 From: Juha Yrjola Date: Mon, 26 Jun 2006 16:16:21 -0700 Subject: ARM: OMAP: Fix GPMC compilation when DEBUG is defined Signed-off-by: Juha Yrjola Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/gpmc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 4aeaa4e7958..c7a48f921fe 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -90,7 +90,7 @@ unsigned int gpmc_ns_to_ticks(unsigned int time_ns) #ifdef DEBUG static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit, - int time, int div, const char *name) + int time, const char *name) #else static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit, int time) @@ -111,7 +111,7 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit, l = gpmc_cs_read_reg(cs, reg); #ifdef DEBUG printk(KERN_INFO "GPMC CS%d: %-10s: %d ticks, %3lu ns (was %i ticks)\n", - cs, name, ticks, gpmc_get_clk_period(div) * ticks / 1000, + cs, name, ticks, gpmc_get_fclk_period() * ticks / 1000, (l >> st_bit) & mask); #endif l &= ~(mask << st_bit); @@ -176,8 +176,8 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t) GPMC_SET_ONE(GPMC_CS_CONFIG5, 24, 27, page_burst_access); #ifdef DEBUG - printk(KERN_INFO "GPMC CLK period is %d (div %d)\n", - cs, get_gpmc_clk_period(div), div); + printk(KERN_INFO "GPMC CS%d CLK period is %lu (div %d)\n", + cs, gpmc_get_fclk_period(), div); #endif l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1); -- cgit v1.2.3 From 7df3450e5c22ba3969e4253dce0d7807dd210bf0 Mon Sep 17 00:00:00 2001 From: Juha Yrjola Date: Mon, 26 Jun 2006 16:16:22 -0700 Subject: ARM: OMAP: Make clock variables static Since the mutex protecting the clock list is static, the list itself should be too. Signed-off-by: Juha Yrjola Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/clock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c index 32ec04c58bc..dcd9d81201f 100644 --- a/arch/arm/plat-omap/clock.c +++ b/arch/arm/plat-omap/clock.c @@ -28,9 +28,9 @@ #include -LIST_HEAD(clocks); +static LIST_HEAD(clocks); static DEFINE_MUTEX(clocks_mutex); -DEFINE_SPINLOCK(clockfw_lock); +static DEFINE_SPINLOCK(clockfw_lock); static struct clk_functions *arch_clock; -- cgit v1.2.3 From 83379c81f6f05a6e80db66ae33378feb4cbca6b3 Mon Sep 17 00:00:00 2001 From: Timo Teras Date: Mon, 26 Jun 2006 16:16:23 -0700 Subject: ARM: OMAP: Update dmtimers - Initialize timer outside of spinlock to reduce the time the spinlock is held - Do clk_get to the source clocks during initialization to avoid sleeping later - New function to set counter register Signed-off-by: Timo Teras Signed-off-by: Juha Yrjola Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/dmtimer.c | 46 +++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 16 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index bfccebc7751..804a5353437 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -107,6 +107,14 @@ static struct omap_dm_timer dm_timers[] = { { .phys_base = 0x4808a000, .irq = INT_24XX_GPTIMER12 }, }; +static const char *dm_source_names[] = { + "sys_ck", + "func_32k_ck", + "alt_ck" +}; + +static struct clk *dm_source_clocks[3]; + #else #error OMAP architecture not supported! @@ -114,7 +122,6 @@ static struct omap_dm_timer dm_timers[] = { #endif static const int dm_timer_count = ARRAY_SIZE(dm_timers); - static spinlock_t dm_timer_lock; static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg) @@ -159,9 +166,8 @@ static void omap_dm_timer_reset(struct omap_dm_timer *timer) omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, l); } -static void omap_dm_timer_reserve(struct omap_dm_timer *timer) +static void omap_dm_timer_prepare(struct omap_dm_timer *timer) { - timer->reserved = 1; #ifdef CONFIG_ARCH_OMAP2 clk_enable(timer->iclk); clk_enable(timer->fclk); @@ -181,11 +187,14 @@ struct omap_dm_timer *omap_dm_timer_request(void) continue; timer = &dm_timers[i]; - omap_dm_timer_reserve(timer); + timer->reserved = 1; break; } spin_unlock_irqrestore(&dm_timer_lock, flags); + if (timer != NULL) + omap_dm_timer_prepare(timer); + return timer; } @@ -204,9 +213,11 @@ struct omap_dm_timer *omap_dm_timer_request_specific(int id) } timer = &dm_timers[id-1]; - omap_dm_timer_reserve(timer); + timer->reserved = 1; spin_unlock_irqrestore(&dm_timer_lock, flags); + omap_dm_timer_prepare(timer); + return timer; } @@ -318,21 +329,12 @@ void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) { - static const char *source_timers[] = { - "sys_ck", - "func_32k_ck", - "alt_ck" - }; - struct clk *parent; - if (source < 0 || source >= 3) return; - parent = clk_get(NULL, source_timers[source]); clk_disable(timer->fclk); - clk_set_parent(timer->fclk, parent); + clk_set_parent(timer->fclk, dm_source_clocks[source]); clk_enable(timer->fclk); - clk_put(parent); /* When the functional clock disappears, too quick writes seem to * cause an abort. */ @@ -362,7 +364,7 @@ void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable, u32 l; l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); - if (enable) + if (enable) l |= OMAP_TIMER_CTRL_CE; else l &= ~OMAP_TIMER_CTRL_CE; @@ -421,6 +423,11 @@ unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer) return omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG); } +void omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value) +{ + return omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value); +} + int omap_dm_timers_active(void) { int i; @@ -445,6 +452,13 @@ int omap_dm_timer_init(void) return -ENODEV; spin_lock_init(&dm_timer_lock); +#ifdef CONFIG_ARCH_OMAP2 + for (i = 0; i < ARRAY_SIZE(dm_source_names); i++) { + dm_source_clocks[i] = clk_get(NULL, dm_source_names[i]); + BUG_ON(dm_source_clocks[i] == NULL); + } +#endif + for (i = 0; i < dm_timer_count; i++) { #ifdef CONFIG_ARCH_OMAP2 char clk_name[16]; -- cgit v1.2.3 From ce2deca27acc761ab90a0e79bd31d6816df38960 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 26 Jun 2006 16:16:24 -0700 Subject: ARM: OMAP: Fix SRAM to use MT_MEMORY instead of MT_DEVICE MT_MEMORY is needed in order to execute code in SRAM. Also need to use section mapping. Based on a patch by Richard Woodruff. Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/sram.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c index b7bf09b1b41..aebd06faf2c 100644 --- a/arch/arm/plat-omap/sram.c +++ b/arch/arm/plat-omap/sram.c @@ -158,14 +158,12 @@ static struct map_desc omap_sram_io_desc[] __initdata = { { /* .length gets filled in at runtime */ .virtual = OMAP1_SRAM_VA, .pfn = __phys_to_pfn(OMAP1_SRAM_PA), - .type = MT_DEVICE + .type = MT_MEMORY } }; /* - * In order to use last 2kB of SRAM on 1611b, we must round the size - * up to multiple of PAGE_SIZE. We cannot use ioremap for SRAM, as - * clock init needs SRAM early. + * Note that we cannot use ioremap for SRAM, as clock init needs SRAM early. */ void __init omap_map_sram(void) { @@ -185,8 +183,7 @@ void __init omap_map_sram(void) omap_sram_io_desc[0].pfn = __phys_to_pfn(base); } - omap_sram_io_desc[0].length = (omap_sram_size + PAGE_SIZE-1)/PAGE_SIZE; - omap_sram_io_desc[0].length *= PAGE_SIZE; + omap_sram_io_desc[0].length = 1024 * 1024; /* Use section desc */ iotable_init(omap_sram_io_desc, ARRAY_SIZE(omap_sram_io_desc)); printk(KERN_INFO "SRAM: Mapped pa 0x%08lx to va 0x%08lx size: 0x%lx\n", -- cgit v1.2.3 From 3cbc96050b02d8e5764bd0970067ef294737e324 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 26 Jun 2006 16:16:25 -0700 Subject: ARM: OMAP: Multiplexing for 24xx GPMC wait pin monitoring Multiplexing for 24xx GPMC wait pin monitoring Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/mux.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c index fa9000ed0b5..c2c482cd1cb 100644 --- a/arch/arm/mach-omap2/mux.c +++ b/arch/arm/mach-omap2/mux.c @@ -53,6 +53,12 @@ MUX_CFG_24XX("W19_24XX_SYS_NIRQ", 0x12c, 0, 1, 1, 1) /* 24xx clocks */ MUX_CFG_24XX("W14_24XX_SYS_CLKOUT", 0x137, 0, 1, 1, 1) +/* 24xx GPMC wait pin monitoring */ +MUX_CFG_24XX("L3_GPMC_WAIT0", 0x09a, 0, 1, 1, 1) +MUX_CFG_24XX("N7_GPMC_WAIT1", 0x09b, 0, 1, 1, 1) +MUX_CFG_24XX("M1_GPMC_WAIT2", 0x09c, 0, 1, 1, 1) +MUX_CFG_24XX("P1_GPMC_WAIT3", 0x09d, 0, 1, 1, 1) + /* 24xx McBSP */ MUX_CFG_24XX("Y15_24XX_MCBSP2_CLKX", 0x124, 1, 1, 0, 1) MUX_CFG_24XX("R14_24XX_MCBSP2_FSX", 0x125, 1, 1, 0, 1) -- cgit v1.2.3