blob: 7455704530e142e98de036ecaca024a5e0e98e83 [file] [log] [blame]
Vladimir Serbinenkoa71bdc32014-08-30 00:35:39 +02001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2013, 2014 Vladimir Serbinenko
Nico Huber561bebf2017-01-19 16:28:18 +01005 * Copyright (C) 2017 secunet Security Networks AG
Vladimir Serbinenkoa71bdc32014-08-30 00:35:39 +02006 *
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 or (at your option)
10 * any later version of the License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
Vladimir Serbinenkoa71bdc32014-08-30 00:35:39 +020016 */
17
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020018#include <device/pci_ops.h>
Vladimir Serbinenkoa71bdc32014-08-30 00:35:39 +020019#include <delay.h>
20#include <device/device.h>
21#include <string.h>
Nico Huberd37fa8d2017-01-19 16:11:58 +010022#include <device/pci.h>
Patrick Rudolph45a0dbc2017-03-30 17:07:42 +020023#include <drivers/intel/gma/opregion.h>
Vladimir Serbinenkoa71bdc32014-08-30 00:35:39 +020024
25#include "i915.h"
26#include "intel_bios.h"
27
Nico Huberd37fa8d2017-01-19 16:11:58 +010028static size_t generate_vbt(const struct i915_gpu_controller_info *const conf,
29 struct vbt_header *const head,
30 const char *const idstr)
Vladimir Serbinenkoa71bdc32014-08-30 00:35:39 +020031{
Vladimir Serbinenkoa71bdc32014-08-30 00:35:39 +020032 u8 *ptr;
33
Elyes HAOUAS9b865b42016-10-03 22:19:16 +020034 memset(head, 0, sizeof (*head));
Vladimir Serbinenkoa71bdc32014-08-30 00:35:39 +020035
Nico Huberd37fa8d2017-01-19 16:11:58 +010036 memset(head->signature, ' ', sizeof (head->signature));
37 memcpy(head->signature, idstr,
38 MIN(strlen(idstr), sizeof (head->signature)));
Vladimir Serbinenkoa71bdc32014-08-30 00:35:39 +020039 head->version = 100;
40 head->header_size = sizeof (*head);
41 head->bdb_offset = sizeof (*head);
42
Nico Huberd37fa8d2017-01-19 16:11:58 +010043 struct bdb_header *const bdb_head = (struct bdb_header *)(head + 1);
Elyes HAOUAS9b865b42016-10-03 22:19:16 +020044 memset(bdb_head, 0, sizeof (*bdb_head));
45 memcpy(bdb_head->signature, "BIOS_DATA_BLOCK ", 16);
Vladimir Serbinenkoa71bdc32014-08-30 00:35:39 +020046 bdb_head->version = 0xa8;
47 bdb_head->header_size = sizeof (*bdb_head);
48
Nico Huberd37fa8d2017-01-19 16:11:58 +010049 ptr = (u8 *)(bdb_head + 1);
Vladimir Serbinenkoa71bdc32014-08-30 00:35:39 +020050
51 ptr[0] = BDB_GENERAL_FEATURES;
Nico Huberd37fa8d2017-01-19 16:11:58 +010052 ptr[1] = sizeof (struct bdb_general_features);
53 ptr[2] = sizeof (struct bdb_general_features) >> 8;
Vladimir Serbinenkoa71bdc32014-08-30 00:35:39 +020054 ptr += 3;
55
Nico Huberd37fa8d2017-01-19 16:11:58 +010056 struct bdb_general_features *const genfeat =
57 (struct bdb_general_features *)ptr;
Elyes HAOUAS9b865b42016-10-03 22:19:16 +020058 memset(genfeat, 0, sizeof (*genfeat));
Vladimir Serbinenkoa71bdc32014-08-30 00:35:39 +020059 genfeat->panel_fitting = 3;
60 genfeat->flexaim = 1;
61 genfeat->download_ext_vbt = 1;
62 genfeat->enable_ssc = conf->use_spread_spectrum_clock;
Julius Wernercd49cce2019-03-05 16:53:33 -080063 genfeat->ssc_freq = CONFIG(INTEL_GMA_SSC_ALTERNATE_REF);
Vladimir Serbinenkoa71bdc32014-08-30 00:35:39 +020064 genfeat->rsvd10 = 0x4;
65 genfeat->legacy_monitor_detect = 1;
66 genfeat->int_crt_support = 1;
67 genfeat->dp_ssc_enb = 1;
68
69 ptr += sizeof (*genfeat);
70
71 bdb_head->bdb_size = ptr - (u8 *)bdb_head;
72 head->vbt_size = ptr - (u8 *)head;
73 head->vbt_checksum = 0;
74 return ptr - (u8 *)head;
75}
76
77void
Nico Huberd37fa8d2017-01-19 16:11:58 +010078generate_fake_intel_oprom(const struct i915_gpu_controller_info *const conf,
79 struct device *const dev, const char *const idstr)
Vladimir Serbinenkoa71bdc32014-08-30 00:35:39 +020080{
Nico Huberd37fa8d2017-01-19 16:11:58 +010081 optionrom_header_t *const oh = (void *)PCI_VGA_RAM_IMAGE_START;
Vladimir Serbinenkoa71bdc32014-08-30 00:35:39 +020082
Nico Huberd37fa8d2017-01-19 16:11:58 +010083 memset(oh, 0, 8192);
Vladimir Serbinenkoa71bdc32014-08-30 00:35:39 +020084
Nico Huberd37fa8d2017-01-19 16:11:58 +010085 oh->signature = PCI_ROM_HDR;
86 oh->pcir_offset = 0x40;
87 oh->vbt_offset = 0x80;
Vladimir Serbinenkoa71bdc32014-08-30 00:35:39 +020088
Nico Huberd37fa8d2017-01-19 16:11:58 +010089 optionrom_pcir_t *const pcir = (void *)((u8 *)oh + oh->pcir_offset);
90 pcir->signature = 0x52494350; // PCIR
91 pcir->vendor = dev->vendor;
92 pcir->device = dev->device;
93 pcir->length = sizeof(*pcir);
94 pcir->revision = pci_read_config8(dev, PCI_CLASS_REVISION);
95 pcir->classcode[0] = dev->class;
96 pcir->classcode[1] = dev->class >> 8;
97 pcir->classcode[2] = dev->class >> 16;
98 pcir->indicator = 0x80;
Vladimir Serbinenkoa71bdc32014-08-30 00:35:39 +020099
Nico Huberd37fa8d2017-01-19 16:11:58 +0100100 const size_t vbt_size =
101 generate_vbt(conf, (void *)((u8 *)oh + oh->vbt_offset), idstr);
102 const size_t fake_oprom_size =
103 DIV_ROUND_UP(oh->vbt_offset + vbt_size, 512);
104 oh->size = fake_oprom_size;
105 pcir->imagelength = fake_oprom_size;
Vladimir Serbinenkoa71bdc32014-08-30 00:35:39 +0200106}