aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/serial
diff options
context:
space:
mode:
authorAlbrecht Dreß <albrecht.dress@arcor.de>2010-04-26 07:18:12 -0400
committerGrant Likely <grant.likely@secretlab.ca>2010-07-24 20:27:57 -0400
commit0d1f22e4907fec330ef0e475cb0dad48419498f2 (patch)
tree85a5da2e1c59ddba4f186fcf8b8eae6605f87729 /drivers/serial
parentb37fa16e78d6f9790462b3181602a26b5af36260 (diff)
powerpc/5200: improve uart baud rate calculation (reach high baud rates, better accuracy)
On the MPC5200B, make very high baud rates (e.g. 3 MBaud) accessible and achieve a higher precision for high baud rates in general. This is done by selecting the appropriate prescaler (/4 or /32). As to keep the code clean, the getuartclk method has been dropped, and all calculations are done in a new set_baudrate method. Notes: only "fsl,mpc5200b-psc-uart" compatible devices benefit from these improvements. Tested on a custom 5200B based board, from 110 baud up to 3 MBaud, and with both "fsl,mpc5200b-psc-uart" and "fsl,mpc5200-psc-uart" devices. Also tested on the mpc5121ads board. Signed-off-by: Albrecht Dreß <albrecht.dress@arcor.de> [agust: fixed mpc5121 prescaler comment] Signed-off-by: Anatolij Gustschin <agust@denx.de> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'drivers/serial')
-rw-r--r--drivers/serial/mpc52xx_uart.c145
1 files changed, 116 insertions, 29 deletions
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index 84a35f699016..1a88b363005c 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -113,7 +113,9 @@ struct psc_ops {
113 unsigned char (*read_char)(struct uart_port *port); 113 unsigned char (*read_char)(struct uart_port *port);
114 void (*cw_disable_ints)(struct uart_port *port); 114 void (*cw_disable_ints)(struct uart_port *port);
115 void (*cw_restore_ints)(struct uart_port *port); 115 void (*cw_restore_ints)(struct uart_port *port);
116 unsigned long (*getuartclk)(void *p); 116 unsigned int (*set_baudrate)(struct uart_port *port,
117 struct ktermios *new,
118 struct ktermios *old);
117 int (*clock)(struct uart_port *port, int enable); 119 int (*clock)(struct uart_port *port, int enable);
118 int (*fifoc_init)(void); 120 int (*fifoc_init)(void);
119 void (*fifoc_uninit)(void); 121 void (*fifoc_uninit)(void);
@@ -121,6 +123,16 @@ struct psc_ops {
121 irqreturn_t (*handle_irq)(struct uart_port *port); 123 irqreturn_t (*handle_irq)(struct uart_port *port);
122}; 124};
123 125
126/* setting the prescaler and divisor reg is common for all chips */
127static inline void mpc52xx_set_divisor(struct mpc52xx_psc __iomem *psc,
128 u16 prescaler, unsigned int divisor)
129{
130 /* select prescaler */
131 out_be16(&psc->mpc52xx_psc_clock_select, prescaler);
132 out_8(&psc->ctur, divisor >> 8);
133 out_8(&psc->ctlr, divisor & 0xff);
134}
135
124#ifdef CONFIG_PPC_MPC52xx 136#ifdef CONFIG_PPC_MPC52xx
125#define FIFO_52xx(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1)) 137#define FIFO_52xx(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1))
126static void mpc52xx_psc_fifo_init(struct uart_port *port) 138static void mpc52xx_psc_fifo_init(struct uart_port *port)
@@ -128,9 +140,6 @@ static void mpc52xx_psc_fifo_init(struct uart_port *port)
128 struct mpc52xx_psc __iomem *psc = PSC(port); 140 struct mpc52xx_psc __iomem *psc = PSC(port);
129 struct mpc52xx_psc_fifo __iomem *fifo = FIFO_52xx(port); 141 struct mpc52xx_psc_fifo __iomem *fifo = FIFO_52xx(port);
130 142
131 /* /32 prescaler */
132 out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00);
133
134 out_8(&fifo->rfcntl, 0x00); 143 out_8(&fifo->rfcntl, 0x00);
135 out_be16(&fifo->rfalarm, 0x1ff); 144 out_be16(&fifo->rfalarm, 0x1ff);
136 out_8(&fifo->tfcntl, 0x07); 145 out_8(&fifo->tfcntl, 0x07);
@@ -219,15 +228,47 @@ static void mpc52xx_psc_cw_restore_ints(struct uart_port *port)
219 out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask); 228 out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
220} 229}
221 230
222/* Search for bus-frequency property in this node or a parent */ 231static unsigned int mpc5200_psc_set_baudrate(struct uart_port *port,
223static unsigned long mpc52xx_getuartclk(void *p) 232 struct ktermios *new,
233 struct ktermios *old)
224{ 234{
225 /* 235 unsigned int baud;
226 * 5200 UARTs have a / 32 prescaler 236 unsigned int divisor;
227 * but the generic serial code assumes 16 237
228 * so return ipb freq / 2 238 /* The 5200 has a fixed /32 prescaler, uartclk contains the ipb freq */
229 */ 239 baud = uart_get_baud_rate(port, new, old,
230 return mpc5xxx_get_bus_frequency(p) / 2; 240 port->uartclk / (32 * 0xffff) + 1,
241 port->uartclk / 32);
242 divisor = (port->uartclk + 16 * baud) / (32 * baud);
243
244 /* enable the /32 prescaler and set the divisor */
245 mpc52xx_set_divisor(PSC(port), 0xdd00, divisor);
246 return baud;
247}
248
249static unsigned int mpc5200b_psc_set_baudrate(struct uart_port *port,
250 struct ktermios *new,
251 struct ktermios *old)
252{
253 unsigned int baud;
254 unsigned int divisor;
255 u16 prescaler;
256
257 /* The 5200B has a selectable /4 or /32 prescaler, uartclk contains the
258 * ipb freq */
259 baud = uart_get_baud_rate(port, new, old,
260 port->uartclk / (32 * 0xffff) + 1,
261 port->uartclk / 4);
262 divisor = (port->uartclk + 2 * baud) / (4 * baud);
263
264 /* select the proper prescaler and set the divisor */
265 if (divisor > 0xffff) {
266 divisor = (divisor + 4) / 8;
267 prescaler = 0xdd00; /* /32 */
268 } else
269 prescaler = 0xff00; /* /4 */
270 mpc52xx_set_divisor(PSC(port), prescaler, divisor);
271 return baud;
231} 272}
232 273
233static void mpc52xx_psc_get_irq(struct uart_port *port, struct device_node *np) 274static void mpc52xx_psc_get_irq(struct uart_port *port, struct device_node *np)
@@ -258,7 +299,28 @@ static struct psc_ops mpc52xx_psc_ops = {
258 .read_char = mpc52xx_psc_read_char, 299 .read_char = mpc52xx_psc_read_char,
259 .cw_disable_ints = mpc52xx_psc_cw_disable_ints, 300 .cw_disable_ints = mpc52xx_psc_cw_disable_ints,
260 .cw_restore_ints = mpc52xx_psc_cw_restore_ints, 301 .cw_restore_ints = mpc52xx_psc_cw_restore_ints,
261 .getuartclk = mpc52xx_getuartclk, 302 .set_baudrate = mpc5200_psc_set_baudrate,
303 .get_irq = mpc52xx_psc_get_irq,
304 .handle_irq = mpc52xx_psc_handle_irq,
305};
306
307static struct psc_ops mpc5200b_psc_ops = {
308 .fifo_init = mpc52xx_psc_fifo_init,
309 .raw_rx_rdy = mpc52xx_psc_raw_rx_rdy,
310 .raw_tx_rdy = mpc52xx_psc_raw_tx_rdy,
311 .rx_rdy = mpc52xx_psc_rx_rdy,
312 .tx_rdy = mpc52xx_psc_tx_rdy,
313 .tx_empty = mpc52xx_psc_tx_empty,
314 .stop_rx = mpc52xx_psc_stop_rx,
315 .start_tx = mpc52xx_psc_start_tx,
316 .stop_tx = mpc52xx_psc_stop_tx,
317 .rx_clr_irq = mpc52xx_psc_rx_clr_irq,
318 .tx_clr_irq = mpc52xx_psc_tx_clr_irq,
319 .write_char = mpc52xx_psc_write_char,
320 .read_char = mpc52xx_psc_read_char,
321 .cw_disable_ints = mpc52xx_psc_cw_disable_ints,
322 .cw_restore_ints = mpc52xx_psc_cw_restore_ints,
323 .set_baudrate = mpc5200b_psc_set_baudrate,
262 .get_irq = mpc52xx_psc_get_irq, 324 .get_irq = mpc52xx_psc_get_irq,
263 .handle_irq = mpc52xx_psc_handle_irq, 325 .handle_irq = mpc52xx_psc_handle_irq,
264}; 326};
@@ -392,9 +454,35 @@ static void mpc512x_psc_cw_restore_ints(struct uart_port *port)
392 out_be32(&FIFO_512x(port)->rximr, port->read_status_mask & 0x7f); 454 out_be32(&FIFO_512x(port)->rximr, port->read_status_mask & 0x7f);
393} 455}
394 456
395static unsigned long mpc512x_getuartclk(void *p) 457static unsigned int mpc512x_psc_set_baudrate(struct uart_port *port,
458 struct ktermios *new,
459 struct ktermios *old)
396{ 460{
397 return mpc5xxx_get_bus_frequency(p); 461 unsigned int baud;
462 unsigned int divisor;
463
464 /*
465 * The "MPC5121e Microcontroller Reference Manual, Rev. 3" says on
466 * pg. 30-10 that the chip supports a /32 and a /10 prescaler.
467 * Furthermore, it states that "After reset, the prescaler by 10
468 * for the UART mode is selected", but the reset register value is
469 * 0x0000 which means a /32 prescaler. This is wrong.
470 *
471 * In reality using /32 prescaler doesn't work, as it is not supported!
472 * Use /16 or /10 prescaler, see "MPC5121e Hardware Design Guide",
473 * Chapter 4.1 PSC in UART Mode.
474 * Calculate with a /16 prescaler here.
475 */
476
477 /* uartclk contains the ips freq */
478 baud = uart_get_baud_rate(port, new, old,
479 port->uartclk / (16 * 0xffff) + 1,
480 port->uartclk / 16);
481 divisor = (port->uartclk + 8 * baud) / (16 * baud);
482
483 /* enable the /16 prescaler and set the divisor */
484 mpc52xx_set_divisor(PSC(port), 0xdd00, divisor);
485 return baud;
398} 486}
399 487
400/* Init PSC FIFO Controller */ 488/* Init PSC FIFO Controller */
@@ -498,7 +586,7 @@ static struct psc_ops mpc512x_psc_ops = {
498 .read_char = mpc512x_psc_read_char, 586 .read_char = mpc512x_psc_read_char,
499 .cw_disable_ints = mpc512x_psc_cw_disable_ints, 587 .cw_disable_ints = mpc512x_psc_cw_disable_ints,
500 .cw_restore_ints = mpc512x_psc_cw_restore_ints, 588 .cw_restore_ints = mpc512x_psc_cw_restore_ints,
501 .getuartclk = mpc512x_getuartclk, 589 .set_baudrate = mpc512x_psc_set_baudrate,
502 .clock = mpc512x_psc_clock, 590 .clock = mpc512x_psc_clock,
503 .fifoc_init = mpc512x_psc_fifoc_init, 591 .fifoc_init = mpc512x_psc_fifoc_init,
504 .fifoc_uninit = mpc512x_psc_fifoc_uninit, 592 .fifoc_uninit = mpc512x_psc_fifoc_uninit,
@@ -666,8 +754,8 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
666 struct mpc52xx_psc __iomem *psc = PSC(port); 754 struct mpc52xx_psc __iomem *psc = PSC(port);
667 unsigned long flags; 755 unsigned long flags;
668 unsigned char mr1, mr2; 756 unsigned char mr1, mr2;
669 unsigned short ctr; 757 unsigned int j;
670 unsigned int j, baud, quot; 758 unsigned int baud;
671 759
672 /* Prepare what we're gonna write */ 760 /* Prepare what we're gonna write */
673 mr1 = 0; 761 mr1 = 0;
@@ -704,16 +792,9 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
704 mr2 |= MPC52xx_PSC_MODE_TXCTS; 792 mr2 |= MPC52xx_PSC_MODE_TXCTS;
705 } 793 }
706 794
707 baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16);
708 quot = uart_get_divisor(port, baud);
709 ctr = quot & 0xffff;
710
711 /* Get the lock */ 795 /* Get the lock */
712 spin_lock_irqsave(&port->lock, flags); 796 spin_lock_irqsave(&port->lock, flags);
713 797
714 /* Update the per-port timeout */
715 uart_update_timeout(port, new->c_cflag, baud);
716
717 /* Do our best to flush TX & RX, so we don't lose anything */ 798 /* Do our best to flush TX & RX, so we don't lose anything */
718 /* But we don't wait indefinitely ! */ 799 /* But we don't wait indefinitely ! */
719 j = 5000000; /* Maximum wait */ 800 j = 5000000; /* Maximum wait */
@@ -737,8 +818,10 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
737 out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1); 818 out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
738 out_8(&psc->mode, mr1); 819 out_8(&psc->mode, mr1);
739 out_8(&psc->mode, mr2); 820 out_8(&psc->mode, mr2);
740 out_8(&psc->ctur, ctr >> 8); 821 baud = psc_ops->set_baudrate(port, new, old);
741 out_8(&psc->ctlr, ctr & 0xff); 822
823 /* Update the per-port timeout */
824 uart_update_timeout(port, new->c_cflag, baud);
742 825
743 if (UART_ENABLE_MS(port, new->c_cflag)) 826 if (UART_ENABLE_MS(port, new->c_cflag))
744 mpc52xx_uart_enable_ms(port); 827 mpc52xx_uart_enable_ms(port);
@@ -1118,7 +1201,7 @@ mpc52xx_console_setup(struct console *co, char *options)
1118 return ret; 1201 return ret;
1119 } 1202 }
1120 1203
1121 uartclk = psc_ops->getuartclk(np); 1204 uartclk = mpc5xxx_get_bus_frequency(np);
1122 if (uartclk == 0) { 1205 if (uartclk == 0) {
1123 pr_debug("Could not find uart clock frequency!\n"); 1206 pr_debug("Could not find uart clock frequency!\n");
1124 return -EINVAL; 1207 return -EINVAL;
@@ -1201,6 +1284,7 @@ static struct uart_driver mpc52xx_uart_driver = {
1201 1284
1202static struct of_device_id mpc52xx_uart_of_match[] = { 1285static struct of_device_id mpc52xx_uart_of_match[] = {
1203#ifdef CONFIG_PPC_MPC52xx 1286#ifdef CONFIG_PPC_MPC52xx
1287 { .compatible = "fsl,mpc5200b-psc-uart", .data = &mpc5200b_psc_ops, },
1204 { .compatible = "fsl,mpc5200-psc-uart", .data = &mpc52xx_psc_ops, }, 1288 { .compatible = "fsl,mpc5200-psc-uart", .data = &mpc52xx_psc_ops, },
1205 /* binding used by old lite5200 device trees: */ 1289 /* binding used by old lite5200 device trees: */
1206 { .compatible = "mpc5200-psc-uart", .data = &mpc52xx_psc_ops, }, 1290 { .compatible = "mpc5200-psc-uart", .data = &mpc52xx_psc_ops, },
@@ -1233,7 +1317,10 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
1233 pr_debug("Found %s assigned to ttyPSC%x\n", 1317 pr_debug("Found %s assigned to ttyPSC%x\n",
1234 mpc52xx_uart_nodes[idx]->full_name, idx); 1318 mpc52xx_uart_nodes[idx]->full_name, idx);
1235 1319
1236 uartclk = psc_ops->getuartclk(op->dev.of_node); 1320 /* set the uart clock to the input clock of the psc, the different
1321 * prescalers are taken into account in the set_baudrate() methods
1322 * of the respective chip */
1323 uartclk = mpc5xxx_get_bus_frequency(op->dev.of_node);
1237 if (uartclk == 0) { 1324 if (uartclk == 0) {
1238 dev_dbg(&op->dev, "Could not find uart clock frequency!\n"); 1325 dev_dbg(&op->dev, "Could not find uart clock frequency!\n");
1239 return -EINVAL; 1326 return -EINVAL;