mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-16 16:54:20 +08:00
[PATCH] ARM: 2654/1: i.MX UART initialization sets and honors UFCR value
Patch from Sascha Hauer This patch adds UCFR_RFDIV setting into i.MX serial driver. This is required, if loader does not fully agree with Linux kernel about UART setup manner. Linux only blindly expected some values until now. This should enable to use even serial ports not recognized by boot-loader as for example third UART found in the bluethoot module. Patch also enables to detect original setup baudrate in more cases. Signed-off-by: Pavel Pisa Signed-off-by: Sascha Hauer Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
parent
c60c390620
commit
587897f51f
@ -321,18 +321,39 @@ static void imx_break_ctl(struct uart_port *port, int break_state)
|
|||||||
#define TXTL 2 /* reset default */
|
#define TXTL 2 /* reset default */
|
||||||
#define RXTL 1 /* reset default */
|
#define RXTL 1 /* reset default */
|
||||||
|
|
||||||
|
static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
|
||||||
|
{
|
||||||
|
unsigned int val;
|
||||||
|
unsigned int ufcr_rfdiv;
|
||||||
|
|
||||||
|
/* set receiver / transmitter trigger level.
|
||||||
|
* RFDIV is set such way to satisfy requested uartclk value
|
||||||
|
*/
|
||||||
|
val = TXTL<<10 | RXTL;
|
||||||
|
ufcr_rfdiv = (imx_get_perclk1() + sport->port.uartclk / 2) / sport->port.uartclk;
|
||||||
|
|
||||||
|
if(!ufcr_rfdiv)
|
||||||
|
ufcr_rfdiv = 1;
|
||||||
|
|
||||||
|
if(ufcr_rfdiv >= 7)
|
||||||
|
ufcr_rfdiv = 6;
|
||||||
|
else
|
||||||
|
ufcr_rfdiv = 6 - ufcr_rfdiv;
|
||||||
|
|
||||||
|
val |= UFCR_RFDIV & (ufcr_rfdiv << 7);
|
||||||
|
|
||||||
|
UFCR((u32)sport->port.membase) = val;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int imx_startup(struct uart_port *port)
|
static int imx_startup(struct uart_port *port)
|
||||||
{
|
{
|
||||||
struct imx_port *sport = (struct imx_port *)port;
|
struct imx_port *sport = (struct imx_port *)port;
|
||||||
int retval;
|
int retval;
|
||||||
unsigned int val;
|
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
/* set receiver / transmitter trigger level. We assume
|
imx_setup_ufcr(sport, 0);
|
||||||
* that RFDIV has been set by the arch setup or by the bootloader.
|
|
||||||
*/
|
|
||||||
val = (UFCR((u32)sport->port.membase) & UFCR_RFDIV) | TXTL<<10 | RXTL;
|
|
||||||
UFCR((u32)sport->port.membase) = val;
|
|
||||||
|
|
||||||
/* disable the DREN bit (Data Ready interrupt enable) before
|
/* disable the DREN bit (Data Ready interrupt enable) before
|
||||||
* requesting IRQs
|
* requesting IRQs
|
||||||
@ -737,9 +758,12 @@ static void __init
|
|||||||
imx_console_get_options(struct imx_port *sport, int *baud,
|
imx_console_get_options(struct imx_port *sport, int *baud,
|
||||||
int *parity, int *bits)
|
int *parity, int *bits)
|
||||||
{
|
{
|
||||||
|
|
||||||
if ( UCR1((u32)sport->port.membase) | UCR1_UARTEN ) {
|
if ( UCR1((u32)sport->port.membase) | UCR1_UARTEN ) {
|
||||||
/* ok, the port was enabled */
|
/* ok, the port was enabled */
|
||||||
unsigned int ucr2, ubir,ubmr, uartclk;
|
unsigned int ucr2, ubir,ubmr, uartclk;
|
||||||
|
unsigned int baud_raw;
|
||||||
|
unsigned int ucfr_rfdiv;
|
||||||
|
|
||||||
ucr2 = UCR2((u32)sport->port.membase);
|
ucr2 = UCR2((u32)sport->port.membase);
|
||||||
|
|
||||||
@ -758,9 +782,35 @@ imx_console_get_options(struct imx_port *sport, int *baud,
|
|||||||
|
|
||||||
ubir = UBIR((u32)sport->port.membase) & 0xffff;
|
ubir = UBIR((u32)sport->port.membase) & 0xffff;
|
||||||
ubmr = UBMR((u32)sport->port.membase) & 0xffff;
|
ubmr = UBMR((u32)sport->port.membase) & 0xffff;
|
||||||
uartclk = sport->port.uartclk;
|
|
||||||
|
|
||||||
*baud = ((uartclk/16) * (ubir + 1)) / (ubmr + 1);
|
|
||||||
|
ucfr_rfdiv = (UFCR((u32)sport->port.membase) & UFCR_RFDIV) >> 7;
|
||||||
|
if (ucfr_rfdiv == 6)
|
||||||
|
ucfr_rfdiv = 7;
|
||||||
|
else
|
||||||
|
ucfr_rfdiv = 6 - ucfr_rfdiv;
|
||||||
|
|
||||||
|
uartclk = imx_get_perclk1();
|
||||||
|
uartclk /= ucfr_rfdiv;
|
||||||
|
|
||||||
|
{ /*
|
||||||
|
* The next code provides exact computation of
|
||||||
|
* baud_raw = round(((uartclk/16) * (ubir + 1)) / (ubmr + 1))
|
||||||
|
* without need of float support or long long division,
|
||||||
|
* which would be required to prevent 32bit arithmetic overflow
|
||||||
|
*/
|
||||||
|
unsigned int mul = ubir + 1;
|
||||||
|
unsigned int div = 16 * (ubmr + 1);
|
||||||
|
unsigned int rem = uartclk % div;
|
||||||
|
|
||||||
|
baud_raw = (uartclk / div) * mul;
|
||||||
|
baud_raw += (rem * mul + div / 2) / div;
|
||||||
|
*baud = (baud_raw + 50) / 100 * 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(*baud != baud_raw)
|
||||||
|
printk(KERN_INFO "Serial: Console IMX rounded baud rate from %d to %d\n",
|
||||||
|
baud_raw, *baud);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -787,6 +837,8 @@ imx_console_setup(struct console *co, char *options)
|
|||||||
else
|
else
|
||||||
imx_console_get_options(sport, &baud, &parity, &bits);
|
imx_console_get_options(sport, &baud, &parity, &bits);
|
||||||
|
|
||||||
|
imx_setup_ufcr(sport, 0);
|
||||||
|
|
||||||
return uart_set_options(&sport->port, co, baud, parity, bits, flow);
|
return uart_set_options(&sport->port, co, baud, parity, bits, flow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user