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