1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. 4 */ 5 6 7 #define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__ 8 9 #include <linux/platform_device.h> 10 11 #include <drm/display/drm_dp_helper.h> 12 #include <drm/drm_edid.h> 13 14 #include "dp_catalog.h" 15 #include "dp_audio.h" 16 #include "dp_drm.h" 17 #include "dp_panel.h" 18 #include "dp_reg.h" 19 #include "dp_display.h" 20 #include "dp_utils.h" 21 22 struct msm_dp_audio_private { 23 struct platform_device *pdev; 24 struct drm_device *drm_dev; 25 struct msm_dp_catalog *catalog; 26 27 u32 channels; 28 29 struct msm_dp_audio msm_dp_audio; 30 }; 31 32 static void msm_dp_audio_stream_sdp(struct msm_dp_audio_private *audio) 33 { 34 struct dp_sdp_header sdp_hdr = { 35 .HB0 = 0x00, 36 .HB1 = 0x02, 37 .HB2 = 0x00, 38 .HB3 = audio->channels - 1, 39 }; 40 41 msm_dp_catalog_write_audio_stream(audio->catalog, &sdp_hdr); 42 } 43 44 static void msm_dp_audio_timestamp_sdp(struct msm_dp_audio_private *audio) 45 { 46 struct dp_sdp_header sdp_hdr = { 47 .HB0 = 0x00, 48 .HB1 = 0x01, 49 .HB2 = 0x17, 50 .HB3 = 0x0 | (0x11 << 2), 51 }; 52 53 msm_dp_catalog_write_audio_timestamp(audio->catalog, &sdp_hdr); 54 } 55 56 static void msm_dp_audio_infoframe_sdp(struct msm_dp_audio_private *audio) 57 { 58 struct dp_sdp_header sdp_hdr = { 59 .HB0 = 0x00, 60 .HB1 = 0x84, 61 .HB2 = 0x1b, 62 .HB3 = 0x0 | (0x11 << 2), 63 }; 64 65 msm_dp_catalog_write_audio_infoframe(audio->catalog, &sdp_hdr); 66 } 67 68 static void msm_dp_audio_copy_management_sdp(struct msm_dp_audio_private *audio) 69 { 70 struct dp_sdp_header sdp_hdr = { 71 .HB0 = 0x00, 72 .HB1 = 0x05, 73 .HB2 = 0x0f, 74 .HB3 = 0x00, 75 }; 76 77 msm_dp_catalog_write_audio_copy_mgmt(audio->catalog, &sdp_hdr); 78 } 79 80 static void msm_dp_audio_isrc_sdp(struct msm_dp_audio_private *audio) 81 { 82 struct dp_sdp_header sdp_hdr = { 83 .HB0 = 0x00, 84 .HB1 = 0x06, 85 .HB2 = 0x0f, 86 .HB3 = 0x00, 87 }; 88 89 msm_dp_catalog_write_audio_isrc(audio->catalog, &sdp_hdr); 90 } 91 92 static void msm_dp_audio_setup_sdp(struct msm_dp_audio_private *audio) 93 { 94 msm_dp_catalog_audio_config_sdp(audio->catalog); 95 96 msm_dp_audio_stream_sdp(audio); 97 msm_dp_audio_timestamp_sdp(audio); 98 msm_dp_audio_infoframe_sdp(audio); 99 msm_dp_audio_copy_management_sdp(audio); 100 msm_dp_audio_isrc_sdp(audio); 101 } 102 103 static void msm_dp_audio_setup_acr(struct msm_dp_audio_private *audio) 104 { 105 u32 select = 0; 106 struct msm_dp_catalog *catalog = audio->catalog; 107 108 switch (audio->msm_dp_audio.bw_code) { 109 case DP_LINK_BW_1_62: 110 select = 0; 111 break; 112 case DP_LINK_BW_2_7: 113 select = 1; 114 break; 115 case DP_LINK_BW_5_4: 116 select = 2; 117 break; 118 case DP_LINK_BW_8_1: 119 select = 3; 120 break; 121 default: 122 drm_dbg_dp(audio->drm_dev, "Unknown link rate\n"); 123 select = 0; 124 break; 125 } 126 127 msm_dp_catalog_audio_config_acr(catalog, select); 128 } 129 130 static void msm_dp_audio_safe_to_exit_level(struct msm_dp_audio_private *audio) 131 { 132 struct msm_dp_catalog *catalog = audio->catalog; 133 u32 safe_to_exit_level = 0; 134 135 switch (audio->msm_dp_audio.lane_count) { 136 case 1: 137 safe_to_exit_level = 14; 138 break; 139 case 2: 140 safe_to_exit_level = 8; 141 break; 142 case 4: 143 safe_to_exit_level = 5; 144 break; 145 default: 146 safe_to_exit_level = 14; 147 drm_dbg_dp(audio->drm_dev, 148 "setting the default safe_to_exit_level = %u\n", 149 safe_to_exit_level); 150 break; 151 } 152 153 msm_dp_catalog_audio_sfe_level(catalog, safe_to_exit_level); 154 } 155 156 static void msm_dp_audio_enable(struct msm_dp_audio_private *audio, bool enable) 157 { 158 struct msm_dp_catalog *catalog = audio->catalog; 159 160 msm_dp_catalog_audio_enable(catalog, enable); 161 } 162 163 static struct msm_dp_audio_private *msm_dp_audio_get_data(struct msm_dp *msm_dp_display) 164 { 165 struct msm_dp_audio *msm_dp_audio; 166 167 msm_dp_audio = msm_dp_display->msm_dp_audio; 168 if (!msm_dp_audio) { 169 DRM_ERROR("invalid msm_dp_audio data\n"); 170 return ERR_PTR(-EINVAL); 171 } 172 173 return container_of(msm_dp_audio, struct msm_dp_audio_private, msm_dp_audio); 174 } 175 176 int msm_dp_audio_prepare(struct drm_connector *connector, 177 struct drm_bridge *bridge, 178 struct hdmi_codec_daifmt *daifmt, 179 struct hdmi_codec_params *params) 180 { 181 int rc = 0; 182 struct msm_dp_audio_private *audio; 183 struct msm_dp *msm_dp_display; 184 185 msm_dp_display = to_dp_bridge(bridge)->msm_dp_display; 186 187 /* 188 * there could be cases where sound card can be opened even 189 * before OR even when DP is not connected . This can cause 190 * unclocked access as the audio subsystem relies on the DP 191 * driver to maintain the correct state of clocks. To protect 192 * such cases check for connection status and bail out if not 193 * connected. 194 */ 195 if (!msm_dp_display->power_on) { 196 rc = -EINVAL; 197 goto end; 198 } 199 200 audio = msm_dp_audio_get_data(msm_dp_display); 201 if (IS_ERR(audio)) { 202 rc = PTR_ERR(audio); 203 goto end; 204 } 205 206 audio->channels = params->channels; 207 208 msm_dp_audio_setup_sdp(audio); 209 msm_dp_audio_setup_acr(audio); 210 msm_dp_audio_safe_to_exit_level(audio); 211 msm_dp_audio_enable(audio, true); 212 msm_dp_display_signal_audio_start(msm_dp_display); 213 msm_dp_display->audio_enabled = true; 214 215 end: 216 return rc; 217 } 218 219 void msm_dp_audio_shutdown(struct drm_connector *connector, 220 struct drm_bridge *bridge) 221 { 222 struct msm_dp_audio_private *audio; 223 struct msm_dp *msm_dp_display; 224 225 msm_dp_display = to_dp_bridge(bridge)->msm_dp_display; 226 audio = msm_dp_audio_get_data(msm_dp_display); 227 if (IS_ERR(audio)) { 228 DRM_ERROR("failed to get audio data\n"); 229 return; 230 } 231 232 /* 233 * if audio was not enabled there is no need 234 * to execute the shutdown and we can bail out early. 235 * This also makes sure that we dont cause an unclocked 236 * access when audio subsystem calls this without DP being 237 * connected. is_connected cannot be used here as its set 238 * to false earlier than this call 239 */ 240 if (!msm_dp_display->audio_enabled) 241 return; 242 243 msm_dp_audio_enable(audio, false); 244 /* signal the dp display to safely shutdown clocks */ 245 msm_dp_display_signal_audio_complete(msm_dp_display); 246 } 247 248 struct msm_dp_audio *msm_dp_audio_get(struct platform_device *pdev, 249 struct msm_dp_catalog *catalog) 250 { 251 int rc = 0; 252 struct msm_dp_audio_private *audio; 253 struct msm_dp_audio *msm_dp_audio; 254 255 if (!pdev || !catalog) { 256 DRM_ERROR("invalid input\n"); 257 rc = -EINVAL; 258 goto error; 259 } 260 261 audio = devm_kzalloc(&pdev->dev, sizeof(*audio), GFP_KERNEL); 262 if (!audio) { 263 rc = -ENOMEM; 264 goto error; 265 } 266 267 audio->pdev = pdev; 268 audio->catalog = catalog; 269 270 msm_dp_audio = &audio->msm_dp_audio; 271 272 return msm_dp_audio; 273 error: 274 return ERR_PTR(rc); 275 } 276 277 void msm_dp_audio_put(struct msm_dp_audio *msm_dp_audio) 278 { 279 struct msm_dp_audio_private *audio; 280 281 if (!msm_dp_audio) 282 return; 283 284 audio = container_of(msm_dp_audio, struct msm_dp_audio_private, msm_dp_audio); 285 286 devm_kfree(&audio->pdev->dev, audio); 287 } 288