X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fserial%2Fcpm_uart%2Fcpm_uart_core.c;h=7a3b97fdf8d18713509b8c8b9502ce4cb3072bca;hb=refs%2Fheads%2Fvserver;hp=b7bf4c698a4795e3d3453ff696a90ad7fbdfc7b4;hpb=76828883507a47dae78837ab5dec5a5b4513c667;p=linux-2.6.git diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c index b7bf4c698..7a3b97fdf 100644 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/serial/cpm_uart/cpm_uart_core.c @@ -12,7 +12,8 @@ * * Copyright (C) 2004 Freescale Semiconductor, Inc. * (C) 2004 Intracom, S.A. - * (C) 2005 MontaVista Software, Inc. by Vitaly Bordug + * (C) 2005-2006 MontaVista Software, Inc. + * Vitaly Bordug * * 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 @@ -30,7 +31,6 @@ * */ -#include #include #include #include @@ -41,10 +41,12 @@ #include #include #include +#include #include #include #include +#include #if defined(CONFIG_SERIAL_CPM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ @@ -60,7 +62,7 @@ /* Track which ports are configured as uarts */ int cpm_uart_port_map[UART_NR]; /* How many ports did we config as uarts */ -int cpm_uart_nr; +int cpm_uart_nr = 0; /**************************************************************/ @@ -71,18 +73,51 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo); /**************************************************************/ -static inline unsigned long cpu2cpm_addr(void *addr) + +/* Place-holder for board-specific stuff */ +struct platform_device* __attribute__ ((weak)) __init +early_uart_get_pdev(int index) +{ + return NULL; +} + + +static void cpm_uart_count(void) { - if ((unsigned long)addr >= CPM_ADDR) - return (unsigned long)addr; - return virt_to_bus(addr); + cpm_uart_nr = 0; +#ifdef CONFIG_SERIAL_CPM_SMC1 + cpm_uart_port_map[cpm_uart_nr++] = UART_SMC1; +#endif +#ifdef CONFIG_SERIAL_CPM_SMC2 + cpm_uart_port_map[cpm_uart_nr++] = UART_SMC2; +#endif +#ifdef CONFIG_SERIAL_CPM_SCC1 + cpm_uart_port_map[cpm_uart_nr++] = UART_SCC1; +#endif +#ifdef CONFIG_SERIAL_CPM_SCC2 + cpm_uart_port_map[cpm_uart_nr++] = UART_SCC2; +#endif +#ifdef CONFIG_SERIAL_CPM_SCC3 + cpm_uart_port_map[cpm_uart_nr++] = UART_SCC3; +#endif +#ifdef CONFIG_SERIAL_CPM_SCC4 + cpm_uart_port_map[cpm_uart_nr++] = UART_SCC4; +#endif } -static inline void *cpm2cpu_addr(unsigned long addr) +/* Get UART number by its id */ +static int cpm_uart_id2nr(int id) { - if (addr >= CPM_ADDR) - return (void *)addr; - return bus_to_virt(addr); + int i; + if (id < UART_NR) { + for (i=0; ismc_smcm |= SMCM_TX; - smcp->smc_smcmr |= SMCMR_TEN; } else { sccp->scc_sccm |= UART_SCCM_TX; - pinfo->sccp->scc_gsmrl |= SCC_GSMRL_ENT; } } } @@ -213,7 +246,7 @@ static void cpm_uart_break_ctl(struct uart_port *port, int break_state) /* * Transmit characters, refill buffer descriptor, if possible */ -static void cpm_uart_int_tx(struct uart_port *port, struct pt_regs *regs) +static void cpm_uart_int_tx(struct uart_port *port) { pr_debug("CPM uart[%d]:TX INT\n", port->line); @@ -223,7 +256,7 @@ static void cpm_uart_int_tx(struct uart_port *port, struct pt_regs *regs) /* * Receive characters */ -static void cpm_uart_int_rx(struct uart_port *port, struct pt_regs *regs) +static void cpm_uart_int_rx(struct uart_port *port) { int i; unsigned char ch, *cp; @@ -258,7 +291,7 @@ static void cpm_uart_int_rx(struct uart_port *port, struct pt_regs *regs) } /* get pointer */ - cp = cpm2cpu_addr(bdp->cbd_bufaddr); + cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); /* loop through the buffer */ while (i-- > 0) { @@ -269,7 +302,7 @@ static void cpm_uart_int_rx(struct uart_port *port, struct pt_regs *regs) if (status & (BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV)) goto handle_error; - if (uart_handle_sysrq_char(port, ch, regs)) + if (uart_handle_sysrq_char(port, ch)) continue; error_return: @@ -338,7 +371,7 @@ static void cpm_uart_int_rx(struct uart_port *port, struct pt_regs *regs) /* * Asynchron mode interrupt handler */ -static irqreturn_t cpm_uart_int(int irq, void *data, struct pt_regs *regs) +static irqreturn_t cpm_uart_int(int irq, void *data) { u8 events; struct uart_port *port = (struct uart_port *)data; @@ -354,18 +387,18 @@ static irqreturn_t cpm_uart_int(int irq, void *data, struct pt_regs *regs) if (events & SMCM_BRKE) uart_handle_break(port); if (events & SMCM_RX) - cpm_uart_int_rx(port, regs); + cpm_uart_int_rx(port); if (events & SMCM_TX) - cpm_uart_int_tx(port, regs); + cpm_uart_int_tx(port); } else { events = sccp->scc_scce; sccp->scc_scce = events; if (events & UART_SCCM_BRKE) uart_handle_break(port); if (events & UART_SCCM_RX) - cpm_uart_int_rx(port, regs); + cpm_uart_int_rx(port); if (events & UART_SCCM_TX) - cpm_uart_int_tx(port, regs); + cpm_uart_int_tx(port); } return (events) ? IRQ_HANDLED : IRQ_NONE; } @@ -386,9 +419,10 @@ static int cpm_uart_startup(struct uart_port *port) /* Startup rx-int */ if (IS_SMC(pinfo)) { pinfo->smcp->smc_smcm |= SMCM_RX; - pinfo->smcp->smc_smcmr |= SMCMR_REN; + pinfo->smcp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN); } else { pinfo->sccp->scc_sccm |= UART_SCCM_RX; + pinfo->sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); } if (!(pinfo->flags & FLAG_CONSOLE)) @@ -438,7 +472,11 @@ static void cpm_uart_shutdown(struct uart_port *port) } /* Shut them really down and reinit buffer descriptors */ - cpm_line_cr_cmd(line, CPM_CR_STOP_TX); + if (IS_SMC(pinfo)) + cpm_line_cr_cmd(line, CPM_CR_STOP_TX); + else + cpm_line_cr_cmd(line, CPM_CR_GRA_STOP_TX); + cpm_uart_initbd(pinfo); } } @@ -601,7 +639,7 @@ static int cpm_uart_tx_pump(struct uart_port *port) /* Pick next descriptor and fill from buffer */ bdp = pinfo->tx_cur; - p = cpm2cpu_addr(bdp->cbd_bufaddr); + p = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); *p++ = port->x_char; bdp->cbd_datlen = 1; @@ -628,7 +666,7 @@ static int cpm_uart_tx_pump(struct uart_port *port) while (!(bdp->cbd_sc & BD_SC_READY) && (xmit->tail != xmit->head)) { count = 0; - p = cpm2cpu_addr(bdp->cbd_bufaddr); + p = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); while (count < pinfo->tx_fifosize) { *p++ = xmit->buf[xmit->tail]; xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); @@ -677,12 +715,12 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo) mem_addr = pinfo->mem_addr; bdp = pinfo->rx_cur = pinfo->rx_bd_base; for (i = 0; i < (pinfo->rx_nrfifos - 1); i++, bdp++) { - bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr); + bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo); bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT; mem_addr += pinfo->rx_fifosize; } - bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr); + bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo); bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT; /* Set the physical address of the host memory @@ -692,12 +730,12 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo) mem_addr = pinfo->mem_addr + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize); bdp = pinfo->tx_cur = pinfo->tx_bd_base; for (i = 0; i < (pinfo->tx_nrfifos - 1); i++, bdp++) { - bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr); + bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo); bdp->cbd_sc = BD_SC_INTRPT; mem_addr += pinfo->tx_fifosize; } - bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr); + bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo); bdp->cbd_sc = BD_SC_WRAP | BD_SC_INTRPT; } @@ -829,14 +867,6 @@ static int cpm_uart_request_port(struct uart_port *port) if (pinfo->flags & FLAG_CONSOLE) return 0; - /* - * Setup any port IO, connect any baud rate generators, - * etc. This is expected to be handled by board - * dependant code - */ - if (pinfo->set_lineif) - pinfo->set_lineif(pinfo); - if (IS_SMC(pinfo)) { pinfo->smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX); pinfo->smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); @@ -988,6 +1018,60 @@ struct uart_cpm_port cpm_uart_ports[UART_NR] = { }, }; +int cpm_uart_drv_get_platform_data(struct platform_device *pdev, int is_con) +{ + struct resource *r; + struct fs_uart_platform_info *pdata = pdev->dev.platform_data; + int idx; /* It is UART_SMCx or UART_SCCx index */ + struct uart_cpm_port *pinfo; + int line; + u32 mem, pram; + + idx = pdata->fs_no = fs_uart_get_id(pdata); + + line = cpm_uart_id2nr(idx); + if(line < 0) { + printk(KERN_ERR"%s(): port %d is not registered", __FUNCTION__, idx); + return -EINVAL; + } + + pinfo = (struct uart_cpm_port *) &cpm_uart_ports[idx]; + + pinfo->brg = pdata->brg; + + if (!is_con) { + pinfo->port.line = line; + pinfo->port.flags = UPF_BOOT_AUTOCONF; + } + + if (!(r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"))) + return -EINVAL; + mem = (u32)ioremap(r->start, r->end - r->start + 1); + + if (!(r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pram"))) + return -EINVAL; + pram = (u32)ioremap(r->start, r->end - r->start + 1); + + if(idx > fsid_smc2_uart) { + pinfo->sccp = (scc_t *)mem; + pinfo->sccup = (scc_uart_t *)pram; + } else { + pinfo->smcp = (smc_t *)mem; + pinfo->smcup = (smc_uart_t *)pram; + } + pinfo->tx_nrfifos = pdata->tx_num_fifo; + pinfo->tx_fifosize = pdata->tx_buf_size; + + pinfo->rx_nrfifos = pdata->rx_num_fifo; + pinfo->rx_fifosize = pdata->rx_buf_size; + + pinfo->port.uartclk = pdata->uart_clk; + pinfo->port.mapbase = (unsigned long)mem; + pinfo->port.irq = platform_get_irq(pdev, 0); + + return 0; +} + #ifdef CONFIG_SERIAL_CPM_CONSOLE /* * Print a string to the serial port trying not to disturb @@ -1027,7 +1111,7 @@ static void cpm_uart_console_write(struct console *co, const char *s, * If the buffer address is in the CPM DPRAM, don't * convert it. */ - cp = cpm2cpu_addr(bdp->cbd_bufaddr); + cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); *cp = *s; @@ -1044,7 +1128,7 @@ static void cpm_uart_console_write(struct console *co, const char *s, while ((bdp->cbd_sc & BD_SC_READY) != 0) ; - cp = cpm2cpu_addr(bdp->cbd_bufaddr); + cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); *cp = 13; bdp->cbd_datlen = 1; @@ -1067,9 +1151,7 @@ static void cpm_uart_console_write(struct console *co, const char *s, pinfo->tx_cur = (volatile cbd_t *) bdp; } -/* - * Setup console. Be careful is called early ! - */ + static int __init cpm_uart_console_setup(struct console *co, char *options) { struct uart_port *port; @@ -1080,31 +1162,39 @@ static int __init cpm_uart_console_setup(struct console *co, char *options) int flow = 'n'; int ret; + struct fs_uart_platform_info *pdata; + struct platform_device* pdev = early_uart_get_pdev(co->index); + + if (!pdev) { + pr_info("cpm_uart: console: compat mode\n"); + /* compatibility - will be cleaned up */ + cpm_uart_init_portdesc(); + } + port = (struct uart_port *)&cpm_uart_ports[cpm_uart_port_map[co->index]]; pinfo = (struct uart_cpm_port *)port; + if (!pdev) { + if (pinfo->set_lineif) + pinfo->set_lineif(pinfo); + } else { + pdata = pdev->dev.platform_data; + if (pdata) + if (pdata->init_ioports) + pdata->init_ioports(pdata); + + cpm_uart_drv_get_platform_data(pdev, 1); + } pinfo->flags |= FLAG_CONSOLE; if (options) { uart_parse_options(options, &baud, &parity, &bits, &flow); } else { - bd_t *bd = (bd_t *) __res; - - if (bd->bi_baudrate) - baud = bd->bi_baudrate; - else + if ((baud = uart_baudrate()) == -1) baud = 9600; } - /* - * Setup any port IO, connect any baud rate generators, - * etc. This is expected to be handled by board - * dependant code - */ - if (pinfo->set_lineif) - pinfo->set_lineif(pinfo); - if (IS_SMC(pinfo)) { pinfo->smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX); pinfo->smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); @@ -1143,11 +1233,8 @@ static struct console cpm_scc_uart_console = { int __init cpm_uart_console_init(void) { - int ret = cpm_uart_init_portdesc(); - - if (!ret) - register_console(&cpm_scc_uart_console); - return ret; + register_console(&cpm_scc_uart_console); + return 0; } console_initcall(cpm_uart_console_init); @@ -1165,44 +1252,131 @@ static struct uart_driver cpm_reg = { .minor = SERIAL_CPM_MINOR, .cons = CPM_UART_CONSOLE, }; - -static int __init cpm_uart_init(void) +static int cpm_uart_drv_probe(struct device *dev) { - int ret, i; + struct platform_device *pdev = to_platform_device(dev); + struct fs_uart_platform_info *pdata; + int ret = -ENODEV; - printk(KERN_INFO "Serial: CPM driver $Revision: 0.01 $\n"); - -#ifndef CONFIG_SERIAL_CPM_CONSOLE - ret = cpm_uart_init_portdesc(); - if (ret) + if(!pdev) { + printk(KERN_ERR"CPM UART: platform data missing!\n"); return ret; -#endif + } - cpm_reg.nr = cpm_uart_nr; - ret = uart_register_driver(&cpm_reg); + pdata = pdev->dev.platform_data; - if (ret) + if ((ret = cpm_uart_drv_get_platform_data(pdev, 0))) return ret; - for (i = 0; i < cpm_uart_nr; i++) { - int con = cpm_uart_port_map[i]; - cpm_uart_ports[con].port.line = i; - cpm_uart_ports[con].port.flags = UPF_BOOT_AUTOCONF; - uart_add_one_port(&cpm_reg, &cpm_uart_ports[con].port); - } + pr_debug("cpm_uart_drv_probe: Adding CPM UART %d\n", cpm_uart_id2nr(pdata->fs_no)); - return ret; + if (pdata->init_ioports) + pdata->init_ioports(pdata); + + ret = uart_add_one_port(&cpm_reg, &cpm_uart_ports[pdata->fs_no].port); + + return ret; } -static void __exit cpm_uart_exit(void) +static int cpm_uart_drv_remove(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); + struct fs_uart_platform_info *pdata = pdev->dev.platform_data; + + pr_debug("cpm_uart_drv_remove: Removing CPM UART %d\n", + cpm_uart_id2nr(pdata->fs_no)); + + uart_remove_one_port(&cpm_reg, &cpm_uart_ports[pdata->fs_no].port); + return 0; +} + +static struct device_driver cpm_smc_uart_driver = { + .name = "fsl-cpm-smc:uart", + .bus = &platform_bus_type, + .probe = cpm_uart_drv_probe, + .remove = cpm_uart_drv_remove, +}; + +static struct device_driver cpm_scc_uart_driver = { + .name = "fsl-cpm-scc:uart", + .bus = &platform_bus_type, + .probe = cpm_uart_drv_probe, + .remove = cpm_uart_drv_remove, +}; + +/* + This is supposed to match uart devices on platform bus, + */ +static int match_is_uart (struct device* dev, void* data) +{ + struct platform_device* pdev = container_of(dev, struct platform_device, dev); + int ret = 0; + /* this was setfunc as uart */ + if(strstr(pdev->name,":uart")) { + ret = 1; + } + return ret; +} + + +static int cpm_uart_init(void) { + + int ret; int i; + struct device *dev; + printk(KERN_INFO "Serial: CPM driver $Revision: 0.02 $\n"); + + /* lookup the bus for uart devices */ + dev = bus_find_device(&platform_bus_type, NULL, 0, match_is_uart); + + /* There are devices on the bus - all should be OK */ + if (dev) { + cpm_uart_count(); + cpm_reg.nr = cpm_uart_nr; + + if (!(ret = uart_register_driver(&cpm_reg))) { + if ((ret = driver_register(&cpm_smc_uart_driver))) { + uart_unregister_driver(&cpm_reg); + return ret; + } + if ((ret = driver_register(&cpm_scc_uart_driver))) { + driver_unregister(&cpm_scc_uart_driver); + uart_unregister_driver(&cpm_reg); + } + } + } else { + /* No capable platform devices found - falling back to legacy mode */ + pr_info("cpm_uart: WARNING: no UART devices found on platform bus!\n"); + pr_info( + "cpm_uart: the driver will guess configuration, but this mode is no longer supported.\n"); + + /* Don't run this again, if the console driver did it already */ + if (cpm_uart_nr == 0) + cpm_uart_init_portdesc(); + + cpm_reg.nr = cpm_uart_nr; + ret = uart_register_driver(&cpm_reg); + + if (ret) + return ret; + + for (i = 0; i < cpm_uart_nr; i++) { + int con = cpm_uart_port_map[i]; + cpm_uart_ports[con].port.line = i; + cpm_uart_ports[con].port.flags = UPF_BOOT_AUTOCONF; + if (cpm_uart_ports[con].set_lineif) + cpm_uart_ports[con].set_lineif(&cpm_uart_ports[con]); + uart_add_one_port(&cpm_reg, &cpm_uart_ports[con].port); + } - for (i = 0; i < cpm_uart_nr; i++) { - int con = cpm_uart_port_map[i]; - uart_remove_one_port(&cpm_reg, &cpm_uart_ports[con].port); } + return ret; +} +static void __exit cpm_uart_exit(void) +{ + driver_unregister(&cpm_scc_uart_driver); + driver_unregister(&cpm_smc_uart_driver); uart_unregister_driver(&cpm_reg); }