[POWERPC] mpc512x: Add MPC512x PSC support to MPC52xx psc driver

Add 512x support using the psc_ops framework established
with the previous patch.

All 512x PSCs share the same interrupt so add
IRQF_SHARED to irq flags.

Signed-off-by: John Rigby <jrigby@freescale.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
This commit is contained in:
John Rigby 2008-01-29 04:28:56 +11:00 committed by Grant Likely
parent 599f030cc5
commit 25ae3a0739
3 changed files with 225 additions and 12 deletions

View file

@ -1114,17 +1114,17 @@ config SERIAL_SGI_L1_CONSOLE
say Y. Otherwise, say N. say Y. Otherwise, say N.
config SERIAL_MPC52xx config SERIAL_MPC52xx
tristate "Freescale MPC52xx family PSC serial support" tristate "Freescale MPC52xx/MPC512x family PSC serial support"
depends on PPC_MPC52xx depends on PPC_MPC52xx || PPC_MPC512x
select SERIAL_CORE select SERIAL_CORE
help help
This drivers support the MPC52xx PSC serial ports. If you would This driver supports MPC52xx and MPC512x PSC serial ports. If you would
like to use them, you must answer Y or M to this option. Not that like to use them, you must answer Y or M to this option. Note that
for use as console, it must be included in kernel and not as a for use as console, it must be included in kernel and not as a
module. module.
config SERIAL_MPC52xx_CONSOLE config SERIAL_MPC52xx_CONSOLE
bool "Console on a Freescale MPC52xx family PSC serial port" bool "Console on a Freescale MPC52xx/MPC512x family PSC serial port"
depends on SERIAL_MPC52xx=y depends on SERIAL_MPC52xx=y
select SERIAL_CORE_CONSOLE select SERIAL_CORE_CONSOLE
help help
@ -1132,7 +1132,7 @@ config SERIAL_MPC52xx_CONSOLE
of the Freescale MPC52xx family as a console. of the Freescale MPC52xx family as a console.
config SERIAL_MPC52xx_CONSOLE_BAUD config SERIAL_MPC52xx_CONSOLE_BAUD
int "Freescale MPC52xx family PSC serial port baud" int "Freescale MPC52xx/MPC512x family PSC serial port baud"
depends on SERIAL_MPC52xx_CONSOLE=y depends on SERIAL_MPC52xx_CONSOLE=y
default "9600" default "9600"
help help

View file

