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 static int hx8394_enable(struct drm_panel *panel) 481 { 482 struct hx8394 *ctx = panel_to_hx8394(panel); 483 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 484 struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; 485 int ret; 486 487 ctx->desc->init_sequence(&dsi_ctx); 488 489 mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); 490 491 if (dsi_ctx.accum_err) 492 return dsi_ctx.accum_err; 493 /* Panel is operational 120 msec after reset */ 494 msleep(120); 495 496 mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); 497 if (dsi_ctx.accum_err) 498 goto sleep_in; 499 500 return 0; 501 502 sleep_in: 503 ret = dsi_ctx.accum_err; 504 dsi_ctx.accum_err = 0; 505 506 /* This will probably fail, but let's try orderly power off anyway. */ 507 mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); 508 mipi_dsi_msleep(&dsi_ctx, 50); 509 510 return ret; 511 } 512 513 static int hx8394_disable(struct drm_panel *panel) 514 { 515 struct hx8394 *ctx = panel_to_hx8394(panel); 516 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 517 struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; 518 519 mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); 520 mipi_dsi_msleep(&dsi_ctx, 50); /* about 3 frames */ 521 522 return dsi_ctx.accum_err; 523 } 524 525 static int hx8394_unprepare(struct drm_panel *panel) 526 { 527 struct hx8394 *ctx = panel_to_hx8394(panel); 528 529 gpiod_set_value_cansleep(ctx->reset_gpio, 1); 530 531 regulator_disable(ctx->iovcc); 532 regulator_disable(ctx->vcc); 533 534 return 0; 535 } 536 537 static int hx8394_prepare(struct drm_panel *panel) 538 { 539 struct hx8394 *ctx = panel_to_hx8394(panel); 540 int ret; 541 542 gpiod_set_value_cansleep(ctx->reset_gpio, 1); 543 544 ret = regulator_enable(ctx->vcc); 545 if (ret) { 546 dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret); 547 return ret; 548 } 549 550 ret = regulator_enable(ctx->iovcc); 551 if (ret) { 552 dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret); 553 goto disable_vcc; 554 } 555 556 gpiod_set_value_cansleep(ctx->reset_gpio, 0); 557 558 msleep(180); 559 560 return 0; 561 562 disable_vcc: 563 gpiod_set_value_cansleep(ctx->reset_gpio, 1); 564 regulator_disable(ctx->vcc); 565 return ret; 566 } 567 568 static int hx8394_get_modes(struct drm_panel *panel, 569 struct drm_connector *connector) 570 { 571 struct hx8394 *ctx = panel_to_hx8394(panel); 572 struct drm_display_mode *mode; 573 574 mode = drm_mode_duplicate(connector->dev, ctx->desc->mode); 575 if (!mode) { 576 dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n", 577 ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay, 578 drm_mode_vrefresh(ctx->desc->mode)); 579 return -ENOMEM; 580 } 581 582 drm_mode_set_name(mode); 583 584 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; 585 connector->display_info.width_mm = mode->width_mm; 586 connector->display_info.height_mm = mode->height_mm; 587 drm_mode_probed_add(connector, mode); 588 589 return 1; 590 } 591 592 static enum drm_panel_orientation hx8394_get_orientation(struct drm_panel *panel) 593 { 594 struct hx8394 *ctx = panel_to_hx8394(panel); 595 596 return ctx->orientation; 597 } 598 599 static const struct drm_panel_funcs hx8394_drm_funcs = { 600 .disable = hx8394_disable, 601 .unprepare = hx8394_unprepare, 602 .prepare = hx8394_prepare, 603 .enable = hx8394_enable, 604 .get_modes = hx8394_get_modes, 605 .get_orientation = hx8394_get_orientation, 606 }; 607 608 static int hx8394_probe(struct mipi_dsi_device *dsi) 609 { 610 struct device *dev = &dsi->dev; 611 struct hx8394 *ctx; 612 int ret; 613 614 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); 615 if (!ctx) 616 return -ENOMEM; 617 618 ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); 619 if (IS_ERR(ctx->reset_gpio)) 620 return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), 621 "Failed to get reset gpio\n"); 622 623 ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation); 624 if (ret < 0) { 625 dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, ret); 626 return ret; 627 } 628 629 mipi_dsi_set_drvdata(dsi, ctx); 630 631 ctx->dev = dev; 632 ctx->desc = of_device_get_match_data(dev); 633 634 dsi->mode_flags = ctx->desc->mode_flags; 635 dsi->format = ctx->desc->format; 636 dsi->lanes = ctx->desc->lanes; 637 638 ctx->vcc = devm_regulator_get(dev, "vcc"); 639 if (IS_ERR(ctx->vcc)) 640 return dev_err_probe(dev, PTR_ERR(ctx->vcc), 641 "Failed to request vcc regulator\n"); 642 643 ctx->iovcc = devm_regulator_get(dev, "iovcc"); 644 if (IS_ERR(ctx->iovcc)) 645 return dev_err_probe(dev, PTR_ERR(ctx->iovcc), 646 "Failed to request iovcc regulator\n"); 647 648 drm_panel_init(&ctx->panel, dev, &hx8394_drm_funcs, 649 DRM_MODE_CONNECTOR_DSI); 650 651 ret = drm_panel_of_backlight(&ctx->panel); 652 if (ret) 653 return ret; 654 655 drm_panel_add(&ctx->panel); 656 657 ret = mipi_dsi_attach(dsi); 658 if (ret < 0) { 659 dev_err_probe(dev, ret, "mipi_dsi_attach failed\n"); 660 drm_panel_remove(&ctx->panel); 661 return ret; 662 } 663 664 dev_dbg(dev, "%ux%u@%u %ubpp dsi %udl - ready\n", 665 ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay, 666 drm_mode_vrefresh(ctx->desc->mode), 667 mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes); 668 669 return 0; 670 } 671 672 static void hx8394_remove(struct mipi_dsi_device *dsi) 673 { 674 struct hx8394 *ctx = mipi_dsi_get_drvdata(dsi); 675 int ret; 676 677 ret = mipi_dsi_detach(dsi); 678 if (ret < 0) 679 dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); 680 681 drm_panel_remove(&ctx->panel); 682 } 683 684 static const struct of_device_id hx8394_of_match[] = { 685 { .compatible = "hannstar,hsd060bhw4", .data = &hsd060bhw4_desc }, 686 { .compatible = "powkiddy,x55-panel", .data = &powkiddy_x55_desc }, 687 { .compatible = "microchip,ac40t08a-mipi-panel", .data = &mchp_ac40t08a_desc }, 688 { /* sentinel */ } 689 }; 690 MODULE_DEVICE_TABLE(of, hx8394_of_match); 691 692 static struct mipi_dsi_driver hx8394_driver = { 693 .probe = hx8394_probe, 694 .remove = hx8394_remove, 695 .driver = { 696 .name = DRV_NAME, 697 .of_match_table = hx8394_of_match, 698 }, 699 }; 700 module_mipi_dsi_driver(hx8394_driver); 701 702 MODULE_AUTHOR("Kamil Trzciński <ayufan@ayufan.eu>"); 703 MODULE_DESCRIPTION("DRM driver for Himax HX8394 based MIPI DSI panels"); 704 MODULE_LICENSE("GPL"); 705