1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2019, Huaqin Telecom Technology Co., Ltd
9 #include <linux/delay.h>
10 #include <linux/kernel.h>
11 #include <linux/module.h>
14 #include <linux/gpio/consumer.h>
15 #include <linux/regulator/consumer.h>
17 #include <drm/drm_device.h>
18 #include <drm/drm_mipi_dsi.h>
19 #include <drm/drm_modes.h>
20 #include <drm/drm_panel.h>
22 #include <video/mipi_display.h>
30 const struct drm_display_mode *display_mode;
32 unsigned int width_mm;
33 unsigned int height_mm;
35 unsigned long mode_flags;
36 enum mipi_dsi_pixel_format format;
38 const struct panel_cmd *on_cmds;
39 unsigned int on_cmds_num;
43 struct drm_panel base;
44 struct mipi_dsi_device *link;
45 const struct panel_desc *desc;
47 struct gpio_desc *enable_gpio;
48 struct gpio_desc *pp33_gpio;
49 struct gpio_desc *pp18_gpio;
52 static inline struct panel_info *to_panel_info(struct drm_panel *panel)
54 return container_of(panel, struct panel_info, base);
57 static void disable_gpios(struct panel_info *pinfo)
59 gpiod_set_value(pinfo->enable_gpio, 0);
60 gpiod_set_value(pinfo->pp33_gpio, 0);
61 gpiod_set_value(pinfo->pp18_gpio, 0);
64 static int send_mipi_cmds(struct drm_panel *panel, const struct panel_cmd *cmds)
66 struct panel_info *pinfo = to_panel_info(panel);
70 for (i = 0; i < pinfo->desc->on_cmds_num; i++) {
71 err = mipi_dsi_dcs_write_buffer(pinfo->link, &cmds[i],
72 sizeof(struct panel_cmd));
81 static int boe_panel_disable(struct drm_panel *panel)
83 struct panel_info *pinfo = to_panel_info(panel);
86 err = mipi_dsi_dcs_set_display_off(pinfo->link);
88 dev_err(panel->dev, "failed to set display off: %d\n", err);
95 static int boe_panel_unprepare(struct drm_panel *panel)
97 struct panel_info *pinfo = to_panel_info(panel);
100 err = mipi_dsi_dcs_set_display_off(pinfo->link);
102 dev_err(panel->dev, "failed to set display off: %d\n", err);
104 err = mipi_dsi_dcs_enter_sleep_mode(pinfo->link);
106 dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);
108 /* sleep_mode_delay: 1ms - 2ms */
109 usleep_range(1000, 2000);
111 disable_gpios(pinfo);
116 static int boe_panel_prepare(struct drm_panel *panel)
118 struct panel_info *pinfo = to_panel_info(panel);
121 gpiod_set_value(pinfo->pp18_gpio, 1);
123 usleep_range(5000, 6000);
124 gpiod_set_value(pinfo->pp33_gpio, 1);
127 /* T2: 14ms - 15ms */
128 usleep_range(14000, 15000);
129 gpiod_set_value(pinfo->enable_gpio, 1);
132 usleep_range(1000, 2000);
133 gpiod_set_value(pinfo->enable_gpio, 0);
136 usleep_range(1000, 2000);
137 gpiod_set_value(pinfo->enable_gpio, 1);
140 usleep_range(5000, 6000);
143 err = send_mipi_cmds(panel, pinfo->desc->on_cmds);
145 dev_err(panel->dev, "failed to send DCS Init Code: %d\n", err);
149 err = mipi_dsi_dcs_exit_sleep_mode(pinfo->link);
151 dev_err(panel->dev, "failed to exit sleep mode: %d\n", err);
155 /* T6: 120ms - 121ms */
156 usleep_range(120000, 121000);
158 err = mipi_dsi_dcs_set_display_on(pinfo->link);
160 dev_err(panel->dev, "failed to set display on: %d\n", err);
164 /* T7: 20ms - 21ms */
165 usleep_range(20000, 21000);
170 disable_gpios(pinfo);
174 static int boe_panel_enable(struct drm_panel *panel)
176 struct panel_info *pinfo = to_panel_info(panel);
179 usleep_range(120000, 121000);
181 ret = mipi_dsi_dcs_set_display_on(pinfo->link);
183 dev_err(panel->dev, "failed to set display on: %d\n", ret);
190 static int boe_panel_get_modes(struct drm_panel *panel,
191 struct drm_connector *connector)
193 struct panel_info *pinfo = to_panel_info(panel);
194 const struct drm_display_mode *m = pinfo->desc->display_mode;
195 struct drm_display_mode *mode;
197 mode = drm_mode_duplicate(connector->dev, m);
199 dev_err(pinfo->base.dev, "failed to add mode %ux%u@%u\n",
200 m->hdisplay, m->vdisplay, drm_mode_vrefresh(m));
204 drm_mode_set_name(mode);
206 drm_mode_probed_add(connector, mode);
208 connector->display_info.width_mm = pinfo->desc->width_mm;
209 connector->display_info.height_mm = pinfo->desc->height_mm;
210 connector->display_info.bpc = pinfo->desc->bpc;
215 static const struct drm_panel_funcs panel_funcs = {
216 .disable = boe_panel_disable,
217 .unprepare = boe_panel_unprepare,
218 .prepare = boe_panel_prepare,
219 .enable = boe_panel_enable,
220 .get_modes = boe_panel_get_modes,
223 static const struct drm_display_mode default_display_mode = {
226 .hsync_start = 1200 + 80,
227 .hsync_end = 1200 + 80 + 60,
228 .htotal = 1200 + 80 + 60 + 24,
230 .vsync_start = 1920 + 10,
231 .vsync_end = 1920 + 10 + 14,
232 .vtotal = 1920 + 10 + 14 + 4,
236 static const struct panel_cmd boe_himax8279d8p_on_cmds[] = {
499 static const struct panel_desc boe_himax8279d8p_panel_desc = {
500 .display_mode = &default_display_mode,
504 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
505 MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM,
506 .format = MIPI_DSI_FMT_RGB888,
508 .on_cmds = boe_himax8279d8p_on_cmds,
513 static const struct panel_cmd boe_himax8279d10p_on_cmds[] = {
799 static const struct panel_desc boe_himax8279d10p_panel_desc = {
800 .display_mode = &default_display_mode,
804 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
805 MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM,
806 .format = MIPI_DSI_FMT_RGB888,
808 .on_cmds = boe_himax8279d10p_on_cmds,
812 static const struct of_device_id panel_of_match[] = {
814 .compatible = "boe,himax8279d8p",
815 .data = &boe_himax8279d8p_panel_desc,
818 .compatible = "boe,himax8279d10p",
819 .data = &boe_himax8279d10p_panel_desc,
825 MODULE_DEVICE_TABLE(of, panel_of_match);
827 static int panel_add(struct panel_info *pinfo)
829 struct device *dev = &pinfo->link->dev;
832 pinfo->pp18_gpio = devm_gpiod_get(dev, "pp18", GPIOD_OUT_HIGH);
833 if (IS_ERR(pinfo->pp18_gpio)) {
834 return dev_err_probe(dev, PTR_ERR(pinfo->pp18_gpio),
835 "failed to get pp18 gpio\n");
838 pinfo->pp33_gpio = devm_gpiod_get(dev, "pp33", GPIOD_OUT_HIGH);
839 if (IS_ERR(pinfo->pp33_gpio)) {
840 return dev_err_probe(dev, PTR_ERR(pinfo->pp33_gpio),
841 "failed to get pp33 gpio\n");
844 pinfo->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH);
845 if (IS_ERR(pinfo->enable_gpio)) {
846 return dev_err_probe(dev, PTR_ERR(pinfo->enable_gpio),
847 "failed to get enable gpio\n");
850 drm_panel_init(&pinfo->base, dev, &panel_funcs,
851 DRM_MODE_CONNECTOR_DSI);
853 ret = drm_panel_of_backlight(&pinfo->base);
857 drm_panel_add(&pinfo->base);
862 static int panel_probe(struct mipi_dsi_device *dsi)
864 struct panel_info *pinfo;
865 const struct panel_desc *desc;
868 pinfo = devm_kzalloc(&dsi->dev, sizeof(*pinfo), GFP_KERNEL);
872 desc = of_device_get_match_data(&dsi->dev);
873 dsi->mode_flags = desc->mode_flags;
874 dsi->format = desc->format;
875 dsi->lanes = desc->lanes;
879 mipi_dsi_set_drvdata(dsi, pinfo);
881 err = panel_add(pinfo);
885 err = mipi_dsi_attach(dsi);
887 drm_panel_remove(&pinfo->base);
892 static void panel_remove(struct mipi_dsi_device *dsi)
894 struct panel_info *pinfo = mipi_dsi_get_drvdata(dsi);
897 err = mipi_dsi_detach(dsi);
899 dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err);
901 drm_panel_remove(&pinfo->base);
904 static struct mipi_dsi_driver panel_driver = {
906 .name = "panel-boe-himax8279d",
907 .of_match_table = panel_of_match,
909 .probe = panel_probe,
910 .remove = panel_remove,
912 module_mipi_dsi_driver(panel_driver);
915 MODULE_DESCRIPTION("Boe Himax8279d driver");
916 MODULE_LICENSE("GPL v2");