* [PATCH 0/2] Perfect 8250 mtk uart function. @ 2019-04-25 8:41 Long Cheng 2019-04-25 8:41 ` [PATCH 1/2] serial: 8250-mtk: add follow control Long Cheng 2019-04-25 8:41 ` [PATCH 2/2] serial: 8250-mtk: modify baudrate setting Long Cheng 0 siblings, 2 replies; 6+ messages in thread From: Long Cheng @ 2019-04-25 8:41 UTC (permalink / raw) To: Greg Kroah-Hartman Cc: Jiri Slaby, Matthias Brugger, Long Cheng, Gustavo A. R. Silva, Peter Shih, linux-serial, linux-arm-kernel, linux-mediatek, linux-kernel, srv_heupstream, Yingjoe Chen, YT Shen, Zhenbao Liu, Changqi Hu Perfect 8250 mtk uart function, 1.Modify baudrate setting 2.Add follow control function Long Cheng (2): serial: 8250-mtk: add follow control serial: 8250-mtk: modify baudrate setting drivers/tty/serial/8250/8250_mtk.c | 162 +++++++++++++++++++++++++++++++------ 1 file changed, 139 insertions(+), 23 deletions(-) -- 1.9.1 ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 1/2] serial: 8250-mtk: add follow control 2019-04-25 8:41 [PATCH 0/2] Perfect 8250 mtk uart function Long Cheng @ 2019-04-25 8:41 ` Long Cheng 2019-04-25 10:40 ` Matthias Brugger 2019-04-28 17:40 ` Sean Wang 2019-04-25 8:41 ` [PATCH 2/2] serial: 8250-mtk: modify baudrate setting Long Cheng 1 sibling, 2 replies; 6+ messages in thread From: Long Cheng @ 2019-04-25 8:41 UTC (permalink / raw) To: Greg Kroah-Hartman Cc: Jiri Slaby, Matthias Brugger, Long Cheng, Gustavo A. R. Silva, Peter Shih, linux-serial, linux-arm-kernel, linux-mediatek, linux-kernel, srv_heupstream, Yingjoe Chen, YT Shen, Zhenbao Liu, Changqi Hu Add SW and HW follow control function. Signed-off-by: Long Cheng <long.cheng@mediatek.com> --- drivers/tty/serial/8250/8250_mtk.c | 60 ++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c index c1fdbc0..959fd85 100644 --- a/drivers/tty/serial/8250/8250_mtk.c +++ b/drivers/tty/serial/8250/8250_mtk.c @@ -21,12 +21,14 @@ #include "8250.h" -#define UART_MTK_HIGHS 0x09 /* Highspeed register */ -#define UART_MTK_SAMPLE_COUNT 0x0a /* Sample count register */ -#define UART_MTK_SAMPLE_POINT 0x0b /* Sample point register */ +#define MTK_UART_HIGHS 0x09 /* Highspeed register */ +#define MTK_UART_SAMPLE_COUNT 0x0a /* Sample count register */ +#define MTK_UART_SAMPLE_POINT 0x0b /* Sample point register */ #define MTK_UART_RATE_FIX 0x0d /* UART Rate Fix Register */ - #define MTK_UART_DMA_EN 0x13 /* DMA Enable register */ +#define MTK_UART_RXTRI_AD 0x14 /* RX Trigger address */ +#define MTK_UART_FRACDIV_L 0x15 /* Fractional divider LSB address */ +#define MTK_UART_FRACDIV_M 0x16 /* Fractional divider MSB address */ #define MTK_UART_DMA_EN_TX 0x2 #define MTK_UART_DMA_EN_RX 0x5 @@ -46,6 +48,7 @@ enum dma_rx_status { struct mtk8250_data { int line; unsigned int rx_pos; + unsigned int clk_count; struct clk *uart_clk; struct clk *bus_clk; struct uart_8250_dma *dma; @@ -196,9 +199,15 @@ static void mtk8250_shutdown(struct uart_port *port) mtk8250_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { + unsigned short fraction_L_mapping[] = { + 0, 1, 0x5, 0x15, 0x55, 0x57, 0x57, 0x77, 0x7F, 0xFF, 0xFF + }; + unsigned short fraction_M_mapping[] = { + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 3 + }; struct uart_8250_port *up = up_to_u8250p(port); + unsigned int baud, quot, fraction; unsigned long flags; - unsigned int baud, quot; #ifdef CONFIG_SERIAL_8250_DMA if (up->dma) { @@ -214,7 +223,7 @@ static void mtk8250_shutdown(struct uart_port *port) serial8250_do_set_termios(port, termios, old); /* - * Mediatek UARTs use an extra highspeed register (UART_MTK_HIGHS) + * Mediatek UARTs use an extra highspeed register (MTK_UART_HIGHS) * * We need to recalcualte the quot register, as the claculation depends * on the vaule in the highspeed register. @@ -230,18 +239,11 @@ static void mtk8250_shutdown(struct uart_port *port) port->uartclk / 16 / UART_DIV_MAX, port->uartclk); - if (baud <= 115200) { - serial_port_out(port, UART_MTK_HIGHS, 0x0); + if (baud < 115200) { + serial_port_out(port, MTK_UART_HIGHS, 0x0); quot = uart_get_divisor(port, baud); - } else if (baud <= 576000) { - serial_port_out(port, UART_MTK_HIGHS, 0x2); - - /* Set to next lower baudrate supported */ - if ((baud == 500000) || (baud == 576000)) - baud = 460800; - quot = DIV_ROUND_UP(port->uartclk, 4 * baud); } else { - serial_port_out(port, UART_MTK_HIGHS, 0x3); + serial_port_out(port, MTK_UART_HIGHS, 0x3); quot = DIV_ROUND_UP(port->uartclk, 256 * baud); } @@ -258,17 +260,29 @@ static void mtk8250_shutdown(struct uart_port *port) /* reset DLAB */ serial_port_out(port, UART_LCR, up->lcr); - if (baud > 460800) { + if (baud >= 115200) { unsigned int tmp; - tmp = DIV_ROUND_CLOSEST(port->uartclk, quot * baud); - serial_port_out(port, UART_MTK_SAMPLE_COUNT, tmp - 1); - serial_port_out(port, UART_MTK_SAMPLE_POINT, - (tmp - 2) >> 1); + tmp = (port->uartclk / (baud * quot)) - 1; + serial_port_out(port, MTK_UART_SAMPLE_COUNT, tmp); + serial_port_out(port, MTK_UART_SAMPLE_POINT, + (tmp >> 1) - 1); + + /*count fraction to set fractoin register */ + fraction = ((port->uartclk * 100) / baud / quot) % 100; + fraction = DIV_ROUND_CLOSEST(fraction, 10); + serial_port_out(port, MTK_UART_FRACDIV_L, + fraction_L_mapping[fraction]); + serial_port_out(port, MTK_UART_FRACDIV_M, + fraction_M_mapping[fraction]); } else { - serial_port_out(port, UART_MTK_SAMPLE_COUNT, 0x00); - serial_port_out(port, UART_MTK_SAMPLE_POINT, 0xff); + serial_port_out(port, MTK_UART_SAMPLE_COUNT, 0x00); + serial_port_out(port, MTK_UART_SAMPLE_POINT, 0xff); + serial_port_out(port, MTK_UART_FRACDIV_L, 0x00); + serial_port_out(port, MTK_UART_FRACDIV_M, 0x00); } + if (uart_console(port)) + up->port.cons->cflag = termios->c_cflag; spin_unlock_irqrestore(&port->lock, flags); /* Don't rewrite B0 */ -- 1.7.9.5 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH 1/2] serial: 8250-mtk: add follow control 2019-04-25 8:41 ` [PATCH 1/2] serial: 8250-mtk: add follow control Long Cheng @ 2019-04-25 10:40 ` Matthias Brugger 2019-04-26 5:22 ` Long Cheng 2019-04-28 17:40 ` Sean Wang 1 sibling, 1 reply; 6+ messages in thread From: Matthias Brugger @ 2019-04-25 10:40 UTC (permalink / raw) To: Long Cheng, Greg Kroah-Hartman Cc: Jiri Slaby, Gustavo A. R. Silva, Peter Shih, linux-serial, linux-arm-kernel, linux-mediatek, linux-kernel, srv_heupstream, Yingjoe Chen, YT Shen, Zhenbao Liu, Changqi Hu On 25/04/2019 10:41, Long Cheng wrote: > Add SW and HW follow control function. Can you please explain a bit more what you are doing in this patch. You change the setting of the registers for different baud rates. Please elaborate what is happening there. > > Signed-off-by: Long Cheng <long.cheng@mediatek.com> > --- > drivers/tty/serial/8250/8250_mtk.c | 60 ++++++++++++++++++++++-------------- > 1 file changed, 37 insertions(+), 23 deletions(-) > > diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c > index c1fdbc0..959fd85 100644 > --- a/drivers/tty/serial/8250/8250_mtk.c > +++ b/drivers/tty/serial/8250/8250_mtk.c > @@ -21,12 +21,14 @@ > > #include "8250.h" > > -#define UART_MTK_HIGHS 0x09 /* Highspeed register */ > -#define UART_MTK_SAMPLE_COUNT 0x0a /* Sample count register */ > -#define UART_MTK_SAMPLE_POINT 0x0b /* Sample point register */ > +#define MTK_UART_HIGHS 0x09 /* Highspeed register */ > +#define MTK_UART_SAMPLE_COUNT 0x0a /* Sample count register */ > +#define MTK_UART_SAMPLE_POINT 0x0b /* Sample point register */ Rename looks good to me. But I'd prefer to have it in a separate patch. > #define MTK_UART_RATE_FIX 0x0d /* UART Rate Fix Register */ > - > #define MTK_UART_DMA_EN 0x13 /* DMA Enable register */ > +#define MTK_UART_RXTRI_AD 0x14 /* RX Trigger address */ > +#define MTK_UART_FRACDIV_L 0x15 /* Fractional divider LSB address */ > +#define MTK_UART_FRACDIV_M 0x16 /* Fractional divider MSB address */ > #define MTK_UART_DMA_EN_TX 0x2 > #define MTK_UART_DMA_EN_RX 0x5 > > @@ -46,6 +48,7 @@ enum dma_rx_status { > struct mtk8250_data { > int line; > unsigned int rx_pos; > + unsigned int clk_count; What is that for, not used in this patch. > struct clk *uart_clk; > struct clk *bus_clk; > struct uart_8250_dma *dma; > @@ -196,9 +199,15 @@ static void mtk8250_shutdown(struct uart_port *port) > mtk8250_set_termios(struct uart_port *port, struct ktermios *termios, > struct ktermios *old) > { > + unsigned short fraction_L_mapping[] = { > + 0, 1, 0x5, 0x15, 0x55, 0x57, 0x57, 0x77, 0x7F, 0xFF, 0xFF > + }; > + unsigned short fraction_M_mapping[] = { > + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 3 > + }; > struct uart_8250_port *up = up_to_u8250p(port); > + unsigned int baud, quot, fraction; > unsigned long flags; > - unsigned int baud, quot; > > #ifdef CONFIG_SERIAL_8250_DMA > if (up->dma) { > @@ -214,7 +223,7 @@ static void mtk8250_shutdown(struct uart_port *port) > serial8250_do_set_termios(port, termios, old); > > /* > - * Mediatek UARTs use an extra highspeed register (UART_MTK_HIGHS) > + * Mediatek UARTs use an extra highspeed register (MTK_UART_HIGHS) > * > * We need to recalcualte the quot register, as the claculation depends > * on the vaule in the highspeed register. > @@ -230,18 +239,11 @@ static void mtk8250_shutdown(struct uart_port *port) > port->uartclk / 16 / UART_DIV_MAX, > port->uartclk); > > - if (baud <= 115200) { > - serial_port_out(port, UART_MTK_HIGHS, 0x0); > + if (baud < 115200) { > + serial_port_out(port, MTK_UART_HIGHS, 0x0); > quot = uart_get_divisor(port, baud); > - } else if (baud <= 576000) { > - serial_port_out(port, UART_MTK_HIGHS, 0x2); > - > - /* Set to next lower baudrate supported */ > - if ((baud == 500000) || (baud == 576000)) > - baud = 460800; > - quot = DIV_ROUND_UP(port->uartclk, 4 * baud); So we allow now also these baud rates? Then you have to update the comment as well. Regards, Matthias > } else { > - serial_port_out(port, UART_MTK_HIGHS, 0x3); > + serial_port_out(port, MTK_UART_HIGHS, 0x3); > quot = DIV_ROUND_UP(port->uartclk, 256 * baud); > } > > @@ -258,17 +260,29 @@ static void mtk8250_shutdown(struct uart_port *port) > /* reset DLAB */ > serial_port_out(port, UART_LCR, up->lcr); > > - if (baud > 460800) { > + if (baud >= 115200) { > unsigned int tmp; > > - tmp = DIV_ROUND_CLOSEST(port->uartclk, quot * baud); > - serial_port_out(port, UART_MTK_SAMPLE_COUNT, tmp - 1); > - serial_port_out(port, UART_MTK_SAMPLE_POINT, > - (tmp - 2) >> 1); > + tmp = (port->uartclk / (baud * quot)) - 1; > + serial_port_out(port, MTK_UART_SAMPLE_COUNT, tmp); > + serial_port_out(port, MTK_UART_SAMPLE_POINT, > + (tmp >> 1) - 1); > + > + /*count fraction to set fractoin register */ > + fraction = ((port->uartclk * 100) / baud / quot) % 100; > + fraction = DIV_ROUND_CLOSEST(fraction, 10); > + serial_port_out(port, MTK_UART_FRACDIV_L, > + fraction_L_mapping[fraction]); > + serial_port_out(port, MTK_UART_FRACDIV_M, > + fraction_M_mapping[fraction]); > } else { > - serial_port_out(port, UART_MTK_SAMPLE_COUNT, 0x00); > - serial_port_out(port, UART_MTK_SAMPLE_POINT, 0xff); > + serial_port_out(port, MTK_UART_SAMPLE_COUNT, 0x00); > + serial_port_out(port, MTK_UART_SAMPLE_POINT, 0xff); > + serial_port_out(port, MTK_UART_FRACDIV_L, 0x00); > + serial_port_out(port, MTK_UART_FRACDIV_M, 0x00); > } > + if (uart_console(port)) > + up->port.cons->cflag = termios->c_cflag; > > spin_unlock_irqrestore(&port->lock, flags); > /* Don't rewrite B0 */ > ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 1/2] serial: 8250-mtk: add follow control 2019-04-25 10:40 ` Matthias Brugger @ 2019-04-26 5:22 ` Long Cheng 0 siblings, 0 replies; 6+ messages in thread From: Long Cheng @ 2019-04-26 5:22 UTC (permalink / raw) To: Matthias Brugger Cc: Greg Kroah-Hartman, Jiri Slaby, Gustavo A. R. Silva, Peter Shih, linux-serial, linux-arm-kernel, linux-mediatek, linux-kernel, srv_heupstream, Yingjoe Chen, YT Shen, Zhenbao Liu, Changqi Hu On Thu, 2019-04-25 at 12:40 +0200, Matthias Brugger wrote: > > On 25/04/2019 10:41, Long Cheng wrote: > > Add SW and HW follow control function. > > Can you please explain a bit more what you are doing in this patch. > You change the setting of the registers for different baud rates. Please > elaborate what is happening there. > Clock source is different. Sometimes, baudrate is greater than or equal to 115200, we use highspeed of 3 algorithm and fractional divider to ensure more accurate baudrate. Next release version, I will update this to commit message > > > > Signed-off-by: Long Cheng <long.cheng@mediatek.com> > > --- > > drivers/tty/serial/8250/8250_mtk.c | 60 ++++++++++++++++++++++-------------- > > 1 file changed, 37 insertions(+), 23 deletions(-) > > > > diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c > > index c1fdbc0..959fd85 100644 > > --- a/drivers/tty/serial/8250/8250_mtk.c > > +++ b/drivers/tty/serial/8250/8250_mtk.c > > @@ -21,12 +21,14 @@ > > > > #include "8250.h" > > > > -#define UART_MTK_HIGHS 0x09 /* Highspeed register */ > > -#define UART_MTK_SAMPLE_COUNT 0x0a /* Sample count register */ > > -#define UART_MTK_SAMPLE_POINT 0x0b /* Sample point register */ > > +#define MTK_UART_HIGHS 0x09 /* Highspeed register */ > > +#define MTK_UART_SAMPLE_COUNT 0x0a /* Sample count register */ > > +#define MTK_UART_SAMPLE_POINT 0x0b /* Sample point register */ > > Rename looks good to me. But I'd prefer to have it in a separate patch. > OK. > > #define MTK_UART_RATE_FIX 0x0d /* UART Rate Fix Register */ > > - > > #define MTK_UART_DMA_EN 0x13 /* DMA Enable register */ > > +#define MTK_UART_RXTRI_AD 0x14 /* RX Trigger address */ > > +#define MTK_UART_FRACDIV_L 0x15 /* Fractional divider LSB address */ > > +#define MTK_UART_FRACDIV_M 0x16 /* Fractional divider MSB address */ > > #define MTK_UART_DMA_EN_TX 0x2 > > #define MTK_UART_DMA_EN_RX 0x5 > > > > @@ -46,6 +48,7 @@ enum dma_rx_status { > > struct mtk8250_data { > > int line; > > unsigned int rx_pos; > > + unsigned int clk_count; > > What is that for, not used in this patch. > It's for other patch. Sorry, I will remove it. > > struct clk *uart_clk; > > struct clk *bus_clk; > > struct uart_8250_dma *dma; > > @@ -196,9 +199,15 @@ static void mtk8250_shutdown(struct uart_port *port) > > mtk8250_set_termios(struct uart_port *port, struct ktermios *termios, > > struct ktermios *old) > > { > > + unsigned short fraction_L_mapping[] = { > > + 0, 1, 0x5, 0x15, 0x55, 0x57, 0x57, 0x77, 0x7F, 0xFF, 0xFF > > + }; > > + unsigned short fraction_M_mapping[] = { > > + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 3 > > + }; > > struct uart_8250_port *up = up_to_u8250p(port); > > + unsigned int baud, quot, fraction; > > unsigned long flags; > > - unsigned int baud, quot; > > > > #ifdef CONFIG_SERIAL_8250_DMA > > if (up->dma) { > > @@ -214,7 +223,7 @@ static void mtk8250_shutdown(struct uart_port *port) > > serial8250_do_set_termios(port, termios, old); > > > > /* > > - * Mediatek UARTs use an extra highspeed register (UART_MTK_HIGHS) > > + * Mediatek UARTs use an extra highspeed register (MTK_UART_HIGHS) > > * > > * We need to recalcualte the quot register, as the claculation depends > > * on the vaule in the highspeed register. > > @@ -230,18 +239,11 @@ static void mtk8250_shutdown(struct uart_port *port) > > port->uartclk / 16 / UART_DIV_MAX, > > port->uartclk); > > > > - if (baud <= 115200) { > > - serial_port_out(port, UART_MTK_HIGHS, 0x0); > > + if (baud < 115200) { > > + serial_port_out(port, MTK_UART_HIGHS, 0x0); > > quot = uart_get_divisor(port, baud); > > - } else if (baud <= 576000) { > > - serial_port_out(port, UART_MTK_HIGHS, 0x2); > > - > > - /* Set to next lower baudrate supported */ > > - if ((baud == 500000) || (baud == 576000)) > > - baud = 460800; > > - quot = DIV_ROUND_UP(port->uartclk, 4 * baud); > > So we allow now also these baud rates? Then you have to update the comment as well. > Yes. When clock source is different, data sometimes is error by the previous algorithm. It's not good. So we update new method to fix the issue. > Regards, > Matthias > > > } else { > > - serial_port_out(port, UART_MTK_HIGHS, 0x3); > > + serial_port_out(port, MTK_UART_HIGHS, 0x3); > > quot = DIV_ROUND_UP(port->uartclk, 256 * baud); > > } > > > > @@ -258,17 +260,29 @@ static void mtk8250_shutdown(struct uart_port *port) > > /* reset DLAB */ > > serial_port_out(port, UART_LCR, up->lcr); > > > > - if (baud > 460800) { > > + if (baud >= 115200) { > > unsigned int tmp; > > > > - tmp = DIV_ROUND_CLOSEST(port->uartclk, quot * baud); > > - serial_port_out(port, UART_MTK_SAMPLE_COUNT, tmp - 1); > > - serial_port_out(port, UART_MTK_SAMPLE_POINT, > > - (tmp - 2) >> 1); > > + tmp = (port->uartclk / (baud * quot)) - 1; > > + serial_port_out(port, MTK_UART_SAMPLE_COUNT, tmp); > > + serial_port_out(port, MTK_UART_SAMPLE_POINT, > > + (tmp >> 1) - 1); > > + > > + /*count fraction to set fractoin register */ > > + fraction = ((port->uartclk * 100) / baud / quot) % 100; > > + fraction = DIV_ROUND_CLOSEST(fraction, 10); > > + serial_port_out(port, MTK_UART_FRACDIV_L, > > + fraction_L_mapping[fraction]); > > + serial_port_out(port, MTK_UART_FRACDIV_M, > > + fraction_M_mapping[fraction]); > > } else { > > - serial_port_out(port, UART_MTK_SAMPLE_COUNT, 0x00); > > - serial_port_out(port, UART_MTK_SAMPLE_POINT, 0xff); > > + serial_port_out(port, MTK_UART_SAMPLE_COUNT, 0x00); > > + serial_port_out(port, MTK_UART_SAMPLE_POINT, 0xff); > > + serial_port_out(port, MTK_UART_FRACDIV_L, 0x00); > > + serial_port_out(port, MTK_UART_FRACDIV_M, 0x00); > > } > > + if (uart_console(port)) > > + up->port.cons->cflag = termios->c_cflag; > > > > spin_unlock_irqrestore(&port->lock, flags); > > /* Don't rewrite B0 */ > > ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 1/2] serial: 8250-mtk: add follow control 2019-04-25 8:41 ` [PATCH 1/2] serial: 8250-mtk: add follow control Long Cheng 2019-04-25 10:40 ` Matthias Brugger @ 2019-04-28 17:40 ` Sean Wang 1 sibling, 0 replies; 6+ messages in thread From: Sean Wang @ 2019-04-28 17:40 UTC (permalink / raw) To: Long Cheng Cc: Greg Kroah-Hartman, Zhenbao Liu, Peter Shih, srv_heupstream, Gustavo A. R. Silva, Changqi Hu, linux-kernel, linux-mediatek, linux-serial, Jiri Slaby, Matthias Brugger, Yingjoe Chen, linux-arm-kernel Hi, Long I guess you should mean "flow control", not "follow control". And the commit subject should be swapped between 1/2 and 2/2, otherwise, the subject is inconsistent with its own content. Sean On Thu, Apr 25, 2019 at 1:41 AM Long Cheng <long.cheng@mediatek.com> wrote: > > Add SW and HW follow control function. > > Signed-off-by: Long Cheng <long.cheng@mediatek.com> > --- > drivers/tty/serial/8250/8250_mtk.c | 60 ++++++++++++++++++++++-------------- > 1 file changed, 37 insertions(+), 23 deletions(-) > > diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c > index c1fdbc0..959fd85 100644 > --- a/drivers/tty/serial/8250/8250_mtk.c > +++ b/drivers/tty/serial/8250/8250_mtk.c > @@ -21,12 +21,14 @@ > > #include "8250.h" > > -#define UART_MTK_HIGHS 0x09 /* Highspeed register */ > -#define UART_MTK_SAMPLE_COUNT 0x0a /* Sample count register */ > -#define UART_MTK_SAMPLE_POINT 0x0b /* Sample point register */ > +#define MTK_UART_HIGHS 0x09 /* Highspeed register */ > +#define MTK_UART_SAMPLE_COUNT 0x0a /* Sample count register */ > +#define MTK_UART_SAMPLE_POINT 0x0b /* Sample point register */ > #define MTK_UART_RATE_FIX 0x0d /* UART Rate Fix Register */ > - > #define MTK_UART_DMA_EN 0x13 /* DMA Enable register */ > +#define MTK_UART_RXTRI_AD 0x14 /* RX Trigger address */ > +#define MTK_UART_FRACDIV_L 0x15 /* Fractional divider LSB address */ > +#define MTK_UART_FRACDIV_M 0x16 /* Fractional divider MSB address */ > #define MTK_UART_DMA_EN_TX 0x2 > #define MTK_UART_DMA_EN_RX 0x5 > > @@ -46,6 +48,7 @@ enum dma_rx_status { > struct mtk8250_data { > int line; > unsigned int rx_pos; > + unsigned int clk_count; > struct clk *uart_clk; > struct clk *bus_clk; > struct uart_8250_dma *dma; > @@ -196,9 +199,15 @@ static void mtk8250_shutdown(struct uart_port *port) > mtk8250_set_termios(struct uart_port *port, struct ktermios *termios, > struct ktermios *old) > { > + unsigned short fraction_L_mapping[] = { > + 0, 1, 0x5, 0x15, 0x55, 0x57, 0x57, 0x77, 0x7F, 0xFF, 0xFF > + }; > + unsigned short fraction_M_mapping[] = { > + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 3 > + }; > struct uart_8250_port *up = up_to_u8250p(port); > + unsigned int baud, quot, fraction; > unsigned long flags; > - unsigned int baud, quot; > > #ifdef CONFIG_SERIAL_8250_DMA > if (up->dma) { > @@ -214,7 +223,7 @@ static void mtk8250_shutdown(struct uart_port *port) > serial8250_do_set_termios(port, termios, old); > > /* > - * Mediatek UARTs use an extra highspeed register (UART_MTK_HIGHS) > + * Mediatek UARTs use an extra highspeed register (MTK_UART_HIGHS) > * > * We need to recalcualte the quot register, as the claculation depends > * on the vaule in the highspeed register. > @@ -230,18 +239,11 @@ static void mtk8250_shutdown(struct uart_port *port) > port->uartclk / 16 / UART_DIV_MAX, > port->uartclk); > > - if (baud <= 115200) { > - serial_port_out(port, UART_MTK_HIGHS, 0x0); > + if (baud < 115200) { > + serial_port_out(port, MTK_UART_HIGHS, 0x0); > quot = uart_get_divisor(port, baud); > - } else if (baud <= 576000) { > - serial_port_out(port, UART_MTK_HIGHS, 0x2); > - > - /* Set to next lower baudrate supported */ > - if ((baud == 500000) || (baud == 576000)) > - baud = 460800; > - quot = DIV_ROUND_UP(port->uartclk, 4 * baud); > } else { > - serial_port_out(port, UART_MTK_HIGHS, 0x3); > + serial_port_out(port, MTK_UART_HIGHS, 0x3); > quot = DIV_ROUND_UP(port->uartclk, 256 * baud); > } > > @@ -258,17 +260,29 @@ static void mtk8250_shutdown(struct uart_port *port) > /* reset DLAB */ > serial_port_out(port, UART_LCR, up->lcr); > > - if (baud > 460800) { > + if (baud >= 115200) { > unsigned int tmp; > > - tmp = DIV_ROUND_CLOSEST(port->uartclk, quot * baud); > - serial_port_out(port, UART_MTK_SAMPLE_COUNT, tmp - 1); > - serial_port_out(port, UART_MTK_SAMPLE_POINT, > - (tmp - 2) >> 1); > + tmp = (port->uartclk / (baud * quot)) - 1; > + serial_port_out(port, MTK_UART_SAMPLE_COUNT, tmp); > + serial_port_out(port, MTK_UART_SAMPLE_POINT, > + (tmp >> 1) - 1); > + > + /*count fraction to set fractoin register */ > + fraction = ((port->uartclk * 100) / baud / quot) % 100; > + fraction = DIV_ROUND_CLOSEST(fraction, 10); > + serial_port_out(port, MTK_UART_FRACDIV_L, > + fraction_L_mapping[fraction]); > + serial_port_out(port, MTK_UART_FRACDIV_M, > + fraction_M_mapping[fraction]); > } else { > - serial_port_out(port, UART_MTK_SAMPLE_COUNT, 0x00); > - serial_port_out(port, UART_MTK_SAMPLE_POINT, 0xff); > + serial_port_out(port, MTK_UART_SAMPLE_COUNT, 0x00); > + serial_port_out(port, MTK_UART_SAMPLE_POINT, 0xff); > + serial_port_out(port, MTK_UART_FRACDIV_L, 0x00); > + serial_port_out(port, MTK_UART_FRACDIV_M, 0x00); > } > + if (uart_console(port)) > + up->port.cons->cflag = termios->c_cflag; > > spin_unlock_irqrestore(&port->lock, flags); > /* Don't rewrite B0 */ > -- > 1.7.9.5 > > > _______________________________________________ > Linux-mediatek mailing list > Linux-mediatek@lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-mediatek ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 2/2] serial: 8250-mtk: modify baudrate setting 2019-04-25 8:41 [PATCH 0/2] Perfect 8250 mtk uart function Long Cheng 2019-04-25 8:41 ` [PATCH 1/2] serial: 8250-mtk: add follow control Long Cheng @ 2019-04-25 8:41 ` Long Cheng 1 sibling, 0 replies; 6+ messages in thread From: Long Cheng @ 2019-04-25 8:41 UTC (permalink / raw) To: Greg Kroah-Hartman Cc: Jiri Slaby, Matthias Brugger, Long Cheng, Gustavo A. R. Silva, Peter Shih, linux-serial, linux-arm-kernel, linux-mediatek, linux-kernel, srv_heupstream, Yingjoe Chen, YT Shen, Zhenbao Liu, Changqi Hu In termios function, add Fractional divider to adjust baudrate. Signed-off-by: Long Cheng <long.cheng@mediatek.com> --- drivers/tty/serial/8250/8250_mtk.c | 102 ++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c index 959fd85..417c7c8 100644 --- a/drivers/tty/serial/8250/8250_mtk.c +++ b/drivers/tty/serial/8250/8250_mtk.c @@ -25,13 +25,28 @@ #define MTK_UART_SAMPLE_COUNT 0x0a /* Sample count register */ #define MTK_UART_SAMPLE_POINT 0x0b /* Sample point register */ #define MTK_UART_RATE_FIX 0x0d /* UART Rate Fix Register */ +#define MTK_UART_ESCAPE_DAT 0x10 /* Escape Character register */ +#define MTK_UART_ESCAPE_EN 0x11 /* Escape Enable register */ #define MTK_UART_DMA_EN 0x13 /* DMA Enable register */ #define MTK_UART_RXTRI_AD 0x14 /* RX Trigger address */ #define MTK_UART_FRACDIV_L 0x15 /* Fractional divider LSB address */ #define MTK_UART_FRACDIV_M 0x16 /* Fractional divider MSB address */ +#define MTK_UART_IER_XOFFI 0x20 /* Enable XOFF character interrupt */ +#define MTK_UART_IER_RTSI 0x40 /* Enable RTS Modem status interrupt */ +#define MTK_UART_IER_CTSI 0x80 /* Enable CTS Modem status interrupt */ + +#define MTK_UART_EFR_EN 0x10 /* Enable enhancement feature */ +#define MTK_UART_EFR_RTS 0x40 /* Enable hardware rx flow control */ +#define MTK_UART_EFR_CTS 0x80 /* Enable hardware tx flow control */ +#define MTK_UART_EFR_NO_SW_FC 0x0 /* no sw flow control */ +#define MTK_UART_EFR_XON1_XOFF1 0xa /* XON1/XOFF1 as sw flow control */ +#define MTK_UART_EFR_XON2_XOFF2 0x5 /* XON2/XOFF2 as sw flow control */ +#define MTK_UART_EFR_SW_FC_MASK 0xf /* Enable CTS Modem status interrupt */ +#define MTK_UART_EFR_HW_FC (MTK_UART_EFR_RTS | MTK_UART_EFR_CTS) #define MTK_UART_DMA_EN_TX 0x2 #define MTK_UART_DMA_EN_RX 0x5 +#define MTK_UART_ESCAPE_CHAR 0x77 /* Escape char added under sw fc */ #define MTK_UART_TX_SIZE UART_XMIT_SIZE #define MTK_UART_RX_SIZE 0x8000 #define MTK_UART_TX_TRIGGER 1 @@ -57,6 +72,13 @@ struct mtk8250_data { #endif }; +/* flow control mode */ +enum { + MTK_UART_FC_NONE, + MTK_UART_FC_SW, + MTK_UART_FC_HW, +}; + #ifdef CONFIG_SERIAL_8250_DMA static void mtk8250_rx_dma(struct uart_8250_port *up); @@ -195,6 +217,75 @@ static void mtk8250_shutdown(struct uart_port *port) return serial8250_do_shutdown(port); } +static void mtk8250_disable_intrs(struct uart_8250_port *up, int mask) +{ + serial_out(up, UART_IER, serial_in(up, UART_IER) & (~mask)); +} + +static void mtk8250_enable_intrs(struct uart_8250_port *up, int mask) +{ + serial_out(up, UART_IER, serial_in(up, UART_IER) | mask); +} + +static void mtk8250_set_flow_ctrl(struct uart_8250_port *up, int mode) +{ + struct uart_port *port = &up->port; + int lcr = serial_in(up, UART_LCR); + + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_EFR, UART_EFR_ECB); + serial_out(up, UART_LCR, lcr); + lcr = serial_in(up, UART_LCR); + + switch (mode) { + case MTK_UART_FC_NONE: + serial_out(up, MTK_UART_ESCAPE_DAT, MTK_UART_ESCAPE_CHAR); + serial_out(up, MTK_UART_ESCAPE_EN, 0x00); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_EFR, serial_in(up, UART_EFR) & + (~(MTK_UART_EFR_HW_FC | MTK_UART_EFR_SW_FC_MASK))); + serial_out(up, UART_LCR, lcr); + mtk8250_disable_intrs(up, MTK_UART_IER_XOFFI | + MTK_UART_IER_RTSI | MTK_UART_IER_CTSI); + break; + + case MTK_UART_FC_HW: + serial_out(up, MTK_UART_ESCAPE_DAT, MTK_UART_ESCAPE_CHAR); + serial_out(up, MTK_UART_ESCAPE_EN, 0x00); + serial_out(up, UART_MCR, UART_MCR_RTS); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + + /*enable hw flow control*/ + serial_out(up, UART_EFR, MTK_UART_EFR_HW_FC | + (serial_in(up, UART_EFR) & + (~(MTK_UART_EFR_HW_FC | MTK_UART_EFR_SW_FC_MASK)))); + + serial_out(up, UART_LCR, lcr); + mtk8250_disable_intrs(up, MTK_UART_IER_XOFFI); + mtk8250_enable_intrs(up, MTK_UART_IER_CTSI | MTK_UART_IER_RTSI); + break; + + case MTK_UART_FC_SW: /*MTK software flow control */ + serial_out(up, MTK_UART_ESCAPE_DAT, MTK_UART_ESCAPE_CHAR); + serial_out(up, MTK_UART_ESCAPE_EN, 0x01); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + + /*enable sw flow control */ + serial_out(up, UART_EFR, MTK_UART_EFR_XON1_XOFF1 | + (serial_in(up, UART_EFR) & + (~(MTK_UART_EFR_HW_FC | MTK_UART_EFR_SW_FC_MASK)))); + + serial_out(up, UART_XON1, START_CHAR(port->state->port.tty)); + serial_out(up, UART_XOFF1, STOP_CHAR(port->state->port.tty)); + serial_out(up, UART_LCR, lcr); + mtk8250_disable_intrs(up, MTK_UART_IER_CTSI|MTK_UART_IER_RTSI); + mtk8250_enable_intrs(up, MTK_UART_IER_XOFFI); + break; + default: + break; + } +} + static void mtk8250_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) @@ -208,6 +299,7 @@ static void mtk8250_shutdown(struct uart_port *port) struct uart_8250_port *up = up_to_u8250p(port); unsigned int baud, quot, fraction; unsigned long flags; + int mode; #ifdef CONFIG_SERIAL_8250_DMA if (up->dma) { @@ -281,6 +373,16 @@ static void mtk8250_shutdown(struct uart_port *port) serial_port_out(port, MTK_UART_FRACDIV_L, 0x00); serial_port_out(port, MTK_UART_FRACDIV_M, 0x00); } + + if ((termios->c_cflag & CRTSCTS) && (!(termios->c_iflag & CRTSCTS))) + mode = MTK_UART_FC_HW; + else if (termios->c_iflag & CRTSCTS) + mode = MTK_UART_FC_SW; + else + mode = MTK_UART_FC_NONE; + + mtk8250_set_flow_ctrl(up, mode); + if (uart_console(port)) up->port.cons->cflag = termios->c_cflag; -- 1.7.9.5 ^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2019-04-28 17:41 UTC | newest] Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2019-04-25 8:41 [PATCH 0/2] Perfect 8250 mtk uart function Long Cheng 2019-04-25 8:41 ` [PATCH 1/2] serial: 8250-mtk: add follow control Long Cheng 2019-04-25 10:40 ` Matthias Brugger 2019-04-26 5:22 ` Long Cheng 2019-04-28 17:40 ` Sean Wang 2019-04-25 8:41 ` [PATCH 2/2] serial: 8250-mtk: modify baudrate setting Long Cheng
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).