|
@@ -16,6 +16,9 @@
|
|
|
* Some of the code has been inspired/copied from the 2.4 code written
|
|
|
* by Dale Farnsworth <dfarnsworth@mvista.com>.
|
|
|
*
|
|
|
+ * Copyright (C) 2008 Freescale Semiconductor Inc.
|
|
|
+ * John Rigby <jrigby@gmail.com>
|
|
|
+ * Added support for MPC5121
|
|
|
* Copyright (C) 2006 Secret Lab Technologies Ltd.
|
|
|
* Grant Likely <grant.likely@secretlab.ca>
|
|
|
* Copyright (C) 2004-2006 Sylvain Munaut <tnt@246tNt.com>
|
|
@@ -78,6 +81,7 @@
|
|
|
#endif
|
|
|
|
|
|
#include <asm/mpc52xx.h>
|
|
|
+#include <asm/mpc512x.h>
|
|
|
#include <asm/mpc52xx_psc.h>
|
|
|
|
|
|
#if defined(CONFIG_SERIAL_MPC52xx_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
|
|
@@ -129,13 +133,29 @@ static irqreturn_t mpc52xx_uart_int(int irq, void *dev_id);
|
|
|
|
|
|
#if defined(CONFIG_PPC_MERGE)
|
|
|
static struct of_device_id mpc52xx_uart_of_match[] = {
|
|
|
- { .type = "serial", .compatible = "fsl,mpc5200-psc-uart", },
|
|
|
- { .type = "serial", .compatible = "mpc5200-psc-uart", }, /* lite5200 */
|
|
|
- { .type = "serial", .compatible = "mpc5200-serial", }, /* efika */
|
|
|
+#ifdef CONFIG_PPC_MPC52xx
|
|
|
+ { .compatible = "fsl,mpc5200-psc-uart", .data = &mpc52xx_psc_ops, },
|
|
|
+ /* binding used by old lite5200 device trees: */
|
|
|
+ { .compatible = "mpc5200-psc-uart", .data = &mpc52xx_psc_ops, },
|
|
|
+ /* binding used by efika: */
|
|
|
+ { .compatible = "mpc5200-serial", .data = &mpc52xx_psc_ops, },
|
|
|
+#endif
|
|
|
+#ifdef CONFIG_PPC_MPC512x
|
|
|
+ { .compatible = "fsl,mpc5121-psc-uart", .data = &mpc512x_psc_ops, },
|
|
|
+ {},
|
|
|
+#endif
|
|
|
+};
|
|
|
+#if defined(CONFIG_PPC_MERGE)
|
|
|
+static const struct of_device_id mpc52xx_uart_of_match[] = {
|
|
|
+ {.type = "serial",
|
|
|
+ .compatible = "mpc5200-psc-uart",
|
|
|
+#endif
|
|
|
{},
|
|
|
};
|
|
|
#endif
|
|
|
|
|
|
+#endif
|
|
|
+
|
|
|
/* ======================================================================== */
|
|
|
/* PSC fifo operations for isolating differences between 52xx and 512x */
|
|
|
/* ======================================================================== */
|
|
@@ -159,6 +179,7 @@ struct psc_ops {
|
|
|
unsigned long (*getuartclk)(void *p);
|
|
|
};
|
|
|
|
|
|
+#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)
|
|
|
{
|
|
@@ -291,7 +312,145 @@ static struct psc_ops mpc52xx_psc_ops = {
|
|
|
.getuartclk = mpc52xx_getuartclk,
|
|
|
};
|
|
|
|
|
|
-static struct psc_ops *psc_ops = &mpc52xx_psc_ops;
|
|
|
+#endif /* CONFIG_MPC52xx */
|
|
|
+
|
|
|
+#ifdef CONFIG_PPC_MPC512x
|
|
|
+#define FIFO_512x(port) ((struct mpc512x_psc_fifo __iomem *)(PSC(port)+1))
|
|
|
+static void mpc512x_psc_fifo_init(struct uart_port *port)
|
|
|
+{
|
|
|
+ out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_RESET_SLICE);
|
|
|
+ out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_ENABLE_SLICE);
|
|
|
+ out_be32(&FIFO_512x(port)->txalarm, 1);
|
|
|
+ out_be32(&FIFO_512x(port)->tximr, 0);
|
|
|
+
|
|
|
+ out_be32(&FIFO_512x(port)->rxcmd, MPC512x_PSC_FIFO_RESET_SLICE);
|
|
|
+ out_be32(&FIFO_512x(port)->rxcmd, MPC512x_PSC_FIFO_ENABLE_SLICE);
|
|
|
+ out_be32(&FIFO_512x(port)->rxalarm, 1);
|
|
|
+ out_be32(&FIFO_512x(port)->rximr, 0);
|
|
|
+
|
|
|
+ out_be32(&FIFO_512x(port)->tximr, MPC512x_PSC_FIFO_ALARM);
|
|
|
+ out_be32(&FIFO_512x(port)->rximr, MPC512x_PSC_FIFO_ALARM);
|
|
|
+}
|
|
|
+
|
|
|
+static int mpc512x_psc_raw_rx_rdy(struct uart_port *port)
|
|
|
+{
|
|
|
+ return !(in_be32(&FIFO_512x(port)->rxsr) & MPC512x_PSC_FIFO_EMPTY);
|
|
|
+}
|
|
|
+
|
|
|
+static int mpc512x_psc_raw_tx_rdy(struct uart_port *port)
|
|
|
+{
|
|
|
+ return !(in_be32(&FIFO_512x(port)->txsr) & MPC512x_PSC_FIFO_FULL);
|
|
|
+}
|
|
|
+
|
|
|
+static int mpc512x_psc_rx_rdy(struct uart_port *port)
|
|
|
+{
|
|
|
+ return in_be32(&FIFO_512x(port)->rxsr)
|
|
|
+ & in_be32(&FIFO_512x(port)->rximr)
|
|
|
+ & MPC512x_PSC_FIFO_ALARM;
|
|
|
+}
|
|
|
+
|
|
|
+static int mpc512x_psc_tx_rdy(struct uart_port *port)
|
|
|
+{
|
|
|
+ return in_be32(&FIFO_512x(port)->txsr)
|
|
|
+ & in_be32(&FIFO_512x(port)->tximr)
|
|
|
+ & MPC512x_PSC_FIFO_ALARM;
|
|
|
+}
|
|
|
+
|
|
|
+static int mpc512x_psc_tx_empty(struct uart_port *port)
|
|
|
+{
|
|
|
+ return in_be32(&FIFO_512x(port)->txsr)
|
|
|
+ & MPC512x_PSC_FIFO_EMPTY;
|
|
|
+}
|
|
|
+
|
|
|
+static void mpc512x_psc_stop_rx(struct uart_port *port)
|
|
|
+{
|
|
|
+ unsigned long rx_fifo_imr;
|
|
|
+
|
|
|
+ rx_fifo_imr = in_be32(&FIFO_512x(port)->rximr);
|
|
|
+ rx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM;
|
|
|
+ out_be32(&FIFO_512x(port)->rximr, rx_fifo_imr);
|
|
|
+}
|
|
|
+
|
|
|
+static void mpc512x_psc_start_tx(struct uart_port *port)
|
|
|
+{
|
|
|
+ unsigned long tx_fifo_imr;
|
|
|
+
|
|
|
+ tx_fifo_imr = in_be32(&FIFO_512x(port)->tximr);
|
|
|
+ tx_fifo_imr |= MPC512x_PSC_FIFO_ALARM;
|
|
|
+ out_be32(&FIFO_512x(port)->tximr, tx_fifo_imr);
|
|
|
+}
|
|
|
+
|
|
|
+static void mpc512x_psc_stop_tx(struct uart_port *port)
|
|
|
+{
|
|
|
+ unsigned long tx_fifo_imr;
|
|
|
+
|
|
|
+ tx_fifo_imr = in_be32(&FIFO_512x(port)->tximr);
|
|
|
+ tx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM;
|
|
|
+ out_be32(&FIFO_512x(port)->tximr, tx_fifo_imr);
|
|
|
+}
|
|
|
+
|
|
|
+static void mpc512x_psc_rx_clr_irq(struct uart_port *port)
|
|
|
+{
|
|
|
+ out_be32(&FIFO_512x(port)->rxisr, in_be32(&FIFO_512x(port)->rxisr));
|
|
|
+}
|
|
|
+
|
|
|
+static void mpc512x_psc_tx_clr_irq(struct uart_port *port)
|
|
|
+{
|
|
|
+ out_be32(&FIFO_512x(port)->txisr, in_be32(&FIFO_512x(port)->txisr));
|
|
|
+}
|
|
|
+
|
|
|
+static void mpc512x_psc_write_char(struct uart_port *port, unsigned char c)
|
|
|
+{
|
|
|
+ out_8(&FIFO_512x(port)->txdata_8, c);
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned char mpc512x_psc_read_char(struct uart_port *port)
|
|
|
+{
|
|
|
+ return in_8(&FIFO_512x(port)->rxdata_8);
|
|
|
+}
|
|
|
+
|
|
|
+static void mpc512x_psc_cw_disable_ints(struct uart_port *port)
|
|
|
+{
|
|
|
+ port->read_status_mask =
|
|
|
+ in_be32(&FIFO_512x(port)->tximr) << 16 |
|
|
|
+ in_be32(&FIFO_512x(port)->rximr);
|
|
|
+ out_be32(&FIFO_512x(port)->tximr, 0);
|
|
|
+ out_be32(&FIFO_512x(port)->rximr, 0);
|
|
|
+}
|
|
|
+
|
|
|
+static void mpc512x_psc_cw_restore_ints(struct uart_port *port)
|
|
|
+{
|
|
|
+ out_be32(&FIFO_512x(port)->tximr,
|
|
|
+ (port->read_status_mask >> 16) & 0x7f);
|
|
|
+ out_be32(&FIFO_512x(port)->rximr, port->read_status_mask & 0x7f);
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned long mpc512x_getuartclk(void *p)
|
|
|
+{
|
|
|
+ return mpc512x_find_ips_freq(p);
|
|
|
+}
|
|
|
+
|
|
|
+static struct psc_ops mpc512x_psc_ops = {
|
|
|
+ .fifo_init = mpc512x_psc_fifo_init,
|
|
|
+ .raw_rx_rdy = mpc512x_psc_raw_rx_rdy,
|
|
|
+ .raw_tx_rdy = mpc512x_psc_raw_tx_rdy,
|
|
|
+ .rx_rdy = mpc512x_psc_rx_rdy,
|
|
|
+ .tx_rdy = mpc512x_psc_tx_rdy,
|
|
|
+ .tx_empty = mpc512x_psc_tx_empty,
|
|
|
+ .stop_rx = mpc512x_psc_stop_rx,
|
|
|
+ .start_tx = mpc512x_psc_start_tx,
|
|
|
+ .stop_tx = mpc512x_psc_stop_tx,
|
|
|
+ .rx_clr_irq = mpc512x_psc_rx_clr_irq,
|
|
|
+ .tx_clr_irq = mpc512x_psc_tx_clr_irq,
|
|
|
+ .write_char = mpc512x_psc_write_char,
|
|
|
+ .read_char = mpc512x_psc_read_char,
|
|
|
+ .cw_disable_ints = mpc512x_psc_cw_disable_ints,
|
|
|
+ .cw_restore_ints = mpc512x_psc_cw_restore_ints,
|
|
|
+ .getuartclk = mpc512x_getuartclk,
|
|
|
+};
|
|
|
+#endif
|
|
|
+
|
|
|
+static struct psc_ops *psc_ops;
|
|
|
|
|
|
/* ======================================================================== */
|
|
|
/* UART operations */
|
|
@@ -381,7 +540,8 @@ mpc52xx_uart_startup(struct uart_port *port)
|
|
|
|
|
|
/* Request IRQ */
|
|
|
ret = request_irq(port->irq, mpc52xx_uart_int,
|
|
|
- IRQF_DISABLED | IRQF_SAMPLE_RANDOM, "mpc52xx_psc_uart", port);
|
|
|
+ IRQF_DISABLED | IRQF_SAMPLE_RANDOM | IRQF_SHARED,
|
|
|
+ "mpc52xx_psc_uart", port);
|
|
|
if (ret)
|
|
|
return ret;
|
|
|
|
|
@@ -1208,15 +1368,19 @@ mpc52xx_uart_of_enumerate(void)
|
|
|
static int enum_done;
|
|
|
struct device_node *np;
|
|
|
const unsigned int *devno;
|
|
|
+ const struct of_device_id *match;
|
|
|
int i;
|
|
|
|
|
|
if (enum_done)
|
|
|
return;
|
|
|
|
|
|
for_each_node_by_type(np, "serial") {
|
|
|
- if (!of_match_node(mpc52xx_uart_of_match, np))
|
|
|
+ match = of_match_node(mpc52xx_uart_of_match, np);
|
|
|
+ if (!match)
|
|
|
continue;
|
|
|
|
|
|
+ psc_ops = match->data;
|
|
|
+
|
|
|
/* Is a particular device number requested? */
|
|
|
devno = of_get_property(np, "port-number", NULL);
|
|
|
mpc52xx_uart_of_assign(np, devno ? *devno : -1);
|
|
@@ -1277,6 +1441,7 @@ mpc52xx_uart_init(void)
|
|
|
return ret;
|
|
|
}
|
|
|
#else
|
|
|
+ psc_ops = &mpc52xx_psc_ops;
|
|
|
ret = platform_driver_register(&mpc52xx_uart_platform_driver);
|
|
|
if (ret) {
|
|
|
printk(KERN_ERR "%s: platform_driver_register failed (%i)\n",
|