* [PATCH 1/2] dt-bindings: display: panel: add the BOE TV101WUM-NM0
2026-09-12 18:22 [PATCH 0/2] drm/panel: novatek-nt51021: add the BOE TV101WUM-NM0 Ryan Brue
@ 2026-09-12 18:22 ` Ryan Brue
2026-09-12 18:22 ` [PATCH 2/2] drm/panel: novatek-nt51021: " Ryan Brue
2026-09-13 14:07 ` [PATCH 0/2] " Nickolay Goppen
2 siblings, 0 replies; 4+ messages in thread
From: Ryan Brue @ 2026-09-12 18:22 UTC (permalink / raw)
To: Nickolay Goppen, Neil Armstrong, Jessica Zhang, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno
Cc: dri-devel, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, Ryan Brue
Describe the BOE module fitted to the Amazon Fire HD 10 (2017), an
MT8173
tablet, as a third NT51021 panel.
The methodology for finding the part number for this glass is notable,
since it was done by process of elimination.
The vendor firmware chooses between a BOE and an Innolux module from two
board ID straps. This means whatever the two are, they are mechanically
and electrically interchangeable in the one chassis. An Innolux module
pulled directly from one of these tablets was pictured with the part
number "P101KDA-AB0" on the back, and that part is 216.576 x 135.36 mm
active, 227.926 x 143 x 4.4 mm outline, 51-pin MIPI with four data
lanes, a four-string WLED backlight and a 3.3 V supply. The BOE module
therefore has to match those specifications.
Searching through BOE's panel specifications, only two panels match
these constraints: TV101WUM-NM0 and TV101WUM-NM1. In particular the
number of pins and the dimensions were the greatest discriminators.
Measured on the available board (BOE), the tablet's LCM flex is
silkscreened 1 at one end and 51 at the other, and the area was measured
as 216 x 135 mm, and its backlight regulator is configured for four LED
strings, which matches the TV101WUM-NM0.
Finally, a replacement part listing for the Amazon Fire HD 10 (2017)
device also names the BOE TV101WUM-NM0. The NM1 was released later than
the NM0, but is the same mechanical design and would take the same
programming.
Even though the part number was not physically read from the test unit,
this module is absolutely not the boe,tv101wum-nx0, on the pin count
alone.
Signed-off-by: Ryan Brue <ryanbrue.dev@gmail.com>
---
Documentation/devicetree/bindings/display/panel/novatek,nt51021.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/display/panel/novatek,nt51021.yaml b/Documentation/devicetree/bindings/display/panel/novatek,nt51021.yaml
index 550aefaead46..6045385ce1a7 100644
--- a/Documentation/devicetree/bindings/display/panel/novatek,nt51021.yaml
+++ b/Documentation/devicetree/bindings/display/panel/novatek,nt51021.yaml
@@ -22,6 +22,7 @@ properties:
compatible:
items:
- enum:
+ - boe,tv101wum-nm0
- boe,tv101wum-nx0
- boe,tv080wum-nx2
- const: novatek,nt51021
--
2.55.0
^ permalink raw reply related [flat|nested] 4+ messages in thread* [PATCH 2/2] drm/panel: novatek-nt51021: add the BOE TV101WUM-NM0
2026-09-12 18:22 [PATCH 0/2] drm/panel: novatek-nt51021: add the BOE TV101WUM-NM0 Ryan Brue
2026-09-12 18:22 ` [PATCH 1/2] dt-bindings: display: panel: " Ryan Brue
@ 2026-09-12 18:22 ` Ryan Brue
2026-09-13 14:07 ` [PATCH 0/2] " Nickolay Goppen
2 siblings, 0 replies; 4+ messages in thread
From: Ryan Brue @ 2026-09-12 18:22 UTC (permalink / raw)
To: Nickolay Goppen, Neil Armstrong, Jessica Zhang, David Airlie,
Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno
Cc: dri-devel, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, Ryan Brue
Add the BOE module fitted to the Amazon Fire HD 10 (2017), an MT8173
tablet, as a third NT51021 variant. How the part was identified, since
its label is not readable without removing the main board, is set out in
the binding patch.
The register sequence is the BOE branch of init_lcm_registers() in
drivers/misc/mediatek/lcm/nt51021_wuxga_dsi_vdo/ in the Fire OS 3.18
tree, command for command, with only a 120 ms wait after sleep-out added
where the vendor waits its trailing 5 ms. The 0x8f 0xa5 and 0x8f 0x00
that bracket it are the vendor's command interface selection, sent on
every board that is not an early proto or HVT unit.
It is much shorter than boe_tv101wum_nx0_init() because this module is
left on its own factory trim. NT51021 R8CH selects whether V1/V14, gamma
and HAOP come from the panel's OTP memory or from control registers, and
the 0x8c 0x80 here leaves all three on OTP, where the NX0's 0x8e
switches
them to registers so that the three pages of gamma it then writes take
effect. So the absent gamma is deliberate rather than an omission, and
the differing 0x8c is its consequence. CABC is likewise untouched
because
the vendor drives it over I2C from the backlight path. What is left is
0xc0 and 0xc8, which the public NT51021 specification does not describe;
everything else this sequence touches carries the same value as the
other
two panels, including the terminal resistor, TP_SYNC, the MIPI Rx drive
strength and all three test modes.
The timings are the vendor's lcm_get_params(): hsync 1, hbp 32, hfp 110,
vsync 1, vbp 14, vfp 11, so htotal 1343 and vtotal 1946. The pixel clock
follows the vendor's PLL_CLOCK = 490, which after DDR is 980 Mbps per
lane and over four lanes at 24bpp is 163.33 MHz, so 62.5 Hz. The
bootloader leaves the MIPI TX PLL at that rate: read back before the
kernel touches it, this board's PLL decodes to exactly 980 Mbps per
lane, so the panel is already there when the kernel takes over.
The front porch is the vendor's declared 110 rather than the smaller
value its own DSI driver ends up running. That driver also sets
clk_lp_per_line_enable, which makes ddp_dsi_config() overwrite HFP_WC
after the declared timing is programmed, shrinking it to leave just
enough room to take the clock lane to LP and back. That is a
controller-side workaround rather than a panel property, and it
contradicts the cont_clock = 1 set beside it, which disables the very LP
transition it makes room for. Mainline mtk_dsi handles the clock lane
itself, so the panel's declared timing is the right thing to carry here.
The vendor asks for SYNC_EVENT_VDO_MODE with cont_clock = 1 rather than
burst, so make mode_flags per variant instead of fixed in probe(). The
two existing panels keep the flags they had. Burst was also tried on
this hardware and worked, but the vendor configuration is the one the
module is characterised for.
The physical size is the datasheet active area, 216.576 x 135.36 mm,
which measures 216 x 135 on the glass. The vendor's declared a
physical_width = 136 and physical_height = 221, which appears to be an
error. The size of the test unit was physically measured. 1200/136 and
1920/221 disagree by 1.5%.
The vendor's bootloader and kernel both carry a second register sequence
for the Innolux module this board second-sources against, selected from
two board ID straps. No Innolux unit was available, so that sequence is
left out rather than carried untested; however, the Innolux part number
was identified as "P101KDA-AB0", should someone with that glass need to
upstream support in the future.
Tested on the Amazon Fire HD 10 (2017) driven by mediatek-drm: 1200x1920
at 62.5 Hz across a cold boot, display off and on cycles and a
suspend/resume, with the MIPI TX PLL reading back at the intended rate
every time.
Assisted-by: LLM
Signed-off-by: Ryan Brue <ryanbrue.dev@gmail.com>
---
drivers/gpu/drm/panel/panel-novatek-nt51021.c | 66 ++++++++++++++++++++++++++-
1 file changed, 64 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/panel/panel-novatek-nt51021.c b/drivers/gpu/drm/panel/panel-novatek-nt51021.c
index 61dd283769a7..2a8fa181ac37 100644
--- a/drivers/gpu/drm/panel/panel-novatek-nt51021.c
+++ b/drivers/gpu/drm/panel/panel-novatek-nt51021.c
@@ -23,6 +23,7 @@ struct novatek_nt51021_variant {
int (*init)(struct novatek_nt51021_desc *ctx);
const struct drm_display_mode *display_mode;
+ unsigned long mode_flags;
};
struct novatek_nt51021_desc {
@@ -607,6 +608,39 @@ static int boe_tv101wum_nx0_init(struct novatek_nt51021_desc *ctx)
return dsi_ctx.accum_err;
}
+static int boe_tv101wum_nm0_init(struct novatek_nt51021_desc *ctx)
+{
+ struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
+
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0xa5);
+ mipi_dsi_usleep_range(&dsi_ctx, 1000, 2000);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x01, 0x00);
+ mipi_dsi_msleep(&dsi_ctx, 20);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0xa5);
+ mipi_dsi_usleep_range(&dsi_ctx, 1000, 2000);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8c, 0x80);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcd, 0x6c);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc0, 0x8b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc8, 0xf0);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x97, 0x00);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8b, 0x10);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa9, 0x20);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x83, 0xaa);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x84, 0x11);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xa9, 0x4b);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x85, 0x04);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x86, 0x08);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x9c, 0x10);
+ mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
+ mipi_dsi_msleep(&dsi_ctx, 120);
+ mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x8f, 0x00);
+ mipi_dsi_msleep(&dsi_ctx, 5);
+
+ return dsi_ctx.accum_err;
+}
+
static int nt51021_novatek_off(struct novatek_nt51021_desc *ctx)
{
struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
@@ -713,8 +747,7 @@ static int nt51021_novatek_probe(struct mipi_dsi_device *dsi)
dsi->lanes = 4;
dsi->format = MIPI_DSI_FMT_RGB888;
- dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
- MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_LPM;
+ dsi->mode_flags = ctx->variant->mode_flags;
ctx->panel.prepare_prev_first = true;
@@ -744,6 +777,21 @@ static const struct drm_display_mode boe_tv080wum_nx2_mode = {
.type = DRM_MODE_TYPE_DRIVER,
};
+static const struct drm_display_mode boe_tv101wum_nm0_mode = {
+ .clock = 163333,
+ .hdisplay = 1200,
+ .hsync_start = 1200 + 110,
+ .hsync_end = 1200 + 110 + 1,
+ .htotal = 1200 + 110 + 1 + 32,
+ .vdisplay = 1920,
+ .vsync_start = 1920 + 11,
+ .vsync_end = 1920 + 11 + 1,
+ .vtotal = 1920 + 11 + 1 + 14,
+ .width_mm = 135,
+ .height_mm = 216,
+ .type = DRM_MODE_TYPE_DRIVER,
+};
+
static const struct drm_display_mode boe_tv101wum_nx0_mode = {
.clock = (1200 + 172 + 4 + 32) * (1920 + 25 + 1 + 14) * 60 / 1000,
.hdisplay = 1200,
@@ -759,18 +807,32 @@ static const struct drm_display_mode boe_tv101wum_nx0_mode = {
.type = DRM_MODE_TYPE_DRIVER,
};
+#define NT51021_BURST_MODE_FLAGS (MIPI_DSI_MODE_VIDEO | \
+ MIPI_DSI_MODE_VIDEO_BURST | \
+ MIPI_DSI_MODE_NO_EOT_PACKET | \
+ MIPI_DSI_MODE_LPM)
+
static const struct novatek_nt51021_variant boe_tv080wum_nx2_data = {
.init = boe_tv080wum_nx2_init,
.display_mode = &boe_tv080wum_nx2_mode,
+ .mode_flags = NT51021_BURST_MODE_FLAGS,
+};
+
+static const struct novatek_nt51021_variant boe_tv101wum_nm0_data = {
+ .init = boe_tv101wum_nm0_init,
+ .display_mode = &boe_tv101wum_nm0_mode,
+ .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM,
};
static const struct novatek_nt51021_variant boe_tv101wum_nx0_data = {
.init = boe_tv101wum_nx0_init,
.display_mode = &boe_tv101wum_nx0_mode,
+ .mode_flags = NT51021_BURST_MODE_FLAGS,
};
static const struct of_device_id nt51021_novatek_of_match[] = {
{ .compatible = "boe,tv080wum-nx2", .data = &boe_tv080wum_nx2_data },
+ { .compatible = "boe,tv101wum-nm0", .data = &boe_tv101wum_nm0_data },
{ .compatible = "boe,tv101wum-nx0", .data = &boe_tv101wum_nx0_data },
{ /* sentinel */ }
};
--
2.55.0
^ permalink raw reply related [flat|nested] 4+ messages in thread