[PATCH v1 2/3] serial: 8250_pci: add Intel Penwell ports

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

 



Intel Penwell supports 3 HSUART ports which are 8250 compatible. The patch adds
necessary bits to the driver.

The functions have intel_mid_* prefix due to more than one platform will use
this code.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@xxxxxxxxxxxxxxx>
---
 drivers/tty/serial/8250/8250_pci.c | 183 +++++++++++++++++++++++++++++++++++++
 1 file changed, 183 insertions(+)

diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index daf2c82..9204d0f 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -27,6 +27,7 @@
 
 #include <linux/dmaengine.h>
 #include <linux/platform_data/dma-dw.h>
+#include <linux/platform_data/dma-hsu.h>
 
 #include "8250.h"
 
@@ -1525,6 +1526,148 @@ byt_serial_setup(struct serial_private *priv,
 	return ret;
 }
 
+#define INTEL_MID_UART_PS		0x30
+#define INTEL_MID_UART_MUL		0x34
+
+static void intel_mid_set_termios_50M(struct uart_port *p,
+				      struct ktermios *termios,
+				      struct ktermios *old)
+{
+	unsigned int baud = tty_termios_baud_rate(termios);
+	u32 ps, mul;
+
+	/*
+	 * The uart clk is 50Mhz, and the baud rate come from:
+	 *      baud = 50M * MUL / (DIV * PS * DLAB)
+	 *
+	 * For those basic low baud rate we can get the direct
+	 * scalar from 2746800, like 115200 = 2746800/24. For those
+	 * higher baud rate, we handle them case by case, mainly by
+	 * adjusting the MUL/PS registers, and DIV register is kept
+	 * as default value 0x3d09 to make things simple.
+	 */
+
+	ps = 0x10;
+
+	switch (baud) {
+	case 500000:
+	case 1000000:
+	case 1500000:
+	case 3000000:
+		mul = 0x3a98;
+		p->uartclk = 48000000;
+		break;
+	case 2000000:
+	case 4000000:
+		mul = 0x2710;
+		ps = 0x08;
+		p->uartclk = 64000000;
+		break;
+	case 2500000:
+		mul = 0x30d4;
+		p->uartclk = 40000000;
+		break;
+	case 3500000:
+		mul = 0x3345;
+		ps = 0x0c;
+		p->uartclk = 56000000;
+		break;
+	default:
+		mul = 0x2400;
+		p->uartclk = 29491200;
+	}
+
+	writel(ps, p->membase + INTEL_MID_UART_PS);		/* set PS */
+	writel(mul, p->membase + INTEL_MID_UART_MUL);		/* set MUL */
+
+	serial8250_do_set_termios(p, termios, old);
+}
+
+static bool intel_mid_dma_filter(struct dma_chan *chan, void *param)
+{
+	struct hsu_dma_slave *s = param;
+
+	if (s->dma_dev != chan->device->dev || s->chan_id != chan->chan_id)
+		return false;
+
+	chan->private = s;
+	return true;
+}
+
+static int intel_mid_serial_setup(struct serial_private *priv,
+				  const struct pciserial_board *board,
+				  struct uart_8250_port *port, int idx,
+				  int index, struct pci_dev *dma_dev)
+{
+	struct device *dev = port->port.dev;
+	struct uart_8250_dma *dma;
+	struct hsu_dma_slave *tx_param, *rx_param;
+
+	dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
+	if (!dma)
+		return -ENOMEM;
+
+	tx_param = devm_kzalloc(dev, sizeof(*tx_param), GFP_KERNEL);
+	if (!tx_param)
+		return -ENOMEM;
+
+	rx_param = devm_kzalloc(dev, sizeof(*rx_param), GFP_KERNEL);
+	if (!rx_param)
+		return -ENOMEM;
+
+	rx_param->chan_id = index * 2 + 1;
+	tx_param->chan_id = index * 2;
+
+	dma->rxconf.src_maxburst = 64;
+	dma->txconf.dst_maxburst = 64;
+
+	rx_param->dma_dev = &dma_dev->dev;
+	tx_param->dma_dev = &dma_dev->dev;
+
+	dma->fn = intel_mid_dma_filter;
+	dma->rx_param = rx_param;
+	dma->tx_param = tx_param;
+
+	port->port.type = PORT_16750;
+	port->port.flags |= UPF_FIXED_PORT | UPF_FIXED_TYPE;
+	port->dma = dma;
+
+	return pci_default_setup(priv, board, port, idx);
+}
+
+#define PCI_DEVICE_ID_INTEL_PNW_UART1	0x081b
+#define PCI_DEVICE_ID_INTEL_PNW_UART2	0x081c
+#define PCI_DEVICE_ID_INTEL_PNW_UART3	0x081d
+
+static int pnw_serial_setup(struct serial_private *priv,
+			    const struct pciserial_board *board,
+			    struct uart_8250_port *port, int idx)
+{
+	struct pci_dev *pdev = priv->dev;
+	struct pci_dev *dma_dev;
+	int index;
+
+	switch (pdev->device) {
+	case PCI_DEVICE_ID_INTEL_PNW_UART1:
+		index = 0;
+		break;
+	case PCI_DEVICE_ID_INTEL_PNW_UART2:
+		index = 1;
+		break;
+	case PCI_DEVICE_ID_INTEL_PNW_UART3:
+		index = 2;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	dma_dev = pci_get_slot(pdev->bus, PCI_DEVFN(PCI_SLOT(pdev->devfn), 3));
+
+	port->port.set_termios = intel_mid_set_termios_50M;
+
+	return intel_mid_serial_setup(priv, board, port, idx, index, dma_dev);
+}
+
 static int
 pci_omegapci_setup(struct serial_private *priv,
 		      const struct pciserial_board *board,
@@ -1989,6 +2132,27 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
 	},
 	{
 		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_PNW_UART1,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.setup		= pnw_serial_setup,
+	},
+	{
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_PNW_UART2,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.setup		= pnw_serial_setup,
+	},
+	{
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_PNW_UART3,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.setup		= pnw_serial_setup,
+	},
+	{
+		.vendor		= PCI_VENDOR_ID_INTEL,
 		.device		= PCI_DEVICE_ID_INTEL_QRK_UART,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
@@ -2878,6 +3042,7 @@ enum pci_board_num_t {
 	pbn_ADDIDATA_PCIe_8_3906250,
 	pbn_ce4100_1_115200,
 	pbn_byt,
+	pbn_pnw,
 	pbn_qrk,
 	pbn_omegapci,
 	pbn_NETMOS9900_2s_115200,
@@ -3644,6 +3809,11 @@ static struct pciserial_board pci_boards[] = {
 		.uart_offset	= 0x80,
 		.reg_shift      = 2,
 	},
+	[pbn_pnw] = {
+		.flags		= FL_BASE0,
+		.num_ports	= 1,
+		.base_baud	= 115200,
+	},
 	[pbn_qrk] = {
 		.flags		= FL_BASE0,
 		.num_ports	= 1,
@@ -5377,6 +5547,19 @@ static struct pci_device_id serial_pci_tbl[] = {
 		pbn_byt },
 
 	/*
+	 * Intel Penwell
+	 */
+	{	PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PNW_UART1,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pnw},
+	{	PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PNW_UART2,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pnw},
+	{	PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PNW_UART3,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pnw},
+
+	/*
 	 * Intel Quark x1000
 	 */
 	{	PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_QRK_UART,
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-serial" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[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