blob: bdad49bae87b0e312718ec7d6e8e8353bdaf754b [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>
Patrick Rudolphf6aa7d92017-09-29 18:28:23 +020028#include <cbmem.h>
29#include <southbridge/intel/i82801ix/nvs.h>
Vladimir Serbinenko6481e102014-08-10 23:48:11 +020030
31#include "drivers/intel/gma/i915_reg.h"
32#include "chip.h"
33#include "gm45.h"
Vladimir Serbinenko88010112014-08-16 03:35:33 +020034#include <drivers/intel/gma/intel_bios.h>
35#include <drivers/intel/gma/edid.h>
36#include <drivers/intel/gma/i915.h>
Patrick Rudolphf6aa7d92017-09-29 18:28:23 +020037#include <drivers/intel/gma/opregion.h>
Vladimir Serbinenko88010112014-08-16 03:35:33 +020038#include <pc80/vga.h>
39#include <pc80/vga_io.h>
40
Arthur Heymansfe3eabc2016-09-26 08:44:46 +020041#define BASE_FREQUENCY 96000
Arthur Heymansc51522f2016-08-27 01:09:19 +020042
Vladimir Serbinenko6481e102014-08-10 23:48:11 +020043static struct resource *gtt_res = NULL;
44
Nico Huberb851cc62016-01-09 23:27:16 +010045u32 gtt_read(u32 reg)
46{
47 return read32(res2mmio(gtt_res, reg, 0));
48}
49
Vladimir Serbinenko88010112014-08-16 03:35:33 +020050void gtt_write(u32 reg, u32 data)
Vladimir Serbinenko6481e102014-08-10 23:48:11 +020051{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080052 write32(res2mmio(gtt_res, reg, 0), data);
Vladimir Serbinenko6481e102014-08-10 23:48:11 +020053}
54
Patrick Rudolphf6aa7d92017-09-29 18:28:23 +020055uintptr_t gma_get_gnvs_aslb(const void *gnvs)
56{
57 const global_nvs_t *gnvs_ptr = gnvs;
58 return (uintptr_t)(gnvs_ptr ? gnvs_ptr->aslb : 0);
59}
60
61void gma_set_gnvs_aslb(void *gnvs, uintptr_t aslb)
62{
63 global_nvs_t *gnvs_ptr = gnvs;
64 if (gnvs_ptr)
65 gnvs_ptr->aslb = aslb;
66}
67
Arthur Heymansde6ad832016-08-22 17:58:46 +020068static void gma_init_lvds(const struct northbridge_intel_gm45_config *info,
Arthur Heymans53485d22017-04-30 08:29:54 +020069 u8 *mmio, u32 physbase, u16 piobase, u32 lfb,
70 struct edid *edid)
Vladimir Serbinenko88010112014-08-16 03:35:33 +020071{
Vladimir Serbinenko88010112014-08-16 03:35:33 +020072 int i;
Audrey Pearsonbd0dab22015-09-29 12:36:52 -050073 struct edid_mode *mode;
Vladimir Serbinenko88010112014-08-16 03:35:33 +020074 u32 hactive, vactive, right_border, bottom_border;
75 int hpolarity, vpolarity;
76 u32 vsync, hsync, vblank, hblank, hfront_porch, vfront_porch;
Arthur Heymansfe3eabc2016-09-26 08:44:46 +020077 u32 smallest_err = 0xffffffff;
Vladimir Serbinenko88010112014-08-16 03:35:33 +020078 u32 target_frequency;
79 u32 pixel_p1 = 1;
80 u32 pixel_n = 1;
81 u32 pixel_m1 = 1;
82 u32 pixel_m2 = 1;
Arthur Heymansfe3eabc2016-09-26 08:44:46 +020083 u32 pixel_p2;
Vladimir Serbinenko88010112014-08-16 03:35:33 +020084
85 vga_gr_write(0x18, 0);
86
87 /* Setup GTT. */
88 for (i = 0; i < 0x2000; i++)
89 {
90 outl((i << 2) | 1, piobase);
91 outl(physbase + (i << 12) + 1, piobase + 4);
92 }
93
Timothy Pearson61942de2015-04-06 21:54:56 -050094 write32(mmio + ADPA, 0x40008c18);
Vladimir Serbinenko88010112014-08-16 03:35:33 +020095 write32(mmio + 0x7041c, 0x0);
Timothy Pearson61942de2015-04-06 21:54:56 -050096 write32(mmio + _DPLL_B_MD, 0x3);
Vladimir Serbinenko88010112014-08-16 03:35:33 +020097
98 vga_misc_write(0x67);
99
100 const u8 cr[] = { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
101 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
102 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
103 0xff
104 };
105 vga_cr_write(0x11, 0);
106
107 for (i = 0; i <= 0x18; i++)
108 vga_cr_write(i, cr[i]);
109
Arthur Heymansde6ad832016-08-22 17:58:46 +0200110 /* Disable screen memory to prevent garbage from appearing. */
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200111 vga_sr_write(1, vga_sr_read(1) | 0x20);
112
Arthur Heymans53485d22017-04-30 08:29:54 +0200113 mode = &edid->mode;
114
115 hactive = edid->x_resolution;
116 vactive = edid->y_resolution;
Audrey Pearsonbd0dab22015-09-29 12:36:52 -0500117 right_border = mode->hborder;
118 bottom_border = mode->vborder;
119 hpolarity = (mode->phsync == '-');
120 vpolarity = (mode->pvsync == '-');
121 vsync = mode->vspw;
122 hsync = mode->hspw;
123 vblank = mode->vbl;
124 hblank = mode->hbl;
125 hfront_porch = mode->hso;
126 vfront_porch = mode->vso;
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200127
Nico Huber6d8266b2017-05-20 16:46:01 +0200128 if (IS_ENABLED(CONFIG_LINEAR_FRAMEBUFFER)) {
Nico Huberee352cd2016-01-09 23:15:53 +0100129 vga_sr_write(1, 1);
130 vga_sr_write(0x2, 0xf);
131 vga_sr_write(0x3, 0x0);
132 vga_sr_write(0x4, 0xe);
133 vga_gr_write(0, 0x0);
134 vga_gr_write(1, 0x0);
135 vga_gr_write(2, 0x0);
136 vga_gr_write(3, 0x0);
137 vga_gr_write(4, 0x0);
138 vga_gr_write(5, 0x0);
139 vga_gr_write(6, 0x5);
140 vga_gr_write(7, 0xf);
141 vga_gr_write(0x10, 0x1);
142 vga_gr_write(0x11, 0);
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200143
Arthur Heymans53485d22017-04-30 08:29:54 +0200144 edid->bytes_per_line = (edid->bytes_per_line + 63) & ~63;
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200145
Nico Huberee352cd2016-01-09 23:15:53 +0100146 write32(mmio + DSPCNTR(0), DISPPLANE_BGRX888);
147 write32(mmio + DSPADDR(0), 0);
Arthur Heymans53485d22017-04-30 08:29:54 +0200148 write32(mmio + DSPSTRIDE(0), edid->bytes_per_line);
Nico Huberee352cd2016-01-09 23:15:53 +0100149 write32(mmio + DSPSURF(0), 0);
150 for (i = 0; i < 0x100; i++)
151 write32(mmio + LGC_PALETTE(0) + 4 * i, i * 0x010101);
152 } else {
153 vga_textmode_init();
154 }
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200155
Arthur Heymansfe3eabc2016-09-26 08:44:46 +0200156 target_frequency = mode->pixel_clock;
157 /*
158 * p2 divisor must 7 for dual channel LVDS
159 * and 14 for single channel LVDS
160 */
161 pixel_p2 = mode->lvds_dual_channel ? 7 : 14;
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200162
Arthur Heymansfe3eabc2016-09-26 08:44:46 +0200163 /*
164 * Find suitable divisors, m1, m2, p1, n.
165 * refclock * (5 * (m1 + 2) + (m1 + 2)) / (n + 2) / p1 / p2
166 * should be closest to target frequency as possible
167 */
168 u32 candn, candm1, candm2, candp1;
169 for (candn = 1; candn <= 3; candn++) {
170 for (candm1 = 23; candm1 >= 17; candm1--) {
171 for (candm2 = 11; candm2 >= 5; candm2--) {
172 for (candp1 = mode->lvds_dual_channel ? 6 : 8;
173 candp1 >= 2; candp1--) {
174 u32 m = 5 * (candm1 + 2) + (candm2 + 2);
175 u32 p = candp1 * pixel_p2;
176 u32 vco = DIV_ROUND_CLOSEST(BASE_FREQUENCY * m, candn + 2);
177 u32 dot = DIV_ROUND_CLOSEST(vco, p);
Arthur Heymans75f91312016-10-12 01:04:28 +0200178 u32 this_err = MAX(dot, target_frequency) -
179 MIN(dot, target_frequency);
Arthur Heymansfe3eabc2016-09-26 08:44:46 +0200180 if (this_err < smallest_err) {
181 smallest_err = this_err;
182 pixel_n = candn;
183 pixel_m1 = candm1;
184 pixel_m2 = candm2;
185 pixel_p1 = candp1;
186 }
187 }
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200188 }
189 }
190 }
191
Arthur Heymansfe3eabc2016-09-26 08:44:46 +0200192 if (smallest_err == 0xffffffff) {
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200193 printk (BIOS_ERR, "Couldn't find GFX clock divisors\n");
194 return;
195 }
196
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200197 printk(BIOS_INFO, "bringing up panel at resolution %d x %d\n",
198 hactive, vactive);
199 printk(BIOS_DEBUG, "Borders %d x %d\n",
200 right_border, bottom_border);
201 printk(BIOS_DEBUG, "Blank %d x %d\n",
202 hblank, vblank);
203 printk(BIOS_DEBUG, "Sync %d x %d\n",
204 hsync, vsync);
205 printk(BIOS_DEBUG, "Front porch %d x %d\n",
206 hfront_porch, vfront_porch);
Vladimir Serbinenkoa71bdc32014-08-30 00:35:39 +0200207 printk(BIOS_DEBUG, (info->gfx.use_spread_spectrum_clock
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200208 ? "Spread spectrum clock\n" : "DREF clock\n"));
209 printk(BIOS_DEBUG,
Vladimir Serbinenko551cff02015-10-10 23:58:08 +0200210 mode->lvds_dual_channel ? "Dual channel\n" : "Single channel\n");
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200211 printk(BIOS_DEBUG, "Polarities %d, %d\n",
212 hpolarity, vpolarity);
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200213 printk(BIOS_DEBUG, "Pixel N=%d, M1=%d, M2=%d, P1=%d\n",
214 pixel_n, pixel_m1, pixel_m2, pixel_p1);
215 printk(BIOS_DEBUG, "Pixel clock %d kHz\n",
Arthur Heymans1f060282017-01-19 16:45:45 +0100216 BASE_FREQUENCY * (5 * (pixel_m1 + 2) + (pixel_m2 + 2)) /
217 (pixel_n + 2) / (pixel_p1 * pixel_p2));
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200218
219 write32(mmio + LVDS,
220 (hpolarity << 20) | (vpolarity << 21)
Vladimir Serbinenko551cff02015-10-10 23:58:08 +0200221 | (mode->lvds_dual_channel ? LVDS_CLOCK_B_POWERUP_ALL
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200222 | LVDS_CLOCK_BOTH_POWERUP_ALL : 0)
Arthur Heymans8ba20102016-08-15 00:04:34 +0200223 | LVDS_ENABLE_DITHER
224 | LVDS_CLOCK_A_POWERUP_ALL
225 | LVDS_PIPE(0));
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200226 mdelay(1);
227 write32(mmio + PP_CONTROL, PANEL_UNLOCK_REGS
228 | (read32(mmio + PP_CONTROL) & ~PANEL_UNLOCK_MASK));
229 write32(mmio + FP0(0),
Arthur Heymansfe3eabc2016-09-26 08:44:46 +0200230 (pixel_n << 16)
231 | (pixel_m1 << 8) | (pixel_m2));
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200232 write32(mmio + DPLL(0),
233 DPLL_VCO_ENABLE | DPLLB_MODE_LVDS
Arthur Heymans8ba20102016-08-15 00:04:34 +0200234 | DPLL_VGA_MODE_DIS
Vladimir Serbinenko551cff02015-10-10 23:58:08 +0200235 | (mode->lvds_dual_channel ? DPLLB_LVDS_P2_CLOCK_DIV_7
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200236 : DPLLB_LVDS_P2_CLOCK_DIV_14)
237 | (0x10000 << (pixel_p1 - 1))
Vladimir Serbinenkoa71bdc32014-08-30 00:35:39 +0200238 | ((info->gfx.use_spread_spectrum_clock ? 3 : 0) << 13)
Arthur Heymans8ba20102016-08-15 00:04:34 +0200239 | (6 << PLL_LOAD_PULSE_PHASE_SHIFT));
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200240 mdelay(1);
241 write32(mmio + DPLL(0),
242 DPLL_VCO_ENABLE | DPLLB_MODE_LVDS
Arthur Heymans8ba20102016-08-15 00:04:34 +0200243 | DPLL_VGA_MODE_DIS
Vladimir Serbinenko551cff02015-10-10 23:58:08 +0200244 | (mode->lvds_dual_channel ? DPLLB_LVDS_P2_CLOCK_DIV_7
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200245 : DPLLB_LVDS_P2_CLOCK_DIV_14)
246 | (0x10000 << (pixel_p1 - 1))
Vladimir Serbinenkoa71bdc32014-08-30 00:35:39 +0200247 | ((info->gfx.use_spread_spectrum_clock ? 3 : 0) << 13)
Arthur Heymans8ba20102016-08-15 00:04:34 +0200248 | (6 << PLL_LOAD_PULSE_PHASE_SHIFT));
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200249 /* Re-lock the registers. */
250 write32(mmio + PP_CONTROL,
251 (read32(mmio + PP_CONTROL) & ~PANEL_UNLOCK_MASK));
252
253 write32(mmio + LVDS,
254 (hpolarity << 20) | (vpolarity << 21)
Vladimir Serbinenko551cff02015-10-10 23:58:08 +0200255 | (mode->lvds_dual_channel ? LVDS_CLOCK_B_POWERUP_ALL
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200256 | LVDS_CLOCK_BOTH_POWERUP_ALL : 0)
Arthur Heymans8ba20102016-08-15 00:04:34 +0200257 | LVDS_CLOCK_A_POWERUP_ALL
258 | LVDS_ENABLE_DITHER
259 | LVDS_PIPE(0));
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200260
261 write32(mmio + HTOTAL(0),
262 ((hactive + right_border + hblank - 1) << 16)
263 | (hactive - 1));
264 write32(mmio + HBLANK(0),
265 ((hactive + right_border + hblank - 1) << 16)
266 | (hactive + right_border - 1));
267 write32(mmio + HSYNC(0),
268 ((hactive + right_border + hfront_porch + hsync - 1) << 16)
269 | (hactive + right_border + hfront_porch - 1));
270
271 write32(mmio + VTOTAL(0), ((vactive + bottom_border + vblank - 1) << 16)
272 | (vactive - 1));
273 write32(mmio + VBLANK(0), ((vactive + bottom_border + vblank - 1) << 16)
274 | (vactive + bottom_border - 1));
275 write32(mmio + VSYNC(0),
Arthur Heymans8ba20102016-08-15 00:04:34 +0200276 ((vactive + bottom_border + vfront_porch + vsync - 1) << 16)
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200277 | (vactive + bottom_border + vfront_porch - 1));
278
279 write32(mmio + PIPECONF(0), PIPECONF_DISABLE);
280
281 write32(mmio + PF_WIN_POS(0), 0);
Nico Huber6d8266b2017-05-20 16:46:01 +0200282 if (IS_ENABLED(CONFIG_LINEAR_FRAMEBUFFER)) {
Nico Huberee352cd2016-01-09 23:15:53 +0100283 write32(mmio + PIPESRC(0), ((hactive - 1) << 16)
284 | (vactive - 1));
285 write32(mmio + PF_CTL(0), 0);
286 write32(mmio + PF_WIN_SZ(0), 0);
Arthur Heymans8ba20102016-08-15 00:04:34 +0200287 write32(mmio + PFIT_CONTROL, 0);
Nico Huberee352cd2016-01-09 23:15:53 +0100288 } else {
289 write32(mmio + PIPESRC(0), (639 << 16) | 399);
290 write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
291 write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
Nick High1e302cb2016-04-26 17:22:05 -0400292 write32(mmio + PFIT_CONTROL, 0x80000000);
Nico Huberee352cd2016-01-09 23:15:53 +0100293 }
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200294
295 mdelay(1);
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200296 write32(mmio + PIPECONF(0), PIPECONF_BPP_6);
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200297 write32(mmio + PIPECONF(0), PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
298 write32(mmio + PIPECONF(0), PIPECONF_ENABLE | PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
299
Nico Huber6d8266b2017-05-20 16:46:01 +0200300 if (IS_ENABLED(CONFIG_LINEAR_FRAMEBUFFER)) {
Arthur Heymans8ba20102016-08-15 00:04:34 +0200301 write32(mmio + VGACNTRL, VGA_DISP_DISABLE);
Nico Huberee352cd2016-01-09 23:15:53 +0100302 write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
303 | DISPPLANE_BGRX888);
304 mdelay(1);
305 } else {
Nick High1e302cb2016-04-26 17:22:05 -0400306 write32(mmio + VGACNTRL, 0xc4008e);
Nico Huberee352cd2016-01-09 23:15:53 +0100307 }
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200308
Arthur Heymans8ba20102016-08-15 00:04:34 +0200309 write32(mmio + LVDS, LVDS_PORT_ENABLE
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200310 | (hpolarity << 20) | (vpolarity << 21)
Vladimir Serbinenko551cff02015-10-10 23:58:08 +0200311 | (mode->lvds_dual_channel ? LVDS_CLOCK_B_POWERUP_ALL
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200312 | LVDS_CLOCK_BOTH_POWERUP_ALL : 0)
Arthur Heymans8ba20102016-08-15 00:04:34 +0200313 | LVDS_CLOCK_A_POWERUP_ALL
314 | LVDS_ENABLE_DITHER
315 | LVDS_PIPE(0));
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200316
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200317 write32(mmio + PP_CONTROL, PANEL_POWER_ON | PANEL_POWER_RESET);
318
319 /* Enable screen memory. */
320 vga_sr_write(1, vga_sr_read(1) & ~0x20);
321
322 /* Clear interrupts. */
323 write32(mmio + DEIIR, 0xffffffff);
324 write32(mmio + SDEIIR, 0xffffffff);
325
Nico Huber6d8266b2017-05-20 16:46:01 +0200326 if (IS_ENABLED(CONFIG_LINEAR_FRAMEBUFFER)) {
Nico Huberee352cd2016-01-09 23:15:53 +0100327 memset((void *) lfb, 0,
Arthur Heymans53485d22017-04-30 08:29:54 +0200328 edid->x_resolution * edid->y_resolution * 4);
329 set_vbe_mode_info_valid(edid, lfb);
Nico Huberee352cd2016-01-09 23:15:53 +0100330 }
Vladimir Serbinenko88010112014-08-16 03:35:33 +0200331}
332
Arthur Heymansde6ad832016-08-22 17:58:46 +0200333static void gma_init_vga(const struct northbridge_intel_gm45_config *info,
Arthur Heymans53485d22017-04-30 08:29:54 +0200334 u8 *mmio, u32 physbase, u16 piobase, u32 lfb,
335 struct edid *edid)
Arthur Heymansde6ad832016-08-22 17:58:46 +0200336{
337
338 int i;
Arthur Heymansc51522f2016-08-27 01:09:19 +0200339 struct edid_mode *mode;
340 u32 hactive, vactive, right_border, bottom_border;
341 int hpolarity, vpolarity;
342 u32 vsync, hsync, vblank, hblank, hfront_porch, vfront_porch;
343 u32 target_frequency;
344 u32 smallest_err = 0xffffffff;
345 u32 pixel_p1 = 1;
Arthur Heymans063cd5f2016-10-12 00:05:00 +0200346 u32 pixel_p2;
Arthur Heymansc51522f2016-08-27 01:09:19 +0200347 u32 pixel_n = 1;
348 u32 pixel_m1 = 1;
349 u32 pixel_m2 = 1;
Arthur Heymansde6ad832016-08-22 17:58:46 +0200350
351 vga_gr_write(0x18, 0);
352
Arthur Heymansc51522f2016-08-27 01:09:19 +0200353 /* Set up GTT. */
354 for (i = 0; i < 0x2000; i++) {
355 outl((i << 2) | 1, piobase);
356 outl(physbase + (i << 12) + 1, piobase + 4);
357 }
358
359
Arthur Heymansde6ad832016-08-22 17:58:46 +0200360 write32(mmio + VGA0, 0x31108);
361 write32(mmio + VGA1, 0x31406);
362
363 write32(mmio + ADPA, ADPA_DAC_ENABLE
364 | ADPA_PIPE_A_SELECT
365 | ADPA_CRT_HOTPLUG_MONITOR_COLOR
366 | ADPA_CRT_HOTPLUG_ENABLE
367 | ADPA_USE_VGA_HVPOLARITY
368 | ADPA_VSYNC_CNTL_ENABLE
369 | ADPA_HSYNC_CNTL_ENABLE
Arthur Heymansc51522f2016-08-27 01:09:19 +0200370 | ADPA_DPMS_ON);
Arthur Heymansde6ad832016-08-22 17:58:46 +0200371
372 write32(mmio + 0x7041c, 0x0);
373 write32(mmio + DPLL_MD(0), 0x3);
374 write32(mmio + DPLL_MD(1), 0x3);
375
376 vga_misc_write(0x67);
377
378 const u8 cr[] = { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
379 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
380 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
381 0xff
382 };
383 vga_cr_write(0x11, 0);
384
385 for (i = 0; i <= 0x18; i++)
386 vga_cr_write(i, cr[i]);
387
Arthur Heymansc51522f2016-08-27 01:09:19 +0200388 udelay(1);
389
Arthur Heymansde6ad832016-08-22 17:58:46 +0200390 /* Disable screen memory to prevent garbage from appearing. */
391 vga_sr_write(1, vga_sr_read(1) | 0x20);
392
Arthur Heymans53485d22017-04-30 08:29:54 +0200393 mode = &edid->mode;
394
395 hactive = edid->x_resolution;
396 vactive = edid->y_resolution;
Arthur Heymansc51522f2016-08-27 01:09:19 +0200397 right_border = mode->hborder;
398 bottom_border = mode->vborder;
399 hpolarity = (mode->phsync == '-');
400 vpolarity = (mode->pvsync == '-');
401 vsync = mode->vspw;
402 hsync = mode->hspw;
403 vblank = mode->vbl;
404 hblank = mode->hbl;
405 hfront_porch = mode->hso;
406 vfront_porch = mode->vso;
407 target_frequency = mode->pixel_clock;
408
Nico Huber6d8266b2017-05-20 16:46:01 +0200409 if (IS_ENABLED(CONFIG_LINEAR_FRAMEBUFFER)) {
Arthur Heymansc51522f2016-08-27 01:09:19 +0200410 vga_sr_write(1, 1);
411 vga_sr_write(0x2, 0xf);
412 vga_sr_write(0x3, 0x0);
413 vga_sr_write(0x4, 0xe);
414 vga_gr_write(0, 0x0);
415 vga_gr_write(1, 0x0);
416 vga_gr_write(2, 0x0);
417 vga_gr_write(3, 0x0);
418 vga_gr_write(4, 0x0);
419 vga_gr_write(5, 0x0);
420 vga_gr_write(6, 0x5);
421 vga_gr_write(7, 0xf);
422 vga_gr_write(0x10, 0x1);
423 vga_gr_write(0x11, 0);
424
Arthur Heymans53485d22017-04-30 08:29:54 +0200425 edid->bytes_per_line = (edid->bytes_per_line + 63) & ~63;
Arthur Heymansc51522f2016-08-27 01:09:19 +0200426
427 write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
428 | DISPPLANE_BGRX888);
429 write32(mmio + DSPADDR(0), 0);
Arthur Heymans53485d22017-04-30 08:29:54 +0200430 write32(mmio + DSPSTRIDE(0), edid->bytes_per_line);
Arthur Heymansc51522f2016-08-27 01:09:19 +0200431 write32(mmio + DSPSURF(0), 0);
432 for (i = 0; i < 0x100; i++)
433 write32(mmio + LGC_PALETTE(0) + 4 * i, i * 0x010101);
434 } else {
435 vga_textmode_init();
436 }
437
Arthur Heymans063cd5f2016-10-12 00:05:00 +0200438 pixel_p2 = target_frequency <= 225000 ? 10 : 5;
439
Arthur Heymansc51522f2016-08-27 01:09:19 +0200440 u32 candn, candm1, candm2, candp1;
441 for (candn = 1; candn <= 4; candn++) {
442 for (candm1 = 23; candm1 >= 17; candm1--) {
443 for (candm2 = 11; candm2 >= 5; candm2--) {
444 for (candp1 = 8; candp1 >= 1; candp1--) {
445 u32 m = 5 * (candm1 + 2) + (candm2 + 2);
Arthur Heymans063cd5f2016-10-12 00:05:00 +0200446 u32 p = candp1 * pixel_p2;
Arthur Heymansfe3eabc2016-09-26 08:44:46 +0200447 u32 vco = DIV_ROUND_CLOSEST(BASE_FREQUENCY * m, candn + 2);
Arthur Heymansc51522f2016-08-27 01:09:19 +0200448 u32 dot = DIV_ROUND_CLOSEST(vco, p);
Arthur Heymans75f91312016-10-12 01:04:28 +0200449 u32 this_err = MAX(dot, target_frequency) -
450 MIN(dot, target_frequency);
Arthur Heymansc51522f2016-08-27 01:09:19 +0200451 if (this_err < smallest_err) {
452 smallest_err= this_err;
453 pixel_n = candn;
454 pixel_m1 = candm1;
455 pixel_m2 = candm2;
456 pixel_p1 = candp1;
457 }
458 }
459 }
460 }
461 }
462
463 if (smallest_err == 0xffffffff) {
464 printk(BIOS_ERR, "Error: Couldn't find GFX clock divisors\n");
465 return;
466 }
467
Arthur Heymansc51522f2016-08-27 01:09:19 +0200468 printk(BIOS_INFO, "Bringing up panel at resolution %d x %d\n",
469 hactive, vactive);
470 printk(BIOS_SPEW, "Borders %d x %d\n",
471 right_border, bottom_border);
472 printk(BIOS_SPEW, "Blank %d x %d\n",
473 hblank, vblank);
474 printk(BIOS_SPEW, "Sync %d x %d\n",
475 hsync, vsync);
476 printk(BIOS_SPEW, "Front porch %d x %d\n",
477 hfront_porch, vfront_porch);
478 printk(BIOS_SPEW, (info->gfx.use_spread_spectrum_clock
479 ? "Spread spectrum clock\n" : "DREF clock\n"));
480 printk(BIOS_SPEW, "Polarities %d, %d\n",
481 hpolarity, vpolarity);
Arthur Heymans063cd5f2016-10-12 00:05:00 +0200482 printk(BIOS_SPEW, "Pixel N=%d, M1=%d, M2=%d, P1=%d, P2=%d\n",
483 pixel_n, pixel_m1, pixel_m2, pixel_p1, pixel_p2);
Arthur Heymansc51522f2016-08-27 01:09:19 +0200484 printk(BIOS_SPEW, "Pixel clock %d kHz\n",
Arthur Heymans1f060282017-01-19 16:45:45 +0100485 BASE_FREQUENCY * (5 * (pixel_m1 + 2) + (pixel_m2 + 2)) /
486 (pixel_n + 2) / (pixel_p1 * pixel_p2));
Arthur Heymansde6ad832016-08-22 17:58:46 +0200487
488 mdelay(1);
Arthur Heymansc51522f2016-08-27 01:09:19 +0200489 write32(mmio + FP0(0), (pixel_n << 16)
490 | (pixel_m1 << 8) | pixel_m2);
491 write32(mmio + DPLL(0), DPLL_VCO_ENABLE
492 | DPLL_VGA_MODE_DIS | DPLLB_MODE_DAC_SERIAL
Arthur Heymans063cd5f2016-10-12 00:05:00 +0200493 | (pixel_p2 == 10 ? DPLL_DAC_SERIAL_P2_CLOCK_DIV_10 :
494 DPLL_DAC_SERIAL_P2_CLOCK_DIV_5)
Arthur Heymansc51522f2016-08-27 01:09:19 +0200495 | (0x10000 << (pixel_p1 - 1))
496 | (6 << 9));
497
Arthur Heymansde6ad832016-08-22 17:58:46 +0200498 mdelay(1);
Arthur Heymansc51522f2016-08-27 01:09:19 +0200499 write32(mmio + DPLL(0), DPLL_VCO_ENABLE
500 | DPLL_VGA_MODE_DIS | DPLLB_MODE_DAC_SERIAL
Arthur Heymans063cd5f2016-10-12 00:05:00 +0200501 | (pixel_p2 == 10 ? DPLL_DAC_SERIAL_P2_CLOCK_DIV_10 :
502 DPLL_DAC_SERIAL_P2_CLOCK_DIV_5)
Arthur Heymansc51522f2016-08-27 01:09:19 +0200503 | (0x10000 << (pixel_p1 - 1))
504 | (6 << 9));
Arthur Heymansde6ad832016-08-22 17:58:46 +0200505
506 write32(mmio + ADPA, ADPA_DAC_ENABLE
507 | ADPA_PIPE_A_SELECT
508 | ADPA_CRT_HOTPLUG_MONITOR_COLOR
509 | ADPA_CRT_HOTPLUG_ENABLE
Arthur Heymansde6ad832016-08-22 17:58:46 +0200510 | ADPA_VSYNC_CNTL_ENABLE
511 | ADPA_HSYNC_CNTL_ENABLE
512 | ADPA_DPMS_ON
Arthur Heymansc51522f2016-08-27 01:09:19 +0200513 | (vpolarity ? ADPA_VSYNC_ACTIVE_LOW :
514 ADPA_VSYNC_ACTIVE_HIGH)
515 | (hpolarity ? ADPA_HSYNC_ACTIVE_LOW :
516 ADPA_HSYNC_ACTIVE_HIGH));
Arthur Heymansde6ad832016-08-22 17:58:46 +0200517
518 write32(mmio + HTOTAL(0),
Arthur Heymansc51522f2016-08-27 01:09:19 +0200519 ((hactive + right_border + hblank - 1) << 16)
Arthur Heymansde6ad832016-08-22 17:58:46 +0200520 | (hactive - 1));
521 write32(mmio + HBLANK(0),
Arthur Heymansc51522f2016-08-27 01:09:19 +0200522 ((hactive + right_border + hblank - 1) << 16)
523 | (hactive + right_border - 1));
Arthur Heymansde6ad832016-08-22 17:58:46 +0200524 write32(mmio + HSYNC(0),
Arthur Heymansc51522f2016-08-27 01:09:19 +0200525 ((hactive + right_border + hfront_porch + hsync - 1) << 16)
526 | (hactive + right_border + hfront_porch - 1));
Arthur Heymansde6ad832016-08-22 17:58:46 +0200527
Arthur Heymansc51522f2016-08-27 01:09:19 +0200528 write32(mmio + VTOTAL(0), ((vactive + bottom_border + vblank - 1) << 16)
Arthur Heymansde6ad832016-08-22 17:58:46 +0200529 | (vactive - 1));
Arthur Heymansc51522f2016-08-27 01:09:19 +0200530 write32(mmio + VBLANK(0), ((vactive + bottom_border + vblank - 1) << 16)
531 | (vactive + bottom_border - 1));
Arthur Heymansde6ad832016-08-22 17:58:46 +0200532 write32(mmio + VSYNC(0),
Arthur Heymansc51522f2016-08-27 01:09:19 +0200533 ((vactive + bottom_border + vfront_porch + vsync - 1) << 16)
534 | (vactive + bottom_border + vfront_porch - 1));
Arthur Heymansde6ad832016-08-22 17:58:46 +0200535
536 write32(mmio + PIPECONF(0), PIPECONF_DISABLE);
537
538 write32(mmio + PF_WIN_POS(0), 0);
Nico Huber6d8266b2017-05-20 16:46:01 +0200539 if (IS_ENABLED(CONFIG_LINEAR_FRAMEBUFFER)) {
Arthur Heymansc51522f2016-08-27 01:09:19 +0200540 write32(mmio + PIPESRC(0), ((hactive - 1) << 16)
541 | (vactive - 1));
542 write32(mmio + PF_CTL(0), 0);
543 write32(mmio + PF_WIN_SZ(0), 0);
544 write32(mmio + PFIT_CONTROL, 0);
545 } else {
546 write32(mmio + PIPESRC(0), (639 << 16) | 399);
547 write32(mmio + PF_CTL(0), PF_ENABLE | PF_FILTER_MED_3x3);
548 write32(mmio + PF_WIN_SZ(0), vactive | (hactive << 16));
549 write32(mmio + PFIT_CONTROL, 0x80000000);
550 }
Arthur Heymansde6ad832016-08-22 17:58:46 +0200551
552 mdelay(1);
Arthur Heymansc51522f2016-08-27 01:09:19 +0200553 write32(mmio + PIPECONF(0), PIPECONF_BPP_6);
Arthur Heymansc51522f2016-08-27 01:09:19 +0200554 write32(mmio + PIPECONF(0), PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
Arthur Heymansde6ad832016-08-22 17:58:46 +0200555 write32(mmio + PIPECONF(0), PIPECONF_ENABLE
556 | PIPECONF_BPP_6 | PIPECONF_DITHER_EN);
557
Nico Huber6d8266b2017-05-20 16:46:01 +0200558 if (IS_ENABLED(CONFIG_LINEAR_FRAMEBUFFER)) {
Arthur Heymansc51522f2016-08-27 01:09:19 +0200559 write32(mmio + VGACNTRL, VGA_DISP_DISABLE);
560 write32(mmio + DSPCNTR(0), DISPLAY_PLANE_ENABLE
561 | DISPPLANE_BGRX888);
562 mdelay(1);
563 } else {
564 write32(mmio + VGACNTRL, 0xc4008e);
565 }
Arthur Heymansde6ad832016-08-22 17:58:46 +0200566
567 write32(mmio + ADPA, ADPA_DAC_ENABLE
568 | ADPA_PIPE_A_SELECT
569 | ADPA_CRT_HOTPLUG_MONITOR_COLOR
570 | ADPA_CRT_HOTPLUG_ENABLE
Arthur Heymansde6ad832016-08-22 17:58:46 +0200571 | ADPA_VSYNC_CNTL_ENABLE
572 | ADPA_HSYNC_CNTL_ENABLE
573 | ADPA_DPMS_ON
Arthur Heymansc51522f2016-08-27 01:09:19 +0200574 | (vpolarity ? ADPA_VSYNC_ACTIVE_LOW :
575 ADPA_VSYNC_ACTIVE_HIGH)
576 | (hpolarity ? ADPA_HSYNC_ACTIVE_LOW :
577 ADPA_HSYNC_ACTIVE_HIGH));
Arthur Heymansde6ad832016-08-22 17:58:46 +0200578
Arthur Heymansc51522f2016-08-27 01:09:19 +0200579 write32(mmio + PP_CONTROL, PANEL_POWER_ON | PANEL_POWER_RESET);
Arthur Heymansde6ad832016-08-22 17:58:46 +0200580
Arthur Heymansc51522f2016-08-27 01:09:19 +0200581 /* Enable screen memory. */
Arthur Heymansde6ad832016-08-22 17:58:46 +0200582 vga_sr_write(1, vga_sr_read(1) & ~0x20);
583
584 /* Clear interrupts. */
585 write32(mmio + DEIIR, 0xffffffff);
586 write32(mmio + SDEIIR, 0xffffffff);
Arthur Heymansc51522f2016-08-27 01:09:19 +0200587
Nico Huber6d8266b2017-05-20 16:46:01 +0200588 if (IS_ENABLED(CONFIG_LINEAR_FRAMEBUFFER)) {
Arthur Heymansc51522f2016-08-27 01:09:19 +0200589 memset((void *) lfb, 0,
Arthur Heymans53485d22017-04-30 08:29:54 +0200590 edid->x_resolution * edid->y_resolution * 4);
591 set_vbe_mode_info_valid(edid, lfb);
Arthur Heymansc51522f2016-08-27 01:09:19 +0200592 }
593
594
Arthur Heymansde6ad832016-08-22 17:58:46 +0200595}
596
Arthur Heymans53485d22017-04-30 08:29:54 +0200597static void gma_ngi(struct device *const dev, struct edid *edid_lvds)
Arthur Heymansde6ad832016-08-22 17:58:46 +0200598{
Arthur Heymans53485d22017-04-30 08:29:54 +0200599 u8 edid_data_vga[128];
600 struct edid edid_vga;
601 int vga_edid_status;
602 u8 *mmio;
603 struct northbridge_intel_gm45_config *conf = dev->chip_info;
604
605 mmio = res2mmio(gtt_res, 0, 0);
606 printk(BIOS_DEBUG, "VGA EDID\n");
Arthur Heymans8da22862017-08-06 15:56:30 +0200607 intel_gmbus_read_edid(mmio + GMBUS0, GMBUS_PORT_VGADDC, 0x50,
608 edid_data_vga, sizeof(edid_data_vga));
Arthur Heymansc51522f2016-08-27 01:09:19 +0200609 intel_gmbus_stop(mmio + GMBUS0);
Arthur Heymans53485d22017-04-30 08:29:54 +0200610 vga_edid_status = decode_edid(edid_data_vga,
611 sizeof(edid_data_vga), &edid_vga);
612
613 u32 physbase;
614 struct resource *lfb_res;
615 struct resource *pio_res;
616
617 lfb_res = find_resource(dev, PCI_BASE_ADDRESS_2);
618 pio_res = find_resource(dev, PCI_BASE_ADDRESS_4);
619
620 physbase = pci_read_config32(dev, 0x5c) & ~0xf;
621
622 if (!(physbase && pio_res && pio_res->base && lfb_res && lfb_res->base))
623 return;
624
625 printk(BIOS_SPEW, "Initializing display without OPROM. MMIO 0x%llx\n",
626 gtt_res->base);
627 if (vga_edid_status != EDID_ABSENT) {
628 printk(BIOS_DEBUG, "Initialising display on VGA output\n");
629 gma_init_vga(conf, mmio, physbase, pio_res->base, lfb_res->base,
630 &edid_vga);
631 } else {
632 printk(BIOS_DEBUG, "Initialising display on LVDS output\n");
633 gma_init_lvds(conf, mmio, physbase, pio_res->base,
634 lfb_res->base, edid_lvds);
Arthur Heymansde6ad832016-08-22 17:58:46 +0200635 }
Arthur Heymans53485d22017-04-30 08:29:54 +0200636
637 /* Linux relies on VBT for panel info. */
638 generate_fake_intel_oprom(&conf->gfx, dev, "$VBT CANTIGA");
Arthur Heymansde6ad832016-08-22 17:58:46 +0200639}
640
Nico Huberd85a71a2016-11-27 14:43:12 +0100641static u32 get_cdclk(struct device *const dev)
642{
643 const u16 cdclk_sel =
644 pci_read_config16 (dev, GCFGC_OFFSET) & GCFGC_CD_MASK;
645 switch (MCHBAR8(HPLLVCO_MCHBAR) & 0x7) {
646 case VCO_2666:
647 case VCO_4000:
648 case VCO_5333:
649 return cdclk_sel ? 333333333 : 222222222;
650 case VCO_3200:
651 return cdclk_sel ? 320000000 : 228571429;
652 default:
653 printk(BIOS_WARNING,
654 "Unknown VCO frequency, using default cdclk.\n");
655 return 222222222;
656 }
657}
658
Arthur Heymans12bed262016-11-24 13:23:05 +0100659static u32 freq_to_blc_pwm_ctl(struct device *const dev,
660 u16 pwm_freq, u8 duty_perc)
661{
662 u32 blc_mod;
663
664 blc_mod = get_cdclk(dev) / (128 * pwm_freq);
665
666 if (duty_perc <= 100)
667 return (blc_mod << 16) | (blc_mod * duty_perc / 100);
668 else
669 return (blc_mod << 16) | blc_mod;
670}
671
Arthur Heymans20cb85f2017-04-29 14:31:32 +0200672static void gma_pm_init_post_vbios(struct device *const dev,
673 const char *edid_ascii_string)
Nico Huberb851cc62016-01-09 23:27:16 +0100674{
675 const struct northbridge_intel_gm45_config *const conf = dev->chip_info;
676
677 u32 reg32;
Arthur Heymans12bed262016-11-24 13:23:05 +0100678 u8 reg8;
Arthur Heymans20cb85f2017-04-29 14:31:32 +0200679 const struct blc_pwm_t *blc_pwm;
680 int blc_array_len, i;
681 u16 pwm_freq = 0;
Nico Huberb851cc62016-01-09 23:27:16 +0100682
683 /* Setup Panel Power On Delays */
684 reg32 = gtt_read(PP_ON_DELAYS);
685 if (!reg32) {
686 reg32 = (conf->gpu_panel_power_up_delay & 0x1fff) << 16;
687 reg32 |= (conf->gpu_panel_power_backlight_on_delay & 0x1fff);
688 gtt_write(PP_ON_DELAYS, reg32);
689 }
690
691 /* Setup Panel Power Off Delays */
692 reg32 = gtt_read(PP_OFF_DELAYS);
693 if (!reg32) {
694 reg32 = (conf->gpu_panel_power_down_delay & 0x1fff) << 16;
695 reg32 |= (conf->gpu_panel_power_backlight_off_delay & 0x1fff);
696 gtt_write(PP_OFF_DELAYS, reg32);
697 }
698
699 /* Setup Panel Power Cycle Delay */
700 if (conf->gpu_panel_power_cycle_delay) {
Nico Huberd85a71a2016-11-27 14:43:12 +0100701 reg32 = (get_cdclk(dev) / 20000 - 1)
702 << PP_REFERENCE_DIVIDER_SHIFT;
Nico Huberb851cc62016-01-09 23:27:16 +0100703 reg32 |= conf->gpu_panel_power_cycle_delay & 0x1f;
704 gtt_write(PP_DIVISOR, reg32);
705 }
706
707 /* Enable Backlight */
708 gtt_write(BLC_PWM_CTL2, (1 << 31));
Arthur Heymans12bed262016-11-24 13:23:05 +0100709 reg8 = 100;
710 if (conf->duty_cycle != 0)
711 reg8 = conf->duty_cycle;
Arthur Heymans20cb85f2017-04-29 14:31:32 +0200712 blc_array_len = get_blc_values(&blc_pwm);
713 if (conf->default_pwm_freq != 0)
714 pwm_freq = conf->default_pwm_freq;
715
716 /* Find EDID string and pwm freq in lookup table */
717 for (i = 0; i < blc_array_len; i++) {
718 if (!strncmp(blc_pwm[i].ascii_string, edid_ascii_string,
719 strlen(blc_pwm[i].ascii_string))) {
720 pwm_freq = blc_pwm[i].pwm_freq;
721 printk(BIOS_DEBUG, "Found EDID string: %s in lookup table, pwm: %dHz\n",
722 blc_pwm[i].ascii_string, pwm_freq);
723 break;
724 }
725 }
726
727 if (i == blc_array_len)
728 printk(BIOS_NOTICE, "Your panels EDID `%s` wasn't found in the"
729 "lookup table.\n You may have issues with your panels"
730 "backlight.\n If you want to help improving coreboot"
731 "please report: this EDID string\n and the result"
732 "of `intel_read read BLC_PWM_CTL`"
733 "(from intel-gpu-tools)\n while running vendor BIOS\n",
734 edid_ascii_string);
735
736 if (pwm_freq == 0)
Nico Huberb851cc62016-01-09 23:27:16 +0100737 gtt_write(BLC_PWM_CTL, 0x06100610);
738 else
Arthur Heymans20cb85f2017-04-29 14:31:32 +0200739 gtt_write(BLC_PWM_CTL, freq_to_blc_pwm_ctl(dev, pwm_freq,
740 reg8));
Nico Huberb851cc62016-01-09 23:27:16 +0100741}
742
Vladimir Serbinenko6481e102014-08-10 23:48:11 +0200743static void gma_func0_init(struct device *dev)
744{
745 u32 reg32;
Arthur Heymans53485d22017-04-30 08:29:54 +0200746 u8 *mmio;
747 u8 edid_data_lvds[128];
748 struct edid edid_lvds;
Vladimir Serbinenko6481e102014-08-10 23:48:11 +0200749
750 /* IGD needs to be Bus Master */
751 reg32 = pci_read_config32(dev, PCI_COMMAND);
752 reg32 |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
753 pci_write_config32(dev, PCI_COMMAND, reg32);
754
Vladimir Serbinenko6481e102014-08-10 23:48:11 +0200755 gtt_res = find_resource(dev, PCI_BASE_ADDRESS_0);
Arthur Heymans53485d22017-04-30 08:29:54 +0200756 if (gtt_res == NULL)
757 return;
758 mmio = res2mmio(gtt_res, 0, 0);
Timothy Pearsone7f70902015-04-06 22:01:23 -0500759
Nico Huberee352cd2016-01-09 23:15:53 +0100760 if (!IS_ENABLED(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT)) {
761 /* PCI Init, will run VBIOS */
Arthur Heymans53485d22017-04-30 08:29:54 +0200762 printk(BIOS_DEBUG, "Initialising IGD using VBIOS\n");
Nico Huberee352cd2016-01-09 23:15:53 +0100763 pci_dev_init(dev);
Nico Huberb851cc62016-01-09 23:27:16 +0100764 }
765
Arthur Heymans53485d22017-04-30 08:29:54 +0200766 printk(BIOS_DEBUG, "LVDS EDID\n");
Arthur Heymans8da22862017-08-06 15:56:30 +0200767 intel_gmbus_read_edid(mmio + GMBUS0, GMBUS_PORT_PANEL, 0x50,
768 edid_data_lvds, sizeof(edid_data_lvds));
Arthur Heymans53485d22017-04-30 08:29:54 +0200769 intel_gmbus_stop(mmio + GMBUS0);
770 decode_edid(edid_data_lvds, sizeof(edid_data_lvds), &edid_lvds);
771
Nico Huberb851cc62016-01-09 23:27:16 +0100772 /* Post VBIOS init */
Arthur Heymans20cb85f2017-04-29 14:31:32 +0200773 gma_pm_init_post_vbios(dev, edid_lvds.ascii_string);
Nico Huberb851cc62016-01-09 23:27:16 +0100774
Arthur Heymans53485d22017-04-30 08:29:54 +0200775 if (IS_ENABLED(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT))
776 gma_ngi(dev, &edid_lvds);
Patrick Rudolphf6aa7d92017-09-29 18:28:23 +0200777
778 intel_gma_restore_opregion();
Vladimir Serbinenko6481e102014-08-10 23:48:11 +0200779}
780
781static void gma_set_subsystem(device_t dev, unsigned vendor, unsigned device)
782{
783 if (!vendor || !device) {
784 pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID,
785 pci_read_config32(dev, PCI_VENDOR_ID));
786 } else {
787 pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID,
788 ((device & 0xffff) << 16) | (vendor &
789 0xffff));
790 }
791}
792
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100793const struct i915_gpu_controller_info *
794intel_gma_get_controller_info(void)
795{
796 device_t dev = dev_find_slot(0, PCI_DEVFN(0x2,0));
797 if (!dev) {
798 return NULL;
799 }
800 struct northbridge_intel_gm45_config *chip = dev->chip_info;
801 return &chip->gfx;
802}
803
Alexander Couzens5eea4582015-04-12 22:18:55 +0200804static void gma_ssdt(device_t device)
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100805{
806 const struct i915_gpu_controller_info *gfx = intel_gma_get_controller_info();
807 if (!gfx) {
808 return;
809 }
810
811 drivers_intel_gma_displays_ssdt_generate(gfx);
812}
813
Patrick Rudolphf6aa7d92017-09-29 18:28:23 +0200814static unsigned long
815gma_write_acpi_tables(struct device *const dev,
816 unsigned long current,
817 struct acpi_rsdp *const rsdp)
818{
819 igd_opregion_t *opregion = (igd_opregion_t *)current;
820 global_nvs_t *gnvs;
821
822 if (intel_gma_init_igd_opregion(opregion) != CB_SUCCESS)
823 return current;
824
825 current += sizeof(igd_opregion_t);
826
827 /* GNVS has been already set up */
828 gnvs = cbmem_find(CBMEM_ID_ACPI_GNVS);
829 if (gnvs) {
830 /* IGD OpRegion Base Address */
831 gma_set_gnvs_aslb(gnvs, (uintptr_t)opregion);
832 } else {
833 printk(BIOS_ERR, "Error: GNVS table not found.\n");
834 }
835
836 current = acpi_align_current(current);
837 return current;
838}
839
840static const char *gma_acpi_name(const struct device *dev)
841{
842 return "GFX0";
843}
844
Vladimir Serbinenko6481e102014-08-10 23:48:11 +0200845static struct pci_operations gma_pci_ops = {
846 .set_subsystem = gma_set_subsystem,
847};
848
849static struct device_operations gma_func0_ops = {
850 .read_resources = pci_dev_read_resources,
851 .set_resources = pci_dev_set_resources,
852 .enable_resources = pci_dev_enable_resources,
Vladimir Serbinenkodd2bc3f2014-10-31 09:16:31 +0100853 .acpi_fill_ssdt_generator = gma_ssdt,
Vladimir Serbinenko6481e102014-08-10 23:48:11 +0200854 .init = gma_func0_init,
855 .scan_bus = 0,
856 .enable = 0,
857 .ops_pci = &gma_pci_ops,
Patrick Rudolphf6aa7d92017-09-29 18:28:23 +0200858 .acpi_name = gma_acpi_name,
859 .write_acpi_tables = gma_write_acpi_tables,
Vladimir Serbinenko6481e102014-08-10 23:48:11 +0200860};
861
862static const unsigned short pci_device_ids[] =
863{
864 0x2a42, 0
865};
866
867static const struct pci_driver gma __pci_driver = {
868 .ops = &gma_func0_ops,
869 .vendor = PCI_VENDOR_ID_INTEL,
870 .devices = pci_device_ids,
871};