diff options
-rw-r--r-- | drivers/video/omap2/dss/hdmi.c | 234 | ||||
-rw-r--r-- | include/video/omapdss.h | 44 |
2 files changed, 267 insertions, 11 deletions
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index 2b0a2aac8aed..44a885b92825 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c | |||
@@ -70,6 +70,8 @@ static struct { | |||
70 | int ls_oe_gpio; | 70 | int ls_oe_gpio; |
71 | int hpd_gpio; | 71 | int hpd_gpio; |
72 | 72 | ||
73 | bool core_enabled; | ||
74 | |||
73 | struct omap_dss_device output; | 75 | struct omap_dss_device output; |
74 | } hdmi; | 76 | } hdmi; |
75 | 77 | ||
@@ -515,8 +517,10 @@ static int hdmi_power_on_core(struct omap_dss_device *dssdev) | |||
515 | { | 517 | { |
516 | int r; | 518 | int r; |
517 | 519 | ||
518 | gpio_set_value(hdmi.ct_cp_hpd_gpio, 1); | 520 | if (gpio_is_valid(hdmi.ct_cp_hpd_gpio)) |
519 | gpio_set_value(hdmi.ls_oe_gpio, 1); | 521 | gpio_set_value(hdmi.ct_cp_hpd_gpio, 1); |
522 | if (gpio_is_valid(hdmi.ls_oe_gpio)) | ||
523 | gpio_set_value(hdmi.ls_oe_gpio, 1); | ||
520 | 524 | ||
521 | /* wait 300us after CT_CP_HPD for the 5V power output to reach 90% */ | 525 | /* wait 300us after CT_CP_HPD for the 5V power output to reach 90% */ |
522 | udelay(300); | 526 | udelay(300); |
@@ -532,22 +536,30 @@ static int hdmi_power_on_core(struct omap_dss_device *dssdev) | |||
532 | /* Make selection of HDMI in DSS */ | 536 | /* Make selection of HDMI in DSS */ |
533 | dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK); | 537 | dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK); |
534 | 538 | ||
539 | hdmi.core_enabled = true; | ||
540 | |||
535 | return 0; | 541 | return 0; |
536 | 542 | ||
537 | err_runtime_get: | 543 | err_runtime_get: |
538 | regulator_disable(hdmi.vdda_hdmi_dac_reg); | 544 | regulator_disable(hdmi.vdda_hdmi_dac_reg); |
539 | err_vdac_enable: | 545 | err_vdac_enable: |
540 | gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); | 546 | if (gpio_is_valid(hdmi.ct_cp_hpd_gpio)) |
541 | gpio_set_value(hdmi.ls_oe_gpio, 0); | 547 | gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); |
548 | if (gpio_is_valid(hdmi.ls_oe_gpio)) | ||
549 | gpio_set_value(hdmi.ls_oe_gpio, 0); | ||
542 | return r; | 550 | return r; |
543 | } | 551 | } |
544 | 552 | ||
545 | static void hdmi_power_off_core(struct omap_dss_device *dssdev) | 553 | static void hdmi_power_off_core(struct omap_dss_device *dssdev) |
546 | { | 554 | { |
555 | hdmi.core_enabled = false; | ||
556 | |||
547 | hdmi_runtime_put(); | 557 | hdmi_runtime_put(); |
548 | regulator_disable(hdmi.vdda_hdmi_dac_reg); | 558 | regulator_disable(hdmi.vdda_hdmi_dac_reg); |
549 | gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); | 559 | if (gpio_is_valid(hdmi.ct_cp_hpd_gpio)) |
550 | gpio_set_value(hdmi.ls_oe_gpio, 0); | 560 | gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); |
561 | if (gpio_is_valid(hdmi.ls_oe_gpio)) | ||
562 | gpio_set_value(hdmi.ls_oe_gpio, 0); | ||
551 | } | 563 | } |
552 | 564 | ||
553 | static int hdmi_power_on_full(struct omap_dss_device *dssdev) | 565 | static int hdmi_power_on_full(struct omap_dss_device *dssdev) |
@@ -662,6 +674,18 @@ void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev, | |||
662 | mutex_unlock(&hdmi.lock); | 674 | mutex_unlock(&hdmi.lock); |
663 | } | 675 | } |
664 | 676 | ||
677 | static void omapdss_hdmi_display_get_timings(struct omap_dss_device *dssdev, | ||
678 | struct omap_video_timings *timings) | ||
679 | { | ||
680 | const struct hdmi_config *cfg; | ||
681 | |||
682 | cfg = hdmi_get_timings(); | ||
683 | if (cfg == NULL) | ||
684 | cfg = &vesa_timings[0]; | ||
685 | |||
686 | memcpy(timings, &cfg->timings, sizeof(cfg->timings)); | ||
687 | } | ||
688 | |||
665 | static void hdmi_dump_regs(struct seq_file *s) | 689 | static void hdmi_dump_regs(struct seq_file *s) |
666 | { | 690 | { |
667 | mutex_lock(&hdmi.lock); | 691 | mutex_lock(&hdmi.lock); |
@@ -1025,6 +1049,199 @@ static int hdmi_probe_pdata(struct platform_device *pdev) | |||
1025 | return 0; | 1049 | return 0; |
1026 | } | 1050 | } |
1027 | 1051 | ||
1052 | static int hdmi_connect(struct omap_dss_device *dssdev, | ||
1053 | struct omap_dss_device *dst) | ||
1054 | { | ||
1055 | struct omap_overlay_manager *mgr; | ||
1056 | int r; | ||
1057 | |||
1058 | dss_init_hdmi_ip_ops(&hdmi.ip_data, omapdss_get_version()); | ||
1059 | |||
1060 | r = hdmi_init_regulator(); | ||
1061 | if (r) | ||
1062 | return r; | ||
1063 | |||
1064 | mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel); | ||
1065 | if (!mgr) | ||
1066 | return -ENODEV; | ||
1067 | |||
1068 | r = dss_mgr_connect(mgr, dssdev); | ||
1069 | if (r) | ||
1070 | return r; | ||
1071 | |||
1072 | r = omapdss_output_set_device(dssdev, dst); | ||
1073 | if (r) { | ||
1074 | DSSERR("failed to connect output to new device: %s\n", | ||
1075 | dst->name); | ||
1076 | dss_mgr_disconnect(mgr, dssdev); | ||
1077 | return r; | ||
1078 | } | ||
1079 | |||
1080 | return 0; | ||
1081 | } | ||
1082 | |||
1083 | static void hdmi_disconnect(struct omap_dss_device *dssdev, | ||
1084 | struct omap_dss_device *dst) | ||
1085 | { | ||
1086 | WARN_ON(dst != dssdev->device); | ||
1087 | |||
1088 | if (dst != dssdev->device) | ||
1089 | return; | ||
1090 | |||
1091 | omapdss_output_unset_device(dssdev); | ||
1092 | |||
1093 | if (dssdev->manager) | ||
1094 | dss_mgr_disconnect(dssdev->manager, dssdev); | ||
1095 | } | ||
1096 | |||
1097 | static int hdmi_read_edid(struct omap_dss_device *dssdev, | ||
1098 | u8 *edid, int len) | ||
1099 | { | ||
1100 | bool need_enable; | ||
1101 | int r; | ||
1102 | |||
1103 | need_enable = hdmi.core_enabled == false; | ||
1104 | |||
1105 | if (need_enable) { | ||
1106 | r = omapdss_hdmi_core_enable(dssdev); | ||
1107 | if (r) | ||
1108 | return r; | ||
1109 | } | ||
1110 | |||
1111 | r = omapdss_hdmi_read_edid(edid, len); | ||
1112 | |||
1113 | if (need_enable) | ||
1114 | omapdss_hdmi_core_disable(dssdev); | ||
1115 | |||
1116 | return r; | ||
1117 | } | ||
1118 | |||
1119 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) | ||
1120 | static int omapdss_hdmi_audio_enable(struct omap_dss_device *dssdev) | ||
1121 | { | ||
1122 | int r; | ||
1123 | |||
1124 | mutex_lock(&hdmi.lock); | ||
1125 | |||
1126 | if (!hdmi_mode_has_audio()) { | ||
1127 | r = -EPERM; | ||
1128 | goto err; | ||
1129 | } | ||
1130 | |||
1131 | r = hdmi_audio_enable(); | ||
1132 | if (r) | ||
1133 | goto err; | ||
1134 | |||
1135 | mutex_unlock(&hdmi.lock); | ||
1136 | return 0; | ||
1137 | |||
1138 | err: | ||
1139 | mutex_unlock(&hdmi.lock); | ||
1140 | return r; | ||
1141 | } | ||
1142 | |||
1143 | static void omapdss_hdmi_audio_disable(struct omap_dss_device *dssdev) | ||
1144 | { | ||
1145 | hdmi_audio_disable(); | ||
1146 | } | ||
1147 | |||
1148 | static int omapdss_hdmi_audio_start(struct omap_dss_device *dssdev) | ||
1149 | { | ||
1150 | return hdmi_audio_start(); | ||
1151 | } | ||
1152 | |||
1153 | static void omapdss_hdmi_audio_stop(struct omap_dss_device *dssdev) | ||
1154 | { | ||
1155 | hdmi_audio_stop(); | ||
1156 | } | ||
1157 | |||
1158 | static bool omapdss_hdmi_audio_supported(struct omap_dss_device *dssdev) | ||
1159 | { | ||
1160 | bool r; | ||
1161 | |||
1162 | mutex_lock(&hdmi.lock); | ||
1163 | |||
1164 | r = hdmi_mode_has_audio(); | ||
1165 | |||
1166 | mutex_unlock(&hdmi.lock); | ||
1167 | return r; | ||
1168 | } | ||
1169 | |||
1170 | static int omapdss_hdmi_audio_config(struct omap_dss_device *dssdev, | ||
1171 | struct omap_dss_audio *audio) | ||
1172 | { | ||
1173 | int r; | ||
1174 | |||
1175 | mutex_lock(&hdmi.lock); | ||
1176 | |||
1177 | if (!hdmi_mode_has_audio()) { | ||
1178 | r = -EPERM; | ||
1179 | goto err; | ||
1180 | } | ||
1181 | |||
1182 | r = hdmi_audio_config(audio); | ||
1183 | if (r) | ||
1184 | goto err; | ||
1185 | |||
1186 | mutex_unlock(&hdmi.lock); | ||
1187 | return 0; | ||
1188 | |||
1189 | err: | ||
1190 | mutex_unlock(&hdmi.lock); | ||
1191 | return r; | ||
1192 | } | ||
1193 | #else | ||
1194 | static int omapdss_hdmi_audio_enable(struct omap_dss_device *dssdev) | ||
1195 | { | ||
1196 | return -EPERM; | ||
1197 | } | ||
1198 | |||
1199 | static void omapdss_hdmi_audio_disable(struct omap_dss_device *dssdev) | ||
1200 | { | ||
1201 | } | ||
1202 | |||
1203 | static int omapdss_hdmi_audio_start(struct omap_dss_device *dssdev) | ||
1204 | { | ||
1205 | return -EPERM; | ||
1206 | } | ||
1207 | |||
1208 | static void omapdss_hdmi_audio_stop(struct omap_dss_device *dssdev) | ||
1209 | { | ||
1210 | } | ||
1211 | |||
1212 | static bool omapdss_hdmi_audio_supported(struct omap_dss_device *dssdev) | ||
1213 | { | ||
1214 | return false; | ||
1215 | } | ||
1216 | |||
1217 | static int omapdss_hdmi_audio_config(struct omap_dss_device *dssdev, | ||
1218 | struct omap_dss_audio *audio) | ||
1219 | { | ||
1220 | return -EPERM; | ||
1221 | } | ||
1222 | #endif | ||
1223 | |||
1224 | static const struct omapdss_hdmi_ops hdmi_ops = { | ||
1225 | .connect = hdmi_connect, | ||
1226 | .disconnect = hdmi_disconnect, | ||
1227 | |||
1228 | .enable = omapdss_hdmi_display_enable, | ||
1229 | .disable = omapdss_hdmi_display_disable, | ||
1230 | |||
1231 | .check_timings = omapdss_hdmi_display_check_timing, | ||
1232 | .set_timings = omapdss_hdmi_display_set_timing, | ||
1233 | .get_timings = omapdss_hdmi_display_get_timings, | ||
1234 | |||
1235 | .read_edid = hdmi_read_edid, | ||
1236 | |||
1237 | .audio_enable = omapdss_hdmi_audio_enable, | ||
1238 | .audio_disable = omapdss_hdmi_audio_disable, | ||
1239 | .audio_start = omapdss_hdmi_audio_start, | ||
1240 | .audio_stop = omapdss_hdmi_audio_stop, | ||
1241 | .audio_supported = omapdss_hdmi_audio_supported, | ||
1242 | .audio_config = omapdss_hdmi_audio_config, | ||
1243 | }; | ||
1244 | |||
1028 | static void hdmi_init_output(struct platform_device *pdev) | 1245 | static void hdmi_init_output(struct platform_device *pdev) |
1029 | { | 1246 | { |
1030 | struct omap_dss_device *out = &hdmi.output; | 1247 | struct omap_dss_device *out = &hdmi.output; |
@@ -1034,6 +1251,7 @@ static void hdmi_init_output(struct platform_device *pdev) | |||
1034 | out->output_type = OMAP_DISPLAY_TYPE_HDMI; | 1251 | out->output_type = OMAP_DISPLAY_TYPE_HDMI; |
1035 | out->name = "hdmi.0"; | 1252 | out->name = "hdmi.0"; |
1036 | out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT; | 1253 | out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT; |
1254 | out->ops.hdmi = &hdmi_ops; | ||
1037 | out->owner = THIS_MODULE; | 1255 | out->owner = THIS_MODULE; |
1038 | 1256 | ||
1039 | omapdss_register_output(out); | 1257 | omapdss_register_output(out); |
@@ -1083,6 +1301,10 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev) | |||
1083 | hdmi.ip_data.pll_offset = HDMI_PLLCTRL; | 1301 | hdmi.ip_data.pll_offset = HDMI_PLLCTRL; |
1084 | hdmi.ip_data.phy_offset = HDMI_PHY; | 1302 | hdmi.ip_data.phy_offset = HDMI_PHY; |
1085 | 1303 | ||
1304 | hdmi.ct_cp_hpd_gpio = -1; | ||
1305 | hdmi.ls_oe_gpio = -1; | ||
1306 | hdmi.hpd_gpio = -1; | ||
1307 | |||
1086 | hdmi_init_output(pdev); | 1308 | hdmi_init_output(pdev); |
1087 | 1309 | ||
1088 | r = hdmi_panel_init(); | 1310 | r = hdmi_panel_init(); |
diff --git a/include/video/omapdss.h b/include/video/omapdss.h index adb103633bd1..709e8015f324 100644 --- a/include/video/omapdss.h +++ b/include/video/omapdss.h | |||
@@ -172,6 +172,11 @@ enum omap_dss_audio_state { | |||
172 | OMAP_DSS_AUDIO_PLAYING, | 172 | OMAP_DSS_AUDIO_PLAYING, |
173 | }; | 173 | }; |
174 | 174 | ||
175 | struct omap_dss_audio { | ||
176 | struct snd_aes_iec958 *iec; | ||
177 | struct snd_cea_861_aud_if *cea; | ||
178 | }; | ||
179 | |||
175 | enum omap_dss_rotation_type { | 180 | enum omap_dss_rotation_type { |
176 | OMAP_DSS_ROT_DMA = 1 << 0, | 181 | OMAP_DSS_ROT_DMA = 1 << 0, |
177 | OMAP_DSS_ROT_VRFB = 1 << 1, | 182 | OMAP_DSS_ROT_VRFB = 1 << 1, |
@@ -653,6 +658,39 @@ struct omapdss_atv_ops { | |||
653 | u32 (*get_wss)(struct omap_dss_device *dssdev); | 658 | u32 (*get_wss)(struct omap_dss_device *dssdev); |
654 | }; | 659 | }; |
655 | 660 | ||
661 | struct omapdss_hdmi_ops { | ||
662 | int (*connect)(struct omap_dss_device *dssdev, | ||
663 | struct omap_dss_device *dst); | ||
664 | void (*disconnect)(struct omap_dss_device *dssdev, | ||
665 | struct omap_dss_device *dst); | ||
666 | |||
667 | int (*enable)(struct omap_dss_device *dssdev); | ||
668 | void (*disable)(struct omap_dss_device *dssdev); | ||
669 | |||
670 | int (*check_timings)(struct omap_dss_device *dssdev, | ||
671 | struct omap_video_timings *timings); | ||
672 | void (*set_timings)(struct omap_dss_device *dssdev, | ||
673 | struct omap_video_timings *timings); | ||
674 | void (*get_timings)(struct omap_dss_device *dssdev, | ||
675 | struct omap_video_timings *timings); | ||
676 | |||
677 | int (*read_edid)(struct omap_dss_device *dssdev, u8 *buf, int len); | ||
678 | bool (*detect)(struct omap_dss_device *dssdev); | ||
679 | |||
680 | /* | ||
681 | * Note: These functions might sleep. Do not call while | ||
682 | * holding a spinlock/readlock. | ||
683 | */ | ||
684 | int (*audio_enable)(struct omap_dss_device *dssdev); | ||
685 | void (*audio_disable)(struct omap_dss_device *dssdev); | ||
686 | bool (*audio_supported)(struct omap_dss_device *dssdev); | ||
687 | int (*audio_config)(struct omap_dss_device *dssdev, | ||
688 | struct omap_dss_audio *audio); | ||
689 | /* Note: These functions may not sleep */ | ||
690 | int (*audio_start)(struct omap_dss_device *dssdev); | ||
691 | void (*audio_stop)(struct omap_dss_device *dssdev); | ||
692 | }; | ||
693 | |||
656 | struct omap_dss_device { | 694 | struct omap_dss_device { |
657 | /* old device, to be removed */ | 695 | /* old device, to be removed */ |
658 | struct device old_dev; | 696 | struct device old_dev; |
@@ -722,6 +760,7 @@ struct omap_dss_device { | |||
722 | const struct omapdss_dpi_ops *dpi; | 760 | const struct omapdss_dpi_ops *dpi; |
723 | const struct omapdss_sdi_ops *sdi; | 761 | const struct omapdss_sdi_ops *sdi; |
724 | const struct omapdss_dvi_ops *dvi; | 762 | const struct omapdss_dvi_ops *dvi; |
763 | const struct omapdss_hdmi_ops *hdmi; | ||
725 | const struct omapdss_atv_ops *atv; | 764 | const struct omapdss_atv_ops *atv; |
726 | } ops; | 765 | } ops; |
727 | 766 | ||
@@ -759,11 +798,6 @@ struct omap_dss_hdmi_data | |||
759 | int hpd_gpio; | 798 | int hpd_gpio; |
760 | }; | 799 | }; |
761 | 800 | ||
762 | struct omap_dss_audio { | ||
763 | struct snd_aes_iec958 *iec; | ||
764 | struct snd_cea_861_aud_if *cea; | ||
765 | }; | ||
766 | |||
767 | struct omap_dss_driver { | 801 | struct omap_dss_driver { |
768 | struct device_driver driver; | 802 | struct device_driver driver; |
769 | 803 | ||