serial: 8250_pci: Add F81504A series Support

Fintek F81504A/508A/512A is PCIE to 4/8/12 UARTs device. It's support
IO/MMIO/PCIE conf to access all functions. The old F81504/508/512 is
only support IO.

Signed-off-by: Ji-Ze Hong (Peter Hong) <hpeter+linux_kernel@gmail.com>
Link: https://lore.kernel.org/r/1565933249-23076-1-git-send-email-hpeter+linux_kernel@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Ji-Ze Hong (Peter Hong) 2019-08-16 13:27:29 +08:00 committed by Greg Kroah-Hartman
parent 4ad8e34d1f
commit 68e26a8d22
1 changed files with 121 additions and 0 deletions

View File

@ -43,6 +43,11 @@ struct pci_serial_quirk {
void (*exit)(struct pci_dev *dev);
};
struct f815xxa_data {
spinlock_t lock;
int idx;
};
#define PCI_NUM_BAR_RESOURCES 6
struct serial_private {
@ -1707,6 +1712,77 @@ static int pci_fintek_init(struct pci_dev *dev)
return max_port;
}
static void f815xxa_mem_serial_out(struct uart_port *p, int offset, int value)
{
struct f815xxa_data *data = p->private_data;
unsigned long flags;
spin_lock_irqsave(&data->lock, flags);
writeb(value, p->membase + offset);
readb(p->membase + UART_SCR); /* Dummy read for flush pcie tx queue */
spin_unlock_irqrestore(&data->lock, flags);
}
static int pci_fintek_f815xxa_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_8250_port *port, int idx)
{
struct pci_dev *pdev = priv->dev;
struct f815xxa_data *data;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->idx = idx;
spin_lock_init(&data->lock);
port->port.private_data = data;
port->port.iotype = UPIO_MEM;
port->port.flags |= UPF_IOREMAP;
port->port.mapbase = pci_resource_start(pdev, 0) + 8 * idx;
port->port.serial_out = f815xxa_mem_serial_out;
return 0;
}
static int pci_fintek_f815xxa_init(struct pci_dev *dev)
{
u32 max_port, i;
int config_base;
if (!(pci_resource_flags(dev, 0) & IORESOURCE_MEM))
return -ENODEV;
switch (dev->device) {
case 0x1204: /* 4 ports */
case 0x1208: /* 8 ports */
max_port = dev->device & 0xff;
break;
case 0x1212: /* 12 ports */
max_port = 12;
break;
default:
return -EINVAL;
}
/* Set to mmio decode */
pci_write_config_byte(dev, 0x209, 0x40);
for (i = 0; i < max_port; ++i) {
/* UART0 configuration offset start from 0x2A0 */
config_base = 0x2A0 + 0x08 * i;
/* Select 128-byte FIFO and 8x FIFO threshold */
pci_write_config_byte(dev, config_base + 0x01, 0x33);
/* Enable UART I/O port */
pci_write_config_byte(dev, config_base + 0, 0x01);
}
return max_port;
}
static int skip_tx_en_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_8250_port *port, int idx)
@ -2819,6 +2895,30 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID,
.setup = pci_moxa_setup,
},
{
.vendor = 0x1c29,
.device = 0x1204,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = pci_fintek_f815xxa_setup,
.init = pci_fintek_f815xxa_init,
},
{
.vendor = 0x1c29,
.device = 0x1208,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = pci_fintek_f815xxa_setup,
.init = pci_fintek_f815xxa_init,
},
{
.vendor = 0x1c29,
.device = 0x1212,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = pci_fintek_f815xxa_setup,
.init = pci_fintek_f815xxa_init,
},
/*
* Default "match everything" terminator entry
@ -3014,6 +3114,9 @@ enum pci_board_num_t {
pbn_fintek_4,
pbn_fintek_8,
pbn_fintek_12,
pbn_fintek_F81504A,
pbn_fintek_F81508A,
pbn_fintek_F81512A,
pbn_wch382_2,
pbn_wch384_4,
pbn_pericom_PI7C9X7951,
@ -3773,6 +3876,21 @@ static struct pciserial_board pci_boards[] = {
.base_baud = 115200,
.first_offset = 0x40,
},
[pbn_fintek_F81504A] = {
.num_ports = 4,
.uart_offset = 8,
.base_baud = 115200,
},
[pbn_fintek_F81508A] = {
.num_ports = 8,
.uart_offset = 8,
.base_baud = 115200,
},
[pbn_fintek_F81512A] = {
.num_ports = 12,
.uart_offset = 8,
.base_baud = 115200,
},
[pbn_wch382_2] = {
.flags = FL_BASE0,
.num_ports = 2,
@ -5719,6 +5837,9 @@ static const struct pci_device_id serial_pci_tbl[] = {
{ PCI_DEVICE(0x1c29, 0x1104), .driver_data = pbn_fintek_4 },
{ PCI_DEVICE(0x1c29, 0x1108), .driver_data = pbn_fintek_8 },
{ PCI_DEVICE(0x1c29, 0x1112), .driver_data = pbn_fintek_12 },
{ PCI_DEVICE(0x1c29, 0x1204), .driver_data = pbn_fintek_F81504A },
{ PCI_DEVICE(0x1c29, 0x1208), .driver_data = pbn_fintek_F81508A },
{ PCI_DEVICE(0x1c29, 0x1212), .driver_data = pbn_fintek_F81512A },
/* MKS Tenta SCOM-080x serial cards */
{ PCI_DEVICE(0x1601, 0x0800), .driver_data = pbn_b0_4_1250000 },