xref: /freebsd/sys/dev/acpica/acpi_ec.c (revision 0ae554237ce4b3c25df6640d5c3c546034309df6)
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