162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Zalon 53c7xx device driver. 462306a36Sopenharmony_ci * By Richard Hirst (rhirst@linuxcare.com) 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/init.h> 862306a36Sopenharmony_ci#include <linux/interrupt.h> 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/types.h> 1162306a36Sopenharmony_ci#include <asm/hardware.h> 1262306a36Sopenharmony_ci#include <asm/io.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "../parisc/gsc.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include "ncr53c8xx.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ciMODULE_AUTHOR("Richard Hirst"); 1962306a36Sopenharmony_ciMODULE_DESCRIPTION("Bluefish/Zalon 720 SCSI Driver"); 2062306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define GSC_SCSI_ZALON_OFFSET 0x800 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define IO_MODULE_EIM (1*4) 2562306a36Sopenharmony_ci#define IO_MODULE_DC_ADATA (2*4) 2662306a36Sopenharmony_ci#define IO_MODULE_II_CDATA (3*4) 2762306a36Sopenharmony_ci#define IO_MODULE_IO_COMMAND (12*4) 2862306a36Sopenharmony_ci#define IO_MODULE_IO_STATUS (13*4) 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define IOSTATUS_RY 0x40 3162306a36Sopenharmony_ci#define IOSTATUS_FE 0x80 3262306a36Sopenharmony_ci#define IOIIDATA_SMINT5L 0x40000000 3362306a36Sopenharmony_ci#define IOIIDATA_MINT5EN 0x20000000 3462306a36Sopenharmony_ci#define IOIIDATA_PACKEN 0x10000000 3562306a36Sopenharmony_ci#define IOIIDATA_PREFETCHEN 0x08000000 3662306a36Sopenharmony_ci#define IOIIDATA_IOII 0x00000020 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define CMD_RESET 5 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic struct ncr_chip zalon720_chip __initdata = { 4162306a36Sopenharmony_ci .revision_id = 0x0f, 4262306a36Sopenharmony_ci .burst_max = 3, 4362306a36Sopenharmony_ci .offset_max = 8, 4462306a36Sopenharmony_ci .nr_divisor = 4, 4562306a36Sopenharmony_ci .features = FE_WIDE | FE_DIFF | FE_EHP| FE_MUX | FE_EA, 4662306a36Sopenharmony_ci}; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#if 0 5162306a36Sopenharmony_ci/* FIXME: 5262306a36Sopenharmony_ci * Is this function dead code? or is someone planning on using it in the 5362306a36Sopenharmony_ci * future. The clock = (int) pdc_result[16] does not look correct to 5462306a36Sopenharmony_ci * me ... I think it should be iodc_data[16]. Since this cause a compile 5562306a36Sopenharmony_ci * error with the new encapsulated PDC, I'm not compiling in this function. 5662306a36Sopenharmony_ci * - RB 5762306a36Sopenharmony_ci */ 5862306a36Sopenharmony_ci/* poke SCSI clock out of iodc data */ 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic u8 iodc_data[32] __attribute__ ((aligned (64))); 6162306a36Sopenharmony_cistatic unsigned long pdc_result[32] __attribute__ ((aligned (16))) ={0,0,0,0}; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic int 6462306a36Sopenharmony_cilasi_scsi_clock(void * hpa, int defaultclock) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci int clock, status; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci status = pdc_iodc_read(&pdc_result, hpa, 0, &iodc_data, 32 ); 6962306a36Sopenharmony_ci if (status == PDC_RET_OK) { 7062306a36Sopenharmony_ci clock = (int) pdc_result[16]; 7162306a36Sopenharmony_ci } else { 7262306a36Sopenharmony_ci printk(KERN_WARNING "%s: pdc_iodc_read returned %d\n", __func__, status); 7362306a36Sopenharmony_ci clock = defaultclock; 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci printk(KERN_DEBUG "%s: SCSI clock %d\n", __func__, clock); 7762306a36Sopenharmony_ci return clock; 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci#endif 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic struct scsi_host_template zalon7xx_template = { 8262306a36Sopenharmony_ci .module = THIS_MODULE, 8362306a36Sopenharmony_ci .proc_name = "zalon7xx", 8462306a36Sopenharmony_ci .cmd_size = sizeof(struct ncr_cmd_priv), 8562306a36Sopenharmony_ci}; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic int __init 8862306a36Sopenharmony_cizalon_probe(struct parisc_device *dev) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci struct gsc_irq gsc_irq; 9162306a36Sopenharmony_ci u32 zalon_vers; 9262306a36Sopenharmony_ci int error = -ENODEV; 9362306a36Sopenharmony_ci void __iomem *zalon = ioremap(dev->hpa.start, 4096); 9462306a36Sopenharmony_ci void __iomem *io_port = zalon + GSC_SCSI_ZALON_OFFSET; 9562306a36Sopenharmony_ci static int unit = 0; 9662306a36Sopenharmony_ci struct Scsi_Host *host; 9762306a36Sopenharmony_ci struct ncr_device device; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci __raw_writel(CMD_RESET, zalon + IO_MODULE_IO_COMMAND); 10062306a36Sopenharmony_ci while (!(__raw_readl(zalon + IO_MODULE_IO_STATUS) & IOSTATUS_RY)) 10162306a36Sopenharmony_ci cpu_relax(); 10262306a36Sopenharmony_ci __raw_writel(IOIIDATA_MINT5EN | IOIIDATA_PACKEN | IOIIDATA_PREFETCHEN, 10362306a36Sopenharmony_ci zalon + IO_MODULE_II_CDATA); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci /* XXX: Save the Zalon version for bug workarounds? */ 10662306a36Sopenharmony_ci zalon_vers = (__raw_readl(zalon + IO_MODULE_II_CDATA) >> 24) & 0x07; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci /* Setup the interrupts first. 10962306a36Sopenharmony_ci ** Later on request_irq() will register the handler. 11062306a36Sopenharmony_ci */ 11162306a36Sopenharmony_ci dev->irq = gsc_alloc_irq(&gsc_irq); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci printk(KERN_INFO "%s: Zalon version %d, IRQ %d\n", __func__, 11462306a36Sopenharmony_ci zalon_vers, dev->irq); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci __raw_writel(gsc_irq.txn_addr | gsc_irq.txn_data, zalon + IO_MODULE_EIM); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci if (zalon_vers == 0) 11962306a36Sopenharmony_ci printk(KERN_WARNING "%s: Zalon 1.1 or earlier\n", __func__); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci memset(&device, 0, sizeof(struct ncr_device)); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci /* The following three are needed before any other access. */ 12462306a36Sopenharmony_ci __raw_writeb(0x20, io_port + 0x38); /* DCNTL_REG, EA */ 12562306a36Sopenharmony_ci __raw_writeb(0x04, io_port + 0x1b); /* CTEST0_REG, EHP */ 12662306a36Sopenharmony_ci __raw_writeb(0x80, io_port + 0x22); /* CTEST4_REG, MUX */ 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci /* Initialise ncr_device structure with items required by ncr_attach. */ 12962306a36Sopenharmony_ci device.chip = zalon720_chip; 13062306a36Sopenharmony_ci device.host_id = 7; 13162306a36Sopenharmony_ci device.dev = &dev->dev; 13262306a36Sopenharmony_ci device.slot.base = dev->hpa.start + GSC_SCSI_ZALON_OFFSET; 13362306a36Sopenharmony_ci device.slot.base_v = io_port; 13462306a36Sopenharmony_ci device.slot.irq = dev->irq; 13562306a36Sopenharmony_ci device.differential = 2; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci host = ncr_attach(&zalon7xx_template, unit, &device); 13862306a36Sopenharmony_ci if (!host) 13962306a36Sopenharmony_ci return -ENODEV; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci if (request_irq(dev->irq, ncr53c8xx_intr, IRQF_SHARED, "zalon", host)) { 14262306a36Sopenharmony_ci dev_printk(KERN_ERR, &dev->dev, "irq problem with %d, detaching\n ", 14362306a36Sopenharmony_ci dev->irq); 14462306a36Sopenharmony_ci goto fail; 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci unit++; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci dev_set_drvdata(&dev->dev, host); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci error = scsi_add_host(host, &dev->dev); 15262306a36Sopenharmony_ci if (error) 15362306a36Sopenharmony_ci goto fail_free_irq; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci scsi_scan_host(host); 15662306a36Sopenharmony_ci return 0; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci fail_free_irq: 15962306a36Sopenharmony_ci free_irq(dev->irq, host); 16062306a36Sopenharmony_ci fail: 16162306a36Sopenharmony_ci ncr53c8xx_release(host); 16262306a36Sopenharmony_ci return error; 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic const struct parisc_device_id zalon_tbl[] __initconst = { 16662306a36Sopenharmony_ci { HPHW_A_DMA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00089 }, 16762306a36Sopenharmony_ci { 0, } 16862306a36Sopenharmony_ci}; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(parisc, zalon_tbl); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic void __exit zalon_remove(struct parisc_device *dev) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci struct Scsi_Host *host = dev_get_drvdata(&dev->dev); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci scsi_remove_host(host); 17762306a36Sopenharmony_ci ncr53c8xx_release(host); 17862306a36Sopenharmony_ci free_irq(dev->irq, host); 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic struct parisc_driver zalon_driver __refdata = { 18262306a36Sopenharmony_ci .name = "zalon", 18362306a36Sopenharmony_ci .id_table = zalon_tbl, 18462306a36Sopenharmony_ci .probe = zalon_probe, 18562306a36Sopenharmony_ci .remove = __exit_p(zalon_remove), 18662306a36Sopenharmony_ci}; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic int __init zalon7xx_init(void) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci int ret = ncr53c8xx_init(); 19162306a36Sopenharmony_ci if (!ret) 19262306a36Sopenharmony_ci ret = register_parisc_driver(&zalon_driver); 19362306a36Sopenharmony_ci if (ret) 19462306a36Sopenharmony_ci ncr53c8xx_exit(); 19562306a36Sopenharmony_ci return ret; 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic void __exit zalon7xx_exit(void) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci unregister_parisc_driver(&zalon_driver); 20162306a36Sopenharmony_ci ncr53c8xx_exit(); 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cimodule_init(zalon7xx_init); 20562306a36Sopenharmony_cimodule_exit(zalon7xx_exit); 206