forked from mirrors/linux
		
	[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:
		
							parent
							
								
									599f030cc5
								
							
						
					
					
						commit
						25ae3a0739
					
				
					 3 changed files with 225 additions and 12 deletions
				
			
		| 
						 | 
				
			
			@ -1114,17 +1114,17 @@ config SERIAL_SGI_L1_CONSOLE
 | 
			
		|||
		say Y.  Otherwise, say N.
 | 
			
		||||
 | 
			
		||||
config SERIAL_MPC52xx
 | 
			
		||||
	tristate "Freescale MPC52xx family PSC serial support"
 | 
			
		||||
	depends on PPC_MPC52xx
 | 
			
		||||
	tristate "Freescale MPC52xx/MPC512x family PSC serial support"
 | 
			
		||||
	depends on PPC_MPC52xx || PPC_MPC512x
 | 
			
		||||
	select SERIAL_CORE
 | 
			
		||||
	help
 | 
			
		||||
	  This drivers support the MPC52xx PSC serial ports. If you would
 | 
			
		||||
	  like to use them, you must answer Y or M to this option. Not that
 | 
			
		||||
	  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. Note that
 | 
			
		||||
	  for use as console, it must be included in kernel and not as a
 | 
			
		||||
	  module.
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
	select SERIAL_CORE_CONSOLE
 | 
			
		||||
	help
 | 
			
		||||
| 
						 | 
				
			
			@ -1132,7 +1132,7 @@ config SERIAL_MPC52xx_CONSOLE
 | 
			
		|||
	  of the Freescale MPC52xx family as a console.
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
	default "9600"
 | 
			
		||||
	help
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -190,5 +190,53 @@ struct mpc52xx_psc_fifo {
 | 
			
		|||
	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__ */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue