4 #include <l4/cxx/bitfield>
6 #include <l4/util/port_io.h>
7 #include <l4/util/util.h>
16 struct Acpi_ec : Acpi_dev
21 CXX_BITFIELD_MEMBER( 0, 0, as_handler_installed, raw);
22 CXX_BITFIELD_MEMBER( 1, 1, gpe_handler_installed, raw);
23 CXX_BITFIELD_MEMBER( 0, 1, handlers_installed, raw);
26 explicit Flags(l4_uint32_t v) : raw(v) {}
30 * \brief The EC status register.
35 CXX_BITFIELD_MEMBER_UNSHIFTED(0, 0, out_buffer_full, raw);
36 CXX_BITFIELD_MEMBER_UNSHIFTED(1, 1, in_buffer_full, raw);
37 CXX_BITFIELD_MEMBER_UNSHIFTED(3, 3, command_issued, raw);
38 CXX_BITFIELD_MEMBER_UNSHIFTED(4, 4, burst_mode, raw);
39 CXX_BITFIELD_MEMBER_UNSHIFTED(5, 5, sci_pending, raw);
40 CXX_BITFIELD_MEMBER_UNSHIFTED(6, 6, smi_pending, raw);
43 Status(l4_uint8_t v) : raw(v) {}
47 enum Ec_command : l4_uint8_t
51 Ec_burst_enable = 0x82,
52 Ec_burst_disable = 0x83,
56 Acpi_ec(ACPI_HANDLE hdl) : Acpi_dev(hdl), _flags(0), _data(0) {}
59 static bool discover_ecdt()
61 ACPI_TABLE_ECDT *ecdt;
62 ACPI_STATUS status = AcpiGetTable(ACPI_STRING(ACPI_SIG_ECDT), 1, (ACPI_TABLE_HEADER**)&ecdt);
63 if (ACPI_FAILURE(status))
66 d_printf(DBG_DEBUG, "ACPI: EC via ECDT found\n");
68 Acpi_ec *ec = new Acpi_ec(ACPI_ROOT_OBJECT);
69 ec->_data = ecdt->Data.Address;
70 ec->_control = ecdt->Control.Address;
74 AcpiGetHandle(ACPI_ROOT_OBJECT, ACPI_STRING(ecdt->Id), &ec->_obj);
77 ec->install_handlers();
82 void setup_ec(Hw::Device *host)
84 Resource_list const &r = *host->resources();
87 d_printf(DBG_ERR, "ERROR: EC: error missing resources\n");
91 if (r[0]->type() != Resource::Io_res || r[1]->type() != Resource::Io_res)
93 d_printf(DBG_ERR, "ERROR: EC: resource type mismatch: types=%d,%d\n",
94 r[0]->type(), r[1]->type());
98 if (!r[0]->start() || !r[1]->start())
100 d_printf(DBG_ERR, "ERROR: EC: invalid ec ports=%x,%x\n",
101 (unsigned)r[0]->start(), (unsigned)r[1]->start());
106 // handle ECs _GLK object
107 Acpi_buffer<ACPI_OBJECT> glk;
108 ACPI_STATUS status = AcpiEvaluateObject(handle(), ACPI_STRING("_GLK"), NULL, &glk);
109 if (ACPI_FAILURE(status) || glk.value.Type != ACPI_TYPE_INTEGER)
112 _need_lock = glk.value.Integer.Value;
115 // if we are already initialized (may be via ECDT) we must skip the rest
120 // handle the _GPE object
122 Acpi_buffer<ACPI_OBJECT> gpe;
123 status = AcpiEvaluateObject(handle(), ACPI_STRING("_GPE"), NULL, &gpe);
125 // never seen the package return value here...
126 if (ACPI_FAILURE(status) || gpe.value.Type != ACPI_TYPE_INTEGER)
128 d_printf(DBG_ERR, "ERROR: EC: invalid result from _GPE: %d\n", status);
132 _gpe = gpe.value.Integer.Value;
135 _data = r[0]->start();
136 _control = r[1]->start();
140 Acpi_walk find_qr = [this](ACPI_HANDLE hdl, int)
142 Acpi_buffer<char [5]> name;
143 ACPI_STATUS s = AcpiGetName(hdl, ACPI_SINGLE_NAME, &name);
145 if (ACPI_SUCCESS(s) && sscanf(name.value, "_Q%x", &qval) == 1)
146 _query_handlers[qval] = hdl;
151 find_qr.walk(ACPI_TYPE_METHOD, handle(), 1);
153 AcpiEnableGpe(0, _gpe);
157 friend struct Acpi_ec_drv;
158 typedef std::map<l4_uint8_t, ACPI_HANDLE> Handler_map;
161 Handler_map _query_handlers;
164 l4_uint16_t _control;
171 static Acpi_ec *_ecdt_ec;
174 void write_cmd(l4_uint8_t cmd)
175 { l4util_out8(cmd, _control); }
177 void write_data(l4_uint8_t data)
178 { l4util_out8(data, _data); }
180 l4_uint8_t read_data()
181 { return l4util_in8(_data); }
185 while (!status().out_buffer_full())
191 while (status().in_buffer_full())
195 ACPI_STATUS write(l4_uint8_t address, l4_uint8_t data)
200 AcpiDisableGpe(NULL, _gpe);
207 AcpiEnableGpe(NULL, _gpe);
211 ACPI_STATUS read(l4_uint8_t address, l4_uint8_t *data)
216 AcpiDisableGpe(NULL, _gpe);
223 AcpiEnableGpe(NULL, _gpe);
228 Status status() const
229 { return l4util_in8(_control); }
232 ACPI_STATUS as_handler(l4_uint32_t func, ACPI_PHYSICAL_ADDRESS addr,
233 l4_uint32_t width, UINT64 *_value)
235 ACPI_STATUS result = AE_OK;
236 unsigned bytes = width / 8;
238 l4_uint8_t *value = reinterpret_cast<l4_uint8_t*>(_value);
240 if ((addr > 0xFF) || !value)
241 return AE_BAD_PARAMETER;
243 if (func != ACPI_READ && func != ACPI_WRITE)
244 return AE_BAD_PARAMETER;
246 for (unsigned i = 0; i < bytes; ++i, ++addr, ++value)
247 result = (func == ACPI_READ)
249 : write(addr, *value);
254 ACPI_STATUS gpe_handler(ACPI_HANDLE, l4_uint32_t)
256 if (status().sci_pending())
257 AcpiOsExecute(OSL_NOTIFY_HANDLER, _gpe_query, this);
259 return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE;
264 AcpiDisableGpe(NULL, _gpe);
267 l4_uint8_t q = read_data();
268 AcpiEnableGpe(NULL, _gpe);
270 Handler_map::const_iterator i = _query_handlers.find(q);
271 if (i == _query_handlers.end())
274 AcpiEvaluateObject(i->second, 0, 0, 0);
277 static void _gpe_query(void *ec)
279 static_cast<Acpi_ec*>(ec)->gpe_query();
282 static ACPI_STATUS _as_handler(l4_uint32_t func, ACPI_PHYSICAL_ADDRESS addr,
283 l4_uint32_t width, UINT64 *value,
286 return static_cast<Acpi_ec*>(ctxt)->as_handler(func, addr, width, value);
289 static ACPI_STATUS _gpe_handler(ACPI_HANDLE handle, l4_uint32_t gpe, void *ctxt)
291 return static_cast<Acpi_ec*>(ctxt)->gpe_handler(handle, gpe);
294 void install_handlers()
296 if (_flags.handlers_installed())
300 status = AcpiInstallAddressSpaceHandler(handle(), ACPI_ADR_SPACE_EC,
301 &_as_handler, 0, this);
302 if (ACPI_FAILURE(status))
304 d_printf(DBG_ERR, "error: failed to install EC address-space handler: %s\n",
305 AcpiFormatException(status));
309 _flags.as_handler_installed() = true;
311 status = AcpiInstallGpeHandler(NULL, _gpe, ACPI_GPE_EDGE_TRIGGERED,
312 &_gpe_handler, this);
313 if (ACPI_FAILURE(status))
315 d_printf(DBG_ERR, "error: failed to install EC GPE handler: %s\n",
316 AcpiFormatException(status));
320 _flags.gpe_handler_installed() = true;
325 Acpi_ec *Acpi_ec::_ecdt_ec;
328 struct Acpi_ec_drv : Acpi_device_driver
330 Acpi_dev *probe(Device *device, ACPI_HANDLE acpi_hdl,
331 ACPI_DEVICE_INFO const *)
333 d_printf(DBG_DEBUG, "Found ACPI EC\n");
335 if ( Acpi_ec::_ecdt_ec
336 && ( Acpi_ec::_ecdt_ec->handle() == acpi_hdl
337 || Acpi_ec::_ecdt_ec->handle() == ACPI_ROOT_OBJECT))
339 d_printf(DBG_DEBUG, "ACPI: Use EC from ECDT\n");
340 ec = Acpi_ec::_ecdt_ec;
341 Acpi_ec::_ecdt_ec = 0;
344 ec = new Acpi_ec(acpi_hdl);
346 ec->discover_crs(device);
347 ec->setup_ec(device);
348 device->add_feature(ec);
354 static Acpi_ec_drv _acpi_ec_drv;
360 Acpi_device_driver::register_driver("PNP0C09", &_acpi_ec_drv);
370 Acpi_ec::discover_ecdt();