[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