[PATCH v1 1/3] serial:8250:Add basic driver support for MCHP PCI1XXXX UART

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch adds the support to enumerate the UART ports for all the
combinations and writes the necessary port specific registers to
initialise the UART ports.In addition to that, writes to the module
registers are added in the init and exit callbacks to support the
suspend and resume functionality.

This patch adds the wakeup feature support.Each UART port has three
wakeup sources and this patch handles the suspend and wakeup
sequence.

Signed-off-by: LakshmiPraveen Kopparthi <LakshmiPraveen.Kopparthi@xxxxxxxxxxxxx>
---
 drivers/tty/serial/8250/8250_pci.c  | 298 ++++++++++++++++++++++++++++
 drivers/tty/serial/8250/8250_port.c |   8 +
 include/uapi/linux/serial_core.h    |   3 +
 3 files changed, 309 insertions(+)

diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 93159557a2fb..12a3e0bd50aa 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -58,6 +58,13 @@ struct serial_private {
 
 #define PCI_DEVICE_ID_HPE_PCI_SERIAL	0x37e
 
+#define PCI_VENDOR_ID_MCHP_PCI1XXXX	0x1055
+#define PCI_DEVICE_ID_MCHP_PCI12000	0xA002
+#define PCI_DEVICE_ID_MCHP_PCI11010	0xA012
+#define PCI_DEVICE_ID_MCHP_PCI11101	0xA022
+#define PCI_DEVICE_ID_MCHP_PCI11400	0xA032
+#define PCI_DEVICE_ID_MCHP_PCI11414	0xA042
+
 static const struct pci_device_id pci_use_msi[] = {
 	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900,
 			 0xA000, 0x1000) },
@@ -67,6 +74,16 @@ static const struct pci_device_id pci_use_msi[] = {
 			 0xA000, 0x1000) },
 	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_HP_3PAR, PCI_DEVICE_ID_HPE_PCI_SERIAL,
 			 PCI_ANY_ID, PCI_ANY_ID) },
+	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_MCHP_PCI1XXXX,
+			PCI_DEVICE_ID_MCHP_PCI12000, PCI_ANY_ID, PCI_ANY_ID) },
+	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_MCHP_PCI1XXXX,
+			PCI_DEVICE_ID_MCHP_PCI11101, PCI_ANY_ID, PCI_ANY_ID) },
+	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_MCHP_PCI1XXXX,
+			PCI_DEVICE_ID_MCHP_PCI11010, PCI_ANY_ID, PCI_ANY_ID) },
+	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_MCHP_PCI1XXXX,
+			PCI_DEVICE_ID_MCHP_PCI11400, PCI_ANY_ID, PCI_ANY_ID) },
+	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_MCHP_PCI1XXXX,
+			PCI_DEVICE_ID_MCHP_PCI11414, PCI_ANY_ID, PCI_ANY_ID) },
 	{ }
 };
 
@@ -1853,6 +1870,218 @@ pci_moxa_setup(struct serial_private *priv,
 	return setup_port(priv, port, bar, offset, 0);
 }
 
