1/*
2 * ssdt_pm.asl
3 *
4 * Copyright (c) 2008  Kamala Narasimhan
5 * Copyright (c) 2008  Citrix Systems, Inc.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published
9 * by the Free Software Foundation; version 2.1 only. with the special
10 * exception on linking described in file LICENSE.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU Lesser General Public License for more details.
16 */
17
18/*
19 * SSDT for extended power management within HVM guest. Power management beyond
20 * S3, S4, S5 is handled by this vACPI layer.
21 *
22 * Battery Management Implementation -
23 * Xen vACPI layer exposes battery information to guest using CMBattery
24 * interface. This virtual firmware CMBattery implementation is very similar to
25 * the actual firmware CMBattery implementation.  In fact, a good part of the
26 * below is heavily borrowed from the underlying firmware to support
27 * pass-through and non-pass-through battery management approaches using the
28 * same CMBattery interface implementation. When pass-through approach is used,
29 * the battery ports are directly mapped using xc_domain_ioport_mapping thus
30 * not relying on qemu battery port handling to intercept port reads/writes to
31 * feed relevant battery information to the guest.
32 *
33 * Following are the battery ports read/written to in order to implement
34 * battery support:
35 * Battery command port - 0xb2
36 * Batter data port     - 0x86
37 * Battery commands (written to port 0xb2) -
38 * 0x7b - Battery operation init
39 * 0x7c - Type of battery operation
40 * 0x79 - Get battery data length
41 * 0x7d - Get battery data
42 *
43 * Also the following ports are used for debugging/logging:
44 * 0xB040, 0xB044, 0xB046, 0xB048
45 */
46
47DefinitionBlock ("SSDT_PM.aml", "SSDT", 2, "Xen", "HVM", 0)
48{
49    Scope (\_SB)
50    {
51        OperationRegion (DBGA, SystemIO, 0xB040, 0x01)
52        Field (DBGA, ByteAcc, NoLock, Preserve)
53        {
54            DBG1,   8,
55        }
56
57        OperationRegion (DBGB, SystemIO, 0xB044, 0x01)
58        Field (DBGB, ByteAcc, NoLock, Preserve)
59        {
60            DBG2,   8,
61        }
62
63        OperationRegion (DBGC, SystemIO, 0xB046, 0x01)
64        Field (DBGC, ByteAcc, NoLock, Preserve)
65        {
66            DBG3,   8,
67        }
68
69        OperationRegion (DBGD, SystemIO, 0xB048, 0x01)
70        Field (DBGD, ByteAcc, NoLock, Preserve)
71        {
72            DBG4,   8,
73        }
74
75        OperationRegion (PRT1, SystemIO, 0xB2, 0x02)
76        Field (PRT1, ByteAcc, NoLock, Preserve)
77        {
78            PB2,   8,
79            PB2A,   8
80        }
81
82        OperationRegion (PRT2, SystemIO, 0x86, 0x01)
83        Field (PRT2, ByteAcc, NoLock, Preserve)
84        {
85            P86,   8
86        }
87
88        OperationRegion (PRT3, SystemIO, 0x88, 0x01)
89        Field (PRT3, ByteAcc, NoLock, Preserve)
90        {
91            P88,  8
92        }
93
94
95        Mutex (SYNC, 0x01)
96        Name (BUF0, Buffer (0x0100) {})
97        Name (BUF1, Buffer (0x08) {})
98        CreateWordField (BUF1, 0x00, BUFA)
99        CreateWordField (BUF1, 0x04, BUFB)
100        Method (ACQR, 0, NotSerialized)
101        {
102            Acquire (SYNC, 0xFFFF)
103            Store (0x00, BUFA)
104        }
105
106        /*
107         * Initialize relevant buffer to indicate what type of
108         * information is being queried and by what object (e.g.
109         * by battery device 0 or 1).
110         */
111        Method (INIT, 1, NotSerialized)
112        {
113            Store (BUFA, Local0)
114            Increment (Local0)
115            If (LLessEqual (Local0, SizeOf (BUF0)))
116            {
117                CreateByteField (BUF0, BUFA, TMP1)
118                Store (Arg0, TMP1)
119                Store (Local0, BUFA)
120            }
121        }
122
123        /*
124         * Write to battery port 0xb2 indicating the type of information
125         * to request, initialize battery data port 0x86 and then return
126         * value provided through data port 0x86.
127         */
128        Method (WPRT, 2, NotSerialized)
129        {
130            Store (Arg1, \_SB.P86)
131            Store (Arg0, \_SB.PB2)
132            Store (Arg0, \_SB.DBG2)
133            Store (Arg1, \_SB.DBG4)
134            Store (\_SB.PB2, Local0)
135            While (LNotEqual (Local0, 0x00))
136            {
137                Store (\_SB.PB2, Local0)
138            }
139
140            Store (\_SB.P86, Local1)
141            Store (Local1, \_SB.DBG3)
142            Return (\_SB.P86)
143        }
144
145        /*
146         * Helper method 1 to write to battery command and data port.
147         * 0x7c written to port 0xb2 indicating battery info type command.
148         * Value 1 or 2 written to port 0x86.  1 for BIF (batterry info) and 2
149         * for BST (battery status).
150         */
151        Method (HLP1, 2, NotSerialized)
152        {
153            If (LLess (Arg1, SizeOf (Arg0)))
154            {
155                CreateByteField (Arg0, Arg1, TMP1)
156                WPRT (0x7C, TMP1)
157            }
158        }
159
160        /*
161         * Helper method 2.  Value 0x7b written to battery command port 0xb2
162         * indicating battery info initialization request.  First thing written
163         * to battery port before querying for further information pertaining
164         * to the battery.
165         */
166        Method (HLP2, 0, NotSerialized)
167        {
168            WPRT (0x7B, 0x00)
169            Store (0x00, Local0)
170            While (LLess (Local0, BUFA))
171            {
172                HLP1 (BUF0, Local0)
173                Increment (Local0)
174            }
175        }
176
177        /*
178         * Helper method 3. 0x7d written to battery command port 0xb2
179         * indicating request of battery data returned through battery data
180         * port 0x86.
181         */
182        Method (HLP3, 2, NotSerialized)
183        {
184            If (LLess (Arg1, SizeOf (Arg0)))
185            {
186                CreateByteField (Arg0, Arg1, TMP1)
187                Store (WPRT (0x7D, 0x00), TMP1)
188            }
189        }
190
191        /*
192         * Helper method 4 to indirectly get battery data and store it in a
193         * local buffer.
194         */
195        Method (HLP4, 0, NotSerialized)
196        {
197            Store (0x00, Local0)
198            While (LLess (Local0, BUFB))
199            {
200                Add (BUFA, Local0, Local1)
201                HLP3 (BUF0, Local1)
202                Increment (Local0)
203            }
204        }
205
206        /*
207         * Helper method 5 to indirectly initialize battery port and get
208         * battery data. Also get battery data length by writing 0x79 to
209         * battery command port and receiving battery data length in port 0x86.
210         */
211        Method (HLP5, 0, NotSerialized)
212        {
213            HLP2 ()
214            Store (WPRT (0x79, 0x00), BUFB)
215            Add (BUFA, BUFB, Local0)
216            If (LLess (SizeOf (BUF0), Local0))
217            {
218                Store (SizeOf (BUF0), Local0)
219                Subtract (Local0, BUFA, Local0)
220                Store (Local0, BUFB)
221            }
222
223            HLP4 ()
224        }
225
226        /* Helper method for local buffer housekeeping... */
227        Method (HLP6, 0, NotSerialized)
228        {
229            Store (BUFA, Local0)
230            Increment (Local0)
231            If (LLessEqual (Local0, SizeOf (BUF0)))
232            {
233                CreateByteField (BUF0, BUFA, TMP1)
234                Store (Local0, BUFA)
235                Return (TMP1)
236            }
237
238            Return (0x00)
239        }
240
241        /* Helper methods to help store battery data retrieved through
242         * battery data port 0x86. */
243
244        Method (HLP7, 0, NotSerialized)
245        {
246            Store (BUFA, Local0)
247            Add (Local0, 0x04, Local0)
248            If (LLessEqual (Local0, SizeOf (BUF0)))
249            {
250                CreateDWordField (BUF0, BUFA, SX22)
251                Store (Local0, BUFA)
252                Return (SX22)
253            }
254
255            Return (0x00)
256        }
257
258        Method (HLP8, 2, NotSerialized)
259        {
260            If (LLess (Arg1, SizeOf (Arg0)))
261            {
262                CreateByteField (Arg0, Arg1, TMP1)
263                Store (HLP6 (), TMP1)
264            }
265        }
266
267        Method (HLP9, 2, NotSerialized)
268        {
269            Store (0x00, Local0)
270            While (LLess (Local0, Arg1))
271            {
272                HLP8 (Arg0, Local0)
273                Increment (Local0)
274            }
275            Return (Arg0)
276        }
277
278        Method (HLPA, 0, NotSerialized)
279        {
280            Store (HLP6 (), Local0)
281            Return (HLP9 (Buffer (Local0) {}, Local0))
282        }
283
284        Method (REL, 0, NotSerialized)
285        {
286            Release (SYNC)
287        }
288
289        /* Future patches will extend AC object to better account for
290         * AC to DC transition and more. */
291        Device (AC)
292        {
293            Name (_HID, "ACPI0003")
294            Name (_PCL, Package (0x03)
295            {
296                \_SB,
297                BAT0,
298                BAT1
299            })
300            Method (_PSR, 0, NotSerialized)
301            {
302                Return (0x0)
303            }
304
305            Method (_STA, 0, NotSerialized)
306            {
307                Return (0x0F)
308            }
309        }
310
311        /* Main battery information helper method. */
312        Name (BIFP, Package (0x0D) {})
313        Method (BIF, 1, NotSerialized)
314        {
315            ACQR ()
316            INIT (0x01)
317            INIT (Arg0)
318            HLP5 ()
319            Store (HLP7 (), Index (BIFP, 0x00))
320            Store (HLP7 (), Index (BIFP, 0x01))
321            Store (HLP7 (), Index (BIFP, 0x02))
322            Store (HLP7 (), Index (BIFP, 0x03))
323            Store (HLP7 (), Index (BIFP, 0x04))
324            Store (HLP7 (), Index (BIFP, 0x05))
325            Store (HLP7 (), Index (BIFP, 0x06))
326            Store (HLP7 (), Index (BIFP, 0x07))
327            Store (HLP7 (), Index (BIFP, 0x08))
328            Store (HLPA (), Index (BIFP, 0x09))
329            Store (HLPA (), Index (BIFP, 0x0A))
330            Store (HLPA (), Index (BIFP, 0x0B))
331            Store (HLPA (), Index (BIFP, 0x0C))
332            REL ()
333            Return (BIFP)
334        }
335
336        /* Battery object 0 - Always exposed as present. */
337        Device (BAT0)
338        {
339            Name (_HID, EisaId ("PNP0C0A"))
340            Name (_UID, 0x01)
341            Name (_PCL, Package (0x01)
342            {
343                \_SB
344            })
345
346            /* Always returns 0x1f indicating battery present. */
347            Method (_STA, 0, NotSerialized)
348            {
349                Store (\_SB.P88, Local0)
350                Return ( Local0 )
351            }
352
353            /* Battery generic info: design capacity, voltage, model # etc. */
354            Method (_BIF, 0, NotSerialized)
355            {
356                //Store (1, \_SB.DBG1)
357                Store(BIF ( 0x01 ), Local0)
358                //Store (2, \_SB.DBG1)
359                Return( Local0 )
360            }
361
362            /* Battery status including battery charging/discharging rate. */
363            Method (_BST, 0, NotSerialized)
364            {
365                Store (1, \_SB.DBG1)
366                ACQR ()
367                INIT (0x02)
368                INIT (0x01)
369                HLP5 ()
370                Store (Package (0x04) {}, Local0)
371                Store (HLP7 (), Index (Local0, 0x00))
372                Store (HLP7 (), Index (Local0, 0x01))
373                Store (HLP7 (), Index (Local0, 0x02))
374                Store (HLP7 (), Index (Local0, 0x03))
375                REL ()
376                Store (2, \_SB.DBG1)
377                Return (Local0)
378            }
379        }
380
381        /* Battery object 1 - Always exposed as not present. */
382        Device (BAT1)
383        {
384            Name (_HID, EisaId ("PNP0C0A"))
385            Name (_UID, 0x02)
386            Name (_PCL, Package (0x01)
387            {
388                \_SB
389            })
390            Method (_STA, 0, NotSerialized)
391            {
392                Return (0x0F)
393            }
394
395            Method (_BIF, 0, NotSerialized)
396            {
397                Store (\_SB.PB2, Local0)
398                Return (BIF (0x02))
399            }
400
401            Method (_BST, 0, NotSerialized)
402            {
403                ACQR ()
404                INIT (0x02)
405                INIT (0x02)
406                HLP5 ()
407                Store (Package (0x04) {}, Local0)
408                Store (HLP7 (), Index (Local0, 0x00))
409                Store (HLP7 (), Index (Local0, 0x01))
410                Store (HLP7 (), Index (Local0, 0x02))
411                Store (HLP7 (), Index (Local0, 0x03))
412                REL ()
413                Return (Local0)
414            }
415        }
416    }
417}
418
419