aboutsummaryrefslogtreecommitdiff
path: root/src/mainboard/intel/wtm2/i915.c
diff options
context:
space:
mode:
authorRonald G. Minnich <rminnich@google.com>2013-03-28 17:01:43 -0700
committerStefan Reinauer <stefan.reinauer@coreboot.org>2013-07-09 22:16:09 +0200
commit2a66d6b804acd22fddc2e51550ba39d2561c1234 (patch)
treecc858e8fd6a4c536bff82b7b2cc1e53a12beebe7 /src/mainboard/intel/wtm2/i915.c
parentf42b83e958f4529ef5a859494807914a5601d2f9 (diff)
FOX_WTM2: First pass at FUI.
This lights up the display. We don't get graphics but we are missing the gttsetup at this point, so that is no shock. The real shock is that anything works at all. Change-Id: I03fc470334e96878aeb8465044b3cc9c90378735 Signed-off-by: Ronald G. Minnich <rminnich@google.com> Signed-off-by: Gabe Black <gabeblack@chromium.org> Reviewed-on: http://review.coreboot.org/3634 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Diffstat (limited to 'src/mainboard/intel/wtm2/i915.c')
-rw-r--r--src/mainboard/intel/wtm2/i915.c405
1 files changed, 405 insertions, 0 deletions
diff --git a/src/mainboard/intel/wtm2/i915.c b/src/mainboard/intel/wtm2/i915.c
new file mode 100644
index 0000000000..41c8b15e1c
--- /dev/null
+++ b/src/mainboard/intel/wtm2/i915.c
@@ -0,0 +1,405 @@
+/*
+ * 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 <arch/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/amd/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;
+extern int oprom_is_loaded;
+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];
+ sprintf(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. */
+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));
+ }
+}
+
+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;
+
+}
+
+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(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)
+{
+ static struct edid edid;
+
+ 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();
+
+
+ index = run(0);
+ if (0){
+ decode_edid((unsigned char *)&link_edid_data, sizeof(link_edid_data), &edid);
+
+ 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 |
+ * (0x0<<13602104)|0x00000001*/ /* broken, fix. */
+ 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());
+ i915_init_done = 1;
+ oprom_is_loaded = 1;
+ return 0;
+}