+#define PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_4P	0x0001
+#define PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_3P012	0x0002
+#define PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_3P013	0x0003
+#define PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_3P023	0x0004
+#define PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_3P123	0x0005
+#define PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_2P01	0x0006
+#define PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_2P02	0x0007
+#define PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_2P03	0x0008
+#define PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_2P12	0x0009
+#define PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_2P13	0x000A
+#define PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_2P23	0x000B
+#define PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_1P0	0x000C
+#define PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_1P1	0x000D
+#define PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_1P2	0x000E
+#define PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_1P3	0x000F
+
+#define UART_ACTV_REG 0x11
+#define UART_PCI_CTRL_REG 0x80
+#define UART_WAKE_REG 0x8C
+#define UART_WAKE_MASK_REG 0x90
+#define UART_RESET_REG 0x94
+
+static char pci1xxxx_port_suspend(int line)
+{
+	struct uart_8250_port *up = serial8250_get_port(line);
+	struct uart_port *port = &up->port;
+	unsigned long flags;
+	u8 wakeup_mask;
+	char ret = 0;
+
+	if (port->suspended == 0 && port->dev) {
+		wakeup_mask = readb(up->port.membase + UART_WAKE_MASK_REG);
+
+		spin_lock_irqsave(&port->lock, flags);
+		port->mctrl &= ~TIOCM_OUT2;
+		port->ops->set_mctrl(port, port->mctrl);
+		spin_unlock_irqrestore(&port->lock, flags);
+
+		if ((wakeup_mask & 0x01) == 0x00)
+			ret = 0x01;
+		else
+			ret = 0x00;
+	}
+	writeb(0x07, port->membase + UART_WAKE_REG);
+	return ret;
+}
+
+void pci1xxxx_port_resume(int line)
+{
+	struct uart_8250_port *up = serial8250_get_port(line);
+	struct uart_port *port = &up->port;
+	unsigned long flags;
+
+	writeb(0x07, port->membase + UART_WAKE_REG);
+	if (port->suspended == 0) {
+		spin_lock_irqsave(&port->lock, flags);
+		port->mctrl |= TIOCM_OUT2;
+		port->ops->set_mctrl(port, port->mctrl);
+		spin_unlock_irqrestore(&port->lock, flags);
+	}
+}
+
+static int mchp_pci1xxxx_init(struct pci_dev *dev)
+{
+	struct serial_private *priv = pci_get_drvdata(dev);
+	unsigned int data;
+	void __iomem *p;
+	int rc = 0;
+	int i;
+
+	switch (dev->subsystem_device) {
+	case PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_1P0:
+	case PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_1P1:
+	case PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_1P2:
+	case PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_1P3:
+		rc = 1;
+		break;
+	case PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_2P01:
+	case PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_2P02:
+	case PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_2P03:
+	case PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_2P12:
+	case PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_2P13:
+	case PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_2P23:
+		rc = 2;
+		break;
+	case PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_3P012:
+	case PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_3P123:
+	case PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_3P013:
+	case PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_3P023:
+		rc = 3;
+		break;
+	case PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_4P:
+		rc = 4;
+		break;
+	}
+
+	if (!IS_ERR_OR_NULL(priv)) {
+		for (i = 0; i < priv->nr; i++) {
+			if (priv->line[i] >= 0)
+				pci1xxxx_port_resume(priv->line[i]);
+		}
+	}
+
+	p = pci_ioremap_bar(dev, 0);
+	if (p) {
+		data = readl(p + UART_RESET_REG);
+		writel(data & (~(0x01 << 16)),
+		       p + UART_RESET_REG);
+
+		writeb(0x00, (p + UART_PCI_CTRL_REG));
+
+		iounmap(p);
+	} else {
+		moan_device("remapping of bar 0 memory failed", dev);
+		return -ENOMEM;
+	}
+	return rc;
+}
+
+static void mchp_pci1xxxx_exit(struct pci_dev *dev)
+{
+	struct serial_private *priv = pci_get_drvdata(dev);
+	unsigned int data;
+	void __iomem *p;
+	char wakeup = 0;
+	int i;
+
+	if (!IS_ERR_OR_NULL(priv)) {
+		for (i = 0; i < priv->nr; i++) {
+			if (priv->line[i] >= 0)
+				wakeup |= pci1xxxx_port_suspend(priv->line[i]);
+		}
+	}
+	p = pci_ioremap_bar(dev, 0);
+	if (p) {
+		data = readl(p + UART_RESET_REG);
+		writel(data | (0x01 << 16),
+		       p + UART_RESET_REG);
+
+		if (wakeup & 0x01)
+			writeb(0x01, (p + UART_PCI_CTRL_REG));
+		iounmap(p);
+	} else {
+		moan_device("remapping of bar 0 memory failed", dev);
+	}
+}
+
+static int mchp_pci1xxxx_setup(struct serial_private *priv,
+			       const struct pciserial_board *board,
+			       struct uart_8250_port *port, int idx)
+{
+	unsigned int bar = FL_GET_BASE(board->flags);
+	int first_offset = 0;
+	int offset;
+	int ret;
+
+	switch (priv->dev->subsystem_device) {
+	case PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_1P1:
+		first_offset = 256;
+		break;
+	case PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_1P2:
+		first_offset = 512;
+		break;
+	case PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_1P3:
+		first_offset = 768;
+		break;
+	case PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_2P02:
+		if (idx > 0)
+			idx++;
+		break;
+	case PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_2P03:
+		if (idx > 0)
+			idx += 2;
+		break;
+	case PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_2P12:
+		first_offset = 256;
+		if (idx > 0)
+			idx++;
+		break;
+	case PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_2P13:
+		first_offset = 256;
+		if (idx > 0)
+			idx++;
+		break;
+	case PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_2P23:
+		first_offset = 512;
+		break;
+	case PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_3P123:
+		first_offset = 256;
+		break;
+	case PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_3P013:
+		if (idx > 1)
+			idx++;
+		break;
+	case PCI_SUBDEVICE_ID_MCHP_PCI1XXXX_3P023:
+		if (idx > 0)
+			idx++;
+		break;
+	}
+
+	offset = first_offset + idx * board->uart_offset;
+	port->port.flags |= UPF_FIXED_TYPE | UPF_SKIP_TEST;
+	port->port.type = PORT_MCHP16550A;
+	ret = setup_port(priv, port, bar, offset, board->reg_shift);
+	if (ret < 0)
+		return ret;
+
+	writeb(0x07, port->port.membase + UART_WAKE_REG);
+	writeb(0x01, (port->port.membase + UART_ACTV_REG));
+	return 0;
+}
+
 #define PCI_VENDOR_ID_SBSMODULARIO	0x124B
 #define PCI_SUBVENDOR_ID_SBSMODULARIO	0x124B
 #define PCI_DEVICE_ID_OCTPRO		0x0001
