1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2013 Red Hat
4 * Author: Rob Clark <robdclark@gmail.com>
5 */
6
7 #include <drm/display/drm_hdmi_helper.h>
8 #include <drm/display/drm_hdmi_state_helper.h>
9
10 #include <linux/hdmi.h>
11
12 #include <sound/hdmi-codec.h>
13
14 #include "hdmi.h"
15
msm_hdmi_audio_update(struct hdmi * hdmi)16 int msm_hdmi_audio_update(struct hdmi *hdmi)
17 {
18 struct hdmi_audio *audio = &hdmi->audio;
19 bool enabled = audio->enabled;
20 uint32_t acr_pkt_ctrl, vbi_pkt_ctrl, aud_pkt_ctrl;
21 uint32_t audio_config;
22
23 if (!hdmi->connector->display_info.is_hdmi)
24 return -EINVAL;
25
26 DBG("audio: enabled=%d, channels=%d, rate=%d",
27 audio->enabled, audio->channels, audio->rate);
28
29 DBG("video: power_on=%d, pixclock=%lu", hdmi->power_on, hdmi->pixclock);
30
31 if (enabled && !(hdmi->power_on && hdmi->pixclock)) {
32 DBG("disabling audio: no video");
33 enabled = false;
34 }
35
36 /* Read first before writing */
37 acr_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_ACR_PKT_CTRL);
38 vbi_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_VBI_PKT_CTRL);
39 aud_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_AUDIO_PKT_CTRL1);
40 audio_config = hdmi_read(hdmi, REG_HDMI_AUDIO_CFG);
41
42 /* Clear N/CTS selection bits */
43 acr_pkt_ctrl &= ~HDMI_ACR_PKT_CTRL_SELECT__MASK;
44
45 if (enabled) {
46 uint32_t n, cts, multiplier;
47 enum hdmi_acr_cts select;
48
49 drm_hdmi_acr_get_n_cts(hdmi->pixclock, audio->rate, &n, &cts);
50
51 if (audio->rate == 192000 || audio->rate == 176400) {
52 multiplier = 4;
53 n >>= 2; /* divide N by 4 and use multiplier */
54 } else if (audio->rate == 96000 || audio->rate == 88200) {
55 multiplier = 2;
56 n >>= 1; /* divide N by 2 and use multiplier */
57 } else {
58 multiplier = 1;
59 }
60
61 DBG("n=%u, cts=%u, multiplier=%u", n, cts, multiplier);
62
63 acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_SOURCE;
64 acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_AUDIO_PRIORITY;
65 acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_N_MULTIPLIER(multiplier);
66
67 if (audio->rate == 48000 || audio->rate == 96000 ||
68 audio->rate == 192000)
69 select = ACR_48;
70 else if (audio->rate == 44100 || audio->rate == 88200 ||
71 audio->rate == 176400)
72 select = ACR_44;
73 else /* default to 32k */
74 select = ACR_32;
75
76 acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_SELECT(select);
77
78 hdmi_write(hdmi, REG_HDMI_ACR_0(select - 1),
79 HDMI_ACR_0_CTS(cts));
80 hdmi_write(hdmi, REG_HDMI_ACR_1(select - 1),
81 HDMI_ACR_1_N(n));
82
83 hdmi_write(hdmi, REG_HDMI_AUDIO_PKT_CTRL2,
84 COND(audio->channels != 2, HDMI_AUDIO_PKT_CTRL2_LAYOUT) |
85 HDMI_AUDIO_PKT_CTRL2_OVERRIDE);
86
87 acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_CONT;
88 acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_SEND;
89
90 hdmi_write(hdmi, REG_HDMI_GC, 0);
91
92 vbi_pkt_ctrl |= HDMI_VBI_PKT_CTRL_GC_ENABLE;
93 vbi_pkt_ctrl |= HDMI_VBI_PKT_CTRL_GC_EVERY_FRAME;
94
95 aud_pkt_ctrl |= HDMI_AUDIO_PKT_CTRL1_AUDIO_SAMPLE_SEND;
96
97 audio_config &= ~HDMI_AUDIO_CFG_FIFO_WATERMARK__MASK;
98 audio_config |= HDMI_AUDIO_CFG_FIFO_WATERMARK(4);
99 audio_config |= HDMI_AUDIO_CFG_ENGINE_ENABLE;
100 } else {
101 acr_pkt_ctrl &= ~HDMI_ACR_PKT_CTRL_CONT;
102 acr_pkt_ctrl &= ~HDMI_ACR_PKT_CTRL_SEND;
103 vbi_pkt_ctrl &= ~HDMI_VBI_PKT_CTRL_GC_ENABLE;
104 vbi_pkt_ctrl &= ~HDMI_VBI_PKT_CTRL_GC_EVERY_FRAME;
105 aud_pkt_ctrl &= ~HDMI_AUDIO_PKT_CTRL1_AUDIO_SAMPLE_SEND;
106 audio_config &= ~HDMI_AUDIO_CFG_ENGINE_ENABLE;
107 }
108
109 hdmi_write(hdmi, REG_HDMI_ACR_PKT_CTRL, acr_pkt_ctrl);
110 hdmi_write(hdmi, REG_HDMI_VBI_PKT_CTRL, vbi_pkt_ctrl);
111 hdmi_write(hdmi, REG_HDMI_AUDIO_PKT_CTRL1, aud_pkt_ctrl);
112
113 hdmi_write(hdmi, REG_HDMI_AUD_INT,
114 COND(enabled, HDMI_AUD_INT_AUD_FIFO_URUN_INT) |
115 COND(enabled, HDMI_AUD_INT_AUD_SAM_DROP_INT));
116
117 hdmi_write(hdmi, REG_HDMI_AUDIO_CFG, audio_config);
118
119
120 DBG("audio %sabled", enabled ? "en" : "dis");
121
122 return 0;
123 }
124
msm_hdmi_bridge_audio_prepare(struct drm_bridge * bridge,struct drm_connector * connector,struct hdmi_codec_daifmt * daifmt,struct hdmi_codec_params * params)125 int msm_hdmi_bridge_audio_prepare(struct drm_bridge *bridge,
126 struct drm_connector *connector,
127 struct hdmi_codec_daifmt *daifmt,
128 struct hdmi_codec_params *params)
129 {
130 struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
131 struct hdmi *hdmi = hdmi_bridge->hdmi;
132 int ret;
133
134 drm_dbg_driver(bridge->dev, "%u Hz, %d bit, %d channels\n",
135 params->sample_rate,
136 params->sample_width,
137 params->cea.channels);
138
139 switch (params->sample_rate) {
140 case 32000:
141 case 44100:
142 case 48000:
143 case 88200:
144 case 96000:
145 case 176400:
146 case 192000:
147 break;
148 default:
149 drm_err(bridge->dev, "rate[%d] not supported!\n",
150 params->sample_rate);
151 return -EINVAL;
152 }
153
154 ret = drm_atomic_helper_connector_hdmi_update_audio_infoframe(connector,
155 ¶ms->cea);
156 if (ret)
157 return ret;
158
159 hdmi->audio.rate = params->sample_rate;
160 hdmi->audio.channels = params->cea.channels;
161 hdmi->audio.enabled = true;
162
163 return msm_hdmi_audio_update(hdmi);
164 }
165
msm_hdmi_bridge_audio_shutdown(struct drm_bridge * bridge,struct drm_connector * connector)166 void msm_hdmi_bridge_audio_shutdown(struct drm_bridge *bridge,
167 struct drm_connector *connector)
168 {
169 struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
170 struct hdmi *hdmi = hdmi_bridge->hdmi;
171
172 drm_atomic_helper_connector_hdmi_clear_audio_infoframe(connector);
173
174 hdmi->audio.rate = 0;
175 hdmi->audio.channels = 2;
176 hdmi->audio.enabled = false;
177
178 msm_hdmi_audio_update(hdmi);
179 }
180