115e32d5dSMike Smith /*- 215e32d5dSMike Smith * Copyright (c) 2000 Michael Smith 315e32d5dSMike Smith * Copyright (c) 2000 BSDi 415e32d5dSMike Smith * All rights reserved. 515e32d5dSMike Smith * 615e32d5dSMike Smith * Redistribution and use in source and binary forms, with or without 715e32d5dSMike Smith * modification, are permitted provided that the following conditions 815e32d5dSMike Smith * are met: 915e32d5dSMike Smith * 1. Redistributions of source code must retain the above copyright 1015e32d5dSMike Smith * notice, this list of conditions and the following disclaimer. 1115e32d5dSMike Smith * 2. Redistributions in binary form must reproduce the above copyright 1215e32d5dSMike Smith * notice, this list of conditions and the following disclaimer in the 1315e32d5dSMike Smith * documentation and/or other materials provided with the distribution. 1415e32d5dSMike Smith * 1515e32d5dSMike Smith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1615e32d5dSMike Smith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1715e32d5dSMike Smith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1815e32d5dSMike Smith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1915e32d5dSMike Smith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2015e32d5dSMike Smith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2115e32d5dSMike Smith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2215e32d5dSMike Smith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2315e32d5dSMike Smith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2415e32d5dSMike Smith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2515e32d5dSMike Smith * SUCH DAMAGE. 2615e32d5dSMike Smith * 2715e32d5dSMike Smith * $FreeBSD$ 2815e32d5dSMike Smith */ 2915e32d5dSMike Smith /****************************************************************************** 3015e32d5dSMike Smith * 3115e32d5dSMike Smith * 1. Copyright Notice 3215e32d5dSMike Smith * 3315e32d5dSMike Smith * Some or all of this work - Copyright (c) 1999, Intel Corp. All rights 3415e32d5dSMike Smith * reserved. 3515e32d5dSMike Smith * 3615e32d5dSMike Smith * 2. License 3715e32d5dSMike Smith * 3815e32d5dSMike Smith * 2.1. This is your license from Intel Corp. under its intellectual property 3915e32d5dSMike Smith * rights. You may have additional license terms from the party that provided 4015e32d5dSMike Smith * you this software, covering your right to use that party's intellectual 4115e32d5dSMike Smith * property rights. 4215e32d5dSMike Smith * 4315e32d5dSMike Smith * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a 4415e32d5dSMike Smith * copy of the source code appearing in this file ("Covered Code") an 4515e32d5dSMike Smith * irrevocable, perpetual, worldwide license under Intel's copyrights in the 4615e32d5dSMike Smith * base code distributed originally by Intel ("Original Intel Code") to copy, 4715e32d5dSMike Smith * make derivatives, distribute, use and display any portion of the Covered 4815e32d5dSMike Smith * Code in any form, with the right to sublicense such rights; and 4915e32d5dSMike Smith * 5015e32d5dSMike Smith * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent 5115e32d5dSMike Smith * license (with the right to sublicense), under only those claims of Intel 5215e32d5dSMike Smith * patents that are infringed by the Original Intel Code, to make, use, sell, 5315e32d5dSMike Smith * offer to sell, and import the Covered Code and derivative works thereof 5415e32d5dSMike Smith * solely to the minimum extent necessary to exercise the above copyright 5515e32d5dSMike Smith * license, and in no event shall the patent license extend to any additions 5615e32d5dSMike Smith * to or modifications of the Original Intel Code. No other license or right 5715e32d5dSMike Smith * is granted directly or by implication, estoppel or otherwise; 5815e32d5dSMike Smith * 5915e32d5dSMike Smith * The above copyright and patent license is granted only if the following 6015e32d5dSMike Smith * conditions are met: 6115e32d5dSMike Smith * 6215e32d5dSMike Smith * 3. Conditions 6315e32d5dSMike Smith * 6415e32d5dSMike Smith * 3.1. Redistribution of Source with Rights to Further Distribute Source. 6515e32d5dSMike Smith * Redistribution of source code of any substantial portion of the Covered 6615e32d5dSMike Smith * Code or modification with rights to further distribute source must include 6715e32d5dSMike Smith * the above Copyright Notice, the above License, this list of Conditions, 6815e32d5dSMike Smith * and the following Disclaimer and Export Compliance provision. In addition, 6915e32d5dSMike Smith * Licensee must cause all Covered Code to which Licensee contributes to 7015e32d5dSMike Smith * contain a file documenting the changes Licensee made to create that Covered 7115e32d5dSMike Smith * Code and the date of any change. Licensee must include in that file the 7215e32d5dSMike Smith * documentation of any changes made by any predecessor Licensee. Licensee 7315e32d5dSMike Smith * must include a prominent statement that the modification is derived, 7415e32d5dSMike Smith * directly or indirectly, from Original Intel Code. 7515e32d5dSMike Smith * 7615e32d5dSMike Smith * 3.2. Redistribution of Source with no Rights to Further Distribute Source. 7715e32d5dSMike Smith * Redistribution of source code of any substantial portion of the Covered 7815e32d5dSMike Smith * Code or modification without rights to further distribute source must 7915e32d5dSMike Smith * include the following Disclaimer and Export Compliance provision in the 8015e32d5dSMike Smith * documentation and/or other materials provided with distribution. In 8115e32d5dSMike Smith * addition, Licensee may not authorize further sublicense of source of any 8215e32d5dSMike Smith * portion of the Covered Code, and must include terms to the effect that the 8315e32d5dSMike Smith * license from Licensee to its licensee is limited to the intellectual 8415e32d5dSMike Smith * property embodied in the software Licensee provides to its licensee, and 8515e32d5dSMike Smith * not to intellectual property embodied in modifications its licensee may 8615e32d5dSMike Smith * make. 8715e32d5dSMike Smith * 8815e32d5dSMike Smith * 3.3. Redistribution of Executable. Redistribution in executable form of any 8915e32d5dSMike Smith * substantial portion of the Covered Code or modification must reproduce the 9015e32d5dSMike Smith * above Copyright Notice, and the following Disclaimer and Export Compliance 9115e32d5dSMike Smith * provision in the documentation and/or other materials provided with the 9215e32d5dSMike Smith * distribution. 9315e32d5dSMike Smith * 9415e32d5dSMike Smith * 3.4. Intel retains all right, title, and interest in and to the Original 9515e32d5dSMike Smith * Intel Code. 9615e32d5dSMike Smith * 9715e32d5dSMike Smith * 3.5. Neither the name Intel nor any other trademark owned or controlled by 9815e32d5dSMike Smith * Intel shall be used in advertising or otherwise to promote the sale, use or 9915e32d5dSMike Smith * other dealings in products derived from or relating to the Covered Code 10015e32d5dSMike Smith * without prior written authorization from Intel. 10115e32d5dSMike Smith * 10215e32d5dSMike Smith * 4. Disclaimer and Export Compliance 10315e32d5dSMike Smith * 10415e32d5dSMike Smith * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED 10515e32d5dSMike Smith * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE 10615e32d5dSMike Smith * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, 10715e32d5dSMike Smith * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY 10815e32d5dSMike Smith * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY 10915e32d5dSMike Smith * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A 11015e32d5dSMike Smith * PARTICULAR PURPOSE. 11115e32d5dSMike Smith * 11215e32d5dSMike Smith * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES 11315e32d5dSMike Smith * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR 11415e32d5dSMike Smith * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, 11515e32d5dSMike Smith * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY 11615e32d5dSMike Smith * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL 11715e32d5dSMike Smith * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS 11815e32d5dSMike Smith * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY 11915e32d5dSMike Smith * LIMITED REMEDY. 12015e32d5dSMike Smith * 12115e32d5dSMike Smith * 4.3. Licensee shall not export, either directly or indirectly, any of this 12215e32d5dSMike Smith * software or system incorporating such software without first obtaining any 12315e32d5dSMike Smith * required license or other approval from the U. S. Department of Commerce or 12415e32d5dSMike Smith * any other agency or department of the United States Government. In the 12515e32d5dSMike Smith * event Licensee exports any such software from the United States or 12615e32d5dSMike Smith * re-exports any such software from a foreign destination, Licensee shall 12715e32d5dSMike Smith * ensure that the distribution and export/re-export of the software is in 12815e32d5dSMike Smith * compliance with all laws, regulations, orders, or other restrictions of the 12915e32d5dSMike Smith * U.S. Export Administration Regulations. Licensee agrees that neither it nor 13015e32d5dSMike Smith * any of its subsidiaries will export/re-export any technical data, process, 13115e32d5dSMike Smith * software, or service, directly or indirectly, to any country for which the 13215e32d5dSMike Smith * United States government or any agency thereof requires an export license, 13315e32d5dSMike Smith * other governmental approval, or letter of assurance, without first obtaining 13415e32d5dSMike Smith * such license, approval or letter. 13515e32d5dSMike Smith * 13615e32d5dSMike Smith *****************************************************************************/ 13715e32d5dSMike Smith 13815e32d5dSMike Smith #include "opt_acpi.h" 13915e32d5dSMike Smith #include <sys/param.h> 14015e32d5dSMike Smith #include <sys/kernel.h> 14115e32d5dSMike Smith #include <sys/bus.h> 14215e32d5dSMike Smith 14315e32d5dSMike Smith #include <machine/bus.h> 14415e32d5dSMike Smith #include <machine/resource.h> 14515e32d5dSMike Smith #include <sys/rman.h> 14615e32d5dSMike Smith 14715e32d5dSMike Smith #include "acpi.h" 14815e32d5dSMike Smith 14915e32d5dSMike Smith #include <dev/acpica/acpivar.h> 15015e32d5dSMike Smith 1510ae55423SMike Smith /* 1520ae55423SMike Smith * Hooks for the ACPI CA debugging infrastructure 1530ae55423SMike Smith */ 154a9cf0dffSMike Smith #define _COMPONENT ACPI_EC 155dbd0058aSMike Smith ACPI_MODULE_NAME("EC") 1560ae55423SMike Smith 157da3b867eSMike Smith /* 158da3b867eSMike Smith * EC_COMMAND: 159da3b867eSMike Smith * ----------- 160da3b867eSMike Smith */ 161da3b867eSMike Smith typedef UINT8 EC_COMMAND; 162da3b867eSMike Smith 163da3b867eSMike Smith #define EC_COMMAND_UNKNOWN ((EC_COMMAND) 0x00) 164da3b867eSMike Smith #define EC_COMMAND_READ ((EC_COMMAND) 0x80) 165da3b867eSMike Smith #define EC_COMMAND_WRITE ((EC_COMMAND) 0x81) 166da3b867eSMike Smith #define EC_COMMAND_BURST_ENABLE ((EC_COMMAND) 0x82) 167da3b867eSMike Smith #define EC_COMMAND_BURST_DISABLE ((EC_COMMAND) 0x83) 168da3b867eSMike Smith #define EC_COMMAND_QUERY ((EC_COMMAND) 0x84) 169da3b867eSMike Smith 170da3b867eSMike Smith /* 171da3b867eSMike Smith * EC_STATUS: 172da3b867eSMike Smith * ---------- 173da3b867eSMike Smith * The encoding of the EC status register is illustrated below. 174da3b867eSMike Smith * Note that a set bit (1) indicates the property is TRUE 175da3b867eSMike Smith * (e.g. if bit 0 is set then the output buffer is full). 176da3b867eSMike Smith * +-+-+-+-+-+-+-+-+ 177da3b867eSMike Smith * |7|6|5|4|3|2|1|0| 178da3b867eSMike Smith * +-+-+-+-+-+-+-+-+ 179da3b867eSMike Smith * | | | | | | | | 180da3b867eSMike Smith * | | | | | | | +- Output Buffer Full? 181da3b867eSMike Smith * | | | | | | +--- Input Buffer Full? 182da3b867eSMike Smith * | | | | | +----- <reserved> 183da3b867eSMike Smith * | | | | +------- Data Register is Command Byte? 184da3b867eSMike Smith * | | | +--------- Burst Mode Enabled? 185da3b867eSMike Smith * | | +----------- SCI Event? 186da3b867eSMike Smith * | +------------- SMI Event? 187da3b867eSMike Smith * +--------------- <Reserved> 188da3b867eSMike Smith * 189da3b867eSMike Smith */ 190da3b867eSMike Smith typedef UINT8 EC_STATUS; 191da3b867eSMike Smith 192da3b867eSMike Smith #define EC_FLAG_OUTPUT_BUFFER ((EC_STATUS) 0x01) 193da3b867eSMike Smith #define EC_FLAG_INPUT_BUFFER ((EC_STATUS) 0x02) 194da3b867eSMike Smith #define EC_FLAG_BURST_MODE ((EC_STATUS) 0x10) 195da3b867eSMike Smith #define EC_FLAG_SCI ((EC_STATUS) 0x20) 196da3b867eSMike Smith 197da3b867eSMike Smith /* 198da3b867eSMike Smith * EC_EVENT: 199da3b867eSMike Smith * --------- 200da3b867eSMike Smith */ 201da3b867eSMike Smith typedef UINT8 EC_EVENT; 202da3b867eSMike Smith 203da3b867eSMike Smith #define EC_EVENT_UNKNOWN ((EC_EVENT) 0x00) 204da3b867eSMike Smith #define EC_EVENT_OUTPUT_BUFFER_FULL ((EC_EVENT) 0x01) 205da3b867eSMike Smith #define EC_EVENT_INPUT_BUFFER_EMPTY ((EC_EVENT) 0x02) 206da3b867eSMike Smith #define EC_EVENT_SCI ((EC_EVENT) 0x20) 207da3b867eSMike Smith 208da3b867eSMike Smith /* 209da3b867eSMike Smith * Register access primitives 210da3b867eSMike Smith */ 211da3b867eSMike Smith #define EC_GET_DATA(sc) \ 212da3b867eSMike Smith bus_space_read_1((sc)->ec_data_tag, (sc)->ec_data_handle, 0) 213da3b867eSMike Smith 214da3b867eSMike Smith #define EC_SET_DATA(sc, v) \ 215da3b867eSMike Smith bus_space_write_1((sc)->ec_data_tag, (sc)->ec_data_handle, 0, (v)) 216da3b867eSMike Smith 217da3b867eSMike Smith #define EC_GET_CSR(sc) \ 218da3b867eSMike Smith bus_space_read_1((sc)->ec_csr_tag, (sc)->ec_csr_handle, 0) 219da3b867eSMike Smith 220da3b867eSMike Smith #define EC_SET_CSR(sc, v) \ 221da3b867eSMike Smith bus_space_write_1((sc)->ec_csr_tag, (sc)->ec_csr_handle, 0, (v)) 222da3b867eSMike Smith 223da3b867eSMike Smith /* 224da3b867eSMike Smith * Driver softc. 225da3b867eSMike Smith */ 22615e32d5dSMike Smith struct acpi_ec_softc { 22715e32d5dSMike Smith device_t ec_dev; 22815e32d5dSMike Smith ACPI_HANDLE ec_handle; 22915e32d5dSMike Smith UINT32 ec_gpebit; 23015e32d5dSMike Smith 23115e32d5dSMike Smith int ec_data_rid; 23215e32d5dSMike Smith struct resource *ec_data_res; 23315e32d5dSMike Smith bus_space_tag_t ec_data_tag; 23415e32d5dSMike Smith bus_space_handle_t ec_data_handle; 23515e32d5dSMike Smith 23615e32d5dSMike Smith int ec_csr_rid; 23715e32d5dSMike Smith struct resource *ec_csr_res; 23815e32d5dSMike Smith bus_space_tag_t ec_csr_tag; 23915e32d5dSMike Smith bus_space_handle_t ec_csr_handle; 24015e32d5dSMike Smith 24115e32d5dSMike Smith int ec_locked; 242dbd0058aSMike Smith int ec_lockhandle; 243c07572e7STakanori Watanabe int ec_pendquery; 244c07572e7STakanori Watanabe int ec_csrvalue; 24515e32d5dSMike Smith }; 24615e32d5dSMike Smith 2474690674eSMitsuru IWASAKI static int acpi_ec_event_driven = 0; 2484690674eSMitsuru IWASAKI TUNABLE_INT("hw.acpi.ec.event_driven", &acpi_ec_event_driven); 2494690674eSMitsuru IWASAKI 25015e32d5dSMike Smith #define EC_LOCK_TIMEOUT 1000 /* 1ms */ 25115e32d5dSMike Smith 25215e32d5dSMike Smith static __inline ACPI_STATUS 25315e32d5dSMike Smith EcLock(struct acpi_ec_softc *sc) 25415e32d5dSMike Smith { 25515e32d5dSMike Smith ACPI_STATUS status; 25615e32d5dSMike Smith 25721b5fd3cSMitsuru IWASAKI /* XXX ACPI_WAIT_FOREVER is probably a bad idea, what is a better time? */ 258464c662eSNate Lawson status = AcpiAcquireGlobalLock(ACPI_WAIT_FOREVER, &sc->ec_lockhandle); 259464c662eSNate Lawson if (ACPI_SUCCESS(status)) 260464c662eSNate Lawson sc->ec_locked = 1; 261c573e654SMitsuru IWASAKI 26215e32d5dSMike Smith return (status); 26315e32d5dSMike Smith } 26415e32d5dSMike Smith 26515e32d5dSMike Smith static __inline void 26615e32d5dSMike Smith EcUnlock(struct acpi_ec_softc *sc) 26715e32d5dSMike Smith { 268464c662eSNate Lawson sc->ec_locked = 0; 269dbd0058aSMike Smith AcpiReleaseGlobalLock(sc->ec_lockhandle); 27015e32d5dSMike Smith } 27115e32d5dSMike Smith 27215e32d5dSMike Smith static __inline int 27315e32d5dSMike Smith EcIsLocked(struct acpi_ec_softc *sc) 27415e32d5dSMike Smith { 275464c662eSNate Lawson return (sc->ec_locked != 0); 27615e32d5dSMike Smith } 27715e32d5dSMike Smith 27815e32d5dSMike Smith typedef struct 27915e32d5dSMike Smith { 28015e32d5dSMike Smith EC_COMMAND Command; 28115e32d5dSMike Smith UINT8 Address; 28215e32d5dSMike Smith UINT8 Data; 28315e32d5dSMike Smith } EC_REQUEST; 28415e32d5dSMike Smith 28515e32d5dSMike Smith static void EcGpeHandler(void *Context); 28615e32d5dSMike Smith static ACPI_STATUS EcSpaceSetup(ACPI_HANDLE Region, UINT32 Function, 28715e32d5dSMike Smith void *Context, void **return_Context); 288464c662eSNate Lawson static ACPI_STATUS EcSpaceHandler(UINT32 Function, 289464c662eSNate Lawson ACPI_PHYSICAL_ADDRESS Address, 290464c662eSNate Lawson UINT32 width, ACPI_INTEGER *Value, 29115e32d5dSMike Smith void *Context, void *RegionContext); 29215e32d5dSMike Smith static ACPI_STATUS EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event); 29315e32d5dSMike Smith static ACPI_STATUS EcQuery(struct acpi_ec_softc *sc, UINT8 *Data); 294464c662eSNate Lawson static ACPI_STATUS EcTransaction(struct acpi_ec_softc *sc, 295464c662eSNate Lawson EC_REQUEST *EcRequest); 296464c662eSNate Lawson static ACPI_STATUS EcRead(struct acpi_ec_softc *sc, UINT8 Address, 297464c662eSNate Lawson UINT8 *Data); 298464c662eSNate Lawson static ACPI_STATUS EcWrite(struct acpi_ec_softc *sc, UINT8 Address, 299464c662eSNate Lawson UINT8 *Data); 30015e32d5dSMike Smith static void acpi_ec_identify(driver_t driver, device_t bus); 30115e32d5dSMike Smith static int acpi_ec_probe(device_t dev); 30215e32d5dSMike Smith static int acpi_ec_attach(device_t dev); 30315e32d5dSMike Smith 30415e32d5dSMike Smith static device_method_t acpi_ec_methods[] = { 30515e32d5dSMike Smith /* Device interface */ 30615e32d5dSMike Smith DEVMETHOD(device_identify, acpi_ec_identify), 30715e32d5dSMike Smith DEVMETHOD(device_probe, acpi_ec_probe), 30815e32d5dSMike Smith DEVMETHOD(device_attach, acpi_ec_attach), 30915e32d5dSMike Smith 31015e32d5dSMike Smith {0, 0} 31115e32d5dSMike Smith }; 31215e32d5dSMike Smith 31315e32d5dSMike Smith static driver_t acpi_ec_driver = { 31415e32d5dSMike Smith "acpi_ec", 31515e32d5dSMike Smith acpi_ec_methods, 31615e32d5dSMike Smith sizeof(struct acpi_ec_softc), 31715e32d5dSMike Smith }; 31815e32d5dSMike Smith 3193273b005SMike Smith static devclass_t acpi_ec_devclass; 32015e32d5dSMike Smith DRIVER_MODULE(acpi_ec, acpi, acpi_ec_driver, acpi_ec_devclass, 0, 0); 32115e32d5dSMike Smith 32215e32d5dSMike Smith /* 32315e32d5dSMike Smith * Look for an ECDT table and if we find one, set up a default EC 32415e32d5dSMike Smith * space handler to catch possible attempts to access EC space before 32515e32d5dSMike Smith * we have a real driver instance in place. 32615e32d5dSMike Smith * We're not really an identify routine, but because we get called 32715e32d5dSMike Smith * before most other things, this works out OK. 32815e32d5dSMike Smith */ 32915e32d5dSMike Smith static void 33015e32d5dSMike Smith acpi_ec_identify(driver_t driver, device_t bus) 33115e32d5dSMike Smith { 332b4a05238SPeter Wemm ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 33315e32d5dSMike Smith 33415e32d5dSMike Smith /* XXX implement - need an ACPI 2.0 system to test this */ 33515e32d5dSMike Smith } 33615e32d5dSMike Smith 33715e32d5dSMike Smith /* 33815e32d5dSMike Smith * We could setup resources in the probe routine in order to have them printed 33915e32d5dSMike Smith * when the device is attached. 34015e32d5dSMike Smith */ 34115e32d5dSMike Smith static int 34215e32d5dSMike Smith acpi_ec_probe(device_t dev) 34315e32d5dSMike Smith { 3440ae55423SMike Smith 345464c662eSNate Lawson if (acpi_get_type(dev) == ACPI_TYPE_DEVICE && !acpi_disabled("ec") && 34615e32d5dSMike Smith acpi_MatchHid(dev, "PNP0C09")) { 34715e32d5dSMike Smith 34815e32d5dSMike Smith /* 34915e32d5dSMike Smith * Set device description 35015e32d5dSMike Smith */ 35115e32d5dSMike Smith device_set_desc(dev, "embedded controller"); 35215e32d5dSMike Smith return (0); 35315e32d5dSMike Smith } 35415e32d5dSMike Smith return (ENXIO); 35515e32d5dSMike Smith } 35615e32d5dSMike Smith 35715e32d5dSMike Smith static int 35815e32d5dSMike Smith acpi_ec_attach(device_t dev) 35915e32d5dSMike Smith { 36015e32d5dSMike Smith struct acpi_ec_softc *sc; 36115e32d5dSMike Smith ACPI_STATUS Status; 362f8372adeSTakanori Watanabe int errval = 0; 363dbd0058aSMike Smith 364b4a05238SPeter Wemm ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 3650ae55423SMike Smith 36615e32d5dSMike Smith /* 36715e32d5dSMike Smith * Fetch/initialise softc 36815e32d5dSMike Smith */ 36915e32d5dSMike Smith sc = device_get_softc(dev); 370c07572e7STakanori Watanabe bzero(sc, sizeof(*sc)); 37115e32d5dSMike Smith sc->ec_dev = dev; 37215e32d5dSMike Smith sc->ec_handle = acpi_get_handle(dev); 37315e32d5dSMike Smith 37415e32d5dSMike Smith /* 37515e32d5dSMike Smith * Attach bus resources 37615e32d5dSMike Smith */ 37715e32d5dSMike Smith sc->ec_data_rid = 0; 378464c662eSNate Lawson sc->ec_data_res = bus_alloc_resource(sc->ec_dev, SYS_RES_IOPORT, 379464c662eSNate Lawson &sc->ec_data_rid, 0, ~0, 1, RF_ACTIVE); 380464c662eSNate Lawson if (sc->ec_data_res == NULL) { 38115e32d5dSMike Smith device_printf(dev, "can't allocate data port\n"); 382f8372adeSTakanori Watanabe errval = ENXIO; 383f8372adeSTakanori Watanabe goto out; 38415e32d5dSMike Smith } 38515e32d5dSMike Smith sc->ec_data_tag = rman_get_bustag(sc->ec_data_res); 38615e32d5dSMike Smith sc->ec_data_handle = rman_get_bushandle(sc->ec_data_res); 38715e32d5dSMike Smith 38815e32d5dSMike Smith sc->ec_csr_rid = 1; 389464c662eSNate Lawson sc->ec_csr_res = bus_alloc_resource(sc->ec_dev, SYS_RES_IOPORT, 390464c662eSNate Lawson &sc->ec_csr_rid, 0, ~0, 1, RF_ACTIVE); 391464c662eSNate Lawson if (sc->ec_csr_res == NULL) { 39215e32d5dSMike Smith device_printf(dev, "can't allocate command/status port\n"); 393f8372adeSTakanori Watanabe errval = ENXIO; 394f8372adeSTakanori Watanabe goto out; 39515e32d5dSMike Smith } 39615e32d5dSMike Smith sc->ec_csr_tag = rman_get_bustag(sc->ec_csr_res); 39715e32d5dSMike Smith sc->ec_csr_handle = rman_get_bushandle(sc->ec_csr_res); 39815e32d5dSMike Smith 39915e32d5dSMike Smith /* 40015e32d5dSMike Smith * Install GPE handler 40115e32d5dSMike Smith * 40215e32d5dSMike Smith * Evaluate the _GPE method to find the GPE bit used by the EC to signal 40315e32d5dSMike Smith * status (SCI). 40415e32d5dSMike Smith */ 4054c1cdee6SMike Smith ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "attaching GPE\n")); 406464c662eSNate Lawson Status = acpi_EvaluateInteger(sc->ec_handle, "_GPE", &sc->ec_gpebit); 407464c662eSNate Lawson if (ACPI_FAILURE(Status)) { 408464c662eSNate Lawson device_printf(dev, "can't evaluate _GPE - %s\n", 409464c662eSNate Lawson AcpiFormatException(Status)); 410f8372adeSTakanori Watanabe errval = ENXIO; 411f8372adeSTakanori Watanabe goto out; 41215e32d5dSMike Smith } 41315e32d5dSMike Smith 41415e32d5dSMike Smith /* 41515e32d5dSMike Smith * Install a handler for this EC's GPE bit. Note that EC SCIs are 41615e32d5dSMike Smith * treated as both edge- and level-triggered interrupts; in other words 41715e32d5dSMike Smith * we clear the status bit immediately after getting an EC-SCI, then 41815e32d5dSMike Smith * again after we're done processing the event. This guarantees that 41915e32d5dSMike Smith * events we cause while performing a transaction (e.g. IBE/OBF) get 42015e32d5dSMike Smith * cleared before re-enabling the GPE. 42115e32d5dSMike Smith */ 422464c662eSNate Lawson Status = AcpiInstallGpeHandler(sc->ec_gpebit, 423464c662eSNate Lawson ACPI_EVENT_LEVEL_TRIGGERED | ACPI_EVENT_EDGE_TRIGGERED, 424464c662eSNate Lawson EcGpeHandler, sc); 425464c662eSNate Lawson if (ACPI_FAILURE(Status)) { 42676d1dff4SMike Smith device_printf(dev, "can't install GPE handler for %s - %s\n", 427bfae45aaSMike Smith acpi_name(sc->ec_handle), AcpiFormatException(Status)); 428f8372adeSTakanori Watanabe errval = ENXIO; 429f8372adeSTakanori Watanabe goto out; 43015e32d5dSMike Smith } 43115e32d5dSMike Smith 43215e32d5dSMike Smith /* 43315e32d5dSMike Smith * Install address space handler 43415e32d5dSMike Smith */ 4354c1cdee6SMike Smith ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "attaching address space handler\n")); 436464c662eSNate Lawson Status = AcpiInstallAddressSpaceHandler(sc->ec_handle, ACPI_ADR_SPACE_EC, 437464c662eSNate Lawson EcSpaceHandler, EcSpaceSetup, sc); 438464c662eSNate Lawson if (ACPI_FAILURE(Status)) { 43976d1dff4SMike Smith device_printf(dev, "can't install address space handler for %s - %s\n", 440bfae45aaSMike Smith acpi_name(sc->ec_handle), AcpiFormatException(Status)); 44176d1dff4SMike Smith panic("very suck"); 442f8372adeSTakanori Watanabe errval = ENXIO; 443f8372adeSTakanori Watanabe goto out; 44415e32d5dSMike Smith } 4454c1cdee6SMike Smith ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "attach complete\n")); 4460ae55423SMike Smith return_VALUE (0); 447464c662eSNate Lawson 448f8372adeSTakanori Watanabe out: 449f8372adeSTakanori Watanabe if (sc->ec_csr_res) 450f8372adeSTakanori Watanabe bus_release_resource(sc->ec_dev, SYS_RES_IOPORT, sc->ec_csr_rid, 451f8372adeSTakanori Watanabe sc->ec_csr_res); 452f8372adeSTakanori Watanabe if (sc->ec_data_res) 453f8372adeSTakanori Watanabe bus_release_resource(sc->ec_dev, SYS_RES_IOPORT, sc->ec_data_rid, 454f8372adeSTakanori Watanabe sc->ec_data_res); 455f8372adeSTakanori Watanabe return_VALUE (errval); 45615e32d5dSMike Smith } 45715e32d5dSMike Smith 45815e32d5dSMike Smith static void 459c07572e7STakanori Watanabe EcGpeQueryHandler(void *Context) 46015e32d5dSMike Smith { 46115e32d5dSMike Smith struct acpi_ec_softc *sc = (struct acpi_ec_softc *)Context; 46215e32d5dSMike Smith UINT8 Data; 46315e32d5dSMike Smith ACPI_STATUS Status; 46415e32d5dSMike Smith char qxx[5]; 46515e32d5dSMike Smith 466b4a05238SPeter Wemm ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 4670ae55423SMike Smith 46815e32d5dSMike Smith for (;;) { 46915e32d5dSMike Smith 47015e32d5dSMike Smith /* 47115e32d5dSMike Smith * Check EC_SCI. 47215e32d5dSMike Smith * 47315e32d5dSMike Smith * Bail out if the EC_SCI bit of the status register is not set. 47415e32d5dSMike Smith * Note that this function should only be called when 47515e32d5dSMike Smith * this bit is set (polling is used to detect IBE/OBF events). 47615e32d5dSMike Smith * 47715e32d5dSMike Smith * It is safe to do this without locking the controller, as it's 47815e32d5dSMike Smith * OK to call EcQuery when there's no data ready; in the worst 47915e32d5dSMike Smith * case we should just find nothing waiting for us and bail. 48015e32d5dSMike Smith */ 481464c662eSNate Lawson if ((EC_GET_CSR(sc) & EC_EVENT_SCI) == 0) 48215e32d5dSMike Smith break; 48315e32d5dSMike Smith 48415e32d5dSMike Smith /* 48515e32d5dSMike Smith * Find out why the EC is signalling us 48615e32d5dSMike Smith */ 48715e32d5dSMike Smith Status = EcQuery(sc, &Data); 48815e32d5dSMike Smith 48915e32d5dSMike Smith /* 49015e32d5dSMike Smith * If we failed to get anything from the EC, give up 49115e32d5dSMike Smith */ 492dbd0058aSMike Smith if (ACPI_FAILURE(Status)) { 4936971b3c7SMitsuru IWASAKI ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev), 4946971b3c7SMitsuru IWASAKI "GPE query failed - %s\n", AcpiFormatException(Status)); 49515e32d5dSMike Smith break; 49615e32d5dSMike Smith } 49715e32d5dSMike Smith 49815e32d5dSMike Smith /* 49915e32d5dSMike Smith * Evaluate _Qxx to respond to the controller. 50015e32d5dSMike Smith */ 50115e32d5dSMike Smith sprintf(qxx, "_Q%02x", Data); 50215e32d5dSMike Smith strupr(qxx); 503ee785aa9SJohn Baldwin Status = AcpiEvaluateObject(sc->ec_handle, qxx, NULL, NULL); 504ee785aa9SJohn Baldwin /* 505ee785aa9SJohn Baldwin * Ignore spurious query requests. 506ee785aa9SJohn Baldwin */ 507dbd0058aSMike Smith if (ACPI_FAILURE(Status) && (Data != 0 || Status != AE_NOT_FOUND)) { 5086971b3c7SMitsuru IWASAKI ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev), 5096971b3c7SMitsuru IWASAKI "evaluation of GPE query method %s failed - %s\n", 510bfae45aaSMike Smith qxx, AcpiFormatException(Status)); 51115e32d5dSMike Smith } 51215e32d5dSMike Smith } 513c07572e7STakanori Watanabe /* I know I request Level trigger cleanup */ 514dbd0058aSMike Smith if (ACPI_FAILURE(AcpiClearEvent(sc->ec_gpebit, ACPI_EVENT_GPE))) 515c07572e7STakanori Watanabe printf("EcGpeQueryHandler:ClearEvent Failed\n"); 516dbd0058aSMike Smith if (ACPI_FAILURE(AcpiEnableEvent(sc->ec_gpebit, ACPI_EVENT_GPE, 0))) 517c07572e7STakanori Watanabe printf("EcGpeQueryHandler:EnableEvent Failed\n"); 518c07572e7STakanori Watanabe } 51942f6d122SMike Smith 520a9cf0dffSMike Smith /* 521a9cf0dffSMike Smith * Handle a GPE sent to us. 522a9cf0dffSMike Smith */ 523a9cf0dffSMike Smith static void 524a9cf0dffSMike Smith EcGpeHandler(void *Context) 525c07572e7STakanori Watanabe { 526c07572e7STakanori Watanabe struct acpi_ec_softc *sc = Context; 527c07572e7STakanori Watanabe int csrvalue; 528a9cf0dffSMike Smith 529c07572e7STakanori Watanabe /* 530c07572e7STakanori Watanabe * If EC is locked, the intr must process EcRead/Write wait only. 531c07572e7STakanori Watanabe * Query request must be pending. 532c07572e7STakanori Watanabe */ 533c07572e7STakanori Watanabe if (EcIsLocked(sc)) { 534c07572e7STakanori Watanabe csrvalue = EC_GET_CSR(sc); 535c07572e7STakanori Watanabe if (csrvalue & EC_EVENT_SCI) 536c07572e7STakanori Watanabe sc->ec_pendquery = 1; 537464c662eSNate Lawson if ((csrvalue & EC_FLAG_OUTPUT_BUFFER) != 0 || 538464c662eSNate Lawson (csrvalue & EC_FLAG_INPUT_BUFFER) == 0) { 539c07572e7STakanori Watanabe sc->ec_csrvalue = csrvalue; 540464c662eSNate Lawson wakeup(&sc->ec_csrvalue); 541c07572e7STakanori Watanabe } 542c07572e7STakanori Watanabe } else { 543c07572e7STakanori Watanabe /* Queue GpeQuery Handler */ 544dbd0058aSMike Smith if (ACPI_FAILURE(AcpiOsQueueForExecution(OSD_PRIORITY_HIGH, 545dbd0058aSMike Smith EcGpeQueryHandler,Context))) { 546c07572e7STakanori Watanabe printf("QueryHandler Queuing Failed\n"); 547c07572e7STakanori Watanabe } 548c07572e7STakanori Watanabe } 54915e32d5dSMike Smith } 55015e32d5dSMike Smith 55115e32d5dSMike Smith static ACPI_STATUS 552464c662eSNate Lawson EcSpaceSetup(ACPI_HANDLE Region, UINT32 Function, void *Context, 553464c662eSNate Lawson void **RegionContext) 55415e32d5dSMike Smith { 55542f6d122SMike Smith 556b4a05238SPeter Wemm ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 55742f6d122SMike Smith 55815e32d5dSMike Smith /* 55915e32d5dSMike Smith * Just pass the context through, there's nothing to do here. 56015e32d5dSMike Smith */ 56115e32d5dSMike Smith *RegionContext = Context; 56215e32d5dSMike Smith 56342f6d122SMike Smith return_ACPI_STATUS (AE_OK); 56415e32d5dSMike Smith } 56515e32d5dSMike Smith 56615e32d5dSMike Smith static ACPI_STATUS 567464c662eSNate Lawson EcSpaceHandler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address, UINT32 width, 568464c662eSNate Lawson ACPI_INTEGER *Value, void *Context, void *RegionContext) 56915e32d5dSMike Smith { 57015e32d5dSMike Smith struct acpi_ec_softc *sc = (struct acpi_ec_softc *)Context; 57115e32d5dSMike Smith ACPI_STATUS Status = AE_OK; 57215e32d5dSMike Smith EC_REQUEST EcRequest; 573ee785aa9SJohn Baldwin int i; 57415e32d5dSMike Smith 575b4a05238SPeter Wemm ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, (UINT32)Address); 5760ae55423SMike Smith 577464c662eSNate Lawson if (Address > 0xFF || width % 8 != 0 || Value == NULL || Context == NULL) 5780ae55423SMike Smith return_ACPI_STATUS (AE_BAD_PARAMETER); 57915e32d5dSMike Smith 58015e32d5dSMike Smith switch (Function) { 58176f2b644SMike Smith case ACPI_READ: 58215e32d5dSMike Smith EcRequest.Command = EC_COMMAND_READ; 58315e32d5dSMike Smith EcRequest.Address = Address; 5842a4ac806SMike Smith (*Value) = 0; 58515e32d5dSMike Smith break; 58676f2b644SMike Smith case ACPI_WRITE: 58715e32d5dSMike Smith EcRequest.Command = EC_COMMAND_WRITE; 58815e32d5dSMike Smith EcRequest.Address = Address; 58915e32d5dSMike Smith break; 59015e32d5dSMike Smith default: 591464c662eSNate Lawson device_printf(sc->ec_dev, "invalid Address Space function %d\n", 592464c662eSNate Lawson Function); 5930ae55423SMike Smith return_ACPI_STATUS (AE_BAD_PARAMETER); 59415e32d5dSMike Smith } 59515e32d5dSMike Smith 59615e32d5dSMike Smith /* 59715e32d5dSMike Smith * Perform the transaction. 59815e32d5dSMike Smith */ 599ee785aa9SJohn Baldwin for (i = 0; i < width; i += 8) { 60076f2b644SMike Smith if (Function == ACPI_READ) 601ee785aa9SJohn Baldwin EcRequest.Data = 0; 602ee785aa9SJohn Baldwin else 603ee785aa9SJohn Baldwin EcRequest.Data = (UINT8)((*Value) >> i); 604464c662eSNate Lawson Status = EcTransaction(sc, &EcRequest); 605464c662eSNate Lawson if (ACPI_FAILURE(Status)) 606ee785aa9SJohn Baldwin break; 607464c662eSNate Lawson *Value |= (ACPI_INTEGER)EcRequest.Data << i; 608ee785aa9SJohn Baldwin if (++EcRequest.Address == 0) 609ee785aa9SJohn Baldwin return_ACPI_STATUS (AE_BAD_PARAMETER); 610ee785aa9SJohn Baldwin } 6110ae55423SMike Smith return_ACPI_STATUS (Status); 61215e32d5dSMike Smith } 6132a4ac806SMike Smith 614a9cf0dffSMike Smith /* 615a9cf0dffSMike Smith * Wait for an event interrupt for a specific condition. 616a9cf0dffSMike Smith */ 617c07572e7STakanori Watanabe static ACPI_STATUS 618c07572e7STakanori Watanabe EcWaitEventIntr(struct acpi_ec_softc *sc, EC_EVENT Event) 619c07572e7STakanori Watanabe { 620c07572e7STakanori Watanabe EC_STATUS EcStatus; 621c07572e7STakanori Watanabe int i; 622a9cf0dffSMike Smith 623b4a05238SPeter Wemm ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, (UINT32)Event); 624a9cf0dffSMike Smith 625a9cf0dffSMike Smith /* XXX this should test whether interrupts are available some other way */ 6264690674eSMitsuru IWASAKI if (cold || acpi_ec_event_driven) 627a9cf0dffSMike Smith return_ACPI_STATUS (EcWaitEvent(sc, Event)); 628a9cf0dffSMike Smith 629464c662eSNate Lawson if (!EcIsLocked(sc)) { 6306971b3c7SMitsuru IWASAKI ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev), 6316971b3c7SMitsuru IWASAKI "EcWaitEventIntr called without EC lock!\n"); 632464c662eSNate Lawson } 633a9cf0dffSMike Smith 634c07572e7STakanori Watanabe EcStatus = EC_GET_CSR(sc); 635a9cf0dffSMike Smith 636a9cf0dffSMike Smith /* XXX waiting too long? */ 637c07572e7STakanori Watanabe for (i = 0; i < 10; i++) { 638a9cf0dffSMike Smith /* 639a9cf0dffSMike Smith * Check EC status against the desired event. 640a9cf0dffSMike Smith */ 641c07572e7STakanori Watanabe if ((Event == EC_EVENT_OUTPUT_BUFFER_FULL) && 642464c662eSNate Lawson (EcStatus & EC_FLAG_OUTPUT_BUFFER) != 0) 643a9cf0dffSMike Smith return_ACPI_STATUS (AE_OK); 644c07572e7STakanori Watanabe 645c07572e7STakanori Watanabe if ((Event == EC_EVENT_INPUT_BUFFER_EMPTY) && 646464c662eSNate Lawson (EcStatus & EC_FLAG_INPUT_BUFFER) == 0) 647a9cf0dffSMike Smith return_ACPI_STATUS (AE_OK); 648a9cf0dffSMike Smith 649c07572e7STakanori Watanabe sc->ec_csrvalue = 0; 650464c662eSNate Lawson /* XXX sleeping with Acpi Global Lock held */ 651464c662eSNate Lawson if (tsleep(&sc->ec_csrvalue, PZERO, "EcWait", 1) != EWOULDBLOCK) { 652c07572e7STakanori Watanabe EcStatus = sc->ec_csrvalue; 653c07572e7STakanori Watanabe } else { 654c07572e7STakanori Watanabe EcStatus = EC_GET_CSR(sc); 655c07572e7STakanori Watanabe } 656c07572e7STakanori Watanabe } 657a9cf0dffSMike Smith return_ACPI_STATUS (AE_ERROR); 658c07572e7STakanori Watanabe } 65915e32d5dSMike Smith 66015e32d5dSMike Smith static ACPI_STATUS 66115e32d5dSMike Smith EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event) 66215e32d5dSMike Smith { 66315e32d5dSMike Smith EC_STATUS EcStatus; 66415e32d5dSMike Smith UINT32 i = 0; 66515e32d5dSMike Smith 666464c662eSNate Lawson if (!EcIsLocked(sc)) { 6676971b3c7SMitsuru IWASAKI ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev), 6686971b3c7SMitsuru IWASAKI "EcWaitEvent called without EC lock!\n"); 669464c662eSNate Lawson } 67015e32d5dSMike Smith 67115e32d5dSMike Smith /* 67215e32d5dSMike Smith * Stall 1us: 67315e32d5dSMike Smith * ---------- 67415e32d5dSMike Smith * Stall for 1 microsecond before reading the status register 67515e32d5dSMike Smith * for the first time. This allows the EC to set the IBF/OBF 67615e32d5dSMike Smith * bit to its proper state. 67715e32d5dSMike Smith * 67815e32d5dSMike Smith * XXX it is not clear why we read the CSR twice. 67915e32d5dSMike Smith */ 680da3b867eSMike Smith AcpiOsStall(1); 68115e32d5dSMike Smith EcStatus = EC_GET_CSR(sc); 68215e32d5dSMike Smith 68315e32d5dSMike Smith /* 68415e32d5dSMike Smith * Wait For Event: 68515e32d5dSMike Smith * --------------- 68615e32d5dSMike Smith * Poll the EC status register to detect completion of the last 6872a4ac806SMike Smith * command. Wait up to 10ms (in 10us chunks) for this to occur. 68815e32d5dSMike Smith */ 6892a4ac806SMike Smith for (i = 0; i < 1000; i++) { 69015e32d5dSMike Smith EcStatus = EC_GET_CSR(sc); 69115e32d5dSMike Smith 692464c662eSNate Lawson if (Event == EC_EVENT_OUTPUT_BUFFER_FULL && 693464c662eSNate Lawson (EcStatus & EC_FLAG_OUTPUT_BUFFER) != 0) 69415e32d5dSMike Smith return (AE_OK); 69515e32d5dSMike Smith 696464c662eSNate Lawson if (Event == EC_EVENT_INPUT_BUFFER_EMPTY && 697464c662eSNate Lawson (EcStatus & EC_FLAG_INPUT_BUFFER) == 0) 69815e32d5dSMike Smith return(AE_OK); 69915e32d5dSMike Smith 700da3b867eSMike Smith AcpiOsStall(10); 70115e32d5dSMike Smith } 70215e32d5dSMike Smith 70315e32d5dSMike Smith return (AE_ERROR); 70415e32d5dSMike Smith } 70515e32d5dSMike Smith 70615e32d5dSMike Smith static ACPI_STATUS 70715e32d5dSMike Smith EcQuery(struct acpi_ec_softc *sc, UINT8 *Data) 70815e32d5dSMike Smith { 70915e32d5dSMike Smith ACPI_STATUS Status; 71015e32d5dSMike Smith 711464c662eSNate Lawson Status = EcLock(sc); 712464c662eSNate Lawson if (ACPI_FAILURE(Status)) 71315e32d5dSMike Smith return (Status); 71415e32d5dSMike Smith 71515e32d5dSMike Smith EC_SET_CSR(sc, EC_COMMAND_QUERY); 716464c662eSNate Lawson Status = EcWaitEvent(sc, EC_EVENT_OUTPUT_BUFFER_FULL); 717464c662eSNate Lawson if (ACPI_SUCCESS(Status)) 71815e32d5dSMike Smith *Data = EC_GET_DATA(sc); 71915e32d5dSMike Smith 72015e32d5dSMike Smith EcUnlock(sc); 72115e32d5dSMike Smith 722464c662eSNate Lawson if (ACPI_FAILURE(Status)) { 7236971b3c7SMitsuru IWASAKI ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev), 7246971b3c7SMitsuru IWASAKI "timeout waiting for EC to respond to EC_COMMAND_QUERY\n"); 725464c662eSNate Lawson } 72615e32d5dSMike Smith return (Status); 72715e32d5dSMike Smith } 72815e32d5dSMike Smith 72915e32d5dSMike Smith static ACPI_STATUS 73015e32d5dSMike Smith EcTransaction(struct acpi_ec_softc *sc, EC_REQUEST *EcRequest) 73115e32d5dSMike Smith { 73215e32d5dSMike Smith ACPI_STATUS Status; 73315e32d5dSMike Smith 734464c662eSNate Lawson Status = EcLock(sc); 735464c662eSNate Lawson if (ACPI_FAILURE(Status)) 73615e32d5dSMike Smith return (Status); 73715e32d5dSMike Smith 73815e32d5dSMike Smith /* 73915e32d5dSMike Smith * Perform the transaction. 74015e32d5dSMike Smith */ 74115e32d5dSMike Smith switch (EcRequest->Command) { 74215e32d5dSMike Smith case EC_COMMAND_READ: 743464c662eSNate Lawson Status = EcRead(sc, EcRequest->Address, &EcRequest->Data); 74415e32d5dSMike Smith break; 74515e32d5dSMike Smith case EC_COMMAND_WRITE: 746464c662eSNate Lawson Status = EcWrite(sc, EcRequest->Address, &EcRequest->Data); 74715e32d5dSMike Smith break; 74815e32d5dSMike Smith default: 74915e32d5dSMike Smith Status = AE_SUPPORT; 75015e32d5dSMike Smith break; 75115e32d5dSMike Smith } 75215e32d5dSMike Smith 7532a4ac806SMike Smith EcUnlock(sc); 7542a4ac806SMike Smith 7552a4ac806SMike Smith /* 75615e32d5dSMike Smith * Clear & Re-Enable the EC GPE: 75715e32d5dSMike Smith * ----------------------------- 75815e32d5dSMike Smith * 'Consume' any EC GPE events that we generated while performing 75915e32d5dSMike Smith * the transaction (e.g. IBF/OBF). Clearing the GPE here shouldn't 76015e32d5dSMike Smith * have an adverse affect on outstanding EC-SCI's, as the source 76115e32d5dSMike Smith * (EC-SCI) will still be high and thus should trigger the GPE 76215e32d5dSMike Smith * immediately after we re-enabling it. 76315e32d5dSMike Smith */ 764c07572e7STakanori Watanabe if (sc->ec_pendquery) { 765dbd0058aSMike Smith if (ACPI_FAILURE(AcpiOsQueueForExecution(OSD_PRIORITY_HIGH, 766dbd0058aSMike Smith EcGpeQueryHandler, sc))) 767c07572e7STakanori Watanabe printf("Pend Query Queuing Failed\n"); 768c07572e7STakanori Watanabe sc->ec_pendquery = 0; 769c07572e7STakanori Watanabe } 770c07572e7STakanori Watanabe 771464c662eSNate Lawson if (ACPI_FAILURE(AcpiClearEvent(sc->ec_gpebit, ACPI_EVENT_GPE))) { 7726971b3c7SMitsuru IWASAKI ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev), 7736971b3c7SMitsuru IWASAKI "EcRequest: Unable to clear the EC GPE.\n"); 774464c662eSNate Lawson } 775464c662eSNate Lawson if (ACPI_FAILURE(AcpiEnableEvent(sc->ec_gpebit, ACPI_EVENT_GPE, 0))) { 7766971b3c7SMitsuru IWASAKI ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev), 7776971b3c7SMitsuru IWASAKI "EcRequest: Unable to re-enable the EC GPE.\n"); 778464c662eSNate Lawson } 77915e32d5dSMike Smith 78015e32d5dSMike Smith return (Status); 78115e32d5dSMike Smith } 78215e32d5dSMike Smith 78315e32d5dSMike Smith 78415e32d5dSMike Smith static ACPI_STATUS 78515e32d5dSMike Smith EcRead(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data) 78615e32d5dSMike Smith { 78715e32d5dSMike Smith ACPI_STATUS Status; 78815e32d5dSMike Smith 789464c662eSNate Lawson if (!EcIsLocked(sc)) { 7906971b3c7SMitsuru IWASAKI ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev), 7916971b3c7SMitsuru IWASAKI "EcRead called without EC lock!\n"); 792464c662eSNate Lawson } 79315e32d5dSMike Smith 79415e32d5dSMike Smith /*EcBurstEnable(EmbeddedController);*/ 79515e32d5dSMike Smith 79615e32d5dSMike Smith EC_SET_CSR(sc, EC_COMMAND_READ); 797464c662eSNate Lawson Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY); 798464c662eSNate Lawson if (ACPI_FAILURE(Status)) { 7996971b3c7SMitsuru IWASAKI ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev), 8006971b3c7SMitsuru IWASAKI "EcRead: Failed waiting for EC to process read command.\n"); 80115e32d5dSMike Smith return (Status); 80215e32d5dSMike Smith } 80315e32d5dSMike Smith 80415e32d5dSMike Smith EC_SET_DATA(sc, Address); 805464c662eSNate Lawson Status = EcWaitEventIntr(sc, EC_EVENT_OUTPUT_BUFFER_FULL); 806464c662eSNate Lawson if (ACPI_FAILURE(Status)) { 8076971b3c7SMitsuru IWASAKI ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev), 8086971b3c7SMitsuru IWASAKI "EcRead: Failed waiting for EC to send data.\n"); 80915e32d5dSMike Smith return (Status); 81015e32d5dSMike Smith } 81115e32d5dSMike Smith 812464c662eSNate Lawson *Data = EC_GET_DATA(sc); 81315e32d5dSMike Smith 81415e32d5dSMike Smith /*EcBurstDisable(EmbeddedController);*/ 81515e32d5dSMike Smith 81615e32d5dSMike Smith return (AE_OK); 81715e32d5dSMike Smith } 81815e32d5dSMike Smith 81915e32d5dSMike Smith static ACPI_STATUS 82015e32d5dSMike Smith EcWrite(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data) 82115e32d5dSMike Smith { 82215e32d5dSMike Smith ACPI_STATUS Status; 82315e32d5dSMike Smith 824464c662eSNate Lawson if (!EcIsLocked(sc)) { 8256971b3c7SMitsuru IWASAKI ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev), 8266971b3c7SMitsuru IWASAKI "EcWrite called without EC lock!\n"); 827464c662eSNate Lawson } 82815e32d5dSMike Smith 82915e32d5dSMike Smith /*EcBurstEnable(EmbeddedController);*/ 83015e32d5dSMike Smith 83115e32d5dSMike Smith EC_SET_CSR(sc, EC_COMMAND_WRITE); 832464c662eSNate Lawson Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY); 833464c662eSNate Lawson if (ACPI_FAILURE(Status)) { 8346971b3c7SMitsuru IWASAKI ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev), 8356971b3c7SMitsuru IWASAKI "EcWrite: Failed waiting for EC to process write command.\n"); 83615e32d5dSMike Smith return (Status); 83715e32d5dSMike Smith } 83815e32d5dSMike Smith 83915e32d5dSMike Smith EC_SET_DATA(sc, Address); 840464c662eSNate Lawson Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY); 841464c662eSNate Lawson if (ACPI_FAILURE(Status)) { 8426971b3c7SMitsuru IWASAKI ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev), 8436971b3c7SMitsuru IWASAKI "EcRead: Failed waiting for EC to process address.\n"); 84415e32d5dSMike Smith return (Status); 84515e32d5dSMike Smith } 84615e32d5dSMike Smith 84715e32d5dSMike Smith EC_SET_DATA(sc, *Data); 848464c662eSNate Lawson Status = EcWaitEventIntr(sc, EC_EVENT_INPUT_BUFFER_EMPTY); 849464c662eSNate Lawson if (ACPI_FAILURE(Status)) { 8506971b3c7SMitsuru IWASAKI ACPI_VPRINT(sc->ec_dev, acpi_device_get_parent_softc(sc->ec_dev), 8516971b3c7SMitsuru IWASAKI "EcWrite: Failed waiting for EC to process data.\n"); 85215e32d5dSMike Smith return (Status); 85315e32d5dSMike Smith } 85415e32d5dSMike Smith 85515e32d5dSMike Smith /*EcBurstDisable(EmbeddedController);*/ 85615e32d5dSMike Smith 85715e32d5dSMike Smith return (AE_OK); 85815e32d5dSMike Smith } 859