xref: /openbmc/linux/drivers/tc/tc.c (revision 778220f7)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * tc-init: We assume the TURBOchannel to be up and running so
31da177e4SLinus Torvalds  * just probe for Modules and fill in the global data structure
41da177e4SLinus Torvalds  * tc_bus.
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * This file is subject to the terms and conditions of the GNU General Public
71da177e4SLinus Torvalds  * License.  See the file "COPYING" in the main directory of this archive
81da177e4SLinus Torvalds  * for more details.
91da177e4SLinus Torvalds  *
101da177e4SLinus Torvalds  * Copyright (c) Harald Koerfgen, 1998
11778220f7SMaciej W. Rozycki  * Copyright (c) 2001, 2003, 2005  Maciej W. Rozycki
121da177e4SLinus Torvalds  */
131da177e4SLinus Torvalds #include <linux/string.h>
141da177e4SLinus Torvalds #include <linux/init.h>
151da177e4SLinus Torvalds #include <linux/ioport.h>
161da177e4SLinus Torvalds #include <linux/kernel.h>
171da177e4SLinus Torvalds #include <linux/module.h>
181da177e4SLinus Torvalds 
191da177e4SLinus Torvalds #include <asm/addrspace.h>
201da177e4SLinus Torvalds #include <asm/errno.h>
211da177e4SLinus Torvalds #include <asm/dec/machtype.h>
221da177e4SLinus Torvalds #include <asm/dec/prom.h>
231da177e4SLinus Torvalds #include <asm/dec/tcinfo.h>
241da177e4SLinus Torvalds #include <asm/dec/tcmodule.h>
251da177e4SLinus Torvalds #include <asm/dec/interrupts.h>
261da177e4SLinus Torvalds #include <asm/paccess.h>
271da177e4SLinus Torvalds #include <asm/ptrace.h>
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds #define TC_DEBUG
301da177e4SLinus Torvalds 
311da177e4SLinus Torvalds MODULE_LICENSE("GPL");
321da177e4SLinus Torvalds slot_info tc_bus[MAX_SLOT];
331da177e4SLinus Torvalds static int num_tcslots;
341da177e4SLinus Torvalds static tcinfo *info;
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds unsigned long system_base;
371da177e4SLinus Torvalds 
381da177e4SLinus Torvalds /*
391da177e4SLinus Torvalds  * Interface to the world. Read comment in include/asm-mips/tc.h.
401da177e4SLinus Torvalds  */
411da177e4SLinus Torvalds 
421da177e4SLinus Torvalds int search_tc_card(const char *name)
431da177e4SLinus Torvalds {
441da177e4SLinus Torvalds 	int slot;
451da177e4SLinus Torvalds 	slot_info *sip;
461da177e4SLinus Torvalds 
471da177e4SLinus Torvalds 	for (slot = 0; slot < num_tcslots; slot++) {
481da177e4SLinus Torvalds 		sip = &tc_bus[slot];
491da177e4SLinus Torvalds 		if ((sip->flags & FREE) &&
501da177e4SLinus Torvalds 		    (strncmp(sip->name, name, strlen(name)) == 0)) {
511da177e4SLinus Torvalds 			return slot;
521da177e4SLinus Torvalds 		}
531da177e4SLinus Torvalds 	}
541da177e4SLinus Torvalds 
551da177e4SLinus Torvalds 	return -ENODEV;
561da177e4SLinus Torvalds }
571da177e4SLinus Torvalds 
581da177e4SLinus Torvalds void claim_tc_card(int slot)
591da177e4SLinus Torvalds {
601da177e4SLinus Torvalds 	if (tc_bus[slot].flags & IN_USE) {
611da177e4SLinus Torvalds 		printk("claim_tc_card: attempting to claim a card already in use\n");
621da177e4SLinus Torvalds 		return;
631da177e4SLinus Torvalds 	}
641da177e4SLinus Torvalds 	tc_bus[slot].flags &= ~FREE;
651da177e4SLinus Torvalds 	tc_bus[slot].flags |= IN_USE;
661da177e4SLinus Torvalds }
671da177e4SLinus Torvalds 
681da177e4SLinus Torvalds void release_tc_card(int slot)
691da177e4SLinus Torvalds {
701da177e4SLinus Torvalds 	if (tc_bus[slot].flags & FREE) {
711da177e4SLinus Torvalds 		printk("release_tc_card: "
721da177e4SLinus Torvalds 		       "attempting to release a card already free\n");
731da177e4SLinus Torvalds 		return;
741da177e4SLinus Torvalds 	}
751da177e4SLinus Torvalds 	tc_bus[slot].flags &= ~IN_USE;
761da177e4SLinus Torvalds 	tc_bus[slot].flags |= FREE;
771da177e4SLinus Torvalds }
781da177e4SLinus Torvalds 
791da177e4SLinus Torvalds unsigned long get_tc_base_addr(int slot)
801da177e4SLinus Torvalds {
811da177e4SLinus Torvalds 	return tc_bus[slot].base_addr;
821da177e4SLinus Torvalds }
831da177e4SLinus Torvalds 
841da177e4SLinus Torvalds unsigned long get_tc_irq_nr(int slot)
851da177e4SLinus Torvalds {
861da177e4SLinus Torvalds 	return tc_bus[slot].interrupt;
871da177e4SLinus Torvalds }
881da177e4SLinus Torvalds 
891da177e4SLinus Torvalds unsigned long get_tc_speed(void)
901da177e4SLinus Torvalds {
911da177e4SLinus Torvalds 	return 100000 * (10000 / (unsigned long)info->clk_period);
921da177e4SLinus Torvalds }
931da177e4SLinus Torvalds 
941da177e4SLinus Torvalds /*
951da177e4SLinus Torvalds  * Probing for TURBOchannel modules
961da177e4SLinus Torvalds  */
971da177e4SLinus Torvalds static void __init tc_probe(unsigned long startaddr, unsigned long size,
981da177e4SLinus Torvalds 			    int slots)
991da177e4SLinus Torvalds {
1001da177e4SLinus Torvalds 	int i, slot, err;
1011da177e4SLinus Torvalds 	long offset;
1021da177e4SLinus Torvalds 	unsigned char pattern[4];
1031da177e4SLinus Torvalds 	unsigned char *module;
1041da177e4SLinus Torvalds 
1051da177e4SLinus Torvalds 	for (slot = 0; slot < slots; slot++) {
1061da177e4SLinus Torvalds 		module = (char *)(startaddr + slot * size);
1071da177e4SLinus Torvalds 
1081da177e4SLinus Torvalds 		offset = OLDCARD;
1091da177e4SLinus Torvalds 
1101da177e4SLinus Torvalds 		err = 0;
1111da177e4SLinus Torvalds 		err |= get_dbe(pattern[0], module + OLDCARD + TC_PATTERN0);
1121da177e4SLinus Torvalds 		err |= get_dbe(pattern[1], module + OLDCARD + TC_PATTERN1);
1131da177e4SLinus Torvalds 		err |= get_dbe(pattern[2], module + OLDCARD + TC_PATTERN2);
1141da177e4SLinus Torvalds 		err |= get_dbe(pattern[3], module + OLDCARD + TC_PATTERN3);
1151da177e4SLinus Torvalds 		if (err)
1161da177e4SLinus Torvalds 			continue;
1171da177e4SLinus Torvalds 
1181da177e4SLinus Torvalds 		if (pattern[0] != 0x55 || pattern[1] != 0x00 ||
1191da177e4SLinus Torvalds 		    pattern[2] != 0xaa || pattern[3] != 0xff) {
1201da177e4SLinus Torvalds 			offset = NEWCARD;
1211da177e4SLinus Torvalds 
1221da177e4SLinus Torvalds 			err = 0;
1231da177e4SLinus Torvalds 			err |= get_dbe(pattern[0], module + TC_PATTERN0);
1241da177e4SLinus Torvalds 			err |= get_dbe(pattern[1], module + TC_PATTERN1);
1251da177e4SLinus Torvalds 			err |= get_dbe(pattern[2], module + TC_PATTERN2);
1261da177e4SLinus Torvalds 			err |= get_dbe(pattern[3], module + TC_PATTERN3);
1271da177e4SLinus Torvalds 			if (err)
1281da177e4SLinus Torvalds 				continue;
1291da177e4SLinus Torvalds 		}
1301da177e4SLinus Torvalds 
1311da177e4SLinus Torvalds 		if (pattern[0] != 0x55 || pattern[1] != 0x00 ||
1321da177e4SLinus Torvalds 		    pattern[2] != 0xaa || pattern[3] != 0xff)
1331da177e4SLinus Torvalds 			continue;
1341da177e4SLinus Torvalds 
1351da177e4SLinus Torvalds 		tc_bus[slot].base_addr = (unsigned long)module;
1361da177e4SLinus Torvalds 		for(i = 0; i < 8; i++) {
1371da177e4SLinus Torvalds 			tc_bus[slot].firmware[i] =
1381da177e4SLinus Torvalds 				module[TC_FIRM_VER + offset + 4 * i];
1391da177e4SLinus Torvalds 			tc_bus[slot].vendor[i] =
1401da177e4SLinus Torvalds 				module[TC_VENDOR + offset + 4 * i];
1411da177e4SLinus Torvalds 			tc_bus[slot].name[i] =
1421da177e4SLinus Torvalds 				module[TC_MODULE + offset + 4 * i];
1431da177e4SLinus Torvalds 		}
1441da177e4SLinus Torvalds 		tc_bus[slot].firmware[8] = 0;
1451da177e4SLinus Torvalds 		tc_bus[slot].vendor[8] = 0;
1461da177e4SLinus Torvalds 		tc_bus[slot].name[8] = 0;
1471da177e4SLinus Torvalds 		/*
1481da177e4SLinus Torvalds 		 * Looks unneccesary, but we may change
1491da177e4SLinus Torvalds 		 * TC? in the future
1501da177e4SLinus Torvalds 		 */
1511da177e4SLinus Torvalds 		switch (slot) {
1521da177e4SLinus Torvalds 		case 0:
1531da177e4SLinus Torvalds 			tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC0];
1541da177e4SLinus Torvalds 			break;
1551da177e4SLinus Torvalds 		case 1:
1561da177e4SLinus Torvalds 			tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC1];
1571da177e4SLinus Torvalds 			break;
1581da177e4SLinus Torvalds 		case 2:
1591da177e4SLinus Torvalds 			tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC2];
1601da177e4SLinus Torvalds 			break;
1611da177e4SLinus Torvalds 		/*
1621da177e4SLinus Torvalds 		 * Yuck! DS5000/200 onboard devices
1631da177e4SLinus Torvalds 		 */
1641da177e4SLinus Torvalds 		case 5:
1651da177e4SLinus Torvalds 			tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC5];
1661da177e4SLinus Torvalds 			break;
1671da177e4SLinus Torvalds 		case 6:
1681da177e4SLinus Torvalds 			tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC6];
1691da177e4SLinus Torvalds 			break;
1701da177e4SLinus Torvalds 		default:
1711da177e4SLinus Torvalds 			tc_bus[slot].interrupt = -1;
1721da177e4SLinus Torvalds 			break;
1731da177e4SLinus Torvalds 		}
1741da177e4SLinus Torvalds 	}
1751da177e4SLinus Torvalds }
1761da177e4SLinus Torvalds 
1771da177e4SLinus Torvalds /*
1781da177e4SLinus Torvalds  * the main entry
1791da177e4SLinus Torvalds  */
180778220f7SMaciej W. Rozycki static int __init tc_init(void)
1811da177e4SLinus Torvalds {
1821da177e4SLinus Torvalds 	int tc_clock;
1831da177e4SLinus Torvalds 	int i;
1841da177e4SLinus Torvalds 	unsigned long slot0addr;
1851da177e4SLinus Torvalds 	unsigned long slot_size;
1861da177e4SLinus Torvalds 
1871da177e4SLinus Torvalds 	if (!TURBOCHANNEL)
188778220f7SMaciej W. Rozycki 		return 0;
1891da177e4SLinus Torvalds 
1901da177e4SLinus Torvalds 	for (i = 0; i < MAX_SLOT; i++) {
1911da177e4SLinus Torvalds 		tc_bus[i].base_addr = 0;
1921da177e4SLinus Torvalds 		tc_bus[i].name[0] = 0;
1931da177e4SLinus Torvalds 		tc_bus[i].vendor[0] = 0;
1941da177e4SLinus Torvalds 		tc_bus[i].firmware[0] = 0;
1951da177e4SLinus Torvalds 		tc_bus[i].interrupt = -1;
1961da177e4SLinus Torvalds 		tc_bus[i].flags = FREE;
1971da177e4SLinus Torvalds 	}
1981da177e4SLinus Torvalds 
1991da177e4SLinus Torvalds 	info = (tcinfo *) rex_gettcinfo();
2003bd4c902SMaciej W. Rozycki 	slot0addr = (unsigned long)CKSEG1ADDR(rex_slot_address(0));
2011da177e4SLinus Torvalds 
2021da177e4SLinus Torvalds 	switch (mips_machtype) {
2031da177e4SLinus Torvalds 	case MACH_DS5000_200:
2041da177e4SLinus Torvalds 		num_tcslots = 7;
2051da177e4SLinus Torvalds 		break;
2061da177e4SLinus Torvalds 	case MACH_DS5000_1XX:
2071da177e4SLinus Torvalds 	case MACH_DS5000_2X0:
2081da177e4SLinus Torvalds 	case MACH_DS5900:
2091da177e4SLinus Torvalds 		num_tcslots = 3;
2101da177e4SLinus Torvalds 		break;
2111da177e4SLinus Torvalds 	case MACH_DS5000_XX:
2121da177e4SLinus Torvalds 	default:
2131da177e4SLinus Torvalds 		num_tcslots = 2;
2141da177e4SLinus Torvalds 		break;
2151da177e4SLinus Torvalds 	}
2161da177e4SLinus Torvalds 
2171da177e4SLinus Torvalds 	tc_clock = 10000 / info->clk_period;
2181da177e4SLinus Torvalds 
2191da177e4SLinus Torvalds 	if (TURBOCHANNEL && info->slot_size && slot0addr) {
2201da177e4SLinus Torvalds 		printk("TURBOchannel rev. %1d at %2d.%1d MHz ", info->revision,
2211da177e4SLinus Torvalds 			tc_clock / 10, tc_clock % 10);
2221da177e4SLinus Torvalds 		printk("(with%s parity)\n", info->parity ? "" : "out");
2231da177e4SLinus Torvalds 
2241da177e4SLinus Torvalds 		slot_size = info->slot_size << 20;
2251da177e4SLinus Torvalds 
2261da177e4SLinus Torvalds 		tc_probe(slot0addr, slot_size, num_tcslots);
2271da177e4SLinus Torvalds 
2281da177e4SLinus Torvalds   		/*
2291da177e4SLinus Torvalds   		 * All TURBOchannel DECstations have the onboard devices
2301da177e4SLinus Torvalds  		 * where the (num_tcslots + 0 or 1 on DS5k/xx) Option Module
2311da177e4SLinus Torvalds  		 * would be.
2321da177e4SLinus Torvalds  		 */
2331da177e4SLinus Torvalds  		if(mips_machtype == MACH_DS5000_XX)
2341da177e4SLinus Torvalds  			i = 1;
2351da177e4SLinus Torvalds 		else
2361da177e4SLinus Torvalds  			i = 0;
2371da177e4SLinus Torvalds 
2381da177e4SLinus Torvalds  	        system_base = slot0addr + slot_size * (num_tcslots + i);
2391da177e4SLinus Torvalds 
2401da177e4SLinus Torvalds #ifdef TC_DEBUG
2411da177e4SLinus Torvalds 		for (i = 0; i < num_tcslots; i++)
2421da177e4SLinus Torvalds 			if (tc_bus[i].base_addr) {
2431da177e4SLinus Torvalds 				printk("    slot %d: ", i);
2441da177e4SLinus Torvalds 				printk("%s %s %s\n", tc_bus[i].vendor,
2451da177e4SLinus Torvalds 					tc_bus[i].name, tc_bus[i].firmware);
2461da177e4SLinus Torvalds 			}
2471da177e4SLinus Torvalds #endif
2481da177e4SLinus Torvalds 	}
249778220f7SMaciej W. Rozycki 
250778220f7SMaciej W. Rozycki 	return 0;
2511da177e4SLinus Torvalds }
2521da177e4SLinus Torvalds 
2531da177e4SLinus Torvalds subsys_initcall(tc_init);
2541da177e4SLinus Torvalds 
2551da177e4SLinus Torvalds EXPORT_SYMBOL(search_tc_card);
2561da177e4SLinus Torvalds EXPORT_SYMBOL(claim_tc_card);
2571da177e4SLinus Torvalds EXPORT_SYMBOL(release_tc_card);
2581da177e4SLinus Torvalds EXPORT_SYMBOL(get_tc_base_addr);
2591da177e4SLinus Torvalds EXPORT_SYMBOL(get_tc_irq_nr);
2601da177e4SLinus Torvalds EXPORT_SYMBOL(get_tc_speed);
2611da177e4SLinus Torvalds EXPORT_SYMBOL(system_base);
262