1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/param.h> 28 #include <sys/systm.h> 29 #include <sys/sysmacros.h> 30 #include <sys/sunddi.h> 31 #include <sys/esunddi.h> 32 #include <sys/sunndi.h> 33 #include <sys/conf.h> 34 35 #include <sys/platform_module.h> 36 #include <sys/errno.h> 37 38 #include <sys/sunldi.h> 39 #include <sys/file.h> 40 41 #define SHARED_PCF8584_PATH "/pci@8,700000/ebus@5/i2c@1,2e/nvram@0,a0" 42 static dev_info_t *shared_pcf8584_dip; 43 static kmutex_t excal_pcf8584_mutex; 44 45 int (*p2get_mem_unum)(int, uint64_t, char *, int, int *); 46 47 /* 48 * Excalibur fan information 49 */ 50 typedef struct xcalfan_info { 51 char *pathname; 52 int8_t val8; 53 ldi_handle_t lh; 54 } xcalfan_info_t; 55 56 static xcalfan_info_t xcalfans[] = { 57 {"/pci@8,700000/ebus@5/i2c@1,30/fan-control@0,48:2", 63, NULL}, 58 {"/pci@8,700000/ebus@5/i2c@1,30/fan-control@0,48:0", 63, NULL}, 59 {"/pci@8,700000/ebus@5/i2c@1,30/fan-control@0,48:4", 31, NULL} 60 }; 61 62 #define NFANS (sizeof (xcalfans) / sizeof (xcalfans[0])) 63 64 void 65 startup_platform(void) 66 { 67 mutex_init(&excal_pcf8584_mutex, NULL, MUTEX_ADAPTIVE, NULL); 68 } 69 70 int 71 set_platform_tsb_spares() 72 { 73 return (0); 74 } 75 76 void 77 set_platform_defaults(void) 78 { 79 } 80 81 void 82 load_platform_drivers(void) 83 { 84 ldi_ident_t li; 85 dev_info_t *dip; 86 char **drv; 87 int i, err; 88 89 static char *boot_time_drivers[] = { 90 "todds1287", 91 "us", 92 "mc-us3", 93 "bbc_beep", 94 "max1617", 95 "tda8444", 96 "seeprom", 97 NULL 98 }; 99 100 for (drv = boot_time_drivers; *drv; drv++) { 101 if ((i_ddi_attach_hw_nodes(*drv) != DDI_SUCCESS) && 102 (strcmp(*drv, "us") != 0)) 103 /* 104 * It is OK if 'us' driver doesn't load. It's 105 * not available in Core cluster. 106 */ 107 cmn_err(CE_WARN, "Failed to install \"%s\" driver.", 108 *drv); 109 } 110 111 /* 112 * mc-us3 must stay loaded for plat_get_mem_unum() 113 */ 114 (void) ddi_hold_driver(ddi_name_to_major("mc-us3")); 115 116 /* 117 * Figure out which pcf8584_dip is shared with OBP for the nvram 118 * device, so the lock can be acquired. 119 * 120 * This should really be done elsewhere, like startup_platform, but 121 * that runs before the devinfo tree is setup with configure(). 122 * So it is here until there is a better place. 123 */ 124 dip = e_ddi_hold_devi_by_path(SHARED_PCF8584_PATH, 0); 125 126 ASSERT(dip != NULL); 127 shared_pcf8584_dip = ddi_get_parent(dip); 128 129 ndi_hold_devi(shared_pcf8584_dip); 130 ndi_rele_devi(dip); 131 132 li = ldi_ident_from_anon(); 133 for (i = 0; i < NFANS; ++i) { 134 err = ldi_open_by_name(xcalfans[i].pathname, 135 FWRITE, kcred, &xcalfans[i].lh, li); 136 137 if (err != 0) { 138 cmn_err(CE_WARN, "plat_fan_blast: " 139 "Failed to get fan device handle for %s", 140 xcalfans[i].pathname); 141 continue; 142 } 143 } 144 ldi_ident_release(li); 145 } 146 147 /*ARGSUSED*/ 148 int 149 plat_cpu_poweron(struct cpu *cp) 150 { 151 return (ENOTSUP); /* not supported on this platform */ 152 } 153 154 /*ARGSUSED*/ 155 int 156 plat_cpu_poweroff(struct cpu *cp) 157 { 158 return (ENOTSUP); /* not supported on this platform */ 159 } 160 161 /*ARGSUSED*/ 162 void 163 plat_freelist_process(int mnode) 164 { 165 } 166 167 char *platform_module_list[] = { 168 "schppm", /* must attach before xcalppm */ 169 "xcalppm", 170 (char *)0 171 }; 172 173 /*ARGSUSED*/ 174 void 175 plat_tod_fault(enum tod_fault_type tod_bad) 176 { 177 } 178 179 /*ARGSUSED*/ 180 int 181 plat_get_mem_unum(int synd_code, uint64_t flt_addr, int flt_bus_id, 182 int flt_in_memory, ushort_t flt_status, char *buf, int buflen, int *lenp) 183 { 184 if (flt_in_memory && (p2get_mem_unum != NULL)) 185 return (p2get_mem_unum(synd_code, P2ALIGN(flt_addr, 8), 186 buf, buflen, lenp)); 187 else 188 return (ENOTSUP); 189 } 190 191 int 192 plat_get_cpu_unum(int cpuid, char *buf, int buflen, int *lenp) 193 { 194 if (snprintf(buf, buflen, "Slot %d", cpuid) >= buflen) { 195 return (ENOSPC); 196 } else { 197 *lenp = strlen(buf); 198 return (0); 199 } 200 } 201 202 /* 203 * Unfortunately, excal's BBC pcf8584 controller is used by both OBP 204 * and the OS's i2c drivers. The 'eeprom' command executes 205 * OBP code to handle property requests. If eeprom didn't do this, or if the 206 * controllers were partitioned so that all devices on a given controller were 207 * driven by either OBP or the OS, this wouldn't be necessary. 208 * 209 * Note that getprop doesn't have the same issue as it reads from cached 210 * memory in OBP. 211 */ 212 213 /* 214 * Common locking enter code 215 */ 216 void 217 plat_setprop_enter(void) 218 { 219 mutex_enter(&excal_pcf8584_mutex); 220 } 221 222 /* 223 * Common locking exit code 224 */ 225 void 226 plat_setprop_exit(void) 227 { 228 mutex_exit(&excal_pcf8584_mutex); 229 } 230 231 /* 232 * Called by pcf8584 driver 233 */ 234 void 235 plat_shared_i2c_enter(dev_info_t *dip) 236 { 237 if (dip == shared_pcf8584_dip) { 238 plat_setprop_enter(); 239 } 240 } 241 242 /* 243 * Called by pcf8584 driver 244 */ 245 void 246 plat_shared_i2c_exit(dev_info_t *dip) 247 { 248 if (dip == shared_pcf8584_dip) { 249 plat_setprop_exit(); 250 } 251 } 252 253 /* 254 * Set platform fans to maximum speed 255 */ 256 void 257 plat_fan_blast(void) 258 { 259 struct uio uio; 260 struct iovec iov; 261 int8_t fv; 262 int err; 263 int i; 264 265 for (i = 0; i < NFANS; ++i) { 266 fv = xcalfans[i].val8; 267 bzero(&uio, sizeof (uio)); 268 bzero(&iov, sizeof (iov)); 269 iov.iov_base = &fv; 270 iov.iov_len = sizeof (fv); 271 uio.uio_iov = &iov; 272 uio.uio_iovcnt = 1; 273 uio.uio_loffset = 0; 274 uio.uio_segflg = UIO_SYSSPACE; 275 uio.uio_resid = sizeof (fv); 276 277 err = ldi_write(xcalfans[i].lh, &uio, kcred); 278 if (err != 0) { 279 if (err == EAGAIN) { 280 cmn_err(CE_WARN, "!plat_fan_blast: Cannot " 281 "write %d to %s now, try again later.", 282 xcalfans[i].val8, xcalfans[i].pathname); 283 } else { 284 cmn_err(CE_WARN, "plat_fan_blast: " 285 "Error %d while writing %d to %s.", err, 286 xcalfans[i].val8, xcalfans[i].pathname); 287 } 288 } 289 } 290 } 291