1 #include <linux/ctype.h>
2 #include <linux/string.h>
3 #include <linux/display-sys.h>
4 #include <linux/interrupt.h>
5 #include <linux/moduleparam.h>
6 #include "rockchip-hdmi.h"
9 module_param(hdmi_dbg_level, int, S_IRUGO | S_IWUSR);
11 static int hdmi_get_enable(struct rk_display_device *device)
13 struct hdmi *hdmi = device->priv_data;
16 enable = hdmi->enable;
20 static int hdmi_set_enable(struct rk_display_device *device, int enable)
22 struct hdmi *hdmi = device->priv_data;
25 hdmi_submit_work(hdmi, HDMI_DISABLE_CTL, 0, 0);
27 hdmi_submit_work(hdmi, HDMI_ENABLE_CTL, 0, 0);
31 static int hdmi_get_status(struct rk_display_device *device)
33 struct hdmi *hdmi = device->priv_data;
35 if (hdmi->hotplug == HDMI_HPD_ACTIVED)
41 static int hdmi_get_modelist(struct rk_display_device *device,
42 struct list_head **modelist)
44 struct hdmi *hdmi = device->priv_data;
46 *modelist = &hdmi->edid.modelist;
50 static int hdmi_set_mode(struct rk_display_device *device,
51 struct fb_videomode *mode)
53 struct hdmi *hdmi = device->priv_data;
54 struct display_modelist *display_modelist =
55 container_of(mode, struct display_modelist, mode);
60 vic = hdmi_find_best_mode(hdmi, 0);
63 vic = display_modelist->vic;
66 if (vic && hdmi->vic != vic) {
68 if (hdmi->hotplug == HDMI_HPD_ACTIVED)
69 hdmi_submit_work(hdmi, HDMI_SET_VIDEO, 0, 0);
74 static int hdmi_get_mode(struct rk_display_device *device,
75 struct fb_videomode *mode)
77 struct hdmi *hdmi = device->priv_data;
78 struct fb_videomode *vmode;
84 vmode = (struct fb_videomode *)
85 hdmi_vic_to_videomode(hdmi->vic);
89 if (hdmi->vic & HDMI_VIDEO_YUV420)
92 memset(mode, 0, sizeof(struct fb_videomode));
97 static int hdmi_set_3dmode(struct rk_display_device *device, int mode)
99 struct hdmi *hdmi = device->priv_data;
100 struct list_head *modelist, *pos;
101 struct display_modelist *display_modelist = NULL;
106 modelist = &hdmi->edid.modelist;
107 list_for_each(pos, modelist) {
109 list_entry(pos, struct display_modelist, list);
110 if (hdmi->vic != display_modelist->vic)
111 display_modelist = NULL;
115 if (!display_modelist)
118 if ((mode != HDMI_3D_NONE) &&
119 ((display_modelist->format_3d & (1 << mode)) == 0))
120 pr_warn("warning: sink not support input 3d mode %d", mode);
122 if (hdmi->mode_3d != mode) {
123 hdmi->mode_3d = mode;
124 if (hdmi->hotplug == HDMI_HPD_ACTIVED)
125 hdmi_submit_work(hdmi, HDMI_SET_3D, 0, 0);
130 static int hdmi_get_3dmode(struct rk_display_device *device)
132 struct hdmi *hdmi = device->priv_data;
137 return hdmi->mode_3d;
140 /* CEA 861-E: Audio Coding Type
141 * sync width enum hdmi_audio_type
143 static const char * const audioformatstr[] = {
145 "LPCM", /*HDMI_AUDIO_LPCM = 1,*/
146 "AC3", /*HDMI_AUDIO_AC3,*/
147 "MPEG1", /*HDMI_AUDIO_MPEG1,*/
148 "MP3", /*HDMI_AUDIO_MP3,*/
149 "MPEG2", /*HDMI_AUDIO_MPEG2,*/
150 "AAC-LC", /*HDMI_AUDIO_AAC_LC, AAC*/
151 "DTS", /*HDMI_AUDIO_DTS,*/
152 "ATARC", /*HDMI_AUDIO_ATARC,*/
153 "DSD", /*HDMI_AUDIO_DSD, One bit Audio */
154 "E-AC3", /*HDMI_AUDIO_E_AC3,*/
155 "DTS-HD", /*HDMI_AUDIO_DTS_HD,*/
156 "MLP", /*HDMI_AUDIO_MLP,*/
157 "DST", /*HDMI_AUDIO_DST,*/
158 "WMA-PRO", /*HDMI_AUDIO_WMA_PRO*/
161 static int hdmi_get_edidaudioinfo(struct rk_display_device *device,
162 char *audioinfo, int len)
164 struct hdmi *hdmi = device->priv_data;
166 struct hdmi_audio *audio;
171 memset(audioinfo, 0x00, len);
172 /*printk("hdmi:edid: audio_num: %d\n", hdmi->edid.audio_num);*/
173 for (i = 0; i < hdmi->edid.audio_num; i++) {
174 audio = &hdmi->edid.audio[i];
175 if (audio->type < 1 || audio->type > HDMI_AUDIO_WMA_PRO) {
176 pr_info("audio type: unsupported.");
179 size = strlen(audioformatstr[audio->type]);
180 memcpy(audioinfo, audioformatstr[audio->type], size);
181 audioinfo[size] = ',';
182 audioinfo += (size + 1);
187 static int hdmi_get_color(struct rk_display_device *device, char *buf)
189 struct hdmi *hdmi = device->priv_data;
192 mode = (1 << HDMI_COLOR_RGB_0_255);
193 if (hdmi->edid.sink_hdmi) {
194 mode |= (1 << HDMI_COLOR_RGB_16_235);
195 if (hdmi->edid.ycbcr422)
196 mode |= (1 << HDMI_COLOR_YCBCR422);
197 if (hdmi->edid.ycbcr444)
198 mode |= (1 << HDMI_COLOR_YCBCR444);
200 i = snprintf(buf, PAGE_SIZE,
201 "Supported Color Mode: %d\n", mode);
202 i += snprintf(buf + i, PAGE_SIZE - i,
203 "Current Color Mode: %d\n", hdmi->video.color_output);
205 mode = (1 << 1); /* 24 bit*/
206 if (hdmi->edid.deepcolor & HDMI_DEEP_COLOR_30BITS &&
207 hdmi->property->feature & SUPPORT_DEEP_10BIT)
208 mode |= (1 << HDMI_DEEP_COLOR_30BITS);
209 if (hdmi->edid.deepcolor & HDMI_DEEP_COLOR_36BITS &&
210 hdmi->property->feature & SUPPORT_DEEP_12BIT)
211 mode |= (1 << HDMI_DEEP_COLOR_36BITS);
212 if (hdmi->edid.deepcolor & HDMI_DEEP_COLOR_48BITS &&
213 hdmi->property->feature & SUPPORT_DEEP_16BIT)
214 mode |= (1 << HDMI_DEEP_COLOR_48BITS);
215 i += snprintf(buf + i, PAGE_SIZE - i,
216 "Supported Color Depth: %d\n", mode);
217 i += snprintf(buf + i, PAGE_SIZE - i,
218 "Current Color Depth: %d\n",
219 hdmi->video.color_output_depth);
220 i += snprintf(buf + i, PAGE_SIZE - i,
221 "Supported Colorimetry: %d\n", hdmi->edid.colorimetry);
222 i += snprintf(buf + i, PAGE_SIZE - i,
223 "Current Colorimetry: %d\n", hdmi->colorimetry);
224 i += snprintf(buf + i, PAGE_SIZE - i,
225 "Supported EOTF: 0x%x\n", hdmi->edid.hdr.hdrinfo.eotf);
226 i += snprintf(buf + i, PAGE_SIZE - i,
227 "Current EOTF: 0x%x\n", hdmi->eotf);
231 static int hdmi_set_color(struct rk_display_device *device,
232 const char *buf, int len)
234 struct hdmi *hdmi = device->priv_data;
237 if (!strncmp(buf, "mode", 4)) {
238 if (sscanf(buf, "mode=%d", &value) == -1)
240 pr_debug("current mode is %d input mode is %d\n",
241 hdmi->colormode, value);
242 if (hdmi->colormode != value)
243 hdmi->colormode = value;
244 } else if (!strncmp(buf, "depth", 5)) {
245 if (sscanf(buf, "depth=%d", &value) == -1)
247 pr_debug("current depth is %d input mode is %d\n",
248 hdmi->colordepth, value);
249 if (hdmi->colordepth != value)
250 hdmi->colordepth = value;
251 } else if (!strncmp(buf, "colorimetry", 11)) {
252 if (sscanf(buf, "colorimetry=%d", &value) == -1)
254 pr_debug("current colorimetry is %d input colorimetry is %d\n",
255 hdmi->colorimetry, value);
256 if (hdmi->colorimetry != value)
257 hdmi->colorimetry = value;
258 } else if (!strncmp(buf, "hdr", 3)) {
259 if (sscanf(buf, "hdr=%d", &value) == -1)
261 pr_info("current hdr eotf is %d input hdr eotf is %d\n",
263 if (hdmi->eotf != value &&
264 (value & hdmi->edid.hdr.hdrinfo.eotf ||
272 if (hdmi->hotplug == HDMI_HPD_ACTIVED)
273 hdmi_submit_work(hdmi, HDMI_SET_COLOR, 0, 0);
277 static int hdmi_set_scale(struct rk_display_device *device, int direction,
280 struct hdmi *hdmi = device->priv_data;
282 if (!hdmi || value < 0 || value > 100)
288 if (direction == DISPLAY_SCALE_X)
289 hdmi->xscale = value;
290 else if (direction == DISPLAY_SCALE_Y)
291 hdmi->yscale = value;
294 rk_fb_disp_scale(hdmi->xscale, hdmi->yscale, hdmi->lcdc->id);
298 static int hdmi_get_scale(struct rk_display_device *device, int direction)
300 struct hdmi *hdmi = device->priv_data;
305 if (direction == DISPLAY_SCALE_X)
307 else if (direction == DISPLAY_SCALE_Y)
313 static int hdmi_get_monspecs(struct rk_display_device *device,
314 struct fb_monspecs *monspecs)
316 struct hdmi *hdmi = device->priv_data;
321 if (hdmi->edid.specs)
322 *monspecs = *hdmi->edid.specs;
327 * hdmi_show_sink_info: show hdmi sink device information
328 * @hdmi: handle of hdmi
330 static int hdmi_show_sink_info(struct hdmi *hdmi, char *buf, int len)
332 struct list_head *pos, *head = &hdmi->edid.modelist;
333 struct display_modelist *modelist;
334 struct fb_videomode *m;
335 struct hdmi_audio *audio;
338 lens += snprintf(buf + lens, PAGE_SIZE - lens,
339 "******** Show Sink Info ********\n");
340 lens += snprintf(buf + lens, PAGE_SIZE - lens,
341 "Max tmds clk is %u\n",
342 hdmi->edid.maxtmdsclock);
343 if (hdmi->edid.hf_vsdb_version)
344 lens += snprintf(buf + lens, PAGE_SIZE - lens,
346 if (hdmi->edid.scdc_present)
347 lens += snprintf(buf + lens, PAGE_SIZE - lens,
349 lens += snprintf(buf + lens, PAGE_SIZE - lens,
350 "Support video mode:\n");
351 list_for_each(pos, head) {
352 modelist = list_entry(pos, struct display_modelist, list);
355 lens += snprintf(buf + lens, PAGE_SIZE - lens,
356 "\t%s(YCbCr420)\n", m->name);
358 lens += snprintf(buf + lens, PAGE_SIZE - lens,
361 lens += snprintf(buf + lens, PAGE_SIZE - lens,
362 "Support video color mode:");
363 lens += snprintf(buf + lens, PAGE_SIZE - lens, " RGB");
364 if (hdmi->edid.ycbcr420)
365 lens += snprintf(buf + lens, PAGE_SIZE - lens,
367 if (hdmi->edid.ycbcr422)
368 lens += snprintf(buf + lens, PAGE_SIZE - lens,
370 if (hdmi->edid.ycbcr444)
371 lens += snprintf(buf + lens, PAGE_SIZE - lens,
373 lens += snprintf(buf + lens, PAGE_SIZE - lens,
374 "\nSupport video color depth:");
375 lens += snprintf(buf + lens, PAGE_SIZE - lens, " 24bit");
376 if (hdmi->edid.deepcolor & HDMI_DEEP_COLOR_30BITS)
377 lens += snprintf(buf + lens, PAGE_SIZE - lens, " 30bit");
378 if (hdmi->edid.deepcolor & HDMI_DEEP_COLOR_36BITS)
379 lens += snprintf(buf + lens, PAGE_SIZE - lens, " 36bit");
380 if (hdmi->edid.deepcolor & HDMI_DEEP_COLOR_48BITS)
381 lens += snprintf(buf + lens, PAGE_SIZE - lens, " 48bit");
382 if (hdmi->edid.ycbcr420)
383 lens += snprintf(buf + lens, PAGE_SIZE - lens, " 420_24bit");
384 if (hdmi->edid.deepcolor_420 & HDMI_DEEP_COLOR_30BITS)
385 lens += snprintf(buf + lens, PAGE_SIZE - lens, " 420_30bit");
386 if (hdmi->edid.deepcolor_420 & HDMI_DEEP_COLOR_36BITS)
387 lens += snprintf(buf + lens, PAGE_SIZE - lens, " 420_36bit");
388 if (hdmi->edid.deepcolor_420 & HDMI_DEEP_COLOR_48BITS)
389 lens += snprintf(buf + lens, PAGE_SIZE - lens, " 420_48bit");
390 if (hdmi->edid.colorimetry) {
391 lens += snprintf(buf + lens, PAGE_SIZE - lens,
392 "\nExtended Colorimetry:");
393 if (hdmi->edid.colorimetry &
394 (1 << (HDMI_COLORIMETRY_EXTEND_XVYCC_601 - 3)))
395 lens += snprintf(buf + lens, PAGE_SIZE - lens,
397 if (hdmi->edid.colorimetry &
398 (1 << (HDMI_COLORIMETRY_EXTEND_XVYCC_709 - 3)))
399 lens += snprintf(buf + lens, PAGE_SIZE - lens,
401 if (hdmi->edid.colorimetry &
402 (1 << (HDMI_COLORIMETRY_EXTEND_SYCC_601 - 3)))
403 lens += snprintf(buf + lens, PAGE_SIZE - lens,
405 if (hdmi->edid.colorimetry &
406 (1 << (HDMI_COLORIMETRY_EXTEND_ADOBE_YCC601 - 3)))
407 lens += snprintf(buf + lens, PAGE_SIZE - lens,
409 if (hdmi->edid.colorimetry &
410 (1 << (HDMI_COLORIMETRY_EXTEND_ADOBE_RGB - 3)))
411 lens += snprintf(buf + lens, PAGE_SIZE - lens,
413 if (hdmi->edid.colorimetry &
414 (1 << (HDMI_COLORIMETRY_EXTEND_BT_2020_YCC_C - 3)))
415 lens += snprintf(buf + lens, PAGE_SIZE - lens,
417 if (hdmi->edid.colorimetry &
418 (1 << (HDMI_COLORIMETRY_EXTEND_BT_2020_YCC - 3)))
419 lens += snprintf(buf + lens, PAGE_SIZE - lens,
421 if (hdmi->edid.colorimetry &
422 (1 << (HDMI_COLORIMETRY_EXTEND_BT_2020_RGB - 3)))
423 lens += snprintf(buf + lens, PAGE_SIZE - lens,
426 lens += snprintf(buf + lens, PAGE_SIZE - lens,
427 "\nSupport audio type:");
428 for (i = 0; i < hdmi->edid.audio_num; i++) {
429 audio = &hdmi->edid.audio[i];
430 switch (audio->type) {
431 case HDMI_AUDIO_LPCM:
432 lens += snprintf(buf + lens, PAGE_SIZE - lens,
436 lens += snprintf(buf + lens, PAGE_SIZE - lens,
439 case HDMI_AUDIO_MPEG1:
440 lens += snprintf(buf + lens, PAGE_SIZE - lens,
444 lens += snprintf(buf + lens, PAGE_SIZE - lens,
447 case HDMI_AUDIO_MPEG2:
448 lens += snprintf(buf + lens, PAGE_SIZE - lens,
451 case HDMI_AUDIO_AAC_LC:
452 lens += snprintf(buf + lens, PAGE_SIZE - lens,
456 lens += snprintf(buf + lens, PAGE_SIZE - lens,
459 case HDMI_AUDIO_ATARC:
460 lens += snprintf(buf + lens, PAGE_SIZE - lens,
464 lens += snprintf(buf + lens, PAGE_SIZE - lens,
467 case HDMI_AUDIO_E_AC3:
468 lens += snprintf(buf + lens, PAGE_SIZE - lens,
471 case HDMI_AUDIO_DTS_HD:
472 lens += snprintf(buf + lens, PAGE_SIZE - lens,
476 lens += snprintf(buf + lens, PAGE_SIZE - lens,
480 lens += snprintf(buf + lens, PAGE_SIZE - lens,
483 case HDMI_AUDIO_WMA_PRO:
484 lens += snprintf(buf + lens, PAGE_SIZE - lens,
488 lens += snprintf(buf + lens, PAGE_SIZE - lens,
492 lens += snprintf(buf + lens, PAGE_SIZE - lens,
493 "Support max audio channel is %d\n",
495 lens += snprintf(buf + lens, PAGE_SIZE - lens,
496 "Support audio sample rate:");
497 if (audio->rate & HDMI_AUDIO_FS_32000)
498 lens += snprintf(buf + lens, PAGE_SIZE - lens,
500 if (audio->rate & HDMI_AUDIO_FS_44100)
501 lens += snprintf(buf + lens, PAGE_SIZE - lens,
503 if (audio->rate & HDMI_AUDIO_FS_48000)
504 lens += snprintf(buf + lens, PAGE_SIZE - lens,
506 if (audio->rate & HDMI_AUDIO_FS_88200)
507 lens += snprintf(buf + lens, PAGE_SIZE - lens,
509 if (audio->rate & HDMI_AUDIO_FS_96000)
510 lens += snprintf(buf + lens, PAGE_SIZE - lens,
512 if (audio->rate & HDMI_AUDIO_FS_176400)
513 lens += snprintf(buf + lens, PAGE_SIZE - lens,
515 if (audio->rate & HDMI_AUDIO_FS_192000)
516 lens += snprintf(buf + lens, PAGE_SIZE - lens,
518 lens += snprintf(buf + lens, PAGE_SIZE - lens,
519 "\nSupport audio word length:");
520 if (audio->rate & HDMI_AUDIO_WORD_LENGTH_16bit)
521 lens += snprintf(buf + lens, PAGE_SIZE - lens,
523 if (audio->rate & HDMI_AUDIO_WORD_LENGTH_20bit)
524 lens += snprintf(buf + lens, PAGE_SIZE - lens,
526 if (audio->rate & HDMI_AUDIO_WORD_LENGTH_24bit)
527 lens += snprintf(buf + lens, PAGE_SIZE - lens,
529 lens += snprintf(buf + lens, PAGE_SIZE - lens, "\n");
534 static int hdmi_get_debug(struct rk_display_device *device, char *buf)
536 struct hdmi *hdmi = device->priv_data;
542 len += snprintf(buf + len, PAGE_SIZE - len, "EDID status:%s\n",
543 hdmi->edid.status ? "False" : "Okay");
544 len += snprintf(buf + len, PAGE_SIZE - len, "Raw Data:");
545 for (i = 0; i < HDMI_MAX_EDID_BLOCK; i++) {
546 if (!hdmi->edid.raw[i])
548 buff = hdmi->edid.raw[i];
549 for (j = 0; j < HDMI_EDID_BLOCK_SIZE; j++) {
551 len += snprintf(buf + len,
552 PAGE_SIZE - len, "\n");
553 len += snprintf(buf + len, PAGE_SIZE - len, "0x%02x, ",
557 len += snprintf(buf + len, PAGE_SIZE, "\n");
558 if (!hdmi->edid.status)
559 len += hdmi_show_sink_info(hdmi, buf, len);
563 static int vr_get_info(struct rk_display_device *device, char *buf)
565 struct hdmi *hdmi = device->priv_data;
566 int valid, width, height, x_w, x_h, hwr, einit, vsync, panel, scan;
569 valid = hdmi->prop.valid;
570 width = hdmi->prop.value.width;
571 height = hdmi->prop.value.height;
572 x_w = hdmi->prop.value.x_w;
573 x_h = hdmi->prop.value.x_h;
574 hwr = hdmi->prop.value.hwrotation;
575 einit = hdmi->prop.value.einit;
576 vsync = hdmi->prop.value.vsync;
577 panel = hdmi->prop.value.panel;
578 scan = hdmi->prop.value.scan;
580 len = snprintf(buf, PAGE_SIZE,
581 "valid=%d,width=%d,height=%d,xres=%d,yres=%d,hwrotation=%d,orientation=%d,vsync=%d,panel=%d,scan=%d\n",
582 valid, width, height, x_w, x_h, hwr, einit, vsync, panel, scan);
587 static struct rk_display_ops hdmi_display_ops = {
588 .setenable = hdmi_set_enable,
589 .getenable = hdmi_get_enable,
590 .getstatus = hdmi_get_status,
591 .getmodelist = hdmi_get_modelist,
592 .setmode = hdmi_set_mode,
593 .getmode = hdmi_get_mode,
594 .set3dmode = hdmi_set_3dmode,
595 .get3dmode = hdmi_get_3dmode,
596 .getedidaudioinfo = hdmi_get_edidaudioinfo,
597 .setcolor = hdmi_set_color,
598 .getcolor = hdmi_get_color,
599 .getmonspecs = hdmi_get_monspecs,
600 .setscale = hdmi_set_scale,
601 .getscale = hdmi_get_scale,
602 .getdebug = hdmi_get_debug,
603 .getvrinfo = vr_get_info,
606 static int hdmi_display_probe(struct rk_display_device *device, void *devdata)
608 struct hdmi *hdmi = devdata;
610 device->owner = THIS_MODULE;
611 strcpy(device->type, "HDMI");
612 if (strstr(hdmi->property->name, "dp"))
613 strcpy(device->type, "DP");
615 strcpy(device->type, "HDMI");
617 device->priority = DISPLAY_PRIORITY_HDMI;
618 device->name = hdmi->property->name;
619 device->property = hdmi->property->display;
620 device->priv_data = devdata;
621 device->ops = &hdmi_display_ops;
625 static struct rk_display_driver display_hdmi = {
626 .probe = hdmi_display_probe,
629 struct rk_display_device *hdmi_register_display_sysfs(struct hdmi *hdmi,
630 struct device *parent)
632 return rk_display_device_register(&display_hdmi, parent, hdmi);
635 void hdmi_unregister_display_sysfs(struct hdmi *hdmi)
638 rk_display_device_unregister(hdmi->ddev);