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);
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)
107 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;
252 if (hdmi->hotplug == HDMI_HPD_ACTIVED)
253 hdmi_submit_work(hdmi, HDMI_SET_COLOR, 0, 0);
257 static int hdmi_set_scale(struct rk_display_device *device, int direction,
260 struct hdmi *hdmi = device->priv_data;
262 if (!hdmi || value < 0 || value > 100)
268 if (direction == DISPLAY_SCALE_X)
269 hdmi->xscale = value;
270 else if (direction == DISPLAY_SCALE_Y)
271 hdmi->yscale = value;
274 rk_fb_disp_scale(hdmi->xscale, hdmi->yscale, hdmi->lcdc->id);
278 static int hdmi_get_scale(struct rk_display_device *device, int direction)
280 struct hdmi *hdmi = device->priv_data;
285 if (direction == DISPLAY_SCALE_X)
287 else if (direction == DISPLAY_SCALE_Y)
293 static int hdmi_get_monspecs(struct rk_display_device *device,
294 struct fb_monspecs *monspecs)
296 struct hdmi *hdmi = device->priv_data;
301 if (hdmi->edid.specs)
302 *monspecs = *hdmi->edid.specs;
307 * hdmi_show_sink_info: show hdmi sink device information
308 * @hdmi: handle of hdmi
310 static int hdmi_show_sink_info(struct hdmi *hdmi, char *buf, int len)
312 struct list_head *pos, *head = &hdmi->edid.modelist;
313 struct display_modelist *modelist;
314 struct fb_videomode *m;
315 struct hdmi_audio *audio;
318 lens += snprintf(buf + lens, PAGE_SIZE - lens,
319 "******** Show Sink Info ********\n");
320 lens += snprintf(buf + lens, PAGE_SIZE - lens,
321 "Max tmds clk is %u\n",
322 hdmi->edid.maxtmdsclock);
323 if (hdmi->edid.hf_vsdb_version)
324 lens += snprintf(buf + lens, PAGE_SIZE - lens,
326 if (hdmi->edid.scdc_present)
327 lens += snprintf(buf + lens, PAGE_SIZE - lens,
329 lens += snprintf(buf + lens, PAGE_SIZE - lens,
330 "Support video mode:\n");
331 list_for_each(pos, head) {
332 modelist = list_entry(pos, struct display_modelist, list);
335 lens += snprintf(buf + lens, PAGE_SIZE - lens,
336 "\t%s(YCbCr420)\n", m->name);
338 lens += snprintf(buf + lens, PAGE_SIZE - lens,
341 lens += snprintf(buf + lens, PAGE_SIZE - lens,
342 "Support video color mode:");
343 lens += snprintf(buf + lens, PAGE_SIZE - lens, " RGB");
344 if (hdmi->edid.ycbcr420)
345 lens += snprintf(buf + lens, PAGE_SIZE - lens,
347 if (hdmi->edid.ycbcr422)
348 lens += snprintf(buf + lens, PAGE_SIZE - lens,
350 if (hdmi->edid.ycbcr444)
351 lens += snprintf(buf + lens, PAGE_SIZE - lens,
353 lens += snprintf(buf + lens, PAGE_SIZE - lens,
354 "\nSupport video color depth:");
355 lens += snprintf(buf + lens, PAGE_SIZE - lens, " 24bit");
356 if (hdmi->edid.deepcolor & HDMI_DEEP_COLOR_30BITS)
357 lens += snprintf(buf + lens, PAGE_SIZE - lens, " 30bit");
358 if (hdmi->edid.deepcolor & HDMI_DEEP_COLOR_36BITS)
359 lens += snprintf(buf + lens, PAGE_SIZE - lens, " 36bit");
360 if (hdmi->edid.deepcolor & HDMI_DEEP_COLOR_48BITS)
361 lens += snprintf(buf + lens, PAGE_SIZE - lens, " 48bit");
362 if (hdmi->edid.ycbcr420)
363 lens += snprintf(buf + lens, PAGE_SIZE - lens, " 420_24bit");
364 if (hdmi->edid.deepcolor_420 & HDMI_DEEP_COLOR_30BITS)
365 lens += snprintf(buf + lens, PAGE_SIZE - lens, " 420_30bit");
366 if (hdmi->edid.deepcolor_420 & HDMI_DEEP_COLOR_36BITS)
367 lens += snprintf(buf + lens, PAGE_SIZE - lens, " 420_36bit");
368 if (hdmi->edid.deepcolor_420 & HDMI_DEEP_COLOR_48BITS)
369 lens += snprintf(buf + lens, PAGE_SIZE - lens, " 420_48bit");
370 if (hdmi->edid.colorimetry) {
371 lens += snprintf(buf + lens, PAGE_SIZE - lens,
372 "\nExtended Colorimetry:");
373 if (hdmi->edid.colorimetry &
374 (1 << (HDMI_COLORIMETRY_EXTEND_XVYCC_601 - 3)))
375 lens += snprintf(buf + lens, PAGE_SIZE - lens,
377 if (hdmi->edid.colorimetry &
378 (1 << (HDMI_COLORIMETRY_EXTEND_XVYCC_709 - 3)))
379 lens += snprintf(buf + lens, PAGE_SIZE - lens,
381 if (hdmi->edid.colorimetry &
382 (1 << (HDMI_COLORIMETRY_EXTEND_SYCC_601 - 3)))
383 lens += snprintf(buf + lens, PAGE_SIZE - lens,
385 if (hdmi->edid.colorimetry &
386 (1 << (HDMI_COLORIMETRY_EXTEND_ADOBE_YCC601 - 3)))
387 lens += snprintf(buf + lens, PAGE_SIZE - lens,
389 if (hdmi->edid.colorimetry &
390 (1 << (HDMI_COLORIMETRY_EXTEND_ADOBE_RGB - 3)))
391 lens += snprintf(buf + lens, PAGE_SIZE - lens,
393 if (hdmi->edid.colorimetry &
394 (1 << (HDMI_COLORIMETRY_EXTEND_BT_2020_YCC_C - 3)))
395 lens += snprintf(buf + lens, PAGE_SIZE - lens,
397 if (hdmi->edid.colorimetry &
398 (1 << (HDMI_COLORIMETRY_EXTEND_BT_2020_YCC - 3)))
399 lens += snprintf(buf + lens, PAGE_SIZE - lens,
401 if (hdmi->edid.colorimetry &
402 (1 << (HDMI_COLORIMETRY_EXTEND_BT_2020_RGB - 3)))
403 lens += snprintf(buf + lens, PAGE_SIZE - lens,
406 lens += snprintf(buf + lens, PAGE_SIZE - lens,
407 "\nSupport audio type:");
408 for (i = 0; i < hdmi->edid.audio_num; i++) {
409 audio = &hdmi->edid.audio[i];
410 switch (audio->type) {
411 case HDMI_AUDIO_LPCM:
412 lens += snprintf(buf + lens, PAGE_SIZE - lens,
416 lens += snprintf(buf + lens, PAGE_SIZE - lens,
419 case HDMI_AUDIO_MPEG1:
420 lens += snprintf(buf + lens, PAGE_SIZE - lens,
424 lens += snprintf(buf + lens, PAGE_SIZE - lens,
427 case HDMI_AUDIO_MPEG2:
428 lens += snprintf(buf + lens, PAGE_SIZE - lens,
431 case HDMI_AUDIO_AAC_LC:
432 lens += snprintf(buf + lens, PAGE_SIZE - lens,
436 lens += snprintf(buf + lens, PAGE_SIZE - lens,
439 case HDMI_AUDIO_ATARC:
440 lens += snprintf(buf + lens, PAGE_SIZE - lens,
444 lens += snprintf(buf + lens, PAGE_SIZE - lens,
447 case HDMI_AUDIO_E_AC3:
448 lens += snprintf(buf + lens, PAGE_SIZE - lens,
451 case HDMI_AUDIO_DTS_HD:
452 lens += snprintf(buf + lens, PAGE_SIZE - lens,
456 lens += snprintf(buf + lens, PAGE_SIZE - lens,
460 lens += snprintf(buf + lens, PAGE_SIZE - lens,
463 case HDMI_AUDIO_WMA_PRO:
464 lens += snprintf(buf + lens, PAGE_SIZE - lens,
468 lens += snprintf(buf + lens, PAGE_SIZE - lens,
472 lens += snprintf(buf + lens, PAGE_SIZE - lens,
473 "Support max audio channel is %d\n",
475 lens += snprintf(buf + lens, PAGE_SIZE - lens,
476 "Support audio sample rate:");
477 if (audio->rate & HDMI_AUDIO_FS_32000)
478 lens += snprintf(buf + lens, PAGE_SIZE - lens,
480 if (audio->rate & HDMI_AUDIO_FS_44100)
481 lens += snprintf(buf + lens, PAGE_SIZE - lens,
483 if (audio->rate & HDMI_AUDIO_FS_48000)
484 lens += snprintf(buf + lens, PAGE_SIZE - lens,
486 if (audio->rate & HDMI_AUDIO_FS_88200)
487 lens += snprintf(buf + lens, PAGE_SIZE - lens,
489 if (audio->rate & HDMI_AUDIO_FS_96000)
490 lens += snprintf(buf + lens, PAGE_SIZE - lens,
492 if (audio->rate & HDMI_AUDIO_FS_176400)
493 lens += snprintf(buf + lens, PAGE_SIZE - lens,
495 if (audio->rate & HDMI_AUDIO_FS_192000)
496 lens += snprintf(buf + lens, PAGE_SIZE - lens,
498 lens += snprintf(buf + lens, PAGE_SIZE - lens,
499 "\nSupport audio word length:");
500 if (audio->rate & HDMI_AUDIO_WORD_LENGTH_16bit)
501 lens += snprintf(buf + lens, PAGE_SIZE - lens,
503 if (audio->rate & HDMI_AUDIO_WORD_LENGTH_20bit)
504 lens += snprintf(buf + lens, PAGE_SIZE - lens,
506 if (audio->rate & HDMI_AUDIO_WORD_LENGTH_24bit)
507 lens += snprintf(buf + lens, PAGE_SIZE - lens,
509 lens += snprintf(buf + lens, PAGE_SIZE - lens, "\n");
514 static int hdmi_get_debug(struct rk_display_device *device, char *buf)
516 struct hdmi *hdmi = device->priv_data;
522 len += snprintf(buf + len, PAGE_SIZE - len, "EDID status:%s\n",
523 hdmi->edid.status ? "False" : "Okay");
524 len += snprintf(buf + len, PAGE_SIZE - len, "Raw Data:");
525 for (i = 0; i < HDMI_MAX_EDID_BLOCK; i++) {
526 if (!hdmi->edid.raw[i])
528 buff = hdmi->edid.raw[i];
529 for (j = 0; j < HDMI_EDID_BLOCK_SIZE; j++) {
531 len += snprintf(buf + len,
532 PAGE_SIZE - len, "\n");
533 len += snprintf(buf + len, PAGE_SIZE - len, "0x%02x, ",
537 len += snprintf(buf + len, PAGE_SIZE, "\n");
538 if (!hdmi->edid.status)
539 len += hdmi_show_sink_info(hdmi, buf, len);
543 static struct rk_display_ops hdmi_display_ops = {
544 .setenable = hdmi_set_enable,
545 .getenable = hdmi_get_enable,
546 .getstatus = hdmi_get_status,
547 .getmodelist = hdmi_get_modelist,
548 .setmode = hdmi_set_mode,
549 .getmode = hdmi_get_mode,
550 .set3dmode = hdmi_set_3dmode,
551 .get3dmode = hdmi_get_3dmode,
552 .getedidaudioinfo = hdmi_get_edidaudioinfo,
553 .setcolor = hdmi_set_color,
554 .getcolor = hdmi_get_color,
555 .getmonspecs = hdmi_get_monspecs,
556 .setscale = hdmi_set_scale,
557 .getscale = hdmi_get_scale,
558 .getdebug = hdmi_get_debug,
561 static int hdmi_display_probe(struct rk_display_device *device, void *devdata)
563 struct hdmi *hdmi = devdata;
565 device->owner = THIS_MODULE;
566 strcpy(device->type, "HDMI");
567 device->priority = DISPLAY_PRIORITY_HDMI;
568 device->name = hdmi->property->name;
569 device->property = hdmi->property->display;
570 device->priv_data = devdata;
571 device->ops = &hdmi_display_ops;
575 static struct rk_display_driver display_hdmi = {
576 .probe = hdmi_display_probe,
579 struct rk_display_device *hdmi_register_display_sysfs(struct hdmi *hdmi,
580 struct device *parent)
582 return rk_display_device_register(&display_hdmi, parent, hdmi);
585 void hdmi_unregister_display_sysfs(struct hdmi *hdmi)
588 rk_display_device_unregister(hdmi->ddev);