diff options
Diffstat (limited to 'arch/arm/plat-omap')
-rw-r--r-- | arch/arm/plat-omap/Kconfig | 4 | ||||
-rw-r--r-- | arch/arm/plat-omap/Makefile | 6 | ||||
-rw-r--r-- | arch/arm/plat-omap/clock.c | 67 | ||||
-rw-r--r-- | arch/arm/plat-omap/devices.c | 143 | ||||
-rw-r--r-- | arch/arm/plat-omap/dma.c | 6 | ||||
-rw-r--r-- | arch/arm/plat-omap/dmtimer.c | 26 | ||||
-rw-r--r-- | arch/arm/plat-omap/fb.c | 80 | ||||
-rw-r--r-- | arch/arm/plat-omap/gpio.c | 86 | ||||
-rw-r--r-- | arch/arm/plat-omap/mcbsp.c | 345 | ||||
-rw-r--r-- | arch/arm/plat-omap/ocpi.c | 3 | ||||
-rw-r--r-- | arch/arm/plat-omap/pm.c | 1 | ||||
-rw-r--r-- | arch/arm/plat-omap/sleep.S | 452 | ||||
-rw-r--r-- | arch/arm/plat-omap/sram.c | 143 | ||||
-rw-r--r-- | arch/arm/plat-omap/timer32k.c | 325 |
14 files changed, 1104 insertions, 583 deletions
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index 0887bb2a2551..ec49495e651e 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -70,13 +70,13 @@ config OMAP_MPU_TIMER config OMAP_32K_TIMER bool "Use 32KHz timer" - depends on ARCH_OMAP16XX + depends on ARCH_OMAP16XX || ARCH_OMAP24XX help Select this option if you want to enable the OMAP 32KHz timer. This timer saves power compared to the OMAP_MPU_TIMER, and has support for no tick during idle. The 32KHz timer provides less intra-tick resolution than OMAP_MPU_TIMER. The 32KHz timer is - currently only available for OMAP-16xx. + currently only available for OMAP16XX and 24XX. endchoice diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile index 9ccf1943fc94..2896b4546411 100644 --- a/arch/arm/plat-omap/Makefile +++ b/arch/arm/plat-omap/Makefile @@ -3,16 +3,16 @@ # # Common support -obj-y := common.o sram.o sram-fn.o clock.o devices.o dma.o mux.o gpio.o mcbsp.o usb.o +obj-y := common.o sram.o sram-fn.o clock.o devices.o dma.o mux.o gpio.o mcbsp.o usb.o fb.o obj-m := obj-n := obj- := +obj-$(CONFIG_OMAP_32K_TIMER) += timer32k.o + # OCPI interconnect support for 1710, 1610 and 5912 obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o -# Power Management -obj-$(CONFIG_PM) += pm.o sleep.o obj-$(CONFIG_CPU_FREQ) += cpu-omap.o obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c index 3c2bfc0efdaf..06485c193ee3 100644 --- a/arch/arm/plat-omap/clock.c +++ b/arch/arm/plat-omap/clock.c @@ -21,6 +21,7 @@ #include <linux/string.h> #include <linux/clk.h> #include <linux/mutex.h> +#include <linux/platform_device.h> #include <asm/io.h> #include <asm/semaphore.h> @@ -37,17 +38,37 @@ static struct clk_functions *arch_clock; * Standard clock functions defined in include/linux/clk.h *-------------------------------------------------------------------------*/ +/* + * Returns a clock. Note that we first try to use device id on the bus + * and clock name. If this fails, we try to use clock name only. + */ struct clk * clk_get(struct device *dev, const char *id) { struct clk *p, *clk = ERR_PTR(-ENOENT); + int idno; + + if (dev == NULL || dev->bus != &platform_bus_type) + idno = -1; + else + idno = to_platform_device(dev)->id; mutex_lock(&clocks_mutex); + + list_for_each_entry(p, &clocks, node) { + if (p->id == idno && + strcmp(id, p->name) == 0 && try_module_get(p->owner)) { + clk = p; + break; + } + } + list_for_each_entry(p, &clocks, node) { if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) { clk = p; break; } } + mutex_unlock(&clocks_mutex); return clk; @@ -59,6 +80,9 @@ int clk_enable(struct clk *clk) unsigned long flags; int ret = 0; + if (clk == NULL || IS_ERR(clk)) + return -EINVAL; + spin_lock_irqsave(&clockfw_lock, flags); if (arch_clock->clk_enable) ret = arch_clock->clk_enable(clk); @@ -72,6 +96,9 @@ void clk_disable(struct clk *clk) { unsigned long flags; + if (clk == NULL || IS_ERR(clk)) + return; + spin_lock_irqsave(&clockfw_lock, flags); if (arch_clock->clk_disable) arch_clock->clk_disable(clk); @@ -84,6 +111,9 @@ int clk_get_usecount(struct clk *clk) unsigned long flags; int ret = 0; + if (clk == NULL || IS_ERR(clk)) + return 0; + spin_lock_irqsave(&clockfw_lock, flags); ret = clk->usecount; spin_unlock_irqrestore(&clockfw_lock, flags); @@ -97,6 +127,9 @@ unsigned long clk_get_rate(struct clk *clk) unsigned long flags; unsigned long ret = 0; + if (clk == NULL || IS_ERR(clk)) + return 0; + spin_lock_irqsave(&clockfw_lock, flags); ret = clk->rate; spin_unlock_irqrestore(&clockfw_lock, flags); @@ -121,6 +154,9 @@ long clk_round_rate(struct clk *clk, unsigned long rate) unsigned long flags; long ret = 0; + if (clk == NULL || IS_ERR(clk)) + return ret; + spin_lock_irqsave(&clockfw_lock, flags); if (arch_clock->clk_round_rate) ret = arch_clock->clk_round_rate(clk, rate); @@ -133,7 +169,10 @@ EXPORT_SYMBOL(clk_round_rate); int clk_set_rate(struct clk *clk, unsigned long rate) { unsigned long flags; - int ret = 0; + int ret = -EINVAL; + + if (clk == NULL || IS_ERR(clk)) + return ret; spin_lock_irqsave(&clockfw_lock, flags); if (arch_clock->clk_set_rate) @@ -147,7 +186,10 @@ EXPORT_SYMBOL(clk_set_rate); int clk_set_parent(struct clk *clk, struct clk *parent) { unsigned long flags; - int ret = 0; + int ret = -EINVAL; + + if (clk == NULL || IS_ERR(clk) || parent == NULL || IS_ERR(parent)) + return ret; spin_lock_irqsave(&clockfw_lock, flags); if (arch_clock->clk_set_parent) @@ -163,6 +205,9 @@ struct clk *clk_get_parent(struct clk *clk) unsigned long flags; struct clk * ret = NULL; + if (clk == NULL || IS_ERR(clk)) + return ret; + spin_lock_irqsave(&clockfw_lock, flags); if (arch_clock->clk_get_parent) ret = arch_clock->clk_get_parent(clk); @@ -199,6 +244,9 @@ __setup("mpurate=", omap_clk_setup); /* Used for clocks that always have same value as the parent clock */ void followparent_recalc(struct clk *clk) { + if (clk == NULL || IS_ERR(clk)) + return; + clk->rate = clk->parent->rate; } @@ -207,6 +255,9 @@ void propagate_rate(struct clk * tclk) { struct clk *clkp; + if (tclk == NULL || IS_ERR(tclk)) + return; + list_for_each_entry(clkp, &clocks, node) { if (likely(clkp->parent != tclk)) continue; @@ -217,6 +268,9 @@ void propagate_rate(struct clk * tclk) int clk_register(struct clk *clk) { + if (clk == NULL || IS_ERR(clk)) + return -EINVAL; + mutex_lock(&clocks_mutex); list_add(&clk->node, &clocks); if (clk->init) @@ -229,6 +283,9 @@ EXPORT_SYMBOL(clk_register); void clk_unregister(struct clk *clk) { + if (clk == NULL || IS_ERR(clk)) + return; + mutex_lock(&clocks_mutex); list_del(&clk->node); mutex_unlock(&clocks_mutex); @@ -239,6 +296,9 @@ void clk_deny_idle(struct clk *clk) { unsigned long flags; + if (clk == NULL || IS_ERR(clk)) + return; + spin_lock_irqsave(&clockfw_lock, flags); if (arch_clock->clk_deny_idle) arch_clock->clk_deny_idle(clk); @@ -250,6 +310,9 @@ void clk_allow_idle(struct clk *clk) { unsigned long flags; + if (clk == NULL || IS_ERR(clk)) + return; + spin_lock_irqsave(&clockfw_lock, flags); if (arch_clock->clk_allow_idle) arch_clock->clk_allow_idle(clk); diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c index 9dcce904b608..079b67deac0f 100644 --- a/arch/arm/plat-omap/devices.c +++ b/arch/arm/plat-omap/devices.c @@ -24,6 +24,7 @@ #include <asm/arch/board.h> #include <asm/arch/mux.h> #include <asm/arch/gpio.h> +#include <asm/arch/menelaus.h> void omap_nop_release(struct device *dev) @@ -98,6 +99,62 @@ static inline void omap_init_i2c(void) {} #endif /*-------------------------------------------------------------------------*/ +#if defined(CONFIG_KEYBOARD_OMAP) || defined(CONFIG_KEYBOARD_OMAP_MODULE) + +static void omap_init_kp(void) +{ + if (machine_is_omap_h2() || machine_is_omap_h3()) { + omap_cfg_reg(F18_1610_KBC0); + omap_cfg_reg(D20_1610_KBC1); + omap_cfg_reg(D19_1610_KBC2); + omap_cfg_reg(E18_1610_KBC3); + omap_cfg_reg(C21_1610_KBC4); + + omap_cfg_reg(G18_1610_KBR0); + omap_cfg_reg(F19_1610_KBR1); + omap_cfg_reg(H14_1610_KBR2); + omap_cfg_reg(E20_1610_KBR3); + omap_cfg_reg(E19_1610_KBR4); + omap_cfg_reg(N19_1610_KBR5); + } else if (machine_is_omap_perseus2()) { + omap_cfg_reg(E2_730_KBR0); + omap_cfg_reg(J7_730_KBR1); + omap_cfg_reg(E1_730_KBR2); + omap_cfg_reg(F3_730_KBR3); + omap_cfg_reg(D2_730_KBR4); + + omap_cfg_reg(C2_730_KBC0); + omap_cfg_reg(D3_730_KBC1); + omap_cfg_reg(E4_730_KBC2); + omap_cfg_reg(F4_730_KBC3); + omap_cfg_reg(E3_730_KBC4); + } else if (machine_is_omap_h4()) { + omap_cfg_reg(T19_24XX_KBR0); + omap_cfg_reg(R19_24XX_KBR1); + omap_cfg_reg(V18_24XX_KBR2); + omap_cfg_reg(M21_24XX_KBR3); + omap_cfg_reg(E5__24XX_KBR4); + if (omap_has_menelaus()) { + omap_cfg_reg(B3__24XX_KBR5); + omap_cfg_reg(AA4_24XX_KBC2); + omap_cfg_reg(B13_24XX_KBC6); + } else { + omap_cfg_reg(M18_24XX_KBR5); + omap_cfg_reg(H19_24XX_KBC2); + omap_cfg_reg(N19_24XX_KBC6); + } + omap_cfg_reg(R20_24XX_KBC0); + omap_cfg_reg(M14_24XX_KBC1); + omap_cfg_reg(V17_24XX_KBC3); + omap_cfg_reg(P21_24XX_KBC4); + omap_cfg_reg(L14_24XX_KBC5); + } +} +#else +static inline void omap_init_kp(void) {} +#endif + +/*-------------------------------------------------------------------------*/ #if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) @@ -240,6 +297,55 @@ static void __init omap_init_mmc(void) static inline void omap_init_mmc(void) {} #endif +/*-------------------------------------------------------------------------*/ + +/* Numbering for the SPI-capable controllers when used for SPI: + * spi = 1 + * uwire = 2 + * mmc1..2 = 3..4 + * mcbsp1..3 = 5..7 + */ + +#if defined(CONFIG_SPI_OMAP_UWIRE) || defined(CONFIG_SPI_OMAP_UWIRE_MODULE) + +#define OMAP_UWIRE_BASE 0xfffb3000 + +static struct resource uwire_resources[] = { + { + .start = OMAP_UWIRE_BASE, + .end = OMAP_UWIRE_BASE + 0x20, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device omap_uwire_device = { + .name = "omap_uwire", + .id = -1, + .dev = { + .release = omap_nop_release, + }, + .num_resources = ARRAY_SIZE(uwire_resources), + .resource = uwire_resources, +}; + +static void omap_init_uwire(void) +{ + /* FIXME define and use a boot tag; not all boards will be hooking + * up devices to the microwire controller, and multi-board configs + * mean that CONFIG_SPI_OMAP_UWIRE may be configured anyway... + */ + + /* board-specific code must configure chipselects (only a few + * are normally used) and SCLK/SDI/SDO (each has two choices). + */ + (void) platform_device_register(&omap_uwire_device); +} +#else +static inline void omap_init_uwire(void) {} +#endif + +/*-------------------------------------------------------------------------*/ + #if defined(CONFIG_OMAP_WATCHDOG) || defined(CONFIG_OMAP_WATCHDOG_MODULE) #ifdef CONFIG_ARCH_OMAP24XX @@ -310,40 +416,6 @@ static void omap_init_rng(void) static inline void omap_init_rng(void) {} #endif -#if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE) - -static struct omap_lcd_config omap_fb_conf; - -static u64 omap_fb_dma_mask = ~(u32)0; - -static struct platform_device omap_fb_device = { - .name = "omapfb", - .id = -1, - .dev = { - .release = omap_nop_release, - .dma_mask = &omap_fb_dma_mask, - .coherent_dma_mask = ~(u32)0, - .platform_data = &omap_fb_conf, - }, - .num_resources = 0, -}; - -static inline void omap_init_fb(void) -{ - const struct omap_lcd_config *conf; - - conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config); - if (conf != NULL) - omap_fb_conf = *conf; - platform_device_register(&omap_fb_device); -} - -#else - -static inline void omap_init_fb(void) {} - -#endif - /* * This gets called after board-specific INIT_MACHINE, and initializes most * on-chip peripherals accessible on this board (except for few like USB): @@ -369,9 +441,10 @@ static int __init omap_init_devices(void) /* please keep these calls, and their implementations above, * in alphabetical order so they're easier to sort through. */ - omap_init_fb(); omap_init_i2c(); + omap_init_kp(); omap_init_mmc(); + omap_init_uwire(); omap_init_wdt(); omap_init_rng(); diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c index a4e5ac77f6df..5dac4230360d 100644 --- a/arch/arm/plat-omap/dma.c +++ b/arch/arm/plat-omap/dma.c @@ -1258,6 +1258,11 @@ void omap_stop_lcd_dma(void) omap_writew(w, OMAP1610_DMA_LCD_CTRL); } +int omap_lcd_dma_ext_running(void) +{ + return lcd_dma.ext_ctrl && lcd_dma.active; +} + /*----------------------------------------------------------------------------*/ static int __init omap_init_dma(void) @@ -1389,6 +1394,7 @@ EXPORT_SYMBOL(omap_free_lcd_dma); EXPORT_SYMBOL(omap_enable_lcd_dma); EXPORT_SYMBOL(omap_setup_lcd_dma); EXPORT_SYMBOL(omap_stop_lcd_dma); +EXPORT_SYMBOL(omap_lcd_dma_ext_running); EXPORT_SYMBOL(omap_set_lcd_dma_b1); EXPORT_SYMBOL(omap_set_lcd_dma_single_transfer); EXPORT_SYMBOL(omap_set_lcd_dma_ext_controller); diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index 38d7ebf87920..eba3cb52ad87 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -97,6 +97,32 @@ int omap_dm_timers_active(void) } +/** + * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR + * @inputmask: current value of idlect mask + */ +__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask) +{ + int n; + + /* If ARMXOR cannot be idled this function call is unnecessary */ + if (!(inputmask & (1 << 1))) + return inputmask; + + /* If any active timer is using ARMXOR return modified mask */ + for (n = 0; dm_timers[n].base; ++n) + if (omap_dm_timer_read_reg(&dm_timers[n], OMAP_TIMER_CTRL_REG)& + OMAP_TIMER_CTRL_ST) { + if (((omap_readl(MOD_CONF_CTRL_1)>>(n*2)) & 0x03) == 0) + inputmask &= ~(1 << 1); + else + inputmask &= ~(1 << 2); + } + + return inputmask; +} + + void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) { int n = (timer - dm_timers) << 1; diff --git a/arch/arm/plat-omap/fb.c b/arch/arm/plat-omap/fb.c new file mode 100644 index 000000000000..305e9b990b71 --- /dev/null +++ b/arch/arm/plat-omap/fb.c @@ -0,0 +1,80 @@ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/bootmem.h> + +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/mach-types.h> +#include <asm/mach/map.h> + +#include <asm/arch/board.h> +#include <asm/arch/sram.h> +#include <asm/arch/omapfb.h> + +#if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE) + +static struct omapfb_platform_data omapfb_config; + +static u64 omap_fb_dma_mask = ~(u32)0; + +static struct platform_device omap_fb_device = { + .name = "omapfb", + .id = -1, + .dev = { + .dma_mask = &omap_fb_dma_mask, + .coherent_dma_mask = ~(u32)0, + .platform_data = &omapfb_config, + }, + .num_resources = 0, +}; + +/* called from map_io */ +void omapfb_reserve_mem(void) +{ + const struct omap_fbmem_config *fbmem_conf; + + omapfb_config.fbmem.fb_sram_start = omap_fb_sram_start; + omapfb_config.fbmem.fb_sram_size = omap_fb_sram_size; + + fbmem_conf = omap_get_config(OMAP_TAG_FBMEM, struct omap_fbmem_config); + + if (fbmem_conf != NULL) { + /* indicate that the bootloader already initialized the + * fb device, so we'll skip that part in the fb driver + */ + omapfb_config.fbmem.fb_sdram_start = fbmem_conf->fb_sdram_start; + omapfb_config.fbmem.fb_sdram_size = fbmem_conf->fb_sdram_size; + if (fbmem_conf->fb_sdram_size) { + pr_info("Reserving %u bytes SDRAM for frame buffer\n", + fbmem_conf->fb_sdram_size); + reserve_bootmem(fbmem_conf->fb_sdram_start, + fbmem_conf->fb_sdram_size); + } + } +} + +static inline int omap_init_fb(void) +{ + const struct omap_lcd_config *conf; + + conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config); + if (conf == NULL) + return 0; + + omapfb_config.lcd = *conf; + + return platform_device_register(&omap_fb_device); +} + +arch_initcall(omap_init_fb); + +#else + +void omapfb_reserve_mem(void) {} + +#endif + + diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index b4d5b9e4bfce..d3c8ea7eecfd 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c @@ -174,7 +174,7 @@ static int gpio_bank_count; static inline struct gpio_bank *get_gpio_bank(int gpio) { #ifdef CONFIG_ARCH_OMAP15XX - if (cpu_is_omap1510()) { + if (cpu_is_omap15xx()) { if (OMAP_GPIO_IS_MPUIO(gpio)) return &gpio_bank[0]; return &gpio_bank[1]; @@ -223,7 +223,7 @@ static inline int gpio_valid(int gpio) return 0; } #ifdef CONFIG_ARCH_OMAP15XX - if (cpu_is_omap1510() && gpio < 16) + if (cpu_is_omap15xx() && gpio < 16) return 0; #endif #if defined(CONFIG_ARCH_OMAP16XX) @@ -402,13 +402,13 @@ static inline void set_24xx_gpio_triggering(void __iomem *base, int gpio, int tr u32 gpio_bit = 1 << gpio; MOD_REG_BIT(OMAP24XX_GPIO_LEVELDETECT0, gpio_bit, - trigger & IRQT_LOW); + trigger & __IRQT_LOWLVL); MOD_REG_BIT(OMAP24XX_GPIO_LEVELDETECT1, gpio_bit, - trigger & IRQT_HIGH); + trigger & __IRQT_HIGHLVL); MOD_REG_BIT(OMAP24XX_GPIO_RISINGDETECT, gpio_bit, - trigger & IRQT_RISING); + trigger & __IRQT_RISEDGE); MOD_REG_BIT(OMAP24XX_GPIO_FALLINGDETECT, gpio_bit, - trigger & IRQT_FALLING); + trigger & __IRQT_FALEDGE); /* FIXME: Possibly do 'set_irq_handler(j, do_level_IRQ)' if only level * triggering requested. */ } @@ -422,9 +422,9 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) case METHOD_MPUIO: reg += OMAP_MPUIO_GPIO_INT_EDGE; l = __raw_readl(reg); - if (trigger == IRQT_RISING) + if (trigger & __IRQT_RISEDGE) l |= 1 << gpio; - else if (trigger == IRQT_FALLING) + else if (trigger & __IRQT_FALEDGE) l &= ~(1 << gpio); else goto bad; @@ -432,9 +432,9 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) case METHOD_GPIO_1510: reg += OMAP1510_GPIO_INT_CONTROL; l = __raw_readl(reg); - if (trigger == IRQT_RISING) + if (trigger & __IRQT_RISEDGE) l |= 1 << gpio; - else if (trigger == IRQT_FALLING) + else if (trigger & __IRQT_FALEDGE) l &= ~(1 << gpio); else goto bad; @@ -446,20 +446,21 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) reg += OMAP1610_GPIO_EDGE_CTRL1; gpio &= 0x07; /* We allow only edge triggering, i.e. two lowest bits */ - if (trigger & ~IRQT_BOTHEDGE) + if (trigger & (__IRQT_LOWLVL | __IRQT_HIGHLVL)) BUG(); - /* NOTE: knows __IRQT_{FAL,RIS}EDGE match OMAP hardware */ - trigger &= 0x03; l = __raw_readl(reg); l &= ~(3 << (gpio << 1)); - l |= trigger << (gpio << 1); + if (trigger & __IRQT_RISEDGE) + l |= 2 << (gpio << 1); + if (trigger & __IRQT_FALEDGE) + l |= 1 << (gpio << 1); break; case METHOD_GPIO_730: reg += OMAP730_GPIO_INT_CONTROL; l = __raw_readl(reg); - if (trigger == IRQT_RISING) + if (trigger & __IRQT_RISEDGE) l |= 1 << gpio; - else if (trigger == IRQT_FALLING) + else if (trigger & __IRQT_FALEDGE) l &= ~(1 << gpio); else goto bad; @@ -491,7 +492,9 @@ static int gpio_irq_type(unsigned irq, unsigned type) if (check_gpio(gpio) < 0) return -EINVAL; - if (type & (__IRQT_LOWLVL|__IRQT_HIGHLVL|IRQT_PROBE)) + if (type & IRQT_PROBE) + return -EINVAL; + if (!cpu_is_omap24xx() && (type & (__IRQT_LOWLVL|__IRQT_HIGHLVL))) return -EINVAL; bank = get_gpio_bank(gpio); @@ -755,13 +758,32 @@ static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc, if (bank->method == METHOD_GPIO_24XX) isr_reg = bank->base + OMAP24XX_GPIO_IRQSTATUS1; #endif - while(1) { - isr = __raw_readl(isr_reg); - _enable_gpio_irqbank(bank, isr, 0); - _clear_gpio_irqbank(bank, isr); - _enable_gpio_irqbank(bank, isr, 1); - desc->chip->unmask(irq); + u32 isr_saved, level_mask = 0; + + isr_saved = isr = __raw_readl(isr_reg); + + if (cpu_is_omap15xx() && (bank->method == METHOD_MPUIO)) + isr &= 0x0000ffff; + + if (cpu_is_omap24xx()) + level_mask = + __raw_readl(bank->base + + OMAP24XX_GPIO_LEVELDETECT0) | + __raw_readl(bank->base + + OMAP24XX_GPIO_LEVELDETECT1); + + /* clear edge sensitive interrupts before handler(s) are + called so that we don't miss any interrupt occurred while + executing them */ + _enable_gpio_irqbank(bank, isr_saved & ~level_mask, 0); + _clear_gpio_irqbank(bank, isr_saved & ~level_mask); + _enable_gpio_irqbank(bank, isr_saved & ~level_mask, 1); + + /* if there is only edge sensitive GPIO pin interrupts + configured, we could unmask GPIO bank interrupt immediately */ + if (!level_mask) + desc->chip->unmask(irq); if (!isr) break; @@ -774,6 +796,20 @@ static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc, d = irq_desc + gpio_irq; desc_handle_irq(gpio_irq, d, regs); } + + if (cpu_is_omap24xx()) { + /* clear level sensitive interrupts after handler(s) */ + _enable_gpio_irqbank(bank, isr_saved & level_mask, 0); + _clear_gpio_irqbank(bank, isr_saved & level_mask); + _enable_gpio_irqbank(bank, isr_saved & level_mask, 1); + } + + /* if bank has any level sensitive GPIO pin interrupt + configured, we must unmask the bank interrupt only after + handler(s) are executed in order to avoid spurious bank + interrupt */ + if (level_mask) + desc->chip->unmask(irq); } } @@ -848,7 +884,7 @@ static int __init _omap_gpio_init(void) initialized = 1; - if (cpu_is_omap1510()) { + if (cpu_is_omap15xx()) { gpio_ick = clk_get(NULL, "arm_gpio_ck"); if (IS_ERR(gpio_ick)) printk("Could not get arm_gpio_ck\n"); @@ -869,7 +905,7 @@ static int __init _omap_gpio_init(void) } #ifdef CONFIG_ARCH_OMAP15XX - if (cpu_is_omap1510()) { + if (cpu_is_omap15xx()) { printk(KERN_INFO "OMAP1510 GPIO hardware\n"); gpio_bank_count = 2; gpio_bank = gpio_bank_1510; diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index 1cd2cace7e1b..196aac3ac329 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -34,7 +34,7 @@ #ifdef CONFIG_MCBSP_DEBUG #define DBG(x...) printk(x) #else -#define DBG(x...) do { } while (0) +#define DBG(x...) do { } while (0) #endif struct omap_mcbsp { @@ -44,6 +44,7 @@ struct omap_mcbsp { omap_mcbsp_word_length rx_word_length; omap_mcbsp_word_length tx_word_length; + omap_mcbsp_io_type_t io_type; /* IRQ or poll */ /* IRQ based TX/RX */ int rx_irq; int tx_irq; @@ -64,10 +65,19 @@ struct omap_mcbsp { }; static struct omap_mcbsp mcbsp[OMAP_MAX_MCBSP_COUNT]; +#ifdef CONFIG_ARCH_OMAP1 static struct clk *mcbsp_dsp_ck = 0; static struct clk *mcbsp_api_ck = 0; static struct clk *mcbsp_dspxor_ck = 0; - +#endif +#ifdef CONFIG_ARCH_OMAP2 +static struct clk *mcbsp1_ick = 0; +static struct clk *mcbsp1_fck = 0; +static struct clk *mcbsp2_ick = 0; +static struct clk *mcbsp2_fck = 0; +static struct clk *sys_ck = 0; +static struct clk *sys_clkout = 0; +#endif static void omap_mcbsp_dump_reg(u8 id) { @@ -88,7 +98,6 @@ static void omap_mcbsp_dump_reg(u8 id) DBG("***********************\n"); } - static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id, struct pt_regs *regs) { struct omap_mcbsp * mcbsp_tx = (struct omap_mcbsp *)(dev_id); @@ -109,7 +118,6 @@ static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id, struct pt_re return IRQ_HANDLED; } - static void omap_mcbsp_tx_dma_callback(int lch, u16 ch_status, void *data) { struct omap_mcbsp * mcbsp_dma_tx = (struct omap_mcbsp *)(data); @@ -176,7 +184,7 @@ static int omap_mcbsp_check(unsigned int id) return 0; } - if (cpu_is_omap1510() || cpu_is_omap16xx()) { + if (cpu_is_omap15xx() || cpu_is_omap16xx() || cpu_is_omap24xx()) { if (id > OMAP_MAX_MCBSP_COUNT) { printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", id + 1); return -1; @@ -187,9 +195,10 @@ static int omap_mcbsp_check(unsigned int id) return -1; } +#ifdef CONFIG_ARCH_OMAP1 static void omap_mcbsp_dsp_request(void) { - if (cpu_is_omap1510() || cpu_is_omap16xx()) { + if (cpu_is_omap15xx() || cpu_is_omap16xx()) { clk_enable(mcbsp_dsp_ck); clk_enable(mcbsp_api_ck); @@ -207,12 +216,49 @@ static void omap_mcbsp_dsp_request(void) static void omap_mcbsp_dsp_free(void) { - if (cpu_is_omap1510() || cpu_is_omap16xx()) { + if (cpu_is_omap15xx() || cpu_is_omap16xx()) { clk_disable(mcbsp_dspxor_ck); clk_disable(mcbsp_dsp_ck); clk_disable(mcbsp_api_ck); } } +#endif + +#ifdef CONFIG_ARCH_OMAP2 +static void omap2_mcbsp2_mux_setup(void) +{ + omap_cfg_reg(Y15_24XX_MCBSP2_CLKX); + omap_cfg_reg(R14_24XX_MCBSP2_FSX); + omap_cfg_reg(W15_24XX_MCBSP2_DR); + omap_cfg_reg(V15_24XX_MCBSP2_DX); + omap_cfg_reg(V14_24XX_GPIO117); + omap_cfg_reg(W14_24XX_SYS_CLKOUT); +} +#endif + +/* + * We can choose between IRQ based or polled IO. + * This needs to be called before omap_mcbsp_request(). + */ +int omap_mcbsp_set_io_type(unsigned int id, omap_mcbsp_io_type_t io_type) +{ + if (omap_mcbsp_check(id) < 0) + return -EINVAL; + + spin_lock(&mcbsp[id].lock); + + if (!mcbsp[id].free) { + printk (KERN_ERR "OMAP-McBSP: McBSP%d is currently in use\n", id + 1); + spin_unlock(&mcbsp[id].lock); + return -EINVAL; + } + + mcbsp[id].io_type = io_type; + + spin_unlock(&mcbsp[id].lock); + + return 0; +} int omap_mcbsp_request(unsigned int id) { @@ -221,12 +267,26 @@ int omap_mcbsp_request(unsigned int id) if (omap_mcbsp_check(id) < 0) return -EINVAL; +#ifdef CONFIG_ARCH_OMAP1 /* * On 1510, 1610 and 1710, McBSP1 and McBSP3 * are DSP public peripherals. */ if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3) omap_mcbsp_dsp_request(); +#endif + +#ifdef CONFIG_ARCH_OMAP2 + if (cpu_is_omap24xx()) { + if (id == OMAP_MCBSP1) { + clk_enable(mcbsp1_ick); + clk_enable(mcbsp1_fck); + } else { + clk_enable(mcbsp2_ick); + clk_enable(mcbsp2_fck); + } + } +#endif spin_lock(&mcbsp[id].lock); if (!mcbsp[id].free) { @@ -238,30 +298,33 @@ int omap_mcbsp_request(unsigned int id) mcbsp[id].free = 0; spin_unlock(&mcbsp[id].lock); - /* We need to get IRQs here */ - err = request_irq(mcbsp[id].tx_irq, omap_mcbsp_tx_irq_handler, 0, - "McBSP", - (void *) (&mcbsp[id])); - if (err != 0) { - printk(KERN_ERR "OMAP-McBSP: Unable to request TX IRQ %d for McBSP%d\n", - mcbsp[id].tx_irq, mcbsp[id].id); - return err; - } + if (mcbsp[id].io_type == OMAP_MCBSP_IRQ_IO) { + /* We need to get IRQs here */ + err = request_irq(mcbsp[id].tx_irq, omap_mcbsp_tx_irq_handler, 0, + "McBSP", + (void *) (&mcbsp[id])); + if (err != 0) { + printk(KERN_ERR "OMAP-McBSP: Unable to request TX IRQ %d for McBSP%d\n", + mcbsp[id].tx_irq, mcbsp[id].id); + return err; + } - init_completion(&(mcbsp[id].tx_irq_completion)); + init_completion(&(mcbsp[id].tx_irq_completion)); - err = request_irq(mcbsp[id].rx_irq, omap_mcbsp_rx_irq_handler, 0, - "McBSP", - (void *) (&mcbsp[id])); - if (err != 0) { - printk(KERN_ERR "OMAP-McBSP: Unable to request RX IRQ %d for McBSP%d\n", - mcbsp[id].rx_irq, mcbsp[id].id); - free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id])); - return err; + err = request_irq(mcbsp[id].rx_irq, omap_mcbsp_rx_irq_handler, 0, + "McBSP", + (void *) (&mcbsp[id])); + if (err != 0) { + printk(KERN_ERR "OMAP-McBSP: Unable to request RX IRQ %d for McBSP%d\n", + mcbsp[id].rx_irq, mcbsp[id].id); + free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id])); + return err; + } + + init_completion(&(mcbsp[id].rx_irq_completion)); } - init_completion(&(mcbsp[id].rx_irq_completion)); return 0; } @@ -271,8 +334,24 @@ void omap_mcbsp_free(unsigned int id) if (omap_mcbsp_check(id) < 0) return; - if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3) - omap_mcbsp_dsp_free(); +#ifdef CONFIG_ARCH_OMAP1 + if (cpu_class_is_omap1()) { + if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3) + omap_mcbsp_dsp_free(); + } +#endif + +#ifdef CONFIG_ARCH_OMAP2 + if (cpu_is_omap24xx()) { + if (id == OMAP_MCBSP1) { + clk_disable(mcbsp1_ick); + clk_disable(mcbsp1_fck); + } else { + clk_disable(mcbsp2_ick); + clk_disable(mcbsp2_fck); + } + } +#endif spin_lock(&mcbsp[id].lock); if (mcbsp[id].free) { @@ -284,9 +363,11 @@ void omap_mcbsp_free(unsigned int id) mcbsp[id].free = 1; spin_unlock(&mcbsp[id].lock); - /* Free IRQs */ - free_irq(mcbsp[id].rx_irq, (void *) (&mcbsp[id])); - free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id])); + if (mcbsp[id].io_type == OMAP_MCBSP_IRQ_IO) { + /* Free IRQs */ + free_irq(mcbsp[id].rx_irq, (void *) (&mcbsp[id])); + free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id])); + } } /* @@ -461,6 +542,115 @@ u32 omap_mcbsp_recv_word(unsigned int id) } +int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word) +{ + u32 io_base = mcbsp[id].io_base; + omap_mcbsp_word_length tx_word_length = mcbsp[id].tx_word_length; + omap_mcbsp_word_length rx_word_length = mcbsp[id].rx_word_length; + u16 spcr2, spcr1, attempts = 0, word_lsb, word_msb = 0; + + if (tx_word_length != rx_word_length) + return -EINVAL; + + /* First we wait for the transmitter to be ready */ + spcr2 = OMAP_MCBSP_READ(io_base, SPCR2); + while (!(spcr2 & XRDY)) { + spcr2 = OMAP_MCBSP_READ(io_base, SPCR2); + if (attempts++ > 1000) { + /* We must reset the transmitter */ + OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 & (~XRST)); + udelay(10); + OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 | XRST); + udelay(10); + printk("McBSP transmitter not ready\n"); + return -EAGAIN; + } + } + + /* Now we can push the data */ + if (tx_word_length > OMAP_MCBSP_WORD_16) + OMAP_MCBSP_WRITE(io_base, DXR2, word >> 16); + OMAP_MCBSP_WRITE(io_base, DXR1, word & 0xffff); + + /* We wait for the receiver to be ready */ + spcr1 = OMAP_MCBSP_READ(io_base, SPCR1); + while (!(spcr1 & RRDY)) { + spcr1 = OMAP_MCBSP_READ(io_base, SPCR1); + if (attempts++ > 1000) { + /* We must reset the receiver */ + OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 & (~RRST)); + udelay(10); + OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 | RRST); + udelay(10); + printk("McBSP receiver not ready\n"); + return -EAGAIN; + } + } + + /* Receiver is ready, let's read the dummy data */ + if (rx_word_length > OMAP_MCBSP_WORD_16) + word_msb = OMAP_MCBSP_READ(io_base, DRR2); + word_lsb = OMAP_MCBSP_READ(io_base, DRR1); + + return 0; +} + +int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 * word) +{ + u32 io_base = mcbsp[id].io_base, clock_word = 0; + omap_mcbsp_word_length tx_word_length = mcbsp[id].tx_word_length; + omap_mcbsp_word_length rx_word_length = mcbsp[id].rx_word_length; + u16 spcr2, spcr1, attempts = 0, word_lsb, word_msb = 0; + + if (tx_word_length != rx_word_length) + return -EINVAL; + + /* First we wait for the transmitter to be ready */ + spcr2 = OMAP_MCBSP_READ(io_base, SPCR2); + while (!(spcr2 & XRDY)) { + spcr2 = OMAP_MCBSP_READ(io_base, SPCR2); + if (attempts++ > 1000) { + /* We must reset the transmitter */ + OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 & (~XRST)); + udelay(10); + OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 | XRST); + udelay(10); + printk("McBSP transmitter not ready\n"); + return -EAGAIN; + } + } + + /* We first need to enable the bus clock */ + if (tx_word_length > OMAP_MCBSP_WORD_16) + OMAP_MCBSP_WRITE(io_base, DXR2, clock_word >> 16); + OMAP_MCBSP_WRITE(io_base, DXR1, clock_word & 0xffff); + + /* We wait for the receiver to be ready */ + spcr1 = OMAP_MCBSP_READ(io_base, SPCR1); + while (!(spcr1 & RRDY)) { + spcr1 = OMAP_MCBSP_READ(io_base, SPCR1); + if (attempts++ > 1000) { + /* We must reset the receiver */ + OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 & (~RRST)); + udelay(10); + OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 | RRST); + udelay(10); + printk("McBSP receiver not ready\n"); + return -EAGAIN; + } + } + + /* Receiver is ready, there is something for us */ + if (rx_word_length > OMAP_MCBSP_WORD_16) + word_msb = OMAP_MCBSP_READ(io_base, DRR2); + word_lsb = OMAP_MCBSP_READ(io_base, DRR1); + + word[0] = (word_lsb | (word_msb << 16)); + + return 0; +} + + /* * Simple DMA based buffer rx/tx routines. * Nothing fancy, just a single buffer tx/rx through DMA. @@ -471,6 +661,9 @@ u32 omap_mcbsp_recv_word(unsigned int id) int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer, unsigned int length) { int dma_tx_ch; + int src_port = 0; + int dest_port = 0; + int sync_dev = 0; if (omap_mcbsp_check(id) < 0) return -EINVAL; @@ -487,20 +680,27 @@ int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer, unsigned int leng init_completion(&(mcbsp[id].tx_dma_completion)); + if (cpu_class_is_omap1()) { + src_port = OMAP_DMA_PORT_TIPB; + dest_port = OMAP_DMA_PORT_EMIFF; + } + if (cpu_is_omap24xx()) + sync_dev = mcbsp[id].dma_tx_sync; + omap_set_dma_transfer_params(mcbsp[id].dma_tx_lch, OMAP_DMA_DATA_TYPE_S16, length >> 1, 1, OMAP_DMA_SYNC_ELEMENT, - 0, 0); + sync_dev, 0); omap_set_dma_dest_params(mcbsp[id].dma_tx_lch, - OMAP_DMA_PORT_TIPB, + src_port, OMAP_DMA_AMODE_CONSTANT, mcbsp[id].io_base + OMAP_MCBSP_REG_DXR1, 0, 0); omap_set_dma_src_params(mcbsp[id].dma_tx_lch, - OMAP_DMA_PORT_EMIFF, + dest_port, OMAP_DMA_AMODE_POST_INC, buffer, 0, 0); @@ -514,6 +714,9 @@ int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer, unsigned int leng int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer, unsigned int length) { int dma_rx_ch; + int src_port = 0; + int dest_port = 0; + int sync_dev = 0; if (omap_mcbsp_check(id) < 0) return -EINVAL; @@ -530,20 +733,27 @@ int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer, unsigned int leng init_completion(&(mcbsp[id].rx_dma_completion)); + if (cpu_class_is_omap1()) { + src_port = OMAP_DMA_PORT_TIPB; + dest_port = OMAP_DMA_PORT_EMIFF; + } + if (cpu_is_omap24xx()) + sync_dev = mcbsp[id].dma_rx_sync; + omap_set_dma_transfer_params(mcbsp[id].dma_rx_lch, OMAP_DMA_DATA_TYPE_S16, length >> 1, 1, OMAP_DMA_SYNC_ELEMENT, - 0, 0); + sync_dev, 0); omap_set_dma_src_params(mcbsp[id].dma_rx_lch, - OMAP_DMA_PORT_TIPB, + src_port, OMAP_DMA_AMODE_CONSTANT, mcbsp[id].io_base + OMAP_MCBSP_REG_DRR1, 0, 0); omap_set_dma_dest_params(mcbsp[id].dma_rx_lch, - OMAP_DMA_PORT_EMIFF, + dest_port, OMAP_DMA_AMODE_POST_INC, buffer, 0, 0); @@ -688,6 +898,23 @@ static const struct omap_mcbsp_info mcbsp_1610[] = { }; #endif +#if defined(CONFIG_ARCH_OMAP24XX) +static const struct omap_mcbsp_info mcbsp_24xx[] = { + [0] = { .virt_base = IO_ADDRESS(OMAP24XX_MCBSP1_BASE), + .dma_rx_sync = OMAP24XX_DMA_MCBSP1_RX, + .dma_tx_sync = OMAP24XX_DMA_MCBSP1_TX, + .rx_irq = INT_24XX_MCBSP1_IRQ_RX, + .tx_irq = INT_24XX_MCBSP1_IRQ_TX, + }, + [1] = { .virt_base = IO_ADDRESS(OMAP24XX_MCBSP2_BASE), + .dma_rx_sync = OMAP24XX_DMA_MCBSP2_RX, + .dma_tx_sync = OMAP24XX_DMA_MCBSP2_TX, + .rx_irq = INT_24XX_MCBSP2_IRQ_RX, + .tx_irq = INT_24XX_MCBSP2_IRQ_TX, + }, +}; +#endif + static int __init omap_mcbsp_init(void) { int mcbsp_count = 0, i; @@ -695,6 +922,7 @@ static int __init omap_mcbsp_init(void) printk("Initializing OMAP McBSP system\n"); +#ifdef CONFIG_ARCH_OMAP1 mcbsp_dsp_ck = clk_get(0, "dsp_ck"); if (IS_ERR(mcbsp_dsp_ck)) { printk(KERN_ERR "mcbsp: could not acquire dsp_ck handle.\n"); @@ -710,6 +938,29 @@ static int __init omap_mcbsp_init(void) printk(KERN_ERR "mcbsp: could not acquire dspxor_ck handle.\n"); return PTR_ERR(mcbsp_dspxor_ck); } +#endif +#ifdef CONFIG_ARCH_OMAP2 + mcbsp1_ick = clk_get(0, "mcbsp1_ick"); + if (IS_ERR(mcbsp1_ick)) { + printk(KERN_ERR "mcbsp: could not acquire mcbsp1_ick handle.\n"); + return PTR_ERR(mcbsp1_ick); + } + mcbsp1_fck = clk_get(0, "mcbsp1_fck"); + if (IS_ERR(mcbsp1_fck)) { + printk(KERN_ERR "mcbsp: could not acquire mcbsp1_fck handle.\n"); + return PTR_ERR(mcbsp1_fck); + } + mcbsp2_ick = clk_get(0, "mcbsp2_ick"); + if (IS_ERR(mcbsp2_ick)) { + printk(KERN_ERR "mcbsp: could not acquire mcbsp2_ick handle.\n"); + return PTR_ERR(mcbsp2_ick); + } + mcbsp2_fck = clk_get(0, "mcbsp2_fck"); + if (IS_ERR(mcbsp2_fck)) { + printk(KERN_ERR "mcbsp: could not acquire mcbsp2_fck handle.\n"); + return PTR_ERR(mcbsp2_fck); + } +#endif #ifdef CONFIG_ARCH_OMAP730 if (cpu_is_omap730()) { @@ -718,7 +969,7 @@ static int __init omap_mcbsp_init(void) } #endif #ifdef CONFIG_ARCH_OMAP15XX - if (cpu_is_omap1510()) { + if (cpu_is_omap15xx()) { mcbsp_info = mcbsp_1510; mcbsp_count = ARRAY_SIZE(mcbsp_1510); } @@ -729,6 +980,19 @@ static int __init omap_mcbsp_init(void) mcbsp_count = ARRAY_SIZE(mcbsp_1610); } #endif +#if defined(CONFIG_ARCH_OMAP24XX) + if (cpu_is_omap24xx()) { + mcbsp_info = mcbsp_24xx; + mcbsp_count = ARRAY_SIZE(mcbsp_24xx); + + /* REVISIT: where's the right place? */ + omap2_mcbsp2_mux_setup(); + sys_ck = clk_get(0, "sys_ck"); + sys_clkout = clk_get(0, "sys_clkout"); + clk_set_parent(sys_clkout, sys_ck); + clk_enable(sys_clkout); + } +#endif for (i = 0; i < OMAP_MAX_MCBSP_COUNT ; i++) { if (i >= mcbsp_count) { mcbsp[i].io_base = 0; @@ -741,6 +1005,7 @@ static int __init omap_mcbsp_init(void) mcbsp[i].dma_rx_lch = -1; mcbsp[i].io_base = mcbsp_info[i].virt_base; + mcbsp[i].io_type = OMAP_MCBSP_IRQ_IO; /* Default I/O is IRQ based */ mcbsp[i].tx_irq = mcbsp_info[i].tx_irq; mcbsp[i].rx_irq = mcbsp_info[i].rx_irq; mcbsp[i].dma_rx_sync = mcbsp_info[i].dma_rx_sync; @@ -751,11 +1016,11 @@ static int __init omap_mcbsp_init(void) return 0; } - arch_initcall(omap_mcbsp_init); EXPORT_SYMBOL(omap_mcbsp_config); EXPORT_SYMBOL(omap_mcbsp_request); +EXPORT_SYMBOL(omap_mcbsp_set_io_type); EXPORT_SYMBOL(omap_mcbsp_free); EXPORT_SYMBOL(omap_mcbsp_start); EXPORT_SYMBOL(omap_mcbsp_stop); @@ -763,4 +1028,6 @@ EXPORT_SYMBOL(omap_mcbsp_xmit_word); EXPORT_SYMBOL(omap_mcbsp_recv_word); EXPORT_SYMBOL(omap_mcbsp_xmit_buffer); EXPORT_SYMBOL(omap_mcbsp_recv_buffer); +EXPORT_SYMBOL(omap_mcbsp_spi_master_xmit_word_poll); +EXPORT_SYMBOL(omap_mcbsp_spi_master_recv_word_poll); EXPORT_SYMBOL(omap_mcbsp_set_spi_mode); diff --git a/arch/arm/plat-omap/ocpi.c b/arch/arm/plat-omap/ocpi.c index 5cc6775c789c..37792d43738b 100644 --- a/arch/arm/plat-omap/ocpi.c +++ b/arch/arm/plat-omap/ocpi.c @@ -62,9 +62,6 @@ int ocpi_enable(void) if (!cpu_is_omap16xx()) return -ENODEV; - /* Make sure there's clock for OCPI */ - clk_enable(ocpi_ck); - /* Enable access for OHCI in OCPI */ val = omap_readl(OCPI_PROT); val &= ~0xff; diff --git a/arch/arm/plat-omap/pm.c b/arch/arm/plat-omap/pm.c index 093efd786f21..1a24e2c10714 100644 --- a/arch/arm/plat-omap/pm.c +++ b/arch/arm/plat-omap/pm.c @@ -38,6 +38,7 @@ #include <linux/pm.h> #include <linux/sched.h> #include <linux/proc_fs.h> +#include <linux/pm.h> #include <linux/interrupt.h> #include <asm/io.h> diff --git a/arch/arm/plat-omap/sleep.S b/arch/arm/plat-omap/sleep.S deleted file mode 100644 index 4cd7d292f854..000000000000 --- a/arch/arm/plat-omap/sleep.S +++ /dev/null @@ -1,452 +0,0 @@ -/* - * linux/arch/arm/plat-omap/sleep.S - * - * Low-level OMAP730/1510/1610 sleep/wakeUp support - * - * Initial SA1110 code: - * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com> - * - * Adapted for PXA by Nicolas Pitre: - * Copyright (c) 2002 Monta Vista Software, Inc. - * - * Support for OMAP1510/1610 by Dirk Behme <dirk.behme@de.bosch.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/config.h> -#include <linux/linkage.h> -#include <asm/assembler.h> -#include <asm/arch/io.h> -#include <asm/arch/pm.h> - - .text - -/* - * Forces OMAP into idle state - * - * omapXXXX_idle_loop_suspend() - * - * Note: This code get's copied to internal SRAM at boot. When the OMAP - * wakes up it continues execution at the point it went to sleep. - * - * Note: Because of slightly different configuration values we have - * processor specific functions here. - */ - -#if defined(CONFIG_ARCH_OMAP730) -ENTRY(omap730_idle_loop_suspend) - - stmfd sp!, {r0 - r12, lr} @ save registers on stack - - @ load base address of ARM_IDLECT1 and ARM_IDLECT2 - mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 - - @ turn off clock domains - @ get ARM_IDLECT2 into r2 - ldrh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] - mov r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff - orr r5, r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff00 - strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] - - @ request ARM idle - @ get ARM_IDLECT1 into r1 - ldrh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] - orr r3, r1, #OMAP730_IDLE_LOOP_REQUEST & 0xffff - strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] - - mov r5, #IDLE_WAIT_CYCLES & 0xff - orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00 -l_730: subs r5, r5, #1 - bne l_730 -/* - * Let's wait for the next clock tick to wake us up. - */ - mov r0, #0 - mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt -/* - * omap730_idle_loop_suspend()'s resume point. - * - * It will just start executing here, so we'll restore stuff from the - * stack, reset the ARM_IDLECT1 and ARM_IDLECT2. - */ - - @ restore ARM_IDLECT1 and ARM_IDLECT2 and return - @ r1 has ARM_IDLECT1 and r2 still has ARM_IDLECT2 - strh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] - strh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] - - ldmfd sp!, {r0 - r12, pc} @ restore regs and return - -ENTRY(omap730_idle_loop_suspend_sz) - .word . - omap730_idle_loop_suspend -#endif /* CONFIG_ARCH_OMAP730 */ - -#ifdef CONFIG_ARCH_OMAP15XX -ENTRY(omap1510_idle_loop_suspend) - - stmfd sp!, {r0 - r12, lr} @ save registers on stack - - @ load base address of ARM_IDLECT1 and ARM_IDLECT2 - mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 - - @ turn off clock domains - @ get ARM_IDLECT2 into r2 - ldrh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] - mov r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff - orr r5, r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00 - strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] - - @ request ARM idle - @ get ARM_IDLECT1 into r1 - ldrh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] - orr r3, r1, #OMAP1510_IDLE_LOOP_REQUEST & 0xffff - strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] - - mov r5, #IDLE_WAIT_CYCLES & 0xff - orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00 -l_1510: subs r5, r5, #1 - bne l_1510 -/* - * Let's wait for the next clock tick to wake us up. - */ - mov r0, #0 - mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt -/* - * omap1510_idle_loop_suspend()'s resume point. - * - * It will just start executing here, so we'll restore stuff from the - * stack, reset the ARM_IDLECT1 and ARM_IDLECT2. - */ - - @ restore ARM_IDLECT1 and ARM_IDLECT2 and return - @ r1 has ARM_IDLECT1 and r2 still has ARM_IDLECT2 - strh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] - strh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] - - ldmfd sp!, {r0 - r12, pc} @ restore regs and return - -ENTRY(omap1510_idle_loop_suspend_sz) - .word . - omap1510_idle_loop_suspend -#endif /* CONFIG_ARCH_OMAP15XX */ - -#if defined(CONFIG_ARCH_OMAP16XX) -ENTRY(omap1610_idle_loop_suspend) - - stmfd sp!, {r0 - r12, lr} @ save registers on stack - - @ load base address of ARM_IDLECT1 and ARM_IDLECT2 - mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 - - @ turn off clock domains - @ get ARM_IDLECT2 into r2 - ldrh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] - mov r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff - orr r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00 - strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] - - @ request ARM idle - @ get ARM_IDLECT1 into r1 - ldrh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] - orr r3, r1, #OMAP1610_IDLE_LOOP_REQUEST & 0xffff - strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] - - mov r5, #IDLE_WAIT_CYCLES & 0xff - orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00 -l_1610: subs r5, r5, #1 - bne l_1610 -/* - * Let's wait for the next clock tick to wake us up. - */ - mov r0, #0 - mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt -/* - * omap1610_idle_loop_suspend()'s resume point. - * - * It will just start executing here, so we'll restore stuff from the - * stack, reset the ARM_IDLECT1 and ARM_IDLECT2. - */ - - @ restore ARM_IDLECT1 and ARM_IDLECT2 and return - @ r1 has ARM_IDLECT1 and r2 still has ARM_IDLECT2 - strh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] - strh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] - - ldmfd sp!, {r0 - r12, pc} @ restore regs and return - -ENTRY(omap1610_idle_loop_suspend_sz) - .word . - omap1610_idle_loop_suspend -#endif /* CONFIG_ARCH_OMAP16XX */ - -/* - * Forces OMAP into deep sleep state - * - * omapXXXX_cpu_suspend() - * - * The values of the registers ARM_IDLECT1 and ARM_IDLECT2 are passed - * as arg0 and arg1 from caller. arg0 is stored in register r0 and arg1 - * in register r1. - * - * Note: This code get's copied to internal SRAM at boot. When the OMAP - * wakes up it continues execution at the point it went to sleep. - * - * Note: Because of errata work arounds we have processor specific functions - * here. They are mostly the same, but slightly different. - * - */ - -#if defined(CONFIG_ARCH_OMAP730) -ENTRY(omap730_cpu_suspend) - - @ save registers on stack - stmfd sp!, {r0 - r12, lr} - - @ Drain write cache - mov r4, #0 - mcr p15, 0, r0, c7, c10, 4 - nop - - @ load base address of Traffic Controller - mov r6, #TCMIF_ASM_BASE & 0xff000000 - orr r6, r6, #TCMIF_ASM_BASE & 0x00ff0000 - orr r6, r6, #TCMIF_ASM_BASE & 0x0000ff00 - - @ prepare to put SDRAM into self-refresh manually - ldr r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] - orr r9, r7, #SELF_REFRESH_MODE & 0xff000000 - orr r9, r9, #SELF_REFRESH_MODE & 0x000000ff - str r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] - - @ prepare to put EMIFS to Sleep - ldr r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] - orr r9, r8, #IDLE_EMIFS_REQUEST & 0xff - str r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] - - @ load base address of ARM_IDLECT1 and ARM_IDLECT2 - mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 - - @ turn off clock domains - @ do not disable PERCK (0x04) - mov r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff - orr r5, r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff00 - strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] - - @ request ARM idle - mov r3, #OMAP730_IDLECT1_SLEEP_VAL & 0xff - orr r3, r3, #OMAP730_IDLECT1_SLEEP_VAL & 0xff00 - strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] - - @ disable instruction cache - mrc p15, 0, r9, c1, c0, 0 - bic r2, r9, #0x1000 - mcr p15, 0, r2, c1, c0, 0 - nop - -/* - * Let's wait for the next wake up event to wake us up. r0 can't be - * used here because r0 holds ARM_IDLECT1 - */ - mov r2, #0 - mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt -/* - * omap730_cpu_suspend()'s resume point. - * - * It will just start executing here, so we'll restore stuff from the - * stack. - */ - @ re-enable Icache - mcr p15, 0, r9, c1, c0, 0 - - @ reset the ARM_IDLECT1 and ARM_IDLECT2. - strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] - strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] - - @ Restore EMIFF controls - str r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] - str r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] - - @ restore regs and return - ldmfd sp!, {r0 - r12, pc} - -ENTRY(omap730_cpu_suspend_sz) - .word . - omap730_cpu_suspend -#endif /* CONFIG_ARCH_OMAP730 */ - -#ifdef CONFIG_ARCH_OMAP15XX -ENTRY(omap1510_cpu_suspend) - - @ save registers on stack - stmfd sp!, {r0 - r12, lr} - - @ load base address of Traffic Controller - mov r4, #TCMIF_ASM_BASE & 0xff000000 - orr r4, r4, #TCMIF_ASM_BASE & 0x00ff0000 - orr r4, r4, #TCMIF_ASM_BASE & 0x0000ff00 - - @ work around errata of OMAP1510 PDE bit for TC shut down - @ clear PDE bit - ldr r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] - bic r5, r5, #PDE_BIT & 0xff - str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] - - @ set PWD_EN bit - and r5, r5, #PWD_EN_BIT & 0xff - str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] - - @ prepare to put SDRAM into self-refresh manually - ldr r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] - orr r5, r5, #SELF_REFRESH_MODE & 0xff000000 - orr r5, r5, #SELF_REFRESH_MODE & 0x000000ff - str r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] - - @ prepare to put EMIFS to Sleep - ldr r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] - orr r5, r5, #IDLE_EMIFS_REQUEST & 0xff - str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] - - @ load base address of ARM_IDLECT1 and ARM_IDLECT2 - mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 - - @ turn off clock domains - mov r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff - orr r5, r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00 - strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] - - @ request ARM idle - mov r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff - orr r3, r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff00 - strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] - - mov r5, #IDLE_WAIT_CYCLES & 0xff - orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00 -l_1510_2: - subs r5, r5, #1 - bne l_1510_2 -/* - * Let's wait for the next wake up event to wake us up. r0 can't be - * used here because r0 holds ARM_IDLECT1 - */ - mov r2, #0 - mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt -/* - * omap1510_cpu_suspend()'s resume point. - * - * It will just start executing here, so we'll restore stuff from the - * stack, reset the ARM_IDLECT1 and ARM_IDLECT2. - */ - strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] - strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] - - @ restore regs and return - ldmfd sp!, {r0 - r12, pc} - -ENTRY(omap1510_cpu_suspend_sz) - .word . - omap1510_cpu_suspend -#endif /* CONFIG_ARCH_OMAP15XX */ - -#if defined(CONFIG_ARCH_OMAP16XX) -ENTRY(omap1610_cpu_suspend) - - @ save registers on stack - stmfd sp!, {r0 - r12, lr} - - @ Drain write cache - mov r4, #0 - mcr p15, 0, r0, c7, c10, 4 - nop - - @ load base address of Traffic Controller - mov r6, #TCMIF_ASM_BASE & 0xff000000 - orr r6, r6, #TCMIF_ASM_BASE & 0x00ff0000 - orr r6, r6, #TCMIF_ASM_BASE & 0x0000ff00 - - @ prepare to put SDRAM into self-refresh manually - ldr r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] - orr r9, r7, #SELF_REFRESH_MODE & 0xff000000 - orr r9, r9, #SELF_REFRESH_MODE & 0x000000ff - str r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] - - @ prepare to put EMIFS to Sleep - ldr r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] - orr r9, r8, #IDLE_EMIFS_REQUEST & 0xff - str r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] - - @ load base address of ARM_IDLECT1 and ARM_IDLECT2 - mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 - - @ turn off clock domains - @ do not disable PERCK (0x04) - mov r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff - orr r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00 - strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] - - @ request ARM idle - mov r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff - orr r3, r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff00 - strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] - - @ disable instruction cache - mrc p15, 0, r9, c1, c0, 0 - bic r2, r9, #0x1000 - mcr p15, 0, r2, c1, c0, 0 - nop - -/* - * Let's wait for the next wake up event to wake us up. r0 can't be - * used here because r0 holds ARM_IDLECT1 - */ - mov r2, #0 - mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt -/* - * omap1610_cpu_suspend()'s resume point. - * - * It will just start executing here, so we'll restore stuff from the - * stack. - */ - @ re-enable Icache - mcr p15, 0, r9, c1, c0, 0 - - @ reset the ARM_IDLECT1 and ARM_IDLECT2. - strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] - strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] - - @ Restore EMIFF controls - str r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] - str r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] - - @ restore regs and return - ldmfd sp!, {r0 - r12, pc} - -ENTRY(omap1610_cpu_suspend_sz) - .word . - omap1610_cpu_suspend -#endif /* CONFIG_ARCH_OMAP16XX */ diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c index ee82763b02b8..b7bf09b1b412 100644 --- a/arch/arm/plat-omap/sram.c +++ b/arch/arm/plat-omap/sram.c @@ -16,24 +16,94 @@ #include <linux/kernel.h> #include <linux/init.h> -#include <asm/mach/map.h> #include <asm/tlb.h> #include <asm/io.h> #include <asm/cacheflush.h> +#include <asm/mach/map.h> + #include <asm/arch/sram.h> +#include <asm/arch/board.h> #define OMAP1_SRAM_PA 0x20000000 #define OMAP1_SRAM_VA 0xd0000000 #define OMAP2_SRAM_PA 0x40200000 +#define OMAP2_SRAM_PUB_PA 0x4020f800 #define OMAP2_SRAM_VA 0xd0000000 +#define OMAP2_SRAM_PUB_VA 0xd0000800 +#if defined(CONFIG_ARCH_OMAP24XX) +#define SRAM_BOOTLOADER_SZ 0x00 +#else #define SRAM_BOOTLOADER_SZ 0x80 +#endif + +#define VA_REQINFOPERM0 IO_ADDRESS(0x68005048) +#define VA_READPERM0 IO_ADDRESS(0x68005050) +#define VA_WRITEPERM0 IO_ADDRESS(0x68005058) +#define VA_CONTROL_STAT IO_ADDRESS(0x480002F8) +#define GP_DEVICE 0x300 +#define TYPE_MASK 0x700 + +#define ROUND_DOWN(value,boundary) ((value) & (~((boundary)-1))) static unsigned long omap_sram_base; static unsigned long omap_sram_size; static unsigned long omap_sram_ceil; +unsigned long omap_fb_sram_start; +unsigned long omap_fb_sram_size; + +/* Depending on the target RAMFS firewall setup, the public usable amount of + * SRAM varies. The default accessable size for all device types is 2k. A GP + * device allows ARM11 but not other initators for full size. This + * functionality seems ok until some nice security API happens. + */ +static int is_sram_locked(void) +{ + int type = 0; + + if (cpu_is_omap242x()) + type = __raw_readl(VA_CONTROL_STAT) & TYPE_MASK; + + if (type == GP_DEVICE) { + /* RAMFW: R/W access to all initators for all qualifier sets */ + if (cpu_is_omap242x()) { + __raw_writel(0xFF, VA_REQINFOPERM0); /* all q-vects */ + __raw_writel(0xCFDE, VA_READPERM0); /* all i-read */ + __raw_writel(0xCFDE, VA_WRITEPERM0); /* all i-write */ + } + return 0; + } else + return 1; /* assume locked with no PPA or security driver */ +} + +void get_fb_sram_conf(unsigned long start_avail, unsigned size_avail, + unsigned long *start, unsigned long *size) +{ + const struct omap_fbmem_config *fbmem_conf; + + fbmem_conf = omap_get_config(OMAP_TAG_FBMEM, struct omap_fbmem_config); + if (fbmem_conf != NULL) { + *start = fbmem_conf->fb_sram_start; + *size = fbmem_conf->fb_sram_size; + } else { + *size = 0; + *start = 0; + } + + if (*size && ( + *start < start_avail || + *start + *size > start_avail + size_avail)) { + printk(KERN_ERR "invalid FB SRAM configuration\n"); + *start = start_avail; + *size = size_avail; + } + + if (*size) + pr_info("Reserving %lu bytes SRAM for frame buffer\n", *size); +} + /* * The amount of SRAM depends on the core type. * Note that we cannot try to test for SRAM here because writes @@ -42,26 +112,45 @@ static unsigned long omap_sram_ceil; */ void __init omap_detect_sram(void) { - if (!cpu_is_omap24xx()) + unsigned long sram_start; + + if (cpu_is_omap24xx()) { + if (is_sram_locked()) { + omap_sram_base = OMAP2_SRAM_PUB_VA; + sram_start = OMAP2_SRAM_PUB_PA; + omap_sram_size = 0x800; /* 2K */ + } else { + omap_sram_base = OMAP2_SRAM_VA; + sram_start = OMAP2_SRAM_PA; + if (cpu_is_omap242x()) + omap_sram_size = 0xa0000; /* 640K */ + else if (cpu_is_omap243x()) + omap_sram_size = 0x10000; /* 64K */ + } + } else { omap_sram_base = OMAP1_SRAM_VA; - else - omap_sram_base = OMAP2_SRAM_VA; - - if (cpu_is_omap730()) - omap_sram_size = 0x32000; /* 200K */ - else if (cpu_is_omap15xx()) - omap_sram_size = 0x30000; /* 192K */ - else if (cpu_is_omap1610() || cpu_is_omap1621() || cpu_is_omap1710()) - omap_sram_size = 0x4000; /* 16K */ - else if (cpu_is_omap1611()) - omap_sram_size = 0x3e800; /* 250K */ - else if (cpu_is_omap2420()) - omap_sram_size = 0xa0014; /* 640K */ - else { - printk(KERN_ERR "Could not detect SRAM size\n"); - omap_sram_size = 0x4000; + sram_start = OMAP1_SRAM_PA; + + if (cpu_is_omap730()) + omap_sram_size = 0x32000; /* 200K */ + else if (cpu_is_omap15xx()) + omap_sram_size = 0x30000; /* 192K */ + else if (cpu_is_omap1610() || cpu_is_omap1621() || + cpu_is_omap1710()) + omap_sram_size = 0x4000; /* 16K */ + else if (cpu_is_omap1611()) + omap_sram_size = 0x3e800; /* 250K */ + else { + printk(KERN_ERR "Could not detect SRAM size\n"); + omap_sram_size = 0x4000; + } } - + get_fb_sram_conf(sram_start + SRAM_BOOTLOADER_SZ, + omap_sram_size - SRAM_BOOTLOADER_SZ, + &omap_fb_sram_start, &omap_fb_sram_size); + if (omap_fb_sram_size) + omap_sram_size -= sram_start + omap_sram_size - + omap_fb_sram_start; omap_sram_ceil = omap_sram_base + omap_sram_size; } @@ -80,12 +169,20 @@ static struct map_desc omap_sram_io_desc[] __initdata = { */ void __init omap_map_sram(void) { + unsigned long base; + if (omap_sram_size == 0) return; if (cpu_is_omap24xx()) { omap_sram_io_desc[0].virtual = OMAP2_SRAM_VA; - omap_sram_io_desc[0].pfn = __phys_to_pfn(OMAP2_SRAM_PA); + + if (is_sram_locked()) + base = OMAP2_SRAM_PUB_PA; + else + base = OMAP2_SRAM_PA; + base = ROUND_DOWN(base, PAGE_SIZE); + omap_sram_io_desc[0].pfn = __phys_to_pfn(base); } omap_sram_io_desc[0].length = (omap_sram_size + PAGE_SIZE-1)/PAGE_SIZE; @@ -93,7 +190,8 @@ void __init omap_map_sram(void) iotable_init(omap_sram_io_desc, ARRAY_SIZE(omap_sram_io_desc)); printk(KERN_INFO "SRAM: Mapped pa 0x%08lx to va 0x%08lx size: 0x%lx\n", - omap_sram_io_desc[0].pfn, omap_sram_io_desc[0].virtual, + __pfn_to_phys(omap_sram_io_desc[0].pfn), + omap_sram_io_desc[0].virtual, omap_sram_io_desc[0].length); /* @@ -118,8 +216,9 @@ void * omap_sram_push(void * start, unsigned long size) printk(KERN_ERR "Not enough space in SRAM\n"); return NULL; } + omap_sram_ceil -= size; - omap_sram_ceil &= ~0x3; + omap_sram_ceil = ROUND_DOWN(omap_sram_ceil, sizeof(void *)); memcpy((void *)omap_sram_ceil, start, size); return (void *)omap_sram_ceil; diff --git a/arch/arm/plat-omap/timer32k.c b/arch/arm/plat-omap/timer32k.c new file mode 100644 index 000000000000..b2a943bf11ef --- /dev/null +++ b/arch/arm/plat-omap/timer32k.c @@ -0,0 +1,325 @@ +/* + * linux/arch/arm/plat-omap/timer32k.c + * + * OMAP 32K Timer + * + * Copyright (C) 2004 - 2005 Nokia Corporation + * Partial timer rewrite and additional dynamic tick timer support by + * Tony Lindgen <tony@atomide.com> and + * Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> + * + * MPU timer code based on the older MPU timer code for OMAP + * Copyright (C) 2000 RidgeRun, Inc. + * Author: Greg Lonnon <glonnon@ridgerun.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/sched.h> +#include <linux/spinlock.h> +#include <linux/err.h> +#include <linux/clk.h> + +#include <asm/system.h> +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/leds.h> +#include <asm/irq.h> +#include <asm/mach/irq.h> +#include <asm/mach/time.h> + +struct sys_timer omap_timer; + +/* + * --------------------------------------------------------------------------- + * 32KHz OS timer + * + * This currently works only on 16xx, as 1510 does not have the continuous + * 32KHz synchronous timer. The 32KHz synchronous timer is used to keep track + * of time in addition to the 32KHz OS timer. Using only the 32KHz OS timer + * on 1510 would be possible, but the timer would not be as accurate as + * with the 32KHz synchronized timer. + * --------------------------------------------------------------------------- + */ + +#if defined(CONFIG_ARCH_OMAP16XX) +#define TIMER_32K_SYNCHRONIZED 0xfffbc410 +#elif defined(CONFIG_ARCH_OMAP24XX) +#define TIMER_32K_SYNCHRONIZED 0x48004010 +#else +#error OMAP 32KHz timer does not currently work on 15XX! +#endif + +/* 16xx specific defines */ +#define OMAP1_32K_TIMER_BASE 0xfffb9000 +#define OMAP1_32K_TIMER_CR 0x08 +#define OMAP1_32K_TIMER_TVR 0x00 +#define OMAP1_32K_TIMER_TCR 0x04 + +/* 24xx specific defines */ +#define OMAP2_GP_TIMER_BASE 0x48028000 +#define CM_CLKSEL_WKUP 0x48008440 +#define GP_TIMER_TIDR 0x00 +#define GP_TIMER_TISR 0x18 +#define GP_TIMER_TIER 0x1c +#define GP_TIMER_TCLR 0x24 +#define GP_TIMER_TCRR 0x28 +#define GP_TIMER_TLDR 0x2c +#define GP_TIMER_TTGR 0x30 +#define GP_TIMER_TSICR 0x40 + +#define OMAP_32K_TICKS_PER_HZ (32768 / HZ) + +/* + * TRM says 1 / HZ = ( TVR + 1) / 32768, so TRV = (32768 / HZ) - 1 + * so with HZ = 128, TVR = 255. + */ +#define OMAP_32K_TIMER_TICK_PERIOD ((32768 / HZ) - 1) + +#define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate) \ + (((nr_jiffies) * (clock_rate)) / HZ) + +static inline void omap_32k_timer_write(int val, int reg) +{ + if (cpu_class_is_omap1()) + omap_writew(val, OMAP1_32K_TIMER_BASE + reg); + + if (cpu_is_omap24xx()) + omap_writel(val, OMAP2_GP_TIMER_BASE + reg); +} + +static inline unsigned long omap_32k_timer_read(int reg) +{ + if (cpu_class_is_omap1()) + return omap_readl(OMAP1_32K_TIMER_BASE + reg) & 0xffffff; + + if (cpu_is_omap24xx()) + return omap_readl(OMAP2_GP_TIMER_BASE + reg); +} + +/* + * The 32KHz synchronized timer is an additional timer on 16xx. + * It is always running. + */ +static inline unsigned long omap_32k_sync_timer_read(void) +{ + return omap_readl(TIMER_32K_SYNCHRONIZED); +} + +static inline void omap_32k_timer_start(unsigned long load_val) +{ + if (cpu_class_is_omap1()) { + omap_32k_timer_write(load_val, OMAP1_32K_TIMER_TVR); + omap_32k_timer_write(0x0f, OMAP1_32K_TIMER_CR); + } + + if (cpu_is_omap24xx()) { + omap_32k_timer_write(0xffffffff - load_val, GP_TIMER_TCRR); + omap_32k_timer_write((1 << 1), GP_TIMER_TIER); + omap_32k_timer_write((1 << 1) | 1, GP_TIMER_TCLR); + } +} + +static inline void omap_32k_timer_stop(void) +{ + if (cpu_class_is_omap1()) + omap_32k_timer_write(0x0, OMAP1_32K_TIMER_CR); + + if (cpu_is_omap24xx()) + omap_32k_timer_write(0x0, GP_TIMER_TCLR); +} + +/* + * Rounds down to nearest usec. Note that this will overflow for larger values. + */ +static inline unsigned long omap_32k_ticks_to_usecs(unsigned long ticks_32k) +{ + return (ticks_32k * 5*5*5*5*5*5) >> 9; +} + +/* + * Rounds down to nearest nsec. + */ +static inline unsigned long long +omap_32k_ticks_to_nsecs(unsigned long ticks_32k) +{ + return (unsigned long long) ticks_32k * 1000 * 5*5*5*5*5*5 >> 9; +} + +static unsigned long omap_32k_last_tick = 0; + +/* + * Returns elapsed usecs since last 32k timer interrupt + */ +static unsigned long omap_32k_timer_gettimeoffset(void) +{ + unsigned long now = omap_32k_sync_timer_read(); + return omap_32k_ticks_to_usecs(now - omap_32k_last_tick); +} + +/* + * Returns current time from boot in nsecs. It's OK for this to wrap + * around for now, as it's just a relative time stamp. + */ +unsigned long long sched_clock(void) +{ + return omap_32k_ticks_to_nsecs(omap_32k_sync_timer_read()); +} + +/* + * Timer interrupt for 32KHz timer. When dynamic tick is enabled, this + * function is also called from other interrupts to remove latency + * issues with dynamic tick. In the dynamic tick case, we need to lock + * with irqsave. + */ +static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id, + struct pt_regs *regs) +{ + unsigned long flags; + unsigned long now; + + write_seqlock_irqsave(&xtime_lock, flags); + + if (cpu_is_omap24xx()) { + u32 status = omap_32k_timer_read(GP_TIMER_TISR); + omap_32k_timer_write(status, GP_TIMER_TISR); + } + + now = omap_32k_sync_timer_read(); + + while (now - omap_32k_last_tick >= OMAP_32K_TICKS_PER_HZ) { + omap_32k_last_tick += OMAP_32K_TICKS_PER_HZ; + timer_tick(regs); + } + + /* Restart timer so we don't drift off due to modulo or dynamic tick. + * By default we program the next timer to be continuous to avoid + * latencies during high system load. During dynamic tick operation the + * continuous timer can be overridden from pm_idle to be longer. + */ + omap_32k_timer_start(omap_32k_last_tick + OMAP_32K_TICKS_PER_HZ - now); + write_sequnlock_irqrestore(&xtime_lock, flags); + + return IRQ_HANDLED; +} + +#ifdef CONFIG_NO_IDLE_HZ +/* + * Programs the next timer interrupt needed. Called when dynamic tick is + * enabled, and to reprogram the ticks to skip from pm_idle. Note that + * we can keep the timer continuous, and don't need to set it to run in + * one-shot mode. This is because the timer will get reprogrammed again + * after next interrupt. + */ +void omap_32k_timer_reprogram(unsigned long next_tick) +{ + omap_32k_timer_start(JIFFIES_TO_HW_TICKS(next_tick, 32768) + 1); +} + +static struct irqaction omap_32k_timer_irq; +extern struct timer_update_handler timer_update; + +static int omap_32k_timer_enable_dyn_tick(void) +{ + /* No need to reprogram timer, just use the next interrupt */ + return 0; +} + +static int omap_32k_timer_disable_dyn_tick(void) +{ + omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD); + return 0; +} + +static struct dyn_tick_timer omap_dyn_tick_timer = { + .enable = omap_32k_timer_enable_dyn_tick, + .disable = omap_32k_timer_disable_dyn_tick, + .reprogram = omap_32k_timer_reprogram, + .handler = omap_32k_timer_interrupt, +}; +#endif /* CONFIG_NO_IDLE_HZ */ + +static struct irqaction omap_32k_timer_irq = { + .name = "32KHz timer", + .flags = SA_INTERRUPT | SA_TIMER, + .handler = omap_32k_timer_interrupt, +}; + +static struct clk * gpt1_ick; +static struct clk * gpt1_fck; + +static __init void omap_init_32k_timer(void) +{ +#ifdef CONFIG_NO_IDLE_HZ + omap_timer.dyn_tick = &omap_dyn_tick_timer; +#endif + + if (cpu_class_is_omap1()) + setup_irq(INT_OS_TIMER, &omap_32k_timer_irq); + if (cpu_is_omap24xx()) + setup_irq(37, &omap_32k_timer_irq); + omap_timer.offset = omap_32k_timer_gettimeoffset; + omap_32k_last_tick = omap_32k_sync_timer_read(); + + /* REVISIT: Check 24xx TIOCP_CFG settings after idle works */ + if (cpu_is_omap24xx()) { + omap_32k_timer_write(0, GP_TIMER_TCLR); + omap_writel(0, CM_CLKSEL_WKUP); /* 32KHz clock source */ + + gpt1_ick = clk_get(NULL, "gpt1_ick"); + if (IS_ERR(gpt1_ick)) + printk(KERN_ERR "Could not get gpt1_ick\n"); + else + clk_enable(gpt1_ick); + + gpt1_fck = clk_get(NULL, "gpt1_fck"); + if (IS_ERR(gpt1_fck)) + printk(KERN_ERR "Could not get gpt1_fck\n"); + else + clk_enable(gpt1_fck); + + mdelay(100); /* Wait for clocks to stabilize */ + + omap_32k_timer_write(0x7, GP_TIMER_TISR); + } + + omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD); +} + +/* + * --------------------------------------------------------------------------- + * Timer initialization + * --------------------------------------------------------------------------- + */ +static void __init omap_timer_init(void) +{ + omap_init_32k_timer(); +} + +struct sys_timer omap_timer = { + .init = omap_timer_init, + .offset = NULL, /* Initialized later */ +}; |