Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f549e94e authored by Andy Shevchenko's avatar Andy Shevchenko Committed by Greg Kroah-Hartman
Browse files

serial: 8250_pci: add Intel Penwell ports



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: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 2b49e0c5
Loading
Loading
Loading
Loading
+183 −0
Original line number Diff line number Diff line
@@ -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,
@@ -1987,6 +2130,27 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
		.subdevice	= PCI_ANY_ID,
		.setup		= byt_serial_setup,
	},
	{
		.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,
@@ -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,
@@ -5376,6 +5546,19 @@ static struct pci_device_id serial_pci_tbl[] = {
		PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
		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
	 */