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