diff options
Diffstat (limited to 'arch/arm/mach-omap2/serial.c')
| -rw-r--r-- | arch/arm/mach-omap2/serial.c | 826 |
1 files changed, 224 insertions, 602 deletions
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index 19805a7de06..a388f8c1bcb 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -19,695 +19,317 @@ */ #include <linux/kernel.h> #include <linux/init.h> -#include <linux/serial_8250.h> -#include <linux/serial_reg.h> #include <linux/clk.h> #include <linux/io.h> - -#include <plat/common.h> -#include <plat/board.h> -#include <plat/clock.h> -#include <plat/control.h> - -#include "prm.h" +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/pm_runtime.h> +#include <linux/console.h> +#include <linux/omap-dma.h> +#include <linux/platform_data/serial-omap.h> + +#include "common.h" +#include "omap_hwmod.h" +#include "omap_device.h" +#include "omap-pm.h" +#include "soc.h" +#include "prm2xxx_3xxx.h" #include "pm.h" +#include "cm2xxx_3xxx.h" #include "prm-regbits-34xx.h" +#include "control.h" +#include "mux.h" +#include "serial.h" -#define UART_OMAP_NO_EMPTY_FIFO_READ_IP_REV 0x52 -#define UART_OMAP_WER 0x17 /* Wake-up enable register */ +/* + * NOTE: By default the serial auto_suspend timeout is disabled as it causes + * lost characters over the serial ports. This means that the UART clocks will + * stay on until power/autosuspend_delay is set for the uart from sysfs. + * This also causes that any deeper omap sleep states are blocked. + */ +#define DEFAULT_AUTOSUSPEND_DELAY -1 -#define DEFAULT_TIMEOUT (5 * HZ) +#define MAX_UART_HWMOD_NAME_LEN 16 struct omap_uart_state { int num; - int can_sleep; - struct timer_list timer; - u32 timeout; - void __iomem *wk_st; - void __iomem *wk_en; - u32 wk_mask; - u32 padconf; - - struct clk *ick; - struct clk *fck; - int clocked; - - struct plat_serial8250_port *p; struct list_head node; - struct platform_device pdev; - -#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM) - int context_valid; - - /* Registers to be saved/restored for OFF-mode */ - u16 dll; - u16 dlh; - u16 ier; - u16 sysc; - u16 scr; - u16 wer; -#endif + struct omap_hwmod *oh; + struct omap_device_pad default_omap_uart_pads[2]; }; static LIST_HEAD(uart_list); +static u8 num_uarts; +static u8 console_uart_id = -1; +static u8 uart_debug; -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[] = { - { - .mapbase = OMAP_UART3_BASE, - .irq = 74, - .flags = UPF_BOOT_AUTOCONF, - .iotype = UPIO_MEM, - .regshift = 2, - .uartclk = OMAP24XX_BASE_BAUD * 16, - }, { - .flags = 0 - } -}; +#define DEFAULT_RXDMA_POLLRATE 1 /* RX DMA polling rate (us) */ +#define DEFAULT_RXDMA_BUFSIZE 4096 /* RX DMA buffer size */ +#define DEFAULT_RXDMA_TIMEOUT (3 * HZ)/* RX DMA timeout (jiffies) */ -#ifdef CONFIG_ARCH_OMAP4 -static struct plat_serial8250_port serial_platform_data3[] = { +static struct omap_uart_port_info omap_serial_default_info[] __initdata = { { - .mapbase = OMAP_UART4_BASE, - .irq = 70, - .flags = UPF_BOOT_AUTOCONF, - .iotype = UPIO_MEM, - .regshift = 2, - .uartclk = OMAP24XX_BASE_BAUD * 16, - }, { - .flags = 0 - } + .dma_enabled = false, + .dma_rx_buf_size = DEFAULT_RXDMA_BUFSIZE, + .dma_rx_poll_rate = DEFAULT_RXDMA_POLLRATE, + .dma_rx_timeout = DEFAULT_RXDMA_TIMEOUT, + .autosuspend_timeout = DEFAULT_AUTOSUSPEND_DELAY, + }, }; -#endif -static inline unsigned int serial_read_reg(struct plat_serial8250_port *up, - int offset) -{ - offset <<= up->regshift; - return (unsigned int)__raw_readb(up->membase + offset); -} - -static inline void serial_write_reg(struct plat_serial8250_port *p, int offset, - int value) -{ - offset <<= p->regshift; - __raw_writeb(value, p->membase + offset); -} -/* - * Internal UARTs need to be initialized for the 8250 autoconfig to work - * properly. Note that the TX watermark initialization may not be needed - * once the 8250.c watermark handling code is merged. - */ -static inline void __init omap_uart_reset(struct omap_uart_state *uart) -{ - struct plat_serial8250_port *p = uart->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) - -static void omap_uart_save_context(struct omap_uart_state *uart) +#ifdef CONFIG_PM +static void omap_uart_enable_wakeup(struct device *dev, bool enable) { - u16 lcr = 0; - struct plat_serial8250_port *p = uart->p; + struct platform_device *pdev = to_platform_device(dev); + struct omap_device *od = to_omap_device(pdev); - if (!enable_off_mode) + if (!od) return; - lcr = serial_read_reg(p, UART_LCR); - serial_write_reg(p, UART_LCR, 0xBF); - uart->dll = serial_read_reg(p, UART_DLL); - uart->dlh = serial_read_reg(p, UART_DLM); - serial_write_reg(p, UART_LCR, lcr); - uart->ier = serial_read_reg(p, UART_IER); - uart->sysc = serial_read_reg(p, UART_OMAP_SYSC); - uart->scr = serial_read_reg(p, UART_OMAP_SCR); - uart->wer = serial_read_reg(p, UART_OMAP_WER); - - uart->context_valid = 1; + if (enable) + omap_hwmod_enable_wakeup(od->hwmods[0]); + else + omap_hwmod_disable_wakeup(od->hwmods[0]); } -static void omap_uart_restore_context(struct omap_uart_state *uart) -{ - u16 efr = 0; - struct plat_serial8250_port *p = uart->p; - - if (!enable_off_mode) - return; - - if (!uart->context_valid) - return; - - uart->context_valid = 0; - - serial_write_reg(p, UART_OMAP_MDR1, 0x7); - serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */ - efr = serial_read_reg(p, UART_EFR); - serial_write_reg(p, UART_EFR, UART_EFR_ECB); - serial_write_reg(p, UART_LCR, 0x0); /* Operational mode */ - serial_write_reg(p, UART_IER, 0x0); - serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */ - serial_write_reg(p, UART_DLL, uart->dll); - serial_write_reg(p, UART_DLM, uart->dlh); - serial_write_reg(p, UART_LCR, 0x0); /* Operational mode */ - serial_write_reg(p, UART_IER, uart->ier); - serial_write_reg(p, UART_FCR, 0xA1); - serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */ - serial_write_reg(p, UART_EFR, efr); - serial_write_reg(p, UART_LCR, UART_LCR_WLEN8); - serial_write_reg(p, UART_OMAP_SCR, uart->scr); - serial_write_reg(p, UART_OMAP_WER, uart->wer); - serial_write_reg(p, UART_OMAP_SYSC, uart->sysc); - serial_write_reg(p, UART_OMAP_MDR1, 0x00); /* UART 16x mode */ -} #else -static inline void omap_uart_save_context(struct omap_uart_state *uart) {} -static inline void omap_uart_restore_context(struct omap_uart_state *uart) {} -#endif /* CONFIG_PM && CONFIG_ARCH_OMAP3 */ - -static inline void omap_uart_enable_clocks(struct omap_uart_state *uart) -{ - if (uart->clocked) - return; +static void omap_uart_enable_wakeup(struct device *dev, bool enable) +{} +#endif /* CONFIG_PM */ - clk_enable(uart->ick); - clk_enable(uart->fck); - uart->clocked = 1; - omap_uart_restore_context(uart); -} +#ifdef CONFIG_OMAP_MUX -#ifdef CONFIG_PM +#define OMAP_UART_DEFAULT_PAD_NAME_LEN 28 +static char rx_pad_name[OMAP_UART_DEFAULT_PAD_NAME_LEN], + tx_pad_name[OMAP_UART_DEFAULT_PAD_NAME_LEN] __initdata; -static inline void omap_uart_disable_clocks(struct omap_uart_state *uart) +static void __init +omap_serial_fill_uart_tx_rx_pads(struct omap_board_data *bdata, + struct omap_uart_state *uart) { - if (!uart->clocked) - return; - - omap_uart_save_context(uart); - uart->clocked = 0; - clk_disable(uart->ick); - clk_disable(uart->fck); + uart->default_omap_uart_pads[0].name = rx_pad_name; + uart->default_omap_uart_pads[0].flags = OMAP_DEVICE_PAD_REMUX | + OMAP_DEVICE_PAD_WAKEUP; + uart->default_omap_uart_pads[0].enable = OMAP_PIN_INPUT | + OMAP_MUX_MODE0; + uart->default_omap_uart_pads[0].idle = OMAP_PIN_INPUT | OMAP_MUX_MODE0; + uart->default_omap_uart_pads[1].name = tx_pad_name; + uart->default_omap_uart_pads[1].enable = OMAP_PIN_OUTPUT | + OMAP_MUX_MODE0; + bdata->pads = uart->default_omap_uart_pads; + bdata->pads_cnt = ARRAY_SIZE(uart->default_omap_uart_pads); } -static void omap_uart_enable_wakeup(struct omap_uart_state *uart) +static void __init omap_serial_check_wakeup(struct omap_board_data *bdata, + struct omap_uart_state *uart) { - /* Set wake-enable bit */ - if (uart->wk_en && uart->wk_mask) { - u32 v = __raw_readl(uart->wk_en); - v |= uart->wk_mask; - __raw_writel(v, uart->wk_en); + struct omap_mux_partition *tx_partition = NULL, *rx_partition = NULL; + struct omap_mux *rx_mux = NULL, *tx_mux = NULL; + char *rx_fmt, *tx_fmt; + int uart_nr = bdata->id + 1; + + if (bdata->id != 2) { + rx_fmt = "uart%d_rx.uart%d_rx"; + tx_fmt = "uart%d_tx.uart%d_tx"; + } else { + rx_fmt = "uart%d_rx_irrx.uart%d_rx_irrx"; + tx_fmt = "uart%d_tx_irtx.uart%d_tx_irtx"; } - /* Ensure IOPAD wake-enables are set */ - if (cpu_is_omap34xx() && uart->padconf) { - u16 v = omap_ctrl_readw(uart->padconf); - v |= OMAP3_PADCONF_WAKEUPENABLE0; - omap_ctrl_writew(v, uart->padconf); - } -} + snprintf(rx_pad_name, OMAP_UART_DEFAULT_PAD_NAME_LEN, rx_fmt, + uart_nr, uart_nr); + snprintf(tx_pad_name, OMAP_UART_DEFAULT_PAD_NAME_LEN, tx_fmt, + uart_nr, uart_nr); -static void omap_uart_disable_wakeup(struct omap_uart_state *uart) -{ - /* Clear wake-enable bit */ - if (uart->wk_en && uart->wk_mask) { - u32 v = __raw_readl(uart->wk_en); - v &= ~uart->wk_mask; - __raw_writel(v, uart->wk_en); - } + if (omap_mux_get_by_name(rx_pad_name, &rx_partition, &rx_mux) >= 0 && + omap_mux_get_by_name + (tx_pad_name, &tx_partition, &tx_mux) >= 0) { + u16 tx_mode, rx_mode; - /* Ensure IOPAD wake-enables are cleared */ - if (cpu_is_omap34xx() && uart->padconf) { - u16 v = omap_ctrl_readw(uart->padconf); - v &= ~OMAP3_PADCONF_WAKEUPENABLE0; - omap_ctrl_writew(v, uart->padconf); - } -} + tx_mode = omap_mux_read(tx_partition, tx_mux->reg_offset); + rx_mode = omap_mux_read(rx_partition, rx_mux->reg_offset); -static void omap_uart_smart_idle_enable(struct omap_uart_state *uart, - int enable) -{ - struct plat_serial8250_port *p = uart->p; - u16 sysc; - - sysc = serial_read_reg(p, UART_OMAP_SYSC) & 0x7; - if (enable) - sysc |= 0x2 << 3; - else - sysc |= 0x1 << 3; - - serial_write_reg(p, UART_OMAP_SYSC, sysc); -} - -static void omap_uart_block_sleep(struct omap_uart_state *uart) -{ - omap_uart_enable_clocks(uart); - - omap_uart_smart_idle_enable(uart, 0); - uart->can_sleep = 0; - if (uart->timeout) - mod_timer(&uart->timer, jiffies + uart->timeout); - else - del_timer(&uart->timer); + /* + * Check if uart is used in default tx/rx mode i.e. in mux mode0 + * if yes then configure rx pin for wake up capability + */ + if (OMAP_MODE_UART(rx_mode) && OMAP_MODE_UART(tx_mode)) + omap_serial_fill_uart_tx_rx_pads(bdata, uart); + } } - -static void omap_uart_allow_sleep(struct omap_uart_state *uart) +#else +static void __init omap_serial_check_wakeup(struct omap_board_data *bdata, + struct omap_uart_state *uart) { - if (device_may_wakeup(&uart->pdev.dev)) - omap_uart_enable_wakeup(uart); - else - omap_uart_disable_wakeup(uart); - - if (!uart->clocked) - return; - - omap_uart_smart_idle_enable(uart, 1); - uart->can_sleep = 1; - del_timer(&uart->timer); } +#endif -static void omap_uart_idle_timer(unsigned long data) +static char *cmdline_find_option(char *str) { - struct omap_uart_state *uart = (struct omap_uart_state *)data; + extern char *saved_command_line; - omap_uart_allow_sleep(uart); + return strstr(saved_command_line, str); } -void omap_uart_prepare_idle(int num) +static int __init omap_serial_early_init(void) { - struct omap_uart_state *uart; - - list_for_each_entry(uart, &uart_list, node) { - if (num == uart->num && uart->can_sleep) { - omap_uart_disable_clocks(uart); - return; - } - } -} + if (of_have_populated_dt()) + return -ENODEV; + + do { + char oh_name[MAX_UART_HWMOD_NAME_LEN]; + struct omap_hwmod *oh; + struct omap_uart_state *uart; + char uart_name[MAX_UART_HWMOD_NAME_LEN]; + + snprintf(oh_name, MAX_UART_HWMOD_NAME_LEN, + "uart%d", num_uarts + 1); + oh = omap_hwmod_lookup(oh_name); + if (!oh) + break; -void omap_uart_resume_idle(int num) -{ - struct omap_uart_state *uart; + uart = kzalloc(sizeof(struct omap_uart_state), GFP_KERNEL); + if (WARN_ON(!uart)) + return -ENODEV; - list_for_each_entry(uart, &uart_list, node) { - if (num == uart->num) { - omap_uart_enable_clocks(uart); + uart->oh = oh; + uart->num = num_uarts++; + list_add_tail(&uart->node, &uart_list); + snprintf(uart_name, MAX_UART_HWMOD_NAME_LEN, + "%s%d", OMAP_SERIAL_NAME, uart->num); - /* Check for IO pad wakeup */ - if (cpu_is_omap34xx() && uart->padconf) { - u16 p = omap_ctrl_readw(uart->padconf); + if (cmdline_find_option(uart_name)) { + console_uart_id = uart->num; - if (p & OMAP3_PADCONF_WAKEUPEVENT0) - omap_uart_block_sleep(uart); + if (console_loglevel >= 10) { + uart_debug = true; + pr_info("%s used as console in debug mode: uart%d clocks will not be gated", + uart_name, uart->num); } - - /* Check for normal UART wakeup */ - if (__raw_readl(uart->wk_st) & uart->wk_mask) - omap_uart_block_sleep(uart); - return; - } - } -} - -void omap_uart_prepare_suspend(void) -{ - struct omap_uart_state *uart; - - list_for_each_entry(uart, &uart_list, node) { - omap_uart_allow_sleep(uart); - } -} - -int omap_uart_can_sleep(void) -{ - struct omap_uart_state *uart; - int can_sleep = 1; - - list_for_each_entry(uart, &uart_list, node) { - if (!uart->clocked) - continue; - - if (!uart->can_sleep) { - can_sleep = 0; - continue; } + } while (1); - /* This UART can now safely sleep. */ - omap_uart_allow_sleep(uart); - } - - return can_sleep; + return 0; } +omap_core_initcall(omap_serial_early_init); /** - * omap_uart_interrupt() + * omap_serial_init_port() - initialize single serial port + * @bdata: port specific board data pointer + * @info: platform specific data pointer * - * This handler is used only to detect that *any* UART interrupt has - * occurred. It does _nothing_ to handle the interrupt. Rather, - * any UART interrupt will trigger the inactivity timer so the - * UART will not idle or sleep for its timeout period. + * This function initialies serial driver for given port only. + * Platforms can call this function instead of omap_serial_init() + * if they don't plan to use all available UARTs as serial ports. * - **/ -static irqreturn_t omap_uart_interrupt(int irq, void *dev_id) + * Don't mix calls to omap_serial_init_port() and omap_serial_init(), + * use only one of the two. + */ +void __init omap_serial_init_port(struct omap_board_data *bdata, + struct omap_uart_port_info *info) { - struct omap_uart_state *uart = dev_id; - - omap_uart_block_sleep(uart); + struct omap_uart_state *uart; + struct omap_hwmod *oh; + struct platform_device *pdev; + void *pdata = NULL; + u32 pdata_size = 0; + char *name; + struct omap_uart_port_info omap_up; - return IRQ_NONE; -} + if (WARN_ON(!bdata)) + return; + if (WARN_ON(bdata->id < 0)) + return; + if (WARN_ON(bdata->id >= num_uarts)) + return; -static void omap_uart_idle_init(struct omap_uart_state *uart) -{ - struct plat_serial8250_port *p = uart->p; - int ret; - - uart->can_sleep = 0; - uart->timeout = DEFAULT_TIMEOUT; - setup_timer(&uart->timer, omap_uart_idle_timer, - (unsigned long) uart); - mod_timer(&uart->timer, jiffies + uart->timeout); - omap_uart_smart_idle_enable(uart, 0); - - if (cpu_is_omap34xx()) { - u32 mod = (uart->num == 2) ? OMAP3430_PER_MOD : CORE_MOD; - u32 wk_mask = 0; - u32 padconf = 0; - - uart->wk_en = OMAP34XX_PRM_REGADDR(mod, PM_WKEN1); - uart->wk_st = OMAP34XX_PRM_REGADDR(mod, PM_WKST1); - switch (uart->num) { - case 0: - wk_mask = OMAP3430_ST_UART1_MASK; - padconf = 0x182; - break; - case 1: - wk_mask = OMAP3430_ST_UART2_MASK; - padconf = 0x17a; - break; - case 2: - wk_mask = OMAP3430_ST_UART3_MASK; - padconf = 0x19e; - break; - } - uart->wk_mask = wk_mask; - uart->padconf = padconf; - } else if (cpu_is_omap24xx()) { - u32 wk_mask = 0; - - if (cpu_is_omap2430()) { - uart->wk_en = OMAP2430_PRM_REGADDR(CORE_MOD, PM_WKEN1); - uart->wk_st = OMAP2430_PRM_REGADDR(CORE_MOD, PM_WKST1); - } else if (cpu_is_omap2420()) { - uart->wk_en = OMAP2420_PRM_REGADDR(CORE_MOD, PM_WKEN1); - uart->wk_st = OMAP2420_PRM_REGADDR(CORE_MOD, PM_WKST1); - } - switch (uart->num) { - case 0: - wk_mask = OMAP24XX_ST_UART1_MASK; - break; - case 1: - wk_mask = OMAP24XX_ST_UART2_MASK; + list_for_each_entry(uart, &uart_list, node) + if (bdata->id == uart->num) break; - case 2: - wk_mask = OMAP24XX_ST_UART3_MASK; - break; - } - uart->wk_mask = wk_mask; - } else { - uart->wk_en = 0; - uart->wk_st = 0; - uart->wk_mask = 0; - uart->padconf = 0; - } - - p->irqflags |= IRQF_SHARED; - ret = request_irq(p->irq, omap_uart_interrupt, IRQF_SHARED, - "serial idle", (void *)uart); - WARN_ON(ret); -} - -void omap_uart_enable_irqs(int enable) -{ - int ret; - struct omap_uart_state *uart; + if (!info) + info = omap_serial_default_info; + + oh = uart->oh; + name = DRIVER_NAME; + + omap_up.dma_enabled = info->dma_enabled; + omap_up.uartclk = OMAP24XX_BASE_BAUD * 16; + omap_up.flags = UPF_BOOT_AUTOCONF; + omap_up.get_context_loss_count = omap_pm_get_dev_context_loss_count; + omap_up.enable_wakeup = omap_uart_enable_wakeup; + omap_up.dma_rx_buf_size = info->dma_rx_buf_size; + omap_up.dma_rx_timeout = info->dma_rx_timeout; + omap_up.dma_rx_poll_rate = info->dma_rx_poll_rate; + omap_up.autosuspend_timeout = info->autosuspend_timeout; + omap_up.DTR_gpio = info->DTR_gpio; + omap_up.DTR_inverted = info->DTR_inverted; + omap_up.DTR_present = info->DTR_present; + + pdata = &omap_up; + pdata_size = sizeof(struct omap_uart_port_info); + + if (WARN_ON(!oh)) + return; - list_for_each_entry(uart, &uart_list, node) { - if (enable) - ret = request_irq(uart->p->irq, omap_uart_interrupt, - IRQF_SHARED, "serial idle", (void *)uart); - else - free_irq(uart->p->irq, (void *)uart); + pdev = omap_device_build(name, uart->num, oh, pdata, pdata_size); + if (IS_ERR(pdev)) { + WARN(1, "Could not build omap_device for %s: %s.\n", name, + oh->name); + return; } -} - -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); - return sprintf(buf, "%u\n", uart->timeout / HZ); -} + oh->mux = omap_hwmod_mux_init(bdata->pads, bdata->pads_cnt); -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); - unsigned int value; - - if (sscanf(buf, "%u", &value) != 1) { - printk(KERN_ERR "sleep_timeout_store: Invalid value\n"); - return -EINVAL; + if (console_uart_id == bdata->id) { + omap_device_enable(pdev); + pm_runtime_set_active(&pdev->dev); } - uart->timeout = value * HZ; - if (uart->timeout) - mod_timer(&uart->timer, jiffies + uart->timeout); - else - /* A zero value means disable timeout feature */ - omap_uart_block_sleep(uart); + oh->dev_attr = uart; - return n; -} - -DEVICE_ATTR(sleep_timeout, 0644, sleep_timeout_show, sleep_timeout_store); -#define DEV_CREATE_FILE(dev, attr) WARN_ON(device_create_file(dev, attr)) -#else -static inline void omap_uart_idle_init(struct omap_uart_state *uart) {} -#define DEV_CREATE_FILE(dev, attr) -#endif /* CONFIG_PM */ - -static struct 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, - }, - }, - }, -#endif -}; - -/* - * Override the default 8250 read handler: mem_serial_in() - * Empty RX fifo read causes an abort on omap3630 and omap4 - * This function makes sure that an empty rx fifo is not read on these silicons - * (OMAP1/2/3430 are not affected) - */ -static unsigned int serial_in_override(struct uart_port *up, int offset) -{ - if (UART_RX == offset) { - unsigned int lsr; - lsr = serial_read_reg(omap_uart[up->line].p, UART_LSR); - if (!(lsr & UART_LSR_DR)) - return -EPERM; - } - return serial_read_reg(omap_uart[up->line].p, offset); -} - -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. - */ - - 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; - struct plat_serial8250_port *p = dev->platform_data; - - /* - * Module 4KB + L4 interconnect 4KB - * Static mapping, never released - */ - p->membase = ioremap(p->mapbase, SZ_8K); - if (!p->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; - } - - /* FIXME: Remove this once the clkdev is ready */ - if (!cpu_is_omap44xx()) { - if (!uart->ick || !uart->fck) - continue; - } - - uart->num = i; - p->private_data = uart; - uart->p = p; - - if (cpu_is_omap44xx()) - p->irq += 32; - } + if (((cpu_is_omap34xx() || cpu_is_omap44xx()) && bdata->pads) + && !uart_debug) + device_init_wakeup(&pdev->dev, true); } /** - * omap_serial_init_port() - initialize single serial port - * @port: serial port number (0-3) - * - * This function initialies serial driver for given @port only. - * Platforms can call this function instead of omap_serial_init() - * if they don't plan to use all available UARTs as serial ports. + * omap_serial_board_init() - initialize all supported serial ports + * @info: platform specific data pointer * - * Don't mix calls to omap_serial_init_port() and omap_serial_init(), - * use only one of the two. + * Initializes all available UARTs as serial ports. Platforms + * can call this function when they want to have default behaviour + * for serial ports (e.g initialize them all as serial ports). */ -void __init omap_serial_init_port(int port) +void __init omap_serial_board_init(struct omap_uart_port_info *info) { struct omap_uart_state *uart; - struct platform_device *pdev; - struct device *dev; + struct omap_board_data bdata; - BUG_ON(port < 0); - BUG_ON(port >= ARRAY_SIZE(omap_uart)); - - uart = &omap_uart[port]; - pdev = &uart->pdev; - dev = &pdev->dev; - - omap_uart_enable_clocks(uart); - - omap_uart_reset(uart); - omap_uart_idle_init(uart); - - list_add_tail(&uart->node, &uart_list); + list_for_each_entry(uart, &uart_list, node) { + bdata.id = uart->num; + bdata.flags = 0; + bdata.pads = NULL; + bdata.pads_cnt = 0; - if (WARN_ON(platform_device_register(pdev))) - return; + omap_serial_check_wakeup(&bdata, uart); - 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); + if (!info) + omap_serial_init_port(&bdata, NULL); + else + omap_serial_init_port(&bdata, &info[uart->num]); } - - /* omap44xx: Never read empty UART fifo - * omap3xxx: Never read empty UART fifo on UARTs - * with IP rev >=0x52 - */ - if (cpu_is_omap44xx()) - uart->p->serial_in = serial_in_override; - else if ((serial_read_reg(uart->p, UART_OMAP_MVER) & 0xFF) - >= UART_OMAP_NO_EMPTY_FIFO_READ_IP_REV) - uart->p->serial_in = serial_in_override; } /** - * omap_serial_init() - intialize all supported serial ports + * omap_serial_init() - initialize all supported serial ports * - * Initializes all available UARTs as serial ports. Platforms - * can call this function when they want to have default behaviour + * Initializes all available UARTs. + * Platforms can call this function when they want to have default behaviour * for serial ports (e.g initialize them all as serial ports). */ void __init omap_serial_init(void) { - int i; - - for (i = 0; i < ARRAY_SIZE(omap_uart); i++) - omap_serial_init_port(i); + omap_serial_board_init(NULL); } |
