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); - -				/* Do sysrq handling. */ -				if (uart_handle_break(port)) -					return 0; - -				dev_dbg(port->dev, "BREAK detected\n"); +		/* frame error */ +		port->icount.frame++; -				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;  	struct sci_port *s = to_sci_port(port); @@ -2341,7 +2375,8 @@ done:  		serial_port_out(port, SCFCR, ctrl);  	} -	scr_val |= s->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0); +	scr_val |= SCSCR_RE | SCSCR_TE | +		   (s->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0));  	dev_dbg(port->dev, "SCSCR 0x%x\n", scr_val);  	serial_port_out(port, SCSCR, scr_val);  	if ((srr + 1 == 5) && @@ -2355,7 +2390,6 @@ done:  		udelay(DIV_ROUND_UP(10 * 1000000, baud));  	} -#ifdef CONFIG_SERIAL_SH_SCI_DMA  	/*  	 * Calculate delay for 2 DMA buffers (4 FIFO).  	 * See serial_core.c::uart_update_timeout(). @@ -2366,36 +2400,34 @@ done:  	 * value obtained by this formula is too small. Therefore, if the value  	 * is smaller than 20ms, use 20ms as the timeout value for DMA.  	 */ -	if (s->chan_rx) { -		unsigned int bits; +	/* byte size and parity */ +	switch (termios->c_cflag & CSIZE) { +	case CS5: +		bits = 7; +		break; +	case CS6: +		bits = 8; +		break; +	case CS7: +		bits = 9; +		break; +	default: +		bits = 10; +		break; +	} -		/* byte size and parity */ -		switch (termios->c_cflag & CSIZE) { -		case CS5: -			bits = 7; -			break; -		case CS6: -			bits = 8; -			break; -		case CS7: -			bits = 9; -			break; -		default: -			bits = 10; -			break; -		} +	if (termios->c_cflag & CSTOPB) +		bits++; +	if (termios->c_cflag & PARENB) +		bits++; -		if (termios->c_cflag & CSTOPB) -			bits++; -		if (termios->c_cflag & PARENB) -			bits++; -		s->rx_timeout = DIV_ROUND_UP((s->buf_len_rx * 2 * bits * HZ) / -					     (baud / 10), 10); -		dev_dbg(port->dev, "DMA Rx t-out %ums, tty t-out %u jiffies\n", -			s->rx_timeout * 1000 / HZ, port->timeout); -		if (s->rx_timeout < msecs_to_jiffies(20)) -			s->rx_timeout = msecs_to_jiffies(20); -	} +	s->rx_frame = (100 * bits * HZ) / (baud / 10); +#ifdef CONFIG_SERIAL_SH_SCI_DMA +	s->rx_timeout = DIV_ROUND_UP(s->buf_len_rx * 2 * s->rx_frame, 1000); +	dev_dbg(port->dev, "DMA Rx t-out %ums, tty t-out %u jiffies\n", +		s->rx_timeout * 1000 / HZ, port->timeout); +	if (s->rx_timeout < msecs_to_jiffies(20)) +		s->rx_timeout = msecs_to_jiffies(20);  #endif  	if ((termios->c_cflag & CREAD) != 0) @@ -2452,7 +2484,7 @@ static int sci_remap_port(struct uart_port *port)  	if (port->membase)  		return 0; -	if (port->flags & UPF_IOREMAP) { +	if (port->dev->of_node || (port->flags & UPF_IOREMAP)) {  		port->membase = ioremap_nocache(port->mapbase, sport->reg_size);  		if (unlikely(!port->membase)) {  			dev_err(port->dev, "can't remap port#%d\n", port->line); @@ -2474,7 +2506,7 @@ static void sci_release_port(struct uart_port *port)  {  	struct sci_port *sport = to_sci_port(port); -	if (port->flags & UPF_IOREMAP) { +	if (port->dev->of_node || (port->flags & UPF_IOREMAP)) {  		iounmap(port->membase);  		port->membase = NULL;  	} @@ -2604,9 +2636,50 @@ found:  	return 0;  } +static const struct sci_port_params * +sci_probe_regmap(const struct plat_sci_port *cfg) +{ +	unsigned int regtype; + +	if (cfg->regtype != SCIx_PROBE_REGTYPE) +		return &sci_port_params[cfg->regtype]; + +	switch (cfg->type) { +	case PORT_SCI: +		regtype = SCIx_SCI_REGTYPE; +		break; +	case PORT_IRDA: +		regtype = SCIx_IRDA_REGTYPE; +		break; +	case PORT_SCIFA: +		regtype = SCIx_SCIFA_REGTYPE; +		break; +	case PORT_SCIFB: +		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. +		 */ +		regtype = SCIx_SH4_SCIF_REGTYPE; +		break; +	case PORT_HSCIF: +		regtype = SCIx_HSCIF_REGTYPE; +		break; +	default: +		pr_err("Can't probe register map for given port\n"); +		return NULL; +	} + +	return &sci_port_params[regtype]; +} +  static int sci_init_single(struct platform_device *dev,  			   struct sci_port *sci_port, unsigned int index, -			   struct plat_sci_port *p, bool early) +			   const struct plat_sci_port *p, bool early)  {  	struct uart_port *port = &sci_port->port;  	const struct resource *res; @@ -2643,57 +2716,41 @@ static int sci_init_single(struct platform_device *dev,  		sci_port->irqs[3] = sci_port->irqs[0];  	} -	if (p->regtype == SCIx_PROBE_REGTYPE) { -		ret = sci_probe_regmap(p); -		if (unlikely(ret)) -			return ret; -	} +	sci_port->params = sci_probe_regmap(p); +	if (unlikely(sci_port->params == NULL)) +		return -EINVAL;  	switch (p->type) {  	case PORT_SCIFB: -		port->fifosize = 256; -		sci_port->overrun_reg = SCxSR; -		sci_port->overrun_mask = SCIFA_ORER; -		sci_port->sampling_rate_mask = SCI_SR_SCIFAB; +		sci_port->rx_trigger = 48;  		break;  	case PORT_HSCIF: -		port->fifosize = 128; -		sci_port->overrun_reg = SCLSR; -		sci_port->overrun_mask = SCLSR_ORER; -		sci_port->sampling_rate_mask = SCI_SR_RANGE(8, 32); +		sci_port->rx_trigger = 64;  		break;  	case PORT_SCIFA: -		port->fifosize = 64; -		sci_port->overrun_reg = SCxSR; -		sci_port->overrun_mask = SCIFA_ORER; -		sci_port->sampling_rate_mask = SCI_SR_SCIFAB; +		sci_port->rx_trigger = 32;  		break;  	case PORT_SCIF: -		port->fifosize = 16; -		if (p->regtype == SCIx_SH7705_SCIF_REGTYPE) { -			sci_port->overrun_reg = SCxSR; -			sci_port->overrun_mask = SCIFA_ORER; -			sci_port->sampling_rate_mask = SCI_SR(16); -		} else { -			sci_port->overrun_reg = SCLSR; -			sci_port->overrun_mask = SCLSR_ORER; -			sci_port->sampling_rate_mask = SCI_SR(32); -		} +		if (p->regtype == SCIx_SH7705_SCIF_REGTYPE) +			/* RX triggering not implemented for this IP */ +			sci_port->rx_trigger = 1; +		else +			sci_port->rx_trigger = 8;  		break;  	default: -		port->fifosize = 1; -		sci_port->overrun_reg = SCxSR; -		sci_port->overrun_mask = SCI_ORER; -		sci_port->sampling_rate_mask = SCI_SR(32); +		sci_port->rx_trigger = 1;  		break;  	} +	sci_port->rx_fifo_timeout = 0; +  	/* 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.  	 */ -	if (p->sampling_rate) -		sci_port->sampling_rate_mask = SCI_SR(p->sampling_rate); +	sci_port->sampling_rate_mask = p->sampling_rate +				     ? SCI_SR(p->sampling_rate) +				     : sci_port->params->sampling_rate_mask;  	if (!early) {  		ret = sci_init_clocks(sci_port, &dev->dev); @@ -2705,34 +2762,17 @@ static int sci_init_single(struct platform_device *dev,  		pm_runtime_enable(&dev->dev);  	} -	sci_port->break_timer.data = (unsigned long)sci_port; -	sci_port->break_timer.function = sci_break_timer; -	init_timer(&sci_port->break_timer); - -	/* -	 * Establish some sensible defaults for the error detection. -	 */ -	if (p->type == PORT_SCI) { -		sci_port->error_mask = SCI_DEFAULT_ERROR_MASK; -		sci_port->error_clear = SCI_ERROR_CLEAR; -	} else { -		sci_port->error_mask = SCIF_DEFAULT_ERROR_MASK; -		sci_port->error_clear = SCIF_ERROR_CLEAR; -	} +	port->type		= p->type; +	port->flags		= UPF_FIXED_PORT | UPF_BOOT_AUTOCONF | p->flags; +	port->fifosize		= sci_port->params->fifosize; -	/* -	 * Make the error mask inclusive of overrun detection, if -	 * supported. -	 */ -	if (sci_port->overrun_reg == SCxSR) { -		sci_port->error_mask |= sci_port->overrun_mask; -		sci_port->error_clear &= ~sci_port->overrun_mask; +	if (port->type == PORT_SCI) { +		if (sci_port->reg_size >= 0x20) +			port->regshift = 2; +		else +			port->regshift = 1;  	} -	port->type		= p->type; -	port->flags		= UPF_FIXED_PORT | p->flags; -	port->regshift		= p->regshift; -  	/*  	 * The UART port needs an IRQ value, so we peg this to the RX IRQ  	 * for the multi-IRQ ports, which is where we are primarily @@ -2746,10 +2786,6 @@ static int sci_init_single(struct platform_device *dev,  	port->serial_in		= sci_serial_in;  	port->serial_out	= sci_serial_out; -	if (p->dma_slave_tx > 0 && p->dma_slave_rx > 0) -		dev_dbg(port->dev, "DMA tx %d, rx %d\n", -			p->dma_slave_tx, p->dma_slave_rx); -  	return 0;  } @@ -2791,7 +2827,8 @@ static void serial_console_write(struct console *co, const char *s,  	/* first save SCSCR then disable interrupts, keep clock source */  	ctrl = serial_port_in(port, SCSCR); -	ctrl_temp = (sci_port->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0)) | +	ctrl_temp = SCSCR_RE | SCSCR_TE | +		    (sci_port->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0)) |  		    (ctrl & (SCSCR_CKE1 | SCSCR_CKE0));  	serial_port_out(port, SCSCR, ctrl_temp); @@ -2866,7 +2903,7 @@ static char early_serial_buf[32];  static int sci_probe_earlyprintk(struct platform_device *pdev)  { -	struct plat_sci_port *cfg = dev_get_platdata(&pdev->dev); +	const struct plat_sci_port *cfg = dev_get_platdata(&pdev->dev);  	if (early_serial_console.data)  		return -EEXIST; @@ -2916,6 +2953,15 @@ static int sci_remove(struct platform_device *dev)  	sci_cleanup_single(port); +	if (port->port.fifosize > 1) { +		sysfs_remove_file(&dev->dev.kobj, +				  &dev_attr_rx_fifo_trigger.attr); +	} +	if (port->port.type == PORT_SCIFA || port->port.type == PORT_SCIFB) { +		sysfs_remove_file(&dev->dev.kobj, +				  &dev_attr_rx_fifo_timeout.attr); +	} +  	return 0;  } @@ -2963,12 +3009,13 @@ static const struct of_device_id of_sci_match[] = {  };  MODULE_DEVICE_TABLE(of, of_sci_match); -static struct plat_sci_port * -sci_parse_dt(struct platform_device *pdev, unsigned int *dev_id) +static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev, +					  unsigned int *dev_id)  {  	struct device_node *np = pdev->dev.of_node;  	const struct of_device_id *match;  	struct plat_sci_port *p; +	struct sci_port *sp;  	int id;  	if (!IS_ENABLED(CONFIG_OF) || !np) @@ -2989,15 +3036,14 @@ sci_parse_dt(struct platform_device *pdev, unsigned int *dev_id)  		return NULL;  	} +	sp = &sci_ports[id];  	*dev_id = id; -	p->flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;  	p->type = SCI_OF_TYPE(match->data);  	p->regtype = SCI_OF_REGTYPE(match->data); -	p->scscr = SCSCR_RE | SCSCR_TE;  	if (of_find_property(np, "uart-has-rtscts", NULL)) -		p->capabilities |= SCIx_HAVE_RTSCTS; +		sp->has_rtscts = true;  	return p;  } @@ -3025,7 +3071,7 @@ static int sci_probe_single(struct platform_device *dev,  	if (IS_ERR(sciport->gpios) && PTR_ERR(sciport->gpios) != -ENOSYS)  		return PTR_ERR(sciport->gpios); -	if (p->capabilities & SCIx_HAVE_RTSCTS) { +	if (sciport->has_rtscts) {  		if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(sciport->gpios,  							UART_GPIO_CTS)) ||  		    !IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(sciport->gpios, @@ -3081,6 +3127,24 @@ static int sci_probe(struct platform_device *dev)  	if (ret)  		return ret; +	if (sp->port.fifosize > 1) { +		ret = sysfs_create_file(&dev->dev.kobj, +				&dev_attr_rx_fifo_trigger.attr); +		if (ret) +			return ret; +	} +	if (sp->port.type == PORT_SCIFA || sp->port.type ==  PORT_SCIFB) { +		ret = sysfs_create_file(&dev->dev.kobj, +				&dev_attr_rx_fifo_timeout.attr); +		if (ret) { +			if (sp->port.fifosize > 1) { +				sysfs_remove_file(&dev->dev.kobj, +					&dev_attr_rx_fifo_trigger.attr); +			} +			return ret; +		} +	} +  #ifdef CONFIG_SH_STANDARD_BIOS  	sh_bios_gdb_detach();  #endif @@ -3159,12 +3223,12 @@ static int __init early_console_setup(struct earlycon_device *device,  	device->port.serial_out	= sci_serial_out;  	device->port.type = type;  	memcpy(&sci_ports[0].port, &device->port, sizeof(struct uart_port)); +	port_cfg.type = type;  	sci_ports[0].cfg = &port_cfg; -	sci_ports[0].cfg->type = type; -	sci_probe_regmap(sci_ports[0].cfg); -	port_cfg.scscr = sci_serial_in(&sci_ports[0].port, SCSCR) | -			 SCSCR_RE | SCSCR_TE; -	sci_serial_out(&sci_ports[0].port, SCSCR, port_cfg.scscr); +	sci_ports[0].params = sci_probe_regmap(&port_cfg); +	port_cfg.scscr = sci_serial_in(&sci_ports[0].port, SCSCR); +	sci_serial_out(&sci_ports[0].port, SCSCR, +		       SCSCR_RE | SCSCR_TE | port_cfg.scscr);  	device->con->write = serial_console_write;  	return 0;  | 
