diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-10-06 16:01:27 +0100 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-10-06 16:01:27 +0100 |
commit | 907bc6c7fc7071b00083fc11e510e47dd93df45d (patch) | |
tree | 0697a608561522c00da9e1814974a2eb051bb96d /arch/arm/mach-omap2 | |
parent | d2b247a8be57647d1745535acd58169fbcbe431a (diff) | |
parent | 2a0f5cb32772e9a9560209e241a80bfbbc31dbc3 (diff) |
Merge branch 'for-2.6.32' into for-2.6.33
Diffstat (limited to 'arch/arm/mach-omap2')
59 files changed, 4725 insertions, 586 deletions
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index a755eb5e236..75b1c7efae7 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -31,6 +31,11 @@ config MACH_OMAP_GENERIC bool "Generic OMAP board" depends on ARCH_OMAP2 && ARCH_OMAP24XX +config MACH_OMAP2_TUSB6010 + bool + depends on ARCH_OMAP2 && ARCH_OMAP2420 + default y if MACH_NOKIA_N8X0 + config MACH_OMAP_H4 bool "OMAP 2420 H4 board" depends on ARCH_OMAP2 && ARCH_OMAP24XX @@ -68,6 +73,10 @@ config MACH_OMAP_3430SDP bool "OMAP 3430 SDP board" depends on ARCH_OMAP3 && ARCH_OMAP34XX +config MACH_NOKIA_N8X0 + bool "Nokia N800/N810" + depends on ARCH_OMAP2420 + config MACH_NOKIA_RX51 bool "Nokia RX-51 board" depends on ARCH_OMAP3 && ARCH_OMAP34XX diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 735bae5b0de..8cb16777661 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -5,7 +5,7 @@ # Common support obj-y := id.o io.o control.o mux.o devices.o serial.o gpmc.o timer-gp.o -omap-2-3-common = irq.o sdrc.o +omap-2-3-common = irq.o sdrc.o omap_hwmod.o prcm-common = prcm.o powerdomain.o clock-common = clock.o clockdomain.o @@ -35,6 +35,11 @@ obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o obj-$(CONFIG_PM_DEBUG) += pm-debug.o endif +# PRCM +obj-$(CONFIG_ARCH_OMAP2) += cm.o +obj-$(CONFIG_ARCH_OMAP3) += cm.o +obj-$(CONFIG_ARCH_OMAP4) += cm4xxx.o + # Clock framework obj-$(CONFIG_ARCH_OMAP2) += clock24xx.o obj-$(CONFIG_ARCH_OMAP3) += clock34xx.o @@ -62,7 +67,7 @@ obj-$(CONFIG_MACH_OMAP3_PANDORA) += board-omap3pandora.o \ mmc-twl4030.o obj-$(CONFIG_MACH_OMAP_3430SDP) += board-3430sdp.o \ mmc-twl4030.o - +obj-$(CONFIG_MACH_NOKIA_N8X0) += board-n8x0.o obj-$(CONFIG_MACH_NOKIA_RX51) += board-rx51.o \ board-rx51-peripherals.o \ mmc-twl4030.o @@ -74,6 +79,7 @@ obj-$(CONFIG_MACH_OMAP_4430SDP) += board-4430sdp.o # Platform specific device init code obj-y += usb-musb.o +obj-$(CONFIG_MACH_OMAP2_TUSB6010) += usb-tusb6010.o onenand-$(CONFIG_MTD_ONENAND_OMAP2) := gpmc-onenand.o obj-y += $(onenand-m) $(onenand-y) diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c index 9c3fdcdf76c..42217b32f83 100644 --- a/arch/arm/mach-omap2/board-2430sdp.c +++ b/arch/arm/mach-omap2/board-2430sdp.c @@ -139,23 +139,19 @@ static inline void board_smc91x_init(void) #endif +static struct omap_board_config_kernel sdp2430_config[] = { + {OMAP_TAG_LCD, &sdp2430_lcd_config}, +}; + static void __init omap_2430sdp_init_irq(void) { - omap2_init_common_hw(NULL); + omap_board_config = sdp2430_config; + omap_board_config_size = ARRAY_SIZE(sdp2430_config); + omap2_init_common_hw(NULL, NULL); omap_init_irq(); omap_gpio_init(); } -static struct omap_uart_config sdp2430_uart_config __initdata = { - .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), -}; - -static struct omap_board_config_kernel sdp2430_config[] = { - {OMAP_TAG_UART, &sdp2430_uart_config}, - {OMAP_TAG_LCD, &sdp2430_lcd_config}, -}; - - static struct twl4030_gpio_platform_data sdp2430_gpio_data = { .gpio_base = OMAP_MAX_GPIO_LINES, .irq_base = TWL4030_GPIO_IRQ_BASE, @@ -205,8 +201,6 @@ static void __init omap_2430sdp_init(void) omap2430_i2c_init(); platform_add_devices(sdp2430_devices, ARRAY_SIZE(sdp2430_devices)); - omap_board_config = sdp2430_config; - omap_board_config_size = ARRAY_SIZE(sdp2430_config); omap_serial_init(); twl4030_mmc_init(mmc); usb_musb_init(); diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c index 496a90e4ea7..efaf053eba8 100644 --- a/arch/arm/mach-omap2/board-3430sdp.c +++ b/arch/arm/mach-omap2/board-3430sdp.c @@ -54,7 +54,7 @@ #define TWL4030_MSECURE_GPIO 22 -static int sdp3430_keymap[] = { +static int board_keymap[] = { KEY(0, 0, KEY_LEFT), KEY(0, 1, KEY_RIGHT), KEY(0, 2, KEY_A), @@ -88,11 +88,15 @@ static int sdp3430_keymap[] = { 0 }; +static struct matrix_keymap_data board_map_data = { + .keymap = board_keymap, + .keymap_size = ARRAY_SIZE(board_keymap), +}; + static struct twl4030_keypad_data sdp3430_kp_data = { + .keymap_data = &board_map_data, .rows = 5, .cols = 6, - .keymap = sdp3430_keymap, - .keymapsize = ARRAY_SIZE(sdp3430_keymap), .rep = 1, }; @@ -167,26 +171,23 @@ static struct platform_device *sdp3430_devices[] __initdata = { &sdp3430_lcd_device, }; -static void __init omap_3430sdp_init_irq(void) -{ - omap2_init_common_hw(hyb18m512160af6_sdrc_params); - omap_init_irq(); - omap_gpio_init(); -} - -static struct omap_uart_config sdp3430_uart_config __initdata = { - .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), -}; - static struct omap_lcd_config sdp3430_lcd_config __initdata = { .ctrl_name = "internal", }; static struct omap_board_config_kernel sdp3430_config[] __initdata = { - { OMAP_TAG_UART, &sdp3430_uart_config }, { OMAP_TAG_LCD, &sdp3430_lcd_config }, }; +static void __init omap_3430sdp_init_irq(void) +{ + omap_board_config = sdp3430_config; + omap_board_config_size = ARRAY_SIZE(sdp3430_config); + omap2_init_common_hw(hyb18m512160af6_sdrc_params, NULL); + omap_init_irq(); + omap_gpio_init(); +} + static int sdp3430_batt_table[] = { /* 0 C*/ 30800, 29500, 28300, 27100, @@ -478,12 +479,15 @@ static inline void board_smc91x_init(void) #endif +static void enable_board_wakeup_source(void) +{ + omap_cfg_reg(AF26_34XX_SYS_NIRQ); /* T2 interrupt line (keypad) */ +} + static void __init omap_3430sdp_init(void) { omap3430_i2c_init(); platform_add_devices(sdp3430_devices, ARRAY_SIZE(sdp3430_devices)); - omap_board_config = sdp3430_config; - omap_board_config_size = ARRAY_SIZE(sdp3430_config); if (omap_rev() > OMAP3430_REV_ES1_0) ts_gpio = SDP3430_TS_GPIO_IRQ_SDPV2; else @@ -495,6 +499,7 @@ static void __init omap_3430sdp_init(void) omap_serial_init(); usb_musb_init(); board_smc91x_init(); + enable_board_wakeup_source(); } static void __init omap_3430sdp_map_io(void) diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index 57e477bd89c..eb37c40ea83 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -39,7 +39,7 @@ static struct platform_device *sdp4430_devices[] __initdata = { }; static struct omap_uart_config sdp4430_uart_config __initdata = { - .enabled_uarts = (1 << 0) | (1 << 1) | (1 << 2), + .enabled_uarts = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3), }; static struct omap_lcd_config sdp4430_lcd_config __initdata = { @@ -47,19 +47,18 @@ static struct omap_lcd_config sdp4430_lcd_config __initdata = { }; static struct omap_board_config_kernel sdp4430_config[] __initdata = { - { OMAP_TAG_UART, &sdp4430_uart_config }, { OMAP_TAG_LCD, &sdp4430_lcd_config }, }; static void __init gic_init_irq(void) { - gic_dist_init(0, IO_ADDRESS(OMAP44XX_GIC_DIST_BASE), 29); - gic_cpu_init(0, IO_ADDRESS(OMAP44XX_GIC_CPU_BASE)); + gic_dist_init(0, OMAP2_IO_ADDRESS(OMAP44XX_GIC_DIST_BASE), 29); + gic_cpu_init(0, OMAP2_IO_ADDRESS(OMAP44XX_GIC_CPU_BASE)); } static void __init omap_4430sdp_init_irq(void) { - omap2_init_common_hw(NULL); + omap2_init_common_hw(NULL, NULL); #ifdef CONFIG_OMAP_32K_TIMER omap2_gp_clockevent_set_gptimer(1); #endif diff --git a/arch/arm/mach-omap2/board-apollon.c b/arch/arm/mach-omap2/board-apollon.c index 06dfba888b0..a1132288c70 100644 --- a/arch/arm/mach-omap2/board-apollon.c +++ b/arch/arm/mach-omap2/board-apollon.c @@ -87,7 +87,7 @@ static struct mtd_partition apollon_partitions[] = { }, }; -static struct flash_platform_data apollon_flash_data = { +static struct onenand_platform_data apollon_flash_data = { .parts = apollon_partitions, .nr_parts = ARRAY_SIZE(apollon_partitions), }; @@ -99,7 +99,7 @@ static struct resource apollon_flash_resource[] = { }; static struct platform_device apollon_onenand_device = { - .name = "onenand", + .name = "onenand-flash", .id = -1, .dev = { .platform_data = &apollon_flash_data, @@ -248,18 +248,6 @@ out: clk_put(gpmc_fck); } -static void __init omap_apollon_init_irq(void) -{ - omap2_init_common_hw(NULL); - omap_init_irq(); - omap_gpio_init(); - apollon_init_smc91x(); -} - -static struct omap_uart_config apollon_uart_config __initdata = { - .enabled_uarts = (1 << 0) | (0 << 1) | (0 << 2), -}; - static struct omap_usb_config apollon_usb_config __initdata = { .register_dev = 1, .hmc_mode = 0x14, /* 0:dev 1:host1 2:disable */ @@ -272,10 +260,19 @@ static struct omap_lcd_config apollon_lcd_config __initdata = { }; static struct omap_board_config_kernel apollon_config[] = { - { OMAP_TAG_UART, &apollon_uart_config }, { OMAP_TAG_LCD, &apollon_lcd_config }, }; +static void __init omap_apollon_init_irq(void) +{ + omap_board_config = apollon_config; + omap_board_config_size = ARRAY_SIZE(apollon_config); + omap2_init_common_hw(NULL, NULL); + omap_init_irq(); + omap_gpio_init(); + apollon_init_smc91x(); +} + static void __init apollon_led_init(void) { /* LED0 - AA10 */ @@ -324,8 +321,6 @@ static void __init omap_apollon_init(void) * if not needed. */ platform_add_devices(apollon_devices, ARRAY_SIZE(apollon_devices)); - omap_board_config = apollon_config; - omap_board_config_size = ARRAY_SIZE(apollon_config); omap_serial_init(); } diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c index 3492162a65c..2e09a1c444c 100644 --- a/arch/arm/mach-omap2/board-generic.c +++ b/arch/arm/mach-omap2/board-generic.c @@ -31,24 +31,19 @@ #include <mach/board.h> #include <mach/common.h> +static struct omap_board_config_kernel generic_config[] = { +}; + static void __init omap_generic_init_irq(void) { - omap2_init_common_hw(NULL); + omap_board_config = generic_config; + omap_board_config_size = ARRAY_SIZE(generic_config); + omap2_init_common_hw(NULL, NULL); omap_init_irq(); } -static struct omap_uart_config generic_uart_config __initdata = { - .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), -}; - -static struct omap_board_config_kernel generic_config[] = { - { OMAP_TAG_UART, &generic_uart_config }, -}; - static void __init omap_generic_init(void) { - omap_board_config = generic_config; - omap_board_config_size = ARRAY_SIZE(generic_config); omap_serial_init(); } diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c index e7d017cdc43..eaa02d012c5 100644 --- a/arch/arm/mach-omap2/board-h4.c +++ b/arch/arm/mach-omap2/board-h4.c @@ -268,18 +268,6 @@ static void __init h4_init_flash(void) h4_flash_resource.end = base + SZ_64M - 1; } -static void __init omap_h4_init_irq(void) -{ - omap2_init_common_hw(NULL); - omap_init_irq(); - omap_gpio_init(); - h4_init_flash(); -} - -static struct omap_uart_config h4_uart_config __initdata = { - .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), -}; - static struct omap_lcd_config h4_lcd_config __initdata = { .ctrl_name = "internal", }; @@ -318,10 +306,19 @@ static struct omap_usb_config h4_usb_config __initdata = { }; static struct omap_board_config_kernel h4_config[] = { - { OMAP_TAG_UART, &h4_uart_config }, { OMAP_TAG_LCD, &h4_lcd_config }, }; +static void __init omap_h4_init_irq(void) +{ + omap_board_config = h4_config; + omap_board_config_size = ARRAY_SIZE(h4_config); + omap2_init_common_hw(NULL, NULL); + omap_init_irq(); + omap_gpio_init(); + h4_init_flash(); +} + static struct at24_platform_data m24c01 = { .byte_len = SZ_1K / 8, .page_size = 16, @@ -366,8 +363,6 @@ static void __init omap_h4_init(void) ARRAY_SIZE(h4_i2c_board_info)); platform_add_devices(h4_devices, ARRAY_SIZE(h4_devices)); - omap_board_config = h4_config; - omap_board_config_size = ARRAY_SIZE(h4_config); omap_usb_init(&h4_usb_config); omap_serial_init(); } diff --git a/arch/arm/mach-omap2/board-ldp.c b/arch/arm/mach-omap2/board-ldp.c index d8bc0a7dcb8..d110a7fdfbd 100644 --- a/arch/arm/mach-omap2/board-ldp.c +++ b/arch/arm/mach-omap2/board-ldp.c @@ -80,7 +80,7 @@ static struct platform_device ldp_smsc911x_device = { }, }; -static int ldp_twl4030_keymap[] = { +static int board_keymap[] = { KEY(0, 0, KEY_1), KEY(1, 0, KEY_2), KEY(2, 0, KEY_3), @@ -101,11 +101,15 @@ static int ldp_twl4030_keymap[] = { 0 }; +static struct matrix_keymap_data board_map_data = { + .keymap = board_keymap, + .keymap_size = ARRAY_SIZE(board_keymap), +}; + static struct twl4030_keypad_data ldp_kp_twl4030_data = { + .keymap_data = &board_map_data, .rows = 6, .cols = 6, - .keymap = ldp_twl4030_keymap, - .keymapsize = ARRAY_SIZE(ldp_twl4030_keymap), .rep = 1, }; @@ -268,18 +272,6 @@ static inline void __init ldp_init_smsc911x(void) gpio_direction_input(eth_gpio); } -static void __init omap_ldp_init_irq(void) -{ - omap2_init_common_hw(NULL); - omap_init_irq(); - omap_gpio_init(); - ldp_init_smsc911x(); -} - -static struct omap_uart_config ldp_uart_config __initdata = { - .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), -}; - static struct platform_device ldp_lcd_device = { .name = "ldp_lcd", .id = -1, @@ -290,10 +282,19 @@ static struct omap_lcd_config ldp_lcd_config __initdata = { }; static struct omap_board_config_kernel ldp_config[] __initdata = { - { OMAP_TAG_UART, &ldp_uart_config }, { OMAP_TAG_LCD, &ldp_lcd_config }, }; +static void __init omap_ldp_init_irq(void) +{ + omap_board_config = ldp_config; + omap_board_config_size = ARRAY_SIZE(ldp_config); + omap2_init_common_hw(NULL, NULL); + omap_init_irq(); + omap_gpio_init(); + ldp_init_smsc911x(); +} + static struct twl4030_usb_data ldp_usb_data = { .usb_mode = T2_USB_MODE_ULPI, }; @@ -377,8 +378,6 @@ static void __init omap_ldp_init(void) { omap_i2c_init(); platform_add_devices(ldp_devices, ARRAY_SIZE(ldp_devices)); - omap_board_config = ldp_config; - omap_board_config_size = ARRAY_SIZE(ldp_config); ts_gpio = 54; ldp_spi_board_info[0].irq = gpio_to_irq(ts_gpio); spi_register_board_info(ldp_spi_board_info, diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c new file mode 100644 index 00000000000..8341632d260 --- /dev/null +++ b/arch/arm/mach-omap2/board-n8x0.c @@ -0,0 +1,150 @@ +/* + * linux/arch/arm/mach-omap2/board-n8x0.c + * + * Copyright (C) 2005-2009 Nokia Corporation + * Author: Juha Yrjola <juha.yrjola@nokia.com> + * + * Modified from mach-omap2/board-generic.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/stddef.h> +#include <linux/spi/spi.h> +#include <linux/usb/musb.h> + +#include <asm/mach/arch.h> +#include <asm/mach-types.h> + +#include <mach/board.h> +#include <mach/common.h> +#include <mach/irqs.h> +#include <mach/mcspi.h> +#include <mach/onenand.h> +#include <mach/serial.h> + +static struct omap2_mcspi_device_config p54spi_mcspi_config = { + .turbo_mode = 0, + .single_channel = 1, +}; + +static struct spi_board_info n800_spi_board_info[] __initdata = { + { + .modalias = "p54spi", + .bus_num = 2, + .chip_select = 0, + .max_speed_hz = 48000000, + .controller_data = &p54spi_mcspi_config, + }, +}; + +#if defined(CONFIG_MTD_ONENAND_OMAP2) || \ + defined(CONFIG_MTD_ONENAND_OMAP2_MODULE) + +static struct mtd_partition onenand_partitions[] = { + { + .name = "bootloader", + .offset = 0, + .size = 0x20000, + .mask_flags = MTD_WRITEABLE, /* Force read-only */ + }, + { + .name = "config", + .offset = MTDPART_OFS_APPEND, + .size = 0x60000, + }, + { + .name = "kernel", + .offset = MTDPART_OFS_APPEND, + .size = 0x200000, + }, + { + .name = "initfs", + .offset = MTDPART_OFS_APPEND, + .size = 0x400000, + }, + { + .name = "rootfs", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + }, +}; + +static struct omap_onenand_platform_data board_onenand_data = { + .cs = 0, + .gpio_irq = 26, + .parts = onenand_partitions, + .nr_parts = ARRAY_SIZE(onenand_partitions), + .flags = ONENAND_SYNC_READ, +}; + +static void __init n8x0_onenand_init(void) +{ + gpmc_onenand_init(&board_onenand_data); +} + +#else + +static void __init n8x0_onenand_init(void) {} + +#endif + +static void __init n8x0_map_io(void) +{ + omap2_set_globals_242x(); + omap2_map_common_io(); +} + +static void __init n8x0_init_irq(void) +{ + omap2_init_common_hw(NULL, NULL); + omap_init_irq(); + omap_gpio_init(); +} + +static void __init n8x0_init_machine(void) +{ + /* FIXME: add n810 spi devices */ + spi_register_board_info(n800_spi_board_info, + ARRAY_SIZE(n800_spi_board_info)); + + omap_serial_init(); + n8x0_onenand_init(); +} + +MACHINE_START(NOKIA_N800, "Nokia N800") + .phys_io = 0x48000000, + .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc, + .boot_params = 0x80000100, + .map_io = n8x0_map_io, + .init_irq = n8x0_init_irq, + .init_machine = n8x0_init_machine, + .timer = &omap_timer, +MACHINE_END + +MACHINE_START(NOKIA_N810, "Nokia N810") + .phys_io = 0x48000000, + .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc, + .boot_params = 0x80000100, + .map_io = n8x0_map_io, + .init_irq = n8x0_init_irq, + .init_machine = n8x0_init_machine, + .timer = &omap_timer, +MACHINE_END + +MACHINE_START(NOKIA_N810_WIMAX, "Nokia N810 WiMAX") + .phys_io = 0x48000000, + .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc, + .boot_params = 0x80000100, + .map_io = n8x0_map_io, + .init_irq = n8x0_init_irq, + .init_machine = n8x0_init_machine, + .timer = &omap_timer, +MACHINE_END diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c index 991ac9c3803..70df6b4dbcd 100644 --- a/arch/arm/mach-omap2/board-omap3beagle.c +++ b/arch/arm/mach-omap2/board-omap3beagle.c @@ -108,10 +108,6 @@ static struct platform_device omap3beagle_nand_device = { #include "sdram-micron-mt46h32m32lf-6.h" -static struct omap_uart_config omap3_beagle_uart_config __initdata = { - .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), -}; - static struct twl4030_hsmmc_info mmc[] = { { .mmc = 1, @@ -143,8 +139,13 @@ static struct gpio_led gpio_leds[]; static int beagle_twl_gpio_setup(struct device *dev, unsigned gpio, unsigned ngpio) { + if (system_rev >= 0x20 && system_rev <= 0x34301000) { + omap_cfg_reg(AG9_34XX_GPIO23); + mmc[0].gpio_wp = 23; + } else { + omap_cfg_reg(AH8_34XX_GPIO29); + } /* gpio + 0 is "mmc0_cd" (input/IRQ) */ - omap_cfg_reg(AH8_34XX_GPIO29); mmc[0].gpio_cd = gpio + 0; twl4030_mmc_init(mmc); @@ -249,11 +250,16 @@ static struct regulator_init_data beagle_vpll2 = { .consumer_supplies = &beagle_vdvi_supply, }; +static struct twl4030_usb_data beagle_usb_data = { + .usb_mode = T2_USB_MODE_ULPI, +}; + static struct twl4030_platform_data beagle_twldata = { .irq_base = TWL4030_IRQ_BASE, .irq_end = TWL4030_IRQ_END, /* platform_data for children goes here */ + .usb = &beagle_usb_data, .gpio = &beagle_gpio_data, .vmmc1 = &beagle_vmmc1, .vsim = &beagle_vsim, @@ -280,16 +286,6 @@ static int __init omap3_beagle_i2c_init(void) return 0; } -static void __init omap3_beagle_init_irq(void) -{ - omap2_init_common_hw(mt46h32m32lf6_sdrc_params); - omap_init_irq(); -#ifdef CONFIG_OMAP_32K_TIMER - omap2_gp_clockevent_set_gptimer(12); -#endif - omap_gpio_init(); -} - static struct gpio_led gpio_leds[] = { { .name = "beagleboard::usr0", @@ -344,10 +340,22 @@ static struct platform_device keys_gpio = { }; static struct omap_board_config_kernel omap3_beagle_config[] __initdata = { - { OMAP_TAG_UART, &omap3_beagle_uart_config }, { OMAP_TAG_LCD, &omap3_beagle_lcd_config }, }; +static void __init omap3_beagle_init_irq(void) +{ + omap_board_config = omap3_beagle_config; + omap_board_config_size = ARRAY_SIZE(omap3_beagle_config); + omap2_init_common_hw(mt46h32m32lf6_sdrc_params, + mt46h32m32lf6_sdrc_params); + omap_init_irq(); +#ifdef CONFIG_OMAP_32K_TIMER + omap2_gp_clockevent_set_gptimer(12); +#endif + omap_gpio_init(); +} + static struct platform_device *omap3_beagle_devices[] __initdata = { &omap3_beagle_lcd_device, &leds_gpio, @@ -397,8 +405,6 @@ static void __init omap3_beagle_init(void) omap3_beagle_i2c_init(); platform_add_devices(omap3_beagle_devices, ARRAY_SIZE(omap3_beagle_devices)); - omap_board_config = omap3_beagle_config; - omap_board_config_size = ARRAY_SIZE(omap3_beagle_config); omap_serial_init(); omap_cfg_reg(J25_34XX_GPIO170); @@ -408,6 +414,10 @@ static void __init omap3_beagle_init(void) usb_musb_init(); omap3beagle_flash_init(); + + /* Ensure SDRC pins are mux'd for self-refresh */ + omap_cfg_reg(H16_34XX_SDRC_CKE0); + omap_cfg_reg(H17_34XX_SDRC_CKE1); } static void __init omap3_beagle_map_io(void) diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c index d3cc145814d..e4ec0c59121 100644 --- a/arch/arm/mach-omap2/board-omap3evm.c +++ b/arch/arm/mach-omap2/board-omap3evm.c @@ -25,6 +25,7 @@ #include <linux/spi/spi.h> #include <linux/spi/ads7846.h> #include <linux/i2c/twl4030.h> +#include <linux/usb/otg.h> #include <mach/hardware.h> #include <asm/mach-types.h> @@ -91,10 +92,6 @@ static inline void __init omap3evm_init_smc911x(void) gpio_direction_input(OMAP3EVM_ETHR_GPIO_IRQ); } -static struct omap_uart_config omap3_evm_uart_config __initdata = { - .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), -}; - static struct twl4030_hsmmc_info mmc[] = { { .mmc = 1, @@ -162,7 +159,7 @@ static struct twl4030_usb_data omap3evm_usb_data = { .usb_mode = T2_USB_MODE_ULPI, }; -static int omap3evm_keymap[] = { +static int board_keymap[] = { KEY(0, 0, KEY_LEFT), KEY(0, 1, KEY_RIGHT), KEY(0, 2, KEY_A), @@ -181,11 +178,15 @@ static int omap3evm_keymap[] = { KEY(3, 3, KEY_P) }; +static struct matrix_keymap_data board_map_data = { + .keymap = board_keymap, + .keymap_size = ARRAY_SIZE(board_keymap), +}; + static struct twl4030_keypad_data omap3evm_kp_data = { + .keymap_data = &board_map_data, .rows = 4, .cols = 4, - .keymap = omap3evm_keymap, - .keymapsize = ARRAY_SIZE(omap3evm_keymap), .rep = 1, }; @@ -277,19 +278,20 @@ struct spi_board_info omap3evm_spi_board_info[] = { }, }; +static struct omap_board_config_kernel omap3_evm_config[] __initdata = { + { OMAP_TAG_LCD, &omap3_evm_lcd_config }, +}; + static void __init omap3_evm_init_irq(void) { - omap2_init_common_hw(mt46h32m32lf6_sdrc_params); + omap_board_config = omap3_evm_config; + omap_board_config_size = ARRAY_SIZE(omap3_evm_config); + omap2_init_common_hw(mt46h32m32lf6_sdrc_params, NULL); omap_init_irq(); omap_gpio_init(); omap3evm_init_smc911x(); } -static struct omap_board_config_kernel omap3_evm_config[] __initdata = { - { OMAP_TAG_UART, &omap3_evm_uart_config }, - { OMAP_TAG_LCD, &omap3_evm_lcd_config }, -}; - static struct platform_device *omap3_evm_devices[] __initdata = { &omap3_evm_lcd_device, &omap3evm_smc911x_device, @@ -300,13 +302,15 @@ static void __init omap3_evm_init(void) omap3_evm_i2c_init(); platform_add_devices(omap3_evm_devices, ARRAY_SIZE(omap3_evm_devices)); - omap_board_config = omap3_evm_config; - omap_board_config_size = ARRAY_SIZE(omap3_evm_config); spi_register_board_info(omap3evm_spi_board_info, ARRAY_SIZE(omap3evm_spi_board_info)); omap_serial_init(); +#ifdef CONFIG_NOP_USB_XCEIV + /* OMAP3EVM uses ISP1504 phy and so register nop transceiver */ + usb_nop_xceiv_register(); +#endif usb_musb_init(); ads7846_dev_init(); } diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c index e32aa23ce96..7f6bf8772af 100644 --- a/arch/arm/mach-omap2/board-omap3pandora.c +++ b/arch/arm/mach-omap2/board-omap3pandora.c @@ -40,6 +40,7 @@ #include <mach/mcspi.h> #include <mach/usb.h> #include <mach/keypad.h> +#include <mach/mux.h> #include "sdram-micron-mt46h32m32lf-6.h" #include "mmc-twl4030.h" @@ -132,7 +133,7 @@ static void __init pandora_keys_gpio_init(void) omap_set_gpio_debounce_time(32 * 5, GPIO_DEBOUNCE_TIME); } -static int pandora_keypad_map[] = { +static int board_keymap[] = { /* col, row, code */ KEY(0, 0, KEY_9), KEY(0, 1, KEY_0), @@ -179,11 +180,15 @@ static int pandora_keypad_map[] = { KEY(5, 2, KEY_FN), }; +static struct matrix_keymap_data board_map_data = { + .keymap = board_keymap, + .keymap_size = ARRAY_SIZE(board_keymap), +}; + static struct twl4030_keypad_data pandora_kp_data = { + .keymap_data = &board_map_data, .rows = 8, .cols = 6, - .keymap = pandora_keypad_map, - .keymapsize = ARRAY_SIZE(pandora_keypad_map), .rep = 1, }; @@ -212,10 +217,6 @@ static struct twl4030_hsmmc_info omap3pandora_mmc[] = { {} /* Terminator */ }; -static struct omap_uart_config omap3pandora_uart_config __initdata = { - .enabled_uarts = (1 << 2), /* UART3 */ -}; - static struct regulator_consumer_supply pandora_vmmc1_supply = { .supply = "vmmc", }; @@ -308,13 +309,6 @@ static int __init omap3pandora_i2c_init(void) return 0; } -static void __init omap3pandora_init_irq(void) -{ - omap2_init_common_hw(mt46h32m32lf6_sdrc_params); - omap_init_irq(); - omap_gpio_init(); -} - static void __init omap3pandora_ads7846_init(void) { int gpio = OMAP3_PANDORA_TS_GPIO; @@ -374,10 +368,19 @@ static struct omap_lcd_config omap3pandora_lcd_config __initdata = { }; static struct omap_board_config_kernel omap3pandora_config[] __initdata = { - { OMAP_TAG_UART, &omap3pandora_uart_config }, { OMAP_TAG_LCD, &omap3pandora_lcd_config }, }; +static void __init omap3pandora_init_irq(void) +{ + omap_board_config = omap3pandora_config; + omap_board_config_size = ARRAY_SIZE(omap3pandora_config); + omap2_init_common_hw(mt46h32m32lf6_sdrc_params, + mt46h32m32lf6_sdrc_params); + omap_init_irq(); + omap_gpio_init(); +} + static struct platform_device *omap3pandora_devices[] __initdata = { &omap3pandora_lcd_device, &pandora_leds_gpio, @@ -389,14 +392,16 @@ static void __init omap3pandora_init(void) omap3pandora_i2c_init(); platform_add_devices(omap3pandora_devices, ARRAY_SIZE(omap3pandora_devices)); - omap_board_config = omap3pandora_config; - omap_board_config_size = ARRAY_SIZE(omap3pandora_config); omap_serial_init(); spi_register_board_info(omap3pandora_spi_board_info, ARRAY_SIZE(omap3pandora_spi_board_info)); omap3pandora_ads7846_init(); pandora_keys_gpio_init(); usb_musb_init(); + + /* Ensure SDRC pins are mux'd for self-refresh */ + omap_cfg_reg(H16_34XX_SDRC_CKE0); + omap_cfg_reg(H17_34XX_SDRC_CKE1); } static void __init omap3pandora_map_io(void) diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c index dff5528fbfb..9917d2fddc2 100644 --- a/arch/arm/mach-omap2/board-overo.c +++ b/arch/arm/mach-omap2/board-overo.c @@ -44,6 +44,7 @@ #include <mach/gpmc.h> #include <mach/hardware.h> #include <mach/nand.h> +#include <mach/mux.h> #include <mach/usb.h> #include "sdram-micron-mt46h32m32lf-6.h" @@ -51,6 +52,7 @@ #define OVERO_GPIO_BT_XGATE 15 #define OVERO_GPIO_W2W_NRESET 16 +#define OVERO_GPIO_PENDOWN 114 #define OVERO_GPIO_BT_NRESET 164 #define OVERO_GPIO_USBH_CPEN 168 #define OVERO_GPIO_USBH_NRESET 183 @@ -146,7 +148,7 @@ static struct platform_device overo_smsc911x_device = { .name = "smsc911x", .id = -1, .num_resources = ARRAY_SIZE(overo_smsc911x_resources), - .resource = &overo_smsc911x_resources, + .resource = overo_smsc911x_resources, .dev = { .platform_data = &overo_smsc911x_config, }, @@ -269,9 +271,6 @@ static void __init overo_flash_init(void) printk(KERN_ERR "Unable to register NAND device\n"); } } -static struct omap_uart_config overo_uart_config __initdata = { - .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), -}; static struct twl4030_hsmmc_info mmc[] = { { @@ -358,13 +357,6 @@ static int __init overo_i2c_init(void) return 0; } -static void __init overo_init_irq(void) -{ - omap2_init_common_hw(mt46h32m32lf6_sdrc_params); - omap_init_irq(); - omap_gpio_init(); -} - static struct platform_device overo_lcd_device = { .name = "overo_lcd", .id = -1, @@ -375,10 +367,19 @@ static struct omap_lcd_config overo_lcd_config __initdata = { }; static struct omap_board_config_kernel overo_config[] __initdata = { - { OMAP_TAG_UART, &overo_uart_config }, { OMAP_TAG_LCD, &overo_lcd_config }, }; +static void __init overo_init_irq(void) +{ + omap_board_config = overo_config; + omap_board_config_size = ARRAY_SIZE(overo_config); + omap2_init_common_hw(mt46h32m32lf6_sdrc_params, + mt46h32m32lf6_sdrc_params); + omap_init_irq(); + omap_gpio_init(); +} + static struct platform_device *overo_devices[] __initdata = { &overo_lcd_device, }; @@ -387,14 +388,16 @@ static void __init overo_init(void) { overo_i2c_init(); platform_add_devices(overo_devices, ARRAY_SIZE(overo_devices)); - omap_board_config = overo_config; - omap_board_config_size = ARRAY_SIZE(overo_config); omap_serial_init(); overo_flash_init(); usb_musb_init(); overo_ads7846_init(); overo_init_smsc911x(); + /* Ensure SDRC pins are mux'd for self-refresh */ + omap_cfg_reg(H16_34XX_SDRC_CKE0); + omap_cfg_reg(H17_34XX_SDRC_CKE1); + if ((gpio_request(OVERO_GPIO_W2W_NRESET, "OVERO_GPIO_W2W_NRESET") == 0) && (gpio_direction_output(OVERO_GPIO_W2W_NRESET, 1) == 0)) { diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c index da93b86234e..b45ad312c58 100644 --- a/arch/arm/mach-omap2/board-rx51-peripherals.c +++ b/arch/arm/mach-omap2/board-rx51-peripherals.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-omap2/board-rx51-flash.c + * linux/arch/arm/mach-omap2/board-rx51-peripherals.c * * Copyright (C) 2008-2009 Nokia * @@ -19,6 +19,7 @@ #include <linux/delay.h> #include <linux/regulator/machine.h> #include <linux/gpio.h> +#include <linux/mmc/host.h> #include <mach/mcspi.h> #include <mach/mux.h> @@ -35,7 +36,7 @@ #define SYSTEM_REV_B_USES_VAUX3 0x1699 #define SYSTEM_REV_S_USES_VAUX3 0x8 -static int rx51_keymap[] = { +static int board_keymap[] = { KEY(0, 0, KEY_Q), KEY(0, 1, KEY_W), KEY(0, 2, KEY_E), @@ -82,11 +83,15 @@ static int rx51_keymap[] = { KEY(0xff, 5, KEY_F10), }; +static struct matrix_keymap_data board_map_data = { + .keymap = board_keymap, + .keymap_size = ARRAY_SIZE(board_keymap), +}; + static struct twl4030_keypad_data rx51_kp_data = { + .keymap_data = &board_map_data, .rows = 8, .cols = 8, - .keymap = rx51_keymap, - .keymapsize = ARRAY_SIZE(rx51_keymap), .rep = 1, }; @@ -102,6 +107,7 @@ static struct twl4030_hsmmc_info mmc[] = { .cover_only = true, .gpio_cd = 160, .gpio_wp = -EINVAL, + .power_saving = true, }, { .name = "internal", @@ -109,6 +115,8 @@ static struct twl4030_hsmmc_info mmc[] = { .wires = 8, .gpio_cd = -EINVAL, .gpio_wp = -EINVAL, + .nonremovable = true, + .power_saving = true, }, {} /* Terminator */ }; @@ -278,7 +286,128 @@ static struct twl4030_gpio_platform_data rx51_gpio_data = { .setup = rx51_twlgpio_setup, }; -static struct twl4030_platform_data rx51_twldata = { +static struct twl4030_usb_data rx51_usb_data = { + .usb_mode = T2_USB_MODE_ULPI, +}; + +static struct twl4030_ins sleep_on_seq[] __initdata = { +/* + * Turn off VDD1 and VDD2. + */ + {MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_OFF), 4}, + {MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_OFF), 2}, +/* + * And also turn off the OMAP3 PLLs and the sysclk output. + */ + {MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_OFF), 3}, + {MSG_SINGULAR(DEV_GRP_P1, 0x17, RES_STATE_OFF), 3}, +}; + +static struct twl4030_script sleep_on_script __initdata = { + .script = sleep_on_seq, + .size = ARRAY_SIZE(sleep_on_seq), + .flags = TWL4030_SLEEP_SCRIPT, +}; + +static struct twl4030_ins wakeup_seq[] __initdata = { +/* + * Reenable the OMAP3 PLLs. + * Wakeup VDD1 and VDD2. + * Reenable sysclk output. + */ + {MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_ACTIVE), 0x30}, + {MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_ACTIVE), 0x30}, + {MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_ACTIVE), 0x37}, + {MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_ACTIVE), 3}, +}; + +static struct twl4030_script wakeup_script __initdata = { + .script = wakeup_seq, + .size = ARRAY_SIZE(wakeup_seq), + .flags = TWL4030_WAKEUP12_SCRIPT, +}; + +static struct twl4030_ins wakeup_p3_seq[] __initdata = { +/* + * Wakeup VDD1 (dummy to be able to insert a delay) + * Enable CLKEN + */ + {MSG_SINGULAR(DEV_GRP_P1, 0x17, RES_STATE_ACTIVE), 3}, +}; + +static struct twl4030_script wakeup_p3_script __initdata = { + .script = wakeup_p3_seq, + .size = ARRAY_SIZE(wakeup_p3_seq), + .flags = TWL4030_WAKEUP3_SCRIPT, +}; + +static struct twl4030_ins wrst_seq[] __initdata = { +/* + * Reset twl4030. + * Reset VDD1 regulator. + * Reset VDD2 regulator. + * Reset VPLL1 regulator. + * Enable sysclk output. + * Reenable twl4030. + */ + {MSG_SINGULAR(DEV_GRP_NULL, RES_RESET, RES_STATE_OFF), 2}, + {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, 0, 1, RES_STATE_ACTIVE), + 0x13}, + {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_PP, 0, 2, RES_STATE_WRST), 0x13}, + {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_PP, 0, 3, RES_STATE_OFF), 0x13}, + {MSG_SINGULAR(DEV_GRP_NULL, RES_VDD1, RES_STATE_WRST), 0x13}, + {MSG_SINGULAR(DEV_GRP_NULL, RES_VDD2, RES_STATE_WRST), 0x13}, + {MSG_SINGULAR(DEV_GRP_NULL, RES_VPLL1, RES_STATE_WRST), 0x35}, + {MSG_SINGULAR(DEV_GRP_P1, RES_HFCLKOUT, RES_STATE_ACTIVE), 2}, + {MSG_SINGULAR(DEV_GRP_NULL, RES_RESET, RES_STATE_ACTIVE), 2}, +}; + +static struct twl4030_script wrst_script __initdata = { + .script = wrst_seq, + .size = ARRAY_SIZE(wrst_seq), + .flags = TWL4030_WRST_SCRIPT, +}; + +static struct twl4030_script *twl4030_scripts[] __initdata = { + /* wakeup12 script should be loaded before sleep script, otherwise a + board might hit retention before loading of wakeup script is + completed. This can cause boot failures depending on timing issues. + */ + &wakeup_script, + &sleep_on_script, + &wakeup_p3_script, + &wrst_script, +}; + +static struct twl4030_resconfig twl4030_rconfig[] __initdata = { + { .resource = RES_VINTANA1, .devgroup = -1, .type = -1, .type2 = 1 }, + { .resource = RES_VINTANA2, .devgroup = -1, .type = -1, .type2 = 1 }, + { .resource = RES_VINTDIG, .devgroup = -1, .type = -1, .type2 = 1 }, + { .resource = RES_VMMC1, .devgroup = -1, .type = -1, .type2 = 3}, + { .resource = RES_VMMC2, .devgroup = DEV_GRP_NULL, .type = -1, + .type2 = 3}, + { .resource = RES_VAUX1, .devgroup = -1, .type = -1, .type2 = 3}, + { .resource = RES_VAUX2, .devgroup = -1, .type = -1, .type2 = 3}, + { .resource = RES_VAUX3, .devgroup = -1, .type = -1, .type2 = 3}, + { .resource = RES_VAUX4, .devgroup = -1, .type = -1, .type2 = 3}, + { .resource = RES_VPLL2, .devgroup = -1, .type = -1, .type2 = 3}, + { .resource = RES_VDAC, .devgroup = -1, .type = -1, .type2 = 3}, + { .resource = RES_VSIM, .devgroup = DEV_GRP_NULL, .type = -1, + .type2 = 3}, + { .resource = RES_CLKEN, .devgroup = DEV_GRP_P3, .type = -1, + .type2 = 1 }, + { 0, 0}, +}; + +static struct twl4030_power_data rx51_t2scripts_data __initdata = { + .scripts = twl4030_scripts, + .num = ARRAY_SIZE(twl4030_scripts), + .resource_config = twl4030_rconfig, +}; + + + +static struct twl4030_platform_data rx51_twldata __initdata = { .irq_base = TWL4030_IRQ_BASE, .irq_end = TWL4030_IRQ_END, @@ -286,6 +415,8 @@ static struct twl4030_platform_data rx51_twldata = { .gpio = &rx51_gpio_data, .keypad = &rx51_kp_data, .madc = &rx51_madc_data, + .usb = &rx51_usb_data, + .power = &rx51_t2scripts_data, .vaux1 = &rx51_vaux1, .vaux2 = &rx51_vaux2, @@ -362,6 +493,7 @@ static struct omap_onenand_platform_data board_onenand_data = { .gpio_irq = 65, .parts = onenand_partitions, .nr_parts = ARRAY_SIZE(onenand_partitions), + .flags = ONENAND_SYNC_READWRITE, }; static void __init board_onenand_init(void) diff --git a/arch/arm/mach-omap2/board-rx51.c b/arch/arm/mach-omap2/board-rx51.c index 374ff63c3eb..f9196c3b1a7 100644 --- a/arch/arm/mach-omap2/board-rx51.c +++ b/arch/arm/mach-omap2/board-rx51.c @@ -31,10 +31,6 @@ #include <mach/gpmc.h> #include <mach/usb.h> -static struct omap_uart_config rx51_uart_config = { - .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), -}; - static struct omap_lcd_config rx51_lcd_config = { .ctrl_name = "internal", }; @@ -52,7 +48,6 @@ static struct omap_fbmem_config rx51_fbmem2_config = { }; static struct omap_board_config_kernel rx51_config[] = { - { OMAP_TAG_UART, &rx51_uart_config }, { OMAP_TAG_FBMEM, &rx51_fbmem0_config }, { OMAP_TAG_FBMEM, &rx51_fbmem1_config }, { OMAP_TAG_FBMEM, &rx51_fbmem2_config }, @@ -61,7 +56,9 @@ static struct omap_board_config_kernel rx51_config[] = { static void __init rx51_init_irq(void) { - omap2_init_common_hw(NULL); + omap_board_config = rx51_config; + omap_board_config_size = ARRAY_SIZE(rx51_config); + omap2_init_common_hw(NULL, NULL); omap_init_irq(); omap_gpio_init(); } @@ -70,11 +67,13 @@ extern void __init rx51_peripherals_init(void); static void __init rx51_init(void) { - omap_board_config = rx51_config; - omap_board_config_size = ARRAY_SIZE(rx51_config); omap_serial_init(); usb_musb_init(); rx51_peripherals_init(); + + /* Ensure SDRC pins are mux'd for self-refresh */ + omap_cfg_reg(H16_34XX_SDRC_CKE0); + omap_cfg_reg(H17_34XX_SDRC_CKE1); } static void __init rx51_map_io(void) diff --git a/arch/arm/mach-omap2/board-zoom-debugboard.c b/arch/arm/mach-omap2/board-zoom-debugboard.c index bac5c4321ff..1f13e2a1f32 100644 --- a/arch/arm/mach-omap2/board-zoom-debugboard.c +++ b/arch/arm/mach-omap2/board-zoom-debugboard.c @@ -12,6 +12,7 @@ #include <linux/gpio.h> #include <linux/serial_8250.h> #include <linux/smsc911x.h> +#include <linux/interrupt.h> #include <mach/gpmc.h> @@ -84,6 +85,7 @@ static struct plat_serial8250_port serial_platform_data[] = { .mapbase = 0x10000000, .irq = OMAP_GPIO_IRQ(102), .flags = UPF_BOOT_AUTOCONF|UPF_IOREMAP|UPF_SHARE_IRQ, + .irqflags = IRQF_SHARED | IRQF_TRIGGER_RISING, .iotype = UPIO_MEM, .regshift = 1, .uartclk = QUART_CLK, @@ -94,7 +96,7 @@ static struct plat_serial8250_port serial_platform_data[] = { static struct platform_device zoom2_debugboard_serial_device = { .name = "serial8250", - .id = PLAT8250_DEV_PLATFORM1, + .id = 3, .dev = { .platform_data = serial_platform_data, }, @@ -127,6 +129,7 @@ static inline void __init zoom2_init_quaduart(void) static inline int omap_zoom2_debugboard_detect(void) { int debug_board_detect = 0; + int ret = 1; debug_board_detect = ZOOM2_SMSC911X_GPIO; @@ -138,10 +141,10 @@ static inline int omap_zoom2_debugboard_detect(void) gpio_direction_input(debug_board_detect); if (!gpio_get_value(debug_board_detect)) { - gpio_free(debug_board_detect); - return 0; + ret = 0; } - return 1; + gpio_free(debug_board_detect); + return ret; } static struct platform_device *zoom2_devices[] __initdata = { diff --git a/arch/arm/mach-omap2/board-zoom2.c b/arch/arm/mach-omap2/board-zoom2.c index bcc0f7632de..b7b32208ced 100644 --- a/arch/arm/mach-omap2/board-zoom2.c +++ b/arch/arm/mach-omap2/board-zoom2.c @@ -12,36 +12,221 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/platform_device.h> +#include <linux/input.h> #include <linux/gpio.h> #include <linux/i2c/twl4030.h> +#include <linux/regulator/machine.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> #include <mach/common.h> #include <mach/usb.h> +#include <mach/keypad.h> #include "mmc-twl4030.h" -static void __init omap_zoom2_init_irq(void) +/* Zoom2 has Qwerty keyboard*/ +static int board_keymap[] = { + KEY(0, 0, KEY_E), + KEY(1, 0, KEY_R), + KEY(2, 0, KEY_T), + KEY(3, 0, KEY_HOME), + KEY(6, 0, KEY_I), + KEY(7, 0, KEY_LEFTSHIFT), + KEY(0, 1, KEY_D), + KEY(1, 1, KEY_F), + KEY(2, 1, KEY_G), + KEY(3, 1, KEY_SEND), + KEY(6, 1, KEY_K), + KEY(7, 1, KEY_ENTER), + KEY(0, 2, KEY_X), + KEY(1, 2, KEY_C), + KEY(2, 2, KEY_V), + KEY(3, 2, KEY_END), + KEY(6, 2, KEY_DOT), + KEY(7, 2, KEY_CAPSLOCK), + KEY(0, 3, KEY_Z), + KEY(1, 3, KEY_KPPLUS), + KEY(2, 3, KEY_B), + KEY(3, 3, KEY_F1), + KEY(6, 3, KEY_O), + KEY(7, 3, KEY_SPACE), + KEY(0, 4, KEY_W), + KEY(1, 4, KEY_Y), + KEY(2, 4, KEY_U), + KEY(3, 4, KEY_F2), + KEY(4, 4, KEY_VOLUMEUP), + KEY(6, 4, KEY_L), + KEY(7, 4, KEY_LEFT), + KEY(0, 5, KEY_S), + KEY(1, 5, KEY_H), + KEY(2, 5, KEY_J), + KEY(3, 5, KEY_F3), + KEY(5, 5, KEY_VOLUMEDOWN), + KEY(6, 5, KEY_M), + KEY(4, 5, KEY_ENTER), + KEY(7, 5, KEY_RIGHT), + KEY(0, 6, KEY_Q), + KEY(1, 6, KEY_A), + KEY(2, 6, KEY_N), + KEY(3, 6, KEY_BACKSPACE), + KEY(6, 6, KEY_P), + KEY(7, 6, KEY_UP), + KEY(6, 7, KEY_SELECT), + KEY(7, 7, KEY_DOWN), + KEY(0, 7, KEY_PROG1), /*MACRO 1 <User defined> */ + KEY(1, 7, KEY_PROG2), /*MACRO 2 <User defined> */ + KEY(2, 7, KEY_PROG3), /*MACRO 3 <User defined> */ + KEY(3, 7, KEY_PROG4), /*MACRO 4 <User defined> */ + 0 +}; + +static struct matrix_keymap_data board_map_data = { + .keymap = board_keymap, + .keymap_size = ARRAY_SIZE(board_keymap), +}; + +static struct twl4030_keypad_data zoom2_kp_twl4030_data = { + .keymap_data = &board_map_data, + .rows = 8, + .cols = 8, + .rep = 1, +}; + +static struct omap_board_config_kernel zoom2_config[] __initdata = { +}; + +static struct regulator_consumer_supply zoom2_vmmc1_supply = { + .supply = "vmmc", +}; + +static struct regulator_consumer_supply zoom2_vsim_supply = { + .supply = "vmmc_aux", +}; + +static struct regulator_consumer_supply zoom2_vmmc2_supply = { + .supply = "vmmc", +}; + +/* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */ +static struct regulator_init_data zoom2_vmmc1 = { + .constraints = { + .min_uV = 1850000, + .max_uV = 3150000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = 1, + .consumer_supplies = &zoom2_vmmc1_supply, +}; + +/* VMMC2 for MMC2 card */ +static struct regulator_init_data zoom2_vmmc2 = { + .constraints = { + .min_uV = 1850000, + .max_uV = 1850000, + .apply_uV = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = 1, + .consumer_supplies = &zoom2_vmmc2_supply, +}; + +/* VSIM for OMAP VDD_MMC1A (i/o for DAT4..DAT7) */ +static struct regulator_init_data zoom2_vsim = { + .constraints = { + .min_uV = 1800000, + .max_uV = 3000000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = 1, + .consumer_supplies = &zoom2_vsim_supply, +}; + +static struct twl4030_hsmmc_info mmc[] __initdata = { + { + .mmc = 1, + .wires = 4, + .gpio_wp = -EINVAL, + }, + { + .mmc = 2, + .wires = 4, + .gpio_wp = -EINVAL, + }, + {} /* Terminator */ +}; + +static int zoom2_twl_gpio_setup(struct device *dev, + unsigned gpio, unsigned ngpio) { - omap2_init_common_hw(NULL); - omap_init_irq(); - omap_gpio_init(); + /* gpio + 0 is "mmc0_cd" (input/IRQ), + * gpio + 1 is "mmc1_cd" (input/IRQ) + */ + mmc[0].gpio_cd = gpio + 0; + mmc[1].gpio_cd = gpio + 1; + twl4030_mmc_init(mmc); + + /* link regulators to MMC adapters ... we "know" the + * regulators will be set up only *after* we return. + */ + zoom2_vmmc1_supply.dev = mmc[0].dev; + zoom2_vsim_supply.dev = mmc[0].dev; + zoom2_vmmc2_supply.dev = mmc[1].dev; + + return 0; } -static struct omap_uart_config zoom2_uart_config __initdata = { - .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), + +static int zoom2_batt_table[] = { +/* 0 C*/ +30800, 29500, 28300, 27100, +26000, 24900, 23900, 22900, 22000, 21100, 20300, 19400, 18700, 17900, +17200, 16500, 15900, 15300, 14700, 14100, 13600, 13100, 12600, 12100, +11600, 11200, 10800, 10400, 10000, 9630, 9280, 8950, 8620, 8310, +8020, 7730, 7460, 7200, 6950, 6710, 6470, 6250, 6040, 5830, +5640, 5450, 5260, 5090, 4920, 4760, 4600, 4450, 4310, 4170, +4040, 3910, 3790, 3670, 3550 }; -static struct omap_board_config_kernel zoom2_config[] __initdata = { - { OMAP_TAG_UART, &zoom2_uart_config }, +static struct twl4030_bci_platform_data zoom2_bci_data = { + .battery_tmp_tbl = zoom2_batt_table, + .tblsize = ARRAY_SIZE(zoom2_batt_table), +}; + +static struct twl4030_usb_data zoom2_usb_data = { + .usb_mode = T2_USB_MODE_ULPI, }; +static void __init omap_zoom2_init_irq(void) +{ + omap_board_config = zoom2_config; + omap_board_config_size = ARRAY_SIZE(zoom2_config); + omap2_init_common_hw(NULL, NULL); + omap_init_irq(); + omap_gpio_init(); +} + static struct twl4030_gpio_platform_data zoom2_gpio_data = { .gpio_base = OMAP_MAX_GPIO_LINES, .irq_base = TWL4030_GPIO_IRQ_BASE, .irq_end = TWL4030_GPIO_IRQ_END, + .setup = zoom2_twl_gpio_setup, +}; + +static struct twl4030_madc_platform_data zoom2_madc_data = { + .irq_line = 1, }; static struct twl4030_platform_data zoom2_twldata = { @@ -49,7 +234,15 @@ static struct twl4030_platform_data zoom2_twldata = { .irq_end = TWL4030_IRQ_END, /* platform_data for children goes here */ + .bci = &zoom2_bci_data, + .madc = &zoom2_madc_data, + .usb = &zoom2_usb_data, .gpio = &zoom2_gpio_data, + .keypad = &zoom2_kp_twl4030_data, + .vmmc1 = &zoom2_vmmc1, + .vmmc2 = &zoom2_vmmc2, + .vsim = &zoom2_vsim, + }; static struct i2c_board_info __initdata zoom2_i2c_boardinfo[] = { @@ -70,26 +263,13 @@ static int __init omap_i2c_init(void) return 0; } -static struct twl4030_hsmmc_info mmc[] __initdata = { - { - .mmc = 1, - .wires = 4, - .gpio_cd = -EINVAL, - .gpio_wp = -EINVAL, - }, - {} /* Terminator */ -}; - extern int __init omap_zoom2_debugboard_init(void); static void __init omap_zoom2_init(void) { omap_i2c_init(); - omap_board_config = zoom2_config; - omap_board_config_size = ARRAY_SIZE(zoom2_config); omap_serial_init(); omap_zoom2_debugboard_init(); - twl4030_mmc_init(mmc); usb_musb_init(); } diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index b0665f161c0..f2a92d614f0 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -27,6 +27,7 @@ #include <mach/clock.h> #include <mach/clockdomain.h> #include <mach/cpu.h> +#include <mach/prcm.h> #include <asm/div64.h> #include <mach/sdrc.h> @@ -38,8 +39,6 @@ #include "cm-regbits-24xx.h" #include "cm-regbits-34xx.h" -#define MAX_CLOCK_ENABLE_WAIT 100000 - /* DPLL rate rounding: minimum DPLL multiplier, divider values */ #define DPLL_MIN_MULTIPLIER 1 #define DPLL_MIN_DIVIDER 1 @@ -274,83 +273,97 @@ unsigned long omap2_fixed_divisor_recalc(struct clk *clk) } /** - * omap2_wait_clock_ready - wait for clock to enable - * @reg: physical address of clock IDLEST register - * @mask: value to mask against to determine if the clock is active - * @name: name of the clock (for printk) + * omap2_clk_dflt_find_companion - find companion clock to @clk + * @clk: struct clk * to find the companion clock of + * @other_reg: void __iomem ** to return the companion clock CM_*CLKEN va in + * @other_bit: u8 ** to return the companion clock bit shift in + * + * Note: We don't need special code here for INVERT_ENABLE for the + * time being since INVERT_ENABLE only applies to clocks enabled by + * CM_CLKEN_PLL * - * Returns 1 if the clock enabled in time, or 0 if it failed to enable - * in roughly MAX_CLOCK_ENABLE_WAIT microseconds. + * Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes it's + * just a matter of XORing the bits. + * + * Some clocks don't have companion clocks. For example, modules with + * only an interface clock (such as MAILBOXES) don't have a companion + * clock. Right now, this code relies on the hardware exporting a bit + * in the correct companion register that indicates that the + * nonexistent 'companion clock' is active. Future patches will + * associate this type of code with per-module data structures to + * avoid this issue, and remove the casts. No return value. */ -int omap2_wait_clock_ready(void __iomem *reg, u32 mask, const char *name) +void omap2_clk_dflt_find_companion(struct clk *clk, void __iomem **other_reg, + u8 *other_bit) { - int i = 0; - int ena = 0; + u32 r; /* - * 24xx uses 0 to indicate not ready, and 1 to indicate ready. - * 34xx reverses this, just to keep us on our toes + * Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes + * it's just a matter of XORing the bits. */ - if (cpu_mask & (RATE_IN_242X | RATE_IN_243X)) - ena = mask; - else if (cpu_mask & RATE_IN_343X) - ena = 0; - - /* Wait for lock */ - while (((__raw_readl(reg) & mask) != ena) && - (i++ < MAX_CLOCK_ENABLE_WAIT)) { - udelay(1); - } - - if (i <= MAX_CLOCK_ENABLE_WAIT) - pr_debug("Clock %s stable after %d loops\n", name, i); - else - printk(KERN_ERR "Clock %s didn't enable in %d tries\n", - name, MAX_CLOCK_ENABLE_WAIT); - - - return (i < MAX_CLOCK_ENABLE_WAIT) ? 1 : 0; -}; + r = ((__force u32)clk->enable_reg ^ (CM_FCLKEN ^ CM_ICLKEN)); + *other_reg = (__force void __iomem *)r; + *other_bit = clk->enable_bit; +} -/* - * Note: We don't need special code here for INVERT_ENABLE - * for the time being since INVERT_ENABLE only applies to clocks enabled by - * CM_CLKEN_PLL +/** + * omap2_clk_dflt_find_idlest - find CM_IDLEST reg va, bit shift for @clk + * @clk: struct clk * to find IDLEST info for + * @idlest_reg: void __iomem ** to return the CM_IDLEST va in + * @idlest_bit: u8 ** to return the CM_IDLEST bit shift in + * + * Return the CM_IDLEST register address and bit shift corresponding + * to the module that "owns" this clock. This default code assumes + * that the CM_IDLEST bit shift is the CM_*CLKEN bit shift, and that + * the IDLEST register address ID corresponds to the CM_*CLKEN + * register address ID (e.g., that CM_FCLKEN2 corresponds to + * CM_IDLEST2). This is not true for all modules. No return value. */ -static void omap2_clk_wait_ready(struct clk *clk) +void omap2_clk_dflt_find_idlest(struct clk *clk, void __iomem **idlest_reg, + u8 *idlest_bit) { - void __iomem *reg, *other_reg, *st_reg; - u32 bit; + u32 r; - /* - * REVISIT: This code is pretty ugly. It would be nice to generalize - * it and pull it into struct clk itself somehow. - */ - reg = clk->enable_reg; + r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); + *idlest_reg = (__force void __iomem *)r; + *idlest_bit = clk->enable_bit; +} - /* - * Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes - * it's just a matter of XORing the bits. - */ - other_reg = (void __iomem *)((u32)reg ^ (CM_FCLKEN ^ CM_ICLKEN)); +/** + * omap2_module_wait_ready - wait for an OMAP module to leave IDLE + * @clk: struct clk * belonging to the module + * + * If the necessary clocks for the OMAP hardware IP block that + * corresponds to clock @clk are enabled, then wait for the module to + * indicate readiness (i.e., to leave IDLE). This code does not + * belong in the clock code and will be moved in the medium term to + * module-dependent code. No return value. + */ +static void omap2_module_wait_ready(struct clk *clk) +{ + void __iomem *companion_reg, *idlest_reg; + u8 other_bit, idlest_bit; + + /* Not all modules have multiple clocks that their IDLEST depends on */ + if (clk->ops->find_companion) { + clk->ops->find_companion(clk, &companion_reg, &other_bit); + if (!(__raw_readl(companion_reg) & (1 << other_bit))) + return; + } - /* Check if both functional and interface clocks - * are running. */ - bit = 1 << clk->enable_bit; - if (!(__raw_readl(other_reg) & bit)) - return; - st_reg = (void __iomem *)(((u32)other_reg & ~0xf0) | 0x20); /* CM_IDLEST* */ + clk->ops->find_idlest(clk, &idlest_reg, &idlest_bit); - omap2_wait_clock_ready(st_reg, bit, clk->name); + omap2_cm_wait_idlest(idlest_reg, (1 << idlest_bit), clk->name); } -static int omap2_dflt_clk_enable(struct clk *clk) +int omap2_dflt_clk_enable(struct clk *clk) { u32 v; if (unlikely(clk->enable_reg == NULL)) { - printk(KERN_ERR "clock.c: Enable for %s without enable code\n", + pr_err("clock.c: Enable for %s without enable code\n", clk->name); return 0; /* REVISIT: -EINVAL */ } @@ -363,26 +376,13 @@ static int omap2_dflt_clk_enable(struct clk *clk) __raw_writel(v, clk->enable_reg); v = __raw_readl(clk->enable_reg); /* OCP barrier */ - return 0; -} + if (clk->ops->find_idlest) + omap2_module_wait_ready(clk); -static int omap2_dflt_clk_enable_wait(struct clk *clk) -{ - int ret; - - if (!clk->enable_reg) { - printk(KERN_ERR "clock.c: Enable for %s without enable code\n", - clk->name); - return 0; /* REVISIT: -EINVAL */ - } - - ret = omap2_dflt_clk_enable(clk); - if (ret == 0) - omap2_clk_wait_ready(clk); - return ret; + return 0; } -static void omap2_dflt_clk_disable(struct clk *clk) +void omap2_dflt_clk_disable(struct clk *clk) { u32 v; @@ -406,8 +406,10 @@ static void omap2_dflt_clk_disable(struct clk *clk) } const struct clkops clkops_omap2_dflt_wait = { - .enable = omap2_dflt_clk_enable_wait, + .enable = omap2_dflt_clk_enable, .disable = omap2_dflt_clk_disable, + .find_companion = omap2_clk_dflt_find_companion, + .find_idlest = omap2_clk_dflt_find_idlest, }; const struct clkops clkops_omap2_dflt = { @@ -1041,5 +1043,7 @@ void omap2_clk_disable_unused(struct clk *clk) omap2_clk_disable(clk); } else _omap2_clk_disable(clk); + if (clk->clkdm != NULL) + pwrdm_clkdm_state_switch(clk->clkdm); } #endif diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index 2679ddfa642..9ae7540f8af 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -65,6 +65,12 @@ int omap2_clksel_set_rate(struct clk *clk, unsigned long rate); u32 omap2_get_dpll_rate(struct clk *clk); int omap2_wait_clock_ready(void __iomem *reg, u32 cval, const char *name); void omap2_clk_prepare_for_reboot(void); +int omap2_dflt_clk_enable(struct clk *clk); +void omap2_dflt_clk_disable(struct clk *clk); +void omap2_clk_dflt_find_companion(struct clk *clk, void __iomem **other_reg, + u8 *other_bit); +void omap2_clk_dflt_find_idlest(struct clk *clk, void __iomem **idlest_reg, + u8 *idlest_bit); extern const struct clkops clkops_omap2_dflt_wait; extern const struct clkops clkops_omap2_dflt; diff --git a/arch/arm/mach-omap2/clock24xx.c b/arch/arm/mach-omap2/clock24xx.c index 44de0271fc2..bc5d3ac6661 100644 --- a/arch/arm/mach-omap2/clock24xx.c +++ b/arch/arm/mach-omap2/clock24xx.c @@ -30,6 +30,7 @@ #include <mach/clock.h> #include <mach/sram.h> +#include <mach/prcm.h> #include <asm/div64.h> #include <asm/clkdev.h> @@ -43,6 +44,18 @@ static const struct clkops clkops_oscck; static const struct clkops clkops_fixed; +static void omap2430_clk_i2chs_find_idlest(struct clk *clk, + void __iomem **idlest_reg, + u8 *idlest_bit); + +/* 2430 I2CHS has non-standard IDLEST register */ +static const struct clkops clkops_omap2430_i2chs_wait = { + .enable = omap2_dflt_clk_enable, + .disable = omap2_dflt_clk_disable, + .find_idlest = omap2430_clk_i2chs_find_idlest, + .find_companion = omap2_clk_dflt_find_companion, +}; + #include "clock24xx.h" struct omap_clk { @@ -240,6 +253,26 @@ static void __iomem *prcm_clksrc_ctrl; *-------------------------------------------------------------------------*/ /** + * omap2430_clk_i2chs_find_idlest - return CM_IDLEST info for 2430 I2CHS + * @clk: struct clk * being enabled + * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into + * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into + * + * OMAP2430 I2CHS CM_IDLEST bits are in CM_IDLEST1_CORE, but the + * CM_*CLKEN bits are in CM_{I,F}CLKEN2_CORE. This custom function + * passes back the correct CM_IDLEST register address for I2CHS + * modules. No return value. + */ +static void omap2430_clk_i2chs_find_idlest(struct clk *clk, + void __iomem **idlest_reg, + u8 *idlest_bit) +{ + *idlest_reg = OMAP_CM_REGADDR(CORE_MOD, CM_IDLEST); + *idlest_bit = clk->enable_bit; +} + + +/** * omap2xxx_clk_get_core_rate - return the CORE_CLK rate * @clk: pointer to the combined dpll_ck + core_ck (currently "dpll_ck") * @@ -325,8 +358,8 @@ static int omap2_clk_fixed_enable(struct clk *clk) else if (clk == &apll54_ck) cval = OMAP24XX_ST_54M_APLL; - omap2_wait_clock_ready(OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST), cval, - clk->name); + omap2_cm_wait_idlest(OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST), cval, + clk->name); /* * REVISIT: Should we return an error code if omap2_wait_clock_ready() diff --git a/arch/arm/mach-omap2/clock24xx.h b/arch/arm/mach-omap2/clock24xx.h index 458f00cdcbe..d19cf7a7d8d 100644 --- a/arch/arm/mach-omap2/clock24xx.h +++ b/arch/arm/mach-omap2/clock24xx.h @@ -2337,7 +2337,7 @@ static struct clk i2c2_fck = { static struct clk i2chs2_fck = { .name = "i2c_fck", - .ops = &clkops_omap2_dflt_wait, + .ops = &clkops_omap2430_i2chs_wait, .id = 2, .parent = &func_96m_ck, .clkdm_name = "core_l4_clkdm", @@ -2370,7 +2370,7 @@ static struct clk i2c1_fck = { static struct clk i2chs1_fck = { .name = "i2c_fck", - .ops = &clkops_omap2_dflt_wait, + .ops = &clkops_omap2430_i2chs_wait, .id = 1, .parent = &func_96m_ck, .clkdm_name = "core_l4_clkdm", diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c index 045da923e75..fafcd32e690 100644 --- a/arch/arm/mach-omap2/clock34xx.c +++ b/arch/arm/mach-omap2/clock34xx.c @@ -2,7 +2,7 @@ * OMAP3-specific clock framework functions * * Copyright (C) 2007-2008 Texas Instruments, Inc. - * Copyright (C) 2007-2008 Nokia Corporation + * Copyright (C) 2007-2009 Nokia Corporation * * Written by Paul Walmsley * Testing and integration fixes by Jouni Högander @@ -27,6 +27,7 @@ #include <linux/limits.h> #include <linux/bitops.h> +#include <mach/cpu.h> #include <mach/clock.h> #include <mach/sram.h> #include <asm/div64.h> @@ -41,6 +42,37 @@ static const struct clkops clkops_noncore_dpll_ops; +static void omap3430es2_clk_ssi_find_idlest(struct clk *clk, + void __iomem **idlest_reg, + u8 *idlest_bit); +static void omap3430es2_clk_hsotgusb_find_idlest(struct clk *clk, + void __iomem **idlest_reg, + u8 *idlest_bit); +static void omap3430es2_clk_dss_usbhost_find_idlest(struct clk *clk, + void __iomem **idlest_reg, + u8 *idlest_bit); + +static const struct clkops clkops_omap3430es2_ssi_wait = { + .enable = omap2_dflt_clk_enable, + .disable = omap2_dflt_clk_disable, + .find_idlest = omap3430es2_clk_ssi_find_idlest, + .find_companion = omap2_clk_dflt_find_companion, +}; + +static const struct clkops clkops_omap3430es2_hsotgusb_wait = { + .enable = omap2_dflt_clk_enable, + .disable = omap2_dflt_clk_disable, + .find_idlest = omap3430es2_clk_hsotgusb_find_idlest, + .find_companion = omap2_clk_dflt_find_companion, +}; + +static const struct clkops clkops_omap3430es2_dss_usbhost_wait = { + .enable = omap2_dflt_clk_enable, + .disable = omap2_dflt_clk_disable, + .find_idlest = omap3430es2_clk_dss_usbhost_find_idlest, + .find_companion = omap2_clk_dflt_find_companion, +}; + #include "clock34xx.h" struct omap_clk { @@ -157,10 +189,13 @@ static struct omap_clk omap34xx_clks[] = { CLK(NULL, "fshostusb_fck", &fshostusb_fck, CK_3430ES1), CLK(NULL, "core_12m_fck", &core_12m_fck, CK_343X), CLK("omap_hdq.0", "fck", &hdq_fck, CK_343X), - CLK(NULL, "ssi_ssr_fck", &ssi_ssr_fck, CK_343X), - CLK(NULL, "ssi_sst_fck", &ssi_sst_fck, CK_343X), + CLK(NULL, "ssi_ssr_fck", &ssi_ssr_fck_3430es1, CK_3430ES1), + CLK(NULL, "ssi_ssr_fck", &ssi_ssr_fck_3430es2, CK_3430ES2), + CLK(NULL, "ssi_sst_fck", &ssi_sst_fck_3430es1, CK_3430ES1), + CLK(NULL, "ssi_sst_fck", &ssi_sst_fck_3430es2, CK_3430ES2), CLK(NULL, "core_l3_ick", &core_l3_ick, CK_343X), - CLK("musb_hdrc", "ick", &hsotgusb_ick, CK_343X), + CLK("musb_hdrc", "ick", &hsotgusb_ick_3430es1, CK_3430ES1), + CLK("musb_hdrc", "ick", &hsotgusb_ick_3430es2, CK_3430ES2), CLK(NULL, "sdrc_ick", &sdrc_ick, CK_343X), CLK(NULL, "gpmc_fck", &gpmc_fck, CK_343X), CLK(NULL, "security_l3_ick", &security_l3_ick, CK_343X), @@ -193,18 +228,21 @@ static struct omap_clk omap34xx_clks[] = { CLK(NULL, "mailboxes_ick", &mailboxes_ick, CK_343X), CLK(NULL, "omapctrl_ick", &omapctrl_ick, CK_343X), CLK(NULL, "ssi_l4_ick", &ssi_l4_ick, CK_343X), - CLK(NULL, "ssi_ick", &ssi_ick, CK_343X), + CLK(NULL, "ssi_ick", &ssi_ick_3430es1, CK_3430ES1), + CLK(NULL, "ssi_ick", &ssi_ick_3430es2, CK_3430ES2), CLK(NULL, "usb_l4_ick", &usb_l4_ick, CK_3430ES1), CLK(NULL, "security_l4_ick2", &security_l4_ick2, CK_343X), CLK(NULL, "aes1_ick", &aes1_ick, CK_343X), CLK("omap_rng", "ick", &rng_ick, CK_343X), CLK(NULL, "sha11_ick", &sha11_ick, CK_343X), CLK(NULL, "des1_ick", &des1_ick, CK_343X), - CLK("omapfb", "dss1_fck", &dss1_alwon_fck, CK_343X), + CLK("omapfb", "dss1_fck", &dss1_alwon_fck_3430es1, CK_3430ES1), + CLK("omapfb", "dss1_fck", &dss1_alwon_fck_3430es2, CK_3430ES2), CLK("omapfb", "tv_fck", &dss_tv_fck, CK_343X), CLK("omapfb", "video_fck", &dss_96m_fck, CK_343X), CLK("omapfb", "dss2_fck", &dss2_alwon_fck, CK_343X), - CLK("omapfb", "ick", &dss_ick, CK_343X), + CLK("omapfb", "ick", &dss_ick_3430es1, CK_3430ES1), + CLK("omapfb", "ick", &dss_ick_3430es2, CK_3430ES2), CLK(NULL, "cam_mclk", &cam_mclk, CK_343X), CLK(NULL, "cam_ick", &cam_ick, CK_343X), CLK(NULL, "csi2_96m_fck", &csi2_96m_fck, CK_343X), @@ -301,6 +339,73 @@ static struct omap_clk omap34xx_clks[] = { #define SDRC_MPURATE_LOOPS 96 /** + * omap3430es2_clk_ssi_find_idlest - return CM_IDLEST info for SSI + * @clk: struct clk * being enabled + * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into + * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into + * + * The OMAP3430ES2 SSI target CM_IDLEST bit is at a different shift + * from the CM_{I,F}CLKEN bit. Pass back the correct info via + * @idlest_reg and @idlest_bit. No return value. + */ +static void omap3430es2_clk_ssi_find_idlest(struct clk *clk, + void __iomem **idlest_reg, + u8 *idlest_bit) +{ + u32 r; + + r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); + *idlest_reg = (__force void __iomem *)r; + *idlest_bit = OMAP3430ES2_ST_SSI_IDLE_SHIFT; +} + +/** + * omap3430es2_clk_dss_usbhost_find_idlest - CM_IDLEST info for DSS, USBHOST + * @clk: struct clk * being enabled + * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into + * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into + * + * Some OMAP modules on OMAP3 ES2+ chips have both initiator and + * target IDLEST bits. For our purposes, we are concerned with the + * target IDLEST bits, which exist at a different bit position than + * the *CLKEN bit position for these modules (DSS and USBHOST) (The + * default find_idlest code assumes that they are at the same + * position.) No return value. + */ +static void omap3430es2_clk_dss_usbhost_find_idlest(struct clk *clk, + void __iomem **idlest_reg, + u8 *idlest_bit) +{ + u32 r; + + r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); + *idlest_reg = (__force void __iomem *)r; + /* USBHOST_IDLE has same shift */ + *idlest_bit = OMAP3430ES2_ST_DSS_IDLE_SHIFT; +} + +/** + * omap3430es2_clk_hsotgusb_find_idlest - return CM_IDLEST info for HSOTGUSB + * @clk: struct clk * being enabled + * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into + * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into + * + * The OMAP3430ES2 HSOTGUSB target CM_IDLEST bit is at a different + * shift from the CM_{I,F}CLKEN bit. Pass back the correct info via + * @idlest_reg and @idlest_bit. No return value. + */ +static void omap3430es2_clk_hsotgusb_find_idlest(struct clk *clk, + void __iomem **idlest_reg, + u8 *idlest_bit) +{ + u32 r; + + r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); + *idlest_reg = (__force void __iomem *)r; + *idlest_bit = OMAP3430ES2_ST_HSOTGUSB_IDLE_SHIFT; +} + +/** * omap3_dpll_recalc - recalculate DPLL rate * @clk: DPLL struct clk * @@ -725,7 +830,9 @@ static int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate) u32 unlock_dll = 0; u32 c; unsigned long validrate, sdrcrate, mpurate; - struct omap_sdrc_params *sp; + struct omap_sdrc_params *sdrc_cs0; + struct omap_sdrc_params *sdrc_cs1; + int ret; if (!clk || !rate) return -EINVAL; @@ -743,8 +850,8 @@ static int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate) else sdrcrate >>= ((clk->rate / rate) >> 1); - sp = omap2_sdrc_get_params(sdrcrate); - if (!sp) + ret = omap2_sdrc_get_params(sdrcrate, &sdrc_cs0, &sdrc_cs1); + if (ret) return -EINVAL; if (sdrcrate < MIN_SDRC_DLL_LOCK_FREQ) { @@ -765,12 +872,29 @@ static int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate) pr_debug("clock: changing CORE DPLL rate from %lu to %lu\n", clk->rate, validrate); - pr_debug("clock: SDRC timing params used: %08x %08x %08x\n", - sp->rfr_ctrl, sp->actim_ctrla, sp->actim_ctrlb); - - omap3_configure_core_dpll(sp->rfr_ctrl, sp->actim_ctrla, - sp->actim_ctrlb, new_div, unlock_dll, c, - sp->mr, rate > clk->rate); + pr_debug("clock: SDRC CS0 timing params used:" + " RFR %08x CTRLA %08x CTRLB %08x MR %08x\n", + sdrc_cs0->rfr_ctrl, sdrc_cs0->actim_ctrla, + sdrc_cs0->actim_ctrlb, sdrc_cs0->mr); + if (sdrc_cs1) + pr_debug("clock: SDRC CS1 timing params used: " + " RFR %08x CTRLA %08x CTRLB %08x MR %08x\n", + sdrc_cs1->rfr_ctrl, sdrc_cs1->actim_ctrla, + sdrc_cs1->actim_ctrlb, sdrc_cs1->mr); + + if (sdrc_cs1) + omap3_configure_core_dpll( + new_div, unlock_dll, c, rate > clk->rate, + sdrc_cs0->rfr_ctrl, sdrc_cs0->actim_ctrla, + sdrc_cs0->actim_ctrlb, sdrc_cs0->mr, + sdrc_cs1->rfr_ctrl, sdrc_cs1->actim_ctrla, + sdrc_cs1->actim_ctrlb, sdrc_cs1->mr); + else + omap3_configure_core_dpll( + new_div, unlock_dll, c, rate > clk->rate, + sdrc_cs0->rfr_ctrl, sdrc_cs0->actim_ctrla, + sdrc_cs0->actim_ctrlb, sdrc_cs0->mr, + 0, 0, 0, 0); return 0; } @@ -944,17 +1068,17 @@ static int __init omap2_clk_arch_init(void) return -EINVAL; /* REVISIT: not yet ready for 343x */ -#if 0 - if (clk_set_rate(&virt_prcm_set, mpurate)) - printk(KERN_ERR "Could not find matching MPU rate\n"); -#endif + if (clk_set_rate(&dpll1_ck, mpurate)) + printk(KERN_ERR "*** Unable to set MPU rate\n"); recalculate_root_clocks(); - printk(KERN_INFO "Switched to new clocking rate (Crystal/DPLL3/MPU): " + printk(KERN_INFO "Switched to new clocking rate (Crystal/Core/MPU): " "%ld.%01ld/%ld/%ld MHz\n", - (osc_sys_ck.rate / 1000000), (osc_sys_ck.rate / 100000) % 10, - (core_ck.rate / 1000000), (dpll1_fck.rate / 1000000)) ; + (osc_sys_ck.rate / 1000000), ((osc_sys_ck.rate / 100000) % 10), + (core_ck.rate / 1000000), (arm_fck.rate / 1000000)) ; + + calibrate_delay(); return 0; } @@ -1013,7 +1137,7 @@ int __init omap2_clk_init(void) recalculate_root_clocks(); - printk(KERN_INFO "Clocking rate (Crystal/DPLL/ARM core): " + printk(KERN_INFO "Clocking rate (Crystal/Core/MPU): " "%ld.%01ld/%ld/%ld MHz\n", (osc_sys_ck.rate / 1000000), (osc_sys_ck.rate / 100000) % 10, (core_ck.rate / 1000000), (arm_fck.rate / 1000000)); diff --git a/arch/arm/mach-omap2/clock34xx.h b/arch/arm/mach-omap2/clock34xx.h index e433aec4efd..c8119781e00 100644 --- a/arch/arm/mach-omap2/clock34xx.h +++ b/arch/arm/mach-omap2/clock34xx.h @@ -1020,6 +1020,7 @@ static struct clk arm_fck = { .clksel_reg = OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_IDLEST_PLL), .clksel_mask = OMAP3430_ST_MPU_CLK_MASK, .clksel = arm_fck_clksel, + .clkdm_name = "mpu_clkdm", .recalc = &omap2_clksel_recalc, }; @@ -1155,7 +1156,6 @@ static struct clk gfx_cg1_ck = { .name = "gfx_cg1_ck", .ops = &clkops_omap2_dflt_wait, .parent = &gfx_l3_fck, /* REVISIT: correct? */ - .init = &omap2_init_clk_clkdm, .enable_reg = OMAP_CM_REGADDR(GFX_MOD, CM_FCLKEN), .enable_bit = OMAP3430ES1_EN_2D_SHIFT, .clkdm_name = "gfx_3430es1_clkdm", @@ -1166,7 +1166,6 @@ static struct clk gfx_cg2_ck = { .name = "gfx_cg2_ck", .ops = &clkops_omap2_dflt_wait, .parent = &gfx_l3_fck, /* REVISIT: correct? */ - .init = &omap2_init_clk_clkdm, .enable_reg = OMAP_CM_REGADDR(GFX_MOD, CM_FCLKEN), .enable_bit = OMAP3430ES1_EN_3D_SHIFT, .clkdm_name = "gfx_3430es1_clkdm", @@ -1210,7 +1209,6 @@ static struct clk sgx_ick = { .name = "sgx_ick", .ops = &clkops_omap2_dflt_wait, .parent = &l3_ick, - .init = &omap2_init_clk_clkdm, .enable_reg = OMAP_CM_REGADDR(OMAP3430ES2_SGX_MOD, CM_ICLKEN), .enable_bit = OMAP3430ES2_CM_ICLKEN_SGX_EN_SGX_SHIFT, .clkdm_name = "sgx_clkdm", @@ -1223,7 +1221,6 @@ static struct clk d2d_26m_fck = { .name = "d2d_26m_fck", .ops = &clkops_omap2_dflt_wait, .parent = &sys_ck, - .init = &omap2_init_clk_clkdm, .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP3430ES1_EN_D2D_SHIFT, .clkdm_name = "d2d_clkdm", @@ -1234,7 +1231,6 @@ static struct clk modem_fck = { .name = "modem_fck", .ops = &clkops_omap2_dflt_wait, .parent = &sys_ck, - .init = &omap2_init_clk_clkdm, .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP3430_EN_MODEM_SHIFT, .clkdm_name = "d2d_clkdm", @@ -1568,7 +1564,7 @@ static const struct clksel ssi_ssr_clksel[] = { { .parent = NULL } }; -static struct clk ssi_ssr_fck = { +static struct clk ssi_ssr_fck_3430es1 = { .name = "ssi_ssr_fck", .ops = &clkops_omap2_dflt, .init = &omap2_init_clksel_parent, @@ -1581,10 +1577,31 @@ static struct clk ssi_ssr_fck = { .recalc = &omap2_clksel_recalc, }; -static struct clk ssi_sst_fck = { +static struct clk ssi_ssr_fck_3430es2 = { + .name = "ssi_ssr_fck", + .ops = &clkops_omap3430es2_ssi_wait, + .init = &omap2_init_clksel_parent, + .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), + .enable_bit = OMAP3430_EN_SSI_SHIFT, + .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL), + .clksel_mask = OMAP3430_CLKSEL_SSI_MASK, + .clksel = ssi_ssr_clksel, + .clkdm_name = "core_l4_clkdm", + .recalc = &omap2_clksel_recalc, +}; + +static struct clk ssi_sst_fck_3430es1 = { .name = "ssi_sst_fck", .ops = &clkops_null, - .parent = &ssi_ssr_fck, + .parent = &ssi_ssr_fck_3430es1, + .fixed_div = 2, + .recalc = &omap2_fixed_divisor_recalc, +}; + +static struct clk ssi_sst_fck_3430es2 = { + .name = "ssi_sst_fck", + .ops = &clkops_null, + .parent = &ssi_ssr_fck_3430es2, .fixed_div = 2, .recalc = &omap2_fixed_divisor_recalc, }; @@ -1601,14 +1618,23 @@ static struct clk core_l3_ick = { .name = "core_l3_ick", .ops = &clkops_null, .parent = &l3_ick, - .init = &omap2_init_clk_clkdm, .clkdm_name = "core_l3_clkdm", .recalc = &followparent_recalc, }; -static struct clk hsotgusb_ick = { +static struct clk hsotgusb_ick_3430es1 = { .name = "hsotgusb_ick", - .ops = &clkops_omap2_dflt_wait, + .ops = &clkops_omap2_dflt, + .parent = &core_l3_ick, + .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1), + .enable_bit = OMAP3430_EN_HSOTGUSB_SHIFT, + .clkdm_name = "core_l3_clkdm", + .recalc = &followparent_recalc, +}; + +static struct clk hsotgusb_ick_3430es2 = { + .name = "hsotgusb_ick", + .ops = &clkops_omap3430es2_hsotgusb_wait, .parent = &core_l3_ick, .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1), .enable_bit = OMAP3430_EN_HSOTGUSB_SHIFT, @@ -1660,7 +1686,6 @@ static struct clk core_l4_ick = { .name = "core_l4_ick", .ops = &clkops_null, .parent = &l4_ick, - .init = &omap2_init_clk_clkdm, .clkdm_name = "core_l4_clkdm", .recalc = &followparent_recalc, }; @@ -1947,7 +1972,7 @@ static struct clk ssi_l4_ick = { .recalc = &followparent_recalc, }; -static struct clk ssi_ick = { +static struct clk ssi_ick_3430es1 = { .name = "ssi_ick", .ops = &clkops_omap2_dflt, .parent = &ssi_l4_ick, @@ -1957,6 +1982,16 @@ static struct clk ssi_ick = { .recalc = &followparent_recalc, }; +static struct clk ssi_ick_3430es2 = { + .name = "ssi_ick", + .ops = &clkops_omap3430es2_ssi_wait, + .parent = &ssi_l4_ick, + .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1), + .enable_bit = OMAP3430_EN_SSI_SHIFT, + .clkdm_name = "core_l4_clkdm", + .recalc = &followparent_recalc, +}; + /* REVISIT: Technically the TRM claims that this is CORE_CLK based, * but l4_ick makes more sense to me */ @@ -2024,7 +2059,7 @@ static struct clk des1_ick = { }; /* DSS */ -static struct clk dss1_alwon_fck = { +static struct clk dss1_alwon_fck_3430es1 = { .name = "dss1_alwon_fck", .ops = &clkops_omap2_dflt, .parent = &dpll4_m4x2_ck, @@ -2034,11 +2069,20 @@ static struct clk dss1_alwon_fck = { .recalc = &followparent_recalc, }; +static struct clk dss1_alwon_fck_3430es2 = { + .name = "dss1_alwon_fck", + .ops = &clkops_omap3430es2_dss_usbhost_wait, + .parent = &dpll4_m4x2_ck, + .enable_reg = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_FCLKEN), + .enable_bit = OMAP3430_EN_DSS1_SHIFT, + .clkdm_name = "dss_clkdm", + .recalc = &followparent_recalc, +}; + static struct clk dss_tv_fck = { .name = "dss_tv_fck", .ops = &clkops_omap2_dflt, .parent = &omap_54m_fck, - .init = &omap2_init_clk_clkdm, .enable_reg = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_FCLKEN), .enable_bit = OMAP3430_EN_TV_SHIFT, .clkdm_name = "dss_clkdm", @@ -2049,7 +2093,6 @@ static struct clk dss_96m_fck = { .name = "dss_96m_fck", .ops = &clkops_omap2_dflt, .parent = &omap_96m_fck, - .init = &omap2_init_clk_clkdm, .enable_reg = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_FCLKEN), .enable_bit = OMAP3430_EN_TV_SHIFT, .clkdm_name = "dss_clkdm", @@ -2060,19 +2103,28 @@ static struct clk dss2_alwon_fck = { .name = "dss2_alwon_fck", .ops = &clkops_omap2_dflt, .parent = &sys_ck, - .init = &omap2_init_clk_clkdm, .enable_reg = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_FCLKEN), .enable_bit = OMAP3430_EN_DSS2_SHIFT, .clkdm_name = "dss_clkdm", .recalc = &followparent_recalc, }; -static struct clk dss_ick = { +static struct clk dss_ick_3430es1 = { /* Handles both L3 and L4 clocks */ .name = "dss_ick", .ops = &clkops_omap2_dflt, .parent = &l4_ick, - .init = &omap2_init_clk_clkdm, + .enable_reg = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_ICLKEN), + .enable_bit = OMAP3430_CM_ICLKEN_DSS_EN_DSS_SHIFT, + .clkdm_name = "dss_clkdm", + .recalc = &followparent_recalc, +}; + +static struct clk dss_ick_3430es2 = { + /* Handles both L3 and L4 clocks */ + .name = "dss_ick", + .ops = &clkops_omap3430es2_dss_usbhost_wait, + .parent = &l4_ick, .enable_reg = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_ICLKEN), .enable_bit = OMAP3430_CM_ICLKEN_DSS_EN_DSS_SHIFT, .clkdm_name = "dss_clkdm", @@ -2096,7 +2148,6 @@ static struct clk cam_ick = { .name = "cam_ick", .ops = &clkops_omap2_dflt, .parent = &l4_ick, - .init = &omap2_init_clk_clkdm, .enable_reg = OMAP_CM_REGADDR(OMAP3430_CAM_MOD, CM_ICLKEN), .enable_bit = OMAP3430_EN_CAM_SHIFT, .clkdm_name = "cam_clkdm", @@ -2107,7 +2158,6 @@ static struct clk csi2_96m_fck = { .name = "csi2_96m_fck", .ops = &clkops_omap2_dflt, .parent = &core_96m_fck, - .init = &omap2_init_clk_clkdm, .enable_reg = OMAP_CM_REGADDR(OMAP3430_CAM_MOD, CM_FCLKEN), .enable_bit = OMAP3430_EN_CSI2_SHIFT, .clkdm_name = "cam_clkdm", @@ -2118,9 +2168,8 @@ static struct clk csi2_96m_fck = { static struct clk usbhost_120m_fck = { .name = "usbhost_120m_fck", - .ops = &clkops_omap2_dflt_wait, + .ops = &clkops_omap2_dflt, .parent = &dpll5_m2_ck, - .init = &omap2_init_clk_clkdm, .enable_reg = OMAP_CM_REGADDR(OMAP3430ES2_USBHOST_MOD, CM_FCLKEN), .enable_bit = OMAP3430ES2_EN_USBHOST2_SHIFT, .clkdm_name = "usbhost_clkdm", @@ -2129,9 +2178,8 @@ static struct clk usbhost_120m_fck = { static struct clk usbhost_48m_fck = { .name = "usbhost_48m_fck", - .ops = &clkops_omap2_dflt_wait, + .ops = &clkops_omap3430es2_dss_usbhost_wait, .parent = &omap_48m_fck, - .init = &omap2_init_clk_clkdm, .enable_reg = OMAP_CM_REGADDR(OMAP3430ES2_USBHOST_MOD, CM_FCLKEN), .enable_bit = OMAP3430ES2_EN_USBHOST1_SHIFT, .clkdm_name = "usbhost_clkdm", @@ -2141,9 +2189,8 @@ static struct clk usbhost_48m_fck = { static struct clk usbhost_ick = { /* Handles both L3 and L4 clocks */ .name = "usbhost_ick", - .ops = &clkops_omap2_dflt_wait, + .ops = &clkops_omap3430es2_dss_usbhost_wait, .parent = &l4_ick, - .init = &omap2_init_clk_clkdm, .enable_reg = OMAP_CM_REGADDR(OMAP3430ES2_USBHOST_MOD, CM_ICLKEN), .enable_bit = OMAP3430ES2_EN_USBHOST_SHIFT, .clkdm_name = "usbhost_clkdm", @@ -2205,7 +2252,6 @@ static struct clk gpt1_fck = { static struct clk wkup_32k_fck = { .name = "wkup_32k_fck", .ops = &clkops_null, - .init = &omap2_init_clk_clkdm, .parent = &omap_32k_fck, .clkdm_name = "wkup_clkdm", .recalc = &followparent_recalc, @@ -2320,7 +2366,6 @@ static struct clk per_96m_fck = { .name = "per_96m_fck", .ops = &clkops_null, .parent = &omap_96m_alwon_fck, - .init = &omap2_init_clk_clkdm, .clkdm_name = "per_clkdm", .recalc = &followparent_recalc, }; @@ -2329,7 +2374,6 @@ static struct clk per_48m_fck = { .name = "per_48m_fck", .ops = &clkops_null, .parent = &omap_48m_fck, - .init = &omap2_init_clk_clkdm, .clkdm_name = "per_clkdm", .recalc = &followparent_recalc, }; diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index 0e7d501865b..4ef7b4f5474 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c @@ -299,7 +299,8 @@ struct clockdomain *clkdm_lookup(const char *name) * anything else to indicate failure; or -EINVAL if the function pointer * is null. */ -int clkdm_for_each(int (*fn)(struct clockdomain *clkdm)) +int clkdm_for_each(int (*fn)(struct clockdomain *clkdm, void *user), + void *user) { struct clockdomain *clkdm; int ret = 0; @@ -309,7 +310,7 @@ int clkdm_for_each(int (*fn)(struct clockdomain *clkdm)) mutex_lock(&clkdm_mutex); list_for_each_entry(clkdm, &clkdm_list, node) { - ret = (*fn)(clkdm); + ret = (*fn)(clkdm, user); if (ret) break; } @@ -484,6 +485,8 @@ void omap2_clkdm_allow_idle(struct clockdomain *clkdm) v << __ffs(clkdm->clktrctrl_mask), clkdm->pwrdm.ptr->prcm_offs, CM_CLKSTCTRL); + + pwrdm_clkdm_state_switch(clkdm); } /** @@ -572,6 +575,7 @@ int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk) omap2_clkdm_wakeup(clkdm); pwrdm_wait_transition(clkdm->pwrdm.ptr); + pwrdm_clkdm_state_switch(clkdm); return 0; } @@ -624,6 +628,8 @@ int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk) else omap2_clkdm_sleep(clkdm); + pwrdm_clkdm_state_switch(clkdm); + return 0; } diff --git a/arch/arm/mach-omap2/cm.c b/arch/arm/mach-omap2/cm.c new file mode 100644 index 00000000000..8eb2dab8c7d --- /dev/null +++ b/arch/arm/mach-omap2/cm.c @@ -0,0 +1,70 @@ +/* + * OMAP2/3 CM module functions + * + * Copyright (C) 2009 Nokia Corporation + * Paul Walmsley + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/delay.h> +#include <linux/spinlock.h> +#include <linux/list.h> +#include <linux/errno.h> +#include <linux/err.h> +#include <linux/io.h> + +#include <asm/atomic.h> + +#include "cm.h" +#include "cm-regbits-24xx.h" +#include "cm-regbits-34xx.h" + +/* MAX_MODULE_READY_TIME: max milliseconds for module to leave idle */ +#define MAX_MODULE_READY_TIME 20000 + +static const u8 cm_idlest_offs[] = { + CM_IDLEST1, CM_IDLEST2, OMAP2430_CM_IDLEST3 +}; + +/** + * omap2_cm_wait_idlest_ready - wait for a module to leave idle or standby + * @prcm_mod: PRCM module offset + * @idlest_id: CM_IDLESTx register ID (i.e., x = 1, 2, 3) + * @idlest_shift: shift of the bit in the CM_IDLEST* register to check + * + * XXX document + */ +int omap2_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift) +{ + int ena = 0, i = 0; + u8 cm_idlest_reg; + u32 mask; + + if (!idlest_id || (idlest_id > ARRAY_SIZE(cm_idlest_offs))) + return -EINVAL; + + cm_idlest_reg = cm_idlest_offs[idlest_id - 1]; + + if (cpu_is_omap24xx()) + ena = idlest_shift; + else if (cpu_is_omap34xx()) + ena = 0; + else + BUG(); + + mask = 1 << idlest_shift; + + /* XXX should be OMAP2 CM */ + while (((cm_read_mod_reg(prcm_mod, cm_idlest_reg) & mask) != ena) && + (i++ < MAX_MODULE_READY_TIME)) + udelay(1); + + return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY; +} + diff --git a/arch/arm/mach-omap2/cm.h b/arch/arm/mach-omap2/cm.h index 1d3c93bf86d..cfd0b726ba4 100644 --- a/arch/arm/mach-omap2/cm.h +++ b/arch/arm/mach-omap2/cm.h @@ -17,11 +17,11 @@ #include "prcm-common.h" #define OMAP2420_CM_REGADDR(module, reg) \ - IO_ADDRESS(OMAP2420_CM_BASE + (module) + (reg)) + OMAP2_IO_ADDRESS(OMAP2420_CM_BASE + (module) + (reg)) #define OMAP2430_CM_REGADDR(module, reg) \ - IO_ADDRESS(OMAP2430_CM_BASE + (module) + (reg)) + OMAP2_IO_ADDRESS(OMAP2430_CM_BASE + (module) + (reg)) #define OMAP34XX_CM_REGADDR(module, reg) \ - IO_ADDRESS(OMAP3430_CM_BASE + (module) + (reg)) + OMAP2_IO_ADDRESS(OMAP3430_CM_BASE + (module) + (reg)) /* * Architecture-specific global CM registers @@ -29,9 +29,9 @@ * These registers appear once per CM module. */ -#define OMAP3430_CM_REVISION OMAP_CM_REGADDR(OCP_MOD, 0x0000) -#define OMAP3430_CM_SYSCONFIG OMAP_CM_REGADDR(OCP_MOD, 0x0010) -#define OMAP3430_CM_POLCTRL OMAP_CM_REGADDR(OCP_MOD, 0x009c) +#define OMAP3430_CM_REVISION OMAP34XX_CM_REGADDR(OCP_MOD, 0x0000) +#define OMAP3430_CM_SYSCONFIG OMAP34XX_CM_REGADDR(OCP_MOD, 0x0010) +#define OMAP3430_CM_POLCTRL OMAP34XX_CM_REGADDR(OCP_MOD, 0x009c) #define OMAP3_CM_CLKOUT_CTRL_OFFSET 0x0070 #define OMAP3430_CM_CLKOUT_CTRL OMAP_CM_REGADDR(OMAP3430_CCR_MOD, 0x0070) @@ -98,6 +98,10 @@ extern u32 cm_read_mod_reg(s16 module, u16 idx); extern void cm_write_mod_reg(u32 val, s16 module, u16 idx); extern u32 cm_rmw_mod_reg_bits(u32 mask, u32 bits, s16 module, s16 idx); +extern int omap2_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, + u8 idlest_shift); +extern int omap4_cm_wait_module_ready(u32 prcm_mod, u8 prcm_dev_offs); + static inline u32 cm_set_mod_reg_bits(u32 bits, s16 module, s16 idx) { return cm_rmw_mod_reg_bits(bits, bits, module, idx); diff --git a/arch/arm/mach-omap2/cm4xxx.c b/arch/arm/mach-omap2/cm4xxx.c new file mode 100644 index 00000000000..4af76bb1003 --- /dev/null +++ b/arch/arm/mach-omap2/cm4xxx.c @@ -0,0 +1,55 @@ +/* + * OMAP4 CM module functions + * + * Copyright (C) 2009 Nokia Corporation + * Paul Walmsley + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/delay.h> +#include <linux/spinlock.h> +#include <linux/list.h> +#include <linux/errno.h> +#include <linux/err.h> +#include <linux/io.h> + +#include <asm/atomic.h> + +#include "cm.h" + +/* XXX move this to cm.h */ +/* MAX_MODULE_READY_TIME: max milliseconds for module to leave idle */ +#define MAX_MODULE_READY_TIME 20000 + +/* + * OMAP4_PRCM_CM_CLKCTRL_IDLEST_MASK: isolates the IDLEST field in the + * CM_CLKCTRL register. + */ +#define OMAP4_PRCM_CM_CLKCTRL_IDLEST_MASK (0x2 << 16) + +/* + * OMAP4 prcm_mod u32 fields contain packed data: the CM ID in bit 16 and + * the PRCM module offset address (from the CM module base) in bits 15-0. + */ +#define OMAP4_PRCM_MOD_CM_ID_SHIFT 16 +#define OMAP4_PRCM_MOD_OFFS_MASK 0xffff + +/** + * omap4_cm_wait_idlest_ready - wait for a module to leave idle or standby + * @prcm_mod: PRCM module offset (XXX example) + * @prcm_dev_offs: PRCM device offset (e.g. MCASP XXX example) + * + * XXX document + */ +int omap4_cm_wait_idlest_ready(u32 prcm_mod, u8 prcm_dev_offs) +{ + /* FIXME: Add clock manager related code */ + return 0; +} + diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index 894cc355818..faf7a1e0c52 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c @@ -257,6 +257,11 @@ static inline void omap_init_sti(void) {} #define OMAP2_MCSPI3_BASE 0x480b8000 #define OMAP2_MCSPI4_BASE 0x480ba000 +#define OMAP4_MCSPI1_BASE 0x48098100 +#define OMAP4_MCSPI2_BASE 0x4809a100 +#define OMAP4_MCSPI3_BASE 0x480b8100 +#define OMAP4_MCSPI4_BASE 0x480ba100 + static struct omap2_mcspi_platform_config omap2_mcspi1_config = { .num_cs = 4, }; @@ -301,7 +306,8 @@ static struct platform_device omap2_mcspi2 = { }, }; -#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) +#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \ + defined(CONFIG_ARCH_OMAP4) static struct omap2_mcspi_platform_config omap2_mcspi3_config = { .num_cs = 2, }; @@ -325,7 +331,7 @@ static struct platform_device omap2_mcspi3 = { }; #endif -#ifdef CONFIG_ARCH_OMAP3 +#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4) static struct omap2_mcspi_platform_config omap2_mcspi4_config = { .num_cs = 1, }; @@ -349,18 +355,60 @@ static struct platform_device omap2_mcspi4 = { }; #endif +#ifdef CONFIG_ARCH_OMAP4 +static inline void omap4_mcspi_fixup(void) +{ + omap2_mcspi1_resources[0].start = OMAP4_MCSPI1_BASE; + omap2_mcspi1_resources[0].end = OMAP4_MCSPI1_BASE + 0xff; + omap2_mcspi2_resources[0].start = OMAP4_MCSPI2_BASE; + omap2_mcspi2_resources[0].end = OMAP4_MCSPI2_BASE + 0xff; + omap2_mcspi3_resources[0].start = OMAP4_MCSPI3_BASE; + omap2_mcspi3_resources[0].end = OMAP4_MCSPI3_BASE + 0xff; + omap2_mcspi4_resources[0].start = OMAP4_MCSPI4_BASE; + omap2_mcspi4_resources[0].end = OMAP4_MCSPI4_BASE + 0xff; +} +#else +static inline void omap4_mcspi_fixup(void) +{ +} +#endif + +#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \ + defined(CONFIG_ARCH_OMAP4) +static inline void omap2_mcspi3_init(void) +{ + platform_device_register(&omap2_mcspi3); +} +#else +static inline void omap2_mcspi3_init(void) +{ +} +#endif + +#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4) +static inline void omap2_mcspi4_init(void) +{ + platform_device_register(&omap2_mcspi4); +} +#else +static inline void omap2_mcspi4_init(void) +{ +} +#endif + static void omap_init_mcspi(void) { + if (cpu_is_omap44xx()) + omap4_mcspi_fixup(); + platform_device_register(&omap2_mcspi1); platform_device_register(&omap2_mcspi2); -#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) - if (cpu_is_omap2430() || cpu_is_omap343x()) - platform_device_register(&omap2_mcspi3); -#endif -#ifdef CONFIG_ARCH_OMAP3 - if (cpu_is_omap343x()) - platform_device_register(&omap2_mcspi4); -#endif + + if (cpu_is_omap2430() || cpu_is_omap343x() || cpu_is_omap44xx()) + omap2_mcspi3_init(); + + if (cpu_is_omap343x() || cpu_is_omap44xx()) + omap2_mcspi4_init(); } #else @@ -397,7 +445,7 @@ static inline void omap_init_sha1_md5(void) { } /*-------------------------------------------------------------------------*/ -#ifdef CONFIG_ARCH_OMAP3 +#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4) #define MMCHS_SYSCONFIG 0x0010 #define MMCHS_SYSCONFIG_SWRESET (1 << 1) @@ -424,8 +472,8 @@ static struct platform_device dummy_pdev = { **/ static void __init omap_hsmmc_reset(void) { - u32 i, nr_controllers = cpu_is_omap34xx() ? OMAP34XX_NR_MMC : - OMAP24XX_NR_MMC; + u32 i, nr_controllers = cpu_is_omap44xx() ? OMAP44XX_NR_MMC : + (cpu_is_omap34xx() ? OMAP34XX_NR_MMC : OMAP24XX_NR_MMC); for (i = 0; i < nr_controllers; i++) { u32 v, base = 0; @@ -442,8 +490,21 @@ static void __init omap_hsmmc_reset(void) case 2: base = OMAP3_MMC3_BASE; break; + case 3: + if (!cpu_is_omap44xx()) + return; + base = OMAP4_MMC4_BASE; + break; + case 4: + if (!cpu_is_omap44xx()) + return; + base = OMAP4_MMC5_BASE; + break; } + if (cpu_is_omap44xx()) + base += OMAP4_MMC_REG_OFFSET; + dummy_pdev.id = i; dev_set_name(&dummy_pdev.dev, "mmci-omap-hs.%d", i); iclk = clk_get(dev, "ick"); @@ -513,6 +574,47 @@ static inline void omap2_mmc_mux(struct omap_mmc_platform_data *mmc_controller, omap_ctrl_writel(v, OMAP2_CONTROL_DEVCONF0); } } + + if (cpu_is_omap3430()) { + if (controller_nr == 0) { + omap_cfg_reg(N28_3430_MMC1_CLK); + omap_cfg_reg(M27_3430_MMC1_CMD); + omap_cfg_reg(N27_3430_MMC1_DAT0); + if (mmc_controller->slots[0].wires == 4 || + mmc_controller->slots[0].wires == 8) { + omap_cfg_reg(N26_3430_MMC1_DAT1); + omap_cfg_reg(N25_3430_MMC1_DAT2); + omap_cfg_reg(P28_3430_MMC1_DAT3); + } + if (mmc_controller->slots[0].wires == 8) { + omap_cfg_reg(P27_3430_MMC1_DAT4); + omap_cfg_reg(P26_3430_MMC1_DAT5); + omap_cfg_reg(R27_3430_MMC1_DAT6); + omap_cfg_reg(R25_3430_MMC1_DAT7); + } + } + if (controller_nr == 1) { + /* MMC2 */ + omap_cfg_reg(AE2_3430_MMC2_CLK); + omap_cfg_reg(AG5_3430_MMC2_CMD); + omap_cfg_reg(AH5_3430_MMC2_DAT0); + + /* + * For 8 wire configurations, Lines DAT4, 5, 6 and 7 need to be muxed + * in the board-*.c files + */ + if (mmc_controller->slots[0].wires == 4 || + mmc_controller->slots[0].wires == 8) { + omap_cfg_reg(AH4_3430_MMC2_DAT1); + omap_cfg_reg(AG4_3430_MMC2_DAT2); + omap_cfg_reg(AF4_3430_MMC2_DAT3); + } + } + + /* + * For MMC3 the pins need to be muxed in the board-*.c files + */ + } } void __init omap2_init_mmc(struct omap_mmc_platform_data **mmc_data, @@ -540,11 +642,23 @@ void __init omap2_init_mmc(struct omap_mmc_platform_data **mmc_data, irq = INT_24XX_MMC2_IRQ; break; case 2: - if (!cpu_is_omap34xx()) + if (!cpu_is_omap44xx() && !cpu_is_omap34xx()) return; base = OMAP3_MMC3_BASE; irq = INT_34XX_MMC3_IRQ; break; + case 3: + if (!cpu_is_omap44xx()) + return; + base = OMAP4_MMC4_BASE + OMAP4_MMC_REG_OFFSET; + irq = INT_44XX_MMC4_IRQ; + break; + case 4: + if (!cpu_is_omap44xx()) + return; + base = OMAP4_MMC5_BASE + OMAP4_MMC_REG_OFFSET; + irq = INT_44XX_MMC5_IRQ; + break; default: continue; } @@ -552,8 +666,15 @@ void __init omap2_init_mmc(struct omap_mmc_platform_data **mmc_data, if (cpu_is_omap2420()) { size = OMAP2420_MMC_SIZE; name = "mmci-omap"; + } else if (cpu_is_omap44xx()) { + if (i < 3) { + base += OMAP4_MMC_REG_OFFSET; + irq += IRQ_GIC_START; + } + size = OMAP4_HSMMC_SIZE; + name = "mmci-omap-hs"; } else { - size = HSMMC_SIZE; + size = OMAP3_HSMMC_SIZE; name = "mmci-omap-hs"; } omap_mmc_add(name, i, base, size, irq, mmc_data[i]); diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c index 2fd22f9c5f0..54fec53a48e 100644 --- a/arch/arm/mach-omap2/gpmc-onenand.c +++ b/arch/arm/mach-omap2/gpmc-onenand.c @@ -31,6 +31,8 @@ static struct platform_device gpmc_onenand_device = { static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base) { struct gpmc_timings t; + u32 reg; + int err; const int t_cer = 15; const int t_avdp = 12; @@ -43,6 +45,11 @@ static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base) const int t_wpl = 40; const int t_wph = 30; + /* Ensure sync read and sync write are disabled */ + reg = readw(onenand_base + ONENAND_REG_SYS_CFG1); + reg &= ~ONENAND_SYS_CFG1_SYNC_READ & ~ONENAND_SYS_CFG1_SYNC_WRITE; + writew(reg, onenand_base + ONENAND_REG_SYS_CFG1); + memset(&t, 0, sizeof(t)); t.sync_clk = 0; t.cs_on = 0; @@ -74,7 +81,16 @@ static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base) GPMC_CONFIG1_DEVICESIZE_16 | GPMC_CONFIG1_MUXADDDATA); - return gpmc_cs_set_timings(cs, &t); + err = gpmc_cs_set_timings(cs, &t); + if (err) + return err; + + /* Ensure sync read and sync write are disabled */ + reg = readw(onenand_base + ONENAND_REG_SYS_CFG1); + reg &= ~ONENAND_SYS_CFG1_SYNC_READ & ~ONENAND_SYS_CFG1_SYNC_WRITE; + writew(reg, onenand_base + ONENAND_REG_SYS_CFG1); + + return 0; } static void set_onenand_cfg(void __iomem *onenand_base, int latency, @@ -124,7 +140,8 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg, } else if (cfg->flags & ONENAND_SYNC_READWRITE) { sync_read = 1; sync_write = 1; - } + } else + return omap2_onenand_set_async_mode(cs, onenand_base); if (!freq) { /* Very first call freq is not known */ diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index f91934b2b09..15876828db2 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -57,6 +57,11 @@ #define GPMC_CHUNK_SHIFT 24 /* 16 MB */ #define GPMC_SECTION_SHIFT 28 /* 128 MB */ +#define PREFETCH_FIFOTHRESHOLD (0x40 << 8) +#define CS_NUM_SHIFT 24 +#define ENABLE_PREFETCH (0x1 << 7) +#define DMA_MPU_MODE 2 + static struct resource gpmc_mem_root; static struct resource gpmc_cs_mem[GPMC_CS_NUM]; static DEFINE_SPINLOCK(gpmc_mem_lock); @@ -386,6 +391,63 @@ void gpmc_cs_free(int cs) } EXPORT_SYMBOL(gpmc_cs_free); +/** + * gpmc_prefetch_enable - configures and starts prefetch transfer + * @cs: nand cs (chip select) number + * @dma_mode: dma mode enable (1) or disable (0) + * @u32_count: number of bytes to be transferred + * @is_write: prefetch read(0) or write post(1) mode + */ +int gpmc_prefetch_enable(int cs, int dma_mode, + unsigned int u32_count, int is_write) +{ + uint32_t prefetch_config1; + + if (!(gpmc_read_reg(GPMC_PREFETCH_CONTROL))) { + /* Set the amount of bytes to be prefetched */ + gpmc_write_reg(GPMC_PREFETCH_CONFIG2, u32_count); + + /* Set dma/mpu mode, the prefetch read / post write and + * enable the engine. Set which cs is has requested for. + */ + prefetch_config1 = ((cs << CS_NUM_SHIFT) | + PREFETCH_FIFOTHRESHOLD | + ENABLE_PREFETCH | + (dma_mode << DMA_MPU_MODE) | + (0x1 & is_write)); + gpmc_write_reg(GPMC_PREFETCH_CONFIG1, prefetch_config1); + } else { + return -EBUSY; + } + /* Start the prefetch engine */ + gpmc_write_reg(GPMC_PREFETCH_CONTROL, 0x1); + + return 0; +} +EXPORT_SYMBOL(gpmc_prefetch_enable); + +/** + * gpmc_prefetch_reset - disables and stops the prefetch engine + */ +void gpmc_prefetch_reset(void) +{ + /* Stop the PFPW engine */ + gpmc_write_reg(GPMC_PREFETCH_CONTROL, 0x0); + + /* Reset/disable the PFPW engine */ + gpmc_write_reg(GPMC_PREFETCH_CONFIG1, 0x0); +} +EXPORT_SYMBOL(gpmc_prefetch_reset); + +/** + * gpmc_prefetch_status - reads prefetch status of engine + */ +int gpmc_prefetch_status(void) +{ + return gpmc_read_reg(GPMC_PREFETCH_STATUS); +} +EXPORT_SYMBOL(gpmc_prefetch_status); + static void __init gpmc_mem_init(void) { int cs; @@ -452,6 +514,5 @@ void __init gpmc_init(void) l &= 0x03 << 3; l |= (0x02 << 3) | (1 << 0); gpmc_write_reg(GPMC_SYSCONFIG, l); - gpmc_mem_init(); } diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c index 458990e20c6..a98201cc265 100644 --- a/arch/arm/mach-omap2/id.c +++ b/arch/arm/mach-omap2/id.c @@ -48,6 +48,28 @@ int omap_chip_is(struct omap_chip_id oci) } EXPORT_SYMBOL(omap_chip_is); +int omap_type(void) +{ + u32 val = 0; + + if (cpu_is_omap24xx()) + val = omap_ctrl_readl(OMAP24XX_CONTROL_STATUS); + else if (cpu_is_omap34xx()) + val = omap_ctrl_readl(OMAP343X_CONTROL_STATUS); + else { + pr_err("Cannot detect omap type!\n"); + goto out; + } + + val &= OMAP2_DEVICETYPE_MASK; + val >>= 8; + +out: + return val; +} +EXPORT_SYMBOL(omap_type); + + /*----------------------------------------------------------------------------*/ #define OMAP_TAP_IDCODE 0x0204 diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 3a86b0f6603..e3a3bad1d84 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -32,17 +32,23 @@ #include <mach/sram.h> #include <mach/sdrc.h> #include <mach/gpmc.h> +#include <mach/serial.h> #ifndef CONFIG_ARCH_OMAP4 /* FIXME: Remove this once clkdev is ready */ #include "clock.h" +#include <mach/omap-pm.h> #include <mach/powerdomain.h> - #include "powerdomains.h" #include <mach/clockdomain.h> #include "clockdomains.h" #endif +#include <mach/omap_hwmod.h> +#include "omap_hwmod_2420.h" +#include "omap_hwmod_2430.h" +#include "omap_hwmod_34xx.h" + /* * The machine specific code may provide the extra mapping besides the * default mapping provided here. @@ -276,14 +282,30 @@ static int __init _omap2_init_reprogram_sdrc(void) return v; } -void __init omap2_init_common_hw(struct omap_sdrc_params *sp) +void __init omap2_init_common_hw(struct omap_sdrc_params *sdrc_cs0, + struct omap_sdrc_params *sdrc_cs1) { - omap2_mux_init(); + struct omap_hwmod **hwmods = NULL; + + if (cpu_is_omap2420()) + hwmods = omap2420_hwmods; + else if (cpu_is_omap2430()) + hwmods = omap2430_hwmods; + else if (cpu_is_omap34xx()) + hwmods = omap34xx_hwmods; + #ifndef CONFIG_ARCH_OMAP4 /* FIXME: Remove this once the clkdev is ready */ + /* The OPP tables have to be registered before a clk init */ + omap_hwmod_init(hwmods); + omap2_mux_init(); + omap_pm_if_early_init(mpu_opps, dsp_opps, l3_opps); pwrdm_init(powerdomains_omap); clkdm_init(clockdomains_omap, clkdm_pwrdm_autodeps); omap2_clk_init(); - omap2_sdrc_init(sp); + omap_serial_early_init(); + omap_hwmod_late_init(); + omap_pm_if_init(); + omap2_sdrc_init(sdrc_cs0, sdrc_cs1); _omap2_init_reprogram_sdrc(); #endif gpmc_init(); diff --git a/arch/arm/mach-omap2/iommu2.c b/arch/arm/mach-omap2/iommu2.c index 015f22a53ea..4a0e1cd5c1f 100644 --- a/arch/arm/mach-omap2/iommu2.c +++ b/arch/arm/mach-omap2/iommu2.c @@ -79,7 +79,7 @@ static int omap2_iommu_enable(struct iommu *obj) l = iommu_read_reg(obj, MMU_SYSSTATUS); if (l & MMU_SYS_RESETDONE) break; - } while (time_after(jiffies, timeout)); + } while (!time_after(jiffies, timeout)); if (!(l & MMU_SYS_RESETDONE)) { dev_err(obj->dev, "can't take mmu out of reset\n"); @@ -217,10 +217,19 @@ static ssize_t omap2_dump_cr(struct iommu *obj, struct cr_regs *cr, char *buf) } #define pr_reg(name) \ - p += sprintf(p, "%20s: %08x\n", \ - __stringify(name), iommu_read_reg(obj, MMU_##name)); - -static ssize_t omap2_iommu_dump_ctx(struct iommu *obj, char *buf) + do { \ + ssize_t bytes; \ + const char *str = "%20s: %08x\n"; \ + const int maxcol = 32; \ + bytes = snprintf(p, maxcol, str, __stringify(name), \ + iommu_read_reg(obj, MMU_##name)); \ + p += bytes; \ + len -= bytes; \ + if (len < maxcol) \ + goto out; \ + } while (0) + +static ssize_t omap2_iommu_dump_ctx(struct iommu *obj, char *buf, ssize_t len) { char *p = buf; @@ -242,7 +251,7 @@ static ssize_t omap2_iommu_dump_ctx(struct iommu *obj, char *buf) pr_reg(READ_CAM); pr_reg(READ_RAM); pr_reg(EMU_FAULT_AD); - +out: return p - buf; } diff --git a/arch/arm/mach-omap2/mailbox.c b/arch/arm/mach-omap2/mailbox.c index fd5b8a5925c..c035ad3426d 100644 --- a/arch/arm/mach-omap2/mailbox.c +++ b/arch/arm/mach-omap2/mailbox.c @@ -30,6 +30,14 @@ #define MAILBOX_IRQ_NEWMSG(u) (1 << (2 * (u))) #define MAILBOX_IRQ_NOTFULL(u) (1 << (2 * (u) + 1)) +/* SYSCONFIG: register bit definition */ +#define AUTOIDLE (1 << 0) +#define SOFTRESET (1 << 1) +#define SMARTIDLE (2 << 3) + +/* SYSSTATUS: register bit definition */ +#define RESETDONE (1 << 0) + #define MBOX_REG_SIZE 0x120 #define MBOX_NR_REGS (MBOX_REG_SIZE / sizeof(u32)) @@ -69,21 +77,33 @@ static inline void mbox_write_reg(u32 val, size_t ofs) /* Mailbox H/W preparations */ static int omap2_mbox_startup(struct omap_mbox *mbox) { - unsigned int l; + u32 l; + unsigned long timeout; mbox_ick_handle = clk_get(NULL, "mailboxes_ick"); if (IS_ERR(mbox_ick_handle)) { - printk("Could not get mailboxes_ick\n"); + pr_err("Can't get mailboxes_ick\n"); return -ENODEV; } clk_enable(mbox_ick_handle); + mbox_write_reg(SOFTRESET, MAILBOX_SYSCONFIG); + timeout = jiffies + msecs_to_jiffies(20); + do { + l = mbox_read_reg(MAILBOX_SYSSTATUS); + if (l & RESETDONE) + break; + } while (!time_after(jiffies, timeout)); + + if (!(l & RESETDONE)) { + pr_err("Can't take mmu out of reset\n"); + return -ENODEV; + } + l = mbox_read_reg(MAILBOX_REVISION); pr_info("omap mailbox rev %d.%d\n", (l & 0xf0) >> 4, (l & 0x0f)); - /* set smart-idle & autoidle */ - l = mbox_read_reg(MAILBOX_SYSCONFIG); - l |= 0x00000011; + l = SMARTIDLE | AUTOIDLE; mbox_write_reg(l, MAILBOX_SYSCONFIG); omap2_mbox_enable_irq(mbox, IRQ_RX); @@ -156,6 +176,9 @@ static void omap2_mbox_ack_irq(struct omap_mbox *mbox, u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit; mbox_write_reg(bit, p->irqstatus); + + /* Flush posted write for irq status to avoid spurious interrupts */ + mbox_read_reg(p->irqstatus); } static int omap2_mbox_is_irq(struct omap_mbox *mbox, @@ -282,12 +305,12 @@ static int __devinit omap2_mbox_probe(struct platform_device *pdev) return -ENOMEM; /* DSP or IVA2 IRQ */ - mbox_dsp_info.irq = platform_get_irq(pdev, 0); - if (mbox_dsp_info.irq < 0) { + ret = platform_get_irq(pdev, 0); + if (ret < 0) { dev_err(&pdev->dev, "invalid irq resource\n"); - ret = -ENODEV; goto err_dsp; } + mbox_dsp_info.irq = ret; ret = omap_mbox_register(&pdev->dev, &mbox_dsp_info); if (ret) diff --git a/arch/arm/mach-omap2/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c index 7d22caf6009..a846aa1ebb4 100644 --- a/arch/arm/mach-omap2/mcbsp.c +++ b/arch/arm/mach-omap2/mcbsp.c @@ -19,7 +19,6 @@ #include <mach/irqs.h> #include <mach/dma.h> -#include <mach/irqs.h> #include <mach/mux.h> #include <mach/cpu.h> #include <mach/mcbsp.h> @@ -174,6 +173,42 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = { #define OMAP34XX_MCBSP_PDATA_SZ 0 #endif +static struct omap_mcbsp_platform_data omap44xx_mcbsp_pdata[] = { + { + .phys_base = OMAP44XX_MCBSP1_BASE, + .dma_rx_sync = OMAP44XX_DMA_MCBSP1_RX, + .dma_tx_sync = OMAP44XX_DMA_MCBSP1_TX, + .rx_irq = INT_24XX_MCBSP1_IRQ_RX, + .tx_irq = INT_24XX_MCBSP1_IRQ_TX, + .ops = &omap2_mcbsp_ops, + }, + { + .phys_base = OMAP44XX_MCBSP2_BASE, + .dma_rx_sync = OMAP44XX_DMA_MCBSP2_RX, + .dma_tx_sync = OMAP44XX_DMA_MCBSP2_TX, + .rx_irq = INT_24XX_MCBSP2_IRQ_RX, + .tx_irq = INT_24XX_MCBSP2_IRQ_TX, + .ops = &omap2_mcbsp_ops, + }, + { + .phys_base = OMAP44XX_MCBSP3_BASE, + .dma_rx_sync = OMAP44XX_DMA_MCBSP3_RX, + .dma_tx_sync = OMAP44XX_DMA_MCBSP3_TX, + .rx_irq = INT_24XX_MCBSP3_IRQ_RX, + .tx_irq = INT_24XX_MCBSP3_IRQ_TX, + .ops = &omap2_mcbsp_ops, + }, + { + .phys_base = OMAP44XX_MCBSP4_BASE, + .dma_rx_sync = OMAP44XX_DMA_MCBSP4_RX, + .dma_tx_sync = OMAP44XX_DMA_MCBSP4_TX, + .rx_irq = INT_24XX_MCBSP4_IRQ_RX, + .tx_irq = INT_24XX_MCBSP4_IRQ_TX, + .ops = &omap2_mcbsp_ops, + }, +}; +#define OMAP44XX_MCBSP_PDATA_SZ ARRAY_SIZE(omap44xx_mcbsp_pdata) + static int __init omap2_mcbsp_init(void) { if (cpu_is_omap2420()) @@ -182,6 +217,8 @@ static int __init omap2_mcbsp_init(void) omap_mcbsp_count = OMAP2430_MCBSP_PDATA_SZ; if (cpu_is_omap34xx()) omap_mcbsp_count = OMAP34XX_MCBSP_PDATA_SZ; + if (cpu_is_omap44xx()) + omap_mcbsp_count = OMAP44XX_MCBSP_PDATA_SZ; mcbsp_ptr = kzalloc(omap_mcbsp_count * sizeof(struct omap_mcbsp *), GFP_KERNEL); @@ -197,6 +234,9 @@ static int __init omap2_mcbsp_init(void) if (cpu_is_omap34xx()) omap_mcbsp_register_board_cfg(omap34xx_mcbsp_pdata, OMAP34XX_MCBSP_PDATA_SZ); + if (cpu_is_omap44xx()) + omap_mcbsp_register_board_cfg(omap44xx_mcbsp_pdata, + OMAP44XX_MCBSP_PDATA_SZ); return omap_mcbsp_init(); } diff --git a/arch/arm/mach-omap2/mmc-twl4030.c b/arch/arm/mach-omap2/mmc-twl4030.c index 9756a878fd9..c9c59a2db4e 100644 --- a/arch/arm/mach-omap2/mmc-twl4030.c +++ b/arch/arm/mach-omap2/mmc-twl4030.c @@ -119,6 +119,7 @@ static int twl_mmc_late_init(struct device *dev) if (i != 0) break; ret = PTR_ERR(reg); + hsmmc[i].vcc = NULL; goto err; } hsmmc[i].vcc = reg; @@ -165,8 +166,13 @@ done: static void twl_mmc_cleanup(struct device *dev) { struct omap_mmc_platform_data *mmc = dev->platform_data; + int i; gpio_free(mmc->slots[0].switch_pin); + for(i = 0; i < ARRAY_SIZE(hsmmc); i++) { + regulator_put(hsmmc[i].vcc); + regulator_put(hsmmc[i].vcc_aux); + } } #ifdef CONFIG_PM @@ -192,6 +198,18 @@ static int twl_mmc_resume(struct device *dev, int slot) #define twl_mmc_resume NULL #endif +#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM) + +static int twl4030_mmc_get_context_loss(struct device *dev) +{ + /* FIXME: PM DPS not implemented yet */ + return 0; +} + +#else +#define twl4030_mmc_get_context_loss NULL +#endif + static int twl_mmc1_set_power(struct device *dev, int slot, int power_on, int vdd) { @@ -263,8 +281,19 @@ static int twl_mmc1_set_power(struct device *dev, int slot, int power_on, static int twl_mmc23_set_power(struct device *dev, int slot, int power_on, int vdd) { int ret = 0; - struct twl_mmc_controller *c = &hsmmc[1]; + struct twl_mmc_controller *c = NULL; struct omap_mmc_platform_data *mmc = dev->platform_data; + int i; + + for (i = 1; i < ARRAY_SIZE(hsmmc); i++) { + if (mmc == hsmmc[i].mmc) { + c = &hsmmc[i]; + break; + } + } + + if (c == NULL) + return -ENODEV; /* If we don't see a Vcc regulator, assume it's a fixed * voltage always-on regulator. @@ -311,6 +340,61 @@ static int twl_mmc23_set_power(struct device *dev, int slot, int power_on, int v return ret; } +static int twl_mmc1_set_sleep(struct device *dev, int slot, int sleep, int vdd, + int cardsleep) +{ + struct twl_mmc_controller *c = &hsmmc[0]; + int mode = sleep ? REGULATOR_MODE_STANDBY : REGULATOR_MODE_NORMAL; + + return regulator_set_mode(c->vcc, mode); +} + +static int twl_mmc23_set_sleep(struct device *dev, int slot, int sleep, int vdd, + int cardsleep) +{ + struct twl_mmc_controller *c = NULL; + struct omap_mmc_platform_data *mmc = dev->platform_data; + int i, err, mode; + + for (i = 1; i < ARRAY_SIZE(hsmmc); i++) { + if (mmc == hsmmc[i].mmc) { + c = &hsmmc[i]; + break; + } + } + + if (c == NULL) + return -ENODEV; + + /* + * If we don't see a Vcc regulator, assume it's a fixed + * voltage always-on regulator. + */ + if (!c->vcc) + return 0; + + mode = sleep ? REGULATOR_MODE_STANDBY : REGULATOR_MODE_NORMAL; + + if (!c->vcc_aux) + return regulator_set_mode(c->vcc, mode); + + if (cardsleep) { + /* VCC can be turned off if card is asleep */ + struct regulator *vcc_aux = c->vcc_aux; + + c->vcc_aux = NULL; + if (sleep) + err = twl_mmc23_set_power(dev, slot, 0, 0); + else + err = twl_mmc23_set_power(dev, slot, 1, vdd); + c->vcc_aux = vcc_aux; + } else + err = regulator_set_mode(c->vcc, mode); + if (err) + return err; + return regulator_set_mode(c->vcc_aux, mode); +} + static struct omap_mmc_platform_data *hsmmc_data[OMAP34XX_NR_MMC] __initdata; void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers) @@ -373,6 +457,9 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers) } else mmc->slots[0].switch_pin = -EINVAL; + mmc->get_context_loss_count = + twl4030_mmc_get_context_loss; + /* write protect normally uses an OMAP gpio */ if (gpio_is_valid(c->gpio_wp)) { gpio_request(c->gpio_wp, "mmc_wp"); @@ -383,6 +470,12 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers) } else mmc->slots[0].gpio_wp = -EINVAL; + if (c->nonremovable) + mmc->slots[0].nonremovable = 1; + + if (c->power_saving) + mmc->slots[0].power_saving = 1; + /* NOTE: MMC slots should have a Vcc regulator set up. * This may be from a TWL4030-family chip, another * controllable regulator, or a fixed supply. @@ -395,6 +488,7 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers) case 1: /* on-chip level shifting via PBIAS0/PBIAS1 */ mmc->slots[0].set_power = twl_mmc1_set_power; + mmc->slots[0].set_sleep = twl_mmc1_set_sleep; break; case 2: if (c->ext_clock) @@ -405,6 +499,7 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers) case 3: /* off-chip level shifting, or none */ mmc->slots[0].set_power = twl_mmc23_set_power; + mmc->slots[0].set_sleep = twl_mmc23_set_sleep; break; default: pr_err("MMC%d configuration not supported!\n", c->mmc); diff --git a/arch/arm/mach-omap2/mmc-twl4030.h b/arch/arm/mach-omap2/mmc-twl4030.h index 3807c45c9a6..a47e68563fb 100644 --- a/arch/arm/mach-omap2/mmc-twl4030.h +++ b/arch/arm/mach-omap2/mmc-twl4030.h @@ -12,6 +12,8 @@ struct twl4030_hsmmc_info { bool transceiver; /* MMC-2 option */ bool ext_clock; /* use external pin for input clock */ bool cover_only; /* No card detect - just cover switch */ + bool nonremovable; /* Nonremovable e.g. eMMC */ + bool power_saving; /* Try to sleep or power off when possible */ int gpio_cd; /* or -EINVAL */ int gpio_wp; /* or -EINVAL */ char *name; /* or NULL for default */ diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c index 026c4fc883a..b5fac32aae7 100644 --- a/arch/arm/mach-omap2/mux.c +++ b/arch/arm/mach-omap2/mux.c @@ -460,6 +460,8 @@ MUX_CFG_34XX("AF26_34XX_GPIO0", 0x1e0, OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT) MUX_CFG_34XX("AF22_34XX_GPIO9", 0xa18, OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT) +MUX_CFG_34XX("AG9_34XX_GPIO23", 0x5ee, + OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT) MUX_CFG_34XX("AH8_34XX_GPIO29", 0x5fa, OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT) MUX_CFG_34XX("U8_34XX_GPIO54_OUT", 0x0b4, @@ -472,6 +474,8 @@ MUX_CFG_34XX("G25_34XX_GPIO86_OUT", 0x0fc, OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_OUTPUT) MUX_CFG_34XX("AG4_34XX_GPIO134_OUT", 0x160, OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_OUTPUT) +MUX_CFG_34XX("AF4_34XX_GPIO135_OUT", 0x162, + OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_OUTPUT) MUX_CFG_34XX("AE4_34XX_GPIO136_OUT", 0x164, OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_OUTPUT) MUX_CFG_34XX("AF6_34XX_GPIO140_UP", 0x16c, @@ -486,6 +490,67 @@ MUX_CFG_34XX("H19_34XX_GPIO164_OUT", 0x19c, OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_OUTPUT) MUX_CFG_34XX("J25_34XX_GPIO170", 0x1c6, OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT) + +/* OMAP3 SDRC CKE signals to SDR/DDR ram chips */ +MUX_CFG_34XX("H16_34XX_SDRC_CKE0", 0x262, + OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_OUTPUT) +MUX_CFG_34XX("H17_34XX_SDRC_CKE1", 0x264, + OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_OUTPUT) + +/* MMC1 */ +MUX_CFG_34XX("N28_3430_MMC1_CLK", 0x144, + OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP) +MUX_CFG_34XX("M27_3430_MMC1_CMD", 0x146, + OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP) +MUX_CFG_34XX("N27_3430_MMC1_DAT0", 0x148, + OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP) +MUX_CFG_34XX("N26_3430_MMC1_DAT1", 0x14a, + OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP) +MUX_CFG_34XX("N25_3430_MMC1_DAT2", 0x14c, + OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP) +MUX_CFG_34XX("P28_3430_MMC1_DAT3", 0x14e, + OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP) +MUX_CFG_34XX("P27_3430_MMC1_DAT4", 0x150, + OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP) +MUX_CFG_34XX("P26_3430_MMC1_DAT5", 0x152, + OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP) +MUX_CFG_34XX("R27_3430_MMC1_DAT6", 0x154, + OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP) +MUX_CFG_34XX("R25_3430_MMC1_DAT7", 0x156, + OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP) + +/* MMC2 */ +MUX_CFG_34XX("AE2_3430_MMC2_CLK", 0x158, + OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP) +MUX_CFG_34XX("AG5_3430_MMC2_CMD", 0x15A, + OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP) +MUX_CFG_34XX("AH5_3430_MMC2_DAT0", 0x15c, + OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP) +MUX_CFG_34XX("AH4_3430_MMC2_DAT1", 0x15e, + OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP) +MUX_CFG_34XX("AG4_3430_MMC2_DAT2", 0x160, + OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP) +MUX_CFG_34XX("AF4_3430_MMC2_DAT3", 0x162, + OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP) + +/* MMC3 */ +MUX_CFG_34XX("AF10_3430_MMC3_CLK", 0x5d8, + OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLUP) +MUX_CFG_34XX("AC3_3430_MMC3_CMD", 0x1d0, + OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLUP) +MUX_CFG_34XX("AE11_3430_MMC3_DAT0", 0x5e4, + OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLUP) +MUX_CFG_34XX("AH9_3430_MMC3_DAT1", 0x5e6, + OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLUP) +MUX_CFG_34XX("AF13_3430_MMC3_DAT2", 0x5e8, + OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLUP) +MUX_CFG_34XX("AF13_3430_MMC3_DAT3", 0x5e2, + OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLUP) + +/* SYS_NIRQ T2 INT1 */ +MUX_CFG_34XX("AF26_34XX_SYS_NIRQ", 0x1E0, + OMAP3_WAKEUP_EN | OMAP34XX_PIN_INPUT_PULLUP | + OMAP34XX_MUX_MODE0) }; #define OMAP34XX_PINS_SZ ARRAY_SIZE(omap34xx_pins) diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c index 8fe8d230f21..48ee295db27 100644 --- a/arch/arm/mach-omap2/omap-smp.c +++ b/arch/arm/mach-omap2/omap-smp.c @@ -54,7 +54,7 @@ void __cpuinit platform_secondary_init(unsigned int cpu) * for us: do so */ - gic_cpu_init(0, IO_ADDRESS(OMAP44XX_GIC_CPU_BASE)); + gic_cpu_init(0, OMAP2_IO_ADDRESS(OMAP44XX_GIC_CPU_BASE)); /* * Synchronise with the boot thread. diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c new file mode 100644 index 00000000000..d2e0f1c9596 --- /dev/null +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -0,0 +1,1554 @@ +/* + * omap_hwmod implementation for OMAP2/3/4 + * + * Copyright (C) 2009 Nokia Corporation + * Paul Walmsley + * With fixes and testing from Kevin Hilman + * + * Created in collaboration with (alphabetical order): Benoit Cousson, + * Kevin Hilman, Tony Lindgren, Rajendra Nayak, Vikram Pandita, Sakari + * Poussa, Anand Sawant, Santosh Shilimkar, 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. + * + * This code manages "OMAP modules" (on-chip devices) and their + * integration with Linux device driver and bus code. + * + * References: + * - OMAP2420 Multimedia Processor Silicon Revision 2.1.1, 2.2 (SWPU064) + * - OMAP2430 Multimedia Device POP Silicon Revision 2.1 (SWPU090) + * - OMAP34xx Multimedia Device Silicon Revision 3.1 (SWPU108) + * - OMAP4430 Multimedia Device Silicon Revision 1.0 (SWPU140) + * - Open Core Protocol Specification 2.2 + * + * To do: + * - pin mux handling + * - handle IO mapping + * - bus throughput & module latency measurement code + * + * XXX add tests at the beginning of each function to ensure the hwmod is + * in the appropriate state + * XXX error return values should be checked to ensure that they are + * appropriate + */ +#undef DEBUG + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/list.h> +#include <linux/mutex.h> +#include <linux/bootmem.h> + +#include <mach/cpu.h> +#include <mach/clockdomain.h> +#include <mach/powerdomain.h> +#include <mach/clock.h> +#include <mach/omap_hwmod.h> + +#include "cm.h" + +/* Maximum microseconds to wait for OMAP module to reset */ +#define MAX_MODULE_RESET_WAIT 10000 + +/* Name of the OMAP hwmod for the MPU */ +#define MPU_INITIATOR_NAME "mpu_hwmod" + +/* omap_hwmod_list contains all registered struct omap_hwmods */ +static LIST_HEAD(omap_hwmod_list); + +static DEFINE_MUTEX(omap_hwmod_mutex); + +/* mpu_oh: used to add/remove MPU initiator from sleepdep list */ +static struct omap_hwmod *mpu_oh; + +/* inited: 0 if omap_hwmod_init() has not yet been called; 1 otherwise */ +static u8 inited; + + +/* Private functions */ + +/** + * _update_sysc_cache - return the module OCP_SYSCONFIG register, keep copy + * @oh: struct omap_hwmod * + * + * Load the current value of the hwmod OCP_SYSCONFIG register into the + * struct omap_hwmod for later use. Returns -EINVAL if the hwmod has no + * OCP_SYSCONFIG register or 0 upon success. + */ +static int _update_sysc_cache(struct omap_hwmod *oh) +{ + if (!oh->sysconfig) { + WARN(!oh->sysconfig, "omap_hwmod: %s: cannot read " + "OCP_SYSCONFIG: not defined on hwmod\n", oh->name); + return -EINVAL; + } + + /* XXX ensure module interface clock is up */ + + oh->_sysc_cache = omap_hwmod_readl(oh, oh->sysconfig->sysc_offs); + + oh->_int_flags |= _HWMOD_SYSCONFIG_LOADED; + + return 0; +} + +/** + * _write_sysconfig - write a value to the module's OCP_SYSCONFIG register + * @v: OCP_SYSCONFIG value to write + * @oh: struct omap_hwmod * + * + * Write @v into the module OCP_SYSCONFIG register, if it has one. No + * return value. + */ +static void _write_sysconfig(u32 v, struct omap_hwmod *oh) +{ + if (!oh->sysconfig) { + WARN(!oh->sysconfig, "omap_hwmod: %s: cannot write " + "OCP_SYSCONFIG: not defined on hwmod\n", oh->name); + return; + } + + /* XXX ensure module interface clock is up */ + + if (oh->_sysc_cache != v) { + oh->_sysc_cache = v; + omap_hwmod_writel(v, oh, oh->sysconfig->sysc_offs); + } +} + +/** + * _set_master_standbymode: set the OCP_SYSCONFIG MIDLEMODE field in @v + * @oh: struct omap_hwmod * + * @standbymode: MIDLEMODE field bits + * @v: pointer to register contents to modify + * + * Update the master standby mode bits in @v to be @standbymode for + * the @oh hwmod. Does not write to the hardware. Returns -EINVAL + * upon error or 0 upon success. + */ +static int _set_master_standbymode(struct omap_hwmod *oh, u8 standbymode, + u32 *v) +{ + if (!oh->sysconfig || + !(oh->sysconfig->sysc_flags & SYSC_HAS_MIDLEMODE)) + return -EINVAL; + + *v &= ~SYSC_MIDLEMODE_MASK; + *v |= __ffs(standbymode) << SYSC_MIDLEMODE_SHIFT; + + return 0; +} + +/** + * _set_slave_idlemode: set the OCP_SYSCONFIG SIDLEMODE field in @v + * @oh: struct omap_hwmod * + * @idlemode: SIDLEMODE field bits + * @v: pointer to register contents to modify + * + * Update the slave idle mode bits in @v to be @idlemode for the @oh + * hwmod. Does not write to the hardware. Returns -EINVAL upon error + * or 0 upon success. + */ +static int _set_slave_idlemode(struct omap_hwmod *oh, u8 idlemode, u32 *v) +{ + if (!oh->sysconfig || + !(oh->sysconfig->sysc_flags & SYSC_HAS_SIDLEMODE)) + return -EINVAL; + + *v &= ~SYSC_SIDLEMODE_MASK; + *v |= __ffs(idlemode) << SYSC_SIDLEMODE_SHIFT; + + return 0; +} + +/** + * _set_clockactivity: set OCP_SYSCONFIG.CLOCKACTIVITY bits in @v + * @oh: struct omap_hwmod * + * @clockact: CLOCKACTIVITY field bits + * @v: pointer to register contents to modify + * + * Update the clockactivity mode bits in @v to be @clockact for the + * @oh hwmod. Used for additional powersaving on some modules. Does + * not write to the hardware. Returns -EINVAL upon error or 0 upon + * success. + */ +static int _set_clockactivity(struct omap_hwmod *oh, u8 clockact, u32 *v) +{ + if (!oh->sysconfig || + !(oh->sysconfig->sysc_flags & SYSC_HAS_CLOCKACTIVITY)) + return -EINVAL; + + *v &= ~SYSC_CLOCKACTIVITY_MASK; + *v |= clockact << SYSC_CLOCKACTIVITY_SHIFT; + + return 0; +} + +/** + * _set_softreset: set OCP_SYSCONFIG.CLOCKACTIVITY bits in @v + * @oh: struct omap_hwmod * + * @v: pointer to register contents to modify + * + * Set the SOFTRESET bit in @v for hwmod @oh. Returns -EINVAL upon + * error or 0 upon success. + */ +static int _set_softreset(struct omap_hwmod *oh, u32 *v) +{ + if (!oh->sysconfig || + !(oh->sysconfig->sysc_flags & SYSC_HAS_SOFTRESET)) + return -EINVAL; + + *v |= SYSC_SOFTRESET_MASK; + + return 0; +} + +/** + * _enable_wakeup: set OCP_SYSCONFIG.ENAWAKEUP bit in the hardware + * @oh: struct omap_hwmod * + * + * Allow the hardware module @oh to send wakeups. Returns -EINVAL + * upon error or 0 upon success. + */ +static int _enable_wakeup(struct omap_hwmod *oh) +{ + u32 v; + + if (!oh->sysconfig || + !(oh->sysconfig->sysc_flags & SYSC_HAS_ENAWAKEUP)) + return -EINVAL; + + v = oh->_sysc_cache; + v |= SYSC_ENAWAKEUP_MASK; + _write_sysconfig(v, oh); + + /* XXX test pwrdm_get_wken for this hwmod's subsystem */ + + oh->_int_flags |= _HWMOD_WAKEUP_ENABLED; + + return 0; +} + +/** + * _disable_wakeup: clear OCP_SYSCONFIG.ENAWAKEUP bit in the hardware + * @oh: struct omap_hwmod * + * + * Prevent the hardware module @oh to send wakeups. Returns -EINVAL + * upon error or 0 upon success. + */ +static int _disable_wakeup(struct omap_hwmod *oh) +{ + u32 v; + + if (!oh->sysconfig || + !(oh->sysconfig->sysc_flags & SYSC_HAS_ENAWAKEUP)) + return -EINVAL; + + v = oh->_sysc_cache; + v &= ~SYSC_ENAWAKEUP_MASK; + _write_sysconfig(v, oh); + + /* XXX test pwrdm_get_wken for this hwmod's subsystem */ + + oh->_int_flags &= ~_HWMOD_WAKEUP_ENABLED; + + return 0; +} + +/** + * _add_initiator_dep: prevent @oh from smart-idling while @init_oh is active + * @oh: struct omap_hwmod * + * + * Prevent the hardware module @oh from entering idle while the + * hardare module initiator @init_oh is active. Useful when a module + * will be accessed by a particular initiator (e.g., if a module will + * be accessed by the IVA, there should be a sleepdep between the IVA + * initiator and the module). Only applies to modules in smart-idle + * mode. Returns -EINVAL upon error or passes along + * pwrdm_add_sleepdep() value upon success. + */ +static int _add_initiator_dep(struct omap_hwmod *oh, struct omap_hwmod *init_oh) +{ + if (!oh->_clk) + return -EINVAL; + + return pwrdm_add_sleepdep(oh->_clk->clkdm->pwrdm.ptr, + init_oh->_clk->clkdm->pwrdm.ptr); +} + +/** + * _del_initiator_dep: allow @oh to smart-idle even if @init_oh is active + * @oh: struct omap_hwmod * + * + * Allow the hardware module @oh to enter idle while the hardare + * module initiator @init_oh is active. Useful when a module will not + * be accessed by a particular initiator (e.g., if a module will not + * be accessed by the IVA, there should be no sleepdep between the IVA + * initiator and the module). Only applies to modules in smart-idle + * mode. Returns -EINVAL upon error or passes along + * pwrdm_add_sleepdep() value upon success. + */ +static int _del_initiator_dep(struct omap_hwmod *oh, struct omap_hwmod *init_oh) +{ + if (!oh->_clk) + return -EINVAL; + + return pwrdm_del_sleepdep(oh->_clk->clkdm->pwrdm.ptr, + init_oh->_clk->clkdm->pwrdm.ptr); +} + +/** + * _init_main_clk - get a struct clk * for the the hwmod's main functional clk + * @oh: struct omap_hwmod * + * + * Called from _init_clocks(). Populates the @oh _clk (main + * functional clock pointer) if a main_clk is present. Returns 0 on + * success or -EINVAL on error. + */ +static int _init_main_clk(struct omap_hwmod *oh) +{ + struct clk *c; + int ret = 0; + + if (!oh->clkdev_con_id) + return 0; + + c = clk_get_sys(oh->clkdev_dev_id, oh->clkdev_con_id); + WARN(IS_ERR(c), "omap_hwmod: %s: cannot clk_get main_clk %s.%s\n", + oh->name, oh->clkdev_dev_id, oh->clkdev_con_id); + if (IS_ERR(c)) + ret = -EINVAL; + oh->_clk = c; + + return ret; +} + +/** + * _init_interface_clk - get a struct clk * for the the hwmod's interface clks + * @oh: struct omap_hwmod * + * + * Called from _init_clocks(). Populates the @oh OCP slave interface + * clock pointers. Returns 0 on success or -EINVAL on error. + */ +static int _init_interface_clks(struct omap_hwmod *oh) +{ + struct omap_hwmod_ocp_if *os; + struct clk *c; + int i; + int ret = 0; + + if (oh->slaves_cnt == 0) + return 0; + + for (i = 0, os = *oh->slaves; i < oh->slaves_cnt; i++, os++) { + if (!os->clkdev_con_id) + continue; + + c = clk_get_sys(os->clkdev_dev_id, os->clkdev_con_id); + WARN(IS_ERR(c), "omap_hwmod: %s: cannot clk_get " + "interface_clk %s.%s\n", oh->name, + os->clkdev_dev_id, os->clkdev_con_id); + if (IS_ERR(c)) + ret = -EINVAL; + os->_clk = c; + } + + return ret; +} + +/** + * _init_opt_clk - get a struct clk * for the the hwmod's optional clocks + * @oh: struct omap_hwmod * + * + * Called from _init_clocks(). Populates the @oh omap_hwmod_opt_clk + * clock pointers. Returns 0 on success or -EINVAL on error. + */ +static int _init_opt_clks(struct omap_hwmod *oh) +{ + struct omap_hwmod_opt_clk *oc; + struct clk *c; + int i; + int ret = 0; + + for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++) { + c = clk_get_sys(oc->clkdev_dev_id, oc->clkdev_con_id); + WARN(IS_ERR(c), "omap_hwmod: %s: cannot clk_get opt_clk " + "%s.%s\n", oh->name, oc->clkdev_dev_id, + oc->clkdev_con_id); + if (IS_ERR(c)) + ret = -EINVAL; + oc->_clk = c; + } + + return ret; +} + +/** + * _enable_clocks - enable hwmod main clock and interface clocks + * @oh: struct omap_hwmod * + * + * Enables all clocks necessary for register reads and writes to succeed + * on the hwmod @oh. Returns 0. + */ +static int _enable_clocks(struct omap_hwmod *oh) +{ + struct omap_hwmod_ocp_if *os; + int i; + + pr_debug("omap_hwmod: %s: enabling clocks\n", oh->name); + + if (oh->_clk && !IS_ERR(oh->_clk)) + clk_enable(oh->_clk); + + if (oh->slaves_cnt > 0) { + for (i = 0, os = *oh->slaves; i < oh->slaves_cnt; i++, os++) { + struct clk *c = os->_clk; + + if (c && !IS_ERR(c) && (os->flags & OCPIF_SWSUP_IDLE)) + clk_enable(c); + } + } + + /* The opt clocks are controlled by the device driver. */ + + return 0; +} + +/** + * _disable_clocks - disable hwmod main clock and interface clocks + * @oh: struct omap_hwmod * + * + * Disables the hwmod @oh main functional and interface clocks. Returns 0. + */ +static int _disable_clocks(struct omap_hwmod *oh) +{ + struct omap_hwmod_ocp_if *os; + int i; + + pr_debug("omap_hwmod: %s: disabling clocks\n", oh->name); + + if (oh->_clk && !IS_ERR(oh->_clk)) + clk_disable(oh->_clk); + + if (oh->slaves_cnt > 0) { + for (i = 0, os = *oh->slaves; i < oh->slaves_cnt; i++, os++) { + struct clk *c = os->_clk; + + if (c && !IS_ERR(c) && (os->flags & OCPIF_SWSUP_IDLE)) + clk_disable(c); + } + } + + /* The opt clocks are controlled by the device driver. */ + + return 0; +} + +/** + * _find_mpu_port_index - find hwmod OCP slave port ID intended for MPU use + * @oh: struct omap_hwmod * + * + * Returns the array index of the OCP slave port that the MPU + * addresses the device on, or -EINVAL upon error or not found. + */ +static int _find_mpu_port_index(struct omap_hwmod *oh) +{ + struct omap_hwmod_ocp_if *os; + int i; + int found = 0; + + if (!oh || oh->slaves_cnt == 0) + return -EINVAL; + + for (i = 0, os = *oh->slaves; i < oh->slaves_cnt; i++, os++) { + if (os->user & OCP_USER_MPU) { + found = 1; + break; + } + } + + if (found) + pr_debug("omap_hwmod: %s: MPU OCP slave port ID %d\n", + oh->name, i); + else + pr_debug("omap_hwmod: %s: no MPU OCP slave port found\n", + oh->name); + + return (found) ? i : -EINVAL; +} + +/** + * _find_mpu_rt_base - find hwmod register target base addr accessible by MPU + * @oh: struct omap_hwmod * + * + * Return the virtual address of the base of the register target of + * device @oh, or NULL on error. + */ +static void __iomem *_find_mpu_rt_base(struct omap_hwmod *oh, u8 index) +{ + struct omap_hwmod_ocp_if *os; + struct omap_hwmod_addr_space *mem; + int i; + int found = 0; + + if (!oh || oh->slaves_cnt == 0) + return NULL; + + os = *oh->slaves + index; + + for (i = 0, mem = os->addr; i < os->addr_cnt; i++, mem++) { + if (mem->flags & ADDR_TYPE_RT) { + found = 1; + break; + } + } + + /* XXX use ioremap() instead? */ + + if (found) + pr_debug("omap_hwmod: %s: MPU register target at va %p\n", + oh->name, OMAP2_IO_ADDRESS(mem->pa_start)); + else + pr_debug("omap_hwmod: %s: no MPU register target found\n", + oh->name); + + return (found) ? OMAP2_IO_ADDRESS(mem->pa_start) : NULL; +} + +/** + * _sysc_enable - try to bring a module out of idle via OCP_SYSCONFIG + * @oh: struct omap_hwmod * + * + * If module is marked as SWSUP_SIDLE, force the module out of slave + * idle; otherwise, configure it for smart-idle. If module is marked + * as SWSUP_MSUSPEND, force the module out of master standby; + * otherwise, configure it for smart-standby. No return value. + */ +static void _sysc_enable(struct omap_hwmod *oh) +{ + u8 idlemode; + u32 v; + + if (!oh->sysconfig) + return; + + v = oh->_sysc_cache; + + if (oh->sysconfig->sysc_flags & SYSC_HAS_SIDLEMODE) { + idlemode = (oh->flags & HWMOD_SWSUP_SIDLE) ? + HWMOD_IDLEMODE_NO : HWMOD_IDLEMODE_SMART; + _set_slave_idlemode(oh, idlemode, &v); + } + + if (oh->sysconfig->sysc_flags & SYSC_HAS_MIDLEMODE) { + idlemode = (oh->flags & HWMOD_SWSUP_MSTANDBY) ? + HWMOD_IDLEMODE_NO : HWMOD_IDLEMODE_SMART; + _set_master_standbymode(oh, idlemode, &v); + } + + /* XXX OCP AUTOIDLE bit? */ + + if (oh->flags & HWMOD_SET_DEFAULT_CLOCKACT && + oh->sysconfig->sysc_flags & SYSC_HAS_CLOCKACTIVITY) + _set_clockactivity(oh, oh->sysconfig->clockact, &v); + + _write_sysconfig(v, oh); +} + +/** + * _sysc_idle - try to put a module into idle via OCP_SYSCONFIG + * @oh: struct omap_hwmod * + * + * If module is marked as SWSUP_SIDLE, force the module into slave + * idle; otherwise, configure it for smart-idle. If module is marked + * as SWSUP_MSUSPEND, force the module into master standby; otherwise, + * configure it for smart-standby. No return value. + */ +static void _sysc_idle(struct omap_hwmod *oh) +{ + u8 idlemode; + u32 v; + + if (!oh->sysconfig) + return; + + v = oh->_sysc_cache; + + if (oh->sysconfig->sysc_flags & SYSC_HAS_SIDLEMODE) { + idlemode = (oh->flags & HWMOD_SWSUP_SIDLE) ? + HWMOD_IDLEMODE_FORCE : HWMOD_IDLEMODE_SMART; + _set_slave_idlemode(oh, idlemode, &v); + } + + if (oh->sysconfig->sysc_flags & SYSC_HAS_MIDLEMODE) { + idlemode = (oh->flags & HWMOD_SWSUP_MSTANDBY) ? + HWMOD_IDLEMODE_FORCE : HWMOD_IDLEMODE_SMART; + _set_master_standbymode(oh, idlemode, &v); + } + + _write_sysconfig(v, oh); +} + +/** + * _sysc_shutdown - force a module into idle via OCP_SYSCONFIG + * @oh: struct omap_hwmod * + * + * Force the module into slave idle and master suspend. No return + * value. + */ +static void _sysc_shutdown(struct omap_hwmod *oh) +{ + u32 v; + + if (!oh->sysconfig) + return; + + v = oh->_sysc_cache; + + if (oh->sysconfig->sysc_flags & SYSC_HAS_SIDLEMODE) + _set_slave_idlemode(oh, HWMOD_IDLEMODE_FORCE, &v); + + if (oh->sysconfig->sysc_flags & SYSC_HAS_MIDLEMODE) + _set_master_standbymode(oh, HWMOD_IDLEMODE_FORCE, &v); + + /* XXX clear OCP AUTOIDLE bit? */ + + _write_sysconfig(v, oh); +} + +/** + * _lookup - find an omap_hwmod by name + * @name: find an omap_hwmod by name + * + * Return a pointer to an omap_hwmod by name, or NULL if not found. + * Caller must hold omap_hwmod_mutex. + */ +static struct omap_hwmod *_lookup(const char *name) +{ + struct omap_hwmod *oh, *temp_oh; + + oh = NULL; + + list_for_each_entry(temp_oh, &omap_hwmod_list, node) { + if (!strcmp(name, temp_oh->name)) { + oh = temp_oh; + break; + } + } + + return oh; +} + +/** + * _init_clocks - clk_get() all clocks associated with this hwmod + * @oh: struct omap_hwmod * + * + * Called by omap_hwmod_late_init() (after omap2_clk_init()). + * Resolves all clock names embedded in the hwmod. Must be called + * with omap_hwmod_mutex held. Returns -EINVAL if the omap_hwmod + * has not yet been registered or if the clocks have already been + * initialized, 0 on success, or a non-zero error on failure. + */ +static int _init_clocks(struct omap_hwmod *oh) +{ + int ret = 0; + + if (!oh || (oh->_state != _HWMOD_STATE_REGISTERED)) + return -EINVAL; + + pr_debug("omap_hwmod: %s: looking up clocks\n", oh->name); + + ret |= _init_main_clk(oh); + ret |= _init_interface_clks(oh); + ret |= _init_opt_clks(oh); + + oh->_state = _HWMOD_STATE_CLKS_INITED; + + return ret; +} + +/** + * _wait_target_ready - wait for a module to leave slave idle + * @oh: struct omap_hwmod * + * + * Wait for a module @oh to leave slave idle. Returns 0 if the module + * does not have an IDLEST bit or if the module successfully leaves + * slave idle; otherwise, pass along the return value of the + * appropriate *_cm_wait_module_ready() function. + */ +static int _wait_target_ready(struct omap_hwmod *oh) +{ + struct omap_hwmod_ocp_if *os; + int ret; + + if (!oh) + return -EINVAL; + + if (oh->_int_flags & _HWMOD_NO_MPU_PORT) + return 0; + + os = *oh->slaves + oh->_mpu_port_index; + + if (!(os->flags & OCPIF_HAS_IDLEST)) + return 0; + + /* XXX check module SIDLEMODE */ + + /* XXX check clock enable states */ + + if (cpu_is_omap24xx() || cpu_is_omap34xx()) { + ret = omap2_cm_wait_module_ready(oh->prcm.omap2.module_offs, + oh->prcm.omap2.idlest_reg_id, + oh->prcm.omap2.idlest_idle_bit); +#if 0 + } else if (cpu_is_omap44xx()) { + ret = omap4_cm_wait_module_ready(oh->prcm.omap4.module_offs, + oh->prcm.omap4.device_offs); +#endif + } else { + BUG(); + }; + + return ret; +} + +/** + * _reset - reset an omap_hwmod + * @oh: struct omap_hwmod * + * + * Resets an omap_hwmod @oh via the OCP_SYSCONFIG bit. hwmod must be + * enabled for this to work. Must be called with omap_hwmod_mutex + * held. Returns -EINVAL if the hwmod cannot be reset this way or if + * the hwmod is in the wrong state, -ETIMEDOUT if the module did not + * reset in time, or 0 upon success. + */ +static int _reset(struct omap_hwmod *oh) +{ + u32 r, v; + int c; + + if (!oh->sysconfig || + !(oh->sysconfig->sysc_flags & SYSC_HAS_SOFTRESET) || + (oh->sysconfig->sysc_flags & SYSS_MISSING)) + return -EINVAL; + + /* clocks must be on for this operation */ + if (oh->_state != _HWMOD_STATE_ENABLED) { + WARN(1, "omap_hwmod: %s: reset can only be entered from " + "enabled state\n", oh->name); + return -EINVAL; + } + + pr_debug("omap_hwmod: %s: resetting\n", oh->name); + + v = oh->_sysc_cache; + r = _set_softreset(oh, &v); + if (r) + return r; + _write_sysconfig(v, oh); + + c = 0; + while (c < MAX_MODULE_RESET_WAIT && + !(omap_hwmod_readl(oh, oh->sysconfig->syss_offs) & + SYSS_RESETDONE_MASK)) { + udelay(1); + c++; + } + + if (c == MAX_MODULE_RESET_WAIT) + WARN(1, "omap_hwmod: %s: failed to reset in %d usec\n", + oh->name, MAX_MODULE_RESET_WAIT); + else + pr_debug("omap_hwmod: %s: reset in %d usec\n", oh->name, c); + + /* + * XXX add _HWMOD_STATE_WEDGED for modules that don't come back from + * _wait_target_ready() or _reset() + */ + + return (c == MAX_MODULE_RESET_WAIT) ? -ETIMEDOUT : 0; +} + +/** + * _enable - enable an omap_hwmod + * @oh: struct omap_hwmod * + * + * Enables an omap_hwmod @oh such that the MPU can access the hwmod's + * register target. Must be called with omap_hwmod_mutex held. + * Returns -EINVAL if the hwmod is in the wrong state or passes along + * the return value of _wait_target_ready(). + */ +static int _enable(struct omap_hwmod *oh) +{ + int r; + + if (oh->_state != _HWMOD_STATE_INITIALIZED && + oh->_state != _HWMOD_STATE_IDLE && + oh->_state != _HWMOD_STATE_DISABLED) { + WARN(1, "omap_hwmod: %s: enabled state can only be entered " + "from initialized, idle, or disabled state\n", oh->name); + return -EINVAL; + } + + pr_debug("omap_hwmod: %s: enabling\n", oh->name); + + /* XXX mux balls */ + + _add_initiator_dep(oh, mpu_oh); + _enable_clocks(oh); + + if (oh->sysconfig) { + if (!(oh->_int_flags & _HWMOD_SYSCONFIG_LOADED)) + _update_sysc_cache(oh); + _sysc_enable(oh); + } + + r = _wait_target_ready(oh); + if (!r) + oh->_state = _HWMOD_STATE_ENABLED; + + return r; +} + +/** + * _idle - idle an omap_hwmod + * @oh: struct omap_hwmod * + * + * Idles an omap_hwmod @oh. This should be called once the hwmod has + * no further work. Returns -EINVAL if the hwmod is in the wrong + * state or returns 0. + */ +static int _idle(struct omap_hwmod *oh) +{ + if (oh->_state != _HWMOD_STATE_ENABLED) { + WARN(1, "omap_hwmod: %s: idle state can only be entered from " + "enabled state\n", oh->name); + return -EINVAL; + } + + pr_debug("omap_hwmod: %s: idling\n", oh->name); + + if (oh->sysconfig) + _sysc_idle(oh); + _del_initiator_dep(oh, mpu_oh); + _disable_clocks(oh); + + oh->_state = _HWMOD_STATE_IDLE; + + return 0; +} + +/** + * _shutdown - shutdown an omap_hwmod + * @oh: struct omap_hwmod * + * + * Shut down an omap_hwmod @oh. This should be called when the driver + * used for the hwmod is removed or unloaded or if the driver is not + * used by the system. Returns -EINVAL if the hwmod is in the wrong + * state or returns 0. + */ +static int _shutdown(struct omap_hwmod *oh) +{ + if (oh->_state != _HWMOD_STATE_IDLE && + oh->_state != _HWMOD_STATE_ENABLED) { + WARN(1, "omap_hwmod: %s: disabled state can only be entered " + "from idle, or enabled state\n", oh->name); + return -EINVAL; + } + + pr_debug("omap_hwmod: %s: disabling\n", oh->name); + + if (oh->sysconfig) + _sysc_shutdown(oh); + _del_initiator_dep(oh, mpu_oh); + /* XXX what about the other system initiators here? DMA, tesla, d2d */ + _disable_clocks(oh); + /* XXX Should this code also force-disable the optional clocks? */ + + /* XXX mux any associated balls to safe mode */ + + oh->_state = _HWMOD_STATE_DISABLED; + + return 0; +} + +/** + * _write_clockact_lock - set the module's clockactivity bits + * @oh: struct omap_hwmod * + * @clockact: CLOCKACTIVITY field bits + * + * Writes the CLOCKACTIVITY bits @clockact to the hwmod @oh + * OCP_SYSCONFIG register. Returns -EINVAL if the hwmod is in the + * wrong state or returns 0. + */ +static int _write_clockact_lock(struct omap_hwmod *oh, u8 clockact) +{ + u32 v; + + if (!oh->sysconfig || + !(oh->sysconfig->sysc_flags & SYSC_HAS_CLOCKACTIVITY)) + return -EINVAL; + + mutex_lock(&omap_hwmod_mutex); + v = oh->_sysc_cache; + _set_clockactivity(oh, clockact, &v); + _write_sysconfig(v, oh); + mutex_unlock(&omap_hwmod_mutex); + + return 0; +} + + +/** + * _setup - do initial configuration of omap_hwmod + * @oh: struct omap_hwmod * + * + * Writes the CLOCKACTIVITY bits @clockact to the hwmod @oh + * OCP_SYSCONFIG register. Must be called with omap_hwmod_mutex + * held. Returns -EINVAL if the hwmod is in the wrong state or returns + * 0. + */ +static int _setup(struct omap_hwmod *oh) +{ + struct omap_hwmod_ocp_if *os; + int i; + + if (!oh) + return -EINVAL; + + /* Set iclk autoidle mode */ + if (oh->slaves_cnt > 0) { + for (i = 0, os = *oh->slaves; i < oh->slaves_cnt; i++, os++) { + struct clk *c = os->_clk; + + if (!c || IS_ERR(c)) + continue; + + if (os->flags & OCPIF_SWSUP_IDLE) { + /* XXX omap_iclk_deny_idle(c); */ + } else { + /* XXX omap_iclk_allow_idle(c); */ + clk_enable(c); + } + } + } + + oh->_state = _HWMOD_STATE_INITIALIZED; + + _enable(oh); + + if (!(oh->flags & HWMOD_INIT_NO_RESET)) + _reset(oh); + + /* XXX OCP AUTOIDLE bit? */ + /* XXX OCP ENAWAKEUP bit? */ + + if (!(oh->flags & HWMOD_INIT_NO_IDLE)) + _idle(oh); + + return 0; +} + + + +/* Public functions */ + +u32 omap_hwmod_readl(struct omap_hwmod *oh, u16 reg_offs) +{ + return __raw_readl(oh->_rt_va + reg_offs); +} + +void omap_hwmod_writel(u32 v, struct omap_hwmod *oh, u16 reg_offs) +{ + __raw_writel(v, oh->_rt_va + reg_offs); +} + +/** + * omap_hwmod_register - register a struct omap_hwmod + * @oh: struct omap_hwmod * + * + * Registers the omap_hwmod @oh. Returns -EEXIST if an omap_hwmod already + * has been registered by the same name; -EINVAL if the omap_hwmod is in the + * wrong state, or 0 on success. + * + * XXX The data should be copied into bootmem, so the original data + * should be marked __initdata and freed after init. This would allow + * unneeded omap_hwmods to be freed on multi-OMAP configurations. Note + * that the copy process would be relatively complex due to the large number + * of substructures. + */ +int omap_hwmod_register(struct omap_hwmod *oh) +{ + int ret, ms_id; + + if (!oh || (oh->_state != _HWMOD_STATE_UNKNOWN)) + return -EINVAL; + + mutex_lock(&omap_hwmod_mutex); + + pr_debug("omap_hwmod: %s: registering\n", oh->name); + + if (_lookup(oh->name)) { + ret = -EEXIST; + goto ohr_unlock; + } + + ms_id = _find_mpu_port_index(oh); + if (!IS_ERR_VALUE(ms_id)) { + oh->_mpu_port_index = ms_id; + oh->_rt_va = _find_mpu_rt_base(oh, oh->_mpu_port_index); + } else { + oh->_int_flags |= _HWMOD_NO_MPU_PORT; + } + + list_add_tail(&oh->node, &omap_hwmod_list); + + oh->_state = _HWMOD_STATE_REGISTERED; + + ret = 0; + +ohr_unlock: + mutex_unlock(&omap_hwmod_mutex); + return ret; +} + +/** + * omap_hwmod_lookup - look up a registered omap_hwmod by name + * @name: name of the omap_hwmod to look up + * + * Given a @name of an omap_hwmod, return a pointer to the registered + * struct omap_hwmod *, or NULL upon error. + */ +struct omap_hwmod *omap_hwmod_lookup(const char *name) +{ + struct omap_hwmod *oh; + + if (!name) + return NULL; + + mutex_lock(&omap_hwmod_mutex); + oh = _lookup(name); + mutex_unlock(&omap_hwmod_mutex); + + return oh; +} + +/** + * omap_hwmod_for_each - call function for each registered omap_hwmod + * @fn: pointer to a callback function + * + * Call @fn for each registered omap_hwmod, passing @data to each + * function. @fn must return 0 for success or any other value for + * failure. If @fn returns non-zero, the iteration across omap_hwmods + * will stop and the non-zero return value will be passed to the + * caller of omap_hwmod_for_each(). @fn is called with + * omap_hwmod_for_each() held. + */ +int omap_hwmod_for_each(int (*fn)(struct omap_hwmod *oh)) +{ + struct omap_hwmod *temp_oh; + int ret; + + if (!fn) + return -EINVAL; + + mutex_lock(&omap_hwmod_mutex); + list_for_each_entry(temp_oh, &omap_hwmod_list, node) { + ret = (*fn)(temp_oh); + if (ret) + break; + } + mutex_unlock(&omap_hwmod_mutex); + + return ret; +} + + +/** + * omap_hwmod_init - init omap_hwmod code and register hwmods + * @ohs: pointer to an array of omap_hwmods to register + * + * Intended to be called early in boot before the clock framework is + * initialized. If @ohs is not null, will register all omap_hwmods + * listed in @ohs that are valid for this chip. Returns -EINVAL if + * omap_hwmod_init() has already been called or 0 otherwise. + */ +int omap_hwmod_init(struct omap_hwmod **ohs) +{ + struct omap_hwmod *oh; + int r; + + if (inited) + return -EINVAL; + + inited = 1; + + if (!ohs) + return 0; + + oh = *ohs; + while (oh) { + if (omap_chip_is(oh->omap_chip)) { + r = omap_hwmod_register(oh); + WARN(r, "omap_hwmod: %s: omap_hwmod_register returned " + "%d\n", oh->name, r); + } + oh = *++ohs; + } + + return 0; +} + +/** + * omap_hwmod_late_init - do some post-clock framework initialization + * + * Must be called after omap2_clk_init(). Resolves the struct clk names + * to struct clk pointers for each registered omap_hwmod. Also calls + * _setup() on each hwmod. Returns 0. + */ +int omap_hwmod_late_init(void) +{ + int r; + + /* XXX check return value */ + r = omap_hwmod_for_each(_init_clocks); + WARN(r, "omap_hwmod: omap_hwmod_late_init(): _init_clocks failed\n"); + + mpu_oh = omap_hwmod_lookup(MPU_INITIATOR_NAME); + WARN(!mpu_oh, "omap_hwmod: could not find MPU initiator hwmod %s\n", + MPU_INITIATOR_NAME); + + omap_hwmod_for_each(_setup); + + return 0; +} + +/** + * omap_hwmod_unregister - unregister an omap_hwmod + * @oh: struct omap_hwmod * + * + * Unregisters a previously-registered omap_hwmod @oh. There's probably + * no use case for this, so it is likely to be removed in a later version. + * + * XXX Free all of the bootmem-allocated structures here when that is + * implemented. Make it clear that core code is the only code that is + * expected to unregister modules. + */ +int omap_hwmod_unregister(struct omap_hwmod *oh) +{ + if (!oh) + return -EINVAL; + + pr_debug("omap_hwmod: %s: unregistering\n", oh->name); + + mutex_lock(&omap_hwmod_mutex); + list_del(&oh->node); + mutex_unlock(&omap_hwmod_mutex); + + return 0; +} + +/** + * omap_hwmod_enable - enable an omap_hwmod + * @oh: struct omap_hwmod * + * + * Enable an omap_hwomd @oh. Intended to be called by omap_device_enable(). + * Returns -EINVAL on error or passes along the return value from _enable(). + */ +int omap_hwmod_enable(struct omap_hwmod *oh) +{ + int r; + + if (!oh) + return -EINVAL; + + mutex_lock(&omap_hwmod_mutex); + r = _enable(oh); + mutex_unlock(&omap_hwmod_mutex); + + return r; +} + +/** + * omap_hwmod_idle - idle an omap_hwmod + * @oh: struct omap_hwmod * + * + * Idle an omap_hwomd @oh. Intended to be called by omap_device_idle(). + * Returns -EINVAL on error or passes along the return value from _idle(). + */ +int omap_hwmod_idle(struct omap_hwmod *oh) +{ + if (!oh) + return -EINVAL; + + mutex_lock(&omap_hwmod_mutex); + _idle(oh); + mutex_unlock(&omap_hwmod_mutex); + + return 0; +} + +/** + * omap_hwmod_shutdown - shutdown an omap_hwmod + * @oh: struct omap_hwmod * + * + * Shutdown an omap_hwomd @oh. Intended to be called by + * omap_device_shutdown(). Returns -EINVAL on error or passes along + * the return value from _shutdown(). + */ +int omap_hwmod_shutdown(struct omap_hwmod *oh) +{ + if (!oh) + return -EINVAL; + + mutex_lock(&omap_hwmod_mutex); + _shutdown(oh); + mutex_unlock(&omap_hwmod_mutex); + + return 0; +} + +/** + * omap_hwmod_enable_clocks - enable main_clk, all interface clocks + * @oh: struct omap_hwmod *oh + * + * Intended to be called by the omap_device code. + */ +int omap_hwmod_enable_clocks(struct omap_hwmod *oh) +{ + mutex_lock(&omap_hwmod_mutex); + _enable_clocks(oh); + mutex_unlock(&omap_hwmod_mutex); + + return 0; +} + +/** + * omap_hwmod_disable_clocks - disable main_clk, all interface clocks + * @oh: struct omap_hwmod *oh + * + * Intended to be called by the omap_device code. + */ +int omap_hwmod_disable_clocks(struct omap_hwmod *oh) +{ + mutex_lock(&omap_hwmod_mutex); + _disable_clocks(oh); + mutex_unlock(&omap_hwmod_mutex); + + return 0; +} + +/** + * omap_hwmod_ocp_barrier - wait for posted writes against the hwmod to complete + * @oh: struct omap_hwmod *oh + * + * Intended to be called by drivers and core code when all posted + * writes to a device must complete before continuing further + * execution (for example, after clearing some device IRQSTATUS + * register bits) + * + * XXX what about targets with multiple OCP threads? + */ +void omap_hwmod_ocp_barrier(struct omap_hwmod *oh) +{ + BUG_ON(!oh); + + if (!oh->sysconfig || !oh->sysconfig->sysc_flags) { + WARN(1, "omap_device: %s: OCP barrier impossible due to " + "device configuration\n", oh->name); + return; + } + + /* + * Forces posted writes to complete on the OCP thread handling + * register writes + */ + omap_hwmod_readl(oh, oh->sysconfig->sysc_offs); +} + +/** + * omap_hwmod_reset - reset the hwmod + * @oh: struct omap_hwmod * + * + * Under some conditions, a driver may wish to reset the entire device. + * Called from omap_device code. Returns -EINVAL on error or passes along + * the return value from _reset()/_enable(). + */ +int omap_hwmod_reset(struct omap_hwmod *oh) +{ + int r; + + if (!oh || !(oh->_state & _HWMOD_STATE_ENABLED)) + return -EINVAL; + + mutex_lock(&omap_hwmod_mutex); + r = _reset(oh); + if (!r) + r = _enable(oh); + mutex_unlock(&omap_hwmod_mutex); + + return r; +} + +/** + * omap_hwmod_count_resources - count number of struct resources needed by hwmod + * @oh: struct omap_hwmod * + * @res: pointer to the first element of an array of struct resource to fill + * + * Count the number of struct resource array elements necessary to + * contain omap_hwmod @oh resources. Intended to be called by code + * that registers omap_devices. Intended to be used to determine the + * size of a dynamically-allocated struct resource array, before + * calling omap_hwmod_fill_resources(). Returns the number of struct + * resource array elements needed. + * + * XXX This code is not optimized. It could attempt to merge adjacent + * resource IDs. + * + */ +int omap_hwmod_count_resources(struct omap_hwmod *oh) +{ + int ret, i; + + ret = oh->mpu_irqs_cnt + oh->sdma_chs_cnt; + + for (i = 0; i < oh->slaves_cnt; i++) + ret += (*oh->slaves + i)->addr_cnt; + + return ret; +} + +/** + * omap_hwmod_fill_resources - fill struct resource array with hwmod data + * @oh: struct omap_hwmod * + * @res: pointer to the first element of an array of struct resource to fill + * + * Fill the struct resource array @res with resource data from the + * omap_hwmod @oh. Intended to be called by code that registers + * omap_devices. See also omap_hwmod_count_resources(). Returns the + * number of array elements filled. + */ +int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res) +{ + int i, j; + int r = 0; + + /* For each IRQ, DMA, memory area, fill in array.*/ + + for (i = 0; i < oh->mpu_irqs_cnt; i++) { + (res + r)->start = *(oh->mpu_irqs + i); + (res + r)->end = *(oh->mpu_irqs + i); + (res + r)->flags = IORESOURCE_IRQ; + r++; + } + + for (i = 0; i < oh->sdma_chs_cnt; i++) { + (res + r)->name = (oh->sdma_chs + i)->name; + (res + r)->start = (oh->sdma_chs + i)->dma_ch; + (res + r)->end = (oh->sdma_chs + i)->dma_ch; + (res + r)->flags = IORESOURCE_DMA; + r++; + } + + for (i = 0; i < oh->slaves_cnt; i++) { + struct omap_hwmod_ocp_if *os; + + os = *oh->slaves + i; + + for (j = 0; j < os->addr_cnt; j++) { + (res + r)->start = (os->addr + j)->pa_start; + (res + r)->end = (os->addr + j)->pa_end; + (res + r)->flags = IORESOURCE_MEM; + r++; + } + } + + return r; +} + +/** + * omap_hwmod_get_pwrdm - return pointer to this module's main powerdomain + * @oh: struct omap_hwmod * + * + * Return the powerdomain pointer associated with the OMAP module + * @oh's main clock. If @oh does not have a main clk, return the + * powerdomain associated with the interface clock associated with the + * module's MPU port. (XXX Perhaps this should use the SDMA port + * instead?) Returns NULL on error, or a struct powerdomain * on + * success. + */ +struct powerdomain *omap_hwmod_get_pwrdm(struct omap_hwmod *oh) +{ + struct clk *c; + + if (!oh) + return NULL; + + if (oh->_clk) { + c = oh->_clk; + } else { + if (oh->_int_flags & _HWMOD_NO_MPU_PORT) + return NULL; + c = oh->slaves[oh->_mpu_port_index]->_clk; + } + + return c->clkdm->pwrdm.ptr; + +} + +/** + * omap_hwmod_add_initiator_dep - add sleepdep from @init_oh to @oh + * @oh: struct omap_hwmod * + * @init_oh: struct omap_hwmod * (initiator) + * + * Add a sleep dependency between the initiator @init_oh and @oh. + * Intended to be called by DSP/Bridge code via platform_data for the + * DSP case; and by the DMA code in the sDMA case. DMA code, *Bridge + * code needs to add/del initiator dependencies dynamically + * before/after accessing a device. Returns the return value from + * _add_initiator_dep(). + * + * XXX Keep a usecount in the clockdomain code + */ +int omap_hwmod_add_initiator_dep(struct omap_hwmod *oh, + struct omap_hwmod *init_oh) +{ + return _add_initiator_dep(oh, init_oh); +} + +/* + * XXX what about functions for drivers to save/restore ocp_sysconfig + * for context save/restore operations? + */ + +/** + * omap_hwmod_del_initiator_dep - remove sleepdep from @init_oh to @oh + * @oh: struct omap_hwmod * + * @init_oh: struct omap_hwmod * (initiator) + * + * Remove a sleep dependency between the initiator @init_oh and @oh. + * Intended to be called by DSP/Bridge code via platform_data for the + * DSP case; and by the DMA code in the sDMA case. DMA code, *Bridge + * code needs to add/del initiator dependencies dynamically + * before/after accessing a device. Returns the return value from + * _del_initiator_dep(). + * + * XXX Keep a usecount in the clockdomain code + */ +int omap_hwmod_del_initiator_dep(struct omap_hwmod *oh, + struct omap_hwmod *init_oh) +{ + return _del_initiator_dep(oh, init_oh); +} + +/** + * omap_hwmod_set_clockact_none - set clockactivity test to BOTH + * @oh: struct omap_hwmod * + * + * On some modules, this function can affect the wakeup latency vs. + * power consumption balance. Intended to be called by the + * omap_device layer. Passes along the return value from + * _write_clockact_lock(). + */ +int omap_hwmod_set_clockact_both(struct omap_hwmod *oh) +{ + return _write_clockact_lock(oh, CLOCKACT_TEST_BOTH); +} + +/** + * omap_hwmod_set_clockact_none - set clockactivity test to MAIN + * @oh: struct omap_hwmod * + * + * On some modules, this function can affect the wakeup latency vs. + * power consumption balance. Intended to be called by the + * omap_device layer. Passes along the return value from + * _write_clockact_lock(). + */ +int omap_hwmod_set_clockact_main(struct omap_hwmod *oh) +{ + return _write_clockact_lock(oh, CLOCKACT_TEST_MAIN); +} + +/** + * omap_hwmod_set_clockact_none - set clockactivity test to ICLK + * @oh: struct omap_hwmod * + * + * On some modules, this function can affect the wakeup latency vs. + * power consumption balance. Intended to be called by the + * omap_device layer. Passes along the return value from + * _write_clockact_lock(). + */ +int omap_hwmod_set_clockact_iclk(struct omap_hwmod *oh) +{ + return _write_clockact_lock(oh, CLOCKACT_TEST_ICLK); +} + +/** + * omap_hwmod_set_clockact_none - set clockactivity test to NONE + * @oh: struct omap_hwmod * + * + * On some modules, this function can affect the wakeup latency vs. + * power consumption balance. Intended to be called by the + * omap_device layer. Passes along the return value from + * _write_clockact_lock(). + */ +int omap_hwmod_set_clockact_none(struct omap_hwmod *oh) +{ + return _write_clockact_lock(oh, CLOCKACT_TEST_NONE); +} + +/** + * omap_hwmod_enable_wakeup - allow device to wake up the system + * @oh: struct omap_hwmod * + * + * Sets the module OCP socket ENAWAKEUP bit to allow the module to + * send wakeups to the PRCM. Eventually this should sets PRCM wakeup + * registers to cause the PRCM to receive wakeup events from the + * module. Does not set any wakeup routing registers beyond this + * point - if the module is to wake up any other module or subsystem, + * that must be set separately. Called by omap_device code. Returns + * -EINVAL on error or 0 upon success. + */ +int omap_hwmod_enable_wakeup(struct omap_hwmod *oh) +{ + if (!oh->sysconfig || + !(oh->sysconfig->sysc_flags & SYSC_HAS_ENAWAKEUP)) + return -EINVAL; + + mutex_lock(&omap_hwmod_mutex); + _enable_wakeup(oh); + mutex_unlock(&omap_hwmod_mutex); + + return 0; +} + +/** + * omap_hwmod_disable_wakeup - prevent device from waking the system + * @oh: struct omap_hwmod * + * + * Clears the module OCP socket ENAWAKEUP bit to prevent the module + * from sending wakeups to the PRCM. Eventually this should clear + * PRCM wakeup registers to cause the PRCM to ignore wakeup events + * from the module. Does not set any wakeup routing registers beyond + * this point - if the module is to wake up any other module or + * subsystem, that must be set separately. Called by omap_device + * code. Returns -EINVAL on error or 0 upon success. + */ +int omap_hwmod_disable_wakeup(struct omap_hwmod *oh) +{ + if (!oh->sysconfig || + !(oh->sysconfig->sysc_flags & SYSC_HAS_ENAWAKEUP)) + return -EINVAL; + + mutex_lock(&omap_hwmod_mutex); + _disable_wakeup(oh); + mutex_unlock(&omap_hwmod_mutex); + + return 0; +} diff --git a/arch/arm/mach-omap2/omap_hwmod_2420.h b/arch/arm/mach-omap2/omap_hwmod_2420.h new file mode 100644 index 00000000000..767e4965ac4 --- /dev/null +++ b/arch/arm/mach-omap2/omap_hwmod_2420.h @@ -0,0 +1,141 @@ +/* + * omap_hwmod_2420.h - hardware modules present on the OMAP2420 chips + * + * Copyright (C) 2009 Nokia Corporation + * Paul Walmsley + * + * 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. + * + * XXX handle crossbar/shared link difference for L3? + * + */ +#ifndef __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_OMAP_HWMOD2420_H +#define __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_OMAP_HWMOD2420_H + +#ifdef CONFIG_ARCH_OMAP2420 + +#include <mach/omap_hwmod.h> +#include <mach/irqs.h> +#include <mach/cpu.h> +#include <mach/dma.h> + +#include "prm-regbits-24xx.h" + +static struct omap_hwmod omap2420_mpu_hwmod; +static struct omap_hwmod omap2420_l3_hwmod; +static struct omap_hwmod omap2420_l4_core_hwmod; + +/* L3 -> L4_CORE interface */ +static struct omap_hwmod_ocp_if omap2420_l3__l4_core = { + .master = &omap2420_l3_hwmod, + .slave = &omap2420_l4_core_hwmod, + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +/* MPU -> L3 interface */ +static struct omap_hwmod_ocp_if omap2420_mpu__l3 = { + .master = &omap2420_mpu_hwmod, + .slave = &omap2420_l3_hwmod, + .user = OCP_USER_MPU, +}; + +/* Slave interfaces on the L3 interconnect */ +static struct omap_hwmod_ocp_if *omap2420_l3_slaves[] = { + &omap2420_mpu__l3, +}; + +/* Master interfaces on the L3 interconnect */ +static struct omap_hwmod_ocp_if *omap2420_l3_masters[] = { + &omap2420_l3__l4_core, +}; + +/* L3 */ +static struct omap_hwmod omap2420_l3_hwmod = { + .name = "l3_hwmod", + .masters = omap2420_l3_masters, + .masters_cnt = ARRAY_SIZE(omap2420_l3_masters), + .slaves = omap2420_l3_slaves, + .slaves_cnt = ARRAY_SIZE(omap2420_l3_slaves), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420) +}; + +static struct omap_hwmod omap2420_l4_wkup_hwmod; + +/* L4_CORE -> L4_WKUP interface */ +static struct omap_hwmod_ocp_if omap2420_l4_core__l4_wkup = { + .master = &omap2420_l4_core_hwmod, + .slave = &omap2420_l4_wkup_hwmod, + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +/* Slave interfaces on the L4_CORE interconnect */ +static struct omap_hwmod_ocp_if *omap2420_l4_core_slaves[] = { + &omap2420_l3__l4_core, +}; + +/* Master interfaces on the L4_CORE interconnect */ +static struct omap_hwmod_ocp_if *omap2420_l4_core_masters[] = { + &omap2420_l4_core__l4_wkup, +}; + +/* L4 CORE */ +static struct omap_hwmod omap2420_l4_core_hwmod = { + .name = "l4_core_hwmod", + .masters = omap2420_l4_core_masters, + .masters_cnt = ARRAY_SIZE(omap2420_l4_core_masters), + .slaves = omap2420_l4_core_slaves, + .slaves_cnt = ARRAY_SIZE(omap2420_l4_core_slaves), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420) +}; + +/* Slave interfaces on the L4_WKUP interconnect */ +static struct omap_hwmod_ocp_if *omap2420_l4_wkup_slaves[] = { + &omap2420_l4_core__l4_wkup, +}; + +/* Master interfaces on the L4_WKUP interconnect */ +static struct omap_hwmod_ocp_if *omap2420_l4_wkup_masters[] = { +}; + +/* L4 WKUP */ +static struct omap_hwmod omap2420_l4_wkup_hwmod = { + .name = "l4_wkup_hwmod", + .masters = omap2420_l4_wkup_masters, + .masters_cnt = ARRAY_SIZE(omap2420_l4_wkup_masters), + .slaves = omap2420_l4_wkup_slaves, + .slaves_cnt = ARRAY_SIZE(omap2420_l4_wkup_slaves), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420) +}; + +/* Master interfaces on the MPU device */ +static struct omap_hwmod_ocp_if *omap2420_mpu_masters[] = { + &omap2420_mpu__l3, +}; + +/* MPU */ +static struct omap_hwmod omap2420_mpu_hwmod = { + .name = "mpu_hwmod", + .clkdev_dev_id = NULL, + .clkdev_con_id = "mpu_ck", + .masters = omap2420_mpu_masters, + .masters_cnt = ARRAY_SIZE(omap2420_mpu_masters), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420), +}; + +static __initdata struct omap_hwmod *omap2420_hwmods[] = { + &omap2420_l3_hwmod, + &omap2420_l4_core_hwmod, + &omap2420_l4_wkup_hwmod, + &omap2420_mpu_hwmod, + NULL, +}; + +#else +# define omap2420_hwmods 0 +#endif + +#endif + + diff --git a/arch/arm/mach-omap2/omap_hwmod_2430.h b/arch/arm/mach-omap2/omap_hwmod_2430.h new file mode 100644 index 00000000000..a412be6420e --- /dev/null +++ b/arch/arm/mach-omap2/omap_hwmod_2430.h @@ -0,0 +1,143 @@ +/* + * omap_hwmod_2430.h - hardware modules present on the OMAP2430 chips + * + * Copyright (C) 2009 Nokia Corporation + * Paul Walmsley + * + * 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. + * + * XXX handle crossbar/shared link difference for L3? + * + */ +#ifndef __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_OMAP_HWMOD2430_H +#define __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_OMAP_HWMOD2430_H + +#ifdef CONFIG_ARCH_OMAP2430 + +#include <mach/omap_hwmod.h> +#include <mach/irqs.h> +#include <mach/cpu.h> +#include <mach/dma.h> + +#include "prm-regbits-24xx.h" + +static struct omap_hwmod omap2430_mpu_hwmod; +static struct omap_hwmod omap2430_l3_hwmod; +static struct omap_hwmod omap2430_l4_core_hwmod; + +/* L3 -> L4_CORE interface */ +static struct omap_hwmod_ocp_if omap2430_l3__l4_core = { + .master = &omap2430_l3_hwmod, + .slave = &omap2430_l4_core_hwmod, + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +/* MPU -> L3 interface */ +static struct omap_hwmod_ocp_if omap2430_mpu__l3 = { + .master = &omap2430_mpu_hwmod, + .slave = &omap2430_l3_hwmod, + .user = OCP_USER_MPU, +}; + +/* Slave interfaces on the L3 interconnect */ +static struct omap_hwmod_ocp_if *omap2430_l3_slaves[] = { + &omap2430_mpu__l3, +}; + +/* Master interfaces on the L3 interconnect */ +static struct omap_hwmod_ocp_if *omap2430_l3_masters[] = { + &omap2430_l3__l4_core, +}; + +/* L3 */ +static struct omap_hwmod omap2430_l3_hwmod = { + .name = "l3_hwmod", + .masters = omap2430_l3_masters, + .masters_cnt = ARRAY_SIZE(omap2430_l3_masters), + .slaves = omap2430_l3_slaves, + .slaves_cnt = ARRAY_SIZE(omap2430_l3_slaves), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430) +}; + +static struct omap_hwmod omap2430_l4_wkup_hwmod; +static struct omap_hwmod omap2430_mmc1_hwmod; +static struct omap_hwmod omap2430_mmc2_hwmod; + +/* L4_CORE -> L4_WKUP interface */ +static struct omap_hwmod_ocp_if omap2430_l4_core__l4_wkup = { + .master = &omap2430_l4_core_hwmod, + .slave = &omap2430_l4_wkup_hwmod, + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +/* Slave interfaces on the L4_CORE interconnect */ +static struct omap_hwmod_ocp_if *omap2430_l4_core_slaves[] = { + &omap2430_l3__l4_core, +}; + +/* Master interfaces on the L4_CORE interconnect */ +static struct omap_hwmod_ocp_if *omap2430_l4_core_masters[] = { + &omap2430_l4_core__l4_wkup, +}; + +/* L4 CORE */ +static struct omap_hwmod omap2430_l4_core_hwmod = { + .name = "l4_core_hwmod", + .masters = omap2430_l4_core_masters, + .masters_cnt = ARRAY_SIZE(omap2430_l4_core_masters), + .slaves = omap2430_l4_core_slaves, + .slaves_cnt = ARRAY_SIZE(omap2430_l4_core_slaves), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430) +}; + +/* Slave interfaces on the L4_WKUP interconnect */ +static struct omap_hwmod_ocp_if *omap2430_l4_wkup_slaves[] = { + &omap2430_l4_core__l4_wkup, +}; + +/* Master interfaces on the L4_WKUP interconnect */ +static struct omap_hwmod_ocp_if *omap2430_l4_wkup_masters[] = { +}; + +/* L4 WKUP */ +static struct omap_hwmod omap2430_l4_wkup_hwmod = { + .name = "l4_wkup_hwmod", + .masters = omap2430_l4_wkup_masters, + .masters_cnt = ARRAY_SIZE(omap2430_l4_wkup_masters), + .slaves = omap2430_l4_wkup_slaves, + .slaves_cnt = ARRAY_SIZE(omap2430_l4_wkup_slaves), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430) +}; + +/* Master interfaces on the MPU device */ +static struct omap_hwmod_ocp_if *omap2430_mpu_masters[] = { + &omap2430_mpu__l3, +}; + +/* MPU */ +static struct omap_hwmod omap2430_mpu_hwmod = { + .name = "mpu_hwmod", + .clkdev_dev_id = NULL, + .clkdev_con_id = "mpu_ck", + .masters = omap2430_mpu_masters, + .masters_cnt = ARRAY_SIZE(omap2430_mpu_masters), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430), +}; + +static __initdata struct omap_hwmod *omap2430_hwmods[] = { + &omap2430_l3_hwmod, + &omap2430_l4_core_hwmod, + &omap2430_l4_wkup_hwmod, + &omap2430_mpu_hwmod, + NULL, +}; + +#else +# define omap2430_hwmods 0 +#endif + +#endif + + diff --git a/arch/arm/mach-omap2/omap_hwmod_34xx.h b/arch/arm/mach-omap2/omap_hwmod_34xx.h new file mode 100644 index 00000000000..1e069f83157 --- /dev/null +++ b/arch/arm/mach-omap2/omap_hwmod_34xx.h @@ -0,0 +1,168 @@ +/* + * omap_hwmod_34xx.h - hardware modules present on the OMAP34xx chips + * + * Copyright (C) 2009 Nokia Corporation + * Paul Walmsley + * + * 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. + * + */ +#ifndef __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_OMAP_HWMOD34XX_H +#define __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_OMAP_HWMOD34XX_H + +#ifdef CONFIG_ARCH_OMAP34XX + +#include <mach/omap_hwmod.h> +#include <mach/irqs.h> +#include <mach/cpu.h> +#include <mach/dma.h> + +#include "prm-regbits-34xx.h" + +static struct omap_hwmod omap34xx_mpu_hwmod; +static struct omap_hwmod omap34xx_l3_hwmod; +static struct omap_hwmod omap34xx_l4_core_hwmod; +static struct omap_hwmod omap34xx_l4_per_hwmod; + +/* L3 -> L4_CORE interface */ +static struct omap_hwmod_ocp_if omap34xx_l3__l4_core = { + .master = &omap34xx_l3_hwmod, + .slave = &omap34xx_l4_core_hwmod, + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +/* L3 -> L4_PER interface */ +static struct omap_hwmod_ocp_if omap34xx_l3__l4_per = { + .master = &omap34xx_l3_hwmod, + .slave = &omap34xx_l4_per_hwmod, + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +/* MPU -> L3 interface */ +static struct omap_hwmod_ocp_if omap34xx_mpu__l3 = { + .master = &omap34xx_mpu_hwmod, + .slave = &omap34xx_l3_hwmod, + .user = OCP_USER_MPU, +}; + +/* Slave interfaces on the L3 interconnect */ +static struct omap_hwmod_ocp_if *omap34xx_l3_slaves[] = { + &omap34xx_mpu__l3, +}; + +/* Master interfaces on the L3 interconnect */ +static struct omap_hwmod_ocp_if *omap34xx_l3_masters[] = { + &omap34xx_l3__l4_core, + &omap34xx_l3__l4_per, +}; + +/* L3 */ +static struct omap_hwmod omap34xx_l3_hwmod = { + .name = "l3_hwmod", + .masters = omap34xx_l3_masters, + .masters_cnt = ARRAY_SIZE(omap34xx_l3_masters), + .slaves = omap34xx_l3_slaves, + .slaves_cnt = ARRAY_SIZE(omap34xx_l3_slaves), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) +}; + +static struct omap_hwmod omap34xx_l4_wkup_hwmod; + +/* L4_CORE -> L4_WKUP interface */ +static struct omap_hwmod_ocp_if omap34xx_l4_core__l4_wkup = { + .master = &omap34xx_l4_core_hwmod, + .slave = &omap34xx_l4_wkup_hwmod, + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +/* Slave interfaces on the L4_CORE interconnect */ +static struct omap_hwmod_ocp_if *omap34xx_l4_core_slaves[] = { + &omap34xx_l3__l4_core, +}; + +/* Master interfaces on the L4_CORE interconnect */ +static struct omap_hwmod_ocp_if *omap34xx_l4_core_masters[] = { + &omap34xx_l4_core__l4_wkup, +}; + +/* L4 CORE */ +static struct omap_hwmod omap34xx_l4_core_hwmod = { + .name = "l4_core_hwmod", + .masters = omap34xx_l4_core_masters, + .masters_cnt = ARRAY_SIZE(omap34xx_l4_core_masters), + .slaves = omap34xx_l4_core_slaves, + .slaves_cnt = ARRAY_SIZE(omap34xx_l4_core_slaves), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) +}; + +/* Slave interfaces on the L4_PER interconnect */ +static struct omap_hwmod_ocp_if *omap34xx_l4_per_slaves[] = { + &omap34xx_l3__l4_per, +}; + +/* Master interfaces on the L4_PER interconnect */ +static struct omap_hwmod_ocp_if *omap34xx_l4_per_masters[] = { +}; + +/* L4 PER */ +static struct omap_hwmod omap34xx_l4_per_hwmod = { + .name = "l4_per_hwmod", + .masters = omap34xx_l4_per_masters, + .masters_cnt = ARRAY_SIZE(omap34xx_l4_per_masters), + .slaves = omap34xx_l4_per_slaves, + .slaves_cnt = ARRAY_SIZE(omap34xx_l4_per_slaves), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) +}; + +/* Slave interfaces on the L4_WKUP interconnect */ +static struct omap_hwmod_ocp_if *omap34xx_l4_wkup_slaves[] = { + &omap34xx_l4_core__l4_wkup, +}; + +/* Master interfaces on the L4_WKUP interconnect */ +static struct omap_hwmod_ocp_if *omap34xx_l4_wkup_masters[] = { +}; + +/* L4 WKUP */ +static struct omap_hwmod omap34xx_l4_wkup_hwmod = { + .name = "l4_wkup_hwmod", + .masters = omap34xx_l4_wkup_masters, + .masters_cnt = ARRAY_SIZE(omap34xx_l4_wkup_masters), + .slaves = omap34xx_l4_wkup_slaves, + .slaves_cnt = ARRAY_SIZE(omap34xx_l4_wkup_slaves), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430) +}; + +/* Master interfaces on the MPU device */ +static struct omap_hwmod_ocp_if *omap34xx_mpu_masters[] = { + &omap34xx_mpu__l3, +}; + +/* MPU */ +static struct omap_hwmod omap34xx_mpu_hwmod = { + .name = "mpu_hwmod", + .clkdev_dev_id = NULL, + .clkdev_con_id = "arm_fck", + .masters = omap34xx_mpu_masters, + .masters_cnt = ARRAY_SIZE(omap34xx_mpu_masters), + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430), +}; + +static __initdata struct omap_hwmod *omap34xx_hwmods[] = { + &omap34xx_l3_hwmod, + &omap34xx_l4_core_hwmod, + &omap34xx_l4_per_hwmod, + &omap34xx_l4_wkup_hwmod, + &omap34xx_mpu_hwmod, + NULL, +}; + +#else +# define omap34xx_hwmods 0 +#endif + +#endif + + diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c index 6cc375a275b..1b4c1600f8d 100644 --- a/arch/arm/mach-omap2/pm-debug.c +++ b/arch/arm/mach-omap2/pm-debug.c @@ -20,13 +20,16 @@ */ #include <linux/kernel.h> -#include <linux/timer.h> +#include <linux/sched.h> #include <linux/clk.h> #include <linux/err.h> #include <linux/io.h> +#include <linux/module.h> #include <mach/clock.h> #include <mach/board.h> +#include <mach/powerdomain.h> +#include <mach/clockdomain.h> #include "prm.h" #include "cm.h" @@ -48,7 +51,9 @@ int omap2_pm_debug; regs[reg_count++].val = __raw_readl(reg) #define DUMP_INTC_REG(reg, off) \ regs[reg_count].name = #reg; \ - regs[reg_count++].val = __raw_readl(IO_ADDRESS(0x480fe000 + (off))) + regs[reg_count++].val = __raw_readl(OMAP2_IO_ADDRESS(0x480fe000 + (off))) + +static int __init pm_dbg_init(void); void omap2_pm_dump(int mode, int resume, unsigned int us) { @@ -150,3 +155,425 @@ void omap2_pm_dump(int mode, int resume, unsigned int us) for (i = 0; i < reg_count; i++) printk(KERN_INFO "%-20s: 0x%08x\n", regs[i].name, regs[i].val); } + +#ifdef CONFIG_DEBUG_FS +#include <linux/debugfs.h> +#include <linux/seq_file.h> + +static void pm_dbg_regset_store(u32 *ptr); + +struct dentry *pm_dbg_dir; + +static int pm_dbg_init_done; + +enum { + DEBUG_FILE_COUNTERS = 0, + DEBUG_FILE_TIMERS, +}; + +struct pm_module_def { + char name[8]; /* Name of the module */ + short type; /* CM or PRM */ + unsigned short offset; + int low; /* First register address on this module */ + int high; /* Last register address on this module */ +}; + +#define MOD_CM 0 +#define MOD_PRM 1 + +static const struct pm_module_def *pm_dbg_reg_modules; +static const struct pm_module_def omap3_pm_reg_modules[] = { + { "IVA2", MOD_CM, OMAP3430_IVA2_MOD, 0, 0x4c }, + { "OCP", MOD_CM, OCP_MOD, 0, 0x10 }, + { "MPU", MOD_CM, MPU_MOD, 4, 0x4c }, + { "CORE", MOD_CM, CORE_MOD, 0, 0x4c }, + { "SGX", MOD_CM, OMAP3430ES2_SGX_MOD, 0, 0x4c }, + { "WKUP", MOD_CM, WKUP_MOD, 0, 0x40 }, + { "CCR", MOD_CM, PLL_MOD, 0, 0x70 }, + { "DSS", MOD_CM, OMAP3430_DSS_MOD, 0, 0x4c }, + { "CAM", MOD_CM, OMAP3430_CAM_MOD, 0, 0x4c }, + { "PER", MOD_CM, OMAP3430_PER_MOD, 0, 0x4c }, + { "EMU", MOD_CM, OMAP3430_EMU_MOD, 0x40, 0x54 }, + { "NEON", MOD_CM, OMAP3430_NEON_MOD, 0x20, 0x48 }, + { "USB", MOD_CM, OMAP3430ES2_USBHOST_MOD, 0, 0x4c }, + + { "IVA2", MOD_PRM, OMAP3430_IVA2_MOD, 0x50, 0xfc }, + { "OCP", MOD_PRM, OCP_MOD, 4, 0x1c }, + { "MPU", MOD_PRM, MPU_MOD, 0x58, 0xe8 }, + { "CORE", MOD_PRM, CORE_MOD, 0x58, 0xf8 }, + { "SGX", MOD_PRM, OMAP3430ES2_SGX_MOD, 0x58, 0xe8 }, + { "WKUP", MOD_PRM, WKUP_MOD, 0xa0, 0xb0 }, + { "CCR", MOD_PRM, PLL_MOD, 0x40, 0x70 }, + { "DSS", MOD_PRM, OMAP3430_DSS_MOD, 0x58, 0xe8 }, + { "CAM", MOD_PRM, OMAP3430_CAM_MOD, 0x58, 0xe8 }, + { "PER", MOD_PRM, OMAP3430_PER_MOD, 0x58, 0xe8 }, + { "EMU", MOD_PRM, OMAP3430_EMU_MOD, 0x58, 0xe4 }, + { "GLBL", MOD_PRM, OMAP3430_GR_MOD, 0x20, 0xe4 }, + { "NEON", MOD_PRM, OMAP3430_NEON_MOD, 0x58, 0xe8 }, + { "USB", MOD_PRM, OMAP3430ES2_USBHOST_MOD, 0x58, 0xe8 }, + { "", 0, 0, 0, 0 }, +}; + +#define PM_DBG_MAX_REG_SETS 4 + +static void *pm_dbg_reg_set[PM_DBG_MAX_REG_SETS]; + +static int pm_dbg_get_regset_size(void) +{ + static int regset_size; + + if (regset_size == 0) { + int i = 0; + + while (pm_dbg_reg_modules[i].name[0] != 0) { + regset_size += pm_dbg_reg_modules[i].high + + 4 - pm_dbg_reg_modules[i].low; + i++; + } + } + return regset_size; +} + +static int pm_dbg_show_regs(struct seq_file *s, void *unused) +{ + int i, j; + unsigned long val; + int reg_set = (int)s->private; + u32 *ptr; + void *store = NULL; + int regs; + int linefeed; + + if (reg_set == 0) { + store = kmalloc(pm_dbg_get_regset_size(), GFP_KERNEL); + ptr = store; + pm_dbg_regset_store(ptr); + } else { + ptr = pm_dbg_reg_set[reg_set - 1]; + } + + i = 0; + + while (pm_dbg_reg_modules[i].name[0] != 0) { + regs = 0; + linefeed = 0; + if (pm_dbg_reg_modules[i].type == MOD_CM) + seq_printf(s, "MOD: CM_%s (%08x)\n", + pm_dbg_reg_modules[i].name, + (u32)(OMAP3430_CM_BASE + + pm_dbg_reg_modules[i].offset)); + else + seq_printf(s, "MOD: PRM_%s (%08x)\n", + pm_dbg_reg_modules[i].name, + (u32)(OMAP3430_PRM_BASE + + pm_dbg_reg_modules[i].offset)); + + for (j = pm_dbg_reg_modules[i].low; + j <= pm_dbg_reg_modules[i].high; j += 4) { + val = *(ptr++); + if (val != 0) { + regs++; + if (linefeed) { + seq_printf(s, "\n"); + linefeed = 0; + } + seq_printf(s, " %02x => %08lx", j, val); + if (regs % 4 == 0) + linefeed = 1; + } + } + seq_printf(s, "\n"); + i++; + } + + if (store != NULL) + kfree(store); + + return 0; +} + +static void pm_dbg_regset_store(u32 *ptr) +{ + int i, j; + u32 val; + + i = 0; + + while (pm_dbg_reg_modules[i].name[0] != 0) { + for (j = pm_dbg_reg_modules[i].low; + j <= pm_dbg_reg_modules[i].high; j += 4) { + if (pm_dbg_reg_modules[i].type == MOD_CM) + val = cm_read_mod_reg( + pm_dbg_reg_modules[i].offset, j); + else + val = prm_read_mod_reg( + pm_dbg_reg_modules[i].offset, j); + *(ptr++) = val; + } + i++; + } +} + +int pm_dbg_regset_save(int reg_set) +{ + if (pm_dbg_reg_set[reg_set-1] == NULL) + return -EINVAL; + + pm_dbg_regset_store(pm_dbg_reg_set[reg_set-1]); + + return 0; +} + +static const char pwrdm_state_names[][4] = { + "OFF", + "RET", + "INA", + "ON" +}; + +void pm_dbg_update_time(struct powerdomain *pwrdm, int prev) +{ + s64 t; + + if (!pm_dbg_init_done) + return ; + + /* Update timer for previous state */ + t = sched_clock(); + + pwrdm->state_timer[prev] += t - pwrdm->timer; + + pwrdm->timer = t; +} + +static int clkdm_dbg_show_counter(struct clockdomain *clkdm, void *user) +{ + struct seq_file *s = (struct seq_file *)user; + + if (strcmp(clkdm->name, "emu_clkdm") == 0 || + strcmp(clkdm->name, "wkup_clkdm") == 0 || + strncmp(clkdm->name, "dpll", 4) == 0) + return 0; + + seq_printf(s, "%s->%s (%d)", clkdm->name, + clkdm->pwrdm.ptr->name, + atomic_read(&clkdm->usecount)); + seq_printf(s, "\n"); + + return 0; +} + +static int pwrdm_dbg_show_counter(struct powerdomain *pwrdm, void *user) +{ + struct seq_file *s = (struct seq_file *)user; + int i; + + if (strcmp(pwrdm->name, "emu_pwrdm") == 0 || + strcmp(pwrdm->name, "wkup_pwrdm") == 0 || + strncmp(pwrdm->name, "dpll", 4) == 0) + return 0; + + if (pwrdm->state != pwrdm_read_pwrst(pwrdm)) + printk(KERN_ERR "pwrdm state mismatch(%s) %d != %d\n", + pwrdm->name, pwrdm->state, pwrdm_read_pwrst(pwrdm)); + + seq_printf(s, "%s (%s)", pwrdm->name, + pwrdm_state_names[pwrdm->state]); + for (i = 0; i < 4; i++) + seq_printf(s, ",%s:%d", pwrdm_state_names[i], + pwrdm->state_counter[i]); + + seq_printf(s, "\n"); + + return 0; +} + +static int pwrdm_dbg_show_timer(struct powerdomain *pwrdm, void *user) +{ + struct seq_file *s = (struct seq_file *)user; + int i; + + if (strcmp(pwrdm->name, "emu_pwrdm") == 0 || + strcmp(pwrdm->name, "wkup_pwrdm") == 0 || + strncmp(pwrdm->name, "dpll", 4) == 0) + return 0; + + pwrdm_state_switch(pwrdm); + + seq_printf(s, "%s (%s)", pwrdm->name, + pwrdm_state_names[pwrdm->state]); + + for (i = 0; i < 4; i++) + seq_printf(s, ",%s:%lld", pwrdm_state_names[i], + pwrdm->state_timer[i]); + + seq_printf(s, "\n"); + return 0; +} + +static int pm_dbg_show_counters(struct seq_file *s, void *unused) +{ + pwrdm_for_each(pwrdm_dbg_show_counter, s); + clkdm_for_each(clkdm_dbg_show_counter, s); + + return 0; +} + +static int pm_dbg_show_timers(struct seq_file *s, void *unused) +{ + pwrdm_for_each(pwrdm_dbg_show_timer, s); + return 0; +} + +static int pm_dbg_open(struct inode *inode, struct file *file) +{ + switch ((int)inode->i_private) { + case DEBUG_FILE_COUNTERS: + return single_open(file, pm_dbg_show_counters, + &inode->i_private); + case DEBUG_FILE_TIMERS: + default: + return single_open(file, pm_dbg_show_timers, + &inode->i_private); + }; +} + +static int pm_dbg_reg_open(struct inode *inode, struct file *file) +{ + return single_open(file, pm_dbg_show_regs, inode->i_private); +} + +static const struct file_operations debug_fops = { + .open = pm_dbg_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations debug_reg_fops = { + .open = pm_dbg_reg_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +int pm_dbg_regset_init(int reg_set) +{ + char name[2]; + + if (!pm_dbg_init_done) + pm_dbg_init(); + + if (reg_set < 1 || reg_set > PM_DBG_MAX_REG_SETS || + pm_dbg_reg_set[reg_set-1] != NULL) + return -EINVAL; + + pm_dbg_reg_set[reg_set-1] = + kmalloc(pm_dbg_get_regset_size(), GFP_KERNEL); + + if (pm_dbg_reg_set[reg_set-1] == NULL) + return -ENOMEM; + + if (pm_dbg_dir != NULL) { + sprintf(name, "%d", reg_set); + + (void) debugfs_create_file(name, S_IRUGO, + pm_dbg_dir, (void *)reg_set, &debug_reg_fops); + } + + return 0; +} + +static int pwrdm_suspend_get(void *data, u64 *val) +{ + *val = omap3_pm_get_suspend_state((struct powerdomain *)data); + + if (*val >= 0) + return 0; + return *val; +} + +static int pwrdm_suspend_set(void *data, u64 val) +{ + return omap3_pm_set_suspend_state((struct powerdomain *)data, (int)val); +} + +DEFINE_SIMPLE_ATTRIBUTE(pwrdm_suspend_fops, pwrdm_suspend_get, + pwrdm_suspend_set, "%llu\n"); + +static int __init pwrdms_setup(struct powerdomain *pwrdm, void *dir) +{ + int i; + s64 t; + struct dentry *d; + + t = sched_clock(); + + for (i = 0; i < 4; i++) + pwrdm->state_timer[i] = 0; + + pwrdm->timer = t; + + if (strncmp(pwrdm->name, "dpll", 4) == 0) + return 0; + + d = debugfs_create_dir(pwrdm->name, (struct dentry *)dir); + + (void) debugfs_create_file("suspend", S_IRUGO|S_IWUSR, d, + (void *)pwrdm, &pwrdm_suspend_fops); + + return 0; +} + +static int __init pm_dbg_init(void) +{ + int i; + struct dentry *d; + char name[2]; + + if (pm_dbg_init_done) + return 0; + + if (cpu_is_omap34xx()) + pm_dbg_reg_modules = omap3_pm_reg_modules; + else { + printk(KERN_ERR "%s: only OMAP3 supported\n", __func__); + return -ENODEV; + } + + d = debugfs_create_dir("pm_debug", NULL); + if (IS_ERR(d)) + return PTR_ERR(d); + + (void) debugfs_create_file("count", S_IRUGO, + d, (void *)DEBUG_FILE_COUNTERS, &debug_fops); + (void) debugfs_create_file("time", S_IRUGO, + d, (void *)DEBUG_FILE_TIMERS, &debug_fops); + + pwrdm_for_each(pwrdms_setup, (void *)d); + + pm_dbg_dir = debugfs_create_dir("registers", d); + if (IS_ERR(pm_dbg_dir)) + return PTR_ERR(pm_dbg_dir); + + (void) debugfs_create_file("current", S_IRUGO, + pm_dbg_dir, (void *)0, &debug_reg_fops); + + for (i = 0; i < PM_DBG_MAX_REG_SETS; i++) + if (pm_dbg_reg_set[i] != NULL) { + sprintf(name, "%d", i+1); + (void) debugfs_create_file(name, S_IRUGO, + pm_dbg_dir, (void *)(i+1), &debug_reg_fops); + + } + + pm_dbg_init_done = 1; + + return 0; +} +arch_initcall(pm_dbg_init); + +#else +void pm_dbg_update_time(struct powerdomain *pwrdm, int prev) {} +#endif diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index f7b3baf7667..8400f576892 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h @@ -11,15 +11,23 @@ #ifndef __ARCH_ARM_MACH_OMAP2_PM_H #define __ARCH_ARM_MACH_OMAP2_PM_H -extern int omap2_pm_init(void); -extern int omap3_pm_init(void); +#include <mach/powerdomain.h> + +extern int omap3_pm_get_suspend_state(struct powerdomain *pwrdm); +extern int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, int state); #ifdef CONFIG_PM_DEBUG extern void omap2_pm_dump(int mode, int resume, unsigned int us); extern int omap2_pm_debug; +extern void pm_dbg_update_time(struct powerdomain *pwrdm, int prev); +extern int pm_dbg_regset_save(int reg_set); +extern int pm_dbg_regset_init(int reg_set); #else #define omap2_pm_dump(mode, resume, us) do {} while (0); #define omap2_pm_debug 0 +#define pm_dbg_update_time(pwrdm, prev) do {} while (0); +#define pm_dbg_regset_save(reg_set) do {} while (0); +#define pm_dbg_regset_init(reg_set) do {} while (0); #endif /* CONFIG_PM_DEBUG */ extern void omap24xx_idle_loop_suspend(void); diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c index db1025562fb..bff5c4e8974 100644 --- a/arch/arm/mach-omap2/pm24xx.c +++ b/arch/arm/mach-omap2/pm24xx.c @@ -333,7 +333,7 @@ static struct platform_suspend_ops omap_pm_ops = { .valid = suspend_valid_only_mem, }; -static int _pm_clkdm_enable_hwsup(struct clockdomain *clkdm) +static int _pm_clkdm_enable_hwsup(struct clockdomain *clkdm, void *unused) { omap2_clkdm_allow_idle(clkdm); return 0; @@ -385,7 +385,7 @@ static void __init prcm_setup_regs(void) omap2_clkdm_sleep(gfx_clkdm); /* Enable clockdomain hardware-supervised control for all clkdms */ - clkdm_for_each(_pm_clkdm_enable_hwsup); + clkdm_for_each(_pm_clkdm_enable_hwsup, NULL); /* Enable clock autoidle for all domains */ cm_write_mod_reg(OMAP24XX_AUTO_CAM | @@ -470,7 +470,7 @@ static void __init prcm_setup_regs(void) WKUP_MOD, PM_WKEN); } -int __init omap2_pm_init(void) +static int __init omap2_pm_init(void) { u32 l; diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 841d4c5ed8b..0ff5a6c53aa 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -39,7 +39,9 @@ struct power_state { struct powerdomain *pwrdm; u32 next_state; +#ifdef CONFIG_SUSPEND u32 saved_state; +#endif struct list_head node; }; @@ -168,6 +170,8 @@ static void omap_sram_idle(void) printk(KERN_ERR "Invalid mpu state in sram_idle\n"); return; } + pwrdm_pre_transition(); + omap2_gpio_prepare_for_retention(); omap_uart_prepare_idle(0); omap_uart_prepare_idle(1); @@ -180,6 +184,9 @@ static void omap_sram_idle(void) omap_uart_resume_idle(1); omap_uart_resume_idle(0); omap2_gpio_resume_after_retention(); + + pwrdm_post_transition(); + } /* @@ -269,6 +276,7 @@ static int set_pwrdm_state(struct powerdomain *pwrdm, u32 state) if (sleep_switch) { omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]); pwrdm_wait_transition(pwrdm); + pwrdm_state_switch(pwrdm); } err: @@ -293,6 +301,9 @@ out: local_irq_enable(); } +#ifdef CONFIG_SUSPEND +static suspend_state_t suspend_state; + static int omap3_pm_prepare(void) { disable_hlt(); @@ -321,7 +332,6 @@ static int omap3_pm_suspend(void) restore: /* Restore next_pwrsts */ list_for_each_entry(pwrst, &pwrst_list, node) { - set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state); state = pwrdm_read_prev_pwrst(pwrst->pwrdm); if (state > pwrst->next_state) { printk(KERN_INFO "Powerdomain (%s) didn't enter " @@ -329,6 +339,7 @@ restore: pwrst->pwrdm->name, pwrst->next_state); ret = -1; } + set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state); } if (ret) printk(KERN_ERR "Could not enter target state in pm_suspend\n"); @@ -339,11 +350,11 @@ restore: return ret; } -static int omap3_pm_enter(suspend_state_t state) +static int omap3_pm_enter(suspend_state_t unused) { int ret = 0; - switch (state) { + switch (suspend_state) { case PM_SUSPEND_STANDBY: case PM_SUSPEND_MEM: ret = omap3_pm_suspend(); @@ -360,12 +371,30 @@ static void omap3_pm_finish(void) enable_hlt(); } +/* Hooks to enable / disable UART interrupts during suspend */ +static int omap3_pm_begin(suspend_state_t state) +{ + suspend_state = state; + omap_uart_enable_irqs(0); + return 0; +} + +static void omap3_pm_end(void) +{ + suspend_state = PM_SUSPEND_ON; + omap_uart_enable_irqs(1); + return; +} + static struct platform_suspend_ops omap_pm_ops = { + .begin = omap3_pm_begin, + .end = omap3_pm_end, .prepare = omap3_pm_prepare, .enter = omap3_pm_enter, .finish = omap3_pm_finish, .valid = suspend_valid_only_mem, }; +#endif /* CONFIG_SUSPEND */ /** @@ -613,18 +642,60 @@ static void __init prcm_setup_regs(void) /* Clear any pending PRCM interrupts */ prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET); + /* Don't attach IVA interrupts */ + prm_write_mod_reg(0, WKUP_MOD, OMAP3430_PM_IVAGRPSEL); + prm_write_mod_reg(0, CORE_MOD, OMAP3430_PM_IVAGRPSEL1); + prm_write_mod_reg(0, CORE_MOD, OMAP3430ES2_PM_IVAGRPSEL3); + prm_write_mod_reg(0, OMAP3430_PER_MOD, OMAP3430_PM_IVAGRPSEL); + + /* Clear any pending 'reset' flags */ + prm_write_mod_reg(0xffffffff, MPU_MOD, RM_RSTST); + prm_write_mod_reg(0xffffffff, CORE_MOD, RM_RSTST); + prm_write_mod_reg(0xffffffff, OMAP3430_PER_MOD, RM_RSTST); + prm_write_mod_reg(0xffffffff, OMAP3430_EMU_MOD, RM_RSTST); + prm_write_mod_reg(0xffffffff, OMAP3430_NEON_MOD, RM_RSTST); + prm_write_mod_reg(0xffffffff, OMAP3430_DSS_MOD, RM_RSTST); + prm_write_mod_reg(0xffffffff, OMAP3430ES2_USBHOST_MOD, RM_RSTST); + + /* Clear any pending PRCM interrupts */ + prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET); + omap3_iva_idle(); omap3_d2d_idle(); } -static int __init pwrdms_setup(struct powerdomain *pwrdm) +int omap3_pm_get_suspend_state(struct powerdomain *pwrdm) +{ + struct power_state *pwrst; + + list_for_each_entry(pwrst, &pwrst_list, node) { + if (pwrst->pwrdm == pwrdm) + return pwrst->next_state; + } + return -EINVAL; +} + +int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, int state) +{ + struct power_state *pwrst; + + list_for_each_entry(pwrst, &pwrst_list, node) { + if (pwrst->pwrdm == pwrdm) { + pwrst->next_state = state; + return 0; + } + } + return -EINVAL; +} + +static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused) { struct power_state *pwrst; if (!pwrdm->pwrsts) return 0; - pwrst = kmalloc(sizeof(struct power_state), GFP_KERNEL); + pwrst = kmalloc(sizeof(struct power_state), GFP_ATOMIC); if (!pwrst) return -ENOMEM; pwrst->pwrdm = pwrdm; @@ -642,7 +713,7 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm) * supported. Initiate sleep transition for other clockdomains, if * they are not used */ -static int __init clkdms_setup(struct clockdomain *clkdm) +static int __init clkdms_setup(struct clockdomain *clkdm, void *unused) { if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO) omap2_clkdm_allow_idle(clkdm); @@ -652,7 +723,7 @@ static int __init clkdms_setup(struct clockdomain *clkdm) return 0; } -int __init omap3_pm_init(void) +static int __init omap3_pm_init(void) { struct power_state *pwrst, *tmp; int ret; @@ -675,13 +746,13 @@ int __init omap3_pm_init(void) goto err1; } - ret = pwrdm_for_each(pwrdms_setup); + ret = pwrdm_for_each(pwrdms_setup, NULL); if (ret) { printk(KERN_ERR "Failed to setup powerdomains\n"); goto err2; } - (void) clkdm_for_each(clkdms_setup); + (void) clkdm_for_each(clkdms_setup, NULL); mpu_pwrdm = pwrdm_lookup("mpu_pwrdm"); if (mpu_pwrdm == NULL) { @@ -692,7 +763,9 @@ int __init omap3_pm_init(void) _omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend, omap34xx_cpu_suspend_sz); +#ifdef CONFIG_SUSPEND suspend_set_ops(&omap_pm_ops); +#endif /* CONFIG_SUSPEND */ pm_idle = omap3_pm_idle; diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 983f1cb676b..2594cbff394 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c @@ -35,6 +35,13 @@ #include <mach/powerdomain.h> #include <mach/clockdomain.h> +#include "pm.h" + +enum { + PWRDM_STATE_NOW = 0, + PWRDM_STATE_PREV, +}; + /* pwrdm_list contains all registered struct powerdomains */ static LIST_HEAD(pwrdm_list); @@ -83,7 +90,7 @@ static struct powerdomain *_pwrdm_deps_lookup(struct powerdomain *pwrdm, if (!pwrdm || !deps || !omap_chip_is(pwrdm->omap_chip)) return ERR_PTR(-EINVAL); - for (pd = deps; pd; pd++) { + for (pd = deps; pd->pwrdm_name; pd++) { if (!omap_chip_is(pd->omap_chip)) continue; @@ -96,12 +103,71 @@ static struct powerdomain *_pwrdm_deps_lookup(struct powerdomain *pwrdm, } - if (!pd) + if (!pd->pwrdm_name) return ERR_PTR(-ENOENT); return pd->pwrdm; } +static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag) +{ + + int prev; + int state; + + if (pwrdm == NULL) + return -EINVAL; + + state = pwrdm_read_pwrst(pwrdm); + + switch (flag) { + case PWRDM_STATE_NOW: + prev = pwrdm->state; + break; + case PWRDM_STATE_PREV: + prev = pwrdm_read_prev_pwrst(pwrdm); + if (pwrdm->state != prev) + pwrdm->state_counter[prev]++; + break; + default: + return -EINVAL; + } + + if (state != prev) + pwrdm->state_counter[state]++; + + pm_dbg_update_time(pwrdm, prev); + + pwrdm->state = state; + + return 0; +} + +static int _pwrdm_pre_transition_cb(struct powerdomain *pwrdm, void *unused) +{ + pwrdm_clear_all_prev_pwrst(pwrdm); + _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW); + return 0; +} + +static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused) +{ + _pwrdm_state_switch(pwrdm, PWRDM_STATE_PREV); + return 0; +} + +static __init void _pwrdm_setup(struct powerdomain *pwrdm) +{ + int i; + + for (i = 0; i < 4; i++) + pwrdm->state_counter[i] = 0; + + pwrdm_wait_transition(pwrdm); + pwrdm->state = pwrdm_read_pwrst(pwrdm); + pwrdm->state_counter[pwrdm->state] = 1; + +} /* Public functions */ @@ -117,9 +183,12 @@ void pwrdm_init(struct powerdomain **pwrdm_list) { struct powerdomain **p = NULL; - if (pwrdm_list) - for (p = pwrdm_list; *p; p++) + if (pwrdm_list) { + for (p = pwrdm_list; *p; p++) { pwrdm_register(*p); + _pwrdm_setup(*p); + } + } } /** @@ -217,7 +286,8 @@ struct powerdomain *pwrdm_lookup(const char *name) * anything else to indicate failure; or -EINVAL if the function * pointer is null. */ -int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm)) +int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user), + void *user) { struct powerdomain *temp_pwrdm; unsigned long flags; @@ -228,7 +298,7 @@ int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm)) read_lock_irqsave(&pwrdm_rwlock, flags); list_for_each_entry(temp_pwrdm, &pwrdm_list, node) { - ret = (*fn)(temp_pwrdm); + ret = (*fn)(temp_pwrdm, user); if (ret) break; } @@ -1110,4 +1180,36 @@ int pwrdm_wait_transition(struct powerdomain *pwrdm) return 0; } +int pwrdm_state_switch(struct powerdomain *pwrdm) +{ + return _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW); +} + +int pwrdm_clkdm_state_switch(struct clockdomain *clkdm) +{ + if (clkdm != NULL && clkdm->pwrdm.ptr != NULL) { + pwrdm_wait_transition(clkdm->pwrdm.ptr); + return pwrdm_state_switch(clkdm->pwrdm.ptr); + } + + return -EINVAL; +} +int pwrdm_clk_state_switch(struct clk *clk) +{ + if (clk != NULL && clk->clkdm != NULL) + return pwrdm_clkdm_state_switch(clk->clkdm); + return -EINVAL; +} + +int pwrdm_pre_transition(void) +{ + pwrdm_for_each(_pwrdm_pre_transition_cb, NULL); + return 0; +} + +int pwrdm_post_transition(void) +{ + pwrdm_for_each(_pwrdm_post_transition_cb, NULL); + return 0; +} diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c index f945156d558..ced555a4cd1 100644 --- a/arch/arm/mach-omap2/prcm.c +++ b/arch/arm/mach-omap2/prcm.c @@ -17,6 +17,7 @@ #include <linux/init.h> #include <linux/clk.h> #include <linux/io.h> +#include <linux/delay.h> #include <mach/common.h> #include <mach/prcm.h> @@ -28,6 +29,8 @@ static void __iomem *prm_base; static void __iomem *cm_base; +#define MAX_MODULE_ENABLE_WAIT 100000 + u32 omap_prcm_get_reset_sources(void) { /* XXX This presumably needs modification for 34XX */ @@ -120,6 +123,46 @@ u32 cm_rmw_mod_reg_bits(u32 mask, u32 bits, s16 module, s16 idx) } EXPORT_SYMBOL(cm_rmw_mod_reg_bits); +/** + * omap2_cm_wait_idlest - wait for IDLEST bit to indicate module readiness + * @reg: physical address of module IDLEST register + * @mask: value to mask against to determine if the module is active + * @name: name of the clock (for printk) + * + * Returns 1 if the module indicated readiness in time, or 0 if it + * failed to enable in roughly MAX_MODULE_ENABLE_WAIT microseconds. + */ +int omap2_cm_wait_idlest(void __iomem *reg, u32 mask, const char *name) +{ + int i = 0; + int ena = 0; + + /* + * 24xx uses 0 to indicate not ready, and 1 to indicate ready. + * 34xx reverses this, just to keep us on our toes + */ + if (cpu_is_omap24xx()) + ena = mask; + else if (cpu_is_omap34xx()) + ena = 0; + else + BUG(); + + /* Wait for lock */ + while (((__raw_readl(reg) & mask) != ena) && + (i++ < MAX_MODULE_ENABLE_WAIT)) + udelay(1); + + if (i < MAX_MODULE_ENABLE_WAIT) + pr_debug("cm: Module associated with clock %s ready after %d " + "loops\n", name, i); + else + pr_err("cm: Module associated with clock %s didn't enable in " + "%d tries\n", name, MAX_MODULE_ENABLE_WAIT); + + return (i < MAX_MODULE_ENABLE_WAIT) ? 1 : 0; +}; + void __init omap2_set_globals_prcm(struct omap_globals *omap2_globals) { prm_base = omap2_globals->prm; diff --git a/arch/arm/mach-omap2/prm.h b/arch/arm/mach-omap2/prm.h index 9937e281469..03c467c35f5 100644 --- a/arch/arm/mach-omap2/prm.h +++ b/arch/arm/mach-omap2/prm.h @@ -17,11 +17,11 @@ #include "prcm-common.h" #define OMAP2420_PRM_REGADDR(module, reg) \ - IO_ADDRESS(OMAP2420_PRM_BASE + (module) + (reg)) + OMAP2_IO_ADDRESS(OMAP2420_PRM_BASE + (module) + (reg)) #define OMAP2430_PRM_REGADDR(module, reg) \ - IO_ADDRESS(OMAP2430_PRM_BASE + (module) + (reg)) + OMAP2_IO_ADDRESS(OMAP2430_PRM_BASE + (module) + (reg)) #define OMAP34XX_PRM_REGADDR(module, reg) \ - IO_ADDRESS(OMAP3430_PRM_BASE + (module) + (reg)) + OMAP2_IO_ADDRESS(OMAP3430_PRM_BASE + (module) + (reg)) /* * Architecture-specific global PRM registers diff --git a/arch/arm/mach-omap2/sdrc.c b/arch/arm/mach-omap2/sdrc.c index 2045441e838..9e3bd4fa781 100644 --- a/arch/arm/mach-omap2/sdrc.c +++ b/arch/arm/mach-omap2/sdrc.c @@ -32,7 +32,7 @@ #include <mach/sdrc.h> #include "sdrc.h" -static struct omap_sdrc_params *sdrc_init_params; +static struct omap_sdrc_params *sdrc_init_params_cs0, *sdrc_init_params_cs1; void __iomem *omap2_sdrc_base; void __iomem *omap2_sms_base; @@ -45,33 +45,49 @@ void __iomem *omap2_sms_base; /** * omap2_sdrc_get_params - return SDRC register values for a given clock rate * @r: SDRC clock rate (in Hz) + * @sdrc_cs0: chip select 0 ram timings ** + * @sdrc_cs1: chip select 1 ram timings ** * * Return pre-calculated values for the SDRC_ACTIM_CTRLA, - * SDRC_ACTIM_CTRLB, SDRC_RFR_CTRL, and SDRC_MR registers, for a given - * SDRC clock rate 'r'. These parameters control various timing - * delays in the SDRAM controller that are expressed in terms of the - * number of SDRC clock cycles to wait; hence the clock rate - * dependency. Note that sdrc_init_params must be sorted rate - * descending. Also assumes that both chip-selects use the same - * timing parameters. Returns a struct omap_sdrc_params * upon - * success, or NULL upon failure. + * SDRC_ACTIM_CTRLB, SDRC_RFR_CTRL and SDRC_MR registers in sdrc_cs[01] + * structs,for a given SDRC clock rate 'r'. + * These parameters control various timing delays in the SDRAM controller + * that are expressed in terms of the number of SDRC clock cycles to + * wait; hence the clock rate dependency. + * + * Supports 2 different timing parameters for both chip selects. + * + * Note 1: the sdrc_init_params_cs[01] must be sorted rate descending. + * Note 2: If sdrc_init_params_cs_1 is not NULL it must be of same size + * as sdrc_init_params_cs_0. + * + * Fills in the struct omap_sdrc_params * for each chip select. + * Returns 0 upon success or -1 upon failure. */ -struct omap_sdrc_params *omap2_sdrc_get_params(unsigned long r) +int omap2_sdrc_get_params(unsigned long r, + struct omap_sdrc_params **sdrc_cs0, + struct omap_sdrc_params **sdrc_cs1) { - struct omap_sdrc_params *sp; + struct omap_sdrc_params *sp0, *sp1; - if (!sdrc_init_params) - return NULL; + if (!sdrc_init_params_cs0) + return -1; - sp = sdrc_init_params; + sp0 = sdrc_init_params_cs0; + sp1 = sdrc_init_params_cs1; - while (sp->rate && sp->rate != r) - sp++; + while (sp0->rate && sp0->rate != r) { + sp0++; + if (sdrc_init_params_cs1) + sp1++; + } - if (!sp->rate) - return NULL; + if (!sp0->rate) + return -1; - return sp; + *sdrc_cs0 = sp0; + *sdrc_cs1 = sp1; + return 0; } @@ -83,13 +99,15 @@ void __init omap2_set_globals_sdrc(struct omap_globals *omap2_globals) /** * omap2_sdrc_init - initialize SMS, SDRC devices on boot - * @sp: pointer to a null-terminated list of struct omap_sdrc_params + * @sdrc_cs[01]: pointers to a null-terminated list of struct omap_sdrc_params + * Support for 2 chip selects timings * * Turn on smart idle modes for SDRAM scheduler and controller. * Program a known-good configuration for the SDRC to deal with buggy * bootloaders. */ -void __init omap2_sdrc_init(struct omap_sdrc_params *sp) +void __init omap2_sdrc_init(struct omap_sdrc_params *sdrc_cs0, + struct omap_sdrc_params *sdrc_cs1) { u32 l; @@ -103,11 +121,15 @@ void __init omap2_sdrc_init(struct omap_sdrc_params *sp) l |= (0x2 << 3); sdrc_write_reg(l, SDRC_SYSCONFIG); - sdrc_init_params = sp; + sdrc_init_params_cs0 = sdrc_cs0; + sdrc_init_params_cs1 = sdrc_cs1; /* XXX Enable SRFRONIDLEREQ here also? */ + /* + * PWDENA should not be set due to 34xx erratum 1.150 - PWDENA + * can cause random memory corruption + */ l = (1 << SDRC_POWER_EXTCLKDIS_SHIFT) | - (1 << SDRC_POWER_PWDENA_SHIFT) | (1 << SDRC_POWER_PAGEPOLICY_SHIFT); sdrc_write_reg(l, SDRC_POWER); } diff --git a/arch/arm/mach-omap2/sdrc.h b/arch/arm/mach-omap2/sdrc.h index 1a8bbd09406..0837eda5f2b 100644 --- a/arch/arm/mach-omap2/sdrc.h +++ b/arch/arm/mach-omap2/sdrc.h @@ -48,9 +48,9 @@ static inline u32 sms_read_reg(u16 reg) return __raw_readl(OMAP_SMS_REGADDR(reg)); } #else -#define OMAP242X_SDRC_REGADDR(reg) IO_ADDRESS(OMAP2420_SDRC_BASE + (reg)) -#define OMAP243X_SDRC_REGADDR(reg) IO_ADDRESS(OMAP243X_SDRC_BASE + (reg)) -#define OMAP34XX_SDRC_REGADDR(reg) IO_ADDRESS(OMAP343X_SDRC_BASE + (reg)) +#define OMAP242X_SDRC_REGADDR(reg) OMAP2_IO_ADDRESS(OMAP2420_SDRC_BASE + (reg)) +#define OMAP243X_SDRC_REGADDR(reg) OMAP2_IO_ADDRESS(OMAP243X_SDRC_BASE + (reg)) +#define OMAP34XX_SDRC_REGADDR(reg) OMAP2_IO_ADDRESS(OMAP343X_SDRC_BASE + (reg)) #endif /* __ASSEMBLER__ */ #endif diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index b094c15bfe4..ae2186892c8 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -54,6 +54,7 @@ struct omap_uart_state { struct plat_serial8250_port *p; struct list_head node; + struct platform_device pdev; #if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM) int context_valid; @@ -68,12 +69,11 @@ struct omap_uart_state { #endif }; -static struct omap_uart_state omap_uart[OMAP_MAX_NR_PORTS]; static LIST_HEAD(uart_list); -static struct plat_serial8250_port serial_platform_data[] = { +static struct plat_serial8250_port serial_platform_data0[] = { { - .membase = IO_ADDRESS(OMAP_UART1_BASE), + .membase = OMAP2_IO_ADDRESS(OMAP_UART1_BASE), .mapbase = OMAP_UART1_BASE, .irq = 72, .flags = UPF_BOOT_AUTOCONF, @@ -81,7 +81,13 @@ static struct plat_serial8250_port serial_platform_data[] = { .regshift = 2, .uartclk = OMAP24XX_BASE_BAUD * 16, }, { - .membase = IO_ADDRESS(OMAP_UART2_BASE), + .flags = 0 + } +}; + +static struct plat_serial8250_port serial_platform_data1[] = { + { + .membase = OMAP2_IO_ADDRESS(OMAP_UART2_BASE), .mapbase = OMAP_UART2_BASE, .irq = 73, .flags = UPF_BOOT_AUTOCONF, @@ -89,7 +95,13 @@ static struct plat_serial8250_port serial_platform_data[] = { .regshift = 2, .uartclk = OMAP24XX_BASE_BAUD * 16, }, { - .membase = IO_ADDRESS(OMAP_UART3_BASE), + .flags = 0 + } +}; + +static struct plat_serial8250_port serial_platform_data2[] = { + { + .membase = OMAP2_IO_ADDRESS(OMAP_UART3_BASE), .mapbase = OMAP_UART3_BASE, .irq = 74, .flags = UPF_BOOT_AUTOCONF, @@ -97,10 +109,35 @@ static struct plat_serial8250_port serial_platform_data[] = { .regshift = 2, .uartclk = OMAP24XX_BASE_BAUD * 16, }, { +#ifdef CONFIG_ARCH_OMAP4 + .membase = OMAP2_IO_ADDRESS(OMAP_UART4_BASE), + .mapbase = OMAP_UART4_BASE, + .irq = 70, + .flags = UPF_BOOT_AUTOCONF, + .iotype = UPIO_MEM, + .regshift = 2, + .uartclk = OMAP24XX_BASE_BAUD * 16, + }, { +#endif .flags = 0 } }; +#ifdef CONFIG_ARCH_OMAP4 +static struct plat_serial8250_port serial_platform_data3[] = { + { + .membase = OMAP2_IO_ADDRESS(OMAP_UART4_BASE), + .mapbase = OMAP_UART4_BASE, + .irq = 70, + .flags = UPF_BOOT_AUTOCONF, + .iotype = UPIO_MEM, + .regshift = 2, + .uartclk = OMAP24XX_BASE_BAUD * 16, + }, { + .flags = 0 + } +}; +#endif static inline unsigned int serial_read_reg(struct plat_serial8250_port *up, int offset) { @@ -217,6 +254,40 @@ static inline void omap_uart_disable_clocks(struct omap_uart_state *uart) clk_disable(uart->fck); } +static void omap_uart_enable_wakeup(struct omap_uart_state *uart) +{ + /* Set wake-enable bit */ + if (uart->wk_en && uart->wk_mask) { + u32 v = __raw_readl(uart->wk_en); + v |= uart->wk_mask; + __raw_writel(v, uart->wk_en); + } + + /* Ensure IOPAD wake-enables are set */ + if (cpu_is_omap34xx() && uart->padconf) { + u16 v = omap_ctrl_readw(uart->padconf); + v |= OMAP3_PADCONF_WAKEUPENABLE0; + omap_ctrl_writew(v, uart->padconf); + } +} + +static void omap_uart_disable_wakeup(struct omap_uart_state *uart) +{ + /* Clear wake-enable bit */ + if (uart->wk_en && uart->wk_mask) { + u32 v = __raw_readl(uart->wk_en); + v &= ~uart->wk_mask; + __raw_writel(v, uart->wk_en); + } + + /* Ensure IOPAD wake-enables are cleared */ + if (cpu_is_omap34xx() && uart->padconf) { + u16 v = omap_ctrl_readw(uart->padconf); + v &= ~OMAP3_PADCONF_WAKEUPENABLE0; + omap_ctrl_writew(v, uart->padconf); + } +} + static void omap_uart_smart_idle_enable(struct omap_uart_state *uart, int enable) { @@ -246,6 +317,11 @@ static void omap_uart_block_sleep(struct omap_uart_state *uart) static void omap_uart_allow_sleep(struct omap_uart_state *uart) { + if (device_may_wakeup(&uart->pdev.dev)) + omap_uart_enable_wakeup(uart); + else + omap_uart_disable_wakeup(uart); + if (!uart->clocked) return; @@ -292,7 +368,6 @@ void omap_uart_resume_idle(int num) /* Check for normal UART wakeup */ if (__raw_readl(uart->wk_st) & uart->wk_mask) omap_uart_block_sleep(uart); - return; } } @@ -346,16 +421,13 @@ static irqreturn_t omap_uart_interrupt(int irq, void *dev_id) return IRQ_NONE; } -static u32 sleep_timeout = DEFAULT_TIMEOUT; - static void omap_uart_idle_init(struct omap_uart_state *uart) { - u32 v; struct plat_serial8250_port *p = uart->p; int ret; uart->can_sleep = 0; - uart->timeout = sleep_timeout; + uart->timeout = DEFAULT_TIMEOUT; setup_timer(&uart->timer, omap_uart_idle_timer, (unsigned long) uart); mod_timer(&uart->timer, jiffies + uart->timeout); @@ -413,77 +485,112 @@ static void omap_uart_idle_init(struct omap_uart_state *uart) uart->padconf = 0; } - /* Set wake-enable bit */ - if (uart->wk_en && uart->wk_mask) { - v = __raw_readl(uart->wk_en); - v |= uart->wk_mask; - __raw_writel(v, uart->wk_en); - } - - /* Ensure IOPAD wake-enables are set */ - if (cpu_is_omap34xx() && uart->padconf) { - u16 v; - - v = omap_ctrl_readw(uart->padconf); - v |= OMAP3_PADCONF_WAKEUPENABLE0; - omap_ctrl_writew(v, uart->padconf); - } - - p->flags |= UPF_SHARE_IRQ; + p->irqflags |= IRQF_SHARED; ret = request_irq(p->irq, omap_uart_interrupt, IRQF_SHARED, "serial idle", (void *)uart); WARN_ON(ret); } -static ssize_t sleep_timeout_show(struct kobject *kobj, - struct kobj_attribute *attr, +void omap_uart_enable_irqs(int enable) +{ + int ret; + struct omap_uart_state *uart; + + list_for_each_entry(uart, &uart_list, node) { + if (enable) + ret = request_irq(uart->p->irq, omap_uart_interrupt, + IRQF_SHARED, "serial idle", (void *)uart); + else + free_irq(uart->p->irq, (void *)uart); + } +} + +static ssize_t sleep_timeout_show(struct device *dev, + struct device_attribute *attr, char *buf) { - return sprintf(buf, "%u\n", sleep_timeout / HZ); + struct platform_device *pdev = container_of(dev, + struct platform_device, dev); + struct omap_uart_state *uart = container_of(pdev, + struct omap_uart_state, pdev); + + return sprintf(buf, "%u\n", uart->timeout / HZ); } -static ssize_t sleep_timeout_store(struct kobject *kobj, - struct kobj_attribute *attr, +static ssize_t sleep_timeout_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t n) { - struct omap_uart_state *uart; + struct platform_device *pdev = container_of(dev, + struct platform_device, dev); + struct omap_uart_state *uart = container_of(pdev, + struct omap_uart_state, pdev); unsigned int value; if (sscanf(buf, "%u", &value) != 1) { printk(KERN_ERR "sleep_timeout_store: Invalid value\n"); return -EINVAL; } - sleep_timeout = value * HZ; - list_for_each_entry(uart, &uart_list, node) { - uart->timeout = sleep_timeout; - if (uart->timeout) - mod_timer(&uart->timer, jiffies + uart->timeout); - else - /* A zero value means disable timeout feature */ - omap_uart_block_sleep(uart); - } + + uart->timeout = value * HZ; + if (uart->timeout) + mod_timer(&uart->timer, jiffies + uart->timeout); + else + /* A zero value means disable timeout feature */ + omap_uart_block_sleep(uart); + return n; } -static struct kobj_attribute sleep_timeout_attr = - __ATTR(sleep_timeout, 0644, sleep_timeout_show, sleep_timeout_store); - +DEVICE_ATTR(sleep_timeout, 0644, sleep_timeout_show, sleep_timeout_store); +#define DEV_CREATE_FILE(dev, attr) WARN_ON(device_create_file(dev, attr)) #else static inline void omap_uart_idle_init(struct omap_uart_state *uart) {} +#define DEV_CREATE_FILE(dev, attr) #endif /* CONFIG_PM */ -static struct platform_device serial_device = { - .name = "serial8250", - .id = PLAT8250_DEV_PLATFORM, - .dev = { - .platform_data = serial_platform_data, +static struct omap_uart_state omap_uart[OMAP_MAX_NR_PORTS] = { + { + .pdev = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = serial_platform_data0, + }, + }, + }, { + .pdev = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM1, + .dev = { + .platform_data = serial_platform_data1, + }, + }, + }, { + .pdev = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM2, + .dev = { + .platform_data = serial_platform_data2, + }, + }, }, +#ifdef CONFIG_ARCH_OMAP4 + { + .pdev = { + .name = "serial8250", + .id = 3, + .dev = { + .platform_data = serial_platform_data3, + }, + }, + }, +#endif }; -void __init omap_serial_init(void) +void __init omap_serial_early_init(void) { - int i, err; - const struct omap_uart_config *info; + int i; char name[16]; /* @@ -492,24 +599,11 @@ void __init omap_serial_init(void) * if not needed. */ - info = omap_get_config(OMAP_TAG_UART, struct omap_uart_config); - - if (info == NULL) - return; - if (cpu_is_omap44xx()) { - for (i = 0; i < OMAP_MAX_NR_PORTS; i++) - serial_platform_data[i].irq += 32; - } - for (i = 0; i < OMAP_MAX_NR_PORTS; i++) { - struct plat_serial8250_port *p = serial_platform_data + i; struct omap_uart_state *uart = &omap_uart[i]; - - if (!(info->enabled_uarts & (1 << i))) { - p->membase = NULL; - p->mapbase = 0; - continue; - } + struct platform_device *pdev = &uart->pdev; + struct device *dev = &pdev->dev; + struct plat_serial8250_port *p = dev->platform_data; sprintf(name, "uart%d_ick", i+1); uart->ick = clk_get(NULL, name); @@ -525,26 +619,42 @@ void __init omap_serial_init(void) uart->fck = NULL; } - if (!uart->ick || !uart->fck) - continue; + /* FIXME: Remove this once the clkdev is ready */ + if (!cpu_is_omap44xx()) { + if (!uart->ick || !uart->fck) + continue; + } uart->num = i; p->private_data = uart; uart->p = p; - list_add(&uart->node, &uart_list); + list_add_tail(&uart->node, &uart_list); + + if (cpu_is_omap44xx()) + p->irq += 32; omap_uart_enable_clocks(uart); - omap_uart_reset(uart); - omap_uart_idle_init(uart); } +} - err = platform_device_register(&serial_device); +void __init omap_serial_init(void) +{ + int i; -#ifdef CONFIG_PM - if (!err) - err = sysfs_create_file(&serial_device.dev.kobj, - &sleep_timeout_attr.attr); -#endif + for (i = 0; i < OMAP_MAX_NR_PORTS; i++) { + struct omap_uart_state *uart = &omap_uart[i]; + struct platform_device *pdev = &uart->pdev; + struct device *dev = &pdev->dev; -} + omap_uart_reset(uart); + omap_uart_idle_init(uart); + if (WARN_ON(platform_device_register(pdev))) + continue; + if ((cpu_is_omap34xx() && uart->padconf) || + (uart->wk_en && uart->wk_mask)) { + device_init_wakeup(dev, true); + DEV_CREATE_FILE(dev, &dev_attr_sleep_timeout); + } + } +} diff --git a/arch/arm/mach-omap2/sram242x.S b/arch/arm/mach-omap2/sram242x.S index bb299851116..9b62208658b 100644 --- a/arch/arm/mach-omap2/sram242x.S +++ b/arch/arm/mach-omap2/sram242x.S @@ -128,7 +128,7 @@ omap242x_sdi_prcm_voltctrl: prcm_mask_val: .word 0xFFFF3FFC omap242x_sdi_timer_32ksynct_cr: - .word IO_ADDRESS(OMAP2420_32KSYNCT_BASE + 0x010) + .word OMAP2_IO_ADDRESS(OMAP2420_32KSYNCT_BASE + 0x010) ENTRY(omap242x_sram_ddr_init_sz) .word . - omap242x_sram_ddr_init @@ -224,7 +224,7 @@ omap242x_srs_prcm_voltctrl: ddr_prcm_mask_val: .word 0xFFFF3FFC omap242x_srs_timer_32ksynct: - .word IO_ADDRESS(OMAP2420_32KSYNCT_BASE + 0x010) + .word OMAP2_IO_ADDRESS(OMAP2420_32KSYNCT_BASE + 0x010) ENTRY(omap242x_sram_reprogram_sdrc_sz) .word . - omap242x_sram_reprogram_sdrc diff --git a/arch/arm/mach-omap2/sram243x.S b/arch/arm/mach-omap2/sram243x.S index 9955abcaeb3..df2cd9277c0 100644 --- a/arch/arm/mach-omap2/sram243x.S +++ b/arch/arm/mach-omap2/sram243x.S @@ -128,7 +128,7 @@ omap243x_sdi_prcm_voltctrl: prcm_mask_val: .word 0xFFFF3FFC omap243x_sdi_timer_32ksynct_cr: - .word IO_ADDRESS(OMAP2430_32KSYNCT_BASE + 0x010) + .word OMAP2_IO_ADDRESS(OMAP2430_32KSYNCT_BASE + 0x010) ENTRY(omap243x_sram_ddr_init_sz) .word . - omap243x_sram_ddr_init @@ -224,7 +224,7 @@ omap243x_srs_prcm_voltctrl: ddr_prcm_mask_val: .word 0xFFFF3FFC omap243x_srs_timer_32ksynct: - .word IO_ADDRESS(OMAP2430_32KSYNCT_BASE + 0x010) + .word OMAP2_IO_ADDRESS(OMAP2430_32KSYNCT_BASE + 0x010) ENTRY(omap243x_sram_reprogram_sdrc_sz) .word . - omap243x_sram_reprogram_sdrc diff --git a/arch/arm/mach-omap2/sram34xx.S b/arch/arm/mach-omap2/sram34xx.S index f41f8d96ddb..82aa4a3d160 100644 --- a/arch/arm/mach-omap2/sram34xx.S +++ b/arch/arm/mach-omap2/sram34xx.S @@ -36,7 +36,7 @@ .text -/* r4 parameters */ +/* r1 parameters */ #define SDRC_NO_UNLOCK_DLL 0x0 #define SDRC_UNLOCK_DLL 0x1 @@ -58,7 +58,6 @@ /* SDRC_POWER bit settings */ #define SRFRONIDLEREQ_MASK 0x40 -#define PWDENA_MASK 0x4 /* CM_IDLEST1_CORE bit settings */ #define ST_SDRC_MASK 0x2 @@ -71,41 +70,72 @@ /* * omap3_sram_configure_core_dpll - change DPLL3 M2 divider - * r0 = new SDRC_RFR_CTRL register contents - * r1 = new SDRC_ACTIM_CTRLA register contents - * r2 = new SDRC_ACTIM_CTRLB register contents - * r3 = new M2 divider setting (only 1 and 2 supported right now) - * r4 = unlock SDRC DLL? (1 = yes, 0 = no). Only unlock DLL for + * + * Params passed in registers: + * r0 = new M2 divider setting (only 1 and 2 supported right now) + * r1 = unlock SDRC DLL? (1 = yes, 0 = no). Only unlock DLL for * SDRC rates < 83MHz - * r5 = number of MPU cycles to wait for SDRC to stabilize after + * r2 = number of MPU cycles to wait for SDRC to stabilize after * reprogramming the SDRC when switching to a slower MPU speed - * r6 = new SDRC_MR_0 register value - * r7 = increasing SDRC rate? (1 = yes, 0 = no) + * r3 = increasing SDRC rate? (1 = yes, 0 = no) + * + * Params passed via the stack. The needed params will be copied in SRAM + * before use by the code in SRAM (SDRAM is not accessible during SDRC + * reconfiguration): + * new SDRC_RFR_CTRL_0 register contents + * new SDRC_ACTIM_CTRL_A_0 register contents + * new SDRC_ACTIM_CTRL_B_0 register contents + * new SDRC_MR_0 register value + * new SDRC_RFR_CTRL_1 register contents + * new SDRC_ACTIM_CTRL_A_1 register contents + * new SDRC_ACTIM_CTRL_B_1 register contents + * new SDRC_MR_1 register value * + * If the param SDRC_RFR_CTRL_1 is 0, the parameters + * are not programmed into the SDRC CS1 registers */ ENTRY(omap3_sram_configure_core_dpll) stmfd sp!, {r1-r12, lr} @ store regs to stack - ldr r4, [sp, #52] @ pull extra args off the stack - ldr r5, [sp, #56] @ load extra args from the stack - ldr r6, [sp, #60] @ load extra args from the stack - ldr r7, [sp, #64] @ load extra args from the stack + + @ pull the extra args off the stack + @ and store them in SRAM + ldr r4, [sp, #52] + str r4, omap_sdrc_rfr_ctrl_0_val + ldr r4, [sp, #56] + str r4, omap_sdrc_actim_ctrl_a_0_val + ldr r4, [sp, #60] + str r4, omap_sdrc_actim_ctrl_b_0_val + ldr r4, [sp, #64] + str r4, omap_sdrc_mr_0_val + ldr r4, [sp, #68] + str r4, omap_sdrc_rfr_ctrl_1_val + cmp r4, #0 @ if SDRC_RFR_CTRL_1 is 0, + beq skip_cs1_params @ do not use cs1 params + ldr r4, [sp, #72] + str r4, omap_sdrc_actim_ctrl_a_1_val + ldr r4, [sp, #76] + str r4, omap_sdrc_actim_ctrl_b_1_val + ldr r4, [sp, #80] + str r4, omap_sdrc_mr_1_val +skip_cs1_params: dsb @ flush buffered writes to interconnect - cmp r7, #1 @ if increasing SDRC clk rate, + + cmp r3, #1 @ if increasing SDRC clk rate, bleq configure_sdrc @ program the SDRC regs early (for RFR) - cmp r4, #SDRC_UNLOCK_DLL @ set the intended DLL state + cmp r1, #SDRC_UNLOCK_DLL @ set the intended DLL state bleq unlock_dll blne lock_dll bl sdram_in_selfrefresh @ put SDRAM in self refresh, idle SDRC bl configure_core_dpll @ change the DPLL3 M2 divider + mov r12, r2 + bl wait_clk_stable @ wait for SDRC to stabilize bl enable_sdrc @ take SDRC out of idle - cmp r4, #SDRC_UNLOCK_DLL @ wait for DLL status to change + cmp r1, #SDRC_UNLOCK_DLL @ wait for DLL status to change bleq wait_dll_unlock blne wait_dll_lock - cmp r7, #1 @ if increasing SDRC clk rate, + cmp r3, #1 @ if increasing SDRC clk rate, beq return_to_sdram @ return to SDRAM code, otherwise, bl configure_sdrc @ reprogram SDRC regs now - mov r12, r5 - bl wait_clk_stable @ wait for SDRC to stabilize return_to_sdram: isb @ prevent speculative exec past here mov r0, #0 @ return value @@ -113,7 +143,7 @@ return_to_sdram: unlock_dll: ldr r11, omap3_sdrc_dlla_ctrl ldr r12, [r11] - and r12, r12, #FIXEDDELAY_MASK + bic r12, r12, #FIXEDDELAY_MASK orr r12, r12, #FIXEDDELAY_DEFAULT orr r12, r12, #DLLIDLE_MASK str r12, [r11] @ (no OCP barrier needed) @@ -129,7 +159,6 @@ sdram_in_selfrefresh: ldr r12, [r11] @ read the contents of SDRC_POWER mov r9, r12 @ keep a copy of SDRC_POWER bits orr r12, r12, #SRFRONIDLEREQ_MASK @ enable self refresh on idle - bic r12, r12, #PWDENA_MASK @ clear PWDENA str r12, [r11] @ write back to SDRC_POWER register ldr r12, [r11] @ posted-write barrier for SDRC idle_sdrc: @@ -149,7 +178,7 @@ configure_core_dpll: ldr r12, [r11] ldr r10, core_m2_mask_val @ modify m2 for core dpll and r12, r12, r10 - orr r12, r12, r3, lsl #CORE_DPLL_CLKOUT_DIV_SHIFT + orr r12, r12, r0, lsl #CORE_DPLL_CLKOUT_DIV_SHIFT str r12, [r11] ldr r12, [r11] @ posted-write barrier for CM bx lr @@ -187,15 +216,34 @@ wait_dll_unlock: bne wait_dll_unlock bx lr configure_sdrc: - ldr r11, omap3_sdrc_rfr_ctrl - str r0, [r11] - ldr r11, omap3_sdrc_actim_ctrla - str r1, [r11] - ldr r11, omap3_sdrc_actim_ctrlb - str r2, [r11] + ldr r12, omap_sdrc_rfr_ctrl_0_val @ fetch value from SRAM + ldr r11, omap3_sdrc_rfr_ctrl_0 @ fetch addr from SRAM + str r12, [r11] @ store + ldr r12, omap_sdrc_actim_ctrl_a_0_val + ldr r11, omap3_sdrc_actim_ctrl_a_0 + str r12, [r11] + ldr r12, omap_sdrc_actim_ctrl_b_0_val + ldr r11, omap3_sdrc_actim_ctrl_b_0 + str r12, [r11] + ldr r12, omap_sdrc_mr_0_val ldr r11, omap3_sdrc_mr_0 - str r6, [r11] - ldr r6, [r11] @ posted-write barrier for SDRC + str r12, [r11] + ldr r12, omap_sdrc_rfr_ctrl_1_val + cmp r12, #0 @ if SDRC_RFR_CTRL_1 is 0, + beq skip_cs1_prog @ do not program cs1 params + ldr r11, omap3_sdrc_rfr_ctrl_1 + str r12, [r11] + ldr r12, omap_sdrc_actim_ctrl_a_1_val + ldr r11, omap3_sdrc_actim_ctrl_a_1 + str r12, [r11] + ldr r12, omap_sdrc_actim_ctrl_b_1_val + ldr r11, omap3_sdrc_actim_ctrl_b_1 + str r12, [r11] + ldr r12, omap_sdrc_mr_1_val + ldr r11, omap3_sdrc_mr_1 + str r12, [r11] +skip_cs1_prog: + ldr r12, [r11] @ posted-write barrier for SDRC bx lr omap3_sdrc_power: @@ -206,14 +254,40 @@ omap3_cm_idlest1_core: .word OMAP34XX_CM_REGADDR(CORE_MOD, CM_IDLEST) omap3_cm_iclken1_core: .word OMAP34XX_CM_REGADDR(CORE_MOD, CM_ICLKEN1) -omap3_sdrc_rfr_ctrl: + +omap3_sdrc_rfr_ctrl_0: .word OMAP34XX_SDRC_REGADDR(SDRC_RFR_CTRL_0) -omap3_sdrc_actim_ctrla: +omap3_sdrc_rfr_ctrl_1: + .word OMAP34XX_SDRC_REGADDR(SDRC_RFR_CTRL_1) +omap3_sdrc_actim_ctrl_a_0: .word OMAP34XX_SDRC_REGADDR(SDRC_ACTIM_CTRL_A_0) -omap3_sdrc_actim_ctrlb: +omap3_sdrc_actim_ctrl_a_1: + .word OMAP34XX_SDRC_REGADDR(SDRC_ACTIM_CTRL_A_1) +omap3_sdrc_actim_ctrl_b_0: .word OMAP34XX_SDRC_REGADDR(SDRC_ACTIM_CTRL_B_0) +omap3_sdrc_actim_ctrl_b_1: + .word OMAP34XX_SDRC_REGADDR(SDRC_ACTIM_CTRL_B_1) omap3_sdrc_mr_0: .word OMAP34XX_SDRC_REGADDR(SDRC_MR_0) +omap3_sdrc_mr_1: + .word OMAP34XX_SDRC_REGADDR(SDRC_MR_1) +omap_sdrc_rfr_ctrl_0_val: + .word 0xDEADBEEF +omap_sdrc_rfr_ctrl_1_val: + .word 0xDEADBEEF +omap_sdrc_actim_ctrl_a_0_val: + .word 0xDEADBEEF +omap_sdrc_actim_ctrl_a_1_val: + .word 0xDEADBEEF +omap_sdrc_actim_ctrl_b_0_val: + .word 0xDEADBEEF +omap_sdrc_actim_ctrl_b_1_val: + .word 0xDEADBEEF +omap_sdrc_mr_0_val: + .word 0xDEADBEEF +omap_sdrc_mr_1_val: + .word 0xDEADBEEF + omap3_sdrc_dlla_status: .word OMAP34XX_SDRC_REGADDR(SDRC_DLLA_STATUS) omap3_sdrc_dlla_ctrl: @@ -223,3 +297,4 @@ core_m2_mask_val: ENTRY(omap3_sram_configure_core_dpll_sz) .word . - omap3_sram_configure_core_dpll + diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c index 97eeeebcb06..e2338c0aebc 100644 --- a/arch/arm/mach-omap2/timer-gp.c +++ b/arch/arm/mach-omap2/timer-gp.c @@ -231,7 +231,7 @@ static void __init omap2_gp_clocksource_init(void) static void __init omap2_gp_timer_init(void) { #ifdef CONFIG_LOCAL_TIMERS - twd_base = IO_ADDRESS(OMAP44XX_LOCAL_TWD_BASE); + twd_base = OMAP2_IO_ADDRESS(OMAP44XX_LOCAL_TWD_BASE); #endif omap_dm_timer_init(); diff --git a/arch/arm/mach-omap2/usb-musb.c b/arch/arm/mach-omap2/usb-musb.c index d85296dc896..1145a2562b0 100644 --- a/arch/arm/mach-omap2/usb-musb.c +++ b/arch/arm/mach-omap2/usb-musb.c @@ -31,15 +31,6 @@ #include <mach/mux.h> #include <mach/usb.h> -#define OTG_SYSCONFIG (OMAP34XX_HSUSB_OTG_BASE + 0x404) - -static void __init usb_musb_pm_init(void) -{ - /* Ensure force-idle mode for OTG controller */ - if (cpu_is_omap34xx()) - omap_writel(0, OTG_SYSCONFIG); -} - #ifdef CONFIG_USB_MUSB_SOC static struct resource musb_resources[] = { @@ -155,20 +146,6 @@ static struct platform_device musb_device = { .resource = musb_resources, }; -#ifdef CONFIG_NOP_USB_XCEIV -static u64 nop_xceiv_dmamask = DMA_BIT_MASK(32); - -static struct platform_device nop_xceiv_device = { - .name = "nop_usb_xceiv", - .id = -1, - .dev = { - .dma_mask = &nop_xceiv_dmamask, - .coherent_dma_mask = DMA_BIT_MASK(32), - .platform_data = NULL, - }, -}; -#endif - void __init usb_musb_init(void) { if (cpu_is_omap243x()) @@ -183,24 +160,14 @@ void __init usb_musb_init(void) */ musb_plat.clock = "ick"; -#ifdef CONFIG_NOP_USB_XCEIV - if (platform_device_register(&nop_xceiv_device) < 0) { - printk(KERN_ERR "Unable to register NOP-XCEIV device\n"); - return; - } -#endif - if (platform_device_register(&musb_device) < 0) { printk(KERN_ERR "Unable to register HS-USB (MUSB) device\n"); return; } - - usb_musb_pm_init(); } #else void __init usb_musb_init(void) { - usb_musb_pm_init(); } #endif /* CONFIG_USB_MUSB_SOC */ |