Quantcast
Channel: Raspberry Pi Forums
Viewing all articles
Browse latest Browse all 6970

Interfacing (DSI, CSI, I2C, etc.) • MIPI DSI Display Jadard JD9165

$
0
0
Hi,

We are in the process of bringing up a 1024x600 display based on the JD9165 controller, connected to the DSI0 port using 2-lane MIPI. We have modified the driver lt070me05000 by adding the initialization sequence and timings provided by the manufacturer, and so far, the only result we've managed to achieve is that the first few lines of the display show some image.

What we have checked:
- BIST mode is working when send commands using MIPI
- Trace length and impedances are correct
- Power supply sequence is ok
- MIPI signal levels are correct,
- many configurations of timings, clock speeds etc.

Jadard (Fitipower) JD9165A driver datasheet: https://dl.espressif.com/AE/esp-iot-sol ... 1-0621.pdf

Below is a photo showing what the screen looks like and a video demonstrating what happens when I move the mouse cursor:


Does anyone have an idea of what we could improve to get the display working correctly?

Display.jpg


Video when moving mouse: https://photos.app.goo.gl/yu4oTYZQUBAx56Xy9

Modified panel-jdi-lt070me05000.c code:

Code:

// SPDX-License-Identifier: GPL-2.0-only/* * Copyright (C) 2016 InforceComputing * Author: Vinay Simha BN <simhavcs@gmail.com> * * Copyright (C) 2016 Linaro Ltd * Author: Sumit Semwal <sumit.semwal@linaro.org> */#include <linux/backlight.h>#include <linux/delay.h>#include <linux/gpio/consumer.h>#include <linux/module.h>#include <linux/of.h>#include <linux/regulator/consumer.h>#include <video/mipi_display.h>#include <drm/drm_crtc.h>#include <drm/drm_mipi_dsi.h>#include <drm/drm_modes.h>#include <drm/drm_panel.h>struct jdi_panel {struct drm_panel base;struct mipi_dsi_device *dsi;struct gpio_desc *enable_gpio;struct gpio_desc *reset_gpio;struct gpio_desc *dcdc_en_gpio;struct backlight_device *backlight;const struct drm_display_mode *mode;};static inline struct jdi_panel *to_jdi_panel(struct drm_panel *panel){return container_of(panel, struct jdi_panel, base);}static int jdi_panel_init(struct jdi_panel *jdi){struct mipi_dsi_device *dsi = jdi->dsi;struct device *dev = &jdi->dsi->dev;int ret;dsi->mode_flags |= MIPI_DSI_MODE_LPM;ret = mipi_dsi_dcs_soft_reset(dsi);if (ret < 0)return ret;usleep_range(10000, 20000);printk("JD9165: START OF LCD INIT SEQUENCE \n");//ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT << 4);//if (ret < 0) {//dev_err(dev, "failed to set pixel format: %d\n", ret);//return ret;//}mipi_dsi_generic_write(dsi, (u8[]){0x30, 0x00}, 2);mipi_dsi_generic_write(dsi, (u8[]){0xf7, 0x49,0x61,0x02,0x00}, 5);mipi_dsi_generic_write(dsi, (u8[]){0x30, 0x01}, 2);mipi_dsi_generic_write(dsi, (u8[]){0x04,0x0C}, 2);mipi_dsi_generic_write(dsi, (u8[]){0x05,0x00}, 2); //05=06(xhs) //0x01 for BISTmipi_dsi_generic_write(dsi, (u8[]){0x06,0x00}, 2);//06=80(xhs) // 0x40 for BISTmipi_dsi_generic_write(dsi, (u8[]){0x0B,0x11}, 2);//0x13=4lanes,0x12=3lanes,0x11=2lanes,0x10=1 lanes  mipi_dsi_generic_write(dsi, (u8[]){0x17,0x00}, 2);mipi_dsi_generic_write(dsi, (u8[]){0x20,0x04}, 2);//add //r_lansel_sel_reg=1, software charge lane must openmipi_dsi_generic_write(dsi, (u8[]){0x1F,0x00}, 2);//add hs_settle timemipi_dsi_generic_write(dsi, (u8[]){0x23,0x00}, 2);//add //close gasmipi_dsi_generic_write(dsi, (u8[]){0x25,0x19}, 2);mipi_dsi_generic_write(dsi, (u8[]){0x28,0x18}, 2);mipi_dsi_generic_write(dsi, (u8[]){0x29,0x04}, 2);//revcommipi_dsi_generic_write(dsi, (u8[]){0x2A,0x01}, 2);//revcommipi_dsi_generic_write(dsi, (u8[]){0x2B,0x04}, 2);//vcommipi_dsi_generic_write(dsi, (u8[]){0x2C,0x01}, 2);//vcommipi_dsi_generic_write(dsi, (u8[]){0x30, 0x02}, 2);mipi_dsi_generic_write(dsi, (u8[]){0x01,0x22}, 2);mipi_dsi_generic_write(dsi, (u8[]){0x03,0x12}, 2);mipi_dsi_generic_write(dsi, (u8[]){0x04,0x00}, 2);mipi_dsi_generic_write(dsi, (u8[]){0x05,0x64}, 2);mipi_dsi_generic_write(dsi, (u8[]){0x0A,0x08}, 2);mipi_dsi_generic_write(dsi, (u8[]){0x0B,0x0A,0x1A,0x0B,0x0D,0x0D,0x11,0x10,0x06,0x08,0x1F,0x1D}, 12);mipi_dsi_generic_write(dsi, (u8[]){0x0C,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D}, 12);mipi_dsi_generic_write(dsi, (u8[]){0x0D,0x16,0x1B,0x0B,0x0D,0x0D,0x11,0x10,0x07,0x09,0x1E,0x1C}, 12);mipi_dsi_generic_write(dsi, (u8[]){0x0E,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D}, 12);mipi_dsi_generic_write(dsi, (u8[]){0x0F,0x16,0x1B,0x0D,0x0B,0x0D,0x11,0x10,0x1C,0x1E,0x09,0x07}, 12);mipi_dsi_generic_write(dsi, (u8[]){0x10,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D}, 12);mipi_dsi_generic_write(dsi, (u8[]){0x11,0x0A,0x1A,0x0D,0x0B,0x0D,0x11,0x10,0x1D,0x1F,0x08,0x06}, 12);mipi_dsi_generic_write(dsi, (u8[]){0x12,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D}, 12);mipi_dsi_generic_write(dsi, (u8[]){0x14,0x00,0x00,0x11,0x11}, 5);  //CKV_OFFmipi_dsi_generic_write(dsi, (u8[]){0x18,0x99}, 2);mipi_dsi_generic_write(dsi, (u8[]){0x30, 0x06}, 2);mipi_dsi_generic_write(dsi, (u8[]){0x12, 0x36,0x2C,0x2E,0x3C,0x38,0x35,0x35,0x32,0x2E,0x1D,0x2B,0x21,0x16,0x29}, 15);mipi_dsi_generic_write(dsi, (u8[]){0x13, 0x36,0x2C,0x2E,0x3C,0x38,0x35,0x35,0x32,0x2E,0x1D,0x2B,0x21,0x16,0x29}, 15);mipi_dsi_generic_write(dsi, (u8[]){0x30, 0x0A}, 2);mipi_dsi_generic_write(dsi, (u8[]){0x02,0x4F}, 2);mipi_dsi_generic_write(dsi, (u8[]){0x0B,0x40}, 2);mipi_dsi_generic_write(dsi, (u8[]){0x12,0x3E}, 2);mipi_dsi_generic_write(dsi, (u8[]){0x13,0x78}, 2);mipi_dsi_generic_write(dsi, (u8[]){0x30, 0x0D}, 2);mipi_dsi_generic_write(dsi, (u8[]){0x0D,0x04}, 2); //0x0C, 0x04mipi_dsi_generic_write(dsi, (u8[]){0x10,0x0C}, 2);mipi_dsi_generic_write(dsi, (u8[]){0x11,0x0C}, 2);mipi_dsi_generic_write(dsi, (u8[]){0x12,0x0C}, 2);mipi_dsi_generic_write(dsi, (u8[]){0x13,0x0C}, 2);mipi_dsi_generic_write(dsi, (u8[]){0x30, 0x00}, 2);mipi_dsi_generic_write(dsi, (u8[]){0x11}, 1); //exit z sleepmodemdelay(120);printk("JD9165: END OF INIT SEQUENCE DISPLAY \n");mipi_dsi_generic_write(dsi, (u8[]){0x29}, 1); //display onmdelay(20);return 0;}static int jdi_panel_on(struct jdi_panel *jdi){struct mipi_dsi_device *dsi = jdi->dsi;struct device *dev = &jdi->dsi->dev;int ret;dsi->mode_flags |= MIPI_DSI_MODE_LPM;ret = mipi_dsi_dcs_set_display_on(dsi);if (ret < 0)dev_err(dev, "failed to set display on: %d\n", ret);return ret;}static void jdi_panel_off(struct jdi_panel *jdi){struct mipi_dsi_device *dsi = jdi->dsi;struct device *dev = &jdi->dsi->dev;int ret;dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;ret = mipi_dsi_dcs_set_display_off(dsi);if (ret < 0)dev_err(dev, "failed to set display off: %d\n", ret);ret = mipi_dsi_dcs_enter_sleep_mode(dsi);if (ret < 0)dev_err(dev, "failed to enter sleep mode: %d\n", ret);msleep(100);}static int jdi_panel_disable(struct drm_panel *panel){struct jdi_panel *jdi = to_jdi_panel(panel);backlight_disable(jdi->backlight);return 0;}static int jdi_panel_unprepare(struct drm_panel *panel){struct jdi_panel *jdi = to_jdi_panel(panel);struct device *dev = &jdi->dsi->dev;int ret;jdi_panel_off(jdi);gpiod_set_value_cansleep(jdi->enable_gpio, 0);gpiod_set_value_cansleep(jdi->reset_gpio, 1);gpiod_set_value_cansleep(jdi->dcdc_en_gpio, 0);return 0;}static int jdi_panel_prepare(struct drm_panel *panel){return 0;}static int jdi_panel_enable(struct drm_panel *panel){struct jdi_panel *jdi = to_jdi_panel(panel);struct device *dev = &jdi->dsi->dev;int ret;gpiod_set_value_cansleep(jdi->reset_gpio, 1);usleep_range(10, 20);msleep(20);gpiod_set_value_cansleep(jdi->dcdc_en_gpio, 1);usleep_range(10, 20);gpiod_set_value_cansleep(jdi->reset_gpio, 0);usleep_range(10, 20);gpiod_set_value_cansleep(jdi->enable_gpio, 1);usleep_range(10, 20);ret = jdi_panel_init(jdi);if (ret < 0) {dev_err(dev, "failed to init panel: %d\n", ret);}ret = jdi_panel_on(jdi);if (ret < 0) {dev_err(dev, "failed to set panel on: %d\n", ret);}return 0;}static const struct drm_display_mode default_mode = {.clock = 50000,.hdisplay    = 1024,.hsync_start = 1024 + 160,               // hdisplay + hsync_front_porch.hsync_end   = 1024 + 160 + 40,          // hsync_start + hsync_pulse_width.htotal      = 1024 + 160 + 40 + 160,    // full line.vdisplay    = 600,.vsync_start = 600 + 12,                 // vdisplay + vsync_front_porch.vsync_end   = 600 + 12 + 10,            // vsync_start + vsync_pulse_width.vtotal      = 600 + 12 + 10 + 23,       // full frame};static int jdi_panel_get_modes(struct drm_panel *panel,       struct drm_connector *connector){struct drm_display_mode *mode;struct jdi_panel *jdi = to_jdi_panel(panel);struct device *dev = &jdi->dsi->dev;mode = drm_mode_duplicate(connector->dev, &default_mode);if (!mode) {dev_err(dev, "failed to add mode %ux%ux@%u\n",default_mode.hdisplay, default_mode.vdisplay,drm_mode_vrefresh(&default_mode));return -ENOMEM;}drm_mode_set_name(mode);drm_mode_probed_add(connector, mode);connector->display_info.width_mm = 95;connector->display_info.height_mm = 151;return 1;}static int dsi_dcs_bl_get_brightness(struct backlight_device *bl){struct mipi_dsi_device *dsi = bl_get_data(bl);int ret;u16 brightness = bl->props.brightness;dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;ret = mipi_dsi_dcs_get_display_brightness(dsi, &brightness);if (ret < 0)return ret;dsi->mode_flags |= MIPI_DSI_MODE_LPM;return brightness & 0xff;}static int dsi_dcs_bl_update_status(struct backlight_device *bl){struct mipi_dsi_device *dsi = bl_get_data(bl);int ret;dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;ret = mipi_dsi_dcs_set_display_brightness(dsi, bl->props.brightness);if (ret < 0)return ret;dsi->mode_flags |= MIPI_DSI_MODE_LPM;return 0;}static const struct backlight_ops dsi_bl_ops = {.update_status = dsi_dcs_bl_update_status,.get_brightness = dsi_dcs_bl_get_brightness,};static struct backlight_device *drm_panel_create_dsi_backlight(struct mipi_dsi_device *dsi){struct device *dev = &dsi->dev;struct backlight_properties props;memset(&props, 0, sizeof(props));props.type = BACKLIGHT_RAW;props.brightness = 255;props.max_brightness = 255;return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,      &dsi_bl_ops, &props);}static const struct drm_panel_funcs jdi_panel_funcs = {.disable = jdi_panel_disable,.unprepare = jdi_panel_unprepare,.prepare = jdi_panel_prepare,.enable = jdi_panel_enable,.get_modes = jdi_panel_get_modes,};static const struct of_device_id jdi_of_match[] = {{ .compatible = "jdi,lt070me05000", },{ }};MODULE_DEVICE_TABLE(of, jdi_of_match);static int jdi_panel_add(struct jdi_panel *jdi){struct device *dev = &jdi->dsi->dev;int ret;unsigned int i;jdi->mode = &default_mode;jdi->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);if (IS_ERR(jdi->enable_gpio)) {return dev_err_probe(dev, PTR_ERR(jdi->enable_gpio),     "cannot get enable-gpio %d\n", ret);}jdi->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);if (IS_ERR(jdi->reset_gpio))return dev_err_probe(dev, PTR_ERR(jdi->reset_gpio),     "cannot get reset-gpios %d\n", ret);jdi->dcdc_en_gpio = devm_gpiod_get(dev, "dcdc-en", GPIOD_OUT_LOW);if (IS_ERR(jdi->dcdc_en_gpio))return dev_err_probe(dev, PTR_ERR(jdi->dcdc_en_gpio),     "cannot get dcdc-en-gpio %d\n", ret);jdi->backlight = drm_panel_create_dsi_backlight(jdi->dsi);if (IS_ERR(jdi->backlight))return dev_err_probe(dev, PTR_ERR(jdi->backlight),     "failed to register backlight %d\n", ret);jdi->base.prepare_prev_first = true;drm_panel_init(&jdi->base, &jdi->dsi->dev, &jdi_panel_funcs,       DRM_MODE_CONNECTOR_DSI);drm_panel_add(&jdi->base);return 0;}static void jdi_panel_del(struct jdi_panel *jdi){if (jdi->base.dev)drm_panel_remove(&jdi->base);}static int jdi_panel_probe(struct mipi_dsi_device *dsi){struct jdi_panel *jdi;int ret;dsi->lanes = 2;dsi->format = MIPI_DSI_FMT_RGB888;dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_CLOCK_NON_CONTINUOUS;jdi = devm_kzalloc(&dsi->dev, sizeof(*jdi), GFP_KERNEL);if (!jdi)return -ENOMEM;mipi_dsi_set_drvdata(dsi, jdi);jdi->dsi = dsi;ret = jdi_panel_add(jdi);if (ret < 0)return ret;ret = mipi_dsi_attach(dsi);if (ret < 0) {jdi_panel_del(jdi);return ret;}return 0;}static void jdi_panel_remove(struct mipi_dsi_device *dsi){struct jdi_panel *jdi = mipi_dsi_get_drvdata(dsi);int ret;ret = mipi_dsi_detach(dsi);if (ret < 0)dev_err(&dsi->dev, "failed to detach from DSI host: %d\n",ret);jdi_panel_del(jdi);}static struct mipi_dsi_driver jdi_panel_driver = {.driver = {.name = "panel-jdi-lt070me05000",.of_match_table = jdi_of_match,},.probe = jdi_panel_probe,.remove = jdi_panel_remove,};module_mipi_dsi_driver(jdi_panel_driver);MODULE_AUTHOR("Sumit Semwal <sumit.semwal@linaro.org>");MODULE_AUTHOR("Vinay Simha BN <simhavcs@gmail.com>");MODULE_DESCRIPTION("JDI LT070ME05000 WUXGA");MODULE_LICENSE("GPL v2");
Modified vc4-kms-dsi-lt070me05000-overlay.dts code:

