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