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

dw-hdmi-gp-audio.c (4802B)


      1// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
      2/*
      3 * dw-hdmi-gp-audio.c
      4 *
      5 * Copyright 2020-2022 NXP
      6 */
      7#include <linux/io.h>
      8#include <linux/interrupt.h>
      9#include <linux/module.h>
     10#include <linux/platform_device.h>
     11#include <linux/dmaengine.h>
     12#include <linux/dma-mapping.h>
     13#include <drm/bridge/dw_hdmi.h>
     14#include <drm/drm_edid.h>
     15#include <drm/drm_connector.h>
     16
     17#include <sound/hdmi-codec.h>
     18#include <sound/asoundef.h>
     19#include <sound/core.h>
     20#include <sound/initval.h>
     21#include <sound/pcm.h>
     22#include <sound/pcm_drm_eld.h>
     23#include <sound/pcm_iec958.h>
     24#include <sound/dmaengine_pcm.h>
     25
     26#include "dw-hdmi-audio.h"
     27
     28#define DRIVER_NAME "dw-hdmi-gp-audio"
     29#define DRV_NAME    "hdmi-gp-audio"
     30
     31struct snd_dw_hdmi {
     32	struct dw_hdmi_audio_data data;
     33	struct platform_device  *audio_pdev;
     34	unsigned int pos;
     35};
     36
     37struct dw_hdmi_channel_conf {
     38	u8 conf1;
     39	u8 ca;
     40};
     41
     42/*
     43 * The default mapping of ALSA channels to HDMI channels and speaker
     44 * allocation bits.  Note that we can't do channel remapping here -
     45 * channels must be in the same order.
     46 *
     47 * Mappings for alsa-lib pcm/surround*.conf files:
     48 *
     49 *		Front	Sur4.0	Sur4.1	Sur5.0	Sur5.1	Sur7.1
     50 * Channels	2	4	6	6	6	8
     51 *
     52 * Our mapping from ALSA channel to CEA686D speaker name and HDMI channel:
     53 *
     54 *				Number of ALSA channels
     55 * ALSA Channel	2	3	4	5	6	7	8
     56 * 0		FL:0	=	=	=	=	=	=
     57 * 1		FR:1	=	=	=	=	=	=
     58 * 2			FC:3	RL:4	LFE:2	=	=	=
     59 * 3				RR:5	RL:4	FC:3	=	=
     60 * 4					RR:5	RL:4	=	=
     61 * 5						RR:5	=	=
     62 * 6							RC:6	=
     63 * 7							RLC/FRC	RLC/FRC
     64 */
     65static struct dw_hdmi_channel_conf default_hdmi_channel_config[7] = {
     66	{ 0x03, 0x00 },	/* FL,FR */
     67	{ 0x0b, 0x02 },	/* FL,FR,FC */
     68	{ 0x33, 0x08 },	/* FL,FR,RL,RR */
     69	{ 0x37, 0x09 },	/* FL,FR,LFE,RL,RR */
     70	{ 0x3f, 0x0b },	/* FL,FR,LFE,FC,RL,RR */
     71	{ 0x7f, 0x0f },	/* FL,FR,LFE,FC,RL,RR,RC */
     72	{ 0xff, 0x13 },	/* FL,FR,LFE,FC,RL,RR,[FR]RC,[FR]LC */
     73};
     74
     75static int audio_hw_params(struct device *dev,  void *data,
     76			   struct hdmi_codec_daifmt *daifmt,
     77			   struct hdmi_codec_params *params)
     78{
     79	struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
     80	u8 ca;
     81
     82	dw_hdmi_set_sample_rate(dw->data.hdmi, params->sample_rate);
     83
     84	ca = default_hdmi_channel_config[params->channels - 2].ca;
     85
     86	dw_hdmi_set_channel_count(dw->data.hdmi, params->channels);
     87	dw_hdmi_set_channel_allocation(dw->data.hdmi, ca);
     88
     89	dw_hdmi_set_sample_non_pcm(dw->data.hdmi,
     90				   params->iec.status[0] & IEC958_AES0_NONAUDIO);
     91	dw_hdmi_set_sample_width(dw->data.hdmi, params->sample_width);
     92
     93	return 0;
     94}
     95
     96static void audio_shutdown(struct device *dev, void *data)
     97{
     98}
     99
    100static int audio_mute_stream(struct device *dev, void *data,
    101			     bool enable, int direction)
    102{
    103	struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
    104
    105	if (!enable)
    106		dw_hdmi_audio_enable(dw->data.hdmi);
    107	else
    108		dw_hdmi_audio_disable(dw->data.hdmi);
    109
    110	return 0;
    111}
    112
    113static int audio_get_eld(struct device *dev, void *data,
    114			 u8 *buf, size_t len)
    115{
    116	struct dw_hdmi_audio_data *audio = data;
    117	u8 *eld;
    118
    119	eld = audio->get_eld(audio->hdmi);
    120	if (eld)
    121		memcpy(buf, eld, min_t(size_t, MAX_ELD_BYTES, len));
    122	else
    123		/* Pass en empty ELD if connector not available */
    124		memset(buf, 0, len);
    125
    126	return 0;
    127}
    128
    129static int audio_hook_plugged_cb(struct device *dev, void *data,
    130				 hdmi_codec_plugged_cb fn,
    131				 struct device *codec_dev)
    132{
    133	struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
    134
    135	return dw_hdmi_set_plugged_cb(dw->data.hdmi, fn, codec_dev);
    136}
    137
    138static const struct hdmi_codec_ops audio_codec_ops = {
    139	.hw_params = audio_hw_params,
    140	.audio_shutdown = audio_shutdown,
    141	.mute_stream = audio_mute_stream,
    142	.get_eld = audio_get_eld,
    143	.hook_plugged_cb = audio_hook_plugged_cb,
    144};
    145
    146static int snd_dw_hdmi_probe(struct platform_device *pdev)
    147{
    148	struct dw_hdmi_audio_data *data = pdev->dev.platform_data;
    149	struct snd_dw_hdmi *dw;
    150
    151	const struct hdmi_codec_pdata codec_data = {
    152		.i2s = 1,
    153		.spdif = 0,
    154		.ops = &audio_codec_ops,
    155		.max_i2s_channels = 8,
    156		.data = data,
    157	};
    158
    159	dw = devm_kzalloc(&pdev->dev, sizeof(*dw), GFP_KERNEL);
    160	if (!dw)
    161		return -ENOMEM;
    162
    163	dw->data = *data;
    164
    165	platform_set_drvdata(pdev, dw);
    166
    167	dw->audio_pdev = platform_device_register_data(&pdev->dev,
    168						       HDMI_CODEC_DRV_NAME, 1,
    169						       &codec_data,
    170						       sizeof(codec_data));
    171
    172	return PTR_ERR_OR_ZERO(dw->audio_pdev);
    173}
    174
    175static int snd_dw_hdmi_remove(struct platform_device *pdev)
    176{
    177	struct snd_dw_hdmi *dw = platform_get_drvdata(pdev);
    178
    179	platform_device_unregister(dw->audio_pdev);
    180
    181	return 0;
    182}
    183
    184static struct platform_driver snd_dw_hdmi_driver = {
    185	.probe	= snd_dw_hdmi_probe,
    186	.remove	= snd_dw_hdmi_remove,
    187	.driver	= {
    188		.name = DRIVER_NAME,
    189	},
    190};
    191
    192module_platform_driver(snd_dw_hdmi_driver);
    193
    194MODULE_AUTHOR("Shengjiu Wang <shengjiu.wang@nxp.com>");
    195MODULE_DESCRIPTION("Synopsys Designware HDMI GPA ALSA interface");
    196MODULE_LICENSE("GPL");
    197MODULE_ALIAS("platform:" DRIVER_NAME);