Loading drivers/tty/serial/sh-sci.c +153 −167 Original line number Diff line number Diff line Loading @@ -23,35 +23,34 @@ #undef DEBUG #include <linux/module.h> #include <linux/clk.h> #include <linux/console.h> #include <linux/ctype.h> #include <linux/cpufreq.h> #include <linux/delay.h> #include <linux/dmaengine.h> #include <linux/dma-mapping.h> #include <linux/err.h> #include <linux/errno.h> #include <linux/sh_dma.h> #include <linux/timer.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/serial.h> #include <linux/major.h> #include <linux/string.h> #include <linux/sysrq.h> #include <linux/ioport.h> #include <linux/major.h> #include <linux/module.h> #include <linux/mm.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/console.h> #include <linux/platform_device.h> #include <linux/serial_sci.h> #include <linux/notifier.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/cpufreq.h> #include <linux/clk.h> #include <linux/ctype.h> #include <linux/err.h> #include <linux/dmaengine.h> #include <linux/dma-mapping.h> #include <linux/scatterlist.h> #include <linux/serial.h> #include <linux/serial_sci.h> #include <linux/sh_dma.h> #include <linux/slab.h> #include <linux/gpio.h> #include <linux/string.h> #include <linux/sysrq.h> #include <linux/timer.h> #include <linux/tty.h> #include <linux/tty_flip.h> #ifdef CONFIG_SUPERH #include <asm/sh_bios.h> Loading @@ -64,6 +63,10 @@ struct sci_port { /* Platform configuration */ struct plat_sci_port *cfg; int overrun_bit; unsigned int error_mask; unsigned int sampling_rate; /* Break timer */ struct timer_list break_timer; Loading @@ -74,8 +77,8 @@ struct sci_port { /* Function clock */ struct clk *fclk; int irqs[SCIx_NR_IRQS]; char *irqstr[SCIx_NR_IRQS]; char *gpiostr[SCIx_NR_FNS]; struct dma_chan *chan_tx; struct dma_chan *chan_rx; Loading Loading @@ -421,9 +424,9 @@ static void sci_port_enable(struct sci_port *sci_port) pm_runtime_get_sync(sci_port->port.dev); clk_enable(sci_port->iclk); clk_prepare_enable(sci_port->iclk); sci_port->port.uartclk = clk_get_rate(sci_port->iclk); clk_enable(sci_port->fclk); clk_prepare_enable(sci_port->fclk); } static void sci_port_disable(struct sci_port *sci_port) Loading @@ -431,8 +434,16 @@ static void sci_port_disable(struct sci_port *sci_port) if (!sci_port->port.dev) return; clk_disable(sci_port->fclk); clk_disable(sci_port->iclk); /* Cancel the break timer to ensure that the timer handler will not try * to access the hardware with clocks and power disabled. Reset the * break flag to make the break debouncing state machine ready for the * next break. */ del_timer_sync(&sci_port->break_timer); sci_port->break_flag = 0; clk_disable_unprepare(sci_port->fclk); clk_disable_unprepare(sci_port->iclk); pm_runtime_put_sync(sci_port->port.dev); } Loading Loading @@ -557,7 +568,7 @@ static inline int sci_rxd_in(struct uart_port *port) return 1; /* Cast for ARM damage */ return !!__raw_readb((void __iomem *)s->cfg->port_reg); return !!__raw_readb((void __iomem *)(uintptr_t)s->cfg->port_reg); } /* ********************************************************************** * Loading Loading @@ -733,8 +744,6 @@ static void sci_break_timer(unsigned long data) { struct sci_port *port = (struct sci_port *)data; sci_port_enable(port); if (sci_rxd_in(&port->port) == 0) { port->break_flag = 1; sci_schedule_break_timer(port); Loading @@ -744,8 +753,6 @@ static void sci_break_timer(unsigned long data) sci_schedule_break_timer(port); } else port->break_flag = 0; sci_port_disable(port); } static int sci_handle_errors(struct uart_port *port) Loading @@ -755,11 +762,8 @@ static int sci_handle_errors(struct uart_port *port) struct tty_port *tport = &port->state->port; struct sci_port *s = to_sci_port(port); /* * Handle overruns, if supported. */ if (s->cfg->overrun_bit != SCIx_NOT_SUPPORTED) { if (status & (1 << s->cfg->overrun_bit)) { /* Handle overruns */ if (status & (1 << s->overrun_bit)) { port->icount.overrun++; /* overrun error */ Loading @@ -768,7 +772,6 @@ static int sci_handle_errors(struct uart_port *port) dev_notice(port->dev, "overrun error"); } } if (status & SCxSR_FER(port)) { if (sci_rxd_in(port) == 0) { Loading Loading @@ -829,7 +832,7 @@ static int sci_handle_fifo_overrun(struct uart_port *port) if (!reg->size) return 0; if ((serial_port_in(port, SCLSR) & (1 << s->cfg->overrun_bit))) { if ((serial_port_in(port, SCLSR) & (1 << s->overrun_bit))) { serial_port_out(port, SCLSR, 0); port->icount.overrun++; Loading Loading @@ -1075,19 +1078,19 @@ static int sci_request_irq(struct sci_port *port) for (i = j = 0; i < SCIx_NR_IRQS; i++, j++) { struct sci_irq_desc *desc; unsigned int irq; int irq; if (SCIx_IRQ_IS_MUXED(port)) { i = SCIx_MUX_IRQ; irq = up->irq; } else { irq = port->cfg->irqs[i]; irq = port->irqs[i]; /* * Certain port types won't support all of the * available interrupt sources. */ if (unlikely(!irq)) if (unlikely(irq < 0)) continue; } Loading @@ -1112,7 +1115,7 @@ static int sci_request_irq(struct sci_port *port) out_noirq: while (--i >= 0) free_irq(port->cfg->irqs[i], port); free_irq(port->irqs[i], port); out_nomem: while (--j >= 0) Loading @@ -1130,16 +1133,16 @@ static void sci_free_irq(struct sci_port *port) * IRQ first. */ for (i = 0; i < SCIx_NR_IRQS; i++) { unsigned int irq = port->cfg->irqs[i]; int irq = port->irqs[i]; /* * Certain port types won't support all of the available * interrupt sources. */ if (unlikely(!irq)) if (unlikely(irq < 0)) continue; free_irq(port->cfg->irqs[i], port); free_irq(port->irqs[i], port); kfree(port->irqstr[i]); if (SCIx_IRQ_IS_MUXED(port)) { Loading @@ -1149,67 +1152,6 @@ static void sci_free_irq(struct sci_port *port) } } static const char *sci_gpio_names[SCIx_NR_FNS] = { "sck", "rxd", "txd", "cts", "rts", }; static const char *sci_gpio_str(unsigned int index) { return sci_gpio_names[index]; } static void sci_init_gpios(struct sci_port *port) { struct uart_port *up = &port->port; int i; if (!port->cfg) return; for (i = 0; i < SCIx_NR_FNS; i++) { const char *desc; int ret; if (!port->cfg->gpios[i]) continue; desc = sci_gpio_str(i); port->gpiostr[i] = kasprintf(GFP_KERNEL, "%s:%s", dev_name(up->dev), desc); /* * If we've failed the allocation, we can still continue * on with a NULL string. */ if (!port->gpiostr[i]) dev_notice(up->dev, "%s string allocation failure\n", desc); ret = gpio_request(port->cfg->gpios[i], port->gpiostr[i]); if (unlikely(ret != 0)) { dev_notice(up->dev, "failed %s gpio request\n", desc); /* * If we can't get the GPIO for whatever reason, * no point in keeping the verbose string around. */ kfree(port->gpiostr[i]); } } } static void sci_free_gpios(struct sci_port *port) { int i; for (i = 0; i < SCIx_NR_FNS; i++) if (port->cfg->gpios[i]) { gpio_free(port->cfg->gpios[i]); kfree(port->gpiostr[i]); } } static unsigned int sci_tx_empty(struct uart_port *port) { unsigned short status = serial_port_in(port, SCxSR); Loading Loading @@ -1309,7 +1251,7 @@ static int sci_dma_rx_push(struct sci_port *s, size_t count) } if (room < count) dev_warn(port->dev, "Rx overrun: dropping %u bytes\n", dev_warn(port->dev, "Rx overrun: dropping %zu bytes\n", count - room); if (!room) return room; Loading Loading @@ -1442,7 +1384,7 @@ static void work_fn_rx(struct work_struct *work) int count; chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); dev_dbg(port->dev, "Read %u bytes with cookie %d\n", dev_dbg(port->dev, "Read %zu bytes with cookie %d\n", sh_desc->partial, sh_desc->cookie); spin_lock_irqsave(&port->lock, flags); Loading Loading @@ -1655,7 +1597,7 @@ static void rx_timer_fn(unsigned long arg) if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { scr &= ~0x4000; enable_irq(s->cfg->irqs[1]); enable_irq(s->irqs[SCIx_RXI_IRQ]); } serial_port_out(port, SCSCR, scr | SCSCR_RIE); dev_dbg(port->dev, "DMA Rx timed out\n"); Loading Loading @@ -1691,16 +1633,17 @@ static void sci_request_dma(struct uart_port *port) s->chan_tx = chan; sg_init_table(&s->sg_tx, 1); /* UART circular tx buffer is an aligned page. */ BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK); BUG_ON((uintptr_t)port->state->xmit.buf & ~PAGE_MASK); sg_set_page(&s->sg_tx, virt_to_page(port->state->xmit.buf), UART_XMIT_SIZE, (int)port->state->xmit.buf & ~PAGE_MASK); UART_XMIT_SIZE, (uintptr_t)port->state->xmit.buf & ~PAGE_MASK); nent = dma_map_sg(port->dev, &s->sg_tx, 1, DMA_TO_DEVICE); if (!nent) sci_tx_dma_release(s, false); else dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", __func__, sg_dma_len(&s->sg_tx), port->state->xmit.buf, sg_dma_address(&s->sg_tx)); dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n", __func__, sg_dma_len(&s->sg_tx), port->state->xmit.buf, &sg_dma_address(&s->sg_tx)); s->sg_len_tx = nent; Loading Loading @@ -1740,7 +1683,7 @@ static void sci_request_dma(struct uart_port *port) sg_init_table(sg, 1); sg_set_page(sg, virt_to_page(buf[i]), s->buf_len_rx, (int)buf[i] & ~PAGE_MASK); (uintptr_t)buf[i] & ~PAGE_MASK); sg_dma_address(sg) = dma[i]; } Loading Loading @@ -1808,20 +1751,21 @@ static void sci_shutdown(struct uart_port *port) sci_free_irq(s); } static unsigned int sci_scbrr_calc(unsigned int algo_id, unsigned int bps, static unsigned int sci_scbrr_calc(struct sci_port *s, unsigned int bps, unsigned long freq) { switch (algo_id) { if (s->sampling_rate) return DIV_ROUND_CLOSEST(freq, s->sampling_rate * bps) - 1; switch (s->cfg->scbrr_algo_id) { case SCBRR_ALGO_1: return ((freq + 16 * bps) / (16 * bps) - 1); return freq / (16 * bps); case SCBRR_ALGO_2: return ((freq + 16 * bps) / (32 * bps) - 1); return DIV_ROUND_CLOSEST(freq, 32 * bps) - 1; case SCBRR_ALGO_3: return (((freq * 2) + 16 * bps) / (16 * bps) - 1); return freq / (8 * bps); case SCBRR_ALGO_4: return (((freq * 2) + 16 * bps) / (32 * bps) - 1); case SCBRR_ALGO_5: return (((freq * 1000 / 32) / bps) - 1); return DIV_ROUND_CLOSEST(freq, 16 * bps) - 1; } /* Warn, but use a safe default */ Loading Loading @@ -1903,12 +1847,11 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, baud = uart_get_baud_rate(port, termios, old, 0, max_baud); if (likely(baud && port->uartclk)) { if (s->cfg->scbrr_algo_id == SCBRR_ALGO_6) { if (s->cfg->type == PORT_HSCIF) { sci_baud_calc_hscif(baud, port->uartclk, &t, &srr, &cks); } else { t = sci_scbrr_calc(s->cfg->scbrr_algo_id, baud, port->uartclk); t = sci_scbrr_calc(s, baud, port->uartclk); for (cks = 0; t >= 256 && cks <= 3; cks++) t >>= 2; } Loading Loading @@ -2115,10 +2058,6 @@ static void sci_config_port(struct uart_port *port, int flags) static int sci_verify_port(struct uart_port *port, struct serial_struct *ser) { struct sci_port *s = to_sci_port(port); if (ser->irq != s->cfg->irqs[SCIx_TXI_IRQ] || ser->irq > nr_irqs) return -EINVAL; if (ser->baud_base < 2400) /* No paper tape reader for Mitch.. */ return -EINVAL; Loading Loading @@ -2151,11 +2090,13 @@ static struct uart_ops sci_uart_ops = { }; static int sci_init_single(struct platform_device *dev, struct sci_port *sci_port, unsigned int index, struct plat_sci_port *p) struct sci_port *sci_port, unsigned int index, struct plat_sci_port *p, bool early) { struct uart_port *port = &sci_port->port; const struct resource *res; unsigned int sampling_rate; unsigned int i; int ret; sci_port->cfg = p; Loading @@ -2164,31 +2105,90 @@ static int sci_init_single(struct platform_device *dev, port->iotype = UPIO_MEM; port->line = index; if (dev->num_resources) { /* Device has resources, use them. */ res = platform_get_resource(dev, IORESOURCE_MEM, 0); if (res == NULL) return -ENOMEM; port->mapbase = res->start; for (i = 0; i < ARRAY_SIZE(sci_port->irqs); ++i) sci_port->irqs[i] = platform_get_irq(dev, i); /* The SCI generates several interrupts. They can be muxed * together or connected to different interrupt lines. In the * muxed case only one interrupt resource is specified. In the * non-muxed case three or four interrupt resources are * specified, as the BRI interrupt is optional. */ if (sci_port->irqs[0] < 0) return -ENXIO; if (sci_port->irqs[1] < 0) { sci_port->irqs[1] = sci_port->irqs[0]; sci_port->irqs[2] = sci_port->irqs[0]; sci_port->irqs[3] = sci_port->irqs[0]; } } else { /* No resources, use old-style platform data. */ port->mapbase = p->mapbase; for (i = 0; i < ARRAY_SIZE(sci_port->irqs); ++i) sci_port->irqs[i] = p->irqs[i] ? p->irqs[i] : -ENXIO; } if (p->regtype == SCIx_PROBE_REGTYPE) { ret = sci_probe_regmap(p); if (unlikely(ret)) return ret; } switch (p->type) { case PORT_SCIFB: port->fifosize = 256; sci_port->overrun_bit = 9; sampling_rate = 16; break; case PORT_HSCIF: port->fifosize = 128; sampling_rate = 0; sci_port->overrun_bit = 0; break; case PORT_SCIFA: port->fifosize = 64; sci_port->overrun_bit = 9; sampling_rate = 16; break; case PORT_SCIF: port->fifosize = 16; if (p->regtype == SCIx_SH7705_SCIF_REGTYPE) { sci_port->overrun_bit = 9; sampling_rate = 16; } else { sci_port->overrun_bit = 0; sampling_rate = 32; } break; default: port->fifosize = 1; sci_port->overrun_bit = 5; sampling_rate = 32; break; } if (p->regtype == SCIx_PROBE_REGTYPE) { ret = sci_probe_regmap(p); if (unlikely(ret)) return ret; /* Set the sampling rate if the baud rate calculation algorithm isn't * specified. */ if (p->scbrr_algo_id == SCBRR_ALGO_NONE) { /* SCIFA on sh7723 and sh7724 need a custom sampling rate that * doesn't match the SoC datasheet, this should be investigated. * Let platform data override the sampling rate for now. */ sci_port->sampling_rate = p->sampling_rate ? p->sampling_rate : sampling_rate; } if (dev) { if (!early) { sci_port->iclk = clk_get(&dev->dev, "sci_ick"); if (IS_ERR(sci_port->iclk)) { sci_port->iclk = clk_get(&dev->dev, "peripheral_clk"); Loading @@ -2208,8 +2208,6 @@ static int sci_init_single(struct platform_device *dev, port->dev = &dev->dev; sci_init_gpios(sci_port); pm_runtime_enable(&dev->dev); } Loading @@ -2220,32 +2218,22 @@ static int sci_init_single(struct platform_device *dev, /* * Establish some sensible defaults for the error detection. */ if (!p->error_mask) p->error_mask = (p->type == PORT_SCI) ? sci_port->error_mask = (p->type == PORT_SCI) ? SCI_DEFAULT_ERROR_MASK : SCIF_DEFAULT_ERROR_MASK; /* * Establish sensible defaults for the overrun detection, unless * the part has explicitly disabled support for it. */ if (p->overrun_bit != SCIx_NOT_SUPPORTED) { if (p->type == PORT_SCI) p->overrun_bit = 5; else if (p->scbrr_algo_id == SCBRR_ALGO_4) p->overrun_bit = 9; else p->overrun_bit = 0; /* * Make the error mask inclusive of overrun detection, if * supported. */ p->error_mask |= (1 << p->overrun_bit); } sci_port->error_mask |= 1 << sci_port->overrun_bit; port->mapbase = p->mapbase; port->type = p->type; port->flags = p->flags; port->flags = UPF_FIXED_PORT | p->flags; port->regshift = p->regshift; /* Loading @@ -2255,7 +2243,7 @@ static int sci_init_single(struct platform_device *dev, * * For the muxed case there's nothing more to do. */ port->irq = p->irqs[SCIx_RXI_IRQ]; port->irq = sci_port->irqs[SCIx_RXI_IRQ]; port->irqflags = 0; port->serial_in = sci_serial_in; Loading @@ -2270,8 +2258,6 @@ static int sci_init_single(struct platform_device *dev, static void sci_cleanup_single(struct sci_port *port) { sci_free_gpios(port); clk_put(port->iclk); clk_put(port->fclk); Loading Loading @@ -2387,7 +2373,7 @@ static int sci_probe_earlyprintk(struct platform_device *pdev) early_serial_console.index = pdev->id; sci_init_single(NULL, &sci_ports[pdev->id], pdev->id, cfg); sci_init_single(pdev, &sci_ports[pdev->id], pdev->id, cfg, true); serial_console_setup(&early_serial_console, early_serial_buf); Loading Loading @@ -2454,7 +2440,7 @@ static int sci_probe_single(struct platform_device *dev, return -EINVAL; } ret = sci_init_single(dev, sciport, index, p); ret = sci_init_single(dev, sciport, index, p, false); if (ret) return ret; Loading drivers/tty/serial/sh-sci.h +1 −1 Original line number Diff line number Diff line Loading @@ -9,7 +9,7 @@ #define SCxSR_PER(port) (((port)->type == PORT_SCI) ? SCI_PER : SCIF_PER) #define SCxSR_BRK(port) (((port)->type == PORT_SCI) ? 0x00 : SCIF_BRK) #define SCxSR_ERRORS(port) (to_sci_port(port)->cfg->error_mask) #define SCxSR_ERRORS(port) (to_sci_port(port)->error_mask) #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ defined(CONFIG_CPU_SUBTYPE_SH7720) || \ Loading include/linux/serial_sci.h +10 −24 Original line number Diff line number Diff line Loading @@ -11,11 +11,11 @@ #define SCIx_NOT_SUPPORTED (-1) enum { SCBRR_ALGO_1, /* ((clk + 16 * bps) / (16 * bps) - 1) */ SCBRR_ALGO_2, /* ((clk + 16 * bps) / (32 * bps) - 1) */ SCBRR_ALGO_3, /* (((clk * 2) + 16 * bps) / (16 * bps) - 1) */ SCBRR_ALGO_4, /* (((clk * 2) + 16 * bps) / (32 * bps) - 1) */ SCBRR_ALGO_5, /* (((clk * 1000 / 32) / bps) - 1) */ SCBRR_ALGO_NONE, /* Compute sampling rate in the driver */ SCBRR_ALGO_1, /* clk / (16 * bps) */ SCBRR_ALGO_2, /* DIV_ROUND_CLOSEST(clk, 32 * bps) - 1 */ SCBRR_ALGO_3, /* clk / (8 * bps) */ SCBRR_ALGO_4, /* DIV_ROUND_CLOSEST(clk, 16 * bps) - 1 */ SCBRR_ALGO_6, /* HSCIF variable sample rate algorithm */ }; Loading Loading @@ -70,17 +70,6 @@ enum { SCIx_MUX_IRQ = SCIx_NR_IRQS, /* special case */ }; /* Offsets into the sci_port->gpios array */ enum { SCIx_SCK, SCIx_RXD, SCIx_TXD, SCIx_CTS, SCIx_RTS, SCIx_NR_FNS, }; enum { SCIx_PROBE_REGTYPE, Loading Loading @@ -108,10 +97,10 @@ enum { } #define SCIx_IRQ_IS_MUXED(port) \ ((port)->cfg->irqs[SCIx_ERI_IRQ] == \ (port)->cfg->irqs[SCIx_RXI_IRQ]) || \ ((port)->cfg->irqs[SCIx_ERI_IRQ] && \ !(port)->cfg->irqs[SCIx_RXI_IRQ]) ((port)->irqs[SCIx_ERI_IRQ] == \ (port)->irqs[SCIx_RXI_IRQ]) || \ ((port)->irqs[SCIx_ERI_IRQ] && \ ((port)->irqs[SCIx_RXI_IRQ] < 0)) /* * SCI register subset common for all port types. * Not all registers will exist on all parts. Loading Loading @@ -142,20 +131,17 @@ struct plat_sci_port_ops { struct plat_sci_port { unsigned long mapbase; /* resource base */ unsigned int irqs[SCIx_NR_IRQS]; /* ERI, RXI, TXI, BRI */ unsigned int gpios[SCIx_NR_FNS]; /* SCK, RXD, TXD, CTS, RTS */ unsigned int type; /* SCI / SCIF / IRDA / HSCIF */ upf_t flags; /* UPF_* flags */ unsigned long capabilities; /* Port features/capabilities */ unsigned int sampling_rate; unsigned int scbrr_algo_id; /* SCBRR calculation algo */ unsigned int scscr; /* SCSCR initialization */ /* * Platform overrides if necessary, defaults otherwise. */ int overrun_bit; unsigned int error_mask; int port_reg; unsigned char regshift; unsigned char regtype; Loading Loading
drivers/tty/serial/sh-sci.c +153 −167 Original line number Diff line number Diff line Loading @@ -23,35 +23,34 @@ #undef DEBUG #include <linux/module.h> #include <linux/clk.h> #include <linux/console.h> #include <linux/ctype.h> #include <linux/cpufreq.h> #include <linux/delay.h> #include <linux/dmaengine.h> #include <linux/dma-mapping.h> #include <linux/err.h> #include <linux/errno.h> #include <linux/sh_dma.h> #include <linux/timer.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/serial.h> #include <linux/major.h> #include <linux/string.h> #include <linux/sysrq.h> #include <linux/ioport.h> #include <linux/major.h> #include <linux/module.h> #include <linux/mm.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/console.h> #include <linux/platform_device.h> #include <linux/serial_sci.h> #include <linux/notifier.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/cpufreq.h> #include <linux/clk.h> #include <linux/ctype.h> #include <linux/err.h> #include <linux/dmaengine.h> #include <linux/dma-mapping.h> #include <linux/scatterlist.h> #include <linux/serial.h> #include <linux/serial_sci.h> #include <linux/sh_dma.h> #include <linux/slab.h> #include <linux/gpio.h> #include <linux/string.h> #include <linux/sysrq.h> #include <linux/timer.h> #include <linux/tty.h> #include <linux/tty_flip.h> #ifdef CONFIG_SUPERH #include <asm/sh_bios.h> Loading @@ -64,6 +63,10 @@ struct sci_port { /* Platform configuration */ struct plat_sci_port *cfg; int overrun_bit; unsigned int error_mask; unsigned int sampling_rate; /* Break timer */ struct timer_list break_timer; Loading @@ -74,8 +77,8 @@ struct sci_port { /* Function clock */ struct clk *fclk; int irqs[SCIx_NR_IRQS]; char *irqstr[SCIx_NR_IRQS]; char *gpiostr[SCIx_NR_FNS]; struct dma_chan *chan_tx; struct dma_chan *chan_rx; Loading Loading @@ -421,9 +424,9 @@ static void sci_port_enable(struct sci_port *sci_port) pm_runtime_get_sync(sci_port->port.dev); clk_enable(sci_port->iclk); clk_prepare_enable(sci_port->iclk); sci_port->port.uartclk = clk_get_rate(sci_port->iclk); clk_enable(sci_port->fclk); clk_prepare_enable(sci_port->fclk); } static void sci_port_disable(struct sci_port *sci_port) Loading @@ -431,8 +434,16 @@ static void sci_port_disable(struct sci_port *sci_port) if (!sci_port->port.dev) return; clk_disable(sci_port->fclk); clk_disable(sci_port->iclk); /* Cancel the break timer to ensure that the timer handler will not try * to access the hardware with clocks and power disabled. Reset the * break flag to make the break debouncing state machine ready for the * next break. */ del_timer_sync(&sci_port->break_timer); sci_port->break_flag = 0; clk_disable_unprepare(sci_port->fclk); clk_disable_unprepare(sci_port->iclk); pm_runtime_put_sync(sci_port->port.dev); } Loading Loading @@ -557,7 +568,7 @@ static inline int sci_rxd_in(struct uart_port *port) return 1; /* Cast for ARM damage */ return !!__raw_readb((void __iomem *)s->cfg->port_reg); return !!__raw_readb((void __iomem *)(uintptr_t)s->cfg->port_reg); } /* ********************************************************************** * Loading Loading @@ -733,8 +744,6 @@ static void sci_break_timer(unsigned long data) { struct sci_port *port = (struct sci_port *)data; sci_port_enable(port); if (sci_rxd_in(&port->port) == 0) { port->break_flag = 1; sci_schedule_break_timer(port); Loading @@ -744,8 +753,6 @@ static void sci_break_timer(unsigned long data) sci_schedule_break_timer(port); } else port->break_flag = 0; sci_port_disable(port); } static int sci_handle_errors(struct uart_port *port) Loading @@ -755,11 +762,8 @@ static int sci_handle_errors(struct uart_port *port) struct tty_port *tport = &port->state->port; struct sci_port *s = to_sci_port(port); /* * Handle overruns, if supported. */ if (s->cfg->overrun_bit != SCIx_NOT_SUPPORTED) { if (status & (1 << s->cfg->overrun_bit)) { /* Handle overruns */ if (status & (1 << s->overrun_bit)) { port->icount.overrun++; /* overrun error */ Loading @@ -768,7 +772,6 @@ static int sci_handle_errors(struct uart_port *port) dev_notice(port->dev, "overrun error"); } } if (status & SCxSR_FER(port)) { if (sci_rxd_in(port) == 0) { Loading Loading @@ -829,7 +832,7 @@ static int sci_handle_fifo_overrun(struct uart_port *port) if (!reg->size) return 0; if ((serial_port_in(port, SCLSR) & (1 << s->cfg->overrun_bit))) { if ((serial_port_in(port, SCLSR) & (1 << s->overrun_bit))) { serial_port_out(port, SCLSR, 0); port->icount.overrun++; Loading Loading @@ -1075,19 +1078,19 @@ static int sci_request_irq(struct sci_port *port) for (i = j = 0; i < SCIx_NR_IRQS; i++, j++) { struct sci_irq_desc *desc; unsigned int irq; int irq; if (SCIx_IRQ_IS_MUXED(port)) { i = SCIx_MUX_IRQ; irq = up->irq; } else { irq = port->cfg->irqs[i]; irq = port->irqs[i]; /* * Certain port types won't support all of the * available interrupt sources. */ if (unlikely(!irq)) if (unlikely(irq < 0)) continue; } Loading @@ -1112,7 +1115,7 @@ static int sci_request_irq(struct sci_port *port) out_noirq: while (--i >= 0) free_irq(port->cfg->irqs[i], port); free_irq(port->irqs[i], port); out_nomem: while (--j >= 0) Loading @@ -1130,16 +1133,16 @@ static void sci_free_irq(struct sci_port *port) * IRQ first. */ for (i = 0; i < SCIx_NR_IRQS; i++) { unsigned int irq = port->cfg->irqs[i]; int irq = port->irqs[i]; /* * Certain port types won't support all of the available * interrupt sources. */ if (unlikely(!irq)) if (unlikely(irq < 0)) continue; free_irq(port->cfg->irqs[i], port); free_irq(port->irqs[i], port); kfree(port->irqstr[i]); if (SCIx_IRQ_IS_MUXED(port)) { Loading @@ -1149,67 +1152,6 @@ static void sci_free_irq(struct sci_port *port) } } static const char *sci_gpio_names[SCIx_NR_FNS] = { "sck", "rxd", "txd", "cts", "rts", }; static const char *sci_gpio_str(unsigned int index) { return sci_gpio_names[index]; } static void sci_init_gpios(struct sci_port *port) { struct uart_port *up = &port->port; int i; if (!port->cfg) return; for (i = 0; i < SCIx_NR_FNS; i++) { const char *desc; int ret; if (!port->cfg->gpios[i]) continue; desc = sci_gpio_str(i); port->gpiostr[i] = kasprintf(GFP_KERNEL, "%s:%s", dev_name(up->dev), desc); /* * If we've failed the allocation, we can still continue * on with a NULL string. */ if (!port->gpiostr[i]) dev_notice(up->dev, "%s string allocation failure\n", desc); ret = gpio_request(port->cfg->gpios[i], port->gpiostr[i]); if (unlikely(ret != 0)) { dev_notice(up->dev, "failed %s gpio request\n", desc); /* * If we can't get the GPIO for whatever reason, * no point in keeping the verbose string around. */ kfree(port->gpiostr[i]); } } } static void sci_free_gpios(struct sci_port *port) { int i; for (i = 0; i < SCIx_NR_FNS; i++) if (port->cfg->gpios[i]) { gpio_free(port->cfg->gpios[i]); kfree(port->gpiostr[i]); } } static unsigned int sci_tx_empty(struct uart_port *port) { unsigned short status = serial_port_in(port, SCxSR); Loading Loading @@ -1309,7 +1251,7 @@ static int sci_dma_rx_push(struct sci_port *s, size_t count) } if (room < count) dev_warn(port->dev, "Rx overrun: dropping %u bytes\n", dev_warn(port->dev, "Rx overrun: dropping %zu bytes\n", count - room); if (!room) return room; Loading Loading @@ -1442,7 +1384,7 @@ static void work_fn_rx(struct work_struct *work) int count; chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); dev_dbg(port->dev, "Read %u bytes with cookie %d\n", dev_dbg(port->dev, "Read %zu bytes with cookie %d\n", sh_desc->partial, sh_desc->cookie); spin_lock_irqsave(&port->lock, flags); Loading Loading @@ -1655,7 +1597,7 @@ static void rx_timer_fn(unsigned long arg) if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { scr &= ~0x4000; enable_irq(s->cfg->irqs[1]); enable_irq(s->irqs[SCIx_RXI_IRQ]); } serial_port_out(port, SCSCR, scr | SCSCR_RIE); dev_dbg(port->dev, "DMA Rx timed out\n"); Loading Loading @@ -1691,16 +1633,17 @@ static void sci_request_dma(struct uart_port *port) s->chan_tx = chan; sg_init_table(&s->sg_tx, 1); /* UART circular tx buffer is an aligned page. */ BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK); BUG_ON((uintptr_t)port->state->xmit.buf & ~PAGE_MASK); sg_set_page(&s->sg_tx, virt_to_page(port->state->xmit.buf), UART_XMIT_SIZE, (int)port->state->xmit.buf & ~PAGE_MASK); UART_XMIT_SIZE, (uintptr_t)port->state->xmit.buf & ~PAGE_MASK); nent = dma_map_sg(port->dev, &s->sg_tx, 1, DMA_TO_DEVICE); if (!nent) sci_tx_dma_release(s, false); else dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", __func__, sg_dma_len(&s->sg_tx), port->state->xmit.buf, sg_dma_address(&s->sg_tx)); dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n", __func__, sg_dma_len(&s->sg_tx), port->state->xmit.buf, &sg_dma_address(&s->sg_tx)); s->sg_len_tx = nent; Loading Loading @@ -1740,7 +1683,7 @@ static void sci_request_dma(struct uart_port *port) sg_init_table(sg, 1); sg_set_page(sg, virt_to_page(buf[i]), s->buf_len_rx, (int)buf[i] & ~PAGE_MASK); (uintptr_t)buf[i] & ~PAGE_MASK); sg_dma_address(sg) = dma[i]; } Loading Loading @@ -1808,20 +1751,21 @@ static void sci_shutdown(struct uart_port *port) sci_free_irq(s); } static unsigned int sci_scbrr_calc(unsigned int algo_id, unsigned int bps, static unsigned int sci_scbrr_calc(struct sci_port *s, unsigned int bps, unsigned long freq) { switch (algo_id) { if (s->sampling_rate) return DIV_ROUND_CLOSEST(freq, s->sampling_rate * bps) - 1; switch (s->cfg->scbrr_algo_id) { case SCBRR_ALGO_1: return ((freq + 16 * bps) / (16 * bps) - 1); return freq / (16 * bps); case SCBRR_ALGO_2: return ((freq + 16 * bps) / (32 * bps) - 1); return DIV_ROUND_CLOSEST(freq, 32 * bps) - 1; case SCBRR_ALGO_3: return (((freq * 2) + 16 * bps) / (16 * bps) - 1); return freq / (8 * bps); case SCBRR_ALGO_4: return (((freq * 2) + 16 * bps) / (32 * bps) - 1); case SCBRR_ALGO_5: return (((freq * 1000 / 32) / bps) - 1); return DIV_ROUND_CLOSEST(freq, 16 * bps) - 1; } /* Warn, but use a safe default */ Loading Loading @@ -1903,12 +1847,11 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, baud = uart_get_baud_rate(port, termios, old, 0, max_baud); if (likely(baud && port->uartclk)) { if (s->cfg->scbrr_algo_id == SCBRR_ALGO_6) { if (s->cfg->type == PORT_HSCIF) { sci_baud_calc_hscif(baud, port->uartclk, &t, &srr, &cks); } else { t = sci_scbrr_calc(s->cfg->scbrr_algo_id, baud, port->uartclk); t = sci_scbrr_calc(s, baud, port->uartclk); for (cks = 0; t >= 256 && cks <= 3; cks++) t >>= 2; } Loading Loading @@ -2115,10 +2058,6 @@ static void sci_config_port(struct uart_port *port, int flags) static int sci_verify_port(struct uart_port *port, struct serial_struct *ser) { struct sci_port *s = to_sci_port(port); if (ser->irq != s->cfg->irqs[SCIx_TXI_IRQ] || ser->irq > nr_irqs) return -EINVAL; if (ser->baud_base < 2400) /* No paper tape reader for Mitch.. */ return -EINVAL; Loading Loading @@ -2151,11 +2090,13 @@ static struct uart_ops sci_uart_ops = { }; static int sci_init_single(struct platform_device *dev, struct sci_port *sci_port, unsigned int index, struct plat_sci_port *p) struct sci_port *sci_port, unsigned int index, struct plat_sci_port *p, bool early) { struct uart_port *port = &sci_port->port; const struct resource *res; unsigned int sampling_rate; unsigned int i; int ret; sci_port->cfg = p; Loading @@ -2164,31 +2105,90 @@ static int sci_init_single(struct platform_device *dev, port->iotype = UPIO_MEM; port->line = index; if (dev->num_resources) { /* Device has resources, use them. */ res = platform_get_resource(dev, IORESOURCE_MEM, 0); if (res == NULL) return -ENOMEM; port->mapbase = res->start; for (i = 0; i < ARRAY_SIZE(sci_port->irqs); ++i) sci_port->irqs[i] = platform_get_irq(dev, i); /* The SCI generates several interrupts. They can be muxed * together or connected to different interrupt lines. In the * muxed case only one interrupt resource is specified. In the * non-muxed case three or four interrupt resources are * specified, as the BRI interrupt is optional. */ if (sci_port->irqs[0] < 0) return -ENXIO; if (sci_port->irqs[1] < 0) { sci_port->irqs[1] = sci_port->irqs[0]; sci_port->irqs[2] = sci_port->irqs[0]; sci_port->irqs[3] = sci_port->irqs[0]; } } else { /* No resources, use old-style platform data. */ port->mapbase = p->mapbase; for (i = 0; i < ARRAY_SIZE(sci_port->irqs); ++i) sci_port->irqs[i] = p->irqs[i] ? p->irqs[i] : -ENXIO; } if (p->regtype == SCIx_PROBE_REGTYPE) { ret = sci_probe_regmap(p); if (unlikely(ret)) return ret; } switch (p->type) { case PORT_SCIFB: port->fifosize = 256; sci_port->overrun_bit = 9; sampling_rate = 16; break; case PORT_HSCIF: port->fifosize = 128; sampling_rate = 0; sci_port->overrun_bit = 0; break; case PORT_SCIFA: port->fifosize = 64; sci_port->overrun_bit = 9; sampling_rate = 16; break; case PORT_SCIF: port->fifosize = 16; if (p->regtype == SCIx_SH7705_SCIF_REGTYPE) { sci_port->overrun_bit = 9; sampling_rate = 16; } else { sci_port->overrun_bit = 0; sampling_rate = 32; } break; default: port->fifosize = 1; sci_port->overrun_bit = 5; sampling_rate = 32; break; } if (p->regtype == SCIx_PROBE_REGTYPE) { ret = sci_probe_regmap(p); if (unlikely(ret)) return ret; /* Set the sampling rate if the baud rate calculation algorithm isn't * specified. */ if (p->scbrr_algo_id == SCBRR_ALGO_NONE) { /* SCIFA on sh7723 and sh7724 need a custom sampling rate that * doesn't match the SoC datasheet, this should be investigated. * Let platform data override the sampling rate for now. */ sci_port->sampling_rate = p->sampling_rate ? p->sampling_rate : sampling_rate; } if (dev) { if (!early) { sci_port->iclk = clk_get(&dev->dev, "sci_ick"); if (IS_ERR(sci_port->iclk)) { sci_port->iclk = clk_get(&dev->dev, "peripheral_clk"); Loading @@ -2208,8 +2208,6 @@ static int sci_init_single(struct platform_device *dev, port->dev = &dev->dev; sci_init_gpios(sci_port); pm_runtime_enable(&dev->dev); } Loading @@ -2220,32 +2218,22 @@ static int sci_init_single(struct platform_device *dev, /* * Establish some sensible defaults for the error detection. */ if (!p->error_mask) p->error_mask = (p->type == PORT_SCI) ? sci_port->error_mask = (p->type == PORT_SCI) ? SCI_DEFAULT_ERROR_MASK : SCIF_DEFAULT_ERROR_MASK; /* * Establish sensible defaults for the overrun detection, unless * the part has explicitly disabled support for it. */ if (p->overrun_bit != SCIx_NOT_SUPPORTED) { if (p->type == PORT_SCI) p->overrun_bit = 5; else if (p->scbrr_algo_id == SCBRR_ALGO_4) p->overrun_bit = 9; else p->overrun_bit = 0; /* * Make the error mask inclusive of overrun detection, if * supported. */ p->error_mask |= (1 << p->overrun_bit); } sci_port->error_mask |= 1 << sci_port->overrun_bit; port->mapbase = p->mapbase; port->type = p->type; port->flags = p->flags; port->flags = UPF_FIXED_PORT | p->flags; port->regshift = p->regshift; /* Loading @@ -2255,7 +2243,7 @@ static int sci_init_single(struct platform_device *dev, * * For the muxed case there's nothing more to do. */ port->irq = p->irqs[SCIx_RXI_IRQ]; port->irq = sci_port->irqs[SCIx_RXI_IRQ]; port->irqflags = 0; port->serial_in = sci_serial_in; Loading @@ -2270,8 +2258,6 @@ static int sci_init_single(struct platform_device *dev, static void sci_cleanup_single(struct sci_port *port) { sci_free_gpios(port); clk_put(port->iclk); clk_put(port->fclk); Loading Loading @@ -2387,7 +2373,7 @@ static int sci_probe_earlyprintk(struct platform_device *pdev) early_serial_console.index = pdev->id; sci_init_single(NULL, &sci_ports[pdev->id], pdev->id, cfg); sci_init_single(pdev, &sci_ports[pdev->id], pdev->id, cfg, true); serial_console_setup(&early_serial_console, early_serial_buf); Loading Loading @@ -2454,7 +2440,7 @@ static int sci_probe_single(struct platform_device *dev, return -EINVAL; } ret = sci_init_single(dev, sciport, index, p); ret = sci_init_single(dev, sciport, index, p, false); if (ret) return ret; Loading
drivers/tty/serial/sh-sci.h +1 −1 Original line number Diff line number Diff line Loading @@ -9,7 +9,7 @@ #define SCxSR_PER(port) (((port)->type == PORT_SCI) ? SCI_PER : SCIF_PER) #define SCxSR_BRK(port) (((port)->type == PORT_SCI) ? 0x00 : SCIF_BRK) #define SCxSR_ERRORS(port) (to_sci_port(port)->cfg->error_mask) #define SCxSR_ERRORS(port) (to_sci_port(port)->error_mask) #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ defined(CONFIG_CPU_SUBTYPE_SH7720) || \ Loading
include/linux/serial_sci.h +10 −24 Original line number Diff line number Diff line Loading @@ -11,11 +11,11 @@ #define SCIx_NOT_SUPPORTED (-1) enum { SCBRR_ALGO_1, /* ((clk + 16 * bps) / (16 * bps) - 1) */ SCBRR_ALGO_2, /* ((clk + 16 * bps) / (32 * bps) - 1) */ SCBRR_ALGO_3, /* (((clk * 2) + 16 * bps) / (16 * bps) - 1) */ SCBRR_ALGO_4, /* (((clk * 2) + 16 * bps) / (32 * bps) - 1) */ SCBRR_ALGO_5, /* (((clk * 1000 / 32) / bps) - 1) */ SCBRR_ALGO_NONE, /* Compute sampling rate in the driver */ SCBRR_ALGO_1, /* clk / (16 * bps) */ SCBRR_ALGO_2, /* DIV_ROUND_CLOSEST(clk, 32 * bps) - 1 */ SCBRR_ALGO_3, /* clk / (8 * bps) */ SCBRR_ALGO_4, /* DIV_ROUND_CLOSEST(clk, 16 * bps) - 1 */ SCBRR_ALGO_6, /* HSCIF variable sample rate algorithm */ }; Loading Loading @@ -70,17 +70,6 @@ enum { SCIx_MUX_IRQ = SCIx_NR_IRQS, /* special case */ }; /* Offsets into the sci_port->gpios array */ enum { SCIx_SCK, SCIx_RXD, SCIx_TXD, SCIx_CTS, SCIx_RTS, SCIx_NR_FNS, }; enum { SCIx_PROBE_REGTYPE, Loading Loading @@ -108,10 +97,10 @@ enum { } #define SCIx_IRQ_IS_MUXED(port) \ ((port)->cfg->irqs[SCIx_ERI_IRQ] == \ (port)->cfg->irqs[SCIx_RXI_IRQ]) || \ ((port)->cfg->irqs[SCIx_ERI_IRQ] && \ !(port)->cfg->irqs[SCIx_RXI_IRQ]) ((port)->irqs[SCIx_ERI_IRQ] == \ (port)->irqs[SCIx_RXI_IRQ]) || \ ((port)->irqs[SCIx_ERI_IRQ] && \ ((port)->irqs[SCIx_RXI_IRQ] < 0)) /* * SCI register subset common for all port types. * Not all registers will exist on all parts. Loading Loading @@ -142,20 +131,17 @@ struct plat_sci_port_ops { struct plat_sci_port { unsigned long mapbase; /* resource base */ unsigned int irqs[SCIx_NR_IRQS]; /* ERI, RXI, TXI, BRI */ unsigned int gpios[SCIx_NR_FNS]; /* SCK, RXD, TXD, CTS, RTS */ unsigned int type; /* SCI / SCIF / IRDA / HSCIF */ upf_t flags; /* UPF_* flags */ unsigned long capabilities; /* Port features/capabilities */ unsigned int sampling_rate; unsigned int scbrr_algo_id; /* SCBRR calculation algo */ unsigned int scscr; /* SCSCR initialization */ /* * Platform overrides if necessary, defaults otherwise. */ int overrun_bit; unsigned int error_mask; int port_reg; unsigned char regshift; unsigned char regtype; Loading