From: "Albrecht Dreß" <albrecht.dress@arcor.de>
To: Linux PPC Development <linuxppc-dev@ozlabs.org>,
"Likely, Grant" <grant.likely@secretlab.ca>
Subject: [Patch] mpc5200b: improve baud rate calculation (reach high baud rates, better accuracy)
Date: Mon, 01 Mar 2010 19:11:54 +0100 [thread overview]
Message-ID: <1267467114.2218.0@antares> (raw)
On the MPC5200B, select the baud rate prescaler as /4 by default to make ve=
ry
high baud rates (e.g. 3 MBaud) accessible and to achieve a higher precision
for high baud rates in general. For baud rates below ~500 Baud, the code wi=
ll
automatically fall back to the /32 prescaler. The original MPC5200 does on=
ly
have a /32 prescaler which is detected only once and stored in a global. A
new chip-dependent method is used to set the divisor.
Tested on a custom 5200B based board, with up to 3 MBaud.
Signed-off-by: Albrecht Dre=DF <albrecht.dress@arcor.de>
---
--- linux-2.6.33/drivers/serial/mpc52xx_uart.c.orig 2010-02-24 19:52:17.000=
000000 +0100
+++ linux-2.6.33/drivers/serial/mpc52xx_uart.c 2010-02-26 21:12:51.00000000=
0 +0100
@@ -144,9 +144,17 @@ struct psc_ops {
unsigned char (*read_char)(struct uart_port *port);
void (*cw_disable_ints)(struct uart_port *port);
void (*cw_restore_ints)(struct uart_port *port);
+ void (*set_divisor)(struct uart_port *port,
+ unsigned int divisor);
unsigned long (*getuartclk)(void *p);
};
=20
+/* We need to distinguish between the MPC5200 which has only a /32 prescal=
er,
+ * and the MPC5200B which has a /32 and a /4 prescaler. The global is fin=
e,
+ * as the chip can be only either a 5200B or not. */
+static int is_mpc5200b =3D -1;
+
+
#ifdef CONFIG_PPC_MPC52xx
#define FIFO_52xx(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1))
static void mpc52xx_psc_fifo_init(struct uart_port *port)
@@ -154,9 +162,6 @@ static void mpc52xx_psc_fifo_init(struct
struct mpc52xx_psc __iomem *psc =3D PSC(port);
struct mpc52xx_psc_fifo __iomem *fifo =3D FIFO_52xx(port);
=20
- /* /32 prescaler */
- out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00);
-
out_8(&fifo->rfcntl, 0x00);
out_be16(&fifo->rfalarm, 0x1ff);
out_8(&fifo->tfcntl, 0x07);
@@ -245,15 +250,40 @@ static void mpc52xx_psc_cw_restore_ints(
out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
}
=20
+static void mpc52xx_psc_set_divisor(struct uart_port *port,
+ unsigned int divisor)
+{
+ struct mpc52xx_psc __iomem *psc =3D PSC(port);
+
+ /* prescaler */
+ if (is_mpc5200b !=3D 1)
+ out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00); /* /32 */
+ else if (divisor > 0xffff) {
+ out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00); /* /32 */
+ divisor =3D (divisor + 4) / 8;
+ } else
+ out_be16(&psc->mpc52xx_psc_clock_select, 0xff00); /* /4 */
+
+ /* ctr */
+ divisor &=3D 0xffff;
+ out_8(&psc->ctur, divisor >> 8);
+ out_8(&psc->ctlr, divisor & 0xff);
+}
+
/* Search for bus-frequency property in this node or a parent */
static unsigned long mpc52xx_getuartclk(void *p)
{
/*
- * 5200 UARTs have a / 32 prescaler
- * but the generic serial code assumes 16
- * so return ipb freq / 2
+ * The 5200 has only /32 prescalers.
+ * 5200B UARTs have a /4 or a /32 prescaler. For higher accuracy, we
+ * do all calculations using the /4 prescaler for this chip.
+ * The generic serial code assumes /16 so return ipb freq / 2 (5200)
+ * or ipb freq * 4 (5200B).
*/
- return mpc5xxx_get_bus_frequency(p) / 2;
+ if (is_mpc5200b =3D=3D 1)
+ return mpc5xxx_get_bus_frequency(p) * 4;
+ else
+ return mpc5xxx_get_bus_frequency(p) / 2;
}
=20
static struct psc_ops mpc52xx_psc_ops =3D {
@@ -272,6 +302,7 @@ static struct psc_ops mpc52xx_psc_ops =3D=20
.read_char =3D mpc52xx_psc_read_char,
.cw_disable_ints =3D mpc52xx_psc_cw_disable_ints,
.cw_restore_ints =3D mpc52xx_psc_cw_restore_ints,
+ .set_divisor =3D mpc52xx_psc_set_divisor,
.getuartclk =3D mpc52xx_getuartclk,
};
=20
@@ -388,6 +419,16 @@ static void mpc512x_psc_cw_restore_ints(
out_be32(&FIFO_512x(port)->rximr, port->read_status_mask & 0x7f);
}
=20
+static void mpc512x_psc_set_divisor(struct uart_port *port,
+ unsigned int divisor)
+{
+ struct mpc52xx_psc __iomem *psc =3D PSC(port);
+
+ divisor &=3D 0xffff;
+ out_8(&psc->ctur, divisor >> 8);
+ out_8(&psc->ctlr, divisor & 0xff);
+}
+
static unsigned long mpc512x_getuartclk(void *p)
{
return mpc5xxx_get_bus_frequency(p);
@@ -409,6 +450,7 @@ static struct psc_ops mpc512x_psc_ops =3D=20
.read_char =3D mpc512x_psc_read_char,
.cw_disable_ints =3D mpc512x_psc_cw_disable_ints,
.cw_restore_ints =3D mpc512x_psc_cw_restore_ints,
+ .set_divisor =3D mpc512x_psc_set_divisor,
.getuartclk =3D mpc512x_getuartclk,
};
#endif
@@ -564,7 +606,6 @@ mpc52xx_uart_set_termios(struct uart_por
struct mpc52xx_psc __iomem *psc =3D PSC(port);
unsigned long flags;
unsigned char mr1, mr2;
- unsigned short ctr;
unsigned int j, baud, quot;
=20
/* Prepare what we're gonna write */
@@ -604,7 +645,6 @@ mpc52xx_uart_set_termios(struct uart_por
=20
baud =3D uart_get_baud_rate(port, new, old, 0, port->uartclk/16);
quot =3D uart_get_divisor(port, baud);
- ctr =3D quot & 0xffff;
=20
/* Get the lock */
spin_lock_irqsave(&port->lock, flags);
@@ -635,8 +675,7 @@ mpc52xx_uart_set_termios(struct uart_por
out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
out_8(&psc->mode, mr1);
out_8(&psc->mode, mr2);
- out_8(&psc->ctur, ctr >> 8);
- out_8(&psc->ctlr, ctr & 0xff);
+ psc_ops->set_divisor(port, quot);
=20
if (UART_ENABLE_MS(port, new->c_cflag))
mpc52xx_uart_enable_ms(port);
@@ -1113,6 +1152,19 @@ mpc52xx_uart_of_probe(struct of_device *
=20
dev_dbg(&op->dev, "mpc52xx_uart_probe(op=3D%p, match=3D%p)\n", op, match)=
;
=20
+ /* Check only once if we are running on a mpc5200b or not */
+ if (is_mpc5200b =3D=3D -1) {
+ struct device_node *np;
+
+ np =3D of_find_compatible_node(NULL, NULL, "fsl,mpc5200b-immr");
+ if (np) {
+ is_mpc5200b =3D 1;
+ dev_dbg(&op->dev, "mpc5200b: using /4 prescaler\n");
+ of_node_put(np);
+ } else
+ is_mpc5200b =3D 0;
+ }
+
/* Check validity & presence */
for (idx =3D 0; idx < MPC52xx_PSC_MAXNUM; idx++)
if (mpc52xx_uart_nodes[idx] =3D=3D op->node)
next reply other threads:[~2010-03-01 18:11 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-03-01 18:11 Albrecht Dreß [this message]
2010-03-02 0:32 ` [Patch] mpc5200b: improve baud rate calculation (reach high baud rates, better accuracy) Wolfram Sang
2010-03-02 20:22 ` Grant Likely
-- strict thread matches above, loose matches on Subject: below --
2010-03-02 8:09 Albrecht Dreß
2010-03-02 8:28 ` Wolfram Sang
2010-03-02 8:56 ` Albrecht Dreß
2010-03-02 15:27 ` Wolfram Sang
2010-03-02 20:12 ` Grant Likely
2010-03-02 20:06 ` Grant Likely
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1267467114.2218.0@antares \
--to=albrecht.dress@arcor.de \
--cc=grant.likely@secretlab.ca \
--cc=linuxppc-dev@ozlabs.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).