aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/serial/imx.c
diff options
context:
space:
mode:
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