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 | |
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(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 | |
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(nd: dp->phandle, cur_inst: &cur_inst, |
63 | compare, compare_arg, |
64 | prom_node, mid); |
65 | if (!err) { |
66 | of_node_put(node: dp); |
67 | return 0; |
68 | } |
69 | } |
70 | |
71 | return -ENODEV; |
72 | } |
73 | |
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 | |
83 | int cpu_find_by_instance(int instance, phandle *prom_node, int *mid) |
84 | { |
85 | return __cpu_find_by(compare: cpu_instance_compare, compare_arg: (void *)instance, |
86 | prom_node, mid); |
87 | } |
88 | |
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 | |
101 | int cpu_find_by_mid(int mid, phandle *prom_node) |
102 | { |
103 | return __cpu_find_by(compare: cpu_mid_compare, compare_arg: (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 | */ |
111 | int cpu_get_hwmid(phandle prom_node) |
112 | { |
113 | return prom_getintdefault(prom_node, cpu_mid_prop(), -ENODEV); |
114 | } |
115 | |
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 | |