1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2019, Huaqin Telecom Technology Co., Ltd 4 * 5 * Author: Jerry Han <jerry.han.hq@gmail.com> 6 * 7 */ 8 9 #include <linux/delay.h> 10 #include <linux/kernel.h> 11 #include <linux/module.h> 12 #include <linux/of.h> 13 14 #include <linux/gpio/consumer.h> 15 #include <linux/regulator/consumer.h> 16 17 #include <drm/drm_device.h> 18 #include <drm/drm_mipi_dsi.h> 19 #include <drm/drm_modes.h> 20 #include <drm/drm_panel.h> 21 22 #include <video/mipi_display.h> 23 24 struct panel_cmd { 25 char cmd; 26 char data; 27 }; 28 29 struct panel_desc { 30 const struct drm_display_mode *display_mode; 31 unsigned int bpc; 32 unsigned int width_mm; 33 unsigned int height_mm; 34 35 unsigned long mode_flags; 36 enum mipi_dsi_pixel_format format; 37 unsigned int lanes; 38 const struct panel_cmd *on_cmds; 39 unsigned int on_cmds_num; 40 }; 41 42 struct panel_info { 43 struct drm_panel base; 44 struct mipi_dsi_device *link; 45 const struct panel_desc *desc; 46 47 struct gpio_desc *enable_gpio; 48 struct gpio_desc *pp33_gpio; 49 struct gpio_desc *pp18_gpio; 50 51 bool prepared; 52 bool enabled; 53 }; 54 55 static inline struct panel_info *to_panel_info(struct drm_panel *panel) 56 { 57 return container_of(panel, struct panel_info, base); 58 } 59 60 static void disable_gpios(struct panel_info *pinfo) 61 { 62 gpiod_set_value(pinfo->enable_gpio, 0); 63 gpiod_set_value(pinfo->pp33_gpio, 0); 64 gpiod_set_value(pinfo->pp18_gpio, 0); 65 } 66 67 static int send_mipi_cmds(struct drm_panel *panel, const struct panel_cmd *cmds) 68 { 69 struct panel_info *pinfo = to_panel_info(panel); 70 unsigned int i = 0; 71 int err; 72 73 for (i = 0; i < pinfo->desc->on_cmds_num; i++) { 74 err = mipi_dsi_dcs_write_buffer(pinfo->link, &cmds[i], 75 sizeof(struct panel_cmd)); 76 77 if (err < 0) 78 return err; 79 } 80 81 return 0; 82 } 83 84 static int boe_panel_disable(struct drm_panel *panel) 85 { 86 struct panel_info *pinfo = to_panel_info(panel); 87 int err; 88 89 if (!pinfo->enabled) 90 return 0; 91 92 err = mipi_dsi_dcs_set_display_off(pinfo->link); 93 if (err < 0) { 94 dev_err(panel->dev, "failed to set display off: %d\n", err); 95 return err; 96 } 97 98 pinfo->enabled = false; 99 100 return 0; 101 } 102 103 static int boe_panel_unprepare(struct drm_panel *panel) 104 { 105 struct panel_info *pinfo = to_panel_info(panel); 106 int err; 107 108 if (!pinfo->prepared) 109 return 0; 110 111 err = mipi_dsi_dcs_set_display_off(pinfo->link); 112 if (err < 0) 113 dev_err(panel->dev, "failed to set display off: %d\n", err); 114 115 err = mipi_dsi_dcs_enter_sleep_mode(pinfo->link); 116 if (err < 0) 117 dev_err(panel->dev, "failed to enter sleep mode: %d\n", err); 118 119 /* sleep_mode_delay: 1ms - 2ms */ 120 usleep_range(1000, 2000); 121 122 disable_gpios(pinfo); 123 124 pinfo->prepared = false; 125 126 return 0; 127 } 128 129 static int boe_panel_prepare(struct drm_panel *panel) 130 { 131 struct panel_info *pinfo = to_panel_info(panel); 132 int err; 133 134 if (pinfo->prepared) 135 return 0; 136 137 gpiod_set_value(pinfo->pp18_gpio, 1); 138 /* T1: 5ms - 6ms */ 139 usleep_range(5000, 6000); 140 gpiod_set_value(pinfo->pp33_gpio, 1); 141 142 /* reset sequence */ 143 /* T2: 14ms - 15ms */ 144 usleep_range(14000, 15000); 145 gpiod_set_value(pinfo->enable_gpio, 1); 146 147 /* T3: 1ms - 2ms */ 148 usleep_range(1000, 2000); 149 gpiod_set_value(pinfo->enable_gpio, 0); 150 151 /* T4: 1ms - 2ms */ 152 usleep_range(1000, 2000); 153 gpiod_set_value(pinfo->enable_gpio, 1); 154 155 /* T5: 5ms - 6ms */ 156 usleep_range(5000, 6000); 157 158 /* send init code */ 159 err = send_mipi_cmds(panel, pinfo->desc->on_cmds); 160 if (err < 0) { 161 dev_err(panel->dev, "failed to send DCS Init Code: %d\n", err); 162 goto poweroff; 163 } 164 165 err = mipi_dsi_dcs_exit_sleep_mode(pinfo->link); 166 if (err < 0) { 167 dev_err(panel->dev, "failed to exit sleep mode: %d\n", err); 168 goto poweroff; 169 } 170 171 /* T6: 120ms - 121ms */ 172 usleep_range(120000, 121000); 173 174 err = mipi_dsi_dcs_set_display_on(pinfo->link); 175 if (err < 0) { 176 dev_err(panel->dev, "failed to set display on: %d\n", err); 177 goto poweroff; 178 } 179 180 /* T7: 20ms - 21ms */ 181 usleep_range(20000, 21000); 182 183 pinfo->prepared = true; 184 185 return 0; 186 187 poweroff: 188 disable_gpios(pinfo); 189 return err; 190 } 191 192 static int boe_panel_enable(struct drm_panel *panel) 193 { 194 struct panel_info *pinfo = to_panel_info(panel); 195 int ret; 196 197 if (pinfo->enabled) 198 return 0; 199 200 usleep_range(120000, 121000); 201 202 ret = mipi_dsi_dcs_set_display_on(pinfo->link); 203 if (ret < 0) { 204 dev_err(panel->dev, "failed to set display on: %d\n", ret); 205 return ret; 206 } 207 208 pinfo->enabled = true; 209 210 return 0; 211 } 212 213 static int boe_panel_get_modes(struct drm_panel *panel, 214 struct drm_connector *connector) 215 { 216 struct panel_info *pinfo = to_panel_info(panel); 217 const struct drm_display_mode *m = pinfo->desc->display_mode; 218 struct drm_display_mode *mode; 219 220 mode = drm_mode_duplicate(connector->dev, m); 221 if (!mode) { 222 dev_err(pinfo->base.dev, "failed to add mode %ux%u@%u\n", 223 m->hdisplay, m->vdisplay, drm_mode_vrefresh(m)); 224 return -ENOMEM; 225 } 226 227 drm_mode_set_name(mode); 228 229 drm_mode_probed_add(connector, mode); 230 231 connector->display_info.width_mm = pinfo->desc->width_mm; 232 connector->display_info.height_mm = pinfo->desc->height_mm; 233 connector->display_info.bpc = pinfo->desc->bpc; 234 235 return 1; 236 } 237 238 static const struct drm_panel_funcs panel_funcs = { 239 .disable = boe_panel_disable, 240 .unprepare = boe_panel_unprepare, 241 .prepare = boe_panel_prepare, 242 .enable = boe_panel_enable, 243 .get_modes = boe_panel_get_modes, 244 }; 245 246 static const struct drm_display_mode default_display_mode = { 247 .clock = 159420, 248 .hdisplay = 1200, 249 .hsync_start = 1200 + 80, 250 .hsync_end = 1200 + 80 + 60, 251 .htotal = 1200 + 80 + 60 + 24, 252 .vdisplay = 1920, 253 .vsync_start = 1920 + 10, 254 .vsync_end = 1920 + 10 + 14, 255 .vtotal = 1920 + 10 + 14 + 4, 256 }; 257 258 /* 8 inch */ 259 static const struct panel_cmd boe_himax8279d8p_on_cmds[] = { 260 { 0xB0, 0x05 }, 261 { 0xB1, 0xE5 }, 262 { 0xB3, 0x52 }, 263 { 0xC0, 0x00 }, 264 { 0xC2, 0x57 }, 265 { 0xD9, 0x85 }, 266 { 0xB0, 0x01 }, 267 { 0xC8, 0x00 }, 268 { 0xC9, 0x00 }, 269 { 0xCC, 0x26 }, 270 { 0xCD, 0x26 }, 271 { 0xDC, 0x00 }, 272 { 0xDD, 0x00 }, 273 { 0xE0, 0x26 }, 274 { 0xE1, 0x26 }, 275 { 0xB0, 0x03 }, 276 { 0xC3, 0x2A }, 277 { 0xE7, 0x2A }, 278 { 0xC5, 0x2A }, 279 { 0xDE, 0x2A }, 280 { 0xBC, 0x02 }, 281 { 0xCB, 0x02 }, 282 { 0xB0, 0x00 }, 283 { 0xB6, 0x03 }, 284 { 0xBA, 0x8B }, 285 { 0xBF, 0x15 }, 286 { 0xC0, 0x18 }, 287 { 0xC2, 0x14 }, 288 { 0xC3, 0x02 }, 289 { 0xC4, 0x14 }, 290 { 0xC5, 0x02 }, 291 { 0xCC, 0x0A }, 292 { 0xB0, 0x06 }, 293 { 0xC0, 0xA5 }, 294 { 0xD5, 0x20 }, 295 { 0xC0, 0x00 }, 296 { 0xB0, 0x02 }, 297 { 0xC0, 0x00 }, 298 { 0xC1, 0x02 }, 299 { 0xC2, 0x06 }, 300 { 0xC3, 0x16 }, 301 { 0xC4, 0x0E }, 302 { 0xC5, 0x18 }, 303 { 0xC6, 0x26 }, 304 { 0xC7, 0x32 }, 305 { 0xC8, 0x3F }, 306 { 0xC9, 0x3F }, 307 { 0xCA, 0x3F }, 308 { 0xCB, 0x3F }, 309 { 0xCC, 0x3D }, 310 { 0xCD, 0x2F }, 311 { 0xCE, 0x2F }, 312 { 0xCF, 0x2F }, 313 { 0xD0, 0x07 }, 314 { 0xD2, 0x00 }, 315 { 0xD3, 0x02 }, 316 { 0xD4, 0x06 }, 317 { 0xD5, 0x12 }, 318 { 0xD6, 0x0A }, 319 { 0xD7, 0x14 }, 320 { 0xD8, 0x22 }, 321 { 0xD9, 0x2E }, 322 { 0xDA, 0x3D }, 323 { 0xDB, 0x3F }, 324 { 0xDC, 0x3F }, 325 { 0xDD, 0x3F }, 326 { 0xDE, 0x3D }, 327 { 0xDF, 0x2F }, 328 { 0xE0, 0x2F }, 329 { 0xE1, 0x2F }, 330 { 0xE2, 0x07 }, 331 { 0xB0, 0x07 }, 332 { 0xB1, 0x18 }, 333 { 0xB2, 0x19 }, 334 { 0xB3, 0x2E }, 335 { 0xB4, 0x52 }, 336 { 0xB5, 0x72 }, 337 { 0xB6, 0x8C }, 338 { 0xB7, 0xBD }, 339 { 0xB8, 0xEB }, 340 { 0xB9, 0x47 }, 341 { 0xBA, 0x96 }, 342 { 0xBB, 0x1E }, 343 { 0xBC, 0x90 }, 344 { 0xBD, 0x93 }, 345 { 0xBE, 0xFA }, 346 { 0xBF, 0x56 }, 347 { 0xC0, 0x8C }, 348 { 0xC1, 0xB7 }, 349 { 0xC2, 0xCC }, 350 { 0xC3, 0xDF }, 351 { 0xC4, 0xE8 }, 352 { 0xC5, 0xF0 }, 353 { 0xC6, 0xF8 }, 354 { 0xC7, 0xFA }, 355 { 0xC8, 0xFC }, 356 { 0xC9, 0x00 }, 357 { 0xCA, 0x00 }, 358 { 0xCB, 0x5A }, 359 { 0xCC, 0xAF }, 360 { 0xCD, 0xFF }, 361 { 0xCE, 0xFF }, 362 { 0xB0, 0x08 }, 363 { 0xB1, 0x04 }, 364 { 0xB2, 0x15 }, 365 { 0xB3, 0x2D }, 366 { 0xB4, 0x51 }, 367 { 0xB5, 0x72 }, 368 { 0xB6, 0x8D }, 369 { 0xB7, 0xBE }, 370 { 0xB8, 0xED }, 371 { 0xB9, 0x4A }, 372 { 0xBA, 0x9A }, 373 { 0xBB, 0x23 }, 374 { 0xBC, 0x95 }, 375 { 0xBD, 0x98 }, 376 { 0xBE, 0xFF }, 377 { 0xBF, 0x59 }, 378 { 0xC0, 0x8E }, 379 { 0xC1, 0xB9 }, 380 { 0xC2, 0xCD }, 381 { 0xC3, 0xDF }, 382 { 0xC4, 0xE8 }, 383 { 0xC5, 0xF0 }, 384 { 0xC6, 0xF8 }, 385 { 0xC7, 0xFA }, 386 { 0xC8, 0xFC }, 387 { 0xC9, 0x00 }, 388 { 0xCA, 0x00 }, 389 { 0xCB, 0x5A }, 390 { 0xCC, 0xAF }, 391 { 0xCD, 0xFF }, 392 { 0xCE, 0xFF }, 393 { 0xB0, 0x09 }, 394 { 0xB1, 0x04 }, 395 { 0xB2, 0x2C }, 396 { 0xB3, 0x36 }, 397 { 0xB4, 0x53 }, 398 { 0xB5, 0x73 }, 399 { 0xB6, 0x8E }, 400 { 0xB7, 0xC0 }, 401 { 0xB8, 0xEF }, 402 { 0xB9, 0x4C }, 403 { 0xBA, 0x9D }, 404 { 0xBB, 0x25 }, 405 { 0xBC, 0x96 }, 406 { 0xBD, 0x9A }, 407 { 0xBE, 0x01 }, 408 { 0xBF, 0x59 }, 409 { 0xC0, 0x8E }, 410 { 0xC1, 0xB9 }, 411 { 0xC2, 0xCD }, 412 { 0xC3, 0xDF }, 413 { 0xC4, 0xE8 }, 414 { 0xC5, 0xF0 }, 415 { 0xC6, 0xF8 }, 416 { 0xC7, 0xFA }, 417 { 0xC8, 0xFC }, 418 { 0xC9, 0x00 }, 419 { 0xCA, 0x00 }, 420 { 0xCB, 0x5A }, 421 { 0xCC, 0xBF }, 422 { 0xCD, 0xFF }, 423 { 0xCE, 0xFF }, 424 { 0xB0, 0x0A }, 425 { 0xB1, 0x18 }, 426 { 0xB2, 0x19 }, 427 { 0xB3, 0x2E }, 428 { 0xB4, 0x52 }, 429 { 0xB5, 0x72 }, 430 { 0xB6, 0x8C }, 431 { 0xB7, 0xBD }, 432 { 0xB8, 0xEB }, 433 { 0xB9, 0x47 }, 434 { 0xBA, 0x96 }, 435 { 0xBB, 0x1E }, 436 { 0xBC, 0x90 }, 437 { 0xBD, 0x93 }, 438 { 0xBE, 0xFA }, 439 { 0xBF, 0x56 }, 440 { 0xC0, 0x8C }, 441 { 0xC1, 0xB7 }, 442 { 0xC2, 0xCC }, 443 { 0xC3, 0xDF }, 444 { 0xC4, 0xE8 }, 445 { 0xC5, 0xF0 }, 446 { 0xC6, 0xF8 }, 447 { 0xC7, 0xFA }, 448 { 0xC8, 0xFC }, 449 { 0xC9, 0x00 }, 450 { 0xCA, 0x00 }, 451 { 0xCB, 0x5A }, 452 { 0xCC, 0xAF }, 453 { 0xCD, 0xFF }, 454 { 0xCE, 0xFF }, 455 { 0xB0, 0x0B }, 456 { 0xB1, 0x04 }, 457 { 0xB2, 0x15 }, 458 { 0xB3, 0x2D }, 459 { 0xB4, 0x51 }, 460 { 0xB5, 0x72 }, 461 { 0xB6, 0x8D }, 462 { 0xB7, 0xBE }, 463 { 0xB8, 0xED }, 464 { 0xB9, 0x4A }, 465 { 0xBA, 0x9A }, 466 { 0xBB, 0x23 }, 467 { 0xBC, 0x95 }, 468 { 0xBD, 0x98 }, 469 { 0xBE, 0xFF }, 470 { 0xBF, 0x59 }, 471 { 0xC0, 0x8E }, 472 { 0xC1, 0xB9 }, 473 { 0xC2, 0xCD }, 474 { 0xC3, 0xDF }, 475 { 0xC4, 0xE8 }, 476 { 0xC5, 0xF0 }, 477 { 0xC6, 0xF8 }, 478 { 0xC7, 0xFA }, 479 { 0xC8, 0xFC }, 480 { 0xC9, 0x00 }, 481 { 0xCA, 0x00 }, 482 { 0xCB, 0x5A }, 483 { 0xCC, 0xAF }, 484 { 0xCD, 0xFF }, 485 { 0xCE, 0xFF }, 486 { 0xB0, 0x0C }, 487 { 0xB1, 0x04 }, 488 { 0xB2, 0x2C }, 489 { 0xB3, 0x36 }, 490 { 0xB4, 0x53 }, 491 { 0xB5, 0x73 }, 492 { 0xB6, 0x8E }, 493 { 0xB7, 0xC0 }, 494 { 0xB8, 0xEF }, 495 { 0xB9, 0x4C }, 496 { 0xBA, 0x9D }, 497 { 0xBB, 0x25 }, 498 { 0xBC, 0x96 }, 499 { 0xBD, 0x9A }, 500 { 0xBE, 0x01 }, 501 { 0xBF, 0x59 }, 502 { 0xC0, 0x8E }, 503 { 0xC1, 0xB9 }, 504 { 0xC2, 0xCD }, 505 { 0xC3, 0xDF }, 506 { 0xC4, 0xE8 }, 507 { 0xC5, 0xF0 }, 508 { 0xC6, 0xF8 }, 509 { 0xC7, 0xFA }, 510 { 0xC8, 0xFC }, 511 { 0xC9, 0x00 }, 512 { 0xCA, 0x00 }, 513 { 0xCB, 0x5A }, 514 { 0xCC, 0xBF }, 515 { 0xCD, 0xFF }, 516 { 0xCE, 0xFF }, 517 { 0xB0, 0x04 }, 518 { 0xB5, 0x02 }, 519 { 0xB6, 0x01 }, 520 }; 521 522 static const struct panel_desc boe_himax8279d8p_panel_desc = { 523 .display_mode = &default_display_mode, 524 .bpc = 8, 525 .width_mm = 107, 526 .height_mm = 172, 527 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | 528 MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM, 529 .format = MIPI_DSI_FMT_RGB888, 530 .lanes = 4, 531 .on_cmds = boe_himax8279d8p_on_cmds, 532 .on_cmds_num = 260, 533 }; 534 535 /* 10 inch */ 536 static const struct panel_cmd boe_himax8279d10p_on_cmds[] = { 537 { 0xB0, 0x05 }, 538 { 0xB1, 0xE5 }, 539 { 0xB3, 0x52 }, 540 { 0xB0, 0x00 }, 541 { 0xB6, 0x03 }, 542 { 0xBA, 0x8B }, 543 { 0xBF, 0x1A }, 544 { 0xC0, 0x0F }, 545 { 0xC2, 0x0C }, 546 { 0xC3, 0x02 }, 547 { 0xC4, 0x0C }, 548 { 0xC5, 0x02 }, 549 { 0xB0, 0x01 }, 550 { 0xE0, 0x26 }, 551 { 0xE1, 0x26 }, 552 { 0xDC, 0x00 }, 553 { 0xDD, 0x00 }, 554 { 0xCC, 0x26 }, 555 { 0xCD, 0x26 }, 556 { 0xC8, 0x00 }, 557 { 0xC9, 0x00 }, 558 { 0xD2, 0x03 }, 559 { 0xD3, 0x03 }, 560 { 0xE6, 0x04 }, 561 { 0xE7, 0x04 }, 562 { 0xC4, 0x09 }, 563 { 0xC5, 0x09 }, 564 { 0xD8, 0x0A }, 565 { 0xD9, 0x0A }, 566 { 0xC2, 0x0B }, 567 { 0xC3, 0x0B }, 568 { 0xD6, 0x0C }, 569 { 0xD7, 0x0C }, 570 { 0xC0, 0x05 }, 571 { 0xC1, 0x05 }, 572 { 0xD4, 0x06 }, 573 { 0xD5, 0x06 }, 574 { 0xCA, 0x07 }, 575 { 0xCB, 0x07 }, 576 { 0xDE, 0x08 }, 577 { 0xDF, 0x08 }, 578 { 0xB0, 0x02 }, 579 { 0xC0, 0x00 }, 580 { 0xC1, 0x0D }, 581 { 0xC2, 0x17 }, 582 { 0xC3, 0x26 }, 583 { 0xC4, 0x31 }, 584 { 0xC5, 0x1C }, 585 { 0xC6, 0x2C }, 586 { 0xC7, 0x33 }, 587 { 0xC8, 0x31 }, 588 { 0xC9, 0x37 }, 589 { 0xCA, 0x37 }, 590 { 0xCB, 0x37 }, 591 { 0xCC, 0x39 }, 592 { 0xCD, 0x2E }, 593 { 0xCE, 0x2F }, 594 { 0xCF, 0x2F }, 595 { 0xD0, 0x07 }, 596 { 0xD2, 0x00 }, 597 { 0xD3, 0x0D }, 598 { 0xD4, 0x17 }, 599 { 0xD5, 0x26 }, 600 { 0xD6, 0x31 }, 601 { 0xD7, 0x3F }, 602 { 0xD8, 0x3F }, 603 { 0xD9, 0x3F }, 604 { 0xDA, 0x3F }, 605 { 0xDB, 0x37 }, 606 { 0xDC, 0x37 }, 607 { 0xDD, 0x37 }, 608 { 0xDE, 0x39 }, 609 { 0xDF, 0x2E }, 610 { 0xE0, 0x2F }, 611 { 0xE1, 0x2F }, 612 { 0xE2, 0x07 }, 613 { 0xB0, 0x03 }, 614 { 0xC8, 0x0B }, 615 { 0xC9, 0x07 }, 616 { 0xC3, 0x00 }, 617 { 0xE7, 0x00 }, 618 { 0xC5, 0x2A }, 619 { 0xDE, 0x2A }, 620 { 0xCA, 0x43 }, 621 { 0xC9, 0x07 }, 622 { 0xE4, 0xC0 }, 623 { 0xE5, 0x0D }, 624 { 0xCB, 0x01 }, 625 { 0xBC, 0x01 }, 626 { 0xB0, 0x06 }, 627 { 0xB8, 0xA5 }, 628 { 0xC0, 0xA5 }, 629 { 0xC7, 0x0F }, 630 { 0xD5, 0x32 }, 631 { 0xB8, 0x00 }, 632 { 0xC0, 0x00 }, 633 { 0xBC, 0x00 }, 634 { 0xB0, 0x07 }, 635 { 0xB1, 0x00 }, 636 { 0xB2, 0x05 }, 637 { 0xB3, 0x10 }, 638 { 0xB4, 0x22 }, 639 { 0xB5, 0x36 }, 640 { 0xB6, 0x4A }, 641 { 0xB7, 0x6C }, 642 { 0xB8, 0x9A }, 643 { 0xB9, 0xD7 }, 644 { 0xBA, 0x17 }, 645 { 0xBB, 0x92 }, 646 { 0xBC, 0x15 }, 647 { 0xBD, 0x18 }, 648 { 0xBE, 0x8C }, 649 { 0xBF, 0x00 }, 650 { 0xC0, 0x3A }, 651 { 0xC1, 0x72 }, 652 { 0xC2, 0x8C }, 653 { 0xC3, 0xA5 }, 654 { 0xC4, 0xB1 }, 655 { 0xC5, 0xBE }, 656 { 0xC6, 0xCA }, 657 { 0xC7, 0xD1 }, 658 { 0xC8, 0xD4 }, 659 { 0xC9, 0x00 }, 660 { 0xCA, 0x00 }, 661 { 0xCB, 0x16 }, 662 { 0xCC, 0xAF }, 663 { 0xCD, 0xFF }, 664 { 0xCE, 0xFF }, 665 { 0xB0, 0x08 }, 666 { 0xB1, 0x04 }, 667 { 0xB2, 0x05 }, 668 { 0xB3, 0x11 }, 669 { 0xB4, 0x24 }, 670 { 0xB5, 0x39 }, 671 { 0xB6, 0x4E }, 672 { 0xB7, 0x72 }, 673 { 0xB8, 0xA3 }, 674 { 0xB9, 0xE1 }, 675 { 0xBA, 0x25 }, 676 { 0xBB, 0xA8 }, 677 { 0xBC, 0x2E }, 678 { 0xBD, 0x32 }, 679 { 0xBE, 0xAD }, 680 { 0xBF, 0x28 }, 681 { 0xC0, 0x63 }, 682 { 0xC1, 0x9B }, 683 { 0xC2, 0xB5 }, 684 { 0xC3, 0xCF }, 685 { 0xC4, 0xDB }, 686 { 0xC5, 0xE8 }, 687 { 0xC6, 0xF5 }, 688 { 0xC7, 0xFA }, 689 { 0xC8, 0xFC }, 690 { 0xC9, 0x00 }, 691 { 0xCA, 0x00 }, 692 { 0xCB, 0x16 }, 693 { 0xCC, 0xAF }, 694 { 0xCD, 0xFF }, 695 { 0xCE, 0xFF }, 696 { 0xB0, 0x09 }, 697 { 0xB1, 0x04 }, 698 { 0xB2, 0x04 }, 699 { 0xB3, 0x0F }, 700 { 0xB4, 0x22 }, 701 { 0xB5, 0x37 }, 702 { 0xB6, 0x4D }, 703 { 0xB7, 0x71 }, 704 { 0xB8, 0xA2 }, 705 { 0xB9, 0xE1 }, 706 { 0xBA, 0x26 }, 707 { 0xBB, 0xA9 }, 708 { 0xBC, 0x2F }, 709 { 0xBD, 0x33 }, 710 { 0xBE, 0xAC }, 711 { 0xBF, 0x24 }, 712 { 0xC0, 0x5D }, 713 { 0xC1, 0x94 }, 714 { 0xC2, 0xAC }, 715 { 0xC3, 0xC5 }, 716 { 0xC4, 0xD1 }, 717 { 0xC5, 0xDC }, 718 { 0xC6, 0xE8 }, 719 { 0xC7, 0xED }, 720 { 0xC8, 0xF0 }, 721 { 0xC9, 0x00 }, 722 { 0xCA, 0x00 }, 723 { 0xCB, 0x16 }, 724 { 0xCC, 0xAF }, 725 { 0xCD, 0xFF }, 726 { 0xCE, 0xFF }, 727 { 0xB0, 0x0A }, 728 { 0xB1, 0x00 }, 729 { 0xB2, 0x05 }, 730 { 0xB3, 0x10 }, 731 { 0xB4, 0x22 }, 732 { 0xB5, 0x36 }, 733 { 0xB6, 0x4A }, 734 { 0xB7, 0x6C }, 735 { 0xB8, 0x9A }, 736 { 0xB9, 0xD7 }, 737 { 0xBA, 0x17 }, 738 { 0xBB, 0x92 }, 739 { 0xBC, 0x15 }, 740 { 0xBD, 0x18 }, 741 { 0xBE, 0x8C }, 742 { 0xBF, 0x00 }, 743 { 0xC0, 0x3A }, 744 { 0xC1, 0x72 }, 745 { 0xC2, 0x8C }, 746 { 0xC3, 0xA5 }, 747 { 0xC4, 0xB1 }, 748 { 0xC5, 0xBE }, 749 { 0xC6, 0xCA }, 750 { 0xC7, 0xD1 }, 751 { 0xC8, 0xD4 }, 752 { 0xC9, 0x00 }, 753 { 0xCA, 0x00 }, 754 { 0xCB, 0x16 }, 755 { 0xCC, 0xAF }, 756 { 0xCD, 0xFF }, 757 { 0xCE, 0xFF }, 758 { 0xB0, 0x0B }, 759 { 0xB1, 0x04 }, 760 { 0xB2, 0x05 }, 761 { 0xB3, 0x11 }, 762 { 0xB4, 0x24 }, 763 { 0xB5, 0x39 }, 764 { 0xB6, 0x4E }, 765 { 0xB7, 0x72 }, 766 { 0xB8, 0xA3 }, 767 { 0xB9, 0xE1 }, 768 { 0xBA, 0x25 }, 769 { 0xBB, 0xA8 }, 770 { 0xBC, 0x2E }, 771 { 0xBD, 0x32 }, 772 { 0xBE, 0xAD }, 773 { 0xBF, 0x28 }, 774 { 0xC0, 0x63 }, 775 { 0xC1, 0x9B }, 776 { 0xC2, 0xB5 }, 777 { 0xC3, 0xCF }, 778 { 0xC4, 0xDB }, 779 { 0xC5, 0xE8 }, 780 { 0xC6, 0xF5 }, 781 { 0xC7, 0xFA }, 782 { 0xC8, 0xFC }, 783 { 0xC9, 0x00 }, 784 { 0xCA, 0x00 }, 785 { 0xCB, 0x16 }, 786 { 0xCC, 0xAF }, 787 { 0xCD, 0xFF }, 788 { 0xCE, 0xFF }, 789 { 0xB0, 0x0C }, 790 { 0xB1, 0x04 }, 791 { 0xB2, 0x04 }, 792 { 0xB3, 0x0F }, 793 { 0xB4, 0x22 }, 794 { 0xB5, 0x37 }, 795 { 0xB6, 0x4D }, 796 { 0xB7, 0x71 }, 797 { 0xB8, 0xA2 }, 798 { 0xB9, 0xE1 }, 799 { 0xBA, 0x26 }, 800 { 0xBB, 0xA9 }, 801 { 0xBC, 0x2F }, 802 { 0xBD, 0x33 }, 803 { 0xBE, 0xAC }, 804 { 0xBF, 0x24 }, 805 { 0xC0, 0x5D }, 806 { 0xC1, 0x94 }, 807 { 0xC2, 0xAC }, 808 { 0xC3, 0xC5 }, 809 { 0xC4, 0xD1 }, 810 { 0xC5, 0xDC }, 811 { 0xC6, 0xE8 }, 812 { 0xC7, 0xED }, 813 { 0xC8, 0xF0 }, 814 { 0xC9, 0x00 }, 815 { 0xCA, 0x00 }, 816 { 0xCB, 0x16 }, 817 { 0xCC, 0xAF }, 818 { 0xCD, 0xFF }, 819 { 0xCE, 0xFF }, 820 }; 821 822 static const struct panel_desc boe_himax8279d10p_panel_desc = { 823 .display_mode = &default_display_mode, 824 .bpc = 8, 825 .width_mm = 135, 826 .height_mm = 216, 827 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | 828 MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM, 829 .format = MIPI_DSI_FMT_RGB888, 830 .lanes = 4, 831 .on_cmds = boe_himax8279d10p_on_cmds, 832 .on_cmds_num = 283, 833 }; 834 835 static const struct of_device_id panel_of_match[] = { 836 { 837 .compatible = "boe,himax8279d8p", 838 .data = &boe_himax8279d8p_panel_desc, 839 }, 840 { 841 .compatible = "boe,himax8279d10p", 842 .data = &boe_himax8279d10p_panel_desc, 843 }, 844 { 845 /* sentinel */ 846 } 847 }; 848 MODULE_DEVICE_TABLE(of, panel_of_match); 849 850 static int panel_add(struct panel_info *pinfo) 851 { 852 struct device *dev = &pinfo->link->dev; 853 int ret; 854 855 pinfo->pp18_gpio = devm_gpiod_get(dev, "pp18", GPIOD_OUT_HIGH); 856 if (IS_ERR(pinfo->pp18_gpio)) { 857 ret = PTR_ERR(pinfo->pp18_gpio); 858 if (ret != -EPROBE_DEFER) 859 dev_err(dev, "failed to get pp18 gpio: %d\n", ret); 860 return ret; 861 } 862 863 pinfo->pp33_gpio = devm_gpiod_get(dev, "pp33", GPIOD_OUT_HIGH); 864 if (IS_ERR(pinfo->pp33_gpio)) { 865 ret = PTR_ERR(pinfo->pp33_gpio); 866 if (ret != -EPROBE_DEFER) 867 dev_err(dev, "failed to get pp33 gpio: %d\n", ret); 868 return ret; 869 } 870 871 pinfo->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH); 872 if (IS_ERR(pinfo->enable_gpio)) { 873 ret = PTR_ERR(pinfo->enable_gpio); 874 if (ret != -EPROBE_DEFER) 875 dev_err(dev, "failed to get enable gpio: %d\n", ret); 876 return ret; 877 } 878 879 drm_panel_init(&pinfo->base, dev, &panel_funcs, 880 DRM_MODE_CONNECTOR_DSI); 881 882 ret = drm_panel_of_backlight(&pinfo->base); 883 if (ret) 884 return ret; 885 886 drm_panel_add(&pinfo->base); 887 888 return 0; 889 } 890 891 static int panel_probe(struct mipi_dsi_device *dsi) 892 { 893 struct panel_info *pinfo; 894 const struct panel_desc *desc; 895 int err; 896 897 pinfo = devm_kzalloc(&dsi->dev, sizeof(*pinfo), GFP_KERNEL); 898 if (!pinfo) 899 return -ENOMEM; 900 901 desc = of_device_get_match_data(&dsi->dev); 902 dsi->mode_flags = desc->mode_flags; 903 dsi->format = desc->format; 904 dsi->lanes = desc->lanes; 905 pinfo->desc = desc; 906 907 pinfo->link = dsi; 908 mipi_dsi_set_drvdata(dsi, pinfo); 909 910 err = panel_add(pinfo); 911 if (err < 0) 912 return err; 913 914 err = mipi_dsi_attach(dsi); 915 if (err < 0) 916 drm_panel_remove(&pinfo->base); 917 918 return err; 919 } 920 921 static void panel_remove(struct mipi_dsi_device *dsi) 922 { 923 struct panel_info *pinfo = mipi_dsi_get_drvdata(dsi); 924 int err; 925 926 err = boe_panel_disable(&pinfo->base); 927 if (err < 0) 928 dev_err(&dsi->dev, "failed to disable panel: %d\n", err); 929 930 err = boe_panel_unprepare(&pinfo->base); 931 if (err < 0) 932 dev_err(&dsi->dev, "failed to unprepare panel: %d\n", err); 933 934 err = mipi_dsi_detach(dsi); 935 if (err < 0) 936 dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err); 937 938 drm_panel_remove(&pinfo->base); 939 } 940 941 static void panel_shutdown(struct mipi_dsi_device *dsi) 942 { 943 struct panel_info *pinfo = mipi_dsi_get_drvdata(dsi); 944 945 boe_panel_disable(&pinfo->base); 946 boe_panel_unprepare(&pinfo->base); 947 } 948 949 static struct mipi_dsi_driver panel_driver = { 950 .driver = { 951 .name = "panel-boe-himax8279d", 952 .of_match_table = panel_of_match, 953 }, 954 .probe = panel_probe, 955 .remove = panel_remove, 956 .shutdown = panel_shutdown, 957 }; 958 module_mipi_dsi_driver(panel_driver); 959 960 MODULE_AUTHOR("Jerry Han <jerry.han.hq@gmail.com>"); 961 MODULE_DESCRIPTION("Boe Himax8279d driver"); 962 MODULE_LICENSE("GPL v2"); 963