Commit 68e26a8d authored by Ji-Ze Hong (Peter Hong)'s avatar Ji-Ze Hong (Peter Hong) Committed by Greg Kroah-Hartman
Browse files

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: default avatarJi-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: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 4ad8e34d
Loading
Loading
Loading
Loading
+121 −0
Original line number Diff line number Diff line
@@ -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 },