1 /* devices.c: Initial scan of the prom device tree for important 2 * Sparc device nodes which we need to find. 3 * 4 * This is based on the sparc64 version, but sun4m doesn't always use 5 * the hardware MIDs, so be careful. 6 * 7 * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) 8 */ 9 10 #include <linux/kernel.h> 11 #include <linux/threads.h> 12 #include <linux/string.h> 13 #include <linux/init.h> 14 #include <linux/errno.h> 15 16 #include <asm/page.h> 17 #include <asm/oplib.h> 18 #include <asm/prom.h> 19 #include <asm/smp.h> 20 #include <asm/system.h> 21 #include <asm/cpudata.h> 22 23 extern void cpu_probe(void); 24 extern void clock_stop_probe(void); /* tadpole.c */ 25 extern void sun4c_probe_memerr_reg(void); 26 27 static char *cpu_mid_prop(void) 28 { 29 if (sparc_cpu_model == sun4d) 30 return "cpu-id"; 31 return "mid"; 32 } 33 34 static int check_cpu_node(int nd, int *cur_inst, 35 int (*compare)(int, int, void *), void *compare_arg, 36 int *prom_node, int *mid) 37 { 38 if (!compare(nd, *cur_inst, compare_arg)) { 39 if (prom_node) 40 *prom_node = nd; 41 if (mid) { 42 *mid = prom_getintdefault(nd, cpu_mid_prop(), 0); 43 if (sparc_cpu_model == sun4m) 44 *mid &= 3; 45 } 46 return 0; 47 } 48 49 (*cur_inst)++; 50 51 return -ENODEV; 52 } 53 54 static int __cpu_find_by(int (*compare)(int, int, void *), void *compare_arg, 55 int *prom_node, int *mid) 56 { 57 struct device_node *dp; 58 int cur_inst; 59 60 cur_inst = 0; 61 for_each_node_by_type(dp, "cpu") { 62 int err = check_cpu_node(dp->node, &cur_inst, 63 compare, compare_arg, 64 prom_node, mid); 65 if (!err) 66 return 0; 67 } 68 69 return -ENODEV; 70 } 71 72 static int cpu_instance_compare(int nd, int instance, void *_arg) 73 { 74 int desired_instance = (int) _arg; 75 76 if (instance == desired_instance) 77 return 0; 78 return -ENODEV; 79 } 80 81 int cpu_find_by_instance(int instance, int *prom_node, int *mid) 82 { 83 return __cpu_find_by(cpu_instance_compare, (void *)instance, 84 prom_node, mid); 85 } 86 87 static int cpu_mid_compare(int nd, int instance, void *_arg) 88 { 89 int desired_mid = (int) _arg; 90 int this_mid; 91 92 this_mid = prom_getintdefault(nd, cpu_mid_prop(), 0); 93 if (this_mid == desired_mid 94 || (sparc_cpu_model == sun4m && (this_mid & 3) == desired_mid)) 95 return 0; 96 return -ENODEV; 97 } 98 99 int cpu_find_by_mid(int mid, int *prom_node) 100 { 101 return __cpu_find_by(cpu_mid_compare, (void *)mid, 102 prom_node, NULL); 103 } 104 105 /* sun4m uses truncated mids since we base the cpuid on the ttable/irqset 106 * address (0-3). This gives us the true hardware mid, which might have 107 * some other bits set. On 4d hardware and software mids are the same. 108 */ 109 int cpu_get_hwmid(int prom_node) 110 { 111 return prom_getintdefault(prom_node, cpu_mid_prop(), -ENODEV); 112 } 113 114 void __init device_scan(void) 115 { 116 prom_printf("Booting Linux...\n"); 117 118 #ifndef CONFIG_SMP 119 { 120 int err, cpu_node; 121 err = cpu_find_by_instance(0, &cpu_node, NULL); 122 if (err) { 123 /* Probably a sun4e, Sun is trying to trick us ;-) */ 124 prom_printf("No cpu nodes, cannot continue\n"); 125 prom_halt(); 126 } 127 cpu_data(0).clock_tick = prom_getintdefault(cpu_node, 128 "clock-frequency", 129 0); 130 } 131 #endif /* !CONFIG_SMP */ 132 133 cpu_probe(); 134 #ifdef CONFIG_SUN_AUXIO 135 { 136 extern void auxio_probe(void); 137 extern void auxio_power_probe(void); 138 auxio_probe(); 139 auxio_power_probe(); 140 } 141 #endif 142 clock_stop_probe(); 143 144 if (ARCH_SUN4C_SUN4) 145 sun4c_probe_memerr_reg(); 146 147 return; 148 } 149