soc/intel/ptl: Update ME specification version to 21
[coreboot.git] / util / superiotool / superiotool.c
bloba62f49a0845dce7f36cc7a2f68038007d236584d
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 #include "superiotool.h"
5 #if defined(__FreeBSD__)
6 #include <fcntl.h>
7 #include <unistd.h>
8 #endif
10 /* Command line options. */
11 int dump = 0, verbose = 0, extra_dump = 0, alternate_dump = 0;
13 /* Global flag which indicates whether a chip was detected at all. */
14 int chip_found = 0;
16 static void set_bank(uint16_t port, uint8_t bank)
18 OUTB(0x4E, port);
19 OUTB(bank, port + 1);
22 static uint8_t datareg(uint16_t port, uint8_t reg)
24 OUTB(reg, port);
25 return INB(port + 1);
28 uint8_t regval(uint16_t port, uint8_t reg)
30 OUTB(reg, port);
31 return INB(port + ((port == 0x3bd) ? 2 : 1)); /* 0x3bd is special. */
34 void regwrite(uint16_t port, uint8_t reg, uint8_t val)
36 OUTB(reg, port);
37 OUTB(val, port + 1);
40 void enter_conf_mode_winbond_fintek_ite_8787(uint16_t port)
42 OUTB(0x87, port);
43 OUTB(0x87, port);
46 void exit_conf_mode_winbond_fintek_ite_8787(uint16_t port)
48 OUTB(0xaa, port); /* Fintek, Winbond */
49 regwrite(port, 0x02, 0x02); /* ITE */
52 void enter_conf_mode_fintek_7777(uint16_t port)
54 OUTB(0x77, port);
55 OUTB(0x77, port);
58 void exit_conf_mode_fintek_7777(uint16_t port)
60 OUTB(0xaa, port); /* Fintek */
63 int superio_unknown(const struct superio_registers reg_table[], uint16_t id)
65 return !strncmp(get_superio_name(reg_table, id), "<unknown>", 9);
69 const char *get_superio_name(const struct superio_registers reg_table[],
70 uint16_t id)
72 int i;
74 for (i = 0; /* Nothing */; i++) {
75 if (reg_table[i].superio_id == EOT)
76 break;
78 if ((uint16_t)reg_table[i].superio_id != id)
79 continue;
81 return reg_table[i].name;
84 return "<unknown>";
87 static void set_extra_selector(uint16_t port, const struct extra_selector *esel)
89 if (esel->idx == 0) /* entry without extra selector */
90 return;
92 uint8_t reg_val = regval(port, esel->idx);
93 reg_val &= ~esel->mask;
94 reg_val |= esel->val;
95 regwrite(port, esel->idx, reg_val);
97 reg_val = regval(port, esel->idx) & esel->mask;
99 printf(" -- ESEL[%02xh] 0x%02x", esel->idx, reg_val);
100 if (esel->name != NULL)
101 printf(" (%s)", esel->name);
102 printf(" --");
104 if (verbose)
105 printf(" config: idx=%02xh, mask=%02xh, val=%02xh --", esel->idx, esel->mask,
106 esel->val);
109 static void dump_regs(const struct superio_registers reg_table[],
110 int i, int j, uint16_t port, uint8_t ldn_sel)
112 int k;
113 const int16_t *idx, *def;
115 if (reg_table[i].ldn[j].ldn != NOLDN) {
116 printf("LDN 0x%02x", reg_table[i].ldn[j].ldn);
117 if (reg_table[i].ldn[j].name != NULL)
118 printf(" (%s)", reg_table[i].ldn[j].name);
119 regwrite(port, ldn_sel, reg_table[i].ldn[j].ldn);
120 } else {
121 if (reg_table[i].ldn[j].name == NULL)
122 printf("Register dump:");
123 else
124 printf("(%s)", reg_table[i].ldn[j].name);
127 set_extra_selector(port, &reg_table[i].ldn[j].esel);
129 idx = reg_table[i].ldn[j].idx;
130 def = reg_table[i].ldn[j].def;
132 if (alternate_dump) {
133 int skip_def = 0;
134 int val;
136 printf("\nidx def val\n");
138 for (k = 0; idx[k] != EOT; k++) {
139 if (skip_def || def[k] == EOT) {
140 skip_def = 1;
141 printf("\n");
142 continue;
145 printf("0x%02x: ", idx[k]);
146 val = regval(port, idx[k]);
148 if (def[k] == NANA)
149 printf("(NA) 0x%02x\n", val);
150 else if (def[k] == RSVD)
151 printf("(RR) 0x%02x\n", val);
152 else if (def[k] == MISC)
153 printf("(MM) 0x%02x\n", val);
154 else {
155 if (def[k] == val)
156 printf("0x%02x 0x%02x\n", def[k], val);
157 else
158 printf("0x%02x [0x%02x]\n", def[k], val);
161 } else {
162 printf("\nidx");
163 for (k = 0; idx[k] != EOT; k++) {
164 if (k && !(k % 8))
165 putchar(' ');
166 printf(" %02x", idx[k]);
169 printf("\nval");
170 for (k = 0; idx[k] != EOT; k++) {
171 if (k && !(k % 8))
172 putchar(' ');
173 printf(" %02x", regval(port, idx[k]));
176 printf("\ndef");
177 for (k = 0; def[k] != EOT; k++) {
178 if (k && !(k % 8))
179 putchar(' ');
180 if (def[k] == NANA)
181 printf(" NA");
182 else if (def[k] == RSVD)
183 printf(" RR");
184 else if (def[k] == MISC)
185 printf(" MM");
186 else
187 printf(" %02x", def[k]);
190 printf("\n");
193 void dump_superio(const char *vendor,
194 const struct superio_registers reg_table[],
195 uint16_t port, uint16_t id, uint8_t ldn_sel)
197 int i, j, no_dump_available = 1;
199 if (!dump)
200 return;
202 for (i = 0; /* Nothing */; i++) {
203 if (reg_table[i].superio_id == EOT)
204 break;
206 if ((uint16_t)reg_table[i].superio_id != id)
207 continue;
209 for (j = 0; /* Nothing */; j++) {
210 if (reg_table[i].ldn[j].ldn == EOT)
211 break;
212 no_dump_available = 0;
213 dump_regs(reg_table, i, j, port, ldn_sel);
216 if (no_dump_available)
217 printf("No dump available for this Super I/O\n");
221 void dump_io(uint16_t iobase, uint16_t length)
223 uint16_t i;
225 printf("Dumping %d I/O mapped registers at base 0x%04x:\n",
226 length, iobase);
227 for (i = 0; i < length; i++)
228 printf("%02x ", i);
229 printf("\n");
230 for (i = 0; i < length; i++)
231 printf("%02x ", INB(iobase + i));
232 printf("\n");
235 void dump_data(uint16_t iobase, int bank)
237 uint16_t i;
239 printf("Bank %d:\n", bank);
240 printf(" ");
241 for (i = 0; i < 16; i++)
242 printf("%02x ", i);
243 set_bank(iobase, bank);
244 for (i = 0; i < 256; i++) {
245 if (i % 16 == 0)
246 printf("\n%02x: ", i / 16);
247 printf("%02x ", datareg(iobase, i));
249 printf("\n");
252 void probing_for(const char *vendor, const char *info, uint16_t port)
254 if (!verbose)
255 return;
257 /* Yes, there's no space between '%s' and 'at'! */
258 printf("Probing for %s Super I/O %sat 0x%x...\n", vendor, info, port);
261 /** Print a list of all supported chips from the given vendor. */
262 void print_vendor_chips(const char *vendor,
263 const struct superio_registers reg_table[])
265 int i;
267 for (i = 0; reg_table[i].superio_id != EOT; i++) {
268 printf("%s %s", vendor, reg_table[i].name);
270 /* Unless the ldn is empty, assume this chip has a dump. */
271 if (reg_table[i].ldn[0].ldn != EOT)
272 printf(" (dump available)");
274 printf("\n");
277 /* If we printed any chips for this vendor, put in a blank line. */
278 if (i != 0)
279 printf("\n");
282 /** Print a list of all chips supported by superiotool. */
283 void print_list_of_supported_chips(void)
285 int i;
287 printf("Supported Super I/O chips:\n\n");
289 for (i = 0; i < ARRAY_SIZE(vendor_print_functions); i++)
290 vendor_print_functions[i].print_list();
292 printf("See <https://coreboot.org/Superiotool#Supported_devices> "
293 "for more information.\n");
296 static void print_version(void)
298 printf("superiotool r%s\n", SUPERIOTOOL_VERSION);
301 int main(int argc, char *argv[])
303 int i, j, opt, option_index;
304 #if defined(__FreeBSD__)
305 int io_fd;
306 #endif
308 static const struct option long_options[] = {
309 {"dump", no_argument, NULL, 'd'},
310 {"extra-dump", no_argument, NULL, 'e'},
311 {"alternate-dump", no_argument, NULL, 'a'},
312 {"list-supported", no_argument, NULL, 'l'},
313 {"verbose", no_argument, NULL, 'V'},
314 {"version", no_argument, NULL, 'v'},
315 {"help", no_argument, NULL, 'h'},
316 {0, 0, 0, 0}
319 while ((opt = getopt_long(argc, argv, "dealVvh",
320 long_options, &option_index)) != EOF) {
321 switch (opt) {
322 case 'd':
323 dump = 1;
324 break;
325 case 'e':
326 extra_dump = 1;
327 break;
328 case 'a':
329 alternate_dump = 1;
330 break;
331 case 'l':
332 print_list_of_supported_chips();
333 exit(0);
334 break;
335 case 'V':
336 verbose = 1;
337 break;
338 case 'v':
339 print_version();
340 exit(0);
341 break;
342 case 'h':
343 printf(USAGE);
344 printf(USAGE_INFO);
345 exit(0);
346 break;
347 default:
348 /* Unknown option. */
349 exit(1);
350 break;
354 #if defined(__FreeBSD__)
355 if ((io_fd = open("/dev/io", O_RDWR)) < 0) {
356 perror("/dev/io");
357 #elif defined(__NetBSD__)
358 if (iopl(3) < 0) {
359 perror("iopl");
360 #else
361 if (ioperm(0, 6000, 1) < 0) {
362 perror("ioperm");
363 #endif
364 printf("Superiotool must be run as root.\n");
365 exit(1);
368 print_version();
370 #ifdef PCI_SUPPORT
371 /* Do some basic libpci init. */
372 pacc = pci_alloc();
373 pci_init(pacc);
374 pci_scan_bus(pacc);
375 #endif
377 for (i = 0; i < ARRAY_SIZE(superio_ports_table); i++) {
378 for (j = 0; superio_ports_table[i].ports[j] != EOT; j++)
379 superio_ports_table[i].probe_idregs(
380 superio_ports_table[i].ports[j]);
383 if (!chip_found)
384 printf("No Super I/O found\n");
386 #if defined(__FreeBSD__)
387 close(io_fd);
388 #endif
389 return 0;