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;
80 video.vic = hdmi->vic & HDMI_VIC_MASK;
81 if (hdmi->vic & HDMI_VIDEO_YUV420)
82 video.color_input = HDMI_COLOR_YCBCR420;
83 else if (hdmi->edid.sink_hdmi == 0)
84 video.color_input = HDMI_COLOR_RGB_0_255;
86 video.color_input = HDMI_COLOR_YCBCR444;
87 video.sink_hdmi = hdmi->edid.sink_hdmi;
88 video.format_3d = hdmi->mode_3d;
89 /* For DVI, output RGB */
90 if (hdmi->edid.sink_hdmi == 0) {
91 video.color_output = HDMI_COLOR_RGB_0_255;
93 if (hdmi->colormode == HDMI_COLOR_AUTO) {
94 if (hdmi->edid.ycbcr444)
95 video.color_output = HDMI_COLOR_YCBCR444;
96 else if (hdmi->edid.ycbcr422)
97 video.color_output = HDMI_COLOR_YCBCR422;
99 video.color_output = HDMI_COLOR_RGB_16_235;
101 video.color_output = hdmi->colormode;
104 if ((hdmi->property->feature & SUPPORT_DEEP_10BIT) &&
105 (hdmi->edid.deepcolor & HDMI_DEEP_COLOR_30BITS)) {
106 if (hdmi->colordepth == HDMI_DEPP_COLOR_AUTO ||
107 hdmi->colordepth == 10)
108 video.color_output_depth = 10;
110 video.color_output_depth = 8;
112 if (hdmi->vic & HDMI_VIDEO_YUV420)
113 video.color_output = HDMI_COLOR_YCBCR420;
114 pr_info("hdmi output corlor mode is %d\n", video.color_output);
115 if (hdmi->ops->setvideo)
116 hdmi->ops->setvideo(hdmi, &video);
119 static void hdmi_wq_parse_edid(struct hdmi *hdmi)
121 struct hdmi_edid *pedid;
122 unsigned char *buff = NULL;
123 int rc = HDMI_ERROR_SUCESS, extendblock = 0, i, trytimes;
130 pedid = &(hdmi->edid);
131 fb_destroy_modelist(&pedid->modelist);
132 memset(pedid, 0, sizeof(struct hdmi_edid));
133 INIT_LIST_HEAD(&pedid->modelist);
135 buff = kmalloc(HDMI_EDID_BLOCK_SIZE, GFP_KERNEL);
138 "[%s] can not allocate memory for edid buff.\n",
140 rc = HDMI_ERROR_FALSE;
144 if (hdmi->ops->getedid == NULL) {
145 rc = HDMI_ERROR_FALSE;
149 /* Read base block edid.*/
150 for (trytimes = 0; trytimes < 3; trytimes++) {
153 memset(buff, 0 , HDMI_EDID_BLOCK_SIZE);
154 rc = hdmi->ops->getedid(hdmi, 0, buff);
157 "[HDMI] read edid base block error\n");
161 rc = hdmi_edid_parse_base(buff, &extendblock, pedid);
164 "[HDMI] parse edid base block error\n");
173 for (i = 1; i < extendblock + 1; i++) {
174 for (trytimes = 0; trytimes < 3; trytimes++) {
177 memset(buff, 0 , HDMI_EDID_BLOCK_SIZE);
178 rc = hdmi->ops->getedid(hdmi, i, buff);
181 "[HDMI] read edid block %d error\n",
186 rc = hdmi_edid_parse_extensions(buff, pedid);
189 "[HDMI] parse edid block %d error\n",
200 rc = hdmi_ouputmode_select(hdmi, rc);
203 static void hdmi_wq_insert(struct hdmi *hdmi)
206 if (hdmi->ops->insert)
207 hdmi->ops->insert(hdmi);
208 hdmi_wq_parse_edid(hdmi);
209 if (hdmi->property->feature & SUPPORT_CEC)
210 rockchip_hdmi_cec_set_pa(hdmi->edid.cecaddress);
211 hdmi_send_uevent(hdmi, KOBJ_ADD);
215 hdmi_wq_set_video(hdmi);
217 if ((hdmi->edid.baseaudio_support &&
218 hdmi->edid.sink_hdmi) ||
219 rk_fb_get_display_policy() == DISPLAY_POLICY_BOX)
220 switch_set_state(&(hdmi->switchdev), 1);
222 hdmi_wq_set_audio(hdmi);
223 hdmi_wq_set_output(hdmi, hdmi->mute);
224 if (hdmi->ops->hdcp_cb)
225 hdmi->ops->hdcp_cb(hdmi);
226 if (hdmi->ops->setcec)
227 hdmi->ops->setcec(hdmi);
233 static void hdmi_wq_remove(struct hdmi *hdmi)
235 struct list_head *pos, *n;
236 struct rk_screen screen;
239 if (hdmi->ops->remove)
240 hdmi->ops->remove(hdmi);
242 if ((hdmi->edid.baseaudio_support &&
243 hdmi->edid.sink_hdmi) ||
244 rk_fb_get_display_policy() == DISPLAY_POLICY_BOX)
245 switch_set_state(&(hdmi->switchdev), 0);
247 list_for_each_safe(pos, n, &hdmi->edid.modelist) {
252 kfree(hdmi->edid.audio);
254 if (hdmi->edid.specs) {
255 kfree(hdmi->edid.specs->modedb);
256 kfree(hdmi->edid.specs);
258 memset(&hdmi->edid, 0, sizeof(struct hdmi_edid));
259 hdmi_init_modelist(hdmi);
260 hdmi->mute = HDMI_AV_UNMUTE;
261 hdmi->mode_3d = HDMI_3D_NONE;
263 if (hdmi->hotplug == HDMI_HPD_ACTIVED) {
264 screen.type = SCREEN_HDMI;
265 rk_fb_switch_screen(&screen, 0, hdmi->lcdc->id);
267 hdmi->hotplug = HDMI_HPD_REMOVED;
268 hdmi_send_uevent(hdmi, KOBJ_REMOVE);
271 static void hdmi_work_queue(struct work_struct *work)
273 struct hdmi_delayed_work *hdmi_w =
274 container_of(work, struct hdmi_delayed_work, work.work);
275 struct hdmi *hdmi = hdmi_w->hdmi;
276 int event = hdmi_w->event;
277 int hpd = HDMI_HPD_REMOVED;
279 mutex_lock(&hdmi->lock);
281 DBG("\nhdmi_work_queue() - evt= %x %d\n",
282 (event & 0xFF00) >> 8,
286 case HDMI_ENABLE_CTL:
290 if (hdmi->ops->enable)
291 hdmi->ops->enable(hdmi);
292 if (hdmi->hotplug == HDMI_HPD_ACTIVED)
293 hdmi_wq_insert(hdmi);
297 case HDMI_RESUME_CTL:
299 if (hdmi->ops->enable)
300 hdmi->ops->enable(hdmi);
304 case HDMI_DISABLE_CTL:
308 if (hdmi->ops->disable)
309 hdmi->ops->disable(hdmi);
311 hdmi_wq_remove(hdmi);
316 case HDMI_SUSPEND_CTL:
318 hdmi_wq_set_output(hdmi,
319 HDMI_VIDEO_MUTE | HDMI_AUDIO_MUTE);
320 if (hdmi->ops->disable)
321 hdmi->ops->disable(hdmi);
323 hdmi_wq_remove(hdmi);
327 case HDMI_HPD_CHANGE:
328 if (hdmi->ops->getstatus)
329 hpd = hdmi->ops->getstatus(hdmi);
330 DBG("hdmi_work_queue() - hpd is %d hotplug is %d",
332 if (hpd != hdmi->hotplug) {
333 if (hpd == HDMI_HPD_ACTIVED) {
335 hdmi_wq_insert(hdmi);
336 } else if (hdmi->hotplug == HDMI_HPD_ACTIVED) {
337 hdmi_wq_remove(hdmi);
343 if (hdmi->enable && !hdmi->sleep) {
344 hdmi_wq_set_output(hdmi,
345 HDMI_VIDEO_MUTE | HDMI_AUDIO_MUTE);
346 if (rk_fb_get_display_policy() == DISPLAY_POLICY_BOX)
351 hdmi_send_uevent(hdmi, KOBJ_CHANGE);
352 hdmi_wq_set_video(hdmi);
353 hdmi_wq_set_audio(hdmi);
354 hdmi_wq_set_output(hdmi, hdmi->mute);
355 if (hdmi->ops->hdcp_cb)
356 hdmi->ops->hdcp_cb(hdmi);
360 if ((hdmi->mute & HDMI_AUDIO_MUTE) == 0 &&
361 hdmi->enable && !hdmi->sleep) {
362 hdmi_wq_set_output(hdmi, HDMI_AUDIO_MUTE);
363 hdmi_wq_set_audio(hdmi);
364 hdmi_wq_set_output(hdmi, hdmi->mute);
367 case HDMI_MUTE_AUDIO:
368 case HDMI_UNMUTE_AUDIO:
369 if (hdmi->mute & HDMI_AUDIO_MUTE ||
370 !hdmi->enable || hdmi->sleep ||
371 hdmi->hotplug != HDMI_HPD_ACTIVED)
373 if (event == HDMI_MUTE_AUDIO)
374 hdmi_wq_set_output(hdmi, hdmi->mute |
377 hdmi_wq_set_output(hdmi,
378 hdmi->mute & (~HDMI_AUDIO_MUTE));
381 if (hdmi->ops->setvsi) {
382 if (hdmi->mode_3d != HDMI_3D_NONE)
383 hdmi->ops->setvsi(hdmi, hdmi->mode_3d,
384 HDMI_VIDEO_FORMAT_3D);
385 else if ((hdmi->vic & HDMI_TYPE_MASK) == 0)
386 hdmi->ops->setvsi(hdmi, hdmi->vic,
387 HDMI_VIDEO_FORMAT_NORMAL);
391 hdmi_wq_set_output(hdmi,
392 HDMI_VIDEO_MUTE | HDMI_AUDIO_MUTE);
394 hdmi_wq_set_video(hdmi);
395 hdmi_wq_set_output(hdmi, hdmi->mute);
397 case HDMI_ENABLE_HDCP:
398 if (hdmi->hotplug == HDMI_HPD_ACTIVED && hdmi->ops->hdcp_cb)
399 hdmi->ops->hdcp_cb(hdmi);
402 pr_err("HDMI: hdmi_work_queue() unkown event\n");
409 DBG("\nhdmi_work_queue() - exit evt= %x %d\n",
410 (event & 0xFF00) >> 8,
412 mutex_unlock(&hdmi->lock);
415 struct hdmi *rockchip_hdmi_register(struct hdmi_property *property,
416 struct hdmi_ops *ops)
422 if (property == NULL || ops == NULL) {
423 pr_err("HDMI: %s invalid parameter\n", __func__);
427 for (i = 0; i < HDMI_MAX_ID; i++) {
428 if (ref_info[i].ref == 0)
431 if (i == HDMI_MAX_ID)
434 DBG("hdmi_register() - video source %d display %d",
435 property->videosrc, property->display);
437 hdmi = kmalloc(sizeof(*hdmi), GFP_KERNEL);
439 pr_err("HDMI: no memory to allocate hdmi device.\n");
442 memset(hdmi, 0, sizeof(struct hdmi));
443 mutex_init(&hdmi->lock);
445 hdmi->property = property;
447 hdmi->enable = false;
448 hdmi->mute = HDMI_AV_UNMUTE;
449 hdmi->hotplug = HDMI_HPD_REMOVED;
450 hdmi->autoset = HDMI_AUTO_CONFIG;
452 hdmi->vic = uboot_vic;
455 } else if (hdmi->autoset) {
458 hdmi->vic = HDMI_VIDEO_DEFAULT_MODE;
460 hdmi->colormode = HDMI_VIDEO_DEFAULT_COLORMODE;
461 hdmi->colordepth = HDMI_DEPP_COLOR_AUTO;
462 hdmi->mode_3d = HDMI_3D_NONE;
463 hdmi->audio.type = HDMI_AUDIO_DEFAULT_TYPE;
464 hdmi->audio.channel = HDMI_AUDIO_DEFAULT_CHANNEL;
465 hdmi->audio.rate = HDMI_AUDIO_DEFAULT_RATE;
466 hdmi->audio.word_length = HDMI_AUDIO_DEFAULT_WORDLENGTH;
469 hdmi_init_modelist(hdmi);
471 #ifndef CONFIG_ARCH_RK29
472 if (hdmi->property->videosrc == DISPLAY_SOURCE_LCDC0)
473 hdmi->lcdc = rk_get_lcdc_drv("lcdc0");
475 hdmi->lcdc = rk_get_lcdc_drv("lcdc1");
478 sprintf(name, "hdmi-%s", hdmi->property->name);
479 hdmi->workqueue = create_singlethread_workqueue(name);
480 if (hdmi->workqueue == NULL) {
481 pr_err("HDMI,: create workqueue failed.\n");
484 hdmi->ddev = hdmi_register_display_sysfs(hdmi, NULL);
485 if (hdmi->ddev == NULL) {
486 pr_err("HDMI : register display sysfs failed.\n");
487 goto err_register_display;
492 hdmi->switchdev.name = "hdmi";
494 hdmi->switchdev.name = kzalloc(32, GFP_KERNEL);
495 memset((char *)hdmi->switchdev.name, 0, 32);
496 sprintf((char *)hdmi->switchdev.name, "hdmi%d", hdmi->id);
498 switch_dev_register(&(hdmi->switchdev));
501 ref_info[i].hdmi = hdmi;
505 err_register_display:
506 destroy_workqueue(hdmi->workqueue);
512 void rockchip_hdmi_unregister(struct hdmi *hdmi)
515 flush_workqueue(hdmi->workqueue);
516 destroy_workqueue(hdmi->workqueue);
518 switch_dev_unregister(&(hdmi->switchdev));
520 hdmi_unregister_display_sysfs(hdmi);
521 fb_destroy_modelist(&hdmi->edid.modelist);
522 kfree(hdmi->edid.audio);
523 if (hdmi->edid.specs) {
524 kfree(hdmi->edid.specs->modedb);
525 kfree(hdmi->edid.specs);
529 ref_info[hdmi->id].ref = 0;
530 ref_info[hdmi->id].hdmi = NULL;
536 int hdmi_get_hotplug(void)
538 if (ref_info[0].hdmi)
539 return ref_info[0].hdmi->hotplug;
541 return HDMI_HPD_REMOVED;
544 int hdmi_config_audio(struct hdmi_audio *audio)
550 return HDMI_ERROR_FALSE;
552 for (i = 0; i < HDMI_MAX_ID; i++) {
553 if (ref_info[i].ref == 0)
555 hdmi = ref_info[i].hdmi;
558 if (memcmp(audio, &hdmi->audio, sizeof(struct hdmi_audio)) == 0)
561 /*for (j = 0; j < hdmi->edid.audio_num; j++) {
562 if (audio->type == hdmi->edid.audio_num)
566 /*if ( (j == hdmi->edid.audio_num) ||
567 (audio->channel > hdmi->edid.audio[j].channel) ||
568 ((audio->rate & hdmi->edid.audio[j].rate) == 0)||
569 ((audio->type == HDMI_AUDIO_LPCM) &&
570 ((audio->word_length &
571 hdmi->edid.audio[j].word_length) == 0)) ) {
572 pr_warn("[%s] warning : input audio type
573 not supported in hdmi sink\n", __func__);
576 memcpy(&hdmi->audio, audio, sizeof(struct hdmi_audio));
577 hdmi_submit_work(hdmi, HDMI_SET_AUDIO, 0, NULL);
582 void hdmi_audio_mute(int mute)
587 for (i = 0; i < HDMI_MAX_ID; i++) {
588 if (ref_info[i].ref == 0)
590 hdmi = ref_info[i].hdmi;
593 hdmi_submit_work(hdmi, HDMI_MUTE_AUDIO, 0, NULL);
595 hdmi_submit_work(hdmi, HDMI_UNMUTE_AUDIO, 0, NULL);
599 static int __init bootloader_setup(char *str)
602 pr_info("hdmi init vic is %s\n", str);
603 if (kstrtoint(str, 0, &uboot_vic) < 0)
609 early_param("hdmi.vic", bootloader_setup);
611 static int __init hdmi_class_init(void)
615 for (i = 0; i < HDMI_MAX_ID; i++) {
618 ref_info[i].hdmi = NULL;
620 pr_info("Rockchip hdmi driver version 2.0\n.");
624 subsys_initcall(hdmi_class_init);