Add driver to support panel innolux,p097pfg with bridge ssd2858. SSD2858 can spilt dsi 4 lanes to 8 lanes.
Jitao Shi (3): drm/panel: panel-innolux: Allow 2 reset pins for panel dt-bindings: display: Add documentation for innolux,p097pfg_ssd2858 panel drm/panel: panel-innolux: Add support for P097PFZ behind SSD2858
.../display/panel/innolux,p097pfg_ssd2858.txt | 39 +++++ drivers/gpu/drm/panel/panel-innolux-p079zca.c | 140 ++++++++++++++++-- 2 files changed, 164 insertions(+), 15 deletions(-) create mode 100644 Documentation/devicetree/bindings/display/panel/innolux,p097pfg_ssd2858.txt
This is useful when there is a bridge between the SoC and the panel.
Signed-off-by: Jitao Shi jitao.shi@mediatek.com --- drivers/gpu/drm/panel/panel-innolux-p079zca.c | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c index d92d1c98878c..8db404fb5eeb 100644 --- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c +++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c @@ -54,7 +54,7 @@ struct innolux_panel {
struct backlight_device *backlight; struct regulator_bulk_data *supplies; - struct gpio_desc *enable_gpio; + struct gpio_desc *enable_gpio[2];
bool prepared; bool enabled; @@ -82,7 +82,7 @@ static int innolux_panel_disable(struct drm_panel *panel) static int innolux_panel_unprepare(struct drm_panel *panel) { struct innolux_panel *innolux = to_innolux_panel(panel); - int err; + int err, i;
if (!innolux->prepared) return 0; @@ -102,7 +102,8 @@ static int innolux_panel_unprepare(struct drm_panel *panel) if (innolux->desc->sleep_mode_delay) msleep(innolux->desc->sleep_mode_delay);
- gpiod_set_value_cansleep(innolux->enable_gpio, 0); + for (i = 0; i < ARRAY_SIZE(innolux->enable_gpio); i++) + gpiod_set_value_cansleep(innolux->enable_gpio[i], 0);
if (innolux->desc->power_down_delay) msleep(innolux->desc->power_down_delay); @@ -120,22 +121,27 @@ static int innolux_panel_unprepare(struct drm_panel *panel) static int innolux_panel_prepare(struct drm_panel *panel) { struct innolux_panel *innolux = to_innolux_panel(panel); - int err; + int err, i;
if (innolux->prepared) return 0;
- gpiod_set_value_cansleep(innolux->enable_gpio, 0); + for (i = 0; i < ARRAY_SIZE(innolux->enable_gpio); i++) + gpiod_set_value_cansleep(innolux->enable_gpio[i], 0);
err = regulator_bulk_enable(innolux->desc->num_supplies, innolux->supplies); if (err < 0) return err;
- /* p079zca: t2 (20ms), p097pfg: t4 (15ms) */ - usleep_range(20000, 21000); + for (i = 0; i < ARRAY_SIZE(innolux->enable_gpio); i++) { + if (!innolux->enable_gpio[i]) + break;
- gpiod_set_value_cansleep(innolux->enable_gpio, 1); + /* p079zca: t2 (20ms), p097pfg: t4 (15ms) */ + usleep_range(20000, 21000); + gpiod_set_value_cansleep(innolux->enable_gpio[i], 1); + }
/* p079zca: t4, p097pfg: t5 */ usleep_range(20000, 21000); @@ -195,7 +201,8 @@ static int innolux_panel_prepare(struct drm_panel *panel) return 0;
poweroff: - gpiod_set_value_cansleep(innolux->enable_gpio, 0); + for (i = 0; i < ARRAY_SIZE(innolux->enable_gpio); i++) + gpiod_set_value_cansleep(innolux->enable_gpio[i], 0); regulator_bulk_disable(innolux->desc->num_supplies, innolux->supplies);
return err; @@ -475,12 +482,14 @@ static int innolux_panel_add(struct mipi_dsi_device *dsi, if (err < 0) return err;
- innolux->enable_gpio = devm_gpiod_get_optional(dev, "enable", - GPIOD_OUT_HIGH); - if (IS_ERR(innolux->enable_gpio)) { - err = PTR_ERR(innolux->enable_gpio); - dev_dbg(dev, "failed to get enable gpio: %d\n", err); - innolux->enable_gpio = NULL; + for (i = 0; i < ARRAY_SIZE(innolux->enable_gpio); i++) { + innolux->enable_gpio[i] = devm_gpiod_get_index_optional(dev, + "enable", i, GPIOD_OUT_HIGH); + if (IS_ERR(innolux->enable_gpio[i])) { + err = PTR_ERR(innolux->enable_gpio[i]); + dev_err(dev, "failed to get enable gpio: %d\n", err); + innolux->enable_gpio[i] = NULL; + } }
innolux->backlight = devm_of_find_backlight(dev);
This adds documentation for innolux,p097pfg panel with bridge chip ssd2858.
Signed-off-by: Jitao Shi jitao.shi@mediatek.com --- .../display/panel/innolux,p097pfg_ssd2858.txt | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/innolux,p097pfg_ssd2858.txt
diff --git a/Documentation/devicetree/bindings/display/panel/innolux,p097pfg_ssd2858.txt b/Documentation/devicetree/bindings/display/panel/innolux,p097pfg_ssd2858.txt new file mode 100644 index 000000000000..4ce55e889ad2 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/innolux,p097pfg_ssd2858.txt @@ -0,0 +1,39 @@ +SSD2858 bridge + Innolux P097PFG 9.7" 1536x2048 TFT LCD panel + +Required properties: +- compatible: should be "innolux,p097pfg_ssd2858" +- reg: DSI virtual channel of the peripheral +- avdd-supply: phandle of the regulator that provides panel positive voltage +- avee-supply: phandle of the regulator that provides panel negative voltage +- pp1800-supply: phandle of the regulator that provides panel 1.8V IO power +- pp3300-supply: phandle of the regulator that provides ssd2858 3.3V URAM power +- pp1200-bridge-supply: phandle of the regulator that provides ssd2858 1.2V core power +- vddio-bridge-supply: phandle of the regulator that provides ssd2858 1.8V IO power +- enable-gpios: panel enable gpio + +Optional properties: +- backlight: phandle of the backlight device attached to the panel + +Example: + + &dsi0 { + panel: panel@0 { + compatible = "innolux,p097pfg_ssd2858"; + reg = <0>; + enable-gpios = <&pio 45 0 &pio 73 0>; + avdd-supply = <...>; + avee-supply = <...>; + pp1800-supply = <...>; + pp3300-supply = <...>; + pp1200-bridge-supply = <...>; + vddio-bridge-supply = <...>; + backlight = <&backlight_lcd0>; + status = "okay"; + port { + panel_in: endpoint { + remote-endpoint = <&dsi_out>; + }; + }; + }; + + };
Add driver to setup P097PFZ behing SSD2858 (4 to 8 lanes bridge).
Signed-off-by: Jitao Shi jitao.shi@mediatek.com --- drivers/gpu/drm/panel/panel-innolux-p079zca.c | 103 +++++++++++++++++- 1 file changed, 102 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/panel/panel-innolux-p079zca.c b/drivers/gpu/drm/panel/panel-innolux-p079zca.c index 8db404fb5eeb..a658ccba30a0 100644 --- a/drivers/gpu/drm/panel/panel-innolux-p079zca.c +++ b/drivers/gpu/drm/panel/panel-innolux-p079zca.c @@ -138,7 +138,7 @@ static int innolux_panel_prepare(struct drm_panel *panel) if (!innolux->enable_gpio[i]) break;
- /* p079zca: t2 (20ms), p097pfg: t4 (15ms) */ + /* p079zca: t2 (20ms), p097pfg: t4 (15ms); ssd2858: 20ms */ usleep_range(20000, 21000); gpiod_set_value_cansleep(innolux->enable_gpio[i], 1); } @@ -162,6 +162,18 @@ static int innolux_panel_prepare(struct drm_panel *panel) goto poweroff; }
+ /* + * If the command list contains exit sleep mode or set + * display on, wait the appropriate time (needed for + * displays behind a bridge). + */ + /* T6: 120ms - 1000ms*/ + if (cmd->data[0] == MIPI_DCS_EXIT_SLEEP_MODE) + msleep(120); + /* T7: 5ms */ + if (cmd->data[0] == MIPI_DCS_SET_DISPLAY_ON) + usleep_range(5000, 6000); + /* * Included by random guessing, because without this * (or at least, some delay), the panel sometimes @@ -410,6 +422,92 @@ static const struct panel_desc innolux_p097pfg_panel_desc = { .sleep_mode_delay = 100, /* T15 */ };
+static const char * const innolux_p097pfg_ssd2858_supply_names[] = { + "avdd", + "avee", + "pp1800", + "pp3300", + "pp1200-bridge", + "vddio-bridge", +}; + +static const struct drm_display_mode innolux_p097pfg_ssd2858_mode = { + .clock = 211660, + .hdisplay = 1536, + .hsync_start = 1536 + 140, + .hsync_end = 1536 + 140 + 10, + .htotal = 1536 + 140 + 10 + 10, + .vdisplay = 2048, + .vsync_start = 2048 + 20, + .vsync_end = 2048 + 20 + 2, + .vtotal = 2048 + 20 + 2 + 10, + .vrefresh = 60, +}; + +static const struct panel_init_cmd innolux_p097pfg_ssd2858_init_cmds[] = { + /* SSD2858 config */ + _INIT_CMD(0xff, 0x00), + /* LOCKCNT=0x1f4, MRX=0, POSTDIV=1 (/2), MULT=0x49 + * 27 Mhz => 985.5 Mhz + */ + _INIT_CMD(0x00, 0x08, 0x01, 0xf4, 0x01, 0x49), + /* MTXDIV=1, SYSDIV=3 (=> 4) */ + _INIT_CMD(0x00, 0x0c, 0x00, 0x00, 0x00, 0x03), + /* MTXVPF=24bpp, MRXLS=4 lanes, MRXVB=bypass, MRXECC=1, MRXEOT=1 + * MRXEE=1 + */ + _INIT_CMD(0x00, 0x14, 0x0c, 0x3d, 0x80, 0x0f), + _INIT_CMD(0x00, 0x20, 0x15, 0x92, 0x56, 0x7d), + _INIT_CMD(0x00, 0x24, 0x00, 0x00, 0x30, 0x00), + + _INIT_CMD(0x10, 0x08, 0x01, 0x20, 0x08, 0x45), + _INIT_CMD(0x10, 0x1c, 0x00, 0x00, 0x00, 0x00), + _INIT_CMD(0x20, 0x0c, 0x00, 0x00, 0x00, 0x04), + /* Pixel clock 985.5 Mhz * 0x49/0x4b = 959 Mhz */ + _INIT_CMD(0x20, 0x10, 0x00, 0x4b, 0x00, 0x49), + _INIT_CMD(0x20, 0xa0, 0x00, 0x00, 0x00, 0x00), + /* EOT=1, LPE = 0, LSOUT=4 lanes, LPD=25 */ + _INIT_CMD(0x60, 0x08, 0x00, 0xd9, 0x00, 0x08), + _INIT_CMD(0x60, 0x14, 0x01, 0x00, 0x01, 0x06), + /* DSI0 enable (default: probably not needed) */ + _INIT_CMD(0x60, 0x80, 0x00, 0x00, 0x00, 0x0f), + /* DSI1 enable */ + _INIT_CMD(0x60, 0xa0, 0x00, 0x00, 0x00, 0x0f), + + /* HSA=0x18, VSA=0x02, HBP=0x50, VBP=0x0c */ + _INIT_CMD(0x60, 0x0c, 0x0c, 0x50, 0x02, 0x18), + /* VACT= 0x800 (2048), VFP= 0x14, HFP=0x50 */ + _INIT_CMD(0x60, 0x10, 0x08, 0x00, 0x14, 0x50), + /* HACT=0x300 (768) */ + _INIT_CMD(0x60, 0x84, 0x00, 0x00, 0x03, 0x00), + _INIT_CMD(0x60, 0xa4, 0x00, 0x00, 0x03, 0x00), + + /* Take panel out of sleep. */ + _INIT_CMD(0xff, 0x01), + _INIT_CMD(0x11), + _INIT_CMD(0x29), + _INIT_CMD(0xff, 0x00), + + {}, +}; + +static const struct panel_desc innolux_p097pfg_ssd2858_panel_desc = { + .mode = &innolux_p097pfg_ssd2858_mode, + .bpc = 8, + .size = { + .width = 147, + .height = 196, + }, + .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM, + .format = MIPI_DSI_FMT_RGB888, + .init_cmds = innolux_p097pfg_ssd2858_init_cmds, + .lanes = 4, + .supply_names = innolux_p097pfg_ssd2858_supply_names, + .num_supplies = ARRAY_SIZE(innolux_p097pfg_ssd2858_supply_names), + .sleep_mode_delay = 100, /* T15 */ +}; + static int innolux_panel_get_modes(struct drm_panel *panel) { struct innolux_panel *innolux = to_innolux_panel(panel); @@ -451,6 +549,9 @@ static const struct of_device_id innolux_of_match[] = { { .compatible = "innolux,p097pfg", .data = &innolux_p097pfg_panel_desc }, + { .compatible = "innolux,p097pfg_ssd2858", + .data = &innolux_p097pfg_ssd2858_panel_desc + }, { } }; MODULE_DEVICE_TABLE(of, innolux_of_match);
Hi Jitao,
On Thu, Sep 12, 2019 at 5:04 PM Jitao Shi jitao.shi@mediatek.com wrote:
Add driver to support panel innolux,p097pfg with bridge ssd2858. SSD2858 can spilt dsi 4 lanes to 8 lanes.
Jitao Shi (3): drm/panel: panel-innolux: Allow 2 reset pins for panel dt-bindings: display: Add documentation for innolux,p097pfg_ssd2858 panel drm/panel: panel-innolux: Add support for P097PFZ behind SSD2858
I'm the author of at least the first patch, and at least part of the third one, so it would have been better if you clarified the origin of the patches.
Also, I do not believe that this is the right approach (this was always a temporary hack that we had no intent to upstream as-is), we'd probably want to add a proper bridge driver for SSD2858, and allow arbitrary panels behind it.
Please consider this series Nacked-by: Nicolas Boichat drinkcat@chromium.org
Thanks,
.../display/panel/innolux,p097pfg_ssd2858.txt | 39 +++++ drivers/gpu/drm/panel/panel-innolux-p079zca.c | 140 ++++++++++++++++-- 2 files changed, 164 insertions(+), 15 deletions(-) create mode 100644 Documentation/devicetree/bindings/display/panel/innolux,p097pfg_ssd2858.txt
-- 2.21.0
dri-devel@lists.freedesktop.org