diff options
Diffstat (limited to 'arch/arm/mach-omap2')
47 files changed, 3600 insertions, 276 deletions
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index a755eb5e2361..75b1c7efae7e 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 735bae5b0dec..8cb16777661a 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 8ec2a132904d..42217b32f835 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) { + 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 ac262cd74503..bd57ec76dc5e 100644 --- a/arch/arm/mach-omap2/board-3430sdp.c +++ b/arch/arm/mach-omap2/board-3430sdp.c @@ -167,26 +167,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, NULL); - 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 +475,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 +495,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 b0c7402248f7..eb37c40ea83a 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,14 +47,13 @@ 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) diff --git a/arch/arm/mach-omap2/board-apollon.c b/arch/arm/mach-omap2/board-apollon.c index b4d4ef6d90b9..a1132288c701 100644 --- a/arch/arm/mach-omap2/board-apollon.c +++ b/arch/arm/mach-omap2/board-apollon.c @@ -248,18 +248,6 @@ out: clk_put(gpmc_fck); } -static void __init omap_apollon_init_irq(void) -{ - omap2_init_common_hw(NULL, 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 fd00aa03690c..2e09a1c444cb 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) { + 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 7b1d61d5bb2c..eaa02d012c5c 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, 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 ea383f88cb1b..ec6854cbdd9f 100644 --- a/arch/arm/mach-omap2/board-ldp.c +++ b/arch/arm/mach-omap2/board-ldp.c @@ -268,18 +268,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, 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 +278,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 +374,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 000000000000..8341632d260b --- /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 e00ba128cece..500c9956876d 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, @@ -249,11 +245,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,17 +281,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, - 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", @@ -345,10 +335,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, @@ -398,8 +400,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); diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c index c4b144647dc5..d50b9be90580 100644 --- a/arch/arm/mach-omap2/board-omap3evm.c +++ b/arch/arm/mach-omap2/board-omap3evm.c @@ -92,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, @@ -278,19 +274,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) { + 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, @@ -301,8 +298,6 @@ 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)); diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c index 864ee3d021f7..b43f6e36b6d9 100644 --- a/arch/arm/mach-omap2/board-omap3pandora.c +++ b/arch/arm/mach-omap2/board-omap3pandora.c @@ -213,10 +213,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", }; @@ -309,14 +305,6 @@ static int __init omap3pandora_i2c_init(void) return 0; } -static void __init omap3pandora_init_irq(void) -{ - omap2_init_common_hw(mt46h32m32lf6_sdrc_params, - mt46h32m32lf6_sdrc_params); - omap_init_irq(); - omap_gpio_init(); -} - static void __init omap3pandora_ads7846_init(void) { int gpio = OMAP3_PANDORA_TS_GPIO; @@ -376,10 +364,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, @@ -391,8 +388,6 @@ 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)); diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c index 6bce23004aa4..9917d2fddc2f 100644 --- a/arch/arm/mach-omap2/board-overo.c +++ b/arch/arm/mach-omap2/board-overo.c @@ -271,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[] = { { @@ -360,14 +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, - mt46h32m32lf6_sdrc_params); - omap_init_irq(); - omap_gpio_init(); -} - static struct platform_device overo_lcd_device = { .name = "overo_lcd", .id = -1, @@ -378,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, }; @@ -390,8 +388,6 @@ 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(); diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c index 56d931a425f7..e70baa799018 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 * @@ -282,7 +282,124 @@ static struct twl4030_usb_data rx51_usb_data = { .usb_mode = T2_USB_MODE_ULPI, }; -static struct twl4030_platform_data rx51_twldata = { +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, @@ -291,6 +408,7 @@ static struct twl4030_platform_data rx51_twldata = { .keypad = &rx51_kp_data, .madc = &rx51_madc_data, .usb = &rx51_usb_data, + .power = &rx51_t2scripts_data, .vaux1 = &rx51_vaux1, .vaux2 = &rx51_vaux2, diff --git a/arch/arm/mach-omap2/board-rx51.c b/arch/arm/mach-omap2/board-rx51.c index 1c9e07fe8266..f9196c3b1a7b 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,6 +56,8 @@ static struct omap_board_config_kernel rx51_config[] = { static void __init rx51_init_irq(void) { + 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,8 +67,6 @@ 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(); diff --git a/arch/arm/mach-omap2/board-zoom-debugboard.c b/arch/arm/mach-omap2/board-zoom-debugboard.c index bac5c4321ff7..1f13e2a1f322 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 427b7b8b1237..324009edbd53 100644 --- a/arch/arm/mach-omap2/board-zoom2.c +++ b/arch/arm/mach-omap2/board-zoom2.c @@ -12,36 +12,217 @@ #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 zoom2_twl4030_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 twl4030_keypad_data zoom2_kp_twl4030_data = { + .rows = 8, + .cols = 8, + .keymap = zoom2_twl4030_keymap, + .keymapsize = ARRAY_SIZE(zoom2_twl4030_keymap), + .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, 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 +230,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 +259,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 456e2ad5f621..f2a92d614f0f 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -1043,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/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c index cd7819cc0c9e..fafcd32e6907 100644 --- a/arch/arm/mach-omap2/clock34xx.c +++ b/arch/arm/mach-omap2/clock34xx.c @@ -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> @@ -1067,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; } @@ -1136,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 57cc2725b923..c8119781e00a 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", @@ -1622,7 +1618,6 @@ 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, }; @@ -1691,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, }; @@ -2089,7 +2083,6 @@ 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", @@ -2100,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", @@ -2111,7 +2103,6 @@ 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", @@ -2123,7 +2114,6 @@ static struct clk dss_ick_3430es1 = { .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", @@ -2135,7 +2125,6 @@ static struct clk dss_ick_3430es2 = { .name = "dss_ick", .ops = &clkops_omap3430es2_dss_usbhost_wait, .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", @@ -2159,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", @@ -2170,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", @@ -2183,7 +2170,6 @@ static struct clk usbhost_120m_fck = { .name = "usbhost_120m_fck", .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", @@ -2194,7 +2180,6 @@ static struct clk usbhost_48m_fck = { .name = "usbhost_48m_fck", .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", @@ -2206,7 +2191,6 @@ static struct clk usbhost_ick = { .name = "usbhost_ick", .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", @@ -2268,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, @@ -2383,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, }; @@ -2392,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 0e7d501865b6..4ef7b4f5474e 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 000000000000..8eb2dab8c7db --- /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 f3c91a1ca391..cfd0b726ba44 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 @@ -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 000000000000..e4ebd6d53135 --- /dev/null +++ b/arch/arm/mach-omap2/cm4xxx.c @@ -0,0 +1,68 @@ +/* + * 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" +#include "cm-regbits-4xxx.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) +{ + int i = 0; + u8 cm_id; + u16 prcm_mod_offs; + u32 mask = OMAP4_PRCM_CM_CLKCTRL_IDLEST_MASK; + + cm_id = prcm_mod >> OMAP4_PRCM_MOD_CM_ID_SHIFT; + prcm_mod_offs = prcm_mod & OMAP4_PRCM_MOD_OFFS_MASK; + + while (((omap4_cm_read_mod_reg(cm_id, prcm_mod_offs, prcm_dev_offs, + OMAP4_CM_CLKCTRL_DREG) & mask) != 0) && + (i++ < MAX_MODULE_READY_TIME)) + udelay(1); + + return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY; +} + diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index 894cc355818a..a2e915639b72 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c @@ -513,6 +513,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, diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index e9b9bcb19b4e..7574b6f20e8e 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. @@ -279,11 +285,26 @@ static int __init _omap2_init_reprogram_sdrc(void) void __init omap2_init_common_hw(struct omap_sdrc_params *sdrc_cs0, struct omap_sdrc_params *sdrc_cs1) { + 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; + + omap_hwmod_init(hwmods); omap2_mux_init(); #ifndef CONFIG_ARCH_OMAP4 /* FIXME: Remove this once the clkdev is ready */ + /* The OPP tables have to be registered before a clk 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(); + omap_serial_early_init(); + omap_hwmod_late_init(); + omap_pm_if_init(); omap2_sdrc_init(sdrc_cs0, sdrc_cs1); _omap2_init_reprogram_sdrc(); #endif diff --git a/arch/arm/mach-omap2/iommu2.c b/arch/arm/mach-omap2/iommu2.c index 015f22a53ead..2d9b5cc981cd 100644 --- a/arch/arm/mach-omap2/iommu2.c +++ b/arch/arm/mach-omap2/iommu2.c @@ -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/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c index 99b6e1546311..a846aa1ebb4d 100644 --- a/arch/arm/mach-omap2/mcbsp.c +++ b/arch/arm/mach-omap2/mcbsp.c @@ -128,6 +128,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = { .rx_irq = INT_24XX_MCBSP1_IRQ_RX, .tx_irq = INT_24XX_MCBSP1_IRQ_TX, .ops = &omap2_mcbsp_ops, + .buffer_size = 0x6F, }, { .phys_base = OMAP34XX_MCBSP2_BASE, @@ -136,6 +137,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = { .rx_irq = INT_24XX_MCBSP2_IRQ_RX, .tx_irq = INT_24XX_MCBSP2_IRQ_TX, .ops = &omap2_mcbsp_ops, + .buffer_size = 0x3FF, }, { .phys_base = OMAP34XX_MCBSP3_BASE, @@ -144,6 +146,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = { .rx_irq = INT_24XX_MCBSP3_IRQ_RX, .tx_irq = INT_24XX_MCBSP3_IRQ_TX, .ops = &omap2_mcbsp_ops, + .buffer_size = 0x6F, }, { .phys_base = OMAP34XX_MCBSP4_BASE, @@ -152,6 +155,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = { .rx_irq = INT_24XX_MCBSP4_IRQ_RX, .tx_irq = INT_24XX_MCBSP4_IRQ_TX, .ops = &omap2_mcbsp_ops, + .buffer_size = 0x6F, }, { .phys_base = OMAP34XX_MCBSP5_BASE, @@ -160,6 +164,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = { .rx_irq = INT_24XX_MCBSP5_IRQ_RX, .tx_irq = INT_24XX_MCBSP5_IRQ_TX, .ops = &omap2_mcbsp_ops, + .buffer_size = 0x6F, }, }; #define OMAP34XX_MCBSP_PDATA_SZ ARRAY_SIZE(omap34xx_mcbsp_pdata) @@ -168,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()) @@ -176,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); @@ -191,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/mux.c b/arch/arm/mach-omap2/mux.c index 43d6b92b65f2..2daa595aaff4 100644 --- a/arch/arm/mach-omap2/mux.c +++ b/arch/arm/mach-omap2/mux.c @@ -492,6 +492,61 @@ 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 8fe8d230f21b..48ee295db275 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 000000000000..d2e0f1c95961 --- /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 000000000000..767e4965ac4e --- /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 000000000000..a412be6420ec --- /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 000000000000..1e069f831575 --- /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 6cc375a275be..1b4c1600f8d8 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 21201cd4117b..8400f5768923 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h @@ -11,12 +11,23 @@ #ifndef __ARCH_ARM_MACH_OMAP2_PM_H #define __ARCH_ARM_MACH_OMAP2_PM_H +#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 528dbdc26e23..bff5c4e89742 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 | diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 488d595d8e4b..0ff5a6c53aa0 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -170,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); @@ -182,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(); + } /* @@ -271,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: @@ -658,14 +664,38 @@ static void __init prcm_setup_regs(void) 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; @@ -683,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); @@ -716,13 +746,13 @@ static 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) { diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 983f1cb676be..2594cbff3947 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/prm.h b/arch/arm/mach-omap2/prm.h index 9937e2814696..03c467c35f54 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.h b/arch/arm/mach-omap2/sdrc.h index 1a8bbd094066..0837eda5f2b6 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 a7421a50410b..3a529c77daa8 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -73,7 +73,7 @@ static LIST_HEAD(uart_list); 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, @@ -87,7 +87,7 @@ static struct plat_serial8250_port serial_platform_data0[] = { static struct plat_serial8250_port serial_platform_data1[] = { { - .membase = IO_ADDRESS(OMAP_UART2_BASE), + .membase = OMAP2_IO_ADDRESS(OMAP_UART2_BASE), .mapbase = OMAP_UART2_BASE, .irq = 73, .flags = UPF_BOOT_AUTOCONF, @@ -101,7 +101,7 @@ static struct plat_serial8250_port serial_platform_data1[] = { static struct plat_serial8250_port serial_platform_data2[] = { { - .membase = IO_ADDRESS(OMAP_UART3_BASE), + .membase = OMAP2_IO_ADDRESS(OMAP_UART3_BASE), .mapbase = OMAP_UART3_BASE, .irq = 74, .flags = UPF_BOOT_AUTOCONF, @@ -109,10 +109,35 @@ static struct plat_serial8250_port serial_platform_data2[] = { .regshift = 2, .uartclk = OMAP24XX_BASE_BAUD * 16, }, { +#ifdef CONFIG_ARCH_OMAP4 + .membase = 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 = 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) { @@ -460,7 +485,7 @@ static void omap_uart_idle_init(struct omap_uart_state *uart) uart->padconf = 0; } - 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); @@ -550,12 +575,22 @@ static struct omap_uart_state omap_uart[OMAP_MAX_NR_PORTS] = { }, }, }, +#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; - const struct omap_uart_config *info; char name[16]; /* @@ -564,23 +599,12 @@ void __init omap_serial_init(void) * if not needed. */ - info = omap_get_config(OMAP_TAG_UART, struct omap_uart_config); - - if (info == NULL) - return; - 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; struct plat_serial8250_port *p = dev->platform_data; - if (!(info->enabled_uarts & (1 << i))) { - p->membase = NULL; - p->mapbase = 0; - continue; - } - sprintf(name, "uart%d_ick", i+1); uart->ick = clk_get(NULL, name); if (IS_ERR(uart->ick)) { @@ -595,8 +619,11 @@ 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; @@ -607,6 +634,18 @@ void __init omap_serial_init(void) p->irq += 32; omap_uart_enable_clocks(uart); + } +} + +void __init omap_serial_init(void) +{ + int i; + + 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); diff --git a/arch/arm/mach-omap2/sram242x.S b/arch/arm/mach-omap2/sram242x.S index bb299851116d..9b62208658bc 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 9955abcaeb31..df2cd9277c00 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/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c index 97eeeebcb066..e2338c0aebcf 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 739e59e8025c..1145a2562b0f 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[] = { @@ -173,13 +164,10 @@ void __init usb_musb_init(void) 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 */ |