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