@@ -2778,6 +3007,51 @@ static struct pci_serial_quirk pci_serial_quirks[] = {
 		.setup		= pci_fintek_f815xxa_setup,
 		.init		= pci_fintek_f815xxa_init,
 	},
+	{
+		.vendor         = PCI_VENDOR_ID_MCHP_PCI1XXXX,
+		.device         = PCI_DEVICE_ID_MCHP_PCI12000,
+		.subvendor      = PCI_ANY_ID,
+		.subdevice      = PCI_ANY_ID,
+		.setup          = mchp_pci1xxxx_setup,
+		.init		 = mchp_pci1xxxx_init,
+		.exit		 = mchp_pci1xxxx_exit,
+	},
+	{
+		.vendor         = PCI_VENDOR_ID_MCHP_PCI1XXXX,
+		.device         = PCI_DEVICE_ID_MCHP_PCI11010,
+		.subvendor      = PCI_ANY_ID,
+		.subdevice      = PCI_ANY_ID,
+		.setup          = mchp_pci1xxxx_setup,
+		.init		 = mchp_pci1xxxx_init,
+		.exit		 = mchp_pci1xxxx_exit,
+	},
+	{
+		.vendor         = PCI_VENDOR_ID_MCHP_PCI1XXXX,
+		.device         = PCI_DEVICE_ID_MCHP_PCI11101,
+		.subvendor      = PCI_ANY_ID,
+		.subdevice      = PCI_ANY_ID,
+		.setup          = mchp_pci1xxxx_setup,
+		.init		 = mchp_pci1xxxx_init,
+		.exit		 = mchp_pci1xxxx_exit,
+	},
+	{
+		.vendor         = PCI_VENDOR_ID_MCHP_PCI1XXXX,
+		.device         = PCI_DEVICE_ID_MCHP_PCI11400,
+		.subvendor      = PCI_ANY_ID,
+		.subdevice      = PCI_ANY_ID,
+		.setup          = mchp_pci1xxxx_setup,
+		.init		 = mchp_pci1xxxx_init,
+		.exit		 = mchp_pci1xxxx_exit,
+	},
+	{
+		.vendor         = PCI_VENDOR_ID_MCHP_PCI1XXXX,
+		.device         = PCI_DEVICE_ID_MCHP_PCI11414,
+		.subvendor      = PCI_ANY_ID,
+		.subdevice      = PCI_ANY_ID,
+		.setup          = mchp_pci1xxxx_setup,
+		.init		 = mchp_pci1xxxx_init,
+		.exit		 = mchp_pci1xxxx_exit,
+	},
 
 	/*
 	 * Default "match everything" terminator entry
@@ -2979,6 +3253,7 @@ enum pci_board_num_t {
 	pbn_moxa8250_2p,
 	pbn_moxa8250_4p,
 	pbn_moxa8250_8p,
+	pbn_mchp_pci1xxxx,
 };
 
 /*
@@ -3809,6 +4084,13 @@ static struct pciserial_board pci_boards[] = {
 		.base_baud      = 921600,
 		.uart_offset	= 0x200,
 	},
+	[pbn_mchp_pci1xxxx] = {
+		.flags		= FL_BASE0,
+		.num_ports      = 1,
+		.base_baud      = 3000000,
+		.uart_offset	= 256,
+		.first_offset	= 0,
+	},
 };
 
 static const struct pci_device_id blacklist[] = {
@@ -5698,6 +5980,22 @@ static const struct pci_device_id serial_pci_tbl[] = {
 	/* Amazon PCI serial device */
 	{ PCI_DEVICE(0x1d0f, 0x8250), .driver_data = pbn_b0_1_115200 },
 
