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 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 err = mipi_dsi_dcs_set_display_off(kingdisplay->link); 192 if (err < 0) 193 dev_err(panel->dev, "failed to set display off: %d\n", err); 194 195 kingdisplay->enabled = false; 196 197 return 0; 198 } 199 200 static int kingdisplay_panel_unprepare(struct drm_panel *panel) 201 { 202 struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel); 203 int err; 204 205 if (!kingdisplay->prepared) 206 return 0; 207 208 err = mipi_dsi_dcs_enter_sleep_mode(kingdisplay->link); 209 if (err < 0) { 210 dev_err(panel->dev, "failed to enter sleep mode: %d\n", err); 211 return err; 212 } 213 214 /* T15: 120ms */ 215 msleep(120); 216 217 gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0); 218 219 err = regulator_disable(kingdisplay->supply); 220 if (err < 0) 221 return err; 222 223 kingdisplay->prepared = false; 224 225 return 0; 226 } 227 228 static int kingdisplay_panel_prepare(struct drm_panel *panel) 229 { 230 struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel); 231 int err, regulator_err; 232 unsigned int i; 233 234 if (kingdisplay->prepared) 235 return 0; 236 237 gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0); 238 239 err = regulator_enable(kingdisplay->supply); 240 if (err < 0) 241 return err; 242 243 /* T2: 15ms */ 244 usleep_range(15000, 16000); 245 246 gpiod_set_value_cansleep(kingdisplay->enable_gpio, 1); 247 248 /* T4: 15ms */ 249 usleep_range(15000, 16000); 250 251 for (i = 0; i < ARRAY_SIZE(init_code); i++) { 252 err = mipi_dsi_generic_write(kingdisplay->link, &init_code[i], 253 sizeof(struct kingdisplay_panel_cmd)); 254 if (err < 0) { 255 dev_err(panel->dev, "failed write init cmds: %d\n", err); 256 goto poweroff; 257 } 258 } 259 260 err = mipi_dsi_dcs_exit_sleep_mode(kingdisplay->link); 261 if (err < 0) { 262 dev_err(panel->dev, "failed to exit sleep mode: %d\n", err); 263 goto poweroff; 264 } 265 266 /* T6: 120ms */ 267 msleep(120); 268 269 err = mipi_dsi_dcs_set_display_on(kingdisplay->link); 270 if (err < 0) { 271 dev_err(panel->dev, "failed to set display on: %d\n", err); 272 goto poweroff; 273 } 274 275 /* T7: 10ms */ 276 usleep_range(10000, 11000); 277 278 kingdisplay->prepared = true; 279 280 return 0; 281 282 poweroff: 283 gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0); 284 285 regulator_err = regulator_disable(kingdisplay->supply); 286 if (regulator_err) 287 dev_err(panel->dev, "failed to disable regulator: %d\n", regulator_err); 288 289 return err; 290 } 291 292 static int kingdisplay_panel_enable(struct drm_panel *panel) 293 { 294 struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel); 295 296 if (kingdisplay->enabled) 297 return 0; 298 299 kingdisplay->enabled = true; 300 301 return 0; 302 } 303 304 static const struct drm_display_mode default_mode = { 305 .clock = 229000, 306 .hdisplay = 1536, 307 .hsync_start = 1536 + 100, 308 .hsync_end = 1536 + 100 + 24, 309 .htotal = 1536 + 100 + 24 + 100, 310 .vdisplay = 2048, 311 .vsync_start = 2048 + 95, 312 .vsync_end = 2048 + 95 + 2, 313 .vtotal = 2048 + 95 + 2 + 23, 314 }; 315 316 static int kingdisplay_panel_get_modes(struct drm_panel *panel, 317 struct drm_connector *connector) 318 { 319 struct drm_display_mode *mode; 320 321 mode = drm_mode_duplicate(connector->dev, &default_mode); 322 if (!mode) { 323 dev_err(panel->dev, "failed to add mode %ux%u@%u\n", 324 default_mode.hdisplay, default_mode.vdisplay, 325 drm_mode_vrefresh(&default_mode)); 326 return -ENOMEM; 327 } 328 329 drm_mode_set_name(mode); 330 331 drm_mode_probed_add(connector, mode); 332 333 connector->display_info.width_mm = 147; 334 connector->display_info.height_mm = 196; 335 connector->display_info.bpc = 8; 336 337 return 1; 338 } 339 340 static const struct drm_panel_funcs kingdisplay_panel_funcs = { 341 .disable = kingdisplay_panel_disable, 342 .unprepare = kingdisplay_panel_unprepare, 343 .prepare = kingdisplay_panel_prepare, 344 .enable = kingdisplay_panel_enable, 345 .get_modes = kingdisplay_panel_get_modes, 346 }; 347 348 static const struct of_device_id kingdisplay_of_match[] = { 349 { .compatible = "kingdisplay,kd097d04", }, 350 { } 351 }; 352 MODULE_DEVICE_TABLE(of, kingdisplay_of_match); 353 354 static int kingdisplay_panel_add(struct kingdisplay_panel *kingdisplay) 355 { 356 struct device *dev = &kingdisplay->link->dev; 357 int err; 358 359 kingdisplay->supply = devm_regulator_get(dev, "power"); 360 if (IS_ERR(kingdisplay->supply)) 361 return PTR_ERR(kingdisplay->supply); 362 363 kingdisplay->enable_gpio = devm_gpiod_get_optional(dev, "enable", 364 GPIOD_OUT_HIGH); 365 if (IS_ERR(kingdisplay->enable_gpio)) { 366 err = PTR_ERR(kingdisplay->enable_gpio); 367 dev_dbg(dev, "failed to get enable gpio: %d\n", err); 368 kingdisplay->enable_gpio = NULL; 369 } 370 371 drm_panel_init(&kingdisplay->base, &kingdisplay->link->dev, 372 &kingdisplay_panel_funcs, DRM_MODE_CONNECTOR_DSI); 373 374 err = drm_panel_of_backlight(&kingdisplay->base); 375 if (err) 376 return err; 377 378 drm_panel_add(&kingdisplay->base); 379 380 return 0; 381 } 382 383 static void kingdisplay_panel_del(struct kingdisplay_panel *kingdisplay) 384 { 385 drm_panel_remove(&kingdisplay->base); 386 } 387 388 static int kingdisplay_panel_probe(struct mipi_dsi_device *dsi) 389 { 390 struct kingdisplay_panel *kingdisplay; 391 int err; 392 393 dsi->lanes = 4; 394 dsi->format = MIPI_DSI_FMT_RGB888; 395 dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | 396 MIPI_DSI_MODE_LPM; 397 398 kingdisplay = devm_kzalloc(&dsi->dev, sizeof(*kingdisplay), GFP_KERNEL); 399 if (!kingdisplay) 400 return -ENOMEM; 401 402 mipi_dsi_set_drvdata(dsi, kingdisplay); 403 kingdisplay->link = dsi; 404 405 err = kingdisplay_panel_add(kingdisplay); 406 if (err < 0) 407 return err; 408 409 return mipi_dsi_attach(dsi); 410 } 411 412 static int kingdisplay_panel_remove(struct mipi_dsi_device *dsi) 413 { 414 struct kingdisplay_panel *kingdisplay = mipi_dsi_get_drvdata(dsi); 415 int err; 416 417 err = drm_panel_unprepare(&kingdisplay->base); 418 if (err < 0) 419 dev_err(&dsi->dev, "failed to unprepare panel: %d\n", err); 420 421 err = drm_panel_disable(&kingdisplay->base); 422 if (err < 0) 423 dev_err(&dsi->dev, "failed to disable panel: %d\n", err); 424 425 err = mipi_dsi_detach(dsi); 426 if (err < 0) 427 dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err); 428 429 kingdisplay_panel_del(kingdisplay); 430 431 return 0; 432 } 433 434 static void kingdisplay_panel_shutdown(struct mipi_dsi_device *dsi) 435 { 436 struct kingdisplay_panel *kingdisplay = mipi_dsi_get_drvdata(dsi); 437 438 drm_panel_unprepare(&kingdisplay->base); 439 drm_panel_disable(&kingdisplay->base); 440 } 441 442 static struct mipi_dsi_driver kingdisplay_panel_driver = { 443 .driver = { 444 .name = "panel-kingdisplay-kd097d04", 445 .of_match_table = kingdisplay_of_match, 446 }, 447 .probe = kingdisplay_panel_probe, 448 .remove = kingdisplay_panel_remove, 449 .shutdown = kingdisplay_panel_shutdown, 450 }; 451 module_mipi_dsi_driver(kingdisplay_panel_driver); 452 453 MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>"); 454 MODULE_AUTHOR("Nickey Yang <nickey.yang@rock-chips.com>"); 455 MODULE_DESCRIPTION("kingdisplay KD097D04 panel driver"); 456 MODULE_LICENSE("GPL v2"); 457