From 34b135e3183d2540f06bb1623d2f4c35cb824beb Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 18 Jan 2003 19:08:18 +0000 Subject: [ARM] Fix printk in rpcmouse.c printk was missing a new line, and displaying the (fixed) IRQ number is rather meaningless. --- drivers/input/mouse/rpcmouse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/mouse/rpcmouse.c b/drivers/input/mouse/rpcmouse.c index d52176323f14..4ceea81ce304 100644 --- a/drivers/input/mouse/rpcmouse.c +++ b/drivers/input/mouse/rpcmouse.c @@ -88,7 +88,7 @@ static int __init rpcmouse_init(void) input_register_device(&rpcmouse_dev); - printk(KERN_INFO "input: Acorn RiscPC mouse irq %d", IRQ_VSYNCPULSE); + printk(KERN_INFO "input: Acorn RiscPC mouse\n"); return 0; } -- cgit v1.2.3 From 073fe9817bab79a303f377a809c57cec959a3b9f Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 18 Jan 2003 19:14:35 +0000 Subject: [ARM] Fix buffer overflow in fas216-based SCSI drivers. 100 characters is too small for the SCSI "info" string buffer; the last few characters appear to get stomped on. Make the buffer 150 characters long. --- drivers/acorn/scsi/arxescsi.c | 2 +- drivers/acorn/scsi/cumana_2.c | 2 +- drivers/acorn/scsi/eesox.c | 2 +- drivers/acorn/scsi/powertec.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/acorn/scsi/arxescsi.c b/drivers/acorn/scsi/arxescsi.c index 6a54f887b61a..01802bfc85ff 100644 --- a/drivers/acorn/scsi/arxescsi.c +++ b/drivers/acorn/scsi/arxescsi.c @@ -262,7 +262,7 @@ static void arxescsi_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp) const char *arxescsi_info(struct Scsi_Host *host) { struct arxescsi_info *info = (struct arxescsi_info *)host->hostdata; - static char string[100], *p; + static char string[150], *p; p = string; p += sprintf(p, "%s ", host->hostt->name); diff --git a/drivers/acorn/scsi/cumana_2.c b/drivers/acorn/scsi/cumana_2.c index 2944d6c79665..900930f3e604 100644 --- a/drivers/acorn/scsi/cumana_2.c +++ b/drivers/acorn/scsi/cumana_2.c @@ -304,7 +304,7 @@ cumanascsi_2_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp) const char *cumanascsi_2_info(struct Scsi_Host *host) { struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata; - static char string[100], *p; + static char string[150], *p; p = string; p += sprintf(p, "%s ", host->hostt->name); diff --git a/drivers/acorn/scsi/eesox.c b/drivers/acorn/scsi/eesox.c index aa4fba599a94..7f2846f25f67 100644 --- a/drivers/acorn/scsi/eesox.c +++ b/drivers/acorn/scsi/eesox.c @@ -307,7 +307,7 @@ eesoxscsi_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp) const char *eesoxscsi_info(struct Scsi_Host *host) { struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata; - static char string[100], *p; + static char string[150], *p; p = string; p += sprintf(p, "%s ", host->hostt->name); diff --git a/drivers/acorn/scsi/powertec.c b/drivers/acorn/scsi/powertec.c index 4bf7e63dc35e..670b19adda59 100644 --- a/drivers/acorn/scsi/powertec.c +++ b/drivers/acorn/scsi/powertec.c @@ -188,7 +188,7 @@ powertecscsi_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp) const char *powertecscsi_info(struct Scsi_Host *host) { struct powertec_info *info = (struct powertec_info *)host->hostdata; - static char string[100], *p; + static char string[150], *p; p = string; p += sprintf(p, "%s ", host->hostt->name); -- cgit v1.2.3 From 2f9da5ab8eb35dff1201f01c8d1282d5a082f042 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 18 Jan 2003 19:23:45 +0000 Subject: [ARM] Fix fas216-based data-phase lockups Ensure SCpnt->request_bufflen is initialised correctly when we request sense information. --- drivers/acorn/scsi/fas216.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/acorn/scsi/fas216.c b/drivers/acorn/scsi/fas216.c index 728f78ac7ce2..5e306d2db63a 100644 --- a/drivers/acorn/scsi/fas216.c +++ b/drivers/acorn/scsi/fas216.c @@ -2213,6 +2213,7 @@ request_sense: SCpnt->SCp.this_residual = sizeof(SCpnt->sense_buffer); SCpnt->SCp.Message = 0; SCpnt->SCp.Status = 0; + SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer); SCpnt->sc_data_direction = SCSI_DATA_READ; SCpnt->use_sg = 0; SCpnt->tag = 0; -- cgit v1.2.3 From 649a49db5dbcff4cc660171df1852eeeb8bab40f Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 18 Jan 2003 19:55:34 +0000 Subject: [ARM] Add soft-cursor support to acornfb and sa1100fb. --- drivers/video/acornfb.c | 1 + drivers/video/sa1100fb.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c index 5ae50460c392..2ba5f133d489 100644 --- a/drivers/video/acornfb.c +++ b/drivers/video/acornfb.c @@ -896,6 +896,7 @@ static struct fb_ops acornfb_ops = { .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, .fb_mmap = acornfb_mmap, + .fb_cursor = soft_cursor, }; /* diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c index 8a562c320c50..39da1994574d 100644 --- a/drivers/video/sa1100fb.c +++ b/drivers/video/sa1100fb.c @@ -1122,6 +1122,7 @@ static struct fb_ops sa1100fb_ops = { .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, .fb_blank = sa1100fb_blank, + .fb_cursor = soft_cursor, }; /* -- cgit v1.2.3 From f78b7ef33a1601764820d9954ed816cc576b391f Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 18 Jan 2003 20:02:05 +0000 Subject: [ARM] Make oops dump reasonble again without kallsyms support enabled. print_symbol() becomes a NOP when CONFIG_KALLSYMS=n, so we loose the new line character as well. Explicitly call printk("\n"). --- arch/arm/kernel/traps.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 3d8f784ce8e4..20cbe15b14d1 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -53,7 +53,8 @@ static const char *handler[]= { "prefetch abort", "data abort", "address excepti void dump_backtrace_entry(unsigned long where, unsigned long from) { printk("Function entered at [<%08lx>] from [<%08lx>]\n", where, from); - print_symbol(" %s\n", where); + print_symbol(" %s", where); + printk("\n"); } /* -- cgit v1.2.3 From bab59d8e79cced9f41a9e97dadd76c454e475459 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 25 Jan 2003 17:07:16 +0000 Subject: [ARM] Drop "alloc" flag for the .stack segment. Some linkers obey the linker script and make .stack unallocatable, others obey the flags from the object files. Dropping "a" should make the end result deterministic in all cases. --- arch/arm/boot/compressed/head.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 1fde5be64c24..90a8f9ad84e2 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -664,5 +664,5 @@ memdump: mov r12, r0 reloc_end: .align - .section ".stack", "aw" + .section ".stack", "w" user_stack: .space 4096 -- cgit v1.2.3 From dde857c28c22b60b8e693e1d987afb405ae68c0b Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 25 Jan 2003 17:11:49 +0000 Subject: [ARM] Add one CPU device to the driver model. Since CPUFreq now uses the driver model, we need to register a CPU device with the driver model. --- arch/arm/kernel/setup.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 02789f5e33fc..991c7490e7d3 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -691,6 +692,15 @@ void __init setup_arch(char **cmdline_p) #endif } +static struct cpu cpu[1]; + +static int __init topology_init(void) +{ + return register_cpu(cpu, 0, NULL); +} + +subsys_initcall(topology_init); + static const char *hwcap_str[] = { "swp", "half", -- cgit v1.2.3 From 2030468e842765184829bb6aed16b67808df290e Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 25 Jan 2003 18:17:42 +0000 Subject: [ARM] Kill build warnings for Integrator PCI V3 driver. --- arch/arm/mach-integrator/pci_v3.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-integrator/pci_v3.c b/arch/arm/mach-integrator/pci_v3.c index 71aa96175a09..f2f73e15a11b 100644 --- a/arch/arm/mach-integrator/pci_v3.c +++ b/arch/arm/mach-integrator/pci_v3.c @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -295,7 +296,7 @@ static int v3_read_config(struct pci_bus *bus, unsigned int devfn, int where, v = __raw_readw(addr); break; - case 4: + default: v = __raw_readl(addr); break; } -- cgit v1.2.3 From 15c2e5448ff3c917af325daf9b49a62e399dba42 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 25 Jan 2003 18:26:32 +0000 Subject: [ARM] Fix KSTK_EIP and KSTK_ESP macros These two macros got missed when converting from the task-struct on stack to thread_info-struct on stack. --- include/asm-arm/proc-armv/processor.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/asm-arm/proc-armv/processor.h b/include/asm-arm/proc-armv/processor.h index 853f411083db..390e887d2037 100644 --- a/include/asm-arm/proc-armv/processor.h +++ b/include/asm-arm/proc-armv/processor.h @@ -23,7 +23,7 @@ #define KERNEL_STACK_SIZE PAGE_SIZE #define INIT_EXTRA_THREAD_INFO \ - cpu_domain: domain_val(DOMAIN_USER, DOMAIN_CLIENT) | \ + .cpu_domain = domain_val(DOMAIN_USER, DOMAIN_CLIENT) | \ domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \ domain_val(DOMAIN_IO, DOMAIN_CLIENT) @@ -45,7 +45,7 @@ regs->ARM_r0 = stack[0]; /* r0 (argc) */ \ }) -#define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1019]) -#define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1017]) +#define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)->thread_info))[1019]) +#define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)->thread_info))[1017]) #endif -- cgit v1.2.3 From a7c4fb648cdfc8d8332d6486fa7b522b7279169c Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 25 Jan 2003 18:33:32 +0000 Subject: [ARM] Add extra IO functionality. Add {read,write}[bwl] functionality to Acorn RISC PC. Add {read,write}s[bwl] functionality for all. --- include/asm-arm/arch-rpc/io.h | 5 +++++ include/asm-arm/io.h | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/include/asm-arm/arch-rpc/io.h b/include/asm-arm/arch-rpc/io.h index 3a1c18ad63bb..3f7a2366cad3 100644 --- a/include/asm-arm/arch-rpc/io.h +++ b/include/asm-arm/arch-rpc/io.h @@ -247,4 +247,9 @@ DECLARE_IO(int,l,"") #define outsb(p,d,l) __raw_writesb(__ioaddr(p),d,l) #define outsw(p,d,l) __raw_writesw(__ioaddr(p),d,l) +/* + * 1:1 mapping for ioremapped regions. + */ +#define __mem_pci(x) (x) + #endif diff --git a/include/asm-arm/io.h b/include/asm-arm/io.h index 1dc1dd5d611a..8bb0d5e1cc9a 100644 --- a/include/asm-arm/io.h +++ b/include/asm-arm/io.h @@ -150,10 +150,18 @@ extern void _memset_io(unsigned long, int, size_t); #define readw(c) ({ unsigned int __v = le16_to_cpu(__raw_readw(__mem_pci(c))); __v; }) #define readl(c) ({ unsigned int __v = le32_to_cpu(__raw_readl(__mem_pci(c))); __v; }) +#define readsb(p,d,l) __raw_readsb((unsigned int)__mem_pci(p),d,l) +#define readsw(p,d,l) __raw_readsw((unsigned int)__mem_pci(p),d,l) +#define readsl(p,d,l) __raw_readsl((unsigned int)__mem_pci(p),d,l) + #define writeb(v,c) __raw_writeb(v,__mem_pci(c)) #define writew(v,c) __raw_writew(cpu_to_le16(v),__mem_pci(c)) #define writel(v,c) __raw_writel(cpu_to_le32(v),__mem_pci(c)) +#define writesb(p,d,l) __raw_writesb((unsigned int)__mem_pci(p),d,l) +#define writesw(p,d,l) __raw_writesw((unsigned int)__mem_pci(p),d,l) +#define writesl(p,d,l) __raw_writesl((unsigned int)__mem_pci(p),d,l) + #define memset_io(c,v,l) _memset_io(__mem_pci(c),(v),(l)) #define memcpy_fromio(a,c,l) _memcpy_fromio((a),__mem_pci(c),(l)) #define memcpy_toio(c,a,l) _memcpy_toio(__mem_pci(c),(a),(l)) -- cgit v1.2.3 From 299c2e8667b2b79a78a3f7f681e443b1a6d0410c Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 26 Jan 2003 14:45:19 +0000 Subject: [ARM] Convert ecard to allow use of ioremap + {read,write}[bwl] --- arch/arm/kernel/ecard.c | 104 +++++++++++++++++++++++++++++++++--- include/asm-arm/arch-rpc/hardware.h | 11 ++++ include/asm-arm/ecard.h | 17 +++++- 3 files changed, 124 insertions(+), 8 deletions(-) diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c index a6c0c1993306..2ce63481432b 100644 --- a/arch/arm/kernel/ecard.c +++ b/arch/arm/kernel/ecard.c @@ -881,6 +881,90 @@ static void ecard_proc_init(void) get_ecard_dev_info); } +#define ec_set_resource(ec,nr,st,sz,flg) \ + do { \ + (ec)->resource[nr].name = ec->dev.name; \ + (ec)->resource[nr].start = st; \ + (ec)->resource[nr].end = (st) + (sz) - 1; \ + (ec)->resource[nr].flags = flg; \ + } while (0) + +static void __init ecard_init_resources(struct expansion_card *ec) +{ + unsigned long base = PODSLOT_IOC4_BASE; + unsigned int slot = ec->slot_no; + int i; + + if (slot < 4) { + ec_set_resource(ec, ECARD_RES_MEMC, + PODSLOT_MEMC_BASE + (slot << 14), + PODSLOT_MEMC_SIZE, IORESOURCE_MEM); + base = PODSLOT_IOC0_BASE; + } + +#ifdef CONFIG_ARCH_RPC + if (slot < 8) { + ec_set_resource(ec, ECARD_RES_EASI, + PODSLOT_EASI_BASE + (slot << 24), + PODSLOT_EASI_SIZE, IORESOURCE_MEM); + } + + if (slot == 8) { + ec_set_resource(ec, ECARD_RES_MEMC, NETSLOT_BASE, + NETSLOT_SIZE, IORESOURCE_MEM); + } else +#endif + + for (i = 0; i < ECARD_RES_IOCSYNC - ECARD_RES_IOCSLOW; i++) { + ec_set_resource(ec, i + ECARD_RES_IOCSLOW, + base + (slot << 14) + (i << 19), + PODSLOT_IOC_SIZE, IORESOURCE_MEM); + } + + for (i = 0; i < ECARD_NUM_RESOURCES; i++) { + if (ec->resource[i].start && + request_resource(&iomem_resource, &ec->resource[i])) { + printk(KERN_ERR "%s: resource(s) not available\n", + ec->dev.bus_id); + ec->resource[i].end -= ec->resource[i].start; + ec->resource[i].start = 0; + } + } +} + +static ssize_t ecard_show_irq(struct device *dev, char *buf) +{ + struct expansion_card *ec = ECARD_DEV(dev); + return sprintf(buf, "%u\n", ec->irq); +} + +static DEVICE_ATTR(irq, S_IRUGO, ecard_show_irq, NULL); + +static ssize_t ecard_show_dma(struct device *dev, char *buf) +{ + struct expansion_card *ec = ECARD_DEV(dev); + return sprintf(buf, "%u\n", ec->dma); +} + +static DEVICE_ATTR(dma, S_IRUGO, ecard_show_dma, NULL); + +static ssize_t ecard_show_resources(struct device *dev, char *buf) +{ + struct expansion_card *ec = ECARD_DEV(dev); + char *str = buf; + int i; + + for (i = 0; i < ECARD_NUM_RESOURCES; i++) + str += sprintf(str, "%08lx %08lx %08lx\n", + ec->resource[i].start, + ec->resource[i].end, + ec->resource[i].flags); + + return str - buf; +} + +static DEVICE_ATTR(resource, S_IRUGO, ecard_show_resources, NULL); + /* * Probe for an expansion card. * @@ -949,6 +1033,16 @@ ecard_probe(int slot, card_type_t type) break; } + snprintf(ec->dev.bus_id, sizeof(ec->dev.bus_id), "ecard%d", slot); + snprintf(ec->dev.name, sizeof(ec->dev.name), "ecard %04x:%04x", + ec->cid.manufacturer, ec->cid.product); + ec->dev.parent = NULL; + ec->dev.bus = &ecard_bus_type; + ec->dev.dma_mask = &ec->dma_mask; + ec->dma_mask = (u64)0xffffffff; + + ecard_init_resources(ec); + /* * hook the interrupt handlers */ @@ -974,14 +1068,10 @@ ecard_probe(int slot, card_type_t type) *ecp = ec; slot_to_expcard[slot] = ec; - snprintf(ec->dev.bus_id, sizeof(ec->dev.bus_id), "ecard%d", slot); - strcpy(ec->dev.name, "fixme!"); - ec->dev.parent = NULL; - ec->dev.bus = &ecard_bus_type; - ec->dev.dma_mask = &ec->dma_mask; - ec->dma_mask = (u64)0xffffffff; - device_register(&ec->dev); + device_create_file(&ec->dev, &dev_attr_dma); + device_create_file(&ec->dev, &dev_attr_irq); + device_create_file(&ec->dev, &dev_attr_resource); return 0; diff --git a/include/asm-arm/arch-rpc/hardware.h b/include/asm-arm/arch-rpc/hardware.h index a25d8394ffc5..9dc5f5d4b912 100644 --- a/include/asm-arm/arch-rpc/hardware.h +++ b/include/asm-arm/arch-rpc/hardware.h @@ -63,6 +63,17 @@ #define IO_EC_MEMC8_BASE 0x8000ac00 #define IO_EC_MEMC_BASE 0x80000000 +#define NETSLOT_BASE 0x0302b000 +#define NETSLOT_SIZE 0x00001000 + +#define PODSLOT_IOC0_BASE 0x03240000 +#define PODSLOT_IOC4_BASE 0x03270000 +#define PODSLOT_IOC_SIZE (1 << 14) +#define PODSLOT_MEMC_BASE 0x03000000 +#define PODSLOT_MEMC_SIZE (1 << 14) +#define PODSLOT_EASI_BASE 0x08000000 +#define PODSLOT_EASI_SIZE (1 << 24) + #define EXPMASK_STATUS (EXPMASK_BASE + 0x00) #define EXPMASK_ENABLE (EXPMASK_BASE + 0x04) diff --git a/include/asm-arm/ecard.h b/include/asm-arm/ecard.h index 602dc63b9dfa..89c1d1db4b7b 100644 --- a/include/asm-arm/ecard.h +++ b/include/asm-arm/ecard.h @@ -130,6 +130,20 @@ typedef struct { /* Card handler routines */ int (*fiqpending)(ecard_t *ec); } expansioncard_ops_t; +#define ECARD_NUM_RESOURCES (6) + +#define ECARD_RES_IOCSLOW (0) +#define ECARD_RES_IOCMEDIUM (1) +#define ECARD_RES_IOCFAST (2) +#define ECARD_RES_IOCSYNC (3) +#define ECARD_RES_MEMC (4) +#define ECARD_RES_EASI (5) + +#define ecard_resource_start(ec,nr) ((ec)->resource[nr].start) +#define ecard_resource_end(ec,nr) ((ec)->resource[nr].end) +#define ecard_resource_len(ec,nr) ((ec)->resource[nr].end - \ + (ec)->resource[nr].start + 1) + /* * This contains all the info needed on an expansion card */ @@ -137,6 +151,7 @@ struct expansion_card { struct expansion_card *next; struct device dev; + struct resource resource[ECARD_NUM_RESOURCES]; /* Public data */ volatile unsigned char *irqaddr; /* address of IRQ register */ @@ -147,7 +162,7 @@ struct expansion_card { void *irq_data; /* Data for use for IRQ by card */ void *fiq_data; /* Data for use for FIQ by card */ - expansioncard_ops_t *ops; /* Enable/Disable Ops for card */ + const expansioncard_ops_t *ops; /* Enable/Disable Ops for card */ CONST unsigned int slot_no; /* Slot number */ CONST unsigned int dma; /* DMA number (for request_dma) */ -- cgit v1.2.3 From cc0f78fc03d0be2da7cbdc559fa08492a4ecd517 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 26 Jan 2003 19:35:44 +0000 Subject: [ARM] Update Acorn SCSI drivers - Add scsi devclass support. - Convert to use ioremap and friends. - Fix oops which can occur when driver claims interrupt, and there's an interrupt pending - move to a two-level fas driver initialisation. --- drivers/acorn/scsi/acornscsi.c | 3 +- drivers/acorn/scsi/arxescsi.c | 212 +++++------ drivers/acorn/scsi/cumana_1.c | 3 +- drivers/acorn/scsi/cumana_2.c | 182 +++++----- drivers/acorn/scsi/eesox.c | 415 ++++++++++++++-------- drivers/acorn/scsi/fas216.c | 771 ++++++++++++++++++++++------------------- drivers/acorn/scsi/fas216.h | 91 +++-- drivers/acorn/scsi/oak.c | 3 +- drivers/acorn/scsi/powertec.c | 181 ++++++---- drivers/acorn/scsi/scsi.h | 6 +- 10 files changed, 1043 insertions(+), 824 deletions(-) diff --git a/drivers/acorn/scsi/acornscsi.c b/drivers/acorn/scsi/acornscsi.c index f37ff3f411ce..ff126d11e6ad 100644 --- a/drivers/acorn/scsi/acornscsi.c +++ b/drivers/acorn/scsi/acornscsi.c @@ -3110,7 +3110,8 @@ static struct ecard_driver acornscsi_driver = { .remove = __devexit_p(acornscsi_remove), .id_table = acornscsi_cids, .drv = { - .name = "acornscsi", + .devclass = &shost_devclass, + .name = "acornscsi", }, }; diff --git a/drivers/acorn/scsi/arxescsi.c b/drivers/acorn/scsi/arxescsi.c index 01802bfc85ff..5e1606280dc7 100644 --- a/drivers/acorn/scsi/arxescsi.c +++ b/drivers/acorn/scsi/arxescsi.c @@ -40,33 +40,18 @@ #include "fas216.h" struct arxescsi_info { - FAS216_Info info; - - /* other info... */ - unsigned int cstatus; /* card status register */ - unsigned int dmaarea; /* Pseudo DMA area */ + FAS216_Info info; + struct expansion_card *ec; }; -#define CSTATUS_IRQ (1 << 0) -#define CSTATUS_DRQ (1 << 0) - -#ifndef CAN_QUEUE -#define CAN_QUEUE 1 -#endif +#define DMADATA_OFFSET (0x200) -#ifndef CMD_PER_LUN -#define CMD_PER_LUN 1 -#endif +#define DMASTAT_OFFSET (0x600) +#define DMASTAT_DRQ (1 << 0) -/* Hmm - this should go somewhere else */ -#define BUS_ADDR(x) ((((unsigned long)(x)) << 2) + IO_BASE) +#define CSTATUS_IRQ (1 << 0) -/* - * Version - */ -#define VER_MAJOR 0 -#define VER_MINOR 1 -#define VER_PATCH 1 +#define VERSION "1.10 (23/01/2003 2.5.57)" /* * Function: int arxescsi_dma_setup(host, SCpnt, direction, min_type) @@ -87,44 +72,7 @@ arxescsi_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp, return fasdma_pseudo; } - - -/* Faster transfer routines, written by SH to speed up the loops */ - -static inline unsigned char getb(unsigned int address, unsigned int reg) -{ - unsigned char value; - - __asm__ __volatile__( - "ldrb %0, [%1, %2, lsl #5]" - : "=r" (value) - : "r" (address), "r" (reg) ); - return value; -} - -static inline unsigned int getw(unsigned int address, unsigned int reg) -{ - unsigned int value; - - __asm__ __volatile__( - "ldr %0, [%1, %2, lsl #5]\n\t" - "mov %0, %0, lsl #16\n\t" - "mov %0, %0, lsr #16" - : "=r" (value) - : "r" (address), "r" (reg) ); - return value; -} - -static inline void putw(unsigned int address, unsigned int reg, unsigned long value) -{ - __asm__ __volatile__( - "mov %0, %0, lsl #16\n\t" - "str %0, [%1, %2, lsl #5]" - : - : "r" (value), "r" (address), "r" (reg) ); -} - -void arxescsi_pseudo_dma_write(unsigned char *addr, unsigned int io) +static void arxescsi_pseudo_dma_write(unsigned char *addr, unsigned char *base) { __asm__ __volatile__( " stmdb sp!, {r0-r12}\n" @@ -149,7 +97,7 @@ void arxescsi_pseudo_dma_write(unsigned char *addr, unsigned int io) " bne .loop_1\n" " ldmia sp!, {r0-r12}\n" : - : "r" (addr), "r" (io) ); + : "r" (addr), "r" (base)); } /* @@ -160,40 +108,41 @@ void arxescsi_pseudo_dma_write(unsigned char *addr, unsigned int io) * direction - DMA on to/off of card * transfer - minimum number of bytes we expect to transfer */ -void arxescsi_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp, - fasdmadir_t direction, int transfer) +static void +arxescsi_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp, + fasdmadir_t direction, int transfer) { struct arxescsi_info *info = (struct arxescsi_info *)host->hostdata; - unsigned int length, io, error=0; + unsigned int length, error = 0; + unsigned char *base = info->info.scsi.io_base; unsigned char *addr; length = SCp->this_residual; addr = SCp->ptr; - io = __ioaddr(host->io_port); if (direction == DMA_OUT) { unsigned int word; while (length > 256) { - if (getb(io, 4) & STAT_INT) { - error=1; + if (readb(base + 0x80) & STAT_INT) { + error = 1; break; } - arxescsi_pseudo_dma_write(addr, io); + arxescsi_pseudo_dma_write(addr, base); addr += 256; length -= 256; } if (!error) while (length > 0) { - if (getb(io, 4) & STAT_INT) + if (readb(base + 0x80) & STAT_INT) break; - if (!(getb(io, 48) & CSTATUS_IRQ)) + if (!(readb(base + DMASTAT_OFFSET) & DMASTAT_DRQ)) continue; word = *addr | *(addr + 1) << 8; - putw(io, 16, word); + writew(word, base + DMADATA_OFFSET); if (length > 1) { addr += 2; length -= 2; @@ -206,15 +155,15 @@ void arxescsi_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp, else { if (transfer && (transfer & 255)) { while (length >= 256) { - if (getb(io, 4) & STAT_INT) { - error=1; + if (readb(base + 0x80) & STAT_INT) { + error = 1; break; } - if (!(getb(io, 48) & CSTATUS_IRQ)) + if (!(readb(base + DMASTAT_OFFSET) & DMASTAT_DRQ)) continue; - insw(info->dmaarea, addr, 256 >> 1); + readsw(base + DMADATA_OFFSET, addr, 256 >> 1); addr += 256; length -= 256; } @@ -224,13 +173,13 @@ void arxescsi_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp, while (length > 0) { unsigned long word; - if (getb(io, 4) & STAT_INT) + if (readb(base + 0x80) & STAT_INT) break; - if (!(getb(io, 48) & CSTATUS_IRQ)) + if (!(readb(base + DMASTAT_OFFSET) & DMASTAT_DRQ)) continue; - word = getw(io, 16); + word = readw(base + DMADATA_OFFSET); *addr++ = word; if (--length > 0) { *addr++ = word >> 8; @@ -259,15 +208,14 @@ static void arxescsi_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp) * Params : host - driver host structure to return info for. * Returns : pointer to a static buffer containing null terminated string. */ -const char *arxescsi_info(struct Scsi_Host *host) +static const char *arxescsi_info(struct Scsi_Host *host) { struct arxescsi_info *info = (struct arxescsi_info *)host->hostdata; - static char string[150], *p; + static char string[150]; - p = string; - p += sprintf(p, "%s ", host->hostt->name); - p += fas216_info(&info->info, p); - p += sprintf(p, "v%d.%d.%d", VER_MAJOR, VER_MINOR, VER_PATCH); + sprintf(string, "%s (%s) in slot %d v%s", + host->hostt->name, info->info.scsi.type, info->ec->slot_no, + VERSION); return string; } @@ -286,8 +234,9 @@ const char *arxescsi_info(struct Scsi_Host *host) * inout - 0 for reading, 1 for writing. * Returns : length of data written to buffer. */ -int arxescsi_proc_info(char *buffer, char **start, off_t offset, - int length, int host_no, int inout) +static int +arxescsi_proc_info(char *buffer, char **start, off_t offset, int length, + int host_no, int inout) { int pos, begin; struct Scsi_Host *host; @@ -303,9 +252,7 @@ int arxescsi_proc_info(char *buffer, char **start, off_t offset, return -EINVAL; begin = 0; - pos = sprintf(buffer, - "ARXE 16-bit SCSI driver version %d.%d.%d\n", - VER_MAJOR, VER_MINOR, VER_PATCH); + pos = sprintf(buffer, "ARXE 16-bit SCSI driver v%s\n", VERSION); pos += fas216_print_host(&info->info, buffer + pos); pos += fas216_print_stats(&info->info, buffer + pos); @@ -343,7 +290,7 @@ static Scsi_Host_Template arxescsi_template = { .can_queue = 0, .this_id = 7, .sg_tablesize = SG_ALL, - .cmd_per_lun = CMD_PER_LUN, + .cmd_per_lun = 1, .use_clustering = DISABLE_CLUSTERING, .proc_name = "arxescsi", }; @@ -352,21 +299,41 @@ static int __devinit arxescsi_probe(struct expansion_card *ec, const struct ecard_id *id) { struct Scsi_Host *host; - struct arxescsi_info *info; - int ret = -ENOMEM; + struct arxescsi_info *info; + unsigned long resbase, reslen; + unsigned char *base; + int ret; - host = scsi_register(&arxescsi_template, sizeof(struct arxescsi_info)); - if (!host) + resbase = ecard_resource_start(ec, ECARD_RES_MEMC); + reslen = ecard_resource_len(ec, ECARD_RES_MEMC); + + if (!request_mem_region(resbase, reslen, "arxescsi")) { + ret = -EBUSY; goto out; + } - host->io_port = ecard_address(ec, ECARD_MEMC, 0) + 0x0800; + base = ioremap(resbase, reslen); + if (!base) { + ret = -ENOMEM; + goto out_region; + } + + host = scsi_register(&arxescsi_template, sizeof(struct arxescsi_info)); + if (!host) { + ret = -ENOMEM; + goto out_unmap; + } + + host->base = (unsigned long)base; host->irq = NO_IRQ; host->dma_channel = NO_DMA; info = (struct arxescsi_info *)host->hostdata; - info->info.scsi.io_port = host->io_port; + info->ec = ec; + + info->info.scsi.io_base = base + 0x2000; info->info.scsi.irq = host->irq; - info->info.scsi.io_shift = 3; + info->info.scsi.io_shift = 5; info->info.ifcfg.clockrate = 24; /* MHz */ info->info.ifcfg.select_timeout = 255; info->info.ifcfg.asyncperiod = 200; /* ns */ @@ -374,39 +341,29 @@ arxescsi_probe(struct expansion_card *ec, const struct ecard_id *id) info->info.ifcfg.cntl3 = CNTL3_FASTSCSI | CNTL3_FASTCLK; info->info.ifcfg.disconnect_ok = 0; info->info.ifcfg.wide_max_size = 0; + info->info.ifcfg.capabilities = FASCAP_PSEUDODMA; info->info.dma.setup = arxescsi_dma_setup; info->info.dma.pseudo = arxescsi_dma_pseudo; info->info.dma.stop = arxescsi_dma_stop; - info->dmaarea = host->io_port + 128; - info->cstatus = host->io_port + 384; - ec->irqaddr = (unsigned char *)BUS_ADDR(host->io_port); + ec->irqaddr = base; ec->irqmask = CSTATUS_IRQ; - if (!request_region(host->io_port, 120, "arxescsi-fas")) { - ret = -EBUSY; - goto out_free; - } - - if (!request_region(host->io_port + 128, 384, "arxescsi-dma")) { - ret = -EBUSY; - goto out_release; - } - - printk("scsi%d: Has no interrupts - using polling mode\n", - host->host_no); + ret = fas216_init(host); + if (ret) + goto out_unregister; - fas216_init(host); - - ret = scsi_add_host(host, &ec->dev); + ret = fas216_add(host, &ec->dev); if (ret == 0) goto out; - release_region(host->io_port + 128, 384); - out_release: - release_region(host->io_port, 120); - out_free: + fas216_release(host); + out_unregister: scsi_unregister(host); + out_unmap: + iounmap(base); + out_region: + release_mem_region(resbase, reslen); out: return ret; } @@ -414,13 +371,19 @@ arxescsi_probe(struct expansion_card *ec, const struct ecard_id *id) static void __devexit arxescsi_remove(struct expansion_card *ec) { struct Scsi_Host *host = ecard_get_drvdata(ec); + unsigned long resbase, reslen; ecard_set_drvdata(ec, NULL); - scsi_remove_host(host); - fas216_release(host); + fas216_remove(host); + + iounmap((void *)host->base); + + resbase = ecard_resource_start(ec, ECARD_RES_MEMC); + reslen = ecard_resource_len(ec, ECARD_RES_MEMC); - release_region(host->io_port + 128, 384); - release_region(host->io_port, 120); + release_mem_region(resbase, reslen); + + fas216_release(host); scsi_unregister(host); } @@ -434,7 +397,8 @@ static struct ecard_driver arxescsi_driver = { .remove = __devexit_p(arxescsi_remove), .id_table = arxescsi_cids, .drv = { - .name = "arxescsi", + .devclass = &shost_devclass, + .name = "arxescsi", }, }; diff --git a/drivers/acorn/scsi/cumana_1.c b/drivers/acorn/scsi/cumana_1.c index 4da215d97759..9ccaee561d5e 100644 --- a/drivers/acorn/scsi/cumana_1.c +++ b/drivers/acorn/scsi/cumana_1.c @@ -334,7 +334,8 @@ static struct ecard_driver cumanascsi1_driver = { .remove = __devexit_p(cumanascsi1_remove), .id_table = cumanascsi1_cids, .drv = { - .name = "cumanascsi1", + .devclass = &shost_devclass, + .name = "cumanascsi1", }, }; diff --git a/drivers/acorn/scsi/cumana_2.c b/drivers/acorn/scsi/cumana_2.c index 900930f3e604..43a1f6734adb 100644 --- a/drivers/acorn/scsi/cumana_2.c +++ b/drivers/acorn/scsi/cumana_2.c @@ -41,12 +41,12 @@ #include -#define CUMANASCSI2_STATUS (0) +#define CUMANASCSI2_STATUS (0x0000) #define STATUS_INT (1 << 0) #define STATUS_DRQ (1 << 1) #define STATUS_LATCHED (1 << 3) -#define CUMANASCSI2_ALATCH (5) +#define CUMANASCSI2_ALATCH (0x0014) #define ALATCH_ENA_INT (3) #define ALATCH_DIS_INT (2) #define ALATCH_ENA_TERM (5) @@ -58,11 +58,10 @@ #define ALATCH_DMA_OUT (15) #define ALATCH_DMA_IN (14) -#define CUMANASCSI2_PSEUDODMA (0x80) +#define CUMANASCSI2_PSEUDODMA (0x0200) -#define CUMANASCSI2_FAS216_OFFSET (0xc0) -#define CUMANASCSI2_FAS216_SHIFT 0 -#define CUMANASCSI2_FAS216_SIZE (16) +#define CUMANASCSI2_FAS216_OFFSET (0x0300) +#define CUMANASCSI2_FAS216_SHIFT 2 /* * Version @@ -77,13 +76,14 @@ static int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 }; #define NR_SG 256 struct cumanascsi2_info { - FAS216_Info info; - - unsigned int status; /* card status register */ - unsigned int alatch; /* Control register */ - unsigned int terms; /* Terminator state */ - unsigned int dmaarea; /* Pseudo DMA area */ - struct scatterlist sg[NR_SG]; /* Scatter DMA list */ + FAS216_Info info; + struct expansion_card *ec; + + void *status; /* card status register */ + void *alatch; /* Control register */ + unsigned int terms; /* Terminator state */ + void *dmaarea; /* Pseudo DMA area */ + struct scatterlist sg[NR_SG]; /* Scatter DMA list */ }; #define CSTATUS_IRQ (1 << 0) @@ -97,8 +97,7 @@ struct cumanascsi2_info { static void cumanascsi_2_irqenable(struct expansion_card *ec, int irqnr) { - unsigned int port = (unsigned int)ec->irq_data; - outb(ALATCH_ENA_INT, port); + writeb(ALATCH_ENA_INT, ec->irq_data); } /* Prototype: void cumanascsi_2_irqdisable(ec, irqnr) @@ -109,8 +108,7 @@ cumanascsi_2_irqenable(struct expansion_card *ec, int irqnr) static void cumanascsi_2_irqdisable(struct expansion_card *ec, int irqnr) { - unsigned int port = (unsigned int)ec->irq_data; - outb(ALATCH_DIS_INT, port); + writeb(ALATCH_DIS_INT, ec->irq_data); } static const expansioncard_ops_t cumanascsi_2_ops = { @@ -130,10 +128,10 @@ cumanascsi_2_terminator_ctl(struct Scsi_Host *host, int on_off) if (on_off) { info->terms = 1; - outb (ALATCH_ENA_TERM, info->alatch); + writeb(ALATCH_ENA_TERM, info->alatch); } else { info->terms = 0; - outb (ALATCH_DIS_TERM, info->alatch); + writeb(ALATCH_DIS_TERM, info->alatch); } } @@ -146,9 +144,9 @@ cumanascsi_2_terminator_ctl(struct Scsi_Host *host, int on_off) static void cumanascsi_2_intr(int irq, void *dev_id, struct pt_regs *regs) { - struct Scsi_Host *host = (struct Scsi_Host *)dev_id; + struct cumanascsi2_info *info = dev_id; - fas216_intr(host); + fas216_intr(&info->info); } /* Prototype: fasdmatype_t cumanascsi_2_dma_setup(host, SCpnt, direction, min_type) @@ -167,7 +165,7 @@ cumanascsi_2_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp, struct device *dev = scsi_get_device(host); int dmach = host->dma_channel; - outb(ALATCH_DIS_DMA, info->alatch); + writeb(ALATCH_DIS_DMA, info->alatch); if (dmach != NO_DMA && (min_type == fasdma_real_all || SCp->this_residual >= 512)) { @@ -188,11 +186,11 @@ cumanascsi_2_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp, disable_dma(dmach); set_dma_sg(dmach, info->sg, bufs + 1); - outb(alatch_dir, info->alatch); + writeb(alatch_dir, info->alatch); set_dma_mode(dmach, dma_dir); enable_dma(dmach); - outb(ALATCH_ENA_DMA, info->alatch); - outb(ALATCH_DIS_BIT32, info->alatch); + writeb(ALATCH_ENA_DMA, info->alatch); + writeb(ALATCH_DIS_BIT32, info->alatch); return fasdma_real_all; } @@ -226,7 +224,7 @@ cumanascsi_2_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp, #if 0 while (length > 1) { unsigned long word; - unsigned int status = inb(info->status); + unsigned int status = readb(info->status); if (status & STATUS_INT) goto end; @@ -235,7 +233,7 @@ cumanascsi_2_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp, continue; word = *addr | *(addr + 1) << 8; - outw (info->dmaarea); + writew(word, info->dmaarea); addr += 2; length -= 2; } @@ -245,15 +243,15 @@ cumanascsi_2_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp, else { if (transfer && (transfer & 255)) { while (length >= 256) { - unsigned int status = inb(info->status); + unsigned int status = readb(info->status); if (status & STATUS_INT) - goto end; + return; if (!(status & STATUS_DRQ)) continue; - insw(info->dmaarea, addr, 256 >> 1); + readsw(info->dmaarea, addr, 256 >> 1); addr += 256; length -= 256; } @@ -261,15 +259,15 @@ cumanascsi_2_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp, while (length > 0) { unsigned long word; - unsigned int status = inb(info->status); + unsigned int status = readb(info->status); if (status & STATUS_INT) - goto end; + return; if (!(status & STATUS_DRQ)) continue; - word = inw (info->dmaarea); + word = readw(info->dmaarea); *addr++ = word; if (--length > 0) { *addr++ = word >> 8; @@ -277,8 +275,6 @@ cumanascsi_2_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp, } } } - -end: } /* Prototype: int cumanascsi_2_dma_stop(host, SCpnt) @@ -291,7 +287,7 @@ cumanascsi_2_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp) { struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata; if (host->dma_channel != NO_DMA) { - outb(ALATCH_DIS_DMA, info->alatch); + writeb(ALATCH_DIS_DMA, info->alatch); disable_dma(host->dma_channel); } } @@ -304,13 +300,11 @@ cumanascsi_2_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp) const char *cumanascsi_2_info(struct Scsi_Host *host) { struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata; - static char string[150], *p; + static char string[150]; - p = string; - p += sprintf(p, "%s ", host->hostt->name); - p += fas216_info(&info->info, p); - p += sprintf(p, "v%s terminators o%s", - VERSION, info->terms ? "n" : "ff"); + sprintf(string, "%s (%s) in slot %d v%s terminators o%s", + host->hostt->name, info->info.scsi.type, info->ec->slot_no, + VERSION, info->terms ? "n" : "ff"); return string; } @@ -377,10 +371,7 @@ int cumanascsi_2_proc_info (char *buffer, char **start, off_t offset, info = (struct cumanascsi2_info *)host->hostdata; begin = 0; - pos = sprintf(buffer, - "Cumana SCSI II driver version v%s\n", - VERSION); - + pos = sprintf(buffer, "Cumana SCSI II driver v%s\n", VERSION); pos += fas216_print_host(&info->info, buffer + pos); pos += sprintf(buffer + pos, "Term : o%s\n", info->terms ? "n" : "ff"); @@ -440,38 +431,52 @@ static int __devinit cumanascsi2_probe(struct expansion_card *ec, const struct ecard_id *id) { struct Scsi_Host *host; - struct cumanascsi2_info *info; - int ret = -ENOMEM; + struct cumanascsi2_info *info; + unsigned long resbase, reslen; + unsigned char *base; + int ret; - host = scsi_register(&cumanascsi2_template, sizeof (struct cumanascsi2_info)); - if (!host) + resbase = ecard_resource_start(ec, ECARD_RES_MEMC); + reslen = ecard_resource_len(ec, ECARD_RES_MEMC); + + if (!request_mem_region(resbase, reslen, "cumanascsi2")) { + ret = -EBUSY; goto out; + } - host->io_port = ecard_address(ec, ECARD_MEMC, 0); - host->irq = ec->irq; - host->dma_channel = ec->dma; + base = ioremap(resbase, reslen); + if (!base) { + ret = -ENOMEM; + goto out_region; + } - if (!request_region(host->io_port + CUMANASCSI2_FAS216_OFFSET, - CUMANASCSI2_FAS216_SIZE, "cumanascsi2-fas")) { - ret = -EBUSY; - goto out_free; + host = scsi_register(&cumanascsi2_template, + sizeof(struct cumanascsi2_info)); + if (!host) { + ret = -ENOMEM; + goto out_unmap; } + host->base = (unsigned long)base; + host->irq = ec->irq; + host->dma_channel = ec->dma; + ecard_set_drvdata(ec, host); info = (struct cumanascsi2_info *)host->hostdata; - info->dmaarea = host->io_port + CUMANASCSI2_PSEUDODMA; - info->status = host->io_port + CUMANASCSI2_STATUS; - info->alatch = host->io_port + CUMANASCSI2_ALATCH; + info->ec = ec; + info->dmaarea = base + CUMANASCSI2_PSEUDODMA; + info->status = base + CUMANASCSI2_STATUS; + info->alatch = base + CUMANASCSI2_ALATCH; - ec->irqaddr = (unsigned char *)ioaddr(info->status); + ec->irqaddr = info->status; ec->irqmask = STATUS_INT; - ec->irq_data = (void *)info->alatch; - ec->ops = (expansioncard_ops_t *)&cumanascsi_2_ops; + ec->irq_data = base + CUMANASCSI2_ALATCH; + ec->ops = &cumanascsi_2_ops; cumanascsi_2_terminator_ctl(host, term[ec->slot_no]); - info->info.scsi.io_port = host->io_port + CUMANASCSI2_FAS216_OFFSET; + info->info.scsi.io_base = base + CUMANASCSI2_FAS216_OFFSET; info->info.scsi.io_shift = CUMANASCSI2_FAS216_SHIFT; info->info.scsi.irq = host->irq; info->info.ifcfg.clockrate = 40; /* MHz */ @@ -481,16 +486,21 @@ cumanascsi2_probe(struct expansion_card *ec, const struct ecard_id *id) info->info.ifcfg.cntl3 = CNTL3_BS8 | CNTL3_FASTSCSI | CNTL3_FASTCLK; info->info.ifcfg.disconnect_ok = 1; info->info.ifcfg.wide_max_size = 0; + info->info.ifcfg.capabilities = FASCAP_PSEUDODMA; info->info.dma.setup = cumanascsi_2_dma_setup; info->info.dma.pseudo = cumanascsi_2_dma_pseudo; info->info.dma.stop = cumanascsi_2_dma_stop; + ret = fas216_init(host); + if (ret) + goto out_free; + ret = request_irq(host->irq, cumanascsi_2_intr, - SA_INTERRUPT, "cumanascsi2", host); + SA_INTERRUPT, "cumanascsi2", info); if (ret) { printk("scsi%d: IRQ%d not free: %d\n", host->host_no, host->irq, ret); - goto out_region; + goto out_release; } if (host->dma_channel != NO_DMA) { @@ -500,26 +510,30 @@ cumanascsi2_probe(struct expansion_card *ec, const struct ecard_id *id) host->dma_channel = NO_DMA; } else { set_dma_speed(host->dma_channel, 180); + info->info.ifcfg.capabilities |= FASCAP_DMA; } } - fas216_init(host); - - ret = scsi_add_host(host, &ec->dev); + ret = fas216_add(host, &ec->dev); if (ret == 0) goto out; - fas216_release(host); - if (host->dma_channel != NO_DMA) free_dma(host->dma_channel); free_irq(host->irq, host); - out_region: - release_region(host->io_port + CUMANASCSI2_FAS216_OFFSET, - CUMANASCSI2_FAS216_SIZE); + + out_release: + fas216_release(host); + out_free: scsi_unregister(host); + out_unmap: + iounmap(base); + + out_region: + release_mem_region(resbase, reslen); + out: return ret; } @@ -527,17 +541,24 @@ cumanascsi2_probe(struct expansion_card *ec, const struct ecard_id *id) static void __devexit cumanascsi2_remove(struct expansion_card *ec) { struct Scsi_Host *host = ecard_get_drvdata(ec); + struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata; + unsigned long resbase, reslen; ecard_set_drvdata(ec, NULL); - scsi_remove_host(host); - fas216_release(host); + fas216_remove(host); if (host->dma_channel != NO_DMA) free_dma(host->dma_channel); - free_irq(host->irq, host); - release_region(host->io_port + CUMANASCSI2_FAS216_OFFSET, - CUMANASCSI2_FAS216_SIZE); + free_irq(host->irq, info); + iounmap((void *)host->base); + + resbase = ecard_resource_start(ec, ECARD_RES_MEMC); + reslen = ecard_resource_len(ec, ECARD_RES_MEMC); + + release_mem_region(resbase, reslen); + + fas216_release(host); scsi_unregister(host); } @@ -551,7 +572,8 @@ static struct ecard_driver cumanascsi2_driver = { .remove = __devexit_p(cumanascsi2_remove), .id_table = cumanascsi2_cids, .drv = { - .name = "cumanascsi2", + .devclass = &shost_devclass, + .name = "cumanascsi2", }, }; diff --git a/drivers/acorn/scsi/eesox.c b/drivers/acorn/scsi/eesox.c index 7f2846f25f67..a3885d8636fd 100644 --- a/drivers/acorn/scsi/eesox.c +++ b/drivers/acorn/scsi/eesox.c @@ -1,7 +1,7 @@ /* * linux/drivers/acorn/scsi/eesox.c * - * Copyright (C) 1997-2002 Russell King + * Copyright (C) 1997-2003 Russell King * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -47,25 +47,21 @@ #include -#define EESOX_FAS216_OFFSET 0xc00 -#define EESOX_FAS216_SHIFT 3 -#define EESOX_FAS216_SIZE (16 << EESOX_FAS216_SHIFT) +#define EESOX_FAS216_OFFSET 0x3000 +#define EESOX_FAS216_SHIFT 5 -#define EESOX_STATUS 0xa00 +#define EESOX_DMASTAT 0x2800 #define EESOX_STAT_INTR 0x01 #define EESOX_STAT_DMA 0x02 -#define EESOX_CONTROL 0xa00 +#define EESOX_CONTROL 0x2800 #define EESOX_INTR_ENABLE 0x04 #define EESOX_TERM_ENABLE 0x02 #define EESOX_RESET 0x01 -#define EESOX_DMA_OFFSET 0xe00 +#define EESOX_DMADATA 0x3800 -/* - * Version - */ -#define VERSION "1.00 (13/11/2002 2.5.47)" +#define VERSION "1.10 (17/01/2003 2.5.59)" /* * Use term=0,1,0,0,0 to turn terminators on/off @@ -75,12 +71,12 @@ static int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 }; #define NR_SG 256 struct eesoxscsi_info { - FAS216_Info info; + FAS216_Info info; + struct expansion_card *ec; - unsigned int ctl_port; - unsigned int control; - unsigned int dmaarea; /* Pseudo DMA area */ - struct scatterlist sg[NR_SG]; /* Scatter DMA list */ + void *ctl_port; + unsigned int control; + struct scatterlist sg[NR_SG]; /* Scatter DMA list */ }; /* Prototype: void eesoxscsi_irqenable(ec, irqnr) @@ -95,7 +91,7 @@ eesoxscsi_irqenable(struct expansion_card *ec, int irqnr) info->control |= EESOX_INTR_ENABLE; - outb(info->control, info->ctl_port); + writeb(info->control, info->ctl_port); } /* Prototype: void eesoxscsi_irqdisable(ec, irqnr) @@ -110,7 +106,7 @@ eesoxscsi_irqdisable(struct expansion_card *ec, int irqnr) info->control &= ~EESOX_INTR_ENABLE; - outb(info->control, info->ctl_port); + writeb(info->control, info->ctl_port); } static const expansioncard_ops_t eesoxscsi_ops = { @@ -135,7 +131,7 @@ eesoxscsi_terminator_ctl(struct Scsi_Host *host, int on_off) else info->control &= ~EESOX_TERM_ENABLE; - outb(info->control, info->ctl_port); + writeb(info->control, info->ctl_port); spin_unlock_irqrestore(host->host_lock, flags); } @@ -148,9 +144,9 @@ eesoxscsi_terminator_ctl(struct Scsi_Host *host, int on_off) static void eesoxscsi_intr(int irq, void *dev_id, struct pt_regs *regs) { - struct Scsi_Host *host = (struct Scsi_Host *)dev_id; + struct eesoxscsi_info *info = dev_id; - fas216_intr(host); + fas216_intr(&info->info); } /* Prototype: fasdmatype_t eesoxscsi_dma_setup(host, SCpnt, direction, min_type) @@ -198,93 +194,164 @@ eesoxscsi_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp, return fasdma_pseudo; } -static void -eesoxscsi_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp, - fasdmadir_t dir, int transfer_size) +static void eesoxscsi_buffer_in(void *buf, int length, void *base) { - struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata; - unsigned int status; - unsigned int length = SCp->this_residual; - union { - unsigned char *c; - unsigned short *s; - unsigned long *l; - } buffer; + const void *reg_fas = base + EESOX_FAS216_OFFSET; + const void *reg_dmastat = base + EESOX_DMASTAT; + const void *reg_dmadata = base + EESOX_DMADATA; + const register unsigned long mask = 0xffff; + + do { + unsigned int status; + + /* + * Interrupt request? + */ + status = readb(reg_fas + (REG_STAT << EESOX_FAS216_SHIFT)); + if (status & STAT_INT) + break; + + /* + * DMA request active? + */ + status = readb(reg_dmastat); + if (!(status & EESOX_STAT_DMA)) + continue; + + /* + * Get number of bytes in FIFO + */ + status = readb(reg_fas + (REG_CFIS << EESOX_FAS216_SHIFT)) & CFIS_CF; + if (status > 16) + status = 16; + if (status > length) + status = length; + + /* + * Align buffer. + */ + if (((u32)buf) & 2 && status >= 2) { + *((u16 *)buf)++ = readl(reg_dmadata); + status -= 2; + length -= 2; + } - buffer.c = SCp->ptr; + if (status >= 8) { + unsigned long l1, l2; + + l1 = readl(reg_dmadata) & mask; + l1 |= readl(reg_dmadata) << 16; + l2 = readl(reg_dmadata) & mask; + l2 |= readl(reg_dmadata) << 16; + *((u32 *)buf)++ = l1; + *((u32 *)buf)++ = l2; + length -= 8; + continue; + } - status = inb(host->io_port + EESOX_STATUS); - if (dir == DMA_IN) { - while (length > 8) { - if (status & EESOX_STAT_DMA) { - unsigned long l1, l2; - - l1 = inw(info->dmaarea); - l1 |= inw(info->dmaarea) << 16; - l2 = inw(info->dmaarea); - l2 |= inw(info->dmaarea) << 16; - *buffer.l++ = l1; - *buffer.l++ = l2; - length -= 8; - } else if (status & EESOX_STAT_INTR) - goto end; - status = inb(host->io_port + EESOX_STATUS); + if (status >= 4) { + unsigned long l1; + + l1 = readl(reg_dmadata) & mask; + l1 |= readl(reg_dmadata) << 16; + + *((u32 *)buf)++ = l1; + length -= 4; + continue; } - while (length > 1) { - if (status & EESOX_STAT_DMA) { - *buffer.s++ = inw(info->dmaarea); - length -= 2; - } else if (status & EESOX_STAT_INTR) - goto end; - status = inb(host->io_port + EESOX_STATUS); + if (status >= 2) { + *((u16 *)buf)++ = readl(reg_dmadata); + length -= 2; } + } while (length); +} - while (length > 0) { - if (status & EESOX_STAT_DMA) { - *buffer.c++ = inw(info->dmaarea); - length -= 1; - } else if (status & EESOX_STAT_INTR) - goto end; - status = inb(host->io_port + EESOX_STATUS); +static void eesoxscsi_buffer_out(void *buf, int length, void *base) +{ + const void *reg_fas = base + EESOX_FAS216_OFFSET; + const void *reg_dmastat = base + EESOX_DMASTAT; + const void *reg_dmadata = base + EESOX_DMADATA; + + do { + unsigned int status; + + /* + * Interrupt request? + */ + status = readb(reg_fas + (REG_STAT << EESOX_FAS216_SHIFT)); + if (status & STAT_INT) + break; + + /* + * DMA request active? + */ + status = readb(reg_dmastat); + if (!(status & EESOX_STAT_DMA)) + continue; + + /* + * Get number of bytes in FIFO + */ + status = readb(reg_fas + (REG_CFIS << EESOX_FAS216_SHIFT)) & CFIS_CF; + if (status > 16) + status = 16; + status = 16 - status; + if (status > length) + status = length; + status &= ~1; + + /* + * Align buffer. + */ + if (((u32)buf) & 2 && status >= 2) { + writel(*((u16 *)buf)++ << 16, reg_dmadata); + status -= 2; + length -= 2; } - } else { - while (length > 8) { - if (status & EESOX_STAT_DMA) { - unsigned long l1, l2; - - l1 = *buffer.l++; - l2 = *buffer.l++; - - outw(l1, info->dmaarea); - outw(l1 >> 16, info->dmaarea); - outw(l2, info->dmaarea); - outw(l2 >> 16, info->dmaarea); - length -= 8; - } else if (status & EESOX_STAT_INTR) - goto end; - status = inb(host->io_port + EESOX_STATUS); + + if (status >= 8) { + unsigned long l1, l2; + + l1 = *((u32 *)buf)++; + l2 = *((u32 *)buf)++; + + writel(l1 << 16, reg_dmadata); + writel(l1, reg_dmadata); + writel(l2 << 16, reg_dmadata); + writel(l2, reg_dmadata); + length -= 8; + continue; } - while (length > 1) { - if (status & EESOX_STAT_DMA) { - outw(*buffer.s++, info->dmaarea); - length -= 2; - } else if (status & EESOX_STAT_INTR) - goto end; - status = inb(host->io_port + EESOX_STATUS); + if (status >= 4) { + unsigned long l1; + + l1 = *((u32 *)buf)++; + + writel(l1 << 16, reg_dmadata); + writel(l1, reg_dmadata); + length -= 4; + continue; } - while (length > 0) { - if (status & EESOX_STAT_DMA) { - outw(*buffer.c++, info->dmaarea); - length -= 1; - } else if (status & EESOX_STAT_INTR) - goto end; - status = inb(host->io_port + EESOX_STATUS); + if (status >= 2) { + writel(*((u16 *)buf)++ << 16, reg_dmadata); + length -= 2; } + } while (length); +} + +static void +eesoxscsi_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp, + fasdmadir_t dir, int transfer_size) +{ + void *base = (void *)host->base; + if (dir == DMA_IN) { + eesoxscsi_buffer_in(SCp->ptr, SCp->this_residual, base); + } else { + eesoxscsi_buffer_out(SCp->ptr, SCp->this_residual, base); } -end: } /* Prototype: int eesoxscsi_dma_stop(host, SCpnt) @@ -307,14 +374,11 @@ eesoxscsi_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp) const char *eesoxscsi_info(struct Scsi_Host *host) { struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata; - static char string[150], *p; + static char string[150]; - p = string; - p += sprintf(p, "%s ", host->hostt->name); - p += fas216_info(&info->info, p); - p += sprintf(p, "v%s terminators o%s", - VERSION, - info->control & EESOX_TERM_ENABLE ? "n" : "ff"); + sprintf(string, "%s (%s) in slot %d v%s terminators o%s", + host->hostt->name, info->info.scsi.type, info->ec->slot_no, + VERSION, info->control & EESOX_TERM_ENABLE ? "n" : "ff"); return string; } @@ -381,9 +445,7 @@ int eesoxscsi_proc_info(char *buffer, char **start, off_t offset, info = (struct eesoxscsi_info *)host->hostdata; begin = 0; - pos = sprintf(buffer, - "EESOX SCSI driver version v%s\n", - VERSION); + pos = sprintf(buffer, "EESOX SCSI driver v%s\n", VERSION); pos += fas216_print_host(&info->info, buffer + pos); pos += sprintf(buffer + pos, "Term : o%s\n", info->control & EESOX_TERM_ENABLE ? "n" : "ff"); @@ -417,6 +479,39 @@ int eesoxscsi_proc_info(char *buffer, char **start, off_t offset, return pos; } +static ssize_t eesoxscsi_show_term(struct device *dev, char *buf) +{ + struct expansion_card *ec = ECARD_DEV(dev); + struct Scsi_Host *host = ecard_get_drvdata(ec); + struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata; + + return sprintf(buf, "%d\n", info->control & EESOX_TERM_ENABLE ? 1 : 0); +} + +static ssize_t eesoxscsi_store_term(struct device *dev, const char *buf, size_t len) +{ + struct expansion_card *ec = ECARD_DEV(dev); + struct Scsi_Host *host = ecard_get_drvdata(ec); + struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata; + unsigned long flags; + + if (len > 1) { + spin_lock_irqsave(host->host_lock, flags); + if (buf[0] != '0') { + info->control |= EESOX_TERM_ENABLE; + } else { + info->control &= ~EESOX_TERM_ENABLE; + } + writeb(info->control, info->ctl_port); + spin_unlock_irqrestore(host->host_lock, flags); + } + + return len; +} + +static DEVICE_ATTR(bus_term, S_IRUGO | S_IWUSR, + eesoxscsi_show_term, eesoxscsi_store_term); + static Scsi_Host_Template eesox_template = { .module = THIS_MODULE, .proc_info = eesoxscsi_proc_info, @@ -440,57 +535,75 @@ static int __devinit eesoxscsi_probe(struct expansion_card *ec, const struct ecard_id *id) { struct Scsi_Host *host; - struct eesoxscsi_info *info; - int ret = -ENOMEM; + struct eesoxscsi_info *info; + unsigned long resbase, reslen; + unsigned char *base; + int ret; - host = scsi_register(&eesox_template, - sizeof(struct eesoxscsi_info)); - if (!host) + resbase = ecard_resource_start(ec, ECARD_RES_IOCFAST); + reslen = ecard_resource_len(ec, ECARD_RES_IOCFAST); + + if (!request_mem_region(resbase, reslen, "eesoxscsi")) { + ret = -EBUSY; goto out; + } - host->io_port = ecard_address(ec, ECARD_IOC, ECARD_FAST); - host->irq = ec->irq; - host->dma_channel = ec->dma; + base = ioremap(resbase, reslen); + if (!base) { + ret = -ENOMEM; + goto out_region; + } - if (!request_region(host->io_port + EESOX_FAS216_OFFSET, - EESOX_FAS216_SIZE, "eesox2-fas")) { - ret = -EBUSY; - goto out_free; + host = scsi_register(&eesox_template, + sizeof(struct eesoxscsi_info)); + if (!host) { + ret = -ENOMEM; + goto out_unmap; } + host->base = (unsigned long)base; + host->irq = ec->irq; + host->dma_channel = ec->dma; + ecard_set_drvdata(ec, host); info = (struct eesoxscsi_info *)host->hostdata; - info->ctl_port = host->io_port + EESOX_CONTROL; - info->control = term[ec->slot_no] ? EESOX_TERM_ENABLE : 0; - outb(info->control, info->ctl_port); + info->ec = ec; + info->ctl_port = base + EESOX_CONTROL; + info->control = term[ec->slot_no] ? EESOX_TERM_ENABLE : 0; + writeb(info->control, info->ctl_port); - ec->irqaddr = (unsigned char *)ioaddr(host->io_port + EESOX_STATUS); - ec->irqmask = EESOX_STAT_INTR; - ec->irq_data = info; - ec->ops = (expansioncard_ops_t *)&eesoxscsi_ops; + ec->irqaddr = base + EESOX_DMASTAT; + ec->irqmask = EESOX_STAT_INTR; + ec->irq_data = info; + ec->ops = &eesoxscsi_ops; - info->info.scsi.io_port = host->io_port + EESOX_FAS216_OFFSET; + info->info.scsi.io_base = base + EESOX_FAS216_OFFSET; info->info.scsi.io_shift = EESOX_FAS216_SHIFT; info->info.scsi.irq = host->irq; info->info.ifcfg.clockrate = 40; /* MHz */ info->info.ifcfg.select_timeout = 255; info->info.ifcfg.asyncperiod = 200; /* ns */ info->info.ifcfg.sync_max_depth = 7; - info->info.ifcfg.cntl3 = CNTL3_BS8 | CNTL3_FASTSCSI | CNTL3_FASTCLK; + info->info.ifcfg.cntl3 = CNTL3_FASTSCSI | CNTL3_FASTCLK; info->info.ifcfg.disconnect_ok = 1; info->info.ifcfg.wide_max_size = 0; + info->info.ifcfg.capabilities = FASCAP_PSEUDODMA; info->info.dma.setup = eesoxscsi_dma_setup; info->info.dma.pseudo = eesoxscsi_dma_pseudo; info->info.dma.stop = eesoxscsi_dma_stop; - info->dmaarea = host->io_port + EESOX_DMA_OFFSET; - ret = request_irq(host->irq, eesoxscsi_intr, - SA_INTERRUPT, "eesox", host); + device_create_file(&ec->dev, &dev_attr_bus_term); + + ret = fas216_init(host); + if (ret) + goto out_free; + + ret = request_irq(host->irq, eesoxscsi_intr, 0, "eesoxscsi", info); if (ret) { printk("scsi%d: IRQ%d not free: %d\n", host->host_no, host->irq, ret); - goto out_region; + goto out_remove; } if (host->dma_channel != NO_DMA) { @@ -500,24 +613,32 @@ eesoxscsi_probe(struct expansion_card *ec, const struct ecard_id *id) host->dma_channel = NO_DMA; } else { set_dma_speed(host->dma_channel, 180); + info->info.ifcfg.capabilities |= FASCAP_DMA; + info->info.ifcfg.cntl3 |= CNTL3_BS8; } } - fas216_init(host); - ret = scsi_add_host(host, &ec->dev); + ret = fas216_add(host, &ec->dev); if (ret == 0) goto out; - fas216_release(host); - if (host->dma_channel != NO_DMA) free_dma(host->dma_channel); free_irq(host->irq, host); - out_region: - release_region(host->io_port + EESOX_FAS216_OFFSET, - EESOX_FAS216_SIZE); + + out_remove: + fas216_remove(host); + out_free: + device_remove_file(&ec->dev, &dev_attr_bus_term); scsi_unregister(host); + + out_unmap: + iounmap(base); + + out_region: + release_mem_region(resbase, reslen); + out: return ret; } @@ -525,15 +646,26 @@ eesoxscsi_probe(struct expansion_card *ec, const struct ecard_id *id) static void __devexit eesoxscsi_remove(struct expansion_card *ec) { struct Scsi_Host *host = ecard_get_drvdata(ec); + struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata; + unsigned long resbase, reslen; ecard_set_drvdata(ec, NULL); - scsi_remove_host(host); - fas216_release(host); + fas216_remove(host); if (host->dma_channel != NO_DMA) free_dma(host->dma_channel); - free_irq(host->irq, host); - release_region(host->io_port + EESOX_FAS216_OFFSET, EESOX_FAS216_SIZE); + free_irq(host->irq, info); + + device_remove_file(&ec->dev, &dev_attr_bus_term); + + iounmap((void *)host->base); + + resbase = ecard_resource_start(ec, ECARD_RES_IOCFAST); + reslen = ecard_resource_len(ec, ECARD_RES_IOCFAST); + + release_mem_region(resbase, reslen); + + fas216_release(host); scsi_unregister(host); } @@ -547,7 +679,8 @@ static struct ecard_driver eesoxscsi_driver = { .remove = __devexit_p(eesoxscsi_remove), .id_table = eesoxscsi_cids, .drv = { - .name = "eesoxscsi", + .devclass = &shost_devclass, + .name = "eesoxscsi", }, }; diff --git a/drivers/acorn/scsi/fas216.c b/drivers/acorn/scsi/fas216.c index 5e306d2db63a..5bdaf3ff9362 100644 --- a/drivers/acorn/scsi/fas216.c +++ b/drivers/acorn/scsi/fas216.c @@ -1,7 +1,7 @@ /* * linux/drivers/acorn/scsi/fas216.c * - * Copyright (C) 1997-2000 Russell King + * Copyright (C) 1997-2003 Russell King * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -10,7 +10,7 @@ * Based on information in qlogicfas.c by Tom Zerucha, Michael Griffith, and * other sources, including: * the AMD Am53CF94 data sheet - * the AMD Am53C94 data sheet + * the AMD Am53C94 data sheet * * This is a generic driver. To use it, have a look at cumana_2.c. You * should define your own structure that overlays FAS216_Info, eg: @@ -33,9 +33,6 @@ * 02-04-2000 RMK Converted to use the new error handling, and * automatically request sense data upon check * condition status from targets. - * - * Todo: - * - allow individual devices to enable sync xfers. */ #include #include @@ -45,6 +42,7 @@ #include #include #include +#include #include #include @@ -52,17 +50,11 @@ #include #include -#define FAS216_C - #include "../../scsi/scsi.h" #include "../../scsi/hosts.h" #include "fas216.h" #include "scsi.h" -#define VER_MAJOR 0 -#define VER_MINOR 0 -#define VER_PATCH 5 - /* NOTE: SCSI2 Synchronous transfers *require* DMA according to * the data sheet. This restriction is crazy, especially when * you only want to send 16 bytes! What were the guys who @@ -104,22 +96,43 @@ static int level_mask = LOG_ERROR; +static inline unsigned char fas216_readb(FAS216_Info *info, unsigned int reg) +{ + unsigned int off = reg << info->scsi.io_shift; + if (info->scsi.io_base) + return readb(info->scsi.io_base + off); + else + return inb(info->scsi.io_port + off); +} + +static inline void fas216_writeb(FAS216_Info *info, unsigned int reg, unsigned int val) +{ + unsigned int off = reg << info->scsi.io_shift; + if (info->scsi.io_base) + writeb(val, info->scsi.io_base + off); + else + outb(val, info->scsi.io_port + off); +} + static void fas216_dumpstate(FAS216_Info *info) { unsigned char is, stat, inst; - is = inb(REG_IS(info)); - stat = inb(REG_STAT(info)); - inst = inb(REG_INST(info)); + is = fas216_readb(info, REG_IS); + stat = fas216_readb(info, REG_STAT); + inst = fas216_readb(info, REG_INST); printk("FAS216: CTCL=%02X CTCM=%02X CMD=%02X STAT=%02X" " INST=%02X IS=%02X CFIS=%02X", - inb(REG_CTCL(info)), inb(REG_CTCM(info)), - inb(REG_CMD(info)), stat, inst, is, - inb(REG_CFIS(info))); + fas216_readb(info, REG_CTCL), + fas216_readb(info, REG_CTCM), + fas216_readb(info, REG_CMD), stat, inst, is, + fas216_readb(info, REG_CFIS)); printk(" CNTL1=%02X CNTL2=%02X CNTL3=%02X CTCH=%02X\n", - inb(REG_CNTL1(info)), inb(REG_CNTL2(info)), - inb(REG_CNTL3(info)), inb(REG_CTCH(info))); + fas216_readb(info, REG_CNTL1), + fas216_readb(info, REG_CNTL2), + fas216_readb(info, REG_CNTL3), + fas216_readb(info, REG_CTCH)); } static void print_SCp(Scsi_Pointer *SCp, const char *prefix, const char *suffix) @@ -236,19 +249,63 @@ static char fas216_target(FAS216_Info *info) return 'H'; } +static void +fas216_do_log(FAS216_Info *info, char target, char *fmt, va_list ap) +{ + static char buf[1024]; + + vsnprintf(buf, sizeof(buf), fmt, ap); + printk("scsi%d.%c: %s", info->host->host_no, target, buf); +} + +static void +fas216_log_command(FAS216_Info *info, int level, Scsi_Cmnd *SCpnt, char *fmt, ...) +{ + va_list args; + + if (level != 0 && !(level & level_mask)) + return; + + va_start(args, fmt); + fas216_do_log(info, '0' + SCpnt->target, fmt, args); + va_end(args); + + printk(" CDB: "); + print_command(SCpnt->cmnd); +} + +static void +fas216_log_target(FAS216_Info *info, int level, int target, char *fmt, ...) +{ + va_list args; + + if (level != 0 && !(level & level_mask)) + return; + + if (target < 0) + target = 'H'; + else + target += '0'; + + va_start(args, fmt); + fas216_do_log(info, target, fmt, args); + va_end(args); + + printk("\n"); +} + static void fas216_log(FAS216_Info *info, int level, char *fmt, ...) { va_list args; - static char buf[1024]; if (level != 0 && !(level & level_mask)) return; va_start(args, fmt); - vsnprintf(buf, sizeof(buf), fmt, args); + fas216_do_log(info, fas216_target(info), fmt, args); va_end(args); - printk("scsi%d.%c: %s\n", info->host->host_no, fas216_target(info), buf); + printk("\n"); } #define PH_SIZE 32 @@ -276,7 +333,7 @@ static void fas216_cmd(FAS216_Info *info, unsigned int command) cmd_ptr = (cmd_ptr + 1) & 7; - outb(command, REG_CMD(info)); + fas216_writeb(info, REG_CMD, command); } static void print_debug_list(void) @@ -308,11 +365,11 @@ static void print_debug_list(void) static void fas216_done(FAS216_Info *info, unsigned int result); -/** - * fast216_clockrate - calculate clock conversion factor +/** + * fas216_clockrate - calculate clock conversion factor * @clock: clock speed in MHz - * - * Calculate correct value to be written into clock conversion factor + * + * Calculate correct value to be written into clock conversion factor * register. Returns CLKF_ value. */ static int fas216_clockrate(int clock) @@ -327,11 +384,11 @@ static int fas216_clockrate(int clock) return clock; } -/** +/** * fas216_get_last_msg - retrive last message from the list * @info: interface to search * @pos: current fifo position - * + * * Retrieve a last message from the list, using position in fifo. */ static inline unsigned short @@ -359,12 +416,12 @@ fas216_get_last_msg(FAS216_Info *info, int pos) return packed_msg; } -/** +/** * fas216_syncperiod - calculate STP register value * @info: state structure for interface connected to device * @ns: period in ns (between subsequent bytes) - * - * Calculate value to be loaded into the STP register for a given period + * + * Calculate value to be loaded into the STP register for a given period * in ns. Returns a value suitable for REG_STP. */ static int fas216_syncperiod(FAS216_Info *info, int ns) @@ -381,11 +438,11 @@ static int fas216_syncperiod(FAS216_Info *info, int ns) return value & 31; } -/** +/** * fas216_set_sync - setup FAS216 chip for specified transfer period. - * @info: state structure for interface connected to device + * @info: state structure for interface connected to device * @target: target - * + * * Correctly setup FAS216 chip for specified transfer period. * Notes : we need to switch the chip out of FASTSCSI mode if we have * a transfer period >= 200ns - otherwise the chip will violate @@ -393,12 +450,16 @@ static int fas216_syncperiod(FAS216_Info *info, int ns) */ static void fas216_set_sync(FAS216_Info *info, int target) { - outb(info->device[target].sof, REG_SOF(info)); - outb(info->device[target].stp, REG_STP(info)); + unsigned int cntl3; + + fas216_writeb(info, REG_SOF, info->device[target].sof); + fas216_writeb(info, REG_STP, info->device[target].stp); + + cntl3 = info->scsi.cfg[2]; if (info->device[target].period >= (200 / 4)) - outb(info->scsi.cfg[2] & ~CNTL3_FASTSCSI, REG_CNTL3(info)); - else - outb(info->scsi.cfg[2], REG_CNTL3(info)); + cntl3 = cntl3 & ~CNTL3_FASTSCSI; + + fas216_writeb(info, REG_CNTL3, cntl3); } /* Synchronous transfer support @@ -428,8 +489,8 @@ static void fas216_set_sync(FAS216_Info *info, int target) /** * fas216_handlesync - Handle a synchronous transfer message * @info: state structure for interface - * @ms: message from target - * + * @msg: message from target + * * Handle a synchronous transfer message from the target */ static void fas216_handlesync(FAS216_Info *info, char *msg) @@ -538,11 +599,11 @@ static void fas216_handlesync(FAS216_Info *info, char *msg) } } -/** - * fas216_handlewide - Handle a wide transfer message +/** + * fas216_handlewide - Handle a wide transfer message * @info: state structure for interface * @msg: message from target - * + * * Handle a wide transfer message from the target */ static void fas216_handlewide(FAS216_Info *info, char *msg) @@ -637,11 +698,11 @@ static void fas216_handlewide(FAS216_Info *info, char *msg) } } -/** +/** * fas216_updateptrs - update data pointers after transfer suspended/paused * @info: interface's local pointer to update * @bytes_transferred: number of bytes transferred - * + * * Update data pointers after transfer suspended/paused */ static void fas216_updateptrs(FAS216_Info *info, int bytes_transferred) @@ -662,7 +723,7 @@ static void fas216_updateptrs(FAS216_Info *info, int bytes_transferred) * next buffer. */ bytes_transferred -= SCp->this_residual; - if (!next_SCp(&info->scsi.SCp) && bytes_transferred) { + if (!next_SCp(SCp) && bytes_transferred) { printk(KERN_WARNING "scsi%d.%c: out of buffers\n", info->host->host_no, '0' + info->SCpnt->target); return; @@ -680,33 +741,67 @@ static void fas216_updateptrs(FAS216_Info *info, int bytes_transferred) * fas216_pio - transfer data off of/on to card using programmed IO * @info: interface to transfer data to/from * @direction: direction to transfer data (DMA_OUT/DMA_IN) - * + * * Transfer data off of/on to card using programmed IO. * Notes: this is incredibly slow. */ static void fas216_pio(FAS216_Info *info, fasdmadir_t direction) { + Scsi_Pointer *SCp = &info->scsi.SCp; + fas216_checkmagic(info); if (direction == DMA_OUT) - outb(get_next_SCp_byte(&info->scsi.SCp), REG_FF(info)); + fas216_writeb(info, REG_FF, get_next_SCp_byte(SCp)); else - put_next_SCp_byte(&info->scsi.SCp, inb(REG_FF(info))); + put_next_SCp_byte(SCp, fas216_readb(info, REG_FF)); + + if (SCp->this_residual == 0) + next_SCp(SCp); +} + +static void fas216_set_stc(FAS216_Info *info, unsigned int length) +{ + fas216_writeb(info, REG_STCL, length); + fas216_writeb(info, REG_STCM, length >> 8); + fas216_writeb(info, REG_STCH, length >> 16); +} + +static unsigned int fas216_get_ctc(FAS216_Info *info) +{ + return fas216_readb(info, REG_CTCL) + + (fas216_readb(info, REG_CTCM) << 8) + + (fas216_readb(info, REG_CTCH) << 16); } +/** + * fas216_cleanuptransfer - clean up after a transfer has completed. + * @info: interface to clean up + * + * Update the data pointers according to the number of bytes transferred + * on the SCSI bus. + */ static void fas216_cleanuptransfer(FAS216_Info *info) { unsigned long total, residual, fifo; + fasdmatype_t dmatype = info->dma.transfer_type; + + info->dma.transfer_type = fasdma_none; - if (info->dma.transfer_type == fasdma_real_all) + /* + * PIO transfers do not need to be cleaned up. + */ + if (dmatype == fasdma_pio || dmatype == fasdma_none) + return; + + if (dmatype == fasdma_real_all) total = info->SCpnt->request_bufflen; else total = info->scsi.SCp.this_residual; - residual = inb(REG_CTCL(info)) + (inb(REG_CTCM(info)) << 8) + - (inb(REG_CTCH(info)) << 16); + residual = fas216_get_ctc(info); - fifo = inb(REG_CFIS(info)) & CFIS_CF; + fifo = fas216_readb(info, REG_CFIS) & CFIS_CF; fas216_log(info, LOG_BUFFER, "cleaning up from previous " "transfer: length 0x%06x, residual 0x%x, fifo %d", @@ -718,54 +813,22 @@ static void fas216_cleanuptransfer(FAS216_Info *info) * host to the FIFO. This means we must include the * bytes left in the FIFO from the transfer counter. */ - if (info->scsi.phase == PHASE_DATAOUT) { + if (info->scsi.phase == PHASE_DATAOUT) residual += fifo; - fifo = 0; - } - - if (info->dma.transfer_type != fasdma_none && - info->dma.transfer_type != fasdma_pio) { - fas216_updateptrs(info, total - residual); - } - - /* - * If we were performing Data-In, then the FIFO counter - * contains the number of bytes not transferred via DMA - * from the on-board FIFO. Read them manually. - */ - if (info->scsi.phase == PHASE_DATAIN) { - while (fifo && info->scsi.SCp.ptr) { - *info->scsi.SCp.ptr = inb(REG_FF(info)); - fas216_updateptrs(info, 1); - fifo--; - } - } - info->dma.transfer_type = fasdma_none; + fas216_updateptrs(info, total - residual); } -/** - * fas216_starttransfer - Start a DMA/PIO transfer off of/on to card +/** + * fas216_transfer - Perform a DMA/PIO transfer off of/on to card * @info: interface from which device disconnected from - * @direction: transfer direction (DMA_OUT/DMA_IN) - * + * * Start a DMA/PIO transfer off of/on to card */ -static void fas216_starttransfer(FAS216_Info *info, fasdmadir_t direction) +static void fas216_transfer(FAS216_Info *info) { + fasdmadir_t direction; fasdmatype_t dmatype; - int phase = (direction == DMA_OUT) ? PHASE_DATAOUT : PHASE_DATAIN; - - fas216_checkmagic(info); - - if (phase != info->scsi.phase) { - info->scsi.phase = phase; - - if (direction == DMA_OUT) - fas216_cmd(info, CMD_FLUSHFIFO); - } else { - fas216_cleanuptransfer(info); - } fas216_log(info, LOG_BUFFER, "starttransfer: buffer %p length 0x%06x reqlen 0x%06x", @@ -781,36 +844,41 @@ static void fas216_starttransfer(FAS216_Info *info, fasdmadir_t direction) } /* - * Default to PIO mode or DMA mode if we have - * a synchronous transfer agreement. + * If we have a synchronous transfer agreement in effect, we must + * use DMA mode. If we are using asynchronous transfers, we may + * use DMA mode or PIO mode. */ - if (info->device[info->SCpnt->target].sof && info->dma.setup) + if (info->device[info->SCpnt->target].sof) dmatype = fasdma_real_all; else dmatype = fasdma_pio; + if (info->scsi.phase == PHASE_DATAOUT) + direction = DMA_OUT; + else + direction = DMA_IN; + if (info->dma.setup) dmatype = info->dma.setup(info->host, &info->scsi.SCp, direction, dmatype); info->dma.transfer_type = dmatype; + if (dmatype == fasdma_real_all) + fas216_set_stc(info, info->SCpnt->request_bufflen); + else + fas216_set_stc(info, info->scsi.SCp.this_residual); + switch (dmatype) { case fasdma_pio: fas216_log(info, LOG_BUFFER, "PIO transfer"); - outb(0, REG_SOF(info)); - outb(info->scsi.async_stp, REG_STP(info)); - outb(info->scsi.SCp.this_residual, REG_STCL(info)); - outb(info->scsi.SCp.this_residual >> 8, REG_STCM(info)); - outb(info->scsi.SCp.this_residual >> 16, REG_STCH(info)); + fas216_writeb(info, REG_SOF, 0); + fas216_writeb(info, REG_STP, info->scsi.async_stp); fas216_cmd(info, CMD_TRANSFERINFO); fas216_pio(info, direction); break; case fasdma_pseudo: fas216_log(info, LOG_BUFFER, "pseudo transfer"); - outb(info->scsi.SCp.this_residual, REG_STCL(info)); - outb(info->scsi.SCp.this_residual >> 8, REG_STCM(info)); - outb(info->scsi.SCp.this_residual >> 16, REG_STCH(info)); fas216_cmd(info, CMD_TRANSFERINFO | CMD_WITHDMA); info->dma.pseudo(info->host, &info->scsi.SCp, direction, info->SCpnt->transfersize); @@ -818,17 +886,11 @@ static void fas216_starttransfer(FAS216_Info *info, fasdmadir_t direction) case fasdma_real_block: fas216_log(info, LOG_BUFFER, "block dma transfer"); - outb(info->scsi.SCp.this_residual, REG_STCL(info)); - outb(info->scsi.SCp.this_residual >> 8, REG_STCM(info)); - outb(info->scsi.SCp.this_residual >> 16, REG_STCH(info)); fas216_cmd(info, CMD_TRANSFERINFO | CMD_WITHDMA); break; case fasdma_real_all: fas216_log(info, LOG_BUFFER, "total dma transfer"); - outb(info->SCpnt->request_bufflen, REG_STCL(info)); - outb(info->SCpnt->request_bufflen >> 8, REG_STCM(info)); - outb(info->SCpnt->request_bufflen >> 16, REG_STCH(info)); fas216_cmd(info, CMD_TRANSFERINFO | CMD_WITHDMA); break; @@ -839,44 +901,61 @@ static void fas216_starttransfer(FAS216_Info *info, fasdmadir_t direction) } } -/** +/** * fas216_stoptransfer - Stop a DMA transfer onto / off of the card * @info: interface from which device disconnected from - * - * Stop a DMA transfer onto / off of the card + * + * Called when we switch away from DATA IN or DATA OUT phases. */ static void fas216_stoptransfer(FAS216_Info *info) { fas216_checkmagic(info); - if ((info->dma.transfer_type == fasdma_real_all || - info->dma.transfer_type == fasdma_real_block) && - info->dma.stop) + if (info->dma.transfer_type == fasdma_real_all || + info->dma.transfer_type == fasdma_real_block) info->dma.stop(info->host, &info->scsi.SCp); fas216_cleanuptransfer(info); - if (info->scsi.phase == PHASE_DATAOUT) + if (info->scsi.phase == PHASE_DATAIN) { + unsigned int fifo; + + /* + * If we were performing Data-In, then the FIFO counter + * contains the number of bytes not transferred via DMA + * from the on-board FIFO. Read them manually. + */ + fifo = fas216_readb(info, REG_CFIS) & CFIS_CF; + while (fifo && info->scsi.SCp.ptr) { + *info->scsi.SCp.ptr = fas216_readb(info, REG_FF); + fas216_updateptrs(info, 1); + fifo--; + } + } else { + /* + * After a Data-Out phase, there may be unsent + * bytes left in the FIFO. Flush them out. + */ fas216_cmd(info, CMD_FLUSHFIFO); + } } static void fas216_aborttransfer(FAS216_Info *info) { fas216_checkmagic(info); - if ((info->dma.transfer_type == fasdma_real_all || - info->dma.transfer_type == fasdma_real_block) && - info->dma.stop) + if (info->dma.transfer_type == fasdma_real_all || + info->dma.transfer_type == fasdma_real_block) info->dma.stop(info->host, &info->scsi.SCp); info->dma.transfer_type = fasdma_none; fas216_cmd(info, CMD_FLUSHFIFO); } -/** +/** * fas216_disconnected_intr - handle device disconnection * @info: interface from which device disconnected from - * + * * Handle device disconnection */ static void fas216_disconnect_intr(FAS216_Info *info) @@ -924,10 +1003,10 @@ static void fas216_disconnect_intr(FAS216_Info *info) } } -/** +/** * fas216_reselected_intr - start reconnection of a device * @info: interface which was reselected - * + * * Start reconnection of a device */ static void @@ -952,19 +1031,14 @@ fas216_reselected_intr(FAS216_Info *info) fas216_log(info, LOG_CONNECT, "reconnect phase=%02X", info->scsi.phase); - if ((inb(REG_CFIS(info)) & CFIS_CF) != 2) { + if ((fas216_readb(info, REG_CFIS) & CFIS_CF) != 2) { printk(KERN_ERR "scsi%d.H: incorrect number of bytes after reselect\n", info->host->host_no); - fas216_cmd(info, CMD_SETATN); - msgqueue_flush(&info->scsi.msgs); - msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR); - info->scsi.phase = PHASE_MSGOUT_EXPECT; - fas216_cmd(info, CMD_MSGACCEPTED); - return; + goto initiator_error; } - target = inb(REG_FF(info)); - identify_msg = inb(REG_FF(info)); + target = fas216_readb(info, REG_FF); + identify_msg = fas216_readb(info, REG_FF); ok = 1; if (!(target & (1 << info->host->this_id))) { @@ -983,26 +1057,11 @@ fas216_reselected_intr(FAS216_Info *info) * Something went wrong - send an initiator error to * the target. */ - fas216_cmd(info, CMD_SETATN); - msgqueue_flush(&info->scsi.msgs); - msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR); - info->scsi.phase = PHASE_MSGOUT_EXPECT; - fas216_cmd(info, CMD_MSGACCEPTED); - return; + goto initiator_error; } target &= ~(1 << info->host->this_id); - switch (target) { - case 1: target = 0; break; - case 2: target = 1; break; - case 4: target = 2; break; - case 8: target = 3; break; - case 16: target = 4; break; - case 32: target = 5; break; - case 64: target = 6; break; - case 128: target = 7; break; - default: target = info->host->this_id; break; - } + target = ffs(target) - 1; identify_msg &= 7; info->scsi.reconnected.target = target; @@ -1023,7 +1082,7 @@ fas216_reselected_intr(FAS216_Info *info) msgqueue_flush(&info->scsi.msgs); if (ok) { info->scsi.phase = PHASE_RECONNECTED; - outb(target, REG_SDID(info)); + fas216_writeb(info, REG_SDID, target); } else { /* * Our command structure not found - abort the @@ -1037,9 +1096,17 @@ fas216_reselected_intr(FAS216_Info *info) } fas216_cmd(info, CMD_MSGACCEPTED); + return; + + initiator_error: + fas216_cmd(info, CMD_SETATN); + msgqueue_flush(&info->scsi.msgs); + msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR); + info->scsi.phase = PHASE_MSGOUT_EXPECT; + fas216_cmd(info, CMD_MSGACCEPTED); } -/** +/** * fas216_finish_reconnect - finish reconnection sequence for device * @info: interface which caused function done interrupt * @@ -1232,7 +1299,7 @@ static int fas216_wait_cmd(FAS216_Info *info, int cmd) fas216_cmd(info, cmd); for (tout = 1000; tout; tout -= 1) { - stat = inb(REG_STAT(info)); + stat = fas216_readb(info, REG_STAT); if (stat & (STAT_INT|STAT_PARITYERROR)) break; udelay(1); @@ -1251,7 +1318,7 @@ static int fas216_get_msg_byte(FAS216_Info *info) if ((stat & STAT_BUSMASK) != STAT_MESGIN) goto unexpected_phase_change; - inb(REG_INST(info)); + fas216_readb(info, REG_INST); stat = fas216_wait_cmd(info, CMD_TRANSFERINFO); @@ -1264,9 +1331,9 @@ static int fas216_get_msg_byte(FAS216_Info *info) if ((stat & STAT_BUSMASK) != STAT_MESGIN) goto unexpected_phase_change; - inb(REG_INST(info)); + fas216_readb(info, REG_INST); - return inb(REG_FF(info)); + return fas216_readb(info, REG_FF); timedout: fas216_log(info, LOG_ERROR, "timed out waiting for message byte"); @@ -1284,7 +1351,7 @@ parity_error: /** * fas216_message - handle a function done interrupt from FAS216 chip * @info: interface which caused function done interrupt - * + * * Handle a function done interrupt from FAS216 chip */ static void fas216_message(FAS216_Info *info) @@ -1295,7 +1362,7 @@ static void fas216_message(FAS216_Info *info) fas216_checkmagic(info); - message[0] = inb(REG_FF(info)); + message[0] = fas216_readb(info, REG_FF); if (message[0] == EXTENDED_MESSAGE) { msgbyte = fas216_get_msg_byte(info); @@ -1317,8 +1384,6 @@ static void fas216_message(FAS216_Info *info) if (msgbyte == -3) goto parity_error; - info->scsi.msglen = msglen; - #ifdef DEBUG_MESSAGES { int i; @@ -1354,7 +1419,7 @@ parity_error: /** * fas216_send_command - send command after all message bytes have been sent * @info: interface which caused bus service - * + * * Send a command to a target after all message bytes have been sent */ static void fas216_send_command(FAS216_Info *info) @@ -1368,17 +1433,17 @@ static void fas216_send_command(FAS216_Info *info) /* load command */ for (i = info->scsi.SCp.sent_command; i < info->SCpnt->cmd_len; i++) - outb(info->SCpnt->cmnd[i], REG_FF(info)); + fas216_writeb(info, REG_FF, info->SCpnt->cmnd[i]); fas216_cmd(info, CMD_TRANSFERINFO); info->scsi.phase = PHASE_COMMAND; } -/** +/** * fas216_send_messageout - handle bus service to send a message * @info: interface which caused bus service - * + * * Handle bus service to send a message. * Note: We do not allow the device to change the data direction! */ @@ -1398,25 +1463,25 @@ static void fas216_send_messageout(FAS216_Info *info, int start) int i; for (i = start; i < msg->length; i++) - outb(msg->msg[i], REG_FF(info)); + fas216_writeb(info, REG_FF, msg->msg[i]); - msg->fifo = tot_msglen - (inb(REG_CFIS(info)) & CFIS_CF); + msg->fifo = tot_msglen - (fas216_readb(info, REG_CFIS) & CFIS_CF); start = 0; } } else - outb(NOP, REG_FF(info)); + fas216_writeb(info, REG_FF, NOP); fas216_cmd(info, CMD_TRANSFERINFO); info->scsi.phase = PHASE_MSGOUT; } -/** +/** * fas216_busservice_intr - handle bus service interrupt from FAS216 chip * @info: interface which caused bus service interrupt * @stat: Status register contents * @ssr: SCSI Status register contents - * + * * Handle a bus service interrupt from FAS216 chip */ static void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigned int ssr) @@ -1429,7 +1494,7 @@ static void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigne switch (info->scsi.phase) { case PHASE_SELECTION: - if ((ssr & IS_BITS) != 1) + if ((ssr & IS_BITS) != IS_MSGBYTESENT) goto bad_is; break; @@ -1464,15 +1529,17 @@ static void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigne case STATE(STAT_DATAIN, PHASE_RECONNECTED): fas216_finish_reconnect(info); case STATE(STAT_DATAIN, PHASE_SELSTEPS):/* Sel w/ steps -> Data In */ - case STATE(STAT_DATAIN, PHASE_DATAIN): /* Data In -> Data In */ case STATE(STAT_DATAIN, PHASE_MSGOUT): /* Message Out -> Data In */ case STATE(STAT_DATAIN, PHASE_COMMAND): /* Command -> Data In */ case STATE(STAT_DATAIN, PHASE_MSGIN): /* Message In -> Data In */ - fas216_starttransfer(info, DMA_IN); + info->scsi.phase = PHASE_DATAIN; + fas216_transfer(info); return; + case STATE(STAT_DATAIN, PHASE_DATAIN): /* Data In -> Data In */ case STATE(STAT_DATAOUT, PHASE_DATAOUT):/* Data Out -> Data Out */ - fas216_starttransfer(info, DMA_OUT); + fas216_cleanuptransfer(info); + fas216_transfer(info); return; /* Reselmsgin -> Data Out */ @@ -1482,7 +1549,9 @@ static void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigne case STATE(STAT_DATAOUT, PHASE_MSGOUT): /* Message Out -> Data Out */ case STATE(STAT_DATAOUT, PHASE_COMMAND):/* Command -> Data Out */ case STATE(STAT_DATAOUT, PHASE_MSGIN): /* Message In -> Data Out */ - fas216_starttransfer(info, DMA_OUT); + fas216_cmd(info, CMD_FLUSHFIFO); + info->scsi.phase = PHASE_DATAOUT; + fas216_transfer(info); return; /* Reselmsgin -> Status */ @@ -1507,7 +1576,7 @@ static void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigne case STATE(STAT_MESGIN, PHASE_COMMAND): /* Command -> Message In */ case STATE(STAT_MESGIN, PHASE_SELSTEPS):/* Sel w/ steps -> Message In */ case STATE(STAT_MESGIN, PHASE_MSGOUT): /* Message Out -> Message In */ - info->scsi.msgin_fifo = inb(REG_CFIS(info)) & CFIS_CF; + info->scsi.msgin_fifo = fas216_readb(info, REG_CFIS) & CFIS_CF; fas216_cmd(info, CMD_FLUSHFIFO); fas216_cmd(info, CMD_TRANSFERINFO); info->scsi.phase = PHASE_MSGIN; @@ -1516,7 +1585,7 @@ static void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigne /* Reselmsgin -> Message In */ case STATE(STAT_MESGIN, PHASE_RECONNECTED): case STATE(STAT_MESGIN, PHASE_MSGIN): - info->scsi.msgin_fifo = inb(REG_CFIS(info)) & CFIS_CF; + info->scsi.msgin_fifo = fas216_readb(info, REG_CFIS) & CFIS_CF; fas216_cmd(info, CMD_TRANSFERINFO); return; @@ -1555,7 +1624,7 @@ static void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigne */ info->device[info->SCpnt->target].parity_check = 0; info->device[info->SCpnt->target].parity_enabled = 1; - outb(info->scsi.cfg[0], REG_CNTL1(info)); + fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0]); } if (msgqueue_msglength(&info->scsi.msgs) > 1) @@ -1584,9 +1653,7 @@ static void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigne "target trying to receive more command bytes\n", info->host->host_no, fas216_target(info)); fas216_cmd(info, CMD_SETATN); - outb(15, REG_STCL(info)); - outb(0, REG_STCM(info)); - outb(0, REG_STCH(info)); + fas216_set_stc(info, 15); fas216_cmd(info, CMD_PADBYTES | CMD_WITHDMA); msgqueue_flush(&info->scsi.msgs); msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR); @@ -1615,6 +1682,7 @@ static void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigne bad_is: fas216_log(info, 0, "bus service at step %d?", ssr & IS_BITS); + fas216_dumpstate(info); print_debug_list(); fas216_done(info, DID_ERROR); @@ -1625,12 +1693,12 @@ bad_is: * @info: interface which caused function done interrupt * @stat: Status register contents * @ssr: SCSI Status register contents - * + * * Handle a function done interrupt from FAS216 chip */ static void fas216_funcdone_intr(FAS216_Info *info, unsigned int stat, unsigned int ssr) { - unsigned int fifo_len = inb(REG_CFIS(info)) & CFIS_CF; + unsigned int fifo_len = fas216_readb(info, REG_CFIS) & CFIS_CF; unsigned int status, message; fas216_checkmagic(info); @@ -1644,8 +1712,8 @@ static void fas216_funcdone_intr(FAS216_Info *info, unsigned int stat, unsigned if (fifo_len != 2) { fas216_log(info, 0, "odd number of bytes in FIFO: %d", fifo_len); } - status = inb(REG_FF(info)); - message = inb(REG_FF(info)); + status = fas216_readb(info, REG_FF); + message = fas216_readb(info, REG_FF); info->scsi.SCp.Message = message; info->scsi.SCp.Status = status; info->scsi.phase = PHASE_DONE; @@ -1679,26 +1747,21 @@ static void fas216_bus_reset(FAS216_Info *info) info->scsi.reconnected.lun = 0; info->scsi.reconnected.tag = 0; - if (info->ifcfg.wide_max_size == 0) - wide_state = neg_invalid; - else + wide_state = neg_invalid; + sync_state = neg_invalid; + #ifdef SCSI2_WIDE + if (info->ifcfg.wide_max_size != 0) wide_state = neg_wait; -#else - wide_state = neg_invalid; #endif - - if (info->host->dma_channel == NO_DMA || !info->dma.setup) - sync_state = neg_invalid; - else #ifdef SCSI2_SYNC + if (info->ifcfg.capabilities & (FASCAP_DMA|FASCAP_PSEUDODMA)) sync_state = neg_wait; -#else - sync_state = neg_invalid; #endif info->scsi.phase = PHASE_IDLE; info->SCpnt = NULL; /* bug! */ + memset(&info->scsi.SCp, 0, sizeof(info->scsi.SCp)); for (i = 0; i < 8; i++) { info->device[i].disconnect_ok = info->ifcfg.disconnect_ok; @@ -1714,22 +1777,21 @@ static void fas216_bus_reset(FAS216_Info *info) wake_up(&info->eh_wait); } -/** +/** * fas216_intr - handle interrupts to progress a command - * @instance: interface to service - * + * @info: interface to service + * * Handle interrupts from the interface to progress a command */ -void fas216_intr(struct Scsi_Host *instance) +void fas216_intr(FAS216_Info *info) { - FAS216_Info *info = (FAS216_Info *)instance->hostdata; unsigned char isr, ssr, stat; fas216_checkmagic(info); - stat = inb(REG_STAT(info)); - ssr = inb(REG_IS(info)); - isr = inb(REG_INST(info)); + stat = fas216_readb(info, REG_STAT); + ssr = fas216_readb(info, REG_IS); + isr = fas216_readb(info, REG_INST); add_debug_list(stat, ssr, isr, info->scsi.phase); @@ -1762,17 +1824,15 @@ static void __fas216_start_command(FAS216_Info *info, Scsi_Cmnd *SCpnt) int tot_msglen; /* following what the ESP driver says */ - outb(0, REG_STCL(info)); - outb(0, REG_STCM(info)); - outb(0, REG_STCH(info)); + fas216_set_stc(info, 0); fas216_cmd(info, CMD_NOP | CMD_WITHDMA); /* flush FIFO */ fas216_cmd(info, CMD_FLUSHFIFO); /* load bus-id and timeout */ - outb(BUSID(SCpnt->target), REG_SDID(info)); - outb(info->ifcfg.select_timeout, REG_STIM(info)); + fas216_writeb(info, REG_SDID, BUSID(SCpnt->target)); + fas216_writeb(info, REG_STIM, info->ifcfg.select_timeout); /* synchronous transfers */ fas216_set_sync(info, SCpnt->target); @@ -1808,13 +1868,13 @@ static void __fas216_start_command(FAS216_Info *info, Scsi_Cmnd *SCpnt) /* load message bytes */ while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) { for (i = 0; i < msg->length; i++) - outb(msg->msg[i], REG_FF(info)); - msg->fifo = tot_msglen - (inb(REG_CFIS(info)) & CFIS_CF); + fas216_writeb(info, REG_FF, msg->msg[i]); + msg->fifo = tot_msglen - (fas216_readb(info, REG_CFIS) & CFIS_CF); } /* load command */ for (i = 0; i < SCpnt->cmd_len; i++) - outb(SCpnt->cmnd[i], REG_FF(info)); + fas216_writeb(info, REG_FF, SCpnt->cmnd[i]); if (tot_msglen == 1) fas216_cmd(info, CMD_SELECTATN); @@ -1828,7 +1888,7 @@ static void __fas216_start_command(FAS216_Info *info, Scsi_Cmnd *SCpnt) */ struct message *msg = msgqueue_getmsg(&info->scsi.msgs, 0); - outb(msg->msg[0], REG_FF(info)); + fas216_writeb(info, REG_FF, msg->msg[0]); msg->fifo = 1; fas216_cmd(info, CMD_SELECTATNSTOP); @@ -1855,11 +1915,6 @@ static void fas216_start_command(FAS216_Info *info, Scsi_Cmnd *SCpnt) { int disconnect_ok; - if (parity_test(info, SCpnt->target)) - outb(info->scsi.cfg[0] | CNTL1_PTE, REG_CNTL1(info)); - else - outb(info->scsi.cfg[0], REG_CNTL1(info)); - /* * claim host busy */ @@ -1868,6 +1923,11 @@ static void fas216_start_command(FAS216_Info *info, Scsi_Cmnd *SCpnt) info->SCpnt = SCpnt; info->dma.transfer_type = fasdma_none; + if (parity_test(info, SCpnt->target)) + fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0] | CNTL1_PTE); + else + fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0]); + /* * Don't allow request sense commands to disconnect. */ @@ -1966,24 +2026,22 @@ static void fas216_do_bus_device_reset(FAS216_Info *info, Scsi_Cmnd *SCpnt) msgqueue_addmsg(&info->scsi.msgs, 1, BUS_DEVICE_RESET); /* following what the ESP driver says */ - outb(0, REG_STCL(info)); - outb(0, REG_STCM(info)); - outb(0, REG_STCH(info)); + fas216_set_stc(info, 0); fas216_cmd(info, CMD_NOP | CMD_WITHDMA); /* flush FIFO */ fas216_cmd(info, CMD_FLUSHFIFO); /* load bus-id and timeout */ - outb(BUSID(SCpnt->target), REG_SDID(info)); - outb(info->ifcfg.select_timeout, REG_STIM(info)); + fas216_writeb(info, REG_SDID, BUSID(SCpnt->target)); + fas216_writeb(info, REG_STIM, info->ifcfg.select_timeout); /* synchronous transfers */ fas216_set_sync(info, SCpnt->target); msg = msgqueue_getmsg(&info->scsi.msgs, 0); - outb(BUS_DEVICE_RESET, REG_FF(info)); + fas216_writeb(info, REG_FF, BUS_DEVICE_RESET); msg->fifo = 1; fas216_cmd(info, CMD_SELECTATNSTOP); @@ -1992,8 +2050,8 @@ static void fas216_do_bus_device_reset(FAS216_Info *info, Scsi_Cmnd *SCpnt) /** * fas216_kick - kick a command to the interface * @info: our host interface to kick - * - * kick a command to the interface, interface should be idle. + * + * Kick a command to the interface, interface should be idle. * Notes: Interrupts are always disabled! */ static void fas216_kick(FAS216_Info *info) @@ -2050,11 +2108,8 @@ static void fas216_kick(FAS216_Info *info) info->SCpnt = NULL; } -#if defined(DEBUG_CONNECT) || defined(DEBUG_MESSAGES) - printk("scsi%d.%c: starting ", - info->host->host_no, '0' + SCpnt->target); - print_command(SCpnt->cmnd); -#endif + fas216_log_command(info, LOG_CONNECT | LOG_MESSAGES, SCpnt, + "starting"); switch (where_from) { case TYPE_QUEUE: @@ -2094,13 +2149,13 @@ fas216_devicereset_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result * @info: interface that completed * @SCpnt: command that completed * @result: driver byte of result - * + * * Finish processing automatic request sense command */ static void fas216_rq_sns_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result) { - fas216_log(info, LOG_CONNECT, + fas216_log_target(info, LOG_CONNECT, SCpnt->target, "request sense complete, result=0x%04x%02x%02x", result, SCpnt->SCp.Message, SCpnt->SCp.Status); @@ -2127,7 +2182,7 @@ fas216_rq_sns_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result) * @info: interface that completed * @SCpnt: command that completed * @result: driver byte of result - * + * * Finish processing of standard command */ static void @@ -2138,17 +2193,14 @@ fas216_std_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result) SCpnt->result = result << 16 | info->scsi.SCp.Message << 8 | info->scsi.SCp.Status; -#ifdef DEBUG_CONNECT - printk("scsi%d.%c: command complete, result=%08X, command=", - info->host->host_no, '0' + SCpnt->target, SCpnt->result); - print_command(SCpnt->cmnd); -#endif + fas216_log_command(info, LOG_CONNECT, SCpnt, + "command complete, result=0x%08x", SCpnt->result); /* - * If the driver detected an error, or the command - * was request sense, then we're all done. + * If the driver detected an error, we're all done. */ - if (result != DID_OK || SCpnt->cmnd[0] == REQUEST_SENSE) + if (host_byte(SCpnt->result) != DID_OK || + msg_byte(SCpnt->result) != COMMAND_COMPLETE) goto done; /* @@ -2163,7 +2215,7 @@ fas216_std_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result) * If the command did not complete with GOOD status, * we are all done here. */ - if (info->scsi.SCp.Status != GOOD) + if (status_byte(SCpnt->result) != GOOD) goto done; /* @@ -2177,17 +2229,19 @@ fas216_std_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result) switch (SCpnt->cmnd[0]) { case INQUIRY: case START_STOP: -// case READ_CAPACITY: case MODE_SENSE: break; default: printk(KERN_ERR "scsi%d.%c: incomplete data transfer " - "detected: res=%08X ptr=%p len=%X command=", + "detected: res=%08X ptr=%p len=%X CDB: ", info->host->host_no, '0' + SCpnt->target, SCpnt->result, info->scsi.SCp.ptr, info->scsi.SCp.this_residual); print_command(SCpnt->cmnd); + SCpnt->result &= ~(255 << 16); + SCpnt->result |= DID_BAD_TARGET << 16; + goto request_sense; } } @@ -2202,6 +2256,11 @@ done: request_sense: + if (SCpnt->cmnd[0] == REQUEST_SENSE) + goto done; + + fas216_log_target(info, LOG_CONNECT, SCpnt->target, + "requesting sense"); memset(SCpnt->cmnd, 0, sizeof (SCpnt->cmnd)); SCpnt->cmnd[0] = REQUEST_SENSE; SCpnt->cmnd[1] = SCpnt->lun << 5; @@ -2234,7 +2293,7 @@ request_sense: * fas216_done - complete processing for current command * @info: interface that completed * @result: driver byte of result - * + * * Complete processing for current command */ static void fas216_done(FAS216_Info *info, unsigned int result) @@ -2264,7 +2323,7 @@ static void fas216_done(FAS216_Info *info, unsigned int result) */ if (info->scsi.SCp.ptr && info->scsi.SCp.this_residual == 0) { printk("scsi%d.%c: zero bytes left to transfer, but " - "buffer pointer still valid: ptr=%p len=%08x command=", + "buffer pointer still valid: ptr=%p len=%08x CDB: ", info->host->host_no, '0' + SCpnt->target, info->scsi.SCp.ptr, info->scsi.SCp.this_residual); info->scsi.SCp.ptr = NULL; @@ -2299,9 +2358,9 @@ no_command: * fas216_queue_command - queue a command for adapter to process. * @SCpnt: Command to queue * @done: done function to call once command is complete - * + * * Queue a command for adapter to process. - * Returns: 0 in success, else error. + * Returns: 0 on success, else error. * Notes: io_request_lock is held, interrupts are disabled. */ int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) @@ -2311,11 +2370,8 @@ int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) fas216_checkmagic(info); -#ifdef DEBUG_CONNECT - printk("scsi%d.H: received command for id %d (%p) ", - SCpnt->host->host_no, SCpnt->target, SCpnt); - print_command(SCpnt->cmnd); -#endif + fas216_log_command(info, LOG_CONNECT, SCpnt, + "received command (%p)", SCpnt); SCpnt->scsi_done = done; SCpnt->host_scribble = (void *)fas216_std_done; @@ -2342,10 +2398,8 @@ int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) fas216_kick(info); spin_unlock(&info->host_lock); -#ifdef DEBUG_CONNECT - printk("scsi%d.H: queue %s\n", info->host->host_no, + fas216_log_target(info, LOG_CONNECT, -1, "queue %s", result ? "failure" : "success"); -#endif return result; } @@ -2353,7 +2407,7 @@ int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) /** * fas216_internal_done - trigger restart of a waiting thread in fas216_command * @SCpnt: Command to wake - * + * * Trigger restart of a waiting thread in fas216_command */ static void fas216_internal_done(Scsi_Cmnd *SCpnt) @@ -2367,9 +2421,9 @@ static void fas216_internal_done(Scsi_Cmnd *SCpnt) /** * fas216_command - queue a command for adapter to process. - * @SCpnt: Command to queue - * - * Qqueue a command for adapter to process. + * @SCpnt: Command to queue + * + * Queue a command for adapter to process. * Returns: scsi result code. * Notes: io_request_lock is held, interrupts are disabled. */ @@ -2406,9 +2460,9 @@ int fas216_command(Scsi_Cmnd *SCpnt) * and go to sleep if we know that the device is going * to be some time (eg, disconnected). */ - if (inb(REG_STAT(info)) & STAT_INT) { + if (fas216_readb(info, REG_STAT) & STAT_INT) { spin_lock_irq(info->host->host_lock); - fas216_intr(info->host); + fas216_intr(info); spin_unlock_irq(info->host->host_lock); } } @@ -2447,7 +2501,7 @@ enum res_find { /** * fas216_do_abort - decide how to abort a command * @SCpnt: command to abort - * + * * Decide how to abort a command. * Returns: abort status */ @@ -2513,7 +2567,7 @@ static enum res_find fas216_find_command(FAS216_Info *info, Scsi_Cmnd *SCpnt) /** * fas216_eh_abort - abort this command * @SCpnt: command to abort - * + * * Abort this command. * Returns: FAILED if unable to abort * Notes: io_request_lock is taken, and irqs are disabled @@ -2568,12 +2622,12 @@ int fas216_eh_abort(Scsi_Cmnd *SCpnt) /** * fas216_eh_device_reset - Reset the device associated with this command - * @SCpnt: command specifing device to reset - * + * @SCpnt: command specifing device to reset + * * Reset the device associated with this command. * Returns: FAILED if unable to reset. * Notes: We won't be re-entered, so we'll only have one device - * reset on the go at one time. + * reset on the go at one time. */ int fas216_eh_device_reset(Scsi_Cmnd *SCpnt) { @@ -2651,7 +2705,7 @@ int fas216_eh_device_reset(Scsi_Cmnd *SCpnt) /** * fas216_eh_bus_reset - Reset the bus associated with the command * @SCpnt: command specifing bus to reset - * + * * Reset the bus associated with the command. * Returns: FAILED if unable to reset. * Notes: Further commands are blocked. @@ -2673,13 +2727,13 @@ int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt) * Stop all activity on this interface. */ fas216_aborttransfer(info); - outb(info->scsi.cfg[2], REG_CNTL3(info)); + fas216_writeb(info, REG_CNTL3, info->scsi.cfg[2]); /* * Clear any pending interrupts. */ - while (inb(REG_STAT(info)) & STAT_INT) - inb(REG_INST(info)); + while (fas216_readb(info, REG_STAT) & STAT_INT) + fas216_readb(info, REG_INST); info->rst_bus_status = 0; @@ -2729,26 +2783,26 @@ int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt) /** * fas216_init_chip - Initialise FAS216 state after reset - * @info: state structure for interface - * + * @info: state structure for interface + * * Initialise FAS216 state after reset */ static void fas216_init_chip(FAS216_Info *info) { - outb(fas216_clockrate(info->ifcfg.clockrate), REG_CLKF(info)); - outb(info->scsi.cfg[0], REG_CNTL1(info)); - outb(info->scsi.cfg[1], REG_CNTL2(info)); - outb(info->scsi.cfg[2], REG_CNTL3(info)); - outb(info->ifcfg.select_timeout, REG_STIM(info)); - outb(0, REG_SOF(info)); - outb(info->scsi.async_stp, REG_STP(info)); - outb(info->scsi.cfg[0], REG_CNTL1(info)); + fas216_writeb(info, REG_CLKF, fas216_clockrate(info->ifcfg.clockrate)); + fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0]); + fas216_writeb(info, REG_CNTL2, info->scsi.cfg[1]); + fas216_writeb(info, REG_CNTL3, info->scsi.cfg[2]); + fas216_writeb(info, REG_STIM, info->ifcfg.select_timeout); + fas216_writeb(info, REG_SOF, 0); + fas216_writeb(info, REG_STP, info->scsi.async_stp); + fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0]); } /** * fas216_eh_host_reset - Reset the host associated with this command * @SCpnt: command specifing host to reset - * + * * Reset the host associated with this command. * Returns: FAILED if unable to reset. * Notes: io_request_lock is taken, and irqs are disabled @@ -2812,56 +2866,56 @@ static int fas216_detect_type(FAS216_Info *info) /* * Reset the chip. */ - outb(CMD_RESETCHIP, REG_CMD(info)); + fas216_writeb(info, REG_CMD, CMD_RESETCHIP); udelay(50); - outb(CMD_NOP, REG_CMD(info)); + fas216_writeb(info, REG_CMD, CMD_NOP); /* * Check to see if control reg 2 is present. */ - outb(0, REG_CNTL3(info)); - outb(CNTL2_S2FE, REG_CNTL2(info)); + fas216_writeb(info, REG_CNTL3, 0); + fas216_writeb(info, REG_CNTL2, CNTL2_S2FE); /* * If we are unable to read back control reg 2 * correctly, it is not present, and we have a * NCR53C90. */ - if ((inb(REG_CNTL2(info)) & (~0xe0)) != CNTL2_S2FE) + if ((fas216_readb(info, REG_CNTL2) & (~0xe0)) != CNTL2_S2FE) return TYPE_NCR53C90; /* * Now, check control register 3 */ - outb(0, REG_CNTL2(info)); - outb(0, REG_CNTL3(info)); - outb(5, REG_CNTL3(info)); + fas216_writeb(info, REG_CNTL2, 0); + fas216_writeb(info, REG_CNTL3, 0); + fas216_writeb(info, REG_CNTL3, 5); /* * If we are unable to read the register back * correctly, we have a NCR53C90A */ - if (inb(REG_CNTL3(info)) != 5) + if (fas216_readb(info, REG_CNTL3) != 5) return TYPE_NCR53C90A; /* * Now read the ID from the chip. */ - outb(0, REG_CNTL3(info)); + fas216_writeb(info, REG_CNTL3, 0); - outb(CNTL3_ADIDCHK, REG_CNTL3(info)); - outb(0, REG_CNTL3(info)); + fas216_writeb(info, REG_CNTL3, CNTL3_ADIDCHK); + fas216_writeb(info, REG_CNTL3, 0); - outb(CMD_RESETCHIP, REG_CMD(info)); - udelay(5); - outb(CMD_WITHDMA | CMD_NOP, REG_CMD(info)); + fas216_writeb(info, REG_CMD, CMD_RESETCHIP); + udelay(50); + fas216_writeb(info, REG_CMD, CMD_WITHDMA | CMD_NOP); - outb(CNTL2_ENF, REG_CNTL2(info)); - outb(CMD_RESETCHIP, REG_CMD(info)); - udelay(5); - outb(CMD_NOP, REG_CMD(info)); + fas216_writeb(info, REG_CNTL2, CNTL2_ENF); + fas216_writeb(info, REG_CMD, CMD_RESETCHIP); + udelay(50); + fas216_writeb(info, REG_CMD, CMD_NOP); - rev = inb(REG1_ID(info)); + rev = fas216_readb(info, REG_ID); family = rev >> 3; rev &= 7; @@ -2887,10 +2941,10 @@ static int fas216_detect_type(FAS216_Info *info) return TYPE_NCR53C9x; } -/** +/** * fas216_reset_state - Initialise driver internal state * @info: state to initialise - * + * * Initialise driver internal state */ static void fas216_reset_state(FAS216_Info *info) @@ -2928,23 +2982,23 @@ static void fas216_reset_state(FAS216_Info *info) } /** - * fas216_init - initialise FAS/NCR/AMD SCSI ic. - * @instance: a driver-specific filled-out structure - * - * Initialise FAS/NCR/AMD SCSI ic. + * fas216_init - initialise FAS/NCR/AMD SCSI structures. + * @host: a driver-specific filled-out structure + * + * Initialise FAS/NCR/AMD SCSI structures. * Returns: 0 on success */ -int fas216_init(struct Scsi_Host *instance) +int fas216_init(struct Scsi_Host *host) { - FAS216_Info *info = (FAS216_Info *)instance->hostdata; - int type; + FAS216_Info *info = (FAS216_Info *)host->hostdata; info->magic_start = MAGIC; info->magic_end = MAGIC; - info->host = instance; - info->scsi.cfg[0] = instance->this_id | CNTL1_PERE; + info->host = host; + info->scsi.cfg[0] = host->this_id | CNTL1_PERE; info->scsi.cfg[1] = CNTL2_ENF | CNTL2_S2FE; - info->scsi.cfg[2] = info->ifcfg.cntl3 | CNTL3_ADIDCHK | CNTL3_G2CB; + info->scsi.cfg[2] = info->ifcfg.cntl3 | + CNTL3_ADIDCHK | CNTL3_G2CB | CNTL3_LBTM; info->scsi.async_stp = fas216_syncperiod(info, info->ifcfg.asyncperiod); info->rst_dev_status = -1; @@ -2961,13 +3015,29 @@ int fas216_init(struct Scsi_Host *instance) msgqueue_initialise(&info->scsi.msgs); if (!queue_initialise(&info->queues.issue)) - return 1; + return -ENOMEM; if (!queue_initialise(&info->queues.disconnected)) { queue_free(&info->queues.issue); - return 1; + return -ENOMEM; } + return 0; +} + +/** + * fas216_add - initialise FAS/NCR/AMD SCSI ic. + * @host: a driver-specific filled-out structure + * @dev: parent device + * + * Initialise FAS/NCR/AMD SCSI ic. + * Returns: 0 on success + */ +int fas216_add(struct Scsi_Host *host, struct device *dev) +{ + FAS216_Info *info = (FAS216_Info *)host->hostdata; + int type, ret; + fas216_reset_state(info); type = fas216_detect_type(info); info->scsi.type = chip_types[type]; @@ -2984,8 +3054,8 @@ int fas216_init(struct Scsi_Host *instance) * the resulting reset interrupt, so mask it * out. */ - outb(info->scsi.cfg[0] | CNTL1_DISR, REG_CNTL1(info)); - outb(CMD_RESETSCSI, REG_CMD(info)); + fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0] | CNTL1_DISR); + fas216_writeb(info, REG_CMD, CMD_RESETSCSI); /* * scsi standard says wait 250ms @@ -2994,60 +3064,40 @@ int fas216_init(struct Scsi_Host *instance) scsi_sleep(100*HZ/100); spin_lock_irq(info->host->host_lock); - outb(info->scsi.cfg[0], REG_CNTL1(info)); - inb(REG_INST(info)); + fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0]); + fas216_readb(info, REG_INST); fas216_checkmagic(info); - return 0; + ret = scsi_add_host(host, dev); + if (ret) + fas216_writeb(info, REG_CMD, CMD_RESETCHIP); + + return ret; } -/** - * fas216_release - release all resources for FAS/NCR/AMD SCSI ic. - * @instance: a driver-specific filled-out structure - * - * release all resources and put everything to bed for FAS/NCR/AMD SCSI ic, - * Returns: 0 on success. - */ -int fas216_release(struct Scsi_Host *instance) +void fas216_remove(struct Scsi_Host *host) { - FAS216_Info *info = (FAS216_Info *)instance->hostdata; + FAS216_Info *info = (FAS216_Info *)host->hostdata; fas216_checkmagic(info); + scsi_remove_host(host); - outb(CMD_RESETCHIP, REG_CMD(info)); - queue_free(&info->queues.disconnected); - queue_free(&info->queues.issue); - - return 0; + fas216_writeb(info, REG_CMD, CMD_RESETCHIP); } /** - * fas216_info - generate a string containing information about host. - * @info: FAS216 host information - * @buffer: string buffer to build string - * - * Generate a string containing information about this host. - * Returns: size of built string + * fas216_release - release all resources for FAS/NCR/AMD SCSI ic. + * @host: a driver-specific filled-out structure + * + * release all resources and put everything to bed for FAS/NCR/AMD SCSI ic. */ -int fas216_info(FAS216_Info *info, char *buffer) +void fas216_release(struct Scsi_Host *host) { - char *p = buffer; - - p += sprintf(p, "(%s) at port 0x%08lX ", - info->scsi.type, info->host->io_port); + FAS216_Info *info = (FAS216_Info *)host->hostdata; - if (info->host->irq != NO_IRQ) - p += sprintf(p, "irq %d ", info->host->irq); - else - p += sprintf(p, "no irq "); - - if (info->host->dma_channel != NO_DMA) - p += sprintf(p, "dma %d ", info->host->dma_channel); - else - p += sprintf(p, "no dma "); - - return p - buffer; + queue_free(&info->queues.disconnected); + queue_free(&info->queues.issue); } int fas216_print_host(FAS216_Info *info, char *buffer) @@ -3055,7 +3105,7 @@ int fas216_print_host(FAS216_Info *info, char *buffer) return sprintf(buffer, "\n" "Chip : %s\n" - " Address: 0x%08lX\n" + " Address: 0x%08lx\n" " IRQ : %d\n" " DMA : %d\n", info->scsi.type, info->host->io_port, @@ -3117,11 +3167,12 @@ int fas216_print_device(FAS216_Info *info, Scsi_Device *scd, char *buffer) return p - buffer; } -EXPORT_SYMBOL(fas216_info); EXPORT_SYMBOL(fas216_init); +EXPORT_SYMBOL(fas216_add); EXPORT_SYMBOL(fas216_queue_command); EXPORT_SYMBOL(fas216_command); EXPORT_SYMBOL(fas216_intr); +EXPORT_SYMBOL(fas216_remove); EXPORT_SYMBOL(fas216_release); EXPORT_SYMBOL(fas216_eh_abort); EXPORT_SYMBOL(fas216_eh_device_reset); diff --git a/drivers/acorn/scsi/fas216.h b/drivers/acorn/scsi/fas216.h index 6fa9cdd572a5..56b7438538df 100644 --- a/drivers/acorn/scsi/fas216.h +++ b/drivers/acorn/scsi/fas216.h @@ -22,18 +22,18 @@ /* FAS register definitions */ /* transfer count low */ -#define REG_CTCL(x) ((x)->scsi.io_port) -#define REG_STCL(x) ((x)->scsi.io_port) +#define REG_CTCL (0) +#define REG_STCL (0) /* transfer count medium */ -#define REG_CTCM(x) ((x)->scsi.io_port + (1 << (x)->scsi.io_shift)) -#define REG_STCM(x) ((x)->scsi.io_port + (1 << (x)->scsi.io_shift)) +#define REG_CTCM (1) +#define REG_STCM (1) /* fifo data */ -#define REG_FF(x) ((x)->scsi.io_port + (2 << (x)->scsi.io_shift)) +#define REG_FF (2) /* command */ -#define REG_CMD(x) ((x)->scsi.io_port + (3 << (x)->scsi.io_shift)) +#define REG_CMD (3) #define CMD_NOP 0x00 #define CMD_FLUSHFIFO 0x01 #define CMD_RESETCHIP 0x02 @@ -57,7 +57,7 @@ #define CMD_WITHDMA 0x80 /* status register (read) */ -#define REG_STAT(x) ((x)->scsi.io_port + (4 << (x)->scsi.io_shift)) +#define REG_STAT (4) #define STAT_IO (1 << 0) /* IO phase */ #define STAT_CD (1 << 1) /* CD phase */ #define STAT_MSG (1 << 2) /* MSG phase */ @@ -76,11 +76,11 @@ #define STAT_MESGIN (STAT_MSG|STAT_CD|STAT_IO) /* Message In */ /* bus ID for select / reselect */ -#define REG_SDID(x) ((x)->scsi.io_port + (4 << (x)->scsi.io_shift)) +#define REG_SDID (4) #define BUSID(target) ((target) & 7) /* Interrupt status register (read) */ -#define REG_INST(x) ((x)->scsi.io_port + (5 << (x)->scsi.io_shift)) +#define REG_INST (5) #define INST_SELWOATN (1 << 0) /* Select w/o ATN */ #define INST_SELATN (1 << 1) /* Select w/ATN */ #define INST_RESELECTED (1 << 2) /* Reselected */ @@ -91,10 +91,10 @@ #define INST_BUSRESET (1 << 7) /* SCSI Bus reset */ /* Timeout register (write) */ -#define REG_STIM(x) ((x)->scsi.io_port + (5 << (x)->scsi.io_shift)) +#define REG_STIM (5) /* Sequence step register (read) */ -#define REG_IS(x) ((x)->scsi.io_port + (6 << (x)->scsi.io_shift)) +#define REG_IS (6) #define IS_BITS 0x07 #define IS_SELARB 0x00 /* Select & Arb ok */ #define IS_MSGBYTESENT 0x01 /* One byte message sent*/ @@ -104,18 +104,18 @@ #define IS_SOF 0x08 /* Sync off flag */ /* Transfer period step (write) */ -#define REG_STP(x) ((x)->scsi.io_port + (6 << (x)->scsi.io_shift)) +#define REG_STP (6) /* Synchronous Offset (write) */ -#define REG_SOF(x) ((x)->scsi.io_port + (7 << (x)->scsi.io_shift)) +#define REG_SOF (7) /* Fifo state register (read) */ -#define REG_CFIS(x) ((x)->scsi.io_port + (7 << (x)->scsi.io_shift)) +#define REG_CFIS (7) #define CFIS_CF 0x1f /* Num bytes in FIFO */ #define CFIS_IS 0xe0 /* Step */ /* config register 1 */ -#define REG_CNTL1(x) ((x)->scsi.io_port + (8 << (x)->scsi.io_shift)) +#define REG_CNTL1 (8) #define CNTL1_CID (7 << 0) /* Chip ID */ #define CNTL1_STE (1 << 3) /* Self test enable */ #define CNTL1_PERE (1 << 4) /* Parity enable reporting en. */ @@ -124,7 +124,7 @@ #define CNTL1_ETM (1 << 7) /* Extended Timing Mode */ /* Clock conversion factor (read) */ -#define REG_CLKF(x) ((x)->scsi.io_port + (9 << (x)->scsi.io_shift)) +#define REG_CLKF (9) #define CLKF_F37MHZ 0x00 /* 35.01 - 40 MHz */ #define CLKF_F10MHZ 0x02 /* 10 MHz */ #define CLKF_F12MHZ 0x03 /* 10.01 - 15 MHz */ @@ -134,13 +134,13 @@ #define CLKF_F32MHZ 0x07 /* 30.01 - 35 MHz */ /* Chip test register (write) */ -#define REG0_FTM(x) ((x)->scsi.io_port + (10 << (x)->scsi.io_shift)) +#define REG_FTM (10) #define TEST_FTM 0x01 /* Force target mode */ #define TEST_FIM 0x02 /* Force initiator mode */ #define TEST_FHI 0x04 /* Force high impedance mode */ /* Configuration register 2 (read/write) */ -#define REG_CNTL2(x) ((x)->scsi.io_port + (11 << (x)->scsi.io_shift)) +#define REG_CNTL2 (11) #define CNTL2_PGDP (1 << 0) /* Pass Th/Generate Data Parity */ #define CNTL2_PGRP (1 << 1) /* Pass Th/Generate Reg Parity */ #define CNTL2_ACDPE (1 << 2) /* Abort on Cmd/Data Parity Err */ @@ -151,7 +151,7 @@ #define CNTL2_DAE (1 << 7) /* Data Alignment Enable */ /* Configuration register 3 (read/write) */ -#define REG_CNTL3(x) ((x)->scsi.io_port + (12 << (x)->scsi.io_shift)) +#define REG_CNTL3 (12) #define CNTL3_BS8 (1 << 0) /* Burst size 8 */ #define CNTL3_MDM (1 << 1) /* Modify DMA mode */ #define CNTL3_LBTM (1 << 2) /* Last Byte Transfer mode */ @@ -162,14 +162,14 @@ #define CNTL3_ADIDCHK (1 << 7) /* Additional ID check */ /* High transfer count (read/write) */ -#define REG_CTCH(x) ((x)->scsi.io_port + (14 << (x)->scsi.io_shift)) -#define REG_STCH(x) ((x)->scsi.io_port + (14 << (x)->scsi.io_shift)) +#define REG_CTCH (14) +#define REG_STCH (14) -/* ID reigster (read only) */ -#define REG1_ID(x) ((x)->scsi.io_port + (14 << (x)->scsi.io_shift)) +/* ID register (read only) */ +#define REG_ID (14) /* Data alignment */ -#define REG0_DAL(x) ((x)->scsi.io_port + (15 << (x)->scsi.io_shift)) +#define REG_DAL (15) typedef enum { PHASE_IDLE, /* we're not planning on doing anything */ @@ -212,6 +212,9 @@ typedef enum { #define MAGIC 0x441296bdUL #define NR_MSGS 8 +#define FASCAP_DMA (1 << 0) +#define FASCAP_PSEUDODMA (1 << 1) + typedef struct { unsigned long magic_start; spinlock_t host_lock; @@ -233,12 +236,13 @@ typedef struct { /* driver information */ struct { + phase_t phase; /* current phase */ + void *io_base; /* iomem base of FAS216 */ unsigned int io_port; /* base address of FAS216 */ unsigned int io_shift; /* shift to adjust reg offsets by */ - unsigned int irq; /* interrupt */ unsigned char cfg[4]; /* configuration registers */ const char *type; /* chip type */ - phase_t phase; /* current phase */ + unsigned int irq; /* interrupt */ struct { unsigned char target; /* reconnected target */ @@ -253,7 +257,6 @@ typedef struct { unsigned int async_stp; /* Async transfer STP value */ unsigned char msgin_fifo; /* bytes in fifo at time of message in */ unsigned char message[256]; /* last message received from device */ - unsigned int msglen; /* length of last message received */ unsigned char disconnectable:1; /* this command can be disconnected */ unsigned char aborting:1; /* aborting command */ @@ -281,6 +284,7 @@ typedef struct { unsigned char wide_max_size; /* Maximum wide transfer size */ unsigned char cntl3; /* Control Reg 3 */ unsigned int asyncperiod; /* Async transfer period (ns) */ + unsigned int capabilities; /* driver capabilities */ unsigned int disconnect_ok:1; /* Disconnects allowed? */ } ifcfg; @@ -319,26 +323,18 @@ typedef struct { } FAS216_Info; /* Function: int fas216_init (struct Scsi_Host *instance) - * Purpose : initialise FAS/NCR/AMD SCSI ic. + * Purpose : initialise FAS/NCR/AMD SCSI structures. * Params : instance - a driver-specific filled-out structure * Returns : 0 on success */ extern int fas216_init (struct Scsi_Host *instance); -/* Function: int fas216_abort (Scsi_Cmnd *SCpnt) - * Purpose : abort a command if something horrible happens. - * Params : SCpnt - Command that is believed to be causing a problem. - * Returns : one of SCSI_ABORT_ macros. - */ -extern int fas216_abort (Scsi_Cmnd *); - -/* Function: int fas216_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags) - * Purpose : resets the adapter if something horrible happens. - * Params : SCpnt - Command that is believed to be causing a problem. - * reset_flags - flags indicating reset type that is believed to be required. - * Returns : one of SCSI_RESET_ macros, or'd with the SCSI_RESET_*_RESET macros. +/* Function: int fas216_add (struct Scsi_Host *instance, struct device *dev) + * Purpose : initialise FAS/NCR/AMD SCSI ic. + * Params : instance - a driver-specific filled-out structure + * Returns : 0 on success */ -extern int fas216_reset (Scsi_Cmnd *, unsigned int); +extern int fas216_add (struct Scsi_Host *instance, struct device *dev); /* Function: int fas216_queue_command (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) * Purpose : queue a command for adapter to process. @@ -355,20 +351,21 @@ extern int fas216_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); */ extern int fas216_command (Scsi_Cmnd *); -/* Function: void fas216_intr (struct Scsi_Host *instance) +/* Function: void fas216_intr (FAS216_Info *info) * Purpose : handle interrupts from the interface to progress a command - * Params : instance - interface to service + * Params : info - interface to service */ -extern void fas216_intr (struct Scsi_Host *instance); +extern void fas216_intr (FAS216_Info *info); + +extern void fas216_remove (struct Scsi_Host *instance); -/* Function: int fas216_release (struct Scsi_Host *instance) +/* Function: void fas216_release (struct Scsi_Host *instance) * Purpose : release all resources and put everything to bed for FAS/NCR/AMD SCSI ic. * Params : instance - a driver-specific filled-out structure * Returns : 0 on success */ -extern int fas216_release (struct Scsi_Host *instance); +extern void fas216_release (struct Scsi_Host *instance); -extern int fas216_info(FAS216_Info *info, char *buffer); extern int fas216_print_host(FAS216_Info *info, char *buffer); extern int fas216_print_stats(FAS216_Info *info, char *buffer); extern int fas216_print_device(FAS216_Info *info, Scsi_Device *scd, char *buffer); diff --git a/drivers/acorn/scsi/oak.c b/drivers/acorn/scsi/oak.c index 283e96275547..0246942f9345 100644 --- a/drivers/acorn/scsi/oak.c +++ b/drivers/acorn/scsi/oak.c @@ -192,7 +192,8 @@ static struct ecard_driver oakscsi_driver = { .remove = __devexit_p(oakscsi_remove), .id_table = oakscsi_cids, .drv = { - .name = "oakscsi", + .devclass = &shost_devclass, + .name = "oakscsi", }, }; diff --git a/drivers/acorn/scsi/powertec.c b/drivers/acorn/scsi/powertec.c index 670b19adda59..bf76791d6b50 100644 --- a/drivers/acorn/scsi/powertec.c +++ b/drivers/acorn/scsi/powertec.c @@ -1,7 +1,7 @@ /* * linux/drivers/acorn/scsi/powertec.c * - * Copyright (C) 1997-2002 Russell King + * Copyright (C) 1997-2003 Russell King * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -32,24 +32,23 @@ #include -#define POWERTEC_FAS216_OFFSET 0xc00 -#define POWERTEC_FAS216_SHIFT 4 -#define POWERTEC_FAS216_SIZE (16 << POWERTEC_FAS216_SHIFT) +#define POWERTEC_FAS216_OFFSET 0x3000 +#define POWERTEC_FAS216_SHIFT 6 -#define POWERTEC_INTR_STATUS 0x800 +#define POWERTEC_INTR_STATUS 0x2000 #define POWERTEC_INTR_BIT 0x80 -#define POWERTEC_RESET_CONTROL 0x406 +#define POWERTEC_RESET_CONTROL 0x1018 #define POWERTEC_RESET_BIT 1 -#define POWERTEC_TERM_CONTROL 0x806 +#define POWERTEC_TERM_CONTROL 0x2018 #define POWERTEC_TERM_ENABLE 1 -#define POWERTEC_INTR_CONTROL 0x407 +#define POWERTEC_INTR_CONTROL 0x101c #define POWERTEC_INTR_ENABLE 1 #define POWERTEC_INTR_DISABLE 0 -#define VERSION "1.00 (13/11/2002 2.5.47)" +#define VERSION "1.10 (19/01/2003 2.5.59)" /* * Use term=0,1,0,0,0 to turn terminators on/off. @@ -60,10 +59,11 @@ static int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 }; #define NR_SG 256 struct powertec_info { - FAS216_Info info; - unsigned int term_port; - unsigned int term_ctl; - struct scatterlist sg[NR_SG]; + FAS216_Info info; + struct expansion_card *ec; + void *term_port; + unsigned int term_ctl; + struct scatterlist sg[NR_SG]; }; /* Prototype: void powertecscsi_irqenable(ec, irqnr) @@ -74,8 +74,7 @@ struct powertec_info { static void powertecscsi_irqenable(struct expansion_card *ec, int irqnr) { - unsigned int port = (unsigned int)ec->irq_data; - outb(POWERTEC_INTR_ENABLE, port); + writeb(POWERTEC_INTR_ENABLE, ec->irq_data); } /* Prototype: void powertecscsi_irqdisable(ec, irqnr) @@ -86,8 +85,7 @@ powertecscsi_irqenable(struct expansion_card *ec, int irqnr) static void powertecscsi_irqdisable(struct expansion_card *ec, int irqnr) { - unsigned int port = (unsigned int)ec->irq_data; - outb(POWERTEC_INTR_DISABLE, port); + writeb(POWERTEC_INTR_DISABLE, ec->irq_data); } static const expansioncard_ops_t powertecscsi_ops = { @@ -106,7 +104,7 @@ powertecscsi_terminator_ctl(struct Scsi_Host *host, int on_off) struct powertec_info *info = (struct powertec_info *)host->hostdata; info->term_ctl = on_off ? POWERTEC_TERM_ENABLE : 0; - outb(info->term_ctl, info->term_port); + writeb(info->term_ctl, info->term_port); } /* Prototype: void powertecscsi_intr(irq, *dev_id, *regs) @@ -118,9 +116,9 @@ powertecscsi_terminator_ctl(struct Scsi_Host *host, int on_off) static void powertecscsi_intr(int irq, void *dev_id, struct pt_regs *regs) { - struct Scsi_Host *host = (struct Scsi_Host *)dev_id; + struct powertec_info *info = dev_id; - fas216_intr(host); + fas216_intr(&info->info); } /* Prototype: fasdmatype_t powertecscsi_dma_setup(host, SCpnt, direction, min_type) @@ -139,8 +137,8 @@ powertecscsi_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp, struct device *dev = scsi_get_device(host); int dmach = host->dma_channel; - if (dmach != NO_DMA && - (min_type == fasdma_real_all || SCp->this_residual >= 512)) { + if (info->info.ifcfg.capabilities & FASCAP_DMA && + min_type == fasdma_real_all) { int bufs, map_dir, dma_dir; bufs = copy_SCp_to_sg(&info->sg[0], SCp, NR_SG); @@ -188,13 +186,11 @@ powertecscsi_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp) const char *powertecscsi_info(struct Scsi_Host *host) { struct powertec_info *info = (struct powertec_info *)host->hostdata; - static char string[150], *p; + static char string[150]; - p = string; - p += sprintf(p, "%s ", host->hostt->name); - p += fas216_info(&info->info, p); - p += sprintf(p, "v%s terminators o%s", - VERSION, info->term_ctl ? "n" : "ff"); + sprintf(string, "%s (%s) in slot %d v%s terminators o%s", + host->hostt->name, info->info.scsi.type, info->ec->slot_no, + VERSION, info->term_ctl ? "n" : "ff"); return string; } @@ -262,7 +258,6 @@ int powertecscsi_proc_info(char *buffer, char **start, off_t offset, begin = 0; pos = sprintf(buffer, "PowerTec SCSI driver v%s\n", VERSION); - pos += fas216_print_host(&info->info, buffer + pos); pos += sprintf(buffer + pos, "Term : o%s\n", info->term_ctl ? "n" : "ff"); @@ -290,6 +285,30 @@ int powertecscsi_proc_info(char *buffer, char **start, off_t offset, return pos; } +static ssize_t powertecscsi_show_term(struct device *dev, char *buf) +{ + struct expansion_card *ec = ECARD_DEV(dev); + struct Scsi_Host *host = ecard_get_drvdata(ec); + struct powertec_info *info = (struct powertec_info *)host->hostdata; + + return sprintf(buf, "%d\n", info->term_ctl ? 1 : 0); +} + +static ssize_t +powertecscsi_store_term(struct device *dev, const char *buf, size_t len) +{ + struct expansion_card *ec = ECARD_DEV(dev); + struct Scsi_Host *host = ecard_get_drvdata(ec); + + if (len > 1) + powertecscsi_terminator_ctl(host, buf[0] != '0'); + + return len; +} + +static DEVICE_ATTR(bus_term, S_IRUGO | S_IWUSR, + powertecscsi_show_term, powertecscsi_store_term); + static Scsi_Host_Template powertecscsi_template = { .module = THIS_MODULE, .proc_info = powertecscsi_proc_info, @@ -302,10 +321,10 @@ static Scsi_Host_Template powertecscsi_template = { .eh_device_reset_handler = fas216_eh_device_reset, .eh_abort_handler = fas216_eh_abort, - .can_queue = 1, + .can_queue = 8, .this_id = 7, .sg_tablesize = SG_ALL, - .cmd_per_lun = 1, + .cmd_per_lun = 2, .use_clustering = ENABLE_CLUSTERING, .proc_name = "powertec", }; @@ -314,37 +333,50 @@ static int __devinit powertecscsi_probe(struct expansion_card *ec, const struct ecard_id *id) { struct Scsi_Host *host; - struct powertec_info *info; - int ret = -ENOMEM; + struct powertec_info *info; + unsigned long resbase, reslen; + unsigned char *base; + int ret; + + resbase = ecard_resource_start(ec, ECARD_RES_IOCFAST); + reslen = ecard_resource_len(ec, ECARD_RES_IOCFAST); + + if (!request_mem_region(resbase, reslen, "powertecscsi")) { + ret = -EBUSY; + goto out; + } + + base = ioremap(resbase, reslen); + if (!base) { + ret = -ENOMEM; + goto out_region; + } host = scsi_register(&powertecscsi_template, sizeof (struct powertec_info)); - if (!host) - goto out; + if (!host) { + ret = -ENOMEM; + goto out_unmap; + } - host->io_port = ecard_address(ec, ECARD_IOC, ECARD_FAST); + host->base = (unsigned long)base; host->irq = ec->irq; host->dma_channel = ec->dma; - if (!request_region(host->io_port + POWERTEC_FAS216_OFFSET, - POWERTEC_FAS216_SIZE, "powertec2-fas")) { - ret = -EBUSY; - goto out_free; - } - - ec->irqaddr = (unsigned char *) - ioaddr(host->io_port + POWERTEC_INTR_STATUS); + ec->irqaddr = base + POWERTEC_INTR_STATUS; ec->irqmask = POWERTEC_INTR_BIT; - ec->irq_data = (void *)(host->io_port + POWERTEC_INTR_CONTROL); - ec->ops = (expansioncard_ops_t *)&powertecscsi_ops; + ec->irq_data = base + POWERTEC_INTR_CONTROL; + ec->ops = &powertecscsi_ops; ecard_set_drvdata(ec, host); info = (struct powertec_info *)host->hostdata; - info->term_port = host->io_port + POWERTEC_TERM_CONTROL; + info->term_port = base + POWERTEC_TERM_CONTROL; powertecscsi_terminator_ctl(host, term[ec->slot_no]); - info->info.scsi.io_port = host->io_port + POWERTEC_FAS216_OFFSET; + device_create_file(&ec->dev, &dev_attr_bus_term); + + info->info.scsi.io_base = base + POWERTEC_FAS216_OFFSET; info->info.scsi.io_shift = POWERTEC_FAS216_SHIFT; info->info.scsi.irq = host->irq; info->info.ifcfg.clockrate = 40; /* MHz */ @@ -354,16 +386,21 @@ powertecscsi_probe(struct expansion_card *ec, const struct ecard_id *id) info->info.ifcfg.cntl3 = CNTL3_BS8 | CNTL3_FASTSCSI | CNTL3_FASTCLK; info->info.ifcfg.disconnect_ok = 1; info->info.ifcfg.wide_max_size = 0; + info->info.ifcfg.capabilities = 0; info->info.dma.setup = powertecscsi_dma_setup; info->info.dma.pseudo = NULL; info->info.dma.stop = powertecscsi_dma_stop; + ret = fas216_init(host); + if (ret) + goto out_free; + ret = request_irq(host->irq, powertecscsi_intr, - SA_INTERRUPT, "powertec", host); + SA_INTERRUPT, "powertec", info); if (ret) { printk("scsi%d: IRQ%d not free: %d\n", host->host_no, host->irq, ret); - goto out_region; + goto out_release; } if (host->dma_channel != NO_DMA) { @@ -373,26 +410,31 @@ powertecscsi_probe(struct expansion_card *ec, const struct ecard_id *id) host->dma_channel = NO_DMA; } else { set_dma_speed(host->dma_channel, 180); + info->info.ifcfg.capabilities |= FASCAP_DMA; } } - fas216_init(host); - - ret = scsi_add_host(host, &ec->dev); + ret = fas216_add(host, &ec->dev); if (ret == 0) goto out; - fas216_release(host); - if (host->dma_channel != NO_DMA) free_dma(host->dma_channel); free_irq(host->irq, host); - out_region: - release_region(host->io_port + POWERTEC_FAS216_OFFSET, - POWERTEC_FAS216_SIZE); + + out_release: + fas216_release(host); + out_free: + device_remove_file(&ec->dev, &dev_attr_bus_term); scsi_unregister(host); + out_unmap: + iounmap(base); + + out_region: + release_mem_region(resbase, reslen); + out: return ret; } @@ -400,16 +442,26 @@ powertecscsi_probe(struct expansion_card *ec, const struct ecard_id *id) static void __devexit powertecscsi_remove(struct expansion_card *ec) { struct Scsi_Host *host = ecard_get_drvdata(ec); + struct powertecscsi_info *info = (struct powertecscsi_info *)host->hostdata; + unsigned long resbase, reslen; ecard_set_drvdata(ec, NULL); - scsi_remove_host(host); - fas216_release(host); + fas216_remove(host); + + device_remove_file(&ec->dev, &dev_attr_bus_term); if (host->dma_channel != NO_DMA) free_dma(host->dma_channel); - free_irq(host->irq, host); - release_region(host->io_port + POWERTEC_FAS216_OFFSET, - POWERTEC_FAS216_SIZE); + free_irq(host->irq, info); + + iounmap((void *)host->base); + + resbase = ecard_resource_start(ec, ECARD_RES_IOCFAST); + reslen = ecard_resource_len(ec, ECARD_RES_IOCFAST); + + release_mem_region(resbase, reslen); + + fas216_release(host); scsi_unregister(host); } @@ -423,7 +475,8 @@ static struct ecard_driver powertecscsi_driver = { .remove = __devexit_p(powertecscsi_remove), .id_table = powertecscsi_cids, .drv = { - .name = "powertecscsi", + .devclass = &shost_devclass, + .name = "powertecscsi", }, }; diff --git a/drivers/acorn/scsi/scsi.h b/drivers/acorn/scsi/scsi.h index f9c6c5869a6c..0eb2c8a0daae 100644 --- a/drivers/acorn/scsi/scsi.h +++ b/drivers/acorn/scsi/scsi.h @@ -55,8 +55,6 @@ static inline unsigned char get_next_SCp_byte(Scsi_Pointer *SCp) SCp->ptr += 1; SCp->this_residual -= 1; - if (SCp->this_residual == 0) - next_SCp(SCp); return c; } @@ -66,8 +64,6 @@ static inline void put_next_SCp_byte(Scsi_Pointer *SCp, unsigned char c) *SCp->ptr = c; SCp->ptr += 1; SCp->this_residual -= 1; - if (SCp->this_residual == 0) - next_SCp(SCp); } static inline void init_SCp(Scsi_Cmnd *SCpnt) @@ -112,7 +108,7 @@ static inline void init_SCp(Scsi_Cmnd *SCpnt) * we aren't interested in the buffer pointer. */ if (SCpnt->SCp.this_residual == 0 && SCpnt->SCp.ptr) { -#ifdef BELT_AND_BRACES +#if 0 //def BELT_AND_BRACES printk(KERN_WARNING "scsi%d.%c: zero length buffer passed for " "command ", SCpnt->host->host_no, '0' + SCpnt->target); print_command(SCpnt->cmnd); -- cgit v1.2.3 From bc870c88cafc75983907f5e95184d74537777d1b Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 26 Jan 2003 23:53:26 +0000 Subject: [ARM] Add linux/errno.h include to allow pcf8583.c to build. --- drivers/acorn/char/pcf8583.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/acorn/char/pcf8583.c b/drivers/acorn/char/pcf8583.c index 05ed2e52c190..216d290606a9 100644 --- a/drivers/acorn/char/pcf8583.c +++ b/drivers/acorn/char/pcf8583.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include "pcf8583.h" -- cgit v1.2.3 From aa2cbc19b92e37e54e5af342699e2bc51e67c1dc Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 27 Jan 2003 00:10:48 +0000 Subject: [ARM] Remove 200Hz -> 100Hz conversion for ebsa110 timer. We now really run the ebsa110 kernel timer at 200Hz, and convert where necessary to 100Hz for user space. --- arch/arm/mach-ebsa110/Makefile | 2 +- arch/arm/mach-ebsa110/time.c | 112 ----------------------------------- include/asm-arm/arch-ebsa110/param.h | 1 + include/asm-arm/arch-ebsa110/time.h | 86 ++++++++++++++++++++++++--- 4 files changed, 80 insertions(+), 121 deletions(-) delete mode 100644 arch/arm/mach-ebsa110/time.c diff --git a/arch/arm/mach-ebsa110/Makefile b/arch/arm/mach-ebsa110/Makefile index 2f0104c4f10e..1504bbe04749 100644 --- a/arch/arm/mach-ebsa110/Makefile +++ b/arch/arm/mach-ebsa110/Makefile @@ -4,7 +4,7 @@ # Object file lists. -obj-y := core.o io.o time.o +obj-y := core.o io.o obj-m := obj-n := obj- := diff --git a/arch/arm/mach-ebsa110/time.c b/arch/arm/mach-ebsa110/time.c deleted file mode 100644 index 989ab98a8d97..000000000000 --- a/arch/arm/mach-ebsa110/time.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * linux/arch/arm/mach-ebsa110/time.c - * - * Copyright (C) 2001 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include - -#include - -#define PIT_CTRL (PIT_BASE + 0x0d) -#define PIT_T2 (PIT_BASE + 0x09) -#define PIT_T1 (PIT_BASE + 0x05) -#define PIT_T0 (PIT_BASE + 0x01) - -/* - * This is the rate at which your MCLK signal toggles (in Hz) - * This was measured on a 10 digit frequency counter sampling - * over 1 second. - */ -#define MCLK 47894000 - -/* - * This is the rate at which the PIT timers get clocked - */ -#define CLKBY7 (MCLK / 7) - -/* - * If CLKBY7 is larger than this, then we must do software - * division of the timer interrupt. - */ -#if CLKBY7 > 6553500 -#define DIVISOR 2 -#else -#define DIVISOR 1 -#endif - -/* - * This is the counter value - */ -#define COUNT ((CLKBY7 + (DIVISOR * HZ / 2)) / (DIVISOR * HZ)) - -extern unsigned long (*gettimeoffset)(void); - -static unsigned long divisor; - -/* - * Get the time offset from the system PIT. Note that if we have missed an - * interrupt, then the PIT counter will roll over (ie, be negative). - * This actually works out to be convenient. - */ -static unsigned long ebsa110_gettimeoffset(void) -{ - unsigned long offset, count; - - __raw_writeb(0x40, PIT_CTRL); - count = __raw_readb(PIT_T1); - count |= __raw_readb(PIT_T1) << 8; - - /* - * If count > COUNT, make the number negative. - */ - if (count > COUNT) - count |= 0xffff0000; - - offset = COUNT * (DIVISOR - divisor); - offset -= count; - - /* - * `offset' is in units of timer counts. Convert - * offset to units of microseconds. - */ - offset = offset * (1000000 / HZ) / (COUNT * DIVISOR); - - return offset; -} - -int ebsa110_reset_timer(void) -{ - u32 count; - - /* latch and read timer 1 */ - __raw_writeb(0x40, PIT_CTRL); - count = __raw_readb(PIT_T1); - count |= __raw_readb(PIT_T1) << 8; - - count += COUNT; - - __raw_writeb(count & 0xff, PIT_T1); - __raw_writeb(count >> 8, PIT_T1); - - if (divisor == 0) - divisor = DIVISOR; - divisor -= 1; - return divisor; -} - -void __init ebsa110_setup_timer(void) -{ - /* - * Timer 1, mode 2, LSB/MSB - */ - __raw_writeb(0x70, PIT_CTRL); - __raw_writeb(COUNT & 0xff, PIT_T1); - __raw_writeb(COUNT >> 8, PIT_T1); - divisor = DIVISOR - 1; - - gettimeoffset = ebsa110_gettimeoffset; -} diff --git a/include/asm-arm/arch-ebsa110/param.h b/include/asm-arm/arch-ebsa110/param.h index f077b717193d..13a9fc1b7a25 100644 --- a/include/asm-arm/arch-ebsa110/param.h +++ b/include/asm-arm/arch-ebsa110/param.h @@ -1,3 +1,4 @@ /* * linux/include/asm-arm/arch-ebsa110/param.h */ +#define __KERNEL_HZ 200 diff --git a/include/asm-arm/arch-ebsa110/time.h b/include/asm-arm/arch-ebsa110/time.h index 278c8e3632a1..30c90e607546 100644 --- a/include/asm-arm/arch-ebsa110/time.h +++ b/include/asm-arm/arch-ebsa110/time.h @@ -17,17 +17,80 @@ */ #include +#include -extern int ebsa110_reset_timer(void); -extern void ebsa110_setup_timer(void); +extern unsigned long (*gettimeoffset)(void); + +#define PIT_CTRL (PIT_BASE + 0x0d) +#define PIT_T2 (PIT_BASE + 0x09) +#define PIT_T1 (PIT_BASE + 0x05) +#define PIT_T0 (PIT_BASE + 0x01) + +/* + * This is the rate at which your MCLK signal toggles (in Hz) + * This was measured on a 10 digit frequency counter sampling + * over 1 second. + */ +#define MCLK 47894000 + +/* + * This is the rate at which the PIT timers get clocked + */ +#define CLKBY7 (MCLK / 7) + +/* + * This is the counter value. We tick at 200Hz on this platform. + */ +#define COUNT ((CLKBY7 + (HZ / 2)) / HZ) + +/* + * Get the time offset from the system PIT. Note that if we have missed an + * interrupt, then the PIT counter will roll over (ie, be negative). + * This actually works out to be convenient. + */ +static unsigned long ebsa110_gettimeoffset(void) +{ + unsigned long offset, count; + + __raw_writeb(0x40, PIT_CTRL); + count = __raw_readb(PIT_T1); + count |= __raw_readb(PIT_T1) << 8; + + /* + * If count > COUNT, make the number negative. + */ + if (count > COUNT) + count |= 0xffff0000; + + offset = COUNT; + offset -= count; + + /* + * `offset' is in units of timer counts. Convert + * offset to units of microseconds. + */ + offset = offset * (1000000 / HZ) / COUNT; + + return offset; +} static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - if (ebsa110_reset_timer()) { - do_leds(); - do_timer(regs); - do_profile(regs); - } + u32 count; + + /* latch and read timer 1 */ + __raw_writeb(0x40, PIT_CTRL); + count = __raw_readb(PIT_T1); + count |= __raw_readb(PIT_T1) << 8; + + count += COUNT; + + __raw_writeb(count & 0xff, PIT_T1); + __raw_writeb(count >> 8, PIT_T1); + + do_leds(); + do_timer(regs); + do_profile(regs); } /* @@ -35,7 +98,14 @@ static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) */ void __init time_init(void) { - ebsa110_setup_timer(); + /* + * Timer 1, mode 2, LSB/MSB + */ + __raw_writeb(0x70, PIT_CTRL); + __raw_writeb(COUNT & 0xff, PIT_T1); + __raw_writeb(COUNT >> 8, PIT_T1); + + gettimeoffset = ebsa110_gettimeoffset; timer_irq.handler = timer_interrupt; -- cgit v1.2.3 From 76a1ee06ce2edfb7cad2d30afa026e3ad122e939 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 27 Jan 2003 10:01:45 +0000 Subject: [ARM] Include ARM architecture version in module "version" string --- include/asm-arm/module.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/asm-arm/module.h b/include/asm-arm/module.h index 5b4d1a3f3679..24b168dc31a3 100644 --- a/include/asm-arm/module.h +++ b/include/asm-arm/module.h @@ -10,4 +10,9 @@ struct mod_arch_specific #define Elf_Sym Elf32_Sym #define Elf_Ehdr Elf32_Ehdr +/* + * Include the ARM architecture version. + */ +#define MODULE_ARCH_VERMAGIC "ARMv" __stringify(__LINUX_ARM_ARCH__) " " + #endif /* _ASM_ARM_MODULE_H */ -- cgit v1.2.3 From 4f00bd8fbffcc71924b1db7a1d54d8eb34d7ea6b Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 29 Jan 2003 16:49:42 +0000 Subject: [ARM PATCH] 1361/1: EPXA10DB: Correct some typos in uart00.c Patch from Dirk Behme Patch some typos in uart00.c. frame is selected with FE_MSK and for OE_MSK rds must be used. --- drivers/serial/uart00.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/serial/uart00.c b/drivers/serial/uart00.c index 8b53824b0ee0..8071a2556950 100644 --- a/drivers/serial/uart00.c +++ b/drivers/serial/uart00.c @@ -1,5 +1,5 @@ /* - * linux/drivers/char/uart00.c + * linux/drivers/serial/uart00.c * * Driver for UART00 serial ports * @@ -149,7 +149,7 @@ uart00_rx_chars(struct uart_port *port, struct pt_regs *regs) goto ignore_char; } else if (rds & UART_RDS_PE_MSK) port->icount.parity++; - else if (rds & UART_RDS_PE_MSK) + else if (rds & UART_RDS_FE_MSK) port->icount.frame++; if (rds & UART_RDS_OE_MSK) port->icount.overrun++; @@ -168,7 +168,7 @@ uart00_rx_chars(struct uart_port *port, struct pt_regs *regs) else if (rds & UART_RDS_FE_MSK) flg = TTY_FRAME; - if (status & UART_RDS_OE_MSK) { + if (rds & UART_RDS_OE_MSK) { /* * CHECK: does overrun affect the current character? * ASSUMPTION: it does not. -- cgit v1.2.3 From c7a3f3c2af248b5c77bf7dd6fe164f83cee79fc6 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 29 Jan 2003 17:07:21 +0000 Subject: [ARM PATCH] 1348/1: Add support for the HackKit board Patch from Stefan Eletzhofer This patch adds basic support for the HackKit Core CPU Board. --- arch/arm/def-configs/hackkit | 654 ++++++++++++++++++++++++++++++++++++ arch/arm/mach-sa1100/Kconfig | 7 + arch/arm/mach-sa1100/Makefile | 4 + arch/arm/mach-sa1100/hackkit.c | 180 ++++++++++ arch/arm/mach-sa1100/leds-hackkit.c | 113 +++++++ arch/arm/mach-sa1100/leds.c | 2 + arch/arm/mach-sa1100/leds.h | 1 + drivers/mtd/maps/sa1100-flash.c | 37 ++ 8 files changed, 998 insertions(+) create mode 100644 arch/arm/def-configs/hackkit create mode 100644 arch/arm/mach-sa1100/hackkit.c create mode 100644 arch/arm/mach-sa1100/leds-hackkit.c diff --git a/arch/arm/def-configs/hackkit b/arch/arm/def-configs/hackkit new file mode 100644 index 000000000000..8d9dfefab4cf --- /dev/null +++ b/arch/arm/def-configs/hackkit @@ -0,0 +1,654 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +CONFIG_MMU=y +CONFIG_SWAP=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# General setup +# +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODULE_UNLOAD is not set +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_KMOD=y + +# +# System Type +# +# CONFIG_ARCH_ADIFCC is not set +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP310 is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_RPC is not set +CONFIG_ARCH_SA1100=y +# CONFIG_ARCH_SHARK is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Archimedes/A5000 Implementations (select only ONE) +# + +# +# CLPS711X/EP721X Implementations +# + +# +# Epxa10db +# + +# +# Footbridge Implementations +# + +# +# IOP310 Implementation Options +# + +# +# IOP310 Chipset Features +# + +# +# Intel PXA250/210 Implementations +# + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ASSABET is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3100 is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_H3800 is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_BADGE4 is not set +# CONFIG_SA1100_JORNADA720 is not set +CONFIG_SA1100_HACKKIT=y +# CONFIG_SA1100_HUW_WEBPANEL is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_OMNIMETER is not set +# CONFIG_SA1100_PANGOLIN is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_PT_SYSTEM3 is not set +# CONFIG_SA1100_SHANNON is not set +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set +# CONFIG_SA1100_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +# CONFIG_SA1100_STORK is not set +# CONFIG_SA1100_USB is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_SA1100=y +CONFIG_CPU_32v4=y + +# +# Processor Features +# + +# +# General setup +# +CONFIG_DISCONTIGMEM=y +CONFIG_ISA=y +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_24_API=y +CONFIG_CPU_FREQ_26_API=y +# CONFIG_HOTPLUG is not set + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_FASTFPE is not set +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +# CONFIG_PREEMPT is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="console=ttySA0,115200 root=/dev/ram0 initrd=0xc0400000,8M init=/rootshell" +CONFIG_LEDS=y +CONFIG_LEDS_TIMER=y +CONFIG_LEDS_CPU=y +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +CONFIG_MTD_DEBUG=y +CONFIG_MTD_DEBUG_VERBOSE=3 +# CONFIG_MTD_PARTITIONS is not set +# CONFIG_MTD_CONCAT is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_EDB7312 is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +CONFIG_INET_ECN=y +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_XFRM_USER is not set +# CONFIG_IPV6 is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +CONFIG_IPV6_SCTP__=y +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_LLC is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +CONFIG_DUMMY=y +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +# CONFIG_NET_ETHERNET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y +# CONFIG_STRIP is not set +# CONFIG_ARLAN is not set +# CONFIG_AIRONET4500 is not set + +# +# Wireless ISA/PCI cards support +# +# CONFIG_WAVELAN is not set +# CONFIG_AIRO is not set +# CONFIG_HERMES is not set +CONFIG_NET_WIRELESS=y + +# +# Token Ring devices (depends on LLC=y) +# +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN_BOOL is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_TSLIBDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_SA1100=y +CONFIG_SERIAL_SA1100_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# L3 serial bus support +# +# CONFIG_L3 is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +CONFIG_SA1100_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +CONFIG_CRAMFS=y +CONFIG_TMPFS=y +CONFIG_RAMFS=y +# CONFIG_ISO9660_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_XFS_FS is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +# CONFIG_NFS_FS is not set +# CONFIG_NFSD is not set +# CONFIG_EXPORTFS is not set +# CONFIG_CIFS is not set +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Console drivers +# +# CONFIG_VGA_CONSOLE is not set + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Misc devices +# + +# +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set + +# +# Console Switches +# +# CONFIG_SWITCHES is not set + +# +# USB support +# + +# +# Bluetooth support +# +# CONFIG_BT is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_INFO is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_SLAB=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_WAITQ=y +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_ERRORS=y +CONFIG_KALLSYMS=y +CONFIG_DEBUG_LL=y + +# +# Security options +# +CONFIG_SECURITY_CAPABILITIES=y + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +# CONFIG_CRC32 is not set +CONFIG_ZLIB_INFLATE=y diff --git a/arch/arm/mach-sa1100/Kconfig b/arch/arm/mach-sa1100/Kconfig index 7255a725d391..3ce853d36c0d 100644 --- a/arch/arm/mach-sa1100/Kconfig +++ b/arch/arm/mach-sa1100/Kconfig @@ -165,6 +165,13 @@ config SA1100_JORNADA720 handheld computer. See for details. +config SA1100_HACKKIT + bool "HackKit Core CPU Board" + depends on ARCH_SA1100 + help + Say Y here to support the HackKit Core CPU Board + ; + config SA1100_HUW_WEBPANEL bool "HuW WebPanel" depends on ARCH_SA1100 diff --git a/arch/arm/mach-sa1100/Makefile b/arch/arm/mach-sa1100/Makefile index 3b852f807ba5..c3a2adedeeeb 100644 --- a/arch/arm/mach-sa1100/Makefile +++ b/arch/arm/mach-sa1100/Makefile @@ -16,6 +16,7 @@ export-objs := dma.o generic.o pcipool.o pm.o sa1111.o sa1111-pcibuf.o ifeq ($(CONFIG_CPU_FREQ),y) obj-$(CONFIG_SA1100_ASSABET) += cpu-sa1110.o obj-$(CONFIG_SA1100_CERF) += cpu-sa1110.o +obj-$(CONFIG_SA1100_HACKKIT) += cpu-sa1110.o obj-$(CONFIG_SA1100_LART) += cpu-sa1100.o obj-$(CONFIG_SA1100_PT_SYSTEM3) += cpu-sa1110.o endif @@ -60,6 +61,9 @@ led-$(CONFIG_SA1100_GRAPHICSMASTER) += leds-graphicsmaster.o obj-$(CONFIG_SA1100_H3600) += h3600.o export-objs += h3600.o +obj-$(CONFIG_SA1100_HACKKIT) += hackkit.o +led-$(CONFIG_SA1100_HACKKIT) += leds-hackkit.o + obj-$(CONFIG_SA1100_HUW_WEBPANEL) += huw_webpanel.o export-objs += huw_webpanel.o diff --git a/arch/arm/mach-sa1100/hackkit.c b/arch/arm/mach-sa1100/hackkit.c new file mode 100644 index 000000000000..745891b05838 --- /dev/null +++ b/arch/arm/mach-sa1100/hackkit.c @@ -0,0 +1,180 @@ +/* + * linux/arch/arm/mach-sa1100/hackkit.c + * + * Copyright (C) 2002 Stefan Eletzhofer + * + * This file contains all HackKit tweaks. Based on original work from + * Nicolas Pitre's assabet fixes + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "generic.h" + +/********************************************************************** + * prototypes + */ + +/* init funcs */ +static void __init get_hackkit_scr(void); +static int __init hackkit_init(void); +static void __init hackkit_init_irq(void); +static void __init hackkit_map_io(void); + +static u_int hackkit_get_mctrl(struct uart_port *port); +static void hackkit_set_mctrl(struct uart_port *port, u_int mctrl); +static void hackkit_uart_pm(struct uart_port *port, u_int state, u_int oldstate); + +/********************************************************************** + * global data + */ + +/********************************************************************** + * static data + */ + +static struct map_desc hackkit_io_desc[] __initdata = { + /* virtual physical length type */ + { 0xe8000000, 0x00000000, 0x01000000, MT_DEVICE } /* Flash bank 0 */ +}; + +static struct sa1100_port_fns hackkit_port_fns __initdata = { + .set_mctrl = hackkit_set_mctrl, + .get_mctrl = hackkit_get_mctrl, + .pm = hackkit_uart_pm, +}; + +/********************************************************************** + * Static functions + */ + +static void __init hackkit_map_io(void) +{ + sa1100_map_io(); + iotable_init(hackkit_io_desc, ARRAY_SIZE(hackkit_io_desc)); + + sa1100_register_uart_fns(&hackkit_port_fns); + sa1100_register_uart(0, 1); /* com port */ + sa1100_register_uart(1, 2); + sa1100_register_uart(2, 3); /* radio module */ + + Ser1SDCR0 |= SDCR0_SUS; +} + +static void __init hackkit_init_irq(void) +{ + /* none used yet */ +} + +/** + * hackkit_uart_pm - powermgmt callback function for system 3 UART + * @port: uart port structure + * @state: pm state + * @oldstate: old pm state + * + */ +static void hackkit_uart_pm(struct uart_port *port, u_int state, u_int oldstate) +{ + /* TODO: switch on/off uart in powersave mode */ +} + +/* + * Note! this can be called from IRQ context. + * FIXME: No modem ctrl lines yet. + */ +static void hackkit_set_mctrl(struct uart_port *port, u_int mctrl) +{ +#if 0 + if (port->mapbase == _Ser1UTCR0) { + u_int set = 0, clear = 0; + + if (mctrl & TIOCM_RTS) + set |= PT_CTRL2_RS1_RTS; + else + clear |= PT_CTRL2_RS1_RTS; + + if (mctrl & TIOCM_DTR) + set |= PT_CTRL2_RS1_DTR; + else + clear |= PT_CTRL2_RS1_DTR; + + PTCTRL2_clear(clear); + PTCTRL2_set(set); + } +#endif +} + +static u_int hackkit_get_mctrl(struct uart_port *port) +{ + u_int ret = 0; +#if 0 + u_int irqsr = PT_IRQSR; + + /* need 2 reads to read current value */ + irqsr = PT_IRQSR; + + /* TODO: check IRQ source register for modem/com + status lines and set them correctly. */ +#endif + + ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR; + + return ret; +} + +static int __init hackkit_init(void) +{ + int ret = 0; + + if ( !machine_is_hackkit() ) { + ret = -EINVAL; + goto DONE; + } + + hackkit_init_irq(); + + ret = 0; +DONE: + return ret; +} + +/********************************************************************** + * Exported Functions + */ + +/********************************************************************** + * kernel magic macros + */ +arch_initcall(hackkit_init); + +MACHINE_START(HACKKIT, "HackKit Cpu Board") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + BOOT_PARAMS(0xc0000100) + MAPIO(hackkit_map_io) + INITIRQ(sa1100_init_irq) +MACHINE_END diff --git a/arch/arm/mach-sa1100/leds-hackkit.c b/arch/arm/mach-sa1100/leds-hackkit.c new file mode 100644 index 000000000000..2e5fa14aa4eb --- /dev/null +++ b/arch/arm/mach-sa1100/leds-hackkit.c @@ -0,0 +1,113 @@ +/* + * linux/arch/arm/mach-sa1100/leds-hackkit.c + * + * based on leds-lart.c + * + * (C) Erik Mouw (J.A.K.Mouw@its.tudelft.nl), April 21, 2000 + * (C) Stefan Eletzhofer , 2002 + * + * The HackKit has two leds (GPIO 22/23). The red led (gpio 22) is used + * as cpu led, the green one is used as timer led. + */ +#include +#include + +#include +#include +#include + +#include "leds.h" + + +#define LED_STATE_ENABLED 1 +#define LED_STATE_CLAIMED 2 + +static unsigned int led_state; +static unsigned int hw_led_state; + +#define LED_GREEN GPIO_GPIO23 +#define LED_RED GPIO_GPIO22 +#define LED_MASK (LED_RED | LED_GREEN) + +void hackkit_leds_event(led_event_t evt) +{ + unsigned long flags; + + local_irq_save(flags); + + switch(evt) { + case led_start: + /* pin 22/23 are outputs */ + GPDR |= LED_MASK; + hw_led_state = LED_MASK; + led_state = LED_STATE_ENABLED; + break; + + case led_stop: + led_state &= ~LED_STATE_ENABLED; + break; + + case led_claim: + led_state |= LED_STATE_CLAIMED; + hw_led_state = LED_MASK; + break; + + case led_release: + led_state &= ~LED_STATE_CLAIMED; + hw_led_state = LED_MASK; + break; + +#ifdef CONFIG_LEDS_TIMER + case led_timer: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state ^= LED_GREEN; + break; +#endif + +#ifdef CONFIG_LEDS_CPU + case led_idle_start: + /* The LART people like the LED to be off when the + system is idle... */ + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state &= ~LED_RED; + break; + + case led_idle_end: + /* ... and on if the system is not idle */ + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state |= LED_RED; + break; +#endif + + case led_red_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~LED_RED; + break; + + case led_red_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= LED_RED; + break; + + case led_green_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~LED_GREEN; + break; + + case led_green_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= LED_GREEN; + break; + + default: + break; + } + + /* Now set the GPIO state, or nothing will happen at all */ + if (led_state & LED_STATE_ENABLED) { + GPSR = hw_led_state; + GPCR = hw_led_state ^ LED_MASK; + } + + local_irq_restore(flags); +} diff --git a/arch/arm/mach-sa1100/leds.c b/arch/arm/mach-sa1100/leds.c index 425a0e4f5b41..eea32648a53e 100644 --- a/arch/arm/mach-sa1100/leds.c +++ b/arch/arm/mach-sa1100/leds.c @@ -29,6 +29,8 @@ sa1100_leds_init(void) leds_event = flexanet_leds_event; if (machine_is_graphicsclient()) leds_event = graphicsclient_leds_event; + if (machine_is_hackkit()) + leds_event = hackkit_leds_event; if (machine_is_lart()) leds_event = lart_leds_event; if (machine_is_pfs168()) diff --git a/arch/arm/mach-sa1100/leds.h b/arch/arm/mach-sa1100/leds.h index 2b4c33a60122..776b6020f550 100644 --- a/arch/arm/mach-sa1100/leds.h +++ b/arch/arm/mach-sa1100/leds.h @@ -5,6 +5,7 @@ extern void brutus_leds_event(led_event_t evt); extern void cerf_leds_event(led_event_t evt); extern void flexanet_leds_event(led_event_t evt); extern void graphicsclient_leds_event(led_event_t evt); +extern void hackkit_leds_event(led_event_t evt); extern void lart_leds_event(led_event_t evt); extern void pfs168_leds_event(led_event_t evt); extern void graphicsmaster_leds_event(led_event_t evt); diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index b6ce51d4d4af..78e67542fbac 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c @@ -512,6 +512,37 @@ static void h3xxx_set_vpp(struct map_info *map, int vpp) #define h3xxx_set_vpp NULL #endif +#ifdef CONFIG_SA1100_HACKKIT +static struct mtd_partition hackkit_partitions[] = { + { + .name = "BLOB", + .size = 0x00040000, + .offset = 0x00000000, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + .name = "config", + .size = 0x00040000, + .offset = MTDPART_OFS_APPEND, + }, { + .name = "kernel", + .size = 0x00100000, + .offset = MTDPART_OFS_APPEND, + }, { + .name = "initrd", + .size = 0x00180000, + .offset = MTDPART_OFS_APPEND, + }, { + .name = "rootfs", + .size = 0x700000, + .offset = MTDPART_OFS_APPEND, + }, { + .name = "data", + .size = MTDPART_SIZ_FULL, + .offset = MTDPART_OFS_APPEND, + } +}; +#endif + #ifdef CONFIG_SA1100_HUW_WEBPANEL static struct mtd_partition huw_webpanel_partitions[] = { { @@ -849,6 +880,12 @@ static int __init sa1100_static_partitions(struct mtd_partition **parts) nb_parts = ARRAY_SIZE(h3xxx_partitions); } #endif +#ifdef CONFIG_SA1100_HACKKIT + if (machine_is_hackkit()) { + *parts = hackkit_partitions; + nb_parts = ARRAY_SIZE(hackkit_partitions); + } +#endif #ifdef CONFIG_SA1100_HUW_WEBPANEL if (machine_is_huw_webpanel()) { *parts = huw_webpanel_partitions; -- cgit v1.2.3 From f29dc87230a91de8e970f38b5ef091112f3425b5 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 1 Feb 2003 16:33:05 +0000 Subject: [ARM PATCH] 1097/3: trizeps IDE support Patch from Guennadi Liakhovetski The enclosed patch includes trizeps-specific IDE code. It adds a Trizeps-specific section to asm/arch/ide.h. The patch is built against 2.5.44-rmk1. --- include/asm-arm/arch-sa1100/ide.h | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/include/asm-arm/arch-sa1100/ide.h b/include/asm-arm/arch-sa1100/ide.h index a5f392d1dd8d..9c8e1c7644aa 100644 --- a/include/asm-arm/arch-sa1100/ide.h +++ b/include/asm-arm/arch-sa1100/ide.h @@ -49,8 +49,9 @@ ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq) *irq = 0; } - - +#ifdef CONFIG_SA1100_TRIZEPS +#include +#endif /* * This registers the standard ports for this architecture with the IDE @@ -124,6 +125,23 @@ ide_init_default_hwifs(void) ide_register_hw(&hw); #endif } -} + else if( machine_is_trizeps() ){ +#ifdef CONFIG_SA1100_TRIZEPS + hw_regs_t hw; + /* Enable appropriate GPIOs as interrupt lines */ + GPDR &= ~GPIO_GPIO(TRIZEPS_IRQ_IDE); + set_irq_type( TRIZEPS_IRQ_IDE, IRQT_RISING ); + /* set the pcmcia interface timing */ + //MECR = 0x00060006; // Done on trizeps init + + /* Take hard drives out of reset */ + GPSR = GPIO_GPIO(TRIZEPS_IRQ_IDE); + + ide_init_hwif_ports(&hw, TRIZEPS_IDE_CS0 + 0, TRIZEPS_IDE_CS1 + 6, NULL); + hw.irq = TRIZEPS_IRQ_IDE; + ide_register_hw(&hw, NULL); +#endif + } +} -- cgit v1.2.3 From 0f19a614e994561e30052277b58049e622546c91 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 1 Feb 2003 16:41:52 +0000 Subject: [ARM PATCH] 1096/4: trizeps PCMCIA support Patch from Guennadi Liakhovetski A minor update, trizeps.h has to be included explicitely now, since platform-specific headers are commented out in hardware.h --- drivers/pcmcia/sa1100_trizeps.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/pcmcia/sa1100_trizeps.c b/drivers/pcmcia/sa1100_trizeps.c index 07660b5e77af..8c308cccdaea 100644 --- a/drivers/pcmcia/sa1100_trizeps.c +++ b/drivers/pcmcia/sa1100_trizeps.c @@ -13,7 +13,8 @@ #include #include -#include // included trizeps.h +#include +#include #include #include #include @@ -54,7 +55,7 @@ static int trizeps_pcmcia_init(struct pcmcia_init *init) return NUMBER_OF_TRIZEPS_PCMCIA_SLOTS; irq_err: - printk( KERN_ERR __FUNCTION__ ": PCMCIA Request for IRQ %u failed\n", TRIZEPS_IRQ_PCMCIA_CD0 ); + printk( KERN_ERR "%s(): PCMCIA Request for IRQ %u failed\n", __FUNCTION__, TRIZEPS_IRQ_PCMCIA_CD0 ); return -1; } -- cgit v1.2.3 From 2e8c54e8dc1e7166f8e6a4dffc8e035a42a92d96 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 1 Feb 2003 16:59:33 +0000 Subject: [ARM PATCH] 1091/3: support for trizeps board (SA1110-based) Patch from Guennadi Liakhovetski The enclosed patch includes support for the trizeps board, based on the StrongARM-1110 CPU, machine number 74. The patch is built against 2.5.44-rmk1. Only the core files - from arch/arm and include/asm-arm directories. --- arch/arm/def-configs/trizeps | 852 ++++++++++++++++++++++++++++++++++ arch/arm/mach-sa1100/Kconfig | 12 + arch/arm/mach-sa1100/Makefile | 3 + arch/arm/mach-sa1100/trizeps.c | 232 +++++++++ include/asm-arm/arch-sa1100/mftb2.h | 210 +++++++++ include/asm-arm/arch-sa1100/trizeps.h | 20 + 6 files changed, 1329 insertions(+) create mode 100644 arch/arm/def-configs/trizeps create mode 100644 arch/arm/mach-sa1100/trizeps.c create mode 100644 include/asm-arm/arch-sa1100/mftb2.h create mode 100644 include/asm-arm/arch-sa1100/trizeps.h diff --git a/arch/arm/def-configs/trizeps b/arch/arm/def-configs/trizeps new file mode 100644 index 000000000000..ce1a1fc9d108 --- /dev/null +++ b/arch/arm/def-configs/trizeps @@ -0,0 +1,852 @@ +# +# Automatically generated by make menuconfig: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# General setup +# +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# System Type +# +# CONFIG_ARCH_ADIFCC is not set +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_CAMELOT is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_IOP310 is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_RPC is not set +CONFIG_ARCH_SA1100=y +# CONFIG_ARCH_SHARK is not set + +# +# Archimedes/A5000 Implementations +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_AUTCPU12 is not set +# CONFIG_ARCH_CDB89712 is not set +# CONFIG_ARCH_CEIVA is not set +# CONFIG_ARCH_CLEP7312 is not set +# CONFIG_ARCH_EDB7211 is not set +# CONFIG_ARCH_P720T is not set +# CONFIG_ARCH_FORTUNET is not set +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set + +# +# Epxa10db +# + +# +# Footbridge Implementations +# +# CONFIG_ARCH_CATS is not set +# CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_EBSA285_ADDIN is not set +# CONFIG_ARCH_EBSA285_HOST is not set +# CONFIG_ARCH_NETWINDER is not set + +# +# IOP310 Implementation Options +# +# CONFIG_ARCH_IQ80310 is not set +# CONFIG_IOP310_AAU is not set +# CONFIG_IOP310_DMA is not set +# CONFIG_IOP310_MU is not set +# CONFIG_IOP310_PMON is not set + +# +# Intel PXA250/210 Implementations +# +# CONFIG_ARCH_LUBBOCK is not set +# CONFIG_ARCH_PXA_IDP is not set + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ASSABET is not set +# CONFIG_ASSABET_NEPONSET is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3100 is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_H3800 is not set +# CONFIG_SA1100_H3XXX is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_BADGE4 is not set +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HUW_WEBPANEL is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_OMNIMETER is not set +# CONFIG_SA1100_PANGOLIN is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_PT_SYSTEM3 is not set +# CONFIG_SA1100_SHANNON is not set +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set +CONFIG_SA1100_TRIZEPS=y +CONFIG_TRIZEPS_MFTB2=y +# CONFIG_SA1100_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +# CONFIG_SA1100_STORK is not set +# CONFIG_SA1100_USB is not set +# CONFIG_SA1100_USB_NETLINK is not set +# CONFIG_SA1100_USB_CHAR is not set +# CONFIG_H3600_SLEEVE is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set +# CONFIG_SA1111 is not set +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +# CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM922T is not set +# CONFIG_CPU_ARM926T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_SA110 is not set +CONFIG_CPU_SA1100=y +# CONFIG_CPU_XSCALE is not set +# CONFIG_CPU_32v3 is not set +CONFIG_CPU_32v4=y +# CONFIG_CPU_32v5 is not set +# CONFIG_ARM_THUMB is not set + +# +# General setup +# +CONFIG_DISCONTIGMEM=y +# CONFIG_PCI is not set +CONFIG_ISA=y +# CONFIG_ISA_DMA is not set +# CONFIG_FIQ is not set +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +# CONFIG_CPU_FREQ is not set +# CONFIG_CPU_FREQ_24_API is not set +# CONFIG_CPU_FREQ_26_API is not set +CONFIG_HOTPLUG=y + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=m +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set +# CONFIG_TCIC is not set +# CONFIG_PCMCIA_CLPS6700 is not set +CONFIG_PCMCIA_SA1100=m +# CONFIG_PCMCIA_SA1111 is not set +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_FASTFPE is not set +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +# CONFIG_PREEMPT is not set +# CONFIG_APM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="keepinitrd mem=16M root=/dev/hda2 1" +# CONFIG_LEDS is not set +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=m +CONFIG_MTD_CONCAT=m +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_CMDLINE_PARTS is not set +CONFIG_MTD_AFS_PARTS=m +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set +# CONFIG_MTD_AMDSTD is not set +# CONFIG_MTD_SHARP is not set +# CONFIG_MTD_JEDEC is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_CDB89712 is not set +CONFIG_MTD_SA1100=m +# CONFIG_MTD_2PARTS_IPAQ is not set +# CONFIG_MTD_DC21285 is not set +# CONFIG_MTD_IQ80310 is not set +# CONFIG_MTD_EPXA10DB is not set +# CONFIG_MTD_FORTUNET is not set +# CONFIG_MTD_AUTCPU12 is not set +# CONFIG_MTD_EDB7312 is not set +# CONFIG_MTD_IMPA7 is not set +# CONFIG_MTD_CEIVA is not set +# CONFIG_MTD_PCI is not set +# CONFIG_MTD_PCMCIA is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_PNP_NAMES is not set +# CONFIG_PNP_DEBUG is not set +# CONFIG_ISAPNP is not set +# CONFIG_PNPBIOS is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +CONFIG_IPV6_SCTP__=y +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_LLC is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +# CONFIG_NET_ETHERNET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_E1000_NAPI is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +CONFIG_PPP=m +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_ASYNC=m +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +# CONFIG_PPPOE is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y +# CONFIG_STRIP is not set +# CONFIG_ARLAN is not set +# CONFIG_AIRONET4500 is not set +# CONFIG_AIRONET4500_NONCS is not set +# CONFIG_AIRONET4500_PROC is not set +# CONFIG_WAVELAN is not set +# CONFIG_AIRO is not set +# CONFIG_HERMES is not set +# CONFIG_PCMCIA_NETWAVE is not set +# CONFIG_PCMCIA_WAVELAN is not set +# CONFIG_PCMCIA_HERMES is not set +CONFIG_AIRO_CS=m +CONFIG_NET_WIRELESS=y + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_FMVJ18X is not set +# CONFIG_PCMCIA_PCNET is not set +# CONFIG_PCMCIA_NMCLAN is not set +# CONFIG_PCMCIA_SMC91C92 is not set +# CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_PCMCIA_AXNET is not set +# CONFIG_ARCNET_COM20020_CS is not set +# CONFIG_PCMCIA_IBMTR is not set +CONFIG_NET_PCMCIA_RADIO=y +# CONFIG_PCMCIA_RAYCS is not set +# CONFIG_AIRONET4500_CS is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEDISK_STROKE is not set +CONFIG_BLK_DEV_IDECS=m +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_BLK_DEV_IDE_ICSIDE is not set +# CONFIG_BLK_DEV_IDEDMA_ICS is not set +# CONFIG_IDEDMA_ICS_AUTO is not set +# CONFIG_BLK_DEV_IDEDMA is not set +# CONFIG_BLK_DEV_IDE_RAPIDE is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +CONFIG_BLK_DEV_IDE_MODES=y + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN_BOOL is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_TSLIBDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +# CONFIG_GAMEPORT_NS558 is not set +# CONFIG_GAMEPORT_L4 is not set +# CONFIG_GAMEPORT_EMU10K1 is not set +# CONFIG_GAMEPORT_VORTEX is not set +# CONFIG_GAMEPORT_FM801 is not set +# CONFIG_GAMEPORT_CS461x is not set +# CONFIG_SERIO is not set +# CONFIG_SERIO_I8042 is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PARKBD is not set +# CONFIG_SERIO_RPCKBD is not set +# CONFIG_SERIO_AMBAKMI is not set +# CONFIG_SERIO_SA1111 is not set +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_MOUSE_PS2 is not set +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_INPORT is not set +# CONFIG_MOUSE_LOGIBM is not set +# CONFIG_MOUSE_PC110PAD is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_JOYSTICK_ANALOG is not set +# CONFIG_JOYSTICK_A3D is not set +# CONFIG_JOYSTICK_ADI is not set +# CONFIG_JOYSTICK_COBRA is not set +# CONFIG_JOYSTICK_GF2K is not set +# CONFIG_JOYSTICK_GRIP is not set +# CONFIG_JOYSTICK_GRIP_MP is not set +# CONFIG_JOYSTICK_GUILLEMOT is not set +# CONFIG_JOYSTICK_INTERACT is not set +# CONFIG_JOYSTICK_SIDEWINDER is not set +# CONFIG_JOYSTICK_TMDC is not set +# CONFIG_JOYSTICK_IFORCE is not set +# CONFIG_JOYSTICK_WARRIOR is not set +# CONFIG_JOYSTICK_MAGELLAN is not set +# CONFIG_JOYSTICK_SPACEORB is not set +# CONFIG_JOYSTICK_SPACEBALL is not set +# CONFIG_JOYSTICK_STINGER is not set +# CONFIG_JOYSTICK_TWIDDLER is not set +# CONFIG_JOYSTICK_DB9 is not set +# CONFIG_JOYSTICK_GAMECON is not set +# CONFIG_JOYSTICK_TURBOGRAFX is not set +# CONFIG_INPUT_JOYDUMP is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_INPUT_MISC is not set +# CONFIG_INPUT_PCSPKR is not set +# CONFIG_INPUT_UINPUT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_SERIAL_8250_CS is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_RSA is not set +# CONFIG_SERIAL_ACORN is not set +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_CONSOLE is not set +# CONFIG_SERIAL_CLPS711X is not set +# CONFIG_SERIAL_CLPS711X_CONSOLE is not set +# CONFIG_SERIAL_CLPS711X_OLD_NAME is not set +# CONFIG_SERIAL_21285 is not set +# CONFIG_SERIAL_21285_OLD is not set +# CONFIG_SERIAL_21285_CONSOLE is not set +# CONFIG_SERIAL_UART00 is not set +# CONFIG_SERIAL_UART00_CONSOLE is not set +CONFIG_SERIAL_SA1100=y +CONFIG_SERIAL_SA1100_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_UNIX98_PTYS is not set + +# +# I2C support +# +CONFIG_I2C=m +CONFIG_I2C_ALGOBIT=m +# CONFIG_I2C_PHILIPSPAR is not set +# CONFIG_I2C_ELV is not set +# CONFIG_I2C_VELLEMAN is not set +# CONFIG_SCx200_I2C is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_I2C_BIT_SA1100_GPIO is not set +# CONFIG_I2C_ALGOPCF is not set +CONFIG_I2C_CHARDEV=m +CONFIG_I2C_PROC=m + +# +# L3 serial bus support +# +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set +# CONFIG_BIT_SA1100_GPIO is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_SA1100_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +# CONFIG_SYNCLINK_CS is not set +# CONFIG_SCx200_GPIO is not set +# CONFIG_RAW_DRIVER is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_QFMT_V1 is not set +# CONFIG_QFMT_V2 is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +CONFIG_RAMFS=y +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_JFS_FS is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +# CONFIG_XFS_FS is not set +# CONFIG_XFS_RT is not set +# CONFIG_XFS_QUOTA is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_V4 is not set +# CONFIG_ROOT_NFS is not set +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +# CONFIG_NFSD_V4 is not set +# CONFIG_NFSD_TCP is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_EXPORTFS is not set +# CONFIG_CIFS is not set +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_AFS_FS is not set +# CONFIG_ZISOFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set +# CONFIG_MCP_SA1100 is not set +# CONFIG_MCP_UCB1200 is not set +# CONFIG_MCP_UCB1200_AUDIO is not set +# CONFIG_MCP_UCB1200_TS is not set + +# +# Console Switches +# +# CONFIG_SWITCHES is not set +# CONFIG_SWITCHES_SA1100 is not set +# CONFIG_SWITCHES_UCB1X00 is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BT is not set + +# +# Kernel hacking +# +# CONFIG_NO_FRAME_POINTER is not set +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_INFO is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_ERRORS=y +# CONFIG_DEBUG_LL is not set +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set + +# +# Security options +# +CONFIG_SECURITY_CAPABILITIES=y + +# +# Library routines +# +# CONFIG_CRC32 is not set +CONFIG_ZLIB_INFLATE=m +CONFIG_ZLIB_DEFLATE=m diff --git a/arch/arm/mach-sa1100/Kconfig b/arch/arm/mach-sa1100/Kconfig index 3ce853d36c0d..ca8c7d80423c 100644 --- a/arch/arm/mach-sa1100/Kconfig +++ b/arch/arm/mach-sa1100/Kconfig @@ -314,6 +314,18 @@ config SA1100_STORK Say Y here if you intend to run this kernel on the Stork handheld computer. +#config SA1100_TRIZEPS +# bool "Trizeps" +# depends on ARCH_SA1100 +# help +# :: write me :: + +#config TRIZEPS_MFTB2 +# bool "MFTB2" +# depends on SA1100_TRIZEPS +# help +# :: write me :: + config SA1100_USB tristate "SA1100 USB function support" depends on ARCH_SA1100 diff --git a/arch/arm/mach-sa1100/Makefile b/arch/arm/mach-sa1100/Makefile index c3a2adedeeeb..1426ab7ab335 100644 --- a/arch/arm/mach-sa1100/Makefile +++ b/arch/arm/mach-sa1100/Makefile @@ -98,6 +98,9 @@ led-$(CONFIG_SA1100_SIMPAD) += leds-simpad.o obj-$(CONFIG_SA1100_STORK) += stork.o export-objs += stork.o +obj-$(CONFIG_SA1100_TRIZEPS) += trizeps.o +export-objs += trizeps.o + obj-$(CONFIG_SA1100_XP860) += xp860.o obj-$(CONFIG_SA1100_YOPY) += yopy.o diff --git a/arch/arm/mach-sa1100/trizeps.c b/arch/arm/mach-sa1100/trizeps.c new file mode 100644 index 000000000000..5546ed1e5d21 --- /dev/null +++ b/arch/arm/mach-sa1100/trizeps.c @@ -0,0 +1,232 @@ +/* + * linux/arch/arm/mach-sa1100/trizeps.c + * + * Authors: + * Andreas Hofer , + * Peter Lueg , + * Guennadi Liakhovetski + * + * This file contains all Trizeps-specific tweaks. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "generic.h" + +#undef DEBUG_TRIZEPS +#ifdef DEBUG_TRIZEPS +#define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) +#else +#define DPRINTK( x... ) +#endif + +static struct tri_uart_cts_data_t tri_uart_cts_data[] = { + { TRIZEPS_GPIO_UART1_CTS, 0, NULL, NULL,"int. UART1 cts" }, + { TRIZEPS_GPIO_UART2_CTS, 0, NULL, NULL,"int. UART2 cts" }, + { TRIZEPS_GPIO_UART3_CTS, 0, NULL, NULL,"int. UART3 cts" } +}; + +static void trizeps_cts_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct tri_uart_cts_data_t * uart_data = (struct tri_uart_cts_data_t *)dev_id; + int cts = (!(GPLR & uart_data->cts_gpio)); + + /* NOTE: I suppose that we will not get any interrupts + if the GPIO is not changed, so maybe + the cts_prev_state can be removed ... */ + if (cts != uart_data->cts_prev_state) { + + uart_data->cts_prev_state = cts; + uart_handle_cts_change(uart_data->port, cts); + DPRINTK("(IRQ %d) changed (cts=%d) stop=%d\n", + irq, cts, uart_data->info->tty->hw_stopped); + } +} + +static int +trizeps_register_cts_intr(int gpio, + int irq, + struct tri_uart_cts_data_t *uart_data) +{ + int ret = 0; + + if(irq != NO_IRQ) + { + set_irq_type(irq, IRQT_BOTHEDGE); + + ret = request_irq(irq, trizeps_cts_intr, + SA_INTERRUPT, uart_data->name, uart_data); + if (ret) + printk(KERN_ERR "uart_open: failed to register CTS irq (%d)\n", ret); + } + return ret; +} + +static void trizeps_set_mctrl(struct uart_port *port, u_int mctrl) +{ + if (port->mapbase == _Ser1UTCR0) + { + /**** ttySA1 ****/ + if (mctrl & TIOCM_RTS) + GPCR |= TRIZEPS_GPIO_UART1_RTS; + else + GPSR |= TRIZEPS_GPIO_UART1_RTS; + + DPRINTK("2 ttySA%d Set RTS %s\n",port->line, + mctrl & TIOCM_RTS ? "low" : "high"); + + } + else if (port->mapbase == _Ser3UTCR0) + { + /**** ttySA0 ****/ + } + else + { + /**** ttySA2 ****/ + } +} + +static u_int trizeps_get_mctrl(struct uart_port *port) +{ + int result = TIOCM_CD | TIOCM_DSR; + + if (port->mapbase == _Ser1UTCR0) + { + if (!(GPLR & TRIZEPS_GPIO_UART1_CTS)) + result |= TIOCM_CTS; + } + else if (port->mapbase == _Ser2UTCR0) + { + result |= TIOCM_CTS; + } + else if (port->mapbase == _Ser3UTCR0) + { + result |= TIOCM_CTS; + } + else + { + result = TIOCM_CTS; + } + + DPRINTK(" ttySA%d %s%s%s\n",port->line, + result & TIOCM_CD ? "CD " : "", + result & TIOCM_CTS ? "CTS " : "", + result & TIOCM_DSR ? "DSR " : ""); + + return result; +} + +static struct sa1100_port_fns trizeps_port_fns __initdata = { + .set_mctrl = trizeps_set_mctrl, + .get_mctrl = trizeps_get_mctrl, +}; + +static void trizeps_power_off(void) +{ + printk("trizeps power off\n"); + mdelay(100); + cli(); + /* disable internal oscillator, float CS lines */ + PCFR = (PCFR_OPDE | PCFR_FP | PCFR_FS); + /* enable wake-up on GPIO0 (Assabet...) */ + PWER = GFER = GRER = 1; + /* + * set scratchpad to zero, just in case it is used as a + * restart address by the bootloader. + */ + PSPR = 0; + + /* + * Power off + * -> disconnect AKku + */ + TRIZEPS_BCR_set(TRIZEPS_BCR0, TRIZEPS_MFT_OFF); + + /* + * if power supply no Akku + * -> enter sleep mode + */ + PMCR = PMCR_SF; +} + +static int __init trizeps_init(void) +{ + if (!machine_is_trizeps()) + return -EINVAL; + + DPRINTK(" \n"); + pm_power_off = trizeps_power_off; + + // Init UART2 for IrDA +// PPDR |= PPC_TXD2; // Set TXD2 as output + Ser2UTCR4 = UTCR4_HSE; // enable HSE + Ser2HSCR0 = 0; + Ser2HSSR0 = HSSR0_EIF | HSSR0_TUR | HSSR0_RAB | HSSR0_FRE; + + /* Init MECR */ + MECR = 0x00060006; + + /* Set up external serial IRQs */ + GAFR &= ~(GPIO_GPIO16 | GPIO_GPIO17); // no alternate function + GPDR &= ~(GPIO_GPIO16 | GPIO_GPIO17); // Set to Input + set_irq_type(IRQ_GPIO16, IRQT_RISING); + set_irq_type(IRQ_GPIO17, IRQT_RISING); + + return 0; +} + +__initcall(trizeps_init); + +static struct map_desc trizeps_io_desc[] __initdata = { + /* virtual physical length type */ + { 0xF0000000l, 0x30000000l, 0x00800000l, MT_DEVICE }, + { 0xF2000000l, 0x38000000l, 0x00800000l, MT_DEVICE }, +}; + +void __init trizeps_map_io(void) +{ + sa1100_map_io(); + iotable_init(trizeps_io_desc, ARRAY_SIZE(trizeps_io_desc)); + + sa1100_register_uart_fns(&trizeps_port_fns); + sa1100_register_uart(0, 3); + sa1100_register_uart(1, 1); + sa1100_register_uart(2, 2); +} + +MACHINE_START(TRIZEPS, "TRIZEPS") + MAINTAINER("DSA") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + MAPIO(trizeps_map_io) + INITIRQ(sa1100_init_irq) +MACHINE_END diff --git a/include/asm-arm/arch-sa1100/mftb2.h b/include/asm-arm/arch-sa1100/mftb2.h new file mode 100644 index 000000000000..1d4c9f7dcdf0 --- /dev/null +++ b/include/asm-arm/arch-sa1100/mftb2.h @@ -0,0 +1,210 @@ +#ifndef _ARCH_ARM_MFTB2_h_ +#define _ARCH_ARM_MFTB2_h_ + +// Defines for arch/arm/mm/mm-sa1100.h +#define TRIZEPS_PHYS_VIRT_MAP_SIZE 0x00800000l + +// physical address (only for mm-sa1100.h) +#define TRIZEPS_PHYS_IO_BASE 0x30000000l +#define TRIZEPS_PHYS_MEM_BASE 0x38000000l + +// virtual +#define TRIZEPS_IO_BASE 0xF0000000l +#define TRIZEPS_MEM_BASE 0xF2000000l + +// Offsets for phys and virtual +#define TRIZEPS_OFFSET_REG0 0x00300000l +#define TRIZEPS_OFFSET_REG1 0x00380000l +#define TRIZEPS_OFFSET_IDE_CS0 0x00000000l +#define TRIZEPS_OFFSET_IDE_CS1 0x00080000l +#define TRIZEPS_OFFSET_UART5 0x00100000l +#define TRIZEPS_OFFSET_UART6 0x00180000l +#define TRIZEPS_PHYS_REG0 (TRIZEPS_PHYS_IO_BASE + TRIZEPS_OFFSET_REG0) +#define TRIZEPS_PHYS_REG1 (TRIZEPS_PHYS_IO_BASE + TRIZEPS_OFFSET_REG1) +#define TRIZEPS_PHYS_IDE_CS0 (TRIZEPS_PHYS_IO_BASE + TRIZEPS_OFFSET_IDE_CS0) +#define TRIZEPS_PHYS_IDE_CS1 (TRIZEPS_PHYS_IO_BASE + TRIZEPS_OFFSET_IDE_CS1) +#define TRIZEPS_PHYS_UART5 (TRIZEPS_PHYS_IO_BASE + TRIZEPS_OFFSET_UART5) +#define TRIZEPS_PHYS_UART6 (TRIZEPS_PHYS_IO_BASE + TRIZEPS_OFFSET_UART6) + +// Use follow defines in devices +// virtual address +#define TRIZEPS_REG0 (TRIZEPS_IO_BASE + TRIZEPS_OFFSET_REG0) +#define TRIZEPS_REG1 (TRIZEPS_IO_BASE + TRIZEPS_OFFSET_REG1) +#define TRIZEPS_IDE_CS0 (TRIZEPS_IO_BASE + TRIZEPS_OFFSET_IDE_CS0) +#define TRIZEPS_IDE_CS1 (TRIZEPS_IO_BASE + TRIZEPS_OFFSET_IDE_CS1) +#define TRIZEPS_UART5 (TRIZEPS_IO_BASE + TRIZEPS_OFFSET_UART5) +#define TRIZEPS_UART6 (TRIZEPS_IO_BASE + TRIZEPS_OFFSET_UART6) + +#define TRIZEPS_BAUD_BASE 1500000 + +//#if 0 //temporarily disabled +#ifndef __ASSEMBLY__ +struct tri_uart_cts_data_t { + int cts_gpio; + int cts_prev_state; + struct uart_info *info; + struct uart_port *port; + const char *name; +}; +#endif /* __ASSEMBLY__ */ + +/* Defines for MFTB2 serial_sa1100.c hardware handshaking lines */ +#define SERIAL_FULL +#define NOT_CONNECTED 0 +#ifdef SERIAL_FULL +#define TRIZEPS_GPIO_UART1_RTS GPIO_GPIO14 +#define TRIZEPS_GPIO_UART1_DTR NOT_CONNECTED //GPIO_GPIO9 +#define TRIZEPS_GPIO_UART1_CTS GPIO_GPIO15 +#define TRIZEPS_GPIO_UART1_DCD NOT_CONNECTED //GPIO_GPIO2 +#define TRIZEPS_GPIO_UART1_DSR NOT_CONNECTED //GPIO_GPIO3 +#define TRIZEPS_GPIO_UART3_RTS NOT_CONNECTED //GPIO_GPIO7 +#define TRIZEPS_GPIO_UART3_DTR NOT_CONNECTED //GPIO_GPIO8 +#define TRIZEPS_GPIO_UART3_CTS NOT_CONNECTED //GPIO_GPIO4 +#define TRIZEPS_GPIO_UART3_DCD NOT_CONNECTED //GPIO_GPIO5 +#define TRIZEPS_GPIO_UART3_DSR NOT_CONNECTED //GPIO_GPIO6 + +#define TRIZEPS_GPIO_UART2_RTS NOT_CONNECTED //GPIO_GPIO7 +#define TRIZEPS_GPIO_UART2_DTR NOT_CONNECTED //GPIO_GPIO8 +#define TRIZEPS_GPIO_UART2_CTS NOT_CONNECTED //GPIO_GPIO4 +#define TRIZEPS_GPIO_UART2_DCD NOT_CONNECTED //GPIO_GPIO5 +#define TRIZEPS_GPIO_UART2_DSR NOT_CONNECTED //GPIO_GPIO6 + +#define TRIZEPS_IRQ_UART1_CTS IRQ_GPIO15 +#define TRIZEPS_IRQ_UART1_DCD NO_IRQ //IRQ_GPIO2 +#define TRIZEPS_IRQ_UART1_DSR NO_IRQ //IRQ_GPIO3 +#define TRIZEPS_IRQ_UART3_CTS NO_IRQ //IRQ_GPIO4 +#define TRIZEPS_IRQ_UART3_DCD NO_IRQ //IRQ_GPIO5 +#define TRIZEPS_IRQ_UART3_DSR NO_IRQ //IRQ_GPIO6 + +#define TRIZEPS_IRQ_UART2_CTS NO_IRQ //IRQ_GPIO4 +#define TRIZEPS_IRQ_UART2_DCD NO_IRQ //IRQ_GPIO5 +#define TRIZEPS_IRQ_UART2_DSR NO_IRQ //IRQ_GPIO6 + +#endif /* SERIAL_FULL */ +//#endif //0 + +/* + * This section contains the defines for the MFTB2 implementation + * of drivers/ide/hd.c. HD_IOBASE_0 and HD_IOBASE_1 have to be + * adjusted if hardware changes. + */ +#define TRIZEPS_IRQ_IDE 10 /* MFTB2 specific */ + +/*--- ROOT ---*/ +#define TRIZEPS_GPIO_ROOT_NFS 0 +#define TRIZEPS_GPIO_ROOT_HD 21 +/*--- PCMCIA ---*/ +#define TRIZEPS_GPIO_PCMCIA_IRQ0 1 +#define TRIZEPS_GPIO_PCMCIA_CD0 24 +#define TRIZEPS_IRQ_PCMCIA_IRQ0 TRIZEPS_GPIO_PCMCIA_IRQ0 +#define TRIZEPS_IRQ_PCMCIA_CD0 TRIZEPS_GPIO_PCMCIA_CD0 + 32 - 11 + +// REGISTER 0 -> 0x0XXXX (16bit access) +// read only +#define TRIZEPS_A_STAT 0x8000l +#define TRIZEPS_F_STAT 0x4000l +#define TRIZEPS_BATT_FAULT_EN 0x2000l +#define TRIZEPS_nDQ 0x1000l +#define TRIZEPS_MFT_OFF 0x0800l +#define TRIZEPS_D_APWOFF 0x0400l +#define TRIZEPS_F_CTRL 0x0200l +#define TRIZEPS_F_STOP 0x0100l + +// read / write +#define TRIZEPS_KP_IR_EN 0x0080l +#define TRIZEPS_FIR 0x0040l +#define TRIZEPS_BAR_ON 0x0020l +#define TRIZEPS_VCI_ON 0x0010l +#define TRIZEPS_LED4 0x0008l +#define TRIZEPS_LED3 0x0004l +#define TRIZEPS_LED2 0x0002l +#define TRIZEPS_LED1 0x0001l + +// REGISTER 1 -> 0x1XXXX (16bit access) +// read only +#define TRIZEPS_nVCI2 0x8000l +#define TRIZEPS_nAB_LOW 0x4000l +#define TRIZEPS_nMB_DEAD 0x2000l +#define TRIZEPS_nMB_LOW 0x1000l +#define TRIZEPS_nPCM_VS2 0x0800l +#define TRIZEPS_nPCM_VS1 0x0400l +#define TRIZEPS_PCM_BVD2 0x0200l +#define TRIZEPS_PCM_BVD1 0x0100l + +// read / write +#define TRIZEPS_nROOT_NFS 0x0080l +#define TRIZEPS_nROOT_HD 0x0040l +#define TRIZEPS_nPCM_ENA_REG 0x0020l +#define TRIZEPS_nPCM_RESET_DISABLE 0x0010l +#define TRIZEPS_PCM_EN0_REG 0x0008l +#define TRIZEPS_PCM_EN1_REG 0x0004l +#define TRIZEPS_PCM_V3_EN_REG 0x0002l +#define TRIZEPS_PCM_V5_EN_REG 0x0001l + +/* Access to Board Control Register */ +#define TRIZEPS_BCR0 (*(volatile unsigned short *)(TRIZEPS_REG0)) +#define TRIZEPS_BCR1 (*(volatile unsigned short *)(TRIZEPS_REG1)) + +#define TRIZEPS_BCR_set( reg, x ) do { \ + unsigned long flags; \ + local_irq_save(flags); \ + (reg) |= (x); \ + local_irq_restore(flags); \ +} while (0) + +#define TRIZEPS_BCR_clear( reg, x ) do { \ + unsigned long flags; \ + local_irq_save(flags); \ + (reg) &= ~(x); \ + local_irq_restore(flags); \ +} while (0) + +#define TRIZEPS_OFFSET_KP_REG 0x00200000l +#define TRIZEPS_OFFSET_VCI2 0x00280000l +#define TRIZEPS_OFFSET_VCI4 0x00400000l + +#define TRIZEPS_OFFSET_VCI2_1_DPR (TRIZEPS_OFFSET_VCI2 + 0x00010000l) +#define TRIZEPS_OFFSET_VCI2_2_DPR (TRIZEPS_OFFSET_VCI2 + 0x00018000l) +#define TRIZEPS_OFFSET_VCI2_1_SEMA (TRIZEPS_OFFSET_VCI2 + 0x00020000l) +#define TRIZEPS_OFFSET_VCI2_2_SEMA (TRIZEPS_OFFSET_VCI2 + 0x00028000l) + +#define TRIZEPS_OFFSET_VCI4_1_DPR (TRIZEPS_OFFSET_VCI4 + 0x00000000l) +#define TRIZEPS_OFFSET_VCI4_2_DPR (TRIZEPS_OFFSET_VCI4 + 0x00008000l) +#define TRIZEPS_OFFSET_VCI4_1_SEMA (TRIZEPS_OFFSET_VCI4 + 0x00000380l) +#define TRIZEPS_OFFSET_VCI4_2_SEMA (TRIZEPS_OFFSET_VCI4 + 0x00000388l) +#define TRIZEPS_OFFSET_VCI4_1_CNTR (TRIZEPS_OFFSET_VCI4 + 0x00000390l) +#define TRIZEPS_OFFSET_VCI4_2_CNTR (TRIZEPS_OFFSET_VCI4 + 0x00000392l) + +#define TRIZEPS_PHYS_KP_REG (PHYS_TRIZEPS_IO_BASE + TRIZEPS_OFFSET_KP_REG) + +// VCI address +#define TRIZEPS_PHYS_VCI2_1_DPR (TRIZEPS_PHYS_MEM_BASE + TRIZEPS_OFFSET_VCI2_1_DPR) +#define TRIZEPS_PHYS_VCI2_2_DPR (TRIZEPS_PHYS_MEM_BASE + TRIZEPS_OFFSET_VCI2_2_DPR) +#define TRIZEPS_PHYS_VCI2_1_SEMA (TRIZEPS_PHYS_MEM_BASE + TRIZEPS_OFFSET_VCI2_1_SEMA) +#define TRIZEPS_PHYS_VCI2_2_SEMA (TRIZEPS_PHYS_MEM_BASE + TRIZEPS_OFFSET_VCI2_2_SEMA) + +// VCI4 address +#define TRIZEPS_PHYS_VCI4_1_DPR (TRIZEPS_PHYS_MEM_BASE + TRIZEPS_OFFSET_VCI4_1_DPR) +#define TRIZEPS_PHYS_VCI4_2_DPR (TRIZEPS_PHYS_MEM_BASE + TRIZEPS_OFFSET_VCI4_2_DPR) +#define TRIZEPS_PHYS_VCI4_1_SEMA (TRIZEPS_PHYS_IO_BASE + TRIZEPS_OFFSET_VCI4_1_SEMA) +#define TRIZEPS_PHYS_VCI4_2_SEMA (TRIZEPS_PHYS_IO_BASE + TRIZEPS_OFFSET_VCI4_2_SEMA) +#define TRIZEPS_PHYS_VCI4_1_CNTR (TRIZEPS_PHYS_IO_BASE + TRIZEPS_OFFSET_VCI4_1_CNTR) +#define TRIZEPS_PHYS_VCI4_2_CNTR (TRIZEPS_PHYS_IO_BASE + TRIZEPS_OFFSET_VCI4_2_CNTR) + +#define TRIZEPS_KP_REG (TRIZEPS_IO_BASE + TRIZEPS_OFFSET_KP_REG) + +// VCI address +#define TRIZEPS_VCI2_1_DPR (TRIZEPS_MEM_BASE + TRIZEPS_OFFSET_VCI2_1_DPR) +#define TRIZEPS_VCI2_2_DPR (TRIZEPS_MEM_BASE + TRIZEPS_OFFSET_VCI2_2_DPR) +#define TRIZEPS_VCI2_1_SEMA (TRIZEPS_MEM_BASE + TRIZEPS_OFFSET_VCI2_1_SEMA) +#define TRIZEPS_VCI2_2_SEMA (TRIZEPS_MEM_BASE + TRIZEPS_OFFSET_VCI2_2_SEMA) + +// VCI4 address +#define TRIZEPS_VCI4_1_DPR (TRIZEPS_MEM_BASE + TRIZEPS_OFFSET_VCI4_1_DPR) +#define TRIZEPS_VCI4_2_DPR (TRIZEPS_MEM_BASE + TRIZEPS_OFFSET_VCI4_2_DPR) +#define TRIZEPS_VCI4_1_SEMA (TRIZEPS_IO_BASE + TRIZEPS_OFFSET_VCI4_1_SEMA) +#define TRIZEPS_VCI4_2_SEMA (TRIZEPS_IO_BASE + TRIZEPS_OFFSET_VCI4_2_SEMA) +#define TRIZEPS_VCI4_1_CNTR (TRIZEPS_IO_BASE + TRIZEPS_OFFSET_VCI4_1_CNTR) +#define TRIZEPS_VCI4_2_CNTR (TRIZEPS_IO_BASE + TRIZEPS_OFFSET_VCI4_2_CNTR) + +#endif diff --git a/include/asm-arm/arch-sa1100/trizeps.h b/include/asm-arm/arch-sa1100/trizeps.h new file mode 100644 index 000000000000..b9cc02bac5d9 --- /dev/null +++ b/include/asm-arm/arch-sa1100/trizeps.h @@ -0,0 +1,20 @@ +/* + * linux/include/asm-arm/arch-sa1100/trizeps.h + * + * This file contains the hardware specific definitions for Trizeps + * + * Authors: + * Andreas Hofer , + * Peter Lueg , + * Guennadi Liakhovetski + * + */ + +#ifndef _ASM_ARCH_TRIZEPS_H_ +#define _ASM_ARCH_TRIZEPS_H_ + +#ifdef CONFIG_TRIZEPS_MFTB2 +#include "mftb2.h" +#endif + +#endif // _INCLUDE_TRIZEPS_ -- cgit v1.2.3 From 9fdec3b4893bf3e6608612eac9fc5778e82710a4 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 1 Feb 2003 17:04:04 +0000 Subject: [ARM] Make trizeps_map_io static. --- arch/arm/mach-sa1100/trizeps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-sa1100/trizeps.c b/arch/arm/mach-sa1100/trizeps.c index 5546ed1e5d21..a41090012ffe 100644 --- a/arch/arm/mach-sa1100/trizeps.c +++ b/arch/arm/mach-sa1100/trizeps.c @@ -213,7 +213,7 @@ static struct map_desc trizeps_io_desc[] __initdata = { { 0xF2000000l, 0x38000000l, 0x00800000l, MT_DEVICE }, }; -void __init trizeps_map_io(void) +static void __init trizeps_map_io(void) { sa1100_map_io(); iotable_init(trizeps_io_desc, ARRAY_SIZE(trizeps_io_desc)); -- cgit v1.2.3 From 504ebbb16b8d2f44428121afec9ab1b3070b5b89 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 1 Feb 2003 17:10:22 +0000 Subject: [ARM] Ensure GCC uses frame pointers when we want them. ARM GCC 2.95 generates frame pointers by default. GCC 3.2.x seems to require some persuasion to generate them, despite being required for debugging. --- arch/arm/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/Makefile b/arch/arm/Makefile index d153a972b6ef..8ebc5b385b76 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -17,7 +17,7 @@ GZFLAGS :=-9 CFLAGS :=$(CFLAGS:-O2=-Os) ifeq ($(CONFIG_FRAME_POINTER),y) -CFLAGS :=$(CFLAGS:-fomit-frame-pointer=-mapcs -mno-sched-prolog) +CFLAGS +=-fno-omit-frame-pointer -mapcs -mno-sched-prolog endif ifeq ($(CONFIG_DEBUG_INFO),y) @@ -36,7 +36,7 @@ apcs-$(CONFIG_CPU_26) :=-mapcs-26 -mcpu=arm3 # series of macros. arch-$(CONFIG_CPU_32v3) :=-D__LINUX_ARM_ARCH__=3 -march=armv3 arch-$(CONFIG_CPU_32v4) :=-D__LINUX_ARM_ARCH__=4 -march=armv4 -arch-$(CONFIG_CPU_32v5) :=-D__LINUX_ARM_ARCH__=5 -march=armv5 +arch-$(CONFIG_CPU_32v5) :=-D__LINUX_ARM_ARCH__=5 -march=armv5te arch-$(CONFIG_CPU_XSCALE) :=-D__LINUX_ARM_ARCH__=5 -march=armv4 -Wa,-mxscale #-march=armv5te # This selects how we optimise for the processor. -- cgit v1.2.3 From a04d2bdfed842189078523eb59ffd4bba44a62a6 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 1 Feb 2003 17:17:52 +0000 Subject: [ARM] Add missing #endif --- include/asm-arm/bug.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/asm-arm/bug.h b/include/asm-arm/bug.h index c9b6e7f6b317..326400b2b83f 100644 --- a/include/asm-arm/bug.h +++ b/include/asm-arm/bug.h @@ -18,3 +18,4 @@ extern volatile void __bug(const char *file, int line, void *data); #endif +#endif -- cgit v1.2.3 From 78a93c96accee297251f9aed06f3c936c508cdcc Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 1 Feb 2003 17:51:52 +0000 Subject: [ARM] Remove IRQ desc->enabled in favour of testing disable_depth --- arch/arm/kernel/irq.c | 45 ++++++++++++++++++++++----------------------- include/asm-arm/mach/irq.h | 5 ++--- 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index 26d191131390..054be68a77eb 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -78,7 +78,8 @@ static struct irqdesc bad_irq_desc = { * disable_irq - disable an irq and wait for completion * @irq: Interrupt to disable * - * Disable the selected interrupt line. We do this lazily. + * Disable the selected interrupt line. Enables and disables + * are nested. We do this lazily. * * This function may be called from IRQ context. */ @@ -88,8 +89,7 @@ void disable_irq(unsigned int irq) unsigned long flags; spin_lock_irqsave(&irq_controller_lock, flags); - if (!desc->depth++) - desc->enabled = 0; + desc->disable_depth++; spin_unlock_irqrestore(&irq_controller_lock, flags); } @@ -107,24 +107,25 @@ void enable_irq(unsigned int irq) { struct irqdesc *desc = irq_desc + irq; unsigned long flags; - int pending = 0; spin_lock_irqsave(&irq_controller_lock, flags); - if (unlikely(!desc->depth)) { + if (unlikely(!desc->disable_depth)) { printk("enable_irq(%u) unbalanced from %p\n", irq, __builtin_return_address(0)); - } else if (!--desc->depth) { + } else if (!--desc->disable_depth) { desc->probing = 0; - desc->enabled = 1; desc->chip->unmask(irq); - pending = desc->pending; - desc->pending = 0; + /* - * If the interrupt was waiting to be processed, - * retrigger it. + * If the interrupt is waiting to be processed, + * try to re-run it. We can't directly run it + * from here since the caller might be in an + * interrupt-protected region. */ - if (pending) + if (desc->pending) { + desc->pending = 0; desc->chip->rerun(irq); + } } spin_unlock_irqrestore(&irq_controller_lock, flags); } @@ -264,7 +265,7 @@ do_edge_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) * we shouldn't process the IRQ. Instead, turn on the * hardware masks. */ - if (unlikely(desc->running || !desc->enabled)) + if (unlikely(desc->running || desc->disable_depth)) goto running; /* @@ -286,13 +287,13 @@ do_edge_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) if (!action) break; - if (desc->pending && desc->enabled) { + if (desc->pending && !desc->disable_depth) { desc->pending = 0; desc->chip->unmask(irq); } __do_irq(irq, action, regs); - } while (desc->pending && desc->enabled); + } while (desc->pending && !desc->disable_depth); desc->running = 0; @@ -328,7 +329,7 @@ do_level_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) */ desc->chip->ack(irq); - if (likely(desc->enabled)) { + if (likely(!desc->disable_depth)) { kstat_cpu(cpu).irqs[irq]++; /* @@ -338,7 +339,7 @@ do_level_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) if (action) { __do_irq(irq, desc->action, regs); - if (likely(desc->enabled && + if (likely(!desc->disable_depth && !check_irq_lock(desc, irq, regs))) desc->chip->unmask(irq); } @@ -390,14 +391,13 @@ void __set_irq_handler(unsigned int irq, irq_handler_t handle, int is_chained) if (handle == do_bad_IRQ) { desc->chip->mask(irq); desc->chip->ack(irq); - desc->depth = 1; - desc->enabled = 0; + desc->disable_depth = 1; } desc->handle = handle; if (handle != do_bad_IRQ && is_chained) { desc->valid = 0; desc->probe_ok = 0; - desc->depth = 0; + desc->disable_depth = 0; desc->chip->unmask(irq); } spin_unlock_irqrestore(&irq_controller_lock, flags); @@ -512,10 +512,9 @@ int setup_irq(unsigned int irq, struct irqaction *new) desc->probing = 0; desc->running = 0; desc->pending = 0; - desc->depth = 1; + desc->disable_depth = 1; if (!desc->noautoenable) { - desc->depth = 0; - desc->enabled = 1; + desc->disable_depth = 0; desc->chip->unmask(irq); } } diff --git a/include/asm-arm/mach/irq.h b/include/asm-arm/mach/irq.h index 60ce4643c027..5a3007b97324 100644 --- a/include/asm-arm/mach/irq.h +++ b/include/asm-arm/mach/irq.h @@ -50,8 +50,8 @@ struct irqdesc { irq_handler_t handle; struct irqchip *chip; struct irqaction *action; + unsigned int disable_depth; - unsigned int enabled : 1; /* IRQ is currently enabled */ unsigned int triggered: 1; /* IRQ has occurred */ unsigned int running : 1; /* IRQ is running */ unsigned int pending : 1; /* IRQ is pending */ @@ -59,8 +59,7 @@ struct irqdesc { unsigned int probe_ok : 1; /* IRQ can be used for probe */ unsigned int valid : 1; /* IRQ claimable */ unsigned int noautoenable : 1; /* don't automatically enable IRQ */ - unsigned int unused :23; - unsigned int depth; /* disable depth */ + unsigned int unused :25; /* * IRQ lock detection -- cgit v1.2.3 From 1687c697916fdd7bf8745384477312009ed79933 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 2 Feb 2003 23:27:29 +0000 Subject: [ARM] Add arch/arm/common Certain support files are shared between various ARM machine classes. In other to sanely support these, we place the shared files in arch/arm/common instead of the individual machine class directories. --- arch/arm/Makefile | 2 +- arch/arm/common/Makefile | 10 + arch/arm/common/plx90x0.c | 178 ++++++ arch/arm/common/sa1111-pcibuf.c | 551 +++++++++++++++++ arch/arm/common/sa1111-pcipool.c | 390 ++++++++++++ arch/arm/common/sa1111.c | 1107 ++++++++++++++++++++++++++++++++++ arch/arm/common/via82c505.c | 94 +++ arch/arm/kernel/Makefile | 2 - arch/arm/kernel/plx90x0.c | 178 ------ arch/arm/kernel/via82c505.c | 94 --- arch/arm/mach-sa1100/Makefile | 7 +- arch/arm/mach-sa1100/pcipool.c | 390 ------------ arch/arm/mach-sa1100/sa1111-pcibuf.c | 551 ----------------- arch/arm/mach-sa1100/sa1111.c | 1107 ---------------------------------- 14 files changed, 2333 insertions(+), 2328 deletions(-) create mode 100644 arch/arm/common/Makefile create mode 100644 arch/arm/common/plx90x0.c create mode 100644 arch/arm/common/sa1111-pcibuf.c create mode 100644 arch/arm/common/sa1111-pcipool.c create mode 100644 arch/arm/common/sa1111.c create mode 100644 arch/arm/common/via82c505.c delete mode 100644 arch/arm/kernel/plx90x0.c delete mode 100644 arch/arm/kernel/via82c505.c delete mode 100644 arch/arm/mach-sa1100/pcipool.c delete mode 100644 arch/arm/mach-sa1100/sa1111-pcibuf.c delete mode 100644 arch/arm/mach-sa1100/sa1111.c diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 8ebc5b385b76..af2c30238a85 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -124,10 +124,10 @@ FASTFPE_OBJ :=$(FASTFPE)/ endif # If we have a machine-specific directory, then include it in the build. +core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/ ifneq ($(MACHINE),) core-y += arch/arm/mach-$(MACHINE)/ endif -core-y += arch/arm/kernel/ arch/arm/mm/ core-$(CONFIG_FPE_NWFPE) += arch/arm/nwfpe/ core-$(CONFIG_FPE_FASTFPE) += $(FASTFPE_OBJ) diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile new file mode 100644 index 000000000000..2c35c81e8d8c --- /dev/null +++ b/arch/arm/common/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for the linux kernel. +# + +export-objs := sa1111.o sa1111-pcibuf.o sa1111-pcipool.o + +obj-$(CONFIG_SA1111) += sa1111.o sa1111-pcibuf.o sa1111-pcipool.o + +obj-$(CONFIG_PCI_HOST_PLX90X0) += plx90x0.o +obj-$(CONFIG_PCI_HOST_VIA82C505) += via82c505.o diff --git a/arch/arm/common/plx90x0.c b/arch/arm/common/plx90x0.c new file mode 100644 index 000000000000..60d7d3566af4 --- /dev/null +++ b/arch/arm/common/plx90x0.c @@ -0,0 +1,178 @@ +/* + * Driver for PLX Technology PCI9000-series host bridge. + * + * Copyright (C) 1997, 1998, 1999, 2000 FutureTV Labs Ltd + */ + +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * Since the following functions are all very similar, the common parts + * are pulled out into these macros. + */ + +#define PLX_CLEAR_CONFIG \ + __raw_writel(0, PLX_BASE + 0xac); \ + local_irq_restore(flags); } + +#define PLX_SET_CONFIG \ + { unsigned long flags; \ + local_irq_save(flags); \ + __raw_writel((1<<31 | (bus->number << 16) \ + | (devfn << 8) | (where & ~3) \ + | ((bus->number == 0)?0:1)), PLX_BASE + 0xac); \ + +#define PLX_CONFIG_WRITE(size) \ + PLX_SET_CONFIG \ + __raw_write##size(value, PCIO_BASE + (where & 3)); \ + if (__raw_readw(PLX_BASE + 0x6) & 0x2000) \ + __raw_writew(0x2000, PLX_BASE + 0x6); \ + PLX_CLEAR_CONFIG \ + return PCIBIOS_SUCCESSFUL; + +#define PLX_CONFIG_READ(size) \ + PLX_SET_CONFIG \ + *value = __raw_read##size(PCIO_BASE + (where & 3)); \ + if (__raw_readw(PLX_BASE + 0x6) & 0x2000) { \ + __raw_writew(0x2000, PLX_BASE + 0x6); \ + *value = 0xffffffffUL; \ + } \ + PLX_CLEAR_CONFIG \ + return PCIBIOS_SUCCESSFUL; + +/* Configuration space access routines */ + +static int +plx90x0_read_config (struct pci_bus *bus, unsigned int devfn, int where, + int where, int size, u32 *value) +{ + switch (size) { + case 1: + PLX_CONFIG_READ(b) + break; + case 2: + PLX_CONFIG_READ(w) + break; + case 4: + PLX_CONFIG_READ(l) + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static int +plx90x0_write_config (struct pci_bus *bus, unsigned int devfn, int where, + int where, int size, u32 value) +{ + switch (size) { + case 1: + PLX_CONFIG_WRITE(b) + break; + case 2: + PLX_CONFIG_WRITE(w) + break; + case 4: + PLX_CONFIG_WRITE(l) + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops plx90x0_ops = +{ + .read = plx90x0_read_config, + .write = plx90x0_write_config, +}; + +static void +plx_syserr_handler(int irq, void *handle, struct pt_regs *regs) +{ + printk("PLX90x0: machine check %04x (pc=%08lx)\n", + readw(PLX_BASE + 6), regs->ARM_pc); + __raw_writew(0xf000, PLX_BASE + 6); +} + +/* + * Initialise the PCI system. + */ + +void __init +plx90x0_init(struct arm_sysdata *sysdata) +{ + static const unsigned long int base = PLX_BASE; + char *what; + unsigned long bar = (unsigned long)virt_to_bus((void *)PAGE_OFFSET); + + /* Have a sniff around and see which PLX device is present. */ + unsigned long id = __raw_readl(base + 0xf0); + +#if 0 + /* This check was a good idea, but can fail. The PLX9060 puts no + default value in these registers unless NB# is asserted (which it + isn't on these cards). */ + if ((id & 0xffff) != PCI_VENDOR_ID_PLX) + return; /* Nothing found */ +#endif + + /* Found one - now work out what it is. */ + switch (id >> 16) { + case 0: /* PCI_DEVICE_ID_PLX_9060 */ + what = "PCI9060"; + break; + case PCI_DEVICE_ID_PLX_9060ES: + what = "PCI9060ES"; + break; + case PCI_DEVICE_ID_PLX_9060SD: + what = "PCI9060SD"; /* uhuhh.. */ + break; + case PCI_DEVICE_ID_PLX_9080: + what = "PCI9080"; + break; + default: + printk("PCI: Unknown PLX device %04lx found -- ignored.\n", + id >> 16); + return; + } + + printk("PCI: PLX Technology %s host bridge found.\n", what); + + /* Now set it up for both master and slave accesses. */ + __raw_writel(0xffff0147, base + 0x4); + __raw_writeb(32, base + 0xd); + __raw_writel(0x8 | bar, base + 0x18); + __raw_writel(0xf8000008, base + 0x80); + __raw_writel(0x40000001, base + 0x84); + __raw_writel(0, base + 0x88); + __raw_writel(0, base + 0x8c); + __raw_writel(0x11, base + 0x94); + __raw_writel(0xC3 + (4 << 28) + + (8 << 11) + (1 << 10) + + (1 << 24), base + 0x98); + __raw_writel(0xC0000000, base + 0x9c); + __raw_writel(PLX_MEM_START, base + 0xa0); + __raw_writel(PLX_IO_START, base + 0xa4); + __raw_writel(0x3, base + 0xa8); + __raw_writel(0, base + 0xac); + __raw_writel(0x10001, base + 0xe8); + __raw_writel(0x8000767e, base + 0xec); + + request_irq(IRQ_SYSERR, plx_syserr_handler, 0, + "system error", NULL); + + pci_scan_bus(0, &plx90x0_ops, sysdata); +} diff --git a/arch/arm/common/sa1111-pcibuf.c b/arch/arm/common/sa1111-pcibuf.c new file mode 100644 index 000000000000..05acb901c3b5 --- /dev/null +++ b/arch/arm/common/sa1111-pcibuf.c @@ -0,0 +1,551 @@ +/* + * linux/arch/arm/mach-sa1100/pci-sa1111.c + * + * Special pci_{map/unmap/dma_sync}_* routines for SA-1111. + * + * These functions utilize bouncer buffers to compensate for a bug in + * the SA-1111 hardware which don't allow DMA to/from addresses + * certain addresses above 1MB. + * + * Re-written by Christopher Hoover + * Original version by Brad Parker (brad@heeltoe.com) + * + * Copyright (C) 2002 Hewlett Packard Company. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * */ + +#include +#include +#include +#include +#include +#include + +//#define DEBUG +#ifdef DEBUG +#define DPRINTK(...) do { printk(KERN_DEBUG __VA_ARGS__); } while (0) +#else +#define DPRINTK(...) do { } while (0) +#endif + +//#define STATS +#ifdef STATS +#define DO_STATS(X) do { X ; } while (0) +#else +#define DO_STATS(X) do { } while (0) +#endif + +/* ************************************************** */ + +struct safe_buffer { + struct list_head node; + + /* original request */ + void *ptr; + size_t size; + int direction; + + /* safe buffer info */ + struct pci_pool *pool; + void *safe; + dma_addr_t safe_dma_addr; +}; + +LIST_HEAD(safe_buffers); + + +#define SIZE_SMALL 1024 +#define SIZE_LARGE (4*1024) + +static struct pci_pool *small_buffer_pool, *large_buffer_pool; + +#ifdef STATS +static unsigned long sbp_allocs __initdata = 0; +static unsigned long lbp_allocs __initdata = 0; +static unsigned long total_allocs __initdata= 0; + +static void print_alloc_stats(void) +{ + printk(KERN_INFO + "sa1111_pcibuf: sbp: %lu, lbp: %lu, other: %lu, total: %lu\n", + sbp_allocs, lbp_allocs, + total_allocs - sbp_allocs - lbp_allocs, total_allocs); +} +#endif + +static int __init +create_safe_buffer_pools(void) +{ + small_buffer_pool = pci_pool_create("sa1111_small_dma_buffer", + SA1111_FAKE_PCIDEV, + SIZE_SMALL, + 0 /* byte alignment */, + 0 /* no page-crossing issues */); + if (0 == small_buffer_pool) { + printk(KERN_ERR + "sa1111_pcibuf: could not allocate small pci pool\n"); + return -1; + } + + large_buffer_pool = pci_pool_create("sa1111_large_dma_buffer", + SA1111_FAKE_PCIDEV, + SIZE_LARGE, + 0 /* byte alignment */, + 0 /* no page-crossing issues */); + if (0 == large_buffer_pool) { + printk(KERN_ERR + "sa1111_pcibuf: could not allocate large pci pool\n"); + pci_pool_destroy(small_buffer_pool); + small_buffer_pool = 0; + return -1; + } + + printk(KERN_INFO + "sa1111_pcibuf: buffer sizes: small=%u, large=%u\n", + SIZE_SMALL, SIZE_LARGE); + + return 0; +} + +static void __exit +destroy_safe_buffer_pools(void) +{ + if (small_buffer_pool) + pci_pool_destroy(small_buffer_pool); + if (large_buffer_pool) + pci_pool_destroy(large_buffer_pool); + + small_buffer_pool = large_buffer_pool = 0; +} + + +/* allocate a 'safe' buffer and keep track of it */ +static struct safe_buffer * +alloc_safe_buffer(void *ptr, size_t size, int direction) +{ + struct safe_buffer *buf; + struct pci_pool *pool; + void *safe; + dma_addr_t safe_dma_addr; + + DPRINTK("%s(ptr=%p, size=%d, direction=%d)\n", + __func__, ptr, size, direction); + + DO_STATS ( total_allocs++ ); + + buf = kmalloc(sizeof(struct safe_buffer), GFP_ATOMIC); + if (buf == 0) { + printk(KERN_WARNING "%s: kmalloc failed\n", __func__); + return 0; + } + + if (size <= SIZE_SMALL) { + pool = small_buffer_pool; + safe = pci_pool_alloc(pool, GFP_ATOMIC, &safe_dma_addr); + + DO_STATS ( sbp_allocs++ ); + } else if (size <= SIZE_LARGE) { + pool = large_buffer_pool; + safe = pci_pool_alloc(pool, GFP_ATOMIC, &safe_dma_addr); + + DO_STATS ( lbp_allocs++ ); + } else { + pool = 0; + safe = pci_alloc_consistent(SA1111_FAKE_PCIDEV, size, + &safe_dma_addr); + } + + if (safe == 0) { + printk(KERN_WARNING + "%s: could not alloc dma memory (size=%d)\n", + __func__, size); + kfree(buf); + return 0; + } + +#ifdef STATS + if (total_allocs % 1000 == 0) + print_alloc_stats(); +#endif + + BUG_ON(sa1111_check_dma_bug(safe_dma_addr)); // paranoia + + buf->ptr = ptr; + buf->size = size; + buf->direction = direction; + buf->pool = pool; + buf->safe = safe; + buf->safe_dma_addr = safe_dma_addr; + + MOD_INC_USE_COUNT; + list_add(&buf->node, &safe_buffers); + + return buf; +} + +/* determine if a buffer is from our "safe" pool */ +static struct safe_buffer * +find_safe_buffer(dma_addr_t safe_dma_addr) +{ + struct list_head *entry; + + list_for_each(entry, &safe_buffers) { + struct safe_buffer *b = + list_entry(entry, struct safe_buffer, node); + + if (b->safe_dma_addr == safe_dma_addr) { + return b; + } + } + + return 0; +} + +static void +free_safe_buffer(struct safe_buffer *buf) +{ + DPRINTK("%s(buf=%p)\n", __func__, buf); + + list_del(&buf->node); + + if (buf->pool) + pci_pool_free(buf->pool, buf->safe, buf->safe_dma_addr); + else + pci_free_consistent(SA1111_FAKE_PCIDEV, buf->size, buf->safe, + buf->safe_dma_addr); + kfree(buf); + + MOD_DEC_USE_COUNT; +} + +static inline int +dma_range_is_safe(dma_addr_t addr, size_t size) +{ + unsigned int physaddr = SA1111_DMA_ADDR((unsigned int) addr); + + /* Any address within one megabyte of the start of the target + * bank will be OK. This is an overly conservative test: + * other addresses can be OK depending on the dram + * configuration. (See sa1111.c:sa1111_check_dma_bug() * for + * details.) + * + * We take care to ensure the entire dma region is within + * the safe range. + */ + + return ((physaddr + size - 1) < (1<<20)); +} + +/* ************************************************** */ + +#ifdef STATS +static unsigned long map_op_count __initdata = 0; +static unsigned long bounce_count __initdata = 0; + +static void print_map_stats(void) +{ + printk(KERN_INFO + "sa1111_pcibuf: map_op_count=%lu, bounce_count=%lu\n", + map_op_count, bounce_count); +} +#endif + +static dma_addr_t +map_single(void *ptr, size_t size, int direction) +{ + dma_addr_t dma_addr; + + DO_STATS ( map_op_count++ ); + + dma_addr = virt_to_bus(ptr); + + if (!dma_range_is_safe(dma_addr, size)) { + struct safe_buffer *buf; + + DO_STATS ( bounce_count++ ) ; + + buf = alloc_safe_buffer(ptr, size, direction); + if (buf == 0) { + printk(KERN_ERR + "%s: unable to map unsafe buffer %p!\n", + __func__, ptr); + return 0; + } + + DPRINTK("%s: unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n", + __func__, + buf->ptr, (void *) virt_to_bus(buf->ptr), + buf->safe, (void *) buf->safe_dma_addr); + + if ((direction == PCI_DMA_TODEVICE) || + (direction == PCI_DMA_BIDIRECTIONAL)) { + DPRINTK("%s: copy out from unsafe %p, to safe %p, size %d\n", + __func__, ptr, buf->safe, size); + memcpy(buf->safe, ptr, size); + } + consistent_sync(buf->safe, size, direction); + + dma_addr = buf->safe_dma_addr; + } else { + consistent_sync(ptr, size, direction); + } + +#ifdef STATS + if (map_op_count % 1000 == 0) + print_map_stats(); +#endif + + return dma_addr; +} + +static void +unmap_single(dma_addr_t dma_addr, size_t size, int direction) +{ + struct safe_buffer *buf; + + buf = find_safe_buffer(dma_addr); + + if (buf) { + BUG_ON(buf->size != size); + BUG_ON(buf->direction != direction); + + DPRINTK("%s: unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n", + __func__, + buf->ptr, (void *) virt_to_bus(buf->ptr), + buf->safe, (void *) buf->safe_dma_addr); + + + DO_STATS ( bounce_count++ ); + + if ((direction == PCI_DMA_FROMDEVICE) || + (direction == PCI_DMA_BIDIRECTIONAL)) { + DPRINTK("%s: copy back from safe %p, to unsafe %p size %d\n", + __func__, buf->safe, buf->ptr, size); + memcpy(buf->ptr, buf->safe, size); + } + free_safe_buffer(buf); + } +} + +static void +sync_single(dma_addr_t dma_addr, size_t size, int direction) +{ + struct safe_buffer *buf; + + buf = find_safe_buffer(dma_addr); + + if (buf) { + BUG_ON(buf->size != size); + BUG_ON(buf->direction != direction); + + DPRINTK("%s: unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n", + __func__, + buf->ptr, (void *) virt_to_bus(buf->ptr), + buf->safe, (void *) buf->safe_dma_addr); + + DO_STATS ( bounce_count++ ); + + switch (direction) { + case PCI_DMA_FROMDEVICE: + DPRINTK("%s: copy back from safe %p, to unsafe %p size %d\n", + __func__, buf->safe, buf->ptr, size); + memcpy(buf->ptr, buf->safe, size); + break; + case PCI_DMA_TODEVICE: + DPRINTK("%s: copy out from unsafe %p, to safe %p, size %d\n", + __func__,buf->ptr, buf->safe, size); + memcpy(buf->safe, buf->ptr, size); + break; + case PCI_DMA_BIDIRECTIONAL: + BUG(); /* is this allowed? what does it mean? */ + default: + BUG(); + } + consistent_sync(buf->safe, size, direction); + } else { + consistent_sync(bus_to_virt(dma_addr), size, direction); + } +} + +/* ************************************************** */ + +/* + * see if a buffer address is in an 'unsafe' range. if it is + * allocate a 'safe' buffer and copy the unsafe buffer into it. + * substitute the safe buffer for the unsafe one. + * (basically move the buffer from an unsafe area to a safe one) + */ +dma_addr_t +sa1111_map_single(void *ptr, size_t size, int direction) +{ + unsigned long flags; + dma_addr_t dma_addr; + + DPRINTK("%s(ptr=%p,size=%d,dir=%x)\n", + __func__, ptr, size, direction); + + BUG_ON(direction == PCI_DMA_NONE); + + local_irq_save(flags); + + dma_addr = map_single(ptr, size, direction); + + local_irq_restore(flags); + + return dma_addr; +} + +/* + * see if a mapped address was really a "safe" buffer and if so, copy + * the data from the safe buffer back to the unsafe buffer and free up + * the safe buffer. (basically return things back to the way they + * should be) + */ + +void +sa1111_unmap_single(dma_addr_t dma_addr, size_t size, int direction) +{ + unsigned long flags; + + DPRINTK("%s(ptr=%p,size=%d,dir=%x)\n", + __func__, (void *) dma_addr, size, direction); + + BUG_ON(direction == PCI_DMA_NONE); + + local_irq_save(flags); + + unmap_single(dma_addr, size, direction); + + local_irq_restore(flags); +} + +int +sa1111_map_sg(struct scatterlist *sg, int nents, int direction) +{ + unsigned long flags; + int i; + + DPRINTK("%s(sg=%p,nents=%d,dir=%x)\n", + __func__, sg, nents, direction); + + BUG_ON(direction == PCI_DMA_NONE); + + local_irq_save(flags); + + for (i = 0; i < nents; i++, sg++) { + struct page *page = sg->page; + unsigned int offset = sg->offset; + unsigned int length = sg->length; + void *ptr = page_address(page) + offset; + + sg->dma_address = + map_single(ptr, length, direction); + } + + local_irq_restore(flags); + + return nents; +} + +void +sa1111_unmap_sg(struct scatterlist *sg, int nents, int direction) +{ + unsigned long flags; + int i; + + DPRINTK("%s(sg=%p,nents=%d,dir=%x)\n", + __func__, sg, nents, direction); + + BUG_ON(direction == PCI_DMA_NONE); + + local_irq_save(flags); + + for (i = 0; i < nents; i++, sg++) { + dma_addr_t dma_addr = sg->dma_address; + unsigned int length = sg->length; + + unmap_single(dma_addr, length, direction); + } + + local_irq_restore(flags); +} + +void +sa1111_dma_sync_single(dma_addr_t dma_addr, size_t size, int direction) +{ + unsigned long flags; + + DPRINTK("%s(ptr=%p,size=%d,dir=%x)\n", + __func__, (void *) dma_addr, size, direction); + + local_irq_save(flags); + + sync_single(dma_addr, size, direction); + + local_irq_restore(flags); +} + +void +sa1111_dma_sync_sg(struct scatterlist *sg, int nents, int direction) +{ + unsigned long flags; + int i; + + DPRINTK("%s(sg=%p,nents=%d,dir=%x)\n", + __func__, sg, nents, direction); + + BUG_ON(direction == PCI_DMA_NONE); + + local_irq_save(flags); + + for (i = 0; i < nents; i++, sg++) { + dma_addr_t dma_addr = sg->dma_address; + unsigned int length = sg->length; + + sync_single(dma_addr, length, direction); + } + + local_irq_restore(flags); +} + +EXPORT_SYMBOL(sa1111_map_single); +EXPORT_SYMBOL(sa1111_unmap_single); +EXPORT_SYMBOL(sa1111_map_sg); +EXPORT_SYMBOL(sa1111_unmap_sg); +EXPORT_SYMBOL(sa1111_dma_sync_single); +EXPORT_SYMBOL(sa1111_dma_sync_sg); + +/* **************************************** */ + +static int __init sa1111_pcibuf_init(void) +{ + int ret; + + printk(KERN_DEBUG + "sa1111_pcibuf: initializing SA-1111 DMA workaround\n"); + + ret = create_safe_buffer_pools(); + + return ret; +} +module_init(sa1111_pcibuf_init); + +static void __exit sa1111_pcibuf_exit(void) +{ + BUG_ON(!list_empty(&safe_buffers)); + +#ifdef STATS + print_alloc_stats(); + print_map_stats(); +#endif + + destroy_safe_buffer_pools(); +} +module_exit(sa1111_pcibuf_exit); + +MODULE_AUTHOR("Christopher Hoover "); +MODULE_DESCRIPTION("Special pci_{map/unmap/dma_sync}_* routines for SA-1111."); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/common/sa1111-pcipool.c b/arch/arm/common/sa1111-pcipool.c new file mode 100644 index 000000000000..724afb8714ad --- /dev/null +++ b/arch/arm/common/sa1111-pcipool.c @@ -0,0 +1,390 @@ +/* + NOTE: + + this code was lifted straight out of drivers/pci/pci.c; + when compiling for the Intel StrongARM SA-1110/SA-1111 the + usb-ohci.c driver needs these routines even when the architecture + has no pci bus... +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * Pool allocator ... wraps the pci_alloc_consistent page allocator, so + * small blocks are easily used by drivers for bus mastering controllers. + * This should probably be sharing the guts of the slab allocator. + */ + +struct pci_pool { /* the pool */ + struct list_head page_list; + spinlock_t lock; + size_t blocks_per_page; + size_t size; + struct pci_dev *dev; + size_t allocation; + char name [32]; + wait_queue_head_t waitq; +}; + +struct pci_page { /* cacheable header for 'allocation' bytes */ + struct list_head page_list; + void *vaddr; + dma_addr_t dma; + unsigned long bitmap [0]; +}; + +#define POOL_TIMEOUT_JIFFIES ((100 /* msec */ * HZ) / 1000) +#define POOL_POISON_BYTE 0xa7 + +// #define CONFIG_PCIPOOL_DEBUG + +static inline const char *slot_name(const struct pci_pool *pool) +{ + const struct pci_dev *pdev = pool->dev; + + if (pdev == 0) + return "[0]"; + + else if (pcidev_is_sa1111(pdev)) + return "[SA-1111]"; + else + return pdev->slot_name; +} + + +/** + * pci_pool_create - Creates a pool of pci consistent memory blocks, for dma. + * @name: name of pool, for diagnostics + * @pdev: pci device that will be doing the DMA + * @size: size of the blocks in this pool. + * @align: alignment requirement for blocks; must be a power of two + * @allocation: returned blocks won't cross this boundary (or zero) + * Context: !in_interrupt() + * + * Returns a pci allocation pool with the requested characteristics, or + * null if one can't be created. Given one of these pools, pci_pool_alloc() + * may be used to allocate memory. Such memory will all have "consistent" + * DMA mappings, accessible by the device and its driver without using + * cache flushing primitives. The actual size of blocks allocated may be + * larger than requested because of alignment. + * + * If allocation is nonzero, objects returned from pci_pool_alloc() won't + * cross that size boundary. This is useful for devices which have + * addressing restrictions on individual DMA transfers, such as not crossing + * boundaries of 4KBytes. + */ +struct pci_pool * +pci_pool_create (const char *name, struct pci_dev *pdev, + size_t size, size_t align, size_t allocation) +{ + struct pci_pool *retval; + + if (align == 0) + align = 1; + if (size == 0) + return 0; + else if (size < align) + size = align; + else if ((size % align) != 0) { + size += align + 1; + size &= ~(align - 1); + } + + if (allocation == 0) { + if (PAGE_SIZE < size) + allocation = size; + else + allocation = PAGE_SIZE; + // FIXME: round up for less fragmentation + } else if (allocation < size) + return 0; + + if (!(retval = kmalloc (sizeof *retval, SLAB_KERNEL))) + return retval; + + strncpy (retval->name, name, sizeof retval->name); + retval->name [sizeof retval->name - 1] = 0; + + retval->dev = pdev; + INIT_LIST_HEAD (&retval->page_list); + spin_lock_init (&retval->lock); + retval->size = size; + retval->allocation = allocation; + retval->blocks_per_page = allocation / size; + init_waitqueue_head (&retval->waitq); + +#ifdef CONFIG_PCIPOOL_DEBUG + printk (KERN_DEBUG "pcipool create %s/%s size %d, %d/page (%d alloc)\n", + slot_name(retval), retval->name, size, + retval->blocks_per_page, allocation); +#endif + + return retval; +} + + +static struct pci_page * +pool_alloc_page (struct pci_pool *pool, int mem_flags) +{ + struct pci_page *page; + int mapsize; + + mapsize = pool->blocks_per_page; + mapsize = (mapsize + BITS_PER_LONG - 1) / BITS_PER_LONG; + mapsize *= sizeof (long); + + page = (struct pci_page *) kmalloc (mapsize + sizeof *page, mem_flags); + if (!page) + return 0; + page->vaddr = pci_alloc_consistent (pool->dev, + pool->allocation, + &page->dma); + if (page->vaddr) { + memset (page->bitmap, 0xff, mapsize); // bit set == free +#ifdef CONFIG_DEBUG_SLAB + memset (page->vaddr, POOL_POISON_BYTE, pool->allocation); +#endif + list_add (&page->page_list, &pool->page_list); + } else { + kfree (page); + page = 0; + } + return page; +} + + +static inline int +is_page_busy (int blocks, unsigned long *bitmap) +{ + while (blocks > 0) { + if (*bitmap++ != ~0UL) + return 1; + blocks -= BITS_PER_LONG; + } + return 0; +} + +static void +pool_free_page (struct pci_pool *pool, struct pci_page *page) +{ + dma_addr_t dma = page->dma; + +#ifdef CONFIG_DEBUG_SLAB + memset (page->vaddr, POOL_POISON_BYTE, pool->allocation); +#endif + pci_free_consistent (pool->dev, pool->allocation, page->vaddr, dma); + list_del (&page->page_list); + kfree (page); +} + + +/** + * pci_pool_destroy - destroys a pool of pci memory blocks. + * @pool: pci pool that will be destroyed + * + * Caller guarantees that no more memory from the pool is in use, + * and that nothing will try to use the pool after this call. + */ +void +pci_pool_destroy (struct pci_pool *pool) +{ + unsigned long flags; + +#ifdef CONFIG_PCIPOOL_DEBUG + printk (KERN_DEBUG "pcipool destroy %s/%s\n", + slot_name(pool), pool->name); +#endif + + spin_lock_irqsave (&pool->lock, flags); + while (!list_empty (&pool->page_list)) { + struct pci_page *page; + page = list_entry (pool->page_list.next, + struct pci_page, page_list); + if (is_page_busy (pool->blocks_per_page, page->bitmap)) { + printk (KERN_ERR "pci_pool_destroy %s/%s, %p busy\n", + slot_name(pool), pool->name, page->vaddr); + /* leak the still-in-use consistent memory */ + list_del (&page->page_list); + kfree (page); + } else + pool_free_page (pool, page); + } + spin_unlock_irqrestore (&pool->lock, flags); + kfree (pool); +} + + +/** + * pci_pool_alloc - get a block of consistent memory + * @pool: pci pool that will produce the block + * @mem_flags: SLAB_KERNEL or SLAB_ATOMIC + * @handle: pointer to dma address of block + * + * This returns the kernel virtual address of a currently unused block, + * and reports its dma address through the handle. + * If such a memory block can't be allocated, null is returned. + */ +void * +pci_pool_alloc (struct pci_pool *pool, int mem_flags, dma_addr_t *handle) +{ + unsigned long flags; + struct list_head *entry; + struct pci_page *page; + int map, block; + size_t offset; + void *retval; + +restart: + spin_lock_irqsave (&pool->lock, flags); + list_for_each (entry, &pool->page_list) { + int i; + page = list_entry (entry, struct pci_page, page_list); + /* only cachable accesses here ... */ + for (map = 0, i = 0; + i < pool->blocks_per_page; + i += BITS_PER_LONG, map++) { + if (page->bitmap [map] == 0) + continue; + block = ffz (~ page->bitmap [map]); + if ((i + block) < pool->blocks_per_page) { + clear_bit (block, &page->bitmap [map]); + offset = (BITS_PER_LONG * map) + block; + offset *= pool->size; + goto ready; + } + } + } + if (!(page = pool_alloc_page (pool, mem_flags))) { + if (mem_flags == SLAB_KERNEL) { + DECLARE_WAITQUEUE (wait, current); + + current->state = TASK_INTERRUPTIBLE; + add_wait_queue (&pool->waitq, &wait); + spin_unlock_irqrestore (&pool->lock, flags); + + schedule_timeout (POOL_TIMEOUT_JIFFIES); + + current->state = TASK_RUNNING; + remove_wait_queue (&pool->waitq, &wait); + goto restart; + } + retval = 0; + goto done; + } + + clear_bit (0, &page->bitmap [0]); + offset = 0; +ready: + retval = offset + page->vaddr; + *handle = offset + page->dma; +done: + spin_unlock_irqrestore (&pool->lock, flags); + return retval; +} + + +static struct pci_page * +pool_find_page (struct pci_pool *pool, dma_addr_t dma) +{ + unsigned long flags; + struct list_head *entry; + struct pci_page *page; + + spin_lock_irqsave (&pool->lock, flags); + list_for_each (entry, &pool->page_list) { + page = list_entry (entry, struct pci_page, page_list); + if (dma < page->dma) + continue; + if (dma < (page->dma + pool->allocation)) + goto done; + } + page = 0; +done: + spin_unlock_irqrestore (&pool->lock, flags); + return page; +} + + +/** + * pci_pool_free - put block back into pci pool + * @pool: the pci pool holding the block + * @vaddr: virtual address of block + * @dma: dma address of block + * + * Caller promises neither device nor driver will again touch this block + * unless it is first re-allocated. + */ +void +pci_pool_free (struct pci_pool *pool, void *vaddr, dma_addr_t dma) +{ + struct pci_page *page; + unsigned long flags; + int map, block; + + if ((page = pool_find_page (pool, dma)) == 0) { + printk (KERN_ERR "pci_pool_free %s/%s, %p/%lx (bad dma)\n", + pool->dev ? pool->dev->slot_name : NULL, + pool->name, vaddr, (unsigned long) dma); + return; + } + + block = dma - page->dma; + block /= pool->size; + map = block / BITS_PER_LONG; + block %= BITS_PER_LONG; + +#ifdef CONFIG_DEBUG_SLAB + if (((dma - page->dma) + (void *)page->vaddr) != vaddr) { + printk (KERN_ERR "pci_pool_free %s/%s, %p (bad vaddr)/%lx\n", + pool->dev ? pool->dev->slot_name : NULL, + pool->name, vaddr, (unsigned long) dma); + return; + } + if (page->bitmap [map] & (1UL << block)) { + printk (KERN_ERR "pci_pool_free %s/%s, dma %x already free\n", + pool->dev ? pool->dev->slot_name : NULL, + pool->name, dma); + return; + } + memset (vaddr, POOL_POISON_BYTE, pool->size); +#endif + + spin_lock_irqsave (&pool->lock, flags); + set_bit (block, &page->bitmap [map]); + if (waitqueue_active (&pool->waitq)) + wake_up (&pool->waitq); + /* + * Resist a temptation to do + * if (!is_page_busy(bpp, page->bitmap)) pool_free_page(pool, page); + * it is not interrupt safe. Better have empty pages hang around. + */ + spin_unlock_irqrestore (&pool->lock, flags); +} + +EXPORT_SYMBOL (pci_pool_create); +EXPORT_SYMBOL (pci_pool_destroy); +EXPORT_SYMBOL (pci_pool_alloc); +EXPORT_SYMBOL (pci_pool_free); + +/* **************************************** */ + +static int __init pcipool_init(void) +{ + MOD_INC_USE_COUNT; /* never unload */ + + return 0; +} +module_init(pcipool_init); + +MODULE_LICENSE("GPL"); diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c new file mode 100644 index 000000000000..038101ed24a6 --- /dev/null +++ b/arch/arm/common/sa1111.c @@ -0,0 +1,1107 @@ +/* + * linux/arch/arm/mach-sa1100/sa1111.c + * + * SA1111 support + * + * Original code by John Dorsey + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This file contains all generic SA1111 support. + * + * All initialization functions provided here are intended to be called + * from machine specific code with proper arguments when required. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +/* + * We keep the following data for the overall SA1111. Note that the + * struct device and struct resource are "fake"; they should be supplied + * by the bus above us. However, in the interests of getting all SA1111 + * drivers converted over to the device model, we provide this as an + * anchor point for all the other drivers. + */ +struct sa1111 { + struct device *dev; + struct resource res; + int irq; + spinlock_t lock; + void *base; +}; + +/* + * We _really_ need to eliminate this. Its only users + * are the PWM and DMA checking code. + */ +static struct sa1111 *g_sa1111; + +static struct sa1111_dev usb_dev = { + .dev = { + .name = "Intel Corporation SA1111 [USB Controller]", + }, + .skpcr_mask = SKPCR_UCLKEN, + .devid = SA1111_DEVID_USB, + .irq = { + IRQ_USBPWR, + IRQ_HCIM, + IRQ_HCIBUFFACC, + IRQ_HCIRMTWKP, + IRQ_NHCIMFCIR, + IRQ_USB_PORT_RESUME + }, +}; + +static struct sa1111_dev sac_dev = { + .dev = { + .name = "Intel Corporation SA1111 [Audio Controller]", + }, + .skpcr_mask = SKPCR_I2SCLKEN | SKPCR_L3CLKEN, + .devid = SA1111_DEVID_SAC, + .irq = { + AUDXMTDMADONEA, + AUDXMTDMADONEB, + AUDRCVDMADONEA, + AUDRCVDMADONEB + }, +}; + +static struct sa1111_dev ssp_dev = { + .dev = { + .name = "Intel Corporation SA1111 [SSP Controller]", + }, + .skpcr_mask = SKPCR_SCLKEN, + .devid = SA1111_DEVID_SSP, +}; + +static struct sa1111_dev kbd_dev = { + .dev = { + .name = "Intel Corporation SA1111 [PS2]", + }, + .skpcr_mask = SKPCR_PTCLKEN, + .devid = SA1111_DEVID_PS2, + .irq = { + IRQ_TPRXINT, + IRQ_TPTXINT + }, +}; + +static struct sa1111_dev mse_dev = { + .dev = { + .name = "Intel Corporation SA1111 [PS2]", + }, + .skpcr_mask = SKPCR_PMCLKEN, + .devid = SA1111_DEVID_PS2, + .irq = { + IRQ_MSRXINT, + IRQ_MSTXINT + }, +}; + +static struct sa1111_dev int_dev = { + .dev = { + .name = "Intel Corporation SA1111 [Interrupt Controller]", + }, + .skpcr_mask = 0, + .devid = SA1111_DEVID_INT, +}; + +static struct sa1111_dev pcmcia_dev = { + .dev = { + .name = "Intel Corporation SA1111 [PCMCIA Controller]", + }, + .skpcr_mask = 0, + .devid = SA1111_DEVID_PCMCIA, + .irq = { + IRQ_S0_READY_NINT, + IRQ_S0_CD_VALID, + IRQ_S0_BVD1_STSCHG, + IRQ_S1_READY_NINT, + IRQ_S1_CD_VALID, + IRQ_S1_BVD1_STSCHG, + }, +}; + +static struct sa1111_dev *devs[] = { + &usb_dev, + &sac_dev, + &ssp_dev, + &kbd_dev, + &mse_dev, + &pcmcia_dev, +}; + +static unsigned int dev_offset[] = { + SA1111_USB, + 0x0600, + 0x0800, + SA1111_KBD, + SA1111_MSE, + 0x1800, +}; + +/* + * SA1111 interrupt support. Since clearing an IRQ while there are + * active IRQs causes the interrupt output to pulse, the upper levels + * will call us again if there are more interrupts to process. + */ +static void +sa1111_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) +{ + unsigned int stat0, stat1, i; + + stat0 = INTSTATCLR0; + stat1 = INTSTATCLR1; + + INTSTATCLR0 = stat0; + + desc->chip->ack(irq); + + INTSTATCLR1 = stat1; + + if (stat0 == 0 && stat1 == 0) { + do_bad_IRQ(irq, desc, regs); + return; + } + + for (i = IRQ_SA1111_START; stat0; i++, stat0 >>= 1) + if (stat0 & 1) + do_edge_IRQ(i, irq_desc + i, regs); + + for (i = IRQ_SA1111_START + 32; stat1; i++, stat1 >>= 1) + if (stat1 & 1) + do_edge_IRQ(i, irq_desc + i, regs); + + /* For level-based interrupts */ + desc->chip->unmask(irq); +} + +#define SA1111_IRQMASK_LO(x) (1 << (x - IRQ_SA1111_START)) +#define SA1111_IRQMASK_HI(x) (1 << (x - IRQ_SA1111_START - 32)) + +static void sa1111_ack_irq(unsigned int irq) +{ +} + +static void sa1111_mask_lowirq(unsigned int irq) +{ + INTEN0 &= ~SA1111_IRQMASK_LO(irq); +} + +static void sa1111_unmask_lowirq(unsigned int irq) +{ + INTEN0 |= SA1111_IRQMASK_LO(irq); +} + +/* + * Attempt to re-trigger the interrupt. The SA1111 contains a register + * (INTSET) which claims to do this. However, in practice no amount of + * manipulation of INTEN and INTSET guarantees that the interrupt will + * be triggered. In fact, its very difficult, if not impossible to get + * INTSET to re-trigger the interrupt. + */ +static void sa1111_rerun_lowirq(unsigned int irq) +{ + unsigned int mask = SA1111_IRQMASK_LO(irq); + int i; + + for (i = 0; i < 8; i++) { + INTPOL0 ^= mask; + INTPOL0 ^= mask; + if (INTSTATCLR1 & mask) + break; + } + + if (i == 8) + printk(KERN_ERR "Danger Will Robinson: failed to " + "re-trigger IRQ%d\n", irq); +} + +static int sa1111_type_lowirq(unsigned int irq, unsigned int flags) +{ + unsigned int mask = SA1111_IRQMASK_LO(irq); + + if (flags == IRQT_PROBE) + return 0; + + if ((!(flags & __IRQT_RISEDGE) ^ !(flags & __IRQT_FALEDGE)) == 0) + return -EINVAL; + + if (flags & __IRQT_RISEDGE) + INTPOL0 &= ~mask; + else + INTPOL0 |= mask; + WAKE_POL0 = INTPOL0; + + return 0; +} + +static int sa1111_wake_lowirq(unsigned int irq, unsigned int on) +{ + unsigned int mask = SA1111_IRQMASK_LO(irq); + + if (on) + WAKE_EN0 |= mask; + else + WAKE_EN0 &= ~mask; + + return 0; +} + +static struct irqchip sa1111_low_chip = { + .ack = sa1111_ack_irq, + .mask = sa1111_mask_lowirq, + .unmask = sa1111_unmask_lowirq, + .rerun = sa1111_rerun_lowirq, + .type = sa1111_type_lowirq, + .wake = sa1111_wake_lowirq, +}; + +static void sa1111_mask_highirq(unsigned int irq) +{ + INTEN1 &= ~SA1111_IRQMASK_HI(irq); +} + +static void sa1111_unmask_highirq(unsigned int irq) +{ + INTEN1 |= SA1111_IRQMASK_HI(irq); +} + +/* + * Attempt to re-trigger the interrupt. The SA1111 contains a register + * (INTSET) which claims to do this. However, in practice no amount of + * manipulation of INTEN and INTSET guarantees that the interrupt will + * be triggered. In fact, its very difficult, if not impossible to get + * INTSET to re-trigger the interrupt. + */ +static void sa1111_rerun_highirq(unsigned int irq) +{ + unsigned int mask = SA1111_IRQMASK_HI(irq); + int i; + + for (i = 0; i < 8; i++) { + INTPOL1 ^= mask; + INTPOL1 ^= mask; + if (INTSTATCLR1 & mask) + break; + } + + if (i == 8) + printk(KERN_ERR "Danger Will Robinson: failed to " + "re-trigger IRQ%d\n", irq); +} + +static int sa1111_type_highirq(unsigned int irq, unsigned int flags) +{ + unsigned int mask = SA1111_IRQMASK_HI(irq); + + if (flags == IRQT_PROBE) + return 0; + + if ((!(flags & __IRQT_RISEDGE) ^ !(flags & __IRQT_FALEDGE)) == 0) + return -EINVAL; + + if (flags & __IRQT_RISEDGE) + INTPOL1 &= ~mask; + else + INTPOL1 |= mask; + WAKE_POL1 = INTPOL1; + + return 0; +} + +static int sa1111_wake_highirq(unsigned int irq, unsigned int on) +{ + unsigned int mask = SA1111_IRQMASK_HI(irq); + + if (on) + WAKE_EN1 |= mask; + else + WAKE_EN1 &= ~mask; + + return 0; +} + +static struct irqchip sa1111_high_chip = { + .ack = sa1111_ack_irq, + .mask = sa1111_mask_highirq, + .unmask = sa1111_unmask_highirq, + .rerun = sa1111_rerun_highirq, + .type = sa1111_type_highirq, + .wake = sa1111_wake_highirq, +}; + +static void __init sa1111_init_irq(struct sa1111_dev *sadev) +{ + unsigned int irq; + + /* + * We're guaranteed that this region hasn't been taken. + */ + request_mem_region(sadev->res.start, 512, "irqs"); + + /* disable all IRQs */ + sa1111_writel(0, sadev->mapbase + SA1111_INTEN0); + sa1111_writel(0, sadev->mapbase + SA1111_INTEN1); + sa1111_writel(0, sadev->mapbase + SA1111_WAKEEN0); + sa1111_writel(0, sadev->mapbase + SA1111_WAKEEN1); + + /* + * detect on rising edge. Note: Feb 2001 Errata for SA1111 + * specifies that S0ReadyInt and S1ReadyInt should be '1'. + */ + sa1111_writel(0, sadev->mapbase + SA1111_INTPOL0); + sa1111_writel(SA1111_IRQMASK_HI(IRQ_S0_READY_NINT) | + SA1111_IRQMASK_HI(IRQ_S1_READY_NINT), + sadev->mapbase + SA1111_INTPOL1); + + /* clear all IRQs */ + sa1111_writel(~0, sadev->mapbase + SA1111_INTSTATCLR0); + sa1111_writel(~0, sadev->mapbase + SA1111_INTSTATCLR1); + + for (irq = IRQ_GPAIN0; irq <= SSPROR; irq++) { + set_irq_chip(irq, &sa1111_low_chip); + set_irq_handler(irq, do_edge_IRQ); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + } + + for (irq = AUDXMTDMADONEA; irq <= IRQ_S1_BVD1_STSCHG; irq++) { + set_irq_chip(irq, &sa1111_high_chip); + set_irq_handler(irq, do_edge_IRQ); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + } + + /* + * Register SA1111 interrupt + */ + set_irq_type(sadev->irq[0], IRQT_RISING); + set_irq_chained_handler(sadev->irq[0], sa1111_irq_handler); +} + +/* + * Bring the SA1111 out of reset. This requires a set procedure: + * 1. nRESET asserted (by hardware) + * 2. CLK turned on from SA1110 + * 3. nRESET deasserted + * 4. VCO turned on, PLL_BYPASS turned off + * 5. Wait lock time, then assert RCLKEn + * 7. PCR set to allow clocking of individual functions + * + * Until we've done this, the only registers we can access are: + * SBI_SKCR + * SBI_SMCR + * SBI_SKID + */ +static void sa1111_wake(struct sa1111 *sachip) +{ + unsigned long flags, r; + + spin_lock_irqsave(&sachip->lock, flags); + + /* + * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111: + * (SA-1110 Developer's Manual, section 9.1.2.1) + */ + GAFR |= GPIO_32_768kHz; + GPDR |= GPIO_32_768kHz; + TUCR = TUCR_3_6864MHz; + + /* + * Turn VCO on, and disable PLL Bypass. + */ + r = sa1111_readl(sachip->base + SA1111_SKCR); + r &= ~SKCR_VCO_OFF; + sa1111_writel(r, sachip->base + SA1111_SKCR); + r |= SKCR_PLL_BYPASS | SKCR_OE_EN; + sa1111_writel(r, sachip->base + SA1111_SKCR); + + /* + * Wait lock time. SA1111 manual _doesn't_ + * specify a figure for this! We choose 100us. + */ + udelay(100); + + /* + * Enable RCLK. We also ensure that RDYEN is set. + */ + r |= SKCR_RCLKEN | SKCR_RDYEN; + sa1111_writel(r, sachip->base + SA1111_SKCR); + + /* + * Wait 14 RCLK cycles for the chip to finish coming out + * of reset. (RCLK=24MHz). This is 590ns. + */ + udelay(1); + + /* + * Ensure all clocks are initially off. + */ + sa1111_writel(0, sachip->base + SA1111_SKPCR); + + spin_unlock_irqrestore(&sachip->lock, flags); +} + +/* + * Configure the SA1111 shared memory controller. + */ +void +sa1111_configure_smc(struct sa1111 *sachip, int sdram, unsigned int drac, + unsigned int cas_latency) +{ + unsigned int smcr = SMCR_DTIM | SMCR_MBGE | FInsrt(drac, SMCR_DRAC); + + if (cas_latency == 3) + smcr |= SMCR_CLAT; + + sa1111_writel(smcr, sachip->base + SA1111_SMCR); +} + +static void +sa1111_init_one_child(struct sa1111 *sachip, struct sa1111_dev *sadev, unsigned int offset) +{ + snprintf(sadev->dev.bus_id, sizeof(sadev->dev.bus_id), + "%4.4x", offset); + + sadev->dev.parent = sachip->dev; + sadev->dev.bus = &sa1111_bus_type; + sadev->res.start = sachip->res.start + offset; + sadev->res.end = sadev->res.start + 511; + sadev->res.name = sadev->dev.name; + sadev->res.flags = IORESOURCE_MEM; + sadev->mapbase = sachip->base + offset; + + if (request_resource(&sachip->res, &sadev->res)) { + printk("SA1111: failed to allocate resource for %s\n", + sadev->res.name); + return; + } + + device_register(&sadev->dev); +} + +/** + * sa1111_probe - probe for a single SA1111 chip. + * @phys_addr: physical address of device. + * + * Probe for a SA1111 chip. This must be called + * before any other SA1111-specific code. + * + * Returns: + * %-ENODEV device not found. + * %-EBUSY physical address already marked in-use. + * %0 successful. + */ +static int __init +__sa1111_probe(struct device *me, unsigned long phys_addr, int irq) +{ + struct sa1111 *sachip; + unsigned long id; + unsigned int has_devs, val; + int i, ret = -ENODEV; + + sachip = kmalloc(sizeof(struct sa1111), GFP_KERNEL); + if (!sachip) + return -ENOMEM; + + memset(sachip, 0, sizeof(struct sa1111)); + + spin_lock_init(&sachip->lock); + + sachip->dev = me; + dev_set_drvdata(sachip->dev, sachip); + + sachip->res.name = me->name; + sachip->res.start = phys_addr; + sachip->res.end = phys_addr + 0x2000; + sachip->irq = irq; + + if (request_resource(&iomem_resource, &sachip->res)) { + ret = -EBUSY; + goto out; + } + + /* + * Map the whole region. This also maps the + * registers for our children. + */ + sachip->base = ioremap(phys_addr, PAGE_SIZE * 2); + if (!sachip->base) { + ret = -ENOMEM; + goto release; + } + + /* + * Probe for the chip. Only touch the SBI registers. + */ + id = sa1111_readl(sachip->base + SA1111_SKID); + if ((id & SKID_ID_MASK) != SKID_SA1111_ID) { + printk(KERN_DEBUG "SA1111 not detected: ID = %08lx\n", id); + ret = -ENODEV; + goto unmap; + } + + printk(KERN_INFO "SA1111 Microprocessor Companion Chip: " + "silicon revision %lx, metal revision %lx\n", + (id & SKID_SIREV_MASK)>>4, (id & SKID_MTREV_MASK)); + + /* + * We found it. Wake the chip up, and initialise. + */ + sa1111_wake(sachip); + + /* + * The SDRAM configuration of the SA1110 and the SA1111 must + * match. This is very important to ensure that SA1111 accesses + * don't corrupt the SDRAM. Note that this ungates the SA1111's + * MBGNT signal, so we must have called sa1110_mb_disable() + * beforehand. + */ + sa1111_configure_smc(sachip, 1, + FExtr(MDCNFG, MDCNFG_SA1110_DRAC0), + FExtr(MDCNFG, MDCNFG_SA1110_TDL0)); + + /* + * We only need to turn on DCLK whenever we want to use the + * DMA. It can otherwise be held firmly in the off position. + * (currently, we always enable it.) + */ + val = sa1111_readl(sachip->base + SA1111_SKPCR); + sa1111_writel(val | SKPCR_DCLKEN, sachip->base + SA1111_SKPCR); + + /* + * Enable the SA1110 memory bus request and grant signals. + */ + sa1110_mb_enable(); + + /* + * The interrupt controller must be initialised before any + * other device to ensure that the interrupts are available. + */ + int_dev.irq[0] = irq; + sa1111_init_one_child(sachip, &int_dev, SA1111_INTC); + sa1111_init_irq(&int_dev); + + g_sa1111 = sachip; + + has_devs = ~0; + if (machine_is_assabet() || machine_is_jornada720() || + machine_is_badge4()) + has_devs &= ~(1 << 4); + else + has_devs &= ~(1 << 1); + + for (i = 0; i < ARRAY_SIZE(devs); i++) + if (has_devs & (1 << i)) + sa1111_init_one_child(sachip, devs[i], dev_offset[i]); + + return 0; + + unmap: + iounmap(sachip->base); + release: + release_resource(&sachip->res); + out: + kfree(sachip); + return ret; +} + +static void __sa1111_remove(struct sa1111 *sachip) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(devs); i++) { + put_device(&devs[i]->dev); + release_resource(&devs[i]->res); + } + + iounmap(sachip->base); + release_resource(&sachip->res); + kfree(sachip); +} + +/* + * According to the "Intel StrongARM SA-1111 Microprocessor Companion + * Chip Specification Update" (June 2000), erratum #7, there is a + * significant bug in the SA1111 SDRAM shared memory controller. If + * an access to a region of memory above 1MB relative to the bank base, + * it is important that address bit 10 _NOT_ be asserted. Depending + * on the configuration of the RAM, bit 10 may correspond to one + * of several different (processor-relative) address bits. + * + * This routine only identifies whether or not a given DMA address + * is susceptible to the bug. + */ +int sa1111_check_dma_bug(dma_addr_t addr) +{ + struct sa1111 *sachip = g_sa1111; + unsigned int physaddr = SA1111_DMA_ADDR((unsigned int)addr); + unsigned int smcr; + + /* Section 4.6 of the "Intel StrongARM SA-1111 Development Module + * User's Guide" mentions that jumpers R51 and R52 control the + * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or + * SDRAM bank 1 on Neponset). The default configuration selects + * Assabet, so any address in bank 1 is necessarily invalid. + */ + if ((machine_is_assabet() || machine_is_pfs168()) && addr >= 0xc8000000) + return -1; + + /* The bug only applies to buffers located more than one megabyte + * above the start of the target bank: + */ + if (physaddr<(1<<20)) + return 0; + + smcr = sa1111_readl(sachip->base + SA1111_SMCR); + switch (FExtr(smcr, SMCR_DRAC)) { + case 01: /* 10 row + bank address bits, A<20> must not be set */ + if (physaddr & (1<<20)) + return -1; + break; + case 02: /* 11 row + bank address bits, A<23> must not be set */ + if (physaddr & (1<<23)) + return -1; + break; + case 03: /* 12 row + bank address bits, A<24> must not be set */ + if (physaddr & (1<<24)) + return -1; + break; + case 04: /* 13 row + bank address bits, A<25> must not be set */ + if (physaddr & (1<<25)) + return -1; + break; + case 05: /* 14 row + bank address bits, A<20> must not be set */ + if (physaddr & (1<<20)) + return -1; + break; + case 06: /* 15 row + bank address bits, A<20> must not be set */ + if (physaddr & (1<<20)) + return -1; + break; + default: + printk(KERN_ERR "%s(): invalid SMCR DRAC value 0%lo\n", + __FUNCTION__, FExtr(smcr, SMCR_DRAC)); + return -1; + } + + return 0; +} + +struct sa1111_save_data { + unsigned int skcr; + unsigned int skpcr; + unsigned int skcdr; + unsigned char skaud; + unsigned char skpwm0; + unsigned char skpwm1; + + /* + * Interrupt controller + */ + unsigned int intpol0; + unsigned int intpol1; + unsigned int inten0; + unsigned int inten1; + unsigned int wakepol0; + unsigned int wakepol1; + unsigned int wakeen0; + unsigned int wakeen1; +}; + +static int sa1111_suspend(struct device *dev, u32 state, u32 level) +{ + struct sa1111 *sachip = dev_get_drvdata(dev); + unsigned long flags; + char *base; + + /* + * Save state. + */ + if (level == SUSPEND_SAVE_STATE || + level == SUSPEND_DISABLE || + level == SUSPEND_POWER_DOWN) { + struct sa1111_save_data *save; + + if (!dev->saved_state) + dev->saved_state = kmalloc(sizeof(struct sa1111_save_data), GFP_KERNEL); + if (!dev->saved_state) + return -ENOMEM; + + save = (struct sa1111_save_data *)dev->saved_state; + + spin_lock_irqsave(&sachip->lock, flags); + base = sachip->base; + save->skcr = sa1111_readl(base + SA1111_SKCR); + save->skpcr = sa1111_readl(base + SA1111_SKPCR); + save->skcdr = sa1111_readl(base + SA1111_SKCDR); + save->skaud = sa1111_readl(base + SA1111_SKAUD); + save->skpwm0 = sa1111_readl(base + SA1111_SKPWM0); + save->skpwm1 = sa1111_readl(base + SA1111_SKPWM1); + + base = sachip->base + SA1111_INTC; + save->intpol0 = sa1111_readl(base + SA1111_INTPOL0); + save->intpol1 = sa1111_readl(base + SA1111_INTPOL1); + save->inten0 = sa1111_readl(base + SA1111_INTEN0); + save->inten1 = sa1111_readl(base + SA1111_INTEN1); + save->wakepol0 = sa1111_readl(base + SA1111_WAKEPOL0); + save->wakepol1 = sa1111_readl(base + SA1111_WAKEPOL1); + save->wakeen0 = sa1111_readl(base + SA1111_WAKEEN0); + save->wakeen1 = sa1111_readl(base + SA1111_WAKEEN1); + spin_unlock_irqrestore(&sachip->lock, flags); + } + + /* + * Disable. + */ + if (level == SUSPEND_DISABLE && state == 4) { + unsigned int val; + + spin_lock_irqsave(&sachip->lock, flags); + base = sachip->base; + + sa1111_writel(0, base + SA1111_SKPWM0); + sa1111_writel(0, base + SA1111_SKPWM1); + val = sa1111_readl(base + SA1111_SKCR); + sa1111_writel(val | SKCR_SLEEP, base + SA1111_SKCR); + + spin_unlock_irqrestore(&sachip->lock, flags); + } + + return 0; +} + +/* + * sa1111_resume - Restore the SA1111 device state. + * @dev: device to restore + * @level: resume level + * + * Restore the general state of the SA1111; clock control and + * interrupt controller. Other parts of the SA1111 must be + * restored by their respective drivers, and must be called + * via LDM after this function. + */ +static int sa1111_resume(struct device *dev, u32 level) +{ + struct sa1111 *sachip = dev_get_drvdata(dev); + struct sa1111_save_data *save; + unsigned long flags, id; + char *base; + + if (level != RESUME_RESTORE_STATE && level != RESUME_ENABLE) + return 0; + + save = (struct sa1111_save_data *)dev->saved_state; + if (!save) + return 0; + + dev->saved_state = NULL; + + /* + * Ensure that the SA1111 is still here. + */ + id = sa1111_readl(sachip->base + SA1111_SKID); + if ((id & SKID_ID_MASK) != SKID_SA1111_ID) { + __sa1111_remove(sachip); + dev_set_drvdata(dev, NULL); + kfree(save); + return 0; + } + + spin_lock_irqsave(&sachip->lock, flags); + sa1111_wake(sachip); + + base = sachip->base; + sa1111_writel(save->skcr, base + SA1111_SKCR); + sa1111_writel(save->skpcr, base + SA1111_SKPCR); + sa1111_writel(save->skcdr, base + SA1111_SKCDR); + sa1111_writel(save->skaud, base + SA1111_SKAUD); + sa1111_writel(save->skpwm0, base + SA1111_SKPWM0); + sa1111_writel(save->skpwm1, base + SA1111_SKPWM1); + + base = sachip->base + SA1111_INTC; + sa1111_writel(save->intpol0, base + SA1111_INTPOL0); + sa1111_writel(save->intpol1, base + SA1111_INTPOL1); + sa1111_writel(save->inten0, base + SA1111_INTEN0); + sa1111_writel(save->inten1, base + SA1111_INTEN1); + sa1111_writel(save->wakepol0, base + SA1111_WAKEPOL0); + sa1111_writel(save->wakepol1, base + SA1111_WAKEPOL1); + sa1111_writel(save->wakeen0, base + SA1111_WAKEEN0); + sa1111_writel(save->wakeen1, base + SA1111_WAKEEN1); + spin_unlock_irqrestore(&sachip->lock, flags); + + kfree(save); + + return 0; +} + +static int sa1111_probe(struct device *dev) +{ + return -ENODEV; +} + +static int sa1111_remove(struct device *dev) +{ + struct sa1111 *sachip = dev_get_drvdata(dev); + + if (sachip) { + __sa1111_remove(sachip); + dev_set_drvdata(dev, NULL); + + kfree(dev->saved_state); + dev->saved_state = NULL; + } + + return 0; +} + +/* + * Not sure if this should be on the system bus or not yet. + * We really want some way to register a system device at + * the per-machine level, and then have this driver pick + * up the registered devices. + * + * We also need to handle the SDRAM configuration for + * PXA250/SA1110 machine classes. + */ +static struct device_driver sa1111_device_driver = { + .name = "sa1111", + .bus = &system_bus_type, + .probe = sa1111_probe, + .remove = sa1111_remove, + .suspend = sa1111_suspend, + .resume = sa1111_resume, +}; + +/* + * Register the SA1111 driver with LDM. + */ +static int sa1111_driver_init(void) +{ + driver_register(&sa1111_device_driver); + return 0; +} + +arch_initcall(sa1111_driver_init); + +static struct sys_device sa1111_device = { + .name = "SA1111", + .id = 0, + .root = NULL, + .dev = { + .name = "Intel Corporation SA1111", + .driver = &sa1111_device_driver, + }, +}; + +int sa1111_init(unsigned long phys, unsigned int irq) +{ + int ret; + + snprintf(sa1111_device.dev.bus_id, sizeof(sa1111_device.dev.bus_id), "%8.8lx", phys); + + ret = sys_device_register(&sa1111_device); + if (ret) + printk("sa1111 device_register failed: %d\n", ret); + + return __sa1111_probe(&sa1111_device.dev, phys, irq); +} + +/* + * Get the parent device driver (us) structure + * from a child function device + */ +static inline struct sa1111 *sa1111_chip_driver(struct sa1111_dev *sadev) +{ + return (struct sa1111 *)dev_get_drvdata(sadev->dev.parent); +} + +/* + * The bits in the opdiv field are non-linear. + */ +static unsigned char opdiv_table[] = { 1, 4, 2, 8 }; + +static unsigned int __sa1111_pll_clock(struct sa1111 *sachip) +{ + unsigned int skcdr, fbdiv, ipdiv, opdiv; + + skcdr = sa1111_readl(sachip->base + SA1111_SKCDR); + + fbdiv = (skcdr & 0x007f) + 2; + ipdiv = ((skcdr & 0x0f80) >> 7) + 2; + opdiv = opdiv_table[(skcdr & 0x3000) >> 12]; + + return 3686400 * fbdiv / (ipdiv * opdiv); +} + +/** + * sa1111_pll_clock - return the current PLL clock frequency. + * @sadev: SA1111 function block + * + * BUG: we should look at SKCR. We also blindly believe that + * the chip is being fed with the 3.6864MHz clock. + * + * Returns the PLL clock in Hz. + */ +unsigned int sa1111_pll_clock(struct sa1111_dev *sadev) +{ + struct sa1111 *sachip = sa1111_chip_driver(sadev); + + return __sa1111_pll_clock(sachip); +} + +/** + * sa1111_select_audio_mode - select I2S or AC link mode + * @sadev: SA1111 function block + * @mode: One of %SA1111_AUDIO_ACLINK or %SA1111_AUDIO_I2S + * + * Frob the SKCR to select AC Link mode or I2S mode for + * the audio block. + */ +void sa1111_select_audio_mode(struct sa1111_dev *sadev, int mode) +{ + struct sa1111 *sachip = sa1111_chip_driver(sadev); + unsigned long flags; + unsigned int val; + + spin_lock_irqsave(&sachip->lock, flags); + + val = sa1111_readl(sachip->base + SA1111_SKCR); + if (mode == SA1111_AUDIO_I2S) { + val &= ~SKCR_SELAC; + } else { + val |= SKCR_SELAC; + } + sa1111_writel(val, sachip->base + SA1111_SKCR); + + spin_unlock_irqrestore(&sachip->lock, flags); +} + +/** + * sa1111_set_audio_rate - set the audio sample rate + * @sadev: SA1111 SAC function block + * @rate: sample rate to select + */ +int sa1111_set_audio_rate(struct sa1111_dev *sadev, int rate) +{ + struct sa1111 *sachip = sa1111_chip_driver(sadev); + unsigned int div; + + if (sadev->devid != SA1111_DEVID_SAC) + return -EINVAL; + + div = (__sa1111_pll_clock(sachip) / 256 + rate / 2) / rate; + if (div == 0) + div = 1; + if (div > 128) + div = 128; + + sa1111_writel(div - 1, sachip->base + SA1111_SKAUD); + + return 0; +} + +/** + * sa1111_get_audio_rate - get the audio sample rate + * @sadev: SA1111 SAC function block device + */ +int sa1111_get_audio_rate(struct sa1111_dev *sadev) +{ + struct sa1111 *sachip = sa1111_chip_driver(sadev); + unsigned long div; + + if (sadev->devid != SA1111_DEVID_SAC) + return -EINVAL; + + div = sa1111_readl(sachip->base + SA1111_SKAUD) + 1; + + return __sa1111_pll_clock(sachip) / (256 * div); +} + +/* + * Individual device operations. + */ + +/** + * sa1111_enable_device - enable an on-chip SA1111 function block + * @sadev: SA1111 function block device to enable + */ +void sa1111_enable_device(struct sa1111_dev *sadev) +{ + struct sa1111 *sachip = sa1111_chip_driver(sadev); + unsigned long flags; + unsigned int val; + + spin_lock_irqsave(&sachip->lock, flags); + val = sa1111_readl(sachip->base + SA1111_SKPCR); + sa1111_writel(val | sadev->skpcr_mask, sachip->base + SA1111_SKPCR); + spin_unlock_irqrestore(&sachip->lock, flags); +} + +/** + * sa1111_disable_device - disable an on-chip SA1111 function block + * @sadev: SA1111 function block device to disable + */ +void sa1111_disable_device(struct sa1111_dev *sadev) +{ + struct sa1111 *sachip = sa1111_chip_driver(sadev); + unsigned long flags; + unsigned int val; + + spin_lock_irqsave(&sachip->lock, flags); + val = sa1111_readl(sachip->base + SA1111_SKPCR); + sa1111_writel(val & ~sadev->skpcr_mask, sachip->base + SA1111_SKPCR); + spin_unlock_irqrestore(&sachip->lock, flags); +} + +/* + * SA1111 "Register Access Bus." + * + * We model this as a regular bus type, and hang devices directly + * off this. + */ +static int sa1111_match(struct device *_dev, struct device_driver *_drv) +{ + struct sa1111_dev *dev = SA1111_DEV(_dev); + struct sa1111_driver *drv = SA1111_DRV(_drv); + + return dev->devid == drv->devid; +} + +struct bus_type sa1111_bus_type = { + .name = "RAB", + .match = sa1111_match, +}; + +static int sa1111_rab_bus_init(void) +{ + return bus_register(&sa1111_bus_type); +} + +postcore_initcall(sa1111_rab_bus_init); + +EXPORT_SYMBOL(sa1111_check_dma_bug); +EXPORT_SYMBOL(sa1111_select_audio_mode); +EXPORT_SYMBOL(sa1111_set_audio_rate); +EXPORT_SYMBOL(sa1111_get_audio_rate); +EXPORT_SYMBOL(sa1111_enable_device); +EXPORT_SYMBOL(sa1111_disable_device); +EXPORT_SYMBOL(sa1111_pll_clock); +EXPORT_SYMBOL(sa1111_bus_type); diff --git a/arch/arm/common/via82c505.c b/arch/arm/common/via82c505.c new file mode 100644 index 000000000000..b9d97239734b --- /dev/null +++ b/arch/arm/common/via82c505.c @@ -0,0 +1,94 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#define MAX_SLOTS 7 + +#define CONFIG_CMD(bus, devfn, where) (0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3)) + +static int +via82c505_read_config(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 *value) +{ + outl(CONFIG_CMD(bus,devfn,where),0xCF8); + switch (size) { + case 1: + *value=inb(0xCFC + (where&3)); + break; + case 2: + *value=inw(0xCFC + (where&2)); + break; + case 4: + *value=inl(0xCFC); + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static int +via82c505_write_config(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 value) +{ + outl(CONFIG_CMD(bus,devfn,where),0xCF8); + switch (size) { + case 1: + outb(value, 0xCFC + (where&3)); + break; + case 2: + outw(value, 0xCFC + (where&2)); + break; + case 4: + outl(value, 0xCFC); + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops via82c505_ops = { + .read = via82c505_read_config, + .write = via82c505_write_config, +}; + +void __init via82c505_preinit(void *sysdata) +{ + printk(KERN_DEBUG "PCI: VIA 82c505\n"); + if (!request_region(0xA8,2,"via config")) { + printk(KERN_WARNING"VIA 82c505: Unable to request region 0xA8\n"); + return; + } + if (!request_region(0xCF8,8,"pci config")) { + printk(KERN_WARNING"VIA 82c505: Unable to request region 0xCF8\n"); + release_region(0xA8, 2); + return; + } + + /* Enable compatible Mode */ + outb(0x96,0xA8); + outb(0x18,0xA9); + outb(0x93,0xA8); + outb(0xd0,0xA9); + +} + +int __init via82c505_setup(int nr, struct pci_sys_data *sys) +{ + return (nr == 0); +} + +struct pci_bus * __init via82c505_scan_bus(int nr, struct pci_sys_data *sysdata) +{ + if (nr == 0) + return pci_scan_bus(0, &via82c505_ops, sysdata); + + return NULL; +} diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 9b80c08a9d57..fba9201d9204 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -26,8 +26,6 @@ obj-$(CONFIG_MODULES) += armksyms.o module.o obj-$(CONFIG_ARTHUR) += arthur.o obj-$(CONFIG_ISA_DMA) += dma-isa.o obj-$(CONFIG_PCI) += bios32.o -obj-$(CONFIG_PCI_HOST_PLX90X0) += plx90x0.o -obj-$(CONFIG_PCI_HOST_VIA82C505) += via82c505.o ifneq ($(MACHINE),ebsa110) obj-y += io.o diff --git a/arch/arm/kernel/plx90x0.c b/arch/arm/kernel/plx90x0.c deleted file mode 100644 index 60d7d3566af4..000000000000 --- a/arch/arm/kernel/plx90x0.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Driver for PLX Technology PCI9000-series host bridge. - * - * Copyright (C) 1997, 1998, 1999, 2000 FutureTV Labs Ltd - */ - -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include - -#include -#include -#include -#include -#include - -/* - * Since the following functions are all very similar, the common parts - * are pulled out into these macros. - */ - -#define PLX_CLEAR_CONFIG \ - __raw_writel(0, PLX_BASE + 0xac); \ - local_irq_restore(flags); } - -#define PLX_SET_CONFIG \ - { unsigned long flags; \ - local_irq_save(flags); \ - __raw_writel((1<<31 | (bus->number << 16) \ - | (devfn << 8) | (where & ~3) \ - | ((bus->number == 0)?0:1)), PLX_BASE + 0xac); \ - -#define PLX_CONFIG_WRITE(size) \ - PLX_SET_CONFIG \ - __raw_write##size(value, PCIO_BASE + (where & 3)); \ - if (__raw_readw(PLX_BASE + 0x6) & 0x2000) \ - __raw_writew(0x2000, PLX_BASE + 0x6); \ - PLX_CLEAR_CONFIG \ - return PCIBIOS_SUCCESSFUL; - -#define PLX_CONFIG_READ(size) \ - PLX_SET_CONFIG \ - *value = __raw_read##size(PCIO_BASE + (where & 3)); \ - if (__raw_readw(PLX_BASE + 0x6) & 0x2000) { \ - __raw_writew(0x2000, PLX_BASE + 0x6); \ - *value = 0xffffffffUL; \ - } \ - PLX_CLEAR_CONFIG \ - return PCIBIOS_SUCCESSFUL; - -/* Configuration space access routines */ - -static int -plx90x0_read_config (struct pci_bus *bus, unsigned int devfn, int where, - int where, int size, u32 *value) -{ - switch (size) { - case 1: - PLX_CONFIG_READ(b) - break; - case 2: - PLX_CONFIG_READ(w) - break; - case 4: - PLX_CONFIG_READ(l) - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static int -plx90x0_write_config (struct pci_bus *bus, unsigned int devfn, int where, - int where, int size, u32 value) -{ - switch (size) { - case 1: - PLX_CONFIG_WRITE(b) - break; - case 2: - PLX_CONFIG_WRITE(w) - break; - case 4: - PLX_CONFIG_WRITE(l) - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops plx90x0_ops = -{ - .read = plx90x0_read_config, - .write = plx90x0_write_config, -}; - -static void -plx_syserr_handler(int irq, void *handle, struct pt_regs *regs) -{ - printk("PLX90x0: machine check %04x (pc=%08lx)\n", - readw(PLX_BASE + 6), regs->ARM_pc); - __raw_writew(0xf000, PLX_BASE + 6); -} - -/* - * Initialise the PCI system. - */ - -void __init -plx90x0_init(struct arm_sysdata *sysdata) -{ - static const unsigned long int base = PLX_BASE; - char *what; - unsigned long bar = (unsigned long)virt_to_bus((void *)PAGE_OFFSET); - - /* Have a sniff around and see which PLX device is present. */ - unsigned long id = __raw_readl(base + 0xf0); - -#if 0 - /* This check was a good idea, but can fail. The PLX9060 puts no - default value in these registers unless NB# is asserted (which it - isn't on these cards). */ - if ((id & 0xffff) != PCI_VENDOR_ID_PLX) - return; /* Nothing found */ -#endif - - /* Found one - now work out what it is. */ - switch (id >> 16) { - case 0: /* PCI_DEVICE_ID_PLX_9060 */ - what = "PCI9060"; - break; - case PCI_DEVICE_ID_PLX_9060ES: - what = "PCI9060ES"; - break; - case PCI_DEVICE_ID_PLX_9060SD: - what = "PCI9060SD"; /* uhuhh.. */ - break; - case PCI_DEVICE_ID_PLX_9080: - what = "PCI9080"; - break; - default: - printk("PCI: Unknown PLX device %04lx found -- ignored.\n", - id >> 16); - return; - } - - printk("PCI: PLX Technology %s host bridge found.\n", what); - - /* Now set it up for both master and slave accesses. */ - __raw_writel(0xffff0147, base + 0x4); - __raw_writeb(32, base + 0xd); - __raw_writel(0x8 | bar, base + 0x18); - __raw_writel(0xf8000008, base + 0x80); - __raw_writel(0x40000001, base + 0x84); - __raw_writel(0, base + 0x88); - __raw_writel(0, base + 0x8c); - __raw_writel(0x11, base + 0x94); - __raw_writel(0xC3 + (4 << 28) - + (8 << 11) + (1 << 10) - + (1 << 24), base + 0x98); - __raw_writel(0xC0000000, base + 0x9c); - __raw_writel(PLX_MEM_START, base + 0xa0); - __raw_writel(PLX_IO_START, base + 0xa4); - __raw_writel(0x3, base + 0xa8); - __raw_writel(0, base + 0xac); - __raw_writel(0x10001, base + 0xe8); - __raw_writel(0x8000767e, base + 0xec); - - request_irq(IRQ_SYSERR, plx_syserr_handler, 0, - "system error", NULL); - - pci_scan_bus(0, &plx90x0_ops, sysdata); -} diff --git a/arch/arm/kernel/via82c505.c b/arch/arm/kernel/via82c505.c deleted file mode 100644 index b9d97239734b..000000000000 --- a/arch/arm/kernel/via82c505.c +++ /dev/null @@ -1,94 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#define MAX_SLOTS 7 - -#define CONFIG_CMD(bus, devfn, where) (0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3)) - -static int -via82c505_read_config(struct pci_bus *bus, unsigned int devfn, int where, - int size, u32 *value) -{ - outl(CONFIG_CMD(bus,devfn,where),0xCF8); - switch (size) { - case 1: - *value=inb(0xCFC + (where&3)); - break; - case 2: - *value=inw(0xCFC + (where&2)); - break; - case 4: - *value=inl(0xCFC); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static int -via82c505_write_config(struct pci_bus *bus, unsigned int devfn, int where, - int size, u32 value) -{ - outl(CONFIG_CMD(bus,devfn,where),0xCF8); - switch (size) { - case 1: - outb(value, 0xCFC + (where&3)); - break; - case 2: - outw(value, 0xCFC + (where&2)); - break; - case 4: - outl(value, 0xCFC); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops via82c505_ops = { - .read = via82c505_read_config, - .write = via82c505_write_config, -}; - -void __init via82c505_preinit(void *sysdata) -{ - printk(KERN_DEBUG "PCI: VIA 82c505\n"); - if (!request_region(0xA8,2,"via config")) { - printk(KERN_WARNING"VIA 82c505: Unable to request region 0xA8\n"); - return; - } - if (!request_region(0xCF8,8,"pci config")) { - printk(KERN_WARNING"VIA 82c505: Unable to request region 0xCF8\n"); - release_region(0xA8, 2); - return; - } - - /* Enable compatible Mode */ - outb(0x96,0xA8); - outb(0x18,0xA9); - outb(0x93,0xA8); - outb(0xd0,0xA9); - -} - -int __init via82c505_setup(int nr, struct pci_sys_data *sys) -{ - return (nr == 0); -} - -struct pci_bus * __init via82c505_scan_bus(int nr, struct pci_sys_data *sysdata) -{ - if (nr == 0) - return pci_scan_bus(0, &via82c505_ops, sysdata); - - return NULL; -} diff --git a/arch/arm/mach-sa1100/Makefile b/arch/arm/mach-sa1100/Makefile index 1426ab7ab335..5f60f1e88f4f 100644 --- a/arch/arm/mach-sa1100/Makefile +++ b/arch/arm/mach-sa1100/Makefile @@ -9,7 +9,7 @@ obj-n := obj- := led-y := leds.o -export-objs := dma.o generic.o pcipool.o pm.o sa1111.o sa1111-pcibuf.o +export-objs := dma.o generic.o pm.o # This needs to be cleaned up. We probably need to have SA1100 # and SA1110 config symbols. @@ -21,9 +21,6 @@ obj-$(CONFIG_SA1100_LART) += cpu-sa1100.o obj-$(CONFIG_SA1100_PT_SYSTEM3) += cpu-sa1110.o endif -# Next, the SA1111 stuff. -obj-$(CONFIG_SA1111) += sa1111.o sa1111-pcibuf.o pcipool.o - # Specific board support obj-$(CONFIG_SA1100_ADSBITSY) += adsbitsy.o led-$(CONFIG_SA1100_ADSBITSY) += leds-adsbitsy.o @@ -113,4 +110,4 @@ obj-$(CONFIG_LEDS) += $(led-y) #obj-$(CONFIG_SA1100_USB) += usb/ # Miscelaneous functions -obj-$(CONFIG_PM) += pm.o sleep.o +obj-$(CONFIG_PM) += pm.o sleep.o diff --git a/arch/arm/mach-sa1100/pcipool.c b/arch/arm/mach-sa1100/pcipool.c deleted file mode 100644 index 724afb8714ad..000000000000 --- a/arch/arm/mach-sa1100/pcipool.c +++ /dev/null @@ -1,390 +0,0 @@ -/* - NOTE: - - this code was lifted straight out of drivers/pci/pci.c; - when compiling for the Intel StrongARM SA-1110/SA-1111 the - usb-ohci.c driver needs these routines even when the architecture - has no pci bus... -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* - * Pool allocator ... wraps the pci_alloc_consistent page allocator, so - * small blocks are easily used by drivers for bus mastering controllers. - * This should probably be sharing the guts of the slab allocator. - */ - -struct pci_pool { /* the pool */ - struct list_head page_list; - spinlock_t lock; - size_t blocks_per_page; - size_t size; - struct pci_dev *dev; - size_t allocation; - char name [32]; - wait_queue_head_t waitq; -}; - -struct pci_page { /* cacheable header for 'allocation' bytes */ - struct list_head page_list; - void *vaddr; - dma_addr_t dma; - unsigned long bitmap [0]; -}; - -#define POOL_TIMEOUT_JIFFIES ((100 /* msec */ * HZ) / 1000) -#define POOL_POISON_BYTE 0xa7 - -// #define CONFIG_PCIPOOL_DEBUG - -static inline const char *slot_name(const struct pci_pool *pool) -{ - const struct pci_dev *pdev = pool->dev; - - if (pdev == 0) - return "[0]"; - - else if (pcidev_is_sa1111(pdev)) - return "[SA-1111]"; - else - return pdev->slot_name; -} - - -/** - * pci_pool_create - Creates a pool of pci consistent memory blocks, for dma. - * @name: name of pool, for diagnostics - * @pdev: pci device that will be doing the DMA - * @size: size of the blocks in this pool. - * @align: alignment requirement for blocks; must be a power of two - * @allocation: returned blocks won't cross this boundary (or zero) - * Context: !in_interrupt() - * - * Returns a pci allocation pool with the requested characteristics, or - * null if one can't be created. Given one of these pools, pci_pool_alloc() - * may be used to allocate memory. Such memory will all have "consistent" - * DMA mappings, accessible by the device and its driver without using - * cache flushing primitives. The actual size of blocks allocated may be - * larger than requested because of alignment. - * - * If allocation is nonzero, objects returned from pci_pool_alloc() won't - * cross that size boundary. This is useful for devices which have - * addressing restrictions on individual DMA transfers, such as not crossing - * boundaries of 4KBytes. - */ -struct pci_pool * -pci_pool_create (const char *name, struct pci_dev *pdev, - size_t size, size_t align, size_t allocation) -{ - struct pci_pool *retval; - - if (align == 0) - align = 1; - if (size == 0) - return 0; - else if (size < align) - size = align; - else if ((size % align) != 0) { - size += align + 1; - size &= ~(align - 1); - } - - if (allocation == 0) { - if (PAGE_SIZE < size) - allocation = size; - else - allocation = PAGE_SIZE; - // FIXME: round up for less fragmentation - } else if (allocation < size) - return 0; - - if (!(retval = kmalloc (sizeof *retval, SLAB_KERNEL))) - return retval; - - strncpy (retval->name, name, sizeof retval->name); - retval->name [sizeof retval->name - 1] = 0; - - retval->dev = pdev; - INIT_LIST_HEAD (&retval->page_list); - spin_lock_init (&retval->lock); - retval->size = size; - retval->allocation = allocation; - retval->blocks_per_page = allocation / size; - init_waitqueue_head (&retval->waitq); - -#ifdef CONFIG_PCIPOOL_DEBUG - printk (KERN_DEBUG "pcipool create %s/%s size %d, %d/page (%d alloc)\n", - slot_name(retval), retval->name, size, - retval->blocks_per_page, allocation); -#endif - - return retval; -} - - -static struct pci_page * -pool_alloc_page (struct pci_pool *pool, int mem_flags) -{ - struct pci_page *page; - int mapsize; - - mapsize = pool->blocks_per_page; - mapsize = (mapsize + BITS_PER_LONG - 1) / BITS_PER_LONG; - mapsize *= sizeof (long); - - page = (struct pci_page *) kmalloc (mapsize + sizeof *page, mem_flags); - if (!page) - return 0; - page->vaddr = pci_alloc_consistent (pool->dev, - pool->allocation, - &page->dma); - if (page->vaddr) { - memset (page->bitmap, 0xff, mapsize); // bit set == free -#ifdef CONFIG_DEBUG_SLAB - memset (page->vaddr, POOL_POISON_BYTE, pool->allocation); -#endif - list_add (&page->page_list, &pool->page_list); - } else { - kfree (page); - page = 0; - } - return page; -} - - -static inline int -is_page_busy (int blocks, unsigned long *bitmap) -{ - while (blocks > 0) { - if (*bitmap++ != ~0UL) - return 1; - blocks -= BITS_PER_LONG; - } - return 0; -} - -static void -pool_free_page (struct pci_pool *pool, struct pci_page *page) -{ - dma_addr_t dma = page->dma; - -#ifdef CONFIG_DEBUG_SLAB - memset (page->vaddr, POOL_POISON_BYTE, pool->allocation); -#endif - pci_free_consistent (pool->dev, pool->allocation, page->vaddr, dma); - list_del (&page->page_list); - kfree (page); -} - - -/** - * pci_pool_destroy - destroys a pool of pci memory blocks. - * @pool: pci pool that will be destroyed - * - * Caller guarantees that no more memory from the pool is in use, - * and that nothing will try to use the pool after this call. - */ -void -pci_pool_destroy (struct pci_pool *pool) -{ - unsigned long flags; - -#ifdef CONFIG_PCIPOOL_DEBUG - printk (KERN_DEBUG "pcipool destroy %s/%s\n", - slot_name(pool), pool->name); -#endif - - spin_lock_irqsave (&pool->lock, flags); - while (!list_empty (&pool->page_list)) { - struct pci_page *page; - page = list_entry (pool->page_list.next, - struct pci_page, page_list); - if (is_page_busy (pool->blocks_per_page, page->bitmap)) { - printk (KERN_ERR "pci_pool_destroy %s/%s, %p busy\n", - slot_name(pool), pool->name, page->vaddr); - /* leak the still-in-use consistent memory */ - list_del (&page->page_list); - kfree (page); - } else - pool_free_page (pool, page); - } - spin_unlock_irqrestore (&pool->lock, flags); - kfree (pool); -} - - -/** - * pci_pool_alloc - get a block of consistent memory - * @pool: pci pool that will produce the block - * @mem_flags: SLAB_KERNEL or SLAB_ATOMIC - * @handle: pointer to dma address of block - * - * This returns the kernel virtual address of a currently unused block, - * and reports its dma address through the handle. - * If such a memory block can't be allocated, null is returned. - */ -void * -pci_pool_alloc (struct pci_pool *pool, int mem_flags, dma_addr_t *handle) -{ - unsigned long flags; - struct list_head *entry; - struct pci_page *page; - int map, block; - size_t offset; - void *retval; - -restart: - spin_lock_irqsave (&pool->lock, flags); - list_for_each (entry, &pool->page_list) { - int i; - page = list_entry (entry, struct pci_page, page_list); - /* only cachable accesses here ... */ - for (map = 0, i = 0; - i < pool->blocks_per_page; - i += BITS_PER_LONG, map++) { - if (page->bitmap [map] == 0) - continue; - block = ffz (~ page->bitmap [map]); - if ((i + block) < pool->blocks_per_page) { - clear_bit (block, &page->bitmap [map]); - offset = (BITS_PER_LONG * map) + block; - offset *= pool->size; - goto ready; - } - } - } - if (!(page = pool_alloc_page (pool, mem_flags))) { - if (mem_flags == SLAB_KERNEL) { - DECLARE_WAITQUEUE (wait, current); - - current->state = TASK_INTERRUPTIBLE; - add_wait_queue (&pool->waitq, &wait); - spin_unlock_irqrestore (&pool->lock, flags); - - schedule_timeout (POOL_TIMEOUT_JIFFIES); - - current->state = TASK_RUNNING; - remove_wait_queue (&pool->waitq, &wait); - goto restart; - } - retval = 0; - goto done; - } - - clear_bit (0, &page->bitmap [0]); - offset = 0; -ready: - retval = offset + page->vaddr; - *handle = offset + page->dma; -done: - spin_unlock_irqrestore (&pool->lock, flags); - return retval; -} - - -static struct pci_page * -pool_find_page (struct pci_pool *pool, dma_addr_t dma) -{ - unsigned long flags; - struct list_head *entry; - struct pci_page *page; - - spin_lock_irqsave (&pool->lock, flags); - list_for_each (entry, &pool->page_list) { - page = list_entry (entry, struct pci_page, page_list); - if (dma < page->dma) - continue; - if (dma < (page->dma + pool->allocation)) - goto done; - } - page = 0; -done: - spin_unlock_irqrestore (&pool->lock, flags); - return page; -} - - -/** - * pci_pool_free - put block back into pci pool - * @pool: the pci pool holding the block - * @vaddr: virtual address of block - * @dma: dma address of block - * - * Caller promises neither device nor driver will again touch this block - * unless it is first re-allocated. - */ -void -pci_pool_free (struct pci_pool *pool, void *vaddr, dma_addr_t dma) -{ - struct pci_page *page; - unsigned long flags; - int map, block; - - if ((page = pool_find_page (pool, dma)) == 0) { - printk (KERN_ERR "pci_pool_free %s/%s, %p/%lx (bad dma)\n", - pool->dev ? pool->dev->slot_name : NULL, - pool->name, vaddr, (unsigned long) dma); - return; - } - - block = dma - page->dma; - block /= pool->size; - map = block / BITS_PER_LONG; - block %= BITS_PER_LONG; - -#ifdef CONFIG_DEBUG_SLAB - if (((dma - page->dma) + (void *)page->vaddr) != vaddr) { - printk (KERN_ERR "pci_pool_free %s/%s, %p (bad vaddr)/%lx\n", - pool->dev ? pool->dev->slot_name : NULL, - pool->name, vaddr, (unsigned long) dma); - return; - } - if (page->bitmap [map] & (1UL << block)) { - printk (KERN_ERR "pci_pool_free %s/%s, dma %x already free\n", - pool->dev ? pool->dev->slot_name : NULL, - pool->name, dma); - return; - } - memset (vaddr, POOL_POISON_BYTE, pool->size); -#endif - - spin_lock_irqsave (&pool->lock, flags); - set_bit (block, &page->bitmap [map]); - if (waitqueue_active (&pool->waitq)) - wake_up (&pool->waitq); - /* - * Resist a temptation to do - * if (!is_page_busy(bpp, page->bitmap)) pool_free_page(pool, page); - * it is not interrupt safe. Better have empty pages hang around. - */ - spin_unlock_irqrestore (&pool->lock, flags); -} - -EXPORT_SYMBOL (pci_pool_create); -EXPORT_SYMBOL (pci_pool_destroy); -EXPORT_SYMBOL (pci_pool_alloc); -EXPORT_SYMBOL (pci_pool_free); - -/* **************************************** */ - -static int __init pcipool_init(void) -{ - MOD_INC_USE_COUNT; /* never unload */ - - return 0; -} -module_init(pcipool_init); - -MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-sa1100/sa1111-pcibuf.c b/arch/arm/mach-sa1100/sa1111-pcibuf.c deleted file mode 100644 index 05acb901c3b5..000000000000 --- a/arch/arm/mach-sa1100/sa1111-pcibuf.c +++ /dev/null @@ -1,551 +0,0 @@ -/* - * linux/arch/arm/mach-sa1100/pci-sa1111.c - * - * Special pci_{map/unmap/dma_sync}_* routines for SA-1111. - * - * These functions utilize bouncer buffers to compensate for a bug in - * the SA-1111 hardware which don't allow DMA to/from addresses - * certain addresses above 1MB. - * - * Re-written by Christopher Hoover - * Original version by Brad Parker (brad@heeltoe.com) - * - * Copyright (C) 2002 Hewlett Packard Company. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * */ - -#include -#include -#include -#include -#include -#include - -//#define DEBUG -#ifdef DEBUG -#define DPRINTK(...) do { printk(KERN_DEBUG __VA_ARGS__); } while (0) -#else -#define DPRINTK(...) do { } while (0) -#endif - -//#define STATS -#ifdef STATS -#define DO_STATS(X) do { X ; } while (0) -#else -#define DO_STATS(X) do { } while (0) -#endif - -/* ************************************************** */ - -struct safe_buffer { - struct list_head node; - - /* original request */ - void *ptr; - size_t size; - int direction; - - /* safe buffer info */ - struct pci_pool *pool; - void *safe; - dma_addr_t safe_dma_addr; -}; - -LIST_HEAD(safe_buffers); - - -#define SIZE_SMALL 1024 -#define SIZE_LARGE (4*1024) - -static struct pci_pool *small_buffer_pool, *large_buffer_pool; - -#ifdef STATS -static unsigned long sbp_allocs __initdata = 0; -static unsigned long lbp_allocs __initdata = 0; -static unsigned long total_allocs __initdata= 0; - -static void print_alloc_stats(void) -{ - printk(KERN_INFO - "sa1111_pcibuf: sbp: %lu, lbp: %lu, other: %lu, total: %lu\n", - sbp_allocs, lbp_allocs, - total_allocs - sbp_allocs - lbp_allocs, total_allocs); -} -#endif - -static int __init -create_safe_buffer_pools(void) -{ - small_buffer_pool = pci_pool_create("sa1111_small_dma_buffer", - SA1111_FAKE_PCIDEV, - SIZE_SMALL, - 0 /* byte alignment */, - 0 /* no page-crossing issues */); - if (0 == small_buffer_pool) { - printk(KERN_ERR - "sa1111_pcibuf: could not allocate small pci pool\n"); - return -1; - } - - large_buffer_pool = pci_pool_create("sa1111_large_dma_buffer", - SA1111_FAKE_PCIDEV, - SIZE_LARGE, - 0 /* byte alignment */, - 0 /* no page-crossing issues */); - if (0 == large_buffer_pool) { - printk(KERN_ERR - "sa1111_pcibuf: could not allocate large pci pool\n"); - pci_pool_destroy(small_buffer_pool); - small_buffer_pool = 0; - return -1; - } - - printk(KERN_INFO - "sa1111_pcibuf: buffer sizes: small=%u, large=%u\n", - SIZE_SMALL, SIZE_LARGE); - - return 0; -} - -static void __exit -destroy_safe_buffer_pools(void) -{ - if (small_buffer_pool) - pci_pool_destroy(small_buffer_pool); - if (large_buffer_pool) - pci_pool_destroy(large_buffer_pool); - - small_buffer_pool = large_buffer_pool = 0; -} - - -/* allocate a 'safe' buffer and keep track of it */ -static struct safe_buffer * -alloc_safe_buffer(void *ptr, size_t size, int direction) -{ - struct safe_buffer *buf; - struct pci_pool *pool; - void *safe; - dma_addr_t safe_dma_addr; - - DPRINTK("%s(ptr=%p, size=%d, direction=%d)\n", - __func__, ptr, size, direction); - - DO_STATS ( total_allocs++ ); - - buf = kmalloc(sizeof(struct safe_buffer), GFP_ATOMIC); - if (buf == 0) { - printk(KERN_WARNING "%s: kmalloc failed\n", __func__); - return 0; - } - - if (size <= SIZE_SMALL) { - pool = small_buffer_pool; - safe = pci_pool_alloc(pool, GFP_ATOMIC, &safe_dma_addr); - - DO_STATS ( sbp_allocs++ ); - } else if (size <= SIZE_LARGE) { - pool = large_buffer_pool; - safe = pci_pool_alloc(pool, GFP_ATOMIC, &safe_dma_addr); - - DO_STATS ( lbp_allocs++ ); - } else { - pool = 0; - safe = pci_alloc_consistent(SA1111_FAKE_PCIDEV, size, - &safe_dma_addr); - } - - if (safe == 0) { - printk(KERN_WARNING - "%s: could not alloc dma memory (size=%d)\n", - __func__, size); - kfree(buf); - return 0; - } - -#ifdef STATS - if (total_allocs % 1000 == 0) - print_alloc_stats(); -#endif - - BUG_ON(sa1111_check_dma_bug(safe_dma_addr)); // paranoia - - buf->ptr = ptr; - buf->size = size; - buf->direction = direction; - buf->pool = pool; - buf->safe = safe; - buf->safe_dma_addr = safe_dma_addr; - - MOD_INC_USE_COUNT; - list_add(&buf->node, &safe_buffers); - - return buf; -} - -/* determine if a buffer is from our "safe" pool */ -static struct safe_buffer * -find_safe_buffer(dma_addr_t safe_dma_addr) -{ - struct list_head *entry; - - list_for_each(entry, &safe_buffers) { - struct safe_buffer *b = - list_entry(entry, struct safe_buffer, node); - - if (b->safe_dma_addr == safe_dma_addr) { - return b; - } - } - - return 0; -} - -static void -free_safe_buffer(struct safe_buffer *buf) -{ - DPRINTK("%s(buf=%p)\n", __func__, buf); - - list_del(&buf->node); - - if (buf->pool) - pci_pool_free(buf->pool, buf->safe, buf->safe_dma_addr); - else - pci_free_consistent(SA1111_FAKE_PCIDEV, buf->size, buf->safe, - buf->safe_dma_addr); - kfree(buf); - - MOD_DEC_USE_COUNT; -} - -static inline int -dma_range_is_safe(dma_addr_t addr, size_t size) -{ - unsigned int physaddr = SA1111_DMA_ADDR((unsigned int) addr); - - /* Any address within one megabyte of the start of the target - * bank will be OK. This is an overly conservative test: - * other addresses can be OK depending on the dram - * configuration. (See sa1111.c:sa1111_check_dma_bug() * for - * details.) - * - * We take care to ensure the entire dma region is within - * the safe range. - */ - - return ((physaddr + size - 1) < (1<<20)); -} - -/* ************************************************** */ - -#ifdef STATS -static unsigned long map_op_count __initdata = 0; -static unsigned long bounce_count __initdata = 0; - -static void print_map_stats(void) -{ - printk(KERN_INFO - "sa1111_pcibuf: map_op_count=%lu, bounce_count=%lu\n", - map_op_count, bounce_count); -} -#endif - -static dma_addr_t -map_single(void *ptr, size_t size, int direction) -{ - dma_addr_t dma_addr; - - DO_STATS ( map_op_count++ ); - - dma_addr = virt_to_bus(ptr); - - if (!dma_range_is_safe(dma_addr, size)) { - struct safe_buffer *buf; - - DO_STATS ( bounce_count++ ) ; - - buf = alloc_safe_buffer(ptr, size, direction); - if (buf == 0) { - printk(KERN_ERR - "%s: unable to map unsafe buffer %p!\n", - __func__, ptr); - return 0; - } - - DPRINTK("%s: unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n", - __func__, - buf->ptr, (void *) virt_to_bus(buf->ptr), - buf->safe, (void *) buf->safe_dma_addr); - - if ((direction == PCI_DMA_TODEVICE) || - (direction == PCI_DMA_BIDIRECTIONAL)) { - DPRINTK("%s: copy out from unsafe %p, to safe %p, size %d\n", - __func__, ptr, buf->safe, size); - memcpy(buf->safe, ptr, size); - } - consistent_sync(buf->safe, size, direction); - - dma_addr = buf->safe_dma_addr; - } else { - consistent_sync(ptr, size, direction); - } - -#ifdef STATS - if (map_op_count % 1000 == 0) - print_map_stats(); -#endif - - return dma_addr; -} - -static void -unmap_single(dma_addr_t dma_addr, size_t size, int direction) -{ - struct safe_buffer *buf; - - buf = find_safe_buffer(dma_addr); - - if (buf) { - BUG_ON(buf->size != size); - BUG_ON(buf->direction != direction); - - DPRINTK("%s: unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n", - __func__, - buf->ptr, (void *) virt_to_bus(buf->ptr), - buf->safe, (void *) buf->safe_dma_addr); - - - DO_STATS ( bounce_count++ ); - - if ((direction == PCI_DMA_FROMDEVICE) || - (direction == PCI_DMA_BIDIRECTIONAL)) { - DPRINTK("%s: copy back from safe %p, to unsafe %p size %d\n", - __func__, buf->safe, buf->ptr, size); - memcpy(buf->ptr, buf->safe, size); - } - free_safe_buffer(buf); - } -} - -static void -sync_single(dma_addr_t dma_addr, size_t size, int direction) -{ - struct safe_buffer *buf; - - buf = find_safe_buffer(dma_addr); - - if (buf) { - BUG_ON(buf->size != size); - BUG_ON(buf->direction != direction); - - DPRINTK("%s: unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n", - __func__, - buf->ptr, (void *) virt_to_bus(buf->ptr), - buf->safe, (void *) buf->safe_dma_addr); - - DO_STATS ( bounce_count++ ); - - switch (direction) { - case PCI_DMA_FROMDEVICE: - DPRINTK("%s: copy back from safe %p, to unsafe %p size %d\n", - __func__, buf->safe, buf->ptr, size); - memcpy(buf->ptr, buf->safe, size); - break; - case PCI_DMA_TODEVICE: - DPRINTK("%s: copy out from unsafe %p, to safe %p, size %d\n", - __func__,buf->ptr, buf->safe, size); - memcpy(buf->safe, buf->ptr, size); - break; - case PCI_DMA_BIDIRECTIONAL: - BUG(); /* is this allowed? what does it mean? */ - default: - BUG(); - } - consistent_sync(buf->safe, size, direction); - } else { - consistent_sync(bus_to_virt(dma_addr), size, direction); - } -} - -/* ************************************************** */ - -/* - * see if a buffer address is in an 'unsafe' range. if it is - * allocate a 'safe' buffer and copy the unsafe buffer into it. - * substitute the safe buffer for the unsafe one. - * (basically move the buffer from an unsafe area to a safe one) - */ -dma_addr_t -sa1111_map_single(void *ptr, size_t size, int direction) -{ - unsigned long flags; - dma_addr_t dma_addr; - - DPRINTK("%s(ptr=%p,size=%d,dir=%x)\n", - __func__, ptr, size, direction); - - BUG_ON(direction == PCI_DMA_NONE); - - local_irq_save(flags); - - dma_addr = map_single(ptr, size, direction); - - local_irq_restore(flags); - - return dma_addr; -} - -/* - * see if a mapped address was really a "safe" buffer and if so, copy - * the data from the safe buffer back to the unsafe buffer and free up - * the safe buffer. (basically return things back to the way they - * should be) - */ - -void -sa1111_unmap_single(dma_addr_t dma_addr, size_t size, int direction) -{ - unsigned long flags; - - DPRINTK("%s(ptr=%p,size=%d,dir=%x)\n", - __func__, (void *) dma_addr, size, direction); - - BUG_ON(direction == PCI_DMA_NONE); - - local_irq_save(flags); - - unmap_single(dma_addr, size, direction); - - local_irq_restore(flags); -} - -int -sa1111_map_sg(struct scatterlist *sg, int nents, int direction) -{ - unsigned long flags; - int i; - - DPRINTK("%s(sg=%p,nents=%d,dir=%x)\n", - __func__, sg, nents, direction); - - BUG_ON(direction == PCI_DMA_NONE); - - local_irq_save(flags); - - for (i = 0; i < nents; i++, sg++) { - struct page *page = sg->page; - unsigned int offset = sg->offset; - unsigned int length = sg->length; - void *ptr = page_address(page) + offset; - - sg->dma_address = - map_single(ptr, length, direction); - } - - local_irq_restore(flags); - - return nents; -} - -void -sa1111_unmap_sg(struct scatterlist *sg, int nents, int direction) -{ - unsigned long flags; - int i; - - DPRINTK("%s(sg=%p,nents=%d,dir=%x)\n", - __func__, sg, nents, direction); - - BUG_ON(direction == PCI_DMA_NONE); - - local_irq_save(flags); - - for (i = 0; i < nents; i++, sg++) { - dma_addr_t dma_addr = sg->dma_address; - unsigned int length = sg->length; - - unmap_single(dma_addr, length, direction); - } - - local_irq_restore(flags); -} - -void -sa1111_dma_sync_single(dma_addr_t dma_addr, size_t size, int direction) -{ - unsigned long flags; - - DPRINTK("%s(ptr=%p,size=%d,dir=%x)\n", - __func__, (void *) dma_addr, size, direction); - - local_irq_save(flags); - - sync_single(dma_addr, size, direction); - - local_irq_restore(flags); -} - -void -sa1111_dma_sync_sg(struct scatterlist *sg, int nents, int direction) -{ - unsigned long flags; - int i; - - DPRINTK("%s(sg=%p,nents=%d,dir=%x)\n", - __func__, sg, nents, direction); - - BUG_ON(direction == PCI_DMA_NONE); - - local_irq_save(flags); - - for (i = 0; i < nents; i++, sg++) { - dma_addr_t dma_addr = sg->dma_address; - unsigned int length = sg->length; - - sync_single(dma_addr, length, direction); - } - - local_irq_restore(flags); -} - -EXPORT_SYMBOL(sa1111_map_single); -EXPORT_SYMBOL(sa1111_unmap_single); -EXPORT_SYMBOL(sa1111_map_sg); -EXPORT_SYMBOL(sa1111_unmap_sg); -EXPORT_SYMBOL(sa1111_dma_sync_single); -EXPORT_SYMBOL(sa1111_dma_sync_sg); - -/* **************************************** */ - -static int __init sa1111_pcibuf_init(void) -{ - int ret; - - printk(KERN_DEBUG - "sa1111_pcibuf: initializing SA-1111 DMA workaround\n"); - - ret = create_safe_buffer_pools(); - - return ret; -} -module_init(sa1111_pcibuf_init); - -static void __exit sa1111_pcibuf_exit(void) -{ - BUG_ON(!list_empty(&safe_buffers)); - -#ifdef STATS - print_alloc_stats(); - print_map_stats(); -#endif - - destroy_safe_buffer_pools(); -} -module_exit(sa1111_pcibuf_exit); - -MODULE_AUTHOR("Christopher Hoover "); -MODULE_DESCRIPTION("Special pci_{map/unmap/dma_sync}_* routines for SA-1111."); -MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-sa1100/sa1111.c b/arch/arm/mach-sa1100/sa1111.c deleted file mode 100644 index 038101ed24a6..000000000000 --- a/arch/arm/mach-sa1100/sa1111.c +++ /dev/null @@ -1,1107 +0,0 @@ -/* - * linux/arch/arm/mach-sa1100/sa1111.c - * - * SA1111 support - * - * Original code by John Dorsey - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This file contains all generic SA1111 support. - * - * All initialization functions provided here are intended to be called - * from machine specific code with proper arguments when required. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -/* - * We keep the following data for the overall SA1111. Note that the - * struct device and struct resource are "fake"; they should be supplied - * by the bus above us. However, in the interests of getting all SA1111 - * drivers converted over to the device model, we provide this as an - * anchor point for all the other drivers. - */ -struct sa1111 { - struct device *dev; - struct resource res; - int irq; - spinlock_t lock; - void *base; -}; - -/* - * We _really_ need to eliminate this. Its only users - * are the PWM and DMA checking code. - */ -static struct sa1111 *g_sa1111; - -static struct sa1111_dev usb_dev = { - .dev = { - .name = "Intel Corporation SA1111 [USB Controller]", - }, - .skpcr_mask = SKPCR_UCLKEN, - .devid = SA1111_DEVID_USB, - .irq = { - IRQ_USBPWR, - IRQ_HCIM, - IRQ_HCIBUFFACC, - IRQ_HCIRMTWKP, - IRQ_NHCIMFCIR, - IRQ_USB_PORT_RESUME - }, -}; - -static struct sa1111_dev sac_dev = { - .dev = { - .name = "Intel Corporation SA1111 [Audio Controller]", - }, - .skpcr_mask = SKPCR_I2SCLKEN | SKPCR_L3CLKEN, - .devid = SA1111_DEVID_SAC, - .irq = { - AUDXMTDMADONEA, - AUDXMTDMADONEB, - AUDRCVDMADONEA, - AUDRCVDMADONEB - }, -}; - -static struct sa1111_dev ssp_dev = { - .dev = { - .name = "Intel Corporation SA1111 [SSP Controller]", - }, - .skpcr_mask = SKPCR_SCLKEN, - .devid = SA1111_DEVID_SSP, -}; - -static struct sa1111_dev kbd_dev = { - .dev = { - .name = "Intel Corporation SA1111 [PS2]", - }, - .skpcr_mask = SKPCR_PTCLKEN, - .devid = SA1111_DEVID_PS2, - .irq = { - IRQ_TPRXINT, - IRQ_TPTXINT - }, -}; - -static struct sa1111_dev mse_dev = { - .dev = { - .name = "Intel Corporation SA1111 [PS2]", - }, - .skpcr_mask = SKPCR_PMCLKEN, - .devid = SA1111_DEVID_PS2, - .irq = { - IRQ_MSRXINT, - IRQ_MSTXINT - }, -}; - -static struct sa1111_dev int_dev = { - .dev = { - .name = "Intel Corporation SA1111 [Interrupt Controller]", - }, - .skpcr_mask = 0, - .devid = SA1111_DEVID_INT, -}; - -static struct sa1111_dev pcmcia_dev = { - .dev = { - .name = "Intel Corporation SA1111 [PCMCIA Controller]", - }, - .skpcr_mask = 0, - .devid = SA1111_DEVID_PCMCIA, - .irq = { - IRQ_S0_READY_NINT, - IRQ_S0_CD_VALID, - IRQ_S0_BVD1_STSCHG, - IRQ_S1_READY_NINT, - IRQ_S1_CD_VALID, - IRQ_S1_BVD1_STSCHG, - }, -}; - -static struct sa1111_dev *devs[] = { - &usb_dev, - &sac_dev, - &ssp_dev, - &kbd_dev, - &mse_dev, - &pcmcia_dev, -}; - -static unsigned int dev_offset[] = { - SA1111_USB, - 0x0600, - 0x0800, - SA1111_KBD, - SA1111_MSE, - 0x1800, -}; - -/* - * SA1111 interrupt support. Since clearing an IRQ while there are - * active IRQs causes the interrupt output to pulse, the upper levels - * will call us again if there are more interrupts to process. - */ -static void -sa1111_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) -{ - unsigned int stat0, stat1, i; - - stat0 = INTSTATCLR0; - stat1 = INTSTATCLR1; - - INTSTATCLR0 = stat0; - - desc->chip->ack(irq); - - INTSTATCLR1 = stat1; - - if (stat0 == 0 && stat1 == 0) { - do_bad_IRQ(irq, desc, regs); - return; - } - - for (i = IRQ_SA1111_START; stat0; i++, stat0 >>= 1) - if (stat0 & 1) - do_edge_IRQ(i, irq_desc + i, regs); - - for (i = IRQ_SA1111_START + 32; stat1; i++, stat1 >>= 1) - if (stat1 & 1) - do_edge_IRQ(i, irq_desc + i, regs); - - /* For level-based interrupts */ - desc->chip->unmask(irq); -} - -#define SA1111_IRQMASK_LO(x) (1 << (x - IRQ_SA1111_START)) -#define SA1111_IRQMASK_HI(x) (1 << (x - IRQ_SA1111_START - 32)) - -static void sa1111_ack_irq(unsigned int irq) -{ -} - -static void sa1111_mask_lowirq(unsigned int irq) -{ - INTEN0 &= ~SA1111_IRQMASK_LO(irq); -} - -static void sa1111_unmask_lowirq(unsigned int irq) -{ - INTEN0 |= SA1111_IRQMASK_LO(irq); -} - -/* - * Attempt to re-trigger the interrupt. The SA1111 contains a register - * (INTSET) which claims to do this. However, in practice no amount of - * manipulation of INTEN and INTSET guarantees that the interrupt will - * be triggered. In fact, its very difficult, if not impossible to get - * INTSET to re-trigger the interrupt. - */ -static void sa1111_rerun_lowirq(unsigned int irq) -{ - unsigned int mask = SA1111_IRQMASK_LO(irq); - int i; - - for (i = 0; i < 8; i++) { - INTPOL0 ^= mask; - INTPOL0 ^= mask; - if (INTSTATCLR1 & mask) - break; - } - - if (i == 8) - printk(KERN_ERR "Danger Will Robinson: failed to " - "re-trigger IRQ%d\n", irq); -} - -static int sa1111_type_lowirq(unsigned int irq, unsigned int flags) -{ - unsigned int mask = SA1111_IRQMASK_LO(irq); - - if (flags == IRQT_PROBE) - return 0; - - if ((!(flags & __IRQT_RISEDGE) ^ !(flags & __IRQT_FALEDGE)) == 0) - return -EINVAL; - - if (flags & __IRQT_RISEDGE) - INTPOL0 &= ~mask; - else - INTPOL0 |= mask; - WAKE_POL0 = INTPOL0; - - return 0; -} - -static int sa1111_wake_lowirq(unsigned int irq, unsigned int on) -{ - unsigned int mask = SA1111_IRQMASK_LO(irq); - - if (on) - WAKE_EN0 |= mask; - else - WAKE_EN0 &= ~mask; - - return 0; -} - -static struct irqchip sa1111_low_chip = { - .ack = sa1111_ack_irq, - .mask = sa1111_mask_lowirq, - .unmask = sa1111_unmask_lowirq, - .rerun = sa1111_rerun_lowirq, - .type = sa1111_type_lowirq, - .wake = sa1111_wake_lowirq, -}; - -static void sa1111_mask_highirq(unsigned int irq) -{ - INTEN1 &= ~SA1111_IRQMASK_HI(irq); -} - -static void sa1111_unmask_highirq(unsigned int irq) -{ - INTEN1 |= SA1111_IRQMASK_HI(irq); -} - -/* - * Attempt to re-trigger the interrupt. The SA1111 contains a register - * (INTSET) which claims to do this. However, in practice no amount of - * manipulation of INTEN and INTSET guarantees that the interrupt will - * be triggered. In fact, its very difficult, if not impossible to get - * INTSET to re-trigger the interrupt. - */ -static void sa1111_rerun_highirq(unsigned int irq) -{ - unsigned int mask = SA1111_IRQMASK_HI(irq); - int i; - - for (i = 0; i < 8; i++) { - INTPOL1 ^= mask; - INTPOL1 ^= mask; - if (INTSTATCLR1 & mask) - break; - } - - if (i == 8) - printk(KERN_ERR "Danger Will Robinson: failed to " - "re-trigger IRQ%d\n", irq); -} - -static int sa1111_type_highirq(unsigned int irq, unsigned int flags) -{ - unsigned int mask = SA1111_IRQMASK_HI(irq); - - if (flags == IRQT_PROBE) - return 0; - - if ((!(flags & __IRQT_RISEDGE) ^ !(flags & __IRQT_FALEDGE)) == 0) - return -EINVAL; - - if (flags & __IRQT_RISEDGE) - INTPOL1 &= ~mask; - else - INTPOL1 |= mask; - WAKE_POL1 = INTPOL1; - - return 0; -} - -static int sa1111_wake_highirq(unsigned int irq, unsigned int on) -{ - unsigned int mask = SA1111_IRQMASK_HI(irq); - - if (on) - WAKE_EN1 |= mask; - else - WAKE_EN1 &= ~mask; - - return 0; -} - -static struct irqchip sa1111_high_chip = { - .ack = sa1111_ack_irq, - .mask = sa1111_mask_highirq, - .unmask = sa1111_unmask_highirq, - .rerun = sa1111_rerun_highirq, - .type = sa1111_type_highirq, - .wake = sa1111_wake_highirq, -}; - -static void __init sa1111_init_irq(struct sa1111_dev *sadev) -{ - unsigned int irq; - - /* - * We're guaranteed that this region hasn't been taken. - */ - request_mem_region(sadev->res.start, 512, "irqs"); - - /* disable all IRQs */ - sa1111_writel(0, sadev->mapbase + SA1111_INTEN0); - sa1111_writel(0, sadev->mapbase + SA1111_INTEN1); - sa1111_writel(0, sadev->mapbase + SA1111_WAKEEN0); - sa1111_writel(0, sadev->mapbase + SA1111_WAKEEN1); - - /* - * detect on rising edge. Note: Feb 2001 Errata for SA1111 - * specifies that S0ReadyInt and S1ReadyInt should be '1'. - */ - sa1111_writel(0, sadev->mapbase + SA1111_INTPOL0); - sa1111_writel(SA1111_IRQMASK_HI(IRQ_S0_READY_NINT) | - SA1111_IRQMASK_HI(IRQ_S1_READY_NINT), - sadev->mapbase + SA1111_INTPOL1); - - /* clear all IRQs */ - sa1111_writel(~0, sadev->mapbase + SA1111_INTSTATCLR0); - sa1111_writel(~0, sadev->mapbase + SA1111_INTSTATCLR1); - - for (irq = IRQ_GPAIN0; irq <= SSPROR; irq++) { - set_irq_chip(irq, &sa1111_low_chip); - set_irq_handler(irq, do_edge_IRQ); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); - } - - for (irq = AUDXMTDMADONEA; irq <= IRQ_S1_BVD1_STSCHG; irq++) { - set_irq_chip(irq, &sa1111_high_chip); - set_irq_handler(irq, do_edge_IRQ); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); - } - - /* - * Register SA1111 interrupt - */ - set_irq_type(sadev->irq[0], IRQT_RISING); - set_irq_chained_handler(sadev->irq[0], sa1111_irq_handler); -} - -/* - * Bring the SA1111 out of reset. This requires a set procedure: - * 1. nRESET asserted (by hardware) - * 2. CLK turned on from SA1110 - * 3. nRESET deasserted - * 4. VCO turned on, PLL_BYPASS turned off - * 5. Wait lock time, then assert RCLKEn - * 7. PCR set to allow clocking of individual functions - * - * Until we've done this, the only registers we can access are: - * SBI_SKCR - * SBI_SMCR - * SBI_SKID - */ -static void sa1111_wake(struct sa1111 *sachip) -{ - unsigned long flags, r; - - spin_lock_irqsave(&sachip->lock, flags); - - /* - * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111: - * (SA-1110 Developer's Manual, section 9.1.2.1) - */ - GAFR |= GPIO_32_768kHz; - GPDR |= GPIO_32_768kHz; - TUCR = TUCR_3_6864MHz; - - /* - * Turn VCO on, and disable PLL Bypass. - */ - r = sa1111_readl(sachip->base + SA1111_SKCR); - r &= ~SKCR_VCO_OFF; - sa1111_writel(r, sachip->base + SA1111_SKCR); - r |= SKCR_PLL_BYPASS | SKCR_OE_EN; - sa1111_writel(r, sachip->base + SA1111_SKCR); - - /* - * Wait lock time. SA1111 manual _doesn't_ - * specify a figure for this! We choose 100us. - */ - udelay(100); - - /* - * Enable RCLK. We also ensure that RDYEN is set. - */ - r |= SKCR_RCLKEN | SKCR_RDYEN; - sa1111_writel(r, sachip->base + SA1111_SKCR); - - /* - * Wait 14 RCLK cycles for the chip to finish coming out - * of reset. (RCLK=24MHz). This is 590ns. - */ - udelay(1); - - /* - * Ensure all clocks are initially off. - */ - sa1111_writel(0, sachip->base + SA1111_SKPCR); - - spin_unlock_irqrestore(&sachip->lock, flags); -} - -/* - * Configure the SA1111 shared memory controller. - */ -void -sa1111_configure_smc(struct sa1111 *sachip, int sdram, unsigned int drac, - unsigned int cas_latency) -{ - unsigned int smcr = SMCR_DTIM | SMCR_MBGE | FInsrt(drac, SMCR_DRAC); - - if (cas_latency == 3) - smcr |= SMCR_CLAT; - - sa1111_writel(smcr, sachip->base + SA1111_SMCR); -} - -static void -sa1111_init_one_child(struct sa1111 *sachip, struct sa1111_dev *sadev, unsigned int offset) -{ - snprintf(sadev->dev.bus_id, sizeof(sadev->dev.bus_id), - "%4.4x", offset); - - sadev->dev.parent = sachip->dev; - sadev->dev.bus = &sa1111_bus_type; - sadev->res.start = sachip->res.start + offset; - sadev->res.end = sadev->res.start + 511; - sadev->res.name = sadev->dev.name; - sadev->res.flags = IORESOURCE_MEM; - sadev->mapbase = sachip->base + offset; - - if (request_resource(&sachip->res, &sadev->res)) { - printk("SA1111: failed to allocate resource for %s\n", - sadev->res.name); - return; - } - - device_register(&sadev->dev); -} - -/** - * sa1111_probe - probe for a single SA1111 chip. - * @phys_addr: physical address of device. - * - * Probe for a SA1111 chip. This must be called - * before any other SA1111-specific code. - * - * Returns: - * %-ENODEV device not found. - * %-EBUSY physical address already marked in-use. - * %0 successful. - */ -static int __init -__sa1111_probe(struct device *me, unsigned long phys_addr, int irq) -{ - struct sa1111 *sachip; - unsigned long id; - unsigned int has_devs, val; - int i, ret = -ENODEV; - - sachip = kmalloc(sizeof(struct sa1111), GFP_KERNEL); - if (!sachip) - return -ENOMEM; - - memset(sachip, 0, sizeof(struct sa1111)); - - spin_lock_init(&sachip->lock); - - sachip->dev = me; - dev_set_drvdata(sachip->dev, sachip); - - sachip->res.name = me->name; - sachip->res.start = phys_addr; - sachip->res.end = phys_addr + 0x2000; - sachip->irq = irq; - - if (request_resource(&iomem_resource, &sachip->res)) { - ret = -EBUSY; - goto out; - } - - /* - * Map the whole region. This also maps the - * registers for our children. - */ - sachip->base = ioremap(phys_addr, PAGE_SIZE * 2); - if (!sachip->base) { - ret = -ENOMEM; - goto release; - } - - /* - * Probe for the chip. Only touch the SBI registers. - */ - id = sa1111_readl(sachip->base + SA1111_SKID); - if ((id & SKID_ID_MASK) != SKID_SA1111_ID) { - printk(KERN_DEBUG "SA1111 not detected: ID = %08lx\n", id); - ret = -ENODEV; - goto unmap; - } - - printk(KERN_INFO "SA1111 Microprocessor Companion Chip: " - "silicon revision %lx, metal revision %lx\n", - (id & SKID_SIREV_MASK)>>4, (id & SKID_MTREV_MASK)); - - /* - * We found it. Wake the chip up, and initialise. - */ - sa1111_wake(sachip); - - /* - * The SDRAM configuration of the SA1110 and the SA1111 must - * match. This is very important to ensure that SA1111 accesses - * don't corrupt the SDRAM. Note that this ungates the SA1111's - * MBGNT signal, so we must have called sa1110_mb_disable() - * beforehand. - */ - sa1111_configure_smc(sachip, 1, - FExtr(MDCNFG, MDCNFG_SA1110_DRAC0), - FExtr(MDCNFG, MDCNFG_SA1110_TDL0)); - - /* - * We only need to turn on DCLK whenever we want to use the - * DMA. It can otherwise be held firmly in the off position. - * (currently, we always enable it.) - */ - val = sa1111_readl(sachip->base + SA1111_SKPCR); - sa1111_writel(val | SKPCR_DCLKEN, sachip->base + SA1111_SKPCR); - - /* - * Enable the SA1110 memory bus request and grant signals. - */ - sa1110_mb_enable(); - - /* - * The interrupt controller must be initialised before any - * other device to ensure that the interrupts are available. - */ - int_dev.irq[0] = irq; - sa1111_init_one_child(sachip, &int_dev, SA1111_INTC); - sa1111_init_irq(&int_dev); - - g_sa1111 = sachip; - - has_devs = ~0; - if (machine_is_assabet() || machine_is_jornada720() || - machine_is_badge4()) - has_devs &= ~(1 << 4); - else - has_devs &= ~(1 << 1); - - for (i = 0; i < ARRAY_SIZE(devs); i++) - if (has_devs & (1 << i)) - sa1111_init_one_child(sachip, devs[i], dev_offset[i]); - - return 0; - - unmap: - iounmap(sachip->base); - release: - release_resource(&sachip->res); - out: - kfree(sachip); - return ret; -} - -static void __sa1111_remove(struct sa1111 *sachip) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(devs); i++) { - put_device(&devs[i]->dev); - release_resource(&devs[i]->res); - } - - iounmap(sachip->base); - release_resource(&sachip->res); - kfree(sachip); -} - -/* - * According to the "Intel StrongARM SA-1111 Microprocessor Companion - * Chip Specification Update" (June 2000), erratum #7, there is a - * significant bug in the SA1111 SDRAM shared memory controller. If - * an access to a region of memory above 1MB relative to the bank base, - * it is important that address bit 10 _NOT_ be asserted. Depending - * on the configuration of the RAM, bit 10 may correspond to one - * of several different (processor-relative) address bits. - * - * This routine only identifies whether or not a given DMA address - * is susceptible to the bug. - */ -int sa1111_check_dma_bug(dma_addr_t addr) -{ - struct sa1111 *sachip = g_sa1111; - unsigned int physaddr = SA1111_DMA_ADDR((unsigned int)addr); - unsigned int smcr; - - /* Section 4.6 of the "Intel StrongARM SA-1111 Development Module - * User's Guide" mentions that jumpers R51 and R52 control the - * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or - * SDRAM bank 1 on Neponset). The default configuration selects - * Assabet, so any address in bank 1 is necessarily invalid. - */ - if ((machine_is_assabet() || machine_is_pfs168()) && addr >= 0xc8000000) - return -1; - - /* The bug only applies to buffers located more than one megabyte - * above the start of the target bank: - */ - if (physaddr<(1<<20)) - return 0; - - smcr = sa1111_readl(sachip->base + SA1111_SMCR); - switch (FExtr(smcr, SMCR_DRAC)) { - case 01: /* 10 row + bank address bits, A<20> must not be set */ - if (physaddr & (1<<20)) - return -1; - break; - case 02: /* 11 row + bank address bits, A<23> must not be set */ - if (physaddr & (1<<23)) - return -1; - break; - case 03: /* 12 row + bank address bits, A<24> must not be set */ - if (physaddr & (1<<24)) - return -1; - break; - case 04: /* 13 row + bank address bits, A<25> must not be set */ - if (physaddr & (1<<25)) - return -1; - break; - case 05: /* 14 row + bank address bits, A<20> must not be set */ - if (physaddr & (1<<20)) - return -1; - break; - case 06: /* 15 row + bank address bits, A<20> must not be set */ - if (physaddr & (1<<20)) - return -1; - break; - default: - printk(KERN_ERR "%s(): invalid SMCR DRAC value 0%lo\n", - __FUNCTION__, FExtr(smcr, SMCR_DRAC)); - return -1; - } - - return 0; -} - -struct sa1111_save_data { - unsigned int skcr; - unsigned int skpcr; - unsigned int skcdr; - unsigned char skaud; - unsigned char skpwm0; - unsigned char skpwm1; - - /* - * Interrupt controller - */ - unsigned int intpol0; - unsigned int intpol1; - unsigned int inten0; - unsigned int inten1; - unsigned int wakepol0; - unsigned int wakepol1; - unsigned int wakeen0; - unsigned int wakeen1; -}; - -static int sa1111_suspend(struct device *dev, u32 state, u32 level) -{ - struct sa1111 *sachip = dev_get_drvdata(dev); - unsigned long flags; - char *base; - - /* - * Save state. - */ - if (level == SUSPEND_SAVE_STATE || - level == SUSPEND_DISABLE || - level == SUSPEND_POWER_DOWN) { - struct sa1111_save_data *save; - - if (!dev->saved_state) - dev->saved_state = kmalloc(sizeof(struct sa1111_save_data), GFP_KERNEL); - if (!dev->saved_state) - return -ENOMEM; - - save = (struct sa1111_save_data *)dev->saved_state; - - spin_lock_irqsave(&sachip->lock, flags); - base = sachip->base; - save->skcr = sa1111_readl(base + SA1111_SKCR); - save->skpcr = sa1111_readl(base + SA1111_SKPCR); - save->skcdr = sa1111_readl(base + SA1111_SKCDR); - save->skaud = sa1111_readl(base + SA1111_SKAUD); - save->skpwm0 = sa1111_readl(base + SA1111_SKPWM0); - save->skpwm1 = sa1111_readl(base + SA1111_SKPWM1); - - base = sachip->base + SA1111_INTC; - save->intpol0 = sa1111_readl(base + SA1111_INTPOL0); - save->intpol1 = sa1111_readl(base + SA1111_INTPOL1); - save->inten0 = sa1111_readl(base + SA1111_INTEN0); - save->inten1 = sa1111_readl(base + SA1111_INTEN1); - save->wakepol0 = sa1111_readl(base + SA1111_WAKEPOL0); - save->wakepol1 = sa1111_readl(base + SA1111_WAKEPOL1); - save->wakeen0 = sa1111_readl(base + SA1111_WAKEEN0); - save->wakeen1 = sa1111_readl(base + SA1111_WAKEEN1); - spin_unlock_irqrestore(&sachip->lock, flags); - } - - /* - * Disable. - */ - if (level == SUSPEND_DISABLE && state == 4) { - unsigned int val; - - spin_lock_irqsave(&sachip->lock, flags); - base = sachip->base; - - sa1111_writel(0, base + SA1111_SKPWM0); - sa1111_writel(0, base + SA1111_SKPWM1); - val = sa1111_readl(base + SA1111_SKCR); - sa1111_writel(val | SKCR_SLEEP, base + SA1111_SKCR); - - spin_unlock_irqrestore(&sachip->lock, flags); - } - - return 0; -} - -/* - * sa1111_resume - Restore the SA1111 device state. - * @dev: device to restore - * @level: resume level - * - * Restore the general state of the SA1111; clock control and - * interrupt controller. Other parts of the SA1111 must be - * restored by their respective drivers, and must be called - * via LDM after this function. - */ -static int sa1111_resume(struct device *dev, u32 level) -{ - struct sa1111 *sachip = dev_get_drvdata(dev); - struct sa1111_save_data *save; - unsigned long flags, id; - char *base; - - if (level != RESUME_RESTORE_STATE && level != RESUME_ENABLE) - return 0; - - save = (struct sa1111_save_data *)dev->saved_state; - if (!save) - return 0; - - dev->saved_state = NULL; - - /* - * Ensure that the SA1111 is still here. - */ - id = sa1111_readl(sachip->base + SA1111_SKID); - if ((id & SKID_ID_MASK) != SKID_SA1111_ID) { - __sa1111_remove(sachip); - dev_set_drvdata(dev, NULL); - kfree(save); - return 0; - } - - spin_lock_irqsave(&sachip->lock, flags); - sa1111_wake(sachip); - - base = sachip->base; - sa1111_writel(save->skcr, base + SA1111_SKCR); - sa1111_writel(save->skpcr, base + SA1111_SKPCR); - sa1111_writel(save->skcdr, base + SA1111_SKCDR); - sa1111_writel(save->skaud, base + SA1111_SKAUD); - sa1111_writel(save->skpwm0, base + SA1111_SKPWM0); - sa1111_writel(save->skpwm1, base + SA1111_SKPWM1); - - base = sachip->base + SA1111_INTC; - sa1111_writel(save->intpol0, base + SA1111_INTPOL0); - sa1111_writel(save->intpol1, base + SA1111_INTPOL1); - sa1111_writel(save->inten0, base + SA1111_INTEN0); - sa1111_writel(save->inten1, base + SA1111_INTEN1); - sa1111_writel(save->wakepol0, base + SA1111_WAKEPOL0); - sa1111_writel(save->wakepol1, base + SA1111_WAKEPOL1); - sa1111_writel(save->wakeen0, base + SA1111_WAKEEN0); - sa1111_writel(save->wakeen1, base + SA1111_WAKEEN1); - spin_unlock_irqrestore(&sachip->lock, flags); - - kfree(save); - - return 0; -} - -static int sa1111_probe(struct device *dev) -{ - return -ENODEV; -} - -static int sa1111_remove(struct device *dev) -{ - struct sa1111 *sachip = dev_get_drvdata(dev); - - if (sachip) { - __sa1111_remove(sachip); - dev_set_drvdata(dev, NULL); - - kfree(dev->saved_state); - dev->saved_state = NULL; - } - - return 0; -} - -/* - * Not sure if this should be on the system bus or not yet. - * We really want some way to register a system device at - * the per-machine level, and then have this driver pick - * up the registered devices. - * - * We also need to handle the SDRAM configuration for - * PXA250/SA1110 machine classes. - */ -static struct device_driver sa1111_device_driver = { - .name = "sa1111", - .bus = &system_bus_type, - .probe = sa1111_probe, - .remove = sa1111_remove, - .suspend = sa1111_suspend, - .resume = sa1111_resume, -}; - -/* - * Register the SA1111 driver with LDM. - */ -static int sa1111_driver_init(void) -{ - driver_register(&sa1111_device_driver); - return 0; -} - -arch_initcall(sa1111_driver_init); - -static struct sys_device sa1111_device = { - .name = "SA1111", - .id = 0, - .root = NULL, - .dev = { - .name = "Intel Corporation SA1111", - .driver = &sa1111_device_driver, - }, -}; - -int sa1111_init(unsigned long phys, unsigned int irq) -{ - int ret; - - snprintf(sa1111_device.dev.bus_id, sizeof(sa1111_device.dev.bus_id), "%8.8lx", phys); - - ret = sys_device_register(&sa1111_device); - if (ret) - printk("sa1111 device_register failed: %d\n", ret); - - return __sa1111_probe(&sa1111_device.dev, phys, irq); -} - -/* - * Get the parent device driver (us) structure - * from a child function device - */ -static inline struct sa1111 *sa1111_chip_driver(struct sa1111_dev *sadev) -{ - return (struct sa1111 *)dev_get_drvdata(sadev->dev.parent); -} - -/* - * The bits in the opdiv field are non-linear. - */ -static unsigned char opdiv_table[] = { 1, 4, 2, 8 }; - -static unsigned int __sa1111_pll_clock(struct sa1111 *sachip) -{ - unsigned int skcdr, fbdiv, ipdiv, opdiv; - - skcdr = sa1111_readl(sachip->base + SA1111_SKCDR); - - fbdiv = (skcdr & 0x007f) + 2; - ipdiv = ((skcdr & 0x0f80) >> 7) + 2; - opdiv = opdiv_table[(skcdr & 0x3000) >> 12]; - - return 3686400 * fbdiv / (ipdiv * opdiv); -} - -/** - * sa1111_pll_clock - return the current PLL clock frequency. - * @sadev: SA1111 function block - * - * BUG: we should look at SKCR. We also blindly believe that - * the chip is being fed with the 3.6864MHz clock. - * - * Returns the PLL clock in Hz. - */ -unsigned int sa1111_pll_clock(struct sa1111_dev *sadev) -{ - struct sa1111 *sachip = sa1111_chip_driver(sadev); - - return __sa1111_pll_clock(sachip); -} - -/** - * sa1111_select_audio_mode - select I2S or AC link mode - * @sadev: SA1111 function block - * @mode: One of %SA1111_AUDIO_ACLINK or %SA1111_AUDIO_I2S - * - * Frob the SKCR to select AC Link mode or I2S mode for - * the audio block. - */ -void sa1111_select_audio_mode(struct sa1111_dev *sadev, int mode) -{ - struct sa1111 *sachip = sa1111_chip_driver(sadev); - unsigned long flags; - unsigned int val; - - spin_lock_irqsave(&sachip->lock, flags); - - val = sa1111_readl(sachip->base + SA1111_SKCR); - if (mode == SA1111_AUDIO_I2S) { - val &= ~SKCR_SELAC; - } else { - val |= SKCR_SELAC; - } - sa1111_writel(val, sachip->base + SA1111_SKCR); - - spin_unlock_irqrestore(&sachip->lock, flags); -} - -/** - * sa1111_set_audio_rate - set the audio sample rate - * @sadev: SA1111 SAC function block - * @rate: sample rate to select - */ -int sa1111_set_audio_rate(struct sa1111_dev *sadev, int rate) -{ - struct sa1111 *sachip = sa1111_chip_driver(sadev); - unsigned int div; - - if (sadev->devid != SA1111_DEVID_SAC) - return -EINVAL; - - div = (__sa1111_pll_clock(sachip) / 256 + rate / 2) / rate; - if (div == 0) - div = 1; - if (div > 128) - div = 128; - - sa1111_writel(div - 1, sachip->base + SA1111_SKAUD); - - return 0; -} - -/** - * sa1111_get_audio_rate - get the audio sample rate - * @sadev: SA1111 SAC function block device - */ -int sa1111_get_audio_rate(struct sa1111_dev *sadev) -{ - struct sa1111 *sachip = sa1111_chip_driver(sadev); - unsigned long div; - - if (sadev->devid != SA1111_DEVID_SAC) - return -EINVAL; - - div = sa1111_readl(sachip->base + SA1111_SKAUD) + 1; - - return __sa1111_pll_clock(sachip) / (256 * div); -} - -/* - * Individual device operations. - */ - -/** - * sa1111_enable_device - enable an on-chip SA1111 function block - * @sadev: SA1111 function block device to enable - */ -void sa1111_enable_device(struct sa1111_dev *sadev) -{ - struct sa1111 *sachip = sa1111_chip_driver(sadev); - unsigned long flags; - unsigned int val; - - spin_lock_irqsave(&sachip->lock, flags); - val = sa1111_readl(sachip->base + SA1111_SKPCR); - sa1111_writel(val | sadev->skpcr_mask, sachip->base + SA1111_SKPCR); - spin_unlock_irqrestore(&sachip->lock, flags); -} - -/** - * sa1111_disable_device - disable an on-chip SA1111 function block - * @sadev: SA1111 function block device to disable - */ -void sa1111_disable_device(struct sa1111_dev *sadev) -{ - struct sa1111 *sachip = sa1111_chip_driver(sadev); - unsigned long flags; - unsigned int val; - - spin_lock_irqsave(&sachip->lock, flags); - val = sa1111_readl(sachip->base + SA1111_SKPCR); - sa1111_writel(val & ~sadev->skpcr_mask, sachip->base + SA1111_SKPCR); - spin_unlock_irqrestore(&sachip->lock, flags); -} - -/* - * SA1111 "Register Access Bus." - * - * We model this as a regular bus type, and hang devices directly - * off this. - */ -static int sa1111_match(struct device *_dev, struct device_driver *_drv) -{ - struct sa1111_dev *dev = SA1111_DEV(_dev); - struct sa1111_driver *drv = SA1111_DRV(_drv); - - return dev->devid == drv->devid; -} - -struct bus_type sa1111_bus_type = { - .name = "RAB", - .match = sa1111_match, -}; - -static int sa1111_rab_bus_init(void) -{ - return bus_register(&sa1111_bus_type); -} - -postcore_initcall(sa1111_rab_bus_init); - -EXPORT_SYMBOL(sa1111_check_dma_bug); -EXPORT_SYMBOL(sa1111_select_audio_mode); -EXPORT_SYMBOL(sa1111_set_audio_rate); -EXPORT_SYMBOL(sa1111_get_audio_rate); -EXPORT_SYMBOL(sa1111_enable_device); -EXPORT_SYMBOL(sa1111_disable_device); -EXPORT_SYMBOL(sa1111_pll_clock); -EXPORT_SYMBOL(sa1111_bus_type); -- cgit v1.2.3