]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/io/io/server/src/drivers/acpi/ec.cc
Update
[l4.git] / l4 / pkg / io / io / server / src / drivers / acpi / ec.cc
1 #include "io_acpi.h"
2 #include "__acpi.h"
3 #include "debug.h"
4 #include <l4/cxx/bitfield>
5
6 #include <l4/util/port_io.h>
7 #include <l4/util/util.h>
8
9 #include <map>
10
11 namespace {
12
13 using namespace Hw;
14 using Hw::Device;
15
16 struct Acpi_ec : Acpi_dev
17 {
18   struct Flags
19   {
20     l4_uint32_t raw;
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);
24
25     Flags() = default;
26     explicit Flags(l4_uint32_t v) : raw(v) {}
27   };
28
29   /**
30    * \brief The EC status register.
31    */
32   struct Status
33   {
34     l4_uint8_t raw;
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);
41
42     Status() = default;
43     Status(l4_uint8_t v) : raw(v) {}
44   };
45
46   // EC Commands
47   enum Ec_command : l4_uint8_t
48   {
49     Ec_read          = 0x80,
50     Ec_write         = 0x81,
51     Ec_burst_enable  = 0x82,
52     Ec_burst_disable = 0x83,
53     Ec_query         = 0x84
54   };
55
56   Acpi_ec(ACPI_HANDLE hdl) : Acpi_dev(hdl), _flags(0), _data(0) {}
57
58
59   static bool discover_ecdt()
60   {
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))
64       return false;
65
66     d_printf(DBG_DEBUG, "ACPI: EC via ECDT found\n");
67
68     Acpi_ec *ec = new Acpi_ec(ACPI_ROOT_OBJECT);
69     ec->_data = ecdt->Data.Address;
70     ec->_control = ecdt->Control.Address;
71     ec->_gpe = ecdt->Gpe;
72     ec->_need_lock = 0;
73     ec->_uid = ecdt->Uid;
74     AcpiGetHandle(ACPI_ROOT_OBJECT, ACPI_STRING(ecdt->Id), &ec->_obj);
75
76     _ecdt_ec = ec;
77     ec->install_handlers();
78     return true;
79   }
80
81
82   void setup_ec(Hw::Device *host)
83   {
84     Resource_list const &r = *host->resources();
85     if (r.size() < 2)
86       {
87         d_printf(DBG_ERR, "ERROR: EC: error missing resources\n");
88         return;
89       }
90
91     if (r[0]->type() != Resource::Io_res || r[1]->type() != Resource::Io_res)
92       {
93         d_printf(DBG_ERR, "ERROR: EC: resource type mismatch: types=%d,%d\n",
94                  r[0]->type(), r[1]->type());
95         return;
96       }
97
98     if (!r[0]->start() || !r[1]->start())
99       {
100         d_printf(DBG_ERR, "ERROR: EC: invalid ec ports=%x,%x\n",
101                  (unsigned)r[0]->start(), (unsigned)r[1]->start());
102         return;
103       }
104
105       {
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)
110           _need_lock = 0;
111         else
112           _need_lock = glk.value.Integer.Value;
113       }
114
115     // if we are already initialized (may be via ECDT) we must skip the rest
116     if (_data)
117       return;
118
119       {
120         // handle the _GPE object
121         ACPI_STATUS status;
122         Acpi_buffer<ACPI_OBJECT> gpe;
123         status = AcpiEvaluateObject(handle(), ACPI_STRING("_GPE"), NULL, &gpe);
124
125         // never seen the package return value here...
126         if (ACPI_FAILURE(status) || gpe.value.Type != ACPI_TYPE_INTEGER)
127           {
128             d_printf(DBG_ERR, "ERROR: EC: invalid result from _GPE: %d\n", status);
129             return;
130           }
131
132         _gpe = gpe.value.Integer.Value;
133       }
134
135     _data = r[0]->start();
136     _control = r[1]->start();
137
138     install_handlers();
139
140     Acpi_walk find_qr = [this](ACPI_HANDLE hdl, int)
141     {
142       Acpi_buffer<char [5]> name;
143       ACPI_STATUS s = AcpiGetName(hdl, ACPI_SINGLE_NAME, &name);
144       unsigned qval;
145       if (ACPI_SUCCESS(s) && sscanf(name.value, "_Q%x", &qval) == 1)
146         _query_handlers[qval] = hdl;
147
148       return AE_OK;
149     };
150
151     find_qr.walk(ACPI_TYPE_METHOD, handle(), 1);
152
153     AcpiEnableGpe(0, _gpe);
154   }
155
156 private:
157   friend struct Acpi_ec_drv;
158   typedef std::map<l4_uint8_t, ACPI_HANDLE> Handler_map;
159
160   Flags _flags;
161   Handler_map _query_handlers;
162
163   l4_uint16_t _data;
164   l4_uint16_t _control;
165
166   l4_uint32_t _gpe;
167   l4_uint32_t _uid;
168
169   bool _need_lock : 1;
170
171   static Acpi_ec *_ecdt_ec;
172
173
174   void write_cmd(l4_uint8_t cmd)
175   { l4util_out8(cmd, _control); }
176
177   void write_data(l4_uint8_t data)
178   { l4util_out8(data, _data); }
179
180   l4_uint8_t read_data()
181   { return l4util_in8(_data); }
182
183   void wait_read()
184   {
185     while (!status().out_buffer_full())
186       ;
187   }
188
189   void wait_write()
190   {
191     while (status().in_buffer_full())
192       ;
193   }
194
195   ACPI_STATUS write(l4_uint8_t address, l4_uint8_t data)
196   {
197     if (!_data)
198       return AE_NOT_FOUND;
199
200     AcpiDisableGpe(NULL, _gpe);
201     write_cmd(Ec_write);
202     wait_write();
203     write_data(address);
204     wait_write();
205     write_data(data);
206     l4_sleep(1);
207     AcpiEnableGpe(NULL, _gpe);
208     return AE_OK;
209   }
210
211   ACPI_STATUS read(l4_uint8_t address, l4_uint8_t *data)
212   {
213     if (!_data)
214       return AE_NOT_FOUND;
215
216     AcpiDisableGpe(NULL, _gpe);
217     write_cmd(Ec_read);
218     wait_write();
219     write_data(address);
220     wait_read();
221     *data = read_data();
222     l4_sleep(1);
223     AcpiEnableGpe(NULL, _gpe);
224     return AE_OK;
225   }
226
227
228   Status status() const
229   { return l4util_in8(_control); }
230
231
232   ACPI_STATUS as_handler(l4_uint32_t func, ACPI_PHYSICAL_ADDRESS addr,
233                          l4_uint32_t width, UINT64 *_value)
234   {
235     ACPI_STATUS result = AE_OK;
236     unsigned bytes = width / 8;
237
238     l4_uint8_t *value = reinterpret_cast<l4_uint8_t*>(_value);
239
240     if ((addr > 0xFF) || !value)
241       return AE_BAD_PARAMETER;
242
243     if (func != ACPI_READ && func != ACPI_WRITE)
244       return AE_BAD_PARAMETER;
245
246     for (unsigned i = 0; i < bytes; ++i, ++addr, ++value)
247       result = (func == ACPI_READ)
248                ? read(addr, value)
249                : write(addr, *value);
250
251     return result;
252   }
253
254   ACPI_STATUS gpe_handler(ACPI_HANDLE, l4_uint32_t)
255   {
256     if (status().sci_pending())
257       AcpiOsExecute(OSL_NOTIFY_HANDLER, _gpe_query, this);
258
259     return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE;
260   }
261
262   void gpe_query()
263   {
264     AcpiDisableGpe(NULL, _gpe);
265     write_cmd(Ec_query);
266     wait_read();
267     l4_uint8_t q = read_data();
268     AcpiEnableGpe(NULL, _gpe);
269
270     Handler_map::const_iterator i = _query_handlers.find(q);
271     if (i == _query_handlers.end())
272       return;
273
274     AcpiEvaluateObject(i->second, 0, 0, 0);
275   }
276
277   static void _gpe_query(void *ec)
278   {
279     static_cast<Acpi_ec*>(ec)->gpe_query();
280   }
281
282   static ACPI_STATUS _as_handler(l4_uint32_t func, ACPI_PHYSICAL_ADDRESS addr,
283                                  l4_uint32_t width, UINT64 *value,
284                                  void *ctxt, void *)
285   {
286     return static_cast<Acpi_ec*>(ctxt)->as_handler(func, addr, width, value);
287   }
288
289   static ACPI_STATUS _gpe_handler(ACPI_HANDLE handle, l4_uint32_t gpe, void *ctxt)
290   {
291     return static_cast<Acpi_ec*>(ctxt)->gpe_handler(handle, gpe);
292   }
293
294   void install_handlers()
295   {
296     if (_flags.handlers_installed())
297       return;
298
299     ACPI_STATUS status;
300     status = AcpiInstallAddressSpaceHandler(handle(), ACPI_ADR_SPACE_EC,
301                                             &_as_handler, 0, this);
302     if (ACPI_FAILURE(status))
303       {
304         d_printf(DBG_ERR, "error: failed to install EC address-space handler: %s\n",
305                  AcpiFormatException(status));
306         return;
307       }
308
309     _flags.as_handler_installed() = true;
310
311     status = AcpiInstallGpeHandler(NULL, _gpe, ACPI_GPE_EDGE_TRIGGERED,
312                                    &_gpe_handler, this);
313     if (ACPI_FAILURE(status))
314       {
315         d_printf(DBG_ERR, "error: failed to install EC GPE handler: %s\n",
316                  AcpiFormatException(status));
317         return;
318       }
319
320     _flags.gpe_handler_installed() = true;
321   }
322 };
323
324
325 Acpi_ec *Acpi_ec::_ecdt_ec;
326
327
328 struct Acpi_ec_drv : Acpi_device_driver
329 {
330   Acpi_dev *probe(Device *device, ACPI_HANDLE acpi_hdl,
331                   ACPI_DEVICE_INFO const *)
332   {
333     d_printf(DBG_DEBUG, "Found ACPI EC\n");
334     Acpi_ec *ec = 0;
335     if (   Acpi_ec::_ecdt_ec
336         && (   Acpi_ec::_ecdt_ec->handle() == acpi_hdl
337             || Acpi_ec::_ecdt_ec->handle() == ACPI_ROOT_OBJECT))
338       {
339         d_printf(DBG_DEBUG, "ACPI: Use EC from ECDT\n");
340         ec = Acpi_ec::_ecdt_ec;
341         Acpi_ec::_ecdt_ec = 0;
342       }
343     else
344       ec = new Acpi_ec(acpi_hdl);
345
346     ec->discover_crs(device);
347     ec->setup_ec(device);
348     device->add_feature(ec);
349
350     return ec;
351   };
352 };
353
354 static Acpi_ec_drv _acpi_ec_drv;
355
356 struct Init
357 {
358   Init()
359   {
360     Acpi_device_driver::register_driver("PNP0C09", &_acpi_ec_drv);
361   }
362 };
363
364 static Init init;
365
366 }
367
368 int acpi_ecdt_scan()
369 {
370   Acpi_ec::discover_ecdt();
371   return 0;
372 }
373