"Govindraj.R" <govindraj.raja@xxxxxx> writes: > Kevin, > > I have following changes on top of this patch, > 1.) Updated omap_uart_port_info as per your comments. > 2.) Added Errata 2.15 for DMA mode. > 3.) Fix compilation error if omap-serial is enabled with 8250. Thanks! looks great. [...] > > Do you want me to re-post this patch integrating the above changes? > If changes are fine with you. > I need to update my omap_device series on top of latest l-o and Paul's updates so I will incorporate your changes into the next version. Kevin > > On Wed, Nov 25, 2009 at 1:26 AM, Kevin Hilman <khilman@xxxxxxxxxxxxxxxxxxx> wrote: >> Convert UART core and PM support to use omap_device layer. Also add >> support for both console on 8250 or omap-serial driver. >> >> omap_device conversion: >> - Convert clock API calls to omap_device calls >> - Remove all static platform_data setup and configuration. This is >> all done by the omap_device build phase. >> >> Known issues: >> - broken on OMAP4 until OMAP4 UART hwmods are available >> >> Signed-off-by: Kevin Hilman <khilman@xxxxxxxxxxxxxxxxxxx> >> --- >> arch/arm/mach-omap2/serial.c | 338 +++++++++++++++++++----------------------- >> 1 files changed, 154 insertions(+), 184 deletions(-) >> >> diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c >> index 3595ffa..c067416 100644 >> --- a/arch/arm/mach-omap2/serial.c >> +++ b/arch/arm/mach-omap2/serial.c >> @@ -24,20 +24,33 @@ >> #include <linux/io.h> >> #include <linux/platform_device.h> >> >> +#ifdef CONFIG_SERIAL_8250_CONSOLE >> +#include <linux/serial_8250.h> >> +#endif >> + >> +#ifdef CONFIG_SERIAL_OMAP_CONSOLE >> +#include <plat/omap-serial.h> >> +#endif >> + >> #include <plat/common.h> >> #include <plat/board.h> >> #include <plat/clock.h> >> #include <plat/control.h> >> #include <plat/dma.h> >> +#include <plat/omap_hwmod.h> >> +#include <plat/omap_device.h> >> >> #include "prm.h" >> #include "pm.h" >> +#include "cm.h" >> #include "prm-regbits-34xx.h" >> >> #define UART_OMAP_WER 0x17 /* Wake-up enable register */ >> >> #define DEFAULT_TIMEOUT (5 * HZ) >> >> +#define MAX_UART_HWMOD_NAME_LEN 16 >> + >> struct omap_uart_state { >> int num; >> int can_sleep; >> @@ -61,7 +74,8 @@ struct omap_uart_state { >> resource_size_t mapbase; >> >> struct list_head node; >> - struct platform_device pdev; >> + struct omap_hwmod *oh; >> + struct platform_device *pdev; >> >> #if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM) >> int context_valid; >> @@ -78,102 +92,13 @@ struct omap_uart_state { >> >> static LIST_HEAD(uart_list); >> >> -#ifdef CONFIG_SERIAL_8250 >> -#include <linux/serial_8250.h> >> - >> -static struct plat_serial8250_port serial_platform_data0[] = { >> - { >> - .mapbase = OMAP_UART1_BASE, >> - .irq = 72, >> - .flags = UPF_BOOT_AUTOCONF, >> - .iotype = UPIO_MEM, >> - .regshift = 2, >> - .uartclk = OMAP24XX_BASE_BAUD * 16, >> - }, { >> - .flags = 0 >> - } >> -}; >> - >> -static struct plat_serial8250_port serial_platform_data1[] = { >> - { >> - .mapbase = OMAP_UART2_BASE, >> - .irq = 73, >> - .flags = UPF_BOOT_AUTOCONF, >> - .iotype = UPIO_MEM, >> - .regshift = 2, >> - .uartclk = OMAP24XX_BASE_BAUD * 16, >> - }, { >> - .flags = 0 >> - } >> -}; >> - >> -static struct plat_serial8250_port serial_platform_data2[] = { >> +static struct omap_device_pm_latency omap_uart_latency[] = { >> { >> - .mapbase = OMAP_UART3_BASE, >> - .irq = 74, >> - .flags = UPF_BOOT_AUTOCONF, >> - .iotype = UPIO_MEM, >> - .regshift = 2, >> - .uartclk = OMAP24XX_BASE_BAUD * 16, >> - }, { >> - .flags = 0 >> - } >> -}; >> - >> -#ifdef CONFIG_ARCH_OMAP4 >> -static struct plat_serial8250_port serial_platform_data3[] = { >> - { >> - .mapbase = OMAP_UART4_BASE, >> - .irq = 70, >> - .flags = UPF_BOOT_AUTOCONF, >> - .iotype = UPIO_MEM, >> - .regshift = 2, >> - .uartclk = OMAP24XX_BASE_BAUD * 16, >> - }, { >> - .flags = 0 >> - } >> -}; >> -#endif >> - >> -static struct omap_uart_state omap_uart[] = { >> - { >> - .pdev = { >> - .name = "serial8250", >> - .id = PLAT8250_DEV_PLATFORM, >> - .dev = { >> - .platform_data = serial_platform_data0, >> - }, >> - }, >> - }, { >> - .pdev = { >> - .name = "serial8250", >> - .id = PLAT8250_DEV_PLATFORM1, >> - .dev = { >> - .platform_data = serial_platform_data1, >> - }, >> - }, >> - }, { >> - .pdev = { >> - .name = "serial8250", >> - .id = PLAT8250_DEV_PLATFORM2, >> - .dev = { >> - .platform_data = serial_platform_data2, >> - }, >> - }, >> - }, >> -#ifdef CONFIG_ARCH_OMAP4 >> - { >> - .pdev = { >> - .name = "serial8250", >> - .id = 3, >> - .dev = { >> - .platform_data = serial_platform_data3, >> - }, >> - }, >> + .deactivate_func = omap_device_idle_hwmods, >> + .activate_func = omap_device_enable_hwmods, >> + .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST, >> }, >> -#endif >> }; >> -#endif >> >> static inline unsigned int serial_read_reg(struct omap_uart_state *up, >> int offset) >> @@ -200,7 +125,6 @@ static inline void __init omap_uart_reset(struct omap_uart_state *p) >> serial_write_reg(p, UART_OMAP_MDR1, 0x07); >> serial_write_reg(p, UART_OMAP_SCR, 0x08); >> serial_write_reg(p, UART_OMAP_MDR1, 0x00); >> - serial_write_reg(p, UART_OMAP_SYSC, (0x02 << 3) | (1 << 2) | (1 << 0)); >> } >> >> #if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3) >> @@ -267,8 +191,7 @@ static inline void omap_uart_enable_clocks(struct omap_uart_state *uart) >> if (uart->clocked) >> return; >> >> - clk_enable(uart->ick); >> - clk_enable(uart->fck); >> + omap_device_enable(uart->pdev); >> uart->clocked = 1; >> omap_uart_restore_context(uart); >> } >> @@ -282,8 +205,7 @@ static inline void omap_uart_disable_clocks(struct omap_uart_state *uart) >> >> omap_uart_save_context(uart); >> uart->clocked = 0; >> - clk_disable(uart->ick); >> - clk_disable(uart->fck); >> + omap_device_idle(uart->pdev); >> } >> >> static void omap_uart_enable_wakeup(struct omap_uart_state *uart) >> @@ -320,18 +242,18 @@ static void omap_uart_disable_wakeup(struct omap_uart_state *uart) >> } >> } >> >> -static void omap_uart_smart_idle_enable(struct omap_uart_state *p, >> - int enable) >> +static inline void omap_uart_smart_idle_enable(struct omap_uart_state *p, >> + int enable) >> { >> - u16 sysc; >> + u32 sysc; >> >> - sysc = serial_read_reg(p, UART_OMAP_SYSC) & 0x7; >> + sysc = omap_hwmod_read_sysc(p->oh); >> + sysc &= ~SYSC_SIDLEMODE_MASK; >> if (enable) >> - sysc |= 0x2 << 3; >> + sysc |= 0x2 << SYSC_SIDLEMODE_SHIFT; >> else >> - sysc |= 0x1 << 3; >> - >> - serial_write_reg(p, UART_OMAP_SYSC, sysc); >> + sysc |= 0x1 << SYSC_SIDLEMODE_SHIFT; >> + omap_hwmod_write_sysc(sysc, p->oh); >> } >> >> static void omap_uart_block_sleep(struct omap_uart_state *uart) >> @@ -348,7 +270,7 @@ static void omap_uart_block_sleep(struct omap_uart_state *uart) >> >> static void omap_uart_allow_sleep(struct omap_uart_state *uart) >> { >> - if (device_may_wakeup(&uart->pdev.dev)) >> + if (device_may_wakeup(&uart->pdev->dev)) >> omap_uart_enable_wakeup(uart); >> else >> omap_uart_disable_wakeup(uart); >> @@ -443,6 +365,7 @@ int omap_uart_can_sleep(void) >> * UART will not idle or sleep for its timeout period. >> * >> **/ >> +/* static int first_interrupt; */ >> static irqreturn_t omap_uart_interrupt(int irq, void *dev_id) >> { >> struct omap_uart_state *uart = dev_id; >> @@ -516,8 +439,8 @@ static void omap_uart_idle_init(struct omap_uart_state *uart) >> } >> >> uart->irqflags |= IRQF_SHARED; >> - ret = request_irq(uart->irq, omap_uart_interrupt, IRQF_SHARED, >> - "serial idle", (void *)uart); >> + ret = request_threaded_irq(uart->irq, NULL, omap_uart_interrupt, >> + IRQF_SHARED, "serial idle", (void *)uart); >> WARN_ON(ret); >> } >> >> @@ -528,8 +451,11 @@ void omap_uart_enable_irqs(int enable) >> >> list_for_each_entry(uart, &uart_list, node) { >> if (enable) >> - ret = request_irq(uart->irq, omap_uart_interrupt, >> - IRQF_SHARED, "serial idle", (void *)uart); >> + ret = request_threaded_irq(uart->irq, NULL, >> + omap_uart_interrupt, >> + IRQF_SHARED, >> + "serial idle", >> + (void *)uart); >> else >> free_irq(uart->irq, (void *)uart); >> } >> @@ -539,10 +465,9 @@ static ssize_t sleep_timeout_show(struct device *dev, >> struct device_attribute *attr, >> char *buf) >> { >> - struct platform_device *pdev = container_of(dev, >> - struct platform_device, dev); >> - struct omap_uart_state *uart = container_of(pdev, >> - struct omap_uart_state, pdev); >> + struct platform_device *pdev = to_platform_device(dev); >> + struct omap_device *odev = to_omap_device(pdev); >> + struct omap_uart_state *uart = odev->hwmods[0]->dev_attr; >> >> return sprintf(buf, "%u\n", uart->timeout / HZ); >> } >> @@ -551,10 +476,9 @@ static ssize_t sleep_timeout_store(struct device *dev, >> struct device_attribute *attr, >> const char *buf, size_t n) >> { >> - struct platform_device *pdev = container_of(dev, >> - struct platform_device, dev); >> - struct omap_uart_state *uart = container_of(pdev, >> - struct omap_uart_state, pdev); >> + struct platform_device *pdev = to_platform_device(dev); >> + struct omap_device *odev = to_omap_device(pdev); >> + struct omap_uart_state *uart = odev->hwmods[0]->dev_attr; >> unsigned int value; >> >> if (sscanf(buf, "%u", &value) != 1) { >> @@ -582,87 +506,133 @@ static inline void omap_uart_idle_init(struct omap_uart_state *uart) {} >> >> void __init omap_serial_early_init(void) >> { >> - int i; >> - char name[16]; >> - >> - /* >> - * Make sure the serial ports are muxed on at this point. >> - * You have to mux them off in device drivers later on >> - * if not needed. >> - */ >> + int i = 0; >> >> - for (i = 0; i < ARRAY_SIZE(omap_uart); i++) { >> - struct omap_uart_state *uart = &omap_uart[i]; >> + do { >> + char oh_name[MAX_UART_HWMOD_NAME_LEN]; >> + struct omap_hwmod *oh; >> + struct omap_uart_state *uart; >> >> - uart->num = i; >> - >> - /* >> - * Module 4KB + L4 interconnect 4KB >> - * Static mapping, never released >> - */ >> - uart->membase = ioremap(uart->mapbase, SZ_8K); >> - if (!uart->membase) { >> - printk(KERN_ERR "ioremap failed for uart%i\n", i + 1); >> - continue; >> - } >> - >> - sprintf(name, "uart%d_ick", i+1); >> - uart->ick = clk_get(NULL, name); >> - if (IS_ERR(uart->ick)) { >> - printk(KERN_ERR "Could not get uart%d_ick\n", i+1); >> - uart->ick = NULL; >> - } >> - >> - sprintf(name, "uart%d_fck", i+1); >> - uart->fck = clk_get(NULL, name); >> - if (IS_ERR(uart->fck)) { >> - printk(KERN_ERR "Could not get uart%d_fck\n", i+1); >> - uart->fck = NULL; >> - } >> + snprintf(oh_name, MAX_UART_HWMOD_NAME_LEN, >> + "uart%d_hwmod", i + 1); >> + oh = omap_hwmod_lookup(oh_name); >> + if (!oh) >> + break; >> >> - /* FIXME: Remove this once the clkdev is ready */ >> - if (!cpu_is_omap44xx()) { >> - if (!uart->ick || !uart->fck) >> - continue; >> - } >> + uart = kzalloc(sizeof(struct omap_uart_state), GFP_KERNEL); >> + if (WARN_ON(!uart)) >> + return; >> >> + uart->oh = oh; >> + uart->num = i++; >> list_add_tail(&uart->node, &uart_list); >> >> - if (cpu_is_omap44xx()) >> - uart->irq += 32; >> - >> - omap_uart_enable_clocks(uart); >> - } >> + /* NOTE: omap_hwmod_init() has not yet been called, >> + * so no hwmod functions will work yet. */ >> +#ifdef CONFIG_DEBUG_LL >> + /* For DEBUG_LL, don't reset/idle the UARTs otherwise >> + * early UART access will fault. */ >> + uart->oh->flags |= HWMOD_INIT_NO_IDLE; >> +#endif >> + } while(1); >> } >> >> void __init omap_serial_init(void) >> { >> - int i; >> - >> - for (i = 0; i < ARRAY_SIZE(omap_uart); i++) { >> - struct omap_uart_state *uart = &omap_uart[i]; >> - struct platform_device *pdev = &uart->pdev; >> - struct device *dev = &pdev->dev; >> -#ifdef CONFIG_SERIAL_8250 >> - struct plat_serial8250_port *p = dev->platform_data; >> + struct omap_uart_state *uart; >> + >> + list_for_each_entry(uart, &uart_list, node) { >> + struct omap_hwmod *oh = uart->oh; >> + struct omap_device *od; >> + void *pdata = NULL; >> + u32 pdata_size = 0; >> +#ifdef CONFIG_SERIAL_8250_CONSOLE >> + char *name = "serial8250"; >> + struct plat_serial8250_port ports[2] = { >> + {}, >> + {.flags = 0}, >> + }; >> + struct plat_serial8250_port *p = &ports[0]; >> + >> + /* >> + * !! 8250 driver does not use standard IORESOURCE* It >> + * has it's own custom pdata that can be taken from >> + * the hwmod resource data. But, this needs to be >> + * done after the build. >> + * >> + * ?? does it have to be done before the register ?? >> + * YES, because platform_device_data_add() copies >> + * pdata, it does not use a pointer. >> + */ >> + p->flags = UPF_BOOT_AUTOCONF; >> + p->iotype = UPIO_MEM; >> + p->regshift = 2; >> + p->uartclk = OMAP24XX_BASE_BAUD * 16; >> + p->irq = oh->mpu_irqs[0].irq; >> + p->mapbase = oh->slaves[0]->addr->pa_start; >> + p->membase = oh->_rt_va; >> + p->irqflags = IRQF_SHARED; >> + p->private_data = uart; >> + >> + pdata = &ports[0]; >> + pdata_size = 2 * sizeof(struct plat_serial8250_port); >> #endif >> +#ifdef CONFIG_SERIAL_OMAP_CONSOLE >> + struct uart_port_info p; >> + char *name = "omap-hsuart"; >> >> - omap_uart_reset(uart); >> - omap_uart_idle_init(uart); >> + p.dma_enabled = 0; >> + p.uartclk = OMAP24XX_BASE_BAUD * 16; >> >> -#ifdef CONFIG_SERIAL_8250 >> - p->membase = uart->membase; >> - p->mapbase = uart->mapbase; >> - p->irq = uart->irq; >> - p->irqflags = uart->irqflags; >> - p->private_data = uart; >> + pdata = &p; >> + pdata_size = sizeof(struct uart_port_info); >> #endif >> - if (WARN_ON(platform_device_register(pdev))) >> + >> + if (WARN_ON(!oh)) >> continue; >> + >> + od = omap_device_build(name, uart->num, oh, pdata, pdata_size, >> + omap_uart_latency, >> + ARRAY_SIZE(omap_uart_latency)); >> + WARN(IS_ERR(od), "Could not build omap_device for %s: %s.\n", >> + name, oh->name); >> + >> + uart->irq = oh->mpu_irqs[0].irq; >> + uart->regshift = 2; >> + uart->mapbase = oh->slaves[0]->addr->pa_start; >> + uart->membase = oh->_rt_va; >> + uart->pdev = &od->pdev; >> + >> + oh->dev_attr = uart; >> + >> +#ifdef CONFIG_DEBUG_LL >> + /* >> + * Because of earlyprintk output, UART did not get idled >> + * on init. Now that omap_device is ready, ensure full idle >> + * before doing omap_device_enable(). >> + */ >> + omap_hwmod_idle(uart->oh); >> +#endif >> + omap_device_enable(uart->pdev); >> + omap_uart_idle_init(uart); >> + omap_uart_reset(uart); >> + omap_hwmod_enable_wakeup(uart->oh); >> + omap_device_idle(uart->pdev); >> + >> + /* >> + * Need to block sleep long enough for interrupt driven >> + * driver to start. Console driver is in polling mode >> + * so device needs to be kept enabled while polling driver >> + * is in use. >> + */ >> + uart->timeout = (30 * HZ); >> + omap_uart_block_sleep(uart); >> + uart->timeout = DEFAULT_TIMEOUT; >> + >> if ((cpu_is_omap34xx() && uart->padconf) || >> (uart->wk_en && uart->wk_mask)) { >> - device_init_wakeup(dev, true); >> - DEV_CREATE_FILE(dev, &dev_attr_sleep_timeout); >> + device_init_wakeup(&od->pdev.dev, true); >> + DEV_CREATE_FILE(&od->pdev.dev, &dev_attr_sleep_timeout); >> } >> } >> } >> -- >> 1.6.5.1 >> >> -- >> To unsubscribe from this list: send the line "unsubscribe linux-omap" in >> the body of a message to majordomo@xxxxxxxxxxxxxxx >> More majordomo info at http://vger.kernel.org/majordomo-info.html >> -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html