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