+	/* Microchip PCI to serial interface */
+	{PCI_VENDOR_ID_MCHP_PCI1XXXX, PCI_DEVICE_ID_MCHP_PCI11010,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0, pbn_mchp_pci1xxxx },
+	{PCI_VENDOR_ID_MCHP_PCI1XXXX, PCI_DEVICE_ID_MCHP_PCI11101,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0, pbn_mchp_pci1xxxx },
+	{PCI_VENDOR_ID_MCHP_PCI1XXXX, PCI_DEVICE_ID_MCHP_PCI11400,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0, pbn_mchp_pci1xxxx },
+	{PCI_VENDOR_ID_MCHP_PCI1XXXX, PCI_DEVICE_ID_MCHP_PCI11414,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0, pbn_mchp_pci1xxxx },
+	{PCI_VENDOR_ID_MCHP_PCI1XXXX, PCI_DEVICE_ID_MCHP_PCI12000,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0, pbn_mchp_pci1xxxx },
 	/*
 	 * These entries match devices with class COMMUNICATION_SERIAL,
 	 * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 66374704747e..6a7936f52d9a 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -307,6 +307,14 @@ static const struct serial8250_config uart_config[] = {
 		.rxtrig_bytes	= {1, 32, 64, 112},
 		.flags		= UART_CAP_FIFO | UART_CAP_SLEEP,
 	},
+	[PORT_MCHP16550A] = {
+		.name		= "MCHP16550A",
+		.fifo_size	= 256,
+		.tx_loadsz	= 256,
+		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01,
+		.rxtrig_bytes	= {2, 66, 130, 194},
+		.flags		= UART_CAP_FIFO,
+	},
 };
 
 /* Uart divisor latch read */
diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
index c4042dcfdc0c..21f73b42c46f 100644
--- a/include/uapi/linux/serial_core.h
+++ b/include/uapi/linux/serial_core.h
@@ -274,4 +274,7 @@
 /* Freescale LINFlexD UART */
 #define PORT_LINFLEXUART	122
 
+/* MCHP 16550A UART with 256 byte FIFOs */
+#define PORT_MCHP16550A 123
+
 #endif /* _UAPILINUX_SERIAL_CORE_H */
-- 
2.25.1




[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux PPP]     [Linux FS]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Linmodem]     [Device Mapper]     [Linux Kernel for ARM]

  Powered by Linux