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