blob: c65828ae2900b542517f73c5b38454f4639fbc22 [file] [log] [blame]
Jani Nikula76be7492013-10-08 21:18:13 +03001/*
2 * Copyright © 2013 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 *
23 * Authors:
24 * Jani Nikula <jani.nikula@intel.com>
25 *
26 */
27
28#include <errno.h>
29#include <fcntl.h>
30#include <getopt.h>
31#include <stdint.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <unistd.h>
36#include <sys/mman.h>
37#include <sys/stat.h>
38#include <sys/types.h>
39
Daniel Vetterc03c6ce2014-03-22 21:34:29 +010040#include "intel_io.h"
Daniel Vetter6cfcd712014-03-22 20:07:35 +010041#include "drmtest.h"
Jani Nikula76be7492013-10-08 21:18:13 +030042
43#define OPREGION_HEADER_OFFSET 0
44#define OPREGION_ACPI_OFFSET 0x100
45#define OPREGION_SWSCI_OFFSET 0x200
46#define OPREGION_ASLE_OFFSET 0x300
47#define OPREGION_VBT_OFFSET 0x400
48#define OPREGION_ASLE_EXT_OFFSET 0x1C00
49
50#define MBOX_ACPI (1 << 0)
51#define MBOX_SWSCI (1 << 1)
52#define MBOX_ASLE (1 << 2)
53#define MBOX_VBT (1 << 3)
54#define MBOX_ASLE_EXT (1 << 4)
55
56struct opregion_header {
57 char sign[16];
58 uint32_t size;
59 uint32_t over;
60 char sver[32];
61 char vver[16];
62 char gver[16];
63 uint32_t mbox;
64 uint32_t dmod;
65 uint32_t pcon;
66 char dver[32];
67 uint8_t rsv1[124];
68} __attribute__((packed));
69
70/* OpRegion mailbox #1: public ACPI methods */
71struct opregion_acpi {
72 uint32_t drdy; /* driver readiness */
73 uint32_t csts; /* notification status */
74 uint32_t cevt; /* current event */
75 uint8_t rsvd1[20];
76 uint32_t didl[8]; /* supported display devices ID list */
77 uint32_t cpdl[8]; /* currently presented display list */
78 uint32_t cadl[8]; /* currently active display list */
79 uint32_t nadl[8]; /* next active devices list */
80 uint32_t aslp; /* ASL sleep time-out */
81 uint32_t tidx; /* toggle table index */
82 uint32_t chpd; /* current hotplug enable indicator */
83 uint32_t clid; /* current lid state*/
84 uint32_t cdck; /* current docking state */
85 uint32_t sxsw; /* Sx state resume */
86 uint32_t evts; /* ASL supported events */
87 uint32_t cnot; /* current OS notification */
88 uint32_t nrdy; /* driver status */
89 uint32_t did2[7];
90 uint32_t cpd2[7];
91 uint8_t rsvd2[4];
92} __attribute__((packed));
93
94/* OpRegion mailbox #2: SWSCI */
95struct opregion_swsci {
96 uint32_t scic; /* SWSCI command|status|data */
97 uint32_t parm; /* command parameters */
98 uint32_t dslp; /* driver sleep time-out */
99 uint8_t rsvd[244];
100} __attribute__((packed));
101
102/* OpRegion mailbox #3: ASLE */
103struct opregion_asle {
104 uint32_t ardy; /* driver readiness */
105 uint32_t aslc; /* ASLE interrupt command */
106 uint32_t tche; /* technology enabled indicator */
107 uint32_t alsi; /* current ALS illuminance reading */
108 uint32_t bclp; /* backlight brightness to set */
109 uint32_t pfit; /* panel fitting state */
110 uint32_t cblv; /* current brightness level */
111 uint16_t bclm[20]; /* backlight level duty cycle mapping table */
112 uint32_t cpfm; /* current panel fitting mode */
113 uint32_t epfm; /* enabled panel fitting modes */
114 uint8_t plut_header; /* panel LUT and identifier */
115 uint8_t plut_identifier[10]; /* panel LUT and identifier */
116 uint8_t plut[63]; /* panel LUT and identifier */
117 uint32_t pfmb; /* PWM freq and min brightness */
118 uint32_t ccdv;
119 uint32_t pcft;
120 uint32_t srot;
121 uint32_t iuer;
122 uint8_t fdss[8];
123 uint32_t fdsp;
124 uint32_t stat;
Jani Nikulabdf7b1c2015-12-21 15:22:08 +0200125 uint64_t rvda; /* Physical address of raw vbt data */
126 uint32_t rvds; /* Size of raw vbt data */
127 uint8_t rsvd[58];
Jani Nikula76be7492013-10-08 21:18:13 +0300128} __attribute__((packed));
129
130/* OpRegion mailbox #4: VBT */
131struct opregion_vbt {
132 char product_string[20];
133 /* rest ignored */
134} __attribute__((packed));
135
136/* OpRegion mailbox #5: ASLE extension */
137struct opregion_asle_ext {
138 uint32_t phed;
139 uint8_t bddc[256];
140} __attribute__((packed));
141
142static uint32_t decode_header(const void *buffer)
143{
144 const struct opregion_header *header = buffer;
145 char *s;
146
147 if (strncmp("IntelGraphicsMem", header->sign, sizeof(header->sign))) {
148 fprintf(stderr, "invalid opregion signature\n");
149 return 0;
150 }
151
152 printf("OpRegion Header:\n");
153
154 s = strndup(header->sign, sizeof(header->sign));
155 printf("\tsign:\t%s\n", s);
156 free(s);
157
158 printf("\tsize:\t0x%08x\n", header->size);
159 printf("\tover:\t0x%08x\n", header->over);
160
161 s = strndup(header->sver, sizeof(header->sver));
162 printf("\tsver:\t%s\n", s);
163 free(s);
164
165 s = strndup(header->vver, sizeof(header->vver));
166 printf("\tvver:\t%s\n", s);
167 free(s);
168
169 s = strndup(header->gver, sizeof(header->gver));
170 printf("\tgver:\t%s\n", s);
171 free(s);
172
173 printf("\tmbox:\t0x%08x\n", header->mbox);
174
175 printf("\tdmod:\t0x%08x\n", header->dmod);
176 printf("\tpcon:\t0x%08x\n", header->pcon);
177
178 s = strndup(header->dver, sizeof(header->dver));
179 printf("\tdver:\t%s\n", s);
180 free(s);
181
182 printf("\n");
183
184 return header->mbox;
185}
186
187static void decode_acpi(const void *buffer)
188{
189 const struct opregion_acpi *acpi = buffer;
190 int i;
191
192 printf("OpRegion Mailbox 1: Public ACPI Methods:\n");
193
194 printf("\tdrdy:\t0x%08x\n", acpi->drdy);
195 printf("\tcsts:\t0x%08x\n", acpi->csts);
196 printf("\tcevt:\t0x%08x\n", acpi->cevt);
197
198 printf("\tdidl:\n");
199 for (i = 0; i < ARRAY_SIZE(acpi->didl); i++)
200 printf("\t\tdidl[%d]:\t0x%08x\n", i, acpi->didl[i]);
201
202 printf("\tcpdl:\n");
203 for (i = 0; i < ARRAY_SIZE(acpi->cpdl); i++)
204 printf("\t\tcpdl[%d]:\t0x%08x\n", i, acpi->cpdl[i]);
205
206 printf("\tcadl:\n");
207 for (i = 0; i < ARRAY_SIZE(acpi->cadl); i++)
208 printf("\t\tcadl[%d]:\t0x%08x\n", i, acpi->cadl[i]);
209
210 printf("\tnadl:\n");
211 for (i = 0; i < ARRAY_SIZE(acpi->nadl); i++)
212 printf("\t\tnadl[%d]:\t0x%08x\n", i, acpi->nadl[i]);
213
214 printf("\taslp:\t0x%08x\n", acpi->aslp);
215 printf("\ttidx:\t0x%08x\n", acpi->tidx);
216 printf("\tchpd:\t0x%08x\n", acpi->chpd);
217 printf("\tclid:\t0x%08x\n", acpi->clid);
218 printf("\tcdck:\t0x%08x\n", acpi->cdck);
219 printf("\tsxsw:\t0x%08x\n", acpi->sxsw);
220 printf("\tevts:\t0x%08x\n", acpi->evts);
221 printf("\tcnot:\t0x%08x\n", acpi->cnot);
222 printf("\tnrdy:\t0x%08x\n", acpi->nrdy);
223
224 printf("\tdid2:\n");
225 for (i = 0; i < ARRAY_SIZE(acpi->did2); i++)
226 printf("\t\tdid2[%d]:\t0x%08x\n", i, acpi->did2[i]);
227
228 printf("\tcpd2:\n");
229 for (i = 0; i < ARRAY_SIZE(acpi->cpd2); i++)
230 printf("\t\tcpd2[%d]:\t0x%08x\n", i, acpi->cpd2[i]);
231
232 printf("\n");
233}
234
235static void decode_swsci(const void *buffer)
236{
237 const struct opregion_swsci *swsci = buffer;
238
239 printf("OpRegion Mailbox 2: Software SCI Interface (SWSCI):\n");
240
241 printf("\tscic:\t0x%08x\n", swsci->scic);
242 printf("\tparm:\t0x%08x\n", swsci->parm);
243 printf("\tdslp:\t0x%08x\n", swsci->dslp);
244
245 printf("\n");
246}
247
248static void decode_asle(const void *buffer)
249{
250 const struct opregion_asle *asle = buffer;
251 int i;
252
253 printf("OpRegion Mailbox 3: BIOS to Driver Notification (ASLE):\n");
254
255 printf("\tardy:\t0x%08x\n", asle->ardy);
256 printf("\taslc:\t0x%08x\n", asle->aslc);
257 printf("\ttche:\t0x%08x\n", asle->tche);
258 printf("\talsi:\t0x%08x\n", asle->alsi);
259 printf("\tbclp:\t0x%08x\n", asle->bclp);
260 printf("\tpfit:\t0x%08x\n", asle->pfit);
261 printf("\tcblv:\t0x%08x\n", asle->cblv);
262
263 printf("\tbclm:\n");
Jani Nikula6d3c9172013-10-08 21:18:14 +0300264 for (i = 0; i < ARRAY_SIZE(asle->bclm); i++) {
265 int valid = asle->bclm[i] & (1 << 15);
266 int percentage = (asle->bclm[i] & 0x7f00) >> 8;
267 int duty_cycle = asle->bclm[i] & 0xff;
268
269 printf("\t\tbclm[%d]:\t0x%04x", i, asle->bclm[i]);
270 if (valid)
271 printf(" (%3d%% -> 0x%02x)\n", percentage, duty_cycle);
272 else
273 printf("\n");
274
275 }
Jani Nikula76be7492013-10-08 21:18:13 +0300276
277 printf("\tcpfm:\t0x%08x\n", asle->cpfm);
278 printf("\tepfm:\t0x%08x\n", asle->epfm);
279
280 printf("\tplut header:\t0x%02x\n", asle->plut_header);
281
282 printf("\tplut identifier:");
283 for (i = 0; i < ARRAY_SIZE(asle->plut_identifier); i++)
284 printf(" %02x", asle->plut_identifier[i]);
285 printf("\n");
286
287 printf("\tplut:\n");
288 for (i = 0; i < ARRAY_SIZE(asle->plut); i++) {
289 const int COLUMNS = 7;
290
291 if (i % COLUMNS == 0)
292 printf("\t\tplut[%d]:\t", i / COLUMNS);
293
294 printf("%02x ", asle->plut[i]);
295
296 if (i % COLUMNS == COLUMNS - 1)
297 printf("\n");
298 }
299
300 printf("\tpfmb:\t0x%08x\n", asle->pfmb);
301 printf("\tccdv:\t0x%08x\n", asle->ccdv);
302 printf("\tpcft:\t0x%08x\n", asle->pcft);
303 printf("\tsrot:\t0x%08x\n", asle->srot);
304 printf("\tiuer:\t0x%08x\n", asle->iuer);
305
306 printf("\tfdss:\t");
307 for (i = 0; i < ARRAY_SIZE(asle->fdss); i++)
308 printf("%02x ", asle->fdss[i]);
309 printf("\n");
310
311 printf("\tfdsp:\t0x%08x\n", asle->fdsp);
312 printf("\tstat:\t0x%08x\n", asle->stat);
Jani Nikulabdf7b1c2015-12-21 15:22:08 +0200313 printf("\trvda:\t0x%016lx\n", asle->rvda);
314 printf("\trvds:\t0x%08x\n", asle->rvds);
Jani Nikula76be7492013-10-08 21:18:13 +0300315
316 printf("\n");
317}
318
319static void decode_vbt(const void *buffer)
320{
321 const struct opregion_vbt *vbt = buffer;
322 char *s;
323
324 printf("OpRegion Mailbox 4: Video BIOS Table (VBT):\n");
325
326 s = strndup(vbt->product_string, sizeof(vbt->product_string));
327 printf("\tproduct string:\t%s\n", s);
328 free(s);
329
330 printf("\t(use intel_bios_reader to decode the VBT)\n");
331
332 printf("\n");
333}
334
335static void decode_asle_ext(const void *buffer)
336{
337 const struct opregion_asle_ext *asle_ext = buffer;
338 int i;
339
340 printf("OpRegion Mailbox 5: BIOS to Driver Notification Extension:\n");
341
342 printf("\tphed:\t0x%08x\n", asle_ext->phed);
343
344 printf("\tbddc:\n");
345 for (i = 0; i < ARRAY_SIZE(asle_ext->bddc); i++) {
346 const int COLUMNS = 16;
347
348 if (i % COLUMNS == 0)
349 printf("\t\tbddc[0x%02x]:\t", i);
350
351 printf("%02x ", asle_ext->bddc[i]);
352
353 if (i % COLUMNS == COLUMNS - 1)
354 printf("\n");
355 }
356
357 printf("\n");
358}
359
360static void decode_opregion(const uint8_t *opregion, int size)
361{
362 uint32_t mbox;
363
364 /* XXX: allow decoding up to size */
365 if (OPREGION_ASLE_EXT_OFFSET + sizeof(struct opregion_asle_ext) > size) {
366 fprintf(stderr, "buffer too small\n");
367 return;
368 }
369
370 mbox = decode_header(opregion + OPREGION_HEADER_OFFSET);
371 if (mbox & MBOX_ACPI)
372 decode_acpi(opregion + OPREGION_ACPI_OFFSET);
373 if (mbox & MBOX_SWSCI)
374 decode_swsci(opregion + OPREGION_SWSCI_OFFSET);
375 if (mbox & MBOX_ASLE)
376 decode_asle(opregion + OPREGION_ASLE_OFFSET);
377 if (mbox & MBOX_VBT)
378 decode_vbt(opregion + OPREGION_VBT_OFFSET);
379 if (mbox & MBOX_ASLE_EXT)
380 decode_asle_ext(opregion + OPREGION_ASLE_EXT_OFFSET);
381}
382
383int main(int argc, char *argv[])
384{
385 const char *filename = "/sys/kernel/debug/dri/0/i915_opregion";
386 int fd;
387 struct stat finfo;
388 uint8_t *opregion;
389 int c, option_index = 0;
390
391 static struct option long_options[] = {
392 { "file", required_argument, 0, 'f' },
393 { "help", no_argument, 0, 'h' },
394 { 0 },
395 };
396
397 while ((c = getopt_long(argc, argv, "hf:",
398 long_options, &option_index)) != -1) {
399 switch (c) {
400 case 'h':
401 printf("usage: intel_opregion_decode [-f|--file=<input>]\n");
402 return 0;
403 case 'f':
404 filename = optarg;
405 break;
406 default:
407 fprintf(stderr, "unkown command options\n");
408 return 1;
409 }
410 }
411
412 fd = open(filename, O_RDONLY);
413 if (fd == -1) {
414 printf("Couldn't open \"%s\": %s\n", filename, strerror(errno));
415 return 1;
416 }
417
418 if (stat(filename, &finfo)) {
419 printf("failed to stat \"%s\": %s\n", filename, strerror(errno));
420 return 1;
421 }
422
423 if (finfo.st_size == 0) {
424 int len = 0, ret;
425 finfo.st_size = 8192;
426 opregion = malloc(finfo.st_size);
427 while ((ret = read(fd, opregion + len, finfo.st_size - len))) {
428 if (ret < 0) {
429 printf("failed to read \"%s\": %s\n", filename,
430 strerror(errno));
431 return 1;
432 }
433
434 len += ret;
435 if (len == finfo.st_size) {
436 finfo.st_size *= 2;
437 opregion = realloc(opregion, finfo.st_size);
438 }
439 }
440 } else {
441 opregion = mmap(NULL, finfo.st_size, PROT_READ, MAP_SHARED,
442 fd, 0);
443 if (opregion == MAP_FAILED) {
444 printf("failed to map \"%s\": %s\n", filename,
445 strerror(errno));
446 return 1;
447 }
448 }
449
450 decode_opregion(opregion, finfo.st_size);
451
452 return 0;
453}