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

sdw-mockup.c (7635B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2//
      3// sdw-mockup.c -- a mockup SoundWire codec for tests where only the host
      4// drives the bus.
      5//
      6// Copyright(c) 2021 Intel Corporation
      7//
      8//
      9
     10#include <linux/device.h>
     11#include <linux/mod_devicetable.h>
     12#include <linux/module.h>
     13#include <linux/soundwire/sdw.h>
     14#include <linux/soundwire/sdw_type.h>
     15#include <linux/soundwire/sdw_registers.h>
     16#include <sound/core.h>
     17#include <sound/pcm.h>
     18#include <sound/pcm_params.h>
     19#include <sound/soc.h>
     20
     21struct  sdw_mockup_priv {
     22	struct sdw_slave *slave;
     23};
     24
     25struct sdw_stream_data {
     26	struct sdw_stream_runtime *sdw_stream;
     27};
     28
     29static int sdw_mockup_component_probe(struct snd_soc_component *component)
     30{
     31	return 0;
     32}
     33
     34static void sdw_mockup_component_remove(struct snd_soc_component *component)
     35{
     36}
     37
     38static const struct snd_soc_component_driver snd_soc_sdw_mockup_component = {
     39	.probe = sdw_mockup_component_probe,
     40	.remove = sdw_mockup_component_remove,
     41	.endianness = 1,
     42};
     43
     44static int sdw_mockup_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
     45				     int direction)
     46{
     47	struct sdw_stream_data *stream;
     48
     49	if (!sdw_stream)
     50		return 0;
     51
     52	stream = kzalloc(sizeof(*stream), GFP_KERNEL);
     53	if (!stream)
     54		return -ENOMEM;
     55
     56	stream->sdw_stream = sdw_stream;
     57
     58	/* Use tx_mask or rx_mask to configure stream tag and set dma_data */
     59	if (direction == SNDRV_PCM_STREAM_PLAYBACK)
     60		dai->playback_dma_data = stream;
     61	else
     62		dai->capture_dma_data = stream;
     63
     64	return 0;
     65}
     66
     67static void sdw_mockup_shutdown(struct snd_pcm_substream *substream,
     68				struct snd_soc_dai *dai)
     69{
     70	struct sdw_stream_data *stream;
     71
     72	stream = snd_soc_dai_get_dma_data(dai, substream);
     73	snd_soc_dai_set_dma_data(dai, substream, NULL);
     74	kfree(stream);
     75}
     76
     77static int sdw_mockup_pcm_hw_params(struct snd_pcm_substream *substream,
     78				    struct snd_pcm_hw_params *params,
     79				    struct snd_soc_dai *dai)
     80{
     81	struct snd_soc_component *component = dai->component;
     82	struct sdw_mockup_priv *sdw_mockup = snd_soc_component_get_drvdata(component);
     83	struct sdw_stream_config stream_config;
     84	struct sdw_port_config port_config;
     85	enum sdw_data_direction direction;
     86	struct sdw_stream_data *stream;
     87	int num_channels;
     88	int port;
     89	int ret;
     90
     91	stream = snd_soc_dai_get_dma_data(dai, substream);
     92	if (!stream)
     93		return -EINVAL;
     94
     95	if (!sdw_mockup->slave)
     96		return -EINVAL;
     97
     98	/* SoundWire specific configuration */
     99	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
    100		direction = SDW_DATA_DIR_RX;
    101		port = 1;
    102	} else {
    103		direction = SDW_DATA_DIR_TX;
    104		port = 8;
    105	}
    106
    107	stream_config.frame_rate = params_rate(params);
    108	stream_config.ch_count = params_channels(params);
    109	stream_config.bps = snd_pcm_format_width(params_format(params));
    110	stream_config.direction = direction;
    111
    112	num_channels = params_channels(params);
    113	port_config.ch_mask = (1 << num_channels) - 1;
    114	port_config.num = port;
    115
    116	ret = sdw_stream_add_slave(sdw_mockup->slave, &stream_config,
    117				   &port_config, 1, stream->sdw_stream);
    118	if (ret)
    119		dev_err(dai->dev, "Unable to configure port\n");
    120
    121	return ret;
    122}
    123
    124static int sdw_mockup_pcm_hw_free(struct snd_pcm_substream *substream,
    125				  struct snd_soc_dai *dai)
    126{
    127	struct snd_soc_component *component = dai->component;
    128	struct sdw_mockup_priv *sdw_mockup = snd_soc_component_get_drvdata(component);
    129	struct sdw_stream_data *stream =
    130		snd_soc_dai_get_dma_data(dai, substream);
    131
    132	if (!sdw_mockup->slave)
    133		return -EINVAL;
    134
    135	sdw_stream_remove_slave(sdw_mockup->slave, stream->sdw_stream);
    136	return 0;
    137}
    138
    139static const struct snd_soc_dai_ops sdw_mockup_ops = {
    140	.hw_params	= sdw_mockup_pcm_hw_params,
    141	.hw_free	= sdw_mockup_pcm_hw_free,
    142	.set_stream	= sdw_mockup_set_sdw_stream,
    143	.shutdown	= sdw_mockup_shutdown,
    144};
    145
    146static struct snd_soc_dai_driver sdw_mockup_dai[] = {
    147	{
    148		.name = "sdw-mockup-aif1",
    149		.id = 1,
    150		.playback = {
    151			.stream_name = "DP1 Playback",
    152			.channels_min = 1,
    153			.channels_max = 2,
    154		},
    155		.capture = {
    156			.stream_name = "DP8 Capture",
    157			.channels_min = 1,
    158			.channels_max = 2,
    159		},
    160		.ops = &sdw_mockup_ops,
    161	},
    162};
    163
    164static int sdw_mockup_update_status(struct sdw_slave *slave,
    165				    enum sdw_slave_status status)
    166{
    167	return 0;
    168}
    169
    170static int sdw_mockup_read_prop(struct sdw_slave *slave)
    171{
    172	struct sdw_slave_prop *prop = &slave->prop;
    173	int nval;
    174	int i, j;
    175	u32 bit;
    176	unsigned long addr;
    177	struct sdw_dpn_prop *dpn;
    178
    179	prop->paging_support = false;
    180
    181	/*
    182	 * first we need to allocate memory for set bits in port lists
    183	 * the port allocation is completely arbitrary:
    184	 * DP0 is not supported
    185	 * DP1 is sink
    186	 * DP8 is source
    187	 */
    188	prop->source_ports = BIT(8);
    189	prop->sink_ports = BIT(1);
    190
    191	nval = hweight32(prop->source_ports);
    192	prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval,
    193					  sizeof(*prop->src_dpn_prop),
    194					  GFP_KERNEL);
    195	if (!prop->src_dpn_prop)
    196		return -ENOMEM;
    197
    198	i = 0;
    199	dpn = prop->src_dpn_prop;
    200	addr = prop->source_ports;
    201	for_each_set_bit(bit, &addr, 32) {
    202		dpn[i].num = bit;
    203		dpn[i].type = SDW_DPN_FULL;
    204		dpn[i].simple_ch_prep_sm = true;
    205		i++;
    206	}
    207
    208	/* do this again for sink now */
    209	nval = hweight32(prop->sink_ports);
    210	prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval,
    211					   sizeof(*prop->sink_dpn_prop),
    212					   GFP_KERNEL);
    213	if (!prop->sink_dpn_prop)
    214		return -ENOMEM;
    215
    216	j = 0;
    217	dpn = prop->sink_dpn_prop;
    218	addr = prop->sink_ports;
    219	for_each_set_bit(bit, &addr, 32) {
    220		dpn[j].num = bit;
    221		dpn[j].type = SDW_DPN_FULL;
    222		dpn[j].simple_ch_prep_sm = true;
    223		j++;
    224	}
    225
    226	prop->simple_clk_stop_capable = true;
    227
    228	/* wake-up event */
    229	prop->wake_capable = 0;
    230
    231	return 0;
    232}
    233
    234static int sdw_mockup_bus_config(struct sdw_slave *slave,
    235				 struct sdw_bus_params *params)
    236{
    237	return 0;
    238}
    239
    240static int sdw_mockup_interrupt_callback(struct sdw_slave *slave,
    241					 struct sdw_slave_intr_status *status)
    242{
    243	return 0;
    244}
    245
    246static const struct sdw_slave_ops sdw_mockup_slave_ops = {
    247	.read_prop = sdw_mockup_read_prop,
    248	.interrupt_callback = sdw_mockup_interrupt_callback,
    249	.update_status = sdw_mockup_update_status,
    250	.bus_config = sdw_mockup_bus_config,
    251};
    252
    253static int sdw_mockup_sdw_probe(struct sdw_slave *slave,
    254				const struct sdw_device_id *id)
    255{
    256	struct device *dev = &slave->dev;
    257	struct sdw_mockup_priv *sdw_mockup;
    258	int ret;
    259
    260	sdw_mockup = devm_kzalloc(dev, sizeof(*sdw_mockup), GFP_KERNEL);
    261	if (!sdw_mockup)
    262		return -ENOMEM;
    263
    264	dev_set_drvdata(dev, sdw_mockup);
    265	sdw_mockup->slave = slave;
    266
    267	slave->is_mockup_device = true;
    268
    269	ret =  devm_snd_soc_register_component(dev,
    270					       &snd_soc_sdw_mockup_component,
    271					       sdw_mockup_dai,
    272					       ARRAY_SIZE(sdw_mockup_dai));
    273
    274	return ret;
    275}
    276
    277static int sdw_mockup_sdw_remove(struct sdw_slave *slave)
    278{
    279	return 0;
    280}
    281
    282/*
    283 * Intel reserved parts ID with the following mapping expected:
    284 * 0xAAAA: generic full-duplex codec
    285 * 0xAA55: headset codec (mock-up of RT711/RT5682) - full-duplex
    286 * 0x55AA: amplifier (mock-up of RT1308/Maxim 98373) - playback only with
    287 * IV feedback
    288 * 0x5555: mic codec (mock-up of RT715) - capture-only
    289 */
    290static const struct sdw_device_id sdw_mockup_id[] = {
    291	SDW_SLAVE_ENTRY_EXT(0x0105, 0xAAAA, 0x0, 0, 0),
    292	SDW_SLAVE_ENTRY_EXT(0x0105, 0xAA55, 0x0, 0, 0),
    293	SDW_SLAVE_ENTRY_EXT(0x0105, 0x55AA, 0x0, 0, 0),
    294	SDW_SLAVE_ENTRY_EXT(0x0105, 0x5555, 0x0, 0, 0),
    295	{},
    296};
    297MODULE_DEVICE_TABLE(sdw, sdw_mockup_id);
    298
    299static struct sdw_driver sdw_mockup_sdw_driver = {
    300	.driver = {
    301		.name = "sdw-mockup",
    302		.owner = THIS_MODULE,
    303	},
    304	.probe = sdw_mockup_sdw_probe,
    305	.remove = sdw_mockup_sdw_remove,
    306	.ops = &sdw_mockup_slave_ops,
    307	.id_table = sdw_mockup_id,
    308};
    309module_sdw_driver(sdw_mockup_sdw_driver);
    310
    311MODULE_DESCRIPTION("ASoC SDW mockup codec driver");
    312MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>");
    313MODULE_LICENSE("GPL");