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