aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/serial/imx.c
diff options
context:
space:
mode:
authorSascha Hauer <sascha@de.rmk.(none)>2005-04-29 17:46:40 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2005-04-29 17:46:40 -0400
commit587897f51fac04988de497a553215fdf41e6d5f6 (patch)
tree156025260e508e775b1695479e4fdf69d8454f7f /drivers/serial/imx.c
parentc60c390620e0abb60d4ae8c43583714bda27763f (diff)
[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>
Diffstat (limited to 'drivers/serial/imx.c')
-rw-r--r--drivers/serial/imx.c68
1 files changed, 60 insertions, 8 deletions
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
index c682c6308cde..01a8726a3f97 100644
--- a/drivers/serial/imx.c
+++ b/drivers/serial/imx.c
@@ -321,18 +321,39 @@ static void imx_break_ctl(struct uart_port *port, int break_state)
321#define TXTL 2 /* reset default */ 321#define TXTL 2 /* reset default */
322#define RXTL 1 /* reset default */ 322#define RXTL 1 /* reset default */
323 323
324static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
325{
326 unsigned int val;
327 unsigned int ufcr_rfdiv;
328
329 /* set receiver / transmitter trigger level.
330 * RFDIV is set such way to satisfy requested uartclk value
331 */
332 val = TXTL<<10 | RXTL;
333 ufcr_rfdiv = (imx_get_perclk1() + sport->port.uartclk / 2) / sport->port.uartclk;
334
335 if(!ufcr_rfdiv)
336 ufcr_rfdiv = 1;
337
338 if(ufcr_rfdiv >= 7)
339 ufcr_rfdiv = 6;
340 else
341 ufcr_rfdiv = 6 - ufcr_rfdiv;
342
343 val |= UFCR_RFDIV & (ufcr_rfdiv << 7);
344
345 UFCR((u32)sport->port.membase) = val;
346
347 return 0;
348}
349
324static int imx_startup(struct uart_port *port) 350static int imx_startup(struct uart_port *port)
325{ 351{
326 struct imx_port *sport = (struct imx_port *)port; 352 struct imx_port *sport = (struct imx_port *)port;
327 int retval; 353 int retval;
328 unsigned int val;
329 unsigned long flags; 354 unsigned long flags;
330 355
331 /* set receiver / transmitter trigger level. We assume 356 imx_setup_ufcr(sport, 0);
332 * that RFDIV has been set by the arch setup or by the bootloader.
333 */
334 val = (UFCR((u32)sport->port.membase) & UFCR_RFDIV) | TXTL<<10 | RXTL;
335 UFCR((u32)sport->port.membase) = val;
336 357
337 /* disable the DREN bit (Data Ready interrupt enable) before 358 /* disable the DREN bit (Data Ready interrupt enable) before
338 * requesting IRQs 359 * requesting IRQs
@@ -737,9 +758,12 @@ static void __init
737imx_console_get_options(struct imx_port *sport, int *baud, 758imx_console_get_options(struct imx_port *sport, int *baud,
738 int *parity, int *bits) 759 int *parity, int *bits)
739{ 760{
761
740 if ( UCR1((u32)sport->port.membase) | UCR1_UARTEN ) { 762 if ( UCR1((u32)sport->port.membase) | UCR1_UARTEN ) {
741 /* ok, the port was enabled */ 763 /* ok, the port was enabled */
742 unsigned int ucr2, ubir,ubmr, uartclk; 764 unsigned int ucr2, ubir,ubmr, uartclk;
765 unsigned int baud_raw;
766 unsigned int ucfr_rfdiv;
743 767
744 ucr2 = UCR2((u32)sport->port.membase); 768 ucr2 = UCR2((u32)sport->port.membase);
745 769
@@ -758,9 +782,35 @@ imx_console_get_options(struct imx_port *sport, int *baud,
758 782
759 ubir = UBIR((u32)sport->port.membase) & 0xffff; 783 ubir = UBIR((u32)sport->port.membase) & 0xffff;
760 ubmr = UBMR((u32)sport->port.membase) & 0xffff; 784 ubmr = UBMR((u32)sport->port.membase) & 0xffff;
761 uartclk = sport->port.uartclk;
762 785
763 *baud = ((uartclk/16) * (ubir + 1)) / (ubmr + 1); 786
787 ucfr_rfdiv = (UFCR((u32)sport->port.membase) & UFCR_RFDIV) >> 7;
788 if (ucfr_rfdiv == 6)
789 ucfr_rfdiv = 7;
790 else
791 ucfr_rfdiv = 6 - ucfr_rfdiv;
792
793 uartclk = imx_get_perclk1();
794 uartclk /= ucfr_rfdiv;
795
796 { /*
797 * The next code provides exact computation of
798 * baud_raw = round(((uartclk/16) * (ubir + 1)) / (ubmr + 1))
799 * without need of float support or long long division,
800 * which would be required to prevent 32bit arithmetic overflow
801 */
802 unsigned int mul = ubir + 1;
803 unsigned int div = 16 * (ubmr + 1);
804 unsigned int rem = uartclk % div;
805
806 baud_raw = (uartclk / div) * mul;
807 baud_raw += (rem * mul + div / 2) / div;
808 *baud = (baud_raw + 50) / 100 * 100;
809 }
810
811 if(*baud != baud_raw)
812 printk(KERN_INFO "Serial: Console IMX rounded baud rate from %d to %d\n",
813 baud_raw, *baud);
764 } 814 }
765} 815}
766 816
@@ -787,6 +837,8 @@ imx_console_setup(struct console *co, char *options)
787 else 837 else
788 imx_console_get_options(sport, &baud, &parity, &bits); 838 imx_console_get_options(sport, &baud, &parity, &bits);
789 839
840 imx_setup_ufcr(sport, 0);
841
790 return uart_set_options(&sport->port, co, baud, parity, bits, flow); 842 return uart_set_options(&sport->port, co, baud, parity, bits, flow);
791} 843}
792 844