URL
https://opencores.org/ocsvn/or1k_old/or1k_old/trunk
Subversion Repositories or1k_old
[/] [or1k_old/] [trunk/] [uclinux/] [uClinux-2.0.x/] [arch/] [armnommu/] [drivers/] [block/] [ide-ics.c] - Rev 1782
Compare with Previous | Blame | View Log
/* * linux/arch/arm/drivers/block/ide-ics.c * * Copyright (c) 1996,1997 Russell King. * * Changelog: * 08-06-1996 RMK Created * 12-09-1997 RMK Added interrupt enable/disable */ #include <linux/module.h> #include <linux/malloc.h> #include <linux/blkdev.h> #include <linux/errno.h> #include <asm/dma.h> #include <asm/ecard.h> #include <asm/io.h> #include "ide.h" /* * Maximum number of interfaces per card */ #define MAX_IFS 2 #define ICS_IDENT_OFFSET 0x8a0 #define ICS_ARCIN_V5_INTRSTAT 0x000 #define ICS_ARCIN_V5_INTROFFSET 0x001 #define ICS_ARCIN_V5_IDEOFFSET 0xa00 #define ICS_ARCIN_V5_IDEALTOFFSET 0xae0 #define ICS_ARCIN_V5_IDESTEPPING 4 #define ICS_ARCIN_V6_IDEOFFSET_1 0x800 #define ICS_ARCIN_V6_INTROFFSET_1 0x880 #define ICS_ARCIN_V6_INTRSTAT_1 0x8a4 #define ICS_ARCIN_V6_IDEALTOFFSET_1 0x8e0 #define ICS_ARCIN_V6_IDEOFFSET_2 0xc00 #define ICS_ARCIN_V6_INTROFFSET_2 0xc80 #define ICS_ARCIN_V6_INTRSTAT_2 0xca4 #define ICS_ARCIN_V6_IDEALTOFFSET_2 0xce0 #define ICS_ARCIN_V6_IDESTEPPING 4 static const card_ids icside_cids[] = { { MANU_ICS, PROD_ICS_IDE }, { MANU_ICS2, PROD_ICS2_IDE }, { 0xffff, 0xffff } }; typedef enum { ics_if_unknown, ics_if_arcin_v5, ics_if_arcin_v6 } iftype_t; static struct expansion_card *ec[MAX_ECARDS]; static int result[MAX_ECARDS][MAX_IFS]; /* ---------------- Version 5 PCB Support Functions --------------------- */ /* Prototype: icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr) * Purpose : enable interrupts from card */ static void icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr) { unsigned int memc_port = (unsigned int)ec->irq_data; outb (0, memc_port + ICS_ARCIN_V5_INTROFFSET); } /* Prototype: icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr) * Purpose : disable interrupts from card */ static void icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr) { unsigned int memc_port = (unsigned int)ec->irq_data; inb (memc_port + ICS_ARCIN_V5_INTROFFSET); } static const expansioncard_ops_t icside_ops_arcin_v5 = { icside_irqenable_arcin_v5, icside_irqdisable_arcin_v5, NULL, NULL, NULL, NULL }; /* ---------------- Version 6 PCB Support Functions --------------------- */ /* Prototype: icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr) * Purpose : enable interrupts from card */ static void icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr) { unsigned int ide_base_port = (unsigned int)ec->irq_data; outb (0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_1); outb (0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_2); } /* Prototype: icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr) * Purpose : disable interrupts from card */ static void icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr) { unsigned int ide_base_port = (unsigned int)ec->irq_data; inb (ide_base_port + ICS_ARCIN_V6_INTROFFSET_1); inb (ide_base_port + ICS_ARCIN_V6_INTROFFSET_2); } /* Prototype: icside_irqprobe(struct expansion_card *ec) * Purpose : detect an active interrupt from card */ static int icside_irqprobe_arcin_v6(struct expansion_card *ec) { unsigned int ide_base_port = (unsigned int)ec->irq_data; return inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 || inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_2) & 1; } static const expansioncard_ops_t icside_ops_arcin_v6 = { icside_irqenable_arcin_v6, icside_irqdisable_arcin_v6, icside_irqprobe_arcin_v6, NULL, NULL, NULL }; /* Prototype: icside_identifyif (struct expansion_card *ec) * Purpose : identify IDE interface type * Notes : checks the description string */ static iftype_t icside_identifyif (struct expansion_card *ec) { unsigned int addr; iftype_t iftype; int id = 0; iftype = ics_if_unknown; addr = ecard_address (ec, ECARD_IOC, ECARD_FAST) + ICS_IDENT_OFFSET; id = inb (addr) & 1; id |= (inb (addr + 1) & 1) << 1; id |= (inb (addr + 2) & 1) << 2; id |= (inb (addr + 3) & 1) << 3; switch (id) { case 0: /* A3IN */ printk ("icside: A3IN unsupported\n"); break; case 1: /* A3USER */ printk ("icside: A3USER unsupported\n"); break; case 3: /* ARCIN V6 */ printk ("icside: detected ARCIN V6 in slot %d\n", ec->slot_no); iftype = ics_if_arcin_v6; break; case 15:/* ARCIN V5 (no id) */ printk ("icside: detected ARCIN V5 in slot %d\n", ec->slot_no); iftype = ics_if_arcin_v5; break; default:/* we don't know - complain very loudly */ printk ("icside: ***********************************\n"); printk ("icside: *** UNKNOWN ICS INTERFACE id=%d ***\n", id); printk ("icside: ***********************************\n"); printk ("icside: please report this to: linux@arm.linux.org.uk\n"); break; } return iftype; } /* Prototype: icside_register (struct expansion_card *ec) * Purpose : register an ICS IDE card with the IDE driver * Notes : we make sure that interrupts are disabled from the card */ static inline void icside_register (struct expansion_card *ec, int index) { unsigned long port = 0, latch; result[index][0] = -1; result[index][1] = -1; switch (icside_identifyif (ec)) { case ics_if_unknown: default: printk ("icside: *** Warning: ICS IDE Interface unrecognised! ***\n"); break; case ics_if_arcin_v5: port = ecard_address (ec, ECARD_MEMC, 0); ec->irqaddr = (unsigned char *)ioaddr(port + ICS_ARCIN_V5_INTRSTAT); ec->irqmask = 1; ec->irq_data = (void *)port; ec->ops = (expansioncard_ops_t *)&icside_ops_arcin_v5; /* * Be on the safe side - disable interrupts */ inb (port + ICS_ARCIN_V5_INTROFFSET); result[index][0] = ide_register_port(port + ICS_ARCIN_V5_IDEOFFSET, port + ICS_ARCIN_V5_IDEALTOFFSET, ICS_ARCIN_V5_IDESTEPPING, ec->irq); break; case ics_if_arcin_v6: latch = ecard_address (ec, ECARD_IOC, ECARD_FAST); if (ec->dma == NO_DMA) port = ecard_address (ec, ECARD_EASI, ECARD_FAST); if (port) outb(0x20, latch); else { port = latch; outb(0, port); } ec->irq_data = (void *)port; ec->ops = (expansioncard_ops_t *)&icside_ops_arcin_v6; /* * Be on the safe side - disable interrupts */ inb (port + ICS_ARCIN_V6_INTROFFSET_1); inb (port + ICS_ARCIN_V6_INTROFFSET_2); result[index][0] = ide_register_port(port + ICS_ARCIN_V6_IDEOFFSET_1, port + ICS_ARCIN_V6_IDEALTOFFSET_1, ICS_ARCIN_V6_IDESTEPPING, ec->irq); result[index][1] = ide_register_port(port + ICS_ARCIN_V6_IDEOFFSET_2, port + ICS_ARCIN_V6_IDEALTOFFSET_2, ICS_ARCIN_V6_IDESTEPPING, ec->irq); break; } } int icside_init (void) { int i; for (i = 0; i < MAX_ECARDS; i++) ec[i] = NULL; ecard_startfind (); for (i = 0; ; i++) { if ((ec[i] = ecard_find (0, icside_cids)) == NULL) break; ecard_claim (ec[i]); icside_register (ec[i], i); } for (i = 0; i < MAX_ECARDS; i++) if (ec[i] && result[i][0] < 0 && result[i][1] < 0) { ecard_release (ec[i]); ec[i] = NULL; } return 0; } #ifdef MODULE int init_module (void) { return icside_init(); } void cleanup_module (void) { int i; for (i = 0; i < MAX_ECARDS; i++) if (ec[i]) { if (result[i][0] >= 0) ide_unregister (result[i][0]); if (result[i][1] >= 0) ide_unregister (result[i][1]); ecard_release (ec[i]); ec[i] = NULL; } } #endif