Home | History | Annotate | Line # | Download | only in sparc64
      1 /*	$NetBSD: ofw_patch.c,v 1.19 2026/10/07 11:18:09 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.19 2026/10/07 11:18:09 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 /*
     45  * GPIO pin configurations
     46  *   num: the bit representing the pin
     47  *   act: on/off are reversed
     48  *   def: default state for LED or ALERT (will be set or checked by the driver)
     49  *   to: timeout (secs) before which we need to read the state
     50  */
     51 static void
     52 add_gpio_pin(prop_array_t pins, const char *name, int num, int act,
     53     int def, int to)
     54 {
     55 	prop_dictionary_t pin = prop_dictionary_create();
     56 	prop_dictionary_set_string(pin, "name", name);
     57 	prop_dictionary_set_uint32(pin, "pin", num);
     58 	prop_dictionary_set_bool(pin, "active_high", act);
     59 	if (def != -1)
     60 		prop_dictionary_set_int32(pin, "default_state", def);
     61 	if (to != -1)
     62 		prop_dictionary_set_int32(pin, "timeout", to);
     63 	prop_array_add(pins, pin);
     64 	prop_object_release(pin);
     65 }
     66 
     67 static prop_array_t
     68 create_i2c_dict(device_t busdev)
     69 {
     70 	prop_dictionary_t props = device_properties(busdev);
     71 	prop_array_t cfg = NULL;
     72 
     73 	cfg = prop_dictionary_get(props, "i2c-child-devices");
     74 	if (!cfg) {
     75 		DPRINTF(ACDB_PROBE, ("\nCreating new i2c-child-devices\n"));
     76 		cfg = prop_array_create();
     77 		prop_dictionary_set(props, "i2c-child-devices", cfg);
     78 		prop_dictionary_set_bool(props, "i2c-indirect-config", false);
     79 	}
     80 	return cfg;
     81 }
     82 
     83 static void
     84 add_i2c_device(prop_array_t cfg, const char *name, const char *compat,
     85     uint32_t addr, uint64_t node)
     86 {
     87 	prop_dictionary_t dev;
     88 	devhandle_t child_devhandle;
     89 
     90 	DPRINTF(ACDB_PROBE, ("\nAdding i2c device: %s (%s) @ 0x%x (%lx)\n",
     91 	    name, compat == NULL ? "NULL" : compat, addr, node & 0xffffffff));
     92 	dev = prop_dictionary_create();
     93 	prop_dictionary_set_string(dev, "name", name);
     94 	if (compat != NULL)
     95 		prop_dictionary_set_data(dev, "compatible", compat,
     96 		    strlen(compat) + 1);
     97 	prop_dictionary_set_uint32(dev, "addr", addr);
     98 	if (node != 0) {
     99 		child_devhandle =
    100 		    devhandle_from_of(devhandle_invalid(), node);
    101 	} else {
    102 		child_devhandle = devhandle_invalid();
    103 	}
    104 	prop_dictionary_set_data(dev, "devhandle",
    105 	    &child_devhandle, sizeof(child_devhandle));
    106 
    107 	prop_array_add(cfg, dev);
    108 	prop_object_release(dev);
    109 }
    110 
    111 static void
    112 add_gpio_props_v210(device_t dev, void *aux)
    113 {
    114 	struct i2c_attach_args *ia = aux;
    115 	prop_dictionary_t dict = device_properties(dev);
    116 	prop_array_t pins;
    117 
    118 	switch (ia->ia_addr) {
    119 		case 0x38:	/* front panel LEDs */
    120 			pins = prop_array_create();
    121 			add_gpio_pin(pins, "LED indicator", 7, 0, -1, -1);
    122 			add_gpio_pin(pins, "LED fault", 5, 0, 0, -1);
    123 			add_gpio_pin(pins, "LED power", 4, 0, 1, -1);
    124 			prop_dictionary_set(dict, "pins", pins);
    125 			prop_object_release(pins);
    126 			break;
    127 		case 0x23:	/* drive bay O/1 LEDs */
    128 			pins = prop_array_create();
    129 			add_gpio_pin(pins, "LED bay0_fault", 10, 0, 0, -1);
    130 			add_gpio_pin(pins, "LED bay1_fault", 11, 0, 0, -1);
    131 			add_gpio_pin(pins, "LED bay0_remove", 12, 0, 0, -1);
    132 			add_gpio_pin(pins, "LED bay1_remove", 13, 0, 0, -1);
    133 			prop_dictionary_set(dict, "pins", pins);
    134 			prop_object_release(pins);
    135 			break;
    136 		case 0x25:	/* drive bay 2/3 LEDs (v240 only)*/
    137 			pins = prop_array_create();
    138 			add_gpio_pin(pins, "LED bay2_fault", 10, 0, 0, -1);
    139 			add_gpio_pin(pins, "LED bay3_fault", 11, 0, 0, -1);
    140 			add_gpio_pin(pins, "LED bay2_remove", 12, 0, 0, -1);
    141 			add_gpio_pin(pins, "LED bay3_remove", 13, 0, 0, -1);
    142 			prop_dictionary_set(dict, "pins", pins);
    143 			prop_object_release(pins);
    144 			break;
    145 	}
    146 }
    147 
    148 static void
    149 add_gpio_props_v245(device_t dev, void *aux)
    150 {
    151 	struct i2c_attach_args *ia = aux;
    152 	prop_dictionary_t dict = device_properties(dev);
    153 	prop_array_t pins;
    154 
    155 	switch (ia->ia_addr) {
    156 		case 0x12:	/* V215 disk status / LED's */
    157 			pins = prop_array_create();
    158 			add_gpio_pin(pins, "ALERT HDD 0 present",
    159 			    6, 1, -1, -1);
    160 			add_gpio_pin(pins, "ALERT HDD 1 present",
    161 			    7, 1, -1, -1);
    162 			add_gpio_pin(pins, "LED hdd0_fault", 0, 0, 0, -1);
    163 			add_gpio_pin(pins, "LED hdd0_remove", 4, 0, 0, -1);
    164 			add_gpio_pin(pins, "LED hdd1_fault", 1, 0, 0, -1);
    165 			add_gpio_pin(pins, "LED hdd1_remove", 5, 0, 0, -1);
    166 			prop_dictionary_set(dict, "pins", pins);
    167 			prop_object_release(pins);
    168 			break;
    169 		case 0x22:	/* V245 disk status / LED's */
    170 			pins = prop_array_create();
    171 			add_gpio_pin(pins, "ALERT HDD 0 present",
    172 			    8, 1, -1, -1);
    173 			add_gpio_pin(pins, "ALERT HDD 1 present",
    174 			    9, 1, -1, -1);
    175 			add_gpio_pin(pins, "ALERT HDD 2 present",
    176 			    10, 1, -1, -1);
    177 			add_gpio_pin(pins, "ALERT HDD 3 present",
    178 			    11, 1, -1, -1);
    179 			add_gpio_pin(pins, "LED hdd0_fault", 0, 0, 0, -1);
    180 			add_gpio_pin(pins, "LED hdd0_remove", 4, 0, 0, -1);
    181 			add_gpio_pin(pins, "LED hdd1_fault", 1, 0, 0, -1);
    182 			add_gpio_pin(pins, "LED hdd1_remove", 5, 0, 0, -1);
    183 			add_gpio_pin(pins, "LED hdd2_fault", 2, 0, 0, -1);
    184 			add_gpio_pin(pins, "LED hdd2_remove", 6, 0, 0, -1);
    185 			add_gpio_pin(pins, "LED hdd3_fault", 3, 0, 0, -1);
    186 			add_gpio_pin(pins, "LED hdd3_remove", 7, 0, 0, -1);
    187 			prop_dictionary_set(dict, "pins", pins);
    188 			prop_object_release(pins);
    189 			break;
    190 		case 0x3e:	/* PSU 0 */
    191 			pins = prop_array_create();
    192 			prop_dictionary_set(dict, "pins", pins);
    193 			add_gpio_pin(pins, "ALERT PSU 0 input power",
    194 			    6, 0, 0, -1);
    195 			prop_object_release(pins);
    196 			break;
    197 		case 0x3f:	/* PSU 1 */
    198 			pins = prop_array_create();
    199 			prop_dictionary_set(dict, "pins", pins);
    200 			add_gpio_pin(pins, "ALERT PSU 1 input power",
    201 			    6, 0, 0, -1);
    202 			prop_object_release(pins);
    203 			break;
    204 	}
    205 }
    206 
    207 static void
    208 add_gpio_props_u45(device_t dev, void *aux)
    209 {
    210 	struct i2c_attach_args *ia = aux;
    211 	prop_dictionary_t dict = device_properties(dev);
    212 	prop_array_t pins;
    213 
    214 	switch (ia->ia_addr) {
    215 		case 0x18:	/* front panel LEDs */
    216 			pins = prop_array_create();
    217 			add_gpio_pin(pins, "LED power", 0, 1, -1, -1);
    218 			add_gpio_pin(pins, "LED fault", 1, 0, -1, -1);
    219 			prop_dictionary_set(dict, "pins", pins);
    220 			prop_object_release(pins);
    221 			break;
    222 	}
    223 }
    224 
    225 static void
    226 add_gpio_props_e250(device_t dev, void *aux)
    227 {
    228 	struct i2c_attach_args *ia = aux;
    229 	prop_dictionary_t dict = device_properties(dev);
    230 	prop_array_t pins;
    231 
    232 	switch (ia->ia_addr) {
    233 		case 0x38:	/* interrupt status */
    234 			pins = prop_array_create();
    235 			add_gpio_pin(pins, "ALERT high_temp", 1, 0, -1, 30);
    236 			add_gpio_pin(pins, "ALERT disk_event", 2, 0, -1, 30);
    237 			add_gpio_pin(pins, "ALERT fan_fail", 4, 0, -1, 30);
    238 			add_gpio_pin(pins, "ALERT key_event", 5, 0, -1, 30);
    239 			add_gpio_pin(pins, "ALERT psu_event", 6, 0, -1, 30);
    240 			prop_dictionary_set(dict, "pins", pins);
    241 			prop_object_release(pins);
    242 			break;
    243 		case 0x39:	/* PSU status */
    244 			pins = prop_array_create();
    245 			add_gpio_pin(pins, "INDICATOR psu0_present",
    246 			    0, 0, -1, -1);
    247 			add_gpio_pin(pins, "INDICATOR psu1_present",
    248 			    1, 0, -1, -1);
    249 			add_gpio_pin(pins, "ALERT psu0_fault", 4, 0, 1, -1);
    250 			add_gpio_pin(pins, "ALERT psu1_fault", 5, 0, 1, -1);
    251 			prop_dictionary_set(dict, "pins", pins);
    252 			prop_object_release(pins);
    253 			break;
    254 		case 0x3d:	/* disk status */
    255 			pins = prop_array_create();
    256 			add_gpio_pin(pins, "ALERT disk0_present",
    257 			    0, 0, -1, -1);
    258 			add_gpio_pin(pins, "ALERT disk1_present",
    259 			    1, 0, -1, -1);
    260 			add_gpio_pin(pins, "ALERT disk2_present",
    261 			    2, 0, -1, -1);
    262 			add_gpio_pin(pins, "ALERT disk3_present",
    263 			    3, 0, -1, -1);
    264 			add_gpio_pin(pins, "ALERT disk4_present",
    265 			    4, 0, -1, -1);
    266 			add_gpio_pin(pins, "ALERT disk5_present",
    267 			    5, 0, -1, -1);
    268 			prop_dictionary_set(dict, "pins", pins);
    269 			prop_object_release(pins);
    270 			break;
    271 		case 0x3e:	/* front panel LEDs (E250/E450) */
    272 			pins = prop_array_create();
    273 			add_gpio_pin(pins, "LED disk_fault", 0, 0, -1, -1);
    274 			add_gpio_pin(pins, "LED psu_fault", 1, 0, -1, -1);
    275 			add_gpio_pin(pins, "LED overtemp", 2, 0, -1, -1);
    276 			add_gpio_pin(pins, "LED fault", 3, 0, -1, -1);
    277 			add_gpio_pin(pins, "LED activity", 4, 0, -1, -1);
    278 			/* Pin 5 is power LED, but not controllable */
    279 			add_gpio_pin(pins, "INDICATOR key_normal", 6, 0, -1, -1);
    280 			add_gpio_pin(pins, "INDICATOR key_diag", 7, 0, -1, -1);
    281 			/* If not "normal" or "diag", key is "lock" */
    282 			prop_dictionary_set(dict, "pins", pins);
    283 			prop_object_release(pins);
    284 			break;
    285 		case 0x3f:	/* disk fault LEDs */
    286 			pins = prop_array_create();
    287 			add_gpio_pin(pins, "LED disk0_fault", 0, 0, -1, -1);
    288 			add_gpio_pin(pins, "LED disk1_fault", 1, 0, -1, -1);
    289 			add_gpio_pin(pins, "LED disk2_fault", 2, 0, -1, -1);
    290 			add_gpio_pin(pins, "LED disk3_fault", 3, 0, -1, -1);
    291 			add_gpio_pin(pins, "LED disk4_fault", 4, 0, -1, -1);
    292 			add_gpio_pin(pins, "LED disk5_fault", 5, 0, -1, -1);
    293 			prop_dictionary_set(dict, "pins", pins);
    294 			prop_object_release(pins);
    295 			break;
    296 	}
    297 }
    298 
    299 void
    300 add_drivebay_props(device_t dev, int ofnode, void *aux)
    301 {
    302 	struct scsipibus_attach_args *sa = aux;
    303 	int target = sa->sa_periph->periph_target;
    304 	prop_dictionary_t dict = device_properties(dev);
    305 	char path[256]= "";
    306 	char name[16];
    307 	int nbays;
    308 
    309 	if ((strcmp(machine_model, "SUNW,Sun-Fire-V210") == 0) ||
    310 	    (strcmp(machine_model, "SUNW,Sun-Fire-V240") == 0)) {
    311 		OF_package_to_path(ofnode, path, sizeof(path));
    312 
    313 		/* see if we're on the onboard controller's 1st channel */
    314 		if (strcmp(path, "/pci@1c,600000/scsi@2") != 0)
    315 			return;
    316 
    317 		/* yes, yes we are */
    318 		if (strcmp(machine_model, "SUNW,Sun-Fire-V240") == 0)
    319 			nbays = 4;
    320 		else
    321 			nbays = 2;
    322 		if ( target < nbays) {
    323 			snprintf(name, sizeof(name), "bay%d", target);
    324 			prop_dictionary_set_string(dict, "location", name);
    325 		}
    326 	}
    327 
    328 	if (!strcmp(machine_model, "SUNW,Ultra-250")) {
    329 		OF_package_to_path(ofnode, path, sizeof(path));
    330 
    331 		/* see if we're on the onboard controller's 1st channel */
    332 		if (strcmp(path, "/pci@1f,4000/scsi@3") != 0)
    333 			return;
    334 
    335 		/* disk 0 is target 0 */
    336 		if (!target) {
    337 			strncpy(name, "bay0", sizeof(name));
    338 			prop_dictionary_set_string(dict, "location", name);
    339 		/* disks 1 - 5 are targets 8 - 12 */
    340 		} else if ( target < 13) {
    341 			snprintf(name, sizeof(name), "bay%d", target - 7);
    342 			prop_dictionary_set_string(dict, "location", name);
    343 		}
    344 	}
    345 }
    346 
    347 /*
    348  * Add SPARCle spdmem devices (0x50 and 0x51) that are not in the OFW tree
    349  */
    350 static void
    351 add_spdmem_props_sparcle(device_t busdev)
    352 {
    353 	prop_array_t cfg;
    354 	int i;
    355 
    356 	DPRINTF(ACDB_PROBE, ("\nAdding spdmem for SPARCle "));
    357 
    358 	cfg = create_i2c_dict(busdev);
    359 	for (i = 0x50; i <= 0x51; i++)
    360 		add_i2c_device(cfg, "dimm-spd", NULL, i, 0);
    361 	prop_object_release(cfg);
    362 }
    363 
    364 /*
    365  * Add V210/V240 environmental sensors that are not in the OFW tree.
    366  */
    367 static void
    368 add_env_sensors_v210(device_t busdev)
    369 {
    370 	prop_array_t cfg;
    371 
    372 	DPRINTF(ACDB_PROBE, ("\nAdding sensors for %s ", machine_model));
    373 	cfg = create_i2c_dict(busdev);
    374 
    375 	/* ADM1026 at 0x2e */
    376 	add_i2c_device(cfg, "hardware-monitor", "i2c-adm1026", 0x2e, 0);
    377 
    378 	/* LM75 at 0x4e */
    379 	add_i2c_device(cfg, "temperature-sensor", "i2c-lm75", 0x4e, 0);
    380 }
    381 
    382 /*
    383  * Add U45 environmental sensors that are not in the OFW tree.
    384  */
    385 static void
    386 add_env_sensors_u45(device_t busdev)
    387 {
    388 	prop_array_t cfg;
    389 
    390 	DPRINTF(ACDB_PROBE, ("\nAdding sensors for %s ", machine_model));
    391 	cfg = create_i2c_dict(busdev);
    392 
    393 	/* LM95221 at 0x2b */
    394 	add_i2c_device(cfg, "temperature-sensor", "i2c-lm95221", 0x2b, 0);
    395 
    396 	/* NXP LM75A at 0x4f */
    397 	add_i2c_device(cfg, "temperature-sensor", "i2c-lm75a", 0x4f, 0);
    398 }
    399 
    400 /*
    401  * Add V245 environmental sensors that are not in the OFW tree.
    402  */
    403 static void
    404 add_env_sensors_v245(device_t busdev, int model)
    405 {
    406 	prop_array_t cfg;
    407 
    408 	DPRINTF(ACDB_PROBE, ("\nAdding sensors for %s ", machine_model));
    409 	cfg = create_i2c_dict(busdev);
    410 
    411 	/* PCA9556 at 0x12 (V215) */
    412 	if (model == 215)
    413 		add_i2c_device(cfg, "gpio", "i2c-pca9556", 0x12, 0);
    414 
    415 	/* PCA9555 at 0x22 (V245) */
    416 	if (model == 245)
    417 		add_i2c_device(cfg, "gpio", "i2c-pca9555", 0x22, 0);
    418 
    419 	/* LM95221 at 0x2b */
    420 	add_i2c_device(cfg, "temperature-sensor", "i2c-lm95221", 0x2b, 0);
    421 
    422 	/* ADT7475 at 0x2e */
    423 	add_i2c_device(cfg, "hardware-monitor", "i2c-adt7475", 0x2e, 0);
    424 }
    425 
    426 /* Sensors and GPIO's for E450 and E250 */
    427 static void
    428 add_i2c_props_e450(device_t busdev, uint64_t node)
    429 {
    430 	prop_array_t cfg;
    431 
    432 	DPRINTF(ACDB_PROBE, ("\nAdding sensors for %s ", machine_model));
    433 	cfg = create_i2c_dict(busdev);
    434 
    435 	/* Power supply 1 temperature. */
    436 	add_i2c_device(cfg, "PSU-1", "ecadc", 0x48, node);
    437 
    438 	/* Power supply 2 temperature. */
    439 	add_i2c_device(cfg, "PSU-2", "ecadc", 0x49, node);
    440 
    441 	/* Power supply 3 temperature. */
    442 	add_i2c_device(cfg, "PSU-3", "ecadc", 0x4a, node);
    443 
    444 	/* Ambient temperature. */
    445 	add_i2c_device(cfg, "ambient", "i2c-lm75", 0x4d, node);
    446 
    447 	/* CPU temperatures. */
    448 	add_i2c_device(cfg, "CPU", "ecadc", 0x4f, node);
    449 
    450 	prop_object_release(cfg);
    451 }
    452 
    453 static void
    454 add_i2c_props_e250(device_t busdev, uint64_t node)
    455 {
    456 	prop_array_t cfg;
    457 	int i;
    458 
    459 	DPRINTF(ACDB_PROBE, ("\nAdding sensors for %s ", machine_model));
    460 	cfg = create_i2c_dict(busdev);
    461 
    462 	/* PSU temperature / CPU fan */
    463 	add_i2c_device(cfg, "PSU", "ecadc", 0x4a, node);
    464 
    465 	/* CPU & system board temperature */
    466 	add_i2c_device(cfg, "CPU", "ecadc", 0x4f, node);
    467 
    468 	/* GPIO's */
    469 	for (i = 0x38; i <= 0x39; i++)
    470 		add_i2c_device(cfg, "gpio", "i2c-pcf8574", i, node);
    471 	for (i = 0x3d; i <= 0x3f; i++)
    472 		add_i2c_device(cfg, "gpio", "i2c-pcf8574", i, node);
    473 
    474 	/* NVRAM */
    475 	add_i2c_device(cfg, "nvram", "i2c-at24c02", 0x52, node);
    476 
    477 	prop_object_release(cfg);
    478 }
    479 
    480 /*
    481  * Fix-up U45 incorrect properties in the OFW tree.
    482  */
    483 static void
    484 fix_properties_u45(device_t busdev)
    485 {
    486 	prop_dictionary_t props = device_properties(busdev);
    487 	prop_array_t cfg;
    488 	prop_object_t dev;
    489 	uint32_t addr;
    490 	const char *name;
    491 	int i, n;
    492 
    493 	cfg = prop_dictionary_get(props, "i2c-child-devices");
    494 	if (!cfg)
    495 		return;
    496 
    497 	n = prop_array_count(cfg);
    498 	for (i = 0; i < n; i++) {
    499 		dev = prop_array_get(cfg, i);
    500 		if (prop_object_type(dev) == PROP_TYPE_DICTIONARY &&
    501 		    prop_dictionary_get_uint32(dev, "addr", &addr) &&
    502 		    prop_dictionary_get_string(dev, "name", &name)) {
    503 			/* Change psu-fru-prom to a standard eeprom */
    504 			if (addr == 0x57)
    505 				prop_dictionary_set_data(dev, "compatible",
    506 				    "i2c-at24c02", strlen("i2c-at24c02") + 1);
    507 			/* Remove fake lm76 at addresses 2b, 48 and 4f */
    508 			if ((addr == 0x2b || addr == 0x48 || addr == 0x4f) &&
    509 			    !strcmp(name, "temperature")) {
    510 				prop_array_remove(cfg, i);
    511 				i -= 1;
    512 				n -= 1;
    513 			}
    514 		}
    515 	}
    516 }
    517 
    518 /*
    519  * Fix-up V245 incorrect properties in the OFW tree.
    520  */
    521 static void
    522 fix_properties_v245(device_t busdev)
    523 {
    524 	prop_dictionary_t props = device_properties(busdev);
    525 	prop_array_t cfg;
    526 	prop_object_t dev;
    527 	uint32_t addr;
    528 	const char *name;
    529 	int i, n;
    530 
    531 	cfg = prop_dictionary_get(props, "i2c-child-devices");
    532 	if (!cfg)
    533 		return;
    534 
    535 	n = prop_array_count(cfg);
    536 	for (i = 0; i < n; i++) {
    537 		dev = prop_array_get(cfg, i);
    538 		if (prop_object_type(dev) == PROP_TYPE_DICTIONARY &&
    539 		    prop_dictionary_get_uint32(dev, "addr", &addr) &&
    540 		    prop_dictionary_get_string(dev, "name", &name)) {
    541 			/* Change psu-fru-prom's to standard eeprom's */
    542 			if (addr == 0x36 || addr == 0x37)
    543 				prop_dictionary_set_data(dev, "compatible",
    544 				    "i2c-at24c02", strlen("i2c-at24c02") + 1);
    545 		}
    546 	}
    547 }
    548 
    549 /*
    550  * Fix-up V445 incorrect properties in the OFW tree.
    551  */
    552 static void
    553 fix_properties_v445(device_t busdev)
    554 {
    555 	prop_dictionary_t props = device_properties(busdev);
    556 	prop_array_t cfg;
    557 	prop_object_t dev;
    558 	uint32_t addr;
    559 	const char *name;
    560 	int i, n;
    561 
    562 	cfg = prop_dictionary_get(props, "i2c-child-devices");
    563 	if (!cfg)
    564 		return;
    565 
    566 	n = prop_array_count(cfg);
    567 	for (i = 0; i < n; i++) {
    568 		dev = prop_array_get(cfg, i);
    569 		if (prop_object_type(dev) == PROP_TYPE_DICTIONARY &&
    570 		    prop_dictionary_get_uint32(dev, "addr", &addr) &&
    571 		    prop_dictionary_get_string(dev, "name", &name)) {
    572 			/* Change power-supply-fru-prom to a standard eeprom */
    573 			if (addr == 0x12 || addr == 0x19 ||
    574 			    addr == 0x29 || addr == 0x39)
    575 				prop_dictionary_set_data(dev, "compatible",
    576 				    "i2c-at24c02", strlen("i2c-at24c02") + 1);
    577 			/* Remove "I2c-lm75" from hardware-monitor */
    578 			if (addr == 0x4d)
    579 //				prop_dictionary_remove(dev, "compatible");
    580 				prop_dictionary_set_data(dev, "compatible",
    581 				    "i2c-unknown", strlen("i2c-unknown") + 1);
    582 		}
    583 	}
    584 }
    585 
    586 /* Hardware specific i2c bus properties */
    587 void
    588 set_i2c_bus_props(device_t busdev, uint64_t busnode)
    589 {
    590 
    591 	if (!strcmp(machine_model, "TAD,SPARCLE"))
    592 		add_spdmem_props_sparcle(busdev);
    593 
    594 	if (device_is_a(busdev, "pcfiic")) {
    595 		if (!strcmp(machine_model, "SUNW,Sun-Fire-V240") ||
    596 		    !strcmp(machine_model, "SUNW,Sun-Fire-V210"))
    597 			add_env_sensors_v210(busdev);
    598 
    599 		if (!strcmp(machine_model, "SUNW,A70") ||
    600 		    !strcmp(machine_model, "SUNW,Ultra-25")) {
    601 			add_env_sensors_u45(busdev);
    602 			fix_properties_u45(busdev);
    603 		}
    604 
    605 		/* E450 SUNW,envctrl */
    606 		if (!strcmp(machine_model, "SUNW,Ultra-4"))
    607 			add_i2c_props_e450(busdev, busnode);
    608 
    609 		/* E250 SUNW,envctrltwo */
    610 		if (!strcmp(machine_model, "SUNW,Ultra-250"))
    611 			add_i2c_props_e250(busdev, busnode);
    612 	}
    613 
    614 	if (device_is_a(busdev, "firei2c")) {
    615 		if (!strcmp(machine_model, "SUNW,Sun-Fire-V245") ||
    616 		    !strcmp(machine_model, "SUNW,Sun-Fire-V215")) {
    617 			add_env_sensors_v245(busdev,
    618 			    strcmp(machine_model, "SUNW,Sun-Fire-V245")
    619 			    ? 215 : 245);
    620 			fix_properties_v245(busdev);
    621 		}
    622 
    623 		if (!strcmp(machine_model, "SUNW,Sun-Fire-V445"))
    624 			fix_properties_v445(busdev);
    625 	}
    626 }
    627 
    628 
    629 /* Hardware specific i2c device properties */
    630 void
    631 set_i2c_dev_props(device_t dev, device_t busdev, void *aux)
    632 {
    633 
    634 	if ((!strcmp(machine_model, "SUNW,Sun-Fire-V240") ||
    635 	    !strcmp(machine_model, "SUNW,Sun-Fire-V210"))) {
    636 		if (device_is_a(dev, "pcagpio"))
    637 			add_gpio_props_v210(dev, aux);
    638 
    639 		if (device_is_a(dev, "adm1026hm")) {
    640 			prop_dictionary_t props = device_properties(dev);
    641 			prop_dictionary_set_uint8(props, "fan_div2", 0x55);
    642 			/* There are only 3 fans in the 1st group on V240 */
    643 			if (!strcmp(machine_model, "SUNW,Sun-Fire-V240"))
    644 				prop_dictionary_set_uint8(props,
    645 				    "fan_mask", 0x08);
    646 		}
    647 	}
    648 
    649 	if (!strcmp(machine_model, "SUNW,Sun-Fire-V245") ||
    650 	    !strcmp(machine_model, "SUNW,Sun-Fire-V215")) {
    651 		/* CPU temperatures are offset by 29C */
    652 		if (device_is_a(dev, "adt7462sm")){
    653 			prop_dictionary_t props = device_properties(dev);
    654 			prop_dictionary_set_uint32(props,
    655 			    "temp_off", 0x001d1d00);
    656 		}
    657 		/* Disk status / LED's */
    658 		if (device_is_a(dev, "pcagpio") ||
    659 		     device_is_a(dev, "pcf8574io"))
    660 			add_gpio_props_v245(dev, aux);
    661 
    662 		/* Tach pulse is set incorrectly */
    663 		if (device_is_a(dev, "dbcool")) {
    664 			prop_dictionary_t props = device_properties(dev);
    665 			prop_dictionary_set_uint16(props,
    666 			    "fan_div", 0x0022);
    667 		}
    668 	}
    669 
    670 	if (!strcmp(machine_model, "SUNW,Sun-Blade-2500-S") ||
    671 	    !strcmp(machine_model, "SUNW,Sun-Blade-1500-S")) {
    672 		/* Tach pulse is set incorrectly on both chips */
    673 		if (device_is_a(dev, "dbcool")) {
    674 			prop_dictionary_t props = device_properties(dev);
    675 			prop_dictionary_set_uint16(props,
    676 			    "fan_div", 0x0044);
    677 		}
    678 	}
    679 
    680 	/* U45 has 5 measured fans */
    681 	if (!strcmp(machine_model, "SUNW,A70")) {
    682 		if (device_is_a(dev, "adt7462sm")){
    683 			prop_dictionary_t props = device_properties(dev);
    684 			prop_dictionary_set_uint8(props, "fan_conf", 0x1f);
    685 		}
    686 	}
    687 
    688 	/* U45 pcagpio @ firei2c controls the front panel LED */
    689 	if (!strcmp(machine_model, "SUNW,A70") ||
    690 	    !strcmp(machine_model, "SUNW,Ultra-25"))
    691 		if (device_is_a(dev, "pcagpio") &&
    692 		    device_is_a(busdev, "firei2c"))
    693 			add_gpio_props_u45(dev, aux);
    694 
    695 	/* E250 GPIO's */
    696 	if (!strcmp(machine_model, "SUNW,Ultra-250"))
    697 		if (device_is_a(dev, "pcf8574io"))
    698 			add_gpio_props_e250(dev, aux);
    699 
    700 	if (!strcmp(machine_model, "SUNW,Sun-Fire-V445")) {
    701 		/* CPU temperatures are offset by 29C */
    702 		if (device_is_a(dev, "admtemp")) {
    703 			prop_dictionary_t props = device_properties(dev);
    704 			prop_dictionary_set_uint16(props,
    705 			    "temp_off", 0x1d00);
    706 		}
    707 	}
    708 
    709 	/* Sun use offsets from 2000 but range 1970 to 2069 */
    710 	if (device_is_a(dev, "dsrtc")) {
    711 		prop_dictionary_t props = device_properties(dev);
    712 		prop_dictionary_set_uint(props, "start-year", 2000);
    713 	}
    714 }
    715 
    716 /* Static EDID definitions */
    717 void
    718 set_static_edid(prop_dictionary_t dict)
    719 {
    720 	if (!strcmp(machine_model, "NATE,Meso-999")) {
    721 		prop_data_t edid;
    722 
    723 		DPRINTF(ACDB_PROBE, ("\nAdding EDID for Meso-999 "));
    724 		edid = prop_data_create_copy(edid_meso999,
    725 		    sizeof(edid_meso999));
    726 		prop_dictionary_set(dict, "EDID:1", edid);
    727 		prop_object_release(edid);
    728 	}
    729 }
    730