Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-tc
* 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-tc: [EISA] EISA registration with !CONFIG_EISA [TC] pmagb-b-fb: Convert to the driver model [TC] dec_esp: Driver model for the PMAZ-A [TC] mips: pmag-ba-fb: Convert to the driver model [TC] defxx: TURBOchannel support [TC] TURBOchannel support for the DECstation [TC] MIPS: TURBOchannel resources off-by-one fix [TC] MIPS: TURBOchannel update to the driver model
This commit is contained in:
commit
68a696a01f
@ -3293,6 +3293,11 @@ L: vtun@office.satix.net
|
||||
W: http://vtun.sourceforge.net/tun
|
||||
S: Maintained
|
||||
|
||||
TURBOCHANNEL SUBSYSTEM
|
||||
P: Maciej W. Rozycki
|
||||
M: macro@linux-mips.org
|
||||
S: Maintained
|
||||
|
||||
U14-34F SCSI DRIVER
|
||||
P: Dario Ballabio
|
||||
M: ballabio_dario@emc.com
|
||||
|
@ -6,6 +6,7 @@ obj-y := ecc-berr.o int-handler.o ioasic-irq.o kn01-berr.o \
|
||||
kn02-irq.o kn02xa-berr.o reset.o setup.o time.o
|
||||
|
||||
obj-$(CONFIG_PROM_CONSOLE) += promcon.o
|
||||
obj-$(CONFIG_TC) += tc.o
|
||||
obj-$(CONFIG_CPU_HAS_WB) += wbflush.o
|
||||
|
||||
EXTRA_AFLAGS := $(CFLAGS)
|
||||
|
@ -88,6 +88,7 @@ static inline void prom_init_kn02(void)
|
||||
{
|
||||
dec_kn_slot_base = KN02_SLOT_BASE;
|
||||
dec_kn_slot_size = KN02_SLOT_SIZE;
|
||||
dec_tc_bus = 1;
|
||||
|
||||
dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + KN02_RTC);
|
||||
}
|
||||
@ -96,6 +97,7 @@ static inline void prom_init_kn02xa(void)
|
||||
{
|
||||
dec_kn_slot_base = KN02XA_SLOT_BASE;
|
||||
dec_kn_slot_size = IOASIC_SLOT_SIZE;
|
||||
dec_tc_bus = 1;
|
||||
|
||||
ioasic_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_IOCTL);
|
||||
dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_TOY);
|
||||
@ -105,6 +107,7 @@ static inline void prom_init_kn03(void)
|
||||
{
|
||||
dec_kn_slot_base = KN03_SLOT_BASE;
|
||||
dec_kn_slot_size = IOASIC_SLOT_SIZE;
|
||||
dec_tc_bus = 1;
|
||||
|
||||
ioasic_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_IOCTL);
|
||||
dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_TOY);
|
||||
|
@ -53,6 +53,8 @@ unsigned long dec_kn_slot_base, dec_kn_slot_size;
|
||||
EXPORT_SYMBOL(dec_kn_slot_base);
|
||||
EXPORT_SYMBOL(dec_kn_slot_size);
|
||||
|
||||
int dec_tc_bus;
|
||||
|
||||
spinlock_t ioasic_ssr_lock;
|
||||
|
||||
volatile u32 *ioasic_base;
|
||||
|
95
arch/mips/dec/tc.c
Normal file
95
arch/mips/dec/tc.c
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* TURBOchannel architecture calls.
|
||||
*
|
||||
* Copyright (c) Harald Koerfgen, 1998
|
||||
* Copyright (c) 2001, 2003, 2005, 2006 Maciej W. Rozycki
|
||||
* Copyright (c) 2005 James Simmons
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU
|
||||
* General Public License. See the file "COPYING" in the main
|
||||
* directory of this archive for more details.
|
||||
*/
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/tc.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/addrspace.h>
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/paccess.h>
|
||||
|
||||
#include <asm/dec/interrupts.h>
|
||||
#include <asm/dec/prom.h>
|
||||
#include <asm/dec/system.h>
|
||||
|
||||
/*
|
||||
* Protected read byte from TURBOchannel slot space.
|
||||
*/
|
||||
int tc_preadb(u8 *valp, void __iomem *addr)
|
||||
{
|
||||
return get_dbe(*valp, (u8 *)addr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get TURBOchannel bus information as specified by the spec, plus
|
||||
* the slot space base address and the number of slots.
|
||||
*/
|
||||
int __init tc_bus_get_info(struct tc_bus *tbus)
|
||||
{
|
||||
if (!dec_tc_bus)
|
||||
return -ENXIO;
|
||||
|
||||
memcpy(&tbus->info, rex_gettcinfo(), sizeof(tbus->info));
|
||||
tbus->slot_base = CPHYSADDR((long)rex_slot_address(0));
|
||||
|
||||
switch (mips_machtype) {
|
||||
case MACH_DS5000_200:
|
||||
tbus->num_tcslots = 7;
|
||||
break;
|
||||
case MACH_DS5000_2X0:
|
||||
case MACH_DS5900:
|
||||
tbus->ext_slot_base = 0x20000000;
|
||||
tbus->ext_slot_size = 0x20000000;
|
||||
/* fall through */
|
||||
case MACH_DS5000_1XX:
|
||||
tbus->num_tcslots = 3;
|
||||
break;
|
||||
case MACH_DS5000_XX:
|
||||
tbus->num_tcslots = 2;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the IRQ for the specified slot.
|
||||
*/
|
||||
void __init tc_device_get_irq(struct tc_dev *tdev)
|
||||
{
|
||||
switch (tdev->slot) {
|
||||
case 0:
|
||||
tdev->interrupt = dec_interrupt[DEC_IRQ_TC0];
|
||||
break;
|
||||
case 1:
|
||||
tdev->interrupt = dec_interrupt[DEC_IRQ_TC1];
|
||||
break;
|
||||
case 2:
|
||||
tdev->interrupt = dec_interrupt[DEC_IRQ_TC2];
|
||||
break;
|
||||
/*
|
||||
* Yuck! DS5000/200 onboard devices
|
||||
*/
|
||||
case 5:
|
||||
tdev->interrupt = dec_interrupt[DEC_IRQ_TC5];
|
||||
break;
|
||||
case 6:
|
||||
tdev->interrupt = dec_interrupt[DEC_IRQ_TC6];
|
||||
break;
|
||||
default:
|
||||
tdev->interrupt = -1;
|
||||
break;
|
||||
}
|
||||
}
|
@ -2545,7 +2545,7 @@ config RIONET_RX_SIZE
|
||||
|
||||
config FDDI
|
||||
bool "FDDI driver support"
|
||||
depends on (PCI || EISA)
|
||||
depends on (PCI || EISA || TC)
|
||||
help
|
||||
Fiber Distributed Data Interface is a high speed local area network
|
||||
design; essentially a replacement for high speed Ethernet. FDDI can
|
||||
@ -2555,11 +2555,31 @@ config FDDI
|
||||
will say N.
|
||||
|
||||
config DEFXX
|
||||
tristate "Digital DEFEA and DEFPA adapter support"
|
||||
depends on FDDI && (PCI || EISA)
|
||||
help
|
||||
This is support for the DIGITAL series of EISA (DEFEA) and PCI
|
||||
(DEFPA) controllers which can connect you to a local FDDI network.
|
||||
tristate "Digital DEFTA/DEFEA/DEFPA adapter support"
|
||||
depends on FDDI && (PCI || EISA || TC)
|
||||
---help---
|
||||
This is support for the DIGITAL series of TURBOchannel (DEFTA),
|
||||
EISA (DEFEA) and PCI (DEFPA) controllers which can connect you
|
||||
to a local FDDI network.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called defxx. If unsure, say N.
|
||||
|
||||
config DEFXX_MMIO
|
||||
bool
|
||||
prompt "Use MMIO instead of PIO" if PCI || EISA
|
||||
depends on DEFXX
|
||||
default n if PCI || EISA
|
||||
default y
|
||||
---help---
|
||||
This instructs the driver to use EISA or PCI memory-mapped I/O
|
||||
(MMIO) as appropriate instead of programmed I/O ports (PIO).
|
||||
Enabling this gives an improvement in processing time in parts
|
||||
of the driver, but it may cause problems with EISA (DEFEA)
|
||||
adapters. TURBOchannel does not have the concept of I/O ports,
|
||||
so MMIO is always used for these (DEFTA) adapters.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config SKFP
|
||||
tristate "SysKonnect FDDI PCI support"
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -26,6 +26,7 @@
|
||||
* 12-Sep-96 LVS Removed packet request header pointers.
|
||||
* 04 Aug 2003 macro Converted to the DMA API.
|
||||
* 23 Oct 2006 macro Big-endian host support.
|
||||
* 14 Dec 2006 macro TURBOchannel support.
|
||||
*/
|
||||
|
||||
#ifndef _DEFXX_H_
|
||||
@ -1471,9 +1472,17 @@ typedef union
|
||||
|
||||
#endif /* __BIG_ENDIAN */
|
||||
|
||||
/* Define TC PDQ CSR offset and length */
|
||||
|
||||
#define PI_TC_K_CSR_OFFSET 0x100000
|
||||
#define PI_TC_K_CSR_LEN 0x40 /* 64 bytes */
|
||||
|
||||
/* Define EISA controller register offsets */
|
||||
|
||||
#define PI_ESIC_K_BURST_HOLDOFF 0x040
|
||||
#define PI_ESIC_K_CSR_IO_LEN 0x80 /* 128 bytes */
|
||||
|
||||
#define PI_DEFEA_K_BURST_HOLDOFF 0x040
|
||||
|
||||
#define PI_ESIC_K_SLOT_ID 0xC80
|
||||
#define PI_ESIC_K_SLOT_CNTRL 0xC84
|
||||
#define PI_ESIC_K_MEM_ADD_CMP_0 0xC85
|
||||
@ -1488,14 +1497,14 @@ typedef union
|
||||
#define PI_ESIC_K_MEM_ADD_LO_CMP_0 0xC8E
|
||||
#define PI_ESIC_K_MEM_ADD_LO_CMP_1 0xC8F
|
||||
#define PI_ESIC_K_MEM_ADD_LO_CMP_2 0xC90
|
||||
#define PI_ESIC_K_IO_CMP_0_0 0xC91
|
||||
#define PI_ESIC_K_IO_CMP_0_1 0xC92
|
||||
#define PI_ESIC_K_IO_CMP_1_0 0xC93
|
||||
#define PI_ESIC_K_IO_CMP_1_1 0xC94
|
||||
#define PI_ESIC_K_IO_CMP_2_0 0xC95
|
||||
#define PI_ESIC_K_IO_CMP_2_1 0xC96
|
||||
#define PI_ESIC_K_IO_CMP_3_0 0xC97
|
||||
#define PI_ESIC_K_IO_CMP_3_1 0xC98
|
||||
#define PI_ESIC_K_IO_ADD_CMP_0_0 0xC91
|
||||
#define PI_ESIC_K_IO_ADD_CMP_0_1 0xC92
|
||||
#define PI_ESIC_K_IO_ADD_CMP_1_0 0xC93
|
||||
#define PI_ESIC_K_IO_ADD_CMP_1_1 0xC94
|
||||
#define PI_ESIC_K_IO_ADD_CMP_2_0 0xC95
|
||||
#define PI_ESIC_K_IO_ADD_CMP_2_1 0xC96
|
||||
#define PI_ESIC_K_IO_ADD_CMP_3_0 0xC97
|
||||
#define PI_ESIC_K_IO_ADD_CMP_3_1 0xC98
|
||||
#define PI_ESIC_K_IO_ADD_MASK_0_0 0xC99
|
||||
#define PI_ESIC_K_IO_ADD_MASK_0_1 0xC9A
|
||||
#define PI_ESIC_K_IO_ADD_MASK_1_0 0xC9B
|
||||
@ -1518,11 +1527,16 @@ typedef union
|
||||
#define PI_ESIC_K_INPUT_PORT 0xCAC
|
||||
#define PI_ESIC_K_OUTPUT_PORT 0xCAD
|
||||
#define PI_ESIC_K_FUNCTION_CNTRL 0xCAE
|
||||
#define PI_ESIC_K_CSR_IO_LEN PI_ESIC_K_FUNCTION_CNTRL+1 /* always last reg + 1 */
|
||||
|
||||
/* Define the value all drivers must write to the function control register. */
|
||||
/* Define the bits in the function control register. */
|
||||
|
||||
#define PI_ESIC_K_FUNCTION_CNTRL_IO_ENB 0x03
|
||||
#define PI_FUNCTION_CNTRL_M_IOCS0 0x01
|
||||
#define PI_FUNCTION_CNTRL_M_IOCS1 0x02
|
||||
#define PI_FUNCTION_CNTRL_M_IOCS2 0x04
|
||||
#define PI_FUNCTION_CNTRL_M_IOCS3 0x08
|
||||
#define PI_FUNCTION_CNTRL_M_MEMCS0 0x10
|
||||
#define PI_FUNCTION_CNTRL_M_MEMCS1 0x20
|
||||
#define PI_FUNCTION_CNTRL_M_DMA 0x80
|
||||
|
||||
/* Define the bits in the slot control register. */
|
||||
|
||||
@ -1540,6 +1554,10 @@ typedef union
|
||||
#define PI_BURST_HOLDOFF_V_RESERVED 1
|
||||
#define PI_BURST_HOLDOFF_V_MEM_MAP 0
|
||||
|
||||
/* Define the implicit mask of the Memory Address Mask Register. */
|
||||
|
||||
#define PI_MEM_ADD_MASK_M 0x3ff
|
||||
|
||||
/*
|
||||
* Define the fields in the IO Compare registers.
|
||||
* The driver must initialize the slot field with the slot ID shifted by the
|
||||
@ -1577,6 +1595,7 @@ typedef union
|
||||
#define DEFEA_PROD_ID_1 0x0130A310 /* DEC product 300, rev 1 */
|
||||
#define DEFEA_PROD_ID_2 0x0230A310 /* DEC product 300, rev 2 */
|
||||
#define DEFEA_PROD_ID_3 0x0330A310 /* DEC product 300, rev 3 */
|
||||
#define DEFEA_PROD_ID_4 0x0430A310 /* DEC product 300, rev 4 */
|
||||
|
||||
/**********************************************/
|
||||
/* Digital PFI Specification v1.0 Definitions */
|
||||
@ -1633,12 +1652,6 @@ typedef union
|
||||
#define PFI_STATUS_V_FIFO_EMPTY 1
|
||||
#define PFI_STATUS_V_DMA_IN_PROGRESS 0
|
||||
|
||||
#define DFX_MAX_EISA_SLOTS 16 /* maximum number of EISA slots to scan */
|
||||
#define DFX_MAX_NUM_BOARDS 8 /* maximum number of adapters supported */
|
||||
|
||||
#define DFX_BUS_TYPE_PCI 0 /* type code for DEC FDDIcontroller/PCI */
|
||||
#define DFX_BUS_TYPE_EISA 1 /* type code for DEC FDDIcontroller/EISA */
|
||||
|
||||
#define DFX_FC_PRH2_PRH1_PRH0 0x54003820 /* Packet Request Header bytes + FC */
|
||||
#define DFX_PRH0_BYTE 0x20 /* Packet Request Header byte 0 */
|
||||
#define DFX_PRH1_BYTE 0x38 /* Packet Request Header byte 1 */
|
||||
@ -1756,10 +1769,11 @@ typedef struct DFX_board_tag
|
||||
/* Store device, bus-specific, and parameter information for this adapter */
|
||||
|
||||
struct net_device *dev; /* pointer to device structure */
|
||||
struct net_device *next;
|
||||
u32 bus_type; /* bus type (0 == PCI, 1 == EISA) */
|
||||
u16 base_addr; /* base I/O address (same as dev->base_addr) */
|
||||
struct pci_dev * pci_dev;
|
||||
union {
|
||||
void __iomem *mem;
|
||||
int port;
|
||||
} base; /* base address */
|
||||
struct device *bus_dev;
|
||||
u32 full_duplex_enb; /* FDDI Full Duplex enable (1 == on, 2 == off) */
|
||||
u32 req_ttrt; /* requested TTRT value (in 80ns units) */
|
||||
u32 burst_size; /* adapter burst size (enumerated) */
|
||||
|
@ -528,12 +528,16 @@ void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs)
|
||||
/* Allocate structure and insert basic data such as SCSI chip frequency
|
||||
* data and a pointer to the device
|
||||
*/
|
||||
struct NCR_ESP* esp_allocate(struct scsi_host_template *tpnt, void *esp_dev)
|
||||
struct NCR_ESP* esp_allocate(struct scsi_host_template *tpnt, void *esp_dev,
|
||||
int hotplug)
|
||||
{
|
||||
struct NCR_ESP *esp, *elink;
|
||||
struct Scsi_Host *esp_host;
|
||||
|
||||
esp_host = scsi_register(tpnt, sizeof(struct NCR_ESP));
|
||||
if (hotplug)
|
||||
esp_host = scsi_host_alloc(tpnt, sizeof(struct NCR_ESP));
|
||||
else
|
||||
esp_host = scsi_register(tpnt, sizeof(struct NCR_ESP));
|
||||
if(!esp_host)
|
||||
panic("Cannot register ESP SCSI host");
|
||||
esp = (struct NCR_ESP *) esp_host->hostdata;
|
||||
|
@ -652,7 +652,7 @@ extern int nesps, esps_in_use, esps_running;
|
||||
|
||||
/* External functions */
|
||||
extern void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs);
|
||||
extern struct NCR_ESP *esp_allocate(struct scsi_host_template *, void *);
|
||||
extern struct NCR_ESP *esp_allocate(struct scsi_host_template *, void *, int);
|
||||
extern void esp_deallocate(struct NCR_ESP *);
|
||||
extern void esp_release(void);
|
||||
extern void esp_initialize(struct NCR_ESP *);
|
||||
|
@ -121,7 +121,8 @@ int __init blz1230_esp_detect(struct scsi_host_template *tpnt)
|
||||
*/
|
||||
address = ZTWO_VADDR(board);
|
||||
eregs = (struct ESP_regs *)(address + REAL_BLZ1230_ESP_ADDR);
|
||||
esp = esp_allocate(tpnt, (void *)board+REAL_BLZ1230_ESP_ADDR);
|
||||
esp = esp_allocate(tpnt, (void *)board + REAL_BLZ1230_ESP_ADDR,
|
||||
0);
|
||||
|
||||
esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7));
|
||||
udelay(5);
|
||||
|
@ -100,7 +100,7 @@ int __init blz2060_esp_detect(struct scsi_host_template *tpnt)
|
||||
unsigned long board = z->resource.start;
|
||||
if (request_mem_region(board+BLZ2060_ESP_ADDR,
|
||||
sizeof(struct ESP_regs), "NCR53C9x")) {
|
||||
esp = esp_allocate(tpnt, (void *)board+BLZ2060_ESP_ADDR);
|
||||
esp = esp_allocate(tpnt, (void *)board + BLZ2060_ESP_ADDR, 0);
|
||||
|
||||
/* Do command transfer with programmed I/O */
|
||||
esp->do_pio_cmds = 1;
|
||||
|
@ -126,7 +126,7 @@ int __init cyber_esp_detect(struct scsi_host_template *tpnt)
|
||||
sizeof(struct ESP_regs));
|
||||
return 0;
|
||||
}
|
||||
esp = esp_allocate(tpnt, (void *)board+CYBER_ESP_ADDR);
|
||||
esp = esp_allocate(tpnt, (void *)board + CYBER_ESP_ADDR, 0);
|
||||
|
||||
/* Do command transfer with programmed I/O */
|
||||
esp->do_pio_cmds = 1;
|
||||
|
@ -98,7 +98,7 @@ int __init cyberII_esp_detect(struct scsi_host_template *tpnt)
|
||||
address = (unsigned long)ZTWO_VADDR(board);
|
||||
eregs = (struct ESP_regs *)(address + CYBERII_ESP_ADDR);
|
||||
|
||||
esp = esp_allocate(tpnt, (void *)board+CYBERII_ESP_ADDR);
|
||||
esp = esp_allocate(tpnt, (void *)board + CYBERII_ESP_ADDR, 0);
|
||||
|
||||
esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7));
|
||||
udelay(5);
|
||||
|
@ -18,7 +18,7 @@
|
||||
* 20001005 - Initialization fixes for 2.4.0-test9
|
||||
* Florian Lohoff <flo@rfc822.org>
|
||||
*
|
||||
* Copyright (C) 2002, 2003, 2005 Maciej W. Rozycki
|
||||
* Copyright (C) 2002, 2003, 2005, 2006 Maciej W. Rozycki
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
@ -30,6 +30,7 @@
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/tc.h>
|
||||
|
||||
#include <asm/dma.h>
|
||||
#include <asm/irq.h>
|
||||
@ -42,7 +43,6 @@
|
||||
#include <asm/dec/ioasic_ints.h>
|
||||
#include <asm/dec/machtype.h>
|
||||
#include <asm/dec/system.h>
|
||||
#include <asm/dec/tc.h>
|
||||
|
||||
#define DEC_SCSI_SREG 0
|
||||
#define DEC_SCSI_DMAREG 0x40000
|
||||
@ -98,51 +98,33 @@ static irqreturn_t scsi_dma_merr_int(int, void *);
|
||||
static irqreturn_t scsi_dma_err_int(int, void *);
|
||||
static irqreturn_t scsi_dma_int(int, void *);
|
||||
|
||||
static int dec_esp_detect(struct scsi_host_template * tpnt);
|
||||
|
||||
static int dec_esp_release(struct Scsi_Host *shost)
|
||||
{
|
||||
if (shost->irq)
|
||||
free_irq(shost->irq, NULL);
|
||||
if (shost->io_port && shost->n_io_port)
|
||||
release_region(shost->io_port, shost->n_io_port);
|
||||
scsi_unregister(shost);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct scsi_host_template driver_template = {
|
||||
.proc_name = "dec_esp",
|
||||
.proc_info = esp_proc_info,
|
||||
static struct scsi_host_template dec_esp_template = {
|
||||
.module = THIS_MODULE,
|
||||
.name = "NCR53C94",
|
||||
.detect = dec_esp_detect,
|
||||
.slave_alloc = esp_slave_alloc,
|
||||
.slave_destroy = esp_slave_destroy,
|
||||
.release = dec_esp_release,
|
||||
.info = esp_info,
|
||||
.queuecommand = esp_queue,
|
||||
.eh_abort_handler = esp_abort,
|
||||
.eh_bus_reset_handler = esp_reset,
|
||||
.slave_alloc = esp_slave_alloc,
|
||||
.slave_destroy = esp_slave_destroy,
|
||||
.proc_info = esp_proc_info,
|
||||
.proc_name = "dec_esp",
|
||||
.can_queue = 7,
|
||||
.this_id = 7,
|
||||
.sg_tablesize = SG_ALL,
|
||||
.cmd_per_lun = 1,
|
||||
.use_clustering = DISABLE_CLUSTERING,
|
||||
};
|
||||
|
||||
|
||||
#include "scsi_module.c"
|
||||
static struct NCR_ESP *dec_esp_platform;
|
||||
|
||||
/***************************************************************** Detection */
|
||||
static int dec_esp_detect(struct scsi_host_template * tpnt)
|
||||
static int dec_esp_platform_probe(void)
|
||||
{
|
||||
struct NCR_ESP *esp;
|
||||
struct ConfigDev *esp_dev;
|
||||
int slot;
|
||||
unsigned long mem_start;
|
||||
int err = 0;
|
||||
|
||||
if (IOASIC) {
|
||||
esp_dev = 0;
|
||||
esp = esp_allocate(tpnt, (void *) esp_dev);
|
||||
esp = esp_allocate(&dec_esp_template, NULL, 1);
|
||||
|
||||
/* Do command transfer with programmed I/O */
|
||||
esp->do_pio_cmds = 1;
|
||||
@ -200,112 +182,175 @@ static int dec_esp_detect(struct scsi_host_template * tpnt)
|
||||
/* Check for differential SCSI-bus */
|
||||
esp->diff = 0;
|
||||
|
||||
err = request_irq(esp->irq, esp_intr, IRQF_DISABLED,
|
||||
"ncr53c94", esp->ehost);
|
||||
if (err)
|
||||
goto err_alloc;
|
||||
err = request_irq(dec_interrupt[DEC_IRQ_ASC_MERR],
|
||||
scsi_dma_merr_int, IRQF_DISABLED,
|
||||
"ncr53c94 error", esp->ehost);
|
||||
if (err)
|
||||
goto err_irq;
|
||||
err = request_irq(dec_interrupt[DEC_IRQ_ASC_ERR],
|
||||
scsi_dma_err_int, IRQF_DISABLED,
|
||||
"ncr53c94 overrun", esp->ehost);
|
||||
if (err)
|
||||
goto err_irq_merr;
|
||||
err = request_irq(dec_interrupt[DEC_IRQ_ASC_DMA], scsi_dma_int,
|
||||
IRQF_DISABLED, "ncr53c94 dma", esp->ehost);
|
||||
if (err)
|
||||
goto err_irq_err;
|
||||
|
||||
esp_initialize(esp);
|
||||
|
||||
if (request_irq(esp->irq, esp_intr, IRQF_DISABLED,
|
||||
"ncr53c94", esp->ehost))
|
||||
goto err_dealloc;
|
||||
if (request_irq(dec_interrupt[DEC_IRQ_ASC_MERR],
|
||||
scsi_dma_merr_int, IRQF_DISABLED,
|
||||
"ncr53c94 error", esp->ehost))
|
||||
goto err_free_irq;
|
||||
if (request_irq(dec_interrupt[DEC_IRQ_ASC_ERR],
|
||||
scsi_dma_err_int, IRQF_DISABLED,
|
||||
"ncr53c94 overrun", esp->ehost))
|
||||
goto err_free_irq_merr;
|
||||
if (request_irq(dec_interrupt[DEC_IRQ_ASC_DMA],
|
||||
scsi_dma_int, IRQF_DISABLED,
|
||||
"ncr53c94 dma", esp->ehost))
|
||||
goto err_free_irq_err;
|
||||
|
||||
}
|
||||
|
||||
if (TURBOCHANNEL) {
|
||||
while ((slot = search_tc_card("PMAZ-AA")) >= 0) {
|
||||
claim_tc_card(slot);
|
||||
|
||||
esp_dev = 0;
|
||||
esp = esp_allocate(tpnt, (void *) esp_dev);
|
||||
|
||||
mem_start = get_tc_base_addr(slot);
|
||||
|
||||
/* Store base addr into esp struct */
|
||||
esp->slot = CPHYSADDR(mem_start);
|
||||
|
||||
esp->dregs = 0;
|
||||
esp->eregs = (void *)CKSEG1ADDR(mem_start +
|
||||
DEC_SCSI_SREG);
|
||||
esp->do_pio_cmds = 1;
|
||||
|
||||
/* Set the command buffer */
|
||||
esp->esp_command = (volatile unsigned char *) pmaz_cmd_buffer;
|
||||
|
||||
/* get virtual dma address for command buffer */
|
||||
esp->esp_command_dvma = virt_to_phys(pmaz_cmd_buffer);
|
||||
|
||||
esp->cfreq = get_tc_speed();
|
||||
|
||||
esp->irq = get_tc_irq_nr(slot);
|
||||
|
||||
/* Required functions */
|
||||
esp->dma_bytes_sent = &dma_bytes_sent;
|
||||
esp->dma_can_transfer = &dma_can_transfer;
|
||||
esp->dma_dump_state = &dma_dump_state;
|
||||
esp->dma_init_read = &pmaz_dma_init_read;
|
||||
esp->dma_init_write = &pmaz_dma_init_write;
|
||||
esp->dma_ints_off = &pmaz_dma_ints_off;
|
||||
esp->dma_ints_on = &pmaz_dma_ints_on;
|
||||
esp->dma_irq_p = &dma_irq_p;
|
||||
esp->dma_ports_p = &dma_ports_p;
|
||||
esp->dma_setup = &pmaz_dma_setup;
|
||||
|
||||
/* Optional functions */
|
||||
esp->dma_barrier = 0;
|
||||
esp->dma_drain = &pmaz_dma_drain;
|
||||
esp->dma_invalidate = 0;
|
||||
esp->dma_irq_entry = 0;
|
||||
esp->dma_irq_exit = 0;
|
||||
esp->dma_poll = 0;
|
||||
esp->dma_reset = 0;
|
||||
esp->dma_led_off = 0;
|
||||
esp->dma_led_on = 0;
|
||||
|
||||
esp->dma_mmu_get_scsi_one = pmaz_dma_mmu_get_scsi_one;
|
||||
esp->dma_mmu_get_scsi_sgl = 0;
|
||||
esp->dma_mmu_release_scsi_one = 0;
|
||||
esp->dma_mmu_release_scsi_sgl = 0;
|
||||
esp->dma_advance_sg = 0;
|
||||
|
||||
if (request_irq(esp->irq, esp_intr, IRQF_DISABLED,
|
||||
"PMAZ_AA", esp->ehost)) {
|
||||
esp_deallocate(esp);
|
||||
release_tc_card(slot);
|
||||
continue;
|
||||
}
|
||||
esp->scsi_id = 7;
|
||||
esp->diff = 0;
|
||||
esp_initialize(esp);
|
||||
err = scsi_add_host(esp->ehost, NULL);
|
||||
if (err) {
|
||||
printk(KERN_ERR "ESP: Unable to register adapter\n");
|
||||
goto err_irq_dma;
|
||||
}
|
||||
|
||||
scsi_scan_host(esp->ehost);
|
||||
|
||||
dec_esp_platform = esp;
|
||||
}
|
||||
|
||||
if(nesps) {
|
||||
printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use);
|
||||
esps_running = esps_in_use;
|
||||
return esps_in_use;
|
||||
}
|
||||
return 0;
|
||||
|
||||
err_free_irq_err:
|
||||
free_irq(dec_interrupt[DEC_IRQ_ASC_ERR], scsi_dma_err_int);
|
||||
err_free_irq_merr:
|
||||
free_irq(dec_interrupt[DEC_IRQ_ASC_MERR], scsi_dma_merr_int);
|
||||
err_free_irq:
|
||||
free_irq(esp->irq, esp_intr);
|
||||
err_dealloc:
|
||||
err_irq_dma:
|
||||
free_irq(dec_interrupt[DEC_IRQ_ASC_DMA], esp->ehost);
|
||||
err_irq_err:
|
||||
free_irq(dec_interrupt[DEC_IRQ_ASC_ERR], esp->ehost);
|
||||
err_irq_merr:
|
||||
free_irq(dec_interrupt[DEC_IRQ_ASC_MERR], esp->ehost);
|
||||
err_irq:
|
||||
free_irq(esp->irq, esp->ehost);
|
||||
err_alloc:
|
||||
esp_deallocate(esp);
|
||||
return 0;
|
||||
scsi_host_put(esp->ehost);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __init dec_esp_probe(struct device *dev)
|
||||
{
|
||||
struct NCR_ESP *esp;
|
||||
resource_size_t start, len;
|
||||
int err;
|
||||
|
||||
esp = esp_allocate(&dec_esp_template, NULL, 1);
|
||||
|
||||
dev_set_drvdata(dev, esp);
|
||||
|
||||
start = to_tc_dev(dev)->resource.start;
|
||||
len = to_tc_dev(dev)->resource.end - start + 1;
|
||||
|
||||
if (!request_mem_region(start, len, dev->bus_id)) {
|
||||
printk(KERN_ERR "%s: Unable to reserve MMIO resource\n",
|
||||
dev->bus_id);
|
||||
err = -EBUSY;
|
||||
goto err_alloc;
|
||||
}
|
||||
|
||||
/* Store base addr into esp struct. */
|
||||
esp->slot = start;
|
||||
|
||||
esp->dregs = 0;
|
||||
esp->eregs = (void *)CKSEG1ADDR(start + DEC_SCSI_SREG);
|
||||
esp->do_pio_cmds = 1;
|
||||
|
||||
/* Set the command buffer. */
|
||||
esp->esp_command = (volatile unsigned char *)pmaz_cmd_buffer;
|
||||
|
||||
/* Get virtual dma address for command buffer. */
|
||||
esp->esp_command_dvma = virt_to_phys(pmaz_cmd_buffer);
|
||||
|
||||
esp->cfreq = tc_get_speed(to_tc_dev(dev)->bus);
|
||||
|
||||
esp->irq = to_tc_dev(dev)->interrupt;
|
||||
|
||||
/* Required functions. */
|
||||
esp->dma_bytes_sent = &dma_bytes_sent;
|
||||
esp->dma_can_transfer = &dma_can_transfer;
|
||||
esp->dma_dump_state = &dma_dump_state;
|
||||
esp->dma_init_read = &pmaz_dma_init_read;
|
||||
esp->dma_init_write = &pmaz_dma_init_write;
|
||||
esp->dma_ints_off = &pmaz_dma_ints_off;
|
||||
esp->dma_ints_on = &pmaz_dma_ints_on;
|
||||
esp->dma_irq_p = &dma_irq_p;
|
||||
esp->dma_ports_p = &dma_ports_p;
|
||||
esp->dma_setup = &pmaz_dma_setup;
|
||||
|
||||
/* Optional functions. */
|
||||
esp->dma_barrier = 0;
|
||||
esp->dma_drain = &pmaz_dma_drain;
|
||||
esp->dma_invalidate = 0;
|
||||
esp->dma_irq_entry = 0;
|
||||
esp->dma_irq_exit = 0;
|
||||
esp->dma_poll = 0;
|
||||
esp->dma_reset = 0;
|
||||
esp->dma_led_off = 0;
|
||||
esp->dma_led_on = 0;
|
||||
|
||||
esp->dma_mmu_get_scsi_one = pmaz_dma_mmu_get_scsi_one;
|
||||
esp->dma_mmu_get_scsi_sgl = 0;
|
||||
esp->dma_mmu_release_scsi_one = 0;
|
||||
esp->dma_mmu_release_scsi_sgl = 0;
|
||||
esp->dma_advance_sg = 0;
|
||||
|
||||
err = request_irq(esp->irq, esp_intr, IRQF_DISABLED, "PMAZ_AA",
|
||||
esp->ehost);
|
||||
if (err) {
|
||||
printk(KERN_ERR "%s: Unable to get IRQ %d\n",
|
||||
dev->bus_id, esp->irq);
|
||||
goto err_resource;
|
||||
}
|
||||
|
||||
esp->scsi_id = 7;
|
||||
esp->diff = 0;
|
||||
esp_initialize(esp);
|
||||
|
||||
err = scsi_add_host(esp->ehost, dev);
|
||||
if (err) {
|
||||
printk(KERN_ERR "%s: Unable to register adapter\n",
|
||||
dev->bus_id);
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
scsi_scan_host(esp->ehost);
|
||||
|
||||
return 0;
|
||||
|
||||
err_irq:
|
||||
free_irq(esp->irq, esp->ehost);
|
||||
|
||||
err_resource:
|
||||
release_mem_region(start, len);
|
||||
|
||||
err_alloc:
|
||||
esp_deallocate(esp);
|
||||
scsi_host_put(esp->ehost);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit dec_esp_platform_remove(void)
|
||||
{
|
||||
struct NCR_ESP *esp = dec_esp_platform;
|
||||
|
||||
free_irq(esp->irq, esp->ehost);
|
||||
esp_deallocate(esp);
|
||||
scsi_host_put(esp->ehost);
|
||||
dec_esp_platform = NULL;
|
||||
}
|
||||
|
||||
static void __exit dec_esp_remove(struct device *dev)
|
||||
{
|
||||
struct NCR_ESP *esp = dev_get_drvdata(dev);
|
||||
|
||||
free_irq(esp->irq, esp->ehost);
|
||||
esp_deallocate(esp);
|
||||
scsi_host_put(esp->ehost);
|
||||
}
|
||||
|
||||
|
||||
/************************************************************* DMA Functions */
|
||||
static irqreturn_t scsi_dma_merr_int(int irq, void *dev_id)
|
||||
{
|
||||
@ -576,3 +621,67 @@ static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp
|
||||
{
|
||||
sp->SCp.ptr = (char *)virt_to_phys(sp->request_buffer);
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_TC
|
||||
static int __init dec_esp_tc_probe(struct device *dev);
|
||||
static int __exit dec_esp_tc_remove(struct device *dev);
|
||||
|
||||
static const struct tc_device_id dec_esp_tc_table[] = {
|
||||
{ "DEC ", "PMAZ-AA " },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(tc, dec_esp_tc_table);
|
||||
|
||||
static struct tc_driver dec_esp_tc_driver = {
|
||||
.id_table = dec_esp_tc_table,
|
||||
.driver = {
|
||||
.name = "dec_esp",
|
||||
.bus = &tc_bus_type,
|
||||
.probe = dec_esp_tc_probe,
|
||||
.remove = __exit_p(dec_esp_tc_remove),
|
||||
},
|
||||
};
|
||||
|
||||
static int __init dec_esp_tc_probe(struct device *dev)
|
||||
{
|
||||
int status = dec_esp_probe(dev);
|
||||
if (!status)
|
||||
get_device(dev);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int __exit dec_esp_tc_remove(struct device *dev)
|
||||
{
|
||||
put_device(dev);
|
||||
dec_esp_remove(dev);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __init dec_esp_init(void)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = tc_register_driver(&dec_esp_tc_driver);
|
||||
if (!status)
|
||||
dec_esp_platform_probe();
|
||||
|
||||
if (nesps) {
|
||||
pr_info("ESP: Total of %d ESP hosts found, "
|
||||
"%d actually in use.\n", nesps, esps_in_use);
|
||||
esps_running = esps_in_use;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void __exit dec_esp_exit(void)
|
||||
{
|
||||
dec_esp_platform_remove();
|
||||
tc_unregister_driver(&dec_esp_tc_driver);
|
||||
}
|
||||
|
||||
|
||||
module_init(dec_esp_init);
|
||||
module_exit(dec_esp_exit);
|
||||
|
@ -142,7 +142,7 @@ int __init fastlane_esp_detect(struct scsi_host_template *tpnt)
|
||||
if (board < 0x1000000) {
|
||||
goto err_release;
|
||||
}
|
||||
esp = esp_allocate(tpnt, (void *)board+FASTLANE_ESP_ADDR);
|
||||
esp = esp_allocate(tpnt, (void *)board + FASTLANE_ESP_ADDR, 0);
|
||||
|
||||
/* Do command transfer with programmed I/O */
|
||||
esp->do_pio_cmds = 1;
|
||||
|
@ -75,7 +75,7 @@ static int jazz_esp_detect(struct scsi_host_template *tpnt)
|
||||
*/
|
||||
if (1) {
|
||||
esp_dev = NULL;
|
||||
esp = esp_allocate(tpnt, (void *) esp_dev);
|
||||
esp = esp_allocate(tpnt, esp_dev, 0);
|
||||
|
||||
/* Do command transfer with programmed I/O */
|
||||
esp->do_pio_cmds = 1;
|
||||
|
@ -351,7 +351,7 @@ int mac_esp_detect(struct scsi_host_template * tpnt)
|
||||
for (chipnum = 0; chipnum < chipspresent; chipnum ++) {
|
||||
struct NCR_ESP * esp;
|
||||
|
||||
esp = esp_allocate(tpnt, (void *) NULL);
|
||||
esp = esp_allocate(tpnt, NULL, 0);
|
||||
esp->eregs = (struct ESP_regs *) get_base(chipnum);
|
||||
|
||||
esp->dma_irq_p = &esp_dafb_dma_irq_p;
|
||||
|
@ -122,7 +122,7 @@ static int mca_esp_detect(struct scsi_host_template *tpnt)
|
||||
if ((slot = mca_find_adapter(*id_to_check, 0)) !=
|
||||
MCA_NOTFOUND)
|
||||
{
|
||||
esp = esp_allocate(tpnt, (void *) NULL);
|
||||
esp = esp_allocate(tpnt, NULL, 0);
|
||||
|
||||
pos[0] = mca_read_stored_pos(slot, 2);
|
||||
pos[1] = mca_read_stored_pos(slot, 3);
|
||||
|
@ -133,7 +133,7 @@ int oktagon_esp_detect(struct scsi_host_template *tpnt)
|
||||
eregs = (struct ESP_regs *)(address + OKTAGON_ESP_ADDR);
|
||||
|
||||
/* This line was 5 lines lower */
|
||||
esp = esp_allocate(tpnt, (void *)board+OKTAGON_ESP_ADDR);
|
||||
esp = esp_allocate(tpnt, (void *)board + OKTAGON_ESP_ADDR, 0);
|
||||
|
||||
/* we have to shift the registers only one bit for oktagon */
|
||||
esp->shift = 1;
|
||||
|
@ -53,7 +53,7 @@ int sun3x_esp_detect(struct scsi_host_template *tpnt)
|
||||
struct ConfigDev *esp_dev;
|
||||
|
||||
esp_dev = 0;
|
||||
esp = esp_allocate(tpnt, (void *) esp_dev);
|
||||
esp = esp_allocate(tpnt, esp_dev, 0);
|
||||
|
||||
/* Do command transfer with DMA */
|
||||
esp->do_pio_cmds = 0;
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
# Object file lists.
|
||||
|
||||
obj-$(CONFIG_TC) += tc.o
|
||||
obj-$(CONFIG_TC) += tc.o tc-driver.o
|
||||
obj-$(CONFIG_ZS) += zs.o
|
||||
obj-$(CONFIG_VT) += lk201.o lk201-map.o lk201-remap.o
|
||||
|
||||
|
110
drivers/tc/tc-driver.c
Normal file
110
drivers/tc/tc-driver.c
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* TURBOchannel driver services.
|
||||
*
|
||||
* Copyright (c) 2005 James Simmons
|
||||
* Copyright (c) 2006 Maciej W. Rozycki
|
||||
*
|
||||
* Loosely based on drivers/dio/dio-driver.c and
|
||||
* drivers/pci/pci-driver.c.
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU
|
||||
* General Public License. See the file "COPYING" in the main
|
||||
* directory of this archive for more details.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/tc.h>
|
||||
|
||||
/**
|
||||
* tc_register_driver - register a new TC driver
|
||||
* @drv: the driver structure to register
|
||||
*
|
||||
* Adds the driver structure to the list of registered drivers
|
||||
* Returns a negative value on error, otherwise 0.
|
||||
* If no error occurred, the driver remains registered even if
|
||||
* no device was claimed during registration.
|
||||
*/
|
||||
int tc_register_driver(struct tc_driver *tdrv)
|
||||
{
|
||||
return driver_register(&tdrv->driver);
|
||||
}
|
||||
EXPORT_SYMBOL(tc_register_driver);
|
||||
|
||||
/**
|
||||
* tc_unregister_driver - unregister a TC driver
|
||||
* @drv: the driver structure to unregister
|
||||
*
|
||||
* Deletes the driver structure from the list of registered TC drivers,
|
||||
* gives it a chance to clean up by calling its remove() function for
|
||||
* each device it was responsible for, and marks those devices as
|
||||
* driverless.
|
||||
*/
|
||||
void tc_unregister_driver(struct tc_driver *tdrv)
|
||||
{
|
||||
driver_unregister(&tdrv->driver);
|
||||
}
|
||||
EXPORT_SYMBOL(tc_unregister_driver);
|
||||
|
||||
/**
|
||||
* tc_match_device - tell if a TC device structure has a matching
|
||||
* TC device ID structure
|
||||
* @tdrv: the TC driver to earch for matching TC device ID strings
|
||||
* @tdev: the TC device structure to match against
|
||||
*
|
||||
* Used by a driver to check whether a TC device present in the
|
||||
* system is in its list of supported devices. Returns the matching
|
||||
* tc_device_id structure or %NULL if there is no match.
|
||||
*/
|
||||
const struct tc_device_id *tc_match_device(struct tc_driver *tdrv,
|
||||
struct tc_dev *tdev)
|
||||
{
|
||||
const struct tc_device_id *id = tdrv->id_table;
|
||||
|
||||
if (id) {
|
||||
while (id->name[0] || id->vendor[0]) {
|
||||
if (strcmp(tdev->name, id->name) == 0 &&
|
||||
strcmp(tdev->vendor, id->vendor) == 0)
|
||||
return id;
|
||||
id++;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(tc_match_device);
|
||||
|
||||
/**
|
||||
* tc_bus_match - Tell if a device structure has a matching
|
||||
* TC device ID structure
|
||||
* @dev: the device structure to match against
|
||||
* @drv: the device driver to search for matching TC device ID strings
|
||||
*
|
||||
* Used by a driver to check whether a TC device present in the
|
||||
* system is in its list of supported devices. Returns 1 if there
|
||||
* is a match or 0 otherwise.
|
||||
*/
|
||||
static int tc_bus_match(struct device *dev, struct device_driver *drv)
|
||||
{
|
||||
struct tc_dev *tdev = to_tc_dev(dev);
|
||||
struct tc_driver *tdrv = to_tc_driver(drv);
|
||||
const struct tc_device_id *id;
|
||||
|
||||
id = tc_match_device(tdrv, tdev);
|
||||
if (id)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct bus_type tc_bus_type = {
|
||||
.name = "tc",
|
||||
.match = tc_bus_match,
|
||||
};
|
||||
EXPORT_SYMBOL(tc_bus_type);
|
||||
|
||||
static int __init tc_driver_init(void)
|
||||
{
|
||||
return bus_register(&tc_bus_type);
|
||||
}
|
||||
|
||||
postcore_initcall(tc_driver_init);
|
337
drivers/tc/tc.c
337
drivers/tc/tc.c
@ -1,254 +1,193 @@
|
||||
/*
|
||||
* tc-init: We assume the TURBOchannel to be up and running so
|
||||
* just probe for Modules and fill in the global data structure
|
||||
* tc_bus.
|
||||
* TURBOchannel bus services.
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
* Copyright (c) Harald Koerfgen, 1998
|
||||
* Copyright (c) 2001, 2003, 2005, 2006 Maciej W. Rozycki
|
||||
* Copyright (c) 2005 James Simmons
|
||||
*
|
||||
* Copyright (c) Harald Koerfgen, 1998
|
||||
* Copyright (c) 2001, 2003, 2005 Maciej W. Rozycki
|
||||
* This file is subject to the terms and conditions of the GNU
|
||||
* General Public License. See the file "COPYING" in the main
|
||||
* directory of this archive for more details.
|
||||
*/
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/tc.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/addrspace.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/paccess.h>
|
||||
|
||||
#include <asm/dec/machtype.h>
|
||||
#include <asm/dec/prom.h>
|
||||
#include <asm/dec/tcinfo.h>
|
||||
#include <asm/dec/tcmodule.h>
|
||||
#include <asm/dec/interrupts.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
slot_info tc_bus[MAX_SLOT];
|
||||
static int num_tcslots;
|
||||
static tcinfo *info;
|
||||
static struct tc_bus tc_bus = {
|
||||
.name = "TURBOchannel",
|
||||
};
|
||||
|
||||
/*
|
||||
* Interface to the world. Read comment in include/asm-mips/tc.h.
|
||||
* Probing for TURBOchannel modules.
|
||||
*/
|
||||
|
||||
int search_tc_card(const char *name)
|
||||
static void __init tc_bus_add_devices(struct tc_bus *tbus)
|
||||
{
|
||||
int slot;
|
||||
slot_info *sip;
|
||||
|
||||
for (slot = 0; slot < num_tcslots; slot++) {
|
||||
sip = &tc_bus[slot];
|
||||
if ((sip->flags & FREE) &&
|
||||
(strncmp(sip->name, name, strlen(name)) == 0)) {
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
void claim_tc_card(int slot)
|
||||
{
|
||||
if (tc_bus[slot].flags & IN_USE) {
|
||||
printk("claim_tc_card: attempting to claim a card already in use\n");
|
||||
return;
|
||||
}
|
||||
tc_bus[slot].flags &= ~FREE;
|
||||
tc_bus[slot].flags |= IN_USE;
|
||||
}
|
||||
|
||||
void release_tc_card(int slot)
|
||||
{
|
||||
if (tc_bus[slot].flags & FREE) {
|
||||
printk("release_tc_card: "
|
||||
"attempting to release a card already free\n");
|
||||
return;
|
||||
}
|
||||
tc_bus[slot].flags &= ~IN_USE;
|
||||
tc_bus[slot].flags |= FREE;
|
||||
}
|
||||
|
||||
unsigned long get_tc_base_addr(int slot)
|
||||
{
|
||||
return tc_bus[slot].base_addr;
|
||||
}
|
||||
|
||||
unsigned long get_tc_irq_nr(int slot)
|
||||
{
|
||||
return tc_bus[slot].interrupt;
|
||||
}
|
||||
|
||||
unsigned long get_tc_speed(void)
|
||||
{
|
||||
return 100000 * (10000 / (unsigned long)info->clk_period);
|
||||
}
|
||||
|
||||
/*
|
||||
* Probing for TURBOchannel modules
|
||||
*/
|
||||
static void __init tc_probe(unsigned long startaddr, unsigned long size,
|
||||
int slots)
|
||||
{
|
||||
unsigned long slotaddr;
|
||||
resource_size_t slotsize = tbus->info.slot_size << 20;
|
||||
resource_size_t extslotsize = tbus->ext_slot_size;
|
||||
resource_size_t slotaddr;
|
||||
resource_size_t extslotaddr;
|
||||
resource_size_t devsize;
|
||||
void __iomem *module;
|
||||
struct tc_dev *tdev;
|
||||
int i, slot, err;
|
||||
long offset;
|
||||
u8 pattern[4];
|
||||
volatile u8 *module;
|
||||
long offset;
|
||||
|
||||
for (slot = 0; slot < slots; slot++) {
|
||||
slotaddr = startaddr + slot * size;
|
||||
module = ioremap_nocache(slotaddr, size);
|
||||
for (slot = 0; slot < tbus->num_tcslots; slot++) {
|
||||
slotaddr = tbus->slot_base + slot * slotsize;
|
||||
extslotaddr = tbus->ext_slot_base + slot * extslotsize;
|
||||
module = ioremap_nocache(slotaddr, slotsize);
|
||||
BUG_ON(!module);
|
||||
|
||||
offset = OLDCARD;
|
||||
offset = TC_OLDCARD;
|
||||
|
||||
err = 0;
|
||||
err |= get_dbe(pattern[0], module + OLDCARD + TC_PATTERN0);
|
||||
err |= get_dbe(pattern[1], module + OLDCARD + TC_PATTERN1);
|
||||
err |= get_dbe(pattern[2], module + OLDCARD + TC_PATTERN2);
|
||||
err |= get_dbe(pattern[3], module + OLDCARD + TC_PATTERN3);
|
||||
if (err) {
|
||||
iounmap(module);
|
||||
continue;
|
||||
}
|
||||
err |= tc_preadb(pattern + 0, module + offset + TC_PATTERN0);
|
||||
err |= tc_preadb(pattern + 1, module + offset + TC_PATTERN1);
|
||||
err |= tc_preadb(pattern + 2, module + offset + TC_PATTERN2);
|
||||
err |= tc_preadb(pattern + 3, module + offset + TC_PATTERN3);
|
||||
if (err)
|
||||
goto out_err;
|
||||
|
||||
if (pattern[0] != 0x55 || pattern[1] != 0x00 ||
|
||||
pattern[2] != 0xaa || pattern[3] != 0xff) {
|
||||
offset = NEWCARD;
|
||||
offset = TC_NEWCARD;
|
||||
|
||||
err = 0;
|
||||
err |= get_dbe(pattern[0], module + TC_PATTERN0);
|
||||
err |= get_dbe(pattern[1], module + TC_PATTERN1);
|
||||
err |= get_dbe(pattern[2], module + TC_PATTERN2);
|
||||
err |= get_dbe(pattern[3], module + TC_PATTERN3);
|
||||
if (err) {
|
||||
iounmap(module);
|
||||
continue;
|
||||
}
|
||||
err |= tc_preadb(pattern + 0,
|
||||
module + offset + TC_PATTERN0);
|
||||
err |= tc_preadb(pattern + 1,
|
||||
module + offset + TC_PATTERN1);
|
||||
err |= tc_preadb(pattern + 2,
|
||||
module + offset + TC_PATTERN2);
|
||||
err |= tc_preadb(pattern + 3,
|
||||
module + offset + TC_PATTERN3);
|
||||
if (err)
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (pattern[0] != 0x55 || pattern[1] != 0x00 ||
|
||||
pattern[2] != 0xaa || pattern[3] != 0xff) {
|
||||
iounmap(module);
|
||||
continue;
|
||||
}
|
||||
pattern[2] != 0xaa || pattern[3] != 0xff)
|
||||
goto out_err;
|
||||
|
||||
/* Found a board, allocate it an entry in the list */
|
||||
tdev = kzalloc(sizeof(*tdev), GFP_KERNEL);
|
||||
if (!tdev) {
|
||||
printk(KERN_ERR "tc%x: unable to allocate tc_dev\n",
|
||||
slot);
|
||||
goto out_err;
|
||||
}
|
||||
sprintf(tdev->dev.bus_id, "tc%x", slot);
|
||||
tdev->bus = tbus;
|
||||
tdev->dev.parent = &tbus->dev;
|
||||
tdev->dev.bus = &tc_bus_type;
|
||||
tdev->slot = slot;
|
||||
|
||||
tc_bus[slot].base_addr = slotaddr;
|
||||
for (i = 0; i < 8; i++) {
|
||||
tc_bus[slot].firmware[i] =
|
||||
module[TC_FIRM_VER + offset + 4 * i];
|
||||
tc_bus[slot].vendor[i] =
|
||||
module[TC_VENDOR + offset + 4 * i];
|
||||
tc_bus[slot].name[i] =
|
||||
module[TC_MODULE + offset + 4 * i];
|
||||
}
|
||||
tc_bus[slot].firmware[8] = 0;
|
||||
tc_bus[slot].vendor[8] = 0;
|
||||
tc_bus[slot].name[8] = 0;
|
||||
/*
|
||||
* Looks unneccesary, but we may change
|
||||
* TC? in the future
|
||||
*/
|
||||
switch (slot) {
|
||||
case 0:
|
||||
tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC0];
|
||||
break;
|
||||
case 1:
|
||||
tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC1];
|
||||
break;
|
||||
case 2:
|
||||
tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC2];
|
||||
break;
|
||||
/*
|
||||
* Yuck! DS5000/200 onboard devices
|
||||
*/
|
||||
case 5:
|
||||
tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC5];
|
||||
break;
|
||||
case 6:
|
||||
tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC6];
|
||||
break;
|
||||
default:
|
||||
tc_bus[slot].interrupt = -1;
|
||||
break;
|
||||
tdev->firmware[i] =
|
||||
readb(module + offset + TC_FIRM_VER + 4 * i);
|
||||
tdev->vendor[i] =
|
||||
readb(module + offset + TC_VENDOR + 4 * i);
|
||||
tdev->name[i] =
|
||||
readb(module + offset + TC_MODULE + 4 * i);
|
||||
}
|
||||
tdev->firmware[8] = 0;
|
||||
tdev->vendor[8] = 0;
|
||||
tdev->name[8] = 0;
|
||||
|
||||
pr_info("%s: %s %s %s\n", tdev->dev.bus_id, tdev->vendor,
|
||||
tdev->name, tdev->firmware);
|
||||
|
||||
devsize = readb(module + offset + TC_SLOT_SIZE);
|
||||
devsize <<= 22;
|
||||
if (devsize <= slotsize) {
|
||||
tdev->resource.start = slotaddr;
|
||||
tdev->resource.end = slotaddr + devsize - 1;
|
||||
} else if (devsize <= extslotsize) {
|
||||
tdev->resource.start = extslotaddr;
|
||||
tdev->resource.end = extslotaddr + devsize - 1;
|
||||
} else {
|
||||
printk(KERN_ERR "%s: Cannot provide slot space "
|
||||
"(%dMiB required, up to %dMiB supported)\n",
|
||||
tdev->dev.bus_id, devsize >> 20,
|
||||
max(slotsize, extslotsize) >> 20);
|
||||
kfree(tdev);
|
||||
goto out_err;
|
||||
}
|
||||
tdev->resource.name = tdev->name;
|
||||
tdev->resource.flags = IORESOURCE_MEM;
|
||||
|
||||
tc_device_get_irq(tdev);
|
||||
|
||||
device_register(&tdev->dev);
|
||||
list_add_tail(&tdev->node, &tbus->devices);
|
||||
|
||||
out_err:
|
||||
iounmap(module);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* the main entry
|
||||
* The main entry.
|
||||
*/
|
||||
static int __init tc_init(void)
|
||||
{
|
||||
int tc_clock;
|
||||
int i;
|
||||
unsigned long slot0addr;
|
||||
unsigned long slot_size;
|
||||
|
||||
if (!TURBOCHANNEL)
|
||||
/* Initialize the TURBOchannel bus */
|
||||
if (tc_bus_get_info(&tc_bus))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < MAX_SLOT; i++) {
|
||||
tc_bus[i].base_addr = 0;
|
||||
tc_bus[i].name[0] = 0;
|
||||
tc_bus[i].vendor[0] = 0;
|
||||
tc_bus[i].firmware[0] = 0;
|
||||
tc_bus[i].interrupt = -1;
|
||||
tc_bus[i].flags = FREE;
|
||||
}
|
||||
INIT_LIST_HEAD(&tc_bus.devices);
|
||||
strcpy(tc_bus.dev.bus_id, "tc");
|
||||
device_register(&tc_bus.dev);
|
||||
|
||||
info = rex_gettcinfo();
|
||||
slot0addr = CPHYSADDR((long)rex_slot_address(0));
|
||||
if (tc_bus.info.slot_size) {
|
||||
unsigned int tc_clock = tc_get_speed(&tc_bus) / 100000;
|
||||
|
||||
switch (mips_machtype) {
|
||||
case MACH_DS5000_200:
|
||||
num_tcslots = 7;
|
||||
break;
|
||||
case MACH_DS5000_1XX:
|
||||
case MACH_DS5000_2X0:
|
||||
case MACH_DS5900:
|
||||
num_tcslots = 3;
|
||||
break;
|
||||
case MACH_DS5000_XX:
|
||||
default:
|
||||
num_tcslots = 2;
|
||||
break;
|
||||
}
|
||||
pr_info("tc: TURBOchannel rev. %d at %d.%d MHz "
|
||||
"(with%s parity)\n", tc_bus.info.revision,
|
||||
tc_clock / 10, tc_clock % 10,
|
||||
tc_bus.info.parity ? "" : "out");
|
||||
|
||||
tc_clock = 10000 / info->clk_period;
|
||||
|
||||
if (info->slot_size && slot0addr) {
|
||||
pr_info("TURBOchannel rev. %d at %d.%d MHz (with%s parity)\n",
|
||||
info->revision, tc_clock / 10, tc_clock % 10,
|
||||
info->parity ? "" : "out");
|
||||
|
||||
slot_size = info->slot_size << 20;
|
||||
|
||||
tc_probe(slot0addr, slot_size, num_tcslots);
|
||||
|
||||
for (i = 0; i < num_tcslots; i++) {
|
||||
if (!tc_bus[i].base_addr)
|
||||
continue;
|
||||
pr_info(" slot %d: %s %s %s\n", i, tc_bus[i].vendor,
|
||||
tc_bus[i].name, tc_bus[i].firmware);
|
||||
tc_bus.resource[0].start = tc_bus.slot_base;
|
||||
tc_bus.resource[0].end = tc_bus.slot_base +
|
||||
(tc_bus.info.slot_size << 20) *
|
||||
tc_bus.num_tcslots - 1;
|
||||
tc_bus.resource[0].name = tc_bus.name;
|
||||
tc_bus.resource[0].flags = IORESOURCE_MEM;
|
||||
if (request_resource(&iomem_resource,
|
||||
&tc_bus.resource[0]) < 0) {
|
||||
printk(KERN_ERR "tc: Cannot reserve resource\n");
|
||||
return 0;
|
||||
}
|
||||
if (tc_bus.ext_slot_size) {
|
||||
tc_bus.resource[1].start = tc_bus.ext_slot_base;
|
||||
tc_bus.resource[1].end = tc_bus.ext_slot_base +
|
||||
tc_bus.ext_slot_size *
|
||||
tc_bus.num_tcslots - 1;
|
||||
tc_bus.resource[1].name = tc_bus.name;
|
||||
tc_bus.resource[1].flags = IORESOURCE_MEM;
|
||||
if (request_resource(&iomem_resource,
|
||||
&tc_bus.resource[1]) < 0) {
|
||||
printk(KERN_ERR
|
||||
"tc: Cannot reserve resource\n");
|
||||
release_resource(&tc_bus.resource[0]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
tc_bus_add_devices(&tc_bus);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
subsys_initcall(tc_init);
|
||||
|
||||
EXPORT_SYMBOL(search_tc_card);
|
||||
EXPORT_SYMBOL(claim_tc_card);
|
||||
EXPORT_SYMBOL(release_tc_card);
|
||||
EXPORT_SYMBOL(get_tc_base_addr);
|
||||
EXPORT_SYMBOL(get_tc_irq_nr);
|
||||
EXPORT_SYMBOL(get_tc_speed);
|
||||
|
@ -1444,8 +1444,8 @@ config FB_PMAG_AA
|
||||
used mainly in the MIPS-based DECstation series.
|
||||
|
||||
config FB_PMAG_BA
|
||||
bool "PMAG-BA TURBOchannel framebuffer support"
|
||||
depends on (FB = y) && TC
|
||||
tristate "PMAG-BA TURBOchannel framebuffer support"
|
||||
depends on FB && TC
|
||||
select FB_CFB_FILLRECT
|
||||
select FB_CFB_COPYAREA
|
||||
select FB_CFB_IMAGEBLIT
|
||||
@ -1454,8 +1454,8 @@ config FB_PMAG_BA
|
||||
used mainly in the MIPS-based DECstation series.
|
||||
|
||||
config FB_PMAGB_B
|
||||
bool "PMAGB-B TURBOchannel framebuffer support"
|
||||
depends on (FB = y) && TC
|
||||
tristate "PMAGB-B TURBOchannel framebuffer support"
|
||||
depends on TC
|
||||
select FB_CFB_FILLRECT
|
||||
select FB_CFB_COPYAREA
|
||||
select FB_CFB_IMAGEBLIT
|
||||
|
@ -15,7 +15,8 @@
|
||||
* Michael Engel <engel@unix-ag.org>,
|
||||
* Karsten Merker <merker@linuxtag.org> and
|
||||
* Harald Koerfgen.
|
||||
* Copyright (c) 2005 Maciej W. Rozycki
|
||||
* Copyright (c) 2005, 2006 Maciej W. Rozycki
|
||||
* Copyright (c) 2005 James Simmons
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General
|
||||
* Public License. See the file COPYING in the main directory of this
|
||||
@ -28,26 +29,21 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/tc.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
#include <asm/dec/tc.h>
|
||||
|
||||
#include <video/pmag-ba-fb.h>
|
||||
|
||||
|
||||
struct pmagbafb_par {
|
||||
struct fb_info *next;
|
||||
volatile void __iomem *mmio;
|
||||
volatile u32 __iomem *dac;
|
||||
int slot;
|
||||
};
|
||||
|
||||
|
||||
static struct fb_info *root_pmagbafb_dev;
|
||||
|
||||
static struct fb_var_screeninfo pmagbafb_defined __initdata = {
|
||||
.xres = 1024,
|
||||
.yres = 864,
|
||||
@ -145,24 +141,19 @@ static void __init pmagbafb_erase_cursor(struct fb_info *info)
|
||||
}
|
||||
|
||||
|
||||
static int __init pmagbafb_init_one(int slot)
|
||||
static int __init pmagbafb_probe(struct device *dev)
|
||||
{
|
||||
struct tc_dev *tdev = to_tc_dev(dev);
|
||||
resource_size_t start, len;
|
||||
struct fb_info *info;
|
||||
struct pmagbafb_par *par;
|
||||
unsigned long base_addr;
|
||||
|
||||
info = framebuffer_alloc(sizeof(struct pmagbafb_par), NULL);
|
||||
info = framebuffer_alloc(sizeof(struct pmagbafb_par), dev);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
par = info->par;
|
||||
par->slot = slot;
|
||||
claim_tc_card(par->slot);
|
||||
|
||||
base_addr = get_tc_base_addr(par->slot);
|
||||
|
||||
par->next = root_pmagbafb_dev;
|
||||
root_pmagbafb_dev = info;
|
||||
dev_set_drvdata(dev, info);
|
||||
|
||||
if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
|
||||
goto err_alloc;
|
||||
@ -172,15 +163,21 @@ static int __init pmagbafb_init_one(int slot)
|
||||
info->var = pmagbafb_defined;
|
||||
info->flags = FBINFO_DEFAULT;
|
||||
|
||||
/* Request the I/O MEM resource. */
|
||||
start = tdev->resource.start;
|
||||
len = tdev->resource.end - start + 1;
|
||||
if (!request_mem_region(start, len, dev->bus_id))
|
||||
goto err_cmap;
|
||||
|
||||
/* MMIO mapping setup. */
|
||||
info->fix.mmio_start = base_addr;
|
||||
info->fix.mmio_start = start;
|
||||
par->mmio = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
|
||||
if (!par->mmio)
|
||||
goto err_cmap;
|
||||
goto err_resource;
|
||||
par->dac = par->mmio + PMAG_BA_BT459;
|
||||
|
||||
/* Frame buffer mapping setup. */
|
||||
info->fix.smem_start = base_addr + PMAG_BA_FBMEM;
|
||||
info->fix.smem_start = start + PMAG_BA_FBMEM;
|
||||
info->screen_base = ioremap_nocache(info->fix.smem_start,
|
||||
info->fix.smem_len);
|
||||
if (!info->screen_base)
|
||||
@ -192,8 +189,10 @@ static int __init pmagbafb_init_one(int slot)
|
||||
if (register_framebuffer(info) < 0)
|
||||
goto err_smem_map;
|
||||
|
||||
pr_info("fb%d: %s frame buffer device in slot %d\n",
|
||||
info->node, info->fix.id, par->slot);
|
||||
get_device(dev);
|
||||
|
||||
pr_info("fb%d: %s frame buffer device at %s\n",
|
||||
info->node, info->fix.id, dev->bus_id);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -204,54 +203,68 @@ static int __init pmagbafb_init_one(int slot)
|
||||
err_mmio_map:
|
||||
iounmap(par->mmio);
|
||||
|
||||
err_resource:
|
||||
release_mem_region(start, len);
|
||||
|
||||
err_cmap:
|
||||
fb_dealloc_cmap(&info->cmap);
|
||||
|
||||
err_alloc:
|
||||
root_pmagbafb_dev = par->next;
|
||||
release_tc_card(par->slot);
|
||||
framebuffer_release(info);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
static void __exit pmagbafb_exit_one(void)
|
||||
static int __exit pmagbafb_remove(struct device *dev)
|
||||
{
|
||||
struct fb_info *info = root_pmagbafb_dev;
|
||||
struct tc_dev *tdev = to_tc_dev(dev);
|
||||
struct fb_info *info = dev_get_drvdata(dev);
|
||||
struct pmagbafb_par *par = info->par;
|
||||
resource_size_t start, len;
|
||||
|
||||
put_device(dev);
|
||||
unregister_framebuffer(info);
|
||||
iounmap(info->screen_base);
|
||||
iounmap(par->mmio);
|
||||
start = tdev->resource.start;
|
||||
len = tdev->resource.end - start + 1;
|
||||
release_mem_region(start, len);
|
||||
fb_dealloc_cmap(&info->cmap);
|
||||
root_pmagbafb_dev = par->next;
|
||||
release_tc_card(par->slot);
|
||||
framebuffer_release(info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialise the framebuffer.
|
||||
* Initialize the framebuffer.
|
||||
*/
|
||||
static const struct tc_device_id pmagbafb_tc_table[] = {
|
||||
{ "DEC ", "PMAG-BA " },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(tc, pmagbafb_tc_table);
|
||||
|
||||
static struct tc_driver pmagbafb_driver = {
|
||||
.id_table = pmagbafb_tc_table,
|
||||
.driver = {
|
||||
.name = "pmagbafb",
|
||||
.bus = &tc_bus_type,
|
||||
.probe = pmagbafb_probe,
|
||||
.remove = __exit_p(pmagbafb_remove),
|
||||
},
|
||||
};
|
||||
|
||||
static int __init pmagbafb_init(void)
|
||||
{
|
||||
int count = 0;
|
||||
int slot;
|
||||
|
||||
#ifndef MODULE
|
||||
if (fb_get_options("pmagbafb", NULL))
|
||||
return -ENXIO;
|
||||
|
||||
while ((slot = search_tc_card("PMAG-BA")) >= 0) {
|
||||
if (pmagbafb_init_one(slot) < 0)
|
||||
break;
|
||||
count++;
|
||||
}
|
||||
return (count > 0) ? 0 : -ENXIO;
|
||||
#endif
|
||||
return tc_register_driver(&pmagbafb_driver);
|
||||
}
|
||||
|
||||
static void __exit pmagbafb_exit(void)
|
||||
{
|
||||
while (root_pmagbafb_dev)
|
||||
pmagbafb_exit_one();
|
||||
tc_unregister_driver(&pmagbafb_driver);
|
||||
}
|
||||
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
* Michael Engel <engel@unix-ag.org>,
|
||||
* Karsten Merker <merker@linuxtag.org> and
|
||||
* Harald Koerfgen.
|
||||
* Copyright (c) 2005 Maciej W. Rozycki
|
||||
* Copyright (c) 2005, 2006 Maciej W. Rozycki
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General
|
||||
* Public License. See the file COPYING in the main directory of this
|
||||
@ -25,18 +25,16 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/tc.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
#include <asm/dec/tc.h>
|
||||
|
||||
#include <video/pmagb-b-fb.h>
|
||||
|
||||
|
||||
struct pmagbbfb_par {
|
||||
struct fb_info *next;
|
||||
volatile void __iomem *mmio;
|
||||
volatile void __iomem *smem;
|
||||
volatile u32 __iomem *sfb;
|
||||
@ -47,8 +45,6 @@ struct pmagbbfb_par {
|
||||
};
|
||||
|
||||
|
||||
static struct fb_info *root_pmagbbfb_dev;
|
||||
|
||||
static struct fb_var_screeninfo pmagbbfb_defined __initdata = {
|
||||
.bits_per_pixel = 8,
|
||||
.red.length = 8,
|
||||
@ -190,8 +186,9 @@ static void __init pmagbbfb_osc_setup(struct fb_info *info)
|
||||
69197, 66000, 65000, 50350, 36000, 32000, 25175
|
||||
};
|
||||
struct pmagbbfb_par *par = info->par;
|
||||
struct tc_bus *tbus = to_tc_dev(info->device)->bus;
|
||||
u32 count0 = 8, count1 = 8, counttc = 16 * 256 + 8;
|
||||
u32 freq0, freq1, freqtc = get_tc_speed() / 250;
|
||||
u32 freq0, freq1, freqtc = tc_get_speed(tbus) / 250;
|
||||
int i, j;
|
||||
|
||||
gp0_write(par, 0); /* select Osc0 */
|
||||
@ -249,26 +246,21 @@ static void __init pmagbbfb_osc_setup(struct fb_info *info)
|
||||
};
|
||||
|
||||
|
||||
static int __init pmagbbfb_init_one(int slot)
|
||||
static int __init pmagbbfb_probe(struct device *dev)
|
||||
{
|
||||
char freq0[12], freq1[12];
|
||||
struct tc_dev *tdev = to_tc_dev(dev);
|
||||
resource_size_t start, len;
|
||||
struct fb_info *info;
|
||||
struct pmagbbfb_par *par;
|
||||
unsigned long base_addr;
|
||||
char freq0[12], freq1[12];
|
||||
u32 vid_base;
|
||||
|
||||
info = framebuffer_alloc(sizeof(struct pmagbbfb_par), NULL);
|
||||
info = framebuffer_alloc(sizeof(struct pmagbbfb_par), dev);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
par = info->par;
|
||||
par->slot = slot;
|
||||
claim_tc_card(par->slot);
|
||||
|
||||
base_addr = get_tc_base_addr(par->slot);
|
||||
|
||||
par->next = root_pmagbbfb_dev;
|
||||
root_pmagbbfb_dev = info;
|
||||
dev_set_drvdata(dev, info);
|
||||
|
||||
if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
|
||||
goto err_alloc;
|
||||
@ -278,16 +270,22 @@ static int __init pmagbbfb_init_one(int slot)
|
||||
info->var = pmagbbfb_defined;
|
||||
info->flags = FBINFO_DEFAULT;
|
||||
|
||||
/* Request the I/O MEM resource. */
|
||||
start = tdev->resource.start;
|
||||
len = tdev->resource.end - start + 1;
|
||||
if (!request_mem_region(start, len, dev->bus_id))
|
||||
goto err_cmap;
|
||||
|
||||
/* MMIO mapping setup. */
|
||||
info->fix.mmio_start = base_addr;
|
||||
info->fix.mmio_start = start;
|
||||
par->mmio = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
|
||||
if (!par->mmio)
|
||||
goto err_cmap;
|
||||
goto err_resource;
|
||||
par->sfb = par->mmio + PMAGB_B_SFB;
|
||||
par->dac = par->mmio + PMAGB_B_BT459;
|
||||
|
||||
/* Frame buffer mapping setup. */
|
||||
info->fix.smem_start = base_addr + PMAGB_B_FBMEM;
|
||||
info->fix.smem_start = start + PMAGB_B_FBMEM;
|
||||
par->smem = ioremap_nocache(info->fix.smem_start, info->fix.smem_len);
|
||||
if (!par->smem)
|
||||
goto err_mmio_map;
|
||||
@ -302,13 +300,15 @@ static int __init pmagbbfb_init_one(int slot)
|
||||
if (register_framebuffer(info) < 0)
|
||||
goto err_smem_map;
|
||||
|
||||
get_device(dev);
|
||||
|
||||
snprintf(freq0, sizeof(freq0), "%u.%03uMHz",
|
||||
par->osc0 / 1000, par->osc0 % 1000);
|
||||
snprintf(freq1, sizeof(freq1), "%u.%03uMHz",
|
||||
par->osc1 / 1000, par->osc1 % 1000);
|
||||
|
||||
pr_info("fb%d: %s frame buffer device in slot %d\n",
|
||||
info->node, info->fix.id, par->slot);
|
||||
pr_info("fb%d: %s frame buffer device at %s\n",
|
||||
info->node, info->fix.id, dev->bus_id);
|
||||
pr_info("fb%d: Osc0: %s, Osc1: %s, Osc%u selected\n",
|
||||
info->node, freq0, par->osc1 ? freq1 : "disabled",
|
||||
par->osc1 != 0);
|
||||
@ -322,54 +322,68 @@ static int __init pmagbbfb_init_one(int slot)
|
||||
err_mmio_map:
|
||||
iounmap(par->mmio);
|
||||
|
||||
err_resource:
|
||||
release_mem_region(start, len);
|
||||
|
||||
err_cmap:
|
||||
fb_dealloc_cmap(&info->cmap);
|
||||
|
||||
err_alloc:
|
||||
root_pmagbbfb_dev = par->next;
|
||||
release_tc_card(par->slot);
|
||||
framebuffer_release(info);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
static void __exit pmagbbfb_exit_one(void)
|
||||
static int __exit pmagbbfb_remove(struct device *dev)
|
||||
{
|
||||
struct fb_info *info = root_pmagbbfb_dev;
|
||||
struct tc_dev *tdev = to_tc_dev(dev);
|
||||
struct fb_info *info = dev_get_drvdata(dev);
|
||||
struct pmagbbfb_par *par = info->par;
|
||||
resource_size_t start, len;
|
||||
|
||||
put_device(dev);
|
||||
unregister_framebuffer(info);
|
||||
iounmap(par->smem);
|
||||
iounmap(par->mmio);
|
||||
start = tdev->resource.start;
|
||||
len = tdev->resource.end - start + 1;
|
||||
release_mem_region(start, len);
|
||||
fb_dealloc_cmap(&info->cmap);
|
||||
root_pmagbbfb_dev = par->next;
|
||||
release_tc_card(par->slot);
|
||||
framebuffer_release(info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialise the framebuffer.
|
||||
* Initialize the framebuffer.
|
||||
*/
|
||||
static const struct tc_device_id pmagbbfb_tc_table[] = {
|
||||
{ "DEC ", "PMAGB-BA" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(tc, pmagbbfb_tc_table);
|
||||
|
||||
static struct tc_driver pmagbbfb_driver = {
|
||||
.id_table = pmagbbfb_tc_table,
|
||||
.driver = {
|
||||
.name = "pmagbbfb",
|
||||
.bus = &tc_bus_type,
|
||||
.probe = pmagbbfb_probe,
|
||||
.remove = __exit_p(pmagbbfb_remove),
|
||||
},
|
||||
};
|
||||
|
||||
static int __init pmagbbfb_init(void)
|
||||
{
|
||||
int count = 0;
|
||||
int slot;
|
||||
|
||||
#ifndef MODULE
|
||||
if (fb_get_options("pmagbbfb", NULL))
|
||||
return -ENXIO;
|
||||
|
||||
while ((slot = search_tc_card("PMAGB-BA")) >= 0) {
|
||||
if (pmagbbfb_init_one(slot) < 0)
|
||||
break;
|
||||
count++;
|
||||
}
|
||||
return (count > 0) ? 0 : -ENXIO;
|
||||
#endif
|
||||
return tc_register_driver(&pmagbbfb_driver);
|
||||
}
|
||||
|
||||
static void __exit pmagbbfb_exit(void)
|
||||
{
|
||||
while (root_pmagbbfb_dev)
|
||||
pmagbbfb_exit_one();
|
||||
tc_unregister_driver(&pmagbbfb_driver);
|
||||
}
|
||||
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* Generic DECstation/DECsystem bits.
|
||||
*
|
||||
* Copyright (C) 2005 Maciej W. Rozycki
|
||||
* Copyright (C) 2005, 2006 Maciej W. Rozycki
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@ -14,5 +14,6 @@
|
||||
#define __ASM_DEC_SYSTEM_H
|
||||
|
||||
extern unsigned long dec_kn_slot_base, dec_kn_slot_size;
|
||||
extern int dec_tc_bus;
|
||||
|
||||
#endif /* __ASM_DEC_SYSTEM_H */
|
||||
|
@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Interface to the TURBOchannel related routines
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* Copyright (c) 1998 Harald Koerfgen
|
||||
*/
|
||||
#ifndef __ASM_DEC_TC_H
|
||||
#define __ASM_DEC_TC_H
|
||||
|
||||
/*
|
||||
* Search for a TURBOchannel Option Module
|
||||
* with a certain name. Returns slot number
|
||||
* of the first card not in use or -ENODEV
|
||||
* if none found.
|
||||
*/
|
||||
extern int search_tc_card(const char *);
|
||||
/*
|
||||
* Marks the card in slot as used
|
||||
*/
|
||||
extern void claim_tc_card(int);
|
||||
/*
|
||||
* Marks the card in slot as free
|
||||
*/
|
||||
extern void release_tc_card(int);
|
||||
/*
|
||||
* Return base address of card in slot
|
||||
*/
|
||||
extern unsigned long get_tc_base_addr(int);
|
||||
/*
|
||||
* Return interrupt number of slot
|
||||
*/
|
||||
extern unsigned long get_tc_irq_nr(int);
|
||||
/*
|
||||
* Return TURBOchannel clock frequency in Hz
|
||||
*/
|
||||
extern unsigned long get_tc_speed(void);
|
||||
|
||||
#endif /* __ASM_DEC_TC_H */
|
@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Various TURBOchannel related stuff
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* Information obtained through the get_tcinfo prom call
|
||||
* created from:
|
||||
*
|
||||
* TURBOchannel Firmware Specification
|
||||
*
|
||||
* EK-TCAAD-FS-004
|
||||
* from Digital Equipment Corporation
|
||||
*
|
||||
* Copyright (c) 1998 Harald Koerfgen
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
int revision;
|
||||
int clk_period;
|
||||
int slot_size;
|
||||
int io_timeout;
|
||||
int dma_range;
|
||||
int max_dma_burst;
|
||||
int parity;
|
||||
int reserved[4];
|
||||
} tcinfo;
|
||||
|
||||
#define MAX_SLOT 7
|
||||
|
||||
typedef struct {
|
||||
unsigned long base_addr;
|
||||
unsigned char name[9];
|
||||
unsigned char vendor[9];
|
||||
unsigned char firmware[9];
|
||||
int interrupt;
|
||||
int flags;
|
||||
} slot_info;
|
||||
|
||||
/*
|
||||
* Values for flags
|
||||
*/
|
||||
#define FREE 1<<0
|
||||
#define IN_USE 1<<1
|
||||
|
||||
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* Offsets for the ROM header locations for
|
||||
* TURBOchannel cards
|
||||
*
|
||||
* created from:
|
||||
*
|
||||
* TURBOchannel Firmware Specification
|
||||
*
|
||||
* EK-TCAAD-FS-004
|
||||
* from Digital Equipment Corporation
|
||||
*
|
||||
* Jan.1998 Harald Koerfgen
|
||||
*/
|
||||
#ifndef __ASM_DEC_TCMODULE_H
|
||||
#define __ASM_DEC_TCMODULE_H
|
||||
|
||||
#define OLDCARD 0x3c0000
|
||||
#define NEWCARD 0x000000
|
||||
|
||||
#define TC_ROM_WIDTH 0x3e0
|
||||
#define TC_ROM_STRIDE 0x3e4
|
||||
#define TC_ROM_SIZE 0x3e8
|
||||
#define TC_SLOT_SIZE 0x3ec
|
||||
#define TC_PATTERN0 0x3f0
|
||||
#define TC_PATTERN1 0x3f4
|
||||
#define TC_PATTERN2 0x3f8
|
||||
#define TC_PATTERN3 0x3fc
|
||||
#define TC_FIRM_VER 0x400
|
||||
#define TC_VENDOR 0x420
|
||||
#define TC_MODULE 0x440
|
||||
#define TC_FIRM_TYPE 0x460
|
||||
#define TC_FLAGS 0x470
|
||||
#define TC_ROM_OBJECTS 0x480
|
||||
|
||||
#endif /* __ASM_DEC_TCMODULE_H */
|
@ -61,10 +61,20 @@ struct eisa_driver {
|
||||
|
||||
#define to_eisa_driver(drv) container_of(drv,struct eisa_driver, driver)
|
||||
|
||||
/* These external functions are only available when EISA support is enabled. */
|
||||
#ifdef CONFIG_EISA
|
||||
|
||||
extern struct bus_type eisa_bus_type;
|
||||
int eisa_driver_register (struct eisa_driver *edrv);
|
||||
void eisa_driver_unregister (struct eisa_driver *edrv);
|
||||
|
||||
#else /* !CONFIG_EISA */
|
||||
|
||||
static inline int eisa_driver_register (struct eisa_driver *edrv) { return 0; }
|
||||
static inline void eisa_driver_unregister (struct eisa_driver *edrv) { }
|
||||
|
||||
#endif /* !CONFIG_EISA */
|
||||
|
||||
/* Mimics pci.h... */
|
||||
static inline void *eisa_get_drvdata (struct eisa_device *edev)
|
||||
{
|
||||
|
141
include/linux/tc.h
Normal file
141
include/linux/tc.h
Normal file
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Interface to the TURBOchannel related routines.
|
||||
*
|
||||
* Copyright (c) 1998 Harald Koerfgen
|
||||
* Copyright (c) 2005 James Simmons
|
||||
* Copyright (c) 2006 Maciej W. Rozycki
|
||||
*
|
||||
* Based on:
|
||||
*
|
||||
* "TURBOchannel Firmware Specification", EK-TCAAD-FS-004
|
||||
*
|
||||
* from Digital Equipment Corporation.
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU
|
||||
* General Public License. See the file "COPYING" in the main
|
||||
* directory of this archive for more details.
|
||||
*/
|
||||
#ifndef _LINUX_TC_H
|
||||
#define _LINUX_TC_H
|
||||
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/*
|
||||
* Offsets for the ROM header locations for TURBOchannel cards.
|
||||
*/
|
||||
#define TC_OLDCARD 0x3c0000
|
||||
#define TC_NEWCARD 0x000000
|
||||
|
||||
#define TC_ROM_WIDTH 0x3e0
|
||||
#define TC_ROM_STRIDE 0x3e4
|
||||
#define TC_ROM_SIZE 0x3e8
|
||||
#define TC_SLOT_SIZE 0x3ec
|
||||
#define TC_PATTERN0 0x3f0
|
||||
#define TC_PATTERN1 0x3f4
|
||||
#define TC_PATTERN2 0x3f8
|
||||
#define TC_PATTERN3 0x3fc
|
||||
#define TC_FIRM_VER 0x400
|
||||
#define TC_VENDOR 0x420
|
||||
#define TC_MODULE 0x440
|
||||
#define TC_FIRM_TYPE 0x460
|
||||
#define TC_FLAGS 0x470
|
||||
#define TC_ROM_OBJECTS 0x480
|
||||
|
||||
/*
|
||||
* Information obtained through the get_tcinfo() PROM call.
|
||||
*/
|
||||
struct tcinfo {
|
||||
s32 revision; /* Hardware revision level. */
|
||||
s32 clk_period; /* Clock period in nanoseconds. */
|
||||
s32 slot_size; /* Slot size in megabytes. */
|
||||
s32 io_timeout; /* I/O timeout in cycles. */
|
||||
s32 dma_range; /* DMA address range in megabytes. */
|
||||
s32 max_dma_burst; /* Maximum DMA burst length. */
|
||||
s32 parity; /* System module supports TC parity. */
|
||||
s32 reserved[4];
|
||||
};
|
||||
|
||||
/*
|
||||
* TURBOchannel bus.
|
||||
*/
|
||||
struct tc_bus {
|
||||
struct list_head devices; /* List of devices on this bus. */
|
||||
struct resource resource[2]; /* Address space routed to this bus. */
|
||||
|
||||
struct device dev;
|
||||
char name[13];
|
||||
resource_size_t slot_base;
|
||||
resource_size_t ext_slot_base;
|
||||
resource_size_t ext_slot_size;
|
||||
int num_tcslots;
|
||||
struct tcinfo info;
|
||||
};
|
||||
|
||||
/*
|
||||
* TURBOchannel device.
|
||||
*/
|
||||
struct tc_dev {
|
||||
struct list_head node; /* Node in list of all TC devices. */
|
||||
struct tc_bus *bus; /* Bus this device is on. */
|
||||
struct tc_driver *driver; /* Which driver has allocated this
|
||||
device. */
|
||||
struct device dev; /* Generic device interface. */
|
||||
struct resource resource; /* Address space of this device. */
|
||||
char vendor[9];
|
||||
char name[9];
|
||||
char firmware[9];
|
||||
int interrupt;
|
||||
int slot;
|
||||
};
|
||||
|
||||
#define to_tc_dev(n) container_of(n, struct tc_dev, dev)
|
||||
|
||||
struct tc_device_id {
|
||||
char vendor[9];
|
||||
char name[9];
|
||||
};
|
||||
|
||||
/*
|
||||
* TURBOchannel driver.
|
||||
*/
|
||||
struct tc_driver {
|
||||
struct list_head node;
|
||||
const struct tc_device_id *id_table;
|
||||
struct device_driver driver;
|
||||
};
|
||||
|
||||
#define to_tc_driver(drv) container_of(drv, struct tc_driver, driver)
|
||||
|
||||
/*
|
||||
* Return TURBOchannel clock frequency in Hz.
|
||||
*/
|
||||
static inline unsigned long tc_get_speed(struct tc_bus *tbus)
|
||||
{
|
||||
return 100000 * (10000 / (unsigned long)tbus->info.clk_period);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TC
|
||||
|
||||
extern struct bus_type tc_bus_type;
|
||||
|
||||
extern int tc_register_driver(struct tc_driver *tdrv);
|
||||
extern void tc_unregister_driver(struct tc_driver *tdrv);
|
||||
|
||||
#else /* !CONFIG_TC */
|
||||
|
||||
static inline int tc_register_driver(struct tc_driver *tdrv) { return 0; }
|
||||
static inline void tc_unregister_driver(struct tc_driver *tdrv) { }
|
||||
|
||||
#endif /* CONFIG_TC */
|
||||
|
||||
/*
|
||||
* These have to be provided by the architecture.
|
||||
*/
|
||||
extern int tc_preadb(u8 *valp, void __iomem *addr);
|
||||
extern int tc_bus_get_info(struct tc_bus *tbus);
|
||||
extern void tc_device_get_irq(struct tc_dev *tdev);
|
||||
|
||||
#endif /* _LINUX_TC_H */
|
Loading…
Reference in New Issue
Block a user