1 #include <linux/ctype.h>
2 #include <linux/string.h>
3 #include <linux/display-sys.h>
4 #include <linux/interrupt.h>
5 #include "rockchip-hdmi.h"
7 static int hdmi_get_enable(struct rk_display_device *device)
9 struct hdmi *hdmi = device->priv_data;
12 enable = hdmi->enable;
16 static int hdmi_set_enable(struct rk_display_device *device, int enable)
18 struct hdmi *hdmi = device->priv_data;
21 hdmi_submit_work(hdmi, HDMI_DISABLE_CTL, 0, 0);
23 hdmi_submit_work(hdmi, HDMI_ENABLE_CTL, 0, 0);
27 static int hdmi_get_status(struct rk_display_device *device)
29 struct hdmi *hdmi = device->priv_data;
31 if (hdmi->hotplug == HDMI_HPD_ACTIVED)
37 static int hdmi_get_modelist(struct rk_display_device *device,
38 struct list_head **modelist)
40 struct hdmi *hdmi = device->priv_data;
42 *modelist = &hdmi->edid.modelist;
46 static int hdmi_set_mode(struct rk_display_device *device,
47 struct fb_videomode *mode)
49 struct hdmi *hdmi = device->priv_data;
50 struct display_modelist *display_modelist =
51 container_of(mode, struct display_modelist, mode);
56 vic = hdmi_find_best_mode(hdmi, 0);
59 vic = display_modelist->vic;
62 if (vic && hdmi->vic != vic) {
64 if (hdmi->hotplug == HDMI_HPD_ACTIVED)
65 hdmi_submit_work(hdmi, HDMI_SET_VIDEO, 0, 0);
70 static int hdmi_get_mode(struct rk_display_device *device,
71 struct fb_videomode *mode)
73 struct hdmi *hdmi = device->priv_data;
74 struct fb_videomode *vmode;
80 vmode = (struct fb_videomode *)
81 hdmi_vic_to_videomode(hdmi->vic);
82 if (unlikely(vmode == NULL))
85 if (hdmi->vic & HDMI_VIDEO_YUV420)
88 memset(mode, 0, sizeof(struct fb_videomode));
93 static int hdmi_set_3dmode(struct rk_display_device *device, int mode)
95 struct hdmi *hdmi = device->priv_data;
96 struct list_head *modelist, *pos;
97 struct display_modelist *display_modelist = NULL;
102 modelist = &hdmi->edid.modelist;
103 list_for_each(pos, modelist) {
105 list_entry(pos, struct display_modelist, list);
106 if (hdmi->vic == display_modelist->vic)
109 display_modelist = NULL;
111 if (!display_modelist)
114 if ((mode != HDMI_3D_NONE) &&
115 ((display_modelist->format_3d & (1 << mode)) == 0))
116 pr_warn("warning: sink not support input 3d mode %d", mode);
118 if (hdmi->mode_3d != mode) {
119 hdmi->mode_3d = mode;
120 if (hdmi->hotplug == HDMI_HPD_ACTIVED)
121 hdmi_submit_work(hdmi, HDMI_SET_3D, 0, 0);
126 static int hdmi_get_3dmode(struct rk_display_device *device)
128 struct hdmi *hdmi = device->priv_data;
133 return hdmi->mode_3d;
136 /*CEA 861-E: Audio Coding Type
137 sync width enum hdmi_audio_type
139 static const char * const audioformatstr[] = {
141 "LPCM", /*HDMI_AUDIO_LPCM = 1,*/
142 "AC3", /*HDMI_AUDIO_AC3,*/
143 "MPEG1", /*HDMI_AUDIO_MPEG1,*/
144 "MP3", /*HDMI_AUDIO_MP3,*/
145 "MPEG2", /*HDMI_AUDIO_MPEG2,*/
146 "AAC-LC", /*HDMI_AUDIO_AAC_LC, AAC*/
147 "DTS", /*HDMI_AUDIO_DTS,*/
148 "ATARC", /*HDMI_AUDIO_ATARC,*/
149 "DSD", /*HDMI_AUDIO_DSD, One bit Audio */
150 "E-AC3", /*HDMI_AUDIO_E_AC3,*/
151 "DTS-HD", /*HDMI_AUDIO_DTS_HD,*/
152 "MLP", /*HDMI_AUDIO_MLP,*/
153 "DST", /*HDMI_AUDIO_DST,*/
154 "WMA-PRO", /*HDMI_AUDIO_WMA_PRO*/
157 static int hdmi_get_edidaudioinfo(struct rk_display_device *device,
158 char *audioinfo, int len)
160 struct hdmi *hdmi = device->priv_data;
162 struct hdmi_audio *audio;
167 memset(audioinfo, 0x00, len);
168 /*printk("hdmi:edid: audio_num: %d\n", hdmi->edid.audio_num);*/
169 for (i = 0; i < hdmi->edid.audio_num; i++) {
170 audio = &(hdmi->edid.audio[i]);
171 if (audio->type < 1 || audio->type > HDMI_AUDIO_WMA_PRO) {
172 pr_info("audio type: unsupported.");
175 size = strlen(audioformatstr[audio->type]);
176 memcpy(audioinfo, audioformatstr[audio->type], size);
177 audioinfo[size] = ',';
178 audioinfo += (size+1);
183 static int hdmi_get_color(struct rk_display_device *device, char *buf)
185 struct hdmi *hdmi = device->priv_data;
188 mode = (1 << HDMI_COLOR_RGB_0_255);
189 if (hdmi->edid.sink_hdmi) {
190 mode |= (1 << HDMI_COLOR_RGB_16_235);
191 if (hdmi->edid.ycbcr422)
192 mode |= (1 << HDMI_COLOR_YCBCR422);
193 if (hdmi->edid.ycbcr444)
194 mode |= (1 << HDMI_COLOR_YCBCR444);
196 i = snprintf(buf, PAGE_SIZE,
197 "Supported Color Mode: %d\n", mode);
198 i += snprintf(buf + i, PAGE_SIZE - i,
199 "Current Color Mode: %d\n", hdmi->colormode);
201 mode = (1 << 1); /* 24 bit*/
202 if (hdmi->edid.deepcolor & HDMI_DEEP_COLOR_30BITS &&
203 hdmi->property->feature & SUPPORT_DEEP_10BIT)
204 mode |= (1 << HDMI_DEEP_COLOR_30BITS);
205 if (hdmi->edid.deepcolor & HDMI_DEEP_COLOR_36BITS &&
206 hdmi->property->feature & SUPPORT_DEEP_12BIT)
207 mode |= (1 << HDMI_DEEP_COLOR_36BITS);
208 if (hdmi->edid.deepcolor & HDMI_DEEP_COLOR_48BITS &&
209 hdmi->property->feature & SUPPORT_DEEP_16BIT)
210 mode |= (1 << HDMI_DEEP_COLOR_48BITS);
211 i += snprintf(buf + i, PAGE_SIZE - i,
212 "Supported Color Depth: %d\n", mode);
213 i += snprintf(buf + i, PAGE_SIZE - i,
214 "Current Color Depth: %d\n", hdmi->colordepth);
215 i += snprintf(buf + i, PAGE_SIZE - i,
216 "Supported Colorimetry: %d\n", hdmi->edid.colorimetry);
217 i += snprintf(buf + i, PAGE_SIZE - i,
218 "Current Colorimetry: %d\n", hdmi->colorimetry);
222 static int hdmi_set_color(struct rk_display_device *device,
223 const char *buf, int len)
225 struct hdmi *hdmi = device->priv_data;
228 if (!strncmp(buf, "mode", 4)) {
229 if (sscanf(buf, "mode=%d", &value) == -1)
231 pr_debug("current mode is %d input mode is %d\n",
232 hdmi->colormode, value);
233 if (hdmi->colormode != value)
234 hdmi->colormode = value;
235 } else if (!strncmp(buf, "depth", 5)) {
236 if (sscanf(buf, "depth=%d", &value) == -1)
238 pr_debug("current depth is %d input mode is %d\n",
239 hdmi->colordepth, value);
240 if (hdmi->colordepth != value)
241 hdmi->colordepth = value;
242 } else if (!strncmp(buf, "colorimetry", 11)) {
243 if (sscanf(buf, "colorimetry=%d", &value) == -1)
245 pr_debug("current colorimetry is %d input colorimetry is %d\n",
246 hdmi->colorimetry, value);
247 if (hdmi->colorimetry != value)
248 hdmi->colorimetry = value;
250 pr_err("%s unkown event\n", __func__);
253 if (hdmi->hotplug == HDMI_HPD_ACTIVED)
254 hdmi_submit_work(hdmi, HDMI_SET_COLOR, 0, 0);
258 static int hdmi_set_scale(struct rk_display_device *device, int direction,
261 struct hdmi *hdmi = device->priv_data;
263 if (!hdmi || value < 0 || value > 100)
269 if (direction == DISPLAY_SCALE_X)
270 hdmi->xscale = value;
271 else if (direction == DISPLAY_SCALE_Y)
272 hdmi->yscale = value;
275 rk_fb_disp_scale(hdmi->xscale, hdmi->yscale, hdmi->lcdc->id);
279 static int hdmi_get_scale(struct rk_display_device *device, int direction)
281 struct hdmi *hdmi = device->priv_data;
286 if (direction == DISPLAY_SCALE_X)
288 else if (direction == DISPLAY_SCALE_Y)
294 static int hdmi_get_monspecs(struct rk_display_device *device,
295 struct fb_monspecs *monspecs)
297 struct hdmi *hdmi = device->priv_data;
302 if (hdmi->edid.specs)
303 *monspecs = *(hdmi->edid.specs);
308 * hdmi_show_sink_info: show hdmi sink device infomation
309 * @hdmi: handle of hdmi
311 static int hdmi_show_sink_info(struct hdmi *hdmi, char *buf, int len)
313 struct list_head *pos, *head = &hdmi->edid.modelist;
314 struct display_modelist *modelist;
315 struct fb_videomode *m;
316 struct hdmi_audio *audio;
319 lens += snprintf(buf + lens, PAGE_SIZE - lens,
320 "******** Show Sink Info ********\n");
321 lens += snprintf(buf + lens, PAGE_SIZE - lens,
322 "Max tmds clk is %u\n",
323 hdmi->edid.maxtmdsclock);
324 if (hdmi->edid.hf_vsdb_version)
325 lens += snprintf(buf + lens, PAGE_SIZE - lens,
327 if (hdmi->edid.scdc_present)
328 lens += snprintf(buf + lens, PAGE_SIZE - lens,
330 lens += snprintf(buf + lens, PAGE_SIZE - lens,
331 "Support video mode:\n");
332 list_for_each(pos, head) {
333 modelist = list_entry(pos, struct display_modelist, list);
336 lens += snprintf(buf + lens, PAGE_SIZE - lens,
337 "\t%s(YCbCr420)\n", m->name);
339 lens += snprintf(buf + lens, PAGE_SIZE - lens,
342 lens += snprintf(buf + lens, PAGE_SIZE - lens,
343 "Support video color mode:");
344 lens += snprintf(buf + lens, PAGE_SIZE - lens, " RGB");
345 if (hdmi->edid.ycbcr420)
346 lens += snprintf(buf + lens, PAGE_SIZE - lens,
348 if (hdmi->edid.ycbcr422)
349 lens += snprintf(buf + lens, PAGE_SIZE - lens,
351 if (hdmi->edid.ycbcr444)
352 lens += snprintf(buf + lens, PAGE_SIZE - lens,
354 lens += snprintf(buf + lens, PAGE_SIZE - lens,
355 "\nSupport video color depth:");
356 lens += snprintf(buf + lens, PAGE_SIZE - lens, " 24bit");
357 if (hdmi->edid.deepcolor & HDMI_DEEP_COLOR_30BITS)
358 lens += snprintf(buf + lens, PAGE_SIZE - lens, " 30bit");
359 if (hdmi->edid.deepcolor & HDMI_DEEP_COLOR_36BITS)
360 lens += snprintf(buf + lens, PAGE_SIZE - lens, " 36bit");
361 if (hdmi->edid.deepcolor & HDMI_DEEP_COLOR_48BITS)
362 lens += snprintf(buf + lens, PAGE_SIZE - lens, " 48bit");
363 if (hdmi->edid.ycbcr420)
364 lens += snprintf(buf + lens, PAGE_SIZE - lens, " 420_24bit");
365 if (hdmi->edid.deepcolor_420 & HDMI_DEEP_COLOR_30BITS)
366 lens += snprintf(buf + lens, PAGE_SIZE - lens, " 420_30bit");
367 if (hdmi->edid.deepcolor_420 & HDMI_DEEP_COLOR_36BITS)
368 lens += snprintf(buf + lens, PAGE_SIZE - lens, " 420_36bit");
369 if (hdmi->edid.deepcolor_420 & HDMI_DEEP_COLOR_48BITS)
370 lens += snprintf(buf + lens, PAGE_SIZE - lens, " 420_48bit");
371 if (hdmi->edid.colorimetry) {
372 lens += snprintf(buf + lens, PAGE_SIZE - lens,
373 "\nExtended Colorimetry:");
374 if (hdmi->edid.colorimetry &
375 (1 << (HDMI_COLORIMETRY_EXTEND_XVYCC_601 - 3)))
376 lens += snprintf(buf + lens, PAGE_SIZE - lens,
378 if (hdmi->edid.colorimetry &
379 (1 << (HDMI_COLORIMETRY_EXTEND_XVYCC_709 - 3)))
380 lens += snprintf(buf + lens, PAGE_SIZE - lens,
382 if (hdmi->edid.colorimetry &
383 (1 << (HDMI_COLORIMETRY_EXTEND_SYCC_601 - 3)))
384 lens += snprintf(buf + lens, PAGE_SIZE - lens,
386 if (hdmi->edid.colorimetry &
387 (1 << (HDMI_COLORIMETRY_EXTEND_ADOBE_YCC601 - 3)))
388 lens += snprintf(buf + lens, PAGE_SIZE - lens,
390 if (hdmi->edid.colorimetry &
391 (1 << (HDMI_COLORIMETRY_EXTEND_ADOBE_RGB - 3)))
392 lens += snprintf(buf + lens, PAGE_SIZE - lens,
394 if (hdmi->edid.colorimetry &
395 (1 << (HDMI_COLORIMETRY_EXTEND_BT_2020_YCC_C - 3)))
396 lens += snprintf(buf + lens, PAGE_SIZE - lens,
398 if (hdmi->edid.colorimetry &
399 (1 << (HDMI_COLORIMETRY_EXTEND_BT_2020_YCC - 3)))
400 lens += snprintf(buf + lens, PAGE_SIZE - lens,
402 if (hdmi->edid.colorimetry &
403 (1 << (HDMI_COLORIMETRY_EXTEND_BT_2020_RGB - 3)))
404 lens += snprintf(buf + lens, PAGE_SIZE - lens,
407 lens += snprintf(buf + lens, PAGE_SIZE - lens,
408 "\nSupport audio type:");
409 for (i = 0; i < hdmi->edid.audio_num; i++) {
410 audio = &(hdmi->edid.audio[i]);
411 switch (audio->type) {
412 case HDMI_AUDIO_LPCM:
413 lens += snprintf(buf + lens, PAGE_SIZE - lens,
417 lens += snprintf(buf + lens, PAGE_SIZE - lens,
420 case HDMI_AUDIO_MPEG1:
421 lens += snprintf(buf + lens, PAGE_SIZE - lens,
425 lens += snprintf(buf + lens, PAGE_SIZE - lens,
428 case HDMI_AUDIO_MPEG2:
429 lens += snprintf(buf + lens, PAGE_SIZE - lens,
432 case HDMI_AUDIO_AAC_LC:
433 lens += snprintf(buf + lens, PAGE_SIZE - lens,
437 lens += snprintf(buf + lens, PAGE_SIZE - lens,
440 case HDMI_AUDIO_ATARC:
441 lens += snprintf(buf + lens, PAGE_SIZE - lens,
445 lens += snprintf(buf + lens, PAGE_SIZE - lens,
448 case HDMI_AUDIO_E_AC3:
449 lens += snprintf(buf + lens, PAGE_SIZE - lens,
452 case HDMI_AUDIO_DTS_HD:
453 lens += snprintf(buf + lens, PAGE_SIZE - lens,
457 lens += snprintf(buf + lens, PAGE_SIZE - lens,
461 lens += snprintf(buf + lens, PAGE_SIZE - lens,
464 case HDMI_AUDIO_WMA_PRO:
465 lens += snprintf(buf + lens, PAGE_SIZE - lens,
469 lens += snprintf(buf + lens, PAGE_SIZE - lens,
473 lens += snprintf(buf + lens, PAGE_SIZE - lens,
474 "Support max audio channel is %d\n",
476 lens += snprintf(buf + lens, PAGE_SIZE - lens,
477 "Support audio sample rate:");
478 if (audio->rate & HDMI_AUDIO_FS_32000)
479 lens += snprintf(buf + lens, PAGE_SIZE - lens,
481 if (audio->rate & HDMI_AUDIO_FS_44100)
482 lens += snprintf(buf + lens, PAGE_SIZE - lens,
484 if (audio->rate & HDMI_AUDIO_FS_48000)
485 lens += snprintf(buf + lens, PAGE_SIZE - lens,
487 if (audio->rate & HDMI_AUDIO_FS_88200)
488 lens += snprintf(buf + lens, PAGE_SIZE - lens,
490 if (audio->rate & HDMI_AUDIO_FS_96000)
491 lens += snprintf(buf + lens, PAGE_SIZE - lens,
493 if (audio->rate & HDMI_AUDIO_FS_176400)
494 lens += snprintf(buf + lens, PAGE_SIZE - lens,
496 if (audio->rate & HDMI_AUDIO_FS_192000)
497 lens += snprintf(buf + lens, PAGE_SIZE - lens,
499 lens += snprintf(buf + lens, PAGE_SIZE - lens,
500 "\nSupport audio word lenght:");
501 if (audio->rate & HDMI_AUDIO_WORD_LENGTH_16bit)
502 lens += snprintf(buf + lens, PAGE_SIZE - lens,
504 if (audio->rate & HDMI_AUDIO_WORD_LENGTH_20bit)
505 lens += snprintf(buf + lens, PAGE_SIZE - lens,
507 if (audio->rate & HDMI_AUDIO_WORD_LENGTH_24bit)
508 lens += snprintf(buf + lens, PAGE_SIZE - lens,
510 lens += snprintf(buf + lens, PAGE_SIZE - lens, "\n");
515 static int hdmi_get_debug(struct rk_display_device *device, char *buf)
517 struct hdmi *hdmi = device->priv_data;
523 len += snprintf(buf+len, PAGE_SIZE - len, "EDID status:%s\n",
524 hdmi->edid.status ? "False" : "Okay");
525 len += snprintf(buf+len, PAGE_SIZE - len, "Raw Data:");
526 for (i = 0; i < HDMI_MAX_EDID_BLOCK; i++) {
527 if (!hdmi->edid.raw[i])
529 buff = hdmi->edid.raw[i];
530 for (j = 0; j < HDMI_EDID_BLOCK_SIZE; j++) {
532 len += snprintf(buf + len,
533 PAGE_SIZE - len, "\n");
534 len += snprintf(buf+len, PAGE_SIZE - len, "0x%02x, ",
538 len += snprintf(buf+len, PAGE_SIZE, "\n");
539 if (!hdmi->edid.status)
540 len += hdmi_show_sink_info(hdmi, buf, len);
544 static struct rk_display_ops hdmi_display_ops = {
545 .setenable = hdmi_set_enable,
546 .getenable = hdmi_get_enable,
547 .getstatus = hdmi_get_status,
548 .getmodelist = hdmi_get_modelist,
549 .setmode = hdmi_set_mode,
550 .getmode = hdmi_get_mode,
551 .set3dmode = hdmi_set_3dmode,
552 .get3dmode = hdmi_get_3dmode,
553 .getedidaudioinfo = hdmi_get_edidaudioinfo,
554 .setcolor = hdmi_set_color,
555 .getcolor = hdmi_get_color,
556 .getmonspecs = hdmi_get_monspecs,
557 .setscale = hdmi_set_scale,
558 .getscale = hdmi_get_scale,
559 .getdebug = hdmi_get_debug,
562 static int hdmi_display_probe(struct rk_display_device *device, void *devdata)
564 struct hdmi *hdmi = devdata;
566 device->owner = THIS_MODULE;
567 strcpy(device->type, "HDMI");
568 device->priority = DISPLAY_PRIORITY_HDMI;
569 device->name = hdmi->property->name;
570 device->property = hdmi->property->display;
571 device->priv_data = devdata;
572 device->ops = &hdmi_display_ops;
576 static struct rk_display_driver display_hdmi = {
577 .probe = hdmi_display_probe,
580 struct rk_display_device *hdmi_register_display_sysfs(struct hdmi *hdmi,
581 struct device *parent)
583 return rk_display_device_register(&display_hdmi, parent, hdmi);
586 void hdmi_unregister_display_sysfs(struct hdmi *hdmi)
589 rk_display_device_unregister(hdmi->ddev);