Commit 5f1800bd authored by Ben Skeggs's avatar Ben Skeggs

drm/nouveau/dp: return master dp table pointer too when looking up encoder

Will need to be able to distinguish 2.0/2.1 from 3.0 soon.  Also, move
the vbios parsing to nouveau_dp where it belongs.
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 721b0821
...@@ -1182,18 +1182,16 @@ init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) ...@@ -1182,18 +1182,16 @@ init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
struct dcb_entry *dcb = bios->display.output; struct dcb_entry *dcb = bios->display.output;
struct drm_device *dev = bios->dev; struct drm_device *dev = bios->dev;
uint8_t cond = bios->data[offset + 1]; uint8_t cond = bios->data[offset + 1];
uint8_t *table, headerlen; uint8_t *table, *entry;
BIOSLOG(bios, "0x%04X: subop 0x%02X\n", offset, cond); BIOSLOG(bios, "0x%04X: subop 0x%02X\n", offset, cond);
if (!iexec->execute) if (!iexec->execute)
return 3; return 3;
table = nouveau_bios_dp_table(dev, dcb, &headerlen); table = nouveau_dp_bios_data(dev, dcb, &entry);
if (!table) { if (!table)
NV_ERROR(dev, "0x%04X: INIT_3A: no encoder table!!\n", offset);
return 3; return 3;
}
switch (cond) { switch (cond) {
case 0: case 0:
...@@ -1207,7 +1205,7 @@ init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) ...@@ -1207,7 +1205,7 @@ init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
break; break;
case 1: case 1:
case 2: case 2:
if (!(table[5] & cond)) if (!(entry[5] & cond))
iexec->execute = false; iexec->execute = false;
break; break;
case 5: case 5:
...@@ -4454,40 +4452,6 @@ bios_encoder_match(struct dcb_entry *dcb, u32 hash) ...@@ -4454,40 +4452,6 @@ bios_encoder_match(struct dcb_entry *dcb, u32 hash)
} }
} }
void *
nouveau_bios_dp_table(struct drm_device *dev, struct dcb_entry *dcbent,
uint8_t *headerlen)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvbios *bios = &dev_priv->vbios;
uint8_t *table, *entry;
int i;
if (!bios->display.dp_table_ptr) {
NV_ERROR(dev, "No pointer to DisplayPort table\n");
return NULL;
}
table = &bios->data[bios->display.dp_table_ptr];
if (table[0] != 0x20 && table[0] != 0x21) {
NV_ERROR(dev, "DisplayPort table version 0x%02x unknown\n",
table[0]);
return NULL;
}
entry = table + table[1];
for (i = 0; i < table[3]; i++, entry += table[2]) {
u8 *etable = ROMPTR(bios, entry[0]);
if (etable && bios_encoder_match(dcbent, ROM32(etable[0]))) {
*headerlen = table[4];
return etable;
}
}
NV_ERROR(dev, "DisplayPort encoder table not found\n");
return NULL;
}
int int
nouveau_bios_run_display_table(struct drm_device *dev, u16 type, int pclk, nouveau_bios_run_display_table(struct drm_device *dev, u16 type, int pclk,
struct dcb_entry *dcbent, int crtc) struct dcb_entry *dcbent, int crtc)
...@@ -5503,14 +5467,6 @@ parse_bit_U_tbl_entry(struct drm_device *dev, struct nvbios *bios, ...@@ -5503,14 +5467,6 @@ parse_bit_U_tbl_entry(struct drm_device *dev, struct nvbios *bios,
return 0; return 0;
} }
static int
parse_bit_displayport_tbl_entry(struct drm_device *dev, struct nvbios *bios,
struct bit_entry *bitentry)
{
bios->display.dp_table_ptr = ROM16(bios->data[bitentry->offset]);
return 0;
}
struct bit_table { struct bit_table {
const char id; const char id;
int (* const parse_fn)(struct drm_device *, struct nvbios *, struct bit_entry *); int (* const parse_fn)(struct drm_device *, struct nvbios *, struct bit_entry *);
...@@ -5584,7 +5540,6 @@ parse_bit_structure(struct nvbios *bios, const uint16_t bitoffset) ...@@ -5584,7 +5540,6 @@ parse_bit_structure(struct nvbios *bios, const uint16_t bitoffset)
parse_bit_table(bios, bitoffset, &BIT_TABLE('L', lvds)); parse_bit_table(bios, bitoffset, &BIT_TABLE('L', lvds));
parse_bit_table(bios, bitoffset, &BIT_TABLE('T', tmds)); parse_bit_table(bios, bitoffset, &BIT_TABLE('T', tmds));
parse_bit_table(bios, bitoffset, &BIT_TABLE('U', U)); parse_bit_table(bios, bitoffset, &BIT_TABLE('U', U));
parse_bit_table(bios, bitoffset, &BIT_TABLE('d', displayport));
return 0; return 0;
} }
......
...@@ -291,7 +291,6 @@ struct nvbios { ...@@ -291,7 +291,6 @@ struct nvbios {
struct dcb_entry *output; struct dcb_entry *output;
int crtc; int crtc;
uint16_t script_table_ptr; uint16_t script_table_ptr;
uint16_t dp_table_ptr;
} display; } display;
struct { struct {
......
...@@ -270,11 +270,57 @@ nouveau_dp_tu_update(struct drm_device *dev, int or, int link, u32 clk, u32 bpp) ...@@ -270,11 +270,57 @@ nouveau_dp_tu_update(struct drm_device *dev, int or, int link, u32 clk, u32 bpp)
unk); unk);
} }
u8 *
nouveau_dp_bios_data(struct drm_device *dev, struct dcb_entry *dcb, u8 **entry)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvbios *bios = &dev_priv->vbios;
struct bit_entry d;
u8 *table;
int i;
if (bit_table(dev, 'd', &d)) {
NV_ERROR(dev, "BIT 'd' table not found\n");
return NULL;
}
if (d.version != 1) {
NV_ERROR(dev, "BIT 'd' table version %d unknown\n", d.version);
return NULL;
}
table = ROMPTR(bios, d.data[0]);
if (!table) {
NV_ERROR(dev, "displayport table pointer invalid\n");
return NULL;
}
switch (table[0]) {
case 0x20:
case 0x21:
break;
default:
NV_ERROR(dev, "displayport table 0x%02x unknown\n", table[0]);
return NULL;
}
for (i = 0; i < table[3]; i++) {
*entry = ROMPTR(bios, table[table[1] + (i * table[2])]);
if (*entry && bios_encoder_match(dcb, ROM32((*entry)[0])))
return table;
}
NV_ERROR(dev, "displayport encoder table not found\n");
return NULL;
}
/****************************************************************************** /******************************************************************************
* link training * link training
*****************************************************************************/ *****************************************************************************/
struct dp_state { struct dp_state {
struct dcb_entry *dcb; struct dcb_entry *dcb;
u8 *table;
u8 *entry;
int auxch; int auxch;
int crtc; int crtc;
int or; int or;
...@@ -291,7 +337,7 @@ dp_set_link_config(struct drm_device *dev, struct dp_state *dp) ...@@ -291,7 +337,7 @@ dp_set_link_config(struct drm_device *dev, struct dp_state *dp)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
int or = dp->or, link = dp->link; int or = dp->or, link = dp->link;
u8 *bios, headerlen, sink[2]; u8 *entry, sink[2];
u32 dp_ctrl; u32 dp_ctrl;
NV_DEBUG_KMS(dev, "%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw); NV_DEBUG_KMS(dev, "%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw);
...@@ -312,12 +358,12 @@ dp_set_link_config(struct drm_device *dev, struct dp_state *dp) ...@@ -312,12 +358,12 @@ dp_set_link_config(struct drm_device *dev, struct dp_state *dp)
* table, that has (among other things) pointers to more scripts that * table, that has (among other things) pointers to more scripts that
* need to be executed, this time depending on link speed. * need to be executed, this time depending on link speed.
*/ */
bios = nouveau_bios_dp_table(dev, dp->dcb, &headerlen); entry = ROMPTR(&dev_priv->vbios, dp->entry[10]);
if (bios && (bios = ROMPTR(&dev_priv->vbios, bios[10]))) { if (entry) {
while (dp->link_bw < (ROM16(bios[0]) * 10)) while (dp->link_bw < (ROM16(entry[0]) * 10))
bios += 4; entry += 4;
nouveau_bios_run_init_table(dev, ROM16(bios[2]), dp->dcb, dp->crtc); nouveau_bios_run_init_table(dev, ROM16(entry[2]), dp->dcb, dp->crtc);
} }
/* configure lane count on the source */ /* configure lane count on the source */
...@@ -357,7 +403,6 @@ dp_link_train_commit(struct drm_device *dev, struct dp_state *dp) ...@@ -357,7 +403,6 @@ dp_link_train_commit(struct drm_device *dev, struct dp_state *dp)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
u32 mask = 0, drv = 0, pre = 0, unk = 0; u32 mask = 0, drv = 0, pre = 0, unk = 0;
u8 *bios, *last, headerlen;
const u8 *shifts; const u8 *shifts;
int link = dp->link; int link = dp->link;
int or = dp->or; int or = dp->or;
...@@ -368,11 +413,10 @@ dp_link_train_commit(struct drm_device *dev, struct dp_state *dp) ...@@ -368,11 +413,10 @@ dp_link_train_commit(struct drm_device *dev, struct dp_state *dp)
else else
shifts = nvaf_lane_map; shifts = nvaf_lane_map;
bios = nouveau_bios_dp_table(dev, dp->dcb, &headerlen);
last = bios + headerlen + (bios[4] * 5);
for (i = 0; i < dp->link_nr; i++) { for (i = 0; i < dp->link_nr; i++) {
u8 lane = (dp->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf; u8 lane = (dp->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf;
u8 *conf = bios + headerlen; u8 *conf = dp->entry + dp->table[4];
u8 *last = conf + (dp->entry[4] * dp->table[5]);
while (conf < last) { while (conf < last) {
if ((lane & 3) == conf[0] && if ((lane & 3) == conf[0] &&
...@@ -500,14 +544,13 @@ nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate) ...@@ -500,14 +544,13 @@ nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate)
const u32 bw_list[] = { 270000, 162000, 0 }; const u32 bw_list[] = { 270000, 162000, 0 };
const u32 *link_bw = bw_list; const u32 *link_bw = bw_list;
struct dp_state dp; struct dp_state dp;
u8 *bios, headerlen;
auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);
if (!auxch) if (!auxch)
return false; return false;
bios = nouveau_bios_dp_table(dev, nv_encoder->dcb, &headerlen); dp.table = nouveau_dp_bios_data(dev, nv_encoder->dcb, &dp.entry);
if (!bios) if (!dp.table)
return -EINVAL; return -EINVAL;
dp.dcb = nv_encoder->dcb; dp.dcb = nv_encoder->dcb;
...@@ -524,16 +567,16 @@ nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate) ...@@ -524,16 +567,16 @@ nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate)
pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, false); pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, false);
/* enable down-spreading, if possible */ /* enable down-spreading, if possible */
if (headerlen >= 16) { if (dp.table[1] >= 16) {
u16 script = ROM16(bios[14]); u16 script = ROM16(dp.entry[14]);
if (nv_encoder->dp.dpcd[3] & 1) if (nv_encoder->dp.dpcd[3] & 1)
script = ROM16(bios[12]); script = ROM16(dp.entry[12]);
nouveau_bios_run_init_table(dev, script, dp.dcb, dp.crtc); nouveau_bios_run_init_table(dev, script, dp.dcb, dp.crtc);
} }
/* execute pre-train script from vbios */ /* execute pre-train script from vbios */
nouveau_bios_run_init_table(dev, ROM16(bios[6]), dp.dcb, dp.crtc); nouveau_bios_run_init_table(dev, ROM16(dp.entry[6]), dp.dcb, dp.crtc);
/* start off at highest link rate supported by encoder and display */ /* start off at highest link rate supported by encoder and display */
while (*link_bw > nv_encoder->dp.link_bw) while (*link_bw > nv_encoder->dp.link_bw)
...@@ -567,7 +610,7 @@ nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate) ...@@ -567,7 +610,7 @@ nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate)
dp_set_training_pattern(dev, &dp, DP_TRAINING_PATTERN_DISABLE); dp_set_training_pattern(dev, &dp, DP_TRAINING_PATTERN_DISABLE);
/* execute post-train script from vbios */ /* execute post-train script from vbios */
nouveau_bios_run_init_table(dev, ROM16(bios[8]), dp.dcb, dp.crtc); nouveau_bios_run_init_table(dev, ROM16(dp.entry[8]), dp.dcb, dp.crtc);
/* re-enable hotplug detect */ /* re-enable hotplug detect */
pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, true); pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, true);
......
...@@ -1080,8 +1080,6 @@ extern int get_pll_limits(struct drm_device *, uint32_t limit_match, ...@@ -1080,8 +1080,6 @@ extern int get_pll_limits(struct drm_device *, uint32_t limit_match,
struct pll_lims *); struct pll_lims *);
extern int nouveau_bios_run_display_table(struct drm_device *, u16 id, int clk, extern int nouveau_bios_run_display_table(struct drm_device *, u16 id, int clk,
struct dcb_entry *, int crtc); struct dcb_entry *, int crtc);
extern void *nouveau_bios_dp_table(struct drm_device *, struct dcb_entry *,
u8 *headerlen);
extern bool nouveau_bios_fp_mode(struct drm_device *, struct drm_display_mode *); extern bool nouveau_bios_fp_mode(struct drm_device *, struct drm_display_mode *);
extern uint8_t *nouveau_bios_embedded_edid(struct drm_device *); extern uint8_t *nouveau_bios_embedded_edid(struct drm_device *);
extern int nouveau_bios_parse_lvds_table(struct drm_device *, int pxclk, extern int nouveau_bios_parse_lvds_table(struct drm_device *, int pxclk,
...@@ -1103,6 +1101,7 @@ int nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr, ...@@ -1103,6 +1101,7 @@ int nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
bool nouveau_dp_detect(struct drm_encoder *); bool nouveau_dp_detect(struct drm_encoder *);
bool nouveau_dp_link_train(struct drm_encoder *, u32 datarate); bool nouveau_dp_link_train(struct drm_encoder *, u32 datarate);
void nouveau_dp_tu_update(struct drm_device *, int, int, u32, u32); void nouveau_dp_tu_update(struct drm_device *, int, int, u32, u32);
u8 *nouveau_dp_bios_data(struct drm_device *, struct dcb_entry *, u8 **);
/* nv04_fb.c */ /* nv04_fb.c */
extern int nv04_fb_init(struct drm_device *); extern int nv04_fb_init(struct drm_device *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment