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 <rminnich@chromium.org> Tested-by: Furquan Shaikh <furquan@chromium.org> Commit-Queue: Furquan Shaikh <furquan@chromium.org> Reviewed-on: http://review.coreboot.org/4381 Tested-by: build bot (Jenkins) Reviewed-by: Patrick Georgi <patrick@georgi-clan.de>
This commit is contained in:
parent
3d9b5a2931
commit
6b19071ffb
|
@ -65,6 +65,14 @@ void io_i915_write32(unsigned long val, unsigned long addr);
|
||||||
|
|
||||||
#define DP_LINK_CONFIGURATION_SIZE 9
|
#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 {
|
struct intel_dp {
|
||||||
int gen; // 6 for link, 7 for wtm2
|
int gen; // 6 for link, 7 for wtm2
|
||||||
int has_pch_split; // 1 for link and wtm2
|
int has_pch_split; // 1 for link and wtm2
|
||||||
|
@ -134,6 +142,7 @@ struct intel_dp {
|
||||||
u32 pfa_ctl;
|
u32 pfa_ctl;
|
||||||
u32 pipesrc;
|
u32 pipesrc;
|
||||||
u32 stride;
|
u32 stride;
|
||||||
|
struct intel_dp_m_n m_n;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* we may yet need these. */
|
/* 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_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);
|
||||||
|
|
|
@ -3321,6 +3321,10 @@
|
||||||
#define _PIPEA_DATA_M1 0x60030
|
#define _PIPEA_DATA_M1 0x60030
|
||||||
#define TU_SIZE(x) (((x)-1) << 25) /* default size 64 */
|
#define TU_SIZE(x) (((x)-1) << 25) /* default size 64 */
|
||||||
#define TU_SIZE_MASK 0x7e000000
|
#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 PIPE_DATA_M1_OFFSET 0
|
||||||
#define _PIPEA_DATA_N1 0x60034
|
#define _PIPEA_DATA_N1 0x60034
|
||||||
#define PIPE_DATA_N1_OFFSET 0
|
#define PIPE_DATA_N1_OFFSET 0
|
||||||
|
|
|
@ -393,37 +393,51 @@ intel_dp_i2c_init(struct intel_dp *intel_dp)
|
||||||
return ret;
|
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
|
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;
|
*num >>= 1;
|
||||||
*den >>= 1;
|
*den >>= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
unsigned int roundup_power_of_two(unsigned int n);
|
||||||
intel_dp_compute_m_n(int bpp,
|
|
||||||
int nlanes,
|
unsigned int roundup_power_of_two(unsigned int n)
|
||||||
int pixel_clock,
|
{
|
||||||
int link_clock,
|
n--;
|
||||||
struct intel_dp_m_n *m_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->tu = 64;
|
||||||
m_n->gmch_m = (pixel_clock * bpp) >> 3;
|
|
||||||
m_n->gmch_n = link_clock * nlanes;
|
compute_m_n(bits_per_pixel * pixel_clock,
|
||||||
intel_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n);
|
link_clock * nlanes * 8,
|
||||||
m_n->link_m = pixel_clock;
|
&m_n->gmch_m, &m_n->gmch_n);
|
||||||
m_n->link_n = link_clock;
|
|
||||||
intel_reduce_ratio(&m_n->link_m, &m_n->link_n);
|
compute_m_n(pixel_clock, link_clock,
|
||||||
|
&m_n->link_m, &m_n->link_n);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* not sure. */
|
/* not sure. */
|
||||||
|
|
|
@ -45,6 +45,8 @@ struct edid {
|
||||||
/* used to compute timing for graphics chips. */
|
/* used to compute timing for graphics chips. */
|
||||||
unsigned char phsync;
|
unsigned char phsync;
|
||||||
unsigned char pvsync;
|
unsigned char pvsync;
|
||||||
|
unsigned int pixel_clock;
|
||||||
|
unsigned int link_clock;
|
||||||
unsigned int ha;
|
unsigned int ha;
|
||||||
unsigned int hbl;
|
unsigned int hbl;
|
||||||
unsigned int hso;
|
unsigned int hso;
|
||||||
|
|
|
@ -447,6 +447,8 @@ detailed_block(struct edid *out, unsigned char *x, int in_extension)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! did_detailed_timing){
|
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->ha = (x[2] + ((x[4] & 0xF0) << 4));
|
||||||
out->hbl = (x[3] + ((x[4] & 0x0F) << 8));
|
out->hbl = (x[3] + ((x[4] & 0x0F) << 8));
|
||||||
out->hso = (x[8] + ((x[11] & 0xC0) << 2));
|
out->hso = (x[8] + ((x[11] & 0xC0) << 2));
|
||||||
|
@ -517,11 +519,11 @@ detailed_block(struct edid *out, unsigned char *x, int in_extension)
|
||||||
break;
|
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 hborder %x\n"
|
||||||
" %04x %04x %04x %04x vborder %x\n"
|
" %04x %04x %04x %04x vborder %x\n"
|
||||||
" %chsync %cvsync%s%s %s\n",
|
" %chsync %cvsync%s%s %s\n",
|
||||||
(x[0] + (x[1] << 8)),
|
out->pixel_clock,
|
||||||
(x[12] + ((x[14] & 0xF0) << 4)),
|
(x[12] + ((x[14] & 0xF0) << 4)),
|
||||||
(x[13] + ((x[14] & 0x0F) << 8)),
|
(x[13] + ((x[14] & 0x0F) << 8)),
|
||||||
out->ha, out->ha + out->hso, out->ha + out->hso + out->hspw,
|
out->ha, out->ha + out->hso, out->ha + out->hso + out->hspw,
|
||||||
|
|
|
@ -288,6 +288,12 @@ void dp_init_dim_regs(struct intel_dp *dp)
|
||||||
|
|
||||||
dp->pfa_sz = (edid->ha << 16) | (edid->va);
|
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->stride = 0x%08x\n",dp->stride);
|
||||||
printk(BIOS_SPEW, "dp->htotal = 0x%08x\n", dp->htotal);
|
printk(BIOS_SPEW, "dp->htotal = 0x%08x\n", dp->htotal);
|
||||||
printk(BIOS_SPEW, "dp->hblank = 0x%08x\n", dp->hblank);
|
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_pos = 0x%08x\n", dp->pfa_pos);
|
||||||
printk(BIOS_SPEW, "dp->pfa_ctl = 0x%08x\n", dp->pfa_ctl);
|
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->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,
|
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);
|
edid_ok = decode_edid(dp->rawedid, dp->edidlen, &dp->edid);
|
||||||
printk(BIOS_SPEW, "decode edid returns %d\n", edid_ok);
|
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);
|
dp_init_dim_regs(dp);
|
||||||
|
|
||||||
/* more undocumented stuff. */
|
/* more undocumented stuff. */
|
||||||
|
|
|
@ -117,9 +117,14 @@ printk(BIOS_SPEW, "DP_MAX_DOWNSPREAD");
|
||||||
|
|
||||||
/* undocumented. */
|
/* undocumented. */
|
||||||
io_i915_write32(0x7e4a0000,0x6f030);
|
io_i915_write32(0x7e4a0000,0x6f030);
|
||||||
io_i915_write32(0x00800000,0x6f034);
|
/* io_i915_write32(0x00800000,0x6f034); */
|
||||||
io_i915_write32(0x00021000,0x6f040);
|
/* Write to 0x6f030 has to be 0x7e4ayyyy -- First four hex digits are important.
|
||||||
io_i915_write32(0x00080000,0x6f044);
|
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. */
|
/* leave as is for now. */
|
||||||
io_i915_write32(dp->htotal,0x6f000);
|
io_i915_write32(dp->htotal,0x6f000);
|
||||||
|
|
Loading…
Reference in New Issue