1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Driver for panels based on Himax HX8394 controller, such as: 4 * 5 * - HannStar HSD060BHW4 5.99" MIPI-DSI panel 6 * 7 * Copyright (C) 2021 Kamil Trzciński 8 * 9 * Based on drivers/gpu/drm/panel/panel-sitronix-st7703.c 10 * Copyright (C) Purism SPC 2019 11 */ 12 13 #include <linux/delay.h> 14 #include <linux/gpio/consumer.h> 15 #include <linux/media-bus-format.h> 16 #include <linux/mod_devicetable.h> 17 #include <linux/module.h> 18 #include <linux/of.h> 19 #include <linux/regulator/consumer.h> 20 21 #include <video/mipi_display.h> 22 23 #include <drm/drm_mipi_dsi.h> 24 #include <drm/drm_modes.h> 25 #include <drm/drm_panel.h> 26 27 #define DRV_NAME "panel-himax-hx8394" 28 29 /* Manufacturer specific commands sent via DSI, listed in HX8394-F datasheet */ 30 #define HX8394_CMD_SETSEQUENCE 0xb0 31 #define HX8394_CMD_SETPOWER 0xb1 32 #define HX8394_CMD_SETDISP 0xb2 33 #define HX8394_CMD_SETCYC 0xb4 34 #define HX8394_CMD_SETVCOM 0xb6 35 #define HX8394_CMD_SETTE 0xb7 36 #define HX8394_CMD_SETSENSOR 0xb8 37 #define HX8394_CMD_SETEXTC 0xb9 38 #define HX8394_CMD_SETMIPI 0xba 39 #define HX8394_CMD_SETOTP 0xbb 40 #define HX8394_CMD_SETREGBANK 0xbd 41 #define HX8394_CMD_UNKNOWN5 0xbf 42 #define HX8394_CMD_UNKNOWN1 0xc0 43 #define HX8394_CMD_SETDGCLUT 0xc1 44 #define HX8394_CMD_SETID 0xc3 45 #define HX8394_CMD_SETDDB 0xc4 46 #define HX8394_CMD_UNKNOWN2 0xc6 47 #define HX8394_CMD_SETCABC 0xc9 48 #define HX8394_CMD_SETCABCGAIN 0xca 49 #define HX8394_CMD_SETPANEL 0xcc 50 #define HX8394_CMD_SETOFFSET 0xd2 51 #define HX8394_CMD_SETGIP0 0xd3 52 #define HX8394_CMD_UNKNOWN3 0xd4 53 #define HX8394_CMD_SETGIP1 0xd5 54 #define HX8394_CMD_SETGIP2 0xd6 55 #define HX8394_CMD_SETGPO 0xd6 56 #define HX8394_CMD_UNKNOWN4 0xd8 57 #define HX8394_CMD_SETSCALING 0xdd 58 #define HX8394_CMD_SETIDLE 0xdf 59 #define HX8394_CMD_SETGAMMA 0xe0 60 #define HX8394_CMD_SETCHEMODE_DYN 0xe4 61 #define HX8394_CMD_SETCHE 0xe5 62 #define HX8394_CMD_SETCESEL 0xe6 63 #define HX8394_CMD_SET_SP_CMD 0xe9 64 #define HX8394_CMD_SETREADINDEX 0xfe 65 #define HX8394_CMD_GETSPIREAD 0xff 66 67 struct hx8394 { 68 struct device *dev; 69 struct drm_panel panel; 70 struct gpio_desc *reset_gpio; 71 struct regulator *vcc; 72 struct regulator *iovcc; 73 enum drm_panel_orientation orientation; 74 75 const struct hx8394_panel_desc *desc; 76 }; 77 78 struct hx8394_panel_desc { 79 const struct drm_display_mode *mode; 80 unsigned int lanes; 81 unsigned long mode_flags; 82 enum mipi_dsi_pixel_format format; 83 void (*init_sequence)(struct mipi_dsi_multi_context *dsi_ctx); 84 }; 85 86 static inline struct hx8394 *panel_to_hx8394(struct drm_panel *panel) 87 { 88 return container_of(panel, struct hx8394, panel); 89 } 90 91 static void hsd060bhw4_init_sequence(struct mipi_dsi_multi_context *dsi_ctx) 92 { 93 /* 5.19.8 SETEXTC: Set extension command (B9h) */ 94 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETEXTC, 95 0xff, 0x83, 0x94); 96 97 /* 5.19.2 SETPOWER: Set power (B1h) */ 98 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPOWER, 99 0x48, 0x11, 0x71, 0x09, 0x32, 0x24, 0x71, 0x31, 0x55, 0x30); 100 101 /* 5.19.9 SETMIPI: Set MIPI control (BAh) */ 102 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETMIPI, 103 0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0); 104 105 /* 5.19.3 SETDISP: Set display related register (B2h) */ 106 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETDISP, 107 0x00, 0x80, 0x78, 0x0c, 0x07); 108 109 /* 5.19.4 SETCYC: Set display waveform cycles (B4h) */ 110 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETCYC, 111 0x12, 0x63, 0x12, 0x63, 0x12, 0x63, 0x01, 0x0c, 0x7c, 0x55, 112 0x00, 0x3f, 0x12, 0x6b, 0x12, 0x6b, 0x12, 0x6b, 0x01, 0x0c, 113 0x7c); 114 115 /* 5.19.19 SETGIP0: Set GIP Option0 (D3h) */ 116 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP0, 117 0x00, 0x00, 0x00, 0x00, 0x3c, 0x1c, 0x00, 0x00, 0x32, 0x10, 118 0x09, 0x00, 0x09, 0x32, 0x15, 0xad, 0x05, 0xad, 0x32, 0x00, 119 0x00, 0x00, 0x00, 0x37, 0x03, 0x0b, 0x0b, 0x37, 0x00, 0x00, 120 0x00, 0x0c, 0x40); 121 122 /* 5.19.20 Set GIP Option1 (D5h) */ 123 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP1, 124 0x19, 0x19, 0x18, 0x18, 0x1b, 0x1b, 0x1a, 0x1a, 0x00, 0x01, 125 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x20, 0x21, 0x18, 0x18, 126 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 127 0x24, 0x25, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 128 0x18, 0x18, 0x18, 0x18, 0x18, 0x18); 129 130 /* 5.19.21 Set GIP Option2 (D6h) */ 131 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP2, 132 0x18, 0x18, 0x19, 0x19, 0x1b, 0x1b, 0x1a, 0x1a, 0x07, 0x06, 133 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x25, 0x24, 0x18, 0x18, 134 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 135 0x21, 0x20, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 136 0x18, 0x18, 0x18, 0x18, 0x18, 0x18); 137 138 /* 5.19.25 SETGAMMA: Set gamma curve related setting (E0h) */ 139 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGAMMA, 140 0x00, 0x04, 0x0c, 0x12, 0x14, 0x18, 0x1a, 0x18, 0x31, 0x3f, 141 0x4d, 0x4c, 0x54, 0x65, 0x6b, 0x70, 0x7f, 0x82, 0x7e, 0x8a, 142 0x99, 0x4a, 0x48, 0x49, 0x4b, 0x4a, 0x4c, 0x4b, 0x7f, 0x00, 143 0x04, 0x0c, 0x11, 0x13, 0x17, 0x1a, 0x18, 0x31, 144 0x3f, 0x4d, 0x4c, 0x54, 0x65, 0x6b, 0x70, 0x7f, 145 0x82, 0x7e, 0x8a, 0x99, 0x4a, 0x48, 0x49, 0x4b, 146 0x4a, 0x4c, 0x4b, 0x7f); 147 148 /* 5.19.17 SETPANEL (CCh) */ 149 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPANEL, 150 0x0b); 151 152 /* Unknown command, not listed in the HX8394-F datasheet */ 153 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN1, 154 0x1f, 0x31); 155 156 /* 5.19.5 SETVCOM: Set VCOM voltage (B6h) */ 157 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETVCOM, 158 0x7d, 0x7d); 159 160 /* Unknown command, not listed in the HX8394-F datasheet */ 161 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN3, 162 0x02); 163 164 /* 5.19.11 Set register bank (BDh) */ 165 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK, 166 0x01); 167 168 /* 5.19.2 SETPOWER: Set power (B1h) */ 169 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPOWER, 170 0x00); 171 172 /* 5.19.11 Set register bank (BDh) */ 173 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK, 174 0x00); 175 176 /* Unknown command, not listed in the HX8394-F datasheet */ 177 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN3, 178 0xed); 179 } 180 181 static const struct drm_display_mode hsd060bhw4_mode = { 182 .hdisplay = 720, 183 .hsync_start = 720 + 40, 184 .hsync_end = 720 + 40 + 46, 185 .htotal = 720 + 40 + 46 + 40, 186 .vdisplay = 1440, 187 .vsync_start = 1440 + 9, 188 .vsync_end = 1440 + 9 + 7, 189 .vtotal = 1440 + 9 + 7 + 7, 190 .clock = 74250, 191 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, 192 .width_mm = 68, 193 .height_mm = 136, 194 }; 195 196 static const struct hx8394_panel_desc hsd060bhw4_desc = { 197 .mode = &hsd060bhw4_mode, 198 .lanes = 4, 199 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST, 200 .format = MIPI_DSI_FMT_RGB888, 201 .init_sequence = hsd060bhw4_init_sequence, 202 }; 203 204 static void powkiddy_x55_init_sequence(struct mipi_dsi_multi_context *dsi_ctx) 205 { 206 /* 5.19.8 SETEXTC: Set extension command (B9h) */ 207 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETEXTC, 208 0xff, 0x83, 0x94); 209 210 /* 5.19.9 SETMIPI: Set MIPI control (BAh) */ 211 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETMIPI, 212 0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0); 213 214 /* 5.19.2 SETPOWER: Set power (B1h) */ 215 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPOWER, 216 0x48, 0x12, 0x72, 0x09, 0x32, 0x54, 0x71, 0x71, 0x57, 0x47); 217 218 /* 5.19.3 SETDISP: Set display related register (B2h) */ 219 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETDISP, 220 0x00, 0x80, 0x64, 0x2c, 0x16, 0x2f); 221 222 /* 5.19.4 SETCYC: Set display waveform cycles (B4h) */ 223 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETCYC, 224 0x73, 0x74, 0x73, 0x74, 0x73, 0x74, 0x01, 0x0c, 0x86, 0x75, 225 0x00, 0x3f, 0x73, 0x74, 0x73, 0x74, 0x73, 0x74, 0x01, 0x0c, 226 0x86); 227 228 /* 5.19.5 SETVCOM: Set VCOM voltage (B6h) */ 229 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETVCOM, 230 0x6e, 0x6e); 231 232 /* 5.19.19 SETGIP0: Set GIP Option0 (D3h) */ 233 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP0, 234 0x00, 0x00, 0x07, 0x07, 0x40, 0x07, 0x0c, 0x00, 0x08, 0x10, 235 0x08, 0x00, 0x08, 0x54, 0x15, 0x0a, 0x05, 0x0a, 0x02, 0x15, 236 0x06, 0x05, 0x06, 0x47, 0x44, 0x0a, 0x0a, 0x4b, 0x10, 0x07, 237 0x07, 0x0c, 0x40); 238 239 /* 5.19.20 Set GIP Option1 (D5h) */ 240 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP1, 241 0x1c, 0x1c, 0x1d, 0x1d, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 242 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x24, 0x25, 0x18, 0x18, 243 0x26, 0x27, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 244 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x20, 0x21, 245 0x18, 0x18, 0x18, 0x18); 246 247 /* 5.19.21 Set GIP Option2 (D6h) */ 248 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP2, 249 0x1c, 0x1c, 0x1d, 0x1d, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 250 0x01, 0x00, 0x0b, 0x0a, 0x09, 0x08, 0x21, 0x20, 0x18, 0x18, 251 0x27, 0x26, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 252 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x25, 0x24, 253 0x18, 0x18, 0x18, 0x18); 254 255 /* 5.19.25 SETGAMMA: Set gamma curve related setting (E0h) */ 256 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGAMMA, 257 0x00, 0x0a, 0x15, 0x1b, 0x1e, 0x21, 0x24, 0x22, 0x47, 0x56, 258 0x65, 0x66, 0x6e, 0x82, 0x88, 0x8b, 0x9a, 0x9d, 0x98, 0xa8, 259 0xb9, 0x5d, 0x5c, 0x61, 0x66, 0x6a, 0x6f, 0x7f, 0x7f, 0x00, 260 0x0a, 0x15, 0x1b, 0x1e, 0x21, 0x24, 0x22, 0x47, 0x56, 0x65, 261 0x65, 0x6e, 0x81, 0x87, 0x8b, 0x98, 0x9d, 0x99, 0xa8, 0xba, 262 0x5d, 0x5d, 0x62, 0x67, 0x6b, 0x72, 0x7f, 0x7f); 263 264 /* Unknown command, not listed in the HX8394-F datasheet */ 265 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN1, 266 0x1f, 0x31); 267 268 /* 5.19.17 SETPANEL (CCh) */ 269 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPANEL, 270 0x0b); 271 272 /* Unknown command, not listed in the HX8394-F datasheet */ 273 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN3, 274 0x02); 275 276 /* 5.19.11 Set register bank (BDh) */ 277 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK, 278 0x02); 279 280 /* Unknown command, not listed in the HX8394-F datasheet */ 281 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN4, 282 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 283 0xff, 0xff); 284 285 /* 5.19.11 Set register bank (BDh) */ 286 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK, 287 0x00); 288 289 /* 5.19.11 Set register bank (BDh) */ 290 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK, 291 0x01); 292 293 /* 5.19.2 SETPOWER: Set power (B1h) */ 294 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPOWER, 295 0x00); 296 297 /* 5.19.11 Set register bank (BDh) */ 298 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK, 299 0x00); 300 301 /* Unknown command, not listed in the HX8394-F datasheet */ 302 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN5, 303 0x40, 0x81, 0x50, 0x00, 0x1a, 0xfc, 0x01); 304 305 /* Unknown command, not listed in the HX8394-F datasheet */ 306 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN2, 307 0xed); 308 } 309 310 static const struct drm_display_mode powkiddy_x55_mode = { 311 .hdisplay = 720, 312 .hsync_start = 720 + 44, 313 .hsync_end = 720 + 44 + 20, 314 .htotal = 720 + 44 + 20 + 20, 315 .vdisplay = 1280, 316 .vsync_start = 1280 + 12, 317 .vsync_end = 1280 + 12 + 10, 318 .vtotal = 1280 + 12 + 10 + 10, 319 .clock = 63290, 320 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, 321 .width_mm = 67, 322 .height_mm = 121, 323 }; 324 325 static const struct hx8394_panel_desc powkiddy_x55_desc = { 326 .mode = &powkiddy_x55_mode, 327 .lanes = 4, 328 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | 329 MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET, 330 .format = MIPI_DSI_FMT_RGB888, 331 .init_sequence = powkiddy_x55_init_sequence, 332 }; 333 334 static void mchp_ac40t08a_init_sequence(struct mipi_dsi_multi_context *dsi_ctx) 335 { 336 /* DCS commands do not seem to be sent correclty without this delay */ 337 mipi_dsi_msleep(dsi_ctx, 20); 338 339 /* 5.19.8 SETEXTC: Set extension command (B9h) */ 340 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETEXTC, 341 0xff, 0x83, 0x94); 342 343 /* 5.19.9 SETMIPI: Set MIPI control (BAh) */ 344 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETMIPI, 345 0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0); 346 347 /* 5.19.2 SETPOWER: Set power (B1h) */ 348 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPOWER, 349 0x48, 0x12, 0x72, 0x09, 0x32, 0x54, 350 0x71, 0x71, 0x57, 0x47); 351 352 /* 5.19.3 SETDISP: Set display related register (B2h) */ 353 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETDISP, 354 0x00, 0x80, 0x64, 0x0c, 0x0d, 0x2f); 355 356 /* 5.19.4 SETCYC: Set display waveform cycles (B4h) */ 357 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETCYC, 358 0x73, 0x74, 0x73, 0x74, 0x73, 0x74, 359 0x01, 0x0c, 0x86, 0x75, 0x00, 0x3f, 360 0x73, 0x74, 0x73, 0x74, 0x73, 0x74, 361 0x01, 0x0c, 0x86); 362 363 /* 5.19.5 SETVCOM: Set VCOM voltage (B6h) */ 364 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETVCOM, 365 0x6e, 0x6e); 366 367 /* 5.19.19 SETGIP0: Set GIP Option0 (D3h) */ 368 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP0, 369 0x00, 0x00, 0x07, 0x07, 0x40, 0x07, 370 0x0c, 0x00, 0x08, 0x10, 0x08, 0x00, 371 0x08, 0x54, 0x15, 0x0a, 0x05, 0x0a, 372 0x02, 0x15, 0x06, 0x05, 0x06, 0x47, 373 0x44, 0x0a, 0x0a, 0x4b, 0x10, 0x07, 374 0x07, 0x0c, 0x40); 375 376 /* 5.19.20 Set GIP Option1 (D5h) */ 377 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP1, 378 0x1c, 0x1c, 0x1d, 0x1d, 0x00, 0x01, 379 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 380 0x08, 0x09, 0x0a, 0x0b, 0x24, 0x25, 381 0x18, 0x18, 0x26, 0x27, 0x18, 0x18, 382 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 383 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 384 0x18, 0x18, 0x20, 0x21, 0x18, 0x18, 385 0x18, 0x18); 386 387 /* 5.19.21 Set GIP Option2 (D6h) */ 388 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP2, 389 0x1c, 0x1c, 0x1d, 0x1d, 0x07, 0x06, 390 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 391 0x0b, 0x0a, 0x09, 0x08, 0x21, 0x20, 392 0x18, 0x18, 0x27, 0x26, 0x18, 0x18, 393 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 394 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 395 0x18, 0x18, 0x25, 0x24, 0x18, 0x18, 396 0x18, 0x18); 397 398 /* 5.19.25 SETGAMMA: Set gamma curve related setting (E0h) */ 399 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGAMMA, 400 0x00, 0x0a, 0x15, 0x1b, 0x1e, 0x21, 401 0x24, 0x22, 0x47, 0x56, 0x65, 0x66, 402 0x6e, 0x82, 0x88, 0x8b, 0x9a, 0x9d, 403 0x98, 0xa8, 0xb9, 0x5d, 0x5c, 0x61, 404 0x66, 0x6a, 0x6f, 0x7f, 0x7f, 0x00, 405 0x0a, 0x15, 0x1b, 0x1e, 0x21, 0x24, 406 0x22, 0x47, 0x56, 0x65, 0x65, 0x6e, 407 0x81, 0x87, 0x8b, 0x98, 0x9d, 0x99, 408 0xa8, 0xba, 0x5d, 0x5d, 0x62, 0x67, 409 0x6b, 0x72, 0x7f, 0x7f); 410 411 /* Unknown command, not listed in the HX8394-F datasheet (C0H) */ 412 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN1, 413 0x1f, 0x73); 414 415 /* Set CABC control (C9h)*/ 416 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETCABC, 417 0x76, 0x00, 0x30); 418 419 /* 5.19.17 SETPANEL (CCh) */ 420 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPANEL, 421 0x0b); 422 423 /* Unknown command, not listed in the HX8394-F datasheet (D4h) */ 424 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN3, 425 0x02); 426 427 /* 5.19.11 Set register bank (BDh) */ 428 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK, 429 0x02); 430 431 /* 5.19.11 Set register bank (D8h) */ 432 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN4, 433 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 434 0xff, 0xff, 0xff, 0xff, 0xff, 0xff); 435 436 /* 5.19.11 Set register bank (BDh) */ 437 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK, 438 0x00); 439 440 /* 5.19.11 Set register bank (BDh) */ 441 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK, 442 0x01); 443 444 /* 5.19.2 SETPOWER: Set power (B1h) */ 445 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPOWER, 446 0x00); 447 448 /* 5.19.11 Set register bank (BDh) */ 449 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK, 450 0x00); 451 452 /* Unknown command, not listed in the HX8394-F datasheet (C6h) */ 453 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN2, 454 0xed); 455 } 456 457 static const struct drm_display_mode mchp_ac40t08a_mode = { 458 .hdisplay = 720, 459 .hsync_start = 720 + 12, 460 .hsync_end = 720 + 12 + 24, 461 .htotal = 720 + 12 + 12 + 24, 462 .vdisplay = 1280, 463 .vsync_start = 1280 + 13, 464 .vsync_end = 1280 + 14, 465 .vtotal = 1280 + 14 + 13, 466 .clock = 60226, 467 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, 468 .width_mm = 76, 469 .height_mm = 132, 470 }; 471 472 static const struct hx8394_panel_desc mchp_ac40t08a_desc = { 473 .mode = &mchp_ac40t08a_mode, 474 .lanes = 4, 475 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST, 476 .format = MIPI_DSI_FMT_RGB888, 477 .init_sequence = mchp_ac40t08a_init_sequence, 478 }; 479 480 /* 481 * HL055FHAV028C is based on Himax HX8399, so datasheet pages are 482 * slightly different than HX8394 based panels. 483 */ 484 static void hl055fhav028c_init_sequence(struct mipi_dsi_multi_context *dsi_ctx) 485 { 486 /* 6.3.6 SETEXTC: Set extension command (B9h) */ 487 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETEXTC, 488 0xff, 0x83, 0x99); 489 490 /* 6.3.17 SETOFFSET: Set offset voltage (D2h) */ 491 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETOFFSET, 492 0x77); 493 494 /* 6.3.1 SETPOWER: Set power (B1h) */ 495 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPOWER, 496 0x02, 0x04, 0x74, 0x94, 0x01, 0x32, 497 0x33, 0x11, 0x11, 0xab, 0x4d, 0x56, 498 0x73, 0x02, 0x02); 499 500 /* 6.3.2 SETDISP: Set display related register (B2h) */ 501 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETDISP, 502 0x00, 0x80, 0x80, 0xae, 0x05, 0x07, 503 0x5a, 0x11, 0x00, 0x00, 0x10, 0x1e, 504 0x70, 0x03, 0xd4); 505 506 /* 6.3.3 SETCYC: Set display waveform cycles (B4h) */ 507 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETCYC, 508 0x00, 0xff, 0x02, 0xc0, 0x02, 0xc0, 509 0x00, 0x00, 0x08, 0x00, 0x04, 0x06, 510 0x00, 0x32, 0x04, 0x0a, 0x08, 0x21, 511 0x03, 0x01, 0x00, 0x0f, 0xb8, 0x8b, 512 0x02, 0xc0, 0x02, 0xc0, 0x00, 0x00, 513 0x08, 0x00, 0x04, 0x06, 0x00, 0x32, 514 0x04, 0x0a, 0x08, 0x01, 0x00, 0x0f, 515 0xb8, 0x01); 516 517 /* 6.3.18 SETGIP0: Set GIP Option0 (D3h) */ 518 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP0, 519 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 520 0x06, 0x00, 0x00, 0x10, 0x04, 0x00, 521 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 522 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 523 0x00, 0x05, 0x05, 0x07, 0x00, 0x00, 524 0x00, 0x05, 0x40); 525 526 /* 6.3.19 Set GIP Option1 (D5h) */ 527 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP1, 528 0x18, 0x18, 0x19, 0x19, 0x18, 0x18, 529 0x21, 0x20, 0x01, 0x00, 0x07, 0x06, 530 0x05, 0x04, 0x03, 0x02, 0x18, 0x18, 531 0x18, 0x18, 0x18, 0x18, 0x2f, 0x2f, 532 0x30, 0x30, 0x31, 0x31, 0x18, 0x18, 533 0x18, 0x18); 534 535 /* 6.3.20 Set GIP Option2 (D6h) */ 536 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGIP2, 537 0x18, 0x18, 0x19, 0x19, 0x40, 0x40, 538 0x20, 0x21, 0x02, 0x03, 0x04, 0x05, 539 0x06, 0x07, 0x00, 0x01, 0x40, 0x40, 540 0x40, 0x40, 0x40, 0x40, 0x2f, 0x2f, 541 0x30, 0x30, 0x31, 0x31, 0x40, 0x40, 542 0x40, 0x40); 543 544 /* 6.3.21 Set GIP Option3 (D8h) */ 545 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN4, 546 0xa2, 0xaa, 0x02, 0xa0, 0xa2, 0xa8, 547 0x02, 0xa0, 0xb0, 0x00, 0x00, 0x00, 548 0xb0, 0x00, 0x00, 0x00); 549 550 /* 6.3.9 Set register bank (BDh) */ 551 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK, 552 0x01); 553 554 /* 6.3.21 Set GIP Option3 (D8h) */ 555 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN4, 556 0xb0, 0x00, 0x00, 0x00, 0xb0, 0x00, 557 0x00, 0x00, 0xe2, 0xaa, 0x03, 0xf0, 558 0xe2, 0xaa, 0x03, 0xf0); 559 560 /* 6.3.9 Set register bank (BDh) */ 561 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK, 562 0x02); 563 564 /* 6.3.21 Set GIP Option3 (D8h) */ 565 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN4, 566 0xe2, 0xaa, 0x03, 0xf0, 0xe2, 0xaa, 567 0x03, 0xf0); 568 569 /* 6.3.9 Set register bank (BDh) */ 570 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETREGBANK, 571 0x00); 572 573 /* 6.3.4 SETVCOM: Set VCOM voltage (B6h) */ 574 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETVCOM, 575 0x7a, 0x7a); 576 577 /* 6.3.26 SETGAMMA: Set gamma curve related setting (E0h) */ 578 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETGAMMA, 579 0x00, 0x18, 0x27, 0x24, 0x5a, 0x68, 580 0x79, 0x78, 0x81, 0x8a, 0x92, 0x99, 581 0x9e, 0xa7, 0xaf, 0xb4, 0xb9, 0xc3, 582 0xc7, 0xd1, 0xc6, 0xd4, 0xd5, 0x6c, 583 0x67, 0x71, 0x77, 0x00, 0x00, 0x18, 584 0x27, 0x24, 0x5a, 0x68, 0x79, 0x78, 585 0x81, 0x8a, 0x92, 0x99, 0x9e, 0xa7, 586 0xaf, 0xb4, 0xb9, 0xc3, 0xc7, 0xd1, 587 0xc6, 0xd4, 0xd5, 0x6c, 0x67, 0x77); 588 589 /* Unknown command, not listed in the HX8399-C datasheet (C6h) */ 590 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_UNKNOWN2, 591 0xff, 0xf9); 592 593 /* 6.3.16 SETPANEL (CCh) */ 594 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX8394_CMD_SETPANEL, 595 0x08); 596 } 597 598 static const struct drm_display_mode hl055fhav028c_mode = { 599 .hdisplay = 1080, 600 .hsync_start = 1080 + 32, 601 .hsync_end = 1080 + 32 + 8, 602 .htotal = 1080 + 32 + 8 + 32, 603 .vdisplay = 1920, 604 .vsync_start = 1920 + 16, 605 .vsync_end = 1920 + 16 + 2, 606 .vtotal = 1920 + 16 + 2 + 14, 607 .clock = 134920, 608 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, 609 .width_mm = 70, 610 .height_mm = 127, 611 }; 612 613 static const struct hx8394_panel_desc hl055fhav028c_desc = { 614 .mode = &hl055fhav028c_mode, 615 .lanes = 4, 616 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST, 617 .format = MIPI_DSI_FMT_RGB888, 618 .init_sequence = hl055fhav028c_init_sequence, 619 }; 620 621 static int hx8394_enable(struct drm_panel *panel) 622 { 623 struct hx8394 *ctx = panel_to_hx8394(panel); 624 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 625 struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; 626 int ret; 627 628 ctx->desc->init_sequence(&dsi_ctx); 629 630 mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); 631 632 if (dsi_ctx.accum_err) 633 return dsi_ctx.accum_err; 634 /* Panel is operational 120 msec after reset */ 635 msleep(120); 636 637 mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); 638 if (dsi_ctx.accum_err) 639 goto sleep_in; 640 641 return 0; 642 643 sleep_in: 644 ret = dsi_ctx.accum_err; 645 dsi_ctx.accum_err = 0; 646 647 /* This will probably fail, but let's try orderly power off anyway. */ 648 mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); 649 mipi_dsi_msleep(&dsi_ctx, 50); 650 651 return ret; 652 } 653 654 static int hx8394_disable(struct drm_panel *panel) 655 { 656 struct hx8394 *ctx = panel_to_hx8394(panel); 657 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 658 struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; 659 660 mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); 661 mipi_dsi_msleep(&dsi_ctx, 50); /* about 3 frames */ 662 663 return dsi_ctx.accum_err; 664 } 665 666 static int hx8394_unprepare(struct drm_panel *panel) 667 { 668 struct hx8394 *ctx = panel_to_hx8394(panel); 669 670 gpiod_set_value_cansleep(ctx->reset_gpio, 1); 671 672 regulator_disable(ctx->iovcc); 673 regulator_disable(ctx->vcc); 674 675 return 0; 676 } 677 678 static int hx8394_prepare(struct drm_panel *panel) 679 { 680 struct hx8394 *ctx = panel_to_hx8394(panel); 681 int ret; 682 683 gpiod_set_value_cansleep(ctx->reset_gpio, 1); 684 685 ret = regulator_enable(ctx->vcc); 686 if (ret) { 687 dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret); 688 return ret; 689 } 690 691 ret = regulator_enable(ctx->iovcc); 692 if (ret) { 693 dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret); 694 goto disable_vcc; 695 } 696 697 gpiod_set_value_cansleep(ctx->reset_gpio, 0); 698 699 msleep(180); 700 701 return 0; 702 703 disable_vcc: 704 gpiod_set_value_cansleep(ctx->reset_gpio, 1); 705 regulator_disable(ctx->vcc); 706 return ret; 707 } 708 709 static int hx8394_get_modes(struct drm_panel *panel, 710 struct drm_connector *connector) 711 { 712 struct hx8394 *ctx = panel_to_hx8394(panel); 713 struct drm_display_mode *mode; 714 715 mode = drm_mode_duplicate(connector->dev, ctx->desc->mode); 716 if (!mode) { 717 dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n", 718 ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay, 719 drm_mode_vrefresh(ctx->desc->mode)); 720 return -ENOMEM; 721 } 722 723 drm_mode_set_name(mode); 724 725 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; 726 connector->display_info.width_mm = mode->width_mm; 727 connector->display_info.height_mm = mode->height_mm; 728 drm_mode_probed_add(connector, mode); 729 730 return 1; 731 } 732 733 static enum drm_panel_orientation hx8394_get_orientation(struct drm_panel *panel) 734 { 735 struct hx8394 *ctx = panel_to_hx8394(panel); 736 737 return ctx->orientation; 738 } 739 740 static const struct drm_panel_funcs hx8394_drm_funcs = { 741 .disable = hx8394_disable, 742 .unprepare = hx8394_unprepare, 743 .prepare = hx8394_prepare, 744 .enable = hx8394_enable, 745 .get_modes = hx8394_get_modes, 746 .get_orientation = hx8394_get_orientation, 747 }; 748 749 static int hx8394_probe(struct mipi_dsi_device *dsi) 750 { 751 struct device *dev = &dsi->dev; 752 struct hx8394 *ctx; 753 int ret; 754 755 ctx = devm_drm_panel_alloc(dev, struct hx8394, panel, 756 &hx8394_drm_funcs, 757 DRM_MODE_CONNECTOR_DSI); 758 if (IS_ERR(ctx)) 759 return PTR_ERR(ctx); 760 761 ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); 762 if (IS_ERR(ctx->reset_gpio)) 763 return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), 764 "Failed to get reset gpio\n"); 765 766 ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation); 767 if (ret < 0) { 768 dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, ret); 769 return ret; 770 } 771 772 mipi_dsi_set_drvdata(dsi, ctx); 773 774 ctx->dev = dev; 775 ctx->desc = of_device_get_match_data(dev); 776 777 dsi->mode_flags = ctx->desc->mode_flags; 778 dsi->format = ctx->desc->format; 779 dsi->lanes = ctx->desc->lanes; 780 781 ctx->vcc = devm_regulator_get(dev, "vcc"); 782 if (IS_ERR(ctx->vcc)) 783 return dev_err_probe(dev, PTR_ERR(ctx->vcc), 784 "Failed to request vcc regulator\n"); 785 786 ctx->iovcc = devm_regulator_get(dev, "iovcc"); 787 if (IS_ERR(ctx->iovcc)) 788 return dev_err_probe(dev, PTR_ERR(ctx->iovcc), 789 "Failed to request iovcc regulator\n"); 790 791 ret = drm_panel_of_backlight(&ctx->panel); 792 if (ret) 793 return ret; 794 795 drm_panel_add(&ctx->panel); 796 797 ret = mipi_dsi_attach(dsi); 798 if (ret < 0) { 799 dev_err_probe(dev, ret, "mipi_dsi_attach failed\n"); 800 drm_panel_remove(&ctx->panel); 801 return ret; 802 } 803 804 dev_dbg(dev, "%ux%u@%u %ubpp dsi %udl - ready\n", 805 ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay, 806 drm_mode_vrefresh(ctx->desc->mode), 807 mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes); 808 809 return 0; 810 } 811 812 static void hx8394_remove(struct mipi_dsi_device *dsi) 813 { 814 struct hx8394 *ctx = mipi_dsi_get_drvdata(dsi); 815 int ret; 816 817 ret = mipi_dsi_detach(dsi); 818 if (ret < 0) 819 dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); 820 821 drm_panel_remove(&ctx->panel); 822 } 823 824 static const struct of_device_id hx8394_of_match[] = { 825 { .compatible = "hannstar,hsd060bhw4", .data = &hsd060bhw4_desc }, 826 { .compatible = "huiling,hl055fhav028c", .data = &hl055fhav028c_desc }, 827 { .compatible = "powkiddy,x55-panel", .data = &powkiddy_x55_desc }, 828 { .compatible = "microchip,ac40t08a-mipi-panel", .data = &mchp_ac40t08a_desc }, 829 { /* sentinel */ } 830 }; 831 MODULE_DEVICE_TABLE(of, hx8394_of_match); 832 833 static struct mipi_dsi_driver hx8394_driver = { 834 .probe = hx8394_probe, 835 .remove = hx8394_remove, 836 .driver = { 837 .name = DRV_NAME, 838 .of_match_table = hx8394_of_match, 839 }, 840 }; 841 module_mipi_dsi_driver(hx8394_driver); 842 843 MODULE_AUTHOR("Kamil Trzciński <ayufan@ayufan.eu>"); 844 MODULE_DESCRIPTION("DRM driver for Himax HX8394 based MIPI DSI panels"); 845 MODULE_LICENSE("GPL"); 846