1 #include <linux/delay.h>
2 #include "rockchip-hdmi.h"
3 #include "rockchip-hdmi-cec.h"
5 struct hdmi_delayed_work {
6 struct delayed_work work;
12 struct hdmi_id_ref_info {
16 } ref_info[HDMI_MAX_ID];
19 static void hdmi_work_queue(struct work_struct *work);
21 struct delayed_work *hdmi_submit_work(struct hdmi *hdmi,
22 int event, int delay, void *data)
24 struct hdmi_delayed_work *work;
26 DBG("%s event %04x delay %d", __func__, event, delay);
28 work = kmalloc(sizeof(*work), GFP_ATOMIC);
31 INIT_DELAYED_WORK(&work->work, hdmi_work_queue);
35 queue_delayed_work(hdmi->workqueue,
37 msecs_to_jiffies(delay));
39 pr_warn("HDMI: Cannot allocate memory to create work\n");
46 static void hdmi_send_uevent(struct hdmi *hdmi, int uevent)
50 envp[0] = "INTERFACE=HDMI";
51 envp[1] = kmalloc(32, GFP_KERNEL);
54 sprintf(envp[1], "SCREEN=%d", hdmi->ddev->property);
56 kobject_uevent_env(&hdmi->ddev->dev->kobj, uevent, envp);
60 static inline void hdmi_wq_set_output(struct hdmi *hdmi, int mute)
62 DBG("%s mute %d", __func__, mute);
63 if (hdmi->ops->setmute)
64 hdmi->ops->setmute(hdmi, mute);
67 static inline void hdmi_wq_set_audio(struct hdmi *hdmi)
70 if (hdmi->ops->setaudio)
71 hdmi->ops->setaudio(hdmi, &hdmi->audio);
74 static void hdmi_wq_set_video(struct hdmi *hdmi)
76 struct hdmi_video video;
81 video.vic = hdmi->vic & HDMI_VIC_MASK;
82 video.sink_hdmi = hdmi->edid.sink_hdmi;
83 video.format_3d = hdmi->mode_3d;
85 /* For DVI, output RGB */
86 if (hdmi->edid.sink_hdmi == 0) {
87 video.color_output = HDMI_COLOR_RGB_0_255;
89 if (hdmi->colormode == HDMI_COLOR_AUTO) {
90 if (hdmi->edid.ycbcr444)
91 video.color_output = HDMI_COLOR_YCBCR444;
92 else if (hdmi->edid.ycbcr422)
93 video.color_output = HDMI_COLOR_YCBCR422;
95 video.color_output = HDMI_COLOR_RGB_16_235;
97 video.color_output = hdmi->colormode;
100 if (hdmi->vic & HDMI_VIDEO_YUV420) {
101 video.color_output = HDMI_COLOR_YCBCR420;
102 deepcolor = hdmi->edid.deepcolor_420;
104 deepcolor = hdmi->edid.deepcolor;
106 if ((hdmi->property->feature & SUPPORT_DEEP_10BIT) &&
107 (deepcolor & HDMI_DEEP_COLOR_30BITS)) {
108 if (hdmi->colordepth == HDMI_DEPP_COLOR_AUTO ||
109 hdmi->colordepth == 10)
110 video.color_output_depth = 10;
112 video.color_output_depth = 8;
115 pr_info("hdmi output corlor mode is %d\n", video.color_output);
116 video.color_input = HDMI_COLOR_RGB_0_255;
117 if (hdmi->property->feature & SUPPORT_YCBCR_INPUT) {
118 if (video.color_output == HDMI_COLOR_YCBCR444 ||
119 video.color_output == HDMI_COLOR_YCBCR422)
120 video.color_input = HDMI_COLOR_YCBCR444;
121 else if (video.color_output == HDMI_COLOR_YCBCR420)
122 video.color_input = HDMI_COLOR_YCBCR420;
124 hdmi->colormode_input = video.color_input;
126 if (hdmi->ops->setvideo)
127 hdmi->ops->setvideo(hdmi, &video);
130 static void hdmi_wq_parse_edid(struct hdmi *hdmi)
132 struct hdmi_edid *pedid;
134 int rc = HDMI_ERROR_SUCESS, extendblock = 0, i, trytimes;
141 pedid = &(hdmi->edid);
142 fb_destroy_modelist(&pedid->modelist);
143 memset(pedid, 0, sizeof(struct hdmi_edid));
144 INIT_LIST_HEAD(&pedid->modelist);
146 pedid->raw[0] = kmalloc(HDMI_EDID_BLOCK_SIZE, GFP_KERNEL);
147 if (pedid->raw[0] == NULL) {
149 "[%s] can not allocate memory for edid buff.\n",
151 rc = HDMI_ERROR_FALSE;
155 if (hdmi->ops->getedid == NULL) {
156 rc = HDMI_ERROR_FALSE;
160 /* Read base block edid.*/
161 for (trytimes = 0; trytimes < 3; trytimes++) {
164 memset(pedid->raw[0], 0 , HDMI_EDID_BLOCK_SIZE);
165 rc = hdmi->ops->getedid(hdmi, 0, pedid->raw[0]);
168 "[HDMI] read edid base block error\n");
172 rc = hdmi_edid_parse_base(pedid->raw[0], &extendblock, pedid);
175 "[HDMI] parse edid base block error\n");
184 for (i = 1; (i < extendblock + 1) && (i < HDMI_MAX_EDID_BLOCK); i++) {
185 pedid->raw[i] = kmalloc(HDMI_EDID_BLOCK_SIZE, GFP_KERNEL);
186 if (pedid->raw[i] == NULL) {
188 "[%s] can not allocate memory for edid buff.\n",
190 rc = HDMI_ERROR_FALSE;
193 for (trytimes = 0; trytimes < 3; trytimes++) {
196 memset(pedid->raw[i], 0 , HDMI_EDID_BLOCK_SIZE);
197 rc = hdmi->ops->getedid(hdmi, i, pedid->raw[i]);
200 "[HDMI] read edid block %d error\n",
205 rc = hdmi_edid_parse_extensions(pedid->raw[i], pedid);
208 "[HDMI] parse edid block %d error\n",
218 rc = hdmi_ouputmode_select(hdmi, rc);
221 static void hdmi_wq_insert(struct hdmi *hdmi)
224 if (hdmi->ops->insert)
225 hdmi->ops->insert(hdmi);
226 hdmi_wq_parse_edid(hdmi);
227 if (hdmi->property->feature & SUPPORT_CEC)
228 rockchip_hdmi_cec_set_pa(hdmi->edid.cecaddress);
229 hdmi_send_uevent(hdmi, KOBJ_ADD);
231 /*hdmi->autoset = 0;*/
232 hdmi_wq_set_video(hdmi);
234 switch_set_state(&(hdmi->switchdev), 1);
236 hdmi_wq_set_audio(hdmi);
237 hdmi_wq_set_output(hdmi, hdmi->mute);
238 hdmi_submit_work(hdmi, HDMI_ENABLE_HDCP, 100, NULL);
239 if (hdmi->ops->setcec)
240 hdmi->ops->setcec(hdmi);
246 static void hdmi_wq_remove(struct hdmi *hdmi)
248 struct list_head *pos, *n;
249 struct rk_screen screen;
253 if (hdmi->ops->remove)
254 hdmi->ops->remove(hdmi);
255 if (hdmi->hotplug == HDMI_HPD_ACTIVED) {
256 screen.type = SCREEN_HDMI;
257 rk_fb_switch_screen(&screen, 0, hdmi->lcdc->id);
260 switch_set_state(&(hdmi->switchdev), 0);
262 mutex_lock(&hdmi->ddev->lock);
263 list_for_each_safe(pos, n, &hdmi->edid.modelist) {
267 mutex_unlock(&hdmi->ddev->lock);
268 for (i = 0; i < HDMI_MAX_EDID_BLOCK; i++)
269 kfree(hdmi->edid.raw[i]);
270 kfree(hdmi->edid.audio);
271 if (hdmi->edid.specs) {
272 kfree(hdmi->edid.specs->modedb);
273 kfree(hdmi->edid.specs);
275 memset(&hdmi->edid, 0, sizeof(struct hdmi_edid));
276 hdmi_init_modelist(hdmi);
277 hdmi->mute = HDMI_AV_UNMUTE;
278 hdmi->mode_3d = HDMI_3D_NONE;
280 hdmi->hotplug = HDMI_HPD_REMOVED;
281 hdmi_send_uevent(hdmi, KOBJ_REMOVE);
284 static void hdmi_work_queue(struct work_struct *work)
286 struct hdmi_delayed_work *hdmi_w =
287 container_of(work, struct hdmi_delayed_work, work.work);
288 struct hdmi *hdmi = hdmi_w->hdmi;
289 int event = hdmi_w->event;
290 int hpd = HDMI_HPD_REMOVED;
292 mutex_lock(&hdmi->lock);
294 DBG("\nhdmi_work_queue() - evt= %x %d\n",
295 (event & 0xFF00) >> 8,
299 case HDMI_ENABLE_CTL:
303 if (hdmi->ops->enable)
304 hdmi->ops->enable(hdmi);
305 if (hdmi->hotplug == HDMI_HPD_ACTIVED)
306 hdmi_wq_insert(hdmi);
310 case HDMI_RESUME_CTL:
312 if (hdmi->ops->enable)
313 hdmi->ops->enable(hdmi);
317 case HDMI_DISABLE_CTL:
320 if (hdmi->ops->disable)
321 hdmi->ops->disable(hdmi);
322 hdmi_wq_remove(hdmi);
327 case HDMI_SUSPEND_CTL:
329 hdmi_wq_set_output(hdmi,
330 HDMI_VIDEO_MUTE | HDMI_AUDIO_MUTE);
331 if (hdmi->ops->disable)
332 hdmi->ops->disable(hdmi);
334 hdmi_wq_remove(hdmi);
338 case HDMI_HPD_CHANGE:
339 if (hdmi->ops->getstatus)
340 hpd = hdmi->ops->getstatus(hdmi);
341 DBG("hdmi_work_queue() - hpd is %d hotplug is %d",
343 if (hpd != hdmi->hotplug) {
344 if (hpd == HDMI_HPD_ACTIVED) {
346 hdmi_wq_insert(hdmi);
347 } else if (hdmi->hotplug == HDMI_HPD_ACTIVED) {
348 hdmi_wq_remove(hdmi);
354 if (hdmi->enable && !hdmi->sleep) {
355 hdmi_wq_set_output(hdmi,
356 HDMI_VIDEO_MUTE | HDMI_AUDIO_MUTE);
357 if (rk_fb_get_display_policy() == DISPLAY_POLICY_BOX)
361 hdmi_wq_set_video(hdmi);
362 hdmi_send_uevent(hdmi, KOBJ_CHANGE);
363 hdmi_wq_set_audio(hdmi);
364 hdmi_wq_set_output(hdmi, hdmi->mute);
365 if (hdmi->ops->hdcp_cb)
366 hdmi->ops->hdcp_cb(hdmi);
370 if ((hdmi->mute & HDMI_AUDIO_MUTE) == 0 &&
371 hdmi->enable && !hdmi->sleep) {
372 hdmi_wq_set_output(hdmi, HDMI_AUDIO_MUTE);
373 hdmi_wq_set_audio(hdmi);
374 hdmi_wq_set_output(hdmi, hdmi->mute);
377 case HDMI_MUTE_AUDIO:
378 case HDMI_UNMUTE_AUDIO:
379 if (hdmi->mute & HDMI_AUDIO_MUTE ||
380 !hdmi->enable || hdmi->sleep ||
381 hdmi->hotplug != HDMI_HPD_ACTIVED)
383 if (event == HDMI_MUTE_AUDIO)
384 hdmi_wq_set_output(hdmi, hdmi->mute |
387 hdmi_wq_set_output(hdmi,
388 hdmi->mute & (~HDMI_AUDIO_MUTE));
391 if (hdmi->ops->setvsi) {
392 if (hdmi->mode_3d != HDMI_3D_NONE)
393 hdmi->ops->setvsi(hdmi, hdmi->mode_3d,
394 HDMI_VIDEO_FORMAT_3D);
395 else if ((hdmi->vic & HDMI_TYPE_MASK) == 0)
396 hdmi->ops->setvsi(hdmi, hdmi->vic,
397 HDMI_VIDEO_FORMAT_NORMAL);
401 hdmi_wq_set_output(hdmi,
402 HDMI_VIDEO_MUTE | HDMI_AUDIO_MUTE);
404 hdmi_wq_set_video(hdmi);
405 hdmi_wq_set_output(hdmi, hdmi->mute);
407 case HDMI_ENABLE_HDCP:
408 if (hdmi->hotplug == HDMI_HPD_ACTIVED && hdmi->ops->hdcp_cb)
409 hdmi->ops->hdcp_cb(hdmi);
411 case HDMI_HDCP_AUTH_2ND:
412 if (hdmi->hotplug == HDMI_HPD_ACTIVED &&
413 hdmi->ops->hdcp_auth2nd)
414 hdmi->ops->hdcp_auth2nd(hdmi);
417 pr_err("HDMI: hdmi_work_queue() unkown event\n");
424 DBG("\nhdmi_work_queue() - exit evt= %x %d\n",
425 (event & 0xFF00) >> 8,
427 mutex_unlock(&hdmi->lock);
430 struct hdmi *rockchip_hdmi_register(struct hdmi_property *property,
431 struct hdmi_ops *ops)
437 if (property == NULL || ops == NULL) {
438 pr_err("HDMI: %s invalid parameter\n", __func__);
442 for (i = 0; i < HDMI_MAX_ID; i++) {
443 if (ref_info[i].ref == 0)
446 if (i == HDMI_MAX_ID)
449 DBG("hdmi_register() - video source %d display %d",
450 property->videosrc, property->display);
452 hdmi = kmalloc(sizeof(*hdmi), GFP_KERNEL);
454 pr_err("HDMI: no memory to allocate hdmi device.\n");
457 memset(hdmi, 0, sizeof(struct hdmi));
458 mutex_init(&hdmi->lock);
460 hdmi->property = property;
462 hdmi->enable = false;
463 hdmi->mute = HDMI_AV_UNMUTE;
464 hdmi->hotplug = HDMI_HPD_REMOVED;
465 hdmi->autoset = HDMI_AUTO_CONFIG;
467 hdmi->vic = uboot_vic;
470 } else if (hdmi->autoset) {
473 hdmi->vic = hdmi->property->defaultmode;
475 hdmi->colormode = HDMI_VIDEO_DEFAULT_COLORMODE;
476 hdmi->colordepth = HDMI_DEPP_COLOR_AUTO;
477 hdmi->mode_3d = HDMI_3D_NONE;
478 hdmi->audio.type = HDMI_AUDIO_DEFAULT_TYPE;
479 hdmi->audio.channel = HDMI_AUDIO_DEFAULT_CHANNEL;
480 hdmi->audio.rate = HDMI_AUDIO_DEFAULT_RATE;
481 hdmi->audio.word_length = HDMI_AUDIO_DEFAULT_WORDLENGTH;
484 hdmi_init_modelist(hdmi);
486 if (hdmi->property->videosrc == DISPLAY_SOURCE_LCDC0)
487 hdmi->lcdc = rk_get_lcdc_drv("lcdc0");
489 hdmi->lcdc = rk_get_lcdc_drv("lcdc1");
491 if (hdmi->lcdc->prop == EXTEND)
492 hdmi->property->display = DISPLAY_AUX;
494 hdmi->property->display = DISPLAY_MAIN;
496 sprintf(name, "hdmi-%s", hdmi->property->name);
497 hdmi->workqueue = create_singlethread_workqueue(name);
498 if (hdmi->workqueue == NULL) {
499 pr_err("HDMI,: create workqueue failed.\n");
502 hdmi->ddev = hdmi_register_display_sysfs(hdmi, NULL);
503 if (hdmi->ddev == NULL) {
504 pr_err("HDMI : register display sysfs failed.\n");
505 goto err_register_display;
510 hdmi->switchdev.name = "hdmi";
512 hdmi->switchdev.name = kzalloc(32, GFP_KERNEL);
513 memset((char *)hdmi->switchdev.name, 0, 32);
514 sprintf((char *)hdmi->switchdev.name, "hdmi%d", hdmi->id);
516 switch_dev_register(&(hdmi->switchdev));
519 ref_info[i].hdmi = hdmi;
523 err_register_display:
524 destroy_workqueue(hdmi->workqueue);
530 void rockchip_hdmi_unregister(struct hdmi *hdmi)
533 flush_workqueue(hdmi->workqueue);
534 destroy_workqueue(hdmi->workqueue);
536 switch_dev_unregister(&(hdmi->switchdev));
538 hdmi_unregister_display_sysfs(hdmi);
539 fb_destroy_modelist(&hdmi->edid.modelist);
540 kfree(hdmi->edid.audio);
541 if (hdmi->edid.specs) {
542 kfree(hdmi->edid.specs->modedb);
543 kfree(hdmi->edid.specs);
547 ref_info[hdmi->id].ref = 0;
548 ref_info[hdmi->id].hdmi = NULL;
554 int hdmi_get_hotplug(void)
556 if (ref_info[0].hdmi)
557 return ref_info[0].hdmi->hotplug;
559 return HDMI_HPD_REMOVED;
562 int hdmi_config_audio(struct hdmi_audio *audio)
568 return HDMI_ERROR_FALSE;
570 for (i = 0; i < HDMI_MAX_ID; i++) {
571 if (ref_info[i].ref == 0)
573 hdmi = ref_info[i].hdmi;
576 if (memcmp(audio, &hdmi->audio, sizeof(struct hdmi_audio)) == 0)
579 /*for (j = 0; j < hdmi->edid.audio_num; j++) {
580 if (audio->type == hdmi->edid.audio_num)
584 /*if ( (j == hdmi->edid.audio_num) ||
585 (audio->channel > hdmi->edid.audio[j].channel) ||
586 ((audio->rate & hdmi->edid.audio[j].rate) == 0)||
587 ((audio->type == HDMI_AUDIO_LPCM) &&
588 ((audio->word_length &
589 hdmi->edid.audio[j].word_length) == 0)) ) {
590 pr_warn("[%s] warning : input audio type
591 not supported in hdmi sink\n", __func__);
594 memcpy(&hdmi->audio, audio, sizeof(struct hdmi_audio));
595 if (hdmi->hotplug == HDMI_HPD_ACTIVED)
596 hdmi_submit_work(hdmi, HDMI_SET_AUDIO, 0, NULL);
601 void hdmi_audio_mute(int mute)
606 for (i = 0; i < HDMI_MAX_ID; i++) {
607 if (ref_info[i].ref == 0)
609 hdmi = ref_info[i].hdmi;
612 hdmi_submit_work(hdmi, HDMI_MUTE_AUDIO, 0, NULL);
614 hdmi_submit_work(hdmi, HDMI_UNMUTE_AUDIO, 0, NULL);
618 static int __init bootloader_setup(char *str)
621 pr_info("hdmi init vic is %s\n", str);
622 if (kstrtoint(str, 0, &uboot_vic) < 0)
628 early_param("hdmi.vic", bootloader_setup);
630 static int __init hdmi_class_init(void)
634 for (i = 0; i < HDMI_MAX_ID; i++) {
637 ref_info[i].hdmi = NULL;
639 pr_info("Rockchip hdmi driver version 2.0\n.");
643 subsys_initcall(hdmi_class_init);