|
@@ -113,7 +113,9 @@ struct psc_ops {
|
|
unsigned char (*read_char)(struct uart_port *port);
|
|
unsigned char (*read_char)(struct uart_port *port);
|
|
void (*cw_disable_ints)(struct uart_port *port);
|
|
void (*cw_disable_ints)(struct uart_port *port);
|
|
void (*cw_restore_ints)(struct uart_port *port);
|
|
void (*cw_restore_ints)(struct uart_port *port);
|
|
- unsigned long (*getuartclk)(void *p);
|
|
|
|
|
|
+ unsigned int (*set_baudrate)(struct uart_port *port,
|
|
|
|
+ struct ktermios *new,
|
|
|
|
+ struct ktermios *old);
|
|
int (*clock)(struct uart_port *port, int enable);
|
|
int (*clock)(struct uart_port *port, int enable);
|
|
int (*fifoc_init)(void);
|
|
int (*fifoc_init)(void);
|
|
void (*fifoc_uninit)(void);
|
|
void (*fifoc_uninit)(void);
|
|
@@ -121,6 +123,16 @@ struct psc_ops {
|
|
irqreturn_t (*handle_irq)(struct uart_port *port);
|
|
irqreturn_t (*handle_irq)(struct uart_port *port);
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+/* setting the prescaler and divisor reg is common for all chips */
|
|
|
|
+static inline void mpc52xx_set_divisor(struct mpc52xx_psc __iomem *psc,
|
|
|
|
+ u16 prescaler, unsigned int divisor)
|
|
|
|
+{
|
|
|
|
+ /* select prescaler */
|
|
|
|
+ out_be16(&psc->mpc52xx_psc_clock_select, prescaler);
|
|
|
|
+ out_8(&psc->ctur, divisor >> 8);
|
|
|
|
+ out_8(&psc->ctlr, divisor & 0xff);
|
|
|
|
+}
|
|
|
|
+
|
|
#ifdef CONFIG_PPC_MPC52xx
|
|
#ifdef CONFIG_PPC_MPC52xx
|
|
#define FIFO_52xx(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1))
|
|
#define FIFO_52xx(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1))
|
|
static void mpc52xx_psc_fifo_init(struct uart_port *port)
|
|
static void mpc52xx_psc_fifo_init(struct uart_port *port)
|
|
@@ -128,9 +140,6 @@ static void mpc52xx_psc_fifo_init(struct uart_port *port)
|
|
struct mpc52xx_psc __iomem *psc = PSC(port);
|
|
struct mpc52xx_psc __iomem *psc = PSC(port);
|
|
struct mpc52xx_psc_fifo __iomem *fifo = FIFO_52xx(port);
|
|
struct mpc52xx_psc_fifo __iomem *fifo = FIFO_52xx(port);
|
|
|
|
|
|
- /* /32 prescaler */
|
|
|
|
- out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00);
|
|
|
|
-
|
|
|
|
out_8(&fifo->rfcntl, 0x00);
|
|
out_8(&fifo->rfcntl, 0x00);
|
|
out_be16(&fifo->rfalarm, 0x1ff);
|
|
out_be16(&fifo->rfalarm, 0x1ff);
|
|
out_8(&fifo->tfcntl, 0x07);
|
|
out_8(&fifo->tfcntl, 0x07);
|
|
@@ -219,15 +228,47 @@ static void mpc52xx_psc_cw_restore_ints(struct uart_port *port)
|
|
out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
|
|
out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
|
|
}
|
|
}
|
|
|
|
|
|
-/* Search for bus-frequency property in this node or a parent */
|
|
|
|
-static unsigned long mpc52xx_getuartclk(void *p)
|
|
|
|
|
|
+static unsigned int mpc5200_psc_set_baudrate(struct uart_port *port,
|
|
|
|
+ struct ktermios *new,
|
|
|
|
+ struct ktermios *old)
|
|
{
|
|
{
|
|
- /*
|
|
|
|
- * 5200 UARTs have a / 32 prescaler
|
|
|
|
- * but the generic serial code assumes 16
|
|
|
|
- * so return ipb freq / 2
|
|
|
|
- */
|
|
|
|
- return mpc5xxx_get_bus_frequency(p) / 2;
|
|
|
|
|
|
+ unsigned int baud;
|
|
|
|
+ unsigned int divisor;
|
|
|
|
+
|
|
|
|
+ /* The 5200 has a fixed /32 prescaler, uartclk contains the ipb freq */
|
|
|
|
+ baud = uart_get_baud_rate(port, new, old,
|
|
|
|
+ port->uartclk / (32 * 0xffff) + 1,
|
|
|
|
+ port->uartclk / 32);
|
|
|
|
+ divisor = (port->uartclk + 16 * baud) / (32 * baud);
|
|
|
|
+
|
|
|
|
+ /* enable the /32 prescaler and set the divisor */
|
|
|
|
+ mpc52xx_set_divisor(PSC(port), 0xdd00, divisor);
|
|
|
|
+ return baud;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static unsigned int mpc5200b_psc_set_baudrate(struct uart_port *port,
|
|
|
|
+ struct ktermios *new,
|
|
|
|
+ struct ktermios *old)
|
|
|
|
+{
|
|
|
|
+ unsigned int baud;
|
|
|
|
+ unsigned int divisor;
|
|
|
|
+ u16 prescaler;
|
|
|
|
+
|
|
|
|
+ /* The 5200B has a selectable /4 or /32 prescaler, uartclk contains the
|
|
|
|
+ * ipb freq */
|
|
|
|
+ baud = uart_get_baud_rate(port, new, old,
|
|
|
|
+ port->uartclk / (32 * 0xffff) + 1,
|
|
|
|
+ port->uartclk / 4);
|
|
|
|
+ divisor = (port->uartclk + 2 * baud) / (4 * baud);
|
|
|
|
+
|
|
|
|
+ /* select the proper prescaler and set the divisor */
|
|
|
|
+ if (divisor > 0xffff) {
|
|
|
|
+ divisor = (divisor + 4) / 8;
|
|
|
|
+ prescaler = 0xdd00; /* /32 */
|
|
|
|
+ } else
|
|
|
|
+ prescaler = 0xff00; /* /4 */
|
|
|
|
+ mpc52xx_set_divisor(PSC(port), prescaler, divisor);
|
|
|
|
+ return baud;
|
|
}
|
|
}
|
|
|
|
|
|
static void mpc52xx_psc_get_irq(struct uart_port *port, struct device_node *np)
|
|
static void mpc52xx_psc_get_irq(struct uart_port *port, struct device_node *np)
|
|
@@ -258,7 +299,28 @@ static struct psc_ops mpc52xx_psc_ops = {
|
|
.read_char = mpc52xx_psc_read_char,
|
|
.read_char = mpc52xx_psc_read_char,
|
|
.cw_disable_ints = mpc52xx_psc_cw_disable_ints,
|
|
.cw_disable_ints = mpc52xx_psc_cw_disable_ints,
|
|
.cw_restore_ints = mpc52xx_psc_cw_restore_ints,
|
|
.cw_restore_ints = mpc52xx_psc_cw_restore_ints,
|
|
- .getuartclk = mpc52xx_getuartclk,
|
|
|
|
|
|
+ .set_baudrate = mpc5200_psc_set_baudrate,
|
|
|
|
+ .get_irq = mpc52xx_psc_get_irq,
|
|
|
|
+ .handle_irq = mpc52xx_psc_handle_irq,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static struct psc_ops mpc5200b_psc_ops = {
|
|
|
|
+ .fifo_init = mpc52xx_psc_fifo_init,
|
|
|
|
+ .raw_rx_rdy = mpc52xx_psc_raw_rx_rdy,
|
|
|
|
+ .raw_tx_rdy = mpc52xx_psc_raw_tx_rdy,
|
|
|
|
+ .rx_rdy = mpc52xx_psc_rx_rdy,
|
|
|
|
+ .tx_rdy = mpc52xx_psc_tx_rdy,
|
|
|
|
+ .tx_empty = mpc52xx_psc_tx_empty,
|
|
|
|
+ .stop_rx = mpc52xx_psc_stop_rx,
|
|
|
|
+ .start_tx = mpc52xx_psc_start_tx,
|
|
|
|
+ .stop_tx = mpc52xx_psc_stop_tx,
|
|
|
|
+ .rx_clr_irq = mpc52xx_psc_rx_clr_irq,
|
|
|
|
+ .tx_clr_irq = mpc52xx_psc_tx_clr_irq,
|
|
|
|
+ .write_char = mpc52xx_psc_write_char,
|
|
|
|
+ .read_char = mpc52xx_psc_read_char,
|
|
|
|
+ .cw_disable_ints = mpc52xx_psc_cw_disable_ints,
|
|
|
|
+ .cw_restore_ints = mpc52xx_psc_cw_restore_ints,
|
|
|
|
+ .set_baudrate = mpc5200b_psc_set_baudrate,
|
|
.get_irq = mpc52xx_psc_get_irq,
|
|
.get_irq = mpc52xx_psc_get_irq,
|
|
.handle_irq = mpc52xx_psc_handle_irq,
|
|
.handle_irq = mpc52xx_psc_handle_irq,
|
|
};
|
|
};
|
|
@@ -392,9 +454,35 @@ static void mpc512x_psc_cw_restore_ints(struct uart_port *port)
|
|
out_be32(&FIFO_512x(port)->rximr, port->read_status_mask & 0x7f);
|
|
out_be32(&FIFO_512x(port)->rximr, port->read_status_mask & 0x7f);
|
|
}
|
|
}
|
|
|
|
|
|
-static unsigned long mpc512x_getuartclk(void *p)
|
|
|
|
|
|
+static unsigned int mpc512x_psc_set_baudrate(struct uart_port *port,
|
|
|
|
+ struct ktermios *new,
|
|
|
|
+ struct ktermios *old)
|
|
{
|
|
{
|
|
- return mpc5xxx_get_bus_frequency(p);
|
|
|
|
|
|
+ unsigned int baud;
|
|
|
|
+ unsigned int divisor;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * The "MPC5121e Microcontroller Reference Manual, Rev. 3" says on
|
|
|
|
+ * pg. 30-10 that the chip supports a /32 and a /10 prescaler.
|
|
|
|
+ * Furthermore, it states that "After reset, the prescaler by 10
|
|
|
|
+ * for the UART mode is selected", but the reset register value is
|
|
|
|
+ * 0x0000 which means a /32 prescaler. This is wrong.
|
|
|
|
+ *
|
|
|
|
+ * In reality using /32 prescaler doesn't work, as it is not supported!
|
|
|
|
+ * Use /16 or /10 prescaler, see "MPC5121e Hardware Design Guide",
|
|
|
|
+ * Chapter 4.1 PSC in UART Mode.
|
|
|
|
+ * Calculate with a /16 prescaler here.
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ /* uartclk contains the ips freq */
|
|
|
|
+ baud = uart_get_baud_rate(port, new, old,
|
|
|
|
+ port->uartclk / (16 * 0xffff) + 1,
|
|
|
|
+ port->uartclk / 16);
|
|
|
|
+ divisor = (port->uartclk + 8 * baud) / (16 * baud);
|
|
|
|
+
|
|
|
|
+ /* enable the /16 prescaler and set the divisor */
|
|
|
|
+ mpc52xx_set_divisor(PSC(port), 0xdd00, divisor);
|
|
|
|
+ return baud;
|
|
}
|
|
}
|
|
|
|
|
|
/* Init PSC FIFO Controller */
|
|
/* Init PSC FIFO Controller */
|
|
@@ -498,7 +586,7 @@ static struct psc_ops mpc512x_psc_ops = {
|
|
.read_char = mpc512x_psc_read_char,
|
|
.read_char = mpc512x_psc_read_char,
|
|
.cw_disable_ints = mpc512x_psc_cw_disable_ints,
|
|
.cw_disable_ints = mpc512x_psc_cw_disable_ints,
|
|
.cw_restore_ints = mpc512x_psc_cw_restore_ints,
|
|
.cw_restore_ints = mpc512x_psc_cw_restore_ints,
|
|
- .getuartclk = mpc512x_getuartclk,
|
|
|
|
|
|
+ .set_baudrate = mpc512x_psc_set_baudrate,
|
|
.clock = mpc512x_psc_clock,
|
|
.clock = mpc512x_psc_clock,
|
|
.fifoc_init = mpc512x_psc_fifoc_init,
|
|
.fifoc_init = mpc512x_psc_fifoc_init,
|
|
.fifoc_uninit = mpc512x_psc_fifoc_uninit,
|
|
.fifoc_uninit = mpc512x_psc_fifoc_uninit,
|
|
@@ -666,8 +754,8 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
|
|
struct mpc52xx_psc __iomem *psc = PSC(port);
|
|
struct mpc52xx_psc __iomem *psc = PSC(port);
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
unsigned char mr1, mr2;
|
|
unsigned char mr1, mr2;
|
|
- unsigned short ctr;
|
|
|
|
- unsigned int j, baud, quot;
|
|
|
|
|
|
+ unsigned int j;
|
|
|
|
+ unsigned int baud;
|
|
|
|
|
|
/* Prepare what we're gonna write */
|
|
/* Prepare what we're gonna write */
|
|
mr1 = 0;
|
|
mr1 = 0;
|
|
@@ -704,16 +792,9 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
|
|
mr2 |= MPC52xx_PSC_MODE_TXCTS;
|
|
mr2 |= MPC52xx_PSC_MODE_TXCTS;
|
|
}
|
|
}
|
|
|
|
|
|
- baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16);
|
|
|
|
- quot = uart_get_divisor(port, baud);
|
|
|
|
- ctr = quot & 0xffff;
|
|
|
|
-
|
|
|
|
/* Get the lock */
|
|
/* Get the lock */
|
|
spin_lock_irqsave(&port->lock, flags);
|
|
spin_lock_irqsave(&port->lock, flags);
|
|
|
|
|
|
- /* Update the per-port timeout */
|
|
|
|
- uart_update_timeout(port, new->c_cflag, baud);
|
|
|
|
-
|
|
|
|
/* Do our best to flush TX & RX, so we don't lose anything */
|
|
/* Do our best to flush TX & RX, so we don't lose anything */
|
|
/* But we don't wait indefinitely ! */
|
|
/* But we don't wait indefinitely ! */
|
|
j = 5000000; /* Maximum wait */
|
|
j = 5000000; /* Maximum wait */
|
|
@@ -737,8 +818,10 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
|
|
out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
|
|
out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
|
|
out_8(&psc->mode, mr1);
|
|
out_8(&psc->mode, mr1);
|
|
out_8(&psc->mode, mr2);
|
|
out_8(&psc->mode, mr2);
|
|
- out_8(&psc->ctur, ctr >> 8);
|
|
|
|
- out_8(&psc->ctlr, ctr & 0xff);
|
|
|
|
|
|
+ baud = psc_ops->set_baudrate(port, new, old);
|
|
|
|
+
|
|
|
|
+ /* Update the per-port timeout */
|
|
|
|
+ uart_update_timeout(port, new->c_cflag, baud);
|
|
|
|
|
|
if (UART_ENABLE_MS(port, new->c_cflag))
|
|
if (UART_ENABLE_MS(port, new->c_cflag))
|
|
mpc52xx_uart_enable_ms(port);
|
|
mpc52xx_uart_enable_ms(port);
|
|
@@ -1118,7 +1201,7 @@ mpc52xx_console_setup(struct console *co, char *options)
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
- uartclk = psc_ops->getuartclk(np);
|
|
|
|
|
|
+ uartclk = mpc5xxx_get_bus_frequency(np);
|
|
if (uartclk == 0) {
|
|
if (uartclk == 0) {
|
|
pr_debug("Could not find uart clock frequency!\n");
|
|
pr_debug("Could not find uart clock frequency!\n");
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
@@ -1201,6 +1284,7 @@ static struct uart_driver mpc52xx_uart_driver = {
|
|
|
|
|
|
static struct of_device_id mpc52xx_uart_of_match[] = {
|
|
static struct of_device_id mpc52xx_uart_of_match[] = {
|
|
#ifdef CONFIG_PPC_MPC52xx
|
|
#ifdef CONFIG_PPC_MPC52xx
|
|
|
|
+ { .compatible = "fsl,mpc5200b-psc-uart", .data = &mpc5200b_psc_ops, },
|
|
{ .compatible = "fsl,mpc5200-psc-uart", .data = &mpc52xx_psc_ops, },
|
|
{ .compatible = "fsl,mpc5200-psc-uart", .data = &mpc52xx_psc_ops, },
|
|
/* binding used by old lite5200 device trees: */
|
|
/* binding used by old lite5200 device trees: */
|
|
{ .compatible = "mpc5200-psc-uart", .data = &mpc52xx_psc_ops, },
|
|
{ .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)
|
|
pr_debug("Found %s assigned to ttyPSC%x\n",
|
|
pr_debug("Found %s assigned to ttyPSC%x\n",
|
|
mpc52xx_uart_nodes[idx]->full_name, idx);
|
|
mpc52xx_uart_nodes[idx]->full_name, idx);
|
|
|
|
|
|
- uartclk = psc_ops->getuartclk(op->dev.of_node);
|
|
|
|
|
|
+ /* set the uart clock to the input clock of the psc, the different
|
|
|
|
+ * prescalers are taken into account in the set_baudrate() methods
|
|
|
|
+ * of the respective chip */
|
|
|
|
+ uartclk = mpc5xxx_get_bus_frequency(op->dev.of_node);
|
|
if (uartclk == 0) {
|
|
if (uartclk == 0) {
|
|
dev_dbg(&op->dev, "Could not find uart clock frequency!\n");
|
|
dev_dbg(&op->dev, "Could not find uart clock frequency!\n");
|
|
return -EINVAL;
|
|
return -EINVAL;
|