1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd 4 */ 5 6 #include <linux/delay.h> 7 #include <linux/gpio/consumer.h> 8 #include <linux/module.h> 9 #include <linux/of.h> 10 #include <linux/regulator/consumer.h> 11 12 #include <video/mipi_display.h> 13 14 #include <drm/drm_crtc.h> 15 #include <drm/drm_device.h> 16 #include <drm/drm_mipi_dsi.h> 17 #include <drm/drm_modes.h> 18 #include <drm/drm_panel.h> 19 20 struct kingdisplay_panel { 21 struct drm_panel base; 22 struct mipi_dsi_device *link; 23 24 struct regulator *supply; 25 struct gpio_desc *enable_gpio; 26 }; 27 28 struct kingdisplay_panel_cmd { 29 char cmd; 30 char data; 31 }; 32 33 /* 34 * According to the discussion on 35 * https://review.coreboot.org/#/c/coreboot/+/22472/ 36 * the panel init array is not part of the panels datasheet but instead 37 * just came in this form from the panel vendor. 38 */ 39 static const struct kingdisplay_panel_cmd init_code[] = { 40 /* voltage setting */ 41 { 0xB0, 0x00 }, 42 { 0xB2, 0x02 }, 43 { 0xB3, 0x11 }, 44 { 0xB4, 0x00 }, 45 { 0xB6, 0x80 }, 46 /* VCOM disable */ 47 { 0xB7, 0x02 }, 48 { 0xB8, 0x80 }, 49 { 0xBA, 0x43 }, 50 /* VCOM setting */ 51 { 0xBB, 0x53 }, 52 /* VSP setting */ 53 { 0xBC, 0x0A }, 54 /* VSN setting */ 55 { 0xBD, 0x4A }, 56 /* VGH setting */ 57 { 0xBE, 0x2F }, 58 /* VGL setting */ 59 { 0xBF, 0x1A }, 60 { 0xF0, 0x39 }, 61 { 0xF1, 0x22 }, 62 /* Gamma setting */ 63 { 0xB0, 0x02 }, 64 { 0xC0, 0x00 }, 65 { 0xC1, 0x01 }, 66 { 0xC2, 0x0B }, 67 { 0xC3, 0x15 }, 68 { 0xC4, 0x22 }, 69 { 0xC5, 0x11 }, 70 { 0xC6, 0x15 }, 71 { 0xC7, 0x19 }, 72 { 0xC8, 0x1A }, 73 { 0xC9, 0x16 }, 74 { 0xCA, 0x18 }, 75 { 0xCB, 0x13 }, 76 { 0xCC, 0x18 }, 77 { 0xCD, 0x13 }, 78 { 0xCE, 0x1C }, 79 { 0xCF, 0x19 }, 80 { 0xD0, 0x21 }, 81 { 0xD1, 0x2C }, 82 { 0xD2, 0x2F }, 83 { 0xD3, 0x30 }, 84 { 0xD4, 0x19 }, 85 { 0xD5, 0x1F }, 86 { 0xD6, 0x00 }, 87 { 0xD7, 0x01 }, 88 { 0xD8, 0x0B }, 89 { 0xD9, 0x15 }, 90 { 0xDA, 0x22 }, 91 { 0xDB, 0x11 }, 92 { 0xDC, 0x15 }, 93 { 0xDD, 0x19 }, 94 { 0xDE, 0x1A }, 95 { 0xDF, 0x16 }, 96 { 0xE0, 0x18 }, 97 { 0xE1, 0x13 }, 98 { 0xE2, 0x18 }, 99 { 0xE3, 0x13 }, 100 { 0xE4, 0x1C }, 101 { 0xE5, 0x19 }, 102 { 0xE6, 0x21 }, 103 { 0xE7, 0x2C }, 104 { 0xE8, 0x2F }, 105 { 0xE9, 0x30 }, 106 { 0xEA, 0x19 }, 107 { 0xEB, 0x1F }, 108 /* GOA MUX setting */ 109 { 0xB0, 0x01 }, 110 { 0xC0, 0x10 }, 111 { 0xC1, 0x0F }, 112 { 0xC2, 0x0E }, 113 { 0xC3, 0x0D }, 114 { 0xC4, 0x0C }, 115 { 0xC5, 0x0B }, 116 { 0xC6, 0x0A }, 117 { 0xC7, 0x09 }, 118 { 0xC8, 0x08 }, 119 { 0xC9, 0x07 }, 120 { 0xCA, 0x06 }, 121 { 0xCB, 0x05 }, 122 { 0xCC, 0x00 }, 123 { 0xCD, 0x01 }, 124 { 0xCE, 0x02 }, 125 { 0xCF, 0x03 }, 126 { 0xD0, 0x04 }, 127 { 0xD6, 0x10 }, 128 { 0xD7, 0x0F }, 129 { 0xD8, 0x0E }, 130 { 0xD9, 0x0D }, 131 { 0xDA, 0x0C }, 132 { 0xDB, 0x0B }, 133 { 0xDC, 0x0A }, 134 { 0xDD, 0x09 }, 135 { 0xDE, 0x08 }, 136 { 0xDF, 0x07 }, 137 { 0xE0, 0x06 }, 138 { 0xE1, 0x05 }, 139 { 0xE2, 0x00 }, 140 { 0xE3, 0x01 }, 141 { 0xE4, 0x02 }, 142 { 0xE5, 0x03 }, 143 { 0xE6, 0x04 }, 144 { 0xE7, 0x00 }, 145 { 0xEC, 0xC0 }, 146 /* GOA timing setting */ 147 { 0xB0, 0x03 }, 148 { 0xC0, 0x01 }, 149 { 0xC2, 0x6F }, 150 { 0xC3, 0x6F }, 151 { 0xC5, 0x36 }, 152 { 0xC8, 0x08 }, 153 { 0xC9, 0x04 }, 154 { 0xCA, 0x41 }, 155 { 0xCC, 0x43 }, 156 { 0xCF, 0x60 }, 157 { 0xD2, 0x04 }, 158 { 0xD3, 0x04 }, 159 { 0xD4, 0x03 }, 160 { 0xD5, 0x02 }, 161 { 0xD6, 0x01 }, 162 { 0xD7, 0x00 }, 163 { 0xDB, 0x01 }, 164 { 0xDE, 0x36 }, 165 { 0xE6, 0x6F }, 166 { 0xE7, 0x6F }, 167 /* GOE setting */ 168 { 0xB0, 0x06 }, 169 { 0xB8, 0xA5 }, 170 { 0xC0, 0xA5 }, 171 { 0xD5, 0x3F }, 172 }; 173 174 static inline 175 struct kingdisplay_panel *to_kingdisplay_panel(struct drm_panel *panel) 176 { 177 return container_of(panel, struct kingdisplay_panel, base); 178 } 179 180 static int kingdisplay_panel_disable(struct drm_panel *panel) 181 { 182 struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel); 183 int err; 184 185 err = mipi_dsi_dcs_set_display_off(kingdisplay->link); 186 if (err < 0) 187 dev_err(panel->dev, "failed to set display off: %d\n", err); 188 189 return 0; 190 } 191 192 static int kingdisplay_panel_unprepare(struct drm_panel *panel) 193 { 194 struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel); 195 int err; 196 197 err = mipi_dsi_dcs_enter_sleep_mode(kingdisplay->link); 198 if (err < 0) { 199 dev_err(panel->dev, "failed to enter sleep mode: %d\n", err); 200 return err; 201 } 202 203 /* T15: 120ms */ 204 msleep(120); 205 206 gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0); 207 208 err = regulator_disable(kingdisplay->supply); 209 if (err < 0) 210 return err; 211 212 return 0; 213 } 214 215 static int kingdisplay_panel_prepare(struct drm_panel *panel) 216 { 217 struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel); 218 int err, regulator_err; 219 unsigned int i; 220 221 gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0); 222 223 err = regulator_enable(kingdisplay->supply); 224 if (err < 0) 225 return err; 226 227 /* T2: 15ms */ 228 usleep_range(15000, 16000); 229 230 gpiod_set_value_cansleep(kingdisplay->enable_gpio, 1); 231 232 /* T4: 15ms */ 233 usleep_range(15000, 16000); 234 235 for (i = 0; i < ARRAY_SIZE(init_code); i++) { 236 err = mipi_dsi_generic_write(kingdisplay->link, &init_code[i], 237 sizeof(struct kingdisplay_panel_cmd)); 238 if (err < 0) { 239 dev_err(panel->dev, "failed write init cmds: %d\n", err); 240 goto poweroff; 241 } 242 } 243 244 err = mipi_dsi_dcs_exit_sleep_mode(kingdisplay->link); 245 if (err < 0) { 246 dev_err(panel->dev, "failed to exit sleep mode: %d\n", err); 247 goto poweroff; 248 } 249 250 /* T6: 120ms */ 251 msleep(120); 252 253 err = mipi_dsi_dcs_set_display_on(kingdisplay->link); 254 if (err < 0) { 255 dev_err(panel->dev, "failed to set display on: %d\n", err); 256 goto poweroff; 257 } 258 259 /* T7: 10ms */ 260 usleep_range(10000, 11000); 261 262 return 0; 263 264 poweroff: 265 gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0); 266 267 regulator_err = regulator_disable(kingdisplay->supply); 268 if (regulator_err) 269 dev_err(panel->dev, "failed to disable regulator: %d\n", regulator_err); 270 271 return err; 272 } 273 274 static const struct drm_display_mode default_mode = { 275 .clock = 229000, 276 .hdisplay = 1536, 277 .hsync_start = 1536 + 100, 278 .hsync_end = 1536 + 100 + 24, 279 .htotal = 1536 + 100 + 24 + 100, 280 .vdisplay = 2048, 281 .vsync_start = 2048 + 95, 282 .vsync_end = 2048 + 95 + 2, 283 .vtotal = 2048 + 95 + 2 + 23, 284 }; 285 286 static int kingdisplay_panel_get_modes(struct drm_panel *panel, 287 struct drm_connector *connector) 288 { 289 struct drm_display_mode *mode; 290 291 mode = drm_mode_duplicate(connector->dev, &default_mode); 292 if (!mode) { 293 dev_err(panel->dev, "failed to add mode %ux%u@%u\n", 294 default_mode.hdisplay, default_mode.vdisplay, 295 drm_mode_vrefresh(&default_mode)); 296 return -ENOMEM; 297 } 298 299 drm_mode_set_name(mode); 300 301 drm_mode_probed_add(connector, mode); 302 303 connector->display_info.width_mm = 147; 304 connector->display_info.height_mm = 196; 305 connector->display_info.bpc = 8; 306 307 return 1; 308 } 309 310 static const struct drm_panel_funcs kingdisplay_panel_funcs = { 311 .disable = kingdisplay_panel_disable, 312 .unprepare = kingdisplay_panel_unprepare, 313 .prepare = kingdisplay_panel_prepare, 314 .get_modes = kingdisplay_panel_get_modes, 315 }; 316 317 static const struct of_device_id kingdisplay_of_match[] = { 318 { .compatible = "kingdisplay,kd097d04", }, 319 { } 320 }; 321 MODULE_DEVICE_TABLE(of, kingdisplay_of_match); 322 323 static int kingdisplay_panel_add(struct kingdisplay_panel *kingdisplay) 324 { 325 struct device *dev = &kingdisplay->link->dev; 326 int err; 327 328 kingdisplay->supply = devm_regulator_get(dev, "power"); 329 if (IS_ERR(kingdisplay->supply)) 330 return PTR_ERR(kingdisplay->supply); 331 332 kingdisplay->enable_gpio = devm_gpiod_get_optional(dev, "enable", 333 GPIOD_OUT_HIGH); 334 if (IS_ERR(kingdisplay->enable_gpio)) { 335 err = PTR_ERR(kingdisplay->enable_gpio); 336 dev_dbg(dev, "failed to get enable gpio: %d\n", err); 337 kingdisplay->enable_gpio = NULL; 338 } 339 340 drm_panel_init(&kingdisplay->base, &kingdisplay->link->dev, 341 &kingdisplay_panel_funcs, DRM_MODE_CONNECTOR_DSI); 342 343 err = drm_panel_of_backlight(&kingdisplay->base); 344 if (err) 345 return err; 346 347 drm_panel_add(&kingdisplay->base); 348 349 return 0; 350 } 351 352 static void kingdisplay_panel_del(struct kingdisplay_panel *kingdisplay) 353 { 354 drm_panel_remove(&kingdisplay->base); 355 } 356 357 static int kingdisplay_panel_probe(struct mipi_dsi_device *dsi) 358 { 359 struct kingdisplay_panel *kingdisplay; 360 int err; 361 362 dsi->lanes = 4; 363 dsi->format = MIPI_DSI_FMT_RGB888; 364 dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | 365 MIPI_DSI_MODE_LPM; 366 367 kingdisplay = devm_kzalloc(&dsi->dev, sizeof(*kingdisplay), GFP_KERNEL); 368 if (!kingdisplay) 369 return -ENOMEM; 370 371 mipi_dsi_set_drvdata(dsi, kingdisplay); 372 kingdisplay->link = dsi; 373 374 err = kingdisplay_panel_add(kingdisplay); 375 if (err < 0) 376 return err; 377 378 err = mipi_dsi_attach(dsi); 379 if (err < 0) { 380 kingdisplay_panel_del(kingdisplay); 381 return err; 382 } 383 384 return 0; 385 } 386 387 static void kingdisplay_panel_remove(struct mipi_dsi_device *dsi) 388 { 389 struct kingdisplay_panel *kingdisplay = mipi_dsi_get_drvdata(dsi); 390 int err; 391 392 err = mipi_dsi_detach(dsi); 393 if (err < 0) 394 dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err); 395 396 kingdisplay_panel_del(kingdisplay); 397 } 398 399 static struct mipi_dsi_driver kingdisplay_panel_driver = { 400 .driver = { 401 .name = "panel-kingdisplay-kd097d04", 402 .of_match_table = kingdisplay_of_match, 403 }, 404 .probe = kingdisplay_panel_probe, 405 .remove = kingdisplay_panel_remove, 406 }; 407 module_mipi_dsi_driver(kingdisplay_panel_driver); 408 409 MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>"); 410 MODULE_AUTHOR("Nickey Yang <nickey.yang@rock-chips.com>"); 411 MODULE_DESCRIPTION("kingdisplay KD097D04 panel driver"); 412 MODULE_LICENSE("GPL v2"); 413