diff options
Diffstat (limited to 'src/mainboard/google/stout/i915.c')
-rw-r--r-- | src/mainboard/google/stout/i915.c | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/src/mainboard/google/stout/i915.c b/src/mainboard/google/stout/i915.c new file mode 100644 index 0000000000..309d18c35f --- /dev/null +++ b/src/mainboard/google/stout/i915.c @@ -0,0 +1,283 @@ +#include <types.h> +#include <string.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> +#if defined(CONFIG_PCI_OPTION_ROM_RUN_YABEL)&&CONFIG_PCI_OPTION_ROM_RUN_YABEL +#include <x86emu/x86emu.h> +#endif +#include <pc80/mc146818rtc.h> +#include <arch/acpi.h> +#include <arch/io.h> +#include <arch/interrupt.h> +#include <arch/coreboot_tables.h> +#include "hda_verb.h" +#include "onboard.h" +#include "ec.h" +#include <southbridge/intel/bd82x6x/pch.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/amd/mtrr.h> +#include <cpu/x86/msr.h> +#include "i915_reg.h" + +enum { + vmsg = 1, vio = 2, vspin = 4, +}; + +static int verbose = 0; //vmsg ; + +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; + +#define READ32(addr) io_i915_READ32(addr) +#define WRITE32(val, addr) io_i915_WRITE32(val, addr) + +static unsigned long io_i915_READ32(unsigned long addr) +{ + unsigned long val; + outl(addr, addrport); + val = inl(dataport); + return val; +} + +static void io_i915_WRITE32(unsigned long val, unsigned long addr) +{ + 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 char *regname(unsigned long addr) +{ + static char name[16]; + sprintf(name, "0x%lx", addr); + return name; +} + +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()); +} + +/* One-letter commands for code not mean to be ready for humans. + * The code was generated by a set of programs/scripts. + * M print out a kernel message + * R read a register. We do these mainly to ensure that if hardware wanted + * the register read, it was read; also, in debug, we can see what was expected + * and what was found. This has proven *very* useful to get this debugged. + * The udelay, if non-zero, will make sure there is a + * udelay() call with the value. + * The count is from the kernel and tells us how many times this read was done. + * Also useful for debugging and the state + * machine uses the info to drive a poll. + * W Write a register + * V set verbosity. It's a bit mask. + * 0 -> nothing + * 1 -> print kernel messages + * 2 -> print IO ops + * 4 -> print the number of times we spin on a register in a poll + * 8 -> restore whatever the previous verbosity level was + * (only one deep stack) + * + * Again, this is not really meant for human consumption. There is not a poll + * operator as such because, sometimes, there is a read/write/read where the + * second read is a poll, and this chipset is so touchy I'm reluctant to move + * things around and/or delete too many reads. + */ +#define M 1 +#define R 2 +#define W 3 +#define V 4 +#define I 8 + +struct iodef { + unsigned char op; + unsigned int count; + const char *msg; + unsigned long addr; + unsigned long data; + unsigned long udelay; +} iodefs[] = { +#include "i915io.c" +}; + +static int i915_init_done = 0; + +int vbe_mode_info_valid(void); +int vbe_mode_info_valid(void) +{ + return i915_init_done; +} + +void fill_lb_framebuffer(struct lb_framebuffer *framebuffer); +void fill_lb_framebuffer(struct lb_framebuffer *framebuffer) +{ + printk(BIOS_SPEW, "fill_lb_framebuffer: graphics is %p\n", (void *)graphics); + framebuffer->physical_address = graphics; + framebuffer->x_resolution = 2560; + framebuffer->y_resolution = 1700; + framebuffer->bytes_per_line = 10240; + 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 i, prev = 0; + struct iodef *id, *lastidread = 0; + unsigned long u, t; + static unsigned long times[4096]; + 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(); + + /* state machine! */ + for(i = 0, id = iodefs; i < ARRAY_SIZE(iodefs); i++, id++){ + switch(id->op){ + case M: + if (verbose & vmsg) printk(BIOS_SPEW, "%ld: %s\n", + globalmicroseconds(), id->msg); + break; + case R: + u = READ32(id->addr); + if (verbose & vio)printk(BIOS_SPEW, "%s: Got %08lx, expect %08lx\n", + regname(id->addr), u, 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: + if (verbose & vio)printk(BIOS_SPEW, "%s: outl %08lx\n", regname(id->addr), + id->data); + WRITE32(id->data, id->addr); + if (id->addr == PCH_PP_CONTROL){ + switch(id->data & 0xf){ + case 8: break; + case 7: break; + default: udelay(100000); + } + } + break; + case V: + if (id->count < 8){ + prev = verbose; + verbose = id->count; + } else { + verbose = prev; + } + break; + case I: + break; + default: + printk(BIOS_SPEW, "BAD TABLE, opcode %d @ %d\n", id->op, i); + return -1; + } + if (id->udelay) + udelay(id->udelay); + times[i] = globalmicroseconds(); + } + /* optional, we don't even want to take timestamp overhead + * if we can avoid it. */ + if (0) + for(i = 0, id = iodefs; i < ARRAY_SIZE(iodefs); i++, id++){ + switch(id->op){ + case R: + printk(BIOS_SPEW, "%ld: R %08lx\n", times[i], id->addr); + break; + case W: + printk(BIOS_SPEW, "%ld: W %08lx %08lx\n", times[i], + id->addr, id->data); + break; + } + } + + setgtt(0, 4520, physbase, 4096); + printk(BIOS_SPEW, "memset %p to 0 for %d bytes\n", + (void *)graphics, 4520*4096); + memset((void *)graphics, 0, 4520*4096); + printk(BIOS_SPEW, "%ld microseconds\n", globalmicroseconds()); + i915_init_done = 1; + oprom_is_loaded = 1; + return 0; +} |