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 clock_stop_probe(void); /* tadpole.c */ 24 extern void sun4c_probe_memerr_reg(void); 25 26 static char *cpu_mid_prop(void) 27 { 28 if (sparc_cpu_model == sun4d) 29 return "cpu-id"; 30 return "mid"; 31 } 32 33 static int check_cpu_node(phandle nd, int *cur_inst, 34 int (*compare)(phandle, int, void *), void *compare_arg, 35 phandle *prom_node, int *mid) 36 { 37 if (!compare(nd, *cur_inst, compare_arg)) { 38 if (prom_node) 39 *prom_node = nd; 40 if (mid) { 41 *mid = prom_getintdefault(nd, cpu_mid_prop(), 0); 42 if (sparc_cpu_model == sun4m) 43 *mid &= 3; 44 } 45 return 0; 46 } 47 48 (*cur_inst)++; 49 50 return -ENODEV; 51 } 52 53 static int __cpu_find_by(int (*compare)(phandle, int, void *), 54 void *compare_arg, phandle *prom_node, int *mid) 55 { 56 struct device_node *dp; 57 int cur_inst; 58 59 cur_inst = 0; 60 for_each_node_by_type(dp, "cpu") { 61 int err = check_cpu_node(dp->phandle, &cur_inst, 62 compare, compare_arg, 63 prom_node, mid); 64 if (!err) { 65 of_node_put(dp); 66 return 0; 67 } 68 } 69 70 return -ENODEV; 71 } 72 73 static int cpu_instance_compare(phandle nd, int instance, void *_arg) 74 { 75 int desired_instance = (int) _arg; 76 77 if (instance == desired_instance) 78 return 0; 79 return -ENODEV; 80 } 81 82 int cpu_find_by_instance(int instance, phandle *prom_node, int *mid) 83 { 84 return __cpu_find_by(cpu_instance_compare, (void *)instance, 85 prom_node, mid); 86 } 87 88 static int cpu_mid_compare(phandle nd, int instance, void *_arg) 89 { 90 int desired_mid = (int) _arg; 91 int this_mid; 92 93 this_mid = prom_getintdefault(nd, cpu_mid_prop(), 0); 94 if (this_mid == desired_mid 95 || (sparc_cpu_model == sun4m && (this_mid & 3) == desired_mid)) 96 return 0; 97 return -ENODEV; 98 } 99 100 int cpu_find_by_mid(int mid, phandle *prom_node) 101 { 102 return __cpu_find_by(cpu_mid_compare, (void *)mid, 103 prom_node, NULL); 104 } 105 106 /* sun4m uses truncated mids since we base the cpuid on the ttable/irqset 107 * address (0-3). This gives us the true hardware mid, which might have 108 * some other bits set. On 4d hardware and software mids are the same. 109 */ 110 int cpu_get_hwmid(phandle prom_node) 111 { 112 return prom_getintdefault(prom_node, cpu_mid_prop(), -ENODEV); 113 } 114 115 void __init device_scan(void) 116 { 117 printk(KERN_NOTICE "Booting Linux...\n"); 118 119 #ifndef CONFIG_SMP 120 { 121 phandle cpu_node; 122 int err; 123 err = cpu_find_by_instance(0, &cpu_node, NULL); 124 if (err) { 125 /* Probably a sun4e, Sun is trying to trick us ;-) */ 126 prom_printf("No cpu nodes, cannot continue\n"); 127 prom_halt(); 128 } 129 cpu_data(0).clock_tick = prom_getintdefault(cpu_node, 130 "clock-frequency", 131 0); 132 } 133 #endif /* !CONFIG_SMP */ 134 135 { 136 extern void auxio_probe(void); 137 extern void auxio_power_probe(void); 138 auxio_probe(); 139 auxio_power_probe(); 140 } 141 clock_stop_probe(); 142 143 if (ARCH_SUN4C) 144 sun4c_probe_memerr_reg(); 145 } 146