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

dvc.c (8679B)


      1// SPDX-License-Identifier: GPL-2.0
      2//
      3// Renesas R-Car DVC support
      4//
      5// Copyright (C) 2014 Renesas Solutions Corp.
      6// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
      7
      8/*
      9 * Playback Volume
     10 *	amixer set "DVC Out" 100%
     11 *
     12 * Capture Volume
     13 *	amixer set "DVC In" 100%
     14 *
     15 * Playback Mute
     16 *	amixer set "DVC Out Mute" on
     17 *
     18 * Capture Mute
     19 *	amixer set "DVC In Mute" on
     20 *
     21 * Volume Ramp
     22 *	amixer set "DVC Out Ramp Up Rate"   "0.125 dB/64 steps"
     23 *	amixer set "DVC Out Ramp Down Rate" "0.125 dB/512 steps"
     24 *	amixer set "DVC Out Ramp" on
     25 *	aplay xxx.wav &
     26 *	amixer set "DVC Out"  80%  // Volume Down
     27 *	amixer set "DVC Out" 100%  // Volume Up
     28 */
     29
     30#include "rsnd.h"
     31
     32#define RSND_DVC_NAME_SIZE	16
     33
     34#define DVC_NAME "dvc"
     35
     36struct rsnd_dvc {
     37	struct rsnd_mod mod;
     38	struct rsnd_kctrl_cfg_m volume;
     39	struct rsnd_kctrl_cfg_m mute;
     40	struct rsnd_kctrl_cfg_s ren;	/* Ramp Enable */
     41	struct rsnd_kctrl_cfg_s rup;	/* Ramp Rate Up */
     42	struct rsnd_kctrl_cfg_s rdown;	/* Ramp Rate Down */
     43};
     44
     45#define rsnd_dvc_get(priv, id) ((struct rsnd_dvc *)(priv->dvc) + id)
     46#define rsnd_dvc_nr(priv) ((priv)->dvc_nr)
     47
     48#define rsnd_mod_to_dvc(_mod)	\
     49	container_of((_mod), struct rsnd_dvc, mod)
     50
     51#define for_each_rsnd_dvc(pos, priv, i)				\
     52	for ((i) = 0;						\
     53	     ((i) < rsnd_dvc_nr(priv)) &&			\
     54	     ((pos) = (struct rsnd_dvc *)(priv)->dvc + i);	\
     55	     i++)
     56
     57static void rsnd_dvc_activation(struct rsnd_mod *mod)
     58{
     59	rsnd_mod_write(mod, DVC_SWRSR, 0);
     60	rsnd_mod_write(mod, DVC_SWRSR, 1);
     61}
     62
     63static void rsnd_dvc_halt(struct rsnd_mod *mod)
     64{
     65	rsnd_mod_write(mod, DVC_DVUIR, 1);
     66	rsnd_mod_write(mod, DVC_SWRSR, 0);
     67}
     68
     69#define rsnd_dvc_get_vrpdr(dvc) (rsnd_kctrl_vals(dvc->rup) << 8 | \
     70				 rsnd_kctrl_vals(dvc->rdown))
     71#define rsnd_dvc_get_vrdbr(dvc) (0x3ff - (rsnd_kctrl_valm(dvc->volume, 0) >> 13))
     72
     73static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io,
     74					      struct rsnd_mod *mod)
     75{
     76	struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
     77	u32 val[RSND_MAX_CHANNELS];
     78	int i;
     79
     80	/* Enable Ramp */
     81	if (rsnd_kctrl_vals(dvc->ren))
     82		for (i = 0; i < RSND_MAX_CHANNELS; i++)
     83			val[i] = rsnd_kctrl_max(dvc->volume);
     84	else
     85		for (i = 0; i < RSND_MAX_CHANNELS; i++)
     86			val[i] = rsnd_kctrl_valm(dvc->volume, i);
     87
     88	/* Enable Digital Volume */
     89	for (i = 0; i < RSND_MAX_CHANNELS; i++)
     90		rsnd_mod_write(mod, DVC_VOLxR(i), val[i]);
     91}
     92
     93static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io,
     94				 struct rsnd_mod *mod)
     95{
     96	struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
     97	u32 adinr = 0;
     98	u32 dvucr = 0;
     99	u32 vrctr = 0;
    100	u32 vrpdr = 0;
    101	u32 vrdbr = 0;
    102
    103	adinr = rsnd_get_adinr_bit(mod, io) |
    104		rsnd_runtime_channel_after_ctu(io);
    105
    106	/* Enable Digital Volume, Zero Cross Mute Mode */
    107	dvucr |= 0x101;
    108
    109	/* Enable Ramp */
    110	if (rsnd_kctrl_vals(dvc->ren)) {
    111		dvucr |= 0x10;
    112
    113		/*
    114		 * FIXME !!
    115		 * use scale-downed Digital Volume
    116		 * as Volume Ramp
    117		 * 7F FFFF -> 3FF
    118		 */
    119		vrctr = 0xff;
    120		vrpdr = rsnd_dvc_get_vrpdr(dvc);
    121		vrdbr = rsnd_dvc_get_vrdbr(dvc);
    122	}
    123
    124	/* Initialize operation */
    125	rsnd_mod_write(mod, DVC_DVUIR, 1);
    126
    127	/* General Information */
    128	rsnd_mod_write(mod, DVC_ADINR, adinr);
    129	rsnd_mod_write(mod, DVC_DVUCR, dvucr);
    130
    131	/* Volume Ramp Parameter */
    132	rsnd_mod_write(mod, DVC_VRCTR, vrctr);
    133	rsnd_mod_write(mod, DVC_VRPDR, vrpdr);
    134	rsnd_mod_write(mod, DVC_VRDBR, vrdbr);
    135
    136	/* Digital Volume Function Parameter */
    137	rsnd_dvc_volume_parameter(io, mod);
    138
    139	/* cancel operation */
    140	rsnd_mod_write(mod, DVC_DVUIR, 0);
    141}
    142
    143static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io,
    144				   struct rsnd_mod *mod)
    145{
    146	struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
    147	u32 zcmcr = 0;
    148	u32 vrpdr = 0;
    149	u32 vrdbr = 0;
    150	int i;
    151
    152	for (i = 0; i < rsnd_kctrl_size(dvc->mute); i++)
    153		zcmcr |= (!!rsnd_kctrl_valm(dvc->mute, i)) << i;
    154
    155	if (rsnd_kctrl_vals(dvc->ren)) {
    156		vrpdr = rsnd_dvc_get_vrpdr(dvc);
    157		vrdbr = rsnd_dvc_get_vrdbr(dvc);
    158	}
    159
    160	/* Disable DVC Register access */
    161	rsnd_mod_write(mod, DVC_DVUER, 0);
    162
    163	/* Zero Cross Mute Function */
    164	rsnd_mod_write(mod, DVC_ZCMCR, zcmcr);
    165
    166	/* Volume Ramp Function */
    167	rsnd_mod_write(mod, DVC_VRPDR, vrpdr);
    168	rsnd_mod_write(mod, DVC_VRDBR, vrdbr);
    169	/* add DVC_VRWTR here */
    170
    171	/* Digital Volume Function Parameter */
    172	rsnd_dvc_volume_parameter(io, mod);
    173
    174	/* Enable DVC Register access */
    175	rsnd_mod_write(mod, DVC_DVUER, 1);
    176}
    177
    178static int rsnd_dvc_probe_(struct rsnd_mod *mod,
    179			   struct rsnd_dai_stream *io,
    180			   struct rsnd_priv *priv)
    181{
    182	return rsnd_cmd_attach(io, rsnd_mod_id(mod));
    183}
    184
    185static int rsnd_dvc_init(struct rsnd_mod *mod,
    186			 struct rsnd_dai_stream *io,
    187			 struct rsnd_priv *priv)
    188{
    189	rsnd_mod_power_on(mod);
    190
    191	rsnd_dvc_activation(mod);
    192
    193	rsnd_dvc_volume_init(io, mod);
    194
    195	rsnd_dvc_volume_update(io, mod);
    196
    197	return 0;
    198}
    199
    200static int rsnd_dvc_quit(struct rsnd_mod *mod,
    201			 struct rsnd_dai_stream *io,
    202			 struct rsnd_priv *priv)
    203{
    204	rsnd_dvc_halt(mod);
    205
    206	rsnd_mod_power_off(mod);
    207
    208	return 0;
    209}
    210
    211static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
    212			    struct rsnd_dai_stream *io,
    213			    struct snd_soc_pcm_runtime *rtd)
    214{
    215	struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
    216	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
    217	int is_play = rsnd_io_is_play(io);
    218	int channels = rsnd_rdai_channels_get(rdai);
    219	int ret;
    220
    221	/* Volume */
    222	ret = rsnd_kctrl_new_m(mod, io, rtd,
    223			is_play ?
    224			"DVC Out Playback Volume" : "DVC In Capture Volume",
    225			rsnd_kctrl_accept_anytime,
    226			rsnd_dvc_volume_update,
    227			&dvc->volume, channels,
    228			0x00800000 - 1);
    229	if (ret < 0)
    230		return ret;
    231
    232	/* Mute */
    233	ret = rsnd_kctrl_new_m(mod, io, rtd,
    234			is_play ?
    235			"DVC Out Mute Switch" : "DVC In Mute Switch",
    236			rsnd_kctrl_accept_anytime,
    237			rsnd_dvc_volume_update,
    238			&dvc->mute, channels,
    239			1);
    240	if (ret < 0)
    241		return ret;
    242
    243	/* Ramp */
    244	ret = rsnd_kctrl_new_s(mod, io, rtd,
    245			is_play ?
    246			"DVC Out Ramp Switch" : "DVC In Ramp Switch",
    247			rsnd_kctrl_accept_anytime,
    248			rsnd_dvc_volume_update,
    249			&dvc->ren, 1);
    250	if (ret < 0)
    251		return ret;
    252
    253	ret = rsnd_kctrl_new_e(mod, io, rtd,
    254			is_play ?
    255			"DVC Out Ramp Up Rate" : "DVC In Ramp Up Rate",
    256			rsnd_kctrl_accept_anytime,
    257			rsnd_dvc_volume_update,
    258			&dvc->rup,
    259			volume_ramp_rate,
    260			VOLUME_RAMP_MAX_DVC);
    261	if (ret < 0)
    262		return ret;
    263
    264	ret = rsnd_kctrl_new_e(mod, io, rtd,
    265			is_play ?
    266			"DVC Out Ramp Down Rate" : "DVC In Ramp Down Rate",
    267			rsnd_kctrl_accept_anytime,
    268			rsnd_dvc_volume_update,
    269			&dvc->rdown,
    270			volume_ramp_rate,
    271			VOLUME_RAMP_MAX_DVC);
    272
    273	if (ret < 0)
    274		return ret;
    275
    276	return 0;
    277}
    278
    279static struct dma_chan *rsnd_dvc_dma_req(struct rsnd_dai_stream *io,
    280					 struct rsnd_mod *mod)
    281{
    282	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
    283
    284	return rsnd_dma_request_channel(rsnd_dvc_of_node(priv),
    285					DVC_NAME, mod, "tx");
    286}
    287
    288#ifdef CONFIG_DEBUG_FS
    289static void rsnd_dvc_debug_info(struct seq_file *m,
    290				struct rsnd_dai_stream *io,
    291				struct rsnd_mod *mod)
    292{
    293	rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU,
    294				  0xe00 + rsnd_mod_id(mod) * 0x100, 0x60);
    295}
    296#define DEBUG_INFO .debug_info = rsnd_dvc_debug_info
    297#else
    298#define DEBUG_INFO
    299#endif
    300
    301static struct rsnd_mod_ops rsnd_dvc_ops = {
    302	.name		= DVC_NAME,
    303	.dma_req	= rsnd_dvc_dma_req,
    304	.probe		= rsnd_dvc_probe_,
    305	.init		= rsnd_dvc_init,
    306	.quit		= rsnd_dvc_quit,
    307	.pcm_new	= rsnd_dvc_pcm_new,
    308	.get_status	= rsnd_mod_get_status,
    309	DEBUG_INFO
    310};
    311
    312struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id)
    313{
    314	if (WARN_ON(id < 0 || id >= rsnd_dvc_nr(priv)))
    315		id = 0;
    316
    317	return rsnd_mod_get(rsnd_dvc_get(priv, id));
    318}
    319
    320int rsnd_dvc_probe(struct rsnd_priv *priv)
    321{
    322	struct device_node *node;
    323	struct device_node *np;
    324	struct device *dev = rsnd_priv_to_dev(priv);
    325	struct rsnd_dvc *dvc;
    326	struct clk *clk;
    327	char name[RSND_DVC_NAME_SIZE];
    328	int i, nr, ret;
    329
    330	/* This driver doesn't support Gen1 at this point */
    331	if (rsnd_is_gen1(priv))
    332		return 0;
    333
    334	node = rsnd_dvc_of_node(priv);
    335	if (!node)
    336		return 0; /* not used is not error */
    337
    338	nr = of_get_child_count(node);
    339	if (!nr) {
    340		ret = -EINVAL;
    341		goto rsnd_dvc_probe_done;
    342	}
    343
    344	dvc	= devm_kcalloc(dev, nr, sizeof(*dvc), GFP_KERNEL);
    345	if (!dvc) {
    346		ret = -ENOMEM;
    347		goto rsnd_dvc_probe_done;
    348	}
    349
    350	priv->dvc_nr	= nr;
    351	priv->dvc	= dvc;
    352
    353	i = 0;
    354	ret = 0;
    355	for_each_child_of_node(node, np) {
    356		dvc = rsnd_dvc_get(priv, i);
    357
    358		snprintf(name, RSND_DVC_NAME_SIZE, "%s.%d",
    359			 DVC_NAME, i);
    360
    361		clk = devm_clk_get(dev, name);
    362		if (IS_ERR(clk)) {
    363			ret = PTR_ERR(clk);
    364			of_node_put(np);
    365			goto rsnd_dvc_probe_done;
    366		}
    367
    368		ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops,
    369				    clk, RSND_MOD_DVC, i);
    370		if (ret) {
    371			of_node_put(np);
    372			goto rsnd_dvc_probe_done;
    373		}
    374
    375		i++;
    376	}
    377
    378rsnd_dvc_probe_done:
    379	of_node_put(node);
    380
    381	return ret;
    382}
    383
    384void rsnd_dvc_remove(struct rsnd_priv *priv)
    385{
    386	struct rsnd_dvc *dvc;
    387	int i;
    388
    389	for_each_rsnd_dvc(dvc, priv, i) {
    390		rsnd_mod_quit(rsnd_mod_get(dvc));
    391	}
    392}