582 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*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_panel.h"17#include "dp_display.h"18#include "dp_utils.h"19 20struct dp_audio_private {21 struct platform_device *audio_pdev;22 struct platform_device *pdev;23 struct drm_device *drm_dev;24 struct dp_catalog *catalog;25 26 u32 channels;27 28 struct dp_audio dp_audio;29};30 31static u32 dp_audio_get_header(struct dp_catalog *catalog,32 enum dp_catalog_audio_sdp_type sdp,33 enum dp_catalog_audio_header_type header)34{35 return dp_catalog_audio_get_header(catalog, sdp, header);36}37 38static void dp_audio_set_header(struct dp_catalog *catalog,39 u32 data,40 enum dp_catalog_audio_sdp_type sdp,41 enum dp_catalog_audio_header_type header)42{43 dp_catalog_audio_set_header(catalog, sdp, header, data);44}45 46static void dp_audio_stream_sdp(struct dp_audio_private *audio)47{48 struct dp_catalog *catalog = audio->catalog;49 u32 value, new_value;50 u8 parity_byte;51 52 /* Config header and parity byte 1 */53 value = dp_audio_get_header(catalog,54 DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_1);55 56 new_value = 0x02;57 parity_byte = dp_utils_calculate_parity(new_value);58 value |= ((new_value << HEADER_BYTE_1_BIT)59 | (parity_byte << PARITY_BYTE_1_BIT));60 drm_dbg_dp(audio->drm_dev,61 "Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",62 value, parity_byte);63 dp_audio_set_header(catalog, value,64 DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_1);65 66 /* Config header and parity byte 2 */67 value = dp_audio_get_header(catalog,68 DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_2);69 new_value = value;70 parity_byte = dp_utils_calculate_parity(new_value);71 value |= ((new_value << HEADER_BYTE_2_BIT)72 | (parity_byte << PARITY_BYTE_2_BIT));73 drm_dbg_dp(audio->drm_dev,74 "Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",75 value, parity_byte);76 77 dp_audio_set_header(catalog, value,78 DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_2);79 80 /* Config header and parity byte 3 */81 value = dp_audio_get_header(catalog,82 DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_3);83 84 new_value = audio->channels - 1;85 parity_byte = dp_utils_calculate_parity(new_value);86 value |= ((new_value << HEADER_BYTE_3_BIT)87 | (parity_byte << PARITY_BYTE_3_BIT));88 drm_dbg_dp(audio->drm_dev,89 "Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",90 value, parity_byte);91 92 dp_audio_set_header(catalog, value,93 DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_3);94}95 96static void dp_audio_timestamp_sdp(struct dp_audio_private *audio)97{98 struct dp_catalog *catalog = audio->catalog;99 u32 value, new_value;100 u8 parity_byte;101 102 /* Config header and parity byte 1 */103 value = dp_audio_get_header(catalog,104 DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_1);105 106 new_value = 0x1;107 parity_byte = dp_utils_calculate_parity(new_value);108 value |= ((new_value << HEADER_BYTE_1_BIT)109 | (parity_byte << PARITY_BYTE_1_BIT));110 drm_dbg_dp(audio->drm_dev,111 "Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",112 value, parity_byte);113 dp_audio_set_header(catalog, value,114 DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_1);115 116 /* Config header and parity byte 2 */117 value = dp_audio_get_header(catalog,118 DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_2);119 120 new_value = 0x17;121 parity_byte = dp_utils_calculate_parity(new_value);122 value |= ((new_value << HEADER_BYTE_2_BIT)123 | (parity_byte << PARITY_BYTE_2_BIT));124 drm_dbg_dp(audio->drm_dev,125 "Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",126 value, parity_byte);127 dp_audio_set_header(catalog, value,128 DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_2);129 130 /* Config header and parity byte 3 */131 value = dp_audio_get_header(catalog,132 DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_3);133 134 new_value = (0x0 | (0x11 << 2));135 parity_byte = dp_utils_calculate_parity(new_value);136 value |= ((new_value << HEADER_BYTE_3_BIT)137 | (parity_byte << PARITY_BYTE_3_BIT));138 drm_dbg_dp(audio->drm_dev,139 "Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",140 value, parity_byte);141 dp_audio_set_header(catalog, value,142 DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_3);143}144 145static void dp_audio_infoframe_sdp(struct dp_audio_private *audio)146{147 struct dp_catalog *catalog = audio->catalog;148 u32 value, new_value;149 u8 parity_byte;150 151 /* Config header and parity byte 1 */152 value = dp_audio_get_header(catalog,153 DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_1);154 155 new_value = 0x84;156 parity_byte = dp_utils_calculate_parity(new_value);157 value |= ((new_value << HEADER_BYTE_1_BIT)158 | (parity_byte << PARITY_BYTE_1_BIT));159 drm_dbg_dp(audio->drm_dev,160 "Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",161 value, parity_byte);162 dp_audio_set_header(catalog, value,163 DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_1);164 165 /* Config header and parity byte 2 */166 value = dp_audio_get_header(catalog,167 DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_2);168 169 new_value = 0x1b;170 parity_byte = dp_utils_calculate_parity(new_value);171 value |= ((new_value << HEADER_BYTE_2_BIT)172 | (parity_byte << PARITY_BYTE_2_BIT));173 drm_dbg_dp(audio->drm_dev,174 "Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",175 value, parity_byte);176 dp_audio_set_header(catalog, value,177 DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_2);178 179 /* Config header and parity byte 3 */180 value = dp_audio_get_header(catalog,181 DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_3);182 183 new_value = (0x0 | (0x11 << 2));184 parity_byte = dp_utils_calculate_parity(new_value);185 value |= ((new_value << HEADER_BYTE_3_BIT)186 | (parity_byte << PARITY_BYTE_3_BIT));187 drm_dbg_dp(audio->drm_dev,188 "Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",189 new_value, parity_byte);190 dp_audio_set_header(catalog, value,191 DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_3);192}193 194static void dp_audio_copy_management_sdp(struct dp_audio_private *audio)195{196 struct dp_catalog *catalog = audio->catalog;197 u32 value, new_value;198 u8 parity_byte;199 200 /* Config header and parity byte 1 */201 value = dp_audio_get_header(catalog,202 DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_1);203 204 new_value = 0x05;205 parity_byte = dp_utils_calculate_parity(new_value);206 value |= ((new_value << HEADER_BYTE_1_BIT)207 | (parity_byte << PARITY_BYTE_1_BIT));208 drm_dbg_dp(audio->drm_dev,209 "Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",210 value, parity_byte);211 dp_audio_set_header(catalog, value,212 DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_1);213 214 /* Config header and parity byte 2 */215 value = dp_audio_get_header(catalog,216 DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_2);217 218 new_value = 0x0F;219 parity_byte = dp_utils_calculate_parity(new_value);220 value |= ((new_value << HEADER_BYTE_2_BIT)221 | (parity_byte << PARITY_BYTE_2_BIT));222 drm_dbg_dp(audio->drm_dev,223 "Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",224 value, parity_byte);225 dp_audio_set_header(catalog, value,226 DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_2);227 228 /* Config header and parity byte 3 */229 value = dp_audio_get_header(catalog,230 DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_3);231 232 new_value = 0x0;233 parity_byte = dp_utils_calculate_parity(new_value);234 value |= ((new_value << HEADER_BYTE_3_BIT)235 | (parity_byte << PARITY_BYTE_3_BIT));236 drm_dbg_dp(audio->drm_dev,237 "Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",238 value, parity_byte);239 dp_audio_set_header(catalog, value,240 DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_3);241}242 243static void dp_audio_isrc_sdp(struct dp_audio_private *audio)244{245 struct dp_catalog *catalog = audio->catalog;246 u32 value, new_value;247 u8 parity_byte;248 249 /* Config header and parity byte 1 */250 value = dp_audio_get_header(catalog,251 DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_1);252 253 new_value = 0x06;254 parity_byte = dp_utils_calculate_parity(new_value);255 value |= ((new_value << HEADER_BYTE_1_BIT)256 | (parity_byte << PARITY_BYTE_1_BIT));257 drm_dbg_dp(audio->drm_dev,258 "Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",259 value, parity_byte);260 dp_audio_set_header(catalog, value,261 DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_1);262 263 /* Config header and parity byte 2 */264 value = dp_audio_get_header(catalog,265 DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_2);266 267 new_value = 0x0F;268 parity_byte = dp_utils_calculate_parity(new_value);269 value |= ((new_value << HEADER_BYTE_2_BIT)270 | (parity_byte << PARITY_BYTE_2_BIT));271 drm_dbg_dp(audio->drm_dev,272 "Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",273 value, parity_byte);274 dp_audio_set_header(catalog, value,275 DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_2);276}277 278static void dp_audio_setup_sdp(struct dp_audio_private *audio)279{280 dp_catalog_audio_config_sdp(audio->catalog);281 282 dp_audio_stream_sdp(audio);283 dp_audio_timestamp_sdp(audio);284 dp_audio_infoframe_sdp(audio);285 dp_audio_copy_management_sdp(audio);286 dp_audio_isrc_sdp(audio);287}288 289static void dp_audio_setup_acr(struct dp_audio_private *audio)290{291 u32 select = 0;292 struct dp_catalog *catalog = audio->catalog;293 294 switch (audio->dp_audio.bw_code) {295 case DP_LINK_BW_1_62:296 select = 0;297 break;298 case DP_LINK_BW_2_7:299 select = 1;300 break;301 case DP_LINK_BW_5_4:302 select = 2;303 break;304 case DP_LINK_BW_8_1:305 select = 3;306 break;307 default:308 drm_dbg_dp(audio->drm_dev, "Unknown link rate\n");309 select = 0;310 break;311 }312 313 dp_catalog_audio_config_acr(catalog, select);314}315 316static void dp_audio_safe_to_exit_level(struct dp_audio_private *audio)317{318 struct dp_catalog *catalog = audio->catalog;319 u32 safe_to_exit_level = 0;320 321 switch (audio->dp_audio.lane_count) {322 case 1:323 safe_to_exit_level = 14;324 break;325 case 2:326 safe_to_exit_level = 8;327 break;328 case 4:329 safe_to_exit_level = 5;330 break;331 default:332 drm_dbg_dp(audio->drm_dev,333 "setting the default safe_to_exit_level = %u\n",334 safe_to_exit_level);335 safe_to_exit_level = 14;336 break;337 }338 339 dp_catalog_audio_sfe_level(catalog, safe_to_exit_level);340}341 342static void dp_audio_enable(struct dp_audio_private *audio, bool enable)343{344 struct dp_catalog *catalog = audio->catalog;345 346 dp_catalog_audio_enable(catalog, enable);347}348 349static struct dp_audio_private *dp_audio_get_data(struct platform_device *pdev)350{351 struct dp_audio *dp_audio;352 struct msm_dp *dp_display;353 354 if (!pdev) {355 DRM_ERROR("invalid input\n");356 return ERR_PTR(-ENODEV);357 }358 359 dp_display = platform_get_drvdata(pdev);360 if (!dp_display) {361 DRM_ERROR("invalid input\n");362 return ERR_PTR(-ENODEV);363 }364 365 dp_audio = dp_display->dp_audio;366 367 if (!dp_audio) {368 DRM_ERROR("invalid dp_audio data\n");369 return ERR_PTR(-EINVAL);370 }371 372 return container_of(dp_audio, struct dp_audio_private, dp_audio);373}374 375static int dp_audio_hook_plugged_cb(struct device *dev, void *data,376 hdmi_codec_plugged_cb fn,377 struct device *codec_dev)378{379 380 struct platform_device *pdev;381 struct msm_dp *dp_display;382 383 pdev = to_platform_device(dev);384 if (!pdev) {385 pr_err("invalid input\n");386 return -ENODEV;387 }388 389 dp_display = platform_get_drvdata(pdev);390 if (!dp_display) {391 pr_err("invalid input\n");392 return -ENODEV;393 }394 395 return dp_display_set_plugged_cb(dp_display, fn, codec_dev);396}397 398static int dp_audio_get_eld(struct device *dev,399 void *data, uint8_t *buf, size_t len)400{401 struct platform_device *pdev;402 struct msm_dp *dp_display;403 404 pdev = to_platform_device(dev);405 406 if (!pdev) {407 DRM_ERROR("invalid input\n");408 return -ENODEV;409 }410 411 dp_display = platform_get_drvdata(pdev);412 if (!dp_display) {413 DRM_ERROR("invalid input\n");414 return -ENODEV;415 }416 417 memcpy(buf, dp_display->connector->eld,418 min(sizeof(dp_display->connector->eld), len));419 420 return 0;421}422 423int dp_audio_hw_params(struct device *dev,424 void *data,425 struct hdmi_codec_daifmt *daifmt,426 struct hdmi_codec_params *params)427{428 int rc = 0;429 struct dp_audio_private *audio;430 struct platform_device *pdev;431 struct msm_dp *dp_display;432 433 pdev = to_platform_device(dev);434 dp_display = platform_get_drvdata(pdev);435 436 /*437 * there could be cases where sound card can be opened even438 * before OR even when DP is not connected . This can cause439 * unclocked access as the audio subsystem relies on the DP440 * driver to maintain the correct state of clocks. To protect441 * such cases check for connection status and bail out if not442 * connected.443 */444 if (!dp_display->power_on) {445 rc = -EINVAL;446 goto end;447 }448 449 audio = dp_audio_get_data(pdev);450 if (IS_ERR(audio)) {451 rc = PTR_ERR(audio);452 goto end;453 }454 455 audio->channels = params->channels;456 457 dp_audio_setup_sdp(audio);458 dp_audio_setup_acr(audio);459 dp_audio_safe_to_exit_level(audio);460 dp_audio_enable(audio, true);461 dp_display_signal_audio_start(dp_display);462 dp_display->audio_enabled = true;463 464end:465 return rc;466}467 468static void dp_audio_shutdown(struct device *dev, void *data)469{470 struct dp_audio_private *audio;471 struct platform_device *pdev;472 struct msm_dp *dp_display;473 474 pdev = to_platform_device(dev);475 dp_display = platform_get_drvdata(pdev);476 audio = dp_audio_get_data(pdev);477 if (IS_ERR(audio)) {478 DRM_ERROR("failed to get audio data\n");479 return;480 }481 482 /*483 * if audio was not enabled there is no need484 * to execute the shutdown and we can bail out early.485 * This also makes sure that we dont cause an unclocked486 * access when audio subsystem calls this without DP being487 * connected. is_connected cannot be used here as its set488 * to false earlier than this call489 */490 if (!dp_display->audio_enabled)491 return;492 493 dp_audio_enable(audio, false);494 /* signal the dp display to safely shutdown clocks */495 dp_display_signal_audio_complete(dp_display);496}497 498static const struct hdmi_codec_ops dp_audio_codec_ops = {499 .hw_params = dp_audio_hw_params,500 .audio_shutdown = dp_audio_shutdown,501 .get_eld = dp_audio_get_eld,502 .hook_plugged_cb = dp_audio_hook_plugged_cb,503};504 505static struct hdmi_codec_pdata codec_data = {506 .ops = &dp_audio_codec_ops,507 .max_i2s_channels = 8,508 .i2s = 1,509};510 511void dp_unregister_audio_driver(struct device *dev, struct dp_audio *dp_audio)512{513 struct dp_audio_private *audio_priv;514 515 audio_priv = container_of(dp_audio, struct dp_audio_private, dp_audio);516 517 if (audio_priv->audio_pdev) {518 platform_device_unregister(audio_priv->audio_pdev);519 audio_priv->audio_pdev = NULL;520 }521}522 523int dp_register_audio_driver(struct device *dev,524 struct dp_audio *dp_audio)525{526 struct dp_audio_private *audio_priv;527 528 audio_priv = container_of(dp_audio,529 struct dp_audio_private, dp_audio);530 531 audio_priv->audio_pdev = platform_device_register_data(dev,532 HDMI_CODEC_DRV_NAME,533 PLATFORM_DEVID_AUTO,534 &codec_data,535 sizeof(codec_data));536 return PTR_ERR_OR_ZERO(audio_priv->audio_pdev);537}538 539struct dp_audio *dp_audio_get(struct platform_device *pdev,540 struct dp_panel *panel,541 struct dp_catalog *catalog)542{543 int rc = 0;544 struct dp_audio_private *audio;545 struct dp_audio *dp_audio;546 547 if (!pdev || !panel || !catalog) {548 DRM_ERROR("invalid input\n");549 rc = -EINVAL;550 goto error;551 }552 553 audio = devm_kzalloc(&pdev->dev, sizeof(*audio), GFP_KERNEL);554 if (!audio) {555 rc = -ENOMEM;556 goto error;557 }558 559 audio->pdev = pdev;560 audio->catalog = catalog;561 562 dp_audio = &audio->dp_audio;563 564 dp_catalog_audio_init(catalog);565 566 return dp_audio;567error:568 return ERR_PTR(rc);569}570 571void dp_audio_put(struct dp_audio *dp_audio)572{573 struct dp_audio_private *audio;574 575 if (!dp_audio)576 return;577 578 audio = container_of(dp_audio, struct dp_audio_private, dp_audio);579 580 devm_kfree(&audio->pdev->dev, audio);581}582