From bb01deb8bbed56f15e1143504e4cf012ecf5a281 Mon Sep 17 00:00:00 2001 From: Duncan Laurie Date: Fri, 2 May 2014 14:22:18 -0700 Subject: [PATCH] broadwell: Update ramstage graphics driver to support broadwell - Convert most of the init code to use reg_script - Separate haswell and broadwell init, very similar but there are subtle differences that make it easier to treat the separately. - Set up CD clock based on specific IGD type. The initial value can be selected in devicetree config but may be overridden by specific limitations of the IGD device. This is configured differently on haswell and broadwell and is not done in reg_script because of the subtle requirements for detecting the proper clock frequency. - Panel setup is currently unchanged although it may not be entirely correct as I am still waiting for working kernel graphics. - The i915 init code is removed and the VBIOS is used instead until we can put more resources into native init. BUG=chrome-os-partner:28234 TEST=Tested working firmware graphics on samus panel as well as external panel connected via display port. Change-Id: I3a910f18ae15d02202e51bde104a9c316338712a Signed-off-by: Duncan Laurie Reviewed-on: https://chromium-review.googlesource.com/199368 Reviewed-by: Aaron Durbin --- src/soc/intel/broadwell/igd.c | 673 ++++++++++++++++++---------------- 1 file changed, 350 insertions(+), 323 deletions(-) diff --git a/src/soc/intel/broadwell/igd.c b/src/soc/intel/broadwell/igd.c index 6f72b1fa82..8235b3f3df 100644 --- a/src/soc/intel/broadwell/igd.c +++ b/src/soc/intel/broadwell/igd.c @@ -23,152 +23,226 @@ #include #include #include -#include -#include -#include #include #include +#include +#include +#include #include +#include +#include -#include "chip.h" -#include "haswell.h" +#define GT_RETRY 1000 +#define GT_CDCLK_337 0 +#define GT_CDCLK_450 1 +#define GT_CDCLK_540 2 +#define GT_CDCLK_675 3 -#if CONFIG_CHROMEOS -#include -#endif +struct reg_script haswell_early_init_script[] = { + /* Enable Force Wake */ + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0xa180, 0x00000020), + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0xa188, 0x00010001), + REG_RES_POLL32(PCI_BASE_ADDRESS_0, 0x130044, 1, 1, GT_RETRY), -struct gt_reg { - u32 reg; - u32 andmask; - u32 ormask; -}; - -static const struct gt_reg haswell_gt_setup[] = { /* Enable Counters */ - { 0x0a248, 0x00000000, 0x00000016 }, - { 0x0a000, 0x00000000, 0x00070020 }, - { 0x0a180, 0xff3fffff, 0x15000000 }, + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0xa248, 0x00000016), + + /* GFXPAUSE settings */ + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0xa000, 0x00070020), + + /* ECO Settings */ + REG_RES_RMW32(PCI_BASE_ADDRESS_0, 0xa180, 0xff3fffff, 0x15000000), + /* Enable DOP Clock Gating */ - { 0x09424, 0x00000000, 0x000003fd }, + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0x9424, 0x000003fd), + /* Enable Unit Level Clock Gating */ - { 0x09400, 0x00000000, 0x00000080 }, - { 0x09404, 0x00000000, 0x40401000 }, - { 0x09408, 0x00000000, 0x00000000 }, - { 0x0940c, 0x00000000, 0x02000001 }, - { 0x0a008, 0x00000000, 0x08000000 }, + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0x9400, 0x00000080), + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0x9404, 0x40401000), + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0x9408, 0x00000000), + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0x940c, 0x02000001), + + /* + * RC6 Settings + */ + /* Wake Rate Limits */ - { 0x0a090, 0xffffffff, 0x00000000 }, - { 0x0a098, 0xffffffff, 0x03e80000 }, - { 0x0a09c, 0xffffffff, 0x00280000 }, - { 0x0a0a8, 0xffffffff, 0x0001e848 }, - { 0x0a0ac, 0xffffffff, 0x00000019 }, + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0xa090, 0x00000000), + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0xa098, 0x03e80000), + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0xa09c, 0x00280000), + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0xa0a8, 0x0001e848), + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0xa0ac, 0x00000019), + /* Render/Video/Blitter Idle Max Count */ - { 0x02054, 0x00000000, 0x0000000a }, - { 0x12054, 0x00000000, 0x0000000a }, - { 0x22054, 0x00000000, 0x0000000a }, + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0x02054, 0x0000000a), + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0x12054, 0x0000000a), + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0x22054, 0x0000000a), + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0x1a054, 0x0000000a), + /* RC Sleep / RCx Thresholds */ - { 0x0a0b0, 0xffffffff, 0x00000000 }, - { 0x0a0b4, 0xffffffff, 0x000003e8 }, - { 0x0a0b8, 0xffffffff, 0x0000c350 }, + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0xa0b0, 0x00000000), + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0xa0b4, 0x000003e8), + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0xa0b8, 0x0000c350), + /* RP Settings */ - { 0x0a010, 0xffffffff, 0x000f4240 }, - { 0x0a014, 0xffffffff, 0x12060000 }, - { 0x0a02c, 0xffffffff, 0x0000e808 }, - { 0x0a030, 0xffffffff, 0x0003bd08 }, - { 0x0a068, 0xffffffff, 0x000101d0 }, - { 0x0a06c, 0xffffffff, 0x00055730 }, - { 0x0a070, 0xffffffff, 0x0000000a }, + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0xa010, 0x000f4240), + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0xa014, 0x12060000), + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0xa02c, 0x0000e808), + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0xa030, 0x0003bd08), + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0xa068, 0x000101d0), + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0xa06c, 0x00055730), + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0xa070, 0x0000000a), + /* RP Control */ - { 0x0a024, 0x00000000, 0x00000b92 }, + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0xa024, 0x00000b92), + /* HW RC6 Control */ - { 0x0a090, 0x00000000, 0x88040000 }, + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0xa090, 0x88040000), + /* Video Frequency Request */ - { 0x0a00c, 0x00000000, 0x08000000 }, - { 0 }, + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0xa00c, 0x08000000), + + /* Set RC6 VIDs */ + REG_RES_POLL32(PCI_BASE_ADDRESS_0, 0x138124, (1 << 31), 0, GT_RETRY), + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0x138128, 0), + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0x138124, 0x80000004), + REG_RES_POLL32(PCI_BASE_ADDRESS_0, 0x138124, (1 << 31), 0, GT_RETRY), + + /* Enable PM Interrupts */ + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0x4402c, 0x03000076), + + /* Enable RC6 in idle */ + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0xa094, 0x00040000), + + REG_SCRIPT_END }; -static const struct gt_reg haswell_gt_lock[] = { - { 0x0a248, 0xffffffff, 0x80000000 }, - { 0x0a004, 0xffffffff, 0x00000010 }, - { 0x0a080, 0xffffffff, 0x00000004 }, - { 0x0a180, 0xffffffff, 0x80000000 }, - { 0 }, +static const struct reg_script haswell_late_init_script[] = { + /* Lock settings */ + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x0a248, (1 << 31)), + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x0a004, (1 << 4)), + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x0a080, (1 << 2)), + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x0a180, (1 << 31)), + + /* Disable Force Wake */ + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0xa188, 0x00010000), + REG_RES_POLL32(PCI_BASE_ADDRESS_0, 0x130044, 1, 0, GT_RETRY), + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0xa188, 0x00000001), + + /* Enable power well for DP and Audio */ + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x45400, (1 << 31)), + REG_RES_POLL32(PCI_BASE_ADDRESS_0, 0x45400, + (1 << 30), (1 << 30), GT_RETRY), + + REG_SCRIPT_END }; -/* some vga option roms are used for several chipsets but they only have one - * PCI ID in their header. If we encounter such an option rom, we need to do - * the mapping ourselfes - */ +static const struct reg_script broadwell_early_init_script[] = { + /* Enable Force Wake */ + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0xa188, 0x00010001), + REG_RES_POLL32(PCI_BASE_ADDRESS_0, 0x130044, 1, 1, GT_RETRY), + + /* Enable push bus metric control and shift */ + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0xa248, 0x00000004), + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0xa250, 0x000000ff), + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0xa25c, 0x00000010), + + /* GFXPAUSE settings */ + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0xa000, 0x00030020), + + /* ECO Settings */ + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0xa180, 0x45200000), + + /* Enable DOP Clock Gating */ + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0x9424, 0x000000fd), + + /* Enable Unit Level Clock Gating */ + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0x9400, 0x00000000), + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0x9404, 0x40401000), + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0x9408, 0x00000000), + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0x940c, 0x02000001), + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0x1a054, 0x0000000a), + + /* Video Frequency Request */ + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0xa00c, 0x08000000), + + /* + * RC6 Settings + */ + + /* Wake Rate Limits */ + REG_RES_RMW32(PCI_BASE_ADDRESS_0, 0x0a090, 0, 0), + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x0a098, 0x03e80000), + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x0a09c, 0x00280000), + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x0a0a8, 0x0001e848), + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x0a0ac, 0x00000019), + + /* Render/Video/Blitter Idle Max Count */ + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0x02054, 0x0000000a), + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0x12054, 0x0000000a), + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0x22054, 0x0000000a), + + /* RC Sleep / RCx Thresholds */ + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x0a0b0, 0x00000000), + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x0a0b8, 0x00000271), + + /* RP Settings */ + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x0a010, 0x000f4240), + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x0a014, 0x12060000), + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x0a02c, 0x0000e808), + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x0a030, 0x0003bd08), + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x0a068, 0x000101d0), + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x0a06c, 0x00055730), + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x0a070, 0x0000000a), + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x0a168, 0x00000006), + + /* RP Control */ + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0xa024, 0x00000b92), + + /* HW RC6 Control */ + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0xa090, 0x90040000), + + /* Set RC6 VIDs */ + REG_RES_POLL32(PCI_BASE_ADDRESS_0, 0x138124, (1 << 31), 0, GT_RETRY), + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0x138128, 0), + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0x138124, 0x80000004), + REG_RES_POLL32(PCI_BASE_ADDRESS_0, 0x138124, (1 << 31), 0, GT_RETRY), + + /* Enable PM Interrupts */ + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0x4402c, 0x03000076), + + /* Enable RC6 in idle */ + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0xa094, 0x00040000), + + REG_SCRIPT_END +}; + +static const struct reg_script broadwell_late_init_script[] = { + /* Lock settings */ + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x0a248, (1 << 31)), + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x0a000, (1 << 18)), + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x0a180, (1 << 31)), + + /* Disable Force Wake */ + REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0xa188, 0x00010000), + REG_RES_POLL32(PCI_BASE_ADDRESS_0, 0x130044, 1, 0, GT_RETRY), + + /* Enable power well for DP and Audio */ + REG_RES_OR32(PCI_BASE_ADDRESS_0, 0x45400, (1 << 31)), + REG_RES_POLL32(PCI_BASE_ADDRESS_0, 0x45400, + (1 << 30), (1 << 30), GT_RETRY), + + REG_SCRIPT_END +}; u32 map_oprom_vendev(u32 vendev) { - u32 new_vendev=vendev; - - switch (vendev) { - case 0x80860402: /* GT1 Desktop */ - case 0x80860406: /* GT1 Mobile */ - case 0x8086040a: /* GT1 Server */ - case 0x80860a06: /* GT1 ULT */ - - case 0x80860412: /* GT2 Desktop */ - case 0x80860416: /* GT2 Mobile */ - case 0x8086041a: /* GT2 Server */ - case 0x80860a16: /* GT2 ULT */ - - case 0x80860422: /* GT3 Desktop */ - case 0x80860426: /* GT3 Mobile */ - case 0x8086042a: /* GT3 Server */ - case 0x80860a26: /* GT3 ULT */ - - new_vendev=0x80860406; /* GT1 Mobile */ - break; - } - - return new_vendev; -} - -/* 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. - */ - -#define GTT_PTE_BASE (2 << 20) - -void -set_translation_table(int start, int end, u64 base, int inc) -{ - int i; - - for(i = start; i < end; i++){ - u64 physical_address = base + i*inc; - /* swizzle the 32:39 bits to 4:11 */ - u32 word = physical_address | ((physical_address >> 28) & 0xff0) | 1; - /* note: we've confirmed by checking - * the values that mrc does no - * useful setup before we run this. - */ - gtt_write(GTT_PTE_BASE + i * 4, word); - gtt_read(GTT_PTE_BASE + i * 4); - } + return SA_IGD_OPROM_VENDEV; } static struct resource *gtt_res = NULL; -unsigned long gtt_read(unsigned long reg) +static unsigned long gtt_read(unsigned long reg) { u32 val; val = read32(gtt_res->base + reg); @@ -176,7 +250,7 @@ unsigned long gtt_read(unsigned long reg) } -void gtt_write(unsigned long reg, unsigned long data) +static void gtt_write(unsigned long reg, unsigned long data) { write32(gtt_res->base + reg, data); } @@ -189,20 +263,9 @@ static inline void gtt_rmw(u32 reg, u32 andmask, u32 ormask) gtt_write(reg, val); } -static inline void gtt_write_regs(const struct gt_reg *gt) +static int gtt_poll(u32 reg, u32 mask, u32 value) { - for (; gt && gt->reg; gt++) { - if (gt->andmask) - gtt_rmw(gt->reg, gt->andmask, gt->ormask); - else - gtt_write(gt->reg, gt->ormask); - } -} - -#define GTT_RETRY 1000 -int gtt_poll(u32 reg, u32 mask, u32 value) -{ - unsigned try = GTT_RETRY; + unsigned try = GT_RETRY; u32 data; while (try--) { @@ -216,90 +279,11 @@ int gtt_poll(u32 reg, u32 mask, u32 value) return 0; } -static void power_well_enable(void) +static void igd_setup_panel(struct device *dev) { - gtt_write(HSW_PWR_WELL_CTL1, HSW_PWR_WELL_ENABLE); - gtt_poll(HSW_PWR_WELL_CTL1, HSW_PWR_WELL_STATE, HSW_PWR_WELL_STATE); -#if CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT - /* In the native graphics case, we've got about 20 ms. - * after we power up the the AUX channel until we can talk to it. - * So get that going right now. We can't turn on the panel, yet, just VDD. - */ - gtt_write(PCH_PP_CONTROL, PCH_PP_UNLOCK| EDP_FORCE_VDD | PANEL_POWER_RESET); -#endif -} - -static void gma_pm_init_pre_vbios(struct device *dev) -{ - printk(BIOS_DEBUG, "GT Power Management Init\n"); - - gtt_res = find_resource(dev, PCI_BASE_ADDRESS_0); - if (!gtt_res || !gtt_res->base) - return; - - power_well_enable(); - - /* - * Enable RC6 - */ - - /* Enable Force Wake */ - gtt_write(0x0a180, 1 << 5); - gtt_write(0x0a188, 0x00010001); - gtt_poll(0x130044, 1 << 0, 1 << 0); - - /* GT Settings */ - gtt_write_regs(haswell_gt_setup); - - /* Wait for Mailbox Ready */ - gtt_poll(0x138124, (1 << 31), (0 << 31)); - /* Mailbox Data - RC6 VIDS */ - gtt_write(0x138128, 0x00000000); - /* Mailbox Command */ - gtt_write(0x138124, 0x80000004); - /* Wait for Mailbox Ready */ - gtt_poll(0x138124, (1 << 31), (0 << 31)); - - /* Enable PM Interrupts */ - gtt_write(GEN6_PMIER, GEN6_PM_MBOX_EVENT | GEN6_PM_THERMAL_EVENT | - GEN6_PM_RP_DOWN_TIMEOUT | GEN6_PM_RP_UP_THRESHOLD | - GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_UP_EI_EXPIRED | - GEN6_PM_RP_DOWN_EI_EXPIRED); - - /* Enable RC6 in idle */ - gtt_write(0x0a094, 0x00040000); - - /* PM Lock Settings */ - gtt_write_regs(haswell_gt_lock); -} - -static void init_display_planes(void) -{ - int pipe, plane; - - /* Disable cursor mode */ - for (pipe = PIPE_A; pipe <= PIPE_C; pipe++) { - gtt_write(CURCNTR_IVB(pipe), CURSOR_MODE_DISABLE); - gtt_write(CURBASE_IVB(pipe), 0x00000000); - } - - /* Disable primary plane and set surface base address*/ - for (plane = PLANE_A; plane <= PLANE_C; plane++) { - gtt_write(DSPCNTR(plane), DISPLAY_PLANE_DISABLE); - gtt_write(DSPSURF(plane), 0x00000000); - } - - /* Disable VGA display */ - gtt_write(CPU_VGACNTRL, CPU_VGA_DISABLE); -} - -static void gma_setup_panel(struct device *dev) -{ - struct northbridge_intel_haswell_config *conf = dev->chip_info; + config_t *conf = dev->chip_info; u32 reg32; - printk(BIOS_DEBUG, "GT Power Management Init (post VBIOS)\n"); - /* Setup Digital Port Hotplug */ reg32 = gtt_read(PCH_PORT_HOTPLUG); if (!reg32) { @@ -343,145 +327,188 @@ static void gma_setup_panel(struct device *dev) gtt_write(BLC_PWM_PCH_CTL1, BLM_PCH_PWM_ENABLE); gtt_write(BLC_PWM_PCH_CTL2, conf->gpu_pch_backlight); } - - /* Get display,pipeline,and DDI registers into a basic sane state */ - power_well_enable(); - - init_display_planes(); - - /* DDI-A params set: - bit 0: Display detected (RO) - bit 4: DDI A supports 4 lanes and DDI E is not used - bit 7: DDI buffer is idle - */ - gtt_write(DDI_BUF_CTL_A, DDI_BUF_IS_IDLE | DDI_A_4_LANES | DDI_INIT_DISPLAY_DETECTED); - - /* Set FDI registers - is this required? */ - gtt_write(_FDI_RXA_MISC, 0x00200090); - gtt_write(_FDI_RXA_MISC, 0x0a000000); - - /* Enable the handshake with PCH display when processing reset */ - gtt_write(NDE_RSTWRN_OPT, RST_PCH_HNDSHK_EN); - - /* undocumented */ - gtt_write(0x42090, 0x04000000); - gtt_write(0x9840, 0x00000000); - gtt_write(0x42090, 0xa4000000); - - gtt_write(SOUTH_DSPCLK_GATE_D, PCH_LP_PARTITION_LEVEL_DISABLE); - - /* undocumented */ - gtt_write(0x42080, 0x00004000); - - /* Prepare DDI buffers for DP and FDI */ - intel_prepare_ddi(); - - /* Hot plug detect buffer enabled for port A */ - gtt_write(DIGITAL_PORT_HOTPLUG_CNTRL, DIGITAL_PORTA_HOTPLUG_ENABLE); - - /* Enable HPD buffer for digital port D and B */ - gtt_write(PCH_PORT_HOTPLUG, PORTD_HOTPLUG_ENABLE | PORTB_HOTPLUG_ENABLE); - - /* Bits 4:0 - Power cycle delay (default 0x6 --> 500ms) - Bits 31:8 - Reference divider (0x0004af ----> 24MHz) - */ - gtt_write(PCH_PP_DIVISOR, 0x0004af06); } -static void gma_pm_init_post_vbios(struct device *dev) +static void igd_cdclk_init_haswell(struct device *dev) { - int cdclk = 0; + config_t *conf = dev->chip_info; + int cdclk = conf->cdclk; int devid = pci_read_config16(dev, PCI_DEVICE_ID); int gpu_is_ulx = 0; + u32 dpdiv, lpcll; + /* Check for ULX GT1 or GT2 */ if (devid == 0x0a0e || devid == 0x0a1e) gpu_is_ulx = 1; - /* CD Frequency */ - if ((gtt_read(0x42014) & 0x1000000) || gpu_is_ulx || haswell_is_ult()) - cdclk = 0; /* fixed frequency */ - else - cdclk = 2; /* variable frequency */ + /* 675MHz is not supported on haswell */ + if (cdclk == GT_CDCLK_675) + cdclk = GT_CDCLK_337; - if (gpu_is_ulx || cdclk != 0) - gtt_rmw(0x130040, 0xf7ffffff, 0x04000000); - else - gtt_rmw(0x130040, 0xf3ffffff, 0x00000000); + /* If CD clock is fixed or ULT then set to 450MHz */ + if ((gtt_read(0x42014) & 0x1000000) || cpu_is_ult()) + cdclk = GT_CDCLK_450; - /* More magic */ - if (haswell_is_ult() || gpu_is_ulx) { - if (!gpu_is_ulx) - gtt_write(0x138128, 0x00000000); + /* 540MHz is not supported on ULX */ + if (gpu_is_ulx && cdclk == GT_CDCLK_540) + cdclk = GT_CDCLK_337; + + /* 337.5MHz is not supported on non-ULT/ULX */ + if (!gpu_is_ulx && !cpu_is_ult() && cdclk == GT_CDCLK_337) + cdclk = GT_CDCLK_450; + + /* Set variables based on CD Clock setting */ + switch (cdclk) { + case GT_CDCLK_337: + dpdiv = 169; + lpcll = (1 << 26); + break; + case GT_CDCLK_450: + dpdiv = 225; + lpcll = 0; + break; + case GT_CDCLK_540: + dpdiv = 270; + lpcll = (1 << 26); + break; + default: + return; + } + + /* Set LPCLL_CTL CD Clock Frequency Select */ + gtt_rmw(0x130040, 0xf3ffffff, lpcll); + + /* ULX: Inform power controller of selected frequency */ + if (gpu_is_ulx) { + if (cdclk == GT_CDCLK_450) + gtt_write(0x138128, 0x00000000); /* 450MHz */ else - gtt_write(0x138128, 0x00000001); + gtt_write(0x138128, 0x00000001); /* 337.5MHz */ gtt_write(0x13812c, 0x00000000); gtt_write(0x138124, 0x80000017); } - /* Disable Force Wake */ - gtt_write(0x0a188, 0x00010000); - gtt_poll(0x130044, 1 << 0, 0 << 0); - gtt_write(0x0a188, 0x00000001); + /* Set CPU DP AUX 2X bit clock dividers */ + gtt_rmw(0x64010, 0xfffff800, dpdiv); + gtt_rmw(0x64810, 0xfffff800, dpdiv); +} + +static void igd_cdclk_init_broadwell(struct device *dev) +{ + config_t *conf = dev->chip_info; + int cdclk = conf->cdclk; + u32 dpdiv, lpcll, pwctl, cdset; + + /* Inform power controller of upcoming frequency change */ + gtt_write(0x138128, 0); + gtt_write(0x13812c, 0); + gtt_write(0x138124, 0x80000018); + + /* Poll GT driver mailbox for run/busy clear */ + if (!gtt_poll(0x138124, (1 << 31), (0 << 31))) + cdclk = GT_CDCLK_450; + + if (gtt_read(0x42014) & 0x1000000) { + /* If CD clock is fixed then set to 450MHz */ + cdclk = GT_CDCLK_450; + } else { + /* Program CD clock to highest supported freq */ + if (cpu_is_ult()) + cdclk = GT_CDCLK_540; + else + cdclk = GT_CDCLK_675; + } + + /* CD clock frequency 675MHz not supported on ULT */ + if (cpu_is_ult() && cdclk == GT_CDCLK_675) + cdclk = GT_CDCLK_540; + + /* Set variables based on CD Clock setting */ + switch (cdclk) { + case GT_CDCLK_337: + cdset = 337; + lpcll = (1 << 27); + pwctl = 2; + dpdiv = 169; + break; + case GT_CDCLK_450: + cdset = 449; + lpcll = 0; + pwctl = 0; + dpdiv = 225; + break; + case GT_CDCLK_540: + cdset = 539; + lpcll = (1 << 26); + pwctl = 1; + dpdiv = 270; + break; + case GT_CDCLK_675: + cdset = 674; + lpcll = (1 << 26) | (1 << 27); + pwctl = 3; + dpdiv = 338; + default: + return; + } + + /* Set LPCLL_CTL CD Clock Frequency Select */ + gtt_rmw(0x130040, 0xf3ffffff, lpcll); + + /* Inform power controller of selected frequency */ + gtt_write(0x138128, pwctl); + gtt_write(0x13812c, 0); + gtt_write(0x138124, 0x80000017); + + /* Program CD Clock Frequency */ + gtt_rmw(0x46200, 0xfffffc00, cdset); + + /* Set CPU DP AUX 2X bit clock dividers */ + gtt_rmw(0x64010, 0xfffff800, dpdiv); + gtt_rmw(0x64810, 0xfffff800, dpdiv); } static void igd_init(struct device *dev) { -#if CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT - struct northbridge_intel_haswell_config *conf = dev->chip_info; - struct intel_dp dp; -#endif - int lightup_ok = 0; - u32 reg32; + int is_broadwell = !!(cpu_family_model() == BROADWELL_FAMILY_ULT); + u32 rp1_gfx_freq; + /* IGD needs to be Bus Master */ - reg32 = pci_read_config32(dev, PCI_COMMAND); + u32 reg32 = pci_read_config32(dev, PCI_COMMAND); reg32 |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO; pci_write_config32(dev, PCI_COMMAND, reg32); - /* Init graphics power management */ - gma_pm_init_pre_vbios(dev); + gtt_res = find_resource(dev, PCI_BASE_ADDRESS_0); + if (!gtt_res || !gtt_res->base) + return; - /* Post VBIOS init */ - gma_setup_panel(dev); + /* Wait for any configured pre-graphics delay */ + mdelay(CONFIG_PRE_GRAPHICS_DELAY); -#if CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT - printk(BIOS_SPEW, "NATIVE graphics, run native enable\n"); - /* Default set to 1 since it might be required for - stuff like seabios */ - unsigned int init_fb = 1; - - /* the BAR for graphics space is a well known number for - * sandy and ivy. And the resource code renumbers it. - * So it's almost like having two hardcodes. - */ - dp.graphics = (void *)((uintptr_t)dev->resource_list[1].base); - dp.physbase = pci_read_config32(dev, 0x5c) & ~0xf; - dp.panel_power_down_delay = conf->gpu_panel_power_down_delay; - dp.panel_power_up_delay = conf->gpu_panel_power_up_delay; - dp.panel_power_cycle_delay = conf->gpu_panel_power_cycle_delay; - -#ifdef CONFIG_CHROMEOS - init_fb = developer_mode_enabled() || recovery_mode_enabled(); -#endif - lightup_ok = panel_lightup(&dp, init_fb); -#endif - if (! lightup_ok) { - printk(BIOS_SPEW, "FUI did not run; using VBIOS\n"); - mdelay(CONFIG_PRE_GRAPHICS_DELAY); - pci_dev_init(dev); + /* Early init steps */ + if (is_broadwell) { + reg_script_run_on_dev(dev, broadwell_early_init_script); + } else { + reg_script_run_on_dev(dev, haswell_early_init_script); } - /* Post VBIOS init */ - gma_pm_init_post_vbios(dev); -} + /* Set RP1 graphics frequency */ + rp1_gfx_freq = (MCHBAR32(0x5998) >> 8) & 0xff; + gtt_write(0xa008, rp1_gfx_freq << 24); -static void gma_set_subsystem(device_t dev, unsigned vendor, unsigned device) -{ - if (!vendor || !device) { - pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, - pci_read_config32(dev, PCI_VENDOR_ID)); + /* Post VBIOS panel setup */ + igd_setup_panel(dev); + + /* Initialize PCI device, load/execute BIOS Option ROM */ + pci_dev_init(dev); + + /* Late init steps */ + if (is_broadwell) { + igd_cdclk_init_broadwell(dev); + reg_script_run_on_dev(dev, broadwell_late_init_script); } else { - pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, - ((device & 0xffff) << 16) | (vendor & 0xffff)); + igd_cdclk_init_haswell(dev); + reg_script_run_on_dev(dev, haswell_late_init_script); } }