| .. | .. |
|---|
| 19 | 19 | #include <linux/string.h> |
|---|
| 20 | 20 | #include <linux/tty.h> |
|---|
| 21 | 21 | #include <linux/8250_pci.h> |
|---|
| 22 | +#include <linux/delay.h> |
|---|
| 22 | 23 | |
|---|
| 23 | 24 | #include <asm/byteorder.h> |
|---|
| 24 | 25 | |
|---|
| 25 | 26 | #include "8250.h" |
|---|
| 26 | 27 | |
|---|
| 27 | | -#define PCI_DEVICE_ID_ACCES_COM_2S 0x1052 |
|---|
| 28 | | -#define PCI_DEVICE_ID_ACCES_COM_4S 0x105d |
|---|
| 29 | | -#define PCI_DEVICE_ID_ACCES_COM_8S 0x106c |
|---|
| 30 | | -#define PCI_DEVICE_ID_ACCES_COM232_8 0x10a8 |
|---|
| 31 | | -#define PCI_DEVICE_ID_ACCES_COM_2SM 0x10d2 |
|---|
| 32 | | -#define PCI_DEVICE_ID_ACCES_COM_4SM 0x10db |
|---|
| 33 | | -#define PCI_DEVICE_ID_ACCES_COM_8SM 0x10ea |
|---|
| 28 | +#define PCI_DEVICE_ID_ACCESSIO_COM_2S 0x1052 |
|---|
| 29 | +#define PCI_DEVICE_ID_ACCESSIO_COM_4S 0x105d |
|---|
| 30 | +#define PCI_DEVICE_ID_ACCESSIO_COM_8S 0x106c |
|---|
| 31 | +#define PCI_DEVICE_ID_ACCESSIO_COM232_8 0x10a8 |
|---|
| 32 | +#define PCI_DEVICE_ID_ACCESSIO_COM_2SM 0x10d2 |
|---|
| 33 | +#define PCI_DEVICE_ID_ACCESSIO_COM_4SM 0x10db |
|---|
| 34 | +#define PCI_DEVICE_ID_ACCESSIO_COM_8SM 0x10ea |
|---|
| 34 | 35 | |
|---|
| 35 | 36 | #define PCI_DEVICE_ID_COMMTECH_4224PCI335 0x0002 |
|---|
| 36 | 37 | #define PCI_DEVICE_ID_COMMTECH_4222PCI335 0x0004 |
|---|
| .. | .. |
|---|
| 44 | 45 | |
|---|
| 45 | 46 | #define UART_EXAR_INT0 0x80 |
|---|
| 46 | 47 | #define UART_EXAR_8XMODE 0x88 /* 8X sampling rate select */ |
|---|
| 48 | +#define UART_EXAR_SLEEP 0x8b /* Sleep mode */ |
|---|
| 49 | +#define UART_EXAR_DVID 0x8d /* Device identification */ |
|---|
| 47 | 50 | |
|---|
| 48 | 51 | #define UART_EXAR_FCTR 0x08 /* Feature Control Register */ |
|---|
| 49 | 52 | #define UART_FCTR_EXAR_IRDA 0x10 /* IrDa data encode select */ |
|---|
| .. | .. |
|---|
| 132 | 135 | unsigned int nr; |
|---|
| 133 | 136 | struct exar8250_board *board; |
|---|
| 134 | 137 | void __iomem *virt; |
|---|
| 135 | | - int line[0]; |
|---|
| 138 | + int line[]; |
|---|
| 136 | 139 | }; |
|---|
| 140 | + |
|---|
| 141 | +static void exar_pm(struct uart_port *port, unsigned int state, unsigned int old) |
|---|
| 142 | +{ |
|---|
| 143 | + /* |
|---|
| 144 | + * Exar UARTs have a SLEEP register that enables or disables each UART |
|---|
| 145 | + * to enter sleep mode separately. On the XR17V35x the register |
|---|
| 146 | + * is accessible to each UART at the UART_EXAR_SLEEP offset, but |
|---|
| 147 | + * the UART channel may only write to the corresponding bit. |
|---|
| 148 | + */ |
|---|
| 149 | + serial_port_out(port, UART_EXAR_SLEEP, state ? 0xff : 0); |
|---|
| 150 | +} |
|---|
| 151 | + |
|---|
| 152 | +/* |
|---|
| 153 | + * XR17V35x UARTs have an extra fractional divisor register (DLD) |
|---|
| 154 | + * Calculate divisor with extra 4-bit fractional portion |
|---|
| 155 | + */ |
|---|
| 156 | +static unsigned int xr17v35x_get_divisor(struct uart_port *p, unsigned int baud, |
|---|
| 157 | + unsigned int *frac) |
|---|
| 158 | +{ |
|---|
| 159 | + unsigned int quot_16; |
|---|
| 160 | + |
|---|
| 161 | + quot_16 = DIV_ROUND_CLOSEST(p->uartclk, baud); |
|---|
| 162 | + *frac = quot_16 & 0x0f; |
|---|
| 163 | + |
|---|
| 164 | + return quot_16 >> 4; |
|---|
| 165 | +} |
|---|
| 166 | + |
|---|
| 167 | +static void xr17v35x_set_divisor(struct uart_port *p, unsigned int baud, |
|---|
| 168 | + unsigned int quot, unsigned int quot_frac) |
|---|
| 169 | +{ |
|---|
| 170 | + serial8250_do_set_divisor(p, baud, quot, quot_frac); |
|---|
| 171 | + |
|---|
| 172 | + /* Preserve bits not related to baudrate; DLD[7:4]. */ |
|---|
| 173 | + quot_frac |= serial_port_in(p, 0x2) & 0xf0; |
|---|
| 174 | + serial_port_out(p, 0x2, quot_frac); |
|---|
| 175 | +} |
|---|
| 176 | + |
|---|
| 177 | +static int xr17v35x_startup(struct uart_port *port) |
|---|
| 178 | +{ |
|---|
| 179 | + /* |
|---|
| 180 | + * First enable access to IER [7:5], ISR [5:4], FCR [5:4], |
|---|
| 181 | + * MCR [7:5] and MSR [7:0] |
|---|
| 182 | + */ |
|---|
| 183 | + serial_port_out(port, UART_XR_EFR, UART_EFR_ECB); |
|---|
| 184 | + |
|---|
| 185 | + /* |
|---|
| 186 | + * Make sure all interrups are masked until initialization is |
|---|
| 187 | + * complete and the FIFOs are cleared |
|---|
| 188 | + */ |
|---|
| 189 | + serial_port_out(port, UART_IER, 0); |
|---|
| 190 | + |
|---|
| 191 | + return serial8250_do_startup(port); |
|---|
| 192 | +} |
|---|
| 193 | + |
|---|
| 194 | +static void exar_shutdown(struct uart_port *port) |
|---|
| 195 | +{ |
|---|
| 196 | + unsigned char lsr; |
|---|
| 197 | + bool tx_complete = false; |
|---|
| 198 | + struct uart_8250_port *up = up_to_u8250p(port); |
|---|
| 199 | + struct circ_buf *xmit = &port->state->xmit; |
|---|
| 200 | + int i = 0; |
|---|
| 201 | + |
|---|
| 202 | + do { |
|---|
| 203 | + lsr = serial_in(up, UART_LSR); |
|---|
| 204 | + if (lsr & (UART_LSR_TEMT | UART_LSR_THRE)) |
|---|
| 205 | + tx_complete = true; |
|---|
| 206 | + else |
|---|
| 207 | + tx_complete = false; |
|---|
| 208 | + usleep_range(1000, 1100); |
|---|
| 209 | + } while (!uart_circ_empty(xmit) && !tx_complete && i++ < 1000); |
|---|
| 210 | + |
|---|
| 211 | + serial8250_do_shutdown(port); |
|---|
| 212 | +} |
|---|
| 137 | 213 | |
|---|
| 138 | 214 | static int default_setup(struct exar8250 *priv, struct pci_dev *pcidev, |
|---|
| 139 | 215 | int idx, unsigned int offset, |
|---|
| .. | .. |
|---|
| 141 | 217 | { |
|---|
| 142 | 218 | const struct exar8250_board *board = priv->board; |
|---|
| 143 | 219 | unsigned int bar = 0; |
|---|
| 220 | + unsigned char status; |
|---|
| 144 | 221 | |
|---|
| 145 | 222 | port->port.iotype = UPIO_MEM; |
|---|
| 146 | 223 | port->port.mapbase = pci_resource_start(pcidev, bar) + offset; |
|---|
| 147 | 224 | port->port.membase = priv->virt + offset; |
|---|
| 148 | 225 | port->port.regshift = board->reg_shift; |
|---|
| 226 | + |
|---|
| 227 | + /* |
|---|
| 228 | + * XR17V35x UARTs have an extra divisor register, DLD that gets enabled |
|---|
| 229 | + * with when DLAB is set which will cause the device to incorrectly match |
|---|
| 230 | + * and assign port type to PORT_16650. The EFR for this UART is found |
|---|
| 231 | + * at offset 0x09. Instead check the Deice ID (DVID) register |
|---|
| 232 | + * for a 2, 4 or 8 port UART. |
|---|
| 233 | + */ |
|---|
| 234 | + status = readb(port->port.membase + UART_EXAR_DVID); |
|---|
| 235 | + if (status == 0x82 || status == 0x84 || status == 0x88) { |
|---|
| 236 | + port->port.type = PORT_XR17V35X; |
|---|
| 237 | + |
|---|
| 238 | + port->port.get_divisor = xr17v35x_get_divisor; |
|---|
| 239 | + port->port.set_divisor = xr17v35x_set_divisor; |
|---|
| 240 | + |
|---|
| 241 | + port->port.startup = xr17v35x_startup; |
|---|
| 242 | + } else { |
|---|
| 243 | + port->port.type = PORT_XR17D15X; |
|---|
| 244 | + } |
|---|
| 245 | + |
|---|
| 246 | + port->port.pm = exar_pm; |
|---|
| 247 | + port->port.shutdown = exar_shutdown; |
|---|
| 149 | 248 | |
|---|
| 150 | 249 | return 0; |
|---|
| 151 | 250 | } |
|---|
| .. | .. |
|---|
| 379 | 478 | .register_gpio = iot2040_register_gpio, |
|---|
| 380 | 479 | }; |
|---|
| 381 | 480 | |
|---|
| 481 | +/* |
|---|
| 482 | + * For SIMATIC IOT2000, only IOT2040 and its variants have the Exar device, |
|---|
| 483 | + * IOT2020 doesn't have. Therefore it is sufficient to match on the common |
|---|
| 484 | + * board name after the device was found. |
|---|
| 485 | + */ |
|---|
| 382 | 486 | static const struct dmi_system_id exar_platforms[] = { |
|---|
| 383 | 487 | { |
|---|
| 384 | 488 | .matches = { |
|---|
| 385 | 489 | DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"), |
|---|
| 386 | | - DMI_EXACT_MATCH(DMI_BOARD_ASSET_TAG, |
|---|
| 387 | | - "6ES7647-0AA00-1YA2"), |
|---|
| 388 | 490 | }, |
|---|
| 389 | 491 | .driver_data = (void *)&iot2040_platform, |
|---|
| 390 | 492 | }, |
|---|
| .. | .. |
|---|
| 449 | 551 | port->port.private_data = NULL; |
|---|
| 450 | 552 | } |
|---|
| 451 | 553 | |
|---|
| 554 | +static inline void exar_misc_clear(struct exar8250 *priv) |
|---|
| 555 | +{ |
|---|
| 556 | + /* Clear all PCI interrupts by reading INT0. No effect on IIR */ |
|---|
| 557 | + readb(priv->virt + UART_EXAR_INT0); |
|---|
| 558 | + |
|---|
| 559 | + /* Clear INT0 for Expansion Interface slave ports, too */ |
|---|
| 560 | + if (priv->board->num_ports > 8) |
|---|
| 561 | + readb(priv->virt + 0x2000 + UART_EXAR_INT0); |
|---|
| 562 | +} |
|---|
| 563 | + |
|---|
| 452 | 564 | /* |
|---|
| 453 | 565 | * These Exar UARTs have an extra interrupt indicator that could fire for a |
|---|
| 454 | 566 | * few interrupts that are not presented/cleared through IIR. One of which is |
|---|
| .. | .. |
|---|
| 460 | 572 | */ |
|---|
| 461 | 573 | static irqreturn_t exar_misc_handler(int irq, void *data) |
|---|
| 462 | 574 | { |
|---|
| 463 | | - struct exar8250 *priv = data; |
|---|
| 464 | | - |
|---|
| 465 | | - /* Clear all PCI interrupts by reading INT0. No effect on IIR */ |
|---|
| 466 | | - readb(priv->virt + UART_EXAR_INT0); |
|---|
| 467 | | - |
|---|
| 468 | | - /* Clear INT0 for Expansion Interface slave ports, too */ |
|---|
| 469 | | - if (priv->board->num_ports > 8) |
|---|
| 470 | | - readb(priv->virt + 0x2000 + UART_EXAR_INT0); |
|---|
| 575 | + exar_misc_clear(data); |
|---|
| 471 | 576 | |
|---|
| 472 | 577 | return IRQ_HANDLED; |
|---|
| 473 | 578 | } |
|---|
| .. | .. |
|---|
| 493 | 598 | |
|---|
| 494 | 599 | nr_ports = board->num_ports ? board->num_ports : pcidev->device & 0x0f; |
|---|
| 495 | 600 | |
|---|
| 496 | | - priv = devm_kzalloc(&pcidev->dev, sizeof(*priv) + |
|---|
| 497 | | - sizeof(unsigned int) * nr_ports, |
|---|
| 498 | | - GFP_KERNEL); |
|---|
| 601 | + priv = devm_kzalloc(&pcidev->dev, struct_size(priv, line, nr_ports), GFP_KERNEL); |
|---|
| 499 | 602 | if (!priv) |
|---|
| 500 | 603 | return -ENOMEM; |
|---|
| 501 | 604 | |
|---|
| .. | .. |
|---|
| 511 | 614 | return rc; |
|---|
| 512 | 615 | |
|---|
| 513 | 616 | memset(&uart, 0, sizeof(uart)); |
|---|
| 514 | | - uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ |
|---|
| 515 | | - | UPF_EXAR_EFR; |
|---|
| 617 | + uart.port.flags = UPF_SHARE_IRQ | UPF_EXAR_EFR | UPF_FIXED_TYPE | UPF_FIXED_PORT; |
|---|
| 516 | 618 | uart.port.irq = pci_irq_vector(pcidev, 0); |
|---|
| 517 | 619 | uart.port.dev = &pcidev->dev; |
|---|
| 518 | 620 | |
|---|
| .. | .. |
|---|
| 520 | 622 | IRQF_SHARED, "exar_uart", priv); |
|---|
| 521 | 623 | if (rc) |
|---|
| 522 | 624 | return rc; |
|---|
| 625 | + |
|---|
| 626 | + /* Clear interrupts */ |
|---|
| 627 | + exar_misc_clear(priv); |
|---|
| 523 | 628 | |
|---|
| 524 | 629 | for (i = 0; i < nr_ports && i < maxnr; i++) { |
|---|
| 525 | 630 | rc = board->setup(priv, pcidev, &uart, i); |
|---|
| .. | .. |
|---|
| 576 | 681 | |
|---|
| 577 | 682 | static int __maybe_unused exar_resume(struct device *dev) |
|---|
| 578 | 683 | { |
|---|
| 579 | | - struct pci_dev *pcidev = to_pci_dev(dev); |
|---|
| 580 | | - struct exar8250 *priv = pci_get_drvdata(pcidev); |
|---|
| 684 | + struct exar8250 *priv = dev_get_drvdata(dev); |
|---|
| 581 | 685 | unsigned int i; |
|---|
| 686 | + |
|---|
| 687 | + exar_misc_clear(priv); |
|---|
| 582 | 688 | |
|---|
| 583 | 689 | for (i = 0; i < priv->nr; i++) |
|---|
| 584 | 690 | if (priv->line[i] >= 0) |
|---|
| .. | .. |
|---|
| 677 | 783 | (kernel_ulong_t)&bd \ |
|---|
| 678 | 784 | } |
|---|
| 679 | 785 | |
|---|
| 680 | | -#define EXAR_DEVICE(vend, devid, bd) { \ |
|---|
| 681 | | - PCI_VDEVICE(vend, PCI_DEVICE_ID_##devid), (kernel_ulong_t)&bd \ |
|---|
| 682 | | - } |
|---|
| 786 | +#define EXAR_DEVICE(vend, devid, bd) { PCI_DEVICE_DATA(vend, devid, &bd) } |
|---|
| 683 | 787 | |
|---|
| 684 | 788 | #define IBM_DEVICE(devid, sdevid, bd) { \ |
|---|
| 685 | 789 | PCI_DEVICE_SUB( \ |
|---|
| .. | .. |
|---|
| 691 | 795 | } |
|---|
| 692 | 796 | |
|---|
| 693 | 797 | static const struct pci_device_id exar_pci_tbl[] = { |
|---|
| 694 | | - EXAR_DEVICE(ACCESSIO, ACCES_COM_2S, acces_com_2x), |
|---|
| 695 | | - EXAR_DEVICE(ACCESSIO, ACCES_COM_4S, acces_com_4x), |
|---|
| 696 | | - EXAR_DEVICE(ACCESSIO, ACCES_COM_8S, acces_com_8x), |
|---|
| 697 | | - EXAR_DEVICE(ACCESSIO, ACCES_COM232_8, acces_com_8x), |
|---|
| 698 | | - EXAR_DEVICE(ACCESSIO, ACCES_COM_2SM, acces_com_2x), |
|---|
| 699 | | - EXAR_DEVICE(ACCESSIO, ACCES_COM_4SM, acces_com_4x), |
|---|
| 700 | | - EXAR_DEVICE(ACCESSIO, ACCES_COM_8SM, acces_com_8x), |
|---|
| 701 | | - |
|---|
| 798 | + EXAR_DEVICE(ACCESSIO, COM_2S, acces_com_2x), |
|---|
| 799 | + EXAR_DEVICE(ACCESSIO, COM_4S, acces_com_4x), |
|---|
| 800 | + EXAR_DEVICE(ACCESSIO, COM_8S, acces_com_8x), |
|---|
| 801 | + EXAR_DEVICE(ACCESSIO, COM232_8, acces_com_8x), |
|---|
| 802 | + EXAR_DEVICE(ACCESSIO, COM_2SM, acces_com_2x), |
|---|
| 803 | + EXAR_DEVICE(ACCESSIO, COM_4SM, acces_com_4x), |
|---|
| 804 | + EXAR_DEVICE(ACCESSIO, COM_8SM, acces_com_8x), |
|---|
| 702 | 805 | |
|---|
| 703 | 806 | CONNECT_DEVICE(XR17C152, UART_2_232, pbn_connect), |
|---|
| 704 | 807 | CONNECT_DEVICE(XR17C154, UART_4_232, pbn_connect), |
|---|
| .. | .. |
|---|
| 716 | 819 | IBM_DEVICE(XR17C152, SATURN_SERIAL_ONE_PORT, pbn_exar_ibm_saturn), |
|---|
| 717 | 820 | |
|---|
| 718 | 821 | /* Exar Corp. XR17C15[248] Dual/Quad/Octal UART */ |
|---|
| 719 | | - EXAR_DEVICE(EXAR, EXAR_XR17C152, pbn_exar_XR17C15x), |
|---|
| 720 | | - EXAR_DEVICE(EXAR, EXAR_XR17C154, pbn_exar_XR17C15x), |
|---|
| 721 | | - EXAR_DEVICE(EXAR, EXAR_XR17C158, pbn_exar_XR17C15x), |
|---|
| 822 | + EXAR_DEVICE(EXAR, XR17C152, pbn_exar_XR17C15x), |
|---|
| 823 | + EXAR_DEVICE(EXAR, XR17C154, pbn_exar_XR17C15x), |
|---|
| 824 | + EXAR_DEVICE(EXAR, XR17C158, pbn_exar_XR17C15x), |
|---|
| 722 | 825 | |
|---|
| 723 | 826 | /* Exar Corp. XR17V[48]35[248] Dual/Quad/Octal/Hexa PCIe UARTs */ |
|---|
| 724 | | - EXAR_DEVICE(EXAR, EXAR_XR17V352, pbn_exar_XR17V35x), |
|---|
| 725 | | - EXAR_DEVICE(EXAR, EXAR_XR17V354, pbn_exar_XR17V35x), |
|---|
| 726 | | - EXAR_DEVICE(EXAR, EXAR_XR17V358, pbn_exar_XR17V35x), |
|---|
| 727 | | - EXAR_DEVICE(EXAR, EXAR_XR17V4358, pbn_exar_XR17V4358), |
|---|
| 728 | | - EXAR_DEVICE(EXAR, EXAR_XR17V8358, pbn_exar_XR17V8358), |
|---|
| 729 | | - EXAR_DEVICE(COMMTECH, COMMTECH_4222PCIE, pbn_fastcom35x_2), |
|---|
| 730 | | - EXAR_DEVICE(COMMTECH, COMMTECH_4224PCIE, pbn_fastcom35x_4), |
|---|
| 731 | | - EXAR_DEVICE(COMMTECH, COMMTECH_4228PCIE, pbn_fastcom35x_8), |
|---|
| 827 | + EXAR_DEVICE(EXAR, XR17V352, pbn_exar_XR17V35x), |
|---|
| 828 | + EXAR_DEVICE(EXAR, XR17V354, pbn_exar_XR17V35x), |
|---|
| 829 | + EXAR_DEVICE(EXAR, XR17V358, pbn_exar_XR17V35x), |
|---|
| 830 | + EXAR_DEVICE(EXAR, XR17V4358, pbn_exar_XR17V4358), |
|---|
| 831 | + EXAR_DEVICE(EXAR, XR17V8358, pbn_exar_XR17V8358), |
|---|
| 832 | + EXAR_DEVICE(COMMTECH, 4222PCIE, pbn_fastcom35x_2), |
|---|
| 833 | + EXAR_DEVICE(COMMTECH, 4224PCIE, pbn_fastcom35x_4), |
|---|
| 834 | + EXAR_DEVICE(COMMTECH, 4228PCIE, pbn_fastcom35x_8), |
|---|
| 732 | 835 | |
|---|
| 733 | | - EXAR_DEVICE(COMMTECH, COMMTECH_4222PCI335, pbn_fastcom335_2), |
|---|
| 734 | | - EXAR_DEVICE(COMMTECH, COMMTECH_4224PCI335, pbn_fastcom335_4), |
|---|
| 735 | | - EXAR_DEVICE(COMMTECH, COMMTECH_2324PCI335, pbn_fastcom335_4), |
|---|
| 736 | | - EXAR_DEVICE(COMMTECH, COMMTECH_2328PCI335, pbn_fastcom335_8), |
|---|
| 836 | + EXAR_DEVICE(COMMTECH, 4222PCI335, pbn_fastcom335_2), |
|---|
| 837 | + EXAR_DEVICE(COMMTECH, 4224PCI335, pbn_fastcom335_4), |
|---|
| 838 | + EXAR_DEVICE(COMMTECH, 2324PCI335, pbn_fastcom335_4), |
|---|
| 839 | + EXAR_DEVICE(COMMTECH, 2328PCI335, pbn_fastcom335_8), |
|---|
| 737 | 840 | { 0, } |
|---|
| 738 | 841 | }; |
|---|
| 739 | 842 | MODULE_DEVICE_TABLE(pci, exar_pci_tbl); |
|---|