diff options
Diffstat (limited to 'drivers/tty/serial/sh-sci.c')
-rw-r--r-- | drivers/tty/serial/sh-sci.c | 1092 |
1 files changed, 578 insertions, 514 deletions
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 91e7dddbf72c..9a47cc4f16a2 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -101,23 +101,30 @@ enum SCI_CLKS { for ((_sr) = max_sr(_port); (_sr) >= min_sr(_port); (_sr)--) \ if ((_port)->sampling_rate_mask & SCI_SR((_sr))) +struct plat_sci_reg { + u8 offset, size; +}; + +struct sci_port_params { + const struct plat_sci_reg regs[SCIx_NR_REGS]; + unsigned int fifosize; + unsigned int overrun_reg; + unsigned int overrun_mask; + unsigned int sampling_rate_mask; + unsigned int error_mask; + unsigned int error_clear; +}; + struct sci_port { struct uart_port port; /* Platform configuration */ - struct plat_sci_port *cfg; - unsigned int overrun_reg; - unsigned int overrun_mask; - unsigned int error_mask; - unsigned int error_clear; + const struct sci_port_params *params; + const struct plat_sci_port *cfg; unsigned int sampling_rate_mask; resource_size_t reg_size; struct mctrl_gpios *gpios; - /* Break timer */ - struct timer_list break_timer; - int break_flag; - /* Clocks */ struct clk *clks[SCI_NUM_CLKS]; unsigned long clk_rates[SCI_NUM_CLKS]; @@ -141,7 +148,12 @@ struct sci_port { struct timer_list rx_timer; unsigned int rx_timeout; #endif + unsigned int rx_frame; + int rx_trigger; + struct timer_list rx_fifo_timer; + int rx_fifo_timeout; + bool has_rtscts; bool autorts; }; @@ -156,110 +168,97 @@ to_sci_port(struct uart_port *uart) return container_of(uart, struct sci_port, port); } -struct plat_sci_reg { - u8 offset, size; -}; - -/* Helper for invalidating specific entries of an inherited map. */ -#define sci_reg_invalid { .offset = 0, .size = 0 } - -static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { - [SCIx_PROBE_REGTYPE] = { - [0 ... SCIx_NR_REGS - 1] = sci_reg_invalid, - }, - +static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { /* * Common SCI definitions, dependent on the port's regshift * value. */ [SCIx_SCI_REGTYPE] = { - [SCSMR] = { 0x00, 8 }, - [SCBRR] = { 0x01, 8 }, - [SCSCR] = { 0x02, 8 }, - [SCxTDR] = { 0x03, 8 }, - [SCxSR] = { 0x04, 8 }, - [SCxRDR] = { 0x05, 8 }, - [SCFCR] = sci_reg_invalid, - [SCFDR] = sci_reg_invalid, - [SCTFDR] = sci_reg_invalid, - [SCRFDR] = sci_reg_invalid, - [SCSPTR] = sci_reg_invalid, - [SCLSR] = sci_reg_invalid, - [HSSRR] = sci_reg_invalid, - [SCPCR] = sci_reg_invalid, - [SCPDR] = sci_reg_invalid, - [SCDL] = sci_reg_invalid, - [SCCKS] = sci_reg_invalid, + .regs = { + [SCSMR] = { 0x00, 8 }, + [SCBRR] = { 0x01, 8 }, + [SCSCR] = { 0x02, 8 }, + [SCxTDR] = { 0x03, 8 }, + [SCxSR] = { 0x04, 8 }, + [SCxRDR] = { 0x05, 8 }, + }, + .fifosize = 1, + .overrun_reg = SCxSR, + .overrun_mask = SCI_ORER, + .sampling_rate_mask = SCI_SR(32), + .error_mask = SCI_DEFAULT_ERROR_MASK | SCI_ORER, + .error_clear = SCI_ERROR_CLEAR & ~SCI_ORER, }, /* - * Common definitions for legacy IrDA ports, dependent on - * regshift value. + * Common definitions for legacy IrDA ports. */ [SCIx_IRDA_REGTYPE] = { - [SCSMR] = { 0x00, 8 }, - [SCBRR] = { 0x01, 8 }, - [SCSCR] = { 0x02, 8 }, - [SCxTDR] = { 0x03, 8 }, - [SCxSR] = { 0x04, 8 }, - [SCxRDR] = { 0x05, 8 }, - [SCFCR] = { 0x06, 8 }, - [SCFDR] = { 0x07, 16 }, - [SCTFDR] = sci_reg_invalid, - [SCRFDR] = sci_reg_invalid, - [SCSPTR] = sci_reg_invalid, - [SCLSR] = sci_reg_invalid, - [HSSRR] = sci_reg_invalid, - [SCPCR] = sci_reg_invalid, - [SCPDR] = sci_reg_invalid, - [SCDL] = sci_reg_invalid, - [SCCKS] = sci_reg_invalid, + .regs = { + [SCSMR] = { 0x00, 8 }, + [SCBRR] = { 0x02, 8 }, + [SCSCR] = { 0x04, 8 }, + [SCxTDR] = { 0x06, 8 }, + [SCxSR] = { 0x08, 16 }, + [SCxRDR] = { 0x0a, 8 }, + [SCFCR] = { 0x0c, 8 }, + [SCFDR] = { 0x0e, 16 }, + }, + .fifosize = 1, + .overrun_reg = SCxSR, + .overrun_mask = SCI_ORER, + .sampling_rate_mask = SCI_SR(32), + .error_mask = SCI_DEFAULT_ERROR_MASK | SCI_ORER, + .error_clear = SCI_ERROR_CLEAR & ~SCI_ORER, }, /* * Common SCIFA definitions. */ [SCIx_SCIFA_REGTYPE] = { - [SCSMR] = { 0x00, 16 }, - [SCBRR] = { 0x04, 8 }, - [SCSCR] = { 0x08, 16 }, - [SCxTDR] = { 0x20, 8 }, - [SCxSR] = { 0x14, 16 }, - [SCxRDR] = { 0x24, 8 }, - [SCFCR] = { 0x18, 16 }, - [SCFDR] = { 0x1c, 16 }, - [SCTFDR] = sci_reg_invalid, - [SCRFDR] = sci_reg_invalid, - [SCSPTR] = sci_reg_invalid, - [SCLSR] = sci_reg_invalid, - [HSSRR] = sci_reg_invalid, - [SCPCR] = { 0x30, 16 }, - [SCPDR] = { 0x34, 16 }, - [SCDL] = sci_reg_invalid, - [SCCKS] = sci_reg_invalid, + .regs = { + [SCSMR] = { 0x00, 16 }, + [SCBRR] = { 0x04, 8 }, + [SCSCR] = { 0x08, 16 }, + [SCxTDR] = { 0x20, 8 }, + [SCxSR] = { 0x14, 16 }, + [SCxRDR] = { 0x24, 8 }, + [SCFCR] = { 0x18, 16 }, + [SCFDR] = { 0x1c, 16 }, + [SCPCR] = { 0x30, 16 }, + [SCPDR] = { 0x34, 16 }, + }, + .fifosize = 64, + .overrun_reg = SCxSR, + .overrun_mask = SCIFA_ORER, + .sampling_rate_mask = SCI_SR_SCIFAB, + .error_mask = SCIF_DEFAULT_ERROR_MASK | SCIFA_ORER, + .error_clear = SCIF_ERROR_CLEAR & ~SCIFA_ORER, }, /* * Common SCIFB definitions. */ [SCIx_SCIFB_REGTYPE] = { - [SCSMR] = { 0x00, 16 }, - [SCBRR] = { 0x04, 8 }, - [SCSCR] = { 0x08, 16 }, - [SCxTDR] = { 0x40, 8 }, - [SCxSR] = { 0x14, 16 }, - [SCxRDR] = { 0x60, 8 }, - [SCFCR] = { 0x18, 16 }, - [SCFDR] = sci_reg_invalid, - [SCTFDR] = { 0x38, 16 }, - [SCRFDR] = { 0x3c, 16 }, - [SCSPTR] = sci_reg_invalid, - [SCLSR] = sci_reg_invalid, - [HSSRR] = sci_reg_invalid, - [SCPCR] = { 0x30, 16 }, - [SCPDR] = { 0x34, 16 }, - [SCDL] = sci_reg_invalid, - [SCCKS] = sci_reg_invalid, + .regs = { + [SCSMR] = { 0x00, 16 }, + [SCBRR] = { 0x04, 8 }, + [SCSCR] = { 0x08, 16 }, + [SCxTDR] = { 0x40, 8 }, + [SCxSR] = { 0x14, 16 }, + [SCxRDR] = { 0x60, 8 }, + [SCFCR] = { 0x18, 16 }, + [SCTFDR] = { 0x38, 16 }, + [SCRFDR] = { 0x3c, 16 }, + [SCPCR] = { 0x30, 16 }, + [SCPDR] = { 0x34, 16 }, + }, + .fifosize = 256, + .overrun_reg = SCxSR, + .overrun_mask = SCIFA_ORER, + .sampling_rate_mask = SCI_SR_SCIFAB, + .error_mask = SCIF_DEFAULT_ERROR_MASK | SCIFA_ORER, + .error_clear = SCIF_ERROR_CLEAR & ~SCIFA_ORER, }, /* @@ -267,69 +266,70 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { * count registers. */ [SCIx_SH2_SCIF_FIFODATA_REGTYPE] = { - [SCSMR] = { 0x00, 16 }, - [SCBRR] = { 0x04, 8 }, - [SCSCR] = { 0x08, 16 }, - [SCxTDR] = { 0x0c, 8 }, - [SCxSR] = { 0x10, 16 }, - [SCxRDR] = { 0x14, 8 }, - [SCFCR] = { 0x18, 16 }, - [SCFDR] = { 0x1c, 16 }, - [SCTFDR] = sci_reg_invalid, - [SCRFDR] = sci_reg_invalid, - [SCSPTR] = { 0x20, 16 }, - [SCLSR] = { 0x24, 16 }, - [HSSRR] = sci_reg_invalid, - [SCPCR] = sci_reg_invalid, - [SCPDR] = sci_reg_invalid, - [SCDL] = sci_reg_invalid, - [SCCKS] = sci_reg_invalid, + .regs = { + [SCSMR] = { 0x00, 16 }, + [SCBRR] = { 0x04, 8 }, + [SCSCR] = { 0x08, 16 }, + [SCxTDR] = { 0x0c, 8 }, + [SCxSR] = { 0x10, 16 }, + [SCxRDR] = { 0x14, 8 }, + [SCFCR] = { 0x18, 16 }, + [SCFDR] = { 0x1c, 16 }, + [SCSPTR] = { 0x20, 16 }, + [SCLSR] = { 0x24, 16 }, + }, + .fifosize = 16, + .overrun_reg = SCLSR, + .overrun_mask = SCLSR_ORER, + .sampling_rate_mask = SCI_SR(32), + .error_mask = SCIF_DEFAULT_ERROR_MASK, + .error_clear = SCIF_ERROR_CLEAR, }, /* * Common SH-3 SCIF definitions. */ [SCIx_SH3_SCIF_REGTYPE] = { - [SCSMR] = { 0x00, 8 }, - [SCBRR] = { 0x02, 8 }, - [SCSCR] = { 0x04, 8 }, - [SCxTDR] = { 0x06, 8 }, - [SCxSR] = { 0x08, 16 }, - [SCxRDR] = { 0x0a, 8 }, - [SCFCR] = { 0x0c, 8 }, - [SCFDR] = { 0x0e, 16 }, - [SCTFDR] = sci_reg_invalid, - [SCRFDR] = sci_reg_invalid, - [SCSPTR] = sci_reg_invalid, - [SCLSR] = sci_reg_invalid, - [HSSRR] = sci_reg_invalid, - [SCPCR] = sci_reg_invalid, - [SCPDR] = sci_reg_invalid, - [SCDL] = sci_reg_invalid, - [SCCKS] = sci_reg_invalid, + .regs = { + [SCSMR] = { 0x00, 8 }, + [SCBRR] = { 0x02, 8 }, + [SCSCR] = { 0x04, 8 }, + [SCxTDR] = { 0x06, 8 }, + [SCxSR] = { 0x08, 16 }, + [SCxRDR] = { 0x0a, 8 }, + [SCFCR] = { 0x0c, 8 }, + [SCFDR] = { 0x0e, 16 }, + }, + .fifosize = 16, + .overrun_reg = SCLSR, + .overrun_mask = SCLSR_ORER, + .sampling_rate_mask = SCI_SR(32), + .error_mask = SCIF_DEFAULT_ERROR_MASK, + .error_clear = SCIF_ERROR_CLEAR, }, /* * Common SH-4(A) SCIF(B) definitions. */ [SCIx_SH4_SCIF_REGTYPE] = { - [SCSMR] = { 0x00, 16 }, - [SCBRR] = { 0x04, 8 }, - [SCSCR] = { 0x08, 16 }, - [SCxTDR] = { 0x0c, 8 }, - [SCxSR] = { 0x10, 16 }, - [SCxRDR] = { 0x14, 8 }, - [SCFCR] = { 0x18, 16 }, - [SCFDR] = { 0x1c, 16 }, - [SCTFDR] = sci_reg_invalid, - [SCRFDR] = sci_reg_invalid, - [SCSPTR] = { 0x20, 16 }, - [SCLSR] = { 0x24, 16 }, - [HSSRR] = sci_reg_invalid, - [SCPCR] = sci_reg_invalid, - [SCPDR] = sci_reg_invalid, - [SCDL] = sci_reg_invalid, - [SCCKS] = sci_reg_invalid, + .regs = { + [SCSMR] = { 0x00, 16 }, + [SCBRR] = { 0x04, 8 }, + [SCSCR] = { 0x08, 16 }, + [SCxTDR] = { 0x0c, 8 }, + [SCxSR] = { 0x10, 16 }, + [SCxRDR] = { 0x14, 8 }, + [SCFCR] = { 0x18, 16 }, + [SCFDR] = { 0x1c, 16 }, + [SCSPTR] = { 0x20, 16 }, + [SCLSR] = { 0x24, 16 }, + }, + .fifosize = 16, + .overrun_reg = SCLSR, + .overrun_mask = SCLSR_ORER, + .sampling_rate_mask = SCI_SR(32), + .error_mask = SCIF_DEFAULT_ERROR_MASK, + .error_clear = SCIF_ERROR_CLEAR, }, /* @@ -337,46 +337,55 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { * External Clock (BRG). */ [SCIx_SH4_SCIF_BRG_REGTYPE] = { - [SCSMR] = { 0x00, 16 }, - [SCBRR] = { 0x04, 8 }, - [SCSCR] = { 0x08, 16 }, - [SCxTDR] = { 0x0c, 8 }, - [SCxSR] = { 0x10, 16 }, - [SCxRDR] = { 0x14, 8 }, - [SCFCR] = { 0x18, 16 }, - [SCFDR] = { 0x1c, 16 }, - [SCTFDR] = sci_reg_invalid, - [SCRFDR] = sci_reg_invalid, - [SCSPTR] = { 0x20, 16 }, - [SCLSR] = { 0x24, 16 }, - [HSSRR] = sci_reg_invalid, - [SCPCR] = sci_reg_invalid, - [SCPDR] = sci_reg_invalid, - [SCDL] = { 0x30, 16 }, - [SCCKS] = { 0x34, 16 }, + .regs = { + [SCSMR] = { 0x00, 16 }, + [SCBRR] = { 0x04, 8 }, + [SCSCR] = { 0x08, 16 }, + [SCxTDR] = { 0x0c, 8 }, + [SCxSR] = { 0x10, 16 }, + [SCxRDR] = { 0x14, 8 }, + [SCFCR] = { 0x18, 16 }, + [SCFDR] = { 0x1c, 16 }, + [SCSPTR] = { 0x20, 16 }, + [SCLSR] = { 0x24, 16 }, + [SCDL] = { 0x30, 16 }, + [SCCKS] = { 0x34, 16 }, + }, + .fifosize = 16, + .overrun_reg = SCLSR, + .overrun_mask = SCLSR_ORER, + .sampling_rate_mask = SCI_SR(32), + .error_mask = SCIF_DEFAULT_ERROR_MASK, + .error_clear = SCIF_ERROR_CLEAR, }, /* * Common HSCIF definitions. */ [SCIx_HSCIF_REGTYPE] = { - [SCSMR] = { 0x00, 16 }, - [SCBRR] = { 0x04, 8 }, - [SCSCR] = { 0x08, 16 }, - [SCxTDR] = { 0x0c, 8 }, - [SCxSR] = { 0x10, 16 }, - [SCxRDR] = { 0x14, 8 }, - [SCFCR] = { 0x18, 16 }, - [SCFDR] = { 0x1c, 16 }, - [SCTFDR] = sci_reg_invalid, - [SCRFDR] = sci_reg_invalid, - [SCSPTR] = { 0x20, 16 }, - [SCLSR] = { 0x24, 16 }, - [HSSRR] = { 0x40, 16 }, - [SCPCR] = sci_reg_invalid, - [SCPDR] = sci_reg_invalid, - [SCDL] = { 0x30, 16 }, - [SCCKS] = { 0x34, 16 }, + .regs = { + [SCSMR] = { 0x00, 16 }, + [SCBRR] = { 0x04, 8 }, + [SCSCR] = { 0x08, 16 }, + [SCxTDR] = { 0x0c, 8 }, + [SCxSR] = { 0x10, 16 }, + [SCxRDR] = { 0x14, 8 }, + [SCFCR] = { 0x18, 16 }, + [SCFDR] = { 0x1c, 16 }, + [SCSPTR] = { 0x20, 16 }, + [SCLSR] = { 0x24, 16 }, + [HSSRR] = { 0x40, 16 }, + [SCDL] = { 0x30, 16 }, + [SCCKS] = { 0x34, 16 }, + [HSRTRGR] = { 0x54, 16 }, + [HSTTRGR] = { 0x58, 16 }, + }, + .fifosize = 128, + .overrun_reg = SCLSR, + .overrun_mask = SCLSR_ORER, + .sampling_rate_mask = SCI_SR_RANGE(8, 32), + .error_mask = SCIF_DEFAULT_ERROR_MASK, + .error_clear = SCIF_ERROR_CLEAR, }, /* @@ -384,23 +393,23 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { * register. */ [SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE] = { - [SCSMR] = { 0x00, 16 }, - [SCBRR] = { 0x04, 8 }, - [SCSCR] = { 0x08, 16 }, - [SCxTDR] = { 0x0c, 8 }, - [SCxSR] = { 0x10, 16 }, - [SCxRDR] = { 0x14, 8 }, - [SCFCR] = { 0x18, 16 }, - [SCFDR] = { 0x1c, 16 }, - [SCTFDR] = sci_reg_invalid, - [SCRFDR] = sci_reg_invalid, - [SCSPTR] = sci_reg_invalid, - [SCLSR] = { 0x24, 16 }, - [HSSRR] = sci_reg_invalid, - [SCPCR] = sci_reg_invalid, - [SCPDR] = sci_reg_invalid, - [SCDL] = sci_reg_invalid, - [SCCKS] = sci_reg_invalid, + .regs = { + [SCSMR] = { 0x00, 16 }, + [SCBRR] = { 0x04, 8 }, + [SCSCR] = { 0x08, 16 }, + [SCxTDR] = { 0x0c, 8 }, + [SCxSR] = { 0x10, 16 }, + [SCxRDR] = { 0x14, 8 }, + [SCFCR] = { 0x18, 16 }, + [SCFDR] = { 0x1c, 16 }, + [SCLSR] = { 0x24, 16 }, + }, + .fifosize = 16, + .overrun_reg = SCLSR, + .overrun_mask = SCLSR_ORER, + .sampling_rate_mask = SCI_SR(32), + .error_mask = SCIF_DEFAULT_ERROR_MASK, + .error_clear = SCIF_ERROR_CLEAR, }, /* @@ -408,23 +417,26 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { * count registers. */ [SCIx_SH4_SCIF_FIFODATA_REGTYPE] = { - [SCSMR] = { 0x00, 16 }, - [SCBRR] = { 0x04, 8 }, - [SCSCR] = { 0x08, 16 }, - [SCxTDR] = { 0x0c, 8 }, - [SCxSR] = { 0x10, 16 }, - [SCxRDR] = { 0x14, 8 }, - [SCFCR] = { 0x18, 16 }, - [SCFDR] = { 0x1c, 16 }, - [SCTFDR] = { 0x1c, 16 }, /* aliased to SCFDR */ - [SCRFDR] = { 0x20, 16 }, - [SCSPTR] = { 0x24, 16 }, - [SCLSR] = { 0x28, 16 }, - [HSSRR] = sci_reg_invalid, - [SCPCR] = sci_reg_invalid, - [SCPDR] = sci_reg_invalid, - [SCDL] = sci_reg_invalid, - [SCCKS] = sci_reg_invalid, + .regs = { + [SCSMR] = { 0x00, 16 }, + [SCBRR] = { 0x04, 8 }, + [SCSCR] = { 0x08, 16 }, + [SCxTDR] = { 0x0c, 8 }, + [SCxSR] = { 0x10, 16 }, + [SCxRDR] = { 0x14, 8 }, + [SCFCR] = { 0x18, 16 }, + [SCFDR] = { 0x1c, 16 }, + [SCTFDR] = { 0x1c, 16 }, /* aliased to SCFDR */ + [SCRFDR] = { 0x20, 16 }, + [SCSPTR] = { 0x24, 16 }, + [SCLSR] = { 0x28, 16 }, + }, + .fifosize = 16, + .overrun_reg = SCLSR, + .overrun_mask = SCLSR_ORER, + .sampling_rate_mask = SCI_SR(32), + .error_mask = SCIF_DEFAULT_ERROR_MASK, + .error_clear = SCIF_ERROR_CLEAR, }, /* @@ -432,27 +444,26 @@ static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { * registers. */ [SCIx_SH7705_SCIF_REGTYPE] = { - [SCSMR] = { 0x00, 16 }, - [SCBRR] = { 0x04, 8 }, - [SCSCR] = { 0x08, 16 }, - [SCxTDR] = { 0x20, 8 }, - [SCxSR] = { 0x14, 16 }, - [SCxRDR] = { 0x24, 8 }, - [SCFCR] = { 0x18, 16 }, - [SCFDR] = { 0x1c, 16 }, - [SCTFDR] = sci_reg_invalid, - [SCRFDR] = sci_reg_invalid, - [SCSPTR] = sci_reg_invalid, - [SCLSR] = sci_reg_invalid, - [HSSRR] = sci_reg_invalid, - [SCPCR] = sci_reg_invalid, - [SCPDR] = sci_reg_invalid, - [SCDL] = sci_reg_invalid, - [SCCKS] = sci_reg_invalid, + .regs = { + [SCSMR] = { 0x00, 16 }, + [SCBRR] = { 0x04, 8 }, + [SCSCR] = { 0x08, 16 }, + [SCxTDR] = { 0x20, 8 }, + [SCxSR] = { 0x14, 16 }, + [SCxRDR] = { 0x24, 8 }, + [SCFCR] = { 0x18, 16 }, + [SCFDR] = { 0x1c, 16 }, + }, + .fifosize = 64, + .overrun_reg = SCxSR, + .overrun_mask = SCIFA_ORER, + .sampling_rate_mask = SCI_SR(16), + .error_mask = SCIF_DEFAULT_ERROR_MASK | SCIFA_ORER, + .error_clear = SCIF_ERROR_CLEAR & ~SCIFA_ORER, }, }; -#define sci_getreg(up, offset) (sci_regmap[to_sci_port(up)->cfg->regtype] + offset) +#define sci_getreg(up, offset) (&to_sci_port(up)->params->regs[offset]) /* * The "offset" here is rather misleading, in that it refers to an enum @@ -486,41 +497,6 @@ static void sci_serial_out(struct uart_port *p, int offset, int value) WARN(1, "Invalid register access\n"); } -static int sci_probe_regmap(struct plat_sci_port *cfg) -{ - switch (cfg->type) { - case PORT_SCI: - cfg->regtype = SCIx_SCI_REGTYPE; - break; - case PORT_IRDA: - cfg->regtype = SCIx_IRDA_REGTYPE; - break; - case PORT_SCIFA: - cfg->regtype = SCIx_SCIFA_REGTYPE; - break; - case PORT_SCIFB: - cfg->regtype = SCIx_SCIFB_REGTYPE; - break; - case PORT_SCIF: - /* - * The SH-4 is a bit of a misnomer here, although that's - * where this particular port layout originated. This - * configuration (or some slight variation thereof) - * remains the dominant model for all SCIFs. - */ - cfg->regtype = SCIx_SH4_SCIF_REGTYPE; - break; - case PORT_HSCIF: - cfg->regtype = SCIx_HSCIF_REGTYPE; - break; - default: - pr_err("Can't probe register map for given port\n"); - return -EINVAL; - } - - return 0; -} - static void sci_port_enable(struct sci_port *sci_port) { unsigned int i; @@ -544,14 +520,6 @@ static void sci_port_disable(struct sci_port *sci_port) if (!sci_port->port.dev) return; - /* 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; - for (i = SCI_NUM_CLKS; i-- > 0; ) clk_disable_unprepare(sci_port->clks[i]); @@ -646,7 +614,7 @@ static void sci_clear_SCxSR(struct uart_port *port, unsigned int mask) if (port->type == PORT_SCI) { /* Just store the mask */ serial_port_out(port, SCxSR, mask); - } else if (to_sci_port(port)->overrun_mask == SCIFA_ORER) { + } else if (to_sci_port(port)->params->overrun_mask == SCIFA_ORER) { /* SCIFA/SCIFB and SCIF on SH7705/SH7720/SH7721 */ /* Only clear the status bits we want to clear */ serial_port_out(port, SCxSR, @@ -719,7 +687,7 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag) /* Enable RXD and TXD pin functions */ ctrl &= ~(SCPCR_RXDC | SCPCR_TXDC); - if (to_sci_port(port)->cfg->capabilities & SCIx_HAVE_RTSCTS) { + if (to_sci_port(port)->has_rtscts) { /* RTS# is output, driven 1 */ ctrl |= SCPCR_RTSC; serial_port_out(port, SCPDR, @@ -741,11 +709,13 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag) static int sci_txfill(struct uart_port *port) { + struct sci_port *s = to_sci_port(port); + unsigned int fifo_mask = (s->params->fifosize << 1) - 1; const struct plat_sci_reg *reg; reg = sci_getreg(port, SCTFDR); if (reg->size) - return serial_port_in(port, SCTFDR) & ((port->fifosize << 1) - 1); + return serial_port_in(port, SCTFDR) & fifo_mask; reg = sci_getreg(port, SCFDR); if (reg->size) @@ -761,33 +731,21 @@ static int sci_txroom(struct uart_port *port) static int sci_rxfill(struct uart_port *port) { + struct sci_port *s = to_sci_port(port); + unsigned int fifo_mask = (s->params->fifosize << 1) - 1; const struct plat_sci_reg *reg; reg = sci_getreg(port, SCRFDR); if (reg->size) - return serial_port_in(port, SCRFDR) & ((port->fifosize << 1) - 1); + return serial_port_in(port, SCRFDR) & fifo_mask; reg = sci_getreg(port, SCFDR); if (reg->size) - return serial_port_in(port, SCFDR) & ((port->fifosize << 1) - 1); + return serial_port_in(port, SCFDR) & fifo_mask; return (serial_port_in(port, SCxSR) & SCxSR_RDxF(port)) != 0; } -/* - * SCI helper for checking the state of the muxed port/RXD pins. - */ -static inline int sci_rxd_in(struct uart_port *port) -{ - struct sci_port *s = to_sci_port(port); - - if (s->cfg->port_reg <= 0) - return 1; - - /* Cast for ARM damage */ - return !!__raw_readb((void __iomem *)(uintptr_t)s->cfg->port_reg); -} - /* ********************************************************************** * * the interrupt related routines * * ********************************************************************** */ @@ -855,7 +813,6 @@ static void sci_transmit_chars(struct uart_port *port) static void sci_receive_chars(struct uart_port *port) { - struct sci_port *sci_port = to_sci_port(port); struct tty_port *tport = &port->state->port; int i, count, copied = 0; unsigned short status; @@ -875,8 +832,7 @@ static void sci_receive_chars(struct uart_port *port) if (port->type == PORT_SCI) { char c = serial_port_in(port, SCxRDR); - if (uart_handle_sysrq_char(port, c) || - sci_port->break_flag) + if (uart_handle_sysrq_char(port, c)) count = 0; else tty_insert_flip_char(tport, c, TTY_NORMAL); @@ -885,25 +841,6 @@ static void sci_receive_chars(struct uart_port *port) char c = serial_port_in(port, SCxRDR); status = serial_port_in(port, SCxSR); -#if defined(CONFIG_CPU_SH3) - /* Skip "chars" during break */ - if (sci_port->break_flag) { - if ((c == 0) && - (status & SCxSR_FER(port))) { - count--; i--; - continue; - } - - /* Nonzero => end-of-break */ - dev_dbg(port->dev, "debounce<%02x>\n", c); - sci_port->break_flag = 0; - - if (STEPFN(c)) { - count--; i--; - continue; - } - } -#endif /* CONFIG_CPU_SH3 */ if (uart_handle_sysrq_char(port, c)) { count--; i--; continue; @@ -941,37 +878,6 @@ static void sci_receive_chars(struct uart_port *port) } } -#define SCI_BREAK_JIFFIES (HZ/20) - -/* - * The sci generates interrupts during the break, - * 1 per millisecond or so during the break period, for 9600 baud. - * So dont bother disabling interrupts. - * But dont want more than 1 break event. - * Use a kernel timer to periodically poll the rx line until - * the break is finished. - */ -static inline void sci_schedule_break_timer(struct sci_port *port) -{ - mod_timer(&port->break_timer, jiffies + SCI_BREAK_JIFFIES); -} - -/* Ensure that two consecutive samples find the break over. */ -static void sci_break_timer(unsigned long data) -{ - struct sci_port *port = (struct sci_port *)data; - - if (sci_rxd_in(&port->port) == 0) { - port->break_flag = 1; - sci_schedule_break_timer(port); - } else if (port->break_flag == 1) { - /* break is over. */ - port->break_flag = 2; - sci_schedule_break_timer(port); - } else - port->break_flag = 0; -} - static int sci_handle_errors(struct uart_port *port) { int copied = 0; @@ -980,7 +886,7 @@ static int sci_handle_errors(struct uart_port *port) struct sci_port *s = to_sci_port(port); /* Handle overruns */ - if (status & s->overrun_mask) { + if (status & s->params->overrun_mask) { port->icount.overrun++; /* overrun error */ @@ -991,35 +897,13 @@ static int sci_handle_errors(struct uart_port *port) } if (status & SCxSR_FER(port)) { - if (sci_rxd_in(port) == 0) { - /* Notify of BREAK */ - struct sci_port *sci_port = to_sci_port(port); - - if (!sci_port->break_flag) { - port->icount.brk++; - - sci_port->break_flag = 1; - sci_schedule_break_timer(sci_port); + /* frame error */ + port->icount.frame++; - /* Do sysrq handling. */ - if (uart_handle_break(port)) - return 0; - - dev_dbg(port->dev, "BREAK detected\n"); - - if (tty_insert_flip_char(tport, 0, TTY_BREAK)) - copied++; - } - - } else { - /* frame error */ - port->icount.frame++; - - if (tty_insert_flip_char(tport, 0, TTY_FRAME)) - copied++; + if (tty_insert_flip_char(tport, 0, TTY_FRAME)) + copied++; - dev_notice(port->dev, "frame error\n"); - } + dev_notice(port->dev, "frame error\n"); } if (status & SCxSR_PER(port)) { @@ -1046,14 +930,14 @@ static int sci_handle_fifo_overrun(struct uart_port *port) int copied = 0; u16 status; - reg = sci_getreg(port, s->overrun_reg); + reg = sci_getreg(port, s->params->overrun_reg); if (!reg->size) return 0; - status = serial_port_in(port, s->overrun_reg); - if (status & s->overrun_mask) { - status &= ~s->overrun_mask; - serial_port_out(port, s->overrun_reg, status); + status = serial_port_in(port, s->params->overrun_reg); + if (status & s->params->overrun_mask) { + status &= ~s->params->overrun_mask; + serial_port_out(port, s->params->overrun_reg, status); port->icount.overrun++; @@ -1072,17 +956,11 @@ static int sci_handle_breaks(struct uart_port *port) int copied = 0; unsigned short status = serial_port_in(port, SCxSR); struct tty_port *tport = &port->state->port; - struct sci_port *s = to_sci_port(port); if (uart_handle_break(port)) return 0; - if (!s->break_flag && status & SCxSR_BRK(port)) { -#if defined(CONFIG_CPU_SH3) - /* Debounce break */ - s->break_flag = 1; -#endif - + if (status & SCxSR_BRK(port)) { port->icount.brk++; /* Notify of BREAK */ @@ -1100,6 +978,146 @@ static int sci_handle_breaks(struct uart_port *port) return copied; } +static int scif_set_rtrg(struct uart_port *port, int rx_trig) +{ + unsigned int bits; + + if (rx_trig < 1) + rx_trig = 1; + if (rx_trig >= port->fifosize) + rx_trig = port->fifosize; + + /* HSCIF can be set to an arbitrary level. */ + if (sci_getreg(port, HSRTRGR)->size) { + serial_port_out(port, HSRTRGR, rx_trig); + return rx_trig; + } + + switch (port->type) { + case PORT_SCIF: + if (rx_trig < 4) { + bits = 0; + rx_trig = 1; + } else if (rx_trig < 8) { + bits = SCFCR_RTRG0; + rx_trig = 4; + } else if (rx_trig < 14) { + bits = SCFCR_RTRG1; + rx_trig = 8; + } else { + bits = SCFCR_RTRG0 | SCFCR_RTRG1; + rx_trig = 14; + } + break; + case PORT_SCIFA: + case PORT_SCIFB: + if (rx_trig < 16) { + bits = 0; + rx_trig = 1; + } else if (rx_trig < 32) { + bits = SCFCR_RTRG0; + rx_trig = 16; + } else if (rx_trig < 48) { + bits = SCFCR_RTRG1; + rx_trig = 32; + } else { + bits = SCFCR_RTRG0 | SCFCR_RTRG1; + rx_trig = 48; + } + break; + default: + WARN(1, "unknown FIFO configuration"); + return 1; + } + + serial_port_out(port, SCFCR, + (serial_port_in(port, SCFCR) & + ~(SCFCR_RTRG1 | SCFCR_RTRG0)) | bits); + + return rx_trig; +} + +static int scif_rtrg_enabled(struct uart_port *port) +{ + if (sci_getreg(port, HSRTRGR)->size) + return serial_port_in(port, HSRTRGR) != 0; + else + return (serial_port_in(port, SCFCR) & + (SCFCR_RTRG0 | SCFCR_RTRG1)) != 0; +} + +static void rx_fifo_timer_fn(unsigned long arg) +{ + struct sci_port *s = (struct sci_port *)arg; + struct uart_port *port = &s->port; + + dev_dbg(port->dev, "Rx timed out\n"); + scif_set_rtrg(port, 1); +} + +static ssize_t rx_trigger_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct uart_port *port = dev_get_drvdata(dev); + struct sci_port *sci = to_sci_port(port); + + return sprintf(buf, "%d\n", sci->rx_trigger); +} + +static ssize_t rx_trigger_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct uart_port *port = dev_get_drvdata(dev); + struct sci_port *sci = to_sci_port(port); + long r; + + if (kstrtol(buf, 0, &r) == -EINVAL) + return -EINVAL; + + sci->rx_trigger = scif_set_rtrg(port, r); + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) + scif_set_rtrg(port, 1); + + return count; +} + +static DEVICE_ATTR(rx_fifo_trigger, 0644, rx_trigger_show, rx_trigger_store); + +static ssize_t rx_fifo_timeout_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct uart_port *port = dev_get_drvdata(dev); + struct sci_port *sci = to_sci_port(port); + + return sprintf(buf, "%d\n", sci->rx_fifo_timeout); +} + +static ssize_t rx_fifo_timeout_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct uart_port *port = dev_get_drvdata(dev); + struct sci_port *sci = to_sci_port(port); + long r; + + if (kstrtol(buf, 0, &r) == -EINVAL) + return -EINVAL; + sci->rx_fifo_timeout = r; + scif_set_rtrg(port, 1); + if (r > 0) + setup_timer(&sci->rx_fifo_timer, rx_fifo_timer_fn, + (unsigned long)sci); + return count; +} + +static DEVICE_ATTR(rx_fifo_timeout, 0644, rx_fifo_timeout_show, rx_fifo_timeout_store); + + #ifdef CONFIG_SERIAL_SH_SCI_DMA static void sci_dma_tx_complete(void *arg) { @@ -1410,20 +1428,14 @@ static void rx_timer_fn(unsigned long arg) } static struct dma_chan *sci_request_dma_chan(struct uart_port *port, - enum dma_transfer_direction dir, - unsigned int id) + enum dma_transfer_direction dir) { - dma_cap_mask_t mask; struct dma_chan *chan; struct dma_slave_config cfg; int ret; - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - - chan = dma_request_slave_channel_compat(mask, shdma_chan_filter, - (void *)(unsigned long)id, port->dev, - dir == DMA_MEM_TO_DEV ? "tx" : "rx"); + chan = dma_request_slave_channel(port->dev, + dir == DMA_MEM_TO_DEV ? "tx" : "rx"); if (!chan) { dev_warn(port->dev, "dma_request_slave_channel_compat failed\n"); @@ -1459,12 +1471,11 @@ static void sci_request_dma(struct uart_port *port) dev_dbg(port->dev, "%s: port %d\n", __func__, port->line); - if (!port->dev->of_node && - (s->cfg->dma_slave_tx <= 0 || s->cfg->dma_slave_rx <= 0)) + if (!port->dev->of_node) return; s->cookie_tx = -EINVAL; - chan = sci_request_dma_chan(port, DMA_MEM_TO_DEV, s->cfg->dma_slave_tx); + chan = sci_request_dma_chan(port, DMA_MEM_TO_DEV); dev_dbg(port->dev, "%s: TX: got channel %p\n", __func__, chan); if (chan) { s->chan_tx = chan; @@ -1486,7 +1497,7 @@ static void sci_request_dma(struct uart_port *port) INIT_WORK(&s->work_tx, work_fn_tx); } - chan = sci_request_dma_chan(port, DMA_DEV_TO_MEM, s->cfg->dma_slave_rx); + chan = sci_request_dma_chan(port, DMA_DEV_TO_MEM); dev_dbg(port->dev, "%s: RX: got channel %p\n", __func__, chan); if (chan) { unsigned int i; @@ -1546,10 +1557,10 @@ static inline void sci_free_dma(struct uart_port *port) static irqreturn_t sci_rx_interrupt(int irq, void *ptr) { -#ifdef CONFIG_SERIAL_SH_SCI_DMA struct uart_port *port = ptr; struct sci_port *s = to_sci_port(port); +#ifdef CONFIG_SERIAL_SH_SCI_DMA if (s->chan_rx) { u16 scr = serial_port_in(port, SCSCR); u16 ssr = serial_port_in(port, SCxSR); @@ -1574,6 +1585,14 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr) } #endif + if (s->rx_trigger > 1 && s->rx_fifo_timeout > 0) { + if (!scif_rtrg_enabled(port)) + scif_set_rtrg(port, s->rx_trigger); + + mod_timer(&s->rx_fifo_timer, jiffies + DIV_ROUND_UP( + s->rx_frame * s->rx_fifo_timeout, 1000)); + } + /* I think sci_receive_chars has to be called irrespective * of whether the I_IXOFF is set, otherwise, how is the interrupt * to be disabled? @@ -1642,12 +1661,10 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) ssr_status = serial_port_in(port, SCxSR); scr_status = serial_port_in(port, SCSCR); - if (s->overrun_reg == SCxSR) + if (s->params->overrun_reg == SCxSR) orer_status = ssr_status; - else { - if (sci_getreg(port, s->overrun_reg)->size) - orer_status = serial_port_in(port, s->overrun_reg); - } + else if (sci_getreg(port, s->params->overrun_reg)->size) + orer_status = serial_port_in(port, s->params->overrun_reg); err_enabled = scr_status & port_rx_irq_mask(port); @@ -1673,7 +1690,7 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) ret = sci_br_interrupt(irq, ptr); /* Overrun Interrupt */ - if (orer_status & s->overrun_mask) { + if (orer_status & s->params->overrun_mask) { sci_handle_fifo_overrun(port); ret = IRQ_HANDLED; } @@ -1743,8 +1760,10 @@ static int sci_request_irq(struct sci_port *port) desc = sci_irq_desc + i; port->irqstr[j] = kasprintf(GFP_KERNEL, "%s:%s", dev_name(up->dev), desc->desc); - if (!port->irqstr[j]) + if (!port->irqstr[j]) { + ret = -ENOMEM; goto out_nomem; + } ret = request_irq(irq, desc->handler, up->irqflags, port->irqstr[j], port); @@ -1874,7 +1893,7 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl) mctrl_gpio_set(s->gpios, mctrl); - if (!(s->cfg->capabilities & SCIx_HAVE_RTSCTS)) + if (!s->has_rtscts) return; if (!(mctrl & TIOCM_RTS)) { @@ -2136,6 +2155,7 @@ static void sci_reset(struct uart_port *port) { const struct plat_sci_reg *reg; unsigned int status; + struct sci_port *s = to_sci_port(port); do { status = serial_port_in(port, SCxSR); @@ -2155,12 +2175,26 @@ static void sci_reset(struct uart_port *port) status &= ~(SCLSR_TO | SCLSR_ORER); serial_port_out(port, SCLSR, status); } + + if (s->rx_trigger > 1) { + if (s->rx_fifo_timeout) { + scif_set_rtrg(port, 1); + setup_timer(&s->rx_fifo_timer, rx_fifo_timer_fn, + (unsigned long)s); + } else { + if (port->type == PORT_SCIFA || + port->type == PORT_SCIFB) + scif_set_rtrg(port, 1); + else + scif_set_rtrg(port, s->rx_trigger); + } + } } static void sci_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { - unsigned int baud, smr_val = SCSMR_ASYNC, scr_val = 0, i; + unsigned int baud, smr_val = SCSMR_ASYNC, scr_val = 0, i, bits; unsigned int brr = 255, cks = 0, srr = 15, dl = 0, sccks = 0; unsigned int brr1 = 255, cks1 = 0, srr1 = 15, dl1 = 0; |