Skip to content

drm/panel: add VIEWE 7 inch JD9365TX in-cell DSI panel - #7633

Open
HF-2001 wants to merge 8 commits into
raspberrypi:rpi-6.18.yfrom
HF-2001:viewe-7inch-jd9365tx
Open

HF-2001 wants to merge 8 commits into
raspberrypi:rpi-6.18.yfrom
HF-2001:viewe-7inch-jd9365tx

Conversation

@HF-2001

@HF-2001 HF-2001 commented Sep 18, 2026

Copy link
Copy Markdown

Add support for the VIEWE 7" 720x1280 MIPI DSI panel (Jadard JD9365TX, module 7KF82). Includes the DRM panel driver, in-cell touch (I2C poll), I2C backlight, DT bindings, and overlays for Pi 4 and Pi 5.

Usage:
dtoverlay=vc4-kms-dsi-viewe-7inch # Pi 4
dtoverlay=vc4-kms-dsi-viewe-7inch-pi5 # Pi 5

Panel is 2-lane only. Touch is at 0x68, backlight MCU at 0x45.
Tested on Raspberry Pi 4 and Raspberry Pi 5.

@6by9 6by9 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These comments are based on a fairly brief read through.

* Init sequence (page select via 0xDE). Page0 0xCC = 0x31 (2-lane).
*/
static const struct jd9365tx_cmd jd9365tx_7kf82_init[] = {
#include "panel-viewe-jd9365tx-init.h"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Including a .h file that isn't a header isn't acceptable.

{
struct jd9365tx_panel *ctx = to_jd9365tx(panel);
const struct drm_display_mode *src =
use_60hz ? &jd9365tx_7kf82_mode_60 : &jd9365tx_7kf82_mode_50;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be switched by the compatible string, not a module parameter.

"Delay between DISPOFF/SLPIN retries");

static struct mipi_dsi_device *g_reboot_dsi;
static struct notifier_block jd9365tx_reboot_nb;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Globals don't work if you have two of the devices connected to the system.

static uint sleep_cmd_retry_delay_ms = 20;
module_param(sleep_cmd_retry_delay_ms, uint, 0644);
MODULE_PARM_DESC(sleep_cmd_retry_delay_ms,
"Delay between DISPOFF/SLPIN retries");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

None of these things should be module parameters. You're writing the driver for this particular panel, so these values should be known.

return 0;
}

static void jd9365tx_run_dsi_diag(struct mipi_dsi_device *dsi, const char *tag)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DSI reads are generally a little dubious. This adds nothing.


