1ae115bc7Smrj /* 2ae115bc7Smrj * CDDL HEADER START 3ae115bc7Smrj * 4ae115bc7Smrj * The contents of this file are subject to the terms of the 5ae115bc7Smrj * Common Development and Distribution License (the "License"). 6ae115bc7Smrj * You may not use this file except in compliance with the License. 7ae115bc7Smrj * 8ae115bc7Smrj * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9ae115bc7Smrj * or http://www.opensolaris.org/os/licensing. 10ae115bc7Smrj * See the License for the specific language governing permissions 11ae115bc7Smrj * and limitations under the License. 12ae115bc7Smrj * 13ae115bc7Smrj * When distributing Covered Code, include this CDDL HEADER in each 14ae115bc7Smrj * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15ae115bc7Smrj * If applicable, add the following below this CDDL HEADER, with the 16ae115bc7Smrj * fields enclosed by brackets "[]" replaced with your own identifying 17ae115bc7Smrj * information: Portions Copyright [yyyy] [name of copyright owner] 18ae115bc7Smrj * 19ae115bc7Smrj * CDDL HEADER END 20ae115bc7Smrj */ 21ae115bc7Smrj /* 22a3463f0aSDana Myers * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23ae115bc7Smrj * Use is subject to license terms. 24*26f3cdf0SGordon Ross * Copyright 2011 Joyent, Inc. All rights reserved. 25*26f3cdf0SGordon Ross * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 26ae115bc7Smrj */ 27ae115bc7Smrj /* 28ae115bc7Smrj * Solaris x86 ACPI CA Embedded Controller operation region handler 29ae115bc7Smrj */ 30ae115bc7Smrj 31ae115bc7Smrj #include <sys/file.h> 32ae115bc7Smrj #include <sys/errno.h> 33ae115bc7Smrj #include <sys/conf.h> 34ae115bc7Smrj #include <sys/modctl.h> 35ae115bc7Smrj #include <sys/open.h> 36ae115bc7Smrj #include <sys/stat.h> 37ae115bc7Smrj #include <sys/ddi.h> 38ae115bc7Smrj #include <sys/sunddi.h> 39ae115bc7Smrj #include <sys/note.h> 40a3463f0aSDana Myers #include <sys/atomic.h> 41ae115bc7Smrj 42ae115bc7Smrj #include <sys/acpi/acpi.h> 43ae115bc7Smrj #include <sys/acpica.h> 44ae115bc7Smrj 45ae115bc7Smrj /* 46ae115bc7Smrj * EC status bits 47*26f3cdf0SGordon Ross * Low to high 48*26f3cdf0SGordon Ross * Output buffer full? 49*26f3cdf0SGordon Ross * Input buffer full? 50*26f3cdf0SGordon Ross * <reserved> 51*26f3cdf0SGordon Ross * Data register is command byte? 52*26f3cdf0SGordon Ross * Burst mode enabled? 53*26f3cdf0SGordon Ross * SCI event? 54*26f3cdf0SGordon Ross * SMI event? 55*26f3cdf0SGordon Ross * <reserved> 56ae115bc7Smrj */ 57ae115bc7Smrj #define EC_OBF (0x01) 58*26f3cdf0SGordon Ross #define EC_IBF (0x02) 59*26f3cdf0SGordon Ross #define EC_DRC (0x08) 60*26f3cdf0SGordon Ross #define EC_BME (0x10) 61ae115bc7Smrj #define EC_SCI (0x20) 62*26f3cdf0SGordon Ross #define EC_SMI (0x40) 63ae115bc7Smrj 64ae115bc7Smrj /* 65ae115bc7Smrj * EC commands 66ae115bc7Smrj */ 67ae115bc7Smrj #define EC_RD (0x80) 68ae115bc7Smrj #define EC_WR (0x81) 69ae115bc7Smrj #define EC_BE (0x82) 70ae115bc7Smrj #define EC_BD (0x83) 71ae115bc7Smrj #define EC_QR (0x84) 72ae115bc7Smrj 73ae115bc7Smrj #define IO_PORT_DES (0x47) 74ae115bc7Smrj 75ae115bc7Smrj /* 76ae115bc7Smrj * EC softstate 77ae115bc7Smrj */ 78*26f3cdf0SGordon Ross static struct ec_softstate { 79*26f3cdf0SGordon Ross uint8_t ec_ok; /* != 0 if we have ec_base, ec_sc */ 80ae115bc7Smrj uint16_t ec_base; /* base of EC I/O port - data */ 81ae115bc7Smrj uint16_t ec_sc; /* EC status/command */ 82*26f3cdf0SGordon Ross ACPI_HANDLE ec_dev_hdl; /* EC device handle */ 83*26f3cdf0SGordon Ross ACPI_HANDLE ec_gpe_hdl; /* GPE info */ 84*26f3cdf0SGordon Ross ACPI_INTEGER ec_gpe_bit; 85ae115bc7Smrj kmutex_t ec_mutex; /* serialize access to EC */ 86ae115bc7Smrj } ec; 87ae115bc7Smrj 88ae115bc7Smrj /* I/O port range descriptor */ 89ae115bc7Smrj typedef struct io_port_des { 90ae115bc7Smrj uint8_t type; 91ae115bc7Smrj uint8_t decode; 92ae115bc7Smrj uint8_t min_base_lo; 93ae115bc7Smrj uint8_t min_base_hi; 94ae115bc7Smrj uint8_t max_base_lo; 95ae115bc7Smrj uint8_t max_base_hi; 96ae115bc7Smrj uint8_t align; 97ae115bc7Smrj uint8_t len; 98ae115bc7Smrj } io_port_des_t; 99ae115bc7Smrj 100ae115bc7Smrj /* 101*26f3cdf0SGordon Ross * Patchable to ignore an ECDT, in case using that 102*26f3cdf0SGordon Ross * causes problems on someone's system. 103*26f3cdf0SGordon Ross */ 104*26f3cdf0SGordon Ross int ec_ignore_ecdt = 0; 105*26f3cdf0SGordon Ross 106*26f3cdf0SGordon Ross /* 107a3463f0aSDana Myers * Patchable timeout values for EC input-buffer-full-clear 108a3463f0aSDana Myers * and output-buffer-full-set. These are in 10uS units and 109a3463f0aSDana Myers * default to 1 second. 110a3463f0aSDana Myers */ 111a3463f0aSDana Myers int ibf_clear_timeout = 100000; 112a3463f0aSDana Myers int obf_set_timeout = 100000; 113a3463f0aSDana Myers 114a3463f0aSDana Myers /* 115*26f3cdf0SGordon Ross * ACPI CA EC address space handler support functions 116ae115bc7Smrj */ 117ae115bc7Smrj 118*26f3cdf0SGordon Ross /* 119*26f3cdf0SGordon Ross * Busy-wait for IBF to clear 120*26f3cdf0SGordon Ross * return < 0 for time out, 0 for no error 121*26f3cdf0SGordon Ross */ 122*26f3cdf0SGordon Ross static int 123*26f3cdf0SGordon Ross ec_wait_ibf_clear(int sc_addr) 124*26f3cdf0SGordon Ross { 125*26f3cdf0SGordon Ross int cnt; 126*26f3cdf0SGordon Ross 127*26f3cdf0SGordon Ross cnt = ibf_clear_timeout; 128*26f3cdf0SGordon Ross while (inb(sc_addr) & EC_IBF) { 129*26f3cdf0SGordon Ross if (cnt-- <= 0) 130*26f3cdf0SGordon Ross return (-1); 131*26f3cdf0SGordon Ross drv_usecwait(10); 132*26f3cdf0SGordon Ross } 133*26f3cdf0SGordon Ross return (0); 134*26f3cdf0SGordon Ross } 135*26f3cdf0SGordon Ross 136*26f3cdf0SGordon Ross /* 137*26f3cdf0SGordon Ross * Busy-wait for OBF to set 138*26f3cdf0SGordon Ross * return < 0 for time out, 0 for no error 139*26f3cdf0SGordon Ross */ 140*26f3cdf0SGordon Ross static int 141*26f3cdf0SGordon Ross ec_wait_obf_set(int sc_addr) 142*26f3cdf0SGordon Ross { 143*26f3cdf0SGordon Ross int cnt; 144*26f3cdf0SGordon Ross 145*26f3cdf0SGordon Ross cnt = obf_set_timeout; 146*26f3cdf0SGordon Ross while (!(inb(sc_addr) & EC_OBF)) { 147*26f3cdf0SGordon Ross if (cnt-- <= 0) 148*26f3cdf0SGordon Ross return (-1); 149*26f3cdf0SGordon Ross drv_usecwait(10); 150*26f3cdf0SGordon Ross } 151*26f3cdf0SGordon Ross return (0); 152ae115bc7Smrj } 153ae115bc7Smrj 154a3463f0aSDana Myers /* 155a3463f0aSDana Myers * Only called from ec_handler(), which validates ec_ok 156a3463f0aSDana Myers */ 157ae115bc7Smrj static int 158ae115bc7Smrj ec_rd(int addr) 159ae115bc7Smrj { 160ae115bc7Smrj int cnt, rv; 161ae115bc7Smrj uint8_t sc; 162ae115bc7Smrj 163ae115bc7Smrj mutex_enter(&ec.ec_mutex); 164ae115bc7Smrj sc = inb(ec.ec_sc); 165ae115bc7Smrj 166ae115bc7Smrj #ifdef DEBUG 167ae115bc7Smrj if (sc & EC_IBF) { 168ae115bc7Smrj cmn_err(CE_NOTE, "!ec_rd: IBF already set"); 169ae115bc7Smrj } 170ae115bc7Smrj 171ae115bc7Smrj if (sc & EC_OBF) { 172ae115bc7Smrj cmn_err(CE_NOTE, "!ec_rd: OBF already set"); 173ae115bc7Smrj } 174ae115bc7Smrj #endif 175ae115bc7Smrj 176ae115bc7Smrj outb(ec.ec_sc, EC_RD); /* output a read command */ 177ae115bc7Smrj if (ec_wait_ibf_clear(ec.ec_sc) < 0) { 178ae115bc7Smrj cmn_err(CE_NOTE, "!ec_rd:1: timed-out waiting " 179ae115bc7Smrj "for IBF to clear"); 180ae115bc7Smrj mutex_exit(&ec.ec_mutex); 181ae115bc7Smrj return (-1); 182ae115bc7Smrj } 183ae115bc7Smrj 184ae115bc7Smrj outb(ec.ec_base, addr); /* output addr */ 185ae115bc7Smrj if (ec_wait_ibf_clear(ec.ec_sc) < 0) { 186ae115bc7Smrj cmn_err(CE_NOTE, "!ec_rd:2: timed-out waiting " 187ae115bc7Smrj "for IBF to clear"); 188ae115bc7Smrj mutex_exit(&ec.ec_mutex); 189ae115bc7Smrj return (-1); 190ae115bc7Smrj } 191ae115bc7Smrj if (ec_wait_obf_set(ec.ec_sc) < 0) { 192ae115bc7Smrj cmn_err(CE_NOTE, "!ec_rd:1: timed-out waiting " 193ae115bc7Smrj "for OBF to set"); 194ae115bc7Smrj mutex_exit(&ec.ec_mutex); 195ae115bc7Smrj return (-1); 196ae115bc7Smrj } 197ae115bc7Smrj 198ae115bc7Smrj rv = inb(ec.ec_base); 199ae115bc7Smrj mutex_exit(&ec.ec_mutex); 200ae115bc7Smrj return (rv); 201ae115bc7Smrj } 202ae115bc7Smrj 203a3463f0aSDana Myers /* 204a3463f0aSDana Myers * Only called from ec_handler(), which validates ec_ok 205a3463f0aSDana Myers */ 206ae115bc7Smrj static int 207*26f3cdf0SGordon Ross ec_wr(int addr, uint8_t val) 208ae115bc7Smrj { 209ae115bc7Smrj int cnt; 210ae115bc7Smrj uint8_t sc; 211ae115bc7Smrj 212ae115bc7Smrj mutex_enter(&ec.ec_mutex); 213ae115bc7Smrj sc = inb(ec.ec_sc); 214ae115bc7Smrj 215ae115bc7Smrj #ifdef DEBUG 216ae115bc7Smrj if (sc & EC_IBF) { 217ae115bc7Smrj cmn_err(CE_NOTE, "!ec_wr: IBF already set"); 218ae115bc7Smrj } 219ae115bc7Smrj 220ae115bc7Smrj if (sc & EC_OBF) { 221ae115bc7Smrj cmn_err(CE_NOTE, "!ec_wr: OBF already set"); 222ae115bc7Smrj } 223ae115bc7Smrj #endif 224ae115bc7Smrj 225ae115bc7Smrj outb(ec.ec_sc, EC_WR); /* output a write command */ 226ae115bc7Smrj if (ec_wait_ibf_clear(ec.ec_sc) < 0) { 227ae115bc7Smrj cmn_err(CE_NOTE, "!ec_wr:1: timed-out waiting " 228ae115bc7Smrj "for IBF to clear"); 229ae115bc7Smrj mutex_exit(&ec.ec_mutex); 230ae115bc7Smrj return (-1); 231ae115bc7Smrj } 232ae115bc7Smrj 233ae115bc7Smrj outb(ec.ec_base, addr); /* output addr */ 234ae115bc7Smrj if (ec_wait_ibf_clear(ec.ec_sc) < 0) { 235ae115bc7Smrj cmn_err(CE_NOTE, "!ec_wr:2: timed-out waiting " 236ae115bc7Smrj "for IBF to clear"); 237ae115bc7Smrj mutex_exit(&ec.ec_mutex); 238ae115bc7Smrj return (-1); 239ae115bc7Smrj } 240ae115bc7Smrj 241*26f3cdf0SGordon Ross outb(ec.ec_base, val); /* write data */ 242ae115bc7Smrj if (ec_wait_ibf_clear(ec.ec_sc) < 0) { 243ae115bc7Smrj cmn_err(CE_NOTE, "!ec_wr:3: timed-out waiting " 244ae115bc7Smrj "for IBF to clear"); 245ae115bc7Smrj mutex_exit(&ec.ec_mutex); 246ae115bc7Smrj return (-1); 247ae115bc7Smrj } 248ae115bc7Smrj 249ae115bc7Smrj mutex_exit(&ec.ec_mutex); 250ae115bc7Smrj return (0); 251ae115bc7Smrj } 252ae115bc7Smrj 253a3463f0aSDana Myers /* 254a3463f0aSDana Myers * Only called from ec_gpe_callback(), which validates ec_ok 255a3463f0aSDana Myers */ 256ae115bc7Smrj static int 257ae115bc7Smrj ec_query(void) 258ae115bc7Smrj { 259ae115bc7Smrj int cnt, rv; 260ae115bc7Smrj uint8_t sc; 261ae115bc7Smrj 262ae115bc7Smrj mutex_enter(&ec.ec_mutex); 263ae115bc7Smrj outb(ec.ec_sc, EC_QR); /* output a query command */ 264ae115bc7Smrj if (ec_wait_ibf_clear(ec.ec_sc) < 0) { 265ae115bc7Smrj cmn_err(CE_NOTE, "!ec_query:1: timed-out waiting " 266ae115bc7Smrj "for IBF to clear"); 267ae115bc7Smrj mutex_exit(&ec.ec_mutex); 268ae115bc7Smrj return (-1); 269ae115bc7Smrj } 270ae115bc7Smrj 271ae115bc7Smrj if (ec_wait_obf_set(ec.ec_sc) < 0) { 272ae115bc7Smrj cmn_err(CE_NOTE, "!ec_query:1: timed-out waiting " 273ae115bc7Smrj "for OBF to set"); 274ae115bc7Smrj mutex_exit(&ec.ec_mutex); 275ae115bc7Smrj return (-1); 276ae115bc7Smrj } 277ae115bc7Smrj 278ae115bc7Smrj rv = inb(ec.ec_base); 279ae115bc7Smrj mutex_exit(&ec.ec_mutex); 280ae115bc7Smrj return (rv); 281ae115bc7Smrj } 282ae115bc7Smrj 283*26f3cdf0SGordon Ross /* 284*26f3cdf0SGordon Ross * ACPI CA EC address space handler 285*26f3cdf0SGordon Ross * Requires: ec.ec_sc, ec.ec_base 286*26f3cdf0SGordon Ross */ 287ae115bc7Smrj static ACPI_STATUS 288ae115bc7Smrj ec_handler(UINT32 func, ACPI_PHYSICAL_ADDRESS addr, UINT32 width, 289*26f3cdf0SGordon Ross UINT64 *val, void *context, void *regcontext) 290ae115bc7Smrj { 291ae115bc7Smrj _NOTE(ARGUNUSED(context, regcontext)) 292*26f3cdf0SGordon Ross int i, tw, tmp; 293ae115bc7Smrj 294a3463f0aSDana Myers /* Guard against unexpected invocation */ 295a3463f0aSDana Myers if (ec.ec_ok == 0) 296a3463f0aSDana Myers return (AE_ERROR); 297a3463f0aSDana Myers 298ae115bc7Smrj /* 299ae115bc7Smrj * Add safety checks for BIOSes not strictly compliant 300ae115bc7Smrj * with ACPI spec 301ae115bc7Smrj */ 302*26f3cdf0SGordon Ross if ((width % 8) != 0) { 303a3463f0aSDana Myers cmn_err(CE_NOTE, "!ec_handler: invalid width %d", width); 304*26f3cdf0SGordon Ross return (AE_BAD_PARAMETER); 305*26f3cdf0SGordon Ross } 306*26f3cdf0SGordon Ross if (val == NULL) { 307*26f3cdf0SGordon Ross cmn_err(CE_NOTE, "!ec_handler: NULL value pointer"); 308*26f3cdf0SGordon Ross return (AE_BAD_PARAMETER); 309ae115bc7Smrj } 310ae115bc7Smrj 311*26f3cdf0SGordon Ross while (width > 0) { 312*26f3cdf0SGordon Ross 313*26f3cdf0SGordon Ross /* One UINT64 *val at a time. */ 314*26f3cdf0SGordon Ross tw = min(width, 64); 315*26f3cdf0SGordon Ross 316*26f3cdf0SGordon Ross if (func == ACPI_READ) 317*26f3cdf0SGordon Ross *val = 0; 318*26f3cdf0SGordon Ross 319*26f3cdf0SGordon Ross /* Do I/O of up to 64 bits */ 320*26f3cdf0SGordon Ross for (i = 0; i < tw; i += 8, addr++) { 321ae115bc7Smrj switch (func) { 322ae115bc7Smrj case ACPI_READ: 323ae115bc7Smrj tmp = ec_rd(addr); 324ae115bc7Smrj if (tmp < 0) 325ae115bc7Smrj return (AE_ERROR); 326*26f3cdf0SGordon Ross *val |= ((UINT64)tmp) << i; 327ae115bc7Smrj break; 328ae115bc7Smrj case ACPI_WRITE: 329*26f3cdf0SGordon Ross tmp = ((*val) >> i) & 0xFF; 330*26f3cdf0SGordon Ross if (ec_wr(addr, (uint8_t)tmp) < 0) 331ae115bc7Smrj return (AE_ERROR); 332ae115bc7Smrj break; 333ae115bc7Smrj default: 334ae115bc7Smrj return (AE_ERROR); 335ae115bc7Smrj } 336*26f3cdf0SGordon Ross } 337*26f3cdf0SGordon Ross val++; 338*26f3cdf0SGordon Ross width -= tw; 339*26f3cdf0SGordon Ross } 340ae115bc7Smrj 341ae115bc7Smrj return (AE_OK); 342ae115bc7Smrj } 343ae115bc7Smrj 344*26f3cdf0SGordon Ross /* 345*26f3cdf0SGordon Ross * Called via taskq entry enqueued by ec_gpe_handler, 346*26f3cdf0SGordon Ross * which validates ec_ok 347*26f3cdf0SGordon Ross */ 348ae115bc7Smrj static void 349ae115bc7Smrj ec_gpe_callback(void *ctx) 350ae115bc7Smrj { 351ae115bc7Smrj _NOTE(ARGUNUSED(ctx)) 352ae115bc7Smrj char query_str[5]; 353ae115bc7Smrj int query; 354ae115bc7Smrj 355ae115bc7Smrj if (!(inb(ec.ec_sc) & EC_SCI)) 356*26f3cdf0SGordon Ross goto out; 357a3463f0aSDana Myers 358ae115bc7Smrj query = ec_query(); 359*26f3cdf0SGordon Ross if (query < 0) 360*26f3cdf0SGordon Ross goto out; 361ae115bc7Smrj 362*26f3cdf0SGordon Ross (void) snprintf(query_str, 5, "_Q%02X", (uint8_t)query); 363*26f3cdf0SGordon Ross (void) AcpiEvaluateObject(ec.ec_dev_hdl, query_str, NULL, NULL); 364*26f3cdf0SGordon Ross 365*26f3cdf0SGordon Ross out: 366*26f3cdf0SGordon Ross AcpiFinishGpe(ec.ec_gpe_hdl, ec.ec_gpe_bit); 367ae115bc7Smrj } 368ae115bc7Smrj 369ae115bc7Smrj static UINT32 370*26f3cdf0SGordon Ross ec_gpe_handler(ACPI_HANDLE GpeDevice, UINT32 GpeNumber, void *ctx) 371ae115bc7Smrj { 372*26f3cdf0SGordon Ross _NOTE(ARGUNUSED(GpeDevice)) 373*26f3cdf0SGordon Ross _NOTE(ARGUNUSED(GpeNumber)) 374ae115bc7Smrj _NOTE(ARGUNUSED(ctx)) 375ae115bc7Smrj 376*26f3cdf0SGordon Ross /* 377*26f3cdf0SGordon Ross * With ec_ok==0, we will not install a GPE handler, 378*26f3cdf0SGordon Ross * so this is just paranoia. But if this were to 379*26f3cdf0SGordon Ross * happen somehow, don't add the taskq entry, and 380*26f3cdf0SGordon Ross * tell the caller we're done with this GPE call. 381*26f3cdf0SGordon Ross */ 382*26f3cdf0SGordon Ross if (ec.ec_ok == 0) 383*26f3cdf0SGordon Ross return (ACPI_REENABLE_GPE); 384*26f3cdf0SGordon Ross 385ae115bc7Smrj AcpiOsExecute(OSL_GPE_HANDLER, ec_gpe_callback, NULL); 386*26f3cdf0SGordon Ross 387*26f3cdf0SGordon Ross /* 388*26f3cdf0SGordon Ross * Returning zero tells the ACPI system that we will 389*26f3cdf0SGordon Ross * handle this event asynchronously. 390*26f3cdf0SGordon Ross */ 391ae115bc7Smrj return (0); 392ae115bc7Smrj } 393ae115bc7Smrj 394ae115bc7Smrj /* 395*26f3cdf0SGordon Ross * Some systems describe the EC using an "ECDT" (table). 396*26f3cdf0SGordon Ross * If we find one use it (unless ec_ignore_ecdt is set). 397*26f3cdf0SGordon Ross * Modern systems don't provide an ECDT. 398ae115bc7Smrj */ 399*26f3cdf0SGordon Ross static ACPI_STATUS 400*26f3cdf0SGordon Ross ec_probe_ecdt(void) 401ae115bc7Smrj { 402*26f3cdf0SGordon Ross ACPI_TABLE_HEADER *th; 403*26f3cdf0SGordon Ross ACPI_TABLE_ECDT *ecdt; 404*26f3cdf0SGordon Ross ACPI_HANDLE dev_hdl; 405*26f3cdf0SGordon Ross ACPI_STATUS status; 406ae115bc7Smrj 407*26f3cdf0SGordon Ross status = AcpiGetTable(ACPI_SIG_ECDT, 1, &th); 408*26f3cdf0SGordon Ross #ifndef DEBUG 409*26f3cdf0SGordon Ross if (status == AE_NOT_FOUND) 410*26f3cdf0SGordon Ross return (status); 411*26f3cdf0SGordon Ross #endif 412*26f3cdf0SGordon Ross if (ACPI_FAILURE(status)) { 413*26f3cdf0SGordon Ross cmn_err(CE_NOTE, "!acpica: ECDT not found"); 414*26f3cdf0SGordon Ross return (status); 415ae115bc7Smrj } 416*26f3cdf0SGordon Ross if (ec_ignore_ecdt) { 417*26f3cdf0SGordon Ross /* pretend it was not found */ 418*26f3cdf0SGordon Ross cmn_err(CE_NOTE, "!acpica: ECDT ignored"); 419*26f3cdf0SGordon Ross return (AE_NOT_FOUND); 420*26f3cdf0SGordon Ross } 421*26f3cdf0SGordon Ross 422*26f3cdf0SGordon Ross ecdt = (ACPI_TABLE_ECDT *)th; 423*26f3cdf0SGordon Ross if (ecdt->Control.BitWidth != 8 || 424*26f3cdf0SGordon Ross ecdt->Data.BitWidth != 8) { 425*26f3cdf0SGordon Ross cmn_err(CE_NOTE, "!acpica: bad ECDT I/O width"); 426*26f3cdf0SGordon Ross return (AE_BAD_VALUE); 427*26f3cdf0SGordon Ross } 428*26f3cdf0SGordon Ross status = AcpiGetHandle(NULL, (char *)ecdt->Id, &dev_hdl); 429*26f3cdf0SGordon Ross if (ACPI_FAILURE(status)) { 430*26f3cdf0SGordon Ross cmn_err(CE_NOTE, "!acpica: no ECDT device handle"); 431*26f3cdf0SGordon Ross return (status); 432ae115bc7Smrj } 433ae115bc7Smrj 434ae115bc7Smrj /* 435*26f3cdf0SGordon Ross * Success. Save info for attach. 436ae115bc7Smrj */ 437*26f3cdf0SGordon Ross ec.ec_base = ecdt->Data.Address; 438*26f3cdf0SGordon Ross ec.ec_sc = ecdt->Control.Address; 439*26f3cdf0SGordon Ross ec.ec_dev_hdl = dev_hdl; 440*26f3cdf0SGordon Ross ec.ec_gpe_hdl = NULL; 441*26f3cdf0SGordon Ross ec.ec_gpe_bit = ecdt->Gpe; 442*26f3cdf0SGordon Ross ec.ec_ok = 1; 443ae115bc7Smrj 444*26f3cdf0SGordon Ross #ifdef DEBUG 445*26f3cdf0SGordon Ross cmn_err(CE_NOTE, "!acpica:ec_probe_ecdt: success"); 446*26f3cdf0SGordon Ross #endif 447ae115bc7Smrj return (0); 448ae115bc7Smrj } 449ae115bc7Smrj 450ae115bc7Smrj /* 451ae115bc7Smrj * Called from AcpiWalkDevices() when an EC device is found 452ae115bc7Smrj */ 453ae115bc7Smrj static ACPI_STATUS 454*26f3cdf0SGordon Ross ec_find(ACPI_HANDLE obj, UINT32 nest, void *context, void **rv) 455ae115bc7Smrj { 456*26f3cdf0SGordon Ross _NOTE(ARGUNUSED(nest, rv)) 457ae115bc7Smrj 458*26f3cdf0SGordon Ross *((ACPI_HANDLE *)context) = obj; 459*26f3cdf0SGordon Ross return (AE_OK); 460*26f3cdf0SGordon Ross } 461ae115bc7Smrj 462ae115bc7Smrj /* 463*26f3cdf0SGordon Ross * Normal way to get the details about the EC, 464*26f3cdf0SGordon Ross * by searching the name space. 465ae115bc7Smrj */ 466*26f3cdf0SGordon Ross static ACPI_STATUS 467*26f3cdf0SGordon Ross ec_probe_ns(void) 468*26f3cdf0SGordon Ross { 469*26f3cdf0SGordon Ross ACPI_HANDLE dev_hdl; 470*26f3cdf0SGordon Ross ACPI_BUFFER buf, crs; 471*26f3cdf0SGordon Ross ACPI_OBJECT *gpe_obj; 472*26f3cdf0SGordon Ross ACPI_HANDLE gpe_hdl; 473*26f3cdf0SGordon Ross ACPI_INTEGER gpe_bit; 474*26f3cdf0SGordon Ross ACPI_STATUS status; 475*26f3cdf0SGordon Ross int i, io_port_cnt; 476*26f3cdf0SGordon Ross uint16_t ec_sc, ec_base; 477*26f3cdf0SGordon Ross 478*26f3cdf0SGordon Ross dev_hdl = NULL; 479*26f3cdf0SGordon Ross (void) AcpiGetDevices("PNP0C09", &ec_find, (void *)&dev_hdl, NULL); 480*26f3cdf0SGordon Ross if (dev_hdl == NULL) { 481*26f3cdf0SGordon Ross #ifdef DEBUG 482*26f3cdf0SGordon Ross /* Not an error, just no EC on this machine. */ 483*26f3cdf0SGordon Ross cmn_err(CE_WARN, "!acpica:ec_probe_ns: " 484*26f3cdf0SGordon Ross "PNP0C09 not found"); 485*26f3cdf0SGordon Ross #endif 486*26f3cdf0SGordon Ross return (AE_NOT_FOUND); 487*26f3cdf0SGordon Ross } 488ae115bc7Smrj 489ae115bc7Smrj /* 490ae115bc7Smrj * Find ec_base and ec_sc addresses 491ae115bc7Smrj */ 492ae115bc7Smrj crs.Length = ACPI_ALLOCATE_BUFFER; 493*26f3cdf0SGordon Ross status = AcpiEvaluateObjectTyped(dev_hdl, "_CRS", NULL, &crs, 494*26f3cdf0SGordon Ross ACPI_TYPE_BUFFER); 495*26f3cdf0SGordon Ross if (ACPI_FAILURE(status)) { 496*26f3cdf0SGordon Ross cmn_err(CE_WARN, "!acpica:ec_probe_ns: " 497*26f3cdf0SGordon Ross "_CRS object evaluate failed"); 498*26f3cdf0SGordon Ross return (status); 499ae115bc7Smrj } 500ae115bc7Smrj 501db2bae30SDana Myers for (i = 0, io_port_cnt = 0; 502db2bae30SDana Myers i < ((ACPI_OBJECT *)crs.Pointer)->Buffer.Length; i++) { 503ae115bc7Smrj io_port_des_t *io_port; 504ae115bc7Smrj uint8_t *tmp; 505ae115bc7Smrj 506db2bae30SDana Myers tmp = ((ACPI_OBJECT *)crs.Pointer)->Buffer.Pointer + i; 507ae115bc7Smrj if (*tmp != IO_PORT_DES) 508ae115bc7Smrj continue; 509ae115bc7Smrj io_port = (io_port_des_t *)tmp; 510ae115bc7Smrj /* 511*26f3cdf0SGordon Ross * first port is ec_base and second is ec_sc 512ae115bc7Smrj */ 513*26f3cdf0SGordon Ross if (io_port_cnt == 0) 514*26f3cdf0SGordon Ross ec_base = (io_port->min_base_hi << 8) | 515ae115bc7Smrj io_port->min_base_lo; 516*26f3cdf0SGordon Ross if (io_port_cnt == 1) 517*26f3cdf0SGordon Ross ec_sc = (io_port->min_base_hi << 8) | 518ae115bc7Smrj io_port->min_base_lo; 519ae115bc7Smrj 520ae115bc7Smrj io_port_cnt++; 521ae115bc7Smrj /* 522ae115bc7Smrj * Increment ahead to next struct. 523ae115bc7Smrj */ 524ae115bc7Smrj i += 7; 525ae115bc7Smrj } 526ae115bc7Smrj AcpiOsFree(crs.Pointer); 527*26f3cdf0SGordon Ross if (io_port_cnt < 2) { 528*26f3cdf0SGordon Ross cmn_err(CE_WARN, "!acpica:ec_probe_ns: " 529*26f3cdf0SGordon Ross "_CRS parse failed"); 530*26f3cdf0SGordon Ross return (AE_BAD_VALUE); 531*26f3cdf0SGordon Ross } 532*26f3cdf0SGordon Ross 533*26f3cdf0SGordon Ross /* 534*26f3cdf0SGordon Ross * Get the GPE info. 535*26f3cdf0SGordon Ross */ 536*26f3cdf0SGordon Ross buf.Length = ACPI_ALLOCATE_BUFFER; 537*26f3cdf0SGordon Ross status = AcpiEvaluateObject(dev_hdl, "_GPE", NULL, &buf); 538*26f3cdf0SGordon Ross if (ACPI_FAILURE(status)) { 539*26f3cdf0SGordon Ross cmn_err(CE_WARN, "!acpica:ec_probe_ns: " 540*26f3cdf0SGordon Ross "_GPE object evaluate"); 541*26f3cdf0SGordon Ross return (status); 542*26f3cdf0SGordon Ross } 543*26f3cdf0SGordon Ross gpe_obj = (ACPI_OBJECT *)buf.Pointer; 544*26f3cdf0SGordon Ross /* 545*26f3cdf0SGordon Ross * process the GPE description 546*26f3cdf0SGordon Ross */ 547*26f3cdf0SGordon Ross switch (gpe_obj->Type) { 548*26f3cdf0SGordon Ross case ACPI_TYPE_INTEGER: 549*26f3cdf0SGordon Ross gpe_hdl = NULL; 550*26f3cdf0SGordon Ross gpe_bit = gpe_obj->Integer.Value; 551*26f3cdf0SGordon Ross break; 552*26f3cdf0SGordon Ross case ACPI_TYPE_PACKAGE: 553*26f3cdf0SGordon Ross if (gpe_obj->Package.Count != 2) 554*26f3cdf0SGordon Ross goto bad_gpe; 555*26f3cdf0SGordon Ross gpe_obj = gpe_obj->Package.Elements; 556*26f3cdf0SGordon Ross if (gpe_obj[1].Type != ACPI_TYPE_INTEGER) 557*26f3cdf0SGordon Ross goto bad_gpe; 558*26f3cdf0SGordon Ross gpe_hdl = gpe_obj[0].Reference.Handle; 559*26f3cdf0SGordon Ross gpe_bit = gpe_obj[1].Integer.Value; 560*26f3cdf0SGordon Ross break; 561*26f3cdf0SGordon Ross bad_gpe: 562*26f3cdf0SGordon Ross default: 563*26f3cdf0SGordon Ross status = AE_BAD_VALUE; 564*26f3cdf0SGordon Ross break; 565*26f3cdf0SGordon Ross } 566*26f3cdf0SGordon Ross AcpiOsFree(buf.Pointer); 567*26f3cdf0SGordon Ross if (ACPI_FAILURE(status)) { 568*26f3cdf0SGordon Ross cmn_err(CE_WARN, "!acpica:ec_probe_ns: " 569*26f3cdf0SGordon Ross "_GPE parse failed"); 570*26f3cdf0SGordon Ross return (status); 571*26f3cdf0SGordon Ross } 572*26f3cdf0SGordon Ross 573*26f3cdf0SGordon Ross /* 574*26f3cdf0SGordon Ross * Success. Save info for attach. 575*26f3cdf0SGordon Ross */ 576*26f3cdf0SGordon Ross ec.ec_base = ec_base; 577*26f3cdf0SGordon Ross ec.ec_sc = ec_sc; 578*26f3cdf0SGordon Ross ec.ec_dev_hdl = dev_hdl; 579*26f3cdf0SGordon Ross ec.ec_gpe_hdl = gpe_hdl; 580*26f3cdf0SGordon Ross ec.ec_gpe_bit = gpe_bit; 581*26f3cdf0SGordon Ross ec.ec_ok = 1; 582*26f3cdf0SGordon Ross 583*26f3cdf0SGordon Ross #ifdef DEBUG 584*26f3cdf0SGordon Ross cmn_err(CE_NOTE, "!acpica:ec_probe_ns: success"); 585*26f3cdf0SGordon Ross #endif 586*26f3cdf0SGordon Ross return (0); 587*26f3cdf0SGordon Ross } 588*26f3cdf0SGordon Ross 589*26f3cdf0SGordon Ross /* 590*26f3cdf0SGordon Ross * Setup the Embedded Controller (EC) address space handler. 591*26f3cdf0SGordon Ross * Entered only if one of the EC probe methods found an EC. 592*26f3cdf0SGordon Ross */ 593*26f3cdf0SGordon Ross static void 594*26f3cdf0SGordon Ross ec_init(void) 595*26f3cdf0SGordon Ross { 596*26f3cdf0SGordon Ross ACPI_STATUS rc; 597*26f3cdf0SGordon Ross int x; 598*26f3cdf0SGordon Ross 599*26f3cdf0SGordon Ross /* paranoia */ 600*26f3cdf0SGordon Ross if (ec.ec_ok == 0) 601*26f3cdf0SGordon Ross return; 602ae115bc7Smrj 603ae115bc7Smrj /* 604ae115bc7Smrj * Drain the EC data register if something is left over from 605ae115bc7Smrj * legacy mode 606ae115bc7Smrj */ 607ae115bc7Smrj if (inb(ec.ec_sc) & EC_OBF) { 608*26f3cdf0SGordon Ross x = inb(ec.ec_base); /* read and discard value */ 609*26f3cdf0SGordon Ross #ifdef DEBUG 610*26f3cdf0SGordon Ross cmn_err(CE_NOTE, "!EC had something: 0x%x", x); 611ae115bc7Smrj #endif 612ae115bc7Smrj } 613ae115bc7Smrj 614ae115bc7Smrj /* 615*26f3cdf0SGordon Ross * Install an "EC address space" handler. 616*26f3cdf0SGordon Ross * 617*26f3cdf0SGordon Ross * This call does a name space walk under the passed 618*26f3cdf0SGordon Ross * object looking for child objects with an EC space 619*26f3cdf0SGordon Ross * region for which to install this handler. Using 620*26f3cdf0SGordon Ross * the ROOT object makes sure we find them all. 621*26f3cdf0SGordon Ross * 622*26f3cdf0SGordon Ross * XXX: Some systems return an error from this call 623*26f3cdf0SGordon Ross * after a partial success, i.e. where the NS walk 624*26f3cdf0SGordon Ross * installs on some nodes and fails on other nodes. 625*26f3cdf0SGordon Ross * In such cases, disabling the EC and GPE handlers 626*26f3cdf0SGordon Ross * makes things worse, so just report the error and 627*26f3cdf0SGordon Ross * leave the EC handler enabled. 628*26f3cdf0SGordon Ross * 629*26f3cdf0SGordon Ross * At one point, it seemed that doing this part of 630*26f3cdf0SGordon Ross * EC setup earlier may help, which is why this is 631*26f3cdf0SGordon Ross * now a separate function from ec_attach. Someone 632*26f3cdf0SGordon Ross * needs to figure our why some systems give us an 633*26f3cdf0SGordon Ross * error return from this call. (TODO) 634ae115bc7Smrj */ 635*26f3cdf0SGordon Ross rc = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 636*26f3cdf0SGordon Ross ACPI_ADR_SPACE_EC, &ec_handler, NULL, NULL); 637*26f3cdf0SGordon Ross if (rc != AE_OK) { 638*26f3cdf0SGordon Ross cmn_err(CE_WARN, "!acpica:ec_init: " 639*26f3cdf0SGordon Ross "install AS handler, rc=0x%x", rc); 640*26f3cdf0SGordon Ross return; 641a3463f0aSDana Myers } 642*26f3cdf0SGordon Ross #ifdef DEBUG 643*26f3cdf0SGordon Ross cmn_err(CE_NOTE, "!acpica:ec_init: success"); 644*26f3cdf0SGordon Ross #endif 645*26f3cdf0SGordon Ross } 646*26f3cdf0SGordon Ross 647*26f3cdf0SGordon Ross /* 648*26f3cdf0SGordon Ross * Attach the EC General-Purpose Event (GPE) handler. 649*26f3cdf0SGordon Ross */ 650*26f3cdf0SGordon Ross static void 651*26f3cdf0SGordon Ross ec_attach(void) 652*26f3cdf0SGordon Ross { 653*26f3cdf0SGordon Ross ACPI_STATUS rc; 654*26f3cdf0SGordon Ross 655*26f3cdf0SGordon Ross /* 656*26f3cdf0SGordon Ross * Guard against call without probe results. 657*26f3cdf0SGordon Ross */ 658*26f3cdf0SGordon Ross if (ec.ec_ok == 0) { 659*26f3cdf0SGordon Ross cmn_err(CE_WARN, "!acpica:ec_attach: " 660*26f3cdf0SGordon Ross "no EC device found"); 661*26f3cdf0SGordon Ross return; 662*26f3cdf0SGordon Ross } 663*26f3cdf0SGordon Ross 664*26f3cdf0SGordon Ross /* 665*26f3cdf0SGordon Ross * Install the GPE handler and enable it. 666*26f3cdf0SGordon Ross */ 667*26f3cdf0SGordon Ross rc = AcpiInstallGpeHandler(ec.ec_gpe_hdl, ec.ec_gpe_bit, 668*26f3cdf0SGordon Ross ACPI_GPE_EDGE_TRIGGERED, ec_gpe_handler, NULL); 669*26f3cdf0SGordon Ross if (rc != AE_OK) { 670*26f3cdf0SGordon Ross cmn_err(CE_WARN, "!acpica:ec_attach: " 671*26f3cdf0SGordon Ross "install GPE handler, rc=0x%x", rc); 672*26f3cdf0SGordon Ross goto errout; 673*26f3cdf0SGordon Ross } 674*26f3cdf0SGordon Ross 675*26f3cdf0SGordon Ross rc = AcpiEnableGpe(ec.ec_gpe_hdl, ec.ec_gpe_bit); 676*26f3cdf0SGordon Ross if (rc != AE_OK) { 677*26f3cdf0SGordon Ross cmn_err(CE_WARN, "!acpica:ec_attach: " 678*26f3cdf0SGordon Ross "enable GPE handler, rc=0x%x", rc); 679*26f3cdf0SGordon Ross goto errout; 680*26f3cdf0SGordon Ross } 681*26f3cdf0SGordon Ross 682*26f3cdf0SGordon Ross #ifdef DEBUG 683*26f3cdf0SGordon Ross cmn_err(CE_NOTE, "!acpica:ec_attach: success"); 684*26f3cdf0SGordon Ross #endif 685*26f3cdf0SGordon Ross return; 686*26f3cdf0SGordon Ross 687*26f3cdf0SGordon Ross errout: 688*26f3cdf0SGordon Ross AcpiRemoveGpeHandler(ec.ec_gpe_hdl, ec.ec_gpe_bit, 689*26f3cdf0SGordon Ross ec_gpe_handler); 690*26f3cdf0SGordon Ross } 691*26f3cdf0SGordon Ross 692*26f3cdf0SGordon Ross /* 693*26f3cdf0SGordon Ross * System Management Bus Controller (SMBC) 694*26f3cdf0SGordon Ross * These also go through the EC. 695*26f3cdf0SGordon Ross * (not yet supported) 696*26f3cdf0SGordon Ross */ 697*26f3cdf0SGordon Ross static void 698*26f3cdf0SGordon Ross smbus_attach(void) 699*26f3cdf0SGordon Ross { 700*26f3cdf0SGordon Ross #ifdef DEBUG 701*26f3cdf0SGordon Ross ACPI_HANDLE obj; 702*26f3cdf0SGordon Ross 703*26f3cdf0SGordon Ross obj = NULL; 704*26f3cdf0SGordon Ross (void) AcpiGetDevices("ACPI0001", &ec_find, (void *)&obj, NULL); 705*26f3cdf0SGordon Ross if (obj != NULL) { 706*26f3cdf0SGordon Ross cmn_err(CE_NOTE, "!acpica: found an SMBC Version 1.0"); 707*26f3cdf0SGordon Ross } 708*26f3cdf0SGordon Ross 709*26f3cdf0SGordon Ross obj = NULL; 710*26f3cdf0SGordon Ross (void) AcpiGetDevices("ACPI0005", &ec_find, (void *)&obj, NULL); 711*26f3cdf0SGordon Ross if (obj != NULL) { 712*26f3cdf0SGordon Ross cmn_err(CE_NOTE, "!acpica: found an SMBC Version 2.0"); 713*26f3cdf0SGordon Ross } 714*26f3cdf0SGordon Ross #endif /* DEBUG */ 715*26f3cdf0SGordon Ross } 716*26f3cdf0SGordon Ross 717*26f3cdf0SGordon Ross /* 718*26f3cdf0SGordon Ross * Initialize the EC, if present. 719*26f3cdf0SGordon Ross */ 720*26f3cdf0SGordon Ross void 721*26f3cdf0SGordon Ross acpica_ec_init(void) 722*26f3cdf0SGordon Ross { 723*26f3cdf0SGordon Ross ACPI_STATUS rc; 724ae115bc7Smrj 725ae115bc7Smrj /* 726ae115bc7Smrj * Initialize EC mutex here 727ae115bc7Smrj */ 728ae115bc7Smrj mutex_init(&ec.ec_mutex, NULL, MUTEX_DRIVER, NULL); 729ae115bc7Smrj 730a3463f0aSDana Myers /* 731*26f3cdf0SGordon Ross * First search the ACPI tables for an ECDT, and 732*26f3cdf0SGordon Ross * if not found, search the name space for it. 733a3463f0aSDana Myers */ 734*26f3cdf0SGordon Ross rc = ec_probe_ecdt(); 735*26f3cdf0SGordon Ross if (ACPI_FAILURE(rc)) 736*26f3cdf0SGordon Ross rc = ec_probe_ns(); 737*26f3cdf0SGordon Ross if (ACPI_SUCCESS(rc)) { 738*26f3cdf0SGordon Ross ec_init(); 739*26f3cdf0SGordon Ross ec_attach(); 740ae115bc7Smrj } 741*26f3cdf0SGordon Ross smbus_attach(); 742ae115bc7Smrj } 743