summaryrefslogtreecommitdiff
path: root/src/mainboard/google/stout/i915.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mainboard/google/stout/i915.c')
-rw-r--r--src/mainboard/google/stout/i915.c283
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;
+}