From 277d58efadd67e73aa2860e41042d8d7fc750cea Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 6 Dec 2006 17:13:59 -0800 Subject: ARM: OMAP: gpio init section cleanups Minor GPIO cleanups: remove needless #include, and omap_gpio_init() should be __init, as well as all the board init code calling it. Signed-off-by: David Brownell Signed-off-by: Tony Lindgren Signed-off-by: Russell King --- arch/arm/plat-omap/gpio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'arch/arm/plat-omap') diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index 9dc6d3617bd..337455dfe64 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c @@ -13,7 +13,6 @@ #include #include -#include #include #include #include @@ -1545,7 +1544,7 @@ void omap2_gpio_resume_after_retention(void) * This may get called early from board specific init * for boards that have interrupts routed via FPGA. */ -int omap_gpio_init(void) +int __init omap_gpio_init(void) { if (!initialized) return _omap_gpio_init(); -- cgit v1.2.3 From 3151369d7467a37386e955e6f1ba5b9b5bea7500 Mon Sep 17 00:00:00 2001 From: Juha Yrjola Date: Wed, 6 Dec 2006 17:13:47 -0800 Subject: ARM: OMAP: Add DMA IRQ sanity checks Add DMA IRQ sanity checks Signed-off-by: Juha Yrjola Signed-off-by: Tony Lindgren Signed-off-by: Russell King --- arch/arm/plat-omap/dma.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'arch/arm/plat-omap') diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c index f3f84fbf8b8..2d86b106ff3 100644 --- a/arch/arm/plat-omap/dma.c +++ b/arch/arm/plat-omap/dma.c @@ -925,10 +925,17 @@ static int omap2_dma_handle_ch(int ch) { u32 status = OMAP_DMA_CSR_REG(ch); - if (!status) + if (!status) { + if (printk_ratelimit()) + printk(KERN_WARNING "Spurious DMA IRQ for lch %d\n", ch); return 0; - if (unlikely(dma_chan[ch].dev_id == -1)) + } + if (unlikely(dma_chan[ch].dev_id == -1)) { + if (printk_ratelimit()) + printk(KERN_WARNING "IRQ %04x for non-allocated DMA" + "channel %d\n", status, ch); return 0; + } if (unlikely(status & OMAP_DMA_DROP_IRQ)) printk(KERN_INFO "DMA synchronization event drop occurred with device " @@ -959,11 +966,15 @@ static irqreturn_t omap2_dma_irq_handler(int irq, void *dev_id) int i; val = omap_readl(OMAP_DMA4_IRQSTATUS_L0); - - for (i = 1; i <= OMAP_LOGICAL_DMA_CH_COUNT; i++) { - int active = val & (1 << (i - 1)); - if (active) - omap2_dma_handle_ch(i - 1); + if (val == 0) { + if (printk_ratelimit()) + printk(KERN_WARNING "Spurious DMA IRQ\n"); + return IRQ_HANDLED; + } + for (i = 0; i < OMAP_LOGICAL_DMA_CH_COUNT && val != 0; i++) { + if (val & 1) + omap2_dma_handle_ch(i); + val >>= 1; } return IRQ_HANDLED; -- cgit v1.2.3 From 0ce3356394dadc4704d42beb3788d7d78bda8ff2 Mon Sep 17 00:00:00 2001 From: Juha Yrjola Date: Wed, 6 Dec 2006 17:13:49 -0800 Subject: ARM: OMAP: Add function to print clock usecounts Useful for debugging power management code. Signed-off-by: Juha Yrjola Signed-off-by: Tony Lindgren Signed-off-by: Russell King --- arch/arm/plat-omap/clock.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'arch/arm/plat-omap') diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c index f1179ad4be1..3d017b04784 100644 --- a/arch/arm/plat-omap/clock.c +++ b/arch/arm/plat-omap/clock.c @@ -33,6 +33,41 @@ static DEFINE_SPINLOCK(clockfw_lock); static struct clk_functions *arch_clock; +#ifdef CONFIG_PM_DEBUG + +static void print_parents(struct clk *clk) +{ + struct clk *p; + int printed = 0; + + list_for_each_entry(p, &clocks, node) { + if (p->parent == clk && p->usecount) { + if (!clk->usecount && !printed) { + printk("MISMATCH: %s\n", clk->name); + printed = 1; + } + printk("\t%-15s\n", p->name); + } + } +} + +void clk_print_usecounts(void) +{ + unsigned long flags; + struct clk *p; + + spin_lock_irqsave(&clockfw_lock, flags); + list_for_each_entry(p, &clocks, node) { + if (p->usecount) + printk("%-15s: %d\n", p->name, p->usecount); + print_parents(p); + + } + spin_unlock_irqrestore(&clockfw_lock, flags); +} + +#endif + /*------------------------------------------------------------------------- * Standard clock functions defined in include/linux/clk.h *-------------------------------------------------------------------------*/ -- cgit v1.2.3 From 771af222eb98a60629aa1437901c7f266ff4dc89 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 6 Dec 2006 17:13:50 -0800 Subject: ARM: OMAP: FB: add controller platform data Add controller platform data Signed-off-by: Imre Deak Signed-off-by: Juha Yrjola Signed-off-by: Tony Lindgren Signed-off-by: Russell King --- arch/arm/plat-omap/fb.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'arch/arm/plat-omap') diff --git a/arch/arm/plat-omap/fb.c b/arch/arm/plat-omap/fb.c index 56acb8720f7..91ebdafcca3 100644 --- a/arch/arm/plat-omap/fb.c +++ b/arch/arm/plat-omap/fb.c @@ -55,6 +55,11 @@ void omapfb_reserve_mem(void) } } +void omapfb_set_ctrl_platform_data(void *data) +{ + omapfb_config.ctrl_platform_data = data; +} + static inline int omap_init_fb(void) { const struct omap_lcd_config *conf; -- cgit v1.2.3 From 994c84ea526ea1c348f63dc3aa7cfeec931bb612 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 6 Dec 2006 17:14:03 -0800 Subject: ARM: OMAP: h4 must have blinky leds!! This adds generic support for the "debug board" LEDs used by most of TI's OMAP reference boards, and board-specific support for the H4. It's derived from the not-as-generic stuff used by OMAP1 H2/H3/P2. Those should be able to switch easily to this version, and clean up some of the omap1-specific code. In addition to H4 support, one key improvement is supporting not just the "old" ARM debug LED API (with timer and idle LEDs, plus four that can be handy for kernel debugging), but it also supports the "new" generic LED API (most useful for usermode stuff IMO). Either or both APIs can be enabled. Signed-off-by: David Brownell Signed-off-by: Tony Lindgren Signed-off-by: Russell King --- arch/arm/plat-omap/Kconfig | 5 + arch/arm/plat-omap/Makefile | 2 +- arch/arm/plat-omap/debug-leds.c | 319 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 325 insertions(+), 1 deletion(-) create mode 100644 arch/arm/plat-omap/debug-leds.c (limited to 'arch/arm/plat-omap') diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index f2dc363de66..ce8bc3304e1 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -19,6 +19,11 @@ endchoice comment "OMAP Feature Selections" +config OMAP_DEBUG_LEDS + bool + help + For debug card leds on TI reference boards. + config OMAP_RESET_CLOCKS bool "Reset unused clocks during boot" depends on ARCH_OMAP diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile index 2896b454641..4ce277d3485 100644 --- a/arch/arm/plat-omap/Makefile +++ b/arch/arm/plat-omap/Makefile @@ -16,4 +16,4 @@ obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o obj-$(CONFIG_CPU_FREQ) += cpu-omap.o obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o - +obj-$(CONFIG_OMAP_DEBUG_LEDS) += debug-leds.o diff --git a/arch/arm/plat-omap/debug-leds.c b/arch/arm/plat-omap/debug-leds.c new file mode 100644 index 00000000000..511d6a50041 --- /dev/null +++ b/arch/arm/plat-omap/debug-leds.c @@ -0,0 +1,319 @@ +/* + * linux/arch/arm/plat-omap/debug-leds.c + * + * Copyright 2003 by Texas Instruments Incorporated + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + + +/* Many OMAP development platforms reuse the same "debug board"; these + * platforms include H2, H3, H4, and Perseus2. There are 16 LEDs on the + * debug board (all green), accessed through FPGA registers. + * + * The "surfer" expansion board and H2 sample board also have two-color + * green+red LEDs (in parallel), used here for timer and idle indicators + * in preference to the ones on the debug board, for a "Disco LED" effect. + * + * This driver exports either the original ARM LED API, the new generic + * one, or both. + */ + +static spinlock_t lock; +static struct h2p2_dbg_fpga __iomem *fpga; +static u16 led_state, hw_led_state; + + +#ifdef CONFIG_LEDS +#define old_led_api() 1 +#else +#define old_led_api() 0 +#endif + +#ifdef CONFIG_LEDS_OMAP_DEBUG +#define new_led_api() 1 +#else +#define new_led_api() 0 +#endif + + +/*-------------------------------------------------------------------------*/ + +/* original ARM debug LED API: + * - timer and idle leds (some boards use non-FPGA leds here); + * - up to 4 generic leds, easily accessed in-kernel (any context) + */ + +#define GPIO_LED_RED 3 +#define GPIO_LED_GREEN OMAP_MPUIO(4) + +#define LED_STATE_ENABLED 0x01 +#define LED_STATE_CLAIMED 0x02 +#define LED_TIMER_ON 0x04 + +#define GPIO_IDLE GPIO_LED_GREEN +#define GPIO_TIMER GPIO_LED_RED + +static void h2p2_dbg_leds_event(led_event_t evt) +{ + unsigned long flags; + + spin_lock_irqsave(&lock, flags); + + if (!(led_state & LED_STATE_ENABLED) && evt != led_start) + goto done; + + switch (evt) { + case led_start: + if (fpga) + led_state |= LED_STATE_ENABLED; + break; + + case led_stop: + case led_halted: + /* all leds off during suspend or shutdown */ + + if (!(machine_is_omap_perseus2() || machine_is_omap_h4())) { + omap_set_gpio_dataout(GPIO_TIMER, 0); + omap_set_gpio_dataout(GPIO_IDLE, 0); + } + + __raw_writew(~0, &fpga->leds); + led_state &= ~LED_STATE_ENABLED; + goto done; + + case led_claim: + led_state |= LED_STATE_CLAIMED; + hw_led_state = 0; + break; + + case led_release: + led_state &= ~LED_STATE_CLAIMED; + break; + +#ifdef CONFIG_LEDS_TIMER + case led_timer: + led_state ^= LED_TIMER_ON; + + if (machine_is_omap_perseus2() || machine_is_omap_h4()) + hw_led_state ^= H2P2_DBG_FPGA_P2_LED_TIMER; + else { + omap_set_gpio_dataout(GPIO_TIMER, + led_state & LED_TIMER_ON); + goto done; + } + + break; +#endif + +#ifdef CONFIG_LEDS_CPU + /* LED lit iff busy */ + case led_idle_start: + if (machine_is_omap_perseus2() || machine_is_omap_h4()) + hw_led_state &= ~H2P2_DBG_FPGA_P2_LED_IDLE; + else { + omap_set_gpio_dataout(GPIO_IDLE, 1); + goto done; + } + + break; + + case led_idle_end: + if (machine_is_omap_perseus2() || machine_is_omap_h4()) + hw_led_state |= H2P2_DBG_FPGA_P2_LED_IDLE; + else { + omap_set_gpio_dataout(GPIO_IDLE, 0); + goto done; + } + + break; +#endif + + case led_green_on: + hw_led_state |= H2P2_DBG_FPGA_LED_GREEN; + break; + case led_green_off: + hw_led_state &= ~H2P2_DBG_FPGA_LED_GREEN; + break; + + case led_amber_on: + hw_led_state |= H2P2_DBG_FPGA_LED_AMBER; + break; + case led_amber_off: + hw_led_state &= ~H2P2_DBG_FPGA_LED_AMBER; + break; + + case led_red_on: + hw_led_state |= H2P2_DBG_FPGA_LED_RED; + break; + case led_red_off: + hw_led_state &= ~H2P2_DBG_FPGA_LED_RED; + break; + + case led_blue_on: + hw_led_state |= H2P2_DBG_FPGA_LED_BLUE; + break; + case led_blue_off: + hw_led_state &= ~H2P2_DBG_FPGA_LED_BLUE; + break; + + default: + break; + } + + + /* + * Actually burn the LEDs + */ + if (led_state & LED_STATE_ENABLED) + __raw_writew(~hw_led_state, &fpga->leds); + +done: + spin_unlock_irqrestore(&lock, flags); +} + +/*-------------------------------------------------------------------------*/ + +/* "new" LED API + * - with syfs access and generic triggering + * - not readily accessible to in-kernel drivers + */ + +struct dbg_led { + struct led_classdev cdev; + u16 mask; +}; + +static struct dbg_led dbg_leds[] = { + /* REVISIT at least H2 uses different timer & cpu leds... */ +#ifndef CONFIG_LEDS_TIMER + { .mask = 1 << 0, .cdev.name = "d4:green", }, /* timer */ +#endif +#ifndef CONFIG_LEDS_CPU + { .mask = 1 << 1, .cdev.name = "d5:green", }, /* !idle */ +#endif + { .mask = 1 << 2, .cdev.name = "d6:green", }, + { .mask = 1 << 3, .cdev.name = "d7:green", }, + + { .mask = 1 << 4, .cdev.name = "d8:green", }, + { .mask = 1 << 5, .cdev.name = "d9:green", }, + { .mask = 1 << 6, .cdev.name = "d10:green", }, + { .mask = 1 << 7, .cdev.name = "d11:green", }, + + { .mask = 1 << 8, .cdev.name = "d12:green", }, + { .mask = 1 << 9, .cdev.name = "d13:green", }, + { .mask = 1 << 10, .cdev.name = "d14:green", }, + { .mask = 1 << 11, .cdev.name = "d15:green", }, + +#ifndef CONFIG_LEDS + { .mask = 1 << 12, .cdev.name = "d16:green", }, + { .mask = 1 << 13, .cdev.name = "d17:green", }, + { .mask = 1 << 14, .cdev.name = "d18:green", }, + { .mask = 1 << 15, .cdev.name = "d19:green", }, +#endif +}; + +static void +fpga_led_set(struct led_classdev *cdev, enum led_brightness value) +{ + struct dbg_led *led = container_of(cdev, struct dbg_led, cdev); + unsigned long flags; + + spin_lock_irqsave(&lock, flags); + if (value == LED_OFF) + hw_led_state &= ~led->mask; + else + hw_led_state |= led->mask; + __raw_writew(~hw_led_state, &fpga->leds); + spin_unlock_irqrestore(&lock, flags); +} + +static void __init newled_init(struct device *dev) +{ + unsigned i; + struct dbg_led *led; + int status; + + for (i = 0, led = dbg_leds; i < ARRAY_SIZE(dbg_leds); i++, led++) { + led->cdev.brightness_set = fpga_led_set; + status = led_classdev_register(dev, &led->cdev); + if (status < 0) + break; + } + return; +} + + +/*-------------------------------------------------------------------------*/ + +static int /* __init */ fpga_probe(struct platform_device *pdev) +{ + struct resource *iomem; + + spin_lock_init(&lock); + + iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!iomem) + return -ENODEV; + + fpga = ioremap(iomem->start, H2P2_DBG_FPGA_SIZE); + __raw_writew(~0, &fpga->leds); + + if (old_led_api()) { + leds_event = h2p2_dbg_leds_event; + leds_event(led_start); + } + + if (new_led_api()) { + newled_init(&pdev->dev); + } + + return 0; +} + +static int fpga_suspend_late(struct platform_device *pdev, pm_message_t mesg) +{ + __raw_writew(~0, &fpga->leds); + return 0; +} + +static int fpga_resume_early(struct platform_device *pdev) +{ + __raw_writew(~hw_led_state, &fpga->leds); + return 0; +} + + +static struct platform_driver led_driver = { + .driver.name = "omap_dbg_led", + .probe = fpga_probe, + .suspend_late = fpga_suspend_late, + .resume_early = fpga_resume_early, +}; + +static int __init fpga_init(void) +{ + if (machine_is_omap_h4() + || machine_is_omap_h3() + || machine_is_omap_h2() + || machine_is_omap_perseus2() + ) + return platform_driver_register(&led_driver); + return 0; +} +fs_initcall(fpga_init); -- cgit v1.2.3 From c40fae9525e6c29c87a4f4361ff0a8d67a36e448 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 7 Dec 2006 13:58:10 -0800 Subject: ARM: OMAP: Sync core code with linux-omap This patch syncs omap specific core code with linux-omap. Most of the changes are needed to fix bitrot caused by driver updates in linux-omap tree. Signed-off-by: Tony Lindgren Signed-off-by: Russell King --- arch/arm/plat-omap/Kconfig | 8 ++ arch/arm/plat-omap/Makefile | 3 +- arch/arm/plat-omap/common.c | 8 +- arch/arm/plat-omap/devices.c | 70 ++++++++++++++- arch/arm/plat-omap/dmtimer.c | 2 +- arch/arm/plat-omap/fb.c | 72 ++++++++++++---- arch/arm/plat-omap/sram.c | 77 ++++++++++------- arch/arm/plat-omap/usb.c | 199 ++++++++++++++++++++++++++++++++++--------- 8 files changed, 345 insertions(+), 94 deletions(-) (limited to 'arch/arm/plat-omap') diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index ce8bc3304e1..a347fb5946c 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -62,6 +62,14 @@ config OMAP_MUX_WARNINGS to change the pin multiplexing setup. When there are no warnings printed, it's safe to deselect OMAP_MUX for your product. +config OMAP_MCBSP + bool "McBSP support" + depends on ARCH_OMAP + default y + help + Say Y here if you want support for the OMAP Multichannel + Buffered Serial Port. + choice prompt "System timer" default OMAP_MPU_TIMER diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile index 4ce277d3485..41a3c1cf3bd 100644 --- a/arch/arm/plat-omap/Makefile +++ b/arch/arm/plat-omap/Makefile @@ -3,7 +3,8 @@ # # 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 fb.o +obj-y := common.o sram.o sram-fn.o clock.o devices.o dma.o mux.o gpio.o \ + usb.o fb.o obj-m := obj-n := obj- := diff --git a/arch/arm/plat-omap/common.c b/arch/arm/plat-omap/common.c index 57b7b93674a..ffb94aa164a 100644 --- a/arch/arm/plat-omap/common.c +++ b/arch/arm/plat-omap/common.c @@ -93,8 +93,12 @@ static const void *get_config(u16 tag, size_t len, int skip, size_t *len_out) * in the kernel. */ for (i = 0; i < omap_board_config_size; i++) { if (omap_board_config[i].tag == tag) { - kinfo = &omap_board_config[i]; - break; + if (skip == 0) { + kinfo = &omap_board_config[i]; + break; + } else { + skip--; + } } } if (kinfo == NULL) diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c index eeb33fed6f7..2fac7d3f2af 100644 --- a/arch/arm/plat-omap/devices.c +++ b/arch/arm/plat-omap/devices.c @@ -25,7 +25,71 @@ #include #include -#if defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE) +#if defined(CONFIG_OMAP_DSP) || defined(CONFIG_OMAP_DSP_MODULE) + +#include "../plat-omap/dsp/dsp_common.h" + +static struct dsp_platform_data dsp_pdata = { + .kdev_list = LIST_HEAD_INIT(dsp_pdata.kdev_list), +}; + +static struct resource omap_dsp_resources[] = { + { + .name = "dsp_mmu", + .start = -1, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device omap_dsp_device = { + .name = "dsp", + .id = -1, + .num_resources = ARRAY_SIZE(omap_dsp_resources), + .resource = omap_dsp_resources, + .dev = { + .platform_data = &dsp_pdata, + }, +}; + +static inline void omap_init_dsp(void) +{ + struct resource *res; + int irq; + + if (cpu_is_omap15xx()) + irq = INT_1510_DSP_MMU; + else if (cpu_is_omap16xx()) + irq = INT_1610_DSP_MMU; + else if (cpu_is_omap24xx()) + irq = INT_24XX_DSP_MMU; + + res = platform_get_resource_byname(&omap_dsp_device, + IORESOURCE_IRQ, "dsp_mmu"); + res->start = irq; + + platform_device_register(&omap_dsp_device); +} + +int dsp_kfunc_device_register(struct dsp_kfunc_device *kdev) +{ + static DEFINE_MUTEX(dsp_pdata_lock); + + mutex_init(&kdev->lock); + + mutex_lock(&dsp_pdata_lock); + list_add_tail(&kdev->entry, &dsp_pdata.kdev_list); + mutex_unlock(&dsp_pdata_lock); + + return 0; +} +EXPORT_SYMBOL(dsp_kfunc_device_register); + +#else +static inline void omap_init_dsp(void) { } +#endif /* CONFIG_OMAP_DSP */ + +/*-------------------------------------------------------------------------*/ +#if defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE) #define OMAP1_I2C_BASE 0xfffb3800 #define OMAP2_I2C_BASE1 0x48070000 @@ -376,7 +440,7 @@ static inline void omap_init_wdt(void) {} /*-------------------------------------------------------------------------*/ -#if defined(CONFIG_OMAP_RNG) || defined(CONFIG_OMAP_RNG_MODULE) +#if defined(CONFIG_HW_RANDOM_OMAP) || defined(CONFIG_HW_RANDOM_OMAP_MODULE) #ifdef CONFIG_ARCH_OMAP24XX #define OMAP_RNG_BASE 0x480A0000 @@ -436,6 +500,7 @@ 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_dsp(); omap_init_i2c(); omap_init_kp(); omap_init_mmc(); @@ -446,4 +511,3 @@ static int __init omap_init_devices(void) return 0; } arch_initcall(omap_init_devices); - diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index 659619f235c..36073dfaa4d 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -372,7 +372,7 @@ void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) /* When the functional clock disappears, too quick writes seem to * cause an abort. */ - __delay(15000); + __delay(150000); } #endif diff --git a/arch/arm/plat-omap/fb.c b/arch/arm/plat-omap/fb.c index 91ebdafcca3..a302d9194f5 100644 --- a/arch/arm/plat-omap/fb.c +++ b/arch/arm/plat-omap/fb.c @@ -1,3 +1,26 @@ +/* + * File: arch/arm/plat-omap/fb.c + * + * Framebuffer device registration for TI OMAP platforms + * + * Copyright (C) 2006 Nokia Corporation + * Author: Imre Deak + * + * 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 program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * 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., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + #include #include #include @@ -34,25 +57,42 @@ static struct platform_device omap_fb_device = { void omapfb_reserve_mem(void) { const struct omap_fbmem_config *fbmem_conf; + unsigned long total_size; + int i; + + if (!omap_fb_sram_valid) { + /* FBMEM SRAM configuration was already found to be invalid. + * Ignore the whole configuration block. */ + omapfb_config.mem_desc.region_cnt = 0; + return; + } + + i = 0; + total_size = 0; + while ((fbmem_conf = omap_get_nr_config(OMAP_TAG_FBMEM, + struct omap_fbmem_config, i)) != NULL) { + unsigned long start; + unsigned long size; - 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); + if (i == OMAPFB_PLANE_NUM) { + printk(KERN_ERR "ignoring extra plane info\n"); + break; } + start = fbmem_conf->start; + size = fbmem_conf->size; + omapfb_config.mem_desc.region[i].paddr = start; + omapfb_config.mem_desc.region[i].size = size; + if (omap_fb_sram_plane != i && start) { + reserve_bootmem(start, size); + total_size += size; + } + i++; } + omapfb_config.mem_desc.region_cnt = i; + if (total_size) + pr_info("Reserving %lu bytes SDRAM for frame buffer\n", + total_size); + } void omapfb_set_ctrl_platform_data(void *data) diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c index 19014b2ff4c..7e5f8877e05 100644 --- a/arch/arm/plat-omap/sram.c +++ b/arch/arm/plat-omap/sram.c @@ -46,12 +46,13 @@ #define ROUND_DOWN(value,boundary) ((value) & (~((boundary)-1))) +static unsigned long omap_sram_start; 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; +int omap_fb_sram_plane = -1; +int omap_fb_sram_valid; /* 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 @@ -77,30 +78,43 @@ static int is_sram_locked(void) 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) +static int get_fb_sram_conf(unsigned long start_avail, unsigned size_avail, + unsigned long *start, int *plane_idx) { 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; + unsigned long size = 0; + int i; + + i = 0; + *start = 0; + *plane_idx = -1; + while ((fbmem_conf = omap_get_nr_config(OMAP_TAG_FBMEM, + struct omap_fbmem_config, i)) != NULL) { + u32 paddr, end; + + paddr = fbmem_conf->start; + end = fbmem_conf->start + fbmem_conf->size; + if (paddr > omap_sram_start && + paddr < omap_sram_start + omap_sram_size) { + if (*plane_idx != -1 || paddr < start_avail || + paddr == end || + end > start_avail + size_avail) { + printk(KERN_ERR "invalid FB SRAM configuration"); + *start = 0; + return -1; + } + *plane_idx = i; + *start = fbmem_conf->start; + size = fbmem_conf->size; + } + i++; } - 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 (*plane_idx >= 0) + pr_info("Reserving %lu bytes SRAM frame buffer " + "for plane %d\n", size, *plane_idx); - if (*size) - pr_info("Reserving %lu bytes SRAM for frame buffer\n", *size); + return 0; } /* @@ -111,16 +125,16 @@ void get_fb_sram_conf(unsigned long start_avail, unsigned size_avail, */ void __init omap_detect_sram(void) { - unsigned long sram_start; + unsigned long fb_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_start = OMAP2_SRAM_PUB_PA; omap_sram_size = 0x800; /* 2K */ } else { omap_sram_base = OMAP2_SRAM_VA; - sram_start = OMAP2_SRAM_PA; + omap_sram_start = OMAP2_SRAM_PA; if (cpu_is_omap242x()) omap_sram_size = 0xa0000; /* 640K */ else if (cpu_is_omap243x()) @@ -128,7 +142,7 @@ void __init omap_detect_sram(void) } } else { omap_sram_base = OMAP1_SRAM_VA; - sram_start = OMAP1_SRAM_PA; + omap_sram_start = OMAP1_SRAM_PA; if (cpu_is_omap730()) omap_sram_size = 0x32000; /* 200K */ @@ -144,12 +158,13 @@ void __init omap_detect_sram(void) 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; + if (get_fb_sram_conf(omap_sram_start + SRAM_BOOTLOADER_SZ, + omap_sram_size - SRAM_BOOTLOADER_SZ, + &fb_sram_start, &omap_fb_sram_plane) == 0) + omap_fb_sram_valid = 1; + if (omap_fb_sram_valid && omap_fb_sram_plane >= 0) + omap_sram_size -= omap_sram_start + omap_sram_size - + fb_sram_start; omap_sram_ceil = omap_sram_base + omap_sram_size; } diff --git a/arch/arm/plat-omap/usb.c b/arch/arm/plat-omap/usb.c index 7e8096809be..25489aafb11 100644 --- a/arch/arm/plat-omap/usb.c +++ b/arch/arm/plat-omap/usb.c @@ -37,9 +37,27 @@ #include #include +#ifdef CONFIG_ARCH_OMAP1 + +#define INT_USB_IRQ_GEN IH2_BASE + 20 +#define INT_USB_IRQ_NISO IH2_BASE + 30 +#define INT_USB_IRQ_ISO IH2_BASE + 29 +#define INT_USB_IRQ_HGEN INT_USB_HHC_1 +#define INT_USB_IRQ_OTG IH2_BASE + 8 + +#else + +#define INT_USB_IRQ_GEN INT_24XX_USB_IRQ_GEN +#define INT_USB_IRQ_NISO INT_24XX_USB_IRQ_NISO +#define INT_USB_IRQ_ISO INT_24XX_USB_IRQ_ISO +#define INT_USB_IRQ_HGEN INT_24XX_USB_IRQ_HGEN +#define INT_USB_IRQ_OTG INT_24XX_USB_IRQ_OTG + +#endif + + /* These routines should handle the standard chip-specific modes * for usb0/1/2 ports, covering basic mux and transceiver setup. - * Call omap_usb_init() once, from INIT_MACHINE(). * * Some board-*.c files will need to set up additional mux options, * like for suspend handling, vbus sensing, GPIOs, and the D+ pullup. @@ -96,19 +114,26 @@ static u32 __init omap_usb0_init(unsigned nwires, unsigned is_device) { u32 syscon1 = 0; + if (cpu_is_omap24xx()) + CONTROL_DEVCONF_REG &= ~USBT0WRMODEI(USB_BIDIR_TLL); + if (nwires == 0) { - if (!cpu_is_omap15xx()) { + if (cpu_class_is_omap1() && !cpu_is_omap15xx()) { /* pulldown D+/D- */ USB_TRANSCEIVER_CTRL_REG &= ~(3 << 1); } return 0; } - if (is_device) - omap_cfg_reg(W4_USB_PUEN); + if (is_device) { + if (cpu_is_omap24xx()) + omap_cfg_reg(J20_24XX_USB0_PUEN); + else + omap_cfg_reg(W4_USB_PUEN); + } - /* internal transceiver */ - if (nwires == 2) { + /* internal transceiver (unavailable on 17xx, 24xx) */ + if (!cpu_class_is_omap2() && nwires == 2) { // omap_cfg_reg(P9_USB_DP); // omap_cfg_reg(R8_USB_DM); @@ -136,29 +161,50 @@ static u32 __init omap_usb0_init(unsigned nwires, unsigned is_device) return 0; } - omap_cfg_reg(V6_USB0_TXD); - omap_cfg_reg(W9_USB0_TXEN); - omap_cfg_reg(W5_USB0_SE0); + if (cpu_is_omap24xx()) { + omap_cfg_reg(K18_24XX_USB0_DAT); + omap_cfg_reg(K19_24XX_USB0_TXEN); + omap_cfg_reg(J14_24XX_USB0_SE0); + if (nwires != 3) + omap_cfg_reg(J18_24XX_USB0_RCV); + } else { + omap_cfg_reg(V6_USB0_TXD); + omap_cfg_reg(W9_USB0_TXEN); + omap_cfg_reg(W5_USB0_SE0); + if (nwires != 3) + omap_cfg_reg(Y5_USB0_RCV); + } - /* NOTE: SPEED and SUSP aren't configured here */ + /* NOTE: SPEED and SUSP aren't configured here. OTG hosts + * may be able to use I2C requests to set those bits along + * with VBUS switching and overcurrent detction. + */ - if (nwires != 3) - omap_cfg_reg(Y5_USB0_RCV); - if (nwires != 6) + if (cpu_class_is_omap1() && nwires != 6) USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB2_UNI_R; switch (nwires) { case 3: syscon1 = 2; + if (cpu_is_omap24xx()) + CONTROL_DEVCONF_REG |= USBT0WRMODEI(USB_BIDIR); break; case 4: syscon1 = 1; + if (cpu_is_omap24xx()) + CONTROL_DEVCONF_REG |= USBT0WRMODEI(USB_BIDIR); break; case 6: syscon1 = 3; - omap_cfg_reg(AA9_USB0_VP); - omap_cfg_reg(R9_USB0_VM); - USB_TRANSCEIVER_CTRL_REG |= CONF_USB2_UNI_R; + if (cpu_is_omap24xx()) { + omap_cfg_reg(J19_24XX_USB0_VP); + omap_cfg_reg(K20_24XX_USB0_VM); + CONTROL_DEVCONF_REG |= USBT0WRMODEI(USB_UNIDIR); + } else { + omap_cfg_reg(AA9_USB0_VP); + omap_cfg_reg(R9_USB0_VM); + USB_TRANSCEIVER_CTRL_REG |= CONF_USB2_UNI_R; + } break; default: printk(KERN_ERR "illegal usb%d %d-wire transceiver\n", @@ -171,14 +217,22 @@ static u32 __init omap_usb1_init(unsigned nwires) { u32 syscon1 = 0; - if (nwires != 6 && !cpu_is_omap15xx()) + if (cpu_class_is_omap1() && !cpu_is_omap15xx() && nwires != 6) USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB1_UNI_R; + if (cpu_is_omap24xx()) + CONTROL_DEVCONF_REG &= ~USBT1WRMODEI(USB_BIDIR_TLL); + if (nwires == 0) return 0; /* external transceiver */ - omap_cfg_reg(USB1_TXD); - omap_cfg_reg(USB1_TXEN); + if (cpu_class_is_omap1()) { + omap_cfg_reg(USB1_TXD); + omap_cfg_reg(USB1_TXEN); + if (nwires != 3) + omap_cfg_reg(USB1_RCV); + } + if (cpu_is_omap15xx()) { omap_cfg_reg(USB1_SEO); omap_cfg_reg(USB1_SPEED); @@ -190,20 +244,38 @@ static u32 __init omap_usb1_init(unsigned nwires) } else if (cpu_is_omap1710()) { omap_cfg_reg(R13_1710_USB1_SE0); // SUSP + } else if (cpu_is_omap24xx()) { + /* NOTE: board-specific code must set up pin muxing for usb1, + * since each signal could come out on either of two balls. + */ } else { - pr_debug("usb unrecognized\n"); + pr_debug("usb%d cpu unrecognized\n", 1); + return 0; } - if (nwires != 3) - omap_cfg_reg(USB1_RCV); switch (nwires) { + case 2: + if (!cpu_is_omap24xx()) + goto bad; + /* NOTE: board-specific code must override this setting if + * this TLL link is not using DP/DM + */ + syscon1 = 1; + CONTROL_DEVCONF_REG |= USBT1WRMODEI(USB_BIDIR_TLL); + break; case 3: syscon1 = 2; + if (cpu_is_omap24xx()) + CONTROL_DEVCONF_REG |= USBT1WRMODEI(USB_BIDIR); break; case 4: syscon1 = 1; + if (cpu_is_omap24xx()) + CONTROL_DEVCONF_REG |= USBT1WRMODEI(USB_BIDIR); break; case 6: + if (cpu_is_omap24xx()) + goto bad; syscon1 = 3; omap_cfg_reg(USB1_VP); omap_cfg_reg(USB1_VM); @@ -211,6 +283,7 @@ static u32 __init omap_usb1_init(unsigned nwires) USB_TRANSCEIVER_CTRL_REG |= CONF_USB1_UNI_R; break; default: +bad: printk(KERN_ERR "illegal usb%d %d-wire transceiver\n", 1, nwires); } @@ -221,10 +294,17 @@ static u32 __init omap_usb2_init(unsigned nwires, unsigned alt_pingroup) { u32 syscon1 = 0; - /* NOTE erratum: must leave USB2_UNI_R set if usb0 in use */ + if (cpu_is_omap24xx()) { + CONTROL_DEVCONF_REG &= ~(USBT2WRMODEI(USB_BIDIR_TLL) + | USBT2TLL5PI); + alt_pingroup = 0; + } + + /* NOTE omap1 erratum: must leave USB2_UNI_R set if usb0 in use */ if (alt_pingroup || nwires == 0) return 0; - if (nwires != 6 && !cpu_is_omap15xx()) + + if (cpu_class_is_omap1() && !cpu_is_omap15xx() && nwires != 6) USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB2_UNI_R; /* external transceiver */ @@ -242,19 +322,54 @@ static u32 __init omap_usb2_init(unsigned nwires, unsigned alt_pingroup) if (nwires != 3) omap_cfg_reg(Y5_USB2_RCV); // FIXME omap_cfg_reg(USB2_SPEED); + } else if (cpu_is_omap24xx()) { + omap_cfg_reg(Y11_24XX_USB2_DAT); + omap_cfg_reg(AA10_24XX_USB2_SE0); + if (nwires > 2) + omap_cfg_reg(AA12_24XX_USB2_TXEN); + if (nwires > 3) + omap_cfg_reg(AA6_24XX_USB2_RCV); } else { - pr_debug("usb unrecognized\n"); + pr_debug("usb%d cpu unrecognized\n", 1); + return 0; } - // omap_cfg_reg(USB2_SUSP); + // if (cpu_class_is_omap1()) omap_cfg_reg(USB2_SUSP); switch (nwires) { + case 2: + if (!cpu_is_omap24xx()) + goto bad; + /* NOTE: board-specific code must override this setting if + * this TLL link is not using DP/DM + */ + syscon1 = 1; + CONTROL_DEVCONF_REG |= USBT2WRMODEI(USB_BIDIR_TLL); + break; case 3: syscon1 = 2; + if (cpu_is_omap24xx()) + CONTROL_DEVCONF_REG |= USBT2WRMODEI(USB_BIDIR); break; case 4: syscon1 = 1; + if (cpu_is_omap24xx()) + CONTROL_DEVCONF_REG |= USBT2WRMODEI(USB_BIDIR); + break; + case 5: + if (!cpu_is_omap24xx()) + goto bad; + omap_cfg_reg(AA4_24XX_USB2_TLLSE0); + /* NOTE: board-specific code must override this setting if + * this TLL link is not using DP/DM. Something must also + * set up OTG_SYSCON2.HMC_TLL{ATTACH,SPEED} + */ + syscon1 = 3; + CONTROL_DEVCONF_REG |= USBT2WRMODEI(USB_UNIDIR_TLL) + | USBT2TLL5PI; break; case 6: + if (cpu_is_omap24xx()) + goto bad; syscon1 = 3; if (cpu_is_omap15xx()) { omap_cfg_reg(USB2_VP); @@ -266,6 +381,7 @@ static u32 __init omap_usb2_init(unsigned nwires, unsigned alt_pingroup) } break; default: +bad: printk(KERN_ERR "illegal usb%d %d-wire transceiver\n", 2, nwires); } @@ -294,13 +410,13 @@ static struct resource udc_resources[] = { .end = UDC_BASE + 0xff, .flags = IORESOURCE_MEM, }, { /* general IRQ */ - .start = IH2_BASE + 20, + .start = INT_USB_IRQ_GEN, .flags = IORESOURCE_IRQ, }, { /* PIO IRQ */ - .start = IH2_BASE + 30, + .start = INT_USB_IRQ_NISO, .flags = IORESOURCE_IRQ, }, { /* SOF IRQ */ - .start = IH2_BASE + 29, + .start = INT_USB_IRQ_ISO, .flags = IORESOURCE_IRQ, }, }; @@ -329,11 +445,11 @@ static u64 ohci_dmamask = ~(u32)0; static struct resource ohci_resources[] = { { .start = OMAP_OHCI_BASE, - .end = OMAP_OHCI_BASE + 4096 - 1, + .end = OMAP_OHCI_BASE + 0xff, .flags = IORESOURCE_MEM, }, { - .start = INT_USB_HHC_1, + .start = INT_USB_IRQ_HGEN, .flags = IORESOURCE_IRQ, }, }; @@ -361,7 +477,7 @@ static struct resource otg_resources[] = { .end = OTG_BASE + 0xff, .flags = IORESOURCE_MEM, }, { - .start = IH2_BASE + 8, + .start = INT_USB_IRQ_OTG, .flags = IORESOURCE_IRQ, }, }; @@ -385,7 +501,7 @@ static struct platform_device otg_device = { // FIXME correct answer depends on hmc_mode, -// as does any nonzero value for config->otg port number +// as does (on omap1) any nonzero value for config->otg port number #ifdef CONFIG_USB_GADGET_OMAP #define is_usb0_device(config) 1 #else @@ -426,12 +542,13 @@ omap_otg_init(struct omap_usb_config *config) if (config->otg) syscon |= OTG_EN; #endif - pr_debug("USB_TRANSCEIVER_CTRL_REG = %03x\n", USB_TRANSCEIVER_CTRL_REG); + if (cpu_class_is_omap1()) + pr_debug("USB_TRANSCEIVER_CTRL_REG = %03x\n", USB_TRANSCEIVER_CTRL_REG); pr_debug("OTG_SYSCON_2_REG = %08x\n", syscon); OTG_SYSCON_2_REG = syscon; printk("USB: hmc %d", config->hmc_mode); - if (alt_pingroup) + if (!alt_pingroup) printk(", usb2 alt %d wires", config->pins[2]); else if (config->pins[0]) printk(", usb0 %d wires%s", config->pins[0], @@ -444,10 +561,12 @@ omap_otg_init(struct omap_usb_config *config) printk(", Mini-AB on usb%d", config->otg - 1); printk("\n"); - /* leave USB clocks/controllers off until needed */ - ULPD_SOFT_REQ_REG &= ~SOFT_USB_CLK_REQ; - ULPD_CLOCK_CTRL_REG &= ~USB_MCLK_EN; - ULPD_CLOCK_CTRL_REG |= DIS_USB_PVCI_CLK; + if (cpu_class_is_omap1()) { + /* leave USB clocks/controllers off until needed */ + ULPD_SOFT_REQ_REG &= ~SOFT_USB_CLK_REQ; + ULPD_CLOCK_CTRL_REG &= ~USB_MCLK_EN; + ULPD_CLOCK_CTRL_REG |= DIS_USB_PVCI_CLK; + } syscon = OTG_SYSCON_1_REG; syscon |= HST_IDLE_EN|DEV_IDLE_EN|OTG_IDLE_EN; @@ -585,7 +704,7 @@ omap_usb_init(void) } platform_data = *config; - if (cpu_is_omap730() || cpu_is_omap16xx()) + if (cpu_is_omap730() || cpu_is_omap16xx() || cpu_is_omap24xx()) omap_otg_init(&platform_data); else if (cpu_is_omap15xx()) omap_1510_usb_init(&platform_data); -- cgit v1.2.3 From 340a614ac6766df18cba87ff7e66182193c2bd6d Mon Sep 17 00:00:00 2001 From: Hiroshi DOYU Date: Thu, 7 Dec 2006 15:43:59 -0800 Subject: ARM: OMAP: Add mailbox support for IVA This patch adds a generic mailbox interface for for DSP and IVA (Image Video Accelerator). This patch itself doesn't contain any IVA driver. Signed-off-by: Hiroshi DOYU Signed-off-by: Juha Yrjola Signed-off-by: Tony Lindgren Signed-off-by: Russell King --- arch/arm/plat-omap/mailbox.c | 509 +++++++++++++++++++++++++++++++++++++++++++ arch/arm/plat-omap/mailbox.h | 100 +++++++++ 2 files changed, 609 insertions(+) create mode 100644 arch/arm/plat-omap/mailbox.c create mode 100644 arch/arm/plat-omap/mailbox.h (limited to 'arch/arm/plat-omap') diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c new file mode 100644 index 00000000000..de7e6ef48bd --- /dev/null +++ b/arch/arm/plat-omap/mailbox.c @@ -0,0 +1,509 @@ +/* + * OMAP mailbox driver + * + * Copyright (C) 2006 Nokia Corporation. All rights reserved. + * + * Contact: Toshihiro Kobayashi + * Restructured by Hiroshi DOYU + * + * 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 program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mailbox.h" + +static struct omap_mbox *mboxes; +static DEFINE_RWLOCK(mboxes_lock); + +/* Mailbox Sequence Bit function */ +void omap_mbox_init_seq(struct omap_mbox *mbox) +{ + mbox_seq_init(mbox); +} +EXPORT_SYMBOL(omap_mbox_init_seq); + +/* + * message sender + */ +static int __mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void *arg) +{ + int ret = 0, i = 1000; + + while (mbox_fifo_full(mbox)) { + if (mbox->ops->type == OMAP_MBOX_TYPE2) + return -1; + if (--i == 0) + return -1; + udelay(1); + } + + if (arg && mbox->txq->callback) { + ret = mbox->txq->callback(arg); + if (ret) + goto out; + } + + mbox_seq_toggle(mbox, &msg); + mbox_fifo_write(mbox, msg); + out: + return ret; +} + +int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void* arg) +{ + struct request *rq; + struct request_queue *q = mbox->txq->queue; + int ret = 0; + + rq = blk_get_request(q, WRITE, GFP_ATOMIC); + if (unlikely(!rq)) { + ret = -ENOMEM; + goto fail; + } + + rq->data = (void *)msg; + blk_insert_request(q, rq, 0, arg); + + schedule_work(&mbox->txq->work); + fail: + return ret; +} +EXPORT_SYMBOL(omap_mbox_msg_send); + +static void mbox_tx_work(struct work_struct *work) +{ + int ret; + struct request *rq; + struct omap_mbox_queue *mq = container_of(work, + struct omap_mbox_queue, work); + struct omap_mbox *mbox = mq->queue->queuedata; + struct request_queue *q = mbox->txq->queue; + + while (1) { + spin_lock(q->queue_lock); + rq = elv_next_request(q); + spin_unlock(q->queue_lock); + + if (!rq) + break; + + ret = __mbox_msg_send(mbox, (mbox_msg_t) rq->data, rq->special); + if (ret) { + enable_mbox_irq(mbox, IRQ_TX); + return; + } + + spin_lock(q->queue_lock); + blkdev_dequeue_request(rq); + end_that_request_last(rq, 0); + spin_unlock(q->queue_lock); + } +} + +/* + * Message receiver(workqueue) + */ +static void mbox_rx_work(struct work_struct *work) +{ + struct omap_mbox_queue *mq = + container_of(work, struct omap_mbox_queue, work); + struct omap_mbox *mbox = mq->queue->queuedata; + struct request_queue *q = mbox->rxq->queue; + struct request *rq; + mbox_msg_t msg; + unsigned long flags; + + if (mbox->rxq->callback == NULL) { + sysfs_notify(&mbox->dev.kobj, NULL, "mbox"); + return; + } + + while (1) { + spin_lock_irqsave(q->queue_lock, flags); + rq = elv_next_request(q); + spin_unlock_irqrestore(q->queue_lock, flags); + if (!rq) + break; + + msg = (mbox_msg_t) rq->data; + + spin_lock_irqsave(q->queue_lock, flags); + blkdev_dequeue_request(rq); + end_that_request_last(rq, 0); + spin_unlock_irqrestore(q->queue_lock, flags); + + mbox->rxq->callback((void *)msg); + } +} + +/* + * Mailbox interrupt handler + */ +static void mbox_txq_fn(request_queue_t * q) +{ +} + +static void mbox_rxq_fn(request_queue_t * q) +{ +} + +static void __mbox_tx_interrupt(struct omap_mbox *mbox) +{ + disable_mbox_irq(mbox, IRQ_TX); + ack_mbox_irq(mbox, IRQ_TX); + schedule_work(&mbox->txq->work); +} + +static void __mbox_rx_interrupt(struct omap_mbox *mbox) +{ + struct request *rq; + mbox_msg_t msg; + request_queue_t *q = mbox->rxq->queue; + + disable_mbox_irq(mbox, IRQ_RX); + + while (!mbox_fifo_empty(mbox)) { + rq = blk_get_request(q, WRITE, GFP_ATOMIC); + if (unlikely(!rq)) + goto nomem; + + msg = mbox_fifo_read(mbox); + rq->data = (void *)msg; + + if (unlikely(mbox_seq_test(mbox, msg))) { + pr_info("mbox: Illegal seq bit!(%08x)\n", msg); + if (mbox->err_notify) + mbox->err_notify(); + } + + blk_insert_request(q, rq, 0, NULL); + if (mbox->ops->type == OMAP_MBOX_TYPE1) + break; + } + + /* no more messages in the fifo. clear IRQ source. */ + ack_mbox_irq(mbox, IRQ_RX); + enable_mbox_irq(mbox, IRQ_RX); + nomem: + schedule_work(&mbox->rxq->work); +} + +static irqreturn_t mbox_interrupt(int irq, void *p) +{ + struct omap_mbox *mbox = (struct omap_mbox *)p; + + if (is_mbox_irq(mbox, IRQ_TX)) + __mbox_tx_interrupt(mbox); + + if (is_mbox_irq(mbox, IRQ_RX)) + __mbox_rx_interrupt(mbox); + + return IRQ_HANDLED; +} + +/* + * sysfs files + */ +static ssize_t +omap_mbox_write(struct device *dev, struct device_attribute *attr, + const char * buf, size_t count) +{ + int ret; + mbox_msg_t *p = (mbox_msg_t *)buf; + struct omap_mbox *mbox = dev_get_drvdata(dev); + + for (; count >= sizeof(mbox_msg_t); count -= sizeof(mbox_msg_t)) { + ret = omap_mbox_msg_send(mbox, be32_to_cpu(*p), NULL); + if (ret) + return -EAGAIN; + p++; + } + + return (size_t)((char *)p - buf); +} + +static ssize_t +omap_mbox_read(struct device *dev, struct device_attribute *attr, char *buf) +{ + unsigned long flags; + struct request *rq; + mbox_msg_t *p = (mbox_msg_t *) buf; + struct omap_mbox *mbox = dev_get_drvdata(dev); + struct request_queue *q = mbox->rxq->queue; + + while (1) { + spin_lock_irqsave(q->queue_lock, flags); + rq = elv_next_request(q); + spin_unlock_irqrestore(q->queue_lock, flags); + + if (!rq) + break; + + *p = (mbox_msg_t) rq->data; + + spin_lock_irqsave(q->queue_lock, flags); + blkdev_dequeue_request(rq); + end_that_request_last(rq, 0); + spin_unlock_irqrestore(q->queue_lock, flags); + + if (unlikely(mbox_seq_test(mbox, *p))) { + pr_info("mbox: Illegal seq bit!(%08x) ignored\n", *p); + continue; + } + p++; + } + + pr_debug("%02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3]); + + return (size_t) ((char *)p - buf); +} + +static DEVICE_ATTR(mbox, S_IRUGO | S_IWUSR, omap_mbox_read, omap_mbox_write); + +static ssize_t mbox_show(struct class *class, char *buf) +{ + return sprintf(buf, "mbox"); +} + +static CLASS_ATTR(mbox, S_IRUGO, mbox_show, NULL); + +static struct class omap_mbox_class = { + .name = "omap_mbox", +}; + +static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox, + request_fn_proc * proc, + void (*work) (struct work_struct *)) +{ + request_queue_t *q; + struct omap_mbox_queue *mq; + + mq = kzalloc(sizeof(struct omap_mbox_queue), GFP_KERNEL); + if (!mq) + return NULL; + + spin_lock_init(&mq->lock); + + q = blk_init_queue(proc, &mq->lock); + if (!q) + goto error; + q->queuedata = mbox; + mq->queue = q; + + INIT_WORK(&mq->work, work); + + return mq; +error: + kfree(mq); + return NULL; +} + +static void mbox_queue_free(struct omap_mbox_queue *q) +{ + blk_cleanup_queue(q->queue); + kfree(q); +} + +static int omap_mbox_init(struct omap_mbox *mbox) +{ + int ret; + struct omap_mbox_queue *mq; + + if (likely(mbox->ops->startup)) { + ret = mbox->ops->startup(mbox); + if (unlikely(ret)) + return ret; + } + + mbox->dev.class = &omap_mbox_class; + strlcpy(mbox->dev.bus_id, mbox->name, KOBJ_NAME_LEN); + dev_set_drvdata(&mbox->dev, mbox); + + ret = device_register(&mbox->dev); + if (unlikely(ret)) + goto fail_device_reg; + + ret = device_create_file(&mbox->dev, &dev_attr_mbox); + if (unlikely(ret)) { + printk(KERN_ERR + "device_create_file failed: %d\n", ret); + goto fail_create_mbox; + } + + ret = request_irq(mbox->irq, mbox_interrupt, IRQF_DISABLED, + mbox->name, mbox); + if (unlikely(ret)) { + printk(KERN_ERR + "failed to register mailbox interrupt:%d\n", ret); + goto fail_request_irq; + } + enable_mbox_irq(mbox, IRQ_RX); + + mq = mbox_queue_alloc(mbox, mbox_txq_fn, mbox_tx_work); + if (!mq) { + ret = -ENOMEM; + goto fail_alloc_txq; + } + mbox->txq = mq; + + mq = mbox_queue_alloc(mbox, mbox_rxq_fn, mbox_rx_work); + if (!mq) { + ret = -ENOMEM; + goto fail_alloc_rxq; + } + mbox->rxq = mq; + + return 0; + + fail_alloc_rxq: + mbox_queue_free(mbox->txq); + fail_alloc_txq: + free_irq(mbox->irq, mbox); + fail_request_irq: + device_remove_file(&mbox->dev, &dev_attr_mbox); + fail_create_mbox: + device_unregister(&mbox->dev); + fail_device_reg: + if (unlikely(mbox->ops->shutdown)) + mbox->ops->shutdown(mbox); + + return ret; +} + +static void omap_mbox_fini(struct omap_mbox *mbox) +{ + mbox_queue_free(mbox->txq); + mbox_queue_free(mbox->rxq); + + free_irq(mbox->irq, mbox); + device_remove_file(&mbox->dev, &dev_attr_mbox); + class_unregister(&omap_mbox_class); + + if (unlikely(mbox->ops->shutdown)) + mbox->ops->shutdown(mbox); +} + +static struct omap_mbox **find_mboxes(const char *name) +{ + struct omap_mbox **p; + + for (p = &mboxes; *p; p = &(*p)->next) { + if (strcmp((*p)->name, name) == 0) + break; + } + + return p; +} + +struct omap_mbox *omap_mbox_get(const char *name) +{ + struct omap_mbox *mbox; + int ret; + + read_lock(&mboxes_lock); + mbox = *(find_mboxes(name)); + if (mbox == NULL) { + read_unlock(&mboxes_lock); + return ERR_PTR(-ENOENT); + } + + read_unlock(&mboxes_lock); + + ret = omap_mbox_init(mbox); + if (ret) + return ERR_PTR(-ENODEV); + + return mbox; +} +EXPORT_SYMBOL(omap_mbox_get); + +void omap_mbox_put(struct omap_mbox *mbox) +{ + omap_mbox_fini(mbox); +} +EXPORT_SYMBOL(omap_mbox_put); + +int omap_mbox_register(struct omap_mbox *mbox) +{ + int ret = 0; + struct omap_mbox **tmp; + + if (!mbox) + return -EINVAL; + if (mbox->next) + return -EBUSY; + + write_lock(&mboxes_lock); + tmp = find_mboxes(mbox->name); + if (*tmp) + ret = -EBUSY; + else + *tmp = mbox; + write_unlock(&mboxes_lock); + + return ret; +} +EXPORT_SYMBOL(omap_mbox_register); + +int omap_mbox_unregister(struct omap_mbox *mbox) +{ + struct omap_mbox **tmp; + + write_lock(&mboxes_lock); + tmp = &mboxes; + while (*tmp) { + if (mbox == *tmp) { + *tmp = mbox->next; + mbox->next = NULL; + write_unlock(&mboxes_lock); + return 0; + } + tmp = &(*tmp)->next; + } + write_unlock(&mboxes_lock); + + return -EINVAL; +} +EXPORT_SYMBOL(omap_mbox_unregister); + +static int __init omap_mbox_class_init(void) +{ + int ret = class_register(&omap_mbox_class); + if (!ret) + ret = class_create_file(&omap_mbox_class, &class_attr_mbox); + + return ret; +} + +static void __exit omap_mbox_class_exit(void) +{ + class_remove_file(&omap_mbox_class, &class_attr_mbox); + class_unregister(&omap_mbox_class); +} + +subsys_initcall(omap_mbox_class_init); +module_exit(omap_mbox_class_exit); + +MODULE_LICENSE("GPL"); diff --git a/arch/arm/plat-omap/mailbox.h b/arch/arm/plat-omap/mailbox.h new file mode 100644 index 00000000000..67c6740b8ad --- /dev/null +++ b/arch/arm/plat-omap/mailbox.h @@ -0,0 +1,100 @@ +/* + * Mailbox internal functions + * + * Copyright (C) 2006 Nokia Corporation + * Written by: Hiroshi DOYU + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef __ARCH_ARM_PLAT_MAILBOX_H +#define __ARCH_ARM_PLAT_MAILBOX_H + +/* + * Mailbox sequence bit API + */ +#if defined(CONFIG_ARCH_OMAP1) +# define MBOX_USE_SEQ_BIT +#elif defined(CONFIG_ARCH_OMAP2) +# define MBOX_USE_SEQ_BIT +#endif + +#ifdef MBOX_USE_SEQ_BIT +/* seq_rcv should be initialized with any value other than + * 0 and 1 << 31, to allow either value for the first + * message. */ +static inline void mbox_seq_init(struct omap_mbox *mbox) +{ + /* any value other than 0 and 1 << 31 */ + mbox->seq_rcv = 0xffffffff; +} + +static inline void mbox_seq_toggle(struct omap_mbox *mbox, mbox_msg_t * msg) +{ + /* add seq_snd to msg */ + *msg = (*msg & 0x7fffffff) | mbox->seq_snd; + /* flip seq_snd */ + mbox->seq_snd ^= 1 << 31; +} + +static inline int mbox_seq_test(struct omap_mbox *mbox, mbox_msg_t msg) +{ + mbox_msg_t seq = msg & (1 << 31); + if (seq == mbox->seq_rcv) + return -1; + mbox->seq_rcv = seq; + return 0; +} +#else +static inline void mbox_seq_init(struct omap_mbox *mbox) +{ +} +static inline void mbox_seq_toggle(struct omap_mbox *mbox, mbox_msg_t * msg) +{ +} +static inline int mbox_seq_test(struct omap_mbox *mbox, mbox_msg_t msg) +{ + return 0; +} +#endif + +/* Mailbox FIFO handle functions */ +static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox) +{ + return mbox->ops->fifo_read(mbox); +} +static inline void mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg) +{ + mbox->ops->fifo_write(mbox, msg); +} +static inline int mbox_fifo_empty(struct omap_mbox *mbox) +{ + return mbox->ops->fifo_empty(mbox); +} +static inline int mbox_fifo_full(struct omap_mbox *mbox) +{ + return mbox->ops->fifo_full(mbox); +} + +/* Mailbox IRQ handle functions */ +static inline void enable_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) +{ + mbox->ops->enable_irq(mbox, irq); +} +static inline void disable_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) +{ + mbox->ops->disable_irq(mbox, irq); +} +static inline void ack_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) +{ + if (mbox->ops->ack_irq) + mbox->ops->ack_irq(mbox, irq); +} +static inline int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) +{ + return mbox->ops->is_irq(mbox, irq); +} + +#endif /* __ARCH_ARM_PLAT_MAILBOX_H */ -- cgit v1.2.3 From d82973d1cdc149d06ac9685ae008105d382c4236 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Fri, 26 Jan 2007 12:01:17 -0800 Subject: ARM: OMAP: Mostly cosmetic to sync up with linux-omap tree Mostly cosmetic to sync up with linux-omap tree Signed-off-by: Tony Lindgren Signed-off-by: Russell King --- arch/arm/plat-omap/devices.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/arm/plat-omap') diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c index 2fac7d3f2af..c5dab1d6417 100644 --- a/arch/arm/plat-omap/devices.c +++ b/arch/arm/plat-omap/devices.c @@ -112,8 +112,8 @@ static struct resource i2c_resources1[] = { /* DMA not used; works around erratum writing to non-empty i2c fifo */ static struct platform_device omap_i2c_device1 = { - .name = "i2c_omap", - .id = 1, + .name = "i2c_omap", + .id = 1, .num_resources = ARRAY_SIZE(i2c_resources1), .resource = i2c_resources1, }; -- cgit v1.2.3 From b7cc6d46b4f8157bfc58a6ed143ffa83575e236a Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 6 Mar 2007 03:16:36 -0800 Subject: ARM: OMAP: FB sync with N800 tree (support for dynamic SRAM allocations) - in addition to fixed FB regions - as passed by the bootloader - allow dynamic allocations - do some more checking against overlapping / reserved regions - move the FB specific parts out from sram.c to fb.c Signed-off-by: Imre Deak Signed-off-by: Tony Lindgren Signed-off-by: Russell King --- arch/arm/plat-omap/fb.c | 277 +++++++++++++++++++++++++++++++++++++++++----- arch/arm/plat-omap/sram.c | 63 +++-------- 2 files changed, 260 insertions(+), 80 deletions(-) (limited to 'arch/arm/plat-omap') diff --git a/arch/arm/plat-omap/fb.c b/arch/arm/plat-omap/fb.c index a302d9194f5..469f580ca05 100644 --- a/arch/arm/plat-omap/fb.c +++ b/arch/arm/plat-omap/fb.c @@ -39,6 +39,8 @@ #if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE) static struct omapfb_platform_data omapfb_config; +static int config_invalid; +static int configured_regions; static u64 omap_fb_dma_mask = ~(u32)0; @@ -53,46 +55,246 @@ static struct platform_device omap_fb_device = { .num_resources = 0, }; -/* called from map_io */ -void omapfb_reserve_mem(void) +static inline int ranges_overlap(unsigned long start1, unsigned long size1, + unsigned long start2, unsigned long size2) { - const struct omap_fbmem_config *fbmem_conf; - unsigned long total_size; + return (start1 >= start2 && start1 < start2 + size2) || + (start2 >= start1 && start2 < start1 + size1); +} + +static inline int range_included(unsigned long start1, unsigned long size1, + unsigned long start2, unsigned long size2) +{ + return start1 >= start2 && start1 + size1 <= start2 + size2; +} + + +/* Check if there is an overlapping region. */ +static int fbmem_region_reserved(unsigned long start, size_t size) +{ + struct omapfb_mem_region *rg; int i; - if (!omap_fb_sram_valid) { - /* FBMEM SRAM configuration was already found to be invalid. - * Ignore the whole configuration block. */ - omapfb_config.mem_desc.region_cnt = 0; - return; + rg = &omapfb_config.mem_desc.region[0]; + for (i = 0; i < OMAPFB_PLANE_NUM; i++, rg++) { + if (!rg->paddr) + /* Empty slot. */ + continue; + if (ranges_overlap(start, size, rg->paddr, rg->size)) + return 1; } + return 0; +} - i = 0; - total_size = 0; - while ((fbmem_conf = omap_get_nr_config(OMAP_TAG_FBMEM, - struct omap_fbmem_config, i)) != NULL) { - unsigned long start; - unsigned long size; +/* + * Get the region_idx`th region from board config/ATAG and convert it to + * our internal format. + */ +static int get_fbmem_region(int region_idx, struct omapfb_mem_region *rg) +{ + const struct omap_fbmem_config *conf; + u32 paddr; - if (i == OMAPFB_PLANE_NUM) { - printk(KERN_ERR "ignoring extra plane info\n"); + conf = omap_get_nr_config(OMAP_TAG_FBMEM, + struct omap_fbmem_config, region_idx); + if (conf == NULL) + return -ENOENT; + + paddr = conf->start; + /* + * Low bits encode the page allocation mode, if high bits + * are zero. Otherwise we need a page aligned fixed + * address. + */ + memset(rg, 0, sizeof(*rg)); + rg->type = paddr & ~PAGE_MASK; + rg->paddr = paddr & PAGE_MASK; + rg->size = PAGE_ALIGN(conf->size); + return 0; +} + +static int set_fbmem_region_type(struct omapfb_mem_region *rg, int mem_type, + unsigned long mem_start, + unsigned long mem_size) +{ + /* + * Check if the configuration specifies the type explicitly. + * type = 0 && paddr = 0, a default don't care case maps to + * the SDRAM type. + */ + if (rg->type || (!rg->type && !rg->paddr)) + return 0; + if (ranges_overlap(rg->paddr, rg->size, mem_start, mem_size)) { + rg->type = mem_type; + return 0; + } + /* Can't determine it. */ + return -1; +} + +static int check_fbmem_region(int region_idx, struct omapfb_mem_region *rg, + unsigned long start_avail, unsigned size_avail) +{ + unsigned long paddr = rg->paddr; + size_t size = rg->size; + + if (rg->type > OMAPFB_MEMTYPE_MAX) { + printk(KERN_ERR + "Invalid start address for FB region %d\n", region_idx); + return -EINVAL; + } + + if (!rg->size) { + printk(KERN_ERR "Zero size for FB region %d\n", region_idx); + return -EINVAL; + } + + if (!paddr) + /* Allocate this dynamically, leave paddr 0 for now. */ + return 0; + + /* + * Fixed region for the given RAM range. Check if it's already + * reserved by the FB code or someone else. + */ + if (fbmem_region_reserved(paddr, size) || + !range_included(paddr, size, start_avail, size_avail)) { + printk(KERN_ERR "Trying to use reserved memory " + "for FB region %d\n", region_idx); + return -EINVAL; + } + + return 0; +} + +/* + * Called from map_io. We need to call to this early enough so that we + * can reserve the fixed SDRAM regions before VM could get hold of them. + */ +void omapfb_reserve_sdram(void) +{ + struct bootmem_data *bdata; + unsigned long sdram_start, sdram_size; + unsigned long reserved; + int i; + + if (config_invalid) + return; + + bdata = NODE_DATA(0)->bdata; + sdram_start = bdata->node_boot_start; + sdram_size = (bdata->node_low_pfn << PAGE_SHIFT) - sdram_start; + reserved = 0; + for (i = 0; ; i++) { + struct omapfb_mem_region rg; + + if (get_fbmem_region(i, &rg) < 0) break; + if (i == OMAPFB_PLANE_NUM) { + printk(KERN_ERR + "Extraneous FB mem configuration entries\n"); + config_invalid = 1; + return; } - start = fbmem_conf->start; - size = fbmem_conf->size; - omapfb_config.mem_desc.region[i].paddr = start; - omapfb_config.mem_desc.region[i].size = size; - if (omap_fb_sram_plane != i && start) { - reserve_bootmem(start, size); - total_size += size; + /* Check if it's our memory type. */ + if (set_fbmem_region_type(&rg, OMAPFB_MEMTYPE_SDRAM, + sdram_start, sdram_size) < 0 || + (rg.type != OMAPFB_MEMTYPE_SDRAM)) + continue; + BUG_ON(omapfb_config.mem_desc.region[i].size); + if (check_fbmem_region(i, &rg, sdram_start, sdram_size) < 0) { + config_invalid = 1; + return; } - i++; + if (rg.paddr) + reserve_bootmem(rg.paddr, rg.size); + reserved += rg.size; + omapfb_config.mem_desc.region[i] = rg; + configured_regions++; } omapfb_config.mem_desc.region_cnt = i; - if (total_size) + if (reserved) pr_info("Reserving %lu bytes SDRAM for frame buffer\n", - total_size); + reserved); +} + +/* + * Called at sram init time, before anything is pushed to the SRAM stack. + * Because of the stack scheme, we will allocate everything from the + * start of the lowest address region to the end of SRAM. This will also + * include padding for page alignment and possible holes between regions. + * + * As opposed to the SDRAM case, we'll also do any dynamic allocations at + * this point, since the driver built as a module would have problem with + * freeing / reallocating the regions. + */ +unsigned long omapfb_reserve_sram(unsigned long sram_pstart, + unsigned long sram_vstart, + unsigned long sram_size, + unsigned long pstart_avail, + unsigned long size_avail) +{ + struct omapfb_mem_region rg; + unsigned long pend_avail; + unsigned long reserved; + int i; + + if (config_invalid) + return 0; + + reserved = 0; + pend_avail = pstart_avail + size_avail; + for (i = 0; ; i++) { + if (get_fbmem_region(i, &rg) < 0) + break; + if (i == OMAPFB_PLANE_NUM) { + printk(KERN_ERR + "Extraneous FB mem configuration entries\n"); + config_invalid = 1; + return 0; + } + /* Check if it's our memory type. */ + if (set_fbmem_region_type(&rg, OMAPFB_MEMTYPE_SRAM, + sram_pstart, sram_size) < 0 || + (rg.type != OMAPFB_MEMTYPE_SRAM)) + continue; + BUG_ON(omapfb_config.mem_desc.region[i].size); + + if (check_fbmem_region(i, &rg, pstart_avail, size_avail) < 0) { + config_invalid = 1; + return 0; + } + + if (!rg.paddr) { + /* Dynamic allocation */ + if ((size_avail & PAGE_MASK) < rg.size) { + printk("Not enough SRAM for FB region %d\n", + i); + config_invalid = 1; + return 0; + } + size_avail = (size_avail - rg.size) & PAGE_MASK; + rg.paddr = pstart_avail + size_avail; + } + /* Reserve everything above the start of the region. */ + if (pend_avail - rg.paddr > reserved) + reserved = pend_avail - rg.paddr; + size_avail = pend_avail - reserved - pstart_avail; + + /* + * We have a kernel mapping for this already, so the + * driver won't have to make one. + */ + rg.vaddr = (void *)(sram_vstart + rg.paddr - sram_pstart); + omapfb_config.mem_desc.region[i] = rg; + configured_regions++; + } + omapfb_config.mem_desc.region_cnt = i; + if (reserved) + pr_info("Reserving %lu bytes SRAM for frame buffer\n", + reserved); + return reserved; } void omapfb_set_ctrl_platform_data(void *data) @@ -104,10 +306,19 @@ static inline int omap_init_fb(void) { const struct omap_lcd_config *conf; + if (config_invalid) + return 0; + if (configured_regions != omapfb_config.mem_desc.region_cnt) { + printk(KERN_ERR "Invalid FB mem configuration entries\n"); + return 0; + } conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config); - if (conf == NULL) + if (conf == NULL) { + if (configured_regions) + /* FB mem config, but no LCD config? */ + printk(KERN_ERR "Missing LCD configuration\n"); return 0; - + } omapfb_config.lcd = *conf; return platform_device_register(&omap_fb_device); @@ -117,7 +328,13 @@ arch_initcall(omap_init_fb); #else -void omapfb_reserve_mem(void) {} +void omapfb_reserve_sdram(void) {} +unsigned long omapfb_reserve_sram(unsigned long sram_pstart, + unsigned long sram_vstart, + unsigned long sram_size, + unsigned long start_avail, + unsigned long size_avail) {} + #endif diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c index 7e5f8877e05..bc46f33aede 100644 --- a/arch/arm/plat-omap/sram.c +++ b/arch/arm/plat-omap/sram.c @@ -51,10 +51,14 @@ static unsigned long omap_sram_base; static unsigned long omap_sram_size; static unsigned long omap_sram_ceil; -int omap_fb_sram_plane = -1; -int omap_fb_sram_valid; +extern unsigned long omapfb_reserve_sram(unsigned long sram_pstart, + unsigned long sram_vstart, + unsigned long sram_size, + unsigned long pstart_avail, + unsigned long size_avail); -/* Depending on the target RAMFS firewall setup, the public usable amount of +/* + * 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. @@ -78,45 +82,6 @@ static int is_sram_locked(void) return 1; /* assume locked with no PPA or security driver */ } -static int get_fb_sram_conf(unsigned long start_avail, unsigned size_avail, - unsigned long *start, int *plane_idx) -{ - const struct omap_fbmem_config *fbmem_conf; - unsigned long size = 0; - int i; - - i = 0; - *start = 0; - *plane_idx = -1; - while ((fbmem_conf = omap_get_nr_config(OMAP_TAG_FBMEM, - struct omap_fbmem_config, i)) != NULL) { - u32 paddr, end; - - paddr = fbmem_conf->start; - end = fbmem_conf->start + fbmem_conf->size; - if (paddr > omap_sram_start && - paddr < omap_sram_start + omap_sram_size) { - if (*plane_idx != -1 || paddr < start_avail || - paddr == end || - end > start_avail + size_avail) { - printk(KERN_ERR "invalid FB SRAM configuration"); - *start = 0; - return -1; - } - *plane_idx = i; - *start = fbmem_conf->start; - size = fbmem_conf->size; - } - i++; - } - - if (*plane_idx >= 0) - pr_info("Reserving %lu bytes SRAM frame buffer " - "for plane %d\n", size, *plane_idx); - - return 0; -} - /* * The amount of SRAM depends on the core type. * Note that we cannot try to test for SRAM here because writes @@ -125,7 +90,7 @@ static int get_fb_sram_conf(unsigned long start_avail, unsigned size_avail, */ void __init omap_detect_sram(void) { - unsigned long fb_sram_start; + unsigned long reserved; if (cpu_is_omap24xx()) { if (is_sram_locked()) { @@ -158,13 +123,11 @@ void __init omap_detect_sram(void) omap_sram_size = 0x4000; } } - if (get_fb_sram_conf(omap_sram_start + SRAM_BOOTLOADER_SZ, - omap_sram_size - SRAM_BOOTLOADER_SZ, - &fb_sram_start, &omap_fb_sram_plane) == 0) - omap_fb_sram_valid = 1; - if (omap_fb_sram_valid && omap_fb_sram_plane >= 0) - omap_sram_size -= omap_sram_start + omap_sram_size - - fb_sram_start; + reserved = omapfb_reserve_sram(omap_sram_start, omap_sram_base, + omap_sram_size, + omap_sram_start + SRAM_BOOTLOADER_SZ, + omap_sram_size - SRAM_BOOTLOADER_SZ); + omap_sram_size -= reserved; omap_sram_ceil = omap_sram_base + omap_sram_size; } -- cgit v1.2.3 From b1465bf7098fa761962f09a6bb2c0e831af85e63 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 6 Mar 2007 03:52:01 -0800 Subject: ARM: OMAP: add SoSSI clock (call propagate_rate for childrens) Clocks with the follow parent rate mode were not updating their children at propagate rate time. Signed-off-by: Imre Deak Signed-off-by: Tony Lindgren Signed-off-by: Russell King --- arch/arm/plat-omap/clock.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/arm/plat-omap') diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c index 3d017b04784..0a603242f36 100644 --- a/arch/arm/plat-omap/clock.c +++ b/arch/arm/plat-omap/clock.c @@ -284,6 +284,8 @@ void followparent_recalc(struct clk *clk) return; clk->rate = clk->parent->rate; + if (unlikely(clk->flags & RATE_PROPAGATES)) + propagate_rate(clk); } /* Propagate rate to children */ -- cgit v1.2.3 From e0b50d3c644f10a0022b23fccb58c8003741db52 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 28 Mar 2007 13:09:36 -0700 Subject: ARM: OMAP: partial LED fixes Partial fix for CONFIG_LEDS breakage ... at least allow platforms using the debug-leds support (H4 for now) to build with the generic LED support, and default the LED that would be the timer LED to trigger using the "heartbeat" (timer driven, rate depends on load). Right now only H2 and P2 seem to have working LED support; this at least makes H4 less broken. Signed-off-by: David Brownell Signed-off-by: Tony Lindgren Signed-off-by: Russell King --- arch/arm/plat-omap/debug-leds.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) (limited to 'arch/arm/plat-omap') diff --git a/arch/arm/plat-omap/debug-leds.c b/arch/arm/plat-omap/debug-leds.c index 511d6a50041..9128a80d228 100644 --- a/arch/arm/plat-omap/debug-leds.c +++ b/arch/arm/plat-omap/debug-leds.c @@ -39,12 +39,6 @@ static struct h2p2_dbg_fpga __iomem *fpga; static u16 led_state, hw_led_state; -#ifdef CONFIG_LEDS -#define old_led_api() 1 -#else -#define old_led_api() 0 -#endif - #ifdef CONFIG_LEDS_OMAP_DEBUG #define new_led_api() 1 #else @@ -202,7 +196,8 @@ struct dbg_led { static struct dbg_led dbg_leds[] = { /* REVISIT at least H2 uses different timer & cpu leds... */ #ifndef CONFIG_LEDS_TIMER - { .mask = 1 << 0, .cdev.name = "d4:green", }, /* timer */ + { .mask = 1 << 0, .cdev.name = "d4:green", + .cdev.default_trigger = "heartbeat", }, #endif #ifndef CONFIG_LEDS_CPU { .mask = 1 << 1, .cdev.name = "d5:green", }, /* !idle */ @@ -274,10 +269,10 @@ static int /* __init */ fpga_probe(struct platform_device *pdev) fpga = ioremap(iomem->start, H2P2_DBG_FPGA_SIZE); __raw_writew(~0, &fpga->leds); - if (old_led_api()) { - leds_event = h2p2_dbg_leds_event; - leds_event(led_start); - } +#ifdef CONFIG_LEDS + leds_event = h2p2_dbg_leds_event; + leds_event(led_start); +#endif if (new_led_api()) { newled_init(&pdev->dev); -- cgit v1.2.3 From cc150b03ae79b20e4c023f71913c1225f8a19a6b Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 28 Mar 2007 16:38:14 -0700 Subject: ARM: OMAP: Fix GCC-reported compile time bug Fix GCC-reported compile time bug which prevents booting when the framebuffer code is disabled. Signed-off-by: David Brownell Signed-off-by: Tony Lindgren Signed-off-by: Russell King --- arch/arm/plat-omap/fb.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'arch/arm/plat-omap') diff --git a/arch/arm/plat-omap/fb.c b/arch/arm/plat-omap/fb.c index 469f580ca05..4493bcff517 100644 --- a/arch/arm/plat-omap/fb.c +++ b/arch/arm/plat-omap/fb.c @@ -333,7 +333,10 @@ unsigned long omapfb_reserve_sram(unsigned long sram_pstart, unsigned long sram_vstart, unsigned long sram_size, unsigned long start_avail, - unsigned long size_avail) {} + unsigned long size_avail) +{ + return 0; +} #endif -- cgit v1.2.3