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>
13 #include <linux/of_device.h>
15 #include <linux/gpio/consumer.h>
16 #include <linux/regulator/consumer.h>
18 #include <drm/drm_device.h>
19 #include <drm/drm_mipi_dsi.h>
20 #include <drm/drm_modes.h>
21 #include <drm/drm_panel.h>
22 #include <drm/drm_print.h>
24 #include <video/mipi_display.h>
32 const struct drm_display_mode *display_mode;
34 unsigned int width_mm;
35 unsigned int height_mm;
37 unsigned long mode_flags;
38 enum mipi_dsi_pixel_format format;
40 const struct panel_cmd *on_cmds;
41 unsigned int on_cmds_num;
45 struct drm_panel base;
46 struct mipi_dsi_device *link;
47 const struct panel_desc *desc;
49 struct gpio_desc *enable_gpio;
50 struct gpio_desc *pp33_gpio;
51 struct gpio_desc *pp18_gpio;
57 static inline struct panel_info *to_panel_info(struct drm_panel *panel)
59 return container_of(panel, struct panel_info, base);
62 static void disable_gpios(struct panel_info *pinfo)
64 gpiod_set_value(pinfo->enable_gpio, 0);
65 gpiod_set_value(pinfo->pp33_gpio, 0);
66 gpiod_set_value(pinfo->pp18_gpio, 0);
69 static int send_mipi_cmds(struct drm_panel *panel, const struct panel_cmd *cmds)
71 struct panel_info *pinfo = to_panel_info(panel);
75 for (i = 0; i < pinfo->desc->on_cmds_num; i++) {
76 err = mipi_dsi_dcs_write_buffer(pinfo->link, &cmds[i],
77 sizeof(struct panel_cmd));
86 static int boe_panel_disable(struct drm_panel *panel)
88 struct panel_info *pinfo = to_panel_info(panel);
94 err = mipi_dsi_dcs_set_display_off(pinfo->link);
96 DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n",
101 pinfo->enabled = false;
106 static int boe_panel_unprepare(struct drm_panel *panel)
108 struct panel_info *pinfo = to_panel_info(panel);
111 if (!pinfo->prepared)
114 err = mipi_dsi_dcs_set_display_off(pinfo->link);
116 DRM_DEV_ERROR(panel->dev, "failed to set display off: %d\n",
119 err = mipi_dsi_dcs_enter_sleep_mode(pinfo->link);
121 DRM_DEV_ERROR(panel->dev, "failed to enter sleep mode: %d\n",
124 /* sleep_mode_delay: 1ms - 2ms */
125 usleep_range(1000, 2000);
127 disable_gpios(pinfo);
129 pinfo->prepared = false;
134 static int boe_panel_prepare(struct drm_panel *panel)
136 struct panel_info *pinfo = to_panel_info(panel);
142 gpiod_set_value(pinfo->pp18_gpio, 1);
144 usleep_range(5000, 6000);
145 gpiod_set_value(pinfo->pp33_gpio, 1);
148 /* T2: 14ms - 15ms */
149 usleep_range(14000, 15000);
150 gpiod_set_value(pinfo->enable_gpio, 1);
153 usleep_range(1000, 2000);
154 gpiod_set_value(pinfo->enable_gpio, 0);
157 usleep_range(1000, 2000);
158 gpiod_set_value(pinfo->enable_gpio, 1);
161 usleep_range(5000, 6000);
164 err = send_mipi_cmds(panel, pinfo->desc->on_cmds);
166 DRM_DEV_ERROR(panel->dev, "failed to send DCS Init Code: %d\n",
171 err = mipi_dsi_dcs_exit_sleep_mode(pinfo->link);
173 DRM_DEV_ERROR(panel->dev, "failed to exit sleep mode: %d\n",
178 /* T6: 120ms - 121ms */
179 usleep_range(120000, 121000);
181 err = mipi_dsi_dcs_set_display_on(pinfo->link);
183 DRM_DEV_ERROR(panel->dev, "failed to set display on: %d\n",
188 /* T7: 20ms - 21ms */
189 usleep_range(20000, 21000);
191 pinfo->prepared = true;
196 disable_gpios(pinfo);
200 static int boe_panel_enable(struct drm_panel *panel)
202 struct panel_info *pinfo = to_panel_info(panel);
208 usleep_range(120000, 121000);
210 ret = mipi_dsi_dcs_set_display_on(pinfo->link);
212 DRM_DEV_ERROR(panel->dev, "failed to set display on: %d\n",
217 pinfo->enabled = true;
222 static int boe_panel_get_modes(struct drm_panel *panel,
223 struct drm_connector *connector)
225 struct panel_info *pinfo = to_panel_info(panel);
226 const struct drm_display_mode *m = pinfo->desc->display_mode;
227 struct drm_display_mode *mode;
229 mode = drm_mode_duplicate(connector->dev, m);
231 DRM_DEV_ERROR(pinfo->base.dev, "failed to add mode %ux%u@%u\n",
232 m->hdisplay, m->vdisplay, m->vrefresh);
236 drm_mode_set_name(mode);
238 drm_mode_probed_add(connector, mode);
240 connector->display_info.width_mm = pinfo->desc->width_mm;
241 connector->display_info.height_mm = pinfo->desc->height_mm;
242 connector->display_info.bpc = pinfo->desc->bpc;
247 static const struct drm_panel_funcs panel_funcs = {
248 .disable = boe_panel_disable,
249 .unprepare = boe_panel_unprepare,
250 .prepare = boe_panel_prepare,
251 .enable = boe_panel_enable,
252 .get_modes = boe_panel_get_modes,
255 static const struct drm_display_mode default_display_mode = {
258 .hsync_start = 1200 + 80,
259 .hsync_end = 1200 + 80 + 60,
260 .htotal = 1200 + 80 + 60 + 24,
262 .vsync_start = 1920 + 10,
263 .vsync_end = 1920 + 10 + 14,
264 .vtotal = 1920 + 10 + 14 + 4,
269 static const struct panel_cmd boe_himax8279d8p_on_cmds[] = {
532 static const struct panel_desc boe_himax8279d8p_panel_desc = {
533 .display_mode = &default_display_mode,
537 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
538 MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM,
539 .format = MIPI_DSI_FMT_RGB888,
541 .on_cmds = boe_himax8279d8p_on_cmds,
546 static const struct panel_cmd boe_himax8279d10p_on_cmds[] = {
832 static const struct panel_desc boe_himax8279d10p_panel_desc = {
833 .display_mode = &default_display_mode,
837 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
838 MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM,
839 .format = MIPI_DSI_FMT_RGB888,
841 .on_cmds = boe_himax8279d10p_on_cmds,
845 static const struct of_device_id panel_of_match[] = {
847 .compatible = "boe,himax8279d8p",
848 .data = &boe_himax8279d8p_panel_desc,
851 .compatible = "boe,himax8279d10p",
852 .data = &boe_himax8279d10p_panel_desc,
858 MODULE_DEVICE_TABLE(of, panel_of_match);
860 static int panel_add(struct panel_info *pinfo)
862 struct device *dev = &pinfo->link->dev;
865 pinfo->pp18_gpio = devm_gpiod_get(dev, "pp18", GPIOD_OUT_HIGH);
866 if (IS_ERR(pinfo->pp18_gpio)) {
867 ret = PTR_ERR(pinfo->pp18_gpio);
868 if (ret != -EPROBE_DEFER)
869 DRM_DEV_ERROR(dev, "failed to get pp18 gpio: %d\n",
874 pinfo->pp33_gpio = devm_gpiod_get(dev, "pp33", GPIOD_OUT_HIGH);
875 if (IS_ERR(pinfo->pp33_gpio)) {
876 ret = PTR_ERR(pinfo->pp33_gpio);
877 if (ret != -EPROBE_DEFER)
878 DRM_DEV_ERROR(dev, "failed to get pp33 gpio: %d\n",
883 pinfo->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH);
884 if (IS_ERR(pinfo->enable_gpio)) {
885 ret = PTR_ERR(pinfo->enable_gpio);
886 if (ret != -EPROBE_DEFER)
887 DRM_DEV_ERROR(dev, "failed to get enable gpio: %d\n",
892 drm_panel_init(&pinfo->base, dev, &panel_funcs,
893 DRM_MODE_CONNECTOR_DSI);
895 ret = drm_panel_of_backlight(&pinfo->base);
899 return drm_panel_add(&pinfo->base);
902 static int panel_probe(struct mipi_dsi_device *dsi)
904 struct panel_info *pinfo;
905 const struct panel_desc *desc;
908 pinfo = devm_kzalloc(&dsi->dev, sizeof(*pinfo), GFP_KERNEL);
912 desc = of_device_get_match_data(&dsi->dev);
913 dsi->mode_flags = desc->mode_flags;
914 dsi->format = desc->format;
915 dsi->lanes = desc->lanes;
919 mipi_dsi_set_drvdata(dsi, pinfo);
921 err = panel_add(pinfo);
925 err = mipi_dsi_attach(dsi);
927 drm_panel_remove(&pinfo->base);
932 static int panel_remove(struct mipi_dsi_device *dsi)
934 struct panel_info *pinfo = mipi_dsi_get_drvdata(dsi);
937 err = boe_panel_disable(&pinfo->base);
939 DRM_DEV_ERROR(&dsi->dev, "failed to disable panel: %d\n",
942 err = boe_panel_unprepare(&pinfo->base);
944 DRM_DEV_ERROR(&dsi->dev, "failed to unprepare panel: %d\n",
947 err = mipi_dsi_detach(dsi);
949 DRM_DEV_ERROR(&dsi->dev, "failed to detach from DSI host: %d\n",
952 drm_panel_remove(&pinfo->base);
957 static void panel_shutdown(struct mipi_dsi_device *dsi)
959 struct panel_info *pinfo = mipi_dsi_get_drvdata(dsi);
961 boe_panel_disable(&pinfo->base);
962 boe_panel_unprepare(&pinfo->base);
965 static struct mipi_dsi_driver panel_driver = {
967 .name = "panel-boe-himax8279d",
968 .of_match_table = panel_of_match,
970 .probe = panel_probe,
971 .remove = panel_remove,
972 .shutdown = panel_shutdown,
974 module_mipi_dsi_driver(panel_driver);
977 MODULE_DESCRIPTION("Boe Himax8279d driver");
978 MODULE_LICENSE("GPL v2");