serial: 8250_pnp: Support configurable reg shift property
authorGuanbing Huang <albanhuang@tencent.com>
Tue, 16 Apr 2024 03:16:59 +0000 (11:16 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 17 Apr 2024 11:14:30 +0000 (13:14 +0200)
The 16550a serial port based on the ACPI table requires obtaining the
reg-shift attribute. In the ACPI scenario, If the reg-shift property
is not configured like in DTS, the 16550a serial driver cannot read or
write controller registers properly during initialization.

Signed-off-by: Guanbing Huang <albanhuang@tencent.com>
Suggested-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Bing Fan <tombinfan@tencent.com>
Tested-by: Linheng Du <dylanlhdu@tencent.com>
Link: https://lore.kernel.org/r/4726ecea8f7bfbfe42501b4f6ad9fe5b38994574.1713234515.git.albanhuang@tencent.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/8250/8250_pnp.c

index 1974bbadc9756166ab17c85a15fb54a9ac177ee6..8f72a7de1d1d5b8b01654cd69d02019e8e47200a 100644 (file)
@@ -435,6 +435,7 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
 {
        struct uart_8250_port uart, *port;
        int ret, line, flags = dev_id->driver_data;
+       unsigned char iotype;
 
        if (flags & UNKNOWN_DEV) {
                ret = serial_pnp_guess_board(dev);
@@ -443,37 +444,46 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
        }
 
        memset(&uart, 0, sizeof(uart));
-       if (pnp_irq_valid(dev, 0))
-               uart.port.irq = pnp_irq(dev, 0);
        if ((flags & CIR_PORT) && pnp_port_valid(dev, 2)) {
                uart.port.iobase = pnp_port_start(dev, 2);
-               uart.port.iotype = UPIO_PORT;
+               iotype = UPIO_PORT;
        } else if (pnp_port_valid(dev, 0)) {
                uart.port.iobase = pnp_port_start(dev, 0);
-               uart.port.iotype = UPIO_PORT;
+               iotype = UPIO_PORT;
        } else if (pnp_mem_valid(dev, 0)) {
                uart.port.mapbase = pnp_mem_start(dev, 0);
-               uart.port.iotype = UPIO_MEM;
+               uart.port.mapsize = pnp_mem_len(dev, 0);
+               iotype = UPIO_MEM;
                uart.port.flags = UPF_IOREMAP;
        } else
                return -ENODEV;
 
-       dev_dbg(&dev->dev,
-                "Setup PNP port: port %#lx, mem %#llx, irq %u, type %u\n",
-                uart.port.iobase, (unsigned long long)uart.port.mapbase,
-                uart.port.irq, uart.port.iotype);
+       uart.port.uartclk = 1843200;
+       uart.port.dev = &dev->dev;
+       uart.port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
+
+       ret = uart_read_port_properties(&uart.port);
+       /* no interrupt -> fall back to polling */
+       if (ret == -ENXIO)
+               ret = 0;
+       if (ret)
+               return ret;
+
+       /*
+        * The previous call may not set iotype correctly when reg-io-width
+        * property is absent and it doesn't support IO port resource.
+        */
+       uart.port.iotype = iotype;
 
        if (flags & CIR_PORT) {
                uart.port.flags |= UPF_FIXED_PORT | UPF_FIXED_TYPE;
                uart.port.type = PORT_8250_CIR;
        }
 
-       uart.port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
-       if (pnp_irq_flags(dev, 0) & IORESOURCE_IRQ_SHAREABLE)
-               uart.port.flags |= UPF_SHARE_IRQ;
-       uart.port.uartclk = 1843200;
-       device_property_read_u32(&dev->dev, "clock-frequency", &uart.port.uartclk);
-       uart.port.dev = &dev->dev;
+       dev_dbg(&dev->dev,
+                "Setup PNP port: port %#lx, mem %#llx, size %#llx, irq %u, type %u\n",
+                uart.port.iobase, (unsigned long long)uart.port.mapbase,
+                (unsigned long long)uart.port.mapsize, uart.port.irq, uart.port.iotype);
 
        line = serial8250_register_8250_port(&uart);
        if (line < 0 || (flags & CIR_PORT))