[PATCH 16/19] MPC5xxx/serial: add support for the MPC5125 SoC

Juergen Borleis jbe at pengutronix.de
Tue Oct 7 07:22:15 PDT 2014


Signed-off-by: Juergen Borleis <jbe at pengutronix.de>
---
 arch/ppc/mach-mpc5xxx/include/mach/mpc5xxx_psc.h |  98 ++++++++++++++
 drivers/serial/Kconfig                           |   4 +-
 drivers/serial/serial_mpc5xxx.c                  | 157 +++++++++++++++++++++++
 3 files changed, 257 insertions(+), 2 deletions(-)

diff --git a/arch/ppc/mach-mpc5xxx/include/mach/mpc5xxx_psc.h b/arch/ppc/mach-mpc5xxx/include/mach/mpc5xxx_psc.h
index a44d213..839b394 100644
--- a/arch/ppc/mach-mpc5xxx/include/mach/mpc5xxx_psc.h
+++ b/arch/ppc/mach-mpc5xxx/include/mach/mpc5xxx_psc.h
@@ -60,6 +60,7 @@
 #define PSC_MODE_ONE_STOP		0x07
 #define PSC_MODE_TWO_STOP		0x0f
 
+#ifdef CONFIG_MPC5200
 struct mpc5xxx_psc {
 	u8	mode;		/* PSC + 0x00 */
 	u8	reserved0[3];
@@ -152,3 +153,100 @@ struct mpc5xxx_psc {
 	u16	reserved31;
 	u16	tflwfptr;	/* PSC + 0x9e */
 };
+#endif
+
+#ifdef CONFIG_SOC_MPC5125
+/* PSC definition for MPC5125 */
+struct mpc5xxx_psc {
+	u8 mode;
+	u8 res0[3];
+	u8 mode2;
+	u8 res1[3];
+	u16 psc_status;
+	u8 resx[2];
+	u8 clock_select;
+	u8 res2[3];
+	u8 command;
+	u8 res3[3];
+	u32 buffer_32;
+	u8 ipcr;
+	u8 res4[3];
+	u8 acr;
+	u8 res5[3];
+	u16 isr;
+	u8 res5a[2];
+	u16 psc_imr;
+	u8 res5b[2];
+	u8 ctur;
+	u8 res6[3];
+	u8 ctlr;
+	u8 res7[3];
+	u32 ccr;
+	u32 ac97slots;
+	u32 ac97cmd;
+	u32 ac97data;
+	u8 res8[4];
+	u8 ip;
+	u8 res9[3];
+	u8 op1;
+	u8 res10[3];
+	u8 op0;
+	u8 res11[3];
+	u32 sicr;
+	u8 res12[44];
+	u32 tfcmd;
+	u32 tfalarm;
+	u32 tfstat;
+	u32 tfintstat;
+	u32 tfintmask;
+	u32 tfcount;
+	u32 tfwptr;
+	u32 tfsize;
+	u8 res13[28];
+	union {
+		u8 buffer_8;
+		u16 buffer_16;
+		u32 buffer_32;
+	} tfdata_buffer;
+#define tfdata_8 tfdata_buffer.buffer_8
+#define tfdata_16 tfdata_buffer.buffer_16
+#define tfdata_32 tfdata_buffer.buffer_32
+	u32 rfcmd;
+	u32 rfalarm;
+	u32 rfstat;
+	u32 rfintstat;
+	u32 rfintmask;
+	u32 rfcount;
+	u32 rfrptr;
+	u32 rfsize;
+	u8 res14[28];
+	union {
+		u8 buffer_8;
+		u16 buffer_16;
+		u32 buffer_32;
+	} rfdata_buffer;
+#define rfdata_8 rfdata_buffer.buffer_8
+#define rfdata_16 rfdata_buffer.buffer_16
+#define rfdata_32 rfdata_buffer.buffer_32
+};
+
+struct fifoc5125 {
+	u32 fifoc_cmd;
+	u32 fifoc_int;
+	u32 fifoc_dma;
+	u32 res1;
+	u32 fifoc_debug;
+};
+
+/* PSC FIFO Command values */
+#define PSC_FIFO_RESET_SLICE		0x80
+#define PSC_FIFO_ENABLE_SLICE		0x01
+
+/* PSC FIFO Controller Command values */
+#define FIFOC_ENABLE_CLOCK_GATE		0x01
+#define FIFOC_DISABLE_CLOCK_GATE	0x00
+
+/* PSC FIFO status */
+#define PSC_FIFO_EMPTY			0x01
+
+#endif
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 146bf1e..63c0703 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -50,9 +50,9 @@ config DRIVER_SERIAL_EFI_STDIO
 	bool "EFI stdio driver"
 
 config DRIVER_SERIAL_MPC5XXX
-	depends on MPC5200
+	depends on ARCH_MPC5XXX
 	default y
-	bool "MPC5200 serial driver"
+	bool "MPC5XXX serial driver"
 
 config DRIVER_SERIAL_BLACKFIN
 	depends on BLACKFIN
diff --git a/drivers/serial/serial_mpc5xxx.c b/drivers/serial/serial_mpc5xxx.c
index 7cd448c..670c514 100644
--- a/drivers/serial/serial_mpc5xxx.c
+++ b/drivers/serial/serial_mpc5xxx.c
@@ -39,6 +39,142 @@
 #include <mach/clocks.h>
 #include <mach/mpc5xxx_psc.h>
 
+#ifdef CONFIG_SOC_MPC5125
+
+#define MPC512x_PSC_FIFO_EMPTY (1 << 0)
+
+static struct fifoc5125 * const fifoc = (struct fifoc5125 *)MPC512X_FIFOC;
+
+struct fifo_adr_pair {
+	unsigned tsize, toffs;
+	unsigned rsize, roffs;
+};
+
+/* describe the FIFO's internal memory layout */
+static const struct fifo_adr_pair mpc5xxx_fifo_addresses[] = {
+	{
+		.tsize = 0x04, .toffs = 0x000,
+		.rsize = 0x04, .roffs = 0x010,
+	}, {
+		.tsize = 0x04, .toffs = 0x020,
+		.rsize = 0x04, .roffs = 0x030,
+	}, {
+		.tsize = 0x04, .toffs = 0x040,
+		.rsize = 0x04, .roffs = 0x050,
+	}, {
+		.tsize = 0x04, .toffs = 0x060,
+		.rsize = 0x04, .roffs = 0x070,
+	}, {
+		.tsize = 0x04, .toffs = 0x080,
+		.rsize = 0x04, .roffs = 0x090,
+	}, {
+		.tsize = 0x04, .toffs = 0x0a0,
+		.rsize = 0x04, .roffs = 0x0b0,
+	}, {
+		.tsize = 0x04, .toffs = 0x0c0,
+		.rsize = 0x04, .roffs = 0x0d0,
+	}, {
+		.tsize = 0x04, .toffs = 0x0e0,
+		.rsize = 0x04, .roffs = 0x0f0,
+	}, {
+		.tsize = 0x04, .toffs = 0x100,
+		.rsize = 0x04, .roffs = 0x110,
+	}, {
+		.tsize = 0x04, .toffs = 0x120,
+		.rsize = 0x04, .roffs = 0x130,
+	},
+};
+
+static unsigned mpc5xxx_get_psc_index(void *p)
+{
+	/* all PSC offsets differ in 0x100 steps */
+	return ((unsigned)p & 0xf00) >> 8;
+}
+
+static void mpc5xxx_fifo_init(struct mpc5xxx_psc *psc)
+{
+	unsigned idx = mpc5xxx_get_psc_index(psc);
+	u32 tfsize, rfsize;
+
+	/*
+	 * we must enable the FIFO unit's clock,
+	 * when at least one PSC unit is in use
+	 */
+	mpc5125_enable_psc_fifo_clock();
+
+	/* reset Rx & Tx fifo slice */
+	out_be32(&psc->rfcmd, PSC_FIFO_RESET_SLICE);
+	out_be32(&psc->tfcmd, PSC_FIFO_RESET_SLICE);
+
+	/* disable Tx & Rx FIFO interrupts */
+	out_be32(&psc->rfintmask, 0);
+	out_be32(&psc->tfintmask, 0);
+
+	tfsize = mpc5xxx_fifo_addresses[idx].tsize |
+			(mpc5xxx_fifo_addresses[idx].toffs << 16);
+	rfsize = mpc5xxx_fifo_addresses[idx].rsize |
+			(mpc5xxx_fifo_addresses[idx].roffs << 16);
+
+	out_be32(&psc->tfsize, tfsize);
+	out_be32(&psc->rfsize, rfsize);
+
+	/* enable Tx & Rx FIFO slice */
+	out_be32(&psc->rfcmd, PSC_FIFO_ENABLE_SLICE);
+	out_be32(&psc->tfcmd, PSC_FIFO_ENABLE_SLICE);
+
+	out_be32(&fifoc->fifoc_cmd, FIFOC_DISABLE_CLOCK_GATE);
+	__asm__ volatile ("sync");
+}
+
+static int psc_tx_rdy(struct mpc5xxx_psc *psc)
+{
+	return in_be32(&psc->tfstat) & MPC512x_PSC_FIFO_EMPTY;
+}
+
+static int psc_rx_rdy(struct mpc5xxx_psc *psc)
+{
+	return !(in_be32(&psc->rfstat) & MPC512x_PSC_FIFO_EMPTY);
+}
+
+static void psc_tx_write(struct mpc5xxx_psc *psc, char c)
+{
+	out_8(&psc->tfdata_8, c);
+}
+
+static int psc_rx_read(struct mpc5xxx_psc *psc)
+{
+	return in_8(&psc->rfdata_8);
+}
+
+static unsigned long mpc5xxx_get_base_clock(struct mpc5xxx_psc *psc)
+{
+	return (get_ips_clock() + 8) / 16;
+}
+
+static void mpc5xxx_select_clock_source(struct mpc5xxx_psc *psc)
+{
+	out_8(&psc->clock_select, 0xdd);
+}
+
+static void mpc5xxx_configure_serial_protocol(struct mpc5xxx_psc *psc)
+{
+	out_8(&psc->mode, PSC_MODE_8_BITS | PSC_MODE_PARNONE);
+	out_8(&psc->mode2, PSC_MODE_ONE_STOP);
+}
+
+static int mpc5xxx_enable_psc_unit(struct mpc5xxx_psc *psc)
+{
+	unsigned idx = mpc5xxx_get_psc_index(psc);
+
+	if (idx > ARRAY_SIZE(mpc5xxx_fifo_addresses))
+		return -ENODEV;
+
+	mpc5xxx_enable_psc_clock(idx);
+	return 0;
+}
+
+#else /* CONFIG_MPC512X */
+
 static int psc_tx_rdy(struct mpc5xxx_psc *psc)
 {
 	return in_be16(&psc->psc_status) & PSC_SR_TXEMP;
@@ -81,6 +217,11 @@ static void mpc5xxx_select_clock_source(struct mpc5xxx_psc *psc)
 #endif
 }
 
+static void mpc5xxx_fifo_init(struct mpc5xxx_psc *psc)
+{
+	/* nothing to be done here */
+}
+
 static void mpc5xxx_configure_serial_protocol(struct mpc5xxx_psc *psc)
 {
 #if defined(CONFIG_MGT5100)
@@ -93,6 +234,14 @@ static void mpc5xxx_configure_serial_protocol(struct mpc5xxx_psc *psc)
 #endif
 }
 
+static int mpc5xxx_enable_psc_unit(struct mpc5xxx_psc *psc)
+{
+	/* nothing to be done here */
+	return 0;
+}
+
+#endif /* !CONFIG_MPC512X */
+
 static int __mpc5xxx_serial_setbaudrate(struct mpc5xxx_psc *psc, int baudrate)
 {
 	unsigned long baseclk;
@@ -120,11 +269,19 @@ static int mpc5xxx_serial_setbaudrate(struct console_device *cdev, int baudrate)
 
 static int __mpc5xxx_serial_init(struct mpc5xxx_psc *psc)
 {
+	int ret;
+
+	ret = mpc5xxx_enable_psc_unit(psc);
+	if (ret != 0)
+		return ret;
+
 	/* reset PSC */
 	out_8(&psc->command, PSC_SEL_MODE_REG_1);
 
 	mpc5xxx_select_clock_source(psc);
 
+	mpc5xxx_fifo_init(psc);
+
 	/* switch to UART mode */
 	out_be32(&psc->sicr, 0);
 
-- 
2.1.0




More information about the barebox mailing list