Skip to content

Commit

Permalink
serial: 8250_pci: add Intel Penwell ports
Browse files Browse the repository at this point in the history
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@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Andy Shevchenko authored and Greg Kroah-Hartman committed Mar 7, 2015
1 parent 2b49e0c commit f549e94
Showing 1 changed file with 183 additions and 0 deletions.
183 changes: 183 additions & 0 deletions drivers/tty/serial/8250/8250_pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
*/
Expand Down

0 comments on commit f549e94

Please sign in to comment.