From 6b19071ffb89dbb68196b7f3b088d87d4fad9e80 Mon Sep 17 00:00:00 2001 From: Furquan Shaikh Date: Mon, 22 Jul 2013 16:18:31 -0700 Subject: FUI: Fill in link_m and link_n values ... based on the EDID detailed timing values for pixel_clock and link_clock. Two undocumented registers 0x6f040 and 0x6f044 correspond to link_m and link_n respectively. Other two undocumented registers 0x6f030 and 0x6f034 correspond to data_m and data_n respectively. Calculations are based on the intel_link_compute_m_n from linux kernel. Currently, the value for 0x6f030 does not come up right with our calculations. Hence, set to hard-coded value. Change-Id: I40ff411729d0a61759164c3c1098504973f9cf5e Reviewed-on: https://gerrit.chromium.org/gerrit/62915 Reviewed-by: Ronald G. Minnich Tested-by: Furquan Shaikh Commit-Queue: Furquan Shaikh Reviewed-on: http://review.coreboot.org/4381 Tested-by: build bot (Jenkins) Reviewed-by: Patrick Georgi --- src/drivers/intel/gma/i915.h | 14 +++++++++ src/drivers/intel/gma/i915_reg.h | 4 +++ src/drivers/intel/gma/intel_dp.c | 58 ++++++++++++++++++++++-------------- src/include/edid.h | 2 ++ src/lib/edid.c | 6 ++-- src/mainboard/google/slippy/gma.c | 30 +++++++++++++++++++ src/mainboard/google/slippy/i915io.c | 11 +++++-- 7 files changed, 98 insertions(+), 27 deletions(-) diff --git a/src/drivers/intel/gma/i915.h b/src/drivers/intel/gma/i915.h index e976f912cc..62fe0230e6 100644 --- a/src/drivers/intel/gma/i915.h +++ b/src/drivers/intel/gma/i915.h @@ -65,6 +65,14 @@ void io_i915_write32(unsigned long val, unsigned long addr); #define DP_LINK_CONFIGURATION_SIZE 9 +struct intel_dp_m_n { + uint32_t tu; + uint32_t gmch_m; + uint32_t gmch_n; + uint32_t link_m; + uint32_t link_n; +}; + struct intel_dp { int gen; // 6 for link, 7 for wtm2 int has_pch_split; // 1 for link and wtm2 @@ -134,6 +142,7 @@ struct intel_dp { u32 pfa_ctl; u32 pipesrc; u32 stride; + struct intel_dp_m_n m_n; }; /* we may yet need these. */ @@ -183,3 +192,8 @@ void intel_dp_wait_reg(unsigned long addr, void intel_dp_wait_panel_power_control(unsigned long val); +void intel_dp_compute_m_n(unsigned int bits_per_pixel, + unsigned int nlanes, + unsigned int pixel_clock, + unsigned int link_clock, + struct intel_dp_m_n *m_n); diff --git a/src/drivers/intel/gma/i915_reg.h b/src/drivers/intel/gma/i915_reg.h index d947f1af79..27a3d2b7da 100644 --- a/src/drivers/intel/gma/i915_reg.h +++ b/src/drivers/intel/gma/i915_reg.h @@ -3321,6 +3321,10 @@ #define _PIPEA_DATA_M1 0x60030 #define TU_SIZE(x) (((x)-1) << 25) /* default size 64 */ #define TU_SIZE_MASK 0x7e000000 + +#define DATA_LINK_M_N_MASK (0xffffff) +#define DATA_LINK_N_MAX (0x800000) + #define PIPE_DATA_M1_OFFSET 0 #define _PIPEA_DATA_N1 0x60034 #define PIPE_DATA_N1_OFFSET 0 diff --git a/src/drivers/intel/gma/intel_dp.c b/src/drivers/intel/gma/intel_dp.c index 8097c6aca5..0def7717ac 100644 --- a/src/drivers/intel/gma/intel_dp.c +++ b/src/drivers/intel/gma/intel_dp.c @@ -393,37 +393,51 @@ intel_dp_i2c_init(struct intel_dp *intel_dp) return ret; } -struct intel_dp_m_n { - uint32_t tu; - uint32_t gmch_m; - uint32_t gmch_n; - uint32_t link_m; - uint32_t link_n; -}; - static void -intel_reduce_ratio(uint32_t *num, uint32_t *den) +intel_reduce_m_n_ratio(uint32_t *num, uint32_t *den) { - while (*num > 0xffffff || *den > 0xffffff) { + while (*num > DATA_LINK_M_N_MASK || *den > DATA_LINK_M_N_MASK) { *num >>= 1; *den >>= 1; } } -static void -intel_dp_compute_m_n(int bpp, - int nlanes, - int pixel_clock, - int link_clock, - struct intel_dp_m_n *m_n) +unsigned int roundup_power_of_two(unsigned int n); + +unsigned int roundup_power_of_two(unsigned int n) +{ + n--; + n |= n >> 1; + n |= n >> 2; + n |= n >> 4; + n |= n >> 8; + n |= n >> 16; + n++; + return n; +} + +static void compute_m_n(unsigned int m, unsigned int n, + unsigned int *ret_m, unsigned int *ret_n) +{ + *ret_n = MIN(roundup_power_of_two(n), DATA_LINK_N_MAX); + *ret_m = ( (unsigned long long)m * *ret_n) / n; + intel_reduce_m_n_ratio(ret_m, ret_n); +} + +void intel_dp_compute_m_n(unsigned int bits_per_pixel, + unsigned int nlanes, + unsigned int pixel_clock, + unsigned int link_clock, + struct intel_dp_m_n *m_n) { m_n->tu = 64; - m_n->gmch_m = (pixel_clock * bpp) >> 3; - m_n->gmch_n = link_clock * nlanes; - intel_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n); - m_n->link_m = pixel_clock; - m_n->link_n = link_clock; - intel_reduce_ratio(&m_n->link_m, &m_n->link_n); + + compute_m_n(bits_per_pixel * pixel_clock, + link_clock * nlanes * 8, + &m_n->gmch_m, &m_n->gmch_n); + + compute_m_n(pixel_clock, link_clock, + &m_n->link_m, &m_n->link_n); } /* not sure. */ diff --git a/src/include/edid.h b/src/include/edid.h index ce1f615709..88ce55f804 100644 --- a/src/include/edid.h +++ b/src/include/edid.h @@ -45,6 +45,8 @@ struct edid { /* used to compute timing for graphics chips. */ unsigned char phsync; unsigned char pvsync; + unsigned int pixel_clock; + unsigned int link_clock; unsigned int ha; unsigned int hbl; unsigned int hso; diff --git a/src/lib/edid.c b/src/lib/edid.c index aa12596d89..8018967bf1 100644 --- a/src/lib/edid.c +++ b/src/lib/edid.c @@ -447,6 +447,8 @@ detailed_block(struct edid *out, unsigned char *x, int in_extension) } if (! did_detailed_timing){ + /* Edid contains pixel clock in terms of 10KHz */ + out->pixel_clock = (x[0] + (x[1] << 8)) * 10; out->ha = (x[2] + ((x[4] & 0xF0) << 4)); out->hbl = (x[3] + ((x[4] & 0x0F) << 8)); out->hso = (x[8] + ((x[11] & 0xC0) << 2)); @@ -517,11 +519,11 @@ detailed_block(struct edid *out, unsigned char *x, int in_extension) break; } - printk(BIOS_SPEW, "Detailed mode (IN HEX): Clock %d0 KHz, %x mm x %x mm\n" + printk(BIOS_SPEW, "Detailed mode (IN HEX): Clock %d KHz, %x mm x %x mm\n" " %04x %04x %04x %04x hborder %x\n" " %04x %04x %04x %04x vborder %x\n" " %chsync %cvsync%s%s %s\n", - (x[0] + (x[1] << 8)), + out->pixel_clock, (x[12] + ((x[14] & 0xF0) << 4)), (x[13] + ((x[14] & 0x0F) << 8)), out->ha, out->ha + out->hso, out->ha + out->hso + out->hspw, diff --git a/src/mainboard/google/slippy/gma.c b/src/mainboard/google/slippy/gma.c index 39072186e0..52a7b0b4e8 100644 --- a/src/mainboard/google/slippy/gma.c +++ b/src/mainboard/google/slippy/gma.c @@ -288,6 +288,12 @@ void dp_init_dim_regs(struct intel_dp *dp) dp->pfa_sz = (edid->ha << 16) | (edid->va); + intel_dp_compute_m_n(dp->bpp, + dp->lane_count, + dp->edid.pixel_clock, + dp->edid.link_clock, + &dp->m_n); + printk(BIOS_SPEW, "dp->stride = 0x%08x\n",dp->stride); printk(BIOS_SPEW, "dp->htotal = 0x%08x\n", dp->htotal); printk(BIOS_SPEW, "dp->hblank = 0x%08x\n", dp->hblank); @@ -299,6 +305,26 @@ void dp_init_dim_regs(struct intel_dp *dp) printk(BIOS_SPEW, "dp->pfa_pos = 0x%08x\n", dp->pfa_pos); printk(BIOS_SPEW, "dp->pfa_ctl = 0x%08x\n", dp->pfa_ctl); printk(BIOS_SPEW, "dp->pfa_sz = 0x%08x\n", dp->pfa_sz); + printk(BIOS_SPEW, "dp->link_m = 0x%08x\n", dp->m_n.link_m); + printk(BIOS_SPEW, "dp->link_n = 0x%08x\n", dp->m_n.link_n); + printk(BIOS_SPEW, "0x6f030 = 0x%08x\n", TU_SIZE(dp->m_n.tu) | dp->m_n.gmch_m); + printk(BIOS_SPEW, "0x6f030 = 0x%08x\n", dp->m_n.gmch_m); + printk(BIOS_SPEW, "0x6f034 = 0x%08x\n", dp->m_n.gmch_n); +} + +int intel_dp_bw_code_to_link_rate(u8 link_bw); + +int intel_dp_bw_code_to_link_rate(u8 link_bw) +{ + switch (link_bw) { + case DP_LINK_BW_1_62: + default: + return 162000; + case DP_LINK_BW_2_7: + return 270000; + case DP_LINK_BW_5_4: + return 540000; + } } int i915lightup(unsigned int physbase, unsigned int iobase, unsigned int mmio, @@ -366,6 +392,10 @@ int i915lightup(unsigned int pphysbase, unsigned int piobase, edid_ok = decode_edid(dp->rawedid, dp->edidlen, &dp->edid); printk(BIOS_SPEW, "decode edid returns %d\n", edid_ok); + dp->edid.link_clock = intel_dp_bw_code_to_link_rate(dp->link_bw); + + printk(BIOS_SPEW, "pixel_clock is %i, link_clock is %i\n",dp->edid.pixel_clock, dp->edid.link_clock); + dp_init_dim_regs(dp); /* more undocumented stuff. */ diff --git a/src/mainboard/google/slippy/i915io.c b/src/mainboard/google/slippy/i915io.c index 18e0480e13..c1e05472c9 100644 --- a/src/mainboard/google/slippy/i915io.c +++ b/src/mainboard/google/slippy/i915io.c @@ -117,9 +117,14 @@ printk(BIOS_SPEW, "DP_MAX_DOWNSPREAD"); /* undocumented. */ io_i915_write32(0x7e4a0000,0x6f030); - io_i915_write32(0x00800000,0x6f034); - io_i915_write32(0x00021000,0x6f040); - io_i915_write32(0x00080000,0x6f044); + /* io_i915_write32(0x00800000,0x6f034); */ + /* Write to 0x6f030 has to be 0x7e4ayyyy -- First four hex digits are important. + However, with our formula we always see values 0x7e43yyyy (1366 panel) and + 0x7e42yyy (1280 panel) */ + /* io_i915_write32(TU_SIZE(dp->m_n.tu) | dp->m_n.gmch_m,0x6f030); */ + io_i915_write32(dp->m_n.gmch_n,0x6f034); + io_i915_write32(dp->m_n.link_m,0x6f040); + io_i915_write32(dp->m_n.link_n,0x6f044); /* leave as is for now. */ io_i915_write32(dp->htotal,0x6f000); -- cgit v1.2.3