blob: c8bbbfd00eea80951dfdf1acf92cdd1ed3aecf49 [file] [log] [blame]
Angel Pons4b429832020-04-02 23:48:50 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2/* This file is part of the coreboot project. */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01003
4#include <arch/io.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +02005#include <device/mmio.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +01006#include <console/console.h>
7#include <delay.h>
8#include <device/device.h>
9#include <device/pci.h>
10#include <device/pci_ids.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010011#include <device/pci_ops.h>
Vladimir Serbinenko13157302014-02-19 22:18:08 +010012#include <drivers/intel/gma/edid.h>
13#include <drivers/intel/gma/i915.h>
Patrick Rudolph5c820262017-05-17 19:39:12 +020014#include <drivers/intel/gma/intel_bios.h>
Nico Huber18228162017-06-08 16:31:57 +020015#include <drivers/intel/gma/libgfxinit.h>
Vladimir Serbinenko13157302014-02-19 22:18:08 +010016#include <pc80/vga.h>
Patrick Rudolph2be28402017-04-12 16:54:55 +020017#include <southbridge/intel/ibexpeak/nvs.h>
Matt DeVillierebe08e02017-07-14 13:28:42 -050018#include <drivers/intel/gma/opregion.h>
Patrick Rudolph2be28402017-04-12 16:54:55 +020019#include <cbmem.h>
Elyes HAOUAS51401c32019-05-15 21:09:30 +020020#include <types.h>
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010021
22#include "chip.h"
Angel Pons95de2312020-02-17 13:08:53 +010023#include "ironlake.h"
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010024
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010025/* some vga option roms are used for several chipsets but they only have one
26 * PCI ID in their header. If we encounter such an option rom, we need to do
Martin Roth128c1042016-11-18 09:29:03 -070027 * the mapping ourselves
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010028 */
29
30u32 map_oprom_vendev(u32 vendev)
31{
32 u32 new_vendev = vendev;
33
Martin Roth128c1042016-11-18 09:29:03 -070034 /* none currently. */
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010035
36 return new_vendev;
37}
38
39static struct resource *gtt_res = NULL;
40
Furquan Shaikh77f48cd2013-08-19 10:16:50 -070041u32 gtt_read(u32 reg)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010042{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080043 return read32(res2mmio(gtt_res, reg, 0));
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010044}
45
Furquan Shaikh77f48cd2013-08-19 10:16:50 -070046void gtt_write(u32 reg, u32 data)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010047{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080048 write32(res2mmio(gtt_res, reg, 0), data);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010049}
50
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010051#define GTT_RETRY 1000
Ronald G. Minnich9518b562013-09-19 16:45:22 -070052int gtt_poll(u32 reg, u32 mask, u32 value)
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010053{
Martin Roth468d02c2019-10-23 21:44:42 -060054 unsigned int try = GTT_RETRY;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010055 u32 data;
56
57 while (try--) {
58 data = gtt_read(reg);
59 if ((data & mask) == value)
60 return 1;
61 udelay(10);
62 }
63
64 printk(BIOS_ERR, "GT init timeout\n");
65 return 0;
66}
67
Patrick Rudolph19c2ad82017-06-30 14:52:01 +020068uintptr_t gma_get_gnvs_aslb(const void *gnvs)
69{
70 const global_nvs_t *gnvs_ptr = gnvs;
71 return (uintptr_t)(gnvs_ptr ? gnvs_ptr->aslb : 0);
72}
73
74void gma_set_gnvs_aslb(void *gnvs, uintptr_t aslb)
75{
76 global_nvs_t *gnvs_ptr = gnvs;
77 if (gnvs_ptr)
78 gnvs_ptr->aslb = aslb;
79}
80
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010081static void gma_pm_init_post_vbios(struct device *dev)
82{
Angel Pons95de2312020-02-17 13:08:53 +010083 struct northbridge_intel_ironlake_config *conf = dev->chip_info;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010084 u32 reg32;
85
86 printk(BIOS_DEBUG, "GT Power Management Init (post VBIOS)\n");
87
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +010088 /* Setup Digital Port Hotplug */
89 reg32 = gtt_read(0xc4030);
90 if (!reg32) {
91 reg32 = (conf->gpu_dp_b_hotplug & 0x7) << 2;
92 reg32 |= (conf->gpu_dp_c_hotplug & 0x7) << 10;
93 reg32 |= (conf->gpu_dp_d_hotplug & 0x7) << 18;
94 gtt_write(0xc4030, reg32);
95 }
96
97 /* Setup Panel Power On Delays */
98 reg32 = gtt_read(0xc7208);
99 if (!reg32) {
100 reg32 = (conf->gpu_panel_port_select & 0x3) << 30;
101 reg32 |= (conf->gpu_panel_power_up_delay & 0x1fff) << 16;
102 reg32 |= (conf->gpu_panel_power_backlight_on_delay & 0x1fff);
103 gtt_write(0xc7208, reg32);
104 }
105
106 /* Setup Panel Power Off Delays */
107 reg32 = gtt_read(0xc720c);
108 if (!reg32) {
109 reg32 = (conf->gpu_panel_power_down_delay & 0x1fff) << 16;
110 reg32 |= (conf->gpu_panel_power_backlight_off_delay & 0x1fff);
111 gtt_write(0xc720c, reg32);
112 }
113
114 /* Setup Panel Power Cycle Delay */
115 if (conf->gpu_panel_power_cycle_delay) {
116 reg32 = gtt_read(0xc7210);
117 reg32 &= ~0xff;
118 reg32 |= conf->gpu_panel_power_cycle_delay & 0xff;
119 gtt_write(0xc7210, reg32);
120 }
121
122 /* Enable Backlight if needed */
123 if (conf->gpu_cpu_backlight) {
124 gtt_write(0x48250, (1 << 31));
125 gtt_write(0x48254, conf->gpu_cpu_backlight);
126 }
127 if (conf->gpu_pch_backlight) {
128 gtt_write(0xc8250, (1 << 31));
129 gtt_write(0xc8254, conf->gpu_pch_backlight);
130 }
131}
132
Patrick Rudolph64a702f2017-06-20 18:28:56 +0200133/* Enable SCI to ACPI _GPE._L06 */
134static void gma_enable_swsci(void)
135{
136 u16 reg16;
137
138 /* clear DMISCI status */
139 reg16 = inw(DEFAULT_PMBASE + TCO1_STS);
140 reg16 &= DMISCI_STS;
141 outw(DEFAULT_PMBASE + TCO1_STS, reg16);
142
143 /* clear acpi tco status */
144 outl(DEFAULT_PMBASE + GPE0_STS, TCOSCI_STS);
145
146 /* enable acpi tco scis */
147 reg16 = inw(DEFAULT_PMBASE + GPE0_EN);
148 reg16 |= TCOSCI_EN;
149 outw(DEFAULT_PMBASE + GPE0_EN, reg16);
150}
151
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100152static void gma_func0_init(struct device *dev)
153{
154 u32 reg32;
155
156 /* IGD needs to be Bus Master */
157 reg32 = pci_read_config32(dev, PCI_COMMAND);
158 reg32 |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
159 pci_write_config32(dev, PCI_COMMAND, reg32);
160
Arthur Heymansf266dc62019-10-01 22:02:31 +0200161 gtt_res = find_resource(dev, PCI_BASE_ADDRESS_0);
162 if (!gtt_res || !gtt_res->base)
163 return;
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100164
Arthur Heymans38750f82019-10-03 09:34:57 +0200165 if (!acpi_is_wakeup_s3() &&
166 CONFIG(MAINBOARD_USE_LIBGFXINIT)) {
Angel Pons95de2312020-02-17 13:08:53 +0100167 struct northbridge_intel_ironlake_config *conf = dev->chip_info;
Arthur Heymans4c2f26c2018-07-17 16:59:38 +0200168 int lightup_ok;
169 printk(BIOS_SPEW, "Initializing VGA without OPROM.");
Vladimir Serbinenko13157302014-02-19 22:18:08 +0100170
Arthur Heymans4c2f26c2018-07-17 16:59:38 +0200171 gma_gfxinit(&lightup_ok);
Nico Huberd4ebeaf2017-05-22 13:49:22 +0200172 /* Linux relies on VBT for panel info. */
173 generate_fake_intel_oprom(&conf->gfx, dev,
174 "$VBT IRONLAKE-MOBILE");
175 } else {
176 /* PCI Init, will run VBIOS */
177 pci_dev_init(dev);
Vladimir Serbinenko13157302014-02-19 22:18:08 +0100178 }
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100179
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100180 /* Post VBIOS init */
181 gma_pm_init_post_vbios(dev);
Patrick Rudolph64a702f2017-06-20 18:28:56 +0200182
183 gma_enable_swsci();
184 intel_gma_restore_opregion();
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100185}
186
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100187static void gma_read_resources(struct device *dev)
188{
189 pci_dev_read_resources(dev);
190
191 struct resource *res;
192
193 /* Set the graphics memory to write combining. */
194 res = find_resource(dev, PCI_BASE_ADDRESS_2);
195 if (res == NULL) {
196 printk(BIOS_DEBUG, "gma: memory resource not found.\n");
197 return;
198 }
199 res->flags |= IORESOURCE_RESERVE | IORESOURCE_FIXED | IORESOURCE_ASSIGNED;
Elyes HAOUAScf5430f2016-09-13 21:27:22 +0200200 pci_write_config32(dev, PCI_BASE_ADDRESS_2, 0xd0000001);
201 pci_write_config32(dev, PCI_BASE_ADDRESS_2 + 4, 0);
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100202 res->base = (resource_t) 0xd0000000;
203 res->size = (resource_t) 0x10000000;
204}
205
Matt DeVillier6b059ea2020-03-30 19:31:54 -0500206static void gma_generate_ssdt(struct device *device)
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100207{
Matt DeVillier6b059ea2020-03-30 19:31:54 -0500208 const struct northbridge_intel_ironlake_config *chip = device->chip_info;
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100209
Matt DeVillier6b059ea2020-03-30 19:31:54 -0500210 drivers_intel_gma_displays_ssdt_generate(&chip->gfx);
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100211}
212
Patrick Rudolph2be28402017-04-12 16:54:55 +0200213static unsigned long
214gma_write_acpi_tables(struct device *const dev,
215 unsigned long current,
216 struct acpi_rsdp *const rsdp)
217{
Patrick Rudolph5c820262017-05-17 19:39:12 +0200218 igd_opregion_t *opregion = (igd_opregion_t *)current;
Patrick Rudolph2be28402017-04-12 16:54:55 +0200219 global_nvs_t *gnvs;
220
Matt DeVillierebe08e02017-07-14 13:28:42 -0500221 if (intel_gma_init_igd_opregion(opregion) != CB_SUCCESS)
Patrick Rudolph5c820262017-05-17 19:39:12 +0200222 return current;
223
224 current += sizeof(igd_opregion_t);
225
226 /* GNVS has been already set up */
227 gnvs = cbmem_find(CBMEM_ID_ACPI_GNVS);
228 if (gnvs) {
229 /* IGD OpRegion Base Address */
Patrick Rudolph19c2ad82017-06-30 14:52:01 +0200230 gma_set_gnvs_aslb(gnvs, (uintptr_t)opregion);
Patrick Rudolph5c820262017-05-17 19:39:12 +0200231 } else {
232 printk(BIOS_ERR, "Error: GNVS table not found.\n");
Patrick Rudolph2be28402017-04-12 16:54:55 +0200233 }
234
Patrick Rudolph5c820262017-05-17 19:39:12 +0200235 current = acpi_align_current(current);
Patrick Rudolph2be28402017-04-12 16:54:55 +0200236 return current;
237}
238
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100239static struct pci_operations gma_pci_ops = {
Subrata Banik4a0f0712019-03-20 14:29:47 +0530240 .set_subsystem = pci_dev_set_subsystem,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100241};
242
243static struct device_operations gma_func0_ops = {
Matt DeVillier6b059ea2020-03-30 19:31:54 -0500244 .read_resources = gma_read_resources,
245 .set_resources = pci_dev_set_resources,
246 .enable_resources = pci_dev_enable_resources,
247 .acpi_fill_ssdt = gma_generate_ssdt,
248 .init = gma_func0_init,
Matt DeVillier6b059ea2020-03-30 19:31:54 -0500249 .ops_pci = &gma_pci_ops,
Patrick Rudolph2be28402017-04-12 16:54:55 +0200250 .write_acpi_tables = gma_write_acpi_tables,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100251};
252
Elyes HAOUAScf5430f2016-09-13 21:27:22 +0200253static const unsigned short pci_device_ids[] = {
254 0x0046, 0x0102, 0x0106, 0x010a, 0x0112,
Vladimir Serbinenkoc6f6be02013-11-12 22:32:08 +0100255 0x0116, 0x0122, 0x0126, 0x0156,
256 0x0166,
257 0
258};
259
260static const struct pci_driver gma __pci_driver = {
261 .ops = &gma_func0_ops,
262 .vendor = PCI_VENDOR_ID_INTEL,
263 .devices = pci_device_ids,
264};