mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
204 lines
5.0 KiB
204 lines
5.0 KiB
// SPDX-License-Identifier: GPL-2.0-only |
|
/* |
|
* Zalon 53c7xx device driver. |
|
* By Richard Hirst ([email protected]) |
|
*/ |
|
|
|
#include <linux/init.h> |
|
#include <linux/interrupt.h> |
|
#include <linux/module.h> |
|
#include <linux/types.h> |
|
#include <asm/hardware.h> |
|
#include <asm/io.h> |
|
|
|
#include "../parisc/gsc.h" |
|
|
|
#include "ncr53c8xx.h" |
|
|
|
MODULE_AUTHOR("Richard Hirst"); |
|
MODULE_DESCRIPTION("Bluefish/Zalon 720 SCSI Driver"); |
|
MODULE_LICENSE("GPL"); |
|
|
|
#define GSC_SCSI_ZALON_OFFSET 0x800 |
|
|
|
#define IO_MODULE_EIM (1*4) |
|
#define IO_MODULE_DC_ADATA (2*4) |
|
#define IO_MODULE_II_CDATA (3*4) |
|
#define IO_MODULE_IO_COMMAND (12*4) |
|
#define IO_MODULE_IO_STATUS (13*4) |
|
|
|
#define IOSTATUS_RY 0x40 |
|
#define IOSTATUS_FE 0x80 |
|
#define IOIIDATA_SMINT5L 0x40000000 |
|
#define IOIIDATA_MINT5EN 0x20000000 |
|
#define IOIIDATA_PACKEN 0x10000000 |
|
#define IOIIDATA_PREFETCHEN 0x08000000 |
|
#define IOIIDATA_IOII 0x00000020 |
|
|
|
#define CMD_RESET 5 |
|
|
|
static struct ncr_chip zalon720_chip __initdata = { |
|
.revision_id = 0x0f, |
|
.burst_max = 3, |
|
.offset_max = 8, |
|
.nr_divisor = 4, |
|
.features = FE_WIDE | FE_DIFF | FE_EHP| FE_MUX | FE_EA, |
|
}; |
|
|
|
|
|
|
|
#if 0 |
|
/* FIXME: |
|
* Is this function dead code? or is someone planning on using it in the |
|
* future. The clock = (int) pdc_result[16] does not look correct to |
|
* me ... I think it should be iodc_data[16]. Since this cause a compile |
|
* error with the new encapsulated PDC, I'm not compiling in this function. |
|
* - RB |
|
*/ |
|
/* poke SCSI clock out of iodc data */ |
|
|
|
static u8 iodc_data[32] __attribute__ ((aligned (64))); |
|
static unsigned long pdc_result[32] __attribute__ ((aligned (16))) ={0,0,0,0}; |
|
|
|
static int |
|
lasi_scsi_clock(void * hpa, int defaultclock) |
|
{ |
|
int clock, status; |
|
|
|
status = pdc_iodc_read(&pdc_result, hpa, 0, &iodc_data, 32 ); |
|
if (status == PDC_RET_OK) { |
|
clock = (int) pdc_result[16]; |
|
} else { |
|
printk(KERN_WARNING "%s: pdc_iodc_read returned %d\n", __func__, status); |
|
clock = defaultclock; |
|
} |
|
|
|
printk(KERN_DEBUG "%s: SCSI clock %d\n", __func__, clock); |
|
return clock; |
|
} |
|
#endif |
|
|
|
static struct scsi_host_template zalon7xx_template = { |
|
.module = THIS_MODULE, |
|
.proc_name = "zalon7xx", |
|
}; |
|
|
|
static int __init |
|
zalon_probe(struct parisc_device *dev) |
|
{ |
|
struct gsc_irq gsc_irq; |
|
u32 zalon_vers; |
|
int error = -ENODEV; |
|
void __iomem *zalon = ioremap(dev->hpa.start, 4096); |
|
void __iomem *io_port = zalon + GSC_SCSI_ZALON_OFFSET; |
|
static int unit = 0; |
|
struct Scsi_Host *host; |
|
struct ncr_device device; |
|
|
|
__raw_writel(CMD_RESET, zalon + IO_MODULE_IO_COMMAND); |
|
while (!(__raw_readl(zalon + IO_MODULE_IO_STATUS) & IOSTATUS_RY)) |
|
cpu_relax(); |
|
__raw_writel(IOIIDATA_MINT5EN | IOIIDATA_PACKEN | IOIIDATA_PREFETCHEN, |
|
zalon + IO_MODULE_II_CDATA); |
|
|
|
/* XXX: Save the Zalon version for bug workarounds? */ |
|
zalon_vers = (__raw_readl(zalon + IO_MODULE_II_CDATA) >> 24) & 0x07; |
|
|
|
/* Setup the interrupts first. |
|
** Later on request_irq() will register the handler. |
|
*/ |
|
dev->irq = gsc_alloc_irq(&gsc_irq); |
|
|
|
printk(KERN_INFO "%s: Zalon version %d, IRQ %d\n", __func__, |
|
zalon_vers, dev->irq); |
|
|
|
__raw_writel(gsc_irq.txn_addr | gsc_irq.txn_data, zalon + IO_MODULE_EIM); |
|
|
|
if (zalon_vers == 0) |
|
printk(KERN_WARNING "%s: Zalon 1.1 or earlier\n", __func__); |
|
|
|
memset(&device, 0, sizeof(struct ncr_device)); |
|
|
|
/* The following three are needed before any other access. */ |
|
__raw_writeb(0x20, io_port + 0x38); /* DCNTL_REG, EA */ |
|
__raw_writeb(0x04, io_port + 0x1b); /* CTEST0_REG, EHP */ |
|
__raw_writeb(0x80, io_port + 0x22); /* CTEST4_REG, MUX */ |
|
|
|
/* Initialise ncr_device structure with items required by ncr_attach. */ |
|
device.chip = zalon720_chip; |
|
device.host_id = 7; |
|
device.dev = &dev->dev; |
|
device.slot.base = dev->hpa.start + GSC_SCSI_ZALON_OFFSET; |
|
device.slot.base_v = io_port; |
|
device.slot.irq = dev->irq; |
|
device.differential = 2; |
|
|
|
host = ncr_attach(&zalon7xx_template, unit, &device); |
|
if (!host) |
|
return -ENODEV; |
|
|
|
if (request_irq(dev->irq, ncr53c8xx_intr, IRQF_SHARED, "zalon", host)) { |
|
dev_printk(KERN_ERR, &dev->dev, "irq problem with %d, detaching\n ", |
|
dev->irq); |
|
goto fail; |
|
} |
|
|
|
unit++; |
|
|
|
dev_set_drvdata(&dev->dev, host); |
|
|
|
error = scsi_add_host(host, &dev->dev); |
|
if (error) |
|
goto fail_free_irq; |
|
|
|
scsi_scan_host(host); |
|
return 0; |
|
|
|
fail_free_irq: |
|
free_irq(dev->irq, host); |
|
fail: |
|
ncr53c8xx_release(host); |
|
return error; |
|
} |
|
|
|
static const struct parisc_device_id zalon_tbl[] __initconst = { |
|
{ HPHW_A_DMA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00089 }, |
|
{ 0, } |
|
}; |
|
|
|
MODULE_DEVICE_TABLE(parisc, zalon_tbl); |
|
|
|
static void __exit zalon_remove(struct parisc_device *dev) |
|
{ |
|
struct Scsi_Host *host = dev_get_drvdata(&dev->dev); |
|
|
|
scsi_remove_host(host); |
|
ncr53c8xx_release(host); |
|
free_irq(dev->irq, host); |
|
} |
|
|
|
static struct parisc_driver zalon_driver __refdata = { |
|
.name = "zalon", |
|
.id_table = zalon_tbl, |
|
.probe = zalon_probe, |
|
.remove = __exit_p(zalon_remove), |
|
}; |
|
|
|
static int __init zalon7xx_init(void) |
|
{ |
|
int ret = ncr53c8xx_init(); |
|
if (!ret) |
|
ret = register_parisc_driver(&zalon_driver); |
|
if (ret) |
|
ncr53c8xx_exit(); |
|
return ret; |
|
} |
|
|
|
static void __exit zalon7xx_exit(void) |
|
{ |
|
unregister_parisc_driver(&zalon_driver); |
|
ncr53c8xx_exit(); |
|
} |
|
|
|
module_init(zalon7xx_init); |
|
module_exit(zalon7xx_exit);
|
|
|