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