162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Serial Device Initialisation for Lasi/Asp/Wax/Dino 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * (c) Copyright Matthew Wilcox <willy@debian.org> 2001-2002 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/errno.h> 962306a36Sopenharmony_ci#include <linux/init.h> 1062306a36Sopenharmony_ci#include <linux/interrupt.h> 1162306a36Sopenharmony_ci#include <linux/ioport.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/serial_core.h> 1462306a36Sopenharmony_ci#include <linux/signal.h> 1562306a36Sopenharmony_ci#include <linux/types.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <asm/hardware.h> 1862306a36Sopenharmony_ci#include <asm/parisc-device.h> 1962306a36Sopenharmony_ci#include <asm/io.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include "8250.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic int __init serial_init_chip(struct parisc_device *dev) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci struct uart_8250_port uart; 2662306a36Sopenharmony_ci unsigned long address; 2762306a36Sopenharmony_ci int err; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#if defined(CONFIG_64BIT) && defined(CONFIG_IOSAPIC) 3062306a36Sopenharmony_ci if (!dev->irq && (dev->id.sversion == 0xad)) 3162306a36Sopenharmony_ci dev->irq = iosapic_serial_irq(dev); 3262306a36Sopenharmony_ci#endif 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci if (!dev->irq) { 3562306a36Sopenharmony_ci /* We find some unattached serial ports by walking native 3662306a36Sopenharmony_ci * busses. These should be silently ignored. Otherwise, 3762306a36Sopenharmony_ci * what we have here is a missing parent device, so tell 3862306a36Sopenharmony_ci * the user what they're missing. 3962306a36Sopenharmony_ci */ 4062306a36Sopenharmony_ci if (parisc_parent(dev)->id.hw_type != HPHW_IOA) 4162306a36Sopenharmony_ci dev_info(&dev->dev, 4262306a36Sopenharmony_ci "Serial: device 0x%llx not configured.\n" 4362306a36Sopenharmony_ci "Enable support for Wax, Lasi, Asp or Dino.\n", 4462306a36Sopenharmony_ci (unsigned long long)dev->hpa.start); 4562306a36Sopenharmony_ci return -ENODEV; 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci address = dev->hpa.start; 4962306a36Sopenharmony_ci if (dev->id.sversion != 0x8d) 5062306a36Sopenharmony_ci address += 0x800; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci memset(&uart, 0, sizeof(uart)); 5362306a36Sopenharmony_ci uart.port.iotype = UPIO_MEM; 5462306a36Sopenharmony_ci /* 7.272727MHz on Lasi. Assumed the same for Dino, Wax and Timi. */ 5562306a36Sopenharmony_ci uart.port.uartclk = (dev->id.sversion != 0xad) ? 5662306a36Sopenharmony_ci 7272727 : 1843200; 5762306a36Sopenharmony_ci uart.port.mapbase = address; 5862306a36Sopenharmony_ci uart.port.membase = ioremap(address, 16); 5962306a36Sopenharmony_ci if (!uart.port.membase) { 6062306a36Sopenharmony_ci dev_warn(&dev->dev, "Failed to map memory\n"); 6162306a36Sopenharmony_ci return -ENOMEM; 6262306a36Sopenharmony_ci } 6362306a36Sopenharmony_ci uart.port.irq = dev->irq; 6462306a36Sopenharmony_ci uart.port.flags = UPF_BOOT_AUTOCONF; 6562306a36Sopenharmony_ci uart.port.dev = &dev->dev; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci err = serial8250_register_8250_port(&uart); 6862306a36Sopenharmony_ci if (err < 0) { 6962306a36Sopenharmony_ci dev_warn(&dev->dev, 7062306a36Sopenharmony_ci "serial8250_register_8250_port returned error %d\n", 7162306a36Sopenharmony_ci err); 7262306a36Sopenharmony_ci iounmap(uart.port.membase); 7362306a36Sopenharmony_ci return err; 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci return 0; 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic const struct parisc_device_id serial_tbl[] __initconst = { 8062306a36Sopenharmony_ci { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00075 }, 8162306a36Sopenharmony_ci { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008c }, 8262306a36Sopenharmony_ci { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008d }, 8362306a36Sopenharmony_ci { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x000ad }, 8462306a36Sopenharmony_ci { 0 } 8562306a36Sopenharmony_ci}; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci/* Hack. Some machines have SERIAL_0 attached to Lasi and SERIAL_1 8862306a36Sopenharmony_ci * attached to Dino. Unfortunately, Dino appears before Lasi in the device 8962306a36Sopenharmony_ci * tree. To ensure that ttyS0 == SERIAL_0, we register two drivers; one 9062306a36Sopenharmony_ci * which only knows about Lasi and then a second which will find all the 9162306a36Sopenharmony_ci * other serial ports. HPUX ignores this problem. 9262306a36Sopenharmony_ci */ 9362306a36Sopenharmony_cistatic const struct parisc_device_id lasi_tbl[] __initconst = { 9462306a36Sopenharmony_ci { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03B, 0x0008C }, /* C1xx/C1xxL */ 9562306a36Sopenharmony_ci { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03C, 0x0008C }, /* B132L */ 9662306a36Sopenharmony_ci { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03D, 0x0008C }, /* B160L */ 9762306a36Sopenharmony_ci { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03E, 0x0008C }, /* B132L+ */ 9862306a36Sopenharmony_ci { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03F, 0x0008C }, /* B180L+ */ 9962306a36Sopenharmony_ci { HPHW_FIO, HVERSION_REV_ANY_ID, 0x046, 0x0008C }, /* Rocky2 120 */ 10062306a36Sopenharmony_ci { HPHW_FIO, HVERSION_REV_ANY_ID, 0x047, 0x0008C }, /* Rocky2 150 */ 10162306a36Sopenharmony_ci { HPHW_FIO, HVERSION_REV_ANY_ID, 0x04E, 0x0008C }, /* Kiji L2 132 */ 10262306a36Sopenharmony_ci { HPHW_FIO, HVERSION_REV_ANY_ID, 0x056, 0x0008C }, /* Raven+ */ 10362306a36Sopenharmony_ci { 0 } 10462306a36Sopenharmony_ci}; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(parisc, serial_tbl); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic struct parisc_driver lasi_driver __refdata = { 11062306a36Sopenharmony_ci .name = "serial_1", 11162306a36Sopenharmony_ci .id_table = lasi_tbl, 11262306a36Sopenharmony_ci .probe = serial_init_chip, 11362306a36Sopenharmony_ci}; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic struct parisc_driver serial_driver __refdata = { 11662306a36Sopenharmony_ci .name = "serial", 11762306a36Sopenharmony_ci .id_table = serial_tbl, 11862306a36Sopenharmony_ci .probe = serial_init_chip, 11962306a36Sopenharmony_ci}; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic int __init probe_serial_gsc(void) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci register_parisc_driver(&lasi_driver); 12462306a36Sopenharmony_ci register_parisc_driver(&serial_driver); 12562306a36Sopenharmony_ci return 0; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cimodule_init(probe_serial_gsc); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 131