Commit b15e5691 authored by Heikki Krogerus's avatar Heikki Krogerus Committed by Greg Kroah-Hartman
Browse files

serial: 8250_pci: add support for Intel BayTrail



Intel BayTrail has two HS-UARTs with 64 byte fifo, support
for DMA and support for 16750 compatible Auto Flow Control.

Signed-off-by: default avatarHeikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 3415097f
Loading
Loading
Loading
Loading
+145 −0
Original line number Diff line number Diff line
@@ -1324,6 +1324,120 @@ ce4100_serial_setup(struct serial_private *priv,
	return ret;
}

#define PCI_DEVICE_ID_INTEL_BYT_UART1	0x0f0a
#define PCI_DEVICE_ID_INTEL_BYT_UART2	0x0f0c

#define BYT_PRV_CLK			0x800
#define BYT_PRV_CLK_EN			(1 << 0)
#define BYT_PRV_CLK_M_VAL_SHIFT		1
#define BYT_PRV_CLK_N_VAL_SHIFT		16
#define BYT_PRV_CLK_UPDATE		(1 << 31)

#define BYT_GENERAL_REG			0x808
#define BYT_GENERAL_DIS_RTS_N_OVERRIDE	(1 << 3)

#define BYT_TX_OVF_INT			0x820
#define BYT_TX_OVF_INT_MASK		(1 << 1)

static void
byt_set_termios(struct uart_port *p, struct ktermios *termios,
		struct ktermios *old)
{
	unsigned int baud = tty_termios_baud_rate(termios);
	unsigned int m = 6912;
	unsigned int n = 15625;
	u32 reg;

	/* For baud rates 1M, 2M, 3M and 4M the dividers must be adjusted. */
	if (baud == 1000000 || baud == 2000000 || baud == 4000000) {
		m = 64;
		n = 100;

		p->uartclk = 64000000;
	} else if (baud == 3000000) {
		m = 48;
		n = 100;

		p->uartclk = 48000000;
	} else {
		p->uartclk = 44236800;
	}

	/* Reset the clock */
	reg = (m << BYT_PRV_CLK_M_VAL_SHIFT) | (n << BYT_PRV_CLK_N_VAL_SHIFT);
	writel(reg, p->membase + BYT_PRV_CLK);
	reg |= BYT_PRV_CLK_EN | BYT_PRV_CLK_UPDATE;
	writel(reg, p->membase + BYT_PRV_CLK);

	/*
	 * If auto-handshake mechanism is not enabled,
	 * disable rts_n override
	 */
	reg = readl(p->membase + BYT_GENERAL_REG);
	reg &= ~BYT_GENERAL_DIS_RTS_N_OVERRIDE;
	if (termios->c_cflag & CRTSCTS)
		reg |= BYT_GENERAL_DIS_RTS_N_OVERRIDE;
	writel(reg, p->membase + BYT_GENERAL_REG);

	serial8250_do_set_termios(p, termios, old);
}

static bool byt_dma_filter(struct dma_chan *chan, void *param)
{
	return chan->chan_id == *(int *)param;
}

static int
byt_serial_setup(struct serial_private *priv,
		 const struct pciserial_board *board,
		 struct uart_8250_port *port, int idx)
{
	struct uart_8250_dma *dma;
	int ret;

	dma = devm_kzalloc(port->port.dev, sizeof(*dma), GFP_KERNEL);
	if (!dma)
		return -ENOMEM;

	switch (priv->dev->device) {
	case PCI_DEVICE_ID_INTEL_BYT_UART1:
		dma->rx_chan_id = 3;
		dma->tx_chan_id = 2;
		break;
	case PCI_DEVICE_ID_INTEL_BYT_UART2:
		dma->rx_chan_id = 5;
		dma->tx_chan_id = 4;
		break;
	default:
		return -EINVAL;
	}

	dma->rxconf.slave_id = dma->rx_chan_id;
	dma->rxconf.src_maxburst = 16;

	dma->txconf.slave_id = dma->tx_chan_id;
	dma->txconf.dst_maxburst = 16;

	dma->fn = byt_dma_filter;
	dma->rx_param = &dma->rx_chan_id;
	dma->tx_param = &dma->tx_chan_id;

	ret = pci_default_setup(priv, board, port, idx);
	port->port.iotype = UPIO_MEM;
	port->port.type = PORT_16550A;
	port->port.flags = (port->port.flags | UPF_FIXED_PORT | UPF_FIXED_TYPE);
	port->port.set_termios = byt_set_termios;
	port->port.fifosize = 64;
	port->tx_loadsz = 64;
	port->dma = dma;
	port->capabilities = UART_CAP_FIFO | UART_CAP_AFE;

	/* Disable Tx counter interrupts */
	writel(BYT_TX_OVF_INT_MASK, port->port.membase + BYT_TX_OVF_INT);

	return ret;
}

static int
pci_omegapci_setup(struct serial_private *priv,
		      const struct pciserial_board *board,
@@ -1662,6 +1776,20 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
		.subdevice	= PCI_ANY_ID,
		.setup		= kt_serial_setup,
	},
	{
		.vendor		= PCI_VENDOR_ID_INTEL,
		.device		= PCI_DEVICE_ID_INTEL_BYT_UART1,
		.subvendor	= PCI_ANY_ID,
		.subdevice	= PCI_ANY_ID,
		.setup		= byt_serial_setup,
	},
	{
		.vendor		= PCI_VENDOR_ID_INTEL,
		.device		= PCI_DEVICE_ID_INTEL_BYT_UART2,
		.subvendor	= PCI_ANY_ID,
		.subdevice	= PCI_ANY_ID,
		.setup		= byt_serial_setup,
	},
	/*
	 * ITE
	 */
@@ -2449,6 +2577,7 @@ enum pci_board_num_t {
	pbn_ADDIDATA_PCIe_4_3906250,
	pbn_ADDIDATA_PCIe_8_3906250,
	pbn_ce4100_1_115200,
	pbn_byt,
	pbn_omegapci,
	pbn_NETMOS9900_2s_115200,
	pbn_brcm_trumanage,
@@ -3185,6 +3314,13 @@ static struct pciserial_board pci_boards[] = {
		.base_baud	= 921600,
		.reg_shift      = 2,
	},
	[pbn_byt] = {
		.flags		= FL_BASE0,
		.num_ports	= 1,
		.base_baud	= 2764800,
		.uart_offset	= 0x80,
		.reg_shift      = 2,
	},
	[pbn_omegapci] = {
		.flags		= FL_BASE0,
		.num_ports	= 8,
@@ -4846,6 +4982,15 @@ static struct pci_device_id serial_pci_tbl[] = {
	{	PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CE4100_UART,
		PCI_ANY_ID,  PCI_ANY_ID, 0, 0,
		pbn_ce4100_1_115200 },
	/* Intel BayTrail */
	{	PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_UART1,
		PCI_ANY_ID,  PCI_ANY_ID,
		PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
		pbn_byt },
	{	PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_UART2,
		PCI_ANY_ID,  PCI_ANY_ID,
		PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
		pbn_byt },

	/*
	 * Cronyx Omega PCI