blob: 24046712b4cc87a24ddc2a848be14e34d40ba09d [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>
25#include <cpu/x86/msr.h>
26#include <cpu/x86/mtrr.h>
Arthur Heymansc51522f2016-08-27 01:09:19 +020027#include <commonlib/helpers.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>
35#include <pc80/vga.h>
36#include <pc80/vga_io.h>
37
Arthur Heymansfe3eabc2016-09-26 08:44:46 +020038#define BASE_FREQUENCY 96000
Arthur Heymansc51522f2016-08-27 01:09:19 +020039
Vladimir Serbinenko6481e102014-08-10 23:48:11 +020040static struct resource *gtt_res = NULL;
41
Nico Huberb851cc62016-01-09 23:27:16 +010042u32 gtt_read(u32 reg)
43{
44 return read32(res2mmio(gtt_res, reg, 0));
45}
46
Vladimir Serbinenko88010112014-08-16 03:35:33 +020047void gtt_write(u32 reg, u32 data)
Vladimir Serbinenko6481e102014-08-10 23:48:11 +020048{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080049 write32(res2mmio(gtt_res, reg, 0), data);
Vladimir Serbinenko6481e102014-08-10 23:48:11 +020050}
51
Arthur Heymansde6ad832016-08-22 17:58:46 +020052static void gma_init_lvds(const struct northbridge_intel_gm45_config *info,
Arthur Heymans53485d22017-04-30 08:29:54 +020053 u8 *mmio, u32 physbase, u16 piobase, u32 lfb,
54 struct edid *edid)
Vladimir Serbinenko88010112014-08-16 03:35:33 +020055{
Vladimir Serbinenko88010112014-08-16 03:35:33 +020056 int i;
Audrey Pearsonbd0dab22015-09-29 12:36:52 -050057 struct edid_mode *mode;
Vladimir Serbinenko88010112014-08-16 03:35:33 +020058 u32 hactive, vactive, right_border, bottom_border;
59 int hpolarity, vpolarity;
60 u32 vsync, hsync, vblank, hblank, hfront_porch, vfront_porch;
Arthur Heymansfe3eabc2016-09-26 08:44:46 +020061 u32 smallest_err = 0xffffffff;
Vladimir Serbinenko88010112014-08-16 03:35:33 +020062 u32 target_frequency;
63 u32 pixel_p1 = 1;
64 u32 pixel_n = 1;
65 u32 pixel_m1 = 1;
66 u32 pixel_m2 = 1;
Arthur Heymansfe3eabc2016-09-26 08:44:46 +020067 u32 pixel_p2;
Vladimir Serbinenko88010112014-08-16 03:35:33 +020068
69 vga_gr_write(0x18, 0);
70
71 /* Setup GTT. */
72 for (i = 0; i < 0x2000; i++)
73 {
74 outl((i << 2) | 1, piobase);
75 outl(physbase + (i << 12) + 1, piobase + 4);
76 }
77
Timothy Pearson61942de2015-04-06 21:54:56 -050078 write32(mmio + ADPA, 0x40008c18);
Vladimir Serbinenko88010112014-08-16 03:35:33 +020079 write32(mmio + 0x7041c, 0x0);
Timothy Pearson61942de2015-04-06 21:54:56 -050080 write32(mmio + _DPLL_B_MD, 0x3);
Vladimir Serbinenko88010112014-08-16 03:35:33 +020081
82 vga_misc_write(0x67);
83
84 const u8 cr[] = { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
85 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
86 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
87 0xff
88 };
89 vga_cr_write(0x11, 0);
90
91 for (i = 0; i <= 0x18; i++)
92 vga_cr_write(i, cr[i]);
93
Arthur Heymansde6ad832016-08-22 17:58:46 +020094 /* Disable screen memory to prevent garbage from appearing. */
Vladimir Serbinenko88010112014-08-16 03:35:33 +020095 vga_sr_write(1, vga_sr_read(1) | 0x20);
96
Arthur Heymans53485d22017-04-30 08:29:54 +020097 mode = &edid->mode;
98
99 hactive = edid->x_resolution;
100 vactive = edid->y_resolution;
Audrey Pearsonbd0dab22015-09-29 12:36:52 -0500101 right_border = mode->hborder;
102 bottom_border = mode->vborder;
103 hpolarity = (mode->phsync == '-');
104 vpolarity = (mode->pvsync == '-');
105 vsync = mode->vspw;
106 hsync = mode->hspw;
107 vblank = mode->vbl;
108 hblank = mode->hbl;
109 hfront_porch = mode->hso;
110 vfront_porch = mode->vso;
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200111
Nico Huber6d8266b2017-05-20 16:46:01 +0200112 if (IS_ENABLED(CONFIG_LINEAR_FRAMEBUFFER)) {
Nico Huberee352cd2016-01-09 23:15:53 +0100113 vga_sr_write(1, 1);
114 vga_sr_write(0x2, 0xf);
115 vga_sr_write(0x3, 0x0);
116 vga_sr_write(0x4, 0xe);
117 vga_gr_write(0, 0x0);
118 vga_gr_write(1, 0x0);
119 vga_gr_write(2, 0x0);
120 vga_gr_write(3, 0x0);
121 vga_gr_write(4, 0x0);
122 vga_gr_write(5, 0x0);
123 vga_gr_write(6, 0x5);
124 vga_gr_write(7, 0xf);
125 vga_gr_write(0x10, 0x1);
126 vga_gr_write(0x11, 0);
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200127
Arthur Heymans53485d22017-04-30 08:29:54 +0200128 edid->bytes_per_line = (edid->bytes_per_line + 63) & ~63;
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200129
Nico Huberee352cd2016-01-09 23:15:53 +0100130 write32(mmio + DSPCNTR(0), DISPPLANE_BGRX888);
131 write32(mmio + DSPADDR(0), 0);
Arthur Heymans53485d22017-04-30 08:29:54 +0200132 write32(mmio + DSPSTRIDE(0), edid->bytes_per_line);
Nico Huberee352cd2016-01-09 23:15:53 +0100133 write32(mmio + DSPSURF(0), 0);
134 for (i = 0; i < 0x100; i++)
135 write32(mmio + LGC_PALETTE(0) + 4 * i, i * 0x010101);
136 } else {
137 vga_textmode_init();
138 }
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200139
Arthur Heymansfe3eabc2016-09-26 08:44:46 +0200140 target_frequency = mode->pixel_clock;
141 /*
142 * p2 divisor must 7 for dual channel LVDS
143 * and 14 for single channel LVDS
144 */
145 pixel_p2 = mode->lvds_dual_channel ? 7 : 14;
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200146
Arthur Heymansfe3eabc2016-09-26 08:44:46 +0200147 /*
148 * Find suitable divisors, m1, m2, p1, n.
149 * refclock * (5 * (m1 + 2) + (m1 + 2)) / (n + 2) / p1 / p2
150 * should be closest to target frequency as possible
151 */
152 u32 candn, candm1, candm2, candp1;
153 for (candn = 1; candn <= 3; candn++) {
154 for (candm1 = 23; candm1 >= 17; candm1--) {
155 for (candm2 = 11; candm2 >= 5; candm2--) {
156 for (candp1 = mode->lvds_dual_channel ? 6 : 8;
157 candp1 >= 2; candp1--) {
158 u32 m = 5 * (candm1 + 2) + (candm2 + 2);
159 u32 p = candp1 * pixel_p2;
160 u32 vco = DIV_ROUND_CLOSEST(BASE_FREQUENCY * m, candn + 2);
161 u32 dot = DIV_ROUND_CLOSEST(vco, p);
Arthur Heymans75f91312016-10-12 01:04:28 +0200162 u32 this_err = MAX(dot, target_frequency) -
163 MIN(dot, target_frequency);
Arthur Heymansfe3eabc2016-09-26 08:44:46 +0200164 if (this_err < smallest_err) {
165 smallest_err = this_err;
166 pixel_n = candn;
167 pixel_m1 = candm1;
168 pixel_m2 = candm2;
169 pixel_p1 = candp1;
170 }
171 }
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200172 }
173 }
174 }
175
Arthur Heymansfe3eabc2016-09-26 08:44:46 +0200176 if (smallest_err == 0xffffffff) {
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200177 printk (BIOS_ERR, "Couldn't find GFX clock divisors\n");
178 return;
179 }
180
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200181 printk(BIOS_INFO, "bringing up panel at resolution %d x %d\n",
182 hactive, vactive);
183 printk(BIOS_DEBUG, "Borders %d x %d\n",
184 right_border, bottom_border);
185 printk(BIOS_DEBUG, "Blank %d x %d\n",
186 hblank, vblank);
187 printk(BIOS_DEBUG, "Sync %d x %d\n",
188 hsync, vsync);
189 printk(BIOS_DEBUG, "Front porch %d x %d\n",
190 hfront_porch, vfront_porch);
Vladimir Serbinenkoa71bdc32014-08-30 00:35:39 +0200191 printk(BIOS_DEBUG, (info->gfx.use_spread_spectrum_clock
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200192 ? "Spread spectrum clock\n" : "DREF clock\n"));
193 printk(BIOS_DEBUG,
Vladimir Serbinenko551cff02015-10-10 23:58:08 +0200194 mode->lvds_dual_channel ? "Dual channel\n" : "Single channel\n");
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200195 printk(BIOS_DEBUG, "Polarities %d, %d\n",
196 hpolarity, vpolarity);
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200197 printk(BIOS_DEBUG, "Pixel N=%d, M1=%d, M2=%d, P1=%d\n",
198 pixel_n, pixel_m1, pixel_m2, pixel_p1);
199 printk(BIOS_DEBUG, "Pixel clock %d kHz\n",
Arthur Heymans1f060282017-01-19 16:45:45 +0100200 BASE_FREQUENCY * (5 * (pixel_m1 + 2) + (pixel_m2 + 2)) /
201 (pixel_n + 2) / (pixel_p1 * pixel_p2));
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200202
203 write32(mmio + LVDS,
204 (hpolarity << 20) | (vpolarity << 21)
Vladimir Serbinenko551cff02015-10-10 23:58:08 +0200205 | (mode->lvds_dual_channel ? LVDS_CLOCK_B_POWERUP_ALL
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200206 | LVDS_CLOCK_BOTH_POWERUP_ALL : 0)
Arthur Heymans8ba20102016-08-15 00:04:34 +0200207 | LVDS_ENABLE_DITHER
208 | LVDS_CLOCK_A_POWERUP_ALL
209 | LVDS_PIPE(0));
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200210 mdelay(1);
211 write32(mmio + PP_CONTROL, PANEL_UNLOCK_REGS
212 | (read32(mmio + PP_CONTROL) & ~PANEL_UNLOCK_MASK));
213 write32(mmio + FP0(0),
Arthur Heymansfe3eabc2016-09-26 08:44:46 +0200214 (pixel_n << 16)
215 | (pixel_m1 << 8) | (pixel_m2));
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200216 write32(mmio + DPLL(0),
217 DPLL_VCO_ENABLE | DPLLB_MODE_LVDS
Arthur Heymans8ba20102016-08-15 00:04:34 +0200218 | DPLL_VGA_MODE_DIS
Vladimir Serbinenko551cff02015-10-10 23:58:08 +0200219 | (mode->lvds_dual_channel ? DPLLB_LVDS_P2_CLOCK_DIV_7
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200220 : DPLLB_LVDS_P2_CLOCK_DIV_14)
221 | (0x10000 << (pixel_p1 - 1))
Vladimir Serbinenkoa71bdc32014-08-30 00:35:39 +0200222 | ((info->gfx.use_spread_spectrum_clock ? 3 : 0) << 13)
Arthur Heymans8ba20102016-08-15 00:04:34 +0200223 | (6 << PLL_LOAD_PULSE_PHASE_SHIFT));
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200224 mdelay(1);
225 write32(mmio + DPLL(0),
226 DPLL_VCO_ENABLE | DPLLB_MODE_LVDS
Arthur Heymans8ba20102016-08-15 00:04:34 +0200227 | DPLL_VGA_MODE_DIS
Vladimir Serbinenko551cff02015-10-10 23:58:08 +0200228 | (mode->lvds_dual_channel ? DPLLB_LVDS_P2_CLOCK_DIV_7
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200229 : DPLLB_LVDS_P2_CLOCK_DIV_14)
230 | (0x10000 << (pixel_p1 - 1))
Vladimir Serbinenkoa71bdc32014-08-30 00:35:39 +0200231 | ((info->gfx.use_spread_spectrum_clock ? 3 : 0) << 13)
Arthur Heymans8ba20102016-08-15 00:04:34 +0200232 | (6 << PLL_LOAD_PULSE_PHASE_SHIFT));
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200233 /* Re-lock the registers. */
234 write32(mmio + PP_CONTROL,
235 (read32(mmio + PP_CONTROL) & ~PANEL_UNLOCK_MASK));
236
237 write32(mmio + LVDS,
238 (hpolarity << 20) | (vpolarity << 21)
Vladimir Serbinenko551cff02015-10-10 23:58:08 +0200239 | (mode->lvds_dual_channel ? LVDS_CLOCK_B_POWERUP_ALL
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200240 | LVDS_CLOCK_BOTH_POWERUP_ALL : 0)
Arthur Heymans8ba20102016-08-15 00:04:34 +0200241 | LVDS_CLOCK_A_POWERUP_ALL
242 | LVDS_ENABLE_DITHER
243 | LVDS_PIPE(0));
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200244
245 write32(mmio + HTOTAL(0),
246 ((hactive + right_border + hblank - 1) << 16)
247 | (hactive - 1));
248 write32(mmio + HBLANK(0),
249 ((hactive + right_border + hblank - 1) << 16)
250 | (hactive + right_border - 1));
251 write32(mmio + HSYNC(0),
252 ((hactive + right_border + hfront_porch + hsync - 1) << 16)
253 | (hactive + right_border + hfront_porch - 1));
254
255 write32(mmio + VTOTAL(0), ((vactive + bottom_border + vblank - 1) << 16)
256 | (vactive - 1));
257 write32(mmio + VBLANK(0), ((vactive + bottom_border + vblank - 1) << 16)
258 | (vactive + bottom_border - 1));
259 write32(mmio + VSYNC(0),
Arthur Heymans8ba20102016-08-15 00:04:34 +0200260 ((vactive + bottom_border + vfront_porch + vsync - 1) << 16)
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200261 | (vactive + bottom_border + vfront_porch - 1));
262
263 write32(mmio + PIPECONF(0), PIPECONF_DISABLE);
264
265 write32(mmio + PF_WIN_POS(0), 0);
Nico Huber6d8266b2017-05-20 16:46:01 +0200266 if (IS_ENABLED(CONFIG_LINEAR_FRAMEBUFFER)) {
Nico Huberee352cd2016-01-09 23:15:53 +0100267 write32(mmio + PIPESRC(0), ((hactive - 1) << 16)
268 | (vactive - 1));
269 write32(mmio + PF_CTL(0), 0);
270 write32(mmio + PF_WIN_SZ(0), 0);
Arthur Heymans8ba20102016-08-15 00:04:34 +0200271 write32(mmio + PFIT_CONTROL, 0);
Nico Huberee352cd2016-01-09 23:15:53 +0100272 } else {
273 write32(mmio + PIPESRC(0), (639 << 16) | 399);
274 write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
275 write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
Nick High1e302cb2016-04-26 17:22:05 -0400276 write32(mmio + PFIT_CONTROL, 0x80000000);
Nico Huberee352cd2016-01-09 23:15:53 +0100277 }
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200278
279 mdelay(1);
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200280 write32(mmio + PIPECONF(0), PIPECONF_BPP_6);
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200281 write32(mmio + PIPECONF(0), PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
282 write32(mmio + PIPECONF(0), PIPECONF_ENABLE | PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
283
Nico Huber6d8266b2017-05-20 16:46:01 +0200284 if (IS_ENABLED(CONFIG_LINEAR_FRAMEBUFFER)) {
Arthur Heymans8ba20102016-08-15 00:04:34 +0200285 write32(mmio + VGACNTRL, VGA_DISP_DISABLE);
Nico Huberee352cd2016-01-09 23:15:53 +0100286 write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
287 | DISPPLANE_BGRX888);
288 mdelay(1);
289 } else {
Nick High1e302cb2016-04-26 17:22:05 -0400290 write32(mmio + VGACNTRL, 0xc4008e);
Nico Huberee352cd2016-01-09 23:15:53 +0100291 }
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200292
Arthur Heymans8ba20102016-08-15 00:04:34 +0200293 write32(mmio + LVDS, LVDS_PORT_ENABLE
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200294 | (hpolarity << 20) | (vpolarity << 21)
Vladimir Serbinenko551cff02015-10-10 23:58:08 +0200295 | (mode->lvds_dual_channel ? LVDS_CLOCK_B_POWERUP_ALL
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200296 | LVDS_CLOCK_BOTH_POWERUP_ALL : 0)
Arthur Heymans8ba20102016-08-15 00:04:34 +0200297 | LVDS_CLOCK_A_POWERUP_ALL
298 | LVDS_ENABLE_DITHER
299 | LVDS_PIPE(0));
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200300
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200301 write32(mmio + PP_CONTROL, PANEL_POWER_ON | PANEL_POWER_RESET);
302
303 /* Enable screen memory. */
304 vga_sr_write(1, vga_sr_read(1) & ~0x20);
305
306 /* Clear interrupts. */
307 write32(mmio + DEIIR, 0xffffffff);
308 write32(mmio + SDEIIR, 0xffffffff);
309
Nico Huber6d8266b2017-05-20 16:46:01 +0200310 if (IS_ENABLED(CONFIG_LINEAR_FRAMEBUFFER)) {
Nico Huberee352cd2016-01-09 23:15:53 +0100311 memset((void *) lfb, 0,
Arthur Heymans53485d22017-04-30 08:29:54 +0200312 edid->x_resolution * edid->y_resolution * 4);
313 set_vbe_mode_info_valid(edid, lfb);
Nico Huberee352cd2016-01-09 23:15:53 +0100314 }
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200315}
316
Arthur Heymansde6ad832016-08-22 17:58:46 +0200317static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
Arthur Heymans53485d22017-04-30 08:29:54 +0200318 u8 *mmio, u32 physbase, u16 piobase, u32 lfb,
319 struct edid *edid)
Arthur Heymansde6ad832016-08-22 17:58:46 +0200320{
321
322 int i;
Arthur Heymansc51522f2016-08-27 01:09:19 +0200323 struct edid_mode *mode;
324 u32 hactive, vactive, right_border, bottom_border;
325 int hpolarity, vpolarity;
326 u32 vsync, hsync, vblank, hblank, hfront_porch, vfront_porch;
327 u32 target_frequency;
328 u32 smallest_err = 0xffffffff;
329 u32 pixel_p1 = 1;
Arthur Heymans063cd5f2016-10-12 00:05:00 +0200330 u32 pixel_p2;
Arthur Heymansc51522f2016-08-27 01:09:19 +0200331 u32 pixel_n = 1;
332 u32 pixel_m1 = 1;
333 u32 pixel_m2 = 1;
Arthur Heymansde6ad832016-08-22 17:58:46 +0200334
335 vga_gr_write(0x18, 0);
336
Arthur Heymansc51522f2016-08-27 01:09:19 +0200337 /* Set up GTT. */
338 for (i = 0; i < 0x2000; i++) {
339 outl((i << 2) | 1, piobase);
340 outl(physbase + (i << 12) + 1, piobase + 4);
341 }
342
343
Arthur Heymansde6ad832016-08-22 17:58:46 +0200344 write32(mmio + VGA0, 0x31108);
345 write32(mmio + VGA1, 0x31406);
346
347 write32(mmio + ADPA, ADPA_DAC_ENABLE
348 | ADPA_PIPE_A_SELECT
349 | ADPA_CRT_HOTPLUG_MONITOR_COLOR
350 | ADPA_CRT_HOTPLUG_ENABLE
351 | ADPA_USE_VGA_HVPOLARITY
352 | ADPA_VSYNC_CNTL_ENABLE
353 | ADPA_HSYNC_CNTL_ENABLE
Arthur Heymansc51522f2016-08-27 01:09:19 +0200354 | ADPA_DPMS_ON);
Arthur Heymansde6ad832016-08-22 17:58:46 +0200355
356 write32(mmio + 0x7041c, 0x0);
357 write32(mmio + DPLL_MD(0), 0x3);
358 write32(mmio + DPLL_MD(1), 0x3);
359
360 vga_misc_write(0x67);
361
362 const u8 cr[] = { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
363 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
364 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
365 0xff
366 };
367 vga_cr_write(0x11, 0);
368
369 for (i = 0; i <= 0x18; i++)
370 vga_cr_write(i, cr[i]);
371
Arthur Heymansc51522f2016-08-27 01:09:19 +0200372 udelay(1);
373
Arthur Heymansde6ad832016-08-22 17:58:46 +0200374 /* Disable screen memory to prevent garbage from appearing. */
375 vga_sr_write(1, vga_sr_read(1) | 0x20);
376
Arthur Heymans53485d22017-04-30 08:29:54 +0200377 mode = &edid->mode;
378
379 hactive = edid->x_resolution;
380 vactive = edid->y_resolution;
Arthur Heymansc51522f2016-08-27 01:09:19 +0200381 right_border = mode->hborder;
382 bottom_border = mode->vborder;
383 hpolarity = (mode->phsync == '-');
384 vpolarity = (mode->pvsync == '-');
385 vsync = mode->vspw;
386 hsync = mode->hspw;
387 vblank = mode->vbl;
388 hblank = mode->hbl;
389 hfront_porch = mode->hso;
390 vfront_porch = mode->vso;
391 target_frequency = mode->pixel_clock;
392
Nico Huber6d8266b2017-05-20 16:46:01 +0200393 if (IS_ENABLED(CONFIG_LINEAR_FRAMEBUFFER)) {
Arthur Heymansc51522f2016-08-27 01:09:19 +0200394 vga_sr_write(1, 1);
395 vga_sr_write(0x2, 0xf);
396 vga_sr_write(0x3, 0x0);
397 vga_sr_write(0x4, 0xe);
398 vga_gr_write(0, 0x0);
399 vga_gr_write(1, 0x0);
400 vga_gr_write(2, 0x0);
401 vga_gr_write(3, 0x0);
402 vga_gr_write(4, 0x0);
403 vga_gr_write(5, 0x0);
404 vga_gr_write(6, 0x5);
405 vga_gr_write(7, 0xf);
406 vga_gr_write(0x10, 0x1);
407 vga_gr_write(0x11, 0);
408
Arthur Heymans53485d22017-04-30 08:29:54 +0200409 edid->bytes_per_line = (edid->bytes_per_line + 63) & ~63;
Arthur Heymansc51522f2016-08-27 01:09:19 +0200410
411 write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
412 | DISPPLANE_BGRX888);
413 write32(mmio + DSPADDR(0), 0);
Arthur Heymans53485d22017-04-30 08:29:54 +0200414 write32(mmio + DSPSTRIDE(0), edid->bytes_per_line);
Arthur Heymansc51522f2016-08-27 01:09:19 +0200415 write32(mmio + DSPSURF(0), 0);
416 for (i = 0; i < 0x100; i++)
417 write32(mmio + LGC_PALETTE(0) + 4 * i, i * 0x010101);
418 } else {
419 vga_textmode_init();
420 }
421
Arthur Heymans063cd5f2016-10-12 00:05:00 +0200422 pixel_p2 = target_frequency <= 225000 ? 10 : 5;
423
Arthur Heymansc51522f2016-08-27 01:09:19 +0200424 u32 candn, candm1, candm2, candp1;
425 for (candn = 1; candn <= 4; candn++) {
426 for (candm1 = 23; candm1 >= 17; candm1--) {
427 for (candm2 = 11; candm2 >= 5; candm2--) {
428 for (candp1 = 8; candp1 >= 1; candp1--) {
429 u32 m = 5 * (candm1 + 2) + (candm2 + 2);
Arthur Heymans063cd5f2016-10-12 00:05:00 +0200430 u32 p = candp1 * pixel_p2;
Arthur Heymansfe3eabc2016-09-26 08:44:46 +0200431 u32 vco = DIV_ROUND_CLOSEST(BASE_FREQUENCY * m, candn + 2);
Arthur Heymansc51522f2016-08-27 01:09:19 +0200432 u32 dot = DIV_ROUND_CLOSEST(vco, p);
Arthur Heymans75f91312016-10-12 01:04:28 +0200433 u32 this_err = MAX(dot, target_frequency) -
434 MIN(dot, target_frequency);
Arthur Heymansc51522f2016-08-27 01:09:19 +0200435 if (this_err < smallest_err) {
436 smallest_err= this_err;
437 pixel_n = candn;
438 pixel_m1 = candm1;
439 pixel_m2 = candm2;
440 pixel_p1 = candp1;
441 }
442 }
443 }
444 }
445 }
446
447 if (smallest_err == 0xffffffff) {
448 printk(BIOS_ERR, "Error: Couldn't find GFX clock divisors\n");
449 return;
450 }
451
Arthur Heymansc51522f2016-08-27 01:09:19 +0200452 printk(BIOS_INFO, "Bringing up panel at resolution %d x %d\n",
453 hactive, vactive);
454 printk(BIOS_SPEW, "Borders %d x %d\n",
455 right_border, bottom_border);
456 printk(BIOS_SPEW, "Blank %d x %d\n",
457 hblank, vblank);
458 printk(BIOS_SPEW, "Sync %d x %d\n",
459 hsync, vsync);
460 printk(BIOS_SPEW, "Front porch %d x %d\n",
461 hfront_porch, vfront_porch);
462 printk(BIOS_SPEW, (info->gfx.use_spread_spectrum_clock
463 ? "Spread spectrum clock\n" : "DREF clock\n"));
464 printk(BIOS_SPEW, "Polarities %d, %d\n",
465 hpolarity, vpolarity);
Arthur Heymans063cd5f2016-10-12 00:05:00 +0200466 printk(BIOS_SPEW, "Pixel N=%d, M1=%d, M2=%d, P1=%d, P2=%d\n",
467 pixel_n, pixel_m1, pixel_m2, pixel_p1, pixel_p2);
Arthur Heymansc51522f2016-08-27 01:09:19 +0200468 printk(BIOS_SPEW, "Pixel clock %d kHz\n",
Arthur Heymans1f060282017-01-19 16:45:45 +0100469 BASE_FREQUENCY * (5 * (pixel_m1 + 2) + (pixel_m2 + 2)) /
470 (pixel_n + 2) / (pixel_p1 * pixel_p2));
Arthur Heymansde6ad832016-08-22 17:58:46 +0200471
472 mdelay(1);
Arthur Heymansc51522f2016-08-27 01:09:19 +0200473 write32(mmio + FP0(0), (pixel_n << 16)
474 | (pixel_m1 << 8) | pixel_m2);
475 write32(mmio + DPLL(0), DPLL_VCO_ENABLE
476 | DPLL_VGA_MODE_DIS | DPLLB_MODE_DAC_SERIAL
Arthur Heymans063cd5f2016-10-12 00:05:00 +0200477 | (pixel_p2 == 10 ? DPLL_DAC_SERIAL_P2_CLOCK_DIV_10 :
478 DPLL_DAC_SERIAL_P2_CLOCK_DIV_5)
Arthur Heymansc51522f2016-08-27 01:09:19 +0200479 | (0x10000 << (pixel_p1 - 1))
480 | (6 << 9));
481
Arthur Heymansde6ad832016-08-22 17:58:46 +0200482 mdelay(1);
Arthur Heymansc51522f2016-08-27 01:09:19 +0200483 write32(mmio + DPLL(0), DPLL_VCO_ENABLE
484 | DPLL_VGA_MODE_DIS | DPLLB_MODE_DAC_SERIAL
Arthur Heymans063cd5f2016-10-12 00:05:00 +0200485 | (pixel_p2 == 10 ? DPLL_DAC_SERIAL_P2_CLOCK_DIV_10 :
486 DPLL_DAC_SERIAL_P2_CLOCK_DIV_5)
Arthur Heymansc51522f2016-08-27 01:09:19 +0200487 | (0x10000 << (pixel_p1 - 1))
488 | (6 << 9));
Arthur Heymansde6ad832016-08-22 17:58:46 +0200489
490 write32(mmio + ADPA, ADPA_DAC_ENABLE
491 | ADPA_PIPE_A_SELECT
492 | ADPA_CRT_HOTPLUG_MONITOR_COLOR
493 | ADPA_CRT_HOTPLUG_ENABLE
Arthur Heymansde6ad832016-08-22 17:58:46 +0200494 | ADPA_VSYNC_CNTL_ENABLE
495 | ADPA_HSYNC_CNTL_ENABLE
496 | ADPA_DPMS_ON
Arthur Heymansc51522f2016-08-27 01:09:19 +0200497 | (vpolarity ? ADPA_VSYNC_ACTIVE_LOW :
498 ADPA_VSYNC_ACTIVE_HIGH)
499 | (hpolarity ? ADPA_HSYNC_ACTIVE_LOW :
500 ADPA_HSYNC_ACTIVE_HIGH));
Arthur Heymansde6ad832016-08-22 17:58:46 +0200501
502 write32(mmio + HTOTAL(0),
Arthur Heymansc51522f2016-08-27 01:09:19 +0200503 ((hactive + right_border + hblank - 1) << 16)
Arthur Heymansde6ad832016-08-22 17:58:46 +0200504 | (hactive - 1));
505 write32(mmio + HBLANK(0),
Arthur Heymansc51522f2016-08-27 01:09:19 +0200506 ((hactive + right_border + hblank - 1) << 16)
507 | (hactive + right_border - 1));
Arthur Heymansde6ad832016-08-22 17:58:46 +0200508 write32(mmio + HSYNC(0),
Arthur Heymansc51522f2016-08-27 01:09:19 +0200509 ((hactive + right_border + hfront_porch + hsync - 1) << 16)
510 | (hactive + right_border + hfront_porch - 1));
Arthur Heymansde6ad832016-08-22 17:58:46 +0200511
Arthur Heymansc51522f2016-08-27 01:09:19 +0200512 write32(mmio + VTOTAL(0), ((vactive + bottom_border + vblank - 1) << 16)
Arthur Heymansde6ad832016-08-22 17:58:46 +0200513 | (vactive - 1));
Arthur Heymansc51522f2016-08-27 01:09:19 +0200514 write32(mmio + VBLANK(0), ((vactive + bottom_border + vblank - 1) << 16)
515 | (vactive + bottom_border - 1));
Arthur Heymansde6ad832016-08-22 17:58:46 +0200516 write32(mmio + VSYNC(0),
Arthur Heymansc51522f2016-08-27 01:09:19 +0200517 ((vactive + bottom_border + vfront_porch + vsync - 1) << 16)
518 | (vactive + bottom_border + vfront_porch - 1));
Arthur Heymansde6ad832016-08-22 17:58:46 +0200519
520 write32(mmio + PIPECONF(0), PIPECONF_DISABLE);
521
522 write32(mmio + PF_WIN_POS(0), 0);
Nico Huber6d8266b2017-05-20 16:46:01 +0200523 if (IS_ENABLED(CONFIG_LINEAR_FRAMEBUFFER)) {
Arthur Heymansc51522f2016-08-27 01:09:19 +0200524 write32(mmio + PIPESRC(0), ((hactive - 1) << 16)
525 | (vactive - 1));
526 write32(mmio + PF_CTL(0), 0);
527 write32(mmio + PF_WIN_SZ(0), 0);
528 write32(mmio + PFIT_CONTROL, 0);
529 } else {
530 write32(mmio + PIPESRC(0), (639 << 16) | 399);
531 write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
532 write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
533 write32(mmio + PFIT_CONTROL, 0x80000000);
534 }
Arthur Heymansde6ad832016-08-22 17:58:46 +0200535
536 mdelay(1);
Arthur Heymansc51522f2016-08-27 01:09:19 +0200537 write32(mmio + PIPECONF(0), PIPECONF_BPP_6);
Arthur Heymansc51522f2016-08-27 01:09:19 +0200538 write32(mmio + PIPECONF(0), PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
Arthur Heymansde6ad832016-08-22 17:58:46 +0200539 write32(mmio + PIPECONF(0), PIPECONF_ENABLE
540 | PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
541
Nico Huber6d8266b2017-05-20 16:46:01 +0200542 if (IS_ENABLED(CONFIG_LINEAR_FRAMEBUFFER)) {
Arthur Heymansc51522f2016-08-27 01:09:19 +0200543 write32(mmio + VGACNTRL, VGA_DISP_DISABLE);
544 write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
545 | DISPPLANE_BGRX888);
546 mdelay(1);
547 } else {
548 write32(mmio + VGACNTRL, 0xc4008e);
549 }
Arthur Heymansde6ad832016-08-22 17:58:46 +0200550
551 write32(mmio + ADPA, ADPA_DAC_ENABLE
552 | ADPA_PIPE_A_SELECT
553 | ADPA_CRT_HOTPLUG_MONITOR_COLOR
554 | ADPA_CRT_HOTPLUG_ENABLE
Arthur Heymansde6ad832016-08-22 17:58:46 +0200555 | ADPA_VSYNC_CNTL_ENABLE
556 | ADPA_HSYNC_CNTL_ENABLE
557 | ADPA_DPMS_ON
Arthur Heymansc51522f2016-08-27 01:09:19 +0200558 | (vpolarity ? ADPA_VSYNC_ACTIVE_LOW :
559 ADPA_VSYNC_ACTIVE_HIGH)
560 | (hpolarity ? ADPA_HSYNC_ACTIVE_LOW :
561 ADPA_HSYNC_ACTIVE_HIGH));
Arthur Heymansde6ad832016-08-22 17:58:46 +0200562
Arthur Heymansc51522f2016-08-27 01:09:19 +0200563 write32(mmio + PP_CONTROL, PANEL_POWER_ON | PANEL_POWER_RESET);
Arthur Heymansde6ad832016-08-22 17:58:46 +0200564
Arthur Heymansc51522f2016-08-27 01:09:19 +0200565 /* Enable screen memory. */
Arthur Heymansde6ad832016-08-22 17:58:46 +0200566 vga_sr_write(1, vga_sr_read(1) & ~0x20);
567
568 /* Clear interrupts. */
569 write32(mmio + DEIIR, 0xffffffff);
570 write32(mmio + SDEIIR, 0xffffffff);
Arthur Heymansc51522f2016-08-27 01:09:19 +0200571
Nico Huber6d8266b2017-05-20 16:46:01 +0200572 if (IS_ENABLED(CONFIG_LINEAR_FRAMEBUFFER)) {
Arthur Heymansc51522f2016-08-27 01:09:19 +0200573 memset((void *) lfb, 0,
Arthur Heymans53485d22017-04-30 08:29:54 +0200574 edid->x_resolution * edid->y_resolution * 4);
575 set_vbe_mode_info_valid(edid, lfb);
Arthur Heymansc51522f2016-08-27 01:09:19 +0200576 }
577
578
Arthur Heymansde6ad832016-08-22 17:58:46 +0200579}
580
Arthur Heymans53485d22017-04-30 08:29:54 +0200581static void gma_ngi(struct device *const dev, struct edid *edid_lvds)
Arthur Heymansde6ad832016-08-22 17:58:46 +0200582{
Arthur Heymans53485d22017-04-30 08:29:54 +0200583 u8 edid_data_vga[128];
584 struct edid edid_vga;
585 int vga_edid_status;
586 u8 *mmio;
587 struct northbridge_intel_gm45_config *conf = dev->chip_info;
588
589 mmio = res2mmio(gtt_res, 0, 0);
590 printk(BIOS_DEBUG, "VGA EDID\n");
591 intel_gmbus_read_edid(mmio + GMBUS0, 2, 0x50, edid_data_vga,
592 sizeof(edid_data_vga));
Arthur Heymansc51522f2016-08-27 01:09:19 +0200593 intel_gmbus_stop(mmio + GMBUS0);
Arthur Heymans53485d22017-04-30 08:29:54 +0200594 vga_edid_status = decode_edid(edid_data_vga,
595 sizeof(edid_data_vga), &edid_vga);
596
597 u32 physbase;
598 struct resource *lfb_res;
599 struct resource *pio_res;
600
601 lfb_res = find_resource(dev, PCI_BASE_ADDRESS_2);
602 pio_res = find_resource(dev, PCI_BASE_ADDRESS_4);
603
604 physbase = pci_read_config32(dev, 0x5c) & ~0xf;
605
606 if (!(physbase && pio_res && pio_res->base && lfb_res && lfb_res->base))
607 return;
608
609 printk(BIOS_SPEW, "Initializing display without OPROM. MMIO 0x%llx\n",
610 gtt_res->base);
611 if (vga_edid_status != EDID_ABSENT) {
612 printk(BIOS_DEBUG, "Initialising display on VGA output\n");
613 gma_init_vga(conf, mmio, physbase, pio_res->base, lfb_res->base,
614 &edid_vga);
615 } else {
616 printk(BIOS_DEBUG, "Initialising display on LVDS output\n");
617 gma_init_lvds(conf, mmio, physbase, pio_res->base,
618 lfb_res->base, edid_lvds);
Arthur Heymansde6ad832016-08-22 17:58:46 +0200619 }
Arthur Heymans53485d22017-04-30 08:29:54 +0200620
621 /* Linux relies on VBT for panel info. */
622 generate_fake_intel_oprom(&conf->gfx, dev, "$VBT CANTIGA");
Arthur Heymansde6ad832016-08-22 17:58:46 +0200623}
624
Nico Huberd85a71a2016-11-27 14:43:12 +0100625static u32 get_cdclk(struct device *const dev)
626{
627 const u16 cdclk_sel =
628 pci_read_config16 (dev, GCFGC_OFFSET) & GCFGC_CD_MASK;
629 switch (MCHBAR8(HPLLVCO_MCHBAR) & 0x7) {
630 case VCO_2666:
631 case VCO_4000:
632 case VCO_5333:
633 return cdclk_sel ? 333333333 : 222222222;
634 case VCO_3200:
635 return cdclk_sel ? 320000000 : 228571429;
636 default:
637 printk(BIOS_WARNING,
638 "Unknown VCO frequency, using default cdclk.\n");
639 return 222222222;
640 }
641}
642
Arthur Heymans12bed262016-11-24 13:23:05 +0100643static u32 freq_to_blc_pwm_ctl(struct device *const dev,
644 u16 pwm_freq, u8 duty_perc)
645{
646 u32 blc_mod;
647
648 blc_mod = get_cdclk(dev) / (128 * pwm_freq);
649
650 if (duty_perc <= 100)
651 return (blc_mod << 16) | (blc_mod * duty_perc / 100);
652 else
653 return (blc_mod << 16) | blc_mod;
654}
655
Arthur Heymans20cb85f2017-04-29 14:31:32 +0200656static void gma_pm_init_post_vbios(struct device *const dev,
657 const char *edid_ascii_string)
Nico Huberb851cc62016-01-09 23:27:16 +0100658{
659 const struct northbridge_intel_gm45_config *const conf = dev->chip_info;
660
661 u32 reg32;
Arthur Heymans12bed262016-11-24 13:23:05 +0100662 u8 reg8;
Arthur Heymans20cb85f2017-04-29 14:31:32 +0200663 const struct blc_pwm_t *blc_pwm;
664 int blc_array_len, i;
665 u16 pwm_freq = 0;
Nico Huberb851cc62016-01-09 23:27:16 +0100666
667 /* Setup Panel Power On Delays */
668 reg32 = gtt_read(PP_ON_DELAYS);
669 if (!reg32) {
670 reg32 = (conf->gpu_panel_power_up_delay & 0x1fff) << 16;
671 reg32 |= (conf->gpu_panel_power_backlight_on_delay & 0x1fff);
672 gtt_write(PP_ON_DELAYS, reg32);
673 }
674
675 /* Setup Panel Power Off Delays */
676 reg32 = gtt_read(PP_OFF_DELAYS);
677 if (!reg32) {
678 reg32 = (conf->gpu_panel_power_down_delay & 0x1fff) << 16;
679 reg32 |= (conf->gpu_panel_power_backlight_off_delay & 0x1fff);
680 gtt_write(PP_OFF_DELAYS, reg32);
681 }
682
683 /* Setup Panel Power Cycle Delay */
684 if (conf->gpu_panel_power_cycle_delay) {
Nico Huberd85a71a2016-11-27 14:43:12 +0100685 reg32 = (get_cdclk(dev) / 20000 - 1)
686 << PP_REFERENCE_DIVIDER_SHIFT;
Nico Huberb851cc62016-01-09 23:27:16 +0100687 reg32 |= conf->gpu_panel_power_cycle_delay & 0x1f;
688 gtt_write(PP_DIVISOR, reg32);
689 }
690
691 /* Enable Backlight */
692 gtt_write(BLC_PWM_CTL2, (1 << 31));
Arthur Heymans12bed262016-11-24 13:23:05 +0100693 reg8 = 100;
694 if (conf->duty_cycle != 0)
695 reg8 = conf->duty_cycle;
Arthur Heymans20cb85f2017-04-29 14:31:32 +0200696 blc_array_len = get_blc_values(&blc_pwm);
697 if (conf->default_pwm_freq != 0)
698 pwm_freq = conf->default_pwm_freq;
699
700 /* Find EDID string and pwm freq in lookup table */
701 for (i = 0; i < blc_array_len; i++) {
702 if (!strncmp(blc_pwm[i].ascii_string, edid_ascii_string,
703 strlen(blc_pwm[i].ascii_string))) {
704 pwm_freq = blc_pwm[i].pwm_freq;
705 printk(BIOS_DEBUG, "Found EDID string: %s in lookup table, pwm: %dHz\n",
706 blc_pwm[i].ascii_string, pwm_freq);
707 break;
708 }
709 }
710
711 if (i == blc_array_len)
712 printk(BIOS_NOTICE, "Your panels EDID `%s` wasn't found in the"
713 "lookup table.\n You may have issues with your panels"
714 "backlight.\n If you want to help improving coreboot"
715 "please report: this EDID string\n and the result"
716 "of `intel_read read BLC_PWM_CTL`"
717 "(from intel-gpu-tools)\n while running vendor BIOS\n",
718 edid_ascii_string);
719
720 if (pwm_freq == 0)
Nico Huberb851cc62016-01-09 23:27:16 +0100721 gtt_write(BLC_PWM_CTL, 0x06100610);
722 else
Arthur Heymans20cb85f2017-04-29 14:31:32 +0200723 gtt_write(BLC_PWM_CTL, freq_to_blc_pwm_ctl(dev, pwm_freq,
724 reg8));
Nico Huberb851cc62016-01-09 23:27:16 +0100725}
726
Vladimir Serbinenko6481e102014-08-10 23:48:11 +0200727static void gma_func0_init(struct device *dev)
728{
729 u32 reg32;
Arthur Heymans53485d22017-04-30 08:29:54 +0200730 u8 *mmio;
731 u8 edid_data_lvds[128];
732 struct edid edid_lvds;
Vladimir Serbinenko6481e102014-08-10 23:48:11 +0200733
734 /* IGD needs to be Bus Master */
735 reg32 = pci_read_config32(dev, PCI_COMMAND);
736 reg32 |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
737 pci_write_config32(dev, PCI_COMMAND, reg32);
738
Vladimir Serbinenko6481e102014-08-10 23:48:11 +0200739 gtt_res = find_resource(dev, PCI_BASE_ADDRESS_0);
Arthur Heymans53485d22017-04-30 08:29:54 +0200740 if (gtt_res == NULL)
741 return;
742 mmio = res2mmio(gtt_res, 0, 0);
Timothy Pearsone7f70902015-04-06 22:01:23 -0500743
Nico Huberee352cd2016-01-09 23:15:53 +0100744 if (!IS_ENABLED(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT)) {
745 /* PCI Init, will run VBIOS */
Arthur Heymans53485d22017-04-30 08:29:54 +0200746 printk(BIOS_DEBUG, "Initialising IGD using VBIOS\n");
Nico Huberee352cd2016-01-09 23:15:53 +0100747 pci_dev_init(dev);
Nico Huberb851cc62016-01-09 23:27:16 +0100748 }
749
Arthur Heymans53485d22017-04-30 08:29:54 +0200750 printk(BIOS_DEBUG, "LVDS EDID\n");
751 intel_gmbus_read_edid(mmio + GMBUS0, 3, 0x50, edid_data_lvds,
752 sizeof(edid_data_lvds));
753 intel_gmbus_stop(mmio + GMBUS0);
754 decode_edid(edid_data_lvds, sizeof(edid_data_lvds), &edid_lvds);
755
Nico Huberb851cc62016-01-09 23:27:16 +0100756 /* Post VBIOS init */
Arthur Heymans20cb85f2017-04-29 14:31:32 +0200757 gma_pm_init_post_vbios(dev, edid_lvds.ascii_string);
Nico Huberb851cc62016-01-09 23:27:16 +0100758
Arthur Heymans53485d22017-04-30 08:29:54 +0200759 if (IS_ENABLED(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT))
760 gma_ngi(dev, &edid_lvds);
Vladimir Serbinenko6481e102014-08-10 23:48:11 +0200761}
762
763static void gma_set_subsystem(device_t dev, unsigned vendor, unsigned device)
764{
765 if (!vendor || !device) {
766 pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID,
767 pci_read_config32(dev, PCI_VENDOR_ID));
768 } else {
769 pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID,
770 ((device & 0xffff) << 16) | (vendor &
771 0xffff));
772 }
773}
774
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100775const struct i915_gpu_controller_info *
776intel_gma_get_controller_info(void)
777{
778 device_t dev = dev_find_slot(0, PCI_DEVFN(0x2,0));
779 if (!dev) {
780 return NULL;
781 }
782 struct northbridge_intel_gm45_config *chip = dev->chip_info;
783 return &chip->gfx;
784}
785
Alexander Couzens5eea4582015-04-12 22:18:55 +0200786static void gma_ssdt(device_t device)
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100787{
788 const struct i915_gpu_controller_info *gfx = intel_gma_get_controller_info();
789 if (!gfx) {
790 return;
791 }
792
793 drivers_intel_gma_displays_ssdt_generate(gfx);
794}
795
Vladimir Serbinenko6481e102014-08-10 23:48:11 +0200796static struct pci_operations gma_pci_ops = {
797 .set_subsystem = gma_set_subsystem,
798};
799
800static struct device_operations gma_func0_ops = {
801 .read_resources = pci_dev_read_resources,
802 .set_resources = pci_dev_set_resources,
803 .enable_resources = pci_dev_enable_resources,
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100804 .acpi_fill_ssdt_generator = gma_ssdt,
Vladimir Serbinenko6481e102014-08-10 23:48:11 +0200805 .init = gma_func0_init,
806 .scan_bus = 0,
807 .enable = 0,
808 .ops_pci = &gma_pci_ops,
809};
810
811static const unsigned short pci_device_ids[] =
812{
813 0x2a42, 0
814};
815
816static const struct pci_driver gma __pci_driver = {
817 .ops = &gma_func0_ops,
818 .vendor = PCI_VENDOR_ID_INTEL,
819 .devices = pci_device_ids,
820};