diff options
| author | Arnaud Pouliquen <arnaud.pouliquen@st.com> | 2016-05-30 09:31:37 -0400 |
|---|---|---|
| committer | Benjamin Gaignard <benjamin.gaignard@linaro.org> | 2016-07-01 03:12:49 -0400 |
| commit | 2c348e5053281555604233a66a633f7165665156 (patch) | |
| tree | 06b297de8e9049d4e4c4e2025608143c8d7b71de | |
| parent | 4d7037708a357f5dbe9a51cc1aacf4dcb65b7192 (diff) | |
drm: sti: Add ASoC generic hdmi codec support.
Add the interface needed by audio hdmi-codec driver.
Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@st.com>
| -rw-r--r-- | drivers/gpu/drm/sti/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/sti/sti_hdmi.c | 294 | ||||
| -rw-r--r-- | drivers/gpu/drm/sti/sti_hdmi.h | 13 |
3 files changed, 291 insertions, 17 deletions
diff --git a/drivers/gpu/drm/sti/Kconfig b/drivers/gpu/drm/sti/Kconfig index 5ad43a1bb260..494ab257f77c 100644 --- a/drivers/gpu/drm/sti/Kconfig +++ b/drivers/gpu/drm/sti/Kconfig | |||
| @@ -7,5 +7,6 @@ config DRM_STI | |||
| 7 | select DRM_KMS_CMA_HELPER | 7 | select DRM_KMS_CMA_HELPER |
| 8 | select DRM_PANEL | 8 | select DRM_PANEL |
| 9 | select FW_LOADER | 9 | select FW_LOADER |
| 10 | select SND_SOC_HDMI_CODEC if SND_SOC | ||
| 10 | help | 11 | help |
| 11 | Choose this option to enable DRM on STM stiH41x chipset | 12 | Choose this option to enable DRM on STM stiH41x chipset |
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index 8d1402b245bf..927e2b2e5af2 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c | |||
| @@ -18,6 +18,8 @@ | |||
| 18 | #include <drm/drm_crtc_helper.h> | 18 | #include <drm/drm_crtc_helper.h> |
| 19 | #include <drm/drm_edid.h> | 19 | #include <drm/drm_edid.h> |
| 20 | 20 | ||
| 21 | #include <sound/hdmi-codec.h> | ||
| 22 | |||
| 21 | #include "sti_hdmi.h" | 23 | #include "sti_hdmi.h" |
| 22 | #include "sti_hdmi_tx3g4c28phy.h" | 24 | #include "sti_hdmi_tx3g4c28phy.h" |
| 23 | #include "sti_hdmi_tx3g0c55phy.h" | 25 | #include "sti_hdmi_tx3g0c55phy.h" |
| @@ -35,6 +37,8 @@ | |||
| 35 | #define HDMI_DFLT_CHL0_DAT 0x0110 | 37 | #define HDMI_DFLT_CHL0_DAT 0x0110 |
| 36 | #define HDMI_DFLT_CHL1_DAT 0x0114 | 38 | #define HDMI_DFLT_CHL1_DAT 0x0114 |
| 37 | #define HDMI_DFLT_CHL2_DAT 0x0118 | 39 | #define HDMI_DFLT_CHL2_DAT 0x0118 |
| 40 | #define HDMI_AUDIO_CFG 0x0200 | ||
| 41 | #define HDMI_SPDIF_FIFO_STATUS 0x0204 | ||
| 38 | #define HDMI_SW_DI_1_HEAD_WORD 0x0210 | 42 | #define HDMI_SW_DI_1_HEAD_WORD 0x0210 |
| 39 | #define HDMI_SW_DI_1_PKT_WORD0 0x0214 | 43 | #define HDMI_SW_DI_1_PKT_WORD0 0x0214 |
| 40 | #define HDMI_SW_DI_1_PKT_WORD1 0x0218 | 44 | #define HDMI_SW_DI_1_PKT_WORD1 0x0218 |
| @@ -44,6 +48,9 @@ | |||
| 44 | #define HDMI_SW_DI_1_PKT_WORD5 0x0228 | 48 | #define HDMI_SW_DI_1_PKT_WORD5 0x0228 |
| 45 | #define HDMI_SW_DI_1_PKT_WORD6 0x022C | 49 | #define HDMI_SW_DI_1_PKT_WORD6 0x022C |
| 46 | #define HDMI_SW_DI_CFG 0x0230 | 50 | #define HDMI_SW_DI_CFG 0x0230 |
| 51 | #define HDMI_SAMPLE_FLAT_MASK 0x0244 | ||
| 52 | #define HDMI_AUDN 0x0400 | ||
| 53 | #define HDMI_AUD_CTS 0x0404 | ||
| 47 | #define HDMI_SW_DI_2_HEAD_WORD 0x0600 | 54 | #define HDMI_SW_DI_2_HEAD_WORD 0x0600 |
| 48 | #define HDMI_SW_DI_2_PKT_WORD0 0x0604 | 55 | #define HDMI_SW_DI_2_PKT_WORD0 0x0604 |
| 49 | #define HDMI_SW_DI_2_PKT_WORD1 0x0608 | 56 | #define HDMI_SW_DI_2_PKT_WORD1 0x0608 |
| @@ -103,6 +110,7 @@ | |||
| 103 | #define HDMI_INT_DLL_LCK BIT(5) | 110 | #define HDMI_INT_DLL_LCK BIT(5) |
| 104 | #define HDMI_INT_NEW_FRAME BIT(6) | 111 | #define HDMI_INT_NEW_FRAME BIT(6) |
| 105 | #define HDMI_INT_GENCTRL_PKT BIT(7) | 112 | #define HDMI_INT_GENCTRL_PKT BIT(7) |
| 113 | #define HDMI_INT_AUDIO_FIFO_XRUN BIT(8) | ||
| 106 | #define HDMI_INT_SINK_TERM_PRESENT BIT(11) | 114 | #define HDMI_INT_SINK_TERM_PRESENT BIT(11) |
| 107 | 115 | ||
| 108 | #define HDMI_DEFAULT_INT (HDMI_INT_SINK_TERM_PRESENT \ | 116 | #define HDMI_DEFAULT_INT (HDMI_INT_SINK_TERM_PRESENT \ |
| @@ -111,6 +119,7 @@ | |||
| 111 | | HDMI_INT_GLOBAL) | 119 | | HDMI_INT_GLOBAL) |
| 112 | 120 | ||
| 113 | #define HDMI_WORKING_INT (HDMI_INT_SINK_TERM_PRESENT \ | 121 | #define HDMI_WORKING_INT (HDMI_INT_SINK_TERM_PRESENT \ |
| 122 | | HDMI_INT_AUDIO_FIFO_XRUN \ | ||
| 114 | | HDMI_INT_GENCTRL_PKT \ | 123 | | HDMI_INT_GENCTRL_PKT \ |
| 115 | | HDMI_INT_NEW_FRAME \ | 124 | | HDMI_INT_NEW_FRAME \ |
| 116 | | HDMI_INT_DLL_LCK \ | 125 | | HDMI_INT_DLL_LCK \ |
| @@ -121,6 +130,27 @@ | |||
| 121 | 130 | ||
| 122 | #define HDMI_STA_SW_RST BIT(1) | 131 | #define HDMI_STA_SW_RST BIT(1) |
| 123 | 132 | ||
| 133 | #define HDMI_AUD_CFG_8CH BIT(0) | ||
| 134 | #define HDMI_AUD_CFG_SPDIF_DIV_2 BIT(1) | ||
| 135 | #define HDMI_AUD_CFG_SPDIF_DIV_3 BIT(2) | ||
| 136 | #define HDMI_AUD_CFG_SPDIF_CLK_DIV_4 (BIT(1) | BIT(2)) | ||
| 137 | #define HDMI_AUD_CFG_CTS_CLK_256FS BIT(12) | ||
| 138 | #define HDMI_AUD_CFG_DTS_INVALID BIT(16) | ||
| 139 | #define HDMI_AUD_CFG_ONE_BIT_INVALID (BIT(18) | BIT(19) | BIT(20) | BIT(21)) | ||
| 140 | #define HDMI_AUD_CFG_CH12_VALID BIT(28) | ||
| 141 | #define HDMI_AUD_CFG_CH34_VALID BIT(29) | ||
| 142 | #define HDMI_AUD_CFG_CH56_VALID BIT(30) | ||
| 143 | #define HDMI_AUD_CFG_CH78_VALID BIT(31) | ||
| 144 | |||
| 145 | /* sample flat mask */ | ||
| 146 | #define HDMI_SAMPLE_FLAT_NO 0 | ||
| 147 | #define HDMI_SAMPLE_FLAT_SP0 BIT(0) | ||
| 148 | #define HDMI_SAMPLE_FLAT_SP1 BIT(1) | ||
| 149 | #define HDMI_SAMPLE_FLAT_SP2 BIT(2) | ||
| 150 | #define HDMI_SAMPLE_FLAT_SP3 BIT(3) | ||
| 151 | #define HDMI_SAMPLE_FLAT_ALL (HDMI_SAMPLE_FLAT_SP0 | HDMI_SAMPLE_FLAT_SP1 |\ | ||
| 152 | HDMI_SAMPLE_FLAT_SP2 | HDMI_SAMPLE_FLAT_SP3) | ||
| 153 | |||
| 124 | #define HDMI_INFOFRAME_HEADER_TYPE(x) (((x) & 0xff) << 0) | 154 | #define HDMI_INFOFRAME_HEADER_TYPE(x) (((x) & 0xff) << 0) |
| 125 | #define HDMI_INFOFRAME_HEADER_VERSION(x) (((x) & 0xff) << 8) | 155 | #define HDMI_INFOFRAME_HEADER_VERSION(x) (((x) & 0xff) << 8) |
| 126 | #define HDMI_INFOFRAME_HEADER_LEN(x) (((x) & 0x0f) << 16) | 156 | #define HDMI_INFOFRAME_HEADER_LEN(x) (((x) & 0x0f) << 16) |
| @@ -171,6 +201,10 @@ static irqreturn_t hdmi_irq_thread(int irq, void *arg) | |||
| 171 | wake_up_interruptible(&hdmi->wait_event); | 201 | wake_up_interruptible(&hdmi->wait_event); |
| 172 | } | 202 | } |
| 173 | 203 | ||
| 204 | /* Audio FIFO underrun IRQ */ | ||
| 205 | if (hdmi->irq_status & HDMI_INT_AUDIO_FIFO_XRUN) | ||
| 206 | DRM_INFO("Warning: audio FIFO underrun occurs!"); | ||
| 207 | |||
| 174 | return IRQ_HANDLED; | 208 | return IRQ_HANDLED; |
| 175 | } | 209 | } |
| 176 | 210 | ||
| @@ -441,26 +475,29 @@ static int hdmi_avi_infoframe_config(struct sti_hdmi *hdmi) | |||
| 441 | */ | 475 | */ |
| 442 | static int hdmi_audio_infoframe_config(struct sti_hdmi *hdmi) | 476 | static int hdmi_audio_infoframe_config(struct sti_hdmi *hdmi) |
| 443 | { | 477 | { |
| 444 | struct hdmi_audio_infoframe infofame; | 478 | struct hdmi_audio_params *audio = &hdmi->audio; |
| 445 | u8 buffer[HDMI_INFOFRAME_SIZE(AUDIO)]; | 479 | u8 buffer[HDMI_INFOFRAME_SIZE(AUDIO)]; |
| 446 | int ret; | 480 | int ret, val; |
| 447 | 481 | ||
| 448 | ret = hdmi_audio_infoframe_init(&infofame); | 482 | DRM_DEBUG_DRIVER("enter %s, AIF %s\n", __func__, |
| 449 | if (ret < 0) { | 483 | audio->enabled ? "enable" : "disable"); |
| 450 | DRM_ERROR("failed to setup audio infoframe: %d\n", ret); | 484 | if (audio->enabled) { |
| 451 | return ret; | 485 | /* set audio parameters stored*/ |
| 452 | } | 486 | ret = hdmi_audio_infoframe_pack(&audio->cea, buffer, |
| 453 | 487 | sizeof(buffer)); | |
| 454 | infofame.channels = 2; | 488 | if (ret < 0) { |
| 455 | 489 | DRM_ERROR("failed to pack audio infoframe: %d\n", ret); | |
| 456 | ret = hdmi_audio_infoframe_pack(&infofame, buffer, sizeof(buffer)); | 490 | return ret; |
| 457 | if (ret < 0) { | 491 | } |
| 458 | DRM_ERROR("failed to pack audio infoframe: %d\n", ret); | 492 | hdmi_infoframe_write_infopack(hdmi, buffer, ret); |
| 459 | return ret; | 493 | } else { |
| 494 | /*disable audio info frame transmission */ | ||
| 495 | val = hdmi_read(hdmi, HDMI_SW_DI_CFG); | ||
| 496 | val &= ~HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, | ||
| 497 | HDMI_IFRAME_SLOT_AUDIO); | ||
| 498 | hdmi_write(hdmi, val, HDMI_SW_DI_CFG); | ||
| 460 | } | 499 | } |
| 461 | 500 | ||
| 462 | hdmi_infoframe_write_infopack(hdmi, buffer, ret); | ||
| 463 | |||
| 464 | return 0; | 501 | return 0; |
| 465 | } | 502 | } |
| 466 | 503 | ||
| @@ -650,6 +687,10 @@ static int hdmi_dbg_show(struct seq_file *s, void *data) | |||
| 650 | DBGFS_DUMP("", HDMI_SW_DI_CFG); | 687 | DBGFS_DUMP("", HDMI_SW_DI_CFG); |
| 651 | hdmi_dbg_sw_di_cfg(s, hdmi_read(hdmi, HDMI_SW_DI_CFG)); | 688 | hdmi_dbg_sw_di_cfg(s, hdmi_read(hdmi, HDMI_SW_DI_CFG)); |
| 652 | 689 | ||
| 690 | DBGFS_DUMP("\n", HDMI_AUDIO_CFG); | ||
| 691 | DBGFS_DUMP("\n", HDMI_SPDIF_FIFO_STATUS); | ||
| 692 | DBGFS_DUMP("\n", HDMI_AUDN); | ||
| 693 | |||
| 653 | seq_printf(s, "\n AVI Infoframe (Data Island slot N=%d):", | 694 | seq_printf(s, "\n AVI Infoframe (Data Island slot N=%d):", |
| 654 | HDMI_IFRAME_SLOT_AVI); | 695 | HDMI_IFRAME_SLOT_AVI); |
| 655 | DBGFS_DUMP_DI(HDMI_SW_DI_N_HEAD_WORD, HDMI_IFRAME_SLOT_AVI); | 696 | DBGFS_DUMP_DI(HDMI_SW_DI_N_HEAD_WORD, HDMI_IFRAME_SLOT_AVI); |
| @@ -854,6 +895,7 @@ static int sti_hdmi_connector_get_modes(struct drm_connector *connector) | |||
| 854 | 895 | ||
| 855 | count = drm_add_edid_modes(connector, edid); | 896 | count = drm_add_edid_modes(connector, edid); |
| 856 | drm_mode_connector_update_edid_property(connector, edid); | 897 | drm_mode_connector_update_edid_property(connector, edid); |
| 898 | drm_edid_to_eld(connector, edid); | ||
| 857 | 899 | ||
| 858 | kfree(edid); | 900 | kfree(edid); |
| 859 | return count; | 901 | return count; |
| @@ -1036,6 +1078,206 @@ static struct drm_encoder *sti_hdmi_find_encoder(struct drm_device *dev) | |||
| 1036 | return NULL; | 1078 | return NULL; |
| 1037 | } | 1079 | } |
| 1038 | 1080 | ||
| 1081 | /** | ||
| 1082 | * sti_hdmi_audio_get_non_coherent_n() - get N parameter for non-coherent | ||
| 1083 | * clocks. None-coherent clocks means that audio and TMDS clocks have not the | ||
| 1084 | * same source (drifts between clocks). In this case assumption is that CTS is | ||
| 1085 | * automatically calculated by hardware. | ||
| 1086 | * | ||
| 1087 | * @audio_fs: audio frame clock frequency in Hz | ||
| 1088 | * | ||
| 1089 | * Values computed are based on table described in HDMI specification 1.4b | ||
| 1090 | * | ||
| 1091 | * Returns n value. | ||
| 1092 | */ | ||
| 1093 | static int sti_hdmi_audio_get_non_coherent_n(unsigned int audio_fs) | ||
| 1094 | { | ||
| 1095 | unsigned int n; | ||
| 1096 | |||
| 1097 | switch (audio_fs) { | ||
| 1098 | case 32000: | ||
| 1099 | n = 4096; | ||
| 1100 | break; | ||
| 1101 | case 44100: | ||
| 1102 | n = 6272; | ||
| 1103 | break; | ||
| 1104 | case 48000: | ||
| 1105 | n = 6144; | ||
| 1106 | break; | ||
| 1107 | case 88200: | ||
| 1108 | n = 6272 * 2; | ||
| 1109 | break; | ||
| 1110 | case 96000: | ||
| 1111 | n = 6144 * 2; | ||
| 1112 | break; | ||
| 1113 | case 176400: | ||
| 1114 | n = 6272 * 4; | ||
| 1115 | break; | ||
| 1116 | case 192000: | ||
| 1117 | n = 6144 * 4; | ||
| 1118 | break; | ||
| 1119 | default: | ||
| 1120 | /* Not pre-defined, recommended value: 128 * fs / 1000 */ | ||
| 1121 | n = (audio_fs * 128) / 1000; | ||
| 1122 | } | ||
| 1123 | |||
| 1124 | return n; | ||
| 1125 | } | ||
| 1126 | |||
| 1127 | static int hdmi_audio_configure(struct sti_hdmi *hdmi, | ||
| 1128 | struct hdmi_audio_params *params) | ||
| 1129 | { | ||
| 1130 | int audio_cfg, n; | ||
| 1131 | struct hdmi_audio_infoframe *info = ¶ms->cea; | ||
| 1132 | |||
| 1133 | DRM_DEBUG_DRIVER("\n"); | ||
| 1134 | |||
| 1135 | if (!hdmi->enabled) | ||
| 1136 | return 0; | ||
| 1137 | |||
| 1138 | /* update N parameter */ | ||
| 1139 | n = sti_hdmi_audio_get_non_coherent_n(params->sample_rate); | ||
| 1140 | |||
| 1141 | DRM_DEBUG_DRIVER("Audio rate = %d Hz, TMDS clock = %d Hz, n = %d\n", | ||
| 1142 | params->sample_rate, hdmi->mode.clock * 1000, n); | ||
| 1143 | hdmi_write(hdmi, n, HDMI_AUDN); | ||
| 1144 | |||
| 1145 | /* update HDMI registers according to configuration */ | ||
| 1146 | audio_cfg = HDMI_AUD_CFG_SPDIF_DIV_2 | HDMI_AUD_CFG_DTS_INVALID | | ||
| 1147 | HDMI_AUD_CFG_ONE_BIT_INVALID; | ||
| 1148 | |||
| 1149 | switch (info->channels) { | ||
| 1150 | case 8: | ||
| 1151 | audio_cfg |= HDMI_AUD_CFG_CH78_VALID; | ||
| 1152 | case 6: | ||
| 1153 | audio_cfg |= HDMI_AUD_CFG_CH56_VALID; | ||
| 1154 | case 4: | ||
| 1155 | audio_cfg |= HDMI_AUD_CFG_CH34_VALID | HDMI_AUD_CFG_8CH; | ||
| 1156 | case 2: | ||
| 1157 | audio_cfg |= HDMI_AUD_CFG_CH12_VALID; | ||
| 1158 | break; | ||
| 1159 | default: | ||
| 1160 | DRM_ERROR("ERROR: Unsupported number of channels (%d)!\n", | ||
| 1161 | info->channels); | ||
| 1162 | return -EINVAL; | ||
| 1163 | } | ||
| 1164 | |||
| 1165 | hdmi_write(hdmi, audio_cfg, HDMI_AUDIO_CFG); | ||
| 1166 | |||
| 1167 | hdmi->audio = *params; | ||
| 1168 | |||
| 1169 | return hdmi_audio_infoframe_config(hdmi); | ||
| 1170 | } | ||
| 1171 | |||
| 1172 | static void hdmi_audio_shutdown(struct device *dev) | ||
| 1173 | { | ||
| 1174 | struct sti_hdmi *hdmi = dev_get_drvdata(dev); | ||
| 1175 | int audio_cfg; | ||
| 1176 | |||
| 1177 | DRM_DEBUG_DRIVER("\n"); | ||
| 1178 | |||
| 1179 | /* disable audio */ | ||
| 1180 | audio_cfg = HDMI_AUD_CFG_SPDIF_DIV_2 | HDMI_AUD_CFG_DTS_INVALID | | ||
| 1181 | HDMI_AUD_CFG_ONE_BIT_INVALID; | ||
| 1182 | hdmi_write(hdmi, audio_cfg, HDMI_AUDIO_CFG); | ||
| 1183 | |||
| 1184 | hdmi->audio.enabled = 0; | ||
| 1185 | hdmi_audio_infoframe_config(hdmi); | ||
| 1186 | } | ||
| 1187 | |||
| 1188 | static int hdmi_audio_hw_params(struct device *dev, | ||
| 1189 | struct hdmi_codec_daifmt *daifmt, | ||
| 1190 | struct hdmi_codec_params *params) | ||
| 1191 | { | ||
| 1192 | struct sti_hdmi *hdmi = dev_get_drvdata(dev); | ||
| 1193 | int ret; | ||
| 1194 | struct hdmi_audio_params audio = { | ||
| 1195 | .sample_width = params->sample_width, | ||
| 1196 | .sample_rate = params->sample_rate, | ||
| 1197 | .cea = params->cea, | ||
| 1198 | }; | ||
| 1199 | |||
| 1200 | DRM_DEBUG_DRIVER("\n"); | ||
| 1201 | |||
| 1202 | if (!hdmi->enabled) | ||
| 1203 | return 0; | ||
| 1204 | |||
| 1205 | if ((daifmt->fmt != HDMI_I2S) || daifmt->bit_clk_inv || | ||
| 1206 | daifmt->frame_clk_inv || daifmt->bit_clk_master || | ||
| 1207 | daifmt->frame_clk_master) { | ||
| 1208 | dev_err(dev, "%s: Bad flags %d %d %d %d\n", __func__, | ||
| 1209 | daifmt->bit_clk_inv, daifmt->frame_clk_inv, | ||
| 1210 | daifmt->bit_clk_master, | ||
| 1211 | daifmt->frame_clk_master); | ||
| 1212 | return -EINVAL; | ||
| 1213 | } | ||
| 1214 | |||
| 1215 | audio.enabled = 1; | ||
| 1216 | |||
| 1217 | ret = hdmi_audio_configure(hdmi, &audio); | ||
| 1218 | if (ret < 0) | ||
| 1219 | return ret; | ||
| 1220 | |||
| 1221 | return 0; | ||
| 1222 | } | ||
| 1223 | |||
| 1224 | static int hdmi_audio_digital_mute(struct device *dev, bool enable) | ||
| 1225 | { | ||
| 1226 | struct sti_hdmi *hdmi = dev_get_drvdata(dev); | ||
| 1227 | |||
| 1228 | DRM_DEBUG_DRIVER("%s\n", enable ? "enable" : "disable"); | ||
| 1229 | |||
| 1230 | if (enable) | ||
| 1231 | hdmi_write(hdmi, HDMI_SAMPLE_FLAT_ALL, HDMI_SAMPLE_FLAT_MASK); | ||
| 1232 | else | ||
| 1233 | hdmi_write(hdmi, HDMI_SAMPLE_FLAT_NO, HDMI_SAMPLE_FLAT_MASK); | ||
| 1234 | |||
| 1235 | return 0; | ||
| 1236 | } | ||
| 1237 | |||
| 1238 | static int hdmi_audio_get_eld(struct device *dev, uint8_t *buf, size_t len) | ||
| 1239 | { | ||
| 1240 | struct sti_hdmi *hdmi = dev_get_drvdata(dev); | ||
| 1241 | struct drm_connector *connector = hdmi->drm_connector; | ||
| 1242 | |||
| 1243 | DRM_DEBUG_DRIVER("\n"); | ||
| 1244 | memcpy(buf, connector->eld, min(sizeof(connector->eld), len)); | ||
| 1245 | |||
| 1246 | return 0; | ||
| 1247 | } | ||
| 1248 | |||
| 1249 | static const struct hdmi_codec_ops audio_codec_ops = { | ||
| 1250 | .hw_params = hdmi_audio_hw_params, | ||
| 1251 | .audio_shutdown = hdmi_audio_shutdown, | ||
| 1252 | .digital_mute = hdmi_audio_digital_mute, | ||
| 1253 | .get_eld = hdmi_audio_get_eld, | ||
| 1254 | }; | ||
| 1255 | |||
| 1256 | static int sti_hdmi_register_audio_driver(struct device *dev, | ||
| 1257 | struct sti_hdmi *hdmi) | ||
| 1258 | { | ||
| 1259 | struct hdmi_codec_pdata codec_data = { | ||
| 1260 | .ops = &audio_codec_ops, | ||
| 1261 | .max_i2s_channels = 8, | ||
| 1262 | .i2s = 1, | ||
| 1263 | }; | ||
| 1264 | |||
| 1265 | DRM_DEBUG_DRIVER("\n"); | ||
| 1266 | |||
| 1267 | hdmi->audio.enabled = 0; | ||
| 1268 | |||
| 1269 | hdmi->audio_pdev = platform_device_register_data( | ||
| 1270 | dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO, | ||
| 1271 | &codec_data, sizeof(codec_data)); | ||
| 1272 | |||
| 1273 | if (IS_ERR(hdmi->audio_pdev)) | ||
| 1274 | return PTR_ERR(hdmi->audio_pdev); | ||
| 1275 | |||
| 1276 | DRM_INFO("%s Driver bound %s\n", HDMI_CODEC_DRV_NAME, dev_name(dev)); | ||
| 1277 | |||
| 1278 | return 0; | ||
| 1279 | } | ||
| 1280 | |||
| 1039 | static int sti_hdmi_bind(struct device *dev, struct device *master, void *data) | 1281 | static int sti_hdmi_bind(struct device *dev, struct device *master, void *data) |
| 1040 | { | 1282 | { |
| 1041 | struct sti_hdmi *hdmi = dev_get_drvdata(dev); | 1283 | struct sti_hdmi *hdmi = dev_get_drvdata(dev); |
| @@ -1082,12 +1324,27 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data) | |||
| 1082 | /* initialise property */ | 1324 | /* initialise property */ |
| 1083 | sti_hdmi_connector_init_property(drm_dev, drm_connector); | 1325 | sti_hdmi_connector_init_property(drm_dev, drm_connector); |
| 1084 | 1326 | ||
| 1327 | hdmi->drm_connector = drm_connector; | ||
| 1328 | |||
| 1085 | err = drm_mode_connector_attach_encoder(drm_connector, encoder); | 1329 | err = drm_mode_connector_attach_encoder(drm_connector, encoder); |
| 1086 | if (err) { | 1330 | if (err) { |
| 1087 | DRM_ERROR("Failed to attach a connector to a encoder\n"); | 1331 | DRM_ERROR("Failed to attach a connector to a encoder\n"); |
| 1088 | goto err_sysfs; | 1332 | goto err_sysfs; |
| 1089 | } | 1333 | } |
| 1090 | 1334 | ||
| 1335 | err = sti_hdmi_register_audio_driver(dev, hdmi); | ||
| 1336 | if (err) { | ||
| 1337 | DRM_ERROR("Failed to attach an audio codec\n"); | ||
| 1338 | goto err_sysfs; | ||
| 1339 | } | ||
| 1340 | |||
| 1341 | /* Initialize audio infoframe */ | ||
| 1342 | err = hdmi_audio_infoframe_init(&hdmi->audio.cea); | ||
| 1343 | if (err) { | ||
| 1344 | DRM_ERROR("Failed to init audio infoframe\n"); | ||
| 1345 | goto err_sysfs; | ||
| 1346 | } | ||
| 1347 | |||
| 1091 | /* Enable default interrupts */ | 1348 | /* Enable default interrupts */ |
| 1092 | hdmi_write(hdmi, HDMI_DEFAULT_INT, HDMI_INT_EN); | 1349 | hdmi_write(hdmi, HDMI_DEFAULT_INT, HDMI_INT_EN); |
| 1093 | 1350 | ||
| @@ -1095,6 +1352,7 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data) | |||
| 1095 | 1352 | ||
| 1096 | err_sysfs: | 1353 | err_sysfs: |
| 1097 | drm_bridge_remove(bridge); | 1354 | drm_bridge_remove(bridge); |
| 1355 | hdmi->drm_connector = NULL; | ||
| 1098 | return -EINVAL; | 1356 | return -EINVAL; |
| 1099 | } | 1357 | } |
| 1100 | 1358 | ||
| @@ -1244,6 +1502,8 @@ static int sti_hdmi_remove(struct platform_device *pdev) | |||
| 1244 | struct sti_hdmi *hdmi = dev_get_drvdata(&pdev->dev); | 1502 | struct sti_hdmi *hdmi = dev_get_drvdata(&pdev->dev); |
| 1245 | 1503 | ||
| 1246 | i2c_put_adapter(hdmi->ddc_adapt); | 1504 | i2c_put_adapter(hdmi->ddc_adapt); |
| 1505 | if (hdmi->audio_pdev) | ||
| 1506 | platform_device_unregister(hdmi->audio_pdev); | ||
| 1247 | component_del(&pdev->dev, &sti_hdmi_ops); | 1507 | component_del(&pdev->dev, &sti_hdmi_ops); |
| 1248 | 1508 | ||
| 1249 | return 0; | 1509 | return 0; |
diff --git a/drivers/gpu/drm/sti/sti_hdmi.h b/drivers/gpu/drm/sti/sti_hdmi.h index ef3a94583bbd..119bc3582ac7 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.h +++ b/drivers/gpu/drm/sti/sti_hdmi.h | |||
| @@ -23,6 +23,13 @@ struct hdmi_phy_ops { | |||
| 23 | void (*stop)(struct sti_hdmi *hdmi); | 23 | void (*stop)(struct sti_hdmi *hdmi); |
| 24 | }; | 24 | }; |
| 25 | 25 | ||
| 26 | struct hdmi_audio_params { | ||
| 27 | bool enabled; | ||
| 28 | unsigned int sample_width; | ||
| 29 | unsigned int sample_rate; | ||
| 30 | struct hdmi_audio_infoframe cea; | ||
| 31 | }; | ||
| 32 | |||
| 26 | /* values for the framing mode property */ | 33 | /* values for the framing mode property */ |
| 27 | enum sti_hdmi_modes { | 34 | enum sti_hdmi_modes { |
| 28 | HDMI_MODE_HDMI, | 35 | HDMI_MODE_HDMI, |
| @@ -67,6 +74,9 @@ static const struct drm_prop_enum_list colorspace_mode_names[] = { | |||
| 67 | * @ddc_adapt: i2c ddc adapter | 74 | * @ddc_adapt: i2c ddc adapter |
| 68 | * @colorspace: current colorspace selected | 75 | * @colorspace: current colorspace selected |
| 69 | * @hdmi_mode: select framing for HDMI or DVI | 76 | * @hdmi_mode: select framing for HDMI or DVI |
| 77 | * @audio_pdev: ASoC hdmi-codec platform device | ||
| 78 | * @audio: hdmi audio parameters. | ||
| 79 | * @drm_connector: hdmi connector | ||
| 70 | */ | 80 | */ |
| 71 | struct sti_hdmi { | 81 | struct sti_hdmi { |
| 72 | struct device dev; | 82 | struct device dev; |
| @@ -89,6 +99,9 @@ struct sti_hdmi { | |||
| 89 | struct i2c_adapter *ddc_adapt; | 99 | struct i2c_adapter *ddc_adapt; |
| 90 | enum hdmi_colorspace colorspace; | 100 | enum hdmi_colorspace colorspace; |
| 91 | enum sti_hdmi_modes hdmi_mode; | 101 | enum sti_hdmi_modes hdmi_mode; |
| 102 | struct platform_device *audio_pdev; | ||
| 103 | struct hdmi_audio_params audio; | ||
| 104 | struct drm_connector *drm_connector; | ||
| 92 | }; | 105 | }; |
| 93 | 106 | ||
| 94 | u32 hdmi_read(struct sti_hdmi *hdmi, int offset); | 107 | u32 hdmi_read(struct sti_hdmi *hdmi, int offset); |
