blob: 5335fbb0774ebf8a6cbc9059549860cec7984061 [file] [log] [blame]
Vladimir Serbinenko6481e102014-08-10 23:48:11 +02001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2011 Chromium OS Authors
5 * Copyright (C) 2013 Vladimir Serbinenko
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Vladimir Serbinenko6481e102014-08-10 23:48:11 +020015 */
16
17#include <arch/io.h>
18#include <console/console.h>
19#include <delay.h>
20#include <device/device.h>
21#include <device/pci.h>
22#include <device/pci_ids.h>
23#include <string.h>
24#include <device/pci_ops.h>
Arthur Heymansc51522f2016-08-27 01:09:19 +020025#include <commonlib/helpers.h>
Patrick Rudolphf6aa7d92017-09-29 18:28:23 +020026#include <cbmem.h>
27#include <southbridge/intel/i82801ix/nvs.h>
Vladimir Serbinenko6481e102014-08-10 23:48:11 +020028
29#include "drivers/intel/gma/i915_reg.h"
30#include "chip.h"
31#include "gm45.h"
Vladimir Serbinenko88010112014-08-16 03:35:33 +020032#include <drivers/intel/gma/intel_bios.h>
33#include <drivers/intel/gma/edid.h>
34#include <drivers/intel/gma/i915.h>
Patrick Rudolphf6aa7d92017-09-29 18:28:23 +020035#include <drivers/intel/gma/opregion.h>
Vladimir Serbinenko88010112014-08-16 03:35:33 +020036#include <pc80/vga.h>
37#include <pc80/vga_io.h>
Nico Huberf2dd0492017-10-29 15:42:44 +010038#include <drivers/intel/gma/libgfxinit.h>
Vladimir Serbinenko88010112014-08-16 03:35:33 +020039
Arthur Heymansfe3eabc2016-09-26 08:44:46 +020040#define BASE_FREQUENCY 96000
Arthur Heymansc51522f2016-08-27 01:09:19 +020041
Vladimir Serbinenko6481e102014-08-10 23:48:11 +020042static struct resource *gtt_res = NULL;
43
Nico Huberb851cc62016-01-09 23:27:16 +010044u32 gtt_read(u32 reg)
45{
46 return read32(res2mmio(gtt_res, reg, 0));
47}
48
Vladimir Serbinenko88010112014-08-16 03:35:33 +020049void gtt_write(u32 reg, u32 data)
Vladimir Serbinenko6481e102014-08-10 23:48:11 +020050{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080051 write32(res2mmio(gtt_res, reg, 0), data);
Vladimir Serbinenko6481e102014-08-10 23:48:11 +020052}
53
Patrick Rudolphf6aa7d92017-09-29 18:28:23 +020054uintptr_t gma_get_gnvs_aslb(const void *gnvs)
55{
56 const global_nvs_t *gnvs_ptr = gnvs;
57 return (uintptr_t)(gnvs_ptr ? gnvs_ptr->aslb : 0);
58}
59
60void gma_set_gnvs_aslb(void *gnvs, uintptr_t aslb)
61{
62 global_nvs_t *gnvs_ptr = gnvs;
63 if (gnvs_ptr)
64 gnvs_ptr->aslb = aslb;
65}
66
Arthur Heymansde6ad832016-08-22 17:58:46 +020067static void gma_init_lvds(const struct northbridge_intel_gm45_config *info,
Arthur Heymans53485d22017-04-30 08:29:54 +020068 u8 *mmio, u32 physbase, u16 piobase, u32 lfb,
69 struct edid *edid)
Vladimir Serbinenko88010112014-08-16 03:35:33 +020070{
Vladimir Serbinenko88010112014-08-16 03:35:33 +020071 int i;
Audrey Pearsonbd0dab22015-09-29 12:36:52 -050072 struct edid_mode *mode;
Vladimir Serbinenko88010112014-08-16 03:35:33 +020073 u32 hactive, vactive, right_border, bottom_border;
74 int hpolarity, vpolarity;
75 u32 vsync, hsync, vblank, hblank, hfront_porch, vfront_porch;
Arthur Heymansfe3eabc2016-09-26 08:44:46 +020076 u32 smallest_err = 0xffffffff;
Vladimir Serbinenko88010112014-08-16 03:35:33 +020077 u32 target_frequency;
78 u32 pixel_p1 = 1;
79 u32 pixel_n = 1;
80 u32 pixel_m1 = 1;
81 u32 pixel_m2 = 1;
Arthur Heymansfe3eabc2016-09-26 08:44:46 +020082 u32 pixel_p2;
Vladimir Serbinenko88010112014-08-16 03:35:33 +020083
84 vga_gr_write(0x18, 0);
85
86 /* Setup GTT. */
87 for (i = 0; i < 0x2000; i++)
88 {
89 outl((i << 2) | 1, piobase);
90 outl(physbase + (i << 12) + 1, piobase + 4);
91 }
92
Timothy Pearson61942de2015-04-06 21:54:56 -050093 write32(mmio + ADPA, 0x40008c18);
Vladimir Serbinenko88010112014-08-16 03:35:33 +020094 write32(mmio + 0x7041c, 0x0);
Timothy Pearson61942de2015-04-06 21:54:56 -050095 write32(mmio + _DPLL_B_MD, 0x3);
Vladimir Serbinenko88010112014-08-16 03:35:33 +020096
97 vga_misc_write(0x67);
98
99 const u8 cr[] = { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
100 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
101 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
102 0xff
103 };
104 vga_cr_write(0x11, 0);
105
106 for (i = 0; i <= 0x18; i++)
107 vga_cr_write(i, cr[i]);
108
Arthur Heymansde6ad832016-08-22 17:58:46 +0200109 /* Disable screen memory to prevent garbage from appearing. */
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200110 vga_sr_write(1, vga_sr_read(1) | 0x20);
111
Arthur Heymans53485d22017-04-30 08:29:54 +0200112 mode = &edid->mode;
113
114 hactive = edid->x_resolution;
115 vactive = edid->y_resolution;
Audrey Pearsonbd0dab22015-09-29 12:36:52 -0500116 right_border = mode->hborder;
117 bottom_border = mode->vborder;
118 hpolarity = (mode->phsync == '-');
119 vpolarity = (mode->pvsync == '-');
120 vsync = mode->vspw;
121 hsync = mode->hspw;
122 vblank = mode->vbl;
123 hblank = mode->hbl;
124 hfront_porch = mode->hso;
125 vfront_porch = mode->vso;
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200126
Nico Huber6d8266b2017-05-20 16:46:01 +0200127 if (IS_ENABLED(CONFIG_LINEAR_FRAMEBUFFER)) {
Nico Huberee352cd2016-01-09 23:15:53 +0100128 vga_sr_write(1, 1);
129 vga_sr_write(0x2, 0xf);
130 vga_sr_write(0x3, 0x0);
131 vga_sr_write(0x4, 0xe);
132 vga_gr_write(0, 0x0);
133 vga_gr_write(1, 0x0);
134 vga_gr_write(2, 0x0);
135 vga_gr_write(3, 0x0);
136 vga_gr_write(4, 0x0);
137 vga_gr_write(5, 0x0);
138 vga_gr_write(6, 0x5);
139 vga_gr_write(7, 0xf);
140 vga_gr_write(0x10, 0x1);
141 vga_gr_write(0x11, 0);
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200142
Arthur Heymans53485d22017-04-30 08:29:54 +0200143 edid->bytes_per_line = (edid->bytes_per_line + 63) & ~63;
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200144
Nico Huberee352cd2016-01-09 23:15:53 +0100145 write32(mmio + DSPCNTR(0), DISPPLANE_BGRX888);
146 write32(mmio + DSPADDR(0), 0);
Arthur Heymans53485d22017-04-30 08:29:54 +0200147 write32(mmio + DSPSTRIDE(0), edid->bytes_per_line);
Nico Huberee352cd2016-01-09 23:15:53 +0100148 write32(mmio + DSPSURF(0), 0);
149 for (i = 0; i < 0x100; i++)
150 write32(mmio + LGC_PALETTE(0) + 4 * i, i * 0x010101);
151 } else {
152 vga_textmode_init();
153 }
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200154
Arthur Heymansfe3eabc2016-09-26 08:44:46 +0200155 target_frequency = mode->pixel_clock;
156 /*
157 * p2 divisor must 7 for dual channel LVDS
158 * and 14 for single channel LVDS
159 */
160 pixel_p2 = mode->lvds_dual_channel ? 7 : 14;
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200161
Arthur Heymansfe3eabc2016-09-26 08:44:46 +0200162 /*
163 * Find suitable divisors, m1, m2, p1, n.
164 * refclock * (5 * (m1 + 2) + (m1 + 2)) / (n + 2) / p1 / p2
165 * should be closest to target frequency as possible
166 */
167 u32 candn, candm1, candm2, candp1;
168 for (candn = 1; candn <= 3; candn++) {
169 for (candm1 = 23; candm1 >= 17; candm1--) {
170 for (candm2 = 11; candm2 >= 5; candm2--) {
171 for (candp1 = mode->lvds_dual_channel ? 6 : 8;
172 candp1 >= 2; candp1--) {
173 u32 m = 5 * (candm1 + 2) + (candm2 + 2);
174 u32 p = candp1 * pixel_p2;
175 u32 vco = DIV_ROUND_CLOSEST(BASE_FREQUENCY * m, candn + 2);
176 u32 dot = DIV_ROUND_CLOSEST(vco, p);
Arthur Heymans75f91312016-10-12 01:04:28 +0200177 u32 this_err = MAX(dot, target_frequency) -
178 MIN(dot, target_frequency);
Arthur Heymansfe3eabc2016-09-26 08:44:46 +0200179 if (this_err < smallest_err) {
180 smallest_err = this_err;
181 pixel_n = candn;
182 pixel_m1 = candm1;
183 pixel_m2 = candm2;
184 pixel_p1 = candp1;
185 }
186 }
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200187 }
188 }
189 }
190
Arthur Heymansfe3eabc2016-09-26 08:44:46 +0200191 if (smallest_err == 0xffffffff) {
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200192 printk (BIOS_ERR, "Couldn't find GFX clock divisors\n");
193 return;
194 }
195
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200196 printk(BIOS_INFO, "bringing up panel at resolution %d x %d\n",
197 hactive, vactive);
198 printk(BIOS_DEBUG, "Borders %d x %d\n",
199 right_border, bottom_border);
200 printk(BIOS_DEBUG, "Blank %d x %d\n",
201 hblank, vblank);
202 printk(BIOS_DEBUG, "Sync %d x %d\n",
203 hsync, vsync);
204 printk(BIOS_DEBUG, "Front porch %d x %d\n",
205 hfront_porch, vfront_porch);
Vladimir Serbinenkoa71bdc32014-08-30 00:35:39 +0200206 printk(BIOS_DEBUG, (info->gfx.use_spread_spectrum_clock
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200207 ? "Spread spectrum clock\n" : "DREF clock\n"));
208 printk(BIOS_DEBUG,
Vladimir Serbinenko551cff02015-10-10 23:58:08 +0200209 mode->lvds_dual_channel ? "Dual channel\n" : "Single channel\n");
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200210 printk(BIOS_DEBUG, "Polarities %d, %d\n",
211 hpolarity, vpolarity);
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200212 printk(BIOS_DEBUG, "Pixel N=%d, M1=%d, M2=%d, P1=%d\n",
213 pixel_n, pixel_m1, pixel_m2, pixel_p1);
214 printk(BIOS_DEBUG, "Pixel clock %d kHz\n",
Arthur Heymans1f060282017-01-19 16:45:45 +0100215 BASE_FREQUENCY * (5 * (pixel_m1 + 2) + (pixel_m2 + 2)) /
216 (pixel_n + 2) / (pixel_p1 * pixel_p2));
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200217
218 write32(mmio + LVDS,
219 (hpolarity << 20) | (vpolarity << 21)
Vladimir Serbinenko551cff02015-10-10 23:58:08 +0200220 | (mode->lvds_dual_channel ? LVDS_CLOCK_B_POWERUP_ALL
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200221 | LVDS_CLOCK_BOTH_POWERUP_ALL : 0)
Arthur Heymans8ba20102016-08-15 00:04:34 +0200222 | LVDS_ENABLE_DITHER
223 | LVDS_CLOCK_A_POWERUP_ALL
224 | LVDS_PIPE(0));
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200225 mdelay(1);
226 write32(mmio + PP_CONTROL, PANEL_UNLOCK_REGS
227 | (read32(mmio + PP_CONTROL) & ~PANEL_UNLOCK_MASK));
228 write32(mmio + FP0(0),
Arthur Heymansfe3eabc2016-09-26 08:44:46 +0200229 (pixel_n << 16)
230 | (pixel_m1 << 8) | (pixel_m2));
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200231 write32(mmio + DPLL(0),
232 DPLL_VCO_ENABLE | DPLLB_MODE_LVDS
Arthur Heymans8ba20102016-08-15 00:04:34 +0200233 | DPLL_VGA_MODE_DIS
Vladimir Serbinenko551cff02015-10-10 23:58:08 +0200234 | (mode->lvds_dual_channel ? DPLLB_LVDS_P2_CLOCK_DIV_7
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200235 : DPLLB_LVDS_P2_CLOCK_DIV_14)
236 | (0x10000 << (pixel_p1 - 1))
Vladimir Serbinenkoa71bdc32014-08-30 00:35:39 +0200237 | ((info->gfx.use_spread_spectrum_clock ? 3 : 0) << 13)
Arthur Heymans8ba20102016-08-15 00:04:34 +0200238 | (6 << PLL_LOAD_PULSE_PHASE_SHIFT));
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200239 mdelay(1);
240 write32(mmio + DPLL(0),
241 DPLL_VCO_ENABLE | DPLLB_MODE_LVDS
Arthur Heymans8ba20102016-08-15 00:04:34 +0200242 | DPLL_VGA_MODE_DIS
Vladimir Serbinenko551cff02015-10-10 23:58:08 +0200243 | (mode->lvds_dual_channel ? DPLLB_LVDS_P2_CLOCK_DIV_7
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200244 : DPLLB_LVDS_P2_CLOCK_DIV_14)
245 | (0x10000 << (pixel_p1 - 1))
Vladimir Serbinenkoa71bdc32014-08-30 00:35:39 +0200246 | ((info->gfx.use_spread_spectrum_clock ? 3 : 0) << 13)
Arthur Heymans8ba20102016-08-15 00:04:34 +0200247 | (6 << PLL_LOAD_PULSE_PHASE_SHIFT));
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200248 /* Re-lock the registers. */
249 write32(mmio + PP_CONTROL,
250 (read32(mmio + PP_CONTROL) & ~PANEL_UNLOCK_MASK));
251
252 write32(mmio + LVDS,
253 (hpolarity << 20) | (vpolarity << 21)
Vladimir Serbinenko551cff02015-10-10 23:58:08 +0200254 | (mode->lvds_dual_channel ? LVDS_CLOCK_B_POWERUP_ALL
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200255 | LVDS_CLOCK_BOTH_POWERUP_ALL : 0)
Arthur Heymans8ba20102016-08-15 00:04:34 +0200256 | LVDS_CLOCK_A_POWERUP_ALL
257 | LVDS_ENABLE_DITHER
258 | LVDS_PIPE(0));
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200259
260 write32(mmio + HTOTAL(0),
261 ((hactive + right_border + hblank - 1) << 16)
262 | (hactive - 1));
263 write32(mmio + HBLANK(0),
264 ((hactive + right_border + hblank - 1) << 16)
265 | (hactive + right_border - 1));
266 write32(mmio + HSYNC(0),
267 ((hactive + right_border + hfront_porch + hsync - 1) << 16)
268 | (hactive + right_border + hfront_porch - 1));
269
270 write32(mmio + VTOTAL(0), ((vactive + bottom_border + vblank - 1) << 16)
271 | (vactive - 1));
272 write32(mmio + VBLANK(0), ((vactive + bottom_border + vblank - 1) << 16)
273 | (vactive + bottom_border - 1));
274 write32(mmio + VSYNC(0),
Arthur Heymans8ba20102016-08-15 00:04:34 +0200275 ((vactive + bottom_border + vfront_porch + vsync - 1) << 16)
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200276 | (vactive + bottom_border + vfront_porch - 1));
277
278 write32(mmio + PIPECONF(0), PIPECONF_DISABLE);
279
280 write32(mmio + PF_WIN_POS(0), 0);
Nico Huber6d8266b2017-05-20 16:46:01 +0200281 if (IS_ENABLED(CONFIG_LINEAR_FRAMEBUFFER)) {
Nico Huberee352cd2016-01-09 23:15:53 +0100282 write32(mmio + PIPESRC(0), ((hactive - 1) << 16)
283 | (vactive - 1));
284 write32(mmio + PF_CTL(0), 0);
285 write32(mmio + PF_WIN_SZ(0), 0);
Arthur Heymans8ba20102016-08-15 00:04:34 +0200286 write32(mmio + PFIT_CONTROL, 0);
Nico Huberee352cd2016-01-09 23:15:53 +0100287 } else {
288 write32(mmio + PIPESRC(0), (639 << 16) | 399);
289 write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
290 write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
Nick High1e302cb2016-04-26 17:22:05 -0400291 write32(mmio + PFIT_CONTROL, 0x80000000);
Nico Huberee352cd2016-01-09 23:15:53 +0100292 }
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200293
294 mdelay(1);
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200295 write32(mmio + PIPECONF(0), PIPECONF_BPP_6);
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200296 write32(mmio + PIPECONF(0), PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
297 write32(mmio + PIPECONF(0), PIPECONF_ENABLE | PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
298
Nico Huber6d8266b2017-05-20 16:46:01 +0200299 if (IS_ENABLED(CONFIG_LINEAR_FRAMEBUFFER)) {
Arthur Heymans8ba20102016-08-15 00:04:34 +0200300 write32(mmio + VGACNTRL, VGA_DISP_DISABLE);
Nico Huberee352cd2016-01-09 23:15:53 +0100301 write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
302 | DISPPLANE_BGRX888);
303 mdelay(1);
304 } else {
Nick High1e302cb2016-04-26 17:22:05 -0400305 write32(mmio + VGACNTRL, 0xc4008e);
Nico Huberee352cd2016-01-09 23:15:53 +0100306 }
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200307
Arthur Heymans8ba20102016-08-15 00:04:34 +0200308 write32(mmio + LVDS, LVDS_PORT_ENABLE
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200309 | (hpolarity << 20) | (vpolarity << 21)
Vladimir Serbinenko551cff02015-10-10 23:58:08 +0200310 | (mode->lvds_dual_channel ? LVDS_CLOCK_B_POWERUP_ALL
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200311 | LVDS_CLOCK_BOTH_POWERUP_ALL : 0)
Arthur Heymans8ba20102016-08-15 00:04:34 +0200312 | LVDS_CLOCK_A_POWERUP_ALL
313 | LVDS_ENABLE_DITHER
314 | LVDS_PIPE(0));
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200315
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200316 write32(mmio + PP_CONTROL, PANEL_POWER_ON | PANEL_POWER_RESET);
317
318 /* Enable screen memory. */
319 vga_sr_write(1, vga_sr_read(1) & ~0x20);
320
321 /* Clear interrupts. */
322 write32(mmio + DEIIR, 0xffffffff);
323 write32(mmio + SDEIIR, 0xffffffff);
324
Nico Huber6d8266b2017-05-20 16:46:01 +0200325 if (IS_ENABLED(CONFIG_LINEAR_FRAMEBUFFER)) {
Nico Huberee352cd2016-01-09 23:15:53 +0100326 memset((void *) lfb, 0,
Arthur Heymans53485d22017-04-30 08:29:54 +0200327 edid->x_resolution * edid->y_resolution * 4);
328 set_vbe_mode_info_valid(edid, lfb);
Nico Huberee352cd2016-01-09 23:15:53 +0100329 }
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200330}
331
Arthur Heymansde6ad832016-08-22 17:58:46 +0200332static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
Arthur Heymans53485d22017-04-30 08:29:54 +0200333 u8 *mmio, u32 physbase, u16 piobase, u32 lfb,
334 struct edid *edid)
Arthur Heymansde6ad832016-08-22 17:58:46 +0200335{
336
337 int i;
Arthur Heymansc51522f2016-08-27 01:09:19 +0200338 struct edid_mode *mode;
339 u32 hactive, vactive, right_border, bottom_border;
340 int hpolarity, vpolarity;
341 u32 vsync, hsync, vblank, hblank, hfront_porch, vfront_porch;
342 u32 target_frequency;
343 u32 smallest_err = 0xffffffff;
344 u32 pixel_p1 = 1;
Arthur Heymans063cd5f2016-10-12 00:05:00 +0200345 u32 pixel_p2;
Arthur Heymansc51522f2016-08-27 01:09:19 +0200346 u32 pixel_n = 1;
347 u32 pixel_m1 = 1;
348 u32 pixel_m2 = 1;
Arthur Heymansde6ad832016-08-22 17:58:46 +0200349
350 vga_gr_write(0x18, 0);
351
Arthur Heymansc51522f2016-08-27 01:09:19 +0200352 /* Set up GTT. */
353 for (i = 0; i < 0x2000; i++) {
354 outl((i << 2) | 1, piobase);
355 outl(physbase + (i << 12) + 1, piobase + 4);
356 }
357
358
Arthur Heymansde6ad832016-08-22 17:58:46 +0200359 write32(mmio + VGA0, 0x31108);
360 write32(mmio + VGA1, 0x31406);
361
362 write32(mmio + ADPA, ADPA_DAC_ENABLE
363 | ADPA_PIPE_A_SELECT
364 | ADPA_CRT_HOTPLUG_MONITOR_COLOR
365 | ADPA_CRT_HOTPLUG_ENABLE
366 | ADPA_USE_VGA_HVPOLARITY
367 | ADPA_VSYNC_CNTL_ENABLE
368 | ADPA_HSYNC_CNTL_ENABLE
Arthur Heymansc51522f2016-08-27 01:09:19 +0200369 | ADPA_DPMS_ON);
Arthur Heymansde6ad832016-08-22 17:58:46 +0200370
371 write32(mmio + 0x7041c, 0x0);
372 write32(mmio + DPLL_MD(0), 0x3);
373 write32(mmio + DPLL_MD(1), 0x3);
374
375 vga_misc_write(0x67);
376
377 const u8 cr[] = { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
378 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
379 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
380 0xff
381 };
382 vga_cr_write(0x11, 0);
383
384 for (i = 0; i <= 0x18; i++)
385 vga_cr_write(i, cr[i]);
386
Arthur Heymansc51522f2016-08-27 01:09:19 +0200387 udelay(1);
388
Arthur Heymansde6ad832016-08-22 17:58:46 +0200389 /* Disable screen memory to prevent garbage from appearing. */
390 vga_sr_write(1, vga_sr_read(1) | 0x20);
391
Arthur Heymans53485d22017-04-30 08:29:54 +0200392 mode = &edid->mode;
393
394 hactive = edid->x_resolution;
395 vactive = edid->y_resolution;
Arthur Heymansc51522f2016-08-27 01:09:19 +0200396 right_border = mode->hborder;
397 bottom_border = mode->vborder;
398 hpolarity = (mode->phsync == '-');
399 vpolarity = (mode->pvsync == '-');
400 vsync = mode->vspw;
401 hsync = mode->hspw;
402 vblank = mode->vbl;
403 hblank = mode->hbl;
404 hfront_porch = mode->hso;
405 vfront_porch = mode->vso;
406 target_frequency = mode->pixel_clock;
407
Nico Huber6d8266b2017-05-20 16:46:01 +0200408 if (IS_ENABLED(CONFIG_LINEAR_FRAMEBUFFER)) {
Arthur Heymansc51522f2016-08-27 01:09:19 +0200409 vga_sr_write(1, 1);
410 vga_sr_write(0x2, 0xf);
411 vga_sr_write(0x3, 0x0);
412 vga_sr_write(0x4, 0xe);
413 vga_gr_write(0, 0x0);
414 vga_gr_write(1, 0x0);
415 vga_gr_write(2, 0x0);
416 vga_gr_write(3, 0x0);
417 vga_gr_write(4, 0x0);
418 vga_gr_write(5, 0x0);
419 vga_gr_write(6, 0x5);
420 vga_gr_write(7, 0xf);
421 vga_gr_write(0x10, 0x1);
422 vga_gr_write(0x11, 0);
423
Arthur Heymans53485d22017-04-30 08:29:54 +0200424 edid->bytes_per_line = (edid->bytes_per_line + 63) & ~63;
Arthur Heymansc51522f2016-08-27 01:09:19 +0200425
426 write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
427 | DISPPLANE_BGRX888);
428 write32(mmio + DSPADDR(0), 0);
Arthur Heymans53485d22017-04-30 08:29:54 +0200429 write32(mmio + DSPSTRIDE(0), edid->bytes_per_line);
Arthur Heymansc51522f2016-08-27 01:09:19 +0200430 write32(mmio + DSPSURF(0), 0);
431 for (i = 0; i < 0x100; i++)
432 write32(mmio + LGC_PALETTE(0) + 4 * i, i * 0x010101);
433 } else {
434 vga_textmode_init();
435 }
436
Arthur Heymans063cd5f2016-10-12 00:05:00 +0200437 pixel_p2 = target_frequency <= 225000 ? 10 : 5;
438
Arthur Heymansc51522f2016-08-27 01:09:19 +0200439 u32 candn, candm1, candm2, candp1;
440 for (candn = 1; candn <= 4; candn++) {
441 for (candm1 = 23; candm1 >= 17; candm1--) {
442 for (candm2 = 11; candm2 >= 5; candm2--) {
443 for (candp1 = 8; candp1 >= 1; candp1--) {
444 u32 m = 5 * (candm1 + 2) + (candm2 + 2);
Arthur Heymans063cd5f2016-10-12 00:05:00 +0200445 u32 p = candp1 * pixel_p2;
Arthur Heymansfe3eabc2016-09-26 08:44:46 +0200446 u32 vco = DIV_ROUND_CLOSEST(BASE_FREQUENCY * m, candn + 2);
Arthur Heymansc51522f2016-08-27 01:09:19 +0200447 u32 dot = DIV_ROUND_CLOSEST(vco, p);
Arthur Heymans75f91312016-10-12 01:04:28 +0200448 u32 this_err = MAX(dot, target_frequency) -
449 MIN(dot, target_frequency);
Arthur Heymansc51522f2016-08-27 01:09:19 +0200450 if (this_err < smallest_err) {
451 smallest_err= this_err;
452 pixel_n = candn;
453 pixel_m1 = candm1;
454 pixel_m2 = candm2;
455 pixel_p1 = candp1;
456 }
457 }
458 }
459 }
460 }
461
462 if (smallest_err == 0xffffffff) {
463 printk(BIOS_ERR, "Error: Couldn't find GFX clock divisors\n");
464 return;
465 }
466
Arthur Heymansc51522f2016-08-27 01:09:19 +0200467 printk(BIOS_INFO, "Bringing up panel at resolution %d x %d\n",
468 hactive, vactive);
469 printk(BIOS_SPEW, "Borders %d x %d\n",
470 right_border, bottom_border);
471 printk(BIOS_SPEW, "Blank %d x %d\n",
472 hblank, vblank);
473 printk(BIOS_SPEW, "Sync %d x %d\n",
474 hsync, vsync);
475 printk(BIOS_SPEW, "Front porch %d x %d\n",
476 hfront_porch, vfront_porch);
477 printk(BIOS_SPEW, (info->gfx.use_spread_spectrum_clock
478 ? "Spread spectrum clock\n" : "DREF clock\n"));
479 printk(BIOS_SPEW, "Polarities %d, %d\n",
480 hpolarity, vpolarity);
Arthur Heymans063cd5f2016-10-12 00:05:00 +0200481 printk(BIOS_SPEW, "Pixel N=%d, M1=%d, M2=%d, P1=%d, P2=%d\n",
482 pixel_n, pixel_m1, pixel_m2, pixel_p1, pixel_p2);
Arthur Heymansc51522f2016-08-27 01:09:19 +0200483 printk(BIOS_SPEW, "Pixel clock %d kHz\n",
Arthur Heymans1f060282017-01-19 16:45:45 +0100484 BASE_FREQUENCY * (5 * (pixel_m1 + 2) + (pixel_m2 + 2)) /
485 (pixel_n + 2) / (pixel_p1 * pixel_p2));
Arthur Heymansde6ad832016-08-22 17:58:46 +0200486
487 mdelay(1);
Arthur Heymansc51522f2016-08-27 01:09:19 +0200488 write32(mmio + FP0(0), (pixel_n << 16)
489 | (pixel_m1 << 8) | pixel_m2);
490 write32(mmio + DPLL(0), DPLL_VCO_ENABLE
491 | DPLL_VGA_MODE_DIS | DPLLB_MODE_DAC_SERIAL
Arthur Heymans063cd5f2016-10-12 00:05:00 +0200492 | (pixel_p2 == 10 ? DPLL_DAC_SERIAL_P2_CLOCK_DIV_10 :
493 DPLL_DAC_SERIAL_P2_CLOCK_DIV_5)
Arthur Heymansc51522f2016-08-27 01:09:19 +0200494 | (0x10000 << (pixel_p1 - 1))
495 | (6 << 9));
496
Arthur Heymansde6ad832016-08-22 17:58:46 +0200497 mdelay(1);
Arthur Heymansc51522f2016-08-27 01:09:19 +0200498 write32(mmio + DPLL(0), DPLL_VCO_ENABLE
499 | DPLL_VGA_MODE_DIS | DPLLB_MODE_DAC_SERIAL
Arthur Heymans063cd5f2016-10-12 00:05:00 +0200500 | (pixel_p2 == 10 ? DPLL_DAC_SERIAL_P2_CLOCK_DIV_10 :
501 DPLL_DAC_SERIAL_P2_CLOCK_DIV_5)
Arthur Heymansc51522f2016-08-27 01:09:19 +0200502 | (0x10000 << (pixel_p1 - 1))
503 | (6 << 9));
Arthur Heymansde6ad832016-08-22 17:58:46 +0200504
505 write32(mmio + ADPA, ADPA_DAC_ENABLE
506 | ADPA_PIPE_A_SELECT
507 | ADPA_CRT_HOTPLUG_MONITOR_COLOR
508 | ADPA_CRT_HOTPLUG_ENABLE
Arthur Heymansde6ad832016-08-22 17:58:46 +0200509 | ADPA_VSYNC_CNTL_ENABLE
510 | ADPA_HSYNC_CNTL_ENABLE
511 | ADPA_DPMS_ON
Arthur Heymansc51522f2016-08-27 01:09:19 +0200512 | (vpolarity ? ADPA_VSYNC_ACTIVE_LOW :
513 ADPA_VSYNC_ACTIVE_HIGH)
514 | (hpolarity ? ADPA_HSYNC_ACTIVE_LOW :
515 ADPA_HSYNC_ACTIVE_HIGH));
Arthur Heymansde6ad832016-08-22 17:58:46 +0200516
517 write32(mmio + HTOTAL(0),
Arthur Heymansc51522f2016-08-27 01:09:19 +0200518 ((hactive + right_border + hblank - 1) << 16)
Arthur Heymansde6ad832016-08-22 17:58:46 +0200519 | (hactive - 1));
520 write32(mmio + HBLANK(0),
Arthur Heymansc51522f2016-08-27 01:09:19 +0200521 ((hactive + right_border + hblank - 1) << 16)
522 | (hactive + right_border - 1));
Arthur Heymansde6ad832016-08-22 17:58:46 +0200523 write32(mmio + HSYNC(0),
Arthur Heymansc51522f2016-08-27 01:09:19 +0200524 ((hactive + right_border + hfront_porch + hsync - 1) << 16)
525 | (hactive + right_border + hfront_porch - 1));
Arthur Heymansde6ad832016-08-22 17:58:46 +0200526
Arthur Heymansc51522f2016-08-27 01:09:19 +0200527 write32(mmio + VTOTAL(0), ((vactive + bottom_border + vblank - 1) << 16)
Arthur Heymansde6ad832016-08-22 17:58:46 +0200528 | (vactive - 1));
Arthur Heymansc51522f2016-08-27 01:09:19 +0200529 write32(mmio + VBLANK(0), ((vactive + bottom_border + vblank - 1) << 16)
530 | (vactive + bottom_border - 1));
Arthur Heymansde6ad832016-08-22 17:58:46 +0200531 write32(mmio + VSYNC(0),
Arthur Heymansc51522f2016-08-27 01:09:19 +0200532 ((vactive + bottom_border + vfront_porch + vsync - 1) << 16)
533 | (vactive + bottom_border + vfront_porch - 1));
Arthur Heymansde6ad832016-08-22 17:58:46 +0200534
535 write32(mmio + PIPECONF(0), PIPECONF_DISABLE);
536
537 write32(mmio + PF_WIN_POS(0), 0);
Nico Huber6d8266b2017-05-20 16:46:01 +0200538 if (IS_ENABLED(CONFIG_LINEAR_FRAMEBUFFER)) {
Arthur Heymansc51522f2016-08-27 01:09:19 +0200539 write32(mmio + PIPESRC(0), ((hactive - 1) << 16)
540 | (vactive - 1));
541 write32(mmio + PF_CTL(0), 0);
542 write32(mmio + PF_WIN_SZ(0), 0);
543 write32(mmio + PFIT_CONTROL, 0);
544 } else {
545 write32(mmio + PIPESRC(0), (639 << 16) | 399);
546 write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
547 write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
548 write32(mmio + PFIT_CONTROL, 0x80000000);
549 }
Arthur Heymansde6ad832016-08-22 17:58:46 +0200550
551 mdelay(1);
Arthur Heymansc51522f2016-08-27 01:09:19 +0200552 write32(mmio + PIPECONF(0), PIPECONF_BPP_6);
Arthur Heymansc51522f2016-08-27 01:09:19 +0200553 write32(mmio + PIPECONF(0), PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
Arthur Heymansde6ad832016-08-22 17:58:46 +0200554 write32(mmio + PIPECONF(0), PIPECONF_ENABLE
555 | PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
556
Nico Huber6d8266b2017-05-20 16:46:01 +0200557 if (IS_ENABLED(CONFIG_LINEAR_FRAMEBUFFER)) {
Arthur Heymansc51522f2016-08-27 01:09:19 +0200558 write32(mmio + VGACNTRL, VGA_DISP_DISABLE);
559 write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
560 | DISPPLANE_BGRX888);
561 mdelay(1);
562 } else {
563 write32(mmio + VGACNTRL, 0xc4008e);
564 }
Arthur Heymansde6ad832016-08-22 17:58:46 +0200565
566 write32(mmio + ADPA, ADPA_DAC_ENABLE
567 | ADPA_PIPE_A_SELECT
568 | ADPA_CRT_HOTPLUG_MONITOR_COLOR
569 | ADPA_CRT_HOTPLUG_ENABLE
Arthur Heymansde6ad832016-08-22 17:58:46 +0200570 | ADPA_VSYNC_CNTL_ENABLE
571 | ADPA_HSYNC_CNTL_ENABLE
572 | ADPA_DPMS_ON
Arthur Heymansc51522f2016-08-27 01:09:19 +0200573 | (vpolarity ? ADPA_VSYNC_ACTIVE_LOW :
574 ADPA_VSYNC_ACTIVE_HIGH)
575 | (hpolarity ? ADPA_HSYNC_ACTIVE_LOW :
576 ADPA_HSYNC_ACTIVE_HIGH));
Arthur Heymansde6ad832016-08-22 17:58:46 +0200577
Arthur Heymansc51522f2016-08-27 01:09:19 +0200578 write32(mmio + PP_CONTROL, PANEL_POWER_ON | PANEL_POWER_RESET);
Arthur Heymansde6ad832016-08-22 17:58:46 +0200579
Arthur Heymansc51522f2016-08-27 01:09:19 +0200580 /* Enable screen memory. */
Arthur Heymansde6ad832016-08-22 17:58:46 +0200581 vga_sr_write(1, vga_sr_read(1) & ~0x20);
582
583 /* Clear interrupts. */
584 write32(mmio + DEIIR, 0xffffffff);
585 write32(mmio + SDEIIR, 0xffffffff);
Arthur Heymansc51522f2016-08-27 01:09:19 +0200586
Nico Huber6d8266b2017-05-20 16:46:01 +0200587 if (IS_ENABLED(CONFIG_LINEAR_FRAMEBUFFER)) {
Arthur Heymansc51522f2016-08-27 01:09:19 +0200588 memset((void *) lfb, 0,
Arthur Heymans53485d22017-04-30 08:29:54 +0200589 edid->x_resolution * edid->y_resolution * 4);
590 set_vbe_mode_info_valid(edid, lfb);
Arthur Heymansc51522f2016-08-27 01:09:19 +0200591 }
592
593
Arthur Heymansde6ad832016-08-22 17:58:46 +0200594}
595
Arthur Heymans53485d22017-04-30 08:29:54 +0200596static void gma_ngi(struct device *const dev, struct edid *edid_lvds)
Arthur Heymansde6ad832016-08-22 17:58:46 +0200597{
Arthur Heymans53485d22017-04-30 08:29:54 +0200598 u8 edid_data_vga[128];
599 struct edid edid_vga;
600 int vga_edid_status;
601 u8 *mmio;
602 struct northbridge_intel_gm45_config *conf = dev->chip_info;
603
604 mmio = res2mmio(gtt_res, 0, 0);
605 printk(BIOS_DEBUG, "VGA EDID\n");
Arthur Heymans8da22862017-08-06 15:56:30 +0200606 intel_gmbus_read_edid(mmio + GMBUS0, GMBUS_PORT_VGADDC, 0x50,
607 edid_data_vga, sizeof(edid_data_vga));
Arthur Heymansc51522f2016-08-27 01:09:19 +0200608 intel_gmbus_stop(mmio + GMBUS0);
Arthur Heymans53485d22017-04-30 08:29:54 +0200609 vga_edid_status = decode_edid(edid_data_vga,
610 sizeof(edid_data_vga), &edid_vga);
611
612 u32 physbase;
613 struct resource *lfb_res;
614 struct resource *pio_res;
615
616 lfb_res = find_resource(dev, PCI_BASE_ADDRESS_2);
617 pio_res = find_resource(dev, PCI_BASE_ADDRESS_4);
618
619 physbase = pci_read_config32(dev, 0x5c) & ~0xf;
620
621 if (!(physbase && pio_res && pio_res->base && lfb_res && lfb_res->base))
622 return;
623
624 printk(BIOS_SPEW, "Initializing display without OPROM. MMIO 0x%llx\n",
625 gtt_res->base);
626 if (vga_edid_status != EDID_ABSENT) {
627 printk(BIOS_DEBUG, "Initialising display on VGA output\n");
628 gma_init_vga(conf, mmio, physbase, pio_res->base, lfb_res->base,
629 &edid_vga);
630 } else {
631 printk(BIOS_DEBUG, "Initialising display on LVDS output\n");
632 gma_init_lvds(conf, mmio, physbase, pio_res->base,
633 lfb_res->base, edid_lvds);
Arthur Heymansde6ad832016-08-22 17:58:46 +0200634 }
Arthur Heymans53485d22017-04-30 08:29:54 +0200635
636 /* Linux relies on VBT for panel info. */
637 generate_fake_intel_oprom(&conf->gfx, dev, "$VBT CANTIGA");
Arthur Heymansde6ad832016-08-22 17:58:46 +0200638}
639
Nico Huberd85a71a2016-11-27 14:43:12 +0100640static u32 get_cdclk(struct device *const dev)
641{
642 const u16 cdclk_sel =
643 pci_read_config16 (dev, GCFGC_OFFSET) & GCFGC_CD_MASK;
644 switch (MCHBAR8(HPLLVCO_MCHBAR) & 0x7) {
645 case VCO_2666:
646 case VCO_4000:
647 case VCO_5333:
648 return cdclk_sel ? 333333333 : 222222222;
649 case VCO_3200:
650 return cdclk_sel ? 320000000 : 228571429;
651 default:
652 printk(BIOS_WARNING,
653 "Unknown VCO frequency, using default cdclk.\n");
654 return 222222222;
655 }
656}
657
Arthur Heymans12bed262016-11-24 13:23:05 +0100658static u32 freq_to_blc_pwm_ctl(struct device *const dev,
659 u16 pwm_freq, u8 duty_perc)
660{
661 u32 blc_mod;
662
663 blc_mod = get_cdclk(dev) / (128 * pwm_freq);
664
665 if (duty_perc <= 100)
666 return (blc_mod << 16) | (blc_mod * duty_perc / 100);
667 else
668 return (blc_mod << 16) | blc_mod;
669}
670
Arthur Heymans20cb85f2017-04-29 14:31:32 +0200671static void gma_pm_init_post_vbios(struct device *const dev,
672 const char *edid_ascii_string)
Nico Huberb851cc62016-01-09 23:27:16 +0100673{
674 const struct northbridge_intel_gm45_config *const conf = dev->chip_info;
675
676 u32 reg32;
Arthur Heymans12bed262016-11-24 13:23:05 +0100677 u8 reg8;
Arthur Heymans20cb85f2017-04-29 14:31:32 +0200678 const struct blc_pwm_t *blc_pwm;
679 int blc_array_len, i;
680 u16 pwm_freq = 0;
Nico Huberb851cc62016-01-09 23:27:16 +0100681
682 /* Setup Panel Power On Delays */
683 reg32 = gtt_read(PP_ON_DELAYS);
684 if (!reg32) {
685 reg32 = (conf->gpu_panel_power_up_delay & 0x1fff) << 16;
686 reg32 |= (conf->gpu_panel_power_backlight_on_delay & 0x1fff);
687 gtt_write(PP_ON_DELAYS, reg32);
688 }
689
690 /* Setup Panel Power Off Delays */
691 reg32 = gtt_read(PP_OFF_DELAYS);
692 if (!reg32) {
693 reg32 = (conf->gpu_panel_power_down_delay & 0x1fff) << 16;
694 reg32 |= (conf->gpu_panel_power_backlight_off_delay & 0x1fff);
695 gtt_write(PP_OFF_DELAYS, reg32);
696 }
697
698 /* Setup Panel Power Cycle Delay */
699 if (conf->gpu_panel_power_cycle_delay) {
Nico Huberd85a71a2016-11-27 14:43:12 +0100700 reg32 = (get_cdclk(dev) / 20000 - 1)
701 << PP_REFERENCE_DIVIDER_SHIFT;
Nico Huberb851cc62016-01-09 23:27:16 +0100702 reg32 |= conf->gpu_panel_power_cycle_delay & 0x1f;
703 gtt_write(PP_DIVISOR, reg32);
704 }
705
706 /* Enable Backlight */
707 gtt_write(BLC_PWM_CTL2, (1 << 31));
Arthur Heymans12bed262016-11-24 13:23:05 +0100708 reg8 = 100;
709 if (conf->duty_cycle != 0)
710 reg8 = conf->duty_cycle;
Arthur Heymans20cb85f2017-04-29 14:31:32 +0200711 blc_array_len = get_blc_values(&blc_pwm);
712 if (conf->default_pwm_freq != 0)
713 pwm_freq = conf->default_pwm_freq;
714
715 /* Find EDID string and pwm freq in lookup table */
716 for (i = 0; i < blc_array_len; i++) {
717 if (!strncmp(blc_pwm[i].ascii_string, edid_ascii_string,
718 strlen(blc_pwm[i].ascii_string))) {
719 pwm_freq = blc_pwm[i].pwm_freq;
720 printk(BIOS_DEBUG, "Found EDID string: %s in lookup table, pwm: %dHz\n",
721 blc_pwm[i].ascii_string, pwm_freq);
722 break;
723 }
724 }
725
726 if (i == blc_array_len)
727 printk(BIOS_NOTICE, "Your panels EDID `%s` wasn't found in the"
728 "lookup table.\n You may have issues with your panels"
729 "backlight.\n If you want to help improving coreboot"
730 "please report: this EDID string\n and the result"
731 "of `intel_read read BLC_PWM_CTL`"
732 "(from intel-gpu-tools)\n while running vendor BIOS\n",
733 edid_ascii_string);
734
735 if (pwm_freq == 0)
Nico Huberb851cc62016-01-09 23:27:16 +0100736 gtt_write(BLC_PWM_CTL, 0x06100610);
737 else
Arthur Heymans20cb85f2017-04-29 14:31:32 +0200738 gtt_write(BLC_PWM_CTL, freq_to_blc_pwm_ctl(dev, pwm_freq,
739 reg8));
Nico Huberb851cc62016-01-09 23:27:16 +0100740}
741
Vladimir Serbinenko6481e102014-08-10 23:48:11 +0200742static void gma_func0_init(struct device *dev)
743{
744 u32 reg32;
Arthur Heymans53485d22017-04-30 08:29:54 +0200745 u8 *mmio;
746 u8 edid_data_lvds[128];
747 struct edid edid_lvds;
Vladimir Serbinenko6481e102014-08-10 23:48:11 +0200748
749 /* IGD needs to be Bus Master */
750 reg32 = pci_read_config32(dev, PCI_COMMAND);
751 reg32 |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
752 pci_write_config32(dev, PCI_COMMAND, reg32);
753
Vladimir Serbinenko6481e102014-08-10 23:48:11 +0200754 gtt_res = find_resource(dev, PCI_BASE_ADDRESS_0);
Arthur Heymans53485d22017-04-30 08:29:54 +0200755 if (gtt_res == NULL)
756 return;
757 mmio = res2mmio(gtt_res, 0, 0);
Timothy Pearsone7f70902015-04-06 22:01:23 -0500758
Nico Huberee352cd2016-01-09 23:15:53 +0100759 if (!IS_ENABLED(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT)) {
760 /* PCI Init, will run VBIOS */
Arthur Heymans53485d22017-04-30 08:29:54 +0200761 printk(BIOS_DEBUG, "Initialising IGD using VBIOS\n");
Nico Huberee352cd2016-01-09 23:15:53 +0100762 pci_dev_init(dev);
Nico Huberb851cc62016-01-09 23:27:16 +0100763 }
764
Arthur Heymans53485d22017-04-30 08:29:54 +0200765 printk(BIOS_DEBUG, "LVDS EDID\n");
Arthur Heymans8da22862017-08-06 15:56:30 +0200766 intel_gmbus_read_edid(mmio + GMBUS0, GMBUS_PORT_PANEL, 0x50,
767 edid_data_lvds, sizeof(edid_data_lvds));
Arthur Heymans53485d22017-04-30 08:29:54 +0200768 intel_gmbus_stop(mmio + GMBUS0);
769 decode_edid(edid_data_lvds, sizeof(edid_data_lvds), &edid_lvds);
770
Nico Huberb851cc62016-01-09 23:27:16 +0100771 /* Post VBIOS init */
Arthur Heymans20cb85f2017-04-29 14:31:32 +0200772 gma_pm_init_post_vbios(dev, edid_lvds.ascii_string);
Nico Huberb851cc62016-01-09 23:27:16 +0100773
Arthur Heymanse6c8f7e2018-08-09 11:31:51 +0200774 int vga_disable = (pci_read_config16(dev, D0F0_GGC) & 2) >> 1;
775
776 if (vga_disable) {
777 printk(BIOS_INFO,
778 "IGD is not decoding legacy VGA MEM and IO: skipping NATIVE graphic init\n");
779 } else {
780 if (IS_ENABLED(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT)) {
781 gma_ngi(dev, &edid_lvds);
782 } else if (IS_ENABLED(CONFIG_MAINBOARD_USE_LIBGFXINIT)) {
783 int lightup_ok;
784 gma_gfxinit(&lightup_ok);
785 }
Nico Huberf2dd0492017-10-29 15:42:44 +0100786 }
Patrick Rudolphf6aa7d92017-09-29 18:28:23 +0200787
788 intel_gma_restore_opregion();
Vladimir Serbinenko6481e102014-08-10 23:48:11 +0200789}
790
Elyes HAOUAS6dcdaaf2018-02-09 07:44:31 +0100791static void gma_set_subsystem(struct device *dev, unsigned vendor, unsigned device)
Vladimir Serbinenko6481e102014-08-10 23:48:11 +0200792{
793 if (!vendor || !device) {
794 pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID,
795 pci_read_config32(dev, PCI_VENDOR_ID));
796 } else {
797 pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID,
798 ((device & 0xffff) << 16) | (vendor &
799 0xffff));
800 }
801}
802
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100803const struct i915_gpu_controller_info *
804intel_gma_get_controller_info(void)
805{
Elyes HAOUAS6dcdaaf2018-02-09 07:44:31 +0100806 struct device *dev = dev_find_slot(0, PCI_DEVFN(0x2,0));
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100807 if (!dev) {
808 return NULL;
809 }
810 struct northbridge_intel_gm45_config *chip = dev->chip_info;
811 return &chip->gfx;
812}
813
Elyes HAOUAS6dcdaaf2018-02-09 07:44:31 +0100814static void gma_ssdt(struct device *device)
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100815{
816 const struct i915_gpu_controller_info *gfx = intel_gma_get_controller_info();
817 if (!gfx) {
818 return;
819 }
820
821 drivers_intel_gma_displays_ssdt_generate(gfx);
822}
823
Patrick Rudolphf6aa7d92017-09-29 18:28:23 +0200824static unsigned long
825gma_write_acpi_tables(struct device *const dev,
826 unsigned long current,
827 struct acpi_rsdp *const rsdp)
828{
829 igd_opregion_t *opregion = (igd_opregion_t *)current;
830 global_nvs_t *gnvs;
831
832 if (intel_gma_init_igd_opregion(opregion) != CB_SUCCESS)
833 return current;
834
835 current += sizeof(igd_opregion_t);
836
837 /* GNVS has been already set up */
838 gnvs = cbmem_find(CBMEM_ID_ACPI_GNVS);
839 if (gnvs) {
840 /* IGD OpRegion Base Address */
841 gma_set_gnvs_aslb(gnvs, (uintptr_t)opregion);
842 } else {
843 printk(BIOS_ERR, "Error: GNVS table not found.\n");
844 }
845
846 current = acpi_align_current(current);
847 return current;
848}
849
850static const char *gma_acpi_name(const struct device *dev)
851{
852 return "GFX0";
853}
854
Vladimir Serbinenko6481e102014-08-10 23:48:11 +0200855static struct pci_operations gma_pci_ops = {
856 .set_subsystem = gma_set_subsystem,
857};
858
859static struct device_operations gma_func0_ops = {
860 .read_resources = pci_dev_read_resources,
861 .set_resources = pci_dev_set_resources,
862 .enable_resources = pci_dev_enable_resources,
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100863 .acpi_fill_ssdt_generator = gma_ssdt,
Vladimir Serbinenko6481e102014-08-10 23:48:11 +0200864 .init = gma_func0_init,
865 .scan_bus = 0,
866 .enable = 0,
867 .ops_pci = &gma_pci_ops,
Patrick Rudolphf6aa7d92017-09-29 18:28:23 +0200868 .acpi_name = gma_acpi_name,
869 .write_acpi_tables = gma_write_acpi_tables,
Vladimir Serbinenko6481e102014-08-10 23:48:11 +0200870};
871
872static const unsigned short pci_device_ids[] =
873{
874 0x2a42, 0
875};
876
877static const struct pci_driver gma __pci_driver = {
878 .ops = &gma_func0_ops,
879 .vendor = PCI_VENDOR_ID_INTEL,
880 .devices = pci_device_ids,
881};