1 /* 2 * tc-init: We assume the TURBOchannel to be up and running so 3 * just probe for Modules and fill in the global data structure 4 * tc_bus. 5 * 6 * This file is subject to the terms and conditions of the GNU General Public 7 * License. See the file "COPYING" in the main directory of this archive 8 * for more details. 9 * 10 * Copyright (c) Harald Koerfgen, 1998 11 * Copyright (c) 2001, 2003, 2005 Maciej W. Rozycki 12 */ 13 #include <linux/init.h> 14 #include <linux/kernel.h> 15 #include <linux/module.h> 16 #include <linux/string.h> 17 #include <linux/types.h> 18 19 #include <asm/addrspace.h> 20 #include <asm/bug.h> 21 #include <asm/errno.h> 22 #include <asm/io.h> 23 #include <asm/paccess.h> 24 25 #include <asm/dec/machtype.h> 26 #include <asm/dec/prom.h> 27 #include <asm/dec/tcinfo.h> 28 #include <asm/dec/tcmodule.h> 29 #include <asm/dec/interrupts.h> 30 31 MODULE_LICENSE("GPL"); 32 slot_info tc_bus[MAX_SLOT]; 33 static int num_tcslots; 34 static tcinfo *info; 35 36 /* 37 * Interface to the world. Read comment in include/asm-mips/tc.h. 38 */ 39 40 int search_tc_card(const char *name) 41 { 42 int slot; 43 slot_info *sip; 44 45 for (slot = 0; slot < num_tcslots; slot++) { 46 sip = &tc_bus[slot]; 47 if ((sip->flags & FREE) && 48 (strncmp(sip->name, name, strlen(name)) == 0)) { 49 return slot; 50 } 51 } 52 53 return -ENODEV; 54 } 55 56 void claim_tc_card(int slot) 57 { 58 if (tc_bus[slot].flags & IN_USE) { 59 printk("claim_tc_card: attempting to claim a card already in use\n"); 60 return; 61 } 62 tc_bus[slot].flags &= ~FREE; 63 tc_bus[slot].flags |= IN_USE; 64 } 65 66 void release_tc_card(int slot) 67 { 68 if (tc_bus[slot].flags & FREE) { 69 printk("release_tc_card: " 70 "attempting to release a card already free\n"); 71 return; 72 } 73 tc_bus[slot].flags &= ~IN_USE; 74 tc_bus[slot].flags |= FREE; 75 } 76 77 unsigned long get_tc_base_addr(int slot) 78 { 79 return tc_bus[slot].base_addr; 80 } 81 82 unsigned long get_tc_irq_nr(int slot) 83 { 84 return tc_bus[slot].interrupt; 85 } 86 87 unsigned long get_tc_speed(void) 88 { 89 return 100000 * (10000 / (unsigned long)info->clk_period); 90 } 91 92 /* 93 * Probing for TURBOchannel modules 94 */ 95 static void __init tc_probe(unsigned long startaddr, unsigned long size, 96 int slots) 97 { 98 unsigned long slotaddr; 99 int i, slot, err; 100 long offset; 101 u8 pattern[4]; 102 volatile u8 *module; 103 104 for (slot = 0; slot < slots; slot++) { 105 slotaddr = startaddr + slot * size; 106 module = ioremap_nocache(slotaddr, size); 107 BUG_ON(!module); 108 109 offset = OLDCARD; 110 111 err = 0; 112 err |= get_dbe(pattern[0], module + OLDCARD + TC_PATTERN0); 113 err |= get_dbe(pattern[1], module + OLDCARD + TC_PATTERN1); 114 err |= get_dbe(pattern[2], module + OLDCARD + TC_PATTERN2); 115 err |= get_dbe(pattern[3], module + OLDCARD + TC_PATTERN3); 116 if (err) { 117 iounmap(module); 118 continue; 119 } 120 121 if (pattern[0] != 0x55 || pattern[1] != 0x00 || 122 pattern[2] != 0xaa || pattern[3] != 0xff) { 123 offset = NEWCARD; 124 125 err = 0; 126 err |= get_dbe(pattern[0], module + TC_PATTERN0); 127 err |= get_dbe(pattern[1], module + TC_PATTERN1); 128 err |= get_dbe(pattern[2], module + TC_PATTERN2); 129 err |= get_dbe(pattern[3], module + TC_PATTERN3); 130 if (err) { 131 iounmap(module); 132 continue; 133 } 134 } 135 136 if (pattern[0] != 0x55 || pattern[1] != 0x00 || 137 pattern[2] != 0xaa || pattern[3] != 0xff) { 138 iounmap(module); 139 continue; 140 } 141 142 tc_bus[slot].base_addr = slotaddr; 143 for (i = 0; i < 8; i++) { 144 tc_bus[slot].firmware[i] = 145 module[TC_FIRM_VER + offset + 4 * i]; 146 tc_bus[slot].vendor[i] = 147 module[TC_VENDOR + offset + 4 * i]; 148 tc_bus[slot].name[i] = 149 module[TC_MODULE + offset + 4 * i]; 150 } 151 tc_bus[slot].firmware[8] = 0; 152 tc_bus[slot].vendor[8] = 0; 153 tc_bus[slot].name[8] = 0; 154 /* 155 * Looks unneccesary, but we may change 156 * TC? in the future 157 */ 158 switch (slot) { 159 case 0: 160 tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC0]; 161 break; 162 case 1: 163 tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC1]; 164 break; 165 case 2: 166 tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC2]; 167 break; 168 /* 169 * Yuck! DS5000/200 onboard devices 170 */ 171 case 5: 172 tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC5]; 173 break; 174 case 6: 175 tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC6]; 176 break; 177 default: 178 tc_bus[slot].interrupt = -1; 179 break; 180 } 181 182 iounmap(module); 183 } 184 } 185 186 /* 187 * the main entry 188 */ 189 static int __init tc_init(void) 190 { 191 int tc_clock; 192 int i; 193 unsigned long slot0addr; 194 unsigned long slot_size; 195 196 if (!TURBOCHANNEL) 197 return 0; 198 199 for (i = 0; i < MAX_SLOT; i++) { 200 tc_bus[i].base_addr = 0; 201 tc_bus[i].name[0] = 0; 202 tc_bus[i].vendor[0] = 0; 203 tc_bus[i].firmware[0] = 0; 204 tc_bus[i].interrupt = -1; 205 tc_bus[i].flags = FREE; 206 } 207 208 info = rex_gettcinfo(); 209 slot0addr = CPHYSADDR((long)rex_slot_address(0)); 210 211 switch (mips_machtype) { 212 case MACH_DS5000_200: 213 num_tcslots = 7; 214 break; 215 case MACH_DS5000_1XX: 216 case MACH_DS5000_2X0: 217 case MACH_DS5900: 218 num_tcslots = 3; 219 break; 220 case MACH_DS5000_XX: 221 default: 222 num_tcslots = 2; 223 break; 224 } 225 226 tc_clock = 10000 / info->clk_period; 227 228 if (info->slot_size && slot0addr) { 229 pr_info("TURBOchannel rev. %d at %d.%d MHz (with%s parity)\n", 230 info->revision, tc_clock / 10, tc_clock % 10, 231 info->parity ? "" : "out"); 232 233 slot_size = info->slot_size << 20; 234 235 tc_probe(slot0addr, slot_size, num_tcslots); 236 237 for (i = 0; i < num_tcslots; i++) { 238 if (!tc_bus[i].base_addr) 239 continue; 240 pr_info(" slot %d: %s %s %s\n", i, tc_bus[i].vendor, 241 tc_bus[i].name, tc_bus[i].firmware); 242 } 243 } 244 245 return 0; 246 } 247 248 subsys_initcall(tc_init); 249 250 EXPORT_SYMBOL(search_tc_card); 251 EXPORT_SYMBOL(claim_tc_card); 252 EXPORT_SYMBOL(release_tc_card); 253 EXPORT_SYMBOL(get_tc_base_addr); 254 EXPORT_SYMBOL(get_tc_irq_nr); 255 EXPORT_SYMBOL(get_tc_speed); 256