Code:

/* * Device Tree overlay to connect a JDI LT070ME05000 DSI panel to DSI1. * This uses 4 DSI data lanes, so can only be used with a Compute Module. * * The overlay is for V2 of Harlab's interface board that uses a PCA9536 to * handle the panel's control GPIOs instead of wiring it back to Pi GPIOs. * * Credit to Andrey Vostrukhin of Harlab for the overlay. * * Refer to https://github.com/harlab/CM4_LCD_LT070ME05000 for schematics and * other documentation. *//dts-v1/;/plugin/;/ {compatible = "brcm,bcm2711";fragment@0 {target = <&i2c_csi_dsi>;__overlay__ {#address-cells = <1>;#size-cells = <0>;status = "okay";pca: pca@41 {compatible = "nxp,pca9536";reg = <0x41>;gpio-controller;#gpio-cells = <2>;status = "okay";};};};fragment@1 {target = <&dsi0>;__overlay__{status = "okay";#address-cells = <1>;#size-cells = <0>;port {dsi_out_port:endpoint {remote-endpoint = <&panel_dsi_port>;};};lt070me05000:lt070me05000@0 {compatible    = "jdi,lt070me05000";status        = "okay";reg           = <0>;reset-gpios   = <&gpio 8 1>;   // LCD RSTenable-gpios  = <&gpio 12 0>; // Backlightdcdc-en-gpios = <&gpio 24 0>;port {panel_dsi_port: endpoint {remote-endpoint = <&dsi_out_port>;};};};};};};

Statistics: Posted by xpp — Tue May 27, 2025 9:27 am — Replies 3 — Views 87



Viewing all articles
Browse latest Browse all 6970

Trending Articles