return audio->read(hdmi, offset);
}
+static inline void hdmi_update_bits(struct dw_hdmi_i2s_audio_data *audio,
+ u8 data, u8 mask, unsigned int reg)
+{
+ struct dw_hdmi *hdmi = audio->hdmi;
+
+ audio->mod(hdmi, data, mask, reg);
+}
+
static int dw_hdmi_i2s_hw_params(struct device *dev, void *data,
struct hdmi_codec_daifmt *fmt,
struct hdmi_codec_params *hparms)
u8 conf0 = 0;
u8 conf1 = 0;
u8 inputclkfs = 0;
+ u8 val;
/* it cares I2S only */
if ((fmt->fmt != HDMI_I2S) ||
return -EINVAL;
}
- inputclkfs = HDMI_AUD_INPUTCLKFS_64FS;
+ inputclkfs = HDMI_AUD_INPUTCLKFS_128FS;
switch (hparms->sample_width) {
case 16:
return -EINVAL;
}
- dw_hdmi_set_sample_rate(hdmi, hparms->sample_rate);
-
- hdmi_write(audio, inputclkfs, HDMI_AUD_INPUTCLKFS);
- hdmi_write(audio, conf0, HDMI_AUD_CONF0);
- hdmi_write(audio, conf1, HDMI_AUD_CONF1);
/*
* dw-hdmi introduced insert_pcuv bit in version 2.10a.
* When set (1'b1), this bit enables the insertion of the PCUV
* (Parity, Channel Status, User bit and Validity) bits on the
* incoming audio stream (support limited to Linear PCM audio)
*/
- if (hdmi_read(audio, HDMI_DESIGN_ID) > 0x21)
- hdmi_write(audio, HDMI_AUD_CONF2_INSERT_PCUV, HDMI_AUD_CONF2);
+ val = 0;
+ if (hdmi_read(audio, HDMI_DESIGN_ID) >= 0x21)
+ val = HDMI_AUD_CONF2_INSERT_PCUV;
+
+ /*Mask fifo empty and full int and reset fifo*/
+ hdmi_update_bits(audio,
+ HDMI_AUD_INT_FIFO_EMPTY_MSK |
+ HDMI_AUD_INT_FIFO_FULL_MSK,
+ HDMI_AUD_INT_FIFO_EMPTY_MSK |
+ HDMI_AUD_INT_FIFO_FULL_MSK, HDMI_AUD_INT);
+ hdmi_update_bits(audio, HDMI_AUD_CONF0_SW_RESET,
+ HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0);
+ hdmi_update_bits(audio, HDMI_MC_SWRSTZ_I2S_RESET_MSK,
+ HDMI_MC_SWRSTZ_I2S_RESET_MSK, HDMI_MC_SWRSTZ);
+
+ switch (hparms->mode) {
+ case NLPCM:
+ hdmi_write(audio, HDMI_AUD_CONF2_NLPCM, HDMI_AUD_CONF2);
+ conf1 = HDMI_AUD_CONF1_WIDTH_21;
+ break;
+ case HBR:
+ hdmi_write(audio, HDMI_AUD_CONF2_HBR, HDMI_AUD_CONF2);
+ conf1 = HDMI_AUD_CONF1_WIDTH_21;
+ break;
+ default:
+ hdmi_write(audio, val, HDMI_AUD_CONF2);
+ break;
+ }
+
+ dw_hdmi_set_sample_rate(hdmi, hparms->sample_rate);
+
+ hdmi_write(audio, inputclkfs, HDMI_AUD_INPUTCLKFS);
+ hdmi_write(audio, conf0, HDMI_AUD_CONF0);
+ hdmi_write(audio, conf1, HDMI_AUD_CONF1);
+
+ val = HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT0;
+ if (hparms->channels > 2)
+ val = HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT1;
+ hdmi_update_bits(audio, val, HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_MASK,
+ HDMI_FC_AUDSCONF);
+
+ switch (hparms->sample_rate) {
+ case 32000:
+ val = HDMI_FC_AUDSCHNLS_32K;
+ break;
+ case 44100:
+ val = HDMI_FC_AUDSCHNLS_441K;
+ break;
+ case 48000:
+ val = HDMI_FC_AUDSCHNLS_48K;
+ break;
+ case 88200:
+ val = HDMI_FC_AUDSCHNLS_882K;
+ break;
+ case 96000:
+ val = HDMI_FC_AUDSCHNLS_96K;
+ break;
+ case 176400:
+ val = HDMI_FC_AUDSCHNLS_1764K;
+ break;
+ case 192000:
+ val = HDMI_FC_AUDSCHNLS_192K;
+ break;
+ default:
+ val = HDMI_FC_AUDSCHNLS_441K;
+ break;
+ }
+
+ /* set channel status register */
+ hdmi_update_bits(audio, val,
+ HDMI_FC_AUDSCHNLS7_SAMPFREQ_MASK,
+ HDMI_FC_AUDSCHNLS7);
+ hdmi_write(audio,
+ ((~val) << HDMI_FC_AUDSCHNLS8_ORIGSAMPFREQ_OFFSET),
+ HDMI_FC_AUDSCHNLS8);
+
+ /* Refer to CEA861-E Audio infoFrame
+ * Set both Audio Channel Count and Audio Coding
+ * Type Refer to Stream Head for HDMI
+ */
+ hdmi_update_bits(audio,
+ (hparms->channels - 1) << HDMI_FC_AUDICONF0_CC_OFFSET,
+ HDMI_FC_AUDICONF0_CC_MASK, HDMI_FC_AUDICONF0);
+
+ /* Set both Audio Sample Size and Sample Frequency
+ * Refer to Stream Head for HDMI
+ */
+ hdmi_write(audio, 0x00, HDMI_FC_AUDICONF1);
+
+ /* Set Channel Allocation */
+ hdmi_write(audio, 0x00, HDMI_FC_AUDICONF2);
+
+ /* Set LFEPBLDOWN-MIX INH and LSV */
+ hdmi_write(audio, 0x00, HDMI_FC_AUDICONF3);
+
+ hdmi_update_bits(audio, HDMI_AUD_CONF0_SW_RESET,
+ HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0);
+ hdmi_update_bits(audio, HDMI_MC_SWRSTZ_I2S_RESET_MSK,
+ HDMI_MC_SWRSTZ_I2S_RESET_MSK, HDMI_MC_SWRSTZ);
+
dw_hdmi_audio_enable(hdmi);
return 0;
#define HDMI_FC_SPDDEVICEINF 0x1062
#define HDMI_FC_AUDSCONF 0x1063
#define HDMI_FC_AUDSSTAT 0x1064
+#define HDMI_FC_AUDSCHNLS0 0x1067
+#define HDMI_FC_AUDSCHNLS1 0x1068
+#define HDMI_FC_AUDSCHNLS2 0x1069
+#define HDMI_FC_AUDSCHNLS3 0x106a
+#define HDMI_FC_AUDSCHNLS4 0x106b
+#define HDMI_FC_AUDSCHNLS5 0x106c
+#define HDMI_FC_AUDSCHNLS6 0x106d
+#define HDMI_FC_AUDSCHNLS7 0x106e
+#define HDMI_FC_AUDSCHNLS8 0x106f
#define HDMI_FC_DATACH0FILL 0x1070
#define HDMI_FC_DATACH1FILL 0x1071
#define HDMI_FC_DATACH2FILL 0x1072
/* HDMI_FC_AUDSCHNLS7 field values */
HDMI_FC_AUDSCHNLS7_ACCURACY_OFFSET = 4,
HDMI_FC_AUDSCHNLS7_ACCURACY_MASK = 0x30,
+ HDMI_FC_AUDSCHNLS7_SAMPFREQ_OFFSET = 0,
+ HDMI_FC_AUDSCHNLS7_SAMPFREQ_MASK = 0x0f,
/* HDMI_FC_AUDSCHNLS8 field values */
HDMI_FC_AUDSCHNLS8_ORIGSAMPFREQ_MASK = 0xf0,
HDMI_FC_AUDSCHNLS8_WORDLEGNTH_MASK = 0x0f,
HDMI_FC_AUDSCHNLS8_WORDLEGNTH_OFFSET = 0,
+/* HDMI_FC_AUDSCHNLS Sample Rate */
+ HDMI_FC_AUDSCHNLS_32K = 0x3,
+ HDMI_FC_AUDSCHNLS_441K = 0x0,
+ HDMI_FC_AUDSCHNLS_48K = 0x2,
+ HDMI_FC_AUDSCHNLS_882K = 0x8,
+ HDMI_FC_AUDSCHNLS_96K = 0xa,
+ HDMI_FC_AUDSCHNLS_1764K = 0xc,
+ HDMI_FC_AUDSCHNLS_192K = 0xe,
+
/* FC_AUDSCONF field values */
HDMI_FC_AUDSCONF_AUD_PACKET_SAMPFIT_MASK = 0xF0,
HDMI_FC_AUDSCONF_AUD_PACKET_SAMPFIT_OFFSET = 4,
HDMI_AUD_CONF0_I2S_8CHANNEL_ENABLE = 0x2F,
HDMI_AUD_CONF0_I2S_ALL_ENABLE = 0x2F,
+/* AUD_INT field values */
+ HDMI_AUD_INT_FIFO_EMPTY_MSK = BIT(3),
+ HDMI_AUD_INT_FIFO_FULL_MSK = BIT(2),
+
/* AUD_CONF1 field values */
HDMI_AUD_CONF1_MODE_I2S = 0x00,
HDMI_AUD_CONF1_MODE_RIGHT_J = 0x02,
HDMI_AUD_CONF1_MODE_LEFT_J = 0x04,
HDMI_AUD_CONF1_WIDTH_16 = 0x10,
+ HDMI_AUD_CONF1_WIDTH_21 = 0x15,
HDMI_AUD_CONF1_WIDTH_24 = 0x18,
/* AUD_CONF2 filed values */
HDMI_I2CM_DIV_FAST_STD_MODE = 0x8,
HDMI_I2CM_DIV_FAST_MODE = 0x8,
HDMI_I2CM_DIV_STD_MODE = 0,
+
+/* HDMI_MC_SWRSTZ filed values */
+ HDMI_MC_SWRSTZ_I2S_RESET_MSK = BIT(3),
};
#endif /* __DW_HDMI_H__ */