1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (c) 2018 MediaTek Inc. 4 * Author: Jitao Shi <jitao.shi@mediatek.com> 5 */ 6 7#include <linux/delay.h> 8#include <linux/gpio/consumer.h> 9#include <linux/module.h> 10#include <linux/of.h> 11#include <linux/of_device.h> 12#include <linux/regulator/consumer.h> 13 14#include <drm/drm_connector.h> 15#include <drm/drm_crtc.h> 16#include <drm/drm_mipi_dsi.h> 17#include <drm/drm_panel.h> 18 19#include <video/mipi_display.h> 20 21struct panel_desc { 22 const struct drm_display_mode *modes; 23 unsigned int bpc; 24 25 /** 26 * @width_mm: width of the panel's active display area 27 * @height_mm: height of the panel's active display area 28 */ 29 struct { 30 unsigned int width_mm; 31 unsigned int height_mm; 32 } size; 33 34 unsigned long mode_flags; 35 enum mipi_dsi_pixel_format format; 36 const struct panel_init_cmd *init_cmds; 37 unsigned int lanes; 38 bool discharge_on_disable; 39 bool lp11_before_reset; 40}; 41 42struct boe_panel { 43 struct drm_panel base; 44 struct mipi_dsi_device *dsi; 45 46 const struct panel_desc *desc; 47 48 enum drm_panel_orientation orientation; 49 struct regulator *pp1800; 50 struct regulator *avee; 51 struct regulator *avdd; 52 struct gpio_desc *enable_gpio; 53 54 bool prepared; 55}; 56 57enum dsi_cmd_type { 58 INIT_DCS_CMD, 59 DELAY_CMD, 60}; 61 62struct panel_init_cmd { 63 enum dsi_cmd_type type; 64 size_t len; 65 const char *data; 66}; 67 68#define _INIT_DCS_CMD(...) { \ 69 .type = INIT_DCS_CMD, \ 70 .len = sizeof((char[]){__VA_ARGS__}), \ 71 .data = (char[]){__VA_ARGS__} } 72 73#define _INIT_DELAY_CMD(...) { \ 74 .type = DELAY_CMD,\ 75 .len = sizeof((char[]){__VA_ARGS__}), \ 76 .data = (char[]){__VA_ARGS__} } 77 78static const struct panel_init_cmd boe_init_cmd[] = { 79 _INIT_DELAY_CMD(24), 80 _INIT_DCS_CMD(0xB0, 0x05), 81 _INIT_DCS_CMD(0xB1, 0xE5), 82 _INIT_DCS_CMD(0xB3, 0x52), 83 _INIT_DCS_CMD(0xB0, 0x00), 84 _INIT_DCS_CMD(0xB3, 0x88), 85 _INIT_DCS_CMD(0xB0, 0x04), 86 _INIT_DCS_CMD(0xB8, 0x00), 87 _INIT_DCS_CMD(0xB0, 0x00), 88 _INIT_DCS_CMD(0xB6, 0x03), 89 _INIT_DCS_CMD(0xBA, 0x8B), 90 _INIT_DCS_CMD(0xBF, 0x1A), 91 _INIT_DCS_CMD(0xC0, 0x0F), 92 _INIT_DCS_CMD(0xC2, 0x0C), 93 _INIT_DCS_CMD(0xC3, 0x02), 94 _INIT_DCS_CMD(0xC4, 0x0C), 95 _INIT_DCS_CMD(0xC5, 0x02), 96 _INIT_DCS_CMD(0xB0, 0x01), 97 _INIT_DCS_CMD(0xE0, 0x26), 98 _INIT_DCS_CMD(0xE1, 0x26), 99 _INIT_DCS_CMD(0xDC, 0x00), 100 _INIT_DCS_CMD(0xDD, 0x00), 101 _INIT_DCS_CMD(0xCC, 0x26), 102 _INIT_DCS_CMD(0xCD, 0x26), 103 _INIT_DCS_CMD(0xC8, 0x00), 104 _INIT_DCS_CMD(0xC9, 0x00), 105 _INIT_DCS_CMD(0xD2, 0x03), 106 _INIT_DCS_CMD(0xD3, 0x03), 107 _INIT_DCS_CMD(0xE6, 0x04), 108 _INIT_DCS_CMD(0xE7, 0x04), 109 _INIT_DCS_CMD(0xC4, 0x09), 110 _INIT_DCS_CMD(0xC5, 0x09), 111 _INIT_DCS_CMD(0xD8, 0x0A), 112 _INIT_DCS_CMD(0xD9, 0x0A), 113 _INIT_DCS_CMD(0xC2, 0x0B), 114 _INIT_DCS_CMD(0xC3, 0x0B), 115 _INIT_DCS_CMD(0xD6, 0x0C), 116 _INIT_DCS_CMD(0xD7, 0x0C), 117 _INIT_DCS_CMD(0xC0, 0x05), 118 _INIT_DCS_CMD(0xC1, 0x05), 119 _INIT_DCS_CMD(0xD4, 0x06), 120 _INIT_DCS_CMD(0xD5, 0x06), 121 _INIT_DCS_CMD(0xCA, 0x07), 122 _INIT_DCS_CMD(0xCB, 0x07), 123 _INIT_DCS_CMD(0xDE, 0x08), 124 _INIT_DCS_CMD(0xDF, 0x08), 125 _INIT_DCS_CMD(0xB0, 0x02), 126 _INIT_DCS_CMD(0xC0, 0x00), 127 _INIT_DCS_CMD(0xC1, 0x0D), 128 _INIT_DCS_CMD(0xC2, 0x17), 129 _INIT_DCS_CMD(0xC3, 0x26), 130 _INIT_DCS_CMD(0xC4, 0x31), 131 _INIT_DCS_CMD(0xC5, 0x1C), 132 _INIT_DCS_CMD(0xC6, 0x2C), 133 _INIT_DCS_CMD(0xC7, 0x33), 134 _INIT_DCS_CMD(0xC8, 0x31), 135 _INIT_DCS_CMD(0xC9, 0x37), 136 _INIT_DCS_CMD(0xCA, 0x37), 137 _INIT_DCS_CMD(0xCB, 0x37), 138 _INIT_DCS_CMD(0xCC, 0x39), 139 _INIT_DCS_CMD(0xCD, 0x2E), 140 _INIT_DCS_CMD(0xCE, 0x2F), 141 _INIT_DCS_CMD(0xCF, 0x2F), 142 _INIT_DCS_CMD(0xD0, 0x07), 143 _INIT_DCS_CMD(0xD2, 0x00), 144 _INIT_DCS_CMD(0xD3, 0x0D), 145 _INIT_DCS_CMD(0xD4, 0x17), 146 _INIT_DCS_CMD(0xD5, 0x26), 147 _INIT_DCS_CMD(0xD6, 0x31), 148 _INIT_DCS_CMD(0xD7, 0x3F), 149 _INIT_DCS_CMD(0xD8, 0x3F), 150 _INIT_DCS_CMD(0xD9, 0x3F), 151 _INIT_DCS_CMD(0xDA, 0x3F), 152 _INIT_DCS_CMD(0xDB, 0x37), 153 _INIT_DCS_CMD(0xDC, 0x37), 154 _INIT_DCS_CMD(0xDD, 0x37), 155 _INIT_DCS_CMD(0xDE, 0x39), 156 _INIT_DCS_CMD(0xDF, 0x2E), 157 _INIT_DCS_CMD(0xE0, 0x2F), 158 _INIT_DCS_CMD(0xE1, 0x2F), 159 _INIT_DCS_CMD(0xE2, 0x07), 160 _INIT_DCS_CMD(0xB0, 0x03), 161 _INIT_DCS_CMD(0xC8, 0x0B), 162 _INIT_DCS_CMD(0xC9, 0x07), 163 _INIT_DCS_CMD(0xC3, 0x00), 164 _INIT_DCS_CMD(0xE7, 0x00), 165 _INIT_DCS_CMD(0xC5, 0x2A), 166 _INIT_DCS_CMD(0xDE, 0x2A), 167 _INIT_DCS_CMD(0xCA, 0x43), 168 _INIT_DCS_CMD(0xC9, 0x07), 169 _INIT_DCS_CMD(0xE4, 0xC0), 170 _INIT_DCS_CMD(0xE5, 0x0D), 171 _INIT_DCS_CMD(0xCB, 0x00), 172 _INIT_DCS_CMD(0xB0, 0x06), 173 _INIT_DCS_CMD(0xB8, 0xA5), 174 _INIT_DCS_CMD(0xC0, 0xA5), 175 _INIT_DCS_CMD(0xC7, 0x0F), 176 _INIT_DCS_CMD(0xD5, 0x32), 177 _INIT_DCS_CMD(0xB8, 0x00), 178 _INIT_DCS_CMD(0xC0, 0x00), 179 _INIT_DCS_CMD(0xBC, 0x00), 180 _INIT_DCS_CMD(0xB0, 0x07), 181 _INIT_DCS_CMD(0xB1, 0x00), 182 _INIT_DCS_CMD(0xB2, 0x02), 183 _INIT_DCS_CMD(0xB3, 0x0F), 184 _INIT_DCS_CMD(0xB4, 0x25), 185 _INIT_DCS_CMD(0xB5, 0x39), 186 _INIT_DCS_CMD(0xB6, 0x4E), 187 _INIT_DCS_CMD(0xB7, 0x72), 188 _INIT_DCS_CMD(0xB8, 0x97), 189 _INIT_DCS_CMD(0xB9, 0xDC), 190 _INIT_DCS_CMD(0xBA, 0x22), 191 _INIT_DCS_CMD(0xBB, 0xA4), 192 _INIT_DCS_CMD(0xBC, 0x2B), 193 _INIT_DCS_CMD(0xBD, 0x2F), 194 _INIT_DCS_CMD(0xBE, 0xA9), 195 _INIT_DCS_CMD(0xBF, 0x25), 196 _INIT_DCS_CMD(0xC0, 0x61), 197 _INIT_DCS_CMD(0xC1, 0x97), 198 _INIT_DCS_CMD(0xC2, 0xB2), 199 _INIT_DCS_CMD(0xC3, 0xCD), 200 _INIT_DCS_CMD(0xC4, 0xD9), 201 _INIT_DCS_CMD(0xC5, 0xE7), 202 _INIT_DCS_CMD(0xC6, 0xF4), 203 _INIT_DCS_CMD(0xC7, 0xFA), 204 _INIT_DCS_CMD(0xC8, 0xFC), 205 _INIT_DCS_CMD(0xC9, 0x00), 206 _INIT_DCS_CMD(0xCA, 0x00), 207 _INIT_DCS_CMD(0xCB, 0x16), 208 _INIT_DCS_CMD(0xCC, 0xAF), 209 _INIT_DCS_CMD(0xCD, 0xFF), 210 _INIT_DCS_CMD(0xCE, 0xFF), 211 _INIT_DCS_CMD(0xB0, 0x08), 212 _INIT_DCS_CMD(0xB1, 0x04), 213 _INIT_DCS_CMD(0xB2, 0x05), 214 _INIT_DCS_CMD(0xB3, 0x11), 215 _INIT_DCS_CMD(0xB4, 0x24), 216 _INIT_DCS_CMD(0xB5, 0x39), 217 _INIT_DCS_CMD(0xB6, 0x4F), 218 _INIT_DCS_CMD(0xB7, 0x72), 219 _INIT_DCS_CMD(0xB8, 0x98), 220 _INIT_DCS_CMD(0xB9, 0xDC), 221 _INIT_DCS_CMD(0xBA, 0x23), 222 _INIT_DCS_CMD(0xBB, 0xA6), 223 _INIT_DCS_CMD(0xBC, 0x2C), 224 _INIT_DCS_CMD(0xBD, 0x30), 225 _INIT_DCS_CMD(0xBE, 0xAA), 226 _INIT_DCS_CMD(0xBF, 0x26), 227 _INIT_DCS_CMD(0xC0, 0x62), 228 _INIT_DCS_CMD(0xC1, 0x9B), 229 _INIT_DCS_CMD(0xC2, 0xB5), 230 _INIT_DCS_CMD(0xC3, 0xCF), 231 _INIT_DCS_CMD(0xC4, 0xDB), 232 _INIT_DCS_CMD(0xC5, 0xE8), 233 _INIT_DCS_CMD(0xC6, 0xF5), 234 _INIT_DCS_CMD(0xC7, 0xFA), 235 _INIT_DCS_CMD(0xC8, 0xFC), 236 _INIT_DCS_CMD(0xC9, 0x00), 237 _INIT_DCS_CMD(0xCA, 0x00), 238 _INIT_DCS_CMD(0xCB, 0x16), 239 _INIT_DCS_CMD(0xCC, 0xAF), 240 _INIT_DCS_CMD(0xCD, 0xFF), 241 _INIT_DCS_CMD(0xCE, 0xFF), 242 _INIT_DCS_CMD(0xB0, 0x09), 243 _INIT_DCS_CMD(0xB1, 0x04), 244 _INIT_DCS_CMD(0xB2, 0x02), 245 _INIT_DCS_CMD(0xB3, 0x16), 246 _INIT_DCS_CMD(0xB4, 0x24), 247 _INIT_DCS_CMD(0xB5, 0x3B), 248 _INIT_DCS_CMD(0xB6, 0x4F), 249 _INIT_DCS_CMD(0xB7, 0x73), 250 _INIT_DCS_CMD(0xB8, 0x99), 251 _INIT_DCS_CMD(0xB9, 0xE0), 252 _INIT_DCS_CMD(0xBA, 0x26), 253 _INIT_DCS_CMD(0xBB, 0xAD), 254 _INIT_DCS_CMD(0xBC, 0x36), 255 _INIT_DCS_CMD(0xBD, 0x3A), 256 _INIT_DCS_CMD(0xBE, 0xAE), 257 _INIT_DCS_CMD(0xBF, 0x2A), 258 _INIT_DCS_CMD(0xC0, 0x66), 259 _INIT_DCS_CMD(0xC1, 0x9E), 260 _INIT_DCS_CMD(0xC2, 0xB8), 261 _INIT_DCS_CMD(0xC3, 0xD1), 262 _INIT_DCS_CMD(0xC4, 0xDD), 263 _INIT_DCS_CMD(0xC5, 0xE9), 264 _INIT_DCS_CMD(0xC6, 0xF6), 265 _INIT_DCS_CMD(0xC7, 0xFA), 266 _INIT_DCS_CMD(0xC8, 0xFC), 267 _INIT_DCS_CMD(0xC9, 0x00), 268 _INIT_DCS_CMD(0xCA, 0x00), 269 _INIT_DCS_CMD(0xCB, 0x16), 270 _INIT_DCS_CMD(0xCC, 0xAF), 271 _INIT_DCS_CMD(0xCD, 0xFF), 272 _INIT_DCS_CMD(0xCE, 0xFF), 273 _INIT_DCS_CMD(0xB0, 0x0A), 274 _INIT_DCS_CMD(0xB1, 0x00), 275 _INIT_DCS_CMD(0xB2, 0x02), 276 _INIT_DCS_CMD(0xB3, 0x0F), 277 _INIT_DCS_CMD(0xB4, 0x25), 278 _INIT_DCS_CMD(0xB5, 0x39), 279 _INIT_DCS_CMD(0xB6, 0x4E), 280 _INIT_DCS_CMD(0xB7, 0x72), 281 _INIT_DCS_CMD(0xB8, 0x97), 282 _INIT_DCS_CMD(0xB9, 0xDC), 283 _INIT_DCS_CMD(0xBA, 0x22), 284 _INIT_DCS_CMD(0xBB, 0xA4), 285 _INIT_DCS_CMD(0xBC, 0x2B), 286 _INIT_DCS_CMD(0xBD, 0x2F), 287 _INIT_DCS_CMD(0xBE, 0xA9), 288 _INIT_DCS_CMD(0xBF, 0x25), 289 _INIT_DCS_CMD(0xC0, 0x61), 290 _INIT_DCS_CMD(0xC1, 0x97), 291 _INIT_DCS_CMD(0xC2, 0xB2), 292 _INIT_DCS_CMD(0xC3, 0xCD), 293 _INIT_DCS_CMD(0xC4, 0xD9), 294 _INIT_DCS_CMD(0xC5, 0xE7), 295 _INIT_DCS_CMD(0xC6, 0xF4), 296 _INIT_DCS_CMD(0xC7, 0xFA), 297 _INIT_DCS_CMD(0xC8, 0xFC), 298 _INIT_DCS_CMD(0xC9, 0x00), 299 _INIT_DCS_CMD(0xCA, 0x00), 300 _INIT_DCS_CMD(0xCB, 0x16), 301 _INIT_DCS_CMD(0xCC, 0xAF), 302 _INIT_DCS_CMD(0xCD, 0xFF), 303 _INIT_DCS_CMD(0xCE, 0xFF), 304 _INIT_DCS_CMD(0xB0, 0x0B), 305 _INIT_DCS_CMD(0xB1, 0x04), 306 _INIT_DCS_CMD(0xB2, 0x05), 307 _INIT_DCS_CMD(0xB3, 0x11), 308 _INIT_DCS_CMD(0xB4, 0x24), 309 _INIT_DCS_CMD(0xB5, 0x39), 310 _INIT_DCS_CMD(0xB6, 0x4F), 311 _INIT_DCS_CMD(0xB7, 0x72), 312 _INIT_DCS_CMD(0xB8, 0x98), 313 _INIT_DCS_CMD(0xB9, 0xDC), 314 _INIT_DCS_CMD(0xBA, 0x23), 315 _INIT_DCS_CMD(0xBB, 0xA6), 316 _INIT_DCS_CMD(0xBC, 0x2C), 317 _INIT_DCS_CMD(0xBD, 0x30), 318 _INIT_DCS_CMD(0xBE, 0xAA), 319 _INIT_DCS_CMD(0xBF, 0x26), 320 _INIT_DCS_CMD(0xC0, 0x62), 321 _INIT_DCS_CMD(0xC1, 0x9B), 322 _INIT_DCS_CMD(0xC2, 0xB5), 323 _INIT_DCS_CMD(0xC3, 0xCF), 324 _INIT_DCS_CMD(0xC4, 0xDB), 325 _INIT_DCS_CMD(0xC5, 0xE8), 326 _INIT_DCS_CMD(0xC6, 0xF5), 327 _INIT_DCS_CMD(0xC7, 0xFA), 328 _INIT_DCS_CMD(0xC8, 0xFC), 329 _INIT_DCS_CMD(0xC9, 0x00), 330 _INIT_DCS_CMD(0xCA, 0x00), 331 _INIT_DCS_CMD(0xCB, 0x16), 332 _INIT_DCS_CMD(0xCC, 0xAF), 333 _INIT_DCS_CMD(0xCD, 0xFF), 334 _INIT_DCS_CMD(0xCE, 0xFF), 335 _INIT_DCS_CMD(0xB0, 0x0C), 336 _INIT_DCS_CMD(0xB1, 0x04), 337 _INIT_DCS_CMD(0xB2, 0x02), 338 _INIT_DCS_CMD(0xB3, 0x16), 339 _INIT_DCS_CMD(0xB4, 0x24), 340 _INIT_DCS_CMD(0xB5, 0x3B), 341 _INIT_DCS_CMD(0xB6, 0x4F), 342 _INIT_DCS_CMD(0xB7, 0x73), 343 _INIT_DCS_CMD(0xB8, 0x99), 344 _INIT_DCS_CMD(0xB9, 0xE0), 345 _INIT_DCS_CMD(0xBA, 0x26), 346 _INIT_DCS_CMD(0xBB, 0xAD), 347 _INIT_DCS_CMD(0xBC, 0x36), 348 _INIT_DCS_CMD(0xBD, 0x3A), 349 _INIT_DCS_CMD(0xBE, 0xAE), 350 _INIT_DCS_CMD(0xBF, 0x2A), 351 _INIT_DCS_CMD(0xC0, 0x66), 352 _INIT_DCS_CMD(0xC1, 0x9E), 353 _INIT_DCS_CMD(0xC2, 0xB8), 354 _INIT_DCS_CMD(0xC3, 0xD1), 355 _INIT_DCS_CMD(0xC4, 0xDD), 356 _INIT_DCS_CMD(0xC5, 0xE9), 357 _INIT_DCS_CMD(0xC6, 0xF6), 358 _INIT_DCS_CMD(0xC7, 0xFA), 359 _INIT_DCS_CMD(0xC8, 0xFC), 360 _INIT_DCS_CMD(0xC9, 0x00), 361 _INIT_DCS_CMD(0xCA, 0x00), 362 _INIT_DCS_CMD(0xCB, 0x16), 363 _INIT_DCS_CMD(0xCC, 0xAF), 364 _INIT_DCS_CMD(0xCD, 0xFF), 365 _INIT_DCS_CMD(0xCE, 0xFF), 366 _INIT_DCS_CMD(0xB0, 0x00), 367 _INIT_DCS_CMD(0xB3, 0x08), 368 _INIT_DCS_CMD(0xB0, 0x04), 369 _INIT_DCS_CMD(0xB8, 0x68), 370 _INIT_DELAY_CMD(150), 371 {}, 372}; 373 374static const struct panel_init_cmd auo_kd101n80_45na_init_cmd[] = { 375 _INIT_DELAY_CMD(24), 376 _INIT_DCS_CMD(0x11), 377 _INIT_DELAY_CMD(120), 378 _INIT_DCS_CMD(0x29), 379 _INIT_DELAY_CMD(120), 380 {}, 381}; 382 383static const struct panel_init_cmd auo_b101uan08_3_init_cmd[] = { 384 _INIT_DELAY_CMD(24), 385 _INIT_DCS_CMD(0xB0, 0x01), 386 _INIT_DCS_CMD(0xC0, 0x48), 387 _INIT_DCS_CMD(0xC1, 0x48), 388 _INIT_DCS_CMD(0xC2, 0x47), 389 _INIT_DCS_CMD(0xC3, 0x47), 390 _INIT_DCS_CMD(0xC4, 0x46), 391 _INIT_DCS_CMD(0xC5, 0x46), 392 _INIT_DCS_CMD(0xC6, 0x45), 393 _INIT_DCS_CMD(0xC7, 0x45), 394 _INIT_DCS_CMD(0xC8, 0x64), 395 _INIT_DCS_CMD(0xC9, 0x64), 396 _INIT_DCS_CMD(0xCA, 0x4F), 397 _INIT_DCS_CMD(0xCB, 0x4F), 398 _INIT_DCS_CMD(0xCC, 0x40), 399 _INIT_DCS_CMD(0xCD, 0x40), 400 _INIT_DCS_CMD(0xCE, 0x66), 401 _INIT_DCS_CMD(0xCF, 0x66), 402 _INIT_DCS_CMD(0xD0, 0x4F), 403 _INIT_DCS_CMD(0xD1, 0x4F), 404 _INIT_DCS_CMD(0xD2, 0x41), 405 _INIT_DCS_CMD(0xD3, 0x41), 406 _INIT_DCS_CMD(0xD4, 0x48), 407 _INIT_DCS_CMD(0xD5, 0x48), 408 _INIT_DCS_CMD(0xD6, 0x47), 409 _INIT_DCS_CMD(0xD7, 0x47), 410 _INIT_DCS_CMD(0xD8, 0x46), 411 _INIT_DCS_CMD(0xD9, 0x46), 412 _INIT_DCS_CMD(0xDA, 0x45), 413 _INIT_DCS_CMD(0xDB, 0x45), 414 _INIT_DCS_CMD(0xDC, 0x64), 415 _INIT_DCS_CMD(0xDD, 0x64), 416 _INIT_DCS_CMD(0xDE, 0x4F), 417 _INIT_DCS_CMD(0xDF, 0x4F), 418 _INIT_DCS_CMD(0xE0, 0x40), 419 _INIT_DCS_CMD(0xE1, 0x40), 420 _INIT_DCS_CMD(0xE2, 0x66), 421 _INIT_DCS_CMD(0xE3, 0x66), 422 _INIT_DCS_CMD(0xE4, 0x4F), 423 _INIT_DCS_CMD(0xE5, 0x4F), 424 _INIT_DCS_CMD(0xE6, 0x41), 425 _INIT_DCS_CMD(0xE7, 0x41), 426 _INIT_DELAY_CMD(150), 427 {}, 428}; 429 430static inline struct boe_panel *to_boe_panel(struct drm_panel *panel) 431{ 432 return container_of(panel, struct boe_panel, base); 433} 434 435static int boe_panel_init_dcs_cmd(struct boe_panel *boe) 436{ 437 struct mipi_dsi_device *dsi = boe->dsi; 438 struct drm_panel *panel = &boe->base; 439 int i, err = 0; 440 441 if (boe->desc->init_cmds) { 442 const struct panel_init_cmd *init_cmds = boe->desc->init_cmds; 443 444 for (i = 0; init_cmds[i].len != 0; i++) { 445 const struct panel_init_cmd *cmd = &init_cmds[i]; 446 447 switch (cmd->type) { 448 case DELAY_CMD: 449 msleep(cmd->data[0]); 450 err = 0; 451 break; 452 453 case INIT_DCS_CMD: 454 err = mipi_dsi_dcs_write(dsi, cmd->data[0], 455 cmd->len <= 1 ? NULL : 456 &cmd->data[1], 457 cmd->len - 1); 458 break; 459 460 default: 461 err = -EINVAL; 462 } 463 464 if (err < 0) { 465 dev_err(panel->dev, 466 "failed to write command %u\n", i); 467 return err; 468 } 469 } 470 } 471 return 0; 472} 473 474static int boe_panel_enter_sleep_mode(struct boe_panel *boe) 475{ 476 struct mipi_dsi_device *dsi = boe->dsi; 477 int ret; 478 479 dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; 480 481 ret = mipi_dsi_dcs_set_display_off(dsi); 482 if (ret < 0) 483 return ret; 484 485 ret = mipi_dsi_dcs_enter_sleep_mode(dsi); 486 if (ret < 0) 487 return ret; 488 489 return 0; 490} 491 492static int boe_panel_unprepare(struct drm_panel *panel) 493{ 494 struct boe_panel *boe = to_boe_panel(panel); 495 int ret; 496 497 if (!boe->prepared) 498 return 0; 499 500 ret = boe_panel_enter_sleep_mode(boe); 501 if (ret < 0) { 502 dev_err(panel->dev, "failed to set panel off: %d\n", ret); 503 return ret; 504 } 505 506 msleep(150); 507 508 if (boe->desc->discharge_on_disable) { 509 regulator_disable(boe->avee); 510 regulator_disable(boe->avdd); 511 usleep_range(5000, 7000); 512 gpiod_set_value(boe->enable_gpio, 0); 513 usleep_range(5000, 7000); 514 regulator_disable(boe->pp1800); 515 } else { 516 gpiod_set_value(boe->enable_gpio, 0); 517 usleep_range(500, 1000); 518 regulator_disable(boe->avee); 519 regulator_disable(boe->avdd); 520 usleep_range(5000, 7000); 521 regulator_disable(boe->pp1800); 522 } 523 524 boe->prepared = false; 525 526 return 0; 527} 528 529static int boe_panel_prepare(struct drm_panel *panel) 530{ 531 struct boe_panel *boe = to_boe_panel(panel); 532 int ret; 533 534 if (boe->prepared) 535 return 0; 536 537 gpiod_set_value(boe->enable_gpio, 0); 538 usleep_range(1000, 1500); 539 540 ret = regulator_enable(boe->pp1800); 541 if (ret < 0) 542 return ret; 543 544 usleep_range(3000, 5000); 545 546 ret = regulator_enable(boe->avdd); 547 if (ret < 0) 548 goto poweroff1v8; 549 ret = regulator_enable(boe->avee); 550 if (ret < 0) 551 goto poweroffavdd; 552 553 usleep_range(5000, 10000); 554 555 if (boe->desc->lp11_before_reset) { 556 mipi_dsi_dcs_nop(boe->dsi); 557 usleep_range(1000, 2000); 558 } 559 gpiod_set_value(boe->enable_gpio, 1); 560 usleep_range(1000, 2000); 561 gpiod_set_value(boe->enable_gpio, 0); 562 usleep_range(1000, 2000); 563 gpiod_set_value(boe->enable_gpio, 1); 564 usleep_range(6000, 10000); 565 566 ret = boe_panel_init_dcs_cmd(boe); 567 if (ret < 0) { 568 dev_err(panel->dev, "failed to init panel: %d\n", ret); 569 goto poweroff; 570 } 571 572 boe->prepared = true; 573 574 return 0; 575 576poweroff: 577 regulator_disable(boe->avee); 578poweroffavdd: 579 regulator_disable(boe->avdd); 580poweroff1v8: 581 usleep_range(5000, 7000); 582 regulator_disable(boe->pp1800); 583 gpiod_set_value(boe->enable_gpio, 0); 584 585 return ret; 586} 587 588static int boe_panel_enable(struct drm_panel *panel) 589{ 590 msleep(130); 591 return 0; 592} 593 594static const struct drm_display_mode boe_tv101wum_nl6_default_mode = { 595 .clock = 159425, 596 .hdisplay = 1200, 597 .hsync_start = 1200 + 100, 598 .hsync_end = 1200 + 100 + 40, 599 .htotal = 1200 + 100 + 40 + 24, 600 .vdisplay = 1920, 601 .vsync_start = 1920 + 10, 602 .vsync_end = 1920 + 10 + 14, 603 .vtotal = 1920 + 10 + 14 + 4, 604}; 605 606static const struct panel_desc boe_tv101wum_nl6_desc = { 607 .modes = &boe_tv101wum_nl6_default_mode, 608 .bpc = 8, 609 .size = { 610 .width_mm = 135, 611 .height_mm = 216, 612 }, 613 .lanes = 4, 614 .format = MIPI_DSI_FMT_RGB888, 615 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | 616 MIPI_DSI_MODE_LPM, 617 .init_cmds = boe_init_cmd, 618 .discharge_on_disable = false, 619}; 620 621static const struct drm_display_mode auo_kd101n80_45na_default_mode = { 622 .clock = 157000, 623 .hdisplay = 1200, 624 .hsync_start = 1200 + 60, 625 .hsync_end = 1200 + 60 + 24, 626 .htotal = 1200 + 60 + 24 + 56, 627 .vdisplay = 1920, 628 .vsync_start = 1920 + 16, 629 .vsync_end = 1920 + 16 + 4, 630 .vtotal = 1920 + 16 + 4 + 16, 631}; 632 633static const struct panel_desc auo_kd101n80_45na_desc = { 634 .modes = &auo_kd101n80_45na_default_mode, 635 .bpc = 8, 636 .size = { 637 .width_mm = 135, 638 .height_mm = 216, 639 }, 640 .lanes = 4, 641 .format = MIPI_DSI_FMT_RGB888, 642 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | 643 MIPI_DSI_MODE_LPM, 644 .init_cmds = auo_kd101n80_45na_init_cmd, 645 .discharge_on_disable = true, 646}; 647 648static const struct drm_display_mode boe_tv101wum_n53_default_mode = { 649 .clock = 159916, 650 .hdisplay = 1200, 651 .hsync_start = 1200 + 80, 652 .hsync_end = 1200 + 80 + 24, 653 .htotal = 1200 + 80 + 24 + 60, 654 .vdisplay = 1920, 655 .vsync_start = 1920 + 20, 656 .vsync_end = 1920 + 20 + 4, 657 .vtotal = 1920 + 20 + 4 + 10, 658 .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, 659}; 660 661static const struct panel_desc boe_tv101wum_n53_desc = { 662 .modes = &boe_tv101wum_n53_default_mode, 663 .bpc = 8, 664 .size = { 665 .width_mm = 135, 666 .height_mm = 216, 667 }, 668 .lanes = 4, 669 .format = MIPI_DSI_FMT_RGB888, 670 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | 671 MIPI_DSI_MODE_LPM, 672 .init_cmds = boe_init_cmd, 673}; 674 675static const struct drm_display_mode auo_b101uan08_3_default_mode = { 676 .clock = 159667, 677 .hdisplay = 1200, 678 .hsync_start = 1200 + 60, 679 .hsync_end = 1200 + 60 + 4, 680 .htotal = 1200 + 60 + 4 + 80, 681 .vdisplay = 1920, 682 .vsync_start = 1920 + 34, 683 .vsync_end = 1920 + 34 + 2, 684 .vtotal = 1920 + 34 + 2 + 24, 685 .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, 686}; 687 688static const struct panel_desc auo_b101uan08_3_desc = { 689 .modes = &auo_b101uan08_3_default_mode, 690 .bpc = 8, 691 .size = { 692 .width_mm = 135, 693 .height_mm = 216, 694 }, 695 .lanes = 4, 696 .format = MIPI_DSI_FMT_RGB888, 697 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | 698 MIPI_DSI_MODE_LPM, 699 .init_cmds = auo_b101uan08_3_init_cmd, 700 .lp11_before_reset = true, 701}; 702 703static const struct drm_display_mode boe_tv105wum_nw0_default_mode = { 704 .clock = 159916, 705 .hdisplay = 1200, 706 .hsync_start = 1200 + 80, 707 .hsync_end = 1200 + 80 + 24, 708 .htotal = 1200 + 80 + 24 + 60, 709 .vdisplay = 1920, 710 .vsync_start = 1920 + 20, 711 .vsync_end = 1920 + 20 + 4, 712 .vtotal = 1920 + 20 + 4 + 10, 713 .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, 714}; 715 716static const struct panel_desc boe_tv105wum_nw0_desc = { 717 .modes = &boe_tv105wum_nw0_default_mode, 718 .bpc = 8, 719 .size = { 720 .width_mm = 141, 721 .height_mm = 226, 722 }, 723 .lanes = 4, 724 .format = MIPI_DSI_FMT_RGB888, 725 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | 726 MIPI_DSI_MODE_LPM, 727 .init_cmds = boe_init_cmd, 728 .lp11_before_reset = true, 729}; 730 731static int boe_panel_get_modes(struct drm_panel *panel, 732 struct drm_connector *connector) 733{ 734 struct boe_panel *boe = to_boe_panel(panel); 735 const struct drm_display_mode *m = boe->desc->modes; 736 struct drm_display_mode *mode; 737 738 mode = drm_mode_duplicate(connector->dev, m); 739 if (!mode) { 740 dev_err(panel->dev, "failed to add mode %ux%u@%u\n", 741 m->hdisplay, m->vdisplay, drm_mode_vrefresh(m)); 742 return -ENOMEM; 743 } 744 745 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; 746 drm_mode_set_name(mode); 747 drm_mode_probed_add(connector, mode); 748 749 connector->display_info.width_mm = boe->desc->size.width_mm; 750 connector->display_info.height_mm = boe->desc->size.height_mm; 751 connector->display_info.bpc = boe->desc->bpc; 752 drm_connector_set_panel_orientation(connector, boe->orientation); 753 754 return 1; 755} 756 757static const struct drm_panel_funcs boe_panel_funcs = { 758 .unprepare = boe_panel_unprepare, 759 .prepare = boe_panel_prepare, 760 .enable = boe_panel_enable, 761 .get_modes = boe_panel_get_modes, 762}; 763 764static int boe_panel_add(struct boe_panel *boe) 765{ 766 struct device *dev = &boe->dsi->dev; 767 int err; 768 769 boe->avdd = devm_regulator_get(dev, "avdd"); 770 if (IS_ERR(boe->avdd)) 771 return PTR_ERR(boe->avdd); 772 773 boe->avee = devm_regulator_get(dev, "avee"); 774 if (IS_ERR(boe->avee)) 775 return PTR_ERR(boe->avee); 776 777 boe->pp1800 = devm_regulator_get(dev, "pp1800"); 778 if (IS_ERR(boe->pp1800)) 779 return PTR_ERR(boe->pp1800); 780 781 boe->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); 782 if (IS_ERR(boe->enable_gpio)) { 783 dev_err(dev, "cannot get reset-gpios %ld\n", 784 PTR_ERR(boe->enable_gpio)); 785 return PTR_ERR(boe->enable_gpio); 786 } 787 788 gpiod_set_value(boe->enable_gpio, 0); 789 790 drm_panel_init(&boe->base, dev, &boe_panel_funcs, 791 DRM_MODE_CONNECTOR_DSI); 792 err = of_drm_get_panel_orientation(dev->of_node, &boe->orientation); 793 if (err < 0) { 794 dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, err); 795 return err; 796 } 797 798 err = drm_panel_of_backlight(&boe->base); 799 if (err) 800 return err; 801 802 boe->base.funcs = &boe_panel_funcs; 803 boe->base.dev = &boe->dsi->dev; 804 805 drm_panel_add(&boe->base); 806 807 return 0; 808} 809 810static int boe_panel_probe(struct mipi_dsi_device *dsi) 811{ 812 struct boe_panel *boe; 813 int ret; 814 const struct panel_desc *desc; 815 816 boe = devm_kzalloc(&dsi->dev, sizeof(*boe), GFP_KERNEL); 817 if (!boe) 818 return -ENOMEM; 819 820 desc = of_device_get_match_data(&dsi->dev); 821 dsi->lanes = desc->lanes; 822 dsi->format = desc->format; 823 dsi->mode_flags = desc->mode_flags; 824 boe->desc = desc; 825 boe->dsi = dsi; 826 ret = boe_panel_add(boe); 827 if (ret < 0) 828 return ret; 829 830 mipi_dsi_set_drvdata(dsi, boe); 831 832 ret = mipi_dsi_attach(dsi); 833 if (ret) 834 drm_panel_remove(&boe->base); 835 836 return ret; 837} 838 839static void boe_panel_shutdown(struct mipi_dsi_device *dsi) 840{ 841 struct boe_panel *boe = mipi_dsi_get_drvdata(dsi); 842 843 drm_panel_disable(&boe->base); 844 drm_panel_unprepare(&boe->base); 845} 846 847static int boe_panel_remove(struct mipi_dsi_device *dsi) 848{ 849 struct boe_panel *boe = mipi_dsi_get_drvdata(dsi); 850 int ret; 851 852 boe_panel_shutdown(dsi); 853 854 ret = mipi_dsi_detach(dsi); 855 if (ret < 0) 856 dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret); 857 858 if (boe->base.dev) 859 drm_panel_remove(&boe->base); 860 861 return 0; 862} 863 864static const struct of_device_id boe_of_match[] = { 865 { .compatible = "boe,tv101wum-nl6", 866 .data = &boe_tv101wum_nl6_desc 867 }, 868 { .compatible = "auo,kd101n80-45na", 869 .data = &auo_kd101n80_45na_desc 870 }, 871 { .compatible = "boe,tv101wum-n53", 872 .data = &boe_tv101wum_n53_desc 873 }, 874 { .compatible = "auo,b101uan08.3", 875 .data = &auo_b101uan08_3_desc 876 }, 877 { .compatible = "boe,tv105wum-nw0", 878 .data = &boe_tv105wum_nw0_desc 879 }, 880 { /* sentinel */ } 881}; 882MODULE_DEVICE_TABLE(of, boe_of_match); 883 884static struct mipi_dsi_driver boe_panel_driver = { 885 .driver = { 886 .name = "panel-boe-tv101wum-nl6", 887 .of_match_table = boe_of_match, 888 }, 889 .probe = boe_panel_probe, 890 .remove = boe_panel_remove, 891 .shutdown = boe_panel_shutdown, 892}; 893module_mipi_dsi_driver(boe_panel_driver); 894 895MODULE_AUTHOR("Jitao Shi <jitao.shi@mediatek.com>"); 896MODULE_DESCRIPTION("BOE tv101wum-nl6 1200x1920 video mode panel driver"); 897MODULE_LICENSE("GPL v2"); 898