blob: 1e9768abcc0f1e49c4f17556f78e0238363d9c76 [file] [log] [blame]
Cathy Hsuaaba0cf2024-01-16 10:59:40 +00001// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * MIPI-DSI based ct3e AMOLED LCD panel driver.
4 *
5 * Copyright (c) 2024 Google LLC
6 */
7
8#include <drm/display/drm_dsc_helper.h>
9#include <linux/debugfs.h>
10#include <linux/module.h>
11#include <video/mipi_display.h>
12
13#include "trace/dpu_trace.h"
14#include "panel/panel-samsung-drv.h"
15
16/* DSC1.2 */
17static const struct drm_dsc_config pps_config = {
18 .line_buf_depth = 9,
19 .bits_per_component = 8,
20 .convert_rgb = true,
21 .slice_width = 540,
22 .slice_height = 101,
23 .simple_422 = false,
24 .pic_width = 1080,
25 .pic_height = 2424,
26 .rc_tgt_offset_high = 3,
27 .rc_tgt_offset_low = 3,
28 .bits_per_pixel = 128,
29 .rc_edge_factor = 6,
30 .rc_quant_incr_limit1 = 11,
31 .rc_quant_incr_limit0 = 11,
32 .initial_xmit_delay = 512,
33 .initial_dec_delay = 526,
34 .block_pred_enable = true,
35 .first_line_bpg_offset = 12,
36 .initial_offset = 6144,
37 .rc_buf_thresh = {
38 14, 28, 42, 56,
39 70, 84, 98, 105,
40 112, 119, 121, 123,
41 125, 126
42 },
43 .rc_range_params = {
44 {.range_min_qp = 0, .range_max_qp = 4, .range_bpg_offset = 2},
45 {.range_min_qp = 0, .range_max_qp = 4, .range_bpg_offset = 0},
46 {.range_min_qp = 1, .range_max_qp = 5, .range_bpg_offset = 0},
47 {.range_min_qp = 1, .range_max_qp = 6, .range_bpg_offset = 62},
48 {.range_min_qp = 3, .range_max_qp = 7, .range_bpg_offset = 60},
49 {.range_min_qp = 3, .range_max_qp = 7, .range_bpg_offset = 58},
50 {.range_min_qp = 3, .range_max_qp = 7, .range_bpg_offset = 56},
51 {.range_min_qp = 3, .range_max_qp = 8, .range_bpg_offset = 56},
52 {.range_min_qp = 3, .range_max_qp = 9, .range_bpg_offset = 56},
53 {.range_min_qp = 3, .range_max_qp = 10, .range_bpg_offset = 54},
54 {.range_min_qp = 5, .range_max_qp = 11, .range_bpg_offset = 54},
55 {.range_min_qp = 5, .range_max_qp = 12, .range_bpg_offset = 52},
56 {.range_min_qp = 5, .range_max_qp = 13, .range_bpg_offset = 52},
57 {.range_min_qp = 7, .range_max_qp = 13, .range_bpg_offset = 52},
58 {.range_min_qp = 13, .range_max_qp = 15, .range_bpg_offset = 52}
59 },
60 .rc_model_size = 8192,
61 .flatness_min_qp = 3,
62 .flatness_max_qp = 12,
63 .initial_scale_value = 32,
64 .scale_decrement_interval = 7,
65 .scale_increment_interval = 2517,
66 .nfl_bpg_offset = 246,
67 .slice_bpg_offset = 258,
68 .final_offset = 4336,
69 .vbr_enable = false,
70 .slice_chunk_size = 540,
71 .dsc_version_minor = 2,
72 .dsc_version_major = 1,
73 .native_422 = false,
74 .native_420 = false,
75 .second_line_bpg_offset = 0,
76 .nsl_bpg_offset = 0,
77 .second_line_offset_adj = 0,
78};
79
80
81#define CT3E_WRCTRLD_DIMMING_BIT 0x08
82#define CT3E_WRCTRLD_BCTRL_BIT 0x20
83
84static const u8 test_key_enable[] = { 0xF0, 0x5A, 0x5A };
85static const u8 test_key_disable[] = { 0xF0, 0xA5, 0xA5 };
86static const u8 pixel_off[] = { 0x22 };
87
88static const struct exynos_dsi_cmd ct3e_off_cmds[] = {
89 EXYNOS_DSI_CMD_SEQ_DELAY(MIPI_DCS_SET_DISPLAY_OFF),
90 EXYNOS_DSI_CMD_SEQ_DELAY(120, MIPI_DCS_ENTER_SLEEP_MODE),
91};
92static DEFINE_EXYNOS_CMD_SET(ct3e_off);
93
94static const struct exynos_dsi_cmd ct3e_lp_cmds[] = {
95 EXYNOS_DSI_CMD_SEQ(MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24),
96};
97static DEFINE_EXYNOS_CMD_SET(ct3e_lp);
98
99static const struct exynos_dsi_cmd ct3e_lp_low_cmds[] = {
100 EXYNOS_DSI_CMD_SEQ(MIPI_DCS_SET_DISPLAY_BRIGHTNESS, 0x01, 0x7E),
101};
102
103static const struct exynos_dsi_cmd ct3e_lp_high_cmds[] = {
104 EXYNOS_DSI_CMD_SEQ(MIPI_DCS_SET_DISPLAY_BRIGHTNESS, 0x03, 0x1A),
105};
106
107static const struct exynos_binned_lp ct3e_binned_lp[] = {
108 /* low threshold 40 nits */
109 BINNED_LP_MODE_TIMING("low", 717, ct3e_lp_low_cmds,
110 12, 12 + 50),
111 BINNED_LP_MODE_TIMING("high", 3427, ct3e_lp_high_cmds,
112 12, 12 + 50),
113};
114
115static const struct exynos_dsi_cmd ct3e_init_cmds[] = {
116 /* TE on */
117 EXYNOS_DSI_CMD_SEQ(MIPI_DCS_SET_TEAR_ON),
118
119 /* TE2 setting */
120 EXYNOS_DSI_CMD0(test_key_enable),
121 EXYNOS_DSI_CMD_SEQ(0xB0, 0x00, 0x26, 0xB9),
122 EXYNOS_DSI_CMD_SEQ(0xB9, 0x00, 0x00, 0x10, 0x00, 0x00,
123 0x3D, 0x00, 0x09, 0x90, 0x00, 0x09, 0x90),
Cathy Hsuaaba0cf2024-01-16 10:59:40 +0000124
125 /* CASET: 1080 */
126 EXYNOS_DSI_CMD_SEQ(MIPI_DCS_SET_COLUMN_ADDRESS, 0x00, 0x00, 0x04, 0x37),
127
128 /* PASET: 2424 */
129 EXYNOS_DSI_CMD_SEQ(MIPI_DCS_SET_PAGE_ADDRESS, 0x00, 0x00, 0x09, 0x77),
130
131 /* FFC 865Mbps */
Cathy Hsuaaba0cf2024-01-16 10:59:40 +0000132 EXYNOS_DSI_CMD_SEQ(0xFC, 0x5A, 0x5A),
133 EXYNOS_DSI_CMD_SEQ(0xB0, 0x00, 0x3A, 0xC5),
134 EXYNOS_DSI_CMD_SEQ(0xC5, 0x5E, 0xB5), /* 865Mbps FFC Setting */
135 EXYNOS_DSI_CMD_SEQ(0xB0, 0x00, 0x36, 0xC5),
136 EXYNOS_DSI_CMD_SEQ(0xC5, 0x11, 0x10, 0x50, 0x05),
137 EXYNOS_DSI_CMD_SEQ(0xFC, 0xA5, 0xA5),
Cathy Hsu20957ee2024-01-24 06:19:01 +0000138
139 /* TSP HSYNC setting */
140 EXYNOS_DSI_CMD_SEQ(0xB0, 0x00, 0x42, 0xB9),
141 EXYNOS_DSI_CMD_SEQ(0xB9, 0x19),
142 EXYNOS_DSI_CMD_SEQ(0xB0, 0x00, 0x46, 0xB9),
143 EXYNOS_DSI_CMD_SEQ(0xB9, 0xB0),
Cathy Hsuaaba0cf2024-01-16 10:59:40 +0000144 EXYNOS_DSI_CMD0(test_key_disable),
145};
146static DEFINE_EXYNOS_CMD_SET(ct3e_init);
147
148/**
149 * struct ct3e_panel - panel specific runtime info
150 *
151 * This struct maintains ct3e panel specific runtime info, any fixed details about panel
152 * should most likely go into struct exynos_panel_desc
153 */
154struct ct3e_panel {
155 /** @base: base panel struct */
156 struct exynos_panel base;
157 /**
158 * @is_pixel_off: pixel-off command is sent to panel. Only sending normal-on or resetting
159 * panel can recover to normal mode after entering pixel-off state.
160 */
161 bool is_pixel_off;
162};
163#define to_spanel(ctx) container_of(ctx, struct ct3e_panel, base)
164
165static void ct3e_change_frequency(struct exynos_panel *ctx,
166 const struct exynos_panel_mode *pmode)
167{
168 u32 vrefresh = drm_mode_vrefresh(&pmode->mode);
169
170 if (!ctx || (vrefresh != 60 && vrefresh != 120))
171 return;
172
173 EXYNOS_DCS_BUF_ADD_SET(ctx, test_key_enable);
174 EXYNOS_DCS_BUF_ADD(ctx, 0x83, (vrefresh == 120) ? 0x00 : 0x08);
175 EXYNOS_DCS_BUF_ADD(ctx, 0xF7, 0x2F);
176 EXYNOS_DCS_BUF_ADD_SET_AND_FLUSH(ctx, test_key_disable);
177
178 dev_info(ctx->dev, "%s: change to %uHz\n", __func__, vrefresh);
179 return;
180}
181
182static void ct3e_update_wrctrld(struct exynos_panel *ctx)
183{
184 u8 val = CT3E_WRCTRLD_BCTRL_BIT;
185
186 if (ctx->dimming_on)
187 val |= CT3E_WRCTRLD_DIMMING_BIT;
188
189 dev_dbg(ctx->dev,
190 "%s(wrctrld:0x%x, hbm: %s, dimming: %s\n",
191 __func__, val, IS_HBM_ON(ctx->hbm_mode) ? "on" : "off",
192 ctx->dimming_on ? "on" : "off");
193
194 EXYNOS_DCS_BUF_ADD_AND_FLUSH(ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, val);
195}
196
197static int ct3e_set_brightness(struct exynos_panel *ctx, u16 br)
198{
199 u16 brightness;
200 u32 max_brightness;
201 struct ct3e_panel *spanel = to_spanel(ctx);
202
203 if (ctx->current_mode && ctx->current_mode->exynos_mode.is_lp_mode) {
204 const struct exynos_panel_funcs *funcs;
205
206 /* don't stay at pixel-off state in AOD, or black screen is possibly seen */
207 if (spanel->is_pixel_off) {
208 EXYNOS_DCS_WRITE_SEQ(ctx, MIPI_DCS_ENTER_NORMAL_MODE);
209 spanel->is_pixel_off = false;
210 }
211 funcs = ctx->desc->exynos_panel_func;
212 if (funcs && funcs->set_binned_lp)
213 funcs->set_binned_lp(ctx, br);
214 return 0;
215 }
216
217 /* Use pixel off command instead of setting DBV 0 */
218 if (!br) {
219 if (!spanel->is_pixel_off) {
220 EXYNOS_DCS_WRITE_TABLE(ctx, pixel_off);
221 spanel->is_pixel_off = true;
222 dev_dbg(ctx->dev, "%s: pixel off instead of dbv 0\n", __func__);
223 }
224 return 0;
225 } else if (br && spanel->is_pixel_off) {
226 EXYNOS_DCS_WRITE_SEQ(ctx, MIPI_DCS_ENTER_NORMAL_MODE);
227 spanel->is_pixel_off = false;
228 }
229
230 if (!ctx->desc->brt_capability) {
231 dev_err(ctx->dev, "no available brightness capability\n");
232 return -EINVAL;
233 }
234
235 max_brightness = ctx->desc->brt_capability->hbm.level.max;
236
237 if (br > max_brightness) {
238 br = max_brightness;
239 dev_warn(ctx->dev, "%s: capped to dbv(%d)\n", __func__,
240 max_brightness);
241 }
242
243 brightness = __builtin_bswap16(br);
244
245 return exynos_dcs_set_brightness(ctx, brightness);
246}
247
248static void ct3e_set_hbm_mode(struct exynos_panel *ctx,
249 enum exynos_hbm_mode mode)
250{
251 ctx->hbm_mode = mode;
252
253 EXYNOS_DCS_BUF_ADD_SET(ctx, test_key_enable);
254
255 EXYNOS_DCS_BUF_ADD(ctx, 0xB0, 0x00, 0x01, 0xBD);
256 if (IS_HBM_ON_IRC_OFF(ctx->hbm_mode)) {
257 EXYNOS_DCS_BUF_ADD(ctx, 0xBD, 0x80); /* HBM EM Cyc Set */
258 EXYNOS_DCS_BUF_ADD(ctx, 0xB0, 0x00, 0x2E, 0xBD); /* Global para */
259 EXYNOS_DCS_BUF_ADD(ctx, 0xBD, 0x00, 0x01); /* HBM EM Cyc Set */
260 } else {
261 EXYNOS_DCS_BUF_ADD(ctx, 0xBD, 0x81); /* Normal EM Cyc Set */
262 EXYNOS_DCS_BUF_ADD(ctx, 0xB0, 0x00, 0x2E, 0xBD); /* Global para */
263 EXYNOS_DCS_BUF_ADD(ctx, 0xBD, 0x00, 0x02); /* Normal EM Cyc Set */
264 }
265 EXYNOS_DCS_BUF_ADD(ctx, 0xF7, 0x2F);
266
267 EXYNOS_DCS_BUF_ADD_SET_AND_FLUSH(ctx, test_key_disable);
268
269 dev_info(ctx->dev, "hbm_on=%d hbm_ircoff=%d.\n", IS_HBM_ON(ctx->hbm_mode),
270 IS_HBM_ON_IRC_OFF(ctx->hbm_mode));
271}
272
273static void ct3e_set_dimming_on(struct exynos_panel *exynos_panel,
274 bool dimming_on)
275{
276 const struct exynos_panel_mode *pmode = exynos_panel->current_mode;
277 exynos_panel->dimming_on = dimming_on;
278
279 if (pmode->exynos_mode.is_lp_mode) {
280 dev_warn(exynos_panel->dev, "in lp mode, skip to update\n");
281 return;
282 }
283
284 ct3e_update_wrctrld(exynos_panel);
285}
286
287static void ct3e_mode_set(struct exynos_panel *ctx,
288 const struct exynos_panel_mode *pmode)
289{
290 ct3e_change_frequency(ctx, pmode);
291}
292
293static bool ct3e_is_mode_seamless(const struct exynos_panel *ctx,
294 const struct exynos_panel_mode *pmode)
295{
296 /* seamless mode switch is possible if only changing refresh rate */
297 return drm_mode_equal_no_clocks(&ctx->current_mode->mode, &pmode->mode);
298}
299
300static void ct3e_debugfs_init(struct drm_panel *panel, struct dentry *root)
301{
302 if (IS_ENABLED(CONFIG_DEBUG_FS)) {
303 struct exynos_panel *ctx = container_of(panel, struct exynos_panel, panel);
304 struct dentry *panel_root, *csroot;
305
306 if (!ctx)
307 return;
308
309 panel_root = debugfs_lookup("panel", root);
310 if (!panel_root)
311 return;
312
313 csroot = debugfs_lookup("cmdsets", panel_root);
314 if (!csroot)
315 goto panel_out;
316
317 exynos_panel_debugfs_create_cmdset(ctx, csroot, &ct3e_init_cmd_set, "init");
318
319 dput(csroot);
320
321panel_out:
322 dput(panel_root);
323 }
324}
325
326static void ct3e_get_panel_rev(struct exynos_panel *ctx, u32 id)
327{
328 /* extract command 0xDB */
329 u8 build_code = (id & 0xFF00) >> 8;
330 u8 main = (build_code & 0xE0) >> 3;
331 u8 sub = (build_code & 0x0C) >> 2;
332 u8 rev = main | sub;
333
334 exynos_panel_get_panel_rev(ctx, rev);
335}
336
337static void ct3e_set_lp_mode(struct exynos_panel *ctx,
338 const struct exynos_panel_mode *pmode)
339{
340 exynos_panel_set_lp_mode(ctx, pmode);
341}
342
343static void ct3e_set_nolp_mode(struct exynos_panel *ctx,
344 const struct exynos_panel_mode *pmode)
345{
346 const struct exynos_panel_mode *current_mode = ctx->current_mode;
347 unsigned int vrefresh = current_mode ? drm_mode_vrefresh(&current_mode->mode) : 30;
348 unsigned int te_usec = current_mode ? current_mode->exynos_mode.te_usec : 1109;
349
350 if (!is_panel_active(ctx))
351 return;
352
353 /* AOD Mode Off Setting */
354 EXYNOS_DCS_BUF_ADD_SET(ctx, test_key_enable);
Cathy Hsuaaba0cf2024-01-16 10:59:40 +0000355 EXYNOS_DCS_BUF_ADD(ctx, 0x53, 0x20);
356 EXYNOS_DCS_BUF_ADD_SET_AND_FLUSH(ctx, test_key_disable);
357
358 /* backlight control and dimming */
359 ct3e_update_wrctrld(ctx);
360 ct3e_change_frequency(ctx, pmode);
361
362 DPU_ATRACE_BEGIN("ct3e_wait_one_vblank");
363 exynos_panel_wait_for_vsync_done(ctx, te_usec,
364 EXYNOS_VREFRESH_TO_PERIOD_USEC(vrefresh));
365
366 /* Additional sleep time to account for TE variability */
367 usleep_range(1000, 1010);
368 DPU_ATRACE_END("ct3e_wait_one_vblank");
369
370 dev_info(ctx->dev, "exit LP mode\n");
371}
372
373static int ct3e_enable(struct drm_panel *panel)
374{
375 struct exynos_panel *ctx = container_of(panel, struct exynos_panel, panel);
376 const struct exynos_panel_mode *pmode = ctx->current_mode;
377 struct drm_dsc_picture_parameter_set pps_payload;
378
379 if (!pmode) {
380 dev_err(ctx->dev, "no current mode set\n");
381 return -EINVAL;
382 }
383
384 dev_info(ctx->dev, "%s\n", __func__);
385
386 exynos_panel_reset(ctx);
387
388 /* sleep out */
389 EXYNOS_DCS_WRITE_SEQ_DELAY(ctx, 120, MIPI_DCS_EXIT_SLEEP_MODE);
390
391 /* initial command */
392 exynos_panel_send_cmd_set(ctx, &ct3e_init_cmd_set);
393
394 /* frequency */
395 ct3e_change_frequency(ctx, pmode);
396
397 /* DSC related configuration */
398 exynos_dcs_compression_mode(ctx, 0x1);
399 drm_dsc_pps_payload_pack(&pps_payload, &pps_config);
400 EXYNOS_PPS_WRITE_BUF(ctx, &pps_payload);
401 /* DSC Enable */
402 EXYNOS_DCS_BUF_ADD(ctx, 0xC2, 0x14);
403 EXYNOS_DCS_BUF_ADD(ctx, 0x9D, 0x01);
404
405 /* dimming and HBM */
406 ct3e_update_wrctrld(ctx);
407
408 if (pmode->exynos_mode.is_lp_mode)
409 exynos_panel_set_lp_mode(ctx, pmode);
410
411 /* display on */
412 EXYNOS_DCS_WRITE_SEQ(ctx, MIPI_DCS_SET_DISPLAY_ON);
413
414 return 0;
415}
416
417static int ct3e_panel_probe(struct mipi_dsi_device *dsi)
418{
419 struct ct3e_panel *spanel;
420
421 spanel = devm_kzalloc(&dsi->dev, sizeof(*spanel), GFP_KERNEL);
422 if (!spanel)
423 return -ENOMEM;
424
425 spanel->is_pixel_off = false;
426
427 return exynos_panel_common_init(dsi, &spanel->base);
428}
429
430static const struct exynos_display_underrun_param underrun_param = {
431 .te_idle_us = 500,
432 .te_var = 1,
433};
434
435static const u16 WIDTH_MM = 65, HEIGHT_MM = 146;
436static const u16 HDISPLAY = 1080, VDISPLAY = 2424;
437static const u16 HFP = 44, HSA = 16, HBP = 20;
438static const u16 VFP = 10, VSA = 6, VBP = 10;
439
440#define CT3E_DSC {\
441 .enabled = true,\
442 .dsc_count = 1,\
443 .slice_count = 2,\
444 .slice_height = 101,\
445 .cfg = &pps_config,\
446}
447
448static const struct exynos_panel_mode ct3e_modes[] = {
449 {
450 .mode = {
451 .name = "1080x2424x60",
452 .clock = 170520,
453 .hdisplay = HDISPLAY,
454 .hsync_start = HDISPLAY + HFP,
455 .hsync_end = HDISPLAY + HFP + HSA,
456 .htotal = HDISPLAY + HFP + HSA + HBP,
457 .vdisplay = VDISPLAY,
458 .vsync_start = VDISPLAY + VFP,
459 .vsync_end = VDISPLAY + VFP + VSA,
460 .vtotal = VDISPLAY + VFP + VSA + VBP,
461 .flags = 0,
462 .width_mm = WIDTH_MM,
463 .height_mm = HEIGHT_MM,
464 },
465 .exynos_mode = {
466 .mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS,
467 .vblank_usec = 120,
Cathy Hsu20957ee2024-01-24 06:19:01 +0000468 .te_usec = 8605,
Cathy Hsuaaba0cf2024-01-16 10:59:40 +0000469 .bpc = 8,
470 .dsc = CT3E_DSC,
471 .underrun_param = &underrun_param,
472 },
473 },
474 {
475 .mode = {
476 .name = "1080x2424x120",
477 .clock = 341040,
478 .hdisplay = HDISPLAY,
479 .hsync_start = HDISPLAY + HFP,
480 .hsync_end = HDISPLAY + HFP + HSA,
481 .htotal = HDISPLAY + HFP + HSA + HBP,
482 .vdisplay = VDISPLAY,
483 .vsync_start = VDISPLAY + VFP,
484 .vsync_end = VDISPLAY + VFP + VSA,
485 .vtotal = VDISPLAY + VFP + VSA + VBP,
486 .flags = 0,
487 .width_mm = WIDTH_MM,
488 .height_mm = HEIGHT_MM,
489 },
490 .exynos_mode = {
491 .mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS,
492 .vblank_usec = 120,
Cathy Hsuaaba0cf2024-01-16 10:59:40 +0000493 .te_usec = 276,
494 .bpc = 8,
495 .dsc = CT3E_DSC,
496 .underrun_param = &underrun_param,
497 },
498 },
499};
500
501const struct brightness_capability ct3e_brightness_capability = {
502 .normal = {
503 .nits = {
504 .min = 2,
505 .max = 1200,
506 },
507 .level = {
508 .min = 184,
509 .max = 3427,
510 },
511 .percentage = {
512 .min = 0,
513 .max = 67,
514 },
515 },
516 .hbm = {
517 .nits = {
518 .min = 1200,
519 .max = 1800,
520 },
521 .level = {
522 .min = 3428,
523 .max = 4095,
524 },
525 .percentage = {
526 .min = 67,
527 .max = 100,
528 },
529 },
530};
531
532static const struct exynos_panel_mode ct3e_lp_mode = {
533 .mode = {
534 .name = "1080x2424x30",
535 .clock = 85260,
536 .hdisplay = HDISPLAY,
537 .hsync_start = HDISPLAY + HFP,
538 .hsync_end = HDISPLAY + HFP + HSA,
539 .htotal = HDISPLAY + HFP + HSA + HBP,
540 .vdisplay = VDISPLAY,
541 .vsync_start = VDISPLAY + VFP,
542 .vsync_end = VDISPLAY + VFP + VSA,
543 .vtotal = VDISPLAY + VFP + VSA + VBP,
544 .flags = 0,
545 .width_mm = WIDTH_MM,
546 .height_mm = HEIGHT_MM,
547 },
548 .exynos_mode = {
549 .mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS,
550 .vblank_usec = 120,
551 .te_usec = 1109,
552 .bpc = 8,
553 .dsc = CT3E_DSC,
554 .underrun_param = &underrun_param,
555 .is_lp_mode = true,
556 }
557};
558
559static const struct drm_panel_funcs ct3e_drm_funcs = {
560 .disable = exynos_panel_disable,
561 .unprepare = exynos_panel_unprepare,
562 .prepare = exynos_panel_prepare,
563 .enable = ct3e_enable,
564 .get_modes = exynos_panel_get_modes,
565 .debugfs_init = ct3e_debugfs_init,
566};
567
568static const struct exynos_panel_funcs ct3e_exynos_funcs = {
569 .set_brightness = ct3e_set_brightness,
570 .set_lp_mode = ct3e_set_lp_mode,
571 .set_nolp_mode = ct3e_set_nolp_mode,
572 .set_binned_lp = exynos_panel_set_binned_lp,
573 .set_dimming_on = ct3e_set_dimming_on,
574 .set_hbm_mode = ct3e_set_hbm_mode,
575 .is_mode_seamless = ct3e_is_mode_seamless,
576 .mode_set = ct3e_mode_set,
577 .get_panel_rev = ct3e_get_panel_rev,
578 .read_id = exynos_panel_read_ddic_id,
579};
580
581const struct exynos_panel_desc google_ct3e = {
582 .data_lane_cnt = 4,
583 .max_brightness = 4095,
584 .min_brightness = 2,
585 .dft_brightness = 1290, /* 140 nits */
586 .brt_capability = &ct3e_brightness_capability,
587 /* supported HDR format bitmask : 1(DOLBY_VISION), 2(HDR10), 3(HLG) */
588 .hdr_formats = BIT(2) | BIT(3),
589 .max_luminance = 10000000,
590 .max_avg_luminance = 1200000,
591 .min_luminance = 5,
592 .modes = ct3e_modes,
593 .num_modes = ARRAY_SIZE(ct3e_modes),
594 .off_cmd_set = &ct3e_off_cmd_set,
595 .lp_mode = &ct3e_lp_mode,
596 .lp_cmd_set = &ct3e_lp_cmd_set,
597 .binned_lp = ct3e_binned_lp,
598 .num_binned_lp = ARRAY_SIZE(ct3e_binned_lp),
599 .panel_func = &ct3e_drm_funcs,
600 .exynos_panel_func = &ct3e_exynos_funcs,
derickhong5c1c9d42024-03-06 16:34:41 +0800601 .reset_timing_ms = {-1, 1, 6},
Cathy Hsuaaba0cf2024-01-16 10:59:40 +0000602 .reg_ctrl_enable = {
603 {PANEL_REG_ID_VDDI, 0},
derickhong5c1c9d42024-03-06 16:34:41 +0800604 {PANEL_REG_ID_VCI, 2},
Cathy Hsuaaba0cf2024-01-16 10:59:40 +0000605 },
606 .reg_ctrl_post_enable = {
607 {PANEL_REG_ID_VDDD, 5},
608 },
609 .reg_ctrl_pre_disable = {
610 {PANEL_REG_ID_VDDD, 0},
611 },
612 .reg_ctrl_disable = {
613 {PANEL_REG_ID_VCI, 0},
614 {PANEL_REG_ID_VDDI, 0},
615 },
616};
617
618static const struct of_device_id exynos_panel_of_match[] = {
619 { .compatible = "google,ct3e", .data = &google_ct3e },
620 { }
621};
622MODULE_DEVICE_TABLE(of, exynos_panel_of_match);
623
624static struct mipi_dsi_driver exynos_panel_driver = {
625 .probe = ct3e_panel_probe,
626 .remove = exynos_panel_remove,
627 .driver = {
628 .name = "panel-google-ct3e",
629 .of_match_table = exynos_panel_of_match,
630 },
631};
632module_mipi_dsi_driver(exynos_panel_driver);
633
634MODULE_AUTHOR("Cathy Hsu <cathsu@google.com>");
635MODULE_DESCRIPTION("MIPI-DSI based Google ct3e panel driver");
636MODULE_LICENSE("GPL");