I'm working on IMX93 board with mipi screen named "startek,kd050fwfia019" driven by "ili9806e" for a while, and still stucked.
There is no display output while encountering the following message from booting up.
[ 2.089408] imx-drm display-subsystem: bound imx-lcdifv3-crtc.0 (ops lcdifv3_crtc_ops)
[ 2.097386] [drm:drm_bridge_attach] *ERROR* failed to attach bridge /soc@0/dsi@4ae10000 to encoder DSI-34: -517
[ 2.107483] dw-mipi-dsi-imx 4ae10000.dsi: [drm:dw_mipi_dsi_imx_bind] *ERROR* failed to attach bridge: -517
[ 2.117351] dw-mipi-dsi-imx 4ae10000.dsi: [drm:dw_mipi_dsi_imx_probe] *ERROR* failed to register component: -517
I have tried two cases of kernel divice tree, both end up with the same error mentioned above.
test case 1 :
&dsi {
status = "okay";
panel@0 {
compatible = "startek,kd050fwfia019";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_panel0_gpios>;
vdd-supply = <®_vdd_3v3>;
vccio-supply = <®_vddio_1v8>;
reset-gpios = <&gpio2 16 GPIO_ACTIVE_LOW>;
backlight = <&dsi_backlight>;
rotation = <90>;
status = "okay";
port {
panel_in: endpoint {
remote-endpoint = <&dsi_out>;
};
};
};
ports{
#address-cells = <1>;
#size-cells = <0>;
port@1 {
reg = <1>;
dsi_out: endpoint {
remote-endpoint = <&panel_in>;
};
};
};
};
test case 2:
/ {
dsi_panel {
compatible = "startek,kd050fwfia019";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_panel0_gpios>;
vdd-supply = <®_vdd_3v3>;
vccio-supply = <®_vddio_1v8>;
reset-gpios = <&gpio2 16 GPIO_ACTIVE_LOW>;
backlight = <&dsi_backlight>;
rotation = <90>;
status = "okay";
port {
panel_in: endpoint {
remote-endpoint = <&dsi_out>;
};
};
};
};
&dsi {
status = "okay";
ports{
#address-cells = <1>;
#size-cells = <0>;
port@1 {
reg = <1>;
dsi_out: endpoint {
remote-endpoint = <&panel_in>;
};
};
};
};
panel-ilitek-ili9806e.c :
// SPDX-License-Identifier: GPL-2.0
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
#include <drm/drm_probe_helper.h>
#include <video/mipi_display.h>
struct ili9806e_panel;
struct panel_desc {
const struct drm_display_mode *display_mode;
unsigned long mode_flags;
enum mipi_dsi_pixel_format format;
unsigned int lanes;
int (*init_sequence)(struct ili9806e_panel *ctx);
};
struct ili9806e_panel {
struct drm_panel panel;
struct mipi_dsi_device *dsi;
struct gpio_desc *reset_gpio;
struct regulator_bulk_data supplies[2];
const struct panel_desc *desc;
enum drm_panel_orientation orientation;
};
static const char * const regulator_names[] = {
"vdd",
"vccio",
};
static inline struct ili9806e_panel *to_ili9806e_panel(struct drm_panel *panel)
{
return container_of(panel, struct ili9806e_panel, panel);
}
static int ili9806e_power_on(struct ili9806e_panel *ctx)
{
struct mipi_dsi_device *dsi = ctx->dsi;
int ret;
gpiod_set_value(ctx->reset_gpio, 1);
ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
if (ret < 0) {
dev_err(&dsi->dev, "regulator bulk enable failed: %d\n", ret);
return ret;
}
usleep_range(10000, 20000);
gpiod_set_value(ctx->reset_gpio, 0);
usleep_range(10000, 20000);
return 0;
}
static int ili9806e_power_off(struct ili9806e_panel *ctx)
{
struct mipi_dsi_device *dsi = ctx->dsi;
int ret;
gpiod_set_value(ctx->reset_gpio, 1);
ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
if (ret)
dev_err(&dsi->dev, "regulator bulk disable failed: %d\n", ret);
return ret;
}
static int ili9806e_on(struct ili9806e_panel *ctx)
{
int ret = 0;
if (ctx->desc->init_sequence) {
ret = ctx->desc->init_sequence(ctx);
}
if (ret != 0) {
return ret;
}
return mipi_dsi_dcs_exit_sleep_mode(ctx->dsi);
}
static int ili9806e_enable(struct drm_panel *panel)
{
struct ili9806e_panel *ctx = to_ili9806e_panel(panel);
usleep_range(100000, 120000);
return mipi_dsi_dcs_set_display_on(ctx->dsi);
}
static int ili9806e_off(struct ili9806e_panel *ctx)
{
return mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);
}
static int ili9806e_disable(struct drm_panel *panel)
{
struct ili9806e_panel *ctx = to_ili9806e_panel(panel);
return mipi_dsi_dcs_set_display_off(ctx->dsi);
}
static int ili9806e_prepare(struct drm_panel *panel)
{
struct ili9806e_panel *ctx = to_ili9806e_panel(panel);
int ret;
ret = ili9806e_power_on(ctx);
if (ret < 0)
return ret;
ret = ili9806e_on(ctx);
if (ret < 0) {
ili9806e_power_off(ctx);
return ret;
}
return 0;
}
static int ili9806e_unprepare(struct drm_panel *panel)
{
struct ili9806e_panel *ctx = to_ili9806e_panel(panel);
struct mipi_dsi_device *dsi = ctx->dsi;
int ret;
ili9806e_off(ctx);
ret = ili9806e_power_off(ctx);
if (ret < 0)
dev_err(&dsi->dev, "power off failed: %d\n", ret);
return ret;
}
static int ili9806e_get_modes(struct drm_panel *panel,
struct drm_connector *connector)
{
struct ili9806e_panel *ctx = to_ili9806e_panel(panel);
const struct drm_display_mode *mode = ctx->desc->display_mode;
return drm_connector_helper_get_modes_fixed(connector, mode);
}
static enum drm_panel_orientation ili9806e_get_orientation(struct drm_panel *panel)
{
struct ili9806e_panel *ctx = to_ili9806e_panel(panel);
return ctx->orientation;
}
static const struct drm_panel_funcs ili9806e_funcs = {
.prepare = ili9806e_prepare,
.unprepare = ili9806e_unprepare,
.enable = ili9806e_enable,
.disable = ili9806e_disable,
.get_modes = ili9806e_get_modes,
.get_orientation = ili9806e_get_orientation,
};
static int ili9806e_dsi_probe(struct mipi_dsi_device *dsi)
{
struct device *dev = &dsi->dev;
struct ili9806e_panel *ctx;
int i, ret;
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
ctx->desc = device_get_match_data(dev);
for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++)
ctx->supplies[i].supply = regulator_names[i];
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
ctx->supplies);
if (ret < 0)
return ret;
ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(ctx->reset_gpio))
return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
"Failed to get reset-gpios\n");
mipi_dsi_set_drvdata(dsi, ctx);
ctx->dsi = dsi;
dsi->mode_flags = ctx->desc->mode_flags;
dsi->format = ctx->desc->format;
dsi->lanes = ctx->desc->lanes;
drm_panel_init(&ctx->panel, dev, &ili9806e_funcs,
DRM_MODE_CONNECTOR_DSI);
ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation);
if (ret)
return dev_err_probe(dev, ret, "Failed to get orientation\n");
ret = drm_panel_of_backlight(&ctx->panel);
if (ret)
return dev_err_probe(dev, ret, "Failed to get backlight\n");
drm_panel_add(&ctx->panel);
ret = mipi_dsi_attach(dsi);
if (ret < 0) {
dev_err_probe(dev, ret, "Failed to attach to DSI host\n");
drm_panel_remove(&ctx->panel);
return ret;
}
return 0;
}
static void ili9806e_dsi_remove(struct mipi_dsi_device *dsi)
{
struct ili9806e_panel *ctx = mipi_dsi_get_drvdata(dsi);
mipi_dsi_detach(dsi);
drm_panel_remove(&ctx->panel);
}
static int ili9806e_switch_page(struct ili9806e_panel *ctx, u8 page)
{
u8 buf[7] = { 0xff, 0xff, 0x98, 0x81, 0x06, 0x04, page };
int ret;
ret = mipi_dsi_dcs_write_buffer(ctx->dsi, buf, sizeof(buf));
if (ret < 0)
return ret;
return 0;
}
static int ili9806e_send_cmd_data(struct ili9806e_panel *ctx, u8 cmd, u8 data)
{
u8 buf[2] = { cmd, data };
int ret;
ret = mipi_dsi_dcs_write_buffer(ctx->dsi, buf, sizeof(buf));
if (ret < 0)
return ret;
return 0;
}
static int ili9806e_send_cmd(struct ili9806e_panel *ctx, u8 cmd)
{
u8 buf[1] = { cmd };
int ret;
ret = mipi_dsi_dcs_write_buffer(ctx->dsi, buf, sizeof(buf));
if (ret < 0)
return ret;
return 0;
}
static int kd050fwfia019_init(struct ili9806e_panel *ctx)
{
// Change to Page 1
ili9806e_switch_page(ctx, 0x01);
//Output SDA
ili9806e_send_cmd_data(ctx, 0x08, 0x10);
//set DE/VSYNC mode
ili9806e_send_cmd_data(ctx, 0x20, 0x00);
//DE = 1 Active
ili9806e_send_cmd_data(ctx, 0x21, 0x01);
//Resolution setting 480 X 854
ili9806e_send_cmd_data(ctx, 0x30, 0x01);
//Inversion setting 2-dot
ili9806e_send_cmd_data(ctx, 0x31, 0x00);
//BT AVDD,AVDD
ili9806e_send_cmd_data(ctx, 0x40, 0x16);
//22
ili9806e_send_cmd_data(ctx, 0x41, 0x33);
//VGL=DDVDH+VCIP -DDVDL,VGH=2DDVDL-VCIP
ili9806e_send_cmd_data(ctx, 0x42, 0x03);
//SET VGH clamp level
ili9806e_send_cmd_data(ctx, 0x43, 0x09);
//SET VGL clamp level
ili9806e_send_cmd_data(ctx, 0x44, 0x06);
//VREG1
ili9806e_send_cmd_data(ctx, 0x50, 0x88);
//VREG2
ili9806e_send_cmd_data(ctx, 0x51, 0x88);
//Flicker MSB
ili9806e_send_cmd_data(ctx, 0x52, 0x00);
//Flicker LSB
ili9806e_send_cmd_data(ctx, 0x53, 0x49);
//Flicker
ili9806e_send_cmd_data(ctx, 0x55, 0x49);
ili9806e_send_cmd_data(ctx, 0x60, 0x07);
ili9806e_send_cmd_data(ctx, 0x61, 0x00);
ili9806e_send_cmd_data(ctx, 0x62, 0x07);
ili9806e_send_cmd_data(ctx, 0x63, 0x00);
//++++++++++++++++++ Gamma Setting ++++++++++++++++++//
//Positive Gamma
ili9806e_send_cmd_data(ctx, 0xA0, 0x00);
ili9806e_send_cmd_data(ctx, 0xA1, 0x09);
ili9806e_send_cmd_data(ctx, 0xA2, 0x11);
ili9806e_send_cmd_data(ctx, 0xA3, 0x0B);
ili9806e_send_cmd_data(ctx, 0xA4, 0x05);
ili9806e_send_cmd_data(ctx, 0xA5, 0x08);
ili9806e_send_cmd_data(ctx, 0xA6, 0x06);
ili9806e_send_cmd_data(ctx, 0xA7, 0x04);
ili9806e_send_cmd_data(ctx, 0xA8, 0x09);
ili9806e_send_cmd_data(ctx, 0xA9, 0x0C);
ili9806e_send_cmd_data(ctx, 0xAA, 0x15);
ili9806e_send_cmd_data(ctx, 0xAB, 0x08);
ili9806e_send_cmd_data(ctx, 0xAC, 0x0F);
ili9806e_send_cmd_data(ctx, 0xAD, 0x12);
ili9806e_send_cmd_data(ctx, 0xAE, 0x09);
ili9806e_send_cmd_data(ctx, 0xAF, 0x00);
//Negative Gamma
ili9806e_send_cmd_data(ctx, 0xC0, 0x00);
ili9806e_send_cmd_data(ctx, 0xC1, 0x09);
ili9806e_send_cmd_data(ctx, 0xC2, 0x10);
ili9806e_send_cmd_data(ctx, 0xC3, 0x0C);
ili9806e_send_cmd_data(ctx, 0xC4, 0x05);
ili9806e_send_cmd_data(ctx, 0xC5, 0x08);
ili9806e_send_cmd_data(ctx, 0xC6, 0x06);
ili9806e_send_cmd_data(ctx, 0xC7, 0x04);
ili9806e_send_cmd_data(ctx, 0xC8, 0x08);
ili9806e_send_cmd_data(ctx, 0xC9, 0x0C);
ili9806e_send_cmd_data(ctx, 0xCA, 0x14);
ili9806e_send_cmd_data(ctx, 0xCB, 0x08);
ili9806e_send_cmd_data(ctx, 0xCC, 0x0F);
ili9806e_send_cmd_data(ctx, 0xCD, 0x11);
ili9806e_send_cmd_data(ctx, 0xCE, 0x09);
ili9806e_send_cmd_data(ctx, 0xCF, 0x00);
// Change to Page 6 CMD for GIP timing
ili9806e_switch_page(ctx, 0x06);
ili9806e_send_cmd_data(ctx, 0x00, 0x20);
ili9806e_send_cmd_data(ctx, 0x01, 0x0A);
ili9806e_send_cmd_data(ctx, 0x02, 0x00);
ili9806e_send_cmd_data(ctx, 0x03, 0x00);
ili9806e_send_cmd_data(ctx, 0x04, 0x01);
ili9806e_send_cmd_data(ctx, 0x05, 0x01);
ili9806e_send_cmd_data(ctx, 0x06, 0x98);
ili9806e_send_cmd_data(ctx, 0x07, 0x06);
ili9806e_send_cmd_data(ctx, 0x08, 0x01);
ili9806e_send_cmd_data(ctx, 0x09, 0x80);
ili9806e_send_cmd_data(ctx, 0x0A, 0x00);
ili9806e_send_cmd_data(ctx, 0x0B, 0x00);
ili9806e_send_cmd_data(ctx, 0x0C, 0x01);
ili9806e_send_cmd_data(ctx, 0x0D, 0x01);
ili9806e_send_cmd_data(ctx, 0x0E, 0x05);
ili9806e_send_cmd_data(ctx, 0x0F, 0x00);
ili9806e_send_cmd_data(ctx, 0x10, 0xF0);
ili9806e_send_cmd_data(ctx, 0x11, 0xF4);
ili9806e_send_cmd_data(ctx, 0x12, 0x01);
ili9806e_send_cmd_data(ctx, 0x13, 0x00);
ili9806e_send_cmd_data(ctx, 0x14, 0x00);
ili9806e_send_cmd_data(ctx, 0x15, 0xC0);
ili9806e_send_cmd_data(ctx, 0x16, 0x08);
ili9806e_send_cmd_data(ctx, 0x17, 0x00);
ili9806e_send_cmd_data(ctx, 0x18, 0x00);
ili9806e_send_cmd_data(ctx, 0x19, 0x00);
ili9806e_send_cmd_data(ctx, 0x1A, 0x00);
ili9806e_send_cmd_data(ctx, 0x1B, 0x00);
ili9806e_send_cmd_data(ctx, 0x1C, 0x00);
ili9806e_send_cmd_data(ctx, 0x1D, 0x00);
ili9806e_send_cmd_data(ctx, 0x20, 0x01);
ili9806e_send_cmd_data(ctx, 0x21, 0x23);
ili9806e_send_cmd_data(ctx, 0x22, 0x45);
ili9806e_send_cmd_data(ctx, 0x23, 0x67);
ili9806e_send_cmd_data(ctx, 0x24, 0x01);
ili9806e_send_cmd_data(ctx, 0x25, 0x23);
ili9806e_send_cmd_data(ctx, 0x26, 0x45);
ili9806e_send_cmd_data(ctx, 0x27, 0x67);
ili9806e_send_cmd_data(ctx, 0x30, 0x11);
ili9806e_send_cmd_data(ctx, 0x31, 0x11);
ili9806e_send_cmd_data(ctx, 0x32, 0x00);
ili9806e_send_cmd_data(ctx, 0x33, 0xEE);
ili9806e_send_cmd_data(ctx, 0x34, 0xFF);
ili9806e_send_cmd_data(ctx, 0x35, 0xBB);
ili9806e_send_cmd_data(ctx, 0x36, 0xAA);
ili9806e_send_cmd_data(ctx, 0x37, 0xDD);
ili9806e_send_cmd_data(ctx, 0x38, 0xCC);
ili9806e_send_cmd_data(ctx, 0x39, 0x66);
ili9806e_send_cmd_data(ctx, 0x3A, 0x77);
ili9806e_send_cmd_data(ctx, 0x3B, 0x22);
ili9806e_send_cmd_data(ctx, 0x3C, 0x22);
ili9806e_send_cmd_data(ctx, 0x3D, 0x22);
ili9806e_send_cmd_data(ctx, 0x3E, 0x22);
ili9806e_send_cmd_data(ctx, 0x3F, 0x22);
ili9806e_send_cmd_data(ctx, 0x40, 0x22);
// Change to Page 7 CMD for GIP timing
ili9806e_switch_page(ctx, 0x07);
ili9806e_send_cmd_data(ctx, 0x17, 0x22);
ili9806e_send_cmd_data(ctx, 0x02, 0x77);
ili9806e_send_cmd_data(ctx, 0x26, 0xB2);
// Change to Page 0 CMD for Normal command
ili9806e_switch_page(ctx, 0x00);
//TE ON
ili9806e_send_cmd(ctx, 0x35);
//24BIT
ili9806e_send_cmd_data(ctx, 0x3A, 0x70);
// exit sleep
ili9806e_send_cmd(ctx, 0x11);
usleep_range(120, 140);
ili9806e_send_cmd(ctx, 0x29);
usleep_range(25, 30);
// enter sleep
// ili9806e_send_cmd(ctx, 0x28);
// usleep_range(10, 20);
// ili9806e_send_cmd(ctx, 0x10);
// usleep_range(25, 30);
return 0;
}
static const struct drm_display_mode kd050fwfia019_default_mode = {
.clock = 29000, /* 29000kHz, fps: 60hZ */
.hdisplay = 480,
.hsync_start = 480 + 30, /* h + hbp */
.hsync_end = 480 + 30 + 4, /* h + hbp + hspw */
.htotal = 480 + 30 + 4 + 18, /* h + hbp + hspw + hfp = 532 */
.vdisplay = 854,
.vsync_start = 854 + 30, /* h + hbp */
.vsync_end = 854 + 30 + 4, /* h + hbp + vspw */
.vtotal = 854 + 30 + 4 + 20, /* h + hbp + vspw + vfp = 908 */
.width_mm = 62,
.height_mm = 110,
.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
};
static const struct panel_desc kd050fwfia019_desc = {
.init_sequence = kd050fwfia019_init,
.display_mode = &kd050fwfia019_default_mode,
.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
MIPI_DSI_MODE_LPM,
.format = MIPI_DSI_FMT_RGB888,
.lanes = 2,
};
static const struct of_device_id ili9806e_of_match[] = {
{ .compatible = "startek,kd050fwfia019", .data = &kd050fwfia019_desc },
{ }
};
MODULE_DEVICE_TABLE(of, ili9806e_of_match);
static struct mipi_dsi_driver ili9806e_dsi_driver = {
.driver = {
.name = "ili9806e-dsi",
.of_match_table = ili9806e_of_match,
},
.probe = ili9806e_dsi_probe,
.remove = ili9806e_dsi_remove,
};
module_mipi_dsi_driver(ili9806e_dsi_driver);
MODULE_AUTHOR("Author <author@example.com>");
MODULE_DESCRIPTION("Ilitek ILI9806E Controller Driver");
MODULE_LICENSE("GPL");
Hope someone can help me figure it out. Thanks