File Index
Files and directories
Sign in
FILE

hdmi_audio.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/msm/hdmi/hdmi_audio.c C
  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
 16int 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
125int 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
166void 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}
~/ Read-only file preview.