brintos

brintos / linux-shallow public Read only

0
0
Text · 14.9 KiB · a599fc5 Raw
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