@ -16,6 +16,9 @@
* Some of the code has been inspired/copied from the 2.4 code written * Some of the code has been inspired/copied from the 2.4 code written
* by Dale Farnsworth <dfarnsworth@mvista.com>. * 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. * Copyright (C) 2006 Secret Lab Technologies Ltd.
* Grant Likely <grant.likely@secretlab.ca> * Grant Likely <grant.likely@secretlab.ca>
* Copyright (C) 2004-2006 Sylvain Munaut <tnt@246tNt.com> * Copyright (C) 2004-2006 Sylvain Munaut <tnt@246tNt.com>
@ -78,6 +81,7 @@
#endif #endif
#include <asm/mpc52xx.h> #include <asm/mpc52xx.h>
#include <asm/mpc512x.h>
#include <asm/mpc52xx_psc.h> #include <asm/mpc52xx_psc.h>
#if defined(CONFIG_SERIAL_MPC52xx_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #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) #if defined(CONFIG_PPC_MERGE)
static struct of_device_id mpc52xx_uart_of_match[] = { static struct of_device_id mpc52xx_uart_of_match[] = {
{ .type = "serial", .compatible = "fsl,mpc5200-psc-uart", }, #ifdef CONFIG_PPC_MPC52xx
{ .type = "serial", .compatible = "mpc5200-psc-uart", }, /* lite5200 */ { .compatible = "fsl,mpc5200-psc-uart", .data = &mpc52xx_psc_ops, },
{ .type = "serial", .compatible = "mpc5200-serial", }, /* efika */ /* 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
#endif
/* ======================================================================== */ /* ======================================================================== */
/* PSC fifo operations for isolating differences between 52xx and 512x */ /* PSC fifo operations for isolating differences between 52xx and 512x */
/* ======================================================================== */ /* ======================================================================== */
@ -159,6 +179,7 @@ struct psc_ops {
unsigned long (*getuartclk)(void *p); unsigned long (*getuartclk)(void *p);
}; };
#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)
{ {
@ -291,7 +312,145 @@ static struct psc_ops mpc52xx_psc_ops = {
.getuartclk = mpc52xx_getuartclk, .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 */ /* UART operations */
@ -381,7 +540,8 @@ mpc52xx_uart_startup(struct uart_port *port)
/* Request IRQ */ /* Request IRQ */
ret = request_irq(port->irq, mpc52xx_uart_int, 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) if (ret)
return ret; return ret;
@ -1208,15 +1368,19 @@ mpc52xx_uart_of_enumerate(void)
static int enum_done; static int enum_done;
struct device_node *np; struct device_node *np;
const unsigned int *devno; const unsigned int *devno;
const struct of_device_id *match;
int i; int i;
if (enum_done) if (enum_done)
return; return;
for_each_node_by_type(np, "serial") { 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; continue;
psc_ops = match->data;
/* Is a particular device number requested? */ /* Is a particular device number requested? */
devno = of_get_property(np, "port-number", NULL); devno = of_get_property(np, "port-number", NULL);
mpc52xx_uart_of_assign(np, devno ? *devno : -1); mpc52xx_uart_of_assign(np, devno ? *devno : -1);
@ -1277,6 +1441,7 @@ mpc52xx_uart_init(void)
return ret; return ret;
} }
#else #else
psc_ops = &mpc52xx_psc_ops;
ret = platform_driver_register(&mpc52xx_uart_platform_driver); ret = platform_driver_register(&mpc52xx_uart_platform_driver);
if (ret) { if (ret) {
printk(KERN_ERR "%s: platform_driver_register failed (%i)\n", printk(KERN_ERR "%s: platform_driver_register failed (%i)\n",

View file

@ -190,5 +190,53 @@ struct mpc52xx_psc_fifo {
u16 tflwfptr; /* PSC + 0x9e */ u16 tflwfptr; /* PSC + 0x9e */
}; };
#define MPC512x_PSC_FIFO_RESET_SLICE 0x80
#define MPC512x_PSC_FIFO_ENABLE_SLICE 0x01
#define MPC512x_PSC_FIFO_ENABLE_DMA 0x04
#define MPC512x_PSC_FIFO_EMPTY 0x1
#define MPC512x_PSC_FIFO_FULL 0x2
#define MPC512x_PSC_FIFO_ALARM 0x4
#define MPC512x_PSC_FIFO_URERR 0x8
#define MPC512x_PSC_FIFO_ORERR 0x01
#define MPC512x_PSC_FIFO_MEMERROR 0x02
struct mpc512x_psc_fifo {
u32 reserved1[10];
u32 txcmd; /* PSC + 0x80 */
u32 txalarm; /* PSC + 0x84 */
u32 txsr; /* PSC + 0x88 */
u32 txisr; /* PSC + 0x8c */
u32 tximr; /* PSC + 0x90 */
u32 txcnt; /* PSC + 0x94 */
u32 txptr; /* PSC + 0x98 */
u32 txsz; /* PSC + 0x9c */
u32 reserved2[7];
union {
u8 txdata_8;
u16 txdata_16;
u32 txdata_32;
} txdata; /* PSC + 0xbc */
#define txdata_8 txdata.txdata_8
#define txdata_16 txdata.txdata_16
#define txdata_32 txdata.txdata_32
u32 rxcmd; /* PSC + 0xc0 */
u32 rxalarm; /* PSC + 0xc4 */
u32 rxsr; /* PSC + 0xc8 */
u32 rxisr; /* PSC + 0xcc */
u32 rximr; /* PSC + 0xd0 */
u32 rxcnt; /* PSC + 0xd4 */
u32 rxptr; /* PSC + 0xd8 */
u32 rxsz; /* PSC + 0xdc */
u32 reserved3[7];
union {
u8 rxdata_8;
u16 rxdata_16;
u32 rxdata_32;
} rxdata; /* PSC + 0xfc */
#define rxdata_8 rxdata.rxdata_8
#define rxdata_16 rxdata.rxdata_16
#define rxdata_32 rxdata.rxdata_32
};
#endif /* __ASM_MPC52xx_PSC_H__ */ #endif /* __ASM_MPC52xx_PSC_H__ */