Adding support to Himax HX8363 panel

Hi,

I am trying to add support to Himax HX8363 panel for db820c board. I am getting the backlight, but display is not up. The device tree entries for my panel is as follows:

dsi@994000 {
vdd1-supply = <&pm8994_l15>;
vdd2-supply = <&pm8994_l15>;
vdd3-supply = <&pm8994_l15>;
dsi-vcc-supply = <&pm8994_l15>;
pvss-supply = <&pm8994_l15>;
status = “okay”;
panel@0 {
reg = <0>;
status = “okay”;
compatible = “truly,tft480800-16-e-dsi”;
pinctrl-names = “default”, “sleep”;
pinctrl-0 = <&reset_active &disp_bkl_active>;
pinctrl-1 = <&reset_suspend &disp_bkl_active>;
reset-gpios = <&msmgpio 75 GPIO_ACTIVE_LOW>;
port {
panel0_in: endpoint {
remote-endpoint = <&dsi0_out>;
};
};
};
ports {
port@1 {
endpoint {
remote-endpoint = <&panel0_in>;
data-lanes = <0 1 2 3>;
};
};
};

I got the following kernel boot logs by adding debug drm.debug=0x1f in boot aruguments:

Kernel logs

This is on debian with kernel version 4.14.

Can anyone please help me on this issue? @architt

Thanks,
Sakthi

Hi,

I looked at the panel’s datasheet online. It seems to have 2 DSI data lanes. If that’s the case (and the first 2 data lanes from 820c are connected to the panel), then the data-lanes prop should be:

data-lanes = <0 1>;

Other than this, from the kernel logs, you can look into why this happened:

dsi_mgr_bridge_post_disable: Panel 0 OFF failed, -70

Thanks,
Archit

Hi,

I have kept data-lanes = <0 1>; and checked but still I didn’t get display. Since, I was running a service to disable dsi, I got “dsi_mgr_bridge_post_disable: Panel 0 OFF failed, -70” this error. After disabling this service. I am not getting this error. The kernel logs after resolving this are as follows:

Dmesg logs

Any help will be appreciated. @architt

Thanks,
Sakthi

Hi,

facing issues in Himax hx8363a panel bring up, able to see msm_dsi_host_power_on, dsi_mgr_bridge_pre_enable logs but still nothing seen on the panel.

any ideas to debug?

attached logs here,

@architt
@vinaysimha

In this 800x480 2 lane panel brought up, you can refer this.

Thanks @vinaysimha for the reply.

I will refer. what are the changes to be done for Himax hx8363a(480x800)? Is it only Initialization sequence change and drm_display_mode change?

btw, any errors in logs which I have shared?

Please share the code

@vinaysimha
@architt
attached panel driver code

struct hx8363a {
struct device *dev;
struct drm_panel panel;
struct gpio_desc *reset_gpio;
bool prepared;
bool enabled;
};

static const struct drm_display_mode default_mode = {
.clock = 26400,
.hdisplay = 480,
.hsync_start = 480 + 12,
.hsync_end = 480 + 12 + 12,
.htotal = 480 + 12 + 12 + 12,
.vdisplay = 800,
.vsync_start = 800 + 4,
.vsync_end = 800 + 4 + 4,
.vtotal = 800 + 4 + 4 + 4,
.vrefresh = 50,
.flags = 0,
.width_mm = 56,
.height_mm = 93,
};

static inline struct hx8363a *panel_to_hx8363a(struct drm_panel *panel)
{
return container_of(panel, struct hx8363a, panel);
}

static void hx8363a_dcs_write_buf(struct hx8363a *ctx, const void *data,
size_t len)
{
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
int err;

    err = mipi_dsi_dcs_write_buffer(dsi, data, len);
    if (err < 0)
            DRM_ERROR_RATELIMITED("MIPI DSI DCS write buffer failed: %d\n",
                                  err);

}
#define dcs_write_seq(ctx, seq…)
({
static const u8 d[] = { seq };

hx8363a_dcs_write_buf(ctx, d, ARRAY_SIZE(d));
})

static void hx8363a_init_sequence(struct hx8363a *ctx)
{
printk(“hx8363a: %s\n”,func);

    dcs_write_seq(ctx, SETEXTC, 0xff, 0x83, 0x63); //0xb9

    dcs_write_seq(ctx, SETPOWER, 0x81, 0x30, 0x08, 0x36, 0x01,
                                0x13, 0x10, 0x10, 0x35, 0x3D, 0x1A, 0x1A);
    //0xb1

  dcs_write_seq(ctx, SETCYC, 0x01, 0x12, 0x72, 0x12, 0x06,
                                0x03, 0x54, 0x03, 0x4E); //0xb4
    dcs_write_seq(ctx, SETVCOM, 0x56); 
    dcs_write_seq(ctx, SETPANEL, 0x02); //0xcc
    dcs_write_seq(ctx, SETGAMMA, 0x01, 0x07, 0x4c, 0xb0, 0x36,
                                0x3F, 0x06, 0x49, 0x51, 0x96, 0x18, 0xd8,
                                0x18, 0x50, 0x13, 0x01, 0x07, 0x4c, 0xb0,
                                0x36, 0x3f,0x06, 0x49, 0x51, 0x96, 0x18,
                                0xd8, 0x18, 0x50, 0x13); //0xe0
 dcs_write_seq(ctx, SETMIPI, 0x00, 0xa0, 0xc6, 0x00, 0x0a,
                                0x00, 0x10, 0x30, 0x6f, 0x02, 0x11, 0x18,
                                0x40); //0xba
  dcs_write_seq(ctx, 0x3A, 0x77); 

}

static int hx8363a_disable(struct drm_panel *panel)
{
struct hx8363a *ctx = panel_to_hx8363a(panel);
printk(“hx8363a: %s\n”,func);

    if (!ctx->enabled)
            return 0;

    ctx->enabled = false;

    return 0;

}
static int hx8363a_unprepare(struct drm_panel *panel)
{
struct hx8363a *ctx = panel_to_hx8363a(panel);
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
int ret;
printk(“hx8363a: %s\n”,func);

    if (!ctx->prepared)
            return 0;

    ret = mipi_dsi_dcs_set_display_off(dsi);
    if (ret)
            DRM_WARN("failed to set display off: %d\n", ret);

    ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
    if (ret)
            DRM_WARN("failed to enter sleep mode: %d\n", ret);

    msleep(120);

    if (ctx->reset_gpio) {
            gpiod_set_value_cansleep(ctx->reset_gpio, 1);
            msleep(20);
    }

    ctx->prepared = false;

    return 0;

}
static int hx8363a_prepare(struct drm_panel *panel)
{
struct hx8363a *ctx = panel_to_hx8363a(panel);
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
int ret;
printk(“hx8363a: %s\n”,func);

    if (ctx->prepared)
            return 0;

    if (ctx->reset_gpio) {
            gpiod_set_value_cansleep(ctx->reset_gpio, 1);
            msleep(20);
            gpiod_set_value_cansleep(ctx->reset_gpio, 0);
            msleep(100);
    }

    ret = mipi_dsi_set_maximum_return_packet_size(dsi, 4);
    if (ret < 0)
            printk("error %d setting maximum return packet\n",
                    ret);

    hx8363a_init_sequence(ctx);

    ret = mipi_dsi_dcs_set_column_address(dsi, 0, 479);

    if (ret < 0)
    printk("%s failed: %d\n", __func__, ret);

    ret = mipi_dsi_dcs_set_page_address(dsi, 0, 799);
    if (ret < 0)
            printk("%s failed: %d\n", __func__, ret);

    dcs_write_seq(ctx, WRCABC, 0x03);
    dcs_write_seq(ctx, WRCTRLD, 0xff);


    ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
    if (ret)
            return ret;

    msleep(125);

    ret = mipi_dsi_dcs_set_display_on(dsi);

if (ret)
return ret;

    msleep(20);

    ctx->prepared = true;

    return 0;

}
static int hx8363a_enable(struct drm_panel *panel)
{
struct hx8363a *ctx = panel_to_hx8363a(panel);
printk(“hx8363a: %s\n”,func);

    if (ctx->enabled)
            return 0;

    ctx->enabled = true;

    return 0;

}

static int hx8363a_get_modes(struct drm_panel *panel)
{
struct drm_display_mode *mode;
printk(“hx8363a: %s\n”,func);

    mode = drm_mode_duplicate(panel->drm, &default_mode);
    if (!mode) {
            DRM_ERROR("failed to add mode %ux%ux@%u\n",
                      default_mode.hdisplay, default_mode.vdisplay,
                      default_mode.vrefresh);
            return -ENOMEM;
    }

    drm_mode_set_name(mode);

    mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
    drm_mode_probed_add(panel->connector, mode);

    panel->connector->display_info.width_mm = mode->width_mm;
    panel->connector->display_info.height_mm = mode->height_mm;

    return 1;

}
static const struct drm_panel_funcs hx8363a_drm_funcs = {
.disable = hx8363a_disable,
.unprepare = hx8363a_unprepare,
.prepare = hx8363a_prepare,
.enable = hx8363a_enable,
.get_modes = hx8363a_get_modes,
};
static int hx8363a_probe(struct mipi_dsi_device *dsi)
{
struct device *dev = &dsi->dev;
struct hx8363a *ctx;
int ret;
printk(“hx8363a: %s\n”,func);

    ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
    if (!ctx)
            return -ENOMEM;

    ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
    if (IS_ERR(ctx->reset_gpio)) {
            ret = PTR_ERR(ctx->reset_gpio);
            dev_err(dev, "cannot get reset GPIO: %d\n", ret);
            return ret;
    }

    mipi_dsi_set_drvdata(dsi, ctx);

    ctx->dev = dev;

    dsi->lanes = 2;
    dsi->format = MIPI_DSI_FMT_RGB888;
    dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
                      MIPI_DSI_MODE_LPM;

    drm_panel_init(&ctx->panel);
    ctx->panel.dev = dev;
    ctx->panel.funcs = &hx8363a_drm_funcs;

    drm_panel_add(&ctx->panel);

    ret = mipi_dsi_attach(dsi);
    if (ret < 0) {
            dev_err(dev, "mipi_dsi_attach() failed: %d\n", ret);
            drm_panel_remove(&ctx->panel);
            return ret;
    }

    return 0;

}
static int hx8363a_remove(struct mipi_dsi_device *dsi)
{
struct hx8363a *ctx = mipi_dsi_get_drvdata(dsi);
printk(“hx8363a: %s\n”,func);

    mipi_dsi_detach(dsi);
    drm_panel_remove(&ctx->panel);

    return 0;

}

static const struct of_device_id himax_hx8363a_of_match[] = {
{ .compatible = “himax,hx8363a” },
{ }
};
MODULE_DEVICE_TABLE(of, himax_hx8363a_of_match);

static struct mipi_dsi_driver himax_hx8363a_driver = {
.probe = hx8363a_probe,
.remove = hx8363a_remove,
.driver = {
.name = “panel-himax-hx8363a”,
.of_match_table = himax_hx8363a_of_match,
},
};
module_mipi_dsi_driver(himax_hx8363a_driver);

please let me know if anything wrong in the code

i guess you might need to use mipi_dsi_generic_write instead of mipi_dsi_dcs_write_buffer, please refer other panel drivers.

dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
MIPI_DSI_MODE_LPM;
try removing the VIDEO_BURST.

share the driver code in the github. difficult to see the code here in txt format
we need to see how you had configured the device tree.

does the reset_gpio should be high or low in panel_prepare?

regards,
vinaysimha

@vinaysimha

tried using mipi_dsi_generic_write and removing VIDEO_BURST but still nothing was seen on panel.
reset_gpio should be low in pannel_prepare
added code to github
https://github.com/dasariarun/hx8363a/blob/master/panel-himax-hx8363a.c
https://github.com/dasariarun/hx8363a/blob/master/panel.dts

dcs_write_seq(ctx, SETEXTC, 0xff, 0x83, 0x63); //0xb9

    dcs_write_seq(ctx, SETPOWER, 0x81, 0x40, 0x07, 0x36, 0x01,
                                0x13, 0x10, 0x10, 0x39, 0x41, 0x3F, 0x3F);
    //0xb1

    dcs_write_seq(ctx, 0x3A, 0x70);

    dcs_write_seq(ctx, 0xB3, 0x01);

    dcs_write_seq(ctx, SETCYC, 0x00, 0x12, 0x72, 0x12, 0x06,
                                0x03, 0x54, 0x03, 0x4E,0x00,0x00); //0xb4

    dcs_write_seq(ctx, 0xB6, 0x34);

    dcs_write_seq(ctx, SETPANEL, 0x09); //0xcc


    dcs_write_seq(ctx, SETGAMMA, 0x01, 0x0A, 0x10, 0x06, 0x09,

in these dsc write , some might be mipi_dsi_dcs_write (ex: 0xB6, 0x3A…
, more than one commands require mipi_dsi_generic_write

please recheck.
is the datasheet is opensource for this panel? in that they would had mentioned which is dsc and generic.

@vinaysimha
Thank you. I will check.
Hx8363a data sheet available, https://www.displayfuture.com/Display/datasheet/controller/HX8363.pdf

datasheet sharead by you is driver ic, there should be panel datasheet, which shows the pinouts and dsi on and off commands.

@vinaysimha

I got this from panel vendor, based on this i have added dcs commands
https://github.com/dasariarun/hx8363a/blob/master/init_sequence

@architt
@vinaysimha

Any idea how to debug?
Please let me know if you know any pointers to debug.
able to see the backlight but nothing comes on the panel. Attached logs here, https://github.com/dasariarun/hx8363a/blob/master/logs

i suspect you should use mipi_dsi_generic_write instead of dcs_write.

refer this

create arrays like this and try for all the commands
static char write_memory51[2]={0x00,0x00};
static char write_memory52[17]={0xE1,0x05,0x0B,0x0F,0x0F,0x08,0x0D,0x0C,0x0B,0x02,0x06,0x16,0x12,0x18,0x24,0x17,0x00};
//V255 V251 V247 V239 V231 V203 V175 V147 V108 V80 V52 V24 V16 V8 V4 V0

static char write_memory53[2]={0x00,0x00};
static char write_memory54[17]={0xE2,0x05,0x0B,0x0F,0x0F,0x08,0x0D,0x0C,0x0B,0x02,0x06,0x16,0x12,0x18,0x24,0x17,0x00};

if still after changing above does not works, try this

ref

dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
MIPI_DSI_CLOCK_NON_CONTINUOUS;

@Sakthi

Did the panel worked?

Yes, panel is working fine now after changing the write function to mipi_dsi_generic_write. @vinaysimha

1 Like