xref: /netbsd-src/sys/arch/sparc64/sparc64/ofw_patch.c (revision 060ae03544df53d7579b1b7c98529b39ff19a586)
1 /*	$NetBSD: ofw_patch.c,v 1.7 2020/12/23 07:01:14 jdc Exp $ */
2 
3 /*-
4  * Copyright (c) 2020 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Julian Coleman.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: ofw_patch.c,v 1.7 2020/12/23 07:01:14 jdc Exp $");
33 
34 #include <sys/param.h>
35 
36 #include <dev/i2c/i2cvar.h>
37 #include <dev/scsipi/scsipiconf.h>
38 
39 #include <machine/autoconf.h>
40 #include <machine/openfirm.h>
41 #include <sparc64/sparc64/ofw_patch.h>
42 #include <sparc64/sparc64/static_edid.h>
43 
44 static void
add_gpio_pin(prop_array_t pins,const char * name,int num,int act,int def)45 add_gpio_pin(prop_array_t pins, const char *name, int num, int act, int def)
46 {
47 	prop_dictionary_t pin = prop_dictionary_create();
48 	prop_dictionary_set_string(pin, "name", name);
49 	prop_dictionary_set_uint32(pin, "pin", num);
50 	prop_dictionary_set_bool(pin, "active_high", act);
51 	if (def != -1)
52 		prop_dictionary_set_int32(pin, "default_state", def);
53 	prop_array_add(pins, pin);
54 	prop_object_release(pin);
55 }
56 
57 static prop_array_t
create_i2c_dict(device_t busdev)58 create_i2c_dict(device_t busdev)
59 {
60 	prop_dictionary_t props = device_properties(busdev);
61 	prop_array_t cfg = NULL;
62 
63 	cfg = prop_dictionary_get(props, "i2c-child-devices");
64 	if (!cfg) {
65 		DPRINTF(ACDB_PROBE, ("\nCreating new i2c-child-devices\n"));
66 		cfg = prop_array_create();
67 		prop_dictionary_set(props, "i2c-child-devices", cfg);
68 		prop_dictionary_set_bool(props, "i2c-indirect-config", false);
69 	}
70 	return cfg;
71 }
72 
73 static void
add_i2c_device(prop_array_t cfg,const char * name,const char * compat,uint32_t addr,uint64_t node)74 add_i2c_device(prop_array_t cfg, const char *name, const char *compat,
75 uint32_t addr, uint64_t node)
76 {
77 	prop_dictionary_t dev;
78 
79 	DPRINTF(ACDB_PROBE, ("\nAdding i2c device: %s (%s) @ 0x%x (%lx)\n",
80 	    name, compat == NULL ? "NULL" : compat, addr, node & 0xffffffff));
81 	dev = prop_dictionary_create();
82 	prop_dictionary_set_string(dev, "name", name);
83 	if (compat != NULL)
84 		prop_dictionary_set_data(dev, "compatible", compat,
85 		    strlen(compat) + 1);
86 	prop_dictionary_set_uint32(dev, "addr", addr);
87 	prop_dictionary_set_uint64(dev, "cookie", node);
88 	prop_array_add(cfg, dev);
89 	prop_object_release(dev);
90 }
91 
92 void
add_gpio_props_v210(device_t dev,void * aux)93 add_gpio_props_v210(device_t dev, void *aux)
94 {
95 	struct i2c_attach_args *ia = aux;
96 	prop_dictionary_t dict = device_properties(dev);
97 	prop_array_t pins;
98 
99 	switch (ia->ia_addr) {
100 		case 0x38:	/* front panel LEDs */
101 			pins = prop_array_create();
102 			add_gpio_pin(pins, "LED indicator", 7, 0, -1);
103 			add_gpio_pin(pins, "LED fault", 5, 0, 0);
104 			add_gpio_pin(pins, "LED power", 4, 0, 1);
105 			prop_dictionary_set(dict, "pins", pins);
106 			prop_object_release(pins);
107 			break;
108 		case 0x23:	/* drive bay O/1 LEDs */
109 			pins = prop_array_create();
110 			add_gpio_pin(pins, "LED bay0_fault", 10, 0, 0);
111 			add_gpio_pin(pins, "LED bay1_fault", 11, 0, 0);
112 			add_gpio_pin(pins, "LED bay0_remove", 12, 0, 0);
113 			add_gpio_pin(pins, "LED bay1_remove", 13, 0, 0);
114 			prop_dictionary_set(dict, "pins", pins);
115 			prop_object_release(pins);
116 			break;
117 		case 0x25:	/* drive bay 2/3 LEDs (v240 only)*/
118 			pins = prop_array_create();
119 			add_gpio_pin(pins, "LED bay2_fault", 10, 0, 0);
120 			add_gpio_pin(pins, "LED bay3_fault", 11, 0, 0);
121 			add_gpio_pin(pins, "LED bay2_remove", 12, 0, 0);
122 			add_gpio_pin(pins, "LED bay3_remove", 13, 0, 0);
123 			prop_dictionary_set(dict, "pins", pins);
124 			prop_object_release(pins);
125 			break;
126 	}
127 }
128 
129 void
add_gpio_props_e250(device_t dev,void * aux)130 add_gpio_props_e250(device_t dev, void *aux)
131 {
132 	struct i2c_attach_args *ia = aux;
133 	prop_dictionary_t dict = device_properties(dev);
134 	prop_array_t pins;
135 
136 	switch (ia->ia_addr) {
137 		case 0x38:	/* interrupt status */
138 			pins = prop_array_create();
139 			add_gpio_pin(pins, "ALERT high_temp", 1, 0, 30);
140 			add_gpio_pin(pins, "ALERT disk_event", 2, 0, 30);
141 			add_gpio_pin(pins, "ALERT fan_fail", 4, 0, 30);
142 			add_gpio_pin(pins, "ALERT key_event", 5, 0, 30);
143 			add_gpio_pin(pins, "ALERT psu_event", 6, 0, 30);
144 			prop_dictionary_set(dict, "pins", pins);
145 			prop_object_release(pins);
146 			break;
147 		case 0x39:	/* PSU status */
148 			pins = prop_array_create();
149 			add_gpio_pin(pins, "INDICATOR psu0_present", 0, 0, -1);
150 			add_gpio_pin(pins, "INDICATOR psu1_present", 1, 0, -1);
151 			add_gpio_pin(pins, "INDICATOR psu0_fault", 4, 0, -1);
152 			add_gpio_pin(pins, "INDICATOR psu1_fault", 5, 0, -1);
153 			prop_dictionary_set(dict, "pins", pins);
154 			prop_object_release(pins);
155 			break;
156 		case 0x3d:	/* disk status */
157 			pins = prop_array_create();
158 			add_gpio_pin(pins, "INDICATOR disk0_present",
159 			    0, 0, -1);
160 			add_gpio_pin(pins, "INDICATOR disk1_present",
161 			    1, 0, -1);
162 			add_gpio_pin(pins, "INDICATOR disk2_present",
163 			    2, 0, -1);
164 			add_gpio_pin(pins, "INDICATOR disk3_present",
165 			    3, 0, -1);
166 			add_gpio_pin(pins, "INDICATOR disk4_present",
167 			    4, 0, -1);
168 			add_gpio_pin(pins, "INDICATOR disk5_present",
169 			    5, 0, -1);
170 			prop_dictionary_set(dict, "pins", pins);
171 			prop_object_release(pins);
172 			break;
173 		case 0x3e:	/* front panel LEDs (E250/E450) */
174 			pins = prop_array_create();
175 			add_gpio_pin(pins, "LED disk_fault", 0, 0, -1);
176 			add_gpio_pin(pins, "LED psu_fault", 1, 0, -1);
177 			add_gpio_pin(pins, "LED overtemp", 2, 0, -1);
178 			add_gpio_pin(pins, "LED fault", 3, 0, -1);
179 			add_gpio_pin(pins, "LED activity", 4, 0, -1);
180 			/* Pin 5 is power LED, but not controllable */
181 			add_gpio_pin(pins, "INDICATOR key_normal", 6, 0, -1);
182 			add_gpio_pin(pins, "INDICATOR key_diag", 7, 0, -1);
183 			/* If not "normal" or "diag", key is "lock" */
184 			prop_dictionary_set(dict, "pins", pins);
185 			prop_object_release(pins);
186 			break;
187 		case 0x3f:	/* disk fault LEDs */
188 			pins = prop_array_create();
189 			add_gpio_pin(pins, "LED disk0_fault", 0, 0, -1);
190 			add_gpio_pin(pins, "LED disk1_fault", 1, 0, -1);
191 			add_gpio_pin(pins, "LED disk2_fault", 2, 0, -1);
192 			add_gpio_pin(pins, "LED disk3_fault", 3, 0, -1);
193 			add_gpio_pin(pins, "LED disk4_fault", 4, 0, -1);
194 			add_gpio_pin(pins, "LED disk5_fault", 5, 0, -1);
195 			prop_dictionary_set(dict, "pins", pins);
196 			prop_object_release(pins);
197 			break;
198 	}
199 }
200 
201 void
add_drivebay_props(device_t dev,int ofnode,void * aux)202 add_drivebay_props(device_t dev, int ofnode, void *aux)
203 {
204 	struct scsipibus_attach_args *sa = aux;
205 	int target = sa->sa_periph->periph_target;
206 	prop_dictionary_t dict = device_properties(dev);
207 	char path[256]= "";
208 	char name[16];
209 	int nbays;
210 
211 	if ((strcmp(machine_model, "SUNW,Sun-Fire-V210") == 0) ||
212 	    (strcmp(machine_model, "SUNW,Sun-Fire-V240") == 0)) {
213 		OF_package_to_path(ofnode, path, sizeof(path));
214 
215 		/* see if we're on the onboard controller's 1st channel */
216 		if (strcmp(path, "/pci@1c,600000/scsi@2") != 0)
217 			return;
218 
219 		/* yes, yes we are */
220 		if (strcmp(machine_model, "SUNW,Sun-Fire-V240") == 0)
221 			nbays = 4;
222 		else
223 			nbays = 2;
224 		if ( target < nbays) {
225 			snprintf(name, sizeof(name), "bay%d", target);
226 			prop_dictionary_set_string(dict, "location", name);
227 		}
228 	}
229 
230 	if (!strcmp(machine_model, "SUNW,Ultra-250")) {
231 		OF_package_to_path(ofnode, path, sizeof(path));
232 
233 		/* see if we're on the onboard controller's 1st channel */
234 		if (strcmp(path, "/pci@1f,4000/scsi@3") != 0)
235 			return;
236 
237 		/* disk 0 is target 0 */
238 		if (!target) {
239 			strncpy(name, "bay0", sizeof(name));
240 			prop_dictionary_set_string(dict, "location", name);
241 		/* disks 1 - 5 are targets 8 - 12 */
242 		} else if ( target < 13) {
243 			snprintf(name, sizeof(name), "bay%d", target - 7);
244 			prop_dictionary_set_string(dict, "location", name);
245 		}
246 	}
247 }
248 
249 /*
250  * Add SPARCle spdmem devices (0x50 and 0x51) that are not in the OFW tree
251  */
252 void
add_spdmem_props_sparcle(device_t busdev)253 add_spdmem_props_sparcle(device_t busdev)
254 {
255 	prop_array_t cfg;
256 	int i;
257 
258 	DPRINTF(ACDB_PROBE, ("\nAdding spdmem for SPARCle "));
259 
260 	cfg = create_i2c_dict(busdev);
261 	for (i = 0x50; i <= 0x51; i++)
262 		add_i2c_device(cfg, "dimm-spd", NULL, i, 0);
263 	prop_object_release(cfg);
264 }
265 
266 /*
267  * Add V210/V240 environmental sensors that are not in the OFW tree.
268  */
269 void
add_env_sensors_v210(device_t busdev)270 add_env_sensors_v210(device_t busdev)
271 {
272 	prop_array_t cfg;
273 
274 	DPRINTF(ACDB_PROBE, ("\nAdding sensors for %s ", machine_model));
275 	cfg = create_i2c_dict(busdev);
276 
277 	/* ADM1026 at 0x2e */
278 	add_i2c_device(cfg, "hardware-monitor", "i2c-adm1026", 0x2e, 0);
279 	/* LM75 at 0x4e */
280 	add_i2c_device(cfg, "temperature-sensor", "i2c-lm75", 0x4e, 0);
281 }
282 
283 /* Sensors and GPIO's for E450 and E250 */
284 void
add_i2c_props_e450(device_t busdev,uint64_t node)285 add_i2c_props_e450(device_t busdev, uint64_t node)
286 {
287 	prop_array_t cfg;
288 
289 	DPRINTF(ACDB_PROBE, ("\nAdding sensors for %s ", machine_model));
290 	cfg = create_i2c_dict(busdev);
291 
292 	/* Power supply 1 temperature. */
293 	add_i2c_device(cfg, "PSU-1", "ecadc", 0x48, node);
294 
295 	/* Power supply 2 temperature. */
296 	add_i2c_device(cfg, "PSU-2", "ecadc", 0x49, node);
297 
298 	/* Power supply 3 temperature. */
299 	add_i2c_device(cfg, "PSU-3", "ecadc", 0x4a, node);
300 
301 	/* Ambient temperature. */
302 	add_i2c_device(cfg, "ambient", "i2c-lm75", 0x4d, node);
303 
304 	/* CPU temperatures. */
305 	add_i2c_device(cfg, "CPU", "ecadc", 0x4f, node);
306 
307 	prop_object_release(cfg);
308 }
309 
310 void
add_i2c_props_e250(device_t busdev,uint64_t node)311 add_i2c_props_e250(device_t busdev, uint64_t node)
312 {
313 	prop_array_t cfg;
314 	int i;
315 
316 	DPRINTF(ACDB_PROBE, ("\nAdding sensors for %s ", machine_model));
317 	cfg = create_i2c_dict(busdev);
318 
319 	/* PSU temperature / CPU fan */
320 	add_i2c_device(cfg, "PSU", "ecadc", 0x4a, node);
321 
322 	/* CPU & system board temperature */
323 	add_i2c_device(cfg, "CPU", "ecadc", 0x4f, node);
324 
325 	/* GPIO's */
326 	for (i = 0x38; i <= 0x39; i++)
327 		add_i2c_device(cfg, "gpio", "i2c-pcf8574", i, node);
328 	for (i = 0x3d; i <= 0x3f; i++)
329 		add_i2c_device(cfg, "gpio", "i2c-pcf8574", i, node);
330 
331 	/* NVRAM */
332 	add_i2c_device(cfg, "nvram", "i2c-at24c02", 0x52, node);
333 
334 	/* RSC clock */
335 	add_i2c_device(cfg, "rscrtc", "i2c-ds1307", 0x68, node);
336 
337 	prop_object_release(cfg);
338 }
339 
340 /* Hardware specific device properties */
341 void
set_hw_props(device_t dev)342 set_hw_props(device_t dev)
343 {
344 	device_t busdev = device_parent(dev);
345 
346 	if ((!strcmp(machine_model, "SUNW,Sun-Fire-V240") ||
347 	    !strcmp(machine_model, "SUNW,Sun-Fire-V210"))) {
348 		device_t busparent = device_parent(busdev);
349 		prop_dictionary_t props = device_properties(dev);
350 
351 		if (busparent != NULL && device_is_a(busparent, "pcfiic") &&
352 		    device_is_a(dev, "adm1026hm") && props != NULL) {
353 			prop_dictionary_set_uint8(props, "fan_div2", 0x55);
354 			prop_dictionary_set_bool(props, "multi_read", true);
355 		}
356 	}
357 
358 	if (!strcmp(machine_model, "SUNW,Sun-Fire-V440")) {
359 		device_t busparent = device_parent(busdev);
360 		prop_dictionary_t props = device_properties(dev);
361 		if (busparent != NULL && device_is_a(busparent, "pcfiic") &&
362 		    device_is_a(dev, "adm1026hm") && props != NULL) {
363 			prop_dictionary_set_bool(props, "multi_read", true);
364 		}
365 	}
366 }
367 
368 /* Static EDID definitions */
369 void
set_static_edid(prop_dictionary_t dict)370 set_static_edid(prop_dictionary_t dict)
371 {
372 	if (!strcmp(machine_model, "NATE,Meso-999")) {
373 		prop_data_t edid;
374 
375 		DPRINTF(ACDB_PROBE, ("\nAdding EDID for Meso-999 "));
376 		edid = prop_data_create_copy(edid_meso999,
377 		    sizeof(edid_meso999));
378 		prop_dictionary_set(dict, "EDID:1", edid);
379 		prop_object_release(edid);
380 	}
381 }
382