9518b56ab0
Peppy had some issues with FUI. We decided it was time to create peppy-specific gma.c and i915io.c files. Using yabel and the i915tool, we generated a replay attack, then interpolated against the slippy i915io.c to get something working. Also, in preparation for moving code out of the mainboard gma.c to generic driver code, we got rid of some hardcodes in the mainboard gma.c that have no business being there. The worst were the computation of gmch_[m,n] and it turns out that we had some long-standing bugs related to confusion about 'bpp'. I've killed the word bpp everywhere I could because there are at least 3 things that correspond to bpp. We now have framebuffer, pipe, and panel bpp. The names are long because I want to avoid all the mistakes we've all been making in the last year :-) Sadly, that means a lot of changes not just peppy-related, but they are simple and in a good cause. The test pattern generation is driven by a global variable in mainboard/peppy/gma.c. I've found in the past that it's very useful to have a function like this available, as one can activate it while using a jtag debugger: halt at the right place in ramstage, set the variable to 1, continue. It's not enough code to worry about always including. The last hard-codes for M and N registers are gone, and the function to set from generic intel_dp.c code works. To avoid screen trash on a dev mode boot, which we liked but nobody else did :-), we now take the time to put a pleasing background color that sort of doubles as a power LED. Rough timing is ramstage start is at 2.2, and dev setup is done at 3.3. These new platforms are depressingly slow to boot. Rom init alone is taking 1.9 seconds. 13 years ago it was 3 seconds from power on to bash prompt. These CPUs are at least 10x faster and take much longer to get going. Future work, once we get this through, is to move more functions to the intel driver, and combine the mainboard i915io.c into the mainboard gma.c. That separation only existed because i915io.c was generated by a tool, and it had lots of ugliness. Most ugliness is gone. Old-Change-Id: I6a6295b423a41e263f82cef33eacb92a14163321 Signed-off-by: Ronald G. Minnich <rminnich@gmail.com> Reviewed-on: https://chromium-review.googlesource.com/170013 Reviewed-by: Stefan Reinauer <reinauer@google.com> Commit-Queue: Ronald Minnich <rminnich@chromium.org> Tested-by: Ronald Minnich <rminnich@chromium.org> Reviewed-by: Furquan Shaikh <furquan.m.shaikh@gmail.com> (cherry picked from commit 8cdaf73e3602e15925859866714db4d5ec6c947d) snow: Fix a typo in devicetree.cb that was breaking the snow build. A typo in a recent change broke the snow build. Old-Change-Id: I93074e68eb3d21510d974fd8e9c63b3947285afd Signed-off-by: Gabe Black <gabeblack@google.com> Reviewed-on: https://chromium-review.googlesource.com/171014 Reviewed-by: Ronald Minnich <rminnich@chromium.org> Commit-Queue: Gabe Black <gabeblack@chromium.org> Tested-by: Gabe Black <gabeblack@chromium.org> (cherry picked from commit 154876c126a6690930141df178485658533096d2) Squashed a fix into the initial patch and updated nehalem/gma.c to have a non-static gtt_poll. Change-Id: I2f4342c610d87335411da1d6d405171dc80c1f14 Signed-off-by: Isaac Christensen <isaac.christensen@se-eng.com> Reviewed-on: http://review.coreboot.org/6657 Tested-by: build bot (Jenkins)
380 lines
11 KiB
C
380 lines
11 KiB
C
/*
|
|
* This file is part of the coreboot project.
|
|
*
|
|
* Copyright (C) 2012 Google Inc.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; version 2 of the License.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include <types.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <device/device.h>
|
|
#include <device/device.h>
|
|
#include <device/pci_def.h>
|
|
#include <device/pci_ops.h>
|
|
#include <console/console.h>
|
|
#include <delay.h>
|
|
#include <pc80/mc146818rtc.h>
|
|
#include <arch/acpi.h>
|
|
#include <arch/io.h>
|
|
#include <arch/interrupt.h>
|
|
#include <boot/coreboot_tables.h>
|
|
#include "hda_verb.h"
|
|
#include "onboard.h"
|
|
#include "ec.h"
|
|
#include <southbridge/intel/bd82x6x/pch.h>
|
|
#include <northbridge/intel/sandybridge/gma.h>
|
|
#include <smbios.h>
|
|
#include <device/pci.h>
|
|
#include <ec/google/chromeec/ec.h>
|
|
#include <cbfs_core.h>
|
|
|
|
#include <cpu/x86/tsc.h>
|
|
#include <cpu/x86/cache.h>
|
|
#include <cpu/x86/mtrr.h>
|
|
#include <cpu/x86/msr.h>
|
|
#include <edid.h>
|
|
#include "i915io.h"
|
|
|
|
enum {
|
|
vmsg = 1, vio = 2, vspin = 4,
|
|
};
|
|
|
|
static int verbose = 0;
|
|
|
|
static unsigned int *mmio;
|
|
static unsigned int graphics;
|
|
static unsigned short addrport;
|
|
static unsigned short dataport;
|
|
static unsigned int physbase;
|
|
static u32 htotal, hblank, hsync, vtotal, vblank, vsync;
|
|
|
|
const u32 link_edid_data[] = {
|
|
0xffffff00, 0x00ffffff, 0x0379e430, 0x00000000,
|
|
0x04011500, 0x96121ba5, 0xa2d54f02, 0x26935259,
|
|
0x00545017, 0x01010000, 0x01010101, 0x01010101,
|
|
0x01010101, 0x6f6d0101, 0xa4a0a000, 0x20306031,
|
|
0xb510003a, 0x19000010, 0x00000000, 0x00000000,
|
|
0x00000000, 0x00000000, 0x00000000, 0x4c00fe00,
|
|
0x69442047, 0x616c7073, 0x20200a79, 0xfe000000,
|
|
0x31504c00, 0x45513932, 0x50532d31, 0x24003141,
|
|
};
|
|
|
|
#define READ32(addr) io_i915_READ32(addr)
|
|
#define WRITE32(val, addr) io_i915_WRITE32(val, addr)
|
|
|
|
static char *regname(unsigned long addr)
|
|
{
|
|
static char name[16];
|
|
snprintf(name, sizeof (name), "0x%lx", addr);
|
|
return name;
|
|
}
|
|
|
|
unsigned long io_i915_READ32(unsigned long addr)
|
|
{
|
|
unsigned long val;
|
|
outl(addr, addrport);
|
|
val = inl(dataport);
|
|
if (verbose & vio)
|
|
printk(BIOS_SPEW, "%s: Got %08lx\n", regname(addr), val);
|
|
return val;
|
|
}
|
|
|
|
void io_i915_WRITE32(unsigned long val, unsigned long addr)
|
|
{
|
|
if (verbose & vio)
|
|
printk(BIOS_SPEW, "%s: outl %08lx\n", regname(addr), val);
|
|
outl(addr, addrport);
|
|
outl(val, dataport);
|
|
}
|
|
|
|
|
|
/*
|
|
2560
|
|
4 words per
|
|
4 *p
|
|
10240
|
|
4k bytes per page
|
|
4096/p
|
|
2.50
|
|
1700 lines
|
|
1700 * p
|
|
4250.00
|
|
PTEs
|
|
*/
|
|
static void
|
|
setgtt(int start, int end, unsigned long base, int inc)
|
|
{
|
|
int i;
|
|
|
|
for(i = start; i < end; i++){
|
|
u32 word = base + i*inc;
|
|
WRITE32(word|1,(i*4)|1);
|
|
}
|
|
}
|
|
|
|
static unsigned long tickspermicrosecond = 1795;
|
|
static unsigned long long globalstart;
|
|
|
|
static unsigned long
|
|
microseconds(unsigned long long start, unsigned long long end)
|
|
{
|
|
unsigned long ret;
|
|
ret = ((end - start)/tickspermicrosecond);
|
|
return ret;
|
|
}
|
|
|
|
static unsigned long globalmicroseconds(void)
|
|
{
|
|
return microseconds(globalstart, rdtscll());
|
|
}
|
|
|
|
extern struct iodef iodefs[];
|
|
extern int niodefs;
|
|
|
|
static int i915_init_done = 0;
|
|
|
|
/* fill the palette. This runs when the P opcode is hit. */
|
|
/* and, yes, it's needed for even 32 bits per pixel */
|
|
static void palette(void)
|
|
{
|
|
int i;
|
|
unsigned long color = 0;
|
|
|
|
for(i = 0; i < 256; i++, color += 0x010101){
|
|
io_i915_WRITE32(color, _LGC_PALETTE_A + (i<<2));
|
|
}
|
|
}
|
|
|
|
static unsigned long times[4096];
|
|
|
|
static int run(int index)
|
|
{
|
|
int i, prev = 0;
|
|
struct iodef *id, *lastidread = 0;
|
|
unsigned long u, t;
|
|
if (index >= niodefs)
|
|
return index;
|
|
/* state machine! */
|
|
for(i = index, id = &iodefs[i]; id->op; i++, id++){
|
|
switch(id->op){
|
|
case M:
|
|
if (verbose & vmsg) printk(BIOS_SPEW, "%ld: %s\n",
|
|
globalmicroseconds(), id->msg);
|
|
break;
|
|
case P:
|
|
palette();
|
|
break;
|
|
case R:
|
|
u = READ32(id->addr);
|
|
if (verbose & vio)
|
|
printk(BIOS_SPEW, "\texpect %08lx\n", id->data);
|
|
/* we're looking for something. */
|
|
if (lastidread->addr == id->addr){
|
|
/* they're going to be polling.
|
|
* just do it 1000 times
|
|
*/
|
|
for (t = 0; t < 1000 && id->data != u; t++){
|
|
u = READ32(id->addr);
|
|
}
|
|
if (verbose & vspin) printk(BIOS_SPEW,
|
|
"%s: # loops %ld got %08lx want %08lx\n",
|
|
regname(id->addr),
|
|
t, u, id->data);
|
|
}
|
|
lastidread = id;
|
|
break;
|
|
case W:
|
|
WRITE32(id->data, id->addr);
|
|
if (id->addr == PCH_PP_CONTROL){
|
|
if (verbose & vio)
|
|
printk(BIOS_SPEW, "PCH_PP_CONTROL\n");
|
|
switch(id->data & 0xf){
|
|
case 8: break;
|
|
case 7: break;
|
|
default: udelay(100000);
|
|
if (verbose & vio)
|
|
printk(BIOS_SPEW, "U %d\n", 100000);
|
|
}
|
|
}
|
|
break;
|
|
case V:
|
|
if (id->count < 8){
|
|
prev = verbose;
|
|
verbose = id->count;
|
|
} else {
|
|
verbose = prev;
|
|
}
|
|
printk(BIOS_SPEW, "Change verbosity to %d\n", verbose);
|
|
break;
|
|
case I:
|
|
printk(BIOS_SPEW, "run: return %d\n", i+1);
|
|
return i+1;
|
|
break;
|
|
default:
|
|
printk(BIOS_SPEW, "BAD TABLE, opcode %d @ %d\n", id->op, i);
|
|
return -1;
|
|
}
|
|
if (id->udelay)
|
|
udelay(id->udelay);
|
|
if (i < ARRAY_SIZE(times))
|
|
times[i] = globalmicroseconds();
|
|
}
|
|
printk(BIOS_SPEW, "run: return %d\n", i);
|
|
return i+1;
|
|
}
|
|
|
|
int i915lightup(const struct northbridge_intel_sandybridge_config *info,
|
|
u32 pphysbase, u16 piobase, u32 pmmio, u32 pgfx)
|
|
{
|
|
static struct edid edid;
|
|
int edid_ok;
|
|
|
|
int index;
|
|
u32 auxin[16], auxout[16];
|
|
mmio = (void *)pmmio;
|
|
addrport = piobase;
|
|
dataport = addrport + 4;
|
|
physbase = pphysbase;
|
|
graphics = pgfx;
|
|
printk(BIOS_SPEW, "i915lightup: graphics %p mmio %p"
|
|
"addrport %04x physbase %08x\n",
|
|
(void *)graphics, mmio, addrport, physbase);
|
|
globalstart = rdtscll();
|
|
|
|
|
|
edid_ok = decode_edid((unsigned char *)&link_edid_data,
|
|
sizeof(link_edid_data), &edid);
|
|
printk(BIOS_SPEW, "decode edid returns %d\n", edid_ok);
|
|
edid.framebuffer_bits_per_pixel = 32;
|
|
|
|
htotal = (edid.ha - 1) | ((edid.ha + edid.hbl- 1) << 16);
|
|
printk(BIOS_SPEW, "I915_WRITE(HTOTAL(pipe), %08x)\n", htotal);
|
|
|
|
hblank = (edid.ha - 1) | ((edid.ha + edid.hbl- 1) << 16);
|
|
printk(BIOS_SPEW, "I915_WRITE(HBLANK(pipe),0x%08x)\n", hblank);
|
|
|
|
hsync = (edid.ha + edid.hso - 1) |
|
|
((edid.ha + edid.hso + edid.hspw- 1) << 16);
|
|
printk(BIOS_SPEW, "I915_WRITE(HSYNC(pipe),0x%08x)\n", hsync);
|
|
|
|
vtotal = (edid.va - 1) | ((edid.va + edid.vbl- 1) << 16);
|
|
printk(BIOS_SPEW, "I915_WRITE(VTOTAL(pipe), %08x)\n", vtotal);
|
|
|
|
vblank = (edid.va - 1) | ((edid.va + edid.vbl- 1) << 16);
|
|
printk(BIOS_SPEW, "I915_WRITE(VBLANK(pipe),0x%08x)\n", vblank);
|
|
|
|
vsync = (edid.va + edid.vso - 1) |((edid.va + edid.vso + edid.vspw- 1) << 16);
|
|
printk(BIOS_SPEW, "I915_WRITE(VSYNC(pipe),0x%08x)\n", vsync);
|
|
|
|
printk(BIOS_SPEW, "Table has %d elements\n", niodefs);
|
|
|
|
index = run(0);
|
|
printk(BIOS_SPEW, "Run returns %d\n", index);
|
|
auxout[0] = 1<<31 /* dp */|0x1<<28/*R*/|DP_DPCD_REV<<8|0xe;
|
|
intel_dp_aux_ch(DPA_AUX_CH_CTL, DPA_AUX_CH_DATA1, auxout, 4, auxin, 14);
|
|
auxout[0] = 0<<31 /* i2c */|1<<30|0x0<<28/*W*/|0x0<<8|0x0;
|
|
intel_dp_aux_ch(DPA_AUX_CH_CTL, DPA_AUX_CH_DATA1, auxout, 3, auxin, 0);
|
|
index = run(index);
|
|
printk(BIOS_SPEW, "Run returns %d\n", index);
|
|
auxout[0] = 0<<31 /* i2c */|0<<30|0x0<<28/*W*/|0x0<<8|0x0;
|
|
intel_dp_aux_ch(DPA_AUX_CH_CTL, DPA_AUX_CH_DATA1, auxout, 3, auxin, 0);
|
|
index = run(index);
|
|
printk(BIOS_SPEW, "Run returns %d\n", index);
|
|
auxout[0] = 1<<31 /* dp */|0x0<<28/*W*/|DP_SET_POWER<<8|0x0;
|
|
auxout[1] = 0x01000000;
|
|
/* DP_SET_POWER_D0 | DP_PSR_SINK_INACTIVE */
|
|
intel_dp_aux_ch(DPA_AUX_CH_CTL, DPA_AUX_CH_DATA1, auxout, 5, auxin, 0);
|
|
index = run(index);
|
|
auxout[0] = 1<<31 /* dp */|0x0<<28/*W*/|DP_LINK_BW_SET<<8|0x8;
|
|
auxout[1] = 0x0a840000;
|
|
/*( DP_LINK_BW_2_7 &0xa)|0x0000840a*/
|
|
auxout[2] = 0x00000000;
|
|
auxout[3] = 0x01000000;
|
|
intel_dp_aux_ch(DPA_AUX_CH_CTL, DPA_AUX_CH_DATA1, auxout, 13, auxin, 0);
|
|
index = run(index);
|
|
auxout[0] = 1<<31 /* dp */|0x0<<28/*W*/|DP_TRAINING_PATTERN_SET<<8|0x0;
|
|
auxout[1] = 0x21000000;
|
|
/* DP_TRAINING_PATTERN_1 | DP_LINK_SCRAMBLING_DISABLE |
|
|
* DP_SYMBOL_ERROR_COUNT_BOTH |0x00000021*/
|
|
intel_dp_aux_ch(DPA_AUX_CH_CTL, DPA_AUX_CH_DATA1, auxout, 5, auxin, 0);
|
|
index = run(index);
|
|
auxout[0] = 1<<31 /* dp */|0x0<<28/*W*/|DP_TRAINING_LANE0_SET<<8|0x3;
|
|
auxout[1] = 0x00000000;
|
|
/* DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_0 |0x00000000*/
|
|
intel_dp_aux_ch(DPA_AUX_CH_CTL, DPA_AUX_CH_DATA1, auxout, 8, auxin, 0);
|
|
index = run(index);
|
|
auxout[0] = 1<<31 /* dp */|0x1<<28/*R*/|DP_LANE0_1_STATUS<<8|0x5;
|
|
intel_dp_aux_ch(DPA_AUX_CH_CTL, DPA_AUX_CH_DATA1, auxout, 4, auxin, 5);
|
|
index = run(index);
|
|
auxout[0] = 1<<31 /* dp */|0x0<<28/*W*/|DP_TRAINING_PATTERN_SET<<8|0x0;
|
|
auxout[1] = 0x22000000;
|
|
/* DP_TRAINING_PATTERN_2 | DP_LINK_SCRAMBLING_DISABLE |
|
|
* DP_SYMBOL_ERROR_COUNT_BOTH |0x00000022*/
|
|
intel_dp_aux_ch(DPA_AUX_CH_CTL, DPA_AUX_CH_DATA1, auxout, 5, auxin, 0);
|
|
index = run(index);
|
|
auxout[0] = 1<<31 /* dp */|0x0<<28/*W*/|DP_TRAINING_LANE0_SET<<8|0x3;
|
|
auxout[1] = 0x00000000;
|
|
/* DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_0 |0x00000000*/
|
|
intel_dp_aux_ch(DPA_AUX_CH_CTL, DPA_AUX_CH_DATA1, auxout, 8, auxin, 0);
|
|
index = run(index);
|
|
auxout[0] = 1<<31 /* dp */|0x1<<28/*R*/|DP_LANE0_1_STATUS<<8|0x5;
|
|
intel_dp_aux_ch(DPA_AUX_CH_CTL, DPA_AUX_CH_DATA1, auxout, 4, auxin, 5);
|
|
index = run(index);
|
|
auxout[0] = 1<<31 /* dp */|0x0<<28/*W*/|DP_TRAINING_PATTERN_SET<<8|0x0;
|
|
auxout[1] = 0x00000000;
|
|
/* DP_TRAINING_PATTERN_DISABLE | DP_LINK_QUAL_PATTERN_DISABLE |
|
|
* DP_SYMBOL_ERROR_COUNT_BOTH |0x00000000*/
|
|
intel_dp_aux_ch(DPA_AUX_CH_CTL, DPA_AUX_CH_DATA1, auxout, 5, auxin, 0);
|
|
index = run(index);
|
|
|
|
if (index != niodefs)
|
|
printk(BIOS_ERR, "Left over IO work in i915_lightup"
|
|
" -- this is likely a table error. "
|
|
"Only %d of %d were done.\n", index, niodefs);
|
|
printk(BIOS_SPEW, "DONE startup\n");
|
|
verbose = 0;
|
|
/* GTT is the Global Translation Table for the graphics pipeline.
|
|
* It is used to translate graphics addresses to physical
|
|
* memory addresses. As in the CPU, GTTs map 4K pages.
|
|
* There are 32 bits per pixel, or 4 bytes,
|
|
* which means 1024 pixels per page.
|
|
* There are 4250 GTTs on Link:
|
|
* 2650 (X) * 1700 (Y) pixels / 1024 pixels per page.
|
|
* The setgtt function adds a further bit of flexibility:
|
|
* it allows you to set a range (the first two parameters) to point
|
|
* to a physical address (third parameter);the physical address is
|
|
* incremented by a count (fourth parameter) for each GTT in the
|
|
* range.
|
|
* Why do it this way? For ultrafast startup,
|
|
* we can point all the GTT entries to point to one page,
|
|
* and set that page to 0s:
|
|
* memset(physbase, 0, 4096);
|
|
* setgtt(0, 4250, physbase, 0);
|
|
* this takes about 2 ms, and is a win because zeroing
|
|
* the page takes a up to 200 ms. We will be exploiting this
|
|
* trick in a later rev of this code.
|
|
* This call sets the GTT to point to a linear range of pages
|
|
* starting at physbase.
|
|
*/
|
|
setgtt(0, FRAME_BUFFER_PAGES, physbase, 4096);
|
|
printk(BIOS_SPEW, "memset %p to 0 for %d bytes\n",
|
|
(void *)graphics, FRAME_BUFFER_BYTES);
|
|
memset((void *)graphics, 0, FRAME_BUFFER_BYTES);
|
|
printk(BIOS_SPEW, "%ld microseconds\n", globalmicroseconds());
|
|
set_vbe_mode_info_valid(&edid, graphics);
|
|
i915_init_done = 1;
|
|
return i915_init_done;
|
|
}
|