blob: 78caff0dc123b066392d970d0dea9ddc4c869de4 [file] [log] [blame]
Simon Glass057427c2020-09-22 12:45:03 -06001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Writing IntelGraphicsMem table for ACPI
4 *
5 * Copyright 2019 Google LLC
6 * Modified from coreboot src/soc/intel/gma/opregion.c
7 */
8
Simon Glass057427c2020-09-22 12:45:03 -06009#include <binman.h>
10#include <bloblist.h>
11#include <dm.h>
12#include <spi_flash.h>
13#include <asm/intel_opregion.h>
14
15static char vbt_data[8 << 10];
16
17static int locate_vbt(char **vbtp, int *sizep)
18{
19 struct binman_entry vbt;
20 struct udevice *dev;
21 u32 vbtsig = 0;
22 int size;
23 int ret;
24
25 ret = binman_entry_find("intel-vbt", &vbt);
26 if (ret)
27 return log_msg_ret("find VBT", ret);
28 ret = uclass_first_device_err(UCLASS_SPI_FLASH, &dev);
29 if (ret)
30 return log_msg_ret("find flash", ret);
31 size = vbt.size;
32 if (size > sizeof(vbt_data))
33 return log_msg_ret("vbt", -E2BIG);
34 ret = spi_flash_read_dm(dev, vbt.image_pos, size, vbt_data);
35 if (ret)
36 return log_msg_ret("read", ret);
37
38 memcpy(&vbtsig, vbt_data, sizeof(vbtsig));
39 if (vbtsig != VBT_SIGNATURE) {
40 log_err("Missing/invalid signature in VBT data file!\n");
41 return -EINVAL;
42 }
43
Simon Glassdd5fa062020-11-04 09:57:39 -070044 log_debug("Found a VBT of %u bytes\n", size);
Simon Glass057427c2020-09-22 12:45:03 -060045 *sizep = size;
46 *vbtp = vbt_data;
47
48 return 0;
49}
50
51/* Write ASLS PCI register and prepare SWSCI register */
52static int intel_gma_opregion_register(struct udevice *dev, ulong opregion)
53{
54 int sci_reg;
55
56 if (!device_active(dev))
57 return -ENOENT;
58
59 /*
60 * Intel BIOS Specification
61 * Chapter 5.3.7 "Initialise Hardware State"
62 */
63 dm_pci_write_config32(dev, ASLS, opregion);
64
65 /*
66 * Atom-based platforms use a combined SMI/SCI register,
67 * whereas non-Atom platforms use a separate SCI register
68 */
69 if (IS_ENABLED(CONFIG_INTEL_GMA_SWSMISCI))
70 sci_reg = SWSMISCI;
71 else
72 sci_reg = SWSCI;
73
74 /*
75 * Intel's Windows driver relies on this:
76 * Intel BIOS Specification
77 * Chapter 5.4 "ASL Software SCI Handler"
78 */
79 dm_pci_clrset_config16(dev, sci_reg, GSSCIE, SMISCISEL);
80
81 return 0;
82}
83
84int intel_gma_init_igd_opregion(struct udevice *dev,
85 struct igd_opregion *opregion)
86{
87 struct optionrom_vbt *vbt = NULL;
88 char *vbt_buf;
89 int vbt_size;
90 int ret;
91
92 ret = locate_vbt(&vbt_buf, &vbt_size);
93 if (ret) {
94 log_err("GMA: VBT couldn't be found\n");
95 return log_msg_ret("find vbt", ret);
96 }
97 vbt = (struct optionrom_vbt *)vbt_buf;
98
99 memset(opregion, '\0', sizeof(struct igd_opregion));
100
101 memcpy(&opregion->header.signature, IGD_OPREGION_SIGNATURE,
102 sizeof(opregion->header.signature));
103 memcpy(opregion->header.vbios_version, vbt->coreblock_biosbuild,
104 ARRAY_SIZE(vbt->coreblock_biosbuild));
105 /* Extended VBT support */
106 if (vbt->hdr_vbt_size > sizeof(opregion->vbt.gvd1)) {
107 struct optionrom_vbt *ext_vbt;
108
109 ret = bloblist_ensure_size(BLOBLISTT_INTEL_VBT,
Simon Glass06373972020-09-19 18:49:29 -0600110 vbt->hdr_vbt_size, 0,
Simon Glass057427c2020-09-22 12:45:03 -0600111 (void **)&ext_vbt);
112 if (ret) {
113 log_err("GMA: Unable to add Ext VBT to bloblist\n");
114 return log_msg_ret("blob", ret);
115 }
116
117 memcpy(ext_vbt, vbt, vbt->hdr_vbt_size);
118 opregion->mailbox3.rvda = (uintptr_t)ext_vbt;
119 opregion->mailbox3.rvds = vbt->hdr_vbt_size;
120 } else {
121 /* Raw VBT size which can fit in gvd1 */
122 printf("copy to %p\n", opregion->vbt.gvd1);
123 memcpy(opregion->vbt.gvd1, vbt, vbt->hdr_vbt_size);
124 }
125
126 /* 8kb */
127 opregion->header.size = sizeof(struct igd_opregion) / 1024;
128
129 /*
130 * Left-shift version field to accommodate Intel Windows driver quirk
131 * when not using a VBIOS.
132 * Required for Legacy boot + NGI, UEFI + NGI, and UEFI + GOP driver.
133 *
134 * No adverse effects when using VBIOS or booting Linux.
135 */
136 opregion->header.version = IGD_OPREGION_VERSION << 24;
137
138 /* We just assume we're mobile for now */
139 opregion->header.mailboxes = MAILBOXES_MOBILE;
140
141 /* Initialise Mailbox 1 */
142 opregion->mailbox1.clid = 1;
143
144 /* Initialise Mailbox 3 */
145 opregion->mailbox3.bclp = IGD_BACKLIGHT_BRIGHTNESS;
146 opregion->mailbox3.pfit = IGD_FIELD_VALID | IGD_PFIT_STRETCH;
147 opregion->mailbox3.pcft = 0; /* should be (IMON << 1) & 0x3e */
148 opregion->mailbox3.cblv = IGD_FIELD_VALID | IGD_INITIAL_BRIGHTNESS;
149 opregion->mailbox3.bclm[0] = IGD_WORD_FIELD_VALID + 0x0000;
150 opregion->mailbox3.bclm[1] = IGD_WORD_FIELD_VALID + 0x0a19;
151 opregion->mailbox3.bclm[2] = IGD_WORD_FIELD_VALID + 0x1433;
152 opregion->mailbox3.bclm[3] = IGD_WORD_FIELD_VALID + 0x1e4c;
153 opregion->mailbox3.bclm[4] = IGD_WORD_FIELD_VALID + 0x2866;
154 opregion->mailbox3.bclm[5] = IGD_WORD_FIELD_VALID + 0x327f;
155 opregion->mailbox3.bclm[6] = IGD_WORD_FIELD_VALID + 0x3c99;
156 opregion->mailbox3.bclm[7] = IGD_WORD_FIELD_VALID + 0x46b2;
157 opregion->mailbox3.bclm[8] = IGD_WORD_FIELD_VALID + 0x50cc;
158 opregion->mailbox3.bclm[9] = IGD_WORD_FIELD_VALID + 0x5ae5;
159 opregion->mailbox3.bclm[10] = IGD_WORD_FIELD_VALID + 0x64ff;
160
161 /* Write ASLS PCI register and prepare SWSCI register */
162 ret = intel_gma_opregion_register(dev, (ulong)opregion);
163 if (ret)
164 return log_msg_ret("write asls", ret);
165
166 return 0;
167}