blob: 8103016c5143397a6146de49353bb279c4b7db2d [file] [log] [blame]
/*
* This file is part of the coreboot project.
*
* Copyright 2013 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 <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"
static int verbose = 0;
static unsigned int *mmio;
static unsigned int graphics;
static unsigned short addrport;
static unsigned short dataport;
static unsigned int physbase;
extern int oprom_is_loaded;
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,
};
static int ioread = 0, iowrite = 0;
static char *regname(unsigned long addr)
{
static char name[16];
sprintf(name, "0x%lx", addr);
return name;
}
unsigned long io_i915_read32(unsigned long addr)
{
unsigned long val;
outl(addr, addrport);
val = inl(dataport);
ioread += 2;
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);
iowrite += 2;
}
/* 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.
* 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.
* This call sets the GTT to point to a linear range of pages
* starting at physbase.
*/
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;
io_i915_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());
}
static int i915_init_done = 0;
int vbe_mode_info_valid(void)
{
return i915_init_done;
}
void fill_lb_framebuffer(struct lb_framebuffer *framebuffer)
{
printk(BIOS_SPEW, "fill_lb_framebuffer: graphics is %p\n",
(void *)graphics);
/* Please note: these will be filled from EDID.
* these values are a placeholder.
*/
framebuffer->physical_address = graphics;
/* these are a fantasy, but will be fixed once we're getting
* info from the hardware. Hard to get from the device tree,
* which is arguably a defect of the device tree. Bear with me,
* this Will Get Fixed.
*/
framebuffer->x_resolution = 1960;
framebuffer->y_resolution = 1700;
framebuffer->bytes_per_line = 1960*4;
framebuffer->bits_per_pixel = 32;
framebuffer->red_mask_pos = 16;
framebuffer->red_mask_size = 8;
framebuffer->green_mask_pos = 8;
framebuffer->green_mask_size = 8;
framebuffer->blue_mask_pos = 0;
framebuffer->blue_mask_size = 8;
framebuffer->reserved_mask_pos = 0;
framebuffer->reserved_mask_size = 0;
}
int i915lightup(unsigned int physbase,
unsigned int iobase,
unsigned int mmio,
unsigned int gfx);
int i915lightup(unsigned int pphysbase, unsigned int piobase,
unsigned int pmmio, unsigned int pgfx)
{
int must_cycle_power = 0;
/* frame buffer pointer */
u32 *l;
int i;
unsigned long before_gtt, after_gtt;
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();
/* turn it on. The VBIOS does it this way, so we hope that's ok. */
verbose = 0;
io_i915_write32(0xabcd000f, PCH_PP_CONTROL);
/* the AUX channel needs a small amount of time to spin up.
* Rather than udelay, do some useful work:
* Zero out the frame buffer memory,
* and set the global translation table (GTT)
*/
printk(BIOS_SPEW, "Set not-White (%08x) for %d pixels\n", 0xffffff,
FRAME_BUFFER_BYTES/sizeof(u32));
for(l = (u32 *)graphics, i = 0;
i < FRAME_BUFFER_BYTES/sizeof(u32); i++){
l[i] = 0x1122ff;
}
printk(BIOS_SPEW, "GTT: set %d pages starting at %p\n",
FRAME_BUFFER_PAGES, (void *)physbase);
before_gtt = globalmicroseconds();
setgtt(0, FRAME_BUFFER_PAGES, physbase, 4096);
after_gtt = globalmicroseconds();
/* The reset is basically harmless, and can be
* repeated by the VBIOS in any event.
*/
graphics_register_reset(DPA_AUX_CH_CTL, DPA_AUX_CH_DATA1, verbose);
/* failures after this point can return without
* powering off the panel.
*/
if (1)
goto fail;
/* failures after this point MUST power off the panel
* and wait 600 ms.
*/
i915_init_done = 1;
oprom_is_loaded = 1;
return 1;
fail:
printk(BIOS_SPEW, "Graphics could not be started;");
if (must_cycle_power){
printk(BIOS_SPEW, "Turn off power and wait ...");
io_i915_write32(0xabcd0000, PCH_PP_CONTROL);
udelay(600000);
}
printk(BIOS_SPEW, "Returning.\n");
return 0;
}