cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dp_audio.c (16437B)


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