diff options
Diffstat (limited to 'drivers/serial/imx.c')
-rw-r--r-- | drivers/serial/imx.c | 68 |
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 | ||
324 | static 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 | |||
324 | static int imx_startup(struct uart_port *port) | 350 | static 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 | |||
737 | imx_console_get_options(struct imx_port *sport, int *baud, | 758 | imx_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 | ||