xref: /linux/drivers/gpu/drm/msm/hdmi/hdmi_audio.c (revision 220994d61cebfc04f071d69049127657c7e8191b)
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 								      &params->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