aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c
diff options
context:
space:
mode:
authorRicardo Neri <ricardo.neri@ti.com>2012-03-21 14:38:15 -0400
committerTomi Valkeinen <tomi.valkeinen@ti.com>2012-05-11 08:17:08 -0400
commit6ec355d6c79e811a3b7f85ca6b22fa4bd7b1bbfc (patch)
tree316df760312fd6833c0bcc609e5dd46930cc196f /drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c
parent25a653597ee63119a477e9bdeb6b41bd7cd56140 (diff)
OMAPDSS: HDMI: Add an audio configuration function
The generic HDMI driver does not need to know about the specific settings of a given IP. Hence, it just passes the audio configuration and the IP library parses such configuration and sets the IP accordingly. This patch introduces an IP-specific audio configuration function. Also, this patch implements the audio config function for OMAP4. The DMA, format and core config functions are no longer exposed to the generic HDMI driver as they are IP-specific. The audio configuration function caters for 16-bit through 24-bit audio samples with sample rates from 32kHz and up to 192kHz as well as up to 8 audio channels. Signed-off-by: Ricardo Neri <ricardo.neri@ti.com>
Diffstat (limited to 'drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c')
-rw-r--r--drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c189
1 files changed, 185 insertions, 4 deletions
diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c
index 6178bdac384..1ce77f37ab5 100644
--- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c
+++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c
@@ -31,10 +31,12 @@
31#include <linux/gpio.h> 31#include <linux/gpio.h>
32#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) 32#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
33#include <sound/asound.h> 33#include <sound/asound.h>
34#include <sound/asoundef.h>
34#endif 35#endif
35 36
36#include "ti_hdmi_4xxx_ip.h" 37#include "ti_hdmi_4xxx_ip.h"
37#include "dss.h" 38#include "dss.h"
39#include "dss_features.h"
38 40
39static inline void hdmi_write_reg(void __iomem *base_addr, 41static inline void hdmi_write_reg(void __iomem *base_addr,
40 const u16 idx, u32 val) 42 const u16 idx, u32 val)
@@ -1024,7 +1026,7 @@ void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s)
1024} 1026}
1025 1027
1026#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) 1028#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
1027void hdmi_wp_audio_config_format(struct hdmi_ip_data *ip_data, 1029static void ti_hdmi_4xxx_wp_audio_config_format(struct hdmi_ip_data *ip_data,
1028 struct hdmi_audio_format *aud_fmt) 1030 struct hdmi_audio_format *aud_fmt)
1029{ 1031{
1030 u32 r; 1032 u32 r;
@@ -1043,7 +1045,7 @@ void hdmi_wp_audio_config_format(struct hdmi_ip_data *ip_data,
1043 hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CFG, r); 1045 hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CFG, r);
1044} 1046}
1045 1047
1046void hdmi_wp_audio_config_dma(struct hdmi_ip_data *ip_data, 1048static void ti_hdmi_4xxx_wp_audio_config_dma(struct hdmi_ip_data *ip_data,
1047 struct hdmi_audio_dma *aud_dma) 1049 struct hdmi_audio_dma *aud_dma)
1048{ 1050{
1049 u32 r; 1051 u32 r;
@@ -1061,7 +1063,7 @@ void hdmi_wp_audio_config_dma(struct hdmi_ip_data *ip_data,
1061 hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CTRL, r); 1063 hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CTRL, r);
1062} 1064}
1063 1065
1064void hdmi_core_audio_config(struct hdmi_ip_data *ip_data, 1066static void ti_hdmi_4xxx_core_audio_config(struct hdmi_ip_data *ip_data,
1065 struct hdmi_core_audio_config *cfg) 1067 struct hdmi_core_audio_config *cfg)
1066{ 1068{
1067 u32 r; 1069 u32 r;
@@ -1152,7 +1154,7 @@ void hdmi_core_audio_config(struct hdmi_ip_data *ip_data,
1152 hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_MODE, r); 1154 hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_MODE, r);
1153} 1155}
1154 1156
1155void hdmi_core_audio_infoframe_config(struct hdmi_ip_data *ip_data, 1157static void ti_hdmi_4xxx_core_audio_infoframe_cfg(struct hdmi_ip_data *ip_data,
1156 struct snd_cea_861_aud_if *info_aud) 1158 struct snd_cea_861_aud_if *info_aud)
1157{ 1159{
1158 u8 sum = 0, checksum = 0; 1160 u8 sum = 0, checksum = 0;
@@ -1202,6 +1204,185 @@ void hdmi_core_audio_infoframe_config(struct hdmi_ip_data *ip_data,
1202 */ 1204 */
1203} 1205}
1204 1206
1207int ti_hdmi_4xxx_audio_config(struct hdmi_ip_data *ip_data,
1208 struct omap_dss_audio *audio)
1209{
1210 struct hdmi_audio_format audio_format;
1211 struct hdmi_audio_dma audio_dma;
1212 struct hdmi_core_audio_config core;
1213 int err, n, cts, channel_count;
1214 unsigned int fs_nr;
1215 bool word_length_16b = false;
1216
1217 if (!audio || !audio->iec || !audio->cea || !ip_data)
1218 return -EINVAL;
1219
1220 core.iec60958_cfg = audio->iec;
1221 /*
1222 * In the IEC-60958 status word, check if the audio sample word length
1223 * is 16-bit as several optimizations can be performed in such case.
1224 */
1225 if (!(audio->iec->status[4] & IEC958_AES4_CON_MAX_WORDLEN_24))
1226 if (audio->iec->status[4] & IEC958_AES4_CON_WORDLEN_20_16)
1227 word_length_16b = true;
1228
1229 /* I2S configuration. See Phillips' specification */
1230 if (word_length_16b)
1231 core.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_LEFT;
1232 else
1233 core.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_RIGHT;
1234 /*
1235 * The I2S input word length is twice the lenght given in the IEC-60958
1236 * status word. If the word size is greater than
1237 * 20 bits, increment by one.
1238 */
1239 core.i2s_cfg.in_length_bits = audio->iec->status[4]
1240 & IEC958_AES4_CON_WORDLEN;
1241 if (audio->iec->status[4] & IEC958_AES4_CON_MAX_WORDLEN_24)
1242 core.i2s_cfg.in_length_bits++;
1243 core.i2s_cfg.sck_edge_mode = HDMI_AUDIO_I2S_SCK_EDGE_RISING;
1244 core.i2s_cfg.vbit = HDMI_AUDIO_I2S_VBIT_FOR_PCM;
1245 core.i2s_cfg.direction = HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST;
1246 core.i2s_cfg.shift = HDMI_AUDIO_I2S_FIRST_BIT_SHIFT;
1247
1248 /* convert sample frequency to a number */
1249 switch (audio->iec->status[3] & IEC958_AES3_CON_FS) {
1250 case IEC958_AES3_CON_FS_32000:
1251 fs_nr = 32000;
1252 break;
1253 case IEC958_AES3_CON_FS_44100:
1254 fs_nr = 44100;
1255 break;
1256 case IEC958_AES3_CON_FS_48000:
1257 fs_nr = 48000;
1258 break;
1259 case IEC958_AES3_CON_FS_88200:
1260 fs_nr = 88200;
1261 break;
1262 case IEC958_AES3_CON_FS_96000:
1263 fs_nr = 96000;
1264 break;
1265 case IEC958_AES3_CON_FS_176400:
1266 fs_nr = 176400;
1267 break;
1268 case IEC958_AES3_CON_FS_192000:
1269 fs_nr = 192000;
1270 break;
1271 default:
1272 return -EINVAL;
1273 }
1274
1275 err = hdmi_compute_acr(fs_nr, &n, &cts);
1276
1277 /* Audio clock regeneration settings */
1278 core.n = n;
1279 core.cts = cts;
1280 if (dss_has_feature(FEAT_HDMI_CTS_SWMODE)) {
1281 core.aud_par_busclk = 0;
1282 core.cts_mode = HDMI_AUDIO_CTS_MODE_SW;
1283 core.use_mclk = dss_has_feature(FEAT_HDMI_AUDIO_USE_MCLK);
1284 } else {
1285 core.aud_par_busclk = (((128 * 31) - 1) << 8);
1286 core.cts_mode = HDMI_AUDIO_CTS_MODE_HW;
1287 core.use_mclk = true;
1288 }
1289
1290 if (core.use_mclk)
1291 core.mclk_mode = HDMI_AUDIO_MCLK_128FS;
1292
1293 /* Audio channels settings */
1294 channel_count = (audio->cea->db1_ct_cc &
1295 CEA861_AUDIO_INFOFRAME_DB1CC) + 1;
1296
1297 switch (channel_count) {
1298 case 2:
1299 audio_format.active_chnnls_msk = 0x03;
1300 break;
1301 case 3:
1302 audio_format.active_chnnls_msk = 0x07;
1303 break;
1304 case 4:
1305 audio_format.active_chnnls_msk = 0x0f;
1306 break;
1307 case 5:
1308 audio_format.active_chnnls_msk = 0x1f;
1309 break;
1310 case 6:
1311 audio_format.active_chnnls_msk = 0x3f;
1312 break;
1313 case 7:
1314 audio_format.active_chnnls_msk = 0x7f;
1315 break;
1316 case 8:
1317 audio_format.active_chnnls_msk = 0xff;
1318 break;
1319 default:
1320 return -EINVAL;
1321 }
1322
1323 /*
1324 * the HDMI IP needs to enable four stereo channels when transmitting
1325 * more than 2 audio channels
1326 */
1327 if (channel_count == 2) {
1328 audio_format.stereo_channels = HDMI_AUDIO_STEREO_ONECHANNEL;
1329 core.i2s_cfg.active_sds = HDMI_AUDIO_I2S_SD0_EN;
1330 core.layout = HDMI_AUDIO_LAYOUT_2CH;
1331 } else {
1332 audio_format.stereo_channels = HDMI_AUDIO_STEREO_FOURCHANNELS;
1333 core.i2s_cfg.active_sds = HDMI_AUDIO_I2S_SD0_EN |
1334 HDMI_AUDIO_I2S_SD1_EN | HDMI_AUDIO_I2S_SD2_EN |
1335 HDMI_AUDIO_I2S_SD3_EN;
1336 core.layout = HDMI_AUDIO_LAYOUT_8CH;
1337 }
1338
1339 core.en_spdif = false;
1340 /* use sample frequency from channel status word */
1341 core.fs_override = true;
1342 /* enable ACR packets */
1343 core.en_acr_pkt = true;
1344 /* disable direct streaming digital audio */
1345 core.en_dsd_audio = false;
1346 /* use parallel audio interface */
1347 core.en_parallel_aud_input = true;
1348
1349 /* DMA settings */
1350 if (word_length_16b)
1351 audio_dma.transfer_size = 0x10;
1352 else
1353 audio_dma.transfer_size = 0x20;
1354 audio_dma.block_size = 0xC0;
1355 audio_dma.mode = HDMI_AUDIO_TRANSF_DMA;
1356 audio_dma.fifo_threshold = 0x20; /* in number of samples */
1357
1358 /* audio FIFO format settings */
1359 if (word_length_16b) {
1360 audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_TWOSAMPLES;
1361 audio_format.sample_size = HDMI_AUDIO_SAMPLE_16BITS;
1362 audio_format.justification = HDMI_AUDIO_JUSTIFY_LEFT;
1363 } else {
1364 audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_ONESAMPLE;
1365 audio_format.sample_size = HDMI_AUDIO_SAMPLE_24BITS;
1366 audio_format.justification = HDMI_AUDIO_JUSTIFY_RIGHT;
1367 }
1368 audio_format.type = HDMI_AUDIO_TYPE_LPCM;
1369 audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST;
1370 /* disable start/stop signals of IEC 60958 blocks */
1371 audio_format.en_sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_ON;
1372
1373 /* configure DMA and audio FIFO format*/
1374 ti_hdmi_4xxx_wp_audio_config_dma(ip_data, &audio_dma);
1375 ti_hdmi_4xxx_wp_audio_config_format(ip_data, &audio_format);
1376
1377 /* configure the core*/
1378 ti_hdmi_4xxx_core_audio_config(ip_data, &core);
1379
1380 /* configure CEA 861 audio infoframe*/
1381 ti_hdmi_4xxx_core_audio_infoframe_cfg(ip_data, audio->cea);
1382
1383 return 0;
1384}
1385
1205int ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data) 1386int ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data)
1206{ 1387{
1207 REG_FLD_MOD(hdmi_wp_base(ip_data), 1388 REG_FLD_MOD(hdmi_wp_base(ip_data),