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 #include <dev/acpica/acpi_ecreg.h> 15115e32d5dSMike Smith 1520ae55423SMike Smith /* 1530ae55423SMike Smith * Hooks for the ACPI CA debugging infrastructure 1540ae55423SMike Smith */ 1550ae55423SMike Smith #define _COMPONENT EMBEDDED_CONTROLLER 1560ae55423SMike Smith MODULE_NAME("EC") 1570ae55423SMike Smith 15815e32d5dSMike Smith struct acpi_ec_softc { 15915e32d5dSMike Smith device_t ec_dev; 16015e32d5dSMike Smith ACPI_HANDLE ec_handle; 16115e32d5dSMike Smith ACPI_HANDLE ec_semaphore; 16215e32d5dSMike Smith UINT32 ec_gpebit; 16315e32d5dSMike Smith 16415e32d5dSMike Smith int ec_data_rid; 16515e32d5dSMike Smith struct resource *ec_data_res; 16615e32d5dSMike Smith bus_space_tag_t ec_data_tag; 16715e32d5dSMike Smith bus_space_handle_t ec_data_handle; 16815e32d5dSMike Smith 16915e32d5dSMike Smith int ec_csr_rid; 17015e32d5dSMike Smith struct resource *ec_csr_res; 17115e32d5dSMike Smith bus_space_tag_t ec_csr_tag; 17215e32d5dSMike Smith bus_space_handle_t ec_csr_handle; 17315e32d5dSMike Smith 17415e32d5dSMike Smith int ec_locked; 17515e32d5dSMike Smith }; 17615e32d5dSMike Smith 17715e32d5dSMike Smith #define EC_LOCK_TIMEOUT 1000 /* 1ms */ 17815e32d5dSMike Smith 17915e32d5dSMike Smith static __inline ACPI_STATUS 18015e32d5dSMike Smith EcLock(struct acpi_ec_softc *sc) 18115e32d5dSMike Smith { 18215e32d5dSMike Smith ACPI_STATUS status; 18315e32d5dSMike Smith 18415e32d5dSMike Smith status = AcpiOsWaitSemaphore((sc)->ec_semaphore, 1, EC_LOCK_TIMEOUT); 18515e32d5dSMike Smith (sc)->ec_locked = 1; 18615e32d5dSMike Smith return(status); 18715e32d5dSMike Smith } 18815e32d5dSMike Smith 18915e32d5dSMike Smith static __inline void 19015e32d5dSMike Smith EcUnlock(struct acpi_ec_softc *sc) 19115e32d5dSMike Smith { 19215e32d5dSMike Smith (sc)->ec_locked = 0; 19315e32d5dSMike Smith AcpiOsSignalSemaphore((sc)->ec_semaphore, 1); 19415e32d5dSMike Smith } 19515e32d5dSMike Smith 19615e32d5dSMike Smith static __inline int 19715e32d5dSMike Smith EcIsLocked(struct acpi_ec_softc *sc) 19815e32d5dSMike Smith { 19915e32d5dSMike Smith return((sc)->ec_locked != 0); 20015e32d5dSMike Smith } 20115e32d5dSMike Smith 20215e32d5dSMike Smith typedef struct 20315e32d5dSMike Smith { 20415e32d5dSMike Smith EC_COMMAND Command; 20515e32d5dSMike Smith UINT8 Address; 20615e32d5dSMike Smith UINT8 Data; 20715e32d5dSMike Smith } EC_REQUEST; 20815e32d5dSMike Smith 20915e32d5dSMike Smith static struct acpi_ec_softc acpi_ec_default; /* for the default EC handler */ 21015e32d5dSMike Smith 21115e32d5dSMike Smith static void EcGpeHandler(void *Context); 21215e32d5dSMike Smith static ACPI_STATUS EcSpaceSetup(ACPI_HANDLE Region, UINT32 Function, 21315e32d5dSMike Smith void *Context, void **return_Context); 214042283a6SMike Smith static ACPI_STATUS EcSpaceHandler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address, UINT32 width, UINT32 *Value, 21515e32d5dSMike Smith void *Context, void *RegionContext); 21615e32d5dSMike Smith 21715e32d5dSMike Smith static ACPI_STATUS EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event); 21815e32d5dSMike Smith static ACPI_STATUS EcQuery(struct acpi_ec_softc *sc, UINT8 *Data); 21915e32d5dSMike Smith static ACPI_STATUS EcTransaction(struct acpi_ec_softc *sc, EC_REQUEST *EcRequest); 22015e32d5dSMike Smith static ACPI_STATUS EcRead(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data); 22115e32d5dSMike Smith static ACPI_STATUS EcWrite(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data); 22215e32d5dSMike Smith 22315e32d5dSMike Smith static void acpi_ec_identify(driver_t driver, device_t bus); 22415e32d5dSMike Smith static int acpi_ec_probe(device_t dev); 22515e32d5dSMike Smith static int acpi_ec_attach(device_t dev); 22615e32d5dSMike Smith 22715e32d5dSMike Smith static device_method_t acpi_ec_methods[] = { 22815e32d5dSMike Smith /* Device interface */ 22915e32d5dSMike Smith DEVMETHOD(device_identify, acpi_ec_identify), 23015e32d5dSMike Smith DEVMETHOD(device_probe, acpi_ec_probe), 23115e32d5dSMike Smith DEVMETHOD(device_attach, acpi_ec_attach), 23215e32d5dSMike Smith 23315e32d5dSMike Smith {0, 0} 23415e32d5dSMike Smith }; 23515e32d5dSMike Smith 23615e32d5dSMike Smith static driver_t acpi_ec_driver = { 23715e32d5dSMike Smith "acpi_ec", 23815e32d5dSMike Smith acpi_ec_methods, 23915e32d5dSMike Smith sizeof(struct acpi_ec_softc), 24015e32d5dSMike Smith }; 24115e32d5dSMike Smith 24215e32d5dSMike Smith devclass_t acpi_ec_devclass; 24315e32d5dSMike Smith DRIVER_MODULE(acpi_ec, acpi, acpi_ec_driver, acpi_ec_devclass, 0, 0); 24415e32d5dSMike Smith 24515e32d5dSMike Smith /* 24615e32d5dSMike Smith * Look for an ECDT table and if we find one, set up a default EC 24715e32d5dSMike Smith * space handler to catch possible attempts to access EC space before 24815e32d5dSMike Smith * we have a real driver instance in place. 24915e32d5dSMike Smith * We're not really an identify routine, but because we get called 25015e32d5dSMike Smith * before most other things, this works out OK. 25115e32d5dSMike Smith */ 25215e32d5dSMike Smith static void 25315e32d5dSMike Smith acpi_ec_identify(driver_t driver, device_t bus) 25415e32d5dSMike Smith { 2550ae55423SMike Smith FUNCTION_TRACE(__FUNCTION__); 25615e32d5dSMike Smith 25715e32d5dSMike Smith /* XXX implement - need an ACPI 2.0 system to test this */ 2580ae55423SMike Smith 2590ae55423SMike Smith return_VOID; 26015e32d5dSMike Smith } 26115e32d5dSMike Smith 26215e32d5dSMike Smith /* 26315e32d5dSMike Smith * We could setup resources in the probe routine in order to have them printed 26415e32d5dSMike Smith * when the device is attached. 26515e32d5dSMike Smith */ 26615e32d5dSMike Smith static int 26715e32d5dSMike Smith acpi_ec_probe(device_t dev) 26815e32d5dSMike Smith { 2690ae55423SMike Smith 27015e32d5dSMike Smith if ((acpi_get_type(dev) == ACPI_TYPE_DEVICE) && 2710ae55423SMike Smith !acpi_disabled("ec") && 27215e32d5dSMike Smith acpi_MatchHid(dev, "PNP0C09")) { 27315e32d5dSMike Smith 27415e32d5dSMike Smith /* 27515e32d5dSMike Smith * Set device description 27615e32d5dSMike Smith */ 27715e32d5dSMike Smith device_set_desc(dev, "embedded controller"); 27815e32d5dSMike Smith 27915e32d5dSMike Smith return(0); 28015e32d5dSMike Smith } 28115e32d5dSMike Smith return(ENXIO); 28215e32d5dSMike Smith } 28315e32d5dSMike Smith 28415e32d5dSMike Smith static int 28515e32d5dSMike Smith acpi_ec_attach(device_t dev) 28615e32d5dSMike Smith { 28715e32d5dSMike Smith struct acpi_ec_softc *sc; 28815e32d5dSMike Smith ACPI_BUFFER *bufp; 28915e32d5dSMike Smith UINT32 *param; 29015e32d5dSMike Smith ACPI_STATUS Status; 29115e32d5dSMike Smith struct acpi_object_list *args; 29215e32d5dSMike Smith 2930ae55423SMike Smith FUNCTION_TRACE(__FUNCTION__); 2940ae55423SMike Smith 29515e32d5dSMike Smith /* 29615e32d5dSMike Smith * Fetch/initialise softc 29715e32d5dSMike Smith */ 29815e32d5dSMike Smith sc = device_get_softc(dev); 29915e32d5dSMike Smith sc->ec_dev = dev; 30015e32d5dSMike Smith sc->ec_handle = acpi_get_handle(dev); 30115e32d5dSMike Smith 30215e32d5dSMike Smith /* 30315e32d5dSMike Smith * Evaluate resources 30415e32d5dSMike Smith */ 30515e32d5dSMike Smith acpi_parse_resources(sc->ec_dev, sc->ec_handle, &acpi_res_parse_set); 30615e32d5dSMike Smith 30715e32d5dSMike Smith /* 30815e32d5dSMike Smith * Attach bus resources 30915e32d5dSMike Smith */ 31015e32d5dSMike Smith sc->ec_data_rid = 0; 31115e32d5dSMike Smith if ((sc->ec_data_res = bus_alloc_resource(sc->ec_dev, SYS_RES_IOPORT, &sc->ec_data_rid, 31215e32d5dSMike Smith 0, ~0, 1, RF_ACTIVE)) == NULL) { 31315e32d5dSMike Smith device_printf(dev, "can't allocate data port\n"); 3140ae55423SMike Smith return_VALUE(ENXIO); 31515e32d5dSMike Smith } 31615e32d5dSMike Smith sc->ec_data_tag = rman_get_bustag(sc->ec_data_res); 31715e32d5dSMike Smith sc->ec_data_handle = rman_get_bushandle(sc->ec_data_res); 31815e32d5dSMike Smith 31915e32d5dSMike Smith sc->ec_csr_rid = 1; 32015e32d5dSMike Smith if ((sc->ec_csr_res = bus_alloc_resource(sc->ec_dev, SYS_RES_IOPORT, &sc->ec_csr_rid, 32115e32d5dSMike Smith 0, ~0, 1, RF_ACTIVE)) == NULL) { 32215e32d5dSMike Smith device_printf(dev, "can't allocate command/status port\n"); 3230ae55423SMike Smith return_VALUE(ENXIO); 32415e32d5dSMike Smith } 32515e32d5dSMike Smith sc->ec_csr_tag = rman_get_bustag(sc->ec_csr_res); 32615e32d5dSMike Smith sc->ec_csr_handle = rman_get_bushandle(sc->ec_csr_res); 32715e32d5dSMike Smith 32815e32d5dSMike Smith /* 32915e32d5dSMike Smith * Create serialisation semaphore 33015e32d5dSMike Smith */ 33115e32d5dSMike Smith if ((Status = AcpiOsCreateSemaphore(1, 1, &sc->ec_semaphore)) != AE_OK) { 33215e32d5dSMike Smith device_printf(dev, "can't create semaphore - %s\n", acpi_strerror(Status)); 3330ae55423SMike Smith return_VALUE(ENXIO); 33415e32d5dSMike Smith } 33515e32d5dSMike Smith 33615e32d5dSMike Smith /* 33715e32d5dSMike Smith * Install GPE handler 33815e32d5dSMike Smith * 33915e32d5dSMike Smith * Evaluate the _GPE method to find the GPE bit used by the EC to signal 34015e32d5dSMike Smith * status (SCI). 34115e32d5dSMike Smith */ 34215e32d5dSMike Smith if ((bufp = acpi_AllocBuffer(16)) == NULL) 3430ae55423SMike Smith return_VALUE(ENOMEM); 34415e32d5dSMike Smith if ((Status = AcpiEvaluateObject(sc->ec_handle, "_GPE", NULL, bufp)) != AE_OK) { 34515e32d5dSMike Smith device_printf(dev, "can't evaluate _GPE method - %s\n", acpi_strerror(Status)); 3460ae55423SMike Smith return_VALUE(ENXIO); 34715e32d5dSMike Smith } 34815e32d5dSMike Smith param = (UINT32 *)bufp->Pointer; 34915e32d5dSMike Smith if (param[0] != ACPI_TYPE_NUMBER) { 35015e32d5dSMike Smith device_printf(dev, "_GPE method returned bad result\n"); 3510ae55423SMike Smith return_VALUE(ENXIO); 35215e32d5dSMike Smith } 35315e32d5dSMike Smith sc->ec_gpebit = param[1]; 35415e32d5dSMike Smith AcpiOsFree(bufp); 35515e32d5dSMike Smith 35615e32d5dSMike Smith /* 35715e32d5dSMike Smith * Install a handler for this EC's GPE bit. Note that EC SCIs are 35815e32d5dSMike Smith * treated as both edge- and level-triggered interrupts; in other words 35915e32d5dSMike Smith * we clear the status bit immediately after getting an EC-SCI, then 36015e32d5dSMike Smith * again after we're done processing the event. This guarantees that 36115e32d5dSMike Smith * events we cause while performing a transaction (e.g. IBE/OBF) get 36215e32d5dSMike Smith * cleared before re-enabling the GPE. 36315e32d5dSMike Smith */ 36415e32d5dSMike Smith if ((Status = AcpiInstallGpeHandler(sc->ec_gpebit, ACPI_EVENT_LEVEL_TRIGGERED | ACPI_EVENT_EDGE_TRIGGERED, 36515e32d5dSMike Smith EcGpeHandler, sc)) != AE_OK) { 36615e32d5dSMike Smith device_printf(dev, "can't install GPE handler - %s\n", acpi_strerror(Status)); 3670ae55423SMike Smith return_VALUE(ENXIO); 36815e32d5dSMike Smith } 36915e32d5dSMike Smith 37015e32d5dSMike Smith /* 37115e32d5dSMike Smith * Install address space handler 37215e32d5dSMike Smith */ 37315e32d5dSMike Smith if ((Status = AcpiInstallAddressSpaceHandler(sc->ec_handle, ADDRESS_SPACE_EC, 37415e32d5dSMike Smith &EcSpaceHandler, &EcSpaceSetup, sc)) != AE_OK) { 37515e32d5dSMike Smith device_printf(dev, "can't install address space handler - %s\n", acpi_strerror(Status)); 3760ae55423SMike Smith return_VALUE(ENXIO); 37715e32d5dSMike Smith } 37815e32d5dSMike Smith 37915e32d5dSMike Smith /* 38015e32d5dSMike Smith * Evaluate _REG to indicate that the region is now available. 38115e32d5dSMike Smith */ 38215e32d5dSMike Smith if ((args = acpi_AllocObjectList(2)) == NULL) 3830ae55423SMike Smith return_VALUE(ENOMEM); 38415e32d5dSMike Smith args->object[0].Type = ACPI_TYPE_NUMBER; 38515e32d5dSMike Smith args->object[0].Number.Value = ADDRESS_SPACE_EC; 38615e32d5dSMike Smith args->object[1].Type = ACPI_TYPE_NUMBER; 38715e32d5dSMike Smith args->object[1].Number.Value = 1; 38815e32d5dSMike Smith Status = AcpiEvaluateObject(sc->ec_handle, "_REG", (ACPI_OBJECT_LIST *)args, NULL); 38915e32d5dSMike Smith AcpiOsFree(args); 39015e32d5dSMike Smith /* 39115e32d5dSMike Smith * If evaluation failed for some reason other than that the method didn't 39215e32d5dSMike Smith * exist, that's bad and we should not attach. 39315e32d5dSMike Smith */ 39415e32d5dSMike Smith if ((Status != AE_OK) && (Status != AE_NOT_FOUND)) { 39515e32d5dSMike Smith device_printf(dev, "can't evaluate _REG method - %s\n", acpi_strerror(Status)); 3960ae55423SMike Smith return_VALUE(ENXIO); 39715e32d5dSMike Smith } 39815e32d5dSMike Smith 3990ae55423SMike Smith return_VALUE(0); 40015e32d5dSMike Smith } 40115e32d5dSMike Smith 40215e32d5dSMike Smith static void 40315e32d5dSMike Smith EcGpeHandler(void *Context) 40415e32d5dSMike Smith { 40515e32d5dSMike Smith struct acpi_ec_softc *sc = (struct acpi_ec_softc *)Context; 40615e32d5dSMike Smith UINT8 Data; 40715e32d5dSMike Smith ACPI_STATUS Status; 40815e32d5dSMike Smith char qxx[5]; 40915e32d5dSMike Smith 4100ae55423SMike Smith FUNCTION_TRACE(__FUNCTION__); 4110ae55423SMike Smith 41215e32d5dSMike Smith for (;;) { 41315e32d5dSMike Smith 41415e32d5dSMike Smith /* 41515e32d5dSMike Smith * Check EC_SCI. 41615e32d5dSMike Smith * 41715e32d5dSMike Smith * Bail out if the EC_SCI bit of the status register is not set. 41815e32d5dSMike Smith * Note that this function should only be called when 41915e32d5dSMike Smith * this bit is set (polling is used to detect IBE/OBF events). 42015e32d5dSMike Smith * 42115e32d5dSMike Smith * It is safe to do this without locking the controller, as it's 42215e32d5dSMike Smith * OK to call EcQuery when there's no data ready; in the worst 42315e32d5dSMike Smith * case we should just find nothing waiting for us and bail. 42415e32d5dSMike Smith */ 42515e32d5dSMike Smith if (!(EC_GET_CSR(sc) & EC_EVENT_SCI)) 42615e32d5dSMike Smith break; 42715e32d5dSMike Smith 42815e32d5dSMike Smith /* 42915e32d5dSMike Smith * Find out why the EC is signalling us 43015e32d5dSMike Smith */ 43115e32d5dSMike Smith Status = EcQuery(sc, &Data); 43215e32d5dSMike Smith 43315e32d5dSMike Smith /* 43415e32d5dSMike Smith * If we failed to get anything from the EC, give up 43515e32d5dSMike Smith */ 43615e32d5dSMike Smith if (Status != AE_OK) { 43715e32d5dSMike Smith device_printf(sc->ec_dev, "GPE query failed - %s\n", acpi_strerror(Status)); 43815e32d5dSMike Smith break; 43915e32d5dSMike Smith } 44015e32d5dSMike Smith 44115e32d5dSMike Smith /* 44215e32d5dSMike Smith * Evaluate _Qxx to respond to the controller. 44315e32d5dSMike Smith */ 44415e32d5dSMike Smith sprintf(qxx, "_Q%02x", Data); 44515e32d5dSMike Smith strupr(qxx); 44615e32d5dSMike Smith if ((Status - AcpiEvaluateObject(sc->ec_handle, qxx, NULL, NULL)) != AE_OK) { 44715e32d5dSMike Smith device_printf(sc->ec_dev, "evaluation of GPE query method %s failed - %s\n", 44815e32d5dSMike Smith qxx, acpi_strerror(Status)); 44915e32d5dSMike Smith } 45015e32d5dSMike Smith } 4510ae55423SMike Smith return_VOID; 45215e32d5dSMike Smith } 45315e32d5dSMike Smith 45415e32d5dSMike Smith static ACPI_STATUS 45515e32d5dSMike Smith EcSpaceSetup(ACPI_HANDLE Region, UINT32 Function, void *Context, void **RegionContext) 45615e32d5dSMike Smith { 45715e32d5dSMike Smith /* 45815e32d5dSMike Smith * Just pass the context through, there's nothing to do here. 45915e32d5dSMike Smith */ 46015e32d5dSMike Smith *RegionContext = Context; 46115e32d5dSMike Smith 46215e32d5dSMike Smith return(AE_OK); 46315e32d5dSMike Smith } 46415e32d5dSMike Smith 46515e32d5dSMike Smith static ACPI_STATUS 466042283a6SMike Smith EcSpaceHandler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address, UINT32 width, UINT32 *Value, 467042283a6SMike Smith void *Context, void *RegionContext) 46815e32d5dSMike Smith { 46915e32d5dSMike Smith struct acpi_ec_softc *sc = (struct acpi_ec_softc *)Context; 47015e32d5dSMike Smith ACPI_STATUS Status = AE_OK; 47115e32d5dSMike Smith EC_REQUEST EcRequest; 47215e32d5dSMike Smith 4730ae55423SMike Smith FUNCTION_TRACE_U32(__FUNCTION__, Address); 4740ae55423SMike Smith 47515e32d5dSMike Smith if ((Address > 0xFF) || (width != 8) || (Value == NULL) || (Context == NULL)) 4760ae55423SMike Smith return_ACPI_STATUS(AE_BAD_PARAMETER); 47715e32d5dSMike Smith 47815e32d5dSMike Smith switch (Function) { 47915e32d5dSMike Smith case ADDRESS_SPACE_READ: 48015e32d5dSMike Smith EcRequest.Command = EC_COMMAND_READ; 48115e32d5dSMike Smith EcRequest.Address = Address; 48215e32d5dSMike Smith EcRequest.Data = 0; 48315e32d5dSMike Smith break; 48415e32d5dSMike Smith 48515e32d5dSMike Smith case ADDRESS_SPACE_WRITE: 48615e32d5dSMike Smith EcRequest.Command = EC_COMMAND_WRITE; 48715e32d5dSMike Smith EcRequest.Address = Address; 48815e32d5dSMike Smith EcRequest.Data = (UINT8)(*Value); 48915e32d5dSMike Smith break; 49015e32d5dSMike Smith 49115e32d5dSMike Smith default: 49215e32d5dSMike Smith device_printf(sc->ec_dev, "invalid Address Space function %d\n", Function); 4930ae55423SMike Smith return_ACPI_STATUS(AE_BAD_PARAMETER); 49415e32d5dSMike Smith } 49515e32d5dSMike Smith 49615e32d5dSMike Smith /* 49715e32d5dSMike Smith * Perform the transaction. 49815e32d5dSMike Smith */ 49915e32d5dSMike Smith if ((Status = EcTransaction(sc, &EcRequest)) == AE_OK) 50015e32d5dSMike Smith (*Value) = (UINT32)EcRequest.Data; 50115e32d5dSMike Smith 5020ae55423SMike Smith return_ACPI_STATUS(Status); 50315e32d5dSMike Smith } 50415e32d5dSMike Smith 50515e32d5dSMike Smith static ACPI_STATUS 50615e32d5dSMike Smith EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event) 50715e32d5dSMike Smith { 50815e32d5dSMike Smith EC_STATUS EcStatus; 50915e32d5dSMike Smith UINT32 i = 0; 51015e32d5dSMike Smith 51115e32d5dSMike Smith if (!EcIsLocked(sc)) 51215e32d5dSMike Smith device_printf(sc->ec_dev, "EcWaitEvent called without EC lock!\n"); 51315e32d5dSMike Smith 51415e32d5dSMike Smith /* 51515e32d5dSMike Smith * Stall 1us: 51615e32d5dSMike Smith * ---------- 51715e32d5dSMike Smith * Stall for 1 microsecond before reading the status register 51815e32d5dSMike Smith * for the first time. This allows the EC to set the IBF/OBF 51915e32d5dSMike Smith * bit to its proper state. 52015e32d5dSMike Smith * 52115e32d5dSMike Smith * XXX it is not clear why we read the CSR twice. 52215e32d5dSMike Smith */ 52315e32d5dSMike Smith AcpiOsSleepUsec(1); 52415e32d5dSMike Smith EcStatus = EC_GET_CSR(sc); 52515e32d5dSMike Smith 52615e32d5dSMike Smith /* 52715e32d5dSMike Smith * Wait For Event: 52815e32d5dSMike Smith * --------------- 52915e32d5dSMike Smith * Poll the EC status register to detect completion of the last 53015e32d5dSMike Smith * command. Wait up to 10ms (in 100us chunks) for this to occur. 53115e32d5dSMike Smith */ 53215e32d5dSMike Smith for (i = 0; i < 100; i++) { 53315e32d5dSMike Smith EcStatus = EC_GET_CSR(sc); 53415e32d5dSMike Smith 53515e32d5dSMike Smith if ((Event == EC_EVENT_OUTPUT_BUFFER_FULL) && 53615e32d5dSMike Smith (EcStatus & EC_FLAG_OUTPUT_BUFFER)) 53715e32d5dSMike Smith return(AE_OK); 53815e32d5dSMike Smith 53915e32d5dSMike Smith if ((Event == EC_EVENT_INPUT_BUFFER_EMPTY) && 54015e32d5dSMike Smith !(EcStatus & EC_FLAG_INPUT_BUFFER)) 54115e32d5dSMike Smith return(AE_OK); 54215e32d5dSMike Smith 54315e32d5dSMike Smith AcpiOsSleepUsec(100); 54415e32d5dSMike Smith } 54515e32d5dSMike Smith 54615e32d5dSMike Smith return(AE_ERROR); 54715e32d5dSMike Smith } 54815e32d5dSMike Smith 54915e32d5dSMike Smith static ACPI_STATUS 55015e32d5dSMike Smith EcQuery(struct acpi_ec_softc *sc, UINT8 *Data) 55115e32d5dSMike Smith { 55215e32d5dSMike Smith ACPI_STATUS Status; 55315e32d5dSMike Smith 55415e32d5dSMike Smith if ((Status = EcLock(sc)) != AE_OK) 55515e32d5dSMike Smith return(Status); 55615e32d5dSMike Smith 55715e32d5dSMike Smith EC_SET_CSR(sc, EC_COMMAND_QUERY); 55815e32d5dSMike Smith Status = EcWaitEvent(sc, EC_EVENT_OUTPUT_BUFFER_FULL); 55915e32d5dSMike Smith if (Status == AE_OK) 56015e32d5dSMike Smith *Data = EC_GET_DATA(sc); 56115e32d5dSMike Smith 56215e32d5dSMike Smith EcUnlock(sc); 56315e32d5dSMike Smith 56415e32d5dSMike Smith if (Status != AE_OK) 56515e32d5dSMike Smith device_printf(sc->ec_dev, "timeout waiting for EC to respond to EC_COMMAND_QUERY\n"); 56615e32d5dSMike Smith return(Status); 56715e32d5dSMike Smith } 56815e32d5dSMike Smith 56915e32d5dSMike Smith 57015e32d5dSMike Smith static ACPI_STATUS 57115e32d5dSMike Smith EcTransaction(struct acpi_ec_softc *sc, EC_REQUEST *EcRequest) 57215e32d5dSMike Smith { 57315e32d5dSMike Smith ACPI_STATUS Status; 57415e32d5dSMike Smith 57515e32d5dSMike Smith /* 57615e32d5dSMike Smith * Lock the EC 57715e32d5dSMike Smith */ 57815e32d5dSMike Smith if ((Status = EcLock(sc)) != AE_OK) 57915e32d5dSMike Smith return(Status); 58015e32d5dSMike Smith 58115e32d5dSMike Smith /* 58215e32d5dSMike Smith * Disable EC GPE: 58315e32d5dSMike Smith * --------------- 58415e32d5dSMike Smith * Disable EC interrupts (GPEs) from occuring during this transaction. 58515e32d5dSMike Smith * This is done here as EcTransaction() is also called by the EC GPE 58615e32d5dSMike Smith * handler -- where disabling/re-enabling the EC GPE is automatically 58715e32d5dSMike Smith * handled by the ACPI Core Subsystem. 58815e32d5dSMike Smith */ 58915e32d5dSMike Smith if (AcpiDisableEvent(sc->ec_gpebit, ACPI_EVENT_GPE) != AE_OK) 59015e32d5dSMike Smith device_printf(sc->ec_dev, "EcRequest: Unable to disable the EC GPE.\n"); 59115e32d5dSMike Smith 59215e32d5dSMike Smith /* 59315e32d5dSMike Smith * Perform the transaction. 59415e32d5dSMike Smith */ 59515e32d5dSMike Smith switch (EcRequest->Command) { 59615e32d5dSMike Smith case EC_COMMAND_READ: 59715e32d5dSMike Smith Status = EcRead(sc, EcRequest->Address, &(EcRequest->Data)); 59815e32d5dSMike Smith break; 59915e32d5dSMike Smith 60015e32d5dSMike Smith case EC_COMMAND_WRITE: 60115e32d5dSMike Smith Status = EcWrite(sc, EcRequest->Address, &(EcRequest->Data)); 60215e32d5dSMike Smith break; 60315e32d5dSMike Smith 60415e32d5dSMike Smith default: 60515e32d5dSMike Smith Status = AE_SUPPORT; 60615e32d5dSMike Smith break; 60715e32d5dSMike Smith } 60815e32d5dSMike Smith 60915e32d5dSMike Smith /* 61015e32d5dSMike Smith * Clear & Re-Enable the EC GPE: 61115e32d5dSMike Smith * ----------------------------- 61215e32d5dSMike Smith * 'Consume' any EC GPE events that we generated while performing 61315e32d5dSMike Smith * the transaction (e.g. IBF/OBF). Clearing the GPE here shouldn't 61415e32d5dSMike Smith * have an adverse affect on outstanding EC-SCI's, as the source 61515e32d5dSMike Smith * (EC-SCI) will still be high and thus should trigger the GPE 61615e32d5dSMike Smith * immediately after we re-enabling it. 61715e32d5dSMike Smith */ 61815e32d5dSMike Smith if (AcpiClearEvent(sc->ec_gpebit, ACPI_EVENT_GPE) != AE_OK) 61915e32d5dSMike Smith device_printf(sc->ec_dev, "EcRequest: Unable to clear the EC GPE.\n"); 62015e32d5dSMike Smith if (AcpiEnableEvent(sc->ec_gpebit, ACPI_EVENT_GPE) != AE_OK) 62115e32d5dSMike Smith device_printf(sc->ec_dev, "EcRequest: Unable to re-enable the EC GPE.\n"); 62215e32d5dSMike Smith 62315e32d5dSMike Smith /* 62415e32d5dSMike Smith * Unlock the EC 62515e32d5dSMike Smith */ 62615e32d5dSMike Smith EcUnlock(sc); 62715e32d5dSMike Smith 62815e32d5dSMike Smith return(Status); 62915e32d5dSMike Smith } 63015e32d5dSMike Smith 63115e32d5dSMike Smith 63215e32d5dSMike Smith static ACPI_STATUS 63315e32d5dSMike Smith EcRead(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data) 63415e32d5dSMike Smith { 63515e32d5dSMike Smith ACPI_STATUS Status; 63615e32d5dSMike Smith 63715e32d5dSMike Smith if (!EcIsLocked(sc)) 63815e32d5dSMike Smith device_printf(sc->ec_dev, "EcRead called without EC lock!\n"); 63915e32d5dSMike Smith 64015e32d5dSMike Smith /*EcBurstEnable(EmbeddedController);*/ 64115e32d5dSMike Smith 64215e32d5dSMike Smith EC_SET_CSR(sc, EC_COMMAND_READ); 64315e32d5dSMike Smith if ((Status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) { 64415e32d5dSMike Smith device_printf(sc->ec_dev, "EcRead: Failed waiting for EC to process read command.\n"); 64515e32d5dSMike Smith return(Status); 64615e32d5dSMike Smith } 64715e32d5dSMike Smith 64815e32d5dSMike Smith EC_SET_DATA(sc, Address); 64915e32d5dSMike Smith if ((Status = EcWaitEvent(sc, EC_EVENT_OUTPUT_BUFFER_FULL)) != AE_OK) { 65015e32d5dSMike Smith device_printf(sc->ec_dev, "EcRead: Failed waiting for EC to send data.\n"); 65115e32d5dSMike Smith return(Status); 65215e32d5dSMike Smith } 65315e32d5dSMike Smith 65415e32d5dSMike Smith (*Data) = EC_GET_DATA(sc); 65515e32d5dSMike Smith 65615e32d5dSMike Smith /*EcBurstDisable(EmbeddedController);*/ 65715e32d5dSMike Smith 65815e32d5dSMike Smith return(AE_OK); 65915e32d5dSMike Smith } 66015e32d5dSMike Smith 66115e32d5dSMike Smith static ACPI_STATUS 66215e32d5dSMike Smith EcWrite(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data) 66315e32d5dSMike Smith { 66415e32d5dSMike Smith ACPI_STATUS Status; 66515e32d5dSMike Smith 66615e32d5dSMike Smith if (!EcIsLocked(sc)) 66715e32d5dSMike Smith device_printf(sc->ec_dev, "EcWrite called without EC lock!\n"); 66815e32d5dSMike Smith 66915e32d5dSMike Smith /*EcBurstEnable(EmbeddedController);*/ 67015e32d5dSMike Smith 67115e32d5dSMike Smith EC_SET_CSR(sc, EC_COMMAND_WRITE); 67215e32d5dSMike Smith if ((Status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) { 67315e32d5dSMike Smith device_printf(sc->ec_dev, "EcWrite: Failed waiting for EC to process write command.\n"); 67415e32d5dSMike Smith return(Status); 67515e32d5dSMike Smith } 67615e32d5dSMike Smith 67715e32d5dSMike Smith EC_SET_DATA(sc, Address); 67815e32d5dSMike Smith if ((Status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) { 67915e32d5dSMike Smith device_printf(sc->ec_dev, "EcRead: Failed waiting for EC to process address.\n"); 68015e32d5dSMike Smith return(Status); 68115e32d5dSMike Smith } 68215e32d5dSMike Smith 68315e32d5dSMike Smith EC_SET_DATA(sc, *Data); 68415e32d5dSMike Smith if ((Status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY)) != AE_OK) { 68515e32d5dSMike Smith device_printf(sc->ec_dev, "EcWrite: Failed waiting for EC to process data.\n"); 68615e32d5dSMike Smith return(Status); 68715e32d5dSMike Smith } 68815e32d5dSMike Smith 68915e32d5dSMike Smith /*EcBurstDisable(EmbeddedController);*/ 69015e32d5dSMike Smith 69115e32d5dSMike Smith return(AE_OK); 69215e32d5dSMike Smith } 693