/*
* Parse ESRAM section table for coordinate_report address / length.
* Layout matches official jd9365tx_ChipInfoInit / ReadSectionInfo.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're referencing documentation, then it needs to be a complete reference to what the document is.

if (ret == 1)
return 0;
msleep(20);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is I2C communication with this device so unreliable that it requires retries? That implies some issue in the design somewhere.

if (down) {
touchscreen_report_pos(ts->input, &ts->prop, x, y, true);
input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, w);
ts->prev_x[i] = x;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why store the points? They are never read back.

if (ts->suspended)
return;

mutex_lock(&ts->lock);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think this mutex is protecting against? The poll worker will only ever be called from one workqueue context, and this is the only thing that locks and unlocks the mutex.

};

fragment@2 {
target = <&i2c_csi_dsi1>;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On pi5, i2c_csi_dsi is an alias of i2c_csi_dsi1, so no need for a separate overlay at all as that is the only diff.

https://github.com/raspberrypi/linux/blob/rpi-6.18.y/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts#L221

@6by9

6by9 commented Sep 22, 2026

Copy link
Copy Markdown
Contributor

This needs to be broken into at least the following patches:

  • DT bindings for panel driver
  • DT bindings for touch driver
  • DT bindings for backlight MCU
  • DRM panel driver
  • touch driver
  • backlight MCU driver
  • defconfig changes (ideally splitting arm from arm64)
  • overlay

The kernel requires all patches to have the Signed-off-by: to be an identifiable individual. https://www.kernel.org/doc/html/latest/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin
We don't care as much for dtoverlays, but drivers need it.

The weird bus driver setup for touchscreen and backlight needs some explanation. They're on separate I2C addresses, and all i2c_transfer calls are atomic, so why the need to try synchronising them?

And all the drivers and binding should be submitted upstream. Having drivers in this downstream kernel tree adds an undesirable maintenance burden. Upstream will give you a significantly more thorough review as well.

@HF-2001

HF-2001 commented Sep 23, 2026 via email

Copy link
Copy Markdown
Author

@HF-2001
HF-2001 force-pushed the viewe-7inch-jd9365tx branch from 48f2e04 to d9149a0 Compare September 28, 2026 06:03
@HF-2001

HF-2001 commented Sep 28, 2026

Copy link
Copy Markdown
Author

Thanks for the review.

Pushed an updated series:

  • split into separate commits for the bindings, panel, touch, backlight, defconfig and overlay
  • inlined the panel init sequence into the .c and dropped the extra header
  • removed the module parameters, DSI read diagnostics, reboot notifier and globals
  • removed the shared I2C backlight queue; backlight now writes directly
  • touch uses input_setup_polling()
  • one overlay on i2c_csi_dsi

The queue was left over from early bring-up. Touch and backlight are on different addresses, so normal independent I2C transfers are enough.

@HF-2001

HF-2001 commented Oct 21, 2026

Copy link
Copy Markdown
Author

Hi Dave,

Just a gentle reminder that we pushed an updated series on Sep 28 addressing your review comments (split commits, removed the shared I2C queue, input_setup_polling, single overlay, etc.).

Whenever you have a moment to take another look, that would be much appreciated. Thanks again for your guidance.

Best regards

@6by9 6by9 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't reviewed the dtbindings in detail as the upstream maintainers deal with that. However vendor specific properties will have to be justified.

I'd said last time

And all the drivers and binding should be submitted upstream. Having drivers in this downstream kernel tree adds an undesirable maintenance burden. Upstream will give you a significantly more thorough review as well.

Are you intending to submit upstream?

And as per one of my review comments, what is different about JD9365TX vs JD9365A that already has a panel driver?

reg:
maxItems: 1

default-brightness:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You've included common.yaml, so you shouldn't need to define default-brightness again.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. We included common.yaml already, so we will drop the duplicate default-brightness definition.

__overrides__ {
rotation = <&panel>, "rotation:0";
notouch = <&jadard_tp>, "status=disabled";
nobl = <&viewe_bl>, "status=disabled";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't the backlight = <&viewe_bl>; line for the panel not need to be disabled too? (Question rather than statement)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — yes. With nobl we should also stop the panel from referencing &viewe_bl (clear/disable that backlight link), otherwise the panel still expects a backlight device that is disabled. We will fix the overlay accordingly.

@@ -0,0 +1,390 @@
// SPDX-License-Identifier: GPL-2.0

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is already a panel-jadard-jd9365a-h3.c panel driver in the tree (https://github.com/raspberrypi/linux/blob/rpi-6.18.y/drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c)

What's the difference with JD9365TX that makes it incompatible?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The existing driver is for the JD9365DA family (panel-jadard-jd9365da-h3.c), used by 800x1280 / 4-lane modules with their own init tables.

This panel is a JD9365TX on VIEWE 7KF82: 720x1280, 2-lane only, and a different init sequence (including 2-lane config). Those differences make it incompatible with the existing DA driver without turning that file into a catch-all for unrelated modules, so we kept a separate panel driver.

reg:
maxItems: 1

jadard,poll-interval-ms:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

input-common.yaml defines a standard poll-interval property.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. We will switch to the standard poll-interval property from input-common.yaml and drop jadard,poll-interval-ms.

minimum: 8
maximum: 100

jadard,max-touch-number:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really a configurable thing that can't be read back from the touch controller?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this module the touch point count is fixed by the firmware/panel design and we do not have a reliable register readback for it during bring-up. We will hard-code it in the driver and remove the DT property.

Comment thread drivers/video/backlight/viewe_bl_i2c.c Outdated
if (IS_ERR(bl->bd))
return PTR_ERR(bl->bd);

ret = viewe_bl_write(client, VIEWE_BL_DEFAULT);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed as you've set brightness in the backlight_properties struct, which is documented as setting the default brightness
https://elixir.bootlin.com/linux/v6.18.57/source/include/linux/backlight.h#L171

Based on that, viewe_bl_write may as well be merged into viewe_bl_update_status as it's the only place it is then called from.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. We will drop the extra viewe_bl_write() in probe and fold the I2C write into viewe_bl_update_status only.

MODULE_AUTHOR("Hefei <3066883572@qq.com>");
MODULE_DESCRIPTION("VIEWE 7\" JD9365TX MIPI-DSI panel");
MODULE_LICENSE("GPL");
MODULE_SOFTDEP("pre: viewe_bl_i2c"); No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still have a dependency?

No carriage return at the end of the file.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The panel uses drm_panel_of_backlight() via phandle, so there is no hard module load dependency on viewe_bl_i2c. We will drop MODULE_SOFTDEP and add the missing trailing newline.

if (!(jd_section_ready(ts->client) && !jd_resolve_coord_addr(ts))) {
if (!ts->coord_addr)
ts->coord_addr = JD_DEFAULT_COORD_ADDR;
if (!ts->touch_data_size)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How are you expecting this condition to ever be true? Line 272 says
ts->touch_data_size = JD_TOUCH_DATA_SIZE;
and probe has to have completed before poll has a chance to run.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right — that condition cannot become true after probe sets touch_data_size. It was left over from earlier bring-up. We will remove the dead path.

Comment thread drivers/input/touchscreen/Makefile Outdated
obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o
obj-$(CONFIG_TOUCHSCREEN_ILITEK) += ilitek_ts_i2c.o
obj-$(CONFIG_TOUCHSCREEN_ILITEK_V3) += ilitek_v3_ts_i2c.o
obj-$(CONFIG_TOUCHSCREEN_JADARD_JD9365TX) += jadard_jd9365tx.o

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alphabetical order please

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will fix — place the entry in alphabetical order.

Comment thread drivers/input/touchscreen/Kconfig Outdated
To compile this driver as a module, choose M here: the
module will be called ilitek_v3_ts_i2c.

config TOUCHSCREEN_JADARD_JD9365TX

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alphabetical order please.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will fix — place the Kconfig entry in alphabetical order.

@HF-2001

HF-2001 commented Oct 26, 2026

Copy link
Copy Markdown
Author

Thanks for the further review.

Yes — we intend to submit the drivers and bindings upstream. We will prepare that once the remaining review comments here are addressed.

On JD9365TX vs the existing Jadard panel driver (panel-jadard-jd9365da-h3.c, JD9365DA family):

  • Different controller variant: JD9365TX vs JD9365DA
  • Different panel geometry: 720x1280 (VIEWE 7KF82) vs 800x1280 modules in that driver
  • Different DSI topology: 2-lane only here vs 4-lane there
  • Different init / gamma / lane-config sequences (our panel sets 2-lane via page0 0xCC=0x31)

So it is not a compatible drop-in for that driver; a separate panel description is needed.

We will update the series for the other inline comments (bindings cleanup, overlay nobl/backlight handling, remove prepared, backlight probe cleanup, touch dead path, Kconfig/Makefile ordering, etc.) and push again shortly.

@HF-2001

HF-2001 commented Oct 26, 2026

Copy link
Copy Markdown
Author

Pushed a follow-up commit addressing the latest review comments:

  • backlight binding: drop duplicate default-brightness (use common.yaml)
  • overlay: nobl also clears panel backlight phandle; touch uses jadard,jd9365tx + poll-interval
  • panel: DISPON delay #define, remove prepared flag and MODULE_SOFTDEP
  • backlight driver: fold I2C write into update_status; no probe-time write
  • touch: fix coord-addr fallback, hard-coded max points, Kconfig/Makefile order

Happy to adjust further if needed.

@HF-2001

HF-2001 commented Oct 26, 2026 via email

Copy link
Copy Markdown
Author

@6by9 6by9 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On JD9365TX vs the existing Jadard panel driver (panel-jadard-jd9365da-h3.c, JD9365DA family):

  • different controller variant: JD9365TX vs JD9365DA
  • different geometry: 720x1280 (VIEWE 7KF82) vs 800x1280 modules in that driver
  • different DSI setup: 2-lane only here vs 4-lane there
  • different init / lane-config sequences (this panel sets 2-lane via page0 0xCC=0x31)

So it is not a drop-in for that driver; a separate panel description is needed.

I can't find a datasheet for JD9365TX, hence asking these questions. You'll get exactly the same when you send it upstream.

You'll see from panel-ilitek-ili9881c that supporting multiple geometries and number of lanes isn't justification for not extending the existing driver.

The upstream version of the panel-jadard-jd9365da-h3.c (since kernel 7.2) has gained support for 2 and 4 lane modes, 720x1280, 600x1600, and 800x800 panels, and differing init sequences.
It does appear to use register 0x80 bit[1] to switch between 2 and 4 lane modes, so potentially it is different. The datasheet I've found for JD9365DA-H3 lists a DSI_INIT0 register with bit [0] switching modes, so that contradicts the driver. It also doesn't list which register DSI_INIT0 would correspond to.

The cleanups can't just be dumped into one big lump. They should be merged back into the relevant patches that had the issue.


Name: vc4-kms-dsi-viewe-7inch
Info: Enable the VIEWE 7" 720x1280 JD9365TX in-cell DSI panel.
2-lane, DSI1 + i2c_csi_dsi (Pi 3/4/5).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason it doesn't work on Pi1, or by implication Compute Modules?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No hardware reason known against Pi 1 / Compute Modules that expose DSI + i2c_csi_dsi — we only listed Pi 3/4/5 because that is what we tested. We asked in the main thread whether you want full MIPI-capable Pi / CM coverage before we update the README wording.

Add the device tree binding for the VIEWE 7KF82 720x1280 Jadard
JD9365TX MIPI-DSI panel.

Signed-off-by: Hefei <3066883572@qq.com>
Add the binding for the Jadard JD9365TX in-cell touchscreen used on
the VIEWE 7KF82 module.

Signed-off-by: Hefei <3066883572@qq.com>
Add the binding for the VIEWE panel backlight MCU on I2C.

Signed-off-by: Hefei <3066883572@qq.com>
Add a DRM MIPI-DSI panel driver for the VIEWE 7KF82 module based on
Jadard JD9365TX (2-lane video mode).

Signed-off-by: Hefei <3066883572@qq.com>
Add a polling I2C touchscreen driver for Jadard JD9365TX in-cell
panels that do not wire an interrupt line on the FPC.

Signed-off-by: Hefei <3066883572@qq.com>
Add a simple I2C backlight class driver for the VIEWE panel MCU at
address 0x45, register 0x86.

Signed-off-by: Hefei <3066883572@qq.com>
Enable the VIEWE panel, touch and backlight drivers as modules in the
Raspberry Pi bcm2711 and bcm2712 defconfigs.

Signed-off-by: Hefei <3066883572@qq.com>
Add a dtoverlay for the VIEWE 7 inch JD9365TX panel on DSI1 using
i2c_csi_dsi for touch and backlight.

Signed-off-by: Hefei <3066883572@qq.com>
@HF-2001
HF-2001 force-pushed the viewe-7inch-jd9365tx branch from 0ad7783 to 1932bd4 Compare October 27, 2026 07:12
@HF-2001

HF-2001 commented Oct 27, 2026

Copy link
Copy Markdown
Author

Thanks for the follow-up.

On folding into panel-jadard-jd9365da-h3: we looked at that driver (including the newer upstream version with 2/4-lane and 720x1280 variants). The DRM structure is similar (per-module desc + init), but the programming model does not match this panel:

  • page select is 0xDE here, vs 0xE0 on JD9365DA
  • bring-up unlock is 0xDF/0x90/0x84/0x14, vs the DA 0xE1/0xE2/0xE3 sequence
  • lane config is page0 0xCC (0x31 for 2-lane), vs DA register 0x80
  • the rest of the init table is a different register map

So this is not just another geometry/lane combo on the same controller interface. We do not have a public JD9365TX datasheet to hand either; if you still prefer extending the DA driver despite that command-set difference, please say so and we will rework it that way.

On the patch series: the previous single cleanup commit has been folded back into the relevant patches and force-pushed (still the same 8-way split).

On the README "Pi 3/4/5" wording: we only tested on Pi 4 and Pi 5. Would you like us to validate on every Raspberry Pi platform that can drive a MIPI DSI panel (Pi 1 / earlier boards where applicable, and Compute Modules), or is coverage of the current DSI-capable products you care about enough? Happy to widen testing if that is what you need.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants