X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fserial%2Fmpsc.c;h=94681922ea0a6a2e874bef249520ce541a035ee4;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=a8314aee2ab8b7a32e8e67f2f6e0c2e82c8f39b4;hpb=cee37fe97739d85991964371c1f3a745c00dd236;p=linux-2.6.git diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c index a8314aee2..94681922e 100644 --- a/drivers/serial/mpsc.c +++ b/drivers/serial/mpsc.c @@ -1,6 +1,4 @@ /* - * drivers/serial/mpsc.c - * * Generic driver for the MPSC (UART mode) on Marvell parts (e.g., GT64240, * GT64260, MV64340, MV64360, GT96100, ... ). * @@ -52,7 +50,263 @@ * 4) AFAICT, hardware flow control isn't supported by the controller --MAG. */ -#include "mpsc.h" +#include + +#if defined(CONFIG_SERIAL_MPSC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#if defined(CONFIG_SERIAL_MPSC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#define MPSC_NUM_CTLRS 2 + +/* + * Descriptors and buffers must be cache line aligned. + * Buffers lengths must be multiple of cache line size. + * Number of Tx & Rx descriptors must be powers of 2. + */ +#define MPSC_RXR_ENTRIES 32 +#define MPSC_RXRE_SIZE dma_get_cache_alignment() +#define MPSC_RXR_SIZE (MPSC_RXR_ENTRIES * MPSC_RXRE_SIZE) +#define MPSC_RXBE_SIZE dma_get_cache_alignment() +#define MPSC_RXB_SIZE (MPSC_RXR_ENTRIES * MPSC_RXBE_SIZE) + +#define MPSC_TXR_ENTRIES 32 +#define MPSC_TXRE_SIZE dma_get_cache_alignment() +#define MPSC_TXR_SIZE (MPSC_TXR_ENTRIES * MPSC_TXRE_SIZE) +#define MPSC_TXBE_SIZE dma_get_cache_alignment() +#define MPSC_TXB_SIZE (MPSC_TXR_ENTRIES * MPSC_TXBE_SIZE) + +#define MPSC_DMA_ALLOC_SIZE (MPSC_RXR_SIZE + MPSC_RXB_SIZE + \ + MPSC_TXR_SIZE + MPSC_TXB_SIZE + \ + dma_get_cache_alignment() /* for alignment */) + +/* Rx and Tx Ring entry descriptors -- assume entry size is <= cacheline size */ +struct mpsc_rx_desc { + u16 bufsize; + u16 bytecnt; + u32 cmdstat; + u32 link; + u32 buf_ptr; +} __attribute((packed)); + +struct mpsc_tx_desc { + u16 bytecnt; + u16 shadow; + u32 cmdstat; + u32 link; + u32 buf_ptr; +} __attribute((packed)); + +/* + * Some regs that have the erratum that you can't read them are are shared + * between the two MPSC controllers. This struct contains those shared regs. + */ +struct mpsc_shared_regs { + phys_addr_t mpsc_routing_base_p; + phys_addr_t sdma_intr_base_p; + + void __iomem *mpsc_routing_base; + void __iomem *sdma_intr_base; + + u32 MPSC_MRR_m; + u32 MPSC_RCRR_m; + u32 MPSC_TCRR_m; + u32 SDMA_INTR_CAUSE_m; + u32 SDMA_INTR_MASK_m; +}; + +/* The main driver data structure */ +struct mpsc_port_info { + struct uart_port port; /* Overlay uart_port structure */ + + /* Internal driver state for this ctlr */ + u8 ready; + u8 rcv_data; + tcflag_t c_iflag; /* save termios->c_iflag */ + tcflag_t c_cflag; /* save termios->c_cflag */ + + /* Info passed in from platform */ + u8 mirror_regs; /* Need to mirror regs? */ + u8 cache_mgmt; /* Need manual cache mgmt? */ + u8 brg_can_tune; /* BRG has baud tuning? */ + u32 brg_clk_src; + u16 mpsc_max_idle; + int default_baud; + int default_bits; + int default_parity; + int default_flow; + + /* Physical addresses of various blocks of registers (from platform) */ + phys_addr_t mpsc_base_p; + phys_addr_t sdma_base_p; + phys_addr_t brg_base_p; + + /* Virtual addresses of various blocks of registers (from platform) */ + void __iomem *mpsc_base; + void __iomem *sdma_base; + void __iomem *brg_base; + + /* Descriptor ring and buffer allocations */ + void *dma_region; + dma_addr_t dma_region_p; + + dma_addr_t rxr; /* Rx descriptor ring */ + dma_addr_t rxr_p; /* Phys addr of rxr */ + u8 *rxb; /* Rx Ring I/O buf */ + u8 *rxb_p; /* Phys addr of rxb */ + u32 rxr_posn; /* First desc w/ Rx data */ + + dma_addr_t txr; /* Tx descriptor ring */ + dma_addr_t txr_p; /* Phys addr of txr */ + u8 *txb; /* Tx Ring I/O buf */ + u8 *txb_p; /* Phys addr of txb */ + int txr_head; /* Where new data goes */ + int txr_tail; /* Where sent data comes off */ + + /* Mirrored values of regs we can't read (if 'mirror_regs' set) */ + u32 MPSC_MPCR_m; + u32 MPSC_CHR_1_m; + u32 MPSC_CHR_2_m; + u32 MPSC_CHR_10_m; + u32 BRG_BCR_m; + struct mpsc_shared_regs *shared_regs; +}; + +/* Hooks to platform-specific code */ +int mpsc_platform_register_driver(void); +void mpsc_platform_unregister_driver(void); + +/* Hooks back in to mpsc common to be called by platform-specific code */ +struct mpsc_port_info *mpsc_device_probe(int index); +struct mpsc_port_info *mpsc_device_remove(int index); + +/* Main MPSC Configuration Register Offsets */ +#define MPSC_MMCRL 0x0000 +#define MPSC_MMCRH 0x0004 +#define MPSC_MPCR 0x0008 +#define MPSC_CHR_1 0x000c +#define MPSC_CHR_2 0x0010 +#define MPSC_CHR_3 0x0014 +#define MPSC_CHR_4 0x0018 +#define MPSC_CHR_5 0x001c +#define MPSC_CHR_6 0x0020 +#define MPSC_CHR_7 0x0024 +#define MPSC_CHR_8 0x0028 +#define MPSC_CHR_9 0x002c +#define MPSC_CHR_10 0x0030 +#define MPSC_CHR_11 0x0034 + +#define MPSC_MPCR_FRZ (1 << 9) +#define MPSC_MPCR_CL_5 0 +#define MPSC_MPCR_CL_6 1 +#define MPSC_MPCR_CL_7 2 +#define MPSC_MPCR_CL_8 3 +#define MPSC_MPCR_SBL_1 0 +#define MPSC_MPCR_SBL_2 1 + +#define MPSC_CHR_2_TEV (1<<1) +#define MPSC_CHR_2_TA (1<<7) +#define MPSC_CHR_2_TTCS (1<<9) +#define MPSC_CHR_2_REV (1<<17) +#define MPSC_CHR_2_RA (1<<23) +#define MPSC_CHR_2_CRD (1<<25) +#define MPSC_CHR_2_EH (1<<31) +#define MPSC_CHR_2_PAR_ODD 0 +#define MPSC_CHR_2_PAR_SPACE 1 +#define MPSC_CHR_2_PAR_EVEN 2 +#define MPSC_CHR_2_PAR_MARK 3 + +/* MPSC Signal Routing */ +#define MPSC_MRR 0x0000 +#define MPSC_RCRR 0x0004 +#define MPSC_TCRR 0x0008 + +/* Serial DMA Controller Interface Registers */ +#define SDMA_SDC 0x0000 +#define SDMA_SDCM 0x0008 +#define SDMA_RX_DESC 0x0800 +#define SDMA_RX_BUF_PTR 0x0808 +#define SDMA_SCRDP 0x0810 +#define SDMA_TX_DESC 0x0c00 +#define SDMA_SCTDP 0x0c10 +#define SDMA_SFTDP 0x0c14 + +#define SDMA_DESC_CMDSTAT_PE (1<<0) +#define SDMA_DESC_CMDSTAT_CDL (1<<1) +#define SDMA_DESC_CMDSTAT_FR (1<<3) +#define SDMA_DESC_CMDSTAT_OR (1<<6) +#define SDMA_DESC_CMDSTAT_BR (1<<9) +#define SDMA_DESC_CMDSTAT_MI (1<<10) +#define SDMA_DESC_CMDSTAT_A (1<<11) +#define SDMA_DESC_CMDSTAT_AM (1<<12) +#define SDMA_DESC_CMDSTAT_CT (1<<13) +#define SDMA_DESC_CMDSTAT_C (1<<14) +#define SDMA_DESC_CMDSTAT_ES (1<<15) +#define SDMA_DESC_CMDSTAT_L (1<<16) +#define SDMA_DESC_CMDSTAT_F (1<<17) +#define SDMA_DESC_CMDSTAT_P (1<<18) +#define SDMA_DESC_CMDSTAT_EI (1<<23) +#define SDMA_DESC_CMDSTAT_O (1<<31) + +#define SDMA_DESC_DFLT (SDMA_DESC_CMDSTAT_O | \ + SDMA_DESC_CMDSTAT_EI) + +#define SDMA_SDC_RFT (1<<0) +#define SDMA_SDC_SFM (1<<1) +#define SDMA_SDC_BLMR (1<<6) +#define SDMA_SDC_BLMT (1<<7) +#define SDMA_SDC_POVR (1<<8) +#define SDMA_SDC_RIFB (1<<9) + +#define SDMA_SDCM_ERD (1<<7) +#define SDMA_SDCM_AR (1<<15) +#define SDMA_SDCM_STD (1<<16) +#define SDMA_SDCM_TXD (1<<23) +#define SDMA_SDCM_AT (1<<31) + +#define SDMA_0_CAUSE_RXBUF (1<<0) +#define SDMA_0_CAUSE_RXERR (1<<1) +#define SDMA_0_CAUSE_TXBUF (1<<2) +#define SDMA_0_CAUSE_TXEND (1<<3) +#define SDMA_1_CAUSE_RXBUF (1<<8) +#define SDMA_1_CAUSE_RXERR (1<<9) +#define SDMA_1_CAUSE_TXBUF (1<<10) +#define SDMA_1_CAUSE_TXEND (1<<11) + +#define SDMA_CAUSE_RX_MASK (SDMA_0_CAUSE_RXBUF | SDMA_0_CAUSE_RXERR | \ + SDMA_1_CAUSE_RXBUF | SDMA_1_CAUSE_RXERR) +#define SDMA_CAUSE_TX_MASK (SDMA_0_CAUSE_TXBUF | SDMA_0_CAUSE_TXEND | \ + SDMA_1_CAUSE_TXBUF | SDMA_1_CAUSE_TXEND) + +/* SDMA Interrupt registers */ +#define SDMA_INTR_CAUSE 0x0000 +#define SDMA_INTR_MASK 0x0080 + +/* Baud Rate Generator Interface Registers */ +#define BRG_BCR 0x0000 +#define BRG_BTR 0x0004 /* * Define how this driver is known to the outside (we've been assigned a @@ -67,7 +321,11 @@ static struct mpsc_port_info mpsc_ports[MPSC_NUM_CTLRS]; static struct mpsc_shared_regs mpsc_shared_regs; +static struct uart_driver mpsc_reg; +static void mpsc_start_rx(struct mpsc_port_info *pi); +static void mpsc_free_ring_mem(struct mpsc_port_info *pi); +static void mpsc_release_port(struct uart_port *port); /* ****************************************************************************** * @@ -546,7 +804,6 @@ static int mpsc_alloc_ring_mem(struct mpsc_port_info *pi) { int rc = 0; - static void mpsc_free_ring_mem(struct mpsc_port_info *pi); pr_debug("mpsc_alloc_ring_mem[%d]: Allocating ring mem\n", pi->port.line); @@ -745,7 +1002,6 @@ mpsc_rx_intr(struct mpsc_port_info *pi, struct pt_regs *regs) int rc = 0; u8 *bp; char flag = TTY_NORMAL; - static void mpsc_start_rx(struct mpsc_port_info *pi); pr_debug("mpsc_rx_intr[%d]: Handling Rx intr\n", pi->port.line); @@ -765,12 +1021,12 @@ mpsc_rx_intr(struct mpsc_port_info *pi, struct pt_regs *regs) bytes_in = be16_to_cpu(rxre->bytecnt); /* Following use of tty struct directly is deprecated */ - if (unlikely((tty->flip.count + bytes_in) >= TTY_FLIPBUF_SIZE)){ + if (unlikely(tty_buffer_request_room(tty, bytes_in) < bytes_in)) { if (tty->low_latency) tty_flip_buffer_push(tty); /* - * If this failed then we will throw awa the bytes - * but mst do so to clear interrupts. + * If this failed then we will throw away the bytes + * but must do so to clear interrupts. */ } @@ -1056,12 +1312,9 @@ mpsc_get_mctrl(struct uart_port *port) { struct mpsc_port_info *pi = (struct mpsc_port_info *)port; u32 mflags, status; - ulong iflags; - spin_lock_irqsave(&pi->port.lock, iflags); status = (pi->mirror_regs) ? pi->MPSC_CHR_10_m : readl(pi->mpsc_base + MPSC_CHR_10); - spin_unlock_irqrestore(&pi->port.lock, iflags); mflags = 0; if (status & 0x1) @@ -1073,18 +1326,18 @@ mpsc_get_mctrl(struct uart_port *port) } static void -mpsc_stop_tx(struct uart_port *port, uint tty_start) +mpsc_stop_tx(struct uart_port *port) { struct mpsc_port_info *pi = (struct mpsc_port_info *)port; - pr_debug("mpsc_stop_tx[%d]: tty_start: %d\n", port->line, tty_start); + pr_debug("mpsc_stop_tx[%d]\n", port->line); mpsc_freeze(pi); return; } static void -mpsc_start_tx(struct uart_port *port, uint tty_start) +mpsc_start_tx(struct uart_port *port) { struct mpsc_port_info *pi = (struct mpsc_port_info *)port; @@ -1092,7 +1345,7 @@ mpsc_start_tx(struct uart_port *port, uint tty_start) mpsc_copy_tx_data(pi); mpsc_sdma_start_tx(pi); - pr_debug("mpsc_start_tx[%d]: tty_start: %d\n", port->line, tty_start); + pr_debug("mpsc_start_tx[%d]\n", port->line); return; } @@ -1101,6 +1354,8 @@ mpsc_start_rx(struct mpsc_port_info *pi) { pr_debug("mpsc_start_rx[%d]: Starting...\n", pi->port.line); + /* Issue a Receive Abort to clear any receive errors */ + writel(MPSC_CHR_2_RA, pi->mpsc_base + MPSC_CHR_2); if (pi->rcv_data) { mpsc_enter_hunt(pi); mpsc_sdma_cmd(pi, SDMA_SDCM_ERD); @@ -1162,7 +1417,7 @@ mpsc_startup(struct uart_port *port) flag = SA_SHIRQ; if (request_irq(pi->port.irq, mpsc_sdma_intr, flag, - "mpsc/sdma", pi)) + "mpsc-sdma", pi)) printk(KERN_ERR "MPSC: Can't get SDMA IRQ %d\n", pi->port.irq); @@ -1178,7 +1433,6 @@ static void mpsc_shutdown(struct uart_port *port) { struct mpsc_port_info *pi = (struct mpsc_port_info *)port; - static void mpsc_release_port(struct uart_port *port); pr_debug("mpsc_shutdown[%d]: Shutting down MPSC\n", port->line); @@ -1448,7 +1702,6 @@ mpsc_console_setup(struct console *co, char *options) return uart_set_options(&pi->port, co, baud, parity, bits, flow); } -extern struct uart_driver mpsc_reg; static struct console mpsc_console = { .name = MPSC_DEV_NAME, .write = mpsc_console_write, @@ -1550,15 +1803,14 @@ mpsc_shared_unmap_regs(void) } static int -mpsc_shared_drv_probe(struct device *dev) +mpsc_shared_drv_probe(struct platform_device *dev) { - struct platform_device *pd = to_platform_device(dev); struct mpsc_shared_pdata *pdata; int rc = -ENODEV; - if (pd->id == 0) { - if (!(rc = mpsc_shared_map_regs(pd))) { - pdata = (struct mpsc_shared_pdata *)dev->platform_data; + if (dev->id == 0) { + if (!(rc = mpsc_shared_map_regs(dev))) { + pdata = (struct mpsc_shared_pdata *)dev->dev.platform_data; mpsc_shared_regs.MPSC_MRR_m = pdata->mrr_val; mpsc_shared_regs.MPSC_RCRR_m= pdata->rcrr_val; @@ -1576,12 +1828,11 @@ mpsc_shared_drv_probe(struct device *dev) } static int -mpsc_shared_drv_remove(struct device *dev) +mpsc_shared_drv_remove(struct platform_device *dev) { - struct platform_device *pd = to_platform_device(dev); int rc = -ENODEV; - if (pd->id == 0) { + if (dev->id == 0) { mpsc_shared_unmap_regs(); mpsc_shared_regs.MPSC_MRR_m = 0; mpsc_shared_regs.MPSC_RCRR_m = 0; @@ -1594,11 +1845,12 @@ mpsc_shared_drv_remove(struct device *dev) return rc; } -static struct device_driver mpsc_shared_driver = { - .name = MPSC_SHARED_NAME, - .bus = &platform_bus_type, +static struct platform_driver mpsc_shared_driver = { .probe = mpsc_shared_drv_probe, .remove = mpsc_shared_drv_remove, + .driver = { + .name = MPSC_SHARED_NAME, + }, }; /* @@ -1731,19 +1983,18 @@ mpsc_drv_get_platform_data(struct mpsc_port_info *pi, } static int -mpsc_drv_probe(struct device *dev) +mpsc_drv_probe(struct platform_device *dev) { - struct platform_device *pd = to_platform_device(dev); struct mpsc_port_info *pi; int rc = -ENODEV; - pr_debug("mpsc_drv_probe: Adding MPSC %d\n", pd->id); + pr_debug("mpsc_drv_probe: Adding MPSC %d\n", dev->id); - if (pd->id < MPSC_NUM_CTLRS) { - pi = &mpsc_ports[pd->id]; + if (dev->id < MPSC_NUM_CTLRS) { + pi = &mpsc_ports[dev->id]; - if (!(rc = mpsc_drv_map_regs(pi, pd))) { - mpsc_drv_get_platform_data(pi, pd, pd->id); + if (!(rc = mpsc_drv_map_regs(pi, dev))) { + mpsc_drv_get_platform_data(pi, dev, dev->id); if (!(rc = mpsc_make_ready(pi))) if (!(rc = uart_add_one_port(&mpsc_reg, @@ -1763,27 +2014,26 @@ mpsc_drv_probe(struct device *dev) } static int -mpsc_drv_remove(struct device *dev) +mpsc_drv_remove(struct platform_device *dev) { - struct platform_device *pd = to_platform_device(dev); - - pr_debug("mpsc_drv_exit: Removing MPSC %d\n", pd->id); + pr_debug("mpsc_drv_exit: Removing MPSC %d\n", dev->id); - if (pd->id < MPSC_NUM_CTLRS) { - uart_remove_one_port(&mpsc_reg, &mpsc_ports[pd->id].port); - mpsc_release_port((struct uart_port *)&mpsc_ports[pd->id].port); - mpsc_drv_unmap_regs(&mpsc_ports[pd->id]); + if (dev->id < MPSC_NUM_CTLRS) { + uart_remove_one_port(&mpsc_reg, &mpsc_ports[dev->id].port); + mpsc_release_port((struct uart_port *)&mpsc_ports[dev->id].port); + mpsc_drv_unmap_regs(&mpsc_ports[dev->id]); return 0; } else return -ENODEV; } -static struct device_driver mpsc_driver = { - .name = MPSC_CTLR_NAME, - .bus = &platform_bus_type, +static struct platform_driver mpsc_driver = { .probe = mpsc_drv_probe, .remove = mpsc_drv_remove, + .driver = { + .name = MPSC_CTLR_NAME, + }, }; static int __init @@ -1797,9 +2047,9 @@ mpsc_drv_init(void) memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs)); if (!(rc = uart_register_driver(&mpsc_reg))) { - if (!(rc = driver_register(&mpsc_shared_driver))) { - if ((rc = driver_register(&mpsc_driver))) { - driver_unregister(&mpsc_shared_driver); + if (!(rc = platform_driver_register(&mpsc_shared_driver))) { + if ((rc = platform_driver_register(&mpsc_driver))) { + platform_driver_unregister(&mpsc_shared_driver); uart_unregister_driver(&mpsc_reg); } } @@ -1814,8 +2064,8 @@ mpsc_drv_init(void) static void __exit mpsc_drv_exit(void) { - driver_unregister(&mpsc_driver); - driver_unregister(&mpsc_shared_driver); + platform_driver_unregister(&mpsc_driver); + platform_driver_unregister(&mpsc_shared_driver); uart_unregister_driver(&mpsc_reg); memset(mpsc_ports, 0, sizeof(mpsc_ports)); memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs));