lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Wed, 29 Sep 2021 17:00:47 +0530
From:   LakshmiPraveen Kopparthi <LakshmiPraveen.Kopparthi@...rochip.com>
To:     <gregkh@...uxfoundation.org>, <jirislaby@...nel.org>,
        <andriy.shevchenko@...ux.intel.com>, <macro@...am.me.uk>,
        <zev@...ilderbeest.net>, <vigneshr@...com>,
        <linux-serial@...r.kernel.org>, <linux-kernel@...r.kernel.org>
CC:     <UNGLinuxDriver@...rochip.com>
Subject: [PATCH v1 1/3] serial:8250:Add basic driver support for MCHP PCI1XXXX UART

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@...rochip.com>
---
 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

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