[PATCH i-g-t 10/27] tools/intel_vbt_decode: Decode block 15 (Dot Clock Override Table) and block 9 (ALM only)
Ville Syrjala
ville.syrjala at linux.intel.com
Fri Jun 7 13:57:41 UTC 2024
From: Ville Syrjälä <ville.syrjala at linux.intel.com>
Decode VBT block 15 (Dot Clock Override Table) and block 9 (ALM only).
Entirely reverse engineered by intuition as I couldn't find any VBIOS
sources or spec version that has this.
The gen2 decoding looks solid given I had both ALM and MGM with these
tables. The gen3+ stuff can't be 100% sure about as all my gen3+ VBTs
have this block just filled with zeroes.
Block 9 example output from ALM:
BDB block 9 (264 bytes, min 100 bytes) - Dot clock override (ALM):
0000: 09 08 01 57 62 00 00 02 12 07 8b a0 6e 00 00 03
0010: 14 06 88 0c 7b 00 00 02 10 0d 88 ac 8a 00 00 03
0020: 16 0b 87 a0 8c 00 00 02 10 04 86 40 9c 00 00 04
0030: 18 08 85 44 a2 00 00 02 10 05 85 64 af 00 00 03
0040: 16 09 85 80 bb 00 00 02 10 04 84 5c c1 00 00 02
0050: 10 07 84 50 c3 00 00 02 10 08 84 ba db 00 00 03
0060: 14 05 83 e8 fd 00 00 04 16 08 82 f8 24 01 00 02
0070: 10 08 82 9e 33 01 00 02 10 0d 82 24 71 01 00 03
0080: 14 06 81 e0 a5 01 00 02 12 06 81 58 0f 02 00 04
0090: 16 0d a0 14 44 02 00 02 10 07 a0 3c 67 02 00 02
00a0: 10 0d a0 d0 78 02 00 02 12 06 a0 8c ad 02 00 03
00b0: 12 08 01 f0 c6 02 00 03 12 0c 01 48 e2 02 00 03
00c0: 14 06 01 18 ea 02 00 03 14 07 01 04 17 03 00 02
00d0: 10 09 01 ce 1f 03 00 03 16 06 01 8a 54 03 00 02
00e0: 12 07 01 7c 80 03 00 02 12 0d 01 10 92 03 00 04
00f0: 14 05 20 88 fb 03 00 03 12 07 20 00 65 04 00 02
0100: 10 04 20 28 88 04 00 02 10 07 20
Entry #1:
Dotclock: 25175 kHz
Calculated dotclock: 25154 kHz
N: 4
M1: 20
M2: 9
M: 109
P1: 13
P2: 4
P: 52
...
Entry #33:
Dotclock: 297000 kHz
Calculated dotclock: 297000 kHz
N: 4
M1: 18
M2: 9
M: 99
P1: 2
P2: 2
P: 4
Block 15 example output from MGM:
BDB block 15 (124 bytes, min 2 bytes) - Dot clock override:
0000: 0f 7c 00 08 0a 00 00 00 00 00 00 00 00 00 00 00
0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0050: 00 00 00 00 00 08 0a 38 c7 00 00 02 14 07 02 00
0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Normal:
Row size: 8
Num rows: 10
Entry #1:
Dotclock: 0 kHz
...
Entry #10:
Dotclock: 0 kHz
LVDS:
Row size: 8
Num rows: 10
Entry #1:
Dotclock: 51000 kHz
Calculated dotclock: 51000 kHz
N: 4
M1: 22
M2: 9
M: 119
P1: 2
P2: 14
P: 28
...
Entry #5:
Dotclock: 0 kHz
Signed-off-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
---
tools/intel_vbt_decode.c | 144 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 142 insertions(+), 2 deletions(-)
diff --git a/tools/intel_vbt_decode.c b/tools/intel_vbt_decode.c
index fd0753eb11d7..5c334c902966 100644
--- a/tools/intel_vbt_decode.c
+++ b/tools/intel_vbt_decode.c
@@ -327,8 +327,9 @@ static size_t block_min_size(const struct context *context, int section_id)
case BDB_SWF_IO:
case BDB_SWF_MMIO:
return sizeof(struct bdb_reg_table);
- case BDB_PSR:
- return sizeof(struct bdb_psr);
+ case BDB_PSR: /* nee BDB_DOT_CLOCK_OVERRIDE_ALM */
+ return max(sizeof(struct bdb_psr),
+ sizeof(struct bdb_dot_clock_override_alm));
case BDB_MODE_REMOVAL_TABLE:
return sizeof(struct bdb_mode_removal);
case BDB_CHILD_DEVICE_TABLE:
@@ -337,6 +338,8 @@ static size_t block_min_size(const struct context *context, int section_id)
return sizeof(struct bdb_driver_features);
case BDB_DRIVER_PERSISTENCE:
return sizeof(struct bdb_driver_persistence);
+ case BDB_DOT_CLOCK_OVERRIDE:
+ return sizeof(struct bdb_dot_clock_override);
case BDB_SDVO_LVDS_OPTIONS:
return sizeof(struct bdb_sdvo_lvds_options);
case BDB_SDVO_LVDS_DTD:
@@ -1900,6 +1903,132 @@ static void dump_driver_persistence(struct context *context,
printf("\tPersistent max config: %d\n", persistence->persistent_max_config);
}
+static void dump_dot_clock_override_entry_gen2(const struct dot_clock_override_entry_gen2 *t,
+ bool is_lvds)
+{
+ int ref = 48000;
+ int m1 = t->m1 + 2;
+ int m2 = t->m2 + 2;
+ int m = 5 * m1 + m2;
+ int n = t->n + 2;
+ int p1, p2, p;
+
+ if (is_lvds) {
+ p1 = igt_fls((unsigned int)t->p1);
+ p2 = 14;
+ } else {
+ p1 = t->p1_div_by_2 ? 2 : (t->p1 + 2);
+ p2 = t->p2_div_by_4 ? 4 : 2;
+ }
+
+ p = p1 * p2;
+
+ printf("\t\t\tDotclock: %d kHz\n", t->dotclock);
+
+ if (!t->dotclock)
+ return;
+
+ printf("\t\t\tCalculated dotclock: %d kHz\n",
+ n && p ? DIV_ROUND_CLOSEST(ref * m, n * p) : 0);
+ printf("\t\t\tN: %d\n", n);
+ printf("\t\t\tM1: %d\n", m1);
+ printf("\t\t\tM2: %d\n", m2);
+ printf("\t\t\tM: %d\n", m);
+ printf("\t\t\tP1: %d\n", p1);
+ printf("\t\t\tP2: %d\n", p2);
+ printf("\t\t\tP: %d\n", p);
+}
+
+static void dump_dot_clock_override_alm(struct context *context,
+ const struct bdb_block *block)
+{
+ const struct bdb_dot_clock_override_alm *b = block_data(block);
+ int count = block->size / sizeof(b->t[0]);
+
+ for (int i = 0; i < count; i++) {
+ const struct dot_clock_override_entry_gen2 *t = &b->t[i];
+
+ printf("\t\tEntry #%d:\n", i + 1);
+ dump_dot_clock_override_entry_gen2(t, false);
+ }
+}
+
+static void dump_dot_clock_override_entry_gen3(const struct dot_clock_override_entry_gen3 *t)
+{
+ int ref = 96000;
+ int m1 = t->m1 + 2;
+ int m2 = t->m2 + 2;
+ int m = 5 * m1 + m2;
+ int n = t->n + 2;
+ int p1 = t->p1;
+ int p2 = t->p2;
+ int p = p1 * p2;
+
+ printf("\t\t\tDotclock: %d kHz\n", t->dotclock);
+
+ if (!t->dotclock)
+ return;
+
+ printf("\t\t\tCalculated dotclock: %d kHz\n",
+ n && p ? DIV_ROUND_CLOSEST(ref * m, n * p) : 0);
+ printf("\t\t\tN: %d\n", n);
+ printf("\t\t\tM1: %d\n", m1);
+ printf("\t\t\tM2: %d\n", m2);
+ printf("\t\t\tP1: %d\n", p1);
+ printf("\t\t\tP2: %d\n", p2);
+}
+
+static void _dump_dot_clock_override(const struct bdb_dot_clock_override *d,
+ int count, bool is_lvds)
+{
+ printf("\t\tRow size: %d\n", d->row_size);
+ printf("\t\tNum rows: %d\n", d->num_rows);
+
+ for (int i = 0; i < count; i++) {
+ const struct dot_clock_override_entry_gen2 *t_gen2 =
+ (const void *)d->table + i * d->row_size;
+ const struct dot_clock_override_entry_gen3 *t_gen3 =
+ (const void *)d->table + i * d->row_size;
+
+ printf("\t\tEntry #%d:\n", i + 1);
+
+ switch (d->row_size) {
+ case 9:
+ dump_dot_clock_override_entry_gen3(t_gen3);
+ break;
+ case 8:
+ dump_dot_clock_override_entry_gen2(t_gen2, is_lvds);
+ break;
+ default:
+ printf("\t\t\tDotclock: %d kHz\n", t_gen3->dotclock);
+ break;
+ }
+ }
+}
+
+static void dump_dot_clock_override(struct context *context,
+ const struct bdb_block *block)
+{
+ const struct bdb_dot_clock_override *d = block_data(block);
+ const void *start = d->table;
+ const void *end = (const void *)d + block->size;
+ int count;
+
+ count = min((int)(end - start) / d->row_size, (int)d->num_rows);
+ printf("\tNormal:\n");
+ _dump_dot_clock_override(d, count, false);
+
+ d = (const void *)d->table + count * d->row_size;
+ if ((const void *)d + sizeof(*d) >= end)
+ return;
+
+ start = d->table;
+
+ count = min((int)(end - start) / d->row_size, (int)d->num_rows);
+ printf("\tLVDS:\n");
+ _dump_dot_clock_override(d, count, true);
+}
+
static void dump_edp(struct context *context,
const struct bdb_block *block)
{
@@ -2966,6 +3095,12 @@ struct dumper dumpers[] = {
.name = "MMIO SWF register table",
.dump = dump_reg_table,
},
+ {
+ .id = BDB_DOT_CLOCK_OVERRIDE_ALM,
+ .max_bdb_version = 164,
+ .name = "Dot clock override (ALM)",
+ .dump = dump_dot_clock_override_alm,
+ },
{
.id = BDB_PSR,
.min_bdb_version = 165,
@@ -2992,6 +3127,11 @@ struct dumper dumpers[] = {
.name = "Driver persistent algorithm",
.dump = dump_driver_persistence,
},
+ {
+ .id = BDB_DOT_CLOCK_OVERRIDE,
+ .name = "Dot clock override",
+ .dump = dump_dot_clock_override,
+ },
{
.id = BDB_SDVO_LVDS_OPTIONS,
.name = "SDVO LVDS options block",
--
2.44.2
More information about the igt-dev
mailing list