3032f4dbe75f8f585b3b1d91082ba73714977ccf
[coreboot.git] / util / inteltool / powermgt.c
1 /*
2  * inteltool - dump all registers on an Intel CPU + chipset based system.
3  *
4  * Copyright (C) 2008-2010 by coresystems GmbH
5  *  written by Stefan Reinauer <stepan@coresystems.de>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; version 2 of the License.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20
21 #include <stdio.h>
22 #include "inteltool.h"
23
24 static const io_register_t ich10_pm_registers[] = {
25         { 0x00, 2, "PM1_STS" }, // PM1 Status; ACPI pointer: PM1a_EVT_BLK
26         { 0x02, 2, "PM1_EN" },  // PM1 Enables; ACPI pointer: PM1a_EVT_BLK+2
27         { 0x04, 4, "PM1_CNT" }, // PM1 Control; ACPI pointer: PM1a_CNT_BLK
28         { 0x08, 4, "PM1_TMR" }, // PM1 Timer; ACPI pointer: PMTMR_BLK
29         { 0x0c, 4, "RESERVED" },
30         { 0x10, 4, "PROC_CNT" }, // Processor Control; ACPI pointer: P_BLK
31 #if DANGEROUS_REGISTERS
32         /* These registers return 0 on read, but reading them may cause
33          * the system to enter Cx states, which might hang the system.
34          */
35         { 0x14, 1, "LV2 (Mobile)" },
36         { 0x15, 1, "LV3 (Mobile)" },
37         { 0x16, 1, "LV4 (Mobile)" },
38 #endif
39         { 0x17, 2, "RESERVED" },
40         { 0x19, 1, "RESERVED" },
41         { 0x1a, 2, "RESERVED" },
42         { 0x1c, 4, "RESERVED" },
43         { 0x20, 8, "GPE0_STS" }, // General Purpose Event 0 Status; ACPI pointer: GPE0_BLK
44         { 0x2C, 4, "GPE0_EN" },  // General Purpose Event 0 Enables; ACPI pointer: GPE0_BLK+8
45         { 0x30, 4, "SMI_EN" },
46         { 0x34, 4, "SMI_STS" },
47         { 0x38, 2, "ALT_GP_SMI_EN" },
48         { 0x3a, 2, "ALT_GP_SMI_STS" },
49         { 0x3c, 1, "UPRWC" },   // USB Per-Port registers write control;
50         { 0x3d, 2, "RESERVED" },
51         { 0x3f, 1, "RESERVED" },
52         { 0x40, 2, "RESERVED" },
53         { 0x42, 1, "GPE_CNTL" },
54         { 0x43, 1, "RESERVED" },
55         { 0x44, 2, "DEVACT_STS" }, // Device Activity Status
56         { 0x46, 2, "RESERVED" },
57         { 0x48, 4, "RESERVED" },
58         { 0x4c, 4, "RESERVED" },
59         { 0x50, 1, "PM2_CNT (Mobile)" }, // PM2 Control (Mobile only); ACPI pointer: PM2a_CNT_BLK
60         { 0x51, 1, "RESERVED" },
61         { 0x52, 2, "RESERVED" },
62         { 0x54, 4, "C3_RES (Mobile)" },
63         { 0x58, 4, "RESERVED" },
64         { 0x5c, 4, "RESERVED" },
65         /* Here start the TCO registers */
66         { 0x60, 2, "TCO_RLD" },
67         { 0x62, 1, "TCO_DAT_IN" },
68         { 0x63, 1, "TCO_DAT_OUT" },
69         { 0x64, 2, "TCO1_STS" },
70         { 0x66, 2, "TCO2_STS" },
71         { 0x68, 2, "TCO1_CNT" },
72         { 0x6a, 2, "TCO2_CNT" },
73         { 0x6c, 2, "TCO_MESSAGE" },
74         { 0x6e, 1, "TCO_WDCNT" },
75         { 0x6f, 1, "RESERVED" },
76         { 0x70, 1, "SW_IRQ_GEN" },
77         { 0x71, 1, "RESERVED" },
78         { 0x72, 2, "TCO_TMR" },
79         { 0x74, 4, "RESERVED" },
80         { 0x78, 4, "RESERVED" },
81         { 0x7c, 4, "RESERVED" },
82 };
83
84 static const io_register_t ich9_pm_registers[] = {
85         { 0x00, 2, "PM1_STS" }, // PM1 Status; ACPI pointer: PM1a_EVT_BLK
86         { 0x02, 2, "PM1_EN" },  // PM1 Enables; ACPI pointer: PM1a_EVT_BLK+2
87         { 0x04, 4, "PM1_CNT" }, // PM1 Control; ACPI pointer: PM1a_CNT_BLK
88         { 0x08, 4, "PM1_TMR" }, // PM1 Timer; ACPI pointer: PMTMR_BLK
89         { 0x0c, 4, "RESERVED" },
90         { 0x10, 4, "PROC_CNT" }, // Processor Control; ACPI pointer: P_BLK
91 #if DANGEROUS_REGISTERS
92         /* These registers return 0 on read, but reading them may cause
93          * the system to enter Cx states, which might hang the system.
94          */
95         { 0x14, 1, "LV2 (Mobile)" },
96         { 0x15, 1, "LV3 (Mobile)" },
97         { 0x16, 1, "LV4 (Mobile)" },
98         { 0x17, 1, "LV5 (Mobile)" },
99         { 0x18, 1, "LV6 (Mobile)" },
100 #endif
101         { 0x19, 1, "RESERVED" },
102         { 0x1a, 2, "RESERVED" },
103         { 0x1c, 4, "RESERVED" },
104         { 0x20, 8, "GPE0_STS" }, // General Purpose Event 0 Status; ACPI pointer: GPE0_BLK
105         { 0x2C, 4, "GPE0_EN" },  // General Purpose Event 0 Enables; ACPI pointer: GPE0_BLK+8
106         { 0x30, 4, "SMI_EN" },
107         { 0x34, 4, "SMI_STS" },
108         { 0x38, 2, "ALT_GP_SMI_EN" },
109         { 0x3a, 2, "ALT_GP_SMI_STS" },
110         { 0x3c, 1, "UPRWC" },   // USB Per-Port registers write control;
111         { 0x3d, 2, "RESERVED" },
112         { 0x3f, 1, "RESERVED" },
113         { 0x40, 2, "RESERVED" },
114         { 0x42, 1, "GPE_CNTL" },
115         { 0x43, 1, "RESERVED" },
116         { 0x44, 2, "DEVACT_STS" }, // Device Activity Status
117         { 0x46, 2, "RESERVED" },
118         { 0x48, 4, "RESERVED" },
119         { 0x4c, 4, "RESERVED" },
120         { 0x50, 1, "PM2_CNT (Mobile)" }, // PM2 Control (Mobile only); ACPI pointer: PM2a_CNT_BLK
121         { 0x51, 1, "RESERVED" },
122         { 0x52, 2, "RESERVED" },
123         { 0x54, 4, "C3_RES (Mobile)" },
124         { 0x58, 4, "C5_RES (Mobile)" },
125         { 0x5c, 4, "RESERVED" },
126         /* Here start the TCO registers */
127         { 0x60, 2, "TCO_RLD" },
128         { 0x62, 1, "TCO_DAT_IN" },
129         { 0x63, 1, "TCO_DAT_OUT" },
130         { 0x64, 2, "TCO1_STS" },
131         { 0x66, 2, "TCO2_STS" },
132         { 0x68, 2, "TCO1_CNT" },
133         { 0x6a, 2, "TCO2_CNT" },
134         { 0x6c, 2, "TCO_MESSAGE" },
135         { 0x6e, 1, "TCO_WDCNT" },
136         { 0x6f, 1, "RESERVED" },
137         { 0x70, 1, "SW_IRQ_GEN" },
138         { 0x71, 1, "RESERVED" },
139         { 0x72, 2, "TCO_TMR" },
140         { 0x74, 4, "RESERVED" },
141         { 0x78, 4, "RESERVED" },
142         { 0x7c, 4, "RESERVED" },
143 };
144
145 static const io_register_t ich8_pm_registers[] = {
146         { 0x00, 2, "PM1_STS" },
147         { 0x02, 2, "PM1_EN" },
148         { 0x04, 4, "PM1_CNT" },
149         { 0x08, 4, "PM1_TMR" },
150         { 0x0c, 4, "RESERVED" },
151         { 0x10, 4, "PROC_CNT" },
152 #if DANGEROUS_REGISTERS
153         /* These registers return 0 on read, but reading them may cause
154          * the system to enter Cx states, which might hang the system.
155          */
156         { 0x14, 1, "LV2 (Mobile)" },
157         { 0x15, 1, "LV3 (Mobile)" },
158         { 0x16, 1, "LV4 (Mobile)" },
159         { 0x17, 1, "LV5 (Mobile)" },
160         { 0x18, 1, "LV6 (Mobile)" },
161 #endif
162         { 0x19, 1, "RESERVED" },
163         { 0x1a, 2, "RESERVED" },
164         { 0x1c, 4, "RESERVED" },
165         { 0x20, 1, "PM2_CNT (Mobile)" },
166         { 0x21, 1, "RESERVED" },
167         { 0x22, 2, "RESERVED" },
168         { 0x24, 4, "RESERVED" },
169         { 0x28, 4, "GPE0_STS" },
170         { 0x2C, 4, "GPE0_EN" },
171         { 0x30, 4, "SMI_EN" },
172         { 0x34, 4, "SMI_STS" },
173         { 0x38, 2, "ALT_GP_SMI_EN" },
174         { 0x3a, 2, "ALT_GP_SMI_STS" },
175         { 0x3c, 4, "RESERVED" },
176         { 0x40, 2, "RESERVED" },
177         { 0x42, 1, "GPE_CNTL" },
178         { 0x43, 1, "RESERVED" },
179         { 0x44, 2, "DEVACT_STS" },
180         { 0x46, 2, "RESERVED" },
181         { 0x48, 4, "RESERVED" },
182         { 0x4c, 4, "RESERVED" },
183         { 0x50, 1, "SS_CNT (Mobile)" },
184         { 0x51, 1, "RESERVED" },
185         { 0x52, 2, "RESERVED" },
186         { 0x54, 4, "C3_RES (Mobile)" },
187         { 0x58, 4, "C5_RES (Mobile)" },
188         { 0x5c, 4, "RESERVED" },
189         /* Here start the TCO registers */
190         { 0x60, 2, "TCO_RLD" },
191         { 0x62, 1, "TCO_DAT_IN" },
192         { 0x63, 1, "TCO_DAT_OUT" },
193         { 0x64, 2, "TCO1_STS" },
194         { 0x66, 2, "TCO2_STS" },
195         { 0x68, 2, "TCO1_CNT" },
196         { 0x6a, 2, "TCO2_CNT" },
197         { 0x6c, 2, "TCO_MESSAGE" },
198         { 0x6e, 1, "TCO_WDCNT" },
199         { 0x6f, 1, "RESERVED" },
200         { 0x70, 1, "SW_IRQ_GEN" },
201         { 0x71, 1, "RESERVED" },
202         { 0x72, 2, "TCO_TMR" },
203         { 0x74, 4, "RESERVED" },
204         { 0x78, 4, "RESERVED" },
205         { 0x7c, 4, "RESERVED" },
206 };
207
208 static const io_register_t ich7_pm_registers[] = {
209         { 0x00, 2, "PM1_STS" },
210         { 0x02, 2, "PM1_EN" },
211         { 0x04, 4, "PM1_CNT" },
212         { 0x08, 4, "PM1_TMR" },
213         { 0x0c, 4, "RESERVED" },
214         { 0x10, 4, "PROC_CNT" },
215 #if DANGEROUS_REGISTERS
216         /* These registers return 0 on read, but reading them may cause
217          * the system to enter C2/C3/C4 state, which might hang the system.
218          */
219         { 0x14, 1, "LV2 (Mobile/Ultra Mobile)" },
220         { 0x15, 1, "LV3 (Mobile/Ultra Mobile)" },
221         { 0x16, 1, "LV4 (Mobile/Ultra Mobile)" },
222 #endif
223         { 0x17, 1, "RESERVED" },
224         { 0x18, 4, "RESERVED" },
225         { 0x1c, 4, "RESERVED" },
226         { 0x20, 1, "PM2_CNT (Mobile/Ultra Mobile)" },
227         { 0x21, 1, "RESERVED" },
228         { 0x22, 2, "RESERVED" },
229         { 0x24, 4, "RESERVED" },
230         { 0x28, 4, "GPE0_STS" },
231         { 0x2C, 4, "GPE0_EN" },
232         { 0x30, 4, "SMI_EN" },
233         { 0x34, 4, "SMI_STS" },
234         { 0x38, 2, "ALT_GP_SMI_EN" },
235         { 0x3a, 2, "ALT_GP_SMI_STS" },
236         { 0x3c, 4, "RESERVED" },
237         { 0x40, 2, "RESERVED" },
238         { 0x42, 1, "GPE_CNTL" },
239         { 0x43, 1, "RESERVED" },
240         { 0x44, 2, "DEVACT_STS" },
241         { 0x46, 2, "RESERVED" },
242         { 0x48, 4, "RESERVED" },
243         { 0x4c, 4, "RESERVED" },
244         { 0x50, 1, "SS_CNT (Mobile/Ultra Mobile)" },
245         { 0x51, 1, "RESERVED" },
246         { 0x52, 2, "RESERVED" },
247         { 0x54, 4, "C3_RES (Mobile/Ultra Mobile)" },
248         { 0x58, 4, "RESERVED" },
249         { 0x5c, 4, "RESERVED" },
250         /* Here start the TCO registers */
251         { 0x60, 2, "TCO_RLD" },
252         { 0x62, 1, "TCO_DAT_IN" },
253         { 0x63, 1, "TCO_DAT_OUT" },
254         { 0x64, 2, "TCO1_STS" },
255         { 0x66, 2, "TCO2_STS" },
256         { 0x68, 2, "TCO1_CNT" },
257         { 0x6a, 2, "TCO2_CNT" },
258         { 0x6c, 2, "TCO_MESSAGE" },
259         { 0x6e, 1, "TCO_WDCNT" },
260         { 0x6f, 1, "RESERVED" },
261         { 0x70, 1, "SW_IRQ_GEN" },
262         { 0x71, 1, "RESERVED" },
263         { 0x72, 2, "TCO_TMR" },
264         { 0x74, 4, "RESERVED" },
265         { 0x78, 4, "RESERVED" },
266         { 0x7c, 4, "RESERVED" },
267 };
268
269 /*
270  * INTEL I/O Controller Hub 6 Family
271  * http://www.intel.com/assets/pdf/datasheet/301473.pdf
272  */
273 static const io_register_t ich6_pm_registers[] = {
274         /* 10.8.3 */
275         { 0x00, 2, "PM1_STS" },
276         { 0x02, 2, "PM1_EN" },
277         { 0x04, 4, "PM1_CNT" },
278         { 0x08, 4, "PM1_TMR" },
279         { 0x10, 4, "PROC_CNT" },
280 #if DANGEROUS_REGISTERS
281         /* These registers return 0 on read, but reading them may cause
282          * the system to enter C2/C3/C4 state, which might hang the system.
283          */
284         { 0x14, 1, "LV2" },
285         { 0x15, 1, "LV3 (Mobile Only)" },
286         { 0x16, 1, "LV4 (Mobile Only)" },
287 #endif
288         { 0x20, 1, "PM2_CNT (Mobile Only)" },
289         { 0x28, 4, "GPE0_STS" },
290         { 0x2c, 4, "GPE0_EN" },
291         { 0x30, 4, "SMI_EN" },
292         { 0x34, 4, "SMI_STS" },
293         { 0x38, 2, "ALT_GP_SMI_EN" },
294         { 0x3a, 2, "ALT_GP_SMI_STS" },
295         { 0x44, 2, "DEVACT_STS" },
296         { 0x50, 1, "SS_CNT (Mobile Only)" },
297         { 0x54, 4, "C3_RES (Mobile Only)" },
298 };
299
300 static const io_register_t ich4_pm_registers[] = {
301         { 0x00, 2, "PM1_STS" },
302         { 0x02, 2, "PM1_EN" },
303         { 0x04, 4, "PM1_CNT" },
304         { 0x08, 4, "PM1_TMR" },
305         { 0x0c, 4, "RESERVED" },
306         { 0x10, 4, "PROC_CNT" },
307 #if DANGEROUS_REGISTERS
308         /* These registers return 0 on read, but reading them may cause
309          * the system to enter C2/C3/C4 state, which might hang the system.
310          */
311         { 0x14, 1, "LV2 (Mobile)" },
312         { 0x15, 1, "LV3 (Mobile)" },
313         { 0x16, 1, "LV4 (Mobile)" },
314 #endif
315         { 0x17, 1, "RESERVED" },
316         { 0x18, 4, "RESERVED" },
317         { 0x1c, 4, "RESERVED" },
318         { 0x20, 1, "PM2_CNT (Mobile)" },
319         { 0x21, 1, "RESERVED" },
320         { 0x22, 2, "RESERVED" },
321         { 0x24, 4, "RESERVED" },
322         { 0x28, 4, "GPE0_STS" },
323         { 0x2C, 4, "GPE0_EN" },
324         { 0x30, 4, "SMI_EN" },
325         { 0x34, 4, "SMI_STS" },
326         { 0x38, 2, "ALT_GP_SMI_EN" },
327         { 0x3a, 2, "ALT_GP_SMI_STS" },
328         { 0x3c, 4, "RESERVED" },
329         { 0x40, 2, "MON_SMI" },
330         { 0x42, 2, "RESERVED" },
331         { 0x44, 2, "DEVACT_STS" },
332         { 0x46, 2, "RESERVED" },
333         { 0x48, 4, "DEVTRAP_EN" },
334         { 0x4c, 2, "BUS_ADDR_TRACK" },
335         { 0x4e, 2, "BUS_CYC_TRACK" },
336         { 0x50, 1, "SS_CNT (Mobile/Ultra Mobile)" },
337         { 0x51, 1, "RESERVED" },
338         { 0x52, 2, "RESERVED" },
339         { 0x54, 4, "RESERVED" },
340         { 0x58, 4, "RESERVED" },
341         { 0x5c, 4, "RESERVED" },
342         /* Here start the TCO registers */
343         { 0x60, 1, "TCO_RLD" },
344         { 0x61, 1, "TCO_TMR" },
345         { 0x62, 1, "TCO_DAT_IN" },
346         { 0x63, 1, "TCO_DAT_OUT" },
347         { 0x64, 2, "TCO1_STS" },
348         { 0x66, 2, "TCO2_STS" },
349         { 0x68, 2, "TCO1_CNT" },
350         { 0x6a, 2, "TCO2_CNT" },
351         { 0x6c, 2, "TCO_MESSAGE" },
352         { 0x6e, 1, "TCO_WDSTATUS" },
353         { 0x6f, 1, "RESERVED" },
354         { 0x70, 1, "SW_IRQ_GEN" },
355         { 0x71, 1, "RESERVED" },
356         { 0x72, 2, "RESERVED" },
357         { 0x74, 4, "RESERVED" },
358         { 0x78, 4, "RESERVED" },
359         { 0x7c, 4, "RESERVED" },
360 };
361
362 static const io_register_t ich2_pm_registers[] = {
363         { 0x00, 2, "PM1_STS" },
364         { 0x02, 2, "PM1_EN" },
365         { 0x04, 4, "PM1_CNT" },
366         { 0x08, 4, "PM1_TMR" },
367         { 0x0c, 4, "RESERVED" },
368         { 0x10, 4, "PROC_CNT" },
369 #if DANGEROUS_REGISTERS
370         /* This register returns 0 on read, but reading it may cause
371          * the system to enter C2 state, which might hang the system.
372          */
373         { 0x14, 1, "LV2" },
374         { 0x15, 1, "RESERVED" },
375         { 0x16, 2, "RESERVED" },
376 #endif
377         { 0x18, 4, "RESERVED" },
378         { 0x1c, 4, "RESERVED" },
379         { 0x20, 4, "RESERVED" },
380         { 0x24, 4, "RESERVED" },
381         { 0x28, 2, "GPE0_STS" },
382         { 0x2a, 2, "GPE0_EN" },
383         { 0x2c, 2, "GPE1_STS" },
384         { 0x2e, 2, "GPE1_EN" },
385         { 0x30, 2, "SMI_EN" },
386         { 0x32, 2, "RESERVED" },
387         { 0x34, 2, "SMI_STS" },
388         { 0x36, 2, "RESERVED" },
389         { 0x38, 4, "RESERVED" },
390         { 0x3c, 4, "RESERVED" },
391         { 0x40, 2, "MON_SMI_STS" },
392         { 0x42, 2, "RESERVED" },
393         { 0x44, 2, "DEV_TRP_STS" },
394         { 0x46, 2, "RESERVED" },
395         { 0x48, 2, "TRP_EN" },
396         { 0x4A, 2, "RESERVED" },
397         { 0x4c, 2, "BUS_ADDR_TRACK" },
398         { 0x4e, 1, "BUS_CYC_TRACK" },
399         { 0x4f, 1, "RESERVED" },
400         { 0x50, 4, "RESERVED" },
401         { 0x54, 4, "RESERVED" },
402         { 0x58, 4, "RESERVED" },
403         { 0x5c, 4, "RESERVED" },
404         /* Here start the TCO registers */
405         { 0x60, 1, "TCO_RLD" },
406         { 0x61, 1, "TCO_TMR" },
407         { 0x62, 1, "TCO_DAT_IN" },
408         { 0x63, 1, "TCO_DAT_OUT" },
409         { 0x64, 2, "TCO1_STS" },
410         { 0x66, 2, "TCO2_STS" },
411         { 0x68, 2, "TCO1_CNT" },
412         { 0x6a, 2, "TCO2_CNT" },
413         { 0x6c, 1, "TCO_MESSAGE1" },
414         { 0x6d, 1, "TCO_MESSAGE2" },
415         { 0x6e, 1, "TCO_WDSTATUS" },
416         { 0x6f, 1, "RESERVED" },
417         { 0x70, 1, "SW_IRQ_GEN" },
418         { 0x71, 1, "RESERVED" },
419         { 0x72, 2, "RESERVED" },
420         { 0x74, 4, "RESERVED" },
421         { 0x78, 4, "RESERVED" },
422         { 0x7c, 4, "RESERVED" },
423 };
424
425 static const io_register_t ich0_pm_registers[] = {
426         { 0x00, 2, "PM1_STS" },
427         { 0x02, 2, "PM1_EN" },
428         { 0x04, 4, "PM1_CNT" },
429         { 0x08, 4, "PM1_TMR" },
430         { 0x0c, 4, "RESERVED" },
431         { 0x10, 4, "PROC_CNT" },
432 #if DANGEROUS_REGISTERS
433         /* This register returns 0 on read, but reading it may cause
434          * the system to enter C2 state, which might hang the system.
435          */
436         { 0x14, 1, "LV2" },
437         { 0x15, 1, "RESERVED" },
438         { 0x16, 2, "RESERVED" },
439 #endif
440         { 0x18, 4, "RESERVED" },
441         { 0x1c, 4, "RESERVED" },
442         { 0x20, 4, "RESERVED" },
443         { 0x24, 4, "RESERVED" },
444         { 0x28, 4, "GPE0_STS" },
445         { 0x2C, 4, "GPE0_EN" },
446         { 0x30, 2, "SMI_EN" },
447         { 0x32, 2, "RESERVED" },
448         { 0x34, 2, "SMI_STS" },
449         { 0x36, 2, "RESERVED" },
450         { 0x38, 4, "RESERVED" },
451         { 0x3c, 4, "RESERVED" },
452         { 0x40, 2, "IOMON_STS_EN" },
453         { 0x42, 2, "RESERVED" },
454         { 0x44, 2, "DEVACT_STS" },
455         { 0x46, 2, "RESERVED" },
456         { 0x48, 4, "RESERVED" },
457         { 0x4c, 2, "BUS_ADDR_TRACK" },
458         { 0x4e, 1, "BUS_CYC_TRACK" },
459         { 0x4f, 1, "RESERVED" },
460         { 0x50, 4, "RESERVED" },
461         { 0x54, 4, "RESERVED" },
462         { 0x58, 4, "RESERVED" },
463         { 0x5c, 4, "RESERVED" },
464         /* Here start the TCO registers */
465         { 0x60, 1, "TCO_RLD" },
466         { 0x61, 1, "TCO_TMR" },
467         { 0x62, 1, "TCO_DAT_IN" },
468         { 0x63, 1, "TCO_DAT_OUT" },
469         { 0x64, 2, "TCO1_STS" },
470         { 0x66, 2, "TCO2_STS" },
471         { 0x68, 2, "TCO1_CNT" },
472         { 0x6a, 2, "TCO2_CNT" },
473         { 0x6c, 1, "TCO_MESSAGE1" },
474         { 0x6d, 1, "TCO_MESSAGE2" },
475         { 0x6e, 1, "TCO_WDSTATUS" },
476         { 0x6f, 1, "RESERVED" },
477         { 0x70, 4, "RESERVED" },
478         { 0x74, 4, "RESERVED" },
479         { 0x78, 4, "RESERVED" },
480         { 0x7c, 4, "RESERVED" },
481 };
482
483 static const io_register_t i82371xx_pm_registers[] = {
484         { 0x00, 2, "PMSTS" },
485         { 0x02, 2, "PMEN" },
486         { 0x04, 2, "PMCNTRL" },
487         { 0x06, 2, "RESERVED" },
488         { 0x08, 1, "PMTMR" },
489         { 0x09, 1, "RESERVED" },
490         { 0x0A, 1, "RESERVED" },
491         { 0x0B, 1, "RESERVED" },
492         { 0x0C, 2, "GPSTS" },
493         { 0x0E, 2, "GPEN" },
494         { 0x10, 4, "PCNTRL" },
495 #if DANGEROUS_REGISTERS
496         /*
497          * This register returns 0 on read, but reading it may cause
498          * the system to enter C2 state, which might hang the system.
499          */
500         { 0x14, 1, "PLVL2" },
501         { 0x15, 1, "PLVL3" },
502         { 0x16, 2, "RESERVED" },
503 #endif
504         { 0x18, 2, "GLBSTS" },
505         { 0x1A, 2, "RESERVED" },
506         { 0x1c, 4, "DEVSTS" },
507         { 0x20, 2, "GLBEN" },
508         { 0x22, 1, "RESERVED" },
509         { 0x23, 1, "RESERVED" },
510         { 0x24, 1, "RESERVED" },
511         { 0x25, 1, "RESERVED" },
512         { 0x26, 1, "RESERVED" },
513         { 0x27, 1, "RESERVED" },
514         { 0x28, 4, "GLBCTL" },
515         { 0x2C, 4, "DEVCTL" },
516         /* The registers 0x30-0x33 and 0x34-0x37 allow byte-wise reads only. */
517         { 0x30, 1, "GPIREG 0" },
518         { 0x31, 1, "GPIREG 1" },
519         { 0x32, 1, "GPIREG 2" },
520         { 0x33, 1, "GPIREG 3" },
521         { 0x34, 1, "GPOREG 0" },
522         { 0x35, 1, "GPOREG 1" },
523         { 0x36, 1, "GPOREG 2" },
524         { 0x37, 1, "GPOREG 3" },
525 };
526
527 int print_pmbase(struct pci_dev *sb)
528 {
529         int i, size;
530         uint16_t pmbase;
531         const io_register_t *pm_registers;
532
533         printf("\n============= PMBASE ============\n\n");
534
535         switch (sb->device_id) {
536         case PCI_DEVICE_ID_INTEL_ICH10R:
537                 pmbase = pci_read_word(sb, 0x40) & 0xff80;
538                 pm_registers = ich10_pm_registers;
539                 size = ARRAY_SIZE(ich10_pm_registers);
540                 break;
541         case PCI_DEVICE_ID_INTEL_ICH7:
542         case PCI_DEVICE_ID_INTEL_ICH7M:
543         case PCI_DEVICE_ID_INTEL_ICH7DH:
544         case PCI_DEVICE_ID_INTEL_ICH7MDH:
545         case PCI_DEVICE_ID_INTEL_NM10:
546                 pmbase = pci_read_word(sb, 0x40) & 0xfffc;
547                 pm_registers = ich7_pm_registers;
548                 size = ARRAY_SIZE(ich7_pm_registers);
549                 break;
550         case PCI_DEVICE_ID_INTEL_ICH9DH:
551         case PCI_DEVICE_ID_INTEL_ICH9DO:
552         case PCI_DEVICE_ID_INTEL_ICH9R:
553         case PCI_DEVICE_ID_INTEL_ICH9:
554         case PCI_DEVICE_ID_INTEL_ICH9M:
555         case PCI_DEVICE_ID_INTEL_ICH9ME:
556                 pmbase = pci_read_word(sb, 0x40) & 0xfffc;
557                 pm_registers = ich9_pm_registers;
558                 size = ARRAY_SIZE(ich9_pm_registers);
559                 break;
560         case PCI_DEVICE_ID_INTEL_ICH8:
561         case PCI_DEVICE_ID_INTEL_ICH8M:
562                 pmbase = pci_read_word(sb, 0x40) & 0xfffc;
563                 pm_registers = ich8_pm_registers;
564                 size = ARRAY_SIZE(ich8_pm_registers);
565                 break;
566         case PCI_DEVICE_ID_INTEL_ICH6:
567                 pmbase = pci_read_word(sb, 0x40) & 0xfffc;
568                 pm_registers = ich6_pm_registers;
569                 size = ARRAY_SIZE(ich6_pm_registers);
570                 break;
571         case PCI_DEVICE_ID_INTEL_ICH4:
572                 pmbase = pci_read_word(sb, 0x40) & 0xfffc;
573                 pm_registers = ich4_pm_registers;
574                 size = ARRAY_SIZE(ich4_pm_registers);
575                 break;
576         case PCI_DEVICE_ID_INTEL_ICH2:
577                 pmbase = pci_read_word(sb, 0x40) & 0xfffc;
578                 pm_registers = ich2_pm_registers;
579                 size = ARRAY_SIZE(ich2_pm_registers);
580                 break;
581         case PCI_DEVICE_ID_INTEL_ICH0:
582                 pmbase = pci_read_word(sb, 0x40) & 0xfffc;
583                 pm_registers = ich0_pm_registers;
584                 size = ARRAY_SIZE(ich0_pm_registers);
585                 break;
586         case PCI_DEVICE_ID_INTEL_82371XX:
587                 pmbase = pci_read_word(sb, 0x40) & 0xfffc;
588                 pm_registers = i82371xx_pm_registers;
589                 size = ARRAY_SIZE(i82371xx_pm_registers);
590                 break;
591         case 0x1234: // Dummy for non-existent functionality
592                 printf("This southbridge does not have PMBASE.\n");
593                 return 1;
594         default:
595                 printf("Error: Dumping PMBASE on this southbridge is not (yet) supported.\n");
596                 return 1;
597         }
598
599         printf("PMBASE = 0x%04x (IO)\n\n", pmbase);
600
601         for (i = 0; i < size; i++) {
602                 switch (pm_registers[i].size) {
603                 case 4:
604                         printf("pmbase+0x%04x: 0x%08x (%s)\n",
605                                 pm_registers[i].addr,
606                                 inl(pmbase+pm_registers[i].addr),
607                                 pm_registers[i].name);
608                         break;
609                 case 2:
610                         printf("pmbase+0x%04x: 0x%04x     (%s)\n",
611                                 pm_registers[i].addr,
612                                 inw(pmbase+pm_registers[i].addr),
613                                 pm_registers[i].name);
614                         break;
615                 case 1:
616                         printf("pmbase+0x%04x: 0x%02x       (%s)\n",
617                                 pm_registers[i].addr,
618                                 inb(pmbase+pm_registers[i].addr),
619                                 pm_registers[i].name);
620                         break;
621                 }
622         }
623
624         return 0;
625 }
626