blob: e8f8be2f590b4fb3665e8f7760404a8a2d02e8e9 [file] [log] [blame]
Jerome Anand5dab11d2017-01-25 04:27:52 +05301/*
2 * intel_hdmi_audio.c - Intel HDMI audio driver
3 *
4 * Copyright (C) 2016 Intel Corp
5 * Authors: Sailaja Bandarupalli <sailaja.bandarupalli@intel.com>
6 * Ramesh Babu K V <ramesh.babu@intel.com>
7 * Vaibhav Agarwal <vaibhav.agarwal@intel.com>
8 * Jerome Anand <jerome.anand@intel.com>
9 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; version 2 of the License.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
21 * ALSA driver for Intel HDMI audio
22 */
23
Takashi Iwai03c34372017-02-02 16:19:03 +010024#include <linux/types.h>
Jerome Anand5dab11d2017-01-25 04:27:52 +053025#include <linux/platform_device.h>
26#include <linux/io.h>
27#include <linux/slab.h>
28#include <linux/module.h>
Takashi Iwaida864802017-01-31 13:52:22 +010029#include <linux/interrupt.h>
Takashi Iwai03c34372017-02-02 16:19:03 +010030#include <linux/pm_runtime.h>
Takashi Iwai412bbe7d52017-02-02 22:03:22 +010031#include <linux/dma-mapping.h>
Jerome Anand5dab11d2017-01-25 04:27:52 +053032#include <asm/cacheflush.h>
Jerome Anand5dab11d2017-01-25 04:27:52 +053033#include <sound/core.h>
Takashi Iwai03c34372017-02-02 16:19:03 +010034#include <sound/asoundef.h>
35#include <sound/pcm.h>
Jerome Anand5dab11d2017-01-25 04:27:52 +053036#include <sound/pcm_params.h>
37#include <sound/initval.h>
38#include <sound/control.h>
Takashi Iwai03c34372017-02-02 16:19:03 +010039#include <drm/drm_edid.h>
Takashi Iwaida864802017-01-31 13:52:22 +010040#include <drm/intel_lpe_audio.h>
Jerome Anand5dab11d2017-01-25 04:27:52 +053041#include "intel_hdmi_audio.h"
42
Jerome Anand5dab11d2017-01-25 04:27:52 +053043/*standard module options for ALSA. This module supports only one card*/
44static int hdmi_card_index = SNDRV_DEFAULT_IDX1;
45static char *hdmi_card_id = SNDRV_DEFAULT_STR1;
Jerome Anand5dab11d2017-01-25 04:27:52 +053046
47module_param_named(index, hdmi_card_index, int, 0444);
48MODULE_PARM_DESC(index,
49 "Index value for INTEL Intel HDMI Audio controller.");
50module_param_named(id, hdmi_card_id, charp, 0444);
51MODULE_PARM_DESC(id,
52 "ID string for INTEL Intel HDMI Audio controller.");
53
54/*
55 * ELD SA bits in the CEA Speaker Allocation data block
56 */
Takashi Iwai4a5ddb22017-02-01 16:45:38 +010057static const int eld_speaker_allocation_bits[] = {
Jerome Anand5dab11d2017-01-25 04:27:52 +053058 [0] = FL | FR,
59 [1] = LFE,
60 [2] = FC,
61 [3] = RL | RR,
62 [4] = RC,
63 [5] = FLC | FRC,
64 [6] = RLC | RRC,
65 /* the following are not defined in ELD yet */
66 [7] = 0,
67};
68
69/*
70 * This is an ordered list!
71 *
72 * The preceding ones have better chances to be selected by
73 * hdmi_channel_allocation().
74 */
75static struct cea_channel_speaker_allocation channel_allocations[] = {
76/* channel: 7 6 5 4 3 2 1 0 */
77{ .ca_index = 0x00, .speakers = { 0, 0, 0, 0, 0, 0, FR, FL } },
78 /* 2.1 */
79{ .ca_index = 0x01, .speakers = { 0, 0, 0, 0, 0, LFE, FR, FL } },
80 /* Dolby Surround */
81{ .ca_index = 0x02, .speakers = { 0, 0, 0, 0, FC, 0, FR, FL } },
82 /* surround40 */
83{ .ca_index = 0x08, .speakers = { 0, 0, RR, RL, 0, 0, FR, FL } },
84 /* surround41 */
85{ .ca_index = 0x09, .speakers = { 0, 0, RR, RL, 0, LFE, FR, FL } },
86 /* surround50 */
87{ .ca_index = 0x0a, .speakers = { 0, 0, RR, RL, FC, 0, FR, FL } },
88 /* surround51 */
89{ .ca_index = 0x0b, .speakers = { 0, 0, RR, RL, FC, LFE, FR, FL } },
90 /* 6.1 */
91{ .ca_index = 0x0f, .speakers = { 0, RC, RR, RL, FC, LFE, FR, FL } },
92 /* surround71 */
93{ .ca_index = 0x13, .speakers = { RRC, RLC, RR, RL, FC, LFE, FR, FL } },
94
95{ .ca_index = 0x03, .speakers = { 0, 0, 0, 0, FC, LFE, FR, FL } },
96{ .ca_index = 0x04, .speakers = { 0, 0, 0, RC, 0, 0, FR, FL } },
97{ .ca_index = 0x05, .speakers = { 0, 0, 0, RC, 0, LFE, FR, FL } },
98{ .ca_index = 0x06, .speakers = { 0, 0, 0, RC, FC, 0, FR, FL } },
99{ .ca_index = 0x07, .speakers = { 0, 0, 0, RC, FC, LFE, FR, FL } },
100{ .ca_index = 0x0c, .speakers = { 0, RC, RR, RL, 0, 0, FR, FL } },
101{ .ca_index = 0x0d, .speakers = { 0, RC, RR, RL, 0, LFE, FR, FL } },
102{ .ca_index = 0x0e, .speakers = { 0, RC, RR, RL, FC, 0, FR, FL } },
103{ .ca_index = 0x10, .speakers = { RRC, RLC, RR, RL, 0, 0, FR, FL } },
104{ .ca_index = 0x11, .speakers = { RRC, RLC, RR, RL, 0, LFE, FR, FL } },
105{ .ca_index = 0x12, .speakers = { RRC, RLC, RR, RL, FC, 0, FR, FL } },
106{ .ca_index = 0x14, .speakers = { FRC, FLC, 0, 0, 0, 0, FR, FL } },
107{ .ca_index = 0x15, .speakers = { FRC, FLC, 0, 0, 0, LFE, FR, FL } },
108{ .ca_index = 0x16, .speakers = { FRC, FLC, 0, 0, FC, 0, FR, FL } },
109{ .ca_index = 0x17, .speakers = { FRC, FLC, 0, 0, FC, LFE, FR, FL } },
110{ .ca_index = 0x18, .speakers = { FRC, FLC, 0, RC, 0, 0, FR, FL } },
111{ .ca_index = 0x19, .speakers = { FRC, FLC, 0, RC, 0, LFE, FR, FL } },
112{ .ca_index = 0x1a, .speakers = { FRC, FLC, 0, RC, FC, 0, FR, FL } },
113{ .ca_index = 0x1b, .speakers = { FRC, FLC, 0, RC, FC, LFE, FR, FL } },
114{ .ca_index = 0x1c, .speakers = { FRC, FLC, RR, RL, 0, 0, FR, FL } },
115{ .ca_index = 0x1d, .speakers = { FRC, FLC, RR, RL, 0, LFE, FR, FL } },
116{ .ca_index = 0x1e, .speakers = { FRC, FLC, RR, RL, FC, 0, FR, FL } },
117{ .ca_index = 0x1f, .speakers = { FRC, FLC, RR, RL, FC, LFE, FR, FL } },
118};
119
Takashi Iwai4a5ddb22017-02-01 16:45:38 +0100120static const struct channel_map_table map_tables[] = {
Jerome Anand5dab11d2017-01-25 04:27:52 +0530121 { SNDRV_CHMAP_FL, 0x00, FL },
122 { SNDRV_CHMAP_FR, 0x01, FR },
123 { SNDRV_CHMAP_RL, 0x04, RL },
124 { SNDRV_CHMAP_RR, 0x05, RR },
125 { SNDRV_CHMAP_LFE, 0x02, LFE },
126 { SNDRV_CHMAP_FC, 0x03, FC },
127 { SNDRV_CHMAP_RLC, 0x06, RLC },
128 { SNDRV_CHMAP_RRC, 0x07, RRC },
129 {} /* terminator */
130};
131
132/* hardware capability structure */
Takashi Iwaib5562902017-02-04 22:05:33 +0100133static const struct snd_pcm_hardware had_pcm_hardware = {
Jerome Anand5dab11d2017-01-25 04:27:52 +0530134 .info = (SNDRV_PCM_INFO_INTERLEAVED |
Takashi Iwaia9ebdd02017-02-02 21:33:54 +0100135 SNDRV_PCM_INFO_MMAP |
Takashi Iwaie8de9852017-02-07 08:09:12 +0100136 SNDRV_PCM_INFO_MMAP_VALID |
137 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP),
Takashi Iwai85bd8742017-02-07 13:33:17 +0100138 .formats = (SNDRV_PCM_FMTBIT_S24_LE |
139 SNDRV_PCM_FMTBIT_S32_LE),
Jerome Anand5dab11d2017-01-25 04:27:52 +0530140 .rates = SNDRV_PCM_RATE_32000 |
141 SNDRV_PCM_RATE_44100 |
142 SNDRV_PCM_RATE_48000 |
143 SNDRV_PCM_RATE_88200 |
144 SNDRV_PCM_RATE_96000 |
145 SNDRV_PCM_RATE_176400 |
146 SNDRV_PCM_RATE_192000,
147 .rate_min = HAD_MIN_RATE,
148 .rate_max = HAD_MAX_RATE,
149 .channels_min = HAD_MIN_CHANNEL,
150 .channels_max = HAD_MAX_CHANNEL,
151 .buffer_bytes_max = HAD_MAX_BUFFER,
152 .period_bytes_min = HAD_MIN_PERIOD_BYTES,
153 .period_bytes_max = HAD_MAX_PERIOD_BYTES,
154 .periods_min = HAD_MIN_PERIODS,
155 .periods_max = HAD_MAX_PERIODS,
156 .fifo_size = HAD_FIFO_SIZE,
157};
158
Takashi Iwai313d9f22017-02-02 13:00:12 +0100159/* Get the active PCM substream;
160 * Call had_substream_put() for unreferecing.
161 * Don't call this inside had_spinlock, as it takes by itself
162 */
163static struct snd_pcm_substream *
164had_substream_get(struct snd_intelhad *intelhaddata)
165{
166 struct snd_pcm_substream *substream;
167 unsigned long flags;
168
169 spin_lock_irqsave(&intelhaddata->had_spinlock, flags);
170 substream = intelhaddata->stream_info.substream;
171 if (substream)
172 intelhaddata->stream_info.substream_refcount++;
173 spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags);
174 return substream;
175}
176
177/* Unref the active PCM substream;
178 * Don't call this inside had_spinlock, as it takes by itself
179 */
180static void had_substream_put(struct snd_intelhad *intelhaddata)
181{
182 unsigned long flags;
183
184 spin_lock_irqsave(&intelhaddata->had_spinlock, flags);
185 intelhaddata->stream_info.substream_refcount--;
186 spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags);
187}
188
Jerome Anand5dab11d2017-01-25 04:27:52 +0530189/* Register access functions */
Takashi Iwai83af57d2017-02-03 08:50:06 +0100190static void had_read_register(struct snd_intelhad *ctx, u32 reg, u32 *val)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530191{
Takashi Iwaida864802017-01-31 13:52:22 +0100192 *val = ioread32(ctx->mmio_start + ctx->had_config_offset + reg);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530193}
194
Takashi Iwai83af57d2017-02-03 08:50:06 +0100195static void had_write_register(struct snd_intelhad *ctx, u32 reg, u32 val)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530196{
Takashi Iwaida864802017-01-31 13:52:22 +0100197 iowrite32(val, ctx->mmio_start + ctx->had_config_offset + reg);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530198}
199
Takashi Iwaida864802017-01-31 13:52:22 +0100200/*
Takashi Iwai313d9f22017-02-02 13:00:12 +0100201 * enable / disable audio configuration
202 *
Takashi Iwai83af57d2017-02-03 08:50:06 +0100203 * The normal read/modify should not directly be used on VLV2 for
Takashi Iwaida864802017-01-31 13:52:22 +0100204 * updating AUD_CONFIG register.
Jerome Anand5dab11d2017-01-25 04:27:52 +0530205 * This is because:
206 * Bit6 of AUD_CONFIG register is writeonly due to a silicon bug on VLV2
207 * HDMI IP. As a result a read-modify of AUD_CONFIG regiter will always
208 * clear bit6. AUD_CONFIG[6:4] represents the "channels" field of the
209 * register. This field should be 1xy binary for configuration with 6 or
210 * more channels. Read-modify of AUD_CONFIG (Eg. for enabling audio)
211 * causes the "channels" field to be updated as 0xy binary resulting in
212 * bad audio. The fix is to always write the AUD_CONFIG[6:4] with
213 * appropriate value when doing read-modify of AUD_CONFIG register.
Jerome Anand5dab11d2017-01-25 04:27:52 +0530214 */
Takashi Iwai40ce4b52017-02-07 16:17:06 +0100215static void had_enable_audio(struct snd_intelhad *intelhaddata,
Takashi Iwaib5562902017-02-04 22:05:33 +0100216 bool enable)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530217{
Takashi Iwai40ce4b52017-02-07 16:17:06 +0100218 /* update the cached value */
219 intelhaddata->aud_config.regx.aud_en = enable;
220 had_write_register(intelhaddata, AUD_CONFIG,
221 intelhaddata->aud_config.regval);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530222}
223
Takashi Iwai075a1d42017-02-07 07:55:27 +0100224/* forcibly ACKs to both BUFFER_DONE and BUFFER_UNDERRUN interrupts */
225static void had_ack_irqs(struct snd_intelhad *ctx)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530226{
Takashi Iwaida864802017-01-31 13:52:22 +0100227 u32 status_reg;
228
Takashi Iwai075a1d42017-02-07 07:55:27 +0100229 had_read_register(ctx, AUD_HDMI_STATUS, &status_reg);
230 status_reg |= HDMI_AUDIO_BUFFER_DONE | HDMI_AUDIO_UNDERRUN;
231 had_write_register(ctx, AUD_HDMI_STATUS, status_reg);
232 had_read_register(ctx, AUD_HDMI_STATUS, &status_reg);
Takashi Iwaida864802017-01-31 13:52:22 +0100233}
234
Takashi Iwaif4566aa2017-02-04 21:39:56 +0100235/* Reset buffer pointers */
236static void had_reset_audio(struct snd_intelhad *intelhaddata)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530237{
Takashi Iwai77531be2017-02-07 12:17:23 +0100238 had_write_register(intelhaddata, AUD_HDMI_STATUS,
239 AUD_HDMI_STATUSG_MASK_FUNCRST);
Takashi Iwaif4566aa2017-02-04 21:39:56 +0100240 had_write_register(intelhaddata, AUD_HDMI_STATUS, 0);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530241}
242
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100243/*
Jerome Anand5dab11d2017-01-25 04:27:52 +0530244 * initialize audio channel status registers
245 * This function is called in the prepare callback
246 */
247static int had_prog_status_reg(struct snd_pcm_substream *substream,
248 struct snd_intelhad *intelhaddata)
249{
Takashi Iwai7ceba752017-02-02 15:58:35 +0100250 union aud_cfg cfg_val = {.regval = 0};
251 union aud_ch_status_0 ch_stat0 = {.regval = 0};
252 union aud_ch_status_1 ch_stat1 = {.regval = 0};
Jerome Anand5dab11d2017-01-25 04:27:52 +0530253
Takashi Iwai7ceba752017-02-02 15:58:35 +0100254 ch_stat0.regx.lpcm_id = (intelhaddata->aes_bits &
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100255 IEC958_AES0_NONAUDIO) >> 1;
Takashi Iwai7ceba752017-02-02 15:58:35 +0100256 ch_stat0.regx.clk_acc = (intelhaddata->aes_bits &
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100257 IEC958_AES3_CON_CLOCK) >> 4;
Takashi Iwai7ceba752017-02-02 15:58:35 +0100258 cfg_val.regx.val_bit = ch_stat0.regx.lpcm_id;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530259
260 switch (substream->runtime->rate) {
261 case AUD_SAMPLE_RATE_32:
Takashi Iwai7ceba752017-02-02 15:58:35 +0100262 ch_stat0.regx.samp_freq = CH_STATUS_MAP_32KHZ;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530263 break;
264
265 case AUD_SAMPLE_RATE_44_1:
Takashi Iwai7ceba752017-02-02 15:58:35 +0100266 ch_stat0.regx.samp_freq = CH_STATUS_MAP_44KHZ;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530267 break;
268 case AUD_SAMPLE_RATE_48:
Takashi Iwai7ceba752017-02-02 15:58:35 +0100269 ch_stat0.regx.samp_freq = CH_STATUS_MAP_48KHZ;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530270 break;
271 case AUD_SAMPLE_RATE_88_2:
Takashi Iwai7ceba752017-02-02 15:58:35 +0100272 ch_stat0.regx.samp_freq = CH_STATUS_MAP_88KHZ;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530273 break;
274 case AUD_SAMPLE_RATE_96:
Takashi Iwai7ceba752017-02-02 15:58:35 +0100275 ch_stat0.regx.samp_freq = CH_STATUS_MAP_96KHZ;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530276 break;
277 case AUD_SAMPLE_RATE_176_4:
Takashi Iwai7ceba752017-02-02 15:58:35 +0100278 ch_stat0.regx.samp_freq = CH_STATUS_MAP_176KHZ;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530279 break;
280 case AUD_SAMPLE_RATE_192:
Takashi Iwai7ceba752017-02-02 15:58:35 +0100281 ch_stat0.regx.samp_freq = CH_STATUS_MAP_192KHZ;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530282 break;
283
284 default:
285 /* control should never come here */
286 return -EINVAL;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530287 }
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100288
Takashi Iwai79dda752017-01-30 17:23:39 +0100289 had_write_register(intelhaddata,
Takashi Iwai7ceba752017-02-02 15:58:35 +0100290 AUD_CH_STATUS_0, ch_stat0.regval);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530291
Takashi Iwai85bd8742017-02-07 13:33:17 +0100292 switch (substream->runtime->format) {
293#if 0 /* FIXME: not supported yet */
294 case SNDRV_PCM_FORMAT_S16_LE:
Takashi Iwai7ceba752017-02-02 15:58:35 +0100295 ch_stat1.regx.max_wrd_len = MAX_SMPL_WIDTH_20;
296 ch_stat1.regx.wrd_len = SMPL_WIDTH_16BITS;
Takashi Iwai85bd8742017-02-07 13:33:17 +0100297 break;
298#endif
299 case SNDRV_PCM_FORMAT_S24_LE:
300 case SNDRV_PCM_FORMAT_S32_LE:
Takashi Iwai7ceba752017-02-02 15:58:35 +0100301 ch_stat1.regx.max_wrd_len = MAX_SMPL_WIDTH_24;
302 ch_stat1.regx.wrd_len = SMPL_WIDTH_24BITS;
Takashi Iwai85bd8742017-02-07 13:33:17 +0100303 break;
304 default:
305 return -EINVAL;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530306 }
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100307
Takashi Iwai79dda752017-01-30 17:23:39 +0100308 had_write_register(intelhaddata,
Takashi Iwai7ceba752017-02-02 15:58:35 +0100309 AUD_CH_STATUS_1, ch_stat1.regval);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530310 return 0;
311}
312
Takashi Iwai76296ef2017-01-30 16:09:11 +0100313/*
Jerome Anand5dab11d2017-01-25 04:27:52 +0530314 * function to initialize audio
315 * registers and buffer confgiuration registers
316 * This function is called in the prepare callback
317 */
Takashi Iwaib5562902017-02-04 22:05:33 +0100318static int had_init_audio_ctrl(struct snd_pcm_substream *substream,
319 struct snd_intelhad *intelhaddata)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530320{
Takashi Iwai7ceba752017-02-02 15:58:35 +0100321 union aud_cfg cfg_val = {.regval = 0};
322 union aud_buf_config buf_cfg = {.regval = 0};
Jerome Anand5dab11d2017-01-25 04:27:52 +0530323 u8 channels;
324
325 had_prog_status_reg(substream, intelhaddata);
326
Takashi Iwai7ceba752017-02-02 15:58:35 +0100327 buf_cfg.regx.audio_fifo_watermark = FIFO_THRESHOLD;
328 buf_cfg.regx.dma_fifo_watermark = DMA_FIFO_THRESHOLD;
329 buf_cfg.regx.aud_delay = 0;
330 had_write_register(intelhaddata, AUD_BUF_CONFIG, buf_cfg.regval);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530331
332 channels = substream->runtime->channels;
Takashi Iwai7ceba752017-02-02 15:58:35 +0100333 cfg_val.regx.num_ch = channels - 2;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530334 if (channels <= 2)
Takashi Iwai7ceba752017-02-02 15:58:35 +0100335 cfg_val.regx.layout = LAYOUT0;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530336 else
Takashi Iwai7ceba752017-02-02 15:58:35 +0100337 cfg_val.regx.layout = LAYOUT1;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530338
Takashi Iwai85bd8742017-02-07 13:33:17 +0100339 if (substream->runtime->format == SNDRV_PCM_FORMAT_S32_LE)
340 cfg_val.regx.left_align = 1;
341
Takashi Iwai7ceba752017-02-02 15:58:35 +0100342 cfg_val.regx.val_bit = 1;
Takashi Iwai83af57d2017-02-03 08:50:06 +0100343
344 /* fix up the DP bits */
345 if (intelhaddata->dp_output) {
346 cfg_val.regx.dp_modei = 1;
347 cfg_val.regx.set = 1;
348 }
349
Takashi Iwai7ceba752017-02-02 15:58:35 +0100350 had_write_register(intelhaddata, AUD_CONFIG, cfg_val.regval);
Takashi Iwai40ce4b52017-02-07 16:17:06 +0100351 intelhaddata->aud_config = cfg_val;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530352 return 0;
353}
354
Jerome Anand5dab11d2017-01-25 04:27:52 +0530355/*
356 * Compute derived values in channel_allocations[].
357 */
358static void init_channel_allocations(void)
359{
360 int i, j;
361 struct cea_channel_speaker_allocation *p;
362
Jerome Anand5dab11d2017-01-25 04:27:52 +0530363 for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
364 p = channel_allocations + i;
365 p->channels = 0;
366 p->spk_mask = 0;
367 for (j = 0; j < ARRAY_SIZE(p->speakers); j++)
368 if (p->speakers[j]) {
369 p->channels++;
370 p->spk_mask |= p->speakers[j];
371 }
372 }
373}
374
375/*
376 * The transformation takes two steps:
377 *
378 * eld->spk_alloc => (eld_speaker_allocation_bits[]) => spk_mask
379 * spk_mask => (channel_allocations[]) => ai->CA
380 *
381 * TODO: it could select the wrong CA from multiple candidates.
382 */
Takashi Iwaib5562902017-02-04 22:05:33 +0100383static int had_channel_allocation(struct snd_intelhad *intelhaddata,
384 int channels)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530385{
386 int i;
387 int ca = 0;
388 int spk_mask = 0;
389
390 /*
391 * CA defaults to 0 for basic stereo audio
392 */
393 if (channels <= 2)
394 return 0;
395
396 /*
397 * expand ELD's speaker allocation mask
398 *
399 * ELD tells the speaker mask in a compact(paired) form,
400 * expand ELD's notions to match the ones used by Audio InfoFrame.
401 */
402
403 for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) {
Takashi Iwaidf0435d2017-02-02 15:37:11 +0100404 if (intelhaddata->eld[DRM_ELD_SPEAKER] & (1 << i))
Jerome Anand5dab11d2017-01-25 04:27:52 +0530405 spk_mask |= eld_speaker_allocation_bits[i];
406 }
407
408 /* search for the first working match in the CA table */
409 for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
410 if (channels == channel_allocations[i].channels &&
411 (spk_mask & channel_allocations[i].spk_mask) ==
412 channel_allocations[i].spk_mask) {
413 ca = channel_allocations[i].ca_index;
414 break;
415 }
416 }
417
Takashi Iwaic75b0472017-01-31 15:49:15 +0100418 dev_dbg(intelhaddata->dev, "select CA 0x%x for %d\n", ca, channels);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530419
420 return ca;
421}
422
423/* from speaker bit mask to ALSA API channel position */
424static int spk_to_chmap(int spk)
425{
Takashi Iwai4a5ddb22017-02-01 16:45:38 +0100426 const struct channel_map_table *t = map_tables;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530427
428 for (; t->map; t++) {
429 if (t->spk_mask == spk)
430 return t->map;
431 }
432 return 0;
433}
434
Takashi Iwai372d8552017-01-31 13:57:58 +0100435static void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530436{
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100437 int i, c;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530438 int spk_mask = 0;
439 struct snd_pcm_chmap_elem *chmap;
440 u8 eld_high, eld_high_mask = 0xF0;
441 u8 high_msb;
442
443 chmap = kzalloc(sizeof(*chmap), GFP_KERNEL);
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100444 if (!chmap) {
Jerome Anand5dab11d2017-01-25 04:27:52 +0530445 intelhaddata->chmap->chmap = NULL;
446 return;
447 }
448
Takashi Iwaidf0435d2017-02-02 15:37:11 +0100449 dev_dbg(intelhaddata->dev, "eld speaker = %x\n",
450 intelhaddata->eld[DRM_ELD_SPEAKER]);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530451
452 /* WA: Fix the max channel supported to 8 */
453
454 /*
455 * Sink may support more than 8 channels, if eld_high has more than
456 * one bit set. SOC supports max 8 channels.
457 * Refer eld_speaker_allocation_bits, for sink speaker allocation
458 */
459
460 /* if 0x2F < eld < 0x4F fall back to 0x2f, else fall back to 0x4F */
Takashi Iwaidf0435d2017-02-02 15:37:11 +0100461 eld_high = intelhaddata->eld[DRM_ELD_SPEAKER] & eld_high_mask;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530462 if ((eld_high & (eld_high-1)) && (eld_high > 0x1F)) {
463 /* eld_high & (eld_high-1): if more than 1 bit set */
464 /* 0x1F: 7 channels */
465 for (i = 1; i < 4; i++) {
466 high_msb = eld_high & (0x80 >> i);
467 if (high_msb) {
Takashi Iwaidf0435d2017-02-02 15:37:11 +0100468 intelhaddata->eld[DRM_ELD_SPEAKER] &=
Jerome Anand5dab11d2017-01-25 04:27:52 +0530469 high_msb | 0xF;
470 break;
471 }
472 }
473 }
474
475 for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) {
Takashi Iwaidf0435d2017-02-02 15:37:11 +0100476 if (intelhaddata->eld[DRM_ELD_SPEAKER] & (1 << i))
Jerome Anand5dab11d2017-01-25 04:27:52 +0530477 spk_mask |= eld_speaker_allocation_bits[i];
478 }
479
480 for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
481 if (spk_mask == channel_allocations[i].spk_mask) {
482 for (c = 0; c < channel_allocations[i].channels; c++) {
483 chmap->map[c] = spk_to_chmap(
484 channel_allocations[i].speakers[
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100485 (MAX_SPEAKERS - 1) - c]);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530486 }
487 chmap->channels = channel_allocations[i].channels;
488 intelhaddata->chmap->chmap = chmap;
489 break;
490 }
491 }
492 if (i >= ARRAY_SIZE(channel_allocations)) {
493 intelhaddata->chmap->chmap = NULL;
494 kfree(chmap);
495 }
496}
497
498/*
499 * ALSA API channel-map control callbacks
500 */
501static int had_chmap_ctl_info(struct snd_kcontrol *kcontrol,
502 struct snd_ctl_elem_info *uinfo)
503{
504 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
505 struct snd_intelhad *intelhaddata = info->private_data;
506
Takashi Iwai91b0cb02017-02-02 17:46:49 +0100507 if (!intelhaddata->connected)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530508 return -ENODEV;
509 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
510 uinfo->count = HAD_MAX_CHANNEL;
511 uinfo->value.integer.min = 0;
512 uinfo->value.integer.max = SNDRV_CHMAP_LAST;
513 return 0;
514}
515
516static int had_chmap_ctl_get(struct snd_kcontrol *kcontrol,
517 struct snd_ctl_elem_value *ucontrol)
518{
519 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
520 struct snd_intelhad *intelhaddata = info->private_data;
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100521 int i;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530522 const struct snd_pcm_chmap_elem *chmap;
523
Takashi Iwai91b0cb02017-02-02 17:46:49 +0100524 if (!intelhaddata->connected)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530525 return -ENODEV;
Takashi Iwai8f8d1d72017-02-01 17:24:02 +0100526
527 mutex_lock(&intelhaddata->mutex);
528 if (!intelhaddata->chmap->chmap) {
529 mutex_unlock(&intelhaddata->mutex);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530530 return -ENODATA;
Takashi Iwai8f8d1d72017-02-01 17:24:02 +0100531 }
532
Jerome Anand5dab11d2017-01-25 04:27:52 +0530533 chmap = intelhaddata->chmap->chmap;
Takashi Iwaic75b0472017-01-31 15:49:15 +0100534 for (i = 0; i < chmap->channels; i++)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530535 ucontrol->value.integer.value[i] = chmap->map[i];
Takashi Iwai8f8d1d72017-02-01 17:24:02 +0100536 mutex_unlock(&intelhaddata->mutex);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530537
538 return 0;
539}
540
541static int had_register_chmap_ctls(struct snd_intelhad *intelhaddata,
542 struct snd_pcm *pcm)
543{
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100544 int err;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530545
546 err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
547 NULL, 0, (unsigned long)intelhaddata,
548 &intelhaddata->chmap);
549 if (err < 0)
550 return err;
551
552 intelhaddata->chmap->private_data = intelhaddata;
Takashi Iwaie9d65ab2017-01-31 16:11:27 +0100553 intelhaddata->chmap->kctl->info = had_chmap_ctl_info;
554 intelhaddata->chmap->kctl->get = had_chmap_ctl_get;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530555 intelhaddata->chmap->chmap = NULL;
556 return 0;
557}
558
Takashi Iwai76296ef2017-01-30 16:09:11 +0100559/*
Takashi Iwai44684f62017-02-02 17:27:40 +0100560 * Initialize Data Island Packets registers
Jerome Anand5dab11d2017-01-25 04:27:52 +0530561 * This function is called in the prepare callback
562 */
Takashi Iwaib5562902017-02-04 22:05:33 +0100563static void had_prog_dip(struct snd_pcm_substream *substream,
564 struct snd_intelhad *intelhaddata)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530565{
566 int i;
Takashi Iwai7ceba752017-02-02 15:58:35 +0100567 union aud_ctrl_st ctrl_state = {.regval = 0};
568 union aud_info_frame2 frame2 = {.regval = 0};
569 union aud_info_frame3 frame3 = {.regval = 0};
Jerome Anand5dab11d2017-01-25 04:27:52 +0530570 u8 checksum = 0;
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -0600571 u32 info_frame;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530572 int channels;
Takashi Iwai36ed3462017-02-02 17:06:38 +0100573 int ca;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530574
575 channels = substream->runtime->channels;
576
Takashi Iwai7ceba752017-02-02 15:58:35 +0100577 had_write_register(intelhaddata, AUD_CNTL_ST, ctrl_state.regval);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530578
Takashi Iwaib5562902017-02-04 22:05:33 +0100579 ca = had_channel_allocation(intelhaddata, channels);
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -0600580 if (intelhaddata->dp_output) {
581 info_frame = DP_INFO_FRAME_WORD1;
Takashi Iwai36ed3462017-02-02 17:06:38 +0100582 frame2.regval = (substream->runtime->channels - 1) | (ca << 24);
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -0600583 } else {
584 info_frame = HDMI_INFO_FRAME_WORD1;
Takashi Iwai7ceba752017-02-02 15:58:35 +0100585 frame2.regx.chnl_cnt = substream->runtime->channels - 1;
Takashi Iwai36ed3462017-02-02 17:06:38 +0100586 frame3.regx.chnl_alloc = ca;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530587
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100588 /* Calculte the byte wide checksum for all valid DIP words */
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -0600589 for (i = 0; i < BYTES_PER_WORD; i++)
Takashi Iwai7ceba752017-02-02 15:58:35 +0100590 checksum += (info_frame >> (i * 8)) & 0xff;
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -0600591 for (i = 0; i < BYTES_PER_WORD; i++)
Takashi Iwai7ceba752017-02-02 15:58:35 +0100592 checksum += (frame2.regval >> (i * 8)) & 0xff;
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -0600593 for (i = 0; i < BYTES_PER_WORD; i++)
Takashi Iwai7ceba752017-02-02 15:58:35 +0100594 checksum += (frame3.regval >> (i * 8)) & 0xff;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530595
Takashi Iwai7ceba752017-02-02 15:58:35 +0100596 frame2.regx.chksum = -(checksum);
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -0600597 }
Jerome Anand5dab11d2017-01-25 04:27:52 +0530598
Takashi Iwai4151ee82017-01-31 18:14:15 +0100599 had_write_register(intelhaddata, AUD_HDMIW_INFOFR, info_frame);
Takashi Iwai7ceba752017-02-02 15:58:35 +0100600 had_write_register(intelhaddata, AUD_HDMIW_INFOFR, frame2.regval);
601 had_write_register(intelhaddata, AUD_HDMIW_INFOFR, frame3.regval);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530602
603 /* program remaining DIP words with zero */
604 for (i = 0; i < HAD_MAX_DIP_WORDS-VALID_DIP_WORDS; i++)
Takashi Iwai4151ee82017-01-31 18:14:15 +0100605 had_write_register(intelhaddata, AUD_HDMIW_INFOFR, 0x0);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530606
Takashi Iwai7ceba752017-02-02 15:58:35 +0100607 ctrl_state.regx.dip_freq = 1;
608 ctrl_state.regx.dip_en_sta = 1;
609 had_write_register(intelhaddata, AUD_CNTL_ST, ctrl_state.regval);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530610}
611
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -0600612static int had_calculate_maud_value(u32 aud_samp_freq, u32 link_rate)
613{
614 u32 maud_val;
615
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100616 /* Select maud according to DP 1.2 spec */
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -0600617 if (link_rate == DP_2_7_GHZ) {
618 switch (aud_samp_freq) {
619 case AUD_SAMPLE_RATE_32:
620 maud_val = AUD_SAMPLE_RATE_32_DP_2_7_MAUD_VAL;
621 break;
622
623 case AUD_SAMPLE_RATE_44_1:
624 maud_val = AUD_SAMPLE_RATE_44_1_DP_2_7_MAUD_VAL;
625 break;
626
627 case AUD_SAMPLE_RATE_48:
628 maud_val = AUD_SAMPLE_RATE_48_DP_2_7_MAUD_VAL;
629 break;
630
631 case AUD_SAMPLE_RATE_88_2:
632 maud_val = AUD_SAMPLE_RATE_88_2_DP_2_7_MAUD_VAL;
633 break;
634
635 case AUD_SAMPLE_RATE_96:
636 maud_val = AUD_SAMPLE_RATE_96_DP_2_7_MAUD_VAL;
637 break;
638
639 case AUD_SAMPLE_RATE_176_4:
640 maud_val = AUD_SAMPLE_RATE_176_4_DP_2_7_MAUD_VAL;
641 break;
642
643 case HAD_MAX_RATE:
644 maud_val = HAD_MAX_RATE_DP_2_7_MAUD_VAL;
645 break;
646
647 default:
648 maud_val = -EINVAL;
649 break;
650 }
651 } else if (link_rate == DP_1_62_GHZ) {
652 switch (aud_samp_freq) {
653 case AUD_SAMPLE_RATE_32:
654 maud_val = AUD_SAMPLE_RATE_32_DP_1_62_MAUD_VAL;
655 break;
656
657 case AUD_SAMPLE_RATE_44_1:
658 maud_val = AUD_SAMPLE_RATE_44_1_DP_1_62_MAUD_VAL;
659 break;
660
661 case AUD_SAMPLE_RATE_48:
662 maud_val = AUD_SAMPLE_RATE_48_DP_1_62_MAUD_VAL;
663 break;
664
665 case AUD_SAMPLE_RATE_88_2:
666 maud_val = AUD_SAMPLE_RATE_88_2_DP_1_62_MAUD_VAL;
667 break;
668
669 case AUD_SAMPLE_RATE_96:
670 maud_val = AUD_SAMPLE_RATE_96_DP_1_62_MAUD_VAL;
671 break;
672
673 case AUD_SAMPLE_RATE_176_4:
674 maud_val = AUD_SAMPLE_RATE_176_4_DP_1_62_MAUD_VAL;
675 break;
676
677 case HAD_MAX_RATE:
678 maud_val = HAD_MAX_RATE_DP_1_62_MAUD_VAL;
679 break;
680
681 default:
682 maud_val = -EINVAL;
683 break;
684 }
685 } else
686 maud_val = -EINVAL;
687
688 return maud_val;
689}
690
Takashi Iwai76296ef2017-01-30 16:09:11 +0100691/*
Takashi Iwai44684f62017-02-02 17:27:40 +0100692 * Program HDMI audio CTS value
Jerome Anand5dab11d2017-01-25 04:27:52 +0530693 *
694 * @aud_samp_freq: sampling frequency of audio data
695 * @tmds: sampling frequency of the display data
Takashi Iwaib5562902017-02-04 22:05:33 +0100696 * @link_rate: DP link rate
Jerome Anand5dab11d2017-01-25 04:27:52 +0530697 * @n_param: N value, depends on aud_samp_freq
Takashi Iwaib5562902017-02-04 22:05:33 +0100698 * @intelhaddata: substream private data
Jerome Anand5dab11d2017-01-25 04:27:52 +0530699 *
700 * Program CTS register based on the audio and display sampling frequency
701 */
Takashi Iwaib5562902017-02-04 22:05:33 +0100702static void had_prog_cts(u32 aud_samp_freq, u32 tmds, u32 link_rate,
703 u32 n_param, struct snd_intelhad *intelhaddata)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530704{
705 u32 cts_val;
706 u64 dividend, divisor;
707
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -0600708 if (intelhaddata->dp_output) {
709 /* Substitute cts_val with Maud according to DP 1.2 spec*/
710 cts_val = had_calculate_maud_value(aud_samp_freq, link_rate);
711 } else {
712 /* Calculate CTS according to HDMI 1.3a spec*/
713 dividend = (u64)tmds * n_param*1000;
714 divisor = 128 * aud_samp_freq;
715 cts_val = div64_u64(dividend, divisor);
716 }
Takashi Iwaic75b0472017-01-31 15:49:15 +0100717 dev_dbg(intelhaddata->dev, "TMDS value=%d, N value=%d, CTS Value=%d\n",
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -0600718 tmds, n_param, cts_val);
Takashi Iwai79dda752017-01-30 17:23:39 +0100719 had_write_register(intelhaddata, AUD_HDMI_CTS, (BIT(24) | cts_val));
Jerome Anand5dab11d2017-01-25 04:27:52 +0530720}
721
722static int had_calculate_n_value(u32 aud_samp_freq)
723{
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100724 int n_val;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530725
726 /* Select N according to HDMI 1.3a spec*/
727 switch (aud_samp_freq) {
728 case AUD_SAMPLE_RATE_32:
729 n_val = 4096;
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100730 break;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530731
732 case AUD_SAMPLE_RATE_44_1:
733 n_val = 6272;
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100734 break;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530735
736 case AUD_SAMPLE_RATE_48:
737 n_val = 6144;
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100738 break;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530739
740 case AUD_SAMPLE_RATE_88_2:
741 n_val = 12544;
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100742 break;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530743
744 case AUD_SAMPLE_RATE_96:
745 n_val = 12288;
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100746 break;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530747
748 case AUD_SAMPLE_RATE_176_4:
749 n_val = 25088;
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100750 break;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530751
752 case HAD_MAX_RATE:
753 n_val = 24576;
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100754 break;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530755
756 default:
757 n_val = -EINVAL;
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100758 break;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530759 }
760 return n_val;
761}
762
Takashi Iwai76296ef2017-01-30 16:09:11 +0100763/*
Takashi Iwai44684f62017-02-02 17:27:40 +0100764 * Program HDMI audio N value
Jerome Anand5dab11d2017-01-25 04:27:52 +0530765 *
766 * @aud_samp_freq: sampling frequency of audio data
767 * @n_param: N value, depends on aud_samp_freq
Takashi Iwaib5562902017-02-04 22:05:33 +0100768 * @intelhaddata: substream private data
Jerome Anand5dab11d2017-01-25 04:27:52 +0530769 *
770 * This function is called in the prepare callback.
771 * It programs based on the audio and display sampling frequency
772 */
Takashi Iwaib5562902017-02-04 22:05:33 +0100773static int had_prog_n(u32 aud_samp_freq, u32 *n_param,
774 struct snd_intelhad *intelhaddata)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530775{
Takashi Iwai2e52f5e2017-01-31 17:09:13 +0100776 int n_val;
Jerome Anand5dab11d2017-01-25 04:27:52 +0530777
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -0600778 if (intelhaddata->dp_output) {
779 /*
780 * According to DP specs, Maud and Naud values hold
781 * a relationship, which is stated as:
782 * Maud/Naud = 512 * fs / f_LS_Clk
783 * where, fs is the sampling frequency of the audio stream
784 * and Naud is 32768 for Async clock.
785 */
786
787 n_val = DP_NAUD_VAL;
788 } else
789 n_val = had_calculate_n_value(aud_samp_freq);
Jerome Anand5dab11d2017-01-25 04:27:52 +0530790
791 if (n_val < 0)
792 return n_val;
793
Takashi Iwai79dda752017-01-30 17:23:39 +0100794 had_write_register(intelhaddata, AUD_N_ENABLE, (BIT(24) | n_val));
Jerome Anand5dab11d2017-01-25 04:27:52 +0530795 *n_param = n_val;
796 return 0;
797}
798
Takashi Iwaie1b239f2017-02-03 00:01:18 +0100799/*
800 * PCM ring buffer handling
801 *
802 * The hardware provides a ring buffer with the fixed 4 buffer descriptors
803 * (BDs). The driver maps these 4 BDs onto the PCM ring buffer. The mapping
804 * moves at each period elapsed. The below illustrates how it works:
805 *
806 * At time=0
807 * PCM | 0 | 1 | 2 | 3 | 4 | 5 | .... |n-1|
808 * BD | 0 | 1 | 2 | 3 |
809 *
810 * At time=1 (period elapsed)
811 * PCM | 0 | 1 | 2 | 3 | 4 | 5 | .... |n-1|
812 * BD | 1 | 2 | 3 | 0 |
813 *
814 * At time=2 (second period elapsed)
815 * PCM | 0 | 1 | 2 | 3 | 4 | 5 | .... |n-1|
816 * BD | 2 | 3 | 0 | 1 |
817 *
818 * The bd_head field points to the index of the BD to be read. It's also the
819 * position to be filled at next. The pcm_head and the pcm_filled fields
820 * point to the indices of the current position and of the next position to
821 * be filled, respectively. For PCM buffer there are both _head and _filled
822 * because they may be difference when nperiods > 4. For example, in the
823 * example above at t=1, bd_head=1 and pcm_head=1 while pcm_filled=5:
824 *
825 * pcm_head (=1) --v v-- pcm_filled (=5)
826 * PCM | 0 | 1 | 2 | 3 | 4 | 5 | .... |n-1|
827 * BD | 1 | 2 | 3 | 0 |
828 * bd_head (=1) --^ ^-- next to fill (= bd_head)
829 *
830 * For nperiods < 4, the remaining BDs out of 4 are marked as invalid, so that
831 * the hardware skips those BDs in the loop.
Takashi Iwai8d48c012017-02-07 08:05:46 +0100832 *
833 * An exceptional setup is the case with nperiods=1. Since we have to update
834 * BDs after finishing one BD processing, we'd need at least two BDs, where
835 * both BDs point to the same content, the same address, the same size of the
836 * whole PCM buffer.
Takashi Iwaie1b239f2017-02-03 00:01:18 +0100837 */
838
839#define AUD_BUF_ADDR(x) (AUD_BUF_A_ADDR + (x) * HAD_REG_WIDTH)
840#define AUD_BUF_LEN(x) (AUD_BUF_A_LENGTH + (x) * HAD_REG_WIDTH)
841
842/* Set up a buffer descriptor at the "filled" position */
843static void had_prog_bd(struct snd_pcm_substream *substream,
844 struct snd_intelhad *intelhaddata)
845{
846 int idx = intelhaddata->bd_head;
847 int ofs = intelhaddata->pcmbuf_filled * intelhaddata->period_bytes;
848 u32 addr = substream->runtime->dma_addr + ofs;
849
Takashi Iwaie8de9852017-02-07 08:09:12 +0100850 addr |= AUD_BUF_VALID;
851 if (!substream->runtime->no_period_wakeup)
852 addr |= AUD_BUF_INTR_EN;
Takashi Iwaie1b239f2017-02-03 00:01:18 +0100853 had_write_register(intelhaddata, AUD_BUF_ADDR(idx), addr);
854 had_write_register(intelhaddata, AUD_BUF_LEN(idx),
855 intelhaddata->period_bytes);
856
857 /* advance the indices to the next */
858 intelhaddata->bd_head++;
859 intelhaddata->bd_head %= intelhaddata->num_bds;
860 intelhaddata->pcmbuf_filled++;
861 intelhaddata->pcmbuf_filled %= substream->runtime->periods;
862}
863
864/* invalidate a buffer descriptor with the given index */
865static void had_invalidate_bd(struct snd_intelhad *intelhaddata,
866 int idx)
867{
868 had_write_register(intelhaddata, AUD_BUF_ADDR(idx), 0);
869 had_write_register(intelhaddata, AUD_BUF_LEN(idx), 0);
870}
871
872/* Initial programming of ring buffer */
873static void had_init_ringbuf(struct snd_pcm_substream *substream,
874 struct snd_intelhad *intelhaddata)
875{
876 struct snd_pcm_runtime *runtime = substream->runtime;
877 int i, num_periods;
878
879 num_periods = runtime->periods;
880 intelhaddata->num_bds = min(num_periods, HAD_NUM_OF_RING_BUFS);
Takashi Iwai8d48c012017-02-07 08:05:46 +0100881 /* set the minimum 2 BDs for num_periods=1 */
882 intelhaddata->num_bds = max(intelhaddata->num_bds, 2U);
Takashi Iwaie1b239f2017-02-03 00:01:18 +0100883 intelhaddata->period_bytes =
884 frames_to_bytes(runtime, runtime->period_size);
885 WARN_ON(intelhaddata->period_bytes & 0x3f);
886
887 intelhaddata->bd_head = 0;
888 intelhaddata->pcmbuf_head = 0;
889 intelhaddata->pcmbuf_filled = 0;
890
891 for (i = 0; i < HAD_NUM_OF_RING_BUFS; i++) {
Takashi Iwai8d48c012017-02-07 08:05:46 +0100892 if (i < intelhaddata->num_bds)
Takashi Iwaie1b239f2017-02-03 00:01:18 +0100893 had_prog_bd(substream, intelhaddata);
894 else /* invalidate the rest */
895 had_invalidate_bd(intelhaddata, i);
896 }
897
898 intelhaddata->bd_head = 0; /* reset at head again before starting */
899}
900
901/* process a bd, advance to the next */
902static void had_advance_ringbuf(struct snd_pcm_substream *substream,
903 struct snd_intelhad *intelhaddata)
904{
905 int num_periods = substream->runtime->periods;
906
907 /* reprogram the next buffer */
908 had_prog_bd(substream, intelhaddata);
909
910 /* proceed to next */
911 intelhaddata->pcmbuf_head++;
912 intelhaddata->pcmbuf_head %= num_periods;
913}
914
915/* process the current BD(s);
916 * returns the current PCM buffer byte position, or -EPIPE for underrun.
917 */
918static int had_process_ringbuf(struct snd_pcm_substream *substream,
919 struct snd_intelhad *intelhaddata)
920{
921 int len, processed;
922 unsigned long flags;
923
924 processed = 0;
925 spin_lock_irqsave(&intelhaddata->had_spinlock, flags);
926 for (;;) {
927 /* get the remaining bytes on the buffer */
928 had_read_register(intelhaddata,
929 AUD_BUF_LEN(intelhaddata->bd_head),
930 &len);
931 if (len < 0 || len > intelhaddata->period_bytes) {
932 dev_dbg(intelhaddata->dev, "Invalid buf length %d\n",
933 len);
934 len = -EPIPE;
935 goto out;
936 }
937
938 if (len > 0) /* OK, this is the current buffer */
939 break;
940
941 /* len=0 => already empty, check the next buffer */
942 if (++processed >= intelhaddata->num_bds) {
943 len = -EPIPE; /* all empty? - report underrun */
944 goto out;
945 }
946 had_advance_ringbuf(substream, intelhaddata);
947 }
948
949 len = intelhaddata->period_bytes - len;
950 len += intelhaddata->period_bytes * intelhaddata->pcmbuf_head;
951 out:
952 spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags);
953 return len;
954}
955
956/* called from irq handler */
957static void had_process_buffer_done(struct snd_intelhad *intelhaddata)
958{
959 struct snd_pcm_substream *substream;
960
961 if (!intelhaddata->connected)
962 return; /* disconnected? - bail out */
963
964 substream = had_substream_get(intelhaddata);
965 if (!substream)
966 return; /* no stream? - bail out */
967
968 /* process or stop the stream */
969 if (had_process_ringbuf(substream, intelhaddata) < 0)
970 snd_pcm_stop_xrun(substream);
971 else
972 snd_pcm_period_elapsed(substream);
973
974 had_substream_put(intelhaddata);
975}
976
Takashi Iwai03c34372017-02-02 16:19:03 +0100977#define MAX_CNT 0xFF
978
Takashi Iwaie1b239f2017-02-03 00:01:18 +0100979/*
980 * The interrupt status 'sticky' bits might not be cleared by
981 * setting '1' to that bit once...
982 */
983static void wait_clear_underrun_bit(struct snd_intelhad *intelhaddata)
Jerome Anand5dab11d2017-01-25 04:27:52 +0530984{
Takashi Iwaie1b239f2017-02-03 00:01:18 +0100985 int i;
986 u32 val;
987
988 for (i = 0; i < MAX_CNT; i++) {
989 /* clear bit30, 31 AUD_HDMI_STATUS */
990 had_read_register(intelhaddata, AUD_HDMI_STATUS, &val);
Takashi Iwai77531be2017-02-07 12:17:23 +0100991 if (!(val & AUD_HDMI_STATUS_MASK_UNDERRUN))
Takashi Iwaie1b239f2017-02-03 00:01:18 +0100992 return;
993 had_write_register(intelhaddata, AUD_HDMI_STATUS, val);
994 }
995 dev_err(intelhaddata->dev, "Unable to clear UNDERRUN bits\n");
996}
997
998/* called from irq handler */
999static void had_process_buffer_underrun(struct snd_intelhad *intelhaddata)
1000{
1001 struct snd_pcm_substream *substream;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301002
1003 /* Handle Underrun interrupt within Audio Unit */
Takashi Iwai79dda752017-01-30 17:23:39 +01001004 had_write_register(intelhaddata, AUD_CONFIG, 0);
Takashi Iwai40ce4b52017-02-07 16:17:06 +01001005 intelhaddata->aud_config.regval = 0;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301006 /* Reset buffer pointers */
Takashi Iwaif4566aa2017-02-04 21:39:56 +01001007 had_reset_audio(intelhaddata);
Takashi Iwaie1b239f2017-02-03 00:01:18 +01001008
1009 wait_clear_underrun_bit(intelhaddata);
1010
1011 if (!intelhaddata->connected)
1012 return; /* disconnected? - bail out */
1013
1014 /* Report UNDERRUN error to above layers */
1015 substream = had_substream_get(intelhaddata);
1016 if (substream) {
1017 snd_pcm_stop_xrun(substream);
1018 had_substream_put(intelhaddata);
1019 }
Jerome Anand5dab11d2017-01-25 04:27:52 +05301020}
1021
Takashi Iwai2e52f5e2017-01-31 17:09:13 +01001022/*
Takashi Iwai44684f62017-02-02 17:27:40 +01001023 * ALSA PCM open callback
Jerome Anand5dab11d2017-01-25 04:27:52 +05301024 */
Takashi Iwaib5562902017-02-04 22:05:33 +01001025static int had_pcm_open(struct snd_pcm_substream *substream)
Jerome Anand5dab11d2017-01-25 04:27:52 +05301026{
1027 struct snd_intelhad *intelhaddata;
1028 struct snd_pcm_runtime *runtime;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301029 int retval;
1030
Jerome Anand5dab11d2017-01-25 04:27:52 +05301031 intelhaddata = snd_pcm_substream_chip(substream);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301032 runtime = substream->runtime;
1033
Takashi Iwai182cdf22017-02-02 14:43:39 +01001034 pm_runtime_get_sync(intelhaddata->dev);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301035
Takashi Iwai91b0cb02017-02-02 17:46:49 +01001036 if (!intelhaddata->connected) {
Takashi Iwaic75b0472017-01-31 15:49:15 +01001037 dev_dbg(intelhaddata->dev, "%s: HDMI cable plugged-out\n",
1038 __func__);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301039 retval = -ENODEV;
Takashi Iwaifa5dfe62017-02-01 22:03:26 +01001040 goto error;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301041 }
1042
1043 /* set the runtime hw parameter with local snd_pcm_hardware struct */
Takashi Iwaib5562902017-02-04 22:05:33 +01001044 runtime->hw = had_pcm_hardware;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301045
Jerome Anand5dab11d2017-01-25 04:27:52 +05301046 retval = snd_pcm_hw_constraint_integer(runtime,
1047 SNDRV_PCM_HW_PARAM_PERIODS);
1048 if (retval < 0)
Takashi Iwaifa5dfe62017-02-01 22:03:26 +01001049 goto error;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301050
1051 /* Make sure, that the period size is always aligned
1052 * 64byte boundary
1053 */
1054 retval = snd_pcm_hw_constraint_step(substream->runtime, 0,
1055 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64);
Takashi Iwai73997b02017-02-02 17:38:50 +01001056 if (retval < 0)
Takashi Iwaifa5dfe62017-02-01 22:03:26 +01001057 goto error;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301058
Takashi Iwai85bd8742017-02-07 13:33:17 +01001059 retval = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
1060 if (retval < 0)
1061 goto error;
1062
Takashi Iwai73997b02017-02-02 17:38:50 +01001063 /* expose PCM substream */
Takashi Iwai313d9f22017-02-02 13:00:12 +01001064 spin_lock_irq(&intelhaddata->had_spinlock);
1065 intelhaddata->stream_info.substream = substream;
1066 intelhaddata->stream_info.substream_refcount++;
1067 spin_unlock_irq(&intelhaddata->had_spinlock);
1068
Jerome Anand5dab11d2017-01-25 04:27:52 +05301069 return retval;
Takashi Iwaifa5dfe62017-02-01 22:03:26 +01001070 error:
Jerome Anand5dab11d2017-01-25 04:27:52 +05301071 pm_runtime_put(intelhaddata->dev);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301072 return retval;
1073}
1074
Takashi Iwaidf76df12017-01-31 16:04:10 +01001075/*
Takashi Iwai44684f62017-02-02 17:27:40 +01001076 * ALSA PCM close callback
Jerome Anand5dab11d2017-01-25 04:27:52 +05301077 */
Takashi Iwaib5562902017-02-04 22:05:33 +01001078static int had_pcm_close(struct snd_pcm_substream *substream)
Jerome Anand5dab11d2017-01-25 04:27:52 +05301079{
1080 struct snd_intelhad *intelhaddata;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301081
Jerome Anand5dab11d2017-01-25 04:27:52 +05301082 intelhaddata = snd_pcm_substream_chip(substream);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301083
Takashi Iwai73997b02017-02-02 17:38:50 +01001084 /* unreference and sync with the pending PCM accesses */
Takashi Iwai313d9f22017-02-02 13:00:12 +01001085 spin_lock_irq(&intelhaddata->had_spinlock);
1086 intelhaddata->stream_info.substream = NULL;
1087 intelhaddata->stream_info.substream_refcount--;
1088 while (intelhaddata->stream_info.substream_refcount > 0) {
1089 spin_unlock_irq(&intelhaddata->had_spinlock);
1090 cpu_relax();
1091 spin_lock_irq(&intelhaddata->had_spinlock);
1092 }
1093 spin_unlock_irq(&intelhaddata->had_spinlock);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301094
Jerome Anand5dab11d2017-01-25 04:27:52 +05301095 pm_runtime_put(intelhaddata->dev);
1096 return 0;
1097}
1098
Takashi Iwai2e52f5e2017-01-31 17:09:13 +01001099/*
Takashi Iwai44684f62017-02-02 17:27:40 +01001100 * ALSA PCM hw_params callback
Jerome Anand5dab11d2017-01-25 04:27:52 +05301101 */
Takashi Iwaib5562902017-02-04 22:05:33 +01001102static int had_pcm_hw_params(struct snd_pcm_substream *substream,
1103 struct snd_pcm_hw_params *hw_params)
Jerome Anand5dab11d2017-01-25 04:27:52 +05301104{
Takashi Iwaic75b0472017-01-31 15:49:15 +01001105 struct snd_intelhad *intelhaddata;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301106 unsigned long addr;
1107 int pages, buf_size, retval;
1108
Takashi Iwaic75b0472017-01-31 15:49:15 +01001109 intelhaddata = snd_pcm_substream_chip(substream);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301110 buf_size = params_buffer_bytes(hw_params);
1111 retval = snd_pcm_lib_malloc_pages(substream, buf_size);
1112 if (retval < 0)
1113 return retval;
Takashi Iwaic75b0472017-01-31 15:49:15 +01001114 dev_dbg(intelhaddata->dev, "%s:allocated memory = %d\n",
1115 __func__, buf_size);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301116 /* mark the pages as uncached region */
1117 addr = (unsigned long) substream->runtime->dma_area;
1118 pages = (substream->runtime->dma_bytes + PAGE_SIZE - 1) / PAGE_SIZE;
1119 retval = set_memory_uc(addr, pages);
1120 if (retval) {
Takashi Iwaic75b0472017-01-31 15:49:15 +01001121 dev_err(intelhaddata->dev, "set_memory_uc failed.Error:%d\n",
1122 retval);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301123 return retval;
1124 }
1125 memset(substream->runtime->dma_area, 0, buf_size);
1126
1127 return retval;
1128}
1129
Takashi Iwai2e52f5e2017-01-31 17:09:13 +01001130/*
Takashi Iwai44684f62017-02-02 17:27:40 +01001131 * ALSA PCM hw_free callback
Jerome Anand5dab11d2017-01-25 04:27:52 +05301132 */
Takashi Iwaib5562902017-02-04 22:05:33 +01001133static int had_pcm_hw_free(struct snd_pcm_substream *substream)
Jerome Anand5dab11d2017-01-25 04:27:52 +05301134{
1135 unsigned long addr;
1136 u32 pages;
1137
Jerome Anand5dab11d2017-01-25 04:27:52 +05301138 /* mark back the pages as cached/writeback region before the free */
1139 if (substream->runtime->dma_area != NULL) {
1140 addr = (unsigned long) substream->runtime->dma_area;
1141 pages = (substream->runtime->dma_bytes + PAGE_SIZE - 1) /
1142 PAGE_SIZE;
1143 set_memory_wb(addr, pages);
1144 return snd_pcm_lib_free_pages(substream);
1145 }
1146 return 0;
1147}
1148
Takashi Iwai2e52f5e2017-01-31 17:09:13 +01001149/*
Takashi Iwai44684f62017-02-02 17:27:40 +01001150 * ALSA PCM trigger callback
Jerome Anand5dab11d2017-01-25 04:27:52 +05301151 */
Takashi Iwaib5562902017-02-04 22:05:33 +01001152static int had_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
Jerome Anand5dab11d2017-01-25 04:27:52 +05301153{
Takashi Iwaida864802017-01-31 13:52:22 +01001154 int retval = 0;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301155 struct snd_intelhad *intelhaddata;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301156
Jerome Anand5dab11d2017-01-25 04:27:52 +05301157 intelhaddata = snd_pcm_substream_chip(substream);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301158
1159 switch (cmd) {
1160 case SNDRV_PCM_TRIGGER_START:
Takashi Iwai182cdf22017-02-02 14:43:39 +01001161 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
1162 case SNDRV_PCM_TRIGGER_RESUME:
Jerome Anand5dab11d2017-01-25 04:27:52 +05301163 /* Disable local INTRs till register prgmng is done */
Takashi Iwai91b0cb02017-02-02 17:46:49 +01001164 if (!intelhaddata->connected) {
Takashi Iwaic75b0472017-01-31 15:49:15 +01001165 dev_dbg(intelhaddata->dev,
1166 "_START: HDMI cable plugged-out\n");
Jerome Anand5dab11d2017-01-25 04:27:52 +05301167 retval = -ENODEV;
1168 break;
1169 }
Jerome Anand5dab11d2017-01-25 04:27:52 +05301170
Takashi Iwaif69bd102017-02-02 14:57:22 +01001171 intelhaddata->stream_info.running = true;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301172
1173 /* Enable Audio */
Takashi Iwai075a1d42017-02-07 07:55:27 +01001174 had_ack_irqs(intelhaddata); /* FIXME: do we need this? */
Takashi Iwai40ce4b52017-02-07 16:17:06 +01001175 had_enable_audio(intelhaddata, true);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301176 break;
1177
1178 case SNDRV_PCM_TRIGGER_STOP:
Takashi Iwai182cdf22017-02-02 14:43:39 +01001179 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
1180 case SNDRV_PCM_TRIGGER_SUSPEND:
Takashi Iwaibcce7752017-02-01 17:18:20 +01001181 spin_lock(&intelhaddata->had_spinlock);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301182
Takashi Iwaic75b0472017-01-31 15:49:15 +01001183 /* Stop reporting BUFFER_DONE/UNDERRUN to above layers */
Jerome Anand5dab11d2017-01-25 04:27:52 +05301184
Takashi Iwaif69bd102017-02-02 14:57:22 +01001185 intelhaddata->stream_info.running = false;
Takashi Iwaibcce7752017-02-01 17:18:20 +01001186 spin_unlock(&intelhaddata->had_spinlock);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301187 /* Disable Audio */
Takashi Iwai40ce4b52017-02-07 16:17:06 +01001188 had_enable_audio(intelhaddata, false);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301189 /* Reset buffer pointers */
Takashi Iwaif4566aa2017-02-04 21:39:56 +01001190 had_reset_audio(intelhaddata);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301191 break;
1192
1193 default:
1194 retval = -EINVAL;
1195 }
1196 return retval;
1197}
1198
Takashi Iwai2e52f5e2017-01-31 17:09:13 +01001199/*
Takashi Iwai44684f62017-02-02 17:27:40 +01001200 * ALSA PCM prepare callback
Jerome Anand5dab11d2017-01-25 04:27:52 +05301201 */
Takashi Iwaib5562902017-02-04 22:05:33 +01001202static int had_pcm_prepare(struct snd_pcm_substream *substream)
Jerome Anand5dab11d2017-01-25 04:27:52 +05301203{
1204 int retval;
1205 u32 disp_samp_freq, n_param;
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -06001206 u32 link_rate = 0;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301207 struct snd_intelhad *intelhaddata;
1208 struct snd_pcm_runtime *runtime;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301209
Jerome Anand5dab11d2017-01-25 04:27:52 +05301210 intelhaddata = snd_pcm_substream_chip(substream);
1211 runtime = substream->runtime;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301212
Takashi Iwai91b0cb02017-02-02 17:46:49 +01001213 if (!intelhaddata->connected) {
Takashi Iwaic75b0472017-01-31 15:49:15 +01001214 dev_dbg(intelhaddata->dev, "%s: HDMI cable plugged-out\n",
1215 __func__);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301216 retval = -ENODEV;
1217 goto prep_end;
1218 }
1219
Takashi Iwaic75b0472017-01-31 15:49:15 +01001220 dev_dbg(intelhaddata->dev, "period_size=%d\n",
Jerome Anand5dab11d2017-01-25 04:27:52 +05301221 (int)frames_to_bytes(runtime, runtime->period_size));
Takashi Iwaic75b0472017-01-31 15:49:15 +01001222 dev_dbg(intelhaddata->dev, "periods=%d\n", runtime->periods);
1223 dev_dbg(intelhaddata->dev, "buffer_size=%d\n",
1224 (int)snd_pcm_lib_buffer_bytes(substream));
1225 dev_dbg(intelhaddata->dev, "rate=%d\n", runtime->rate);
1226 dev_dbg(intelhaddata->dev, "channels=%d\n", runtime->channels);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301227
Jerome Anand5dab11d2017-01-25 04:27:52 +05301228 /* Get N value in KHz */
Takashi Iwaida864802017-01-31 13:52:22 +01001229 disp_samp_freq = intelhaddata->tmds_clock_speed;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301230
Takashi Iwaib5562902017-02-04 22:05:33 +01001231 retval = had_prog_n(substream->runtime->rate, &n_param, intelhaddata);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301232 if (retval) {
Takashi Iwaic75b0472017-01-31 15:49:15 +01001233 dev_err(intelhaddata->dev,
1234 "programming N value failed %#x\n", retval);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301235 goto prep_end;
1236 }
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -06001237
1238 if (intelhaddata->dp_output)
Takashi Iwaida864802017-01-31 13:52:22 +01001239 link_rate = intelhaddata->link_rate;
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -06001240
Takashi Iwaib5562902017-02-04 22:05:33 +01001241 had_prog_cts(substream->runtime->rate, disp_samp_freq, link_rate,
1242 n_param, intelhaddata);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301243
Takashi Iwaib5562902017-02-04 22:05:33 +01001244 had_prog_dip(substream, intelhaddata);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301245
Takashi Iwaib5562902017-02-04 22:05:33 +01001246 retval = had_init_audio_ctrl(substream, intelhaddata);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301247
1248 /* Prog buffer address */
Takashi Iwaie1b239f2017-02-03 00:01:18 +01001249 had_init_ringbuf(substream, intelhaddata);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301250
1251 /*
1252 * Program channel mapping in following order:
1253 * FL, FR, C, LFE, RL, RR
1254 */
1255
Takashi Iwai79dda752017-01-30 17:23:39 +01001256 had_write_register(intelhaddata, AUD_BUF_CH_SWAP, SWAP_LFE_CENTER);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301257
1258prep_end:
1259 return retval;
1260}
1261
Takashi Iwai2e52f5e2017-01-31 17:09:13 +01001262/*
Takashi Iwai44684f62017-02-02 17:27:40 +01001263 * ALSA PCM pointer callback
Jerome Anand5dab11d2017-01-25 04:27:52 +05301264 */
Takashi Iwaib5562902017-02-04 22:05:33 +01001265static snd_pcm_uframes_t had_pcm_pointer(struct snd_pcm_substream *substream)
Jerome Anand5dab11d2017-01-25 04:27:52 +05301266{
1267 struct snd_intelhad *intelhaddata;
Takashi Iwaie1b239f2017-02-03 00:01:18 +01001268 int len;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301269
Jerome Anand5dab11d2017-01-25 04:27:52 +05301270 intelhaddata = snd_pcm_substream_chip(substream);
1271
Takashi Iwai91b0cb02017-02-02 17:46:49 +01001272 if (!intelhaddata->connected)
Takashi Iwai79f439e2017-01-31 16:46:44 +01001273 return SNDRV_PCM_POS_XRUN;
1274
Takashi Iwaie1b239f2017-02-03 00:01:18 +01001275 len = had_process_ringbuf(substream, intelhaddata);
1276 if (len < 0)
1277 return SNDRV_PCM_POS_XRUN;
Takashi Iwai8d48c012017-02-07 08:05:46 +01001278 len = bytes_to_frames(substream->runtime, len);
1279 /* wrapping may happen when periods=1 */
1280 len %= substream->runtime->buffer_size;
1281 return len;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301282}
1283
Takashi Iwai2e52f5e2017-01-31 17:09:13 +01001284/*
Takashi Iwai44684f62017-02-02 17:27:40 +01001285 * ALSA PCM mmap callback
Jerome Anand5dab11d2017-01-25 04:27:52 +05301286 */
Takashi Iwaib5562902017-02-04 22:05:33 +01001287static int had_pcm_mmap(struct snd_pcm_substream *substream,
1288 struct vm_area_struct *vma)
Jerome Anand5dab11d2017-01-25 04:27:52 +05301289{
Jerome Anand5dab11d2017-01-25 04:27:52 +05301290 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
1291 return remap_pfn_range(vma, vma->vm_start,
1292 substream->dma_buffer.addr >> PAGE_SHIFT,
1293 vma->vm_end - vma->vm_start, vma->vm_page_prot);
1294}
1295
Takashi Iwai73997b02017-02-02 17:38:50 +01001296/*
1297 * ALSA PCM ops
1298 */
Takashi Iwaib5562902017-02-04 22:05:33 +01001299static const struct snd_pcm_ops had_pcm_ops = {
1300 .open = had_pcm_open,
1301 .close = had_pcm_close,
Takashi Iwai73997b02017-02-02 17:38:50 +01001302 .ioctl = snd_pcm_lib_ioctl,
Takashi Iwaib5562902017-02-04 22:05:33 +01001303 .hw_params = had_pcm_hw_params,
1304 .hw_free = had_pcm_hw_free,
1305 .prepare = had_pcm_prepare,
1306 .trigger = had_pcm_trigger,
1307 .pointer = had_pcm_pointer,
1308 .mmap = had_pcm_mmap,
Takashi Iwai73997b02017-02-02 17:38:50 +01001309};
1310
Takashi Iwai8f8d1d72017-02-01 17:24:02 +01001311/* process mode change of the running stream; called in mutex */
Takashi Iwaib5562902017-02-04 22:05:33 +01001312static int had_process_mode_change(struct snd_intelhad *intelhaddata)
Jerome Anand5dab11d2017-01-25 04:27:52 +05301313{
Takashi Iwaida864802017-01-31 13:52:22 +01001314 struct snd_pcm_substream *substream;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301315 int retval = 0;
1316 u32 disp_samp_freq, n_param;
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -06001317 u32 link_rate = 0;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301318
Takashi Iwai313d9f22017-02-02 13:00:12 +01001319 substream = had_substream_get(intelhaddata);
1320 if (!substream)
Takashi Iwaida864802017-01-31 13:52:22 +01001321 return 0;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301322
1323 /* Disable Audio */
Takashi Iwai40ce4b52017-02-07 16:17:06 +01001324 had_enable_audio(intelhaddata, false);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301325
1326 /* Update CTS value */
Takashi Iwaida864802017-01-31 13:52:22 +01001327 disp_samp_freq = intelhaddata->tmds_clock_speed;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301328
Takashi Iwaib5562902017-02-04 22:05:33 +01001329 retval = had_prog_n(substream->runtime->rate, &n_param, intelhaddata);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301330 if (retval) {
Takashi Iwaic75b0472017-01-31 15:49:15 +01001331 dev_err(intelhaddata->dev,
1332 "programming N value failed %#x\n", retval);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301333 goto out;
1334 }
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -06001335
1336 if (intelhaddata->dp_output)
Takashi Iwaida864802017-01-31 13:52:22 +01001337 link_rate = intelhaddata->link_rate;
Pierre-Louis Bossart964ca802017-01-31 14:16:52 -06001338
Takashi Iwaib5562902017-02-04 22:05:33 +01001339 had_prog_cts(substream->runtime->rate, disp_samp_freq, link_rate,
1340 n_param, intelhaddata);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301341
1342 /* Enable Audio */
Takashi Iwai40ce4b52017-02-07 16:17:06 +01001343 had_enable_audio(intelhaddata, true);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301344
1345out:
Takashi Iwai313d9f22017-02-02 13:00:12 +01001346 had_substream_put(intelhaddata);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301347 return retval;
1348}
1349
Takashi Iwai8f8d1d72017-02-01 17:24:02 +01001350/* process hot plug, called from wq with mutex locked */
Takashi Iwai0e9c67d2017-02-01 17:53:19 +01001351static void had_process_hot_plug(struct snd_intelhad *intelhaddata)
Takashi Iwai372d8552017-01-31 13:57:58 +01001352{
Takashi Iwai372d8552017-01-31 13:57:58 +01001353 struct snd_pcm_substream *substream;
Takashi Iwai372d8552017-01-31 13:57:58 +01001354
Takashi Iwaibcce7752017-02-01 17:18:20 +01001355 spin_lock_irq(&intelhaddata->had_spinlock);
Takashi Iwai91b0cb02017-02-02 17:46:49 +01001356 if (intelhaddata->connected) {
Takashi Iwaic75b0472017-01-31 15:49:15 +01001357 dev_dbg(intelhaddata->dev, "Device already connected\n");
Takashi Iwaibcce7752017-02-01 17:18:20 +01001358 spin_unlock_irq(&intelhaddata->had_spinlock);
Takashi Iwai0e9c67d2017-02-01 17:53:19 +01001359 return;
Takashi Iwai372d8552017-01-31 13:57:58 +01001360 }
Takashi Iwai0e9c67d2017-02-01 17:53:19 +01001361
Takashi Iwai91b0cb02017-02-02 17:46:49 +01001362 intelhaddata->connected = true;
Takashi Iwaic75b0472017-01-31 15:49:15 +01001363 dev_dbg(intelhaddata->dev,
1364 "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n",
Takashi Iwai372d8552017-01-31 13:57:58 +01001365 __func__, __LINE__);
Takashi Iwaibcce7752017-02-01 17:18:20 +01001366 spin_unlock_irq(&intelhaddata->had_spinlock);
Takashi Iwai372d8552017-01-31 13:57:58 +01001367
Takashi Iwai372d8552017-01-31 13:57:58 +01001368 /* Safety check */
Takashi Iwai313d9f22017-02-02 13:00:12 +01001369 substream = had_substream_get(intelhaddata);
Takashi Iwai372d8552017-01-31 13:57:58 +01001370 if (substream) {
Takashi Iwaic75b0472017-01-31 15:49:15 +01001371 dev_dbg(intelhaddata->dev,
1372 "Force to stop the active stream by disconnection\n");
Takashi Iwai372d8552017-01-31 13:57:58 +01001373 /* Set runtime->state to hw_params done */
1374 snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
Takashi Iwai313d9f22017-02-02 13:00:12 +01001375 had_substream_put(intelhaddata);
Takashi Iwai372d8552017-01-31 13:57:58 +01001376 }
1377
1378 had_build_channel_allocation_map(intelhaddata);
Takashi Iwai372d8552017-01-31 13:57:58 +01001379}
1380
Takashi Iwai8f8d1d72017-02-01 17:24:02 +01001381/* process hot unplug, called from wq with mutex locked */
Takashi Iwai0e9c67d2017-02-01 17:53:19 +01001382static void had_process_hot_unplug(struct snd_intelhad *intelhaddata)
Takashi Iwai372d8552017-01-31 13:57:58 +01001383{
Takashi Iwai313d9f22017-02-02 13:00:12 +01001384 struct snd_pcm_substream *substream;
Takashi Iwai372d8552017-01-31 13:57:58 +01001385
Takashi Iwai313d9f22017-02-02 13:00:12 +01001386 substream = had_substream_get(intelhaddata);
1387
Takashi Iwaibcce7752017-02-01 17:18:20 +01001388 spin_lock_irq(&intelhaddata->had_spinlock);
Takashi Iwai372d8552017-01-31 13:57:58 +01001389
Takashi Iwai91b0cb02017-02-02 17:46:49 +01001390 if (!intelhaddata->connected) {
Takashi Iwaic75b0472017-01-31 15:49:15 +01001391 dev_dbg(intelhaddata->dev, "Device already disconnected\n");
Takashi Iwaibcce7752017-02-01 17:18:20 +01001392 spin_unlock_irq(&intelhaddata->had_spinlock);
Takashi Iwai313d9f22017-02-02 13:00:12 +01001393 goto out;
Takashi Iwai372d8552017-01-31 13:57:58 +01001394
Takashi Iwai372d8552017-01-31 13:57:58 +01001395 }
1396
Takashi Iwai0e9c67d2017-02-01 17:53:19 +01001397 /* Disable Audio */
Takashi Iwai40ce4b52017-02-07 16:17:06 +01001398 had_enable_audio(intelhaddata, false);
Takashi Iwai0e9c67d2017-02-01 17:53:19 +01001399
Takashi Iwai91b0cb02017-02-02 17:46:49 +01001400 intelhaddata->connected = false;
Takashi Iwaic75b0472017-01-31 15:49:15 +01001401 dev_dbg(intelhaddata->dev,
1402 "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n",
Takashi Iwai372d8552017-01-31 13:57:58 +01001403 __func__, __LINE__);
Takashi Iwaibcce7752017-02-01 17:18:20 +01001404 spin_unlock_irq(&intelhaddata->had_spinlock);
Takashi Iwai313d9f22017-02-02 13:00:12 +01001405
1406 /* Report to above ALSA layer */
1407 if (substream)
1408 snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
1409
1410 out:
1411 if (substream)
1412 had_substream_put(intelhaddata);
Takashi Iwai372d8552017-01-31 13:57:58 +01001413 kfree(intelhaddata->chmap->chmap);
1414 intelhaddata->chmap->chmap = NULL;
Takashi Iwai372d8552017-01-31 13:57:58 +01001415}
1416
Takashi Iwai73997b02017-02-02 17:38:50 +01001417/*
1418 * ALSA iec958 and ELD controls
1419 */
Jerome Anand5dab11d2017-01-25 04:27:52 +05301420
Jerome Anand5dab11d2017-01-25 04:27:52 +05301421static int had_iec958_info(struct snd_kcontrol *kcontrol,
1422 struct snd_ctl_elem_info *uinfo)
1423{
1424 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
1425 uinfo->count = 1;
1426 return 0;
1427}
1428
1429static int had_iec958_get(struct snd_kcontrol *kcontrol,
1430 struct snd_ctl_elem_value *ucontrol)
1431{
1432 struct snd_intelhad *intelhaddata = snd_kcontrol_chip(kcontrol);
1433
Takashi Iwai8f8d1d72017-02-01 17:24:02 +01001434 mutex_lock(&intelhaddata->mutex);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301435 ucontrol->value.iec958.status[0] = (intelhaddata->aes_bits >> 0) & 0xff;
1436 ucontrol->value.iec958.status[1] = (intelhaddata->aes_bits >> 8) & 0xff;
1437 ucontrol->value.iec958.status[2] =
1438 (intelhaddata->aes_bits >> 16) & 0xff;
1439 ucontrol->value.iec958.status[3] =
1440 (intelhaddata->aes_bits >> 24) & 0xff;
Takashi Iwai8f8d1d72017-02-01 17:24:02 +01001441 mutex_unlock(&intelhaddata->mutex);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301442 return 0;
1443}
Takashi Iwai372d8552017-01-31 13:57:58 +01001444
Jerome Anand5dab11d2017-01-25 04:27:52 +05301445static int had_iec958_mask_get(struct snd_kcontrol *kcontrol,
1446 struct snd_ctl_elem_value *ucontrol)
1447{
1448 ucontrol->value.iec958.status[0] = 0xff;
1449 ucontrol->value.iec958.status[1] = 0xff;
1450 ucontrol->value.iec958.status[2] = 0xff;
1451 ucontrol->value.iec958.status[3] = 0xff;
1452 return 0;
1453}
Takashi Iwai372d8552017-01-31 13:57:58 +01001454
Jerome Anand5dab11d2017-01-25 04:27:52 +05301455static int had_iec958_put(struct snd_kcontrol *kcontrol,
1456 struct snd_ctl_elem_value *ucontrol)
1457{
1458 unsigned int val;
1459 struct snd_intelhad *intelhaddata = snd_kcontrol_chip(kcontrol);
Takashi Iwai8f8d1d72017-02-01 17:24:02 +01001460 int changed = 0;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301461
Jerome Anand5dab11d2017-01-25 04:27:52 +05301462 val = (ucontrol->value.iec958.status[0] << 0) |
1463 (ucontrol->value.iec958.status[1] << 8) |
1464 (ucontrol->value.iec958.status[2] << 16) |
1465 (ucontrol->value.iec958.status[3] << 24);
Takashi Iwai8f8d1d72017-02-01 17:24:02 +01001466 mutex_lock(&intelhaddata->mutex);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301467 if (intelhaddata->aes_bits != val) {
1468 intelhaddata->aes_bits = val;
Takashi Iwai8f8d1d72017-02-01 17:24:02 +01001469 changed = 1;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301470 }
Takashi Iwai8f8d1d72017-02-01 17:24:02 +01001471 mutex_unlock(&intelhaddata->mutex);
1472 return changed;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301473}
1474
Takashi Iwai4aedb942017-02-02 16:38:39 +01001475static int had_ctl_eld_info(struct snd_kcontrol *kcontrol,
1476 struct snd_ctl_elem_info *uinfo)
1477{
1478 uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
1479 uinfo->count = HDMI_MAX_ELD_BYTES;
1480 return 0;
1481}
1482
1483static int had_ctl_eld_get(struct snd_kcontrol *kcontrol,
1484 struct snd_ctl_elem_value *ucontrol)
1485{
1486 struct snd_intelhad *intelhaddata = snd_kcontrol_chip(kcontrol);
1487
1488 mutex_lock(&intelhaddata->mutex);
1489 memcpy(ucontrol->value.bytes.data, intelhaddata->eld,
1490 HDMI_MAX_ELD_BYTES);
1491 mutex_unlock(&intelhaddata->mutex);
1492 return 0;
1493}
1494
Takashi Iwai73997b02017-02-02 17:38:50 +01001495static const struct snd_kcontrol_new had_controls[] = {
Takashi Iwai4aedb942017-02-02 16:38:39 +01001496 {
1497 .access = SNDRV_CTL_ELEM_ACCESS_READ,
1498 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1499 .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK),
1500 .info = had_iec958_info, /* shared */
1501 .get = had_iec958_mask_get,
1502 },
1503 {
1504 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1505 .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
1506 .info = had_iec958_info,
1507 .get = had_iec958_get,
1508 .put = had_iec958_put,
1509 },
1510 {
1511 .access = (SNDRV_CTL_ELEM_ACCESS_READ |
1512 SNDRV_CTL_ELEM_ACCESS_VOLATILE),
1513 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1514 .name = "ELD",
1515 .info = had_ctl_eld_info,
1516 .get = had_ctl_eld_get,
1517 },
Jerome Anand5dab11d2017-01-25 04:27:52 +05301518};
1519
Takashi Iwai73997b02017-02-02 17:38:50 +01001520/*
1521 * audio interrupt handler
1522 */
Takashi Iwaida864802017-01-31 13:52:22 +01001523static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id)
1524{
1525 struct snd_intelhad *ctx = dev_id;
1526 u32 audio_stat, audio_reg;
1527
Takashi Iwai4151ee82017-01-31 18:14:15 +01001528 audio_reg = AUD_HDMI_STATUS;
Takashi Iwai83af57d2017-02-03 08:50:06 +01001529 had_read_register(ctx, audio_reg, &audio_stat);
Takashi Iwaida864802017-01-31 13:52:22 +01001530
1531 if (audio_stat & HDMI_AUDIO_UNDERRUN) {
Takashi Iwai83af57d2017-02-03 08:50:06 +01001532 had_write_register(ctx, audio_reg, HDMI_AUDIO_UNDERRUN);
Takashi Iwaida864802017-01-31 13:52:22 +01001533 had_process_buffer_underrun(ctx);
1534 }
1535
1536 if (audio_stat & HDMI_AUDIO_BUFFER_DONE) {
Takashi Iwai83af57d2017-02-03 08:50:06 +01001537 had_write_register(ctx, audio_reg, HDMI_AUDIO_BUFFER_DONE);
Takashi Iwaida864802017-01-31 13:52:22 +01001538 had_process_buffer_done(ctx);
1539 }
1540
1541 return IRQ_HANDLED;
1542}
1543
Takashi Iwai73997b02017-02-02 17:38:50 +01001544/*
1545 * monitor plug/unplug notification from i915; just kick off the work
1546 */
Takashi Iwaida864802017-01-31 13:52:22 +01001547static void notify_audio_lpe(struct platform_device *pdev)
1548{
1549 struct snd_intelhad *ctx = platform_get_drvdata(pdev);
Takashi Iwaida864802017-01-31 13:52:22 +01001550
Takashi Iwai99b2ab92017-01-31 16:26:10 +01001551 schedule_work(&ctx->hdmi_audio_wq);
1552}
Takashi Iwaida864802017-01-31 13:52:22 +01001553
Takashi Iwai73997b02017-02-02 17:38:50 +01001554/* the work to handle monitor hot plug/unplug */
Takashi Iwai99b2ab92017-01-31 16:26:10 +01001555static void had_audio_wq(struct work_struct *work)
1556{
1557 struct snd_intelhad *ctx =
1558 container_of(work, struct snd_intelhad, hdmi_audio_wq);
1559 struct intel_hdmi_lpe_audio_pdata *pdata = ctx->dev->platform_data;
1560
Takashi Iwai182cdf22017-02-02 14:43:39 +01001561 pm_runtime_get_sync(ctx->dev);
Takashi Iwai8f8d1d72017-02-01 17:24:02 +01001562 mutex_lock(&ctx->mutex);
Takashi Iwai99b2ab92017-01-31 16:26:10 +01001563 if (!pdata->hdmi_connected) {
1564 dev_dbg(ctx->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n",
Takashi Iwaida864802017-01-31 13:52:22 +01001565 __func__);
Takashi Iwai4aedb942017-02-02 16:38:39 +01001566 memset(ctx->eld, 0, sizeof(ctx->eld)); /* clear the old ELD */
Takashi Iwai0e9c67d2017-02-01 17:53:19 +01001567 had_process_hot_unplug(ctx);
Takashi Iwaida864802017-01-31 13:52:22 +01001568 } else {
1569 struct intel_hdmi_lpe_audio_eld *eld = &pdata->eld;
1570
Takashi Iwai0e9c67d2017-02-01 17:53:19 +01001571 dev_dbg(ctx->dev, "%s: HAD_NOTIFY_ELD : port = %d, tmds = %d\n",
1572 __func__, eld->port_id, pdata->tmds_clock_speed);
1573
Takashi Iwaida864802017-01-31 13:52:22 +01001574 switch (eld->pipe_id) {
1575 case 0:
1576 ctx->had_config_offset = AUDIO_HDMI_CONFIG_A;
1577 break;
1578 case 1:
1579 ctx->had_config_offset = AUDIO_HDMI_CONFIG_B;
1580 break;
1581 case 2:
1582 ctx->had_config_offset = AUDIO_HDMI_CONFIG_C;
1583 break;
1584 default:
Takashi Iwai99b2ab92017-01-31 16:26:10 +01001585 dev_dbg(ctx->dev, "Invalid pipe %d\n",
Takashi Iwaida864802017-01-31 13:52:22 +01001586 eld->pipe_id);
1587 break;
1588 }
1589
Takashi Iwaidf0435d2017-02-02 15:37:11 +01001590 memcpy(ctx->eld, eld->eld_data, sizeof(ctx->eld));
Takashi Iwaida864802017-01-31 13:52:22 +01001591
Takashi Iwai0e9c67d2017-02-01 17:53:19 +01001592 ctx->dp_output = pdata->dp_output;
1593 ctx->tmds_clock_speed = pdata->tmds_clock_speed;
1594 ctx->link_rate = pdata->link_rate;
1595
Takashi Iwaida864802017-01-31 13:52:22 +01001596 had_process_hot_plug(ctx);
1597
Takashi Iwai0e9c67d2017-02-01 17:53:19 +01001598 /* Process mode change if stream is active */
Takashi Iwaib5562902017-02-04 22:05:33 +01001599 had_process_mode_change(ctx);
Takashi Iwaida864802017-01-31 13:52:22 +01001600 }
Takashi Iwai8f8d1d72017-02-01 17:24:02 +01001601 mutex_unlock(&ctx->mutex);
Takashi Iwai182cdf22017-02-02 14:43:39 +01001602 pm_runtime_put(ctx->dev);
1603}
1604
1605/*
1606 * PM callbacks
1607 */
1608
1609static int hdmi_lpe_audio_runtime_suspend(struct device *dev)
1610{
1611 struct snd_intelhad *ctx = dev_get_drvdata(dev);
1612 struct snd_pcm_substream *substream;
1613
1614 substream = had_substream_get(ctx);
1615 if (substream) {
1616 snd_pcm_suspend(substream);
1617 had_substream_put(ctx);
1618 }
1619
1620 return 0;
1621}
1622
Arnd Bergmann1df98922017-02-07 14:38:51 +01001623static int __maybe_unused hdmi_lpe_audio_suspend(struct device *dev)
Takashi Iwai182cdf22017-02-02 14:43:39 +01001624{
1625 struct snd_intelhad *ctx = dev_get_drvdata(dev);
1626 int err;
1627
1628 err = hdmi_lpe_audio_runtime_suspend(dev);
1629 if (!err)
1630 snd_power_change_state(ctx->card, SNDRV_CTL_POWER_D3hot);
1631 return err;
1632}
1633
Arnd Bergmann1df98922017-02-07 14:38:51 +01001634static int __maybe_unused hdmi_lpe_audio_resume(struct device *dev)
Takashi Iwai182cdf22017-02-02 14:43:39 +01001635{
1636 struct snd_intelhad *ctx = dev_get_drvdata(dev);
1637
1638 snd_power_change_state(ctx->card, SNDRV_CTL_POWER_D0);
1639 return 0;
Takashi Iwaida864802017-01-31 13:52:22 +01001640}
1641
1642/* release resources */
1643static void hdmi_lpe_audio_free(struct snd_card *card)
1644{
1645 struct snd_intelhad *ctx = card->private_data;
1646
Takashi Iwai99b2ab92017-01-31 16:26:10 +01001647 cancel_work_sync(&ctx->hdmi_audio_wq);
1648
Takashi Iwaida864802017-01-31 13:52:22 +01001649 if (ctx->mmio_start)
1650 iounmap(ctx->mmio_start);
1651 if (ctx->irq >= 0)
1652 free_irq(ctx->irq, ctx);
1653}
1654
1655/*
1656 * hdmi_lpe_audio_probe - start bridge with i915
1657 *
1658 * This function is called when the i915 driver creates the
Takashi Iwai2e52f5e2017-01-31 17:09:13 +01001659 * hdmi-lpe-audio platform device.
Takashi Iwaida864802017-01-31 13:52:22 +01001660 */
1661static int hdmi_lpe_audio_probe(struct platform_device *pdev)
1662{
1663 struct snd_card *card;
1664 struct snd_intelhad *ctx;
1665 struct snd_pcm *pcm;
1666 struct intel_hdmi_lpe_audio_pdata *pdata;
1667 int irq;
1668 struct resource *res_mmio;
Takashi Iwai4aedb942017-02-02 16:38:39 +01001669 int i, ret;
Takashi Iwaida864802017-01-31 13:52:22 +01001670
Takashi Iwaida864802017-01-31 13:52:22 +01001671 pdata = pdev->dev.platform_data;
1672 if (!pdata) {
1673 dev_err(&pdev->dev, "%s: quit: pdata not allocated by i915!!\n", __func__);
1674 return -EINVAL;
1675 }
1676
1677 /* get resources */
1678 irq = platform_get_irq(pdev, 0);
1679 if (irq < 0) {
1680 dev_err(&pdev->dev, "Could not get irq resource\n");
1681 return -ENODEV;
1682 }
1683
1684 res_mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1685 if (!res_mmio) {
1686 dev_err(&pdev->dev, "Could not get IO_MEM resources\n");
1687 return -ENXIO;
1688 }
Jerome Anand5dab11d2017-01-25 04:27:52 +05301689
Takashi Iwai5647aec2017-01-31 08:14:34 +01001690 /* create a card instance with ALSA framework */
Takashi Iwaida864802017-01-31 13:52:22 +01001691 ret = snd_card_new(&pdev->dev, hdmi_card_index, hdmi_card_id,
1692 THIS_MODULE, sizeof(*ctx), &card);
1693 if (ret)
1694 return ret;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301695
Takashi Iwaida864802017-01-31 13:52:22 +01001696 ctx = card->private_data;
1697 spin_lock_init(&ctx->had_spinlock);
Takashi Iwai8f8d1d72017-02-01 17:24:02 +01001698 mutex_init(&ctx->mutex);
Takashi Iwai91b0cb02017-02-02 17:46:49 +01001699 ctx->connected = false;
Takashi Iwaida864802017-01-31 13:52:22 +01001700 ctx->dev = &pdev->dev;
1701 ctx->card = card;
Takashi Iwaida864802017-01-31 13:52:22 +01001702 ctx->aes_bits = SNDRV_PCM_DEFAULT_CON_SPDIF;
1703 strcpy(card->driver, INTEL_HAD);
Takashi Iwai873ab032017-02-07 12:14:04 +01001704 strcpy(card->shortname, "Intel HDMI/DP LPE Audio");
1705 strcpy(card->longname, "Intel HDMI/DP LPE Audio");
Jerome Anand5dab11d2017-01-25 04:27:52 +05301706
Takashi Iwaida864802017-01-31 13:52:22 +01001707 ctx->irq = -1;
1708 ctx->tmds_clock_speed = DIS_SAMPLE_RATE_148_5;
Takashi Iwai99b2ab92017-01-31 16:26:10 +01001709 INIT_WORK(&ctx->hdmi_audio_wq, had_audio_wq);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301710
Takashi Iwaida864802017-01-31 13:52:22 +01001711 card->private_free = hdmi_lpe_audio_free;
1712
1713 /* assume pipe A as default */
1714 ctx->had_config_offset = AUDIO_HDMI_CONFIG_A;
1715
1716 platform_set_drvdata(pdev, ctx);
1717
1718 dev_dbg(&pdev->dev, "%s: mmio_start = 0x%x, mmio_end = 0x%x\n",
1719 __func__, (unsigned int)res_mmio->start,
1720 (unsigned int)res_mmio->end);
1721
1722 ctx->mmio_start = ioremap_nocache(res_mmio->start,
1723 (size_t)(resource_size(res_mmio)));
1724 if (!ctx->mmio_start) {
1725 dev_err(&pdev->dev, "Could not get ioremap\n");
1726 ret = -EACCES;
1727 goto err;
1728 }
1729
1730 /* setup interrupt handler */
1731 ret = request_irq(irq, display_pipe_interrupt_handler, 0,
1732 pdev->name, ctx);
1733 if (ret < 0) {
1734 dev_err(&pdev->dev, "request_irq failed\n");
1735 goto err;
1736 }
1737
1738 ctx->irq = irq;
1739
1740 ret = snd_pcm_new(card, INTEL_HAD, PCM_INDEX, MAX_PB_STREAMS,
1741 MAX_CAP_STREAMS, &pcm);
1742 if (ret)
Jerome Anand5dab11d2017-01-25 04:27:52 +05301743 goto err;
1744
1745 /* setup private data which can be retrieved when required */
Takashi Iwaida864802017-01-31 13:52:22 +01001746 pcm->private_data = ctx;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301747 pcm->info_flags = 0;
1748 strncpy(pcm->name, card->shortname, strlen(card->shortname));
Takashi Iwaida864802017-01-31 13:52:22 +01001749 /* setup the ops for playabck */
Takashi Iwaib5562902017-02-04 22:05:33 +01001750 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &had_pcm_ops);
Takashi Iwai412bbe7d52017-02-02 22:03:22 +01001751
1752 /* only 32bit addressable */
1753 dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
1754 dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
1755
Takashi Iwaie1b239f2017-02-03 00:01:18 +01001756 /* allocate dma pages;
1757 * try to allocate 600k buffer as default which is large enough
Jerome Anand5dab11d2017-01-25 04:27:52 +05301758 */
Takashi Iwaida864802017-01-31 13:52:22 +01001759 snd_pcm_lib_preallocate_pages_for_all(pcm,
Jerome Anand5dab11d2017-01-25 04:27:52 +05301760 SNDRV_DMA_TYPE_DEV, NULL,
Takashi Iwaie1b239f2017-02-03 00:01:18 +01001761 HAD_DEFAULT_BUFFER, HAD_MAX_BUFFER);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301762
Takashi Iwai4aedb942017-02-02 16:38:39 +01001763 /* create controls */
1764 for (i = 0; i < ARRAY_SIZE(had_controls); i++) {
1765 ret = snd_ctl_add(card, snd_ctl_new1(&had_controls[i], ctx));
1766 if (ret < 0)
1767 goto err;
1768 }
Jerome Anand5dab11d2017-01-25 04:27:52 +05301769
1770 init_channel_allocations();
1771
1772 /* Register channel map controls */
Takashi Iwaida864802017-01-31 13:52:22 +01001773 ret = had_register_chmap_ctls(ctx, pcm);
1774 if (ret < 0)
Jerome Anand5dab11d2017-01-25 04:27:52 +05301775 goto err;
1776
Takashi Iwaida864802017-01-31 13:52:22 +01001777 ret = snd_card_register(card);
1778 if (ret)
Takashi Iwai36ec0d92017-01-31 08:47:05 +01001779 goto err;
1780
Takashi Iwaibcce7752017-02-01 17:18:20 +01001781 spin_lock_irq(&pdata->lpe_audio_slock);
Takashi Iwaida864802017-01-31 13:52:22 +01001782 pdata->notify_audio_lpe = notify_audio_lpe;
Takashi Iwai99b2ab92017-01-31 16:26:10 +01001783 pdata->notify_pending = false;
Takashi Iwaibcce7752017-02-01 17:18:20 +01001784 spin_unlock_irq(&pdata->lpe_audio_slock);
Takashi Iwaida864802017-01-31 13:52:22 +01001785
1786 pm_runtime_set_active(&pdev->dev);
1787 pm_runtime_enable(&pdev->dev);
1788
Takashi Iwai99b2ab92017-01-31 16:26:10 +01001789 dev_dbg(&pdev->dev, "%s: handle pending notification\n", __func__);
Takashi Iwaida864802017-01-31 13:52:22 +01001790 schedule_work(&ctx->hdmi_audio_wq);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301791
Takashi Iwai79dda752017-01-30 17:23:39 +01001792 return 0;
Takashi Iwai5647aec2017-01-31 08:14:34 +01001793
Jerome Anand5dab11d2017-01-25 04:27:52 +05301794err:
1795 snd_card_free(card);
Takashi Iwaida864802017-01-31 13:52:22 +01001796 return ret;
Jerome Anand5dab11d2017-01-25 04:27:52 +05301797}
1798
Takashi Iwai79dda752017-01-30 17:23:39 +01001799/*
Takashi Iwaida864802017-01-31 13:52:22 +01001800 * hdmi_lpe_audio_remove - stop bridge with i915
Jerome Anand5dab11d2017-01-25 04:27:52 +05301801 *
Takashi Iwai2e52f5e2017-01-31 17:09:13 +01001802 * This function is called when the platform device is destroyed.
Jerome Anand5dab11d2017-01-25 04:27:52 +05301803 */
Takashi Iwaida864802017-01-31 13:52:22 +01001804static int hdmi_lpe_audio_remove(struct platform_device *pdev)
Jerome Anand5dab11d2017-01-25 04:27:52 +05301805{
Takashi Iwaida864802017-01-31 13:52:22 +01001806 struct snd_intelhad *ctx = platform_get_drvdata(pdev);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301807
Takashi Iwaida864802017-01-31 13:52:22 +01001808 snd_card_free(ctx->card);
Jerome Anand5dab11d2017-01-25 04:27:52 +05301809 return 0;
1810}
1811
Takashi Iwai182cdf22017-02-02 14:43:39 +01001812static const struct dev_pm_ops hdmi_lpe_audio_pm = {
1813 SET_SYSTEM_SLEEP_PM_OPS(hdmi_lpe_audio_suspend, hdmi_lpe_audio_resume)
1814 SET_RUNTIME_PM_OPS(hdmi_lpe_audio_runtime_suspend, NULL, NULL)
1815};
1816
Takashi Iwaida864802017-01-31 13:52:22 +01001817static struct platform_driver hdmi_lpe_audio_driver = {
1818 .driver = {
1819 .name = "hdmi-lpe-audio",
Takashi Iwai182cdf22017-02-02 14:43:39 +01001820 .pm = &hdmi_lpe_audio_pm,
Takashi Iwaida864802017-01-31 13:52:22 +01001821 },
1822 .probe = hdmi_lpe_audio_probe,
1823 .remove = hdmi_lpe_audio_remove,
Takashi Iwaida864802017-01-31 13:52:22 +01001824};
1825
1826module_platform_driver(hdmi_lpe_audio_driver);
1827MODULE_ALIAS("platform:hdmi_lpe_audio");
1828
Jerome Anand5dab11d2017-01-25 04:27:52 +05301829MODULE_AUTHOR("Sailaja Bandarupalli <sailaja.bandarupalli@intel.com>");
1830MODULE_AUTHOR("Ramesh Babu K V <ramesh.babu@intel.com>");
1831MODULE_AUTHOR("Vaibhav Agarwal <vaibhav.agarwal@intel.com>");
1832MODULE_AUTHOR("Jerome Anand <jerome.anand@intel.com>");
1833MODULE_DESCRIPTION("Intel HDMI Audio driver");
1834MODULE_LICENSE("GPL v2");
1835MODULE_SUPPORTED_DEVICE("{Intel,Intel_HAD}");