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

mix.c (8281B)


      1// SPDX-License-Identifier: GPL-2.0
      2//
      3// mix.c
      4//
      5// Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
      6
      7/*
      8 *		    CTUn	MIXn
      9 *		    +------+	+------+
     10 * [SRC3 / SRC6] -> |CTU n0| ->	[MIX n0| ->
     11 * [SRC4 / SRC9] -> |CTU n1| ->	[MIX n1| ->
     12 * [SRC0 / SRC1] -> |CTU n2| ->	[MIX n2| ->
     13 * [SRC2 / SRC5] -> |CTU n3| ->	[MIX n3| ->
     14 *		    +------+	+------+
     15 *
     16 * ex)
     17 *	DAI0 : playback = <&src0 &ctu02 &mix0 &dvc0 &ssi0>;
     18 *	DAI1 : playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>;
     19 *
     20 * MIX Volume
     21 *	amixer set "MIX",0  100%  // DAI0 Volume
     22 *	amixer set "MIX",1  100%  // DAI1 Volume
     23 *
     24 * Volume Ramp
     25 *	amixer set "MIX Ramp Up Rate"   "0.125 dB/1 step"
     26 *	amixer set "MIX Ramp Down Rate" "4 dB/1 step"
     27 *	amixer set "MIX Ramp" on
     28 *	aplay xxx.wav &
     29 *	amixer set "MIX",0  80%  // DAI0 Volume Down
     30 *	amixer set "MIX",1 100%  // DAI1 Volume Up
     31 */
     32
     33#include "rsnd.h"
     34
     35#define MIX_NAME_SIZE	16
     36#define MIX_NAME "mix"
     37
     38struct rsnd_mix {
     39	struct rsnd_mod mod;
     40	struct rsnd_kctrl_cfg_s volumeA; /* MDBAR */
     41	struct rsnd_kctrl_cfg_s volumeB; /* MDBBR */
     42	struct rsnd_kctrl_cfg_s volumeC; /* MDBCR */
     43	struct rsnd_kctrl_cfg_s volumeD; /* MDBDR */
     44	struct rsnd_kctrl_cfg_s ren;	/* Ramp Enable */
     45	struct rsnd_kctrl_cfg_s rup;	/* Ramp Rate Up */
     46	struct rsnd_kctrl_cfg_s rdw;	/* Ramp Rate Down */
     47	u32 flags;
     48};
     49
     50#define ONCE_KCTRL_INITIALIZED		(1 << 0)
     51#define HAS_VOLA			(1 << 1)
     52#define HAS_VOLB			(1 << 2)
     53#define HAS_VOLC			(1 << 3)
     54#define HAS_VOLD			(1 << 4)
     55
     56#define VOL_MAX				0x3ff
     57
     58#define rsnd_mod_to_mix(_mod)	\
     59	container_of((_mod), struct rsnd_mix, mod)
     60
     61#define rsnd_mix_get(priv, id) ((struct rsnd_mix *)(priv->mix) + id)
     62#define rsnd_mix_nr(priv) ((priv)->mix_nr)
     63#define for_each_rsnd_mix(pos, priv, i)					\
     64	for ((i) = 0;							\
     65	     ((i) < rsnd_mix_nr(priv)) &&				\
     66		     ((pos) = (struct rsnd_mix *)(priv)->mix + i);	\
     67	     i++)
     68
     69static void rsnd_mix_activation(struct rsnd_mod *mod)
     70{
     71	rsnd_mod_write(mod, MIX_SWRSR, 0);
     72	rsnd_mod_write(mod, MIX_SWRSR, 1);
     73}
     74
     75static void rsnd_mix_halt(struct rsnd_mod *mod)
     76{
     77	rsnd_mod_write(mod, MIX_MIXIR, 1);
     78	rsnd_mod_write(mod, MIX_SWRSR, 0);
     79}
     80
     81#define rsnd_mix_get_vol(mix, X) \
     82	rsnd_flags_has(mix, HAS_VOL##X) ? \
     83		(VOL_MAX - rsnd_kctrl_vals(mix->volume##X)) : 0
     84static void rsnd_mix_volume_parameter(struct rsnd_dai_stream *io,
     85				      struct rsnd_mod *mod)
     86{
     87	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
     88	struct device *dev = rsnd_priv_to_dev(priv);
     89	struct rsnd_mix *mix = rsnd_mod_to_mix(mod);
     90	u32 volA = rsnd_mix_get_vol(mix, A);
     91	u32 volB = rsnd_mix_get_vol(mix, B);
     92	u32 volC = rsnd_mix_get_vol(mix, C);
     93	u32 volD = rsnd_mix_get_vol(mix, D);
     94
     95	dev_dbg(dev, "MIX A/B/C/D = %02x/%02x/%02x/%02x\n",
     96		volA, volB, volC, volD);
     97
     98	rsnd_mod_write(mod, MIX_MDBAR, volA);
     99	rsnd_mod_write(mod, MIX_MDBBR, volB);
    100	rsnd_mod_write(mod, MIX_MDBCR, volC);
    101	rsnd_mod_write(mod, MIX_MDBDR, volD);
    102}
    103
    104static void rsnd_mix_volume_init(struct rsnd_dai_stream *io,
    105				 struct rsnd_mod *mod)
    106{
    107	struct rsnd_mix *mix = rsnd_mod_to_mix(mod);
    108
    109	rsnd_mod_write(mod, MIX_MIXIR, 1);
    110
    111	/* General Information */
    112	rsnd_mod_write(mod, MIX_ADINR, rsnd_runtime_channel_after_ctu(io));
    113
    114	/* volume step */
    115	rsnd_mod_write(mod, MIX_MIXMR, rsnd_kctrl_vals(mix->ren));
    116	rsnd_mod_write(mod, MIX_MVPDR, rsnd_kctrl_vals(mix->rup) << 8 |
    117				       rsnd_kctrl_vals(mix->rdw));
    118
    119	/* common volume parameter */
    120	rsnd_mix_volume_parameter(io, mod);
    121
    122	rsnd_mod_write(mod, MIX_MIXIR, 0);
    123}
    124
    125static void rsnd_mix_volume_update(struct rsnd_dai_stream *io,
    126				  struct rsnd_mod *mod)
    127{
    128	/* Disable MIX dB setting */
    129	rsnd_mod_write(mod, MIX_MDBER, 0);
    130
    131	/* common volume parameter */
    132	rsnd_mix_volume_parameter(io, mod);
    133
    134	/* Enable MIX dB setting */
    135	rsnd_mod_write(mod, MIX_MDBER, 1);
    136}
    137
    138static int rsnd_mix_probe_(struct rsnd_mod *mod,
    139			   struct rsnd_dai_stream *io,
    140			   struct rsnd_priv *priv)
    141{
    142	return rsnd_cmd_attach(io, rsnd_mod_id(mod));
    143}
    144
    145static int rsnd_mix_init(struct rsnd_mod *mod,
    146			 struct rsnd_dai_stream *io,
    147			 struct rsnd_priv *priv)
    148{
    149	rsnd_mod_power_on(mod);
    150
    151	rsnd_mix_activation(mod);
    152
    153	rsnd_mix_volume_init(io, mod);
    154
    155	rsnd_mix_volume_update(io, mod);
    156
    157	return 0;
    158}
    159
    160static int rsnd_mix_quit(struct rsnd_mod *mod,
    161			 struct rsnd_dai_stream *io,
    162			 struct rsnd_priv *priv)
    163{
    164	rsnd_mix_halt(mod);
    165
    166	rsnd_mod_power_off(mod);
    167
    168	return 0;
    169}
    170
    171static int rsnd_mix_pcm_new(struct rsnd_mod *mod,
    172			    struct rsnd_dai_stream *io,
    173			    struct snd_soc_pcm_runtime *rtd)
    174{
    175	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
    176	struct device *dev = rsnd_priv_to_dev(priv);
    177	struct rsnd_mix *mix = rsnd_mod_to_mix(mod);
    178	struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io);
    179	struct rsnd_kctrl_cfg_s *volume;
    180	int ret;
    181
    182	switch (rsnd_mod_id(src_mod)) {
    183	case 3:
    184	case 6:	/* MDBAR */
    185		volume = &mix->volumeA;
    186		rsnd_flags_set(mix, HAS_VOLA);
    187		break;
    188	case 4:
    189	case 9:	/* MDBBR */
    190		volume = &mix->volumeB;
    191		rsnd_flags_set(mix, HAS_VOLB);
    192		break;
    193	case 0:
    194	case 1:	/* MDBCR */
    195		volume = &mix->volumeC;
    196		rsnd_flags_set(mix, HAS_VOLC);
    197		break;
    198	case 2:
    199	case 5:	/* MDBDR */
    200		volume = &mix->volumeD;
    201		rsnd_flags_set(mix, HAS_VOLD);
    202		break;
    203	default:
    204		dev_err(dev, "unknown SRC is connected\n");
    205		return -EINVAL;
    206	}
    207
    208	/* Volume */
    209	ret = rsnd_kctrl_new_s(mod, io, rtd,
    210			       "MIX Playback Volume",
    211			       rsnd_kctrl_accept_anytime,
    212			       rsnd_mix_volume_update,
    213			       volume, VOL_MAX);
    214	if (ret < 0)
    215		return ret;
    216	rsnd_kctrl_vals(*volume) = VOL_MAX;
    217
    218	if (rsnd_flags_has(mix, ONCE_KCTRL_INITIALIZED))
    219		return ret;
    220
    221	/* Ramp */
    222	ret = rsnd_kctrl_new_s(mod, io, rtd,
    223			       "MIX Ramp Switch",
    224			       rsnd_kctrl_accept_anytime,
    225			       rsnd_mix_volume_update,
    226			       &mix->ren, 1);
    227	if (ret < 0)
    228		return ret;
    229
    230	ret = rsnd_kctrl_new_e(mod, io, rtd,
    231			       "MIX Ramp Up Rate",
    232			       rsnd_kctrl_accept_anytime,
    233			       rsnd_mix_volume_update,
    234			       &mix->rup,
    235			       volume_ramp_rate,
    236			       VOLUME_RAMP_MAX_MIX);
    237	if (ret < 0)
    238		return ret;
    239
    240	ret = rsnd_kctrl_new_e(mod, io, rtd,
    241			       "MIX Ramp Down Rate",
    242			       rsnd_kctrl_accept_anytime,
    243			       rsnd_mix_volume_update,
    244			       &mix->rdw,
    245			       volume_ramp_rate,
    246			       VOLUME_RAMP_MAX_MIX);
    247
    248	rsnd_flags_set(mix, ONCE_KCTRL_INITIALIZED);
    249
    250	return ret;
    251}
    252
    253#ifdef CONFIG_DEBUG_FS
    254static void rsnd_mix_debug_info(struct seq_file *m,
    255				struct rsnd_dai_stream *io,
    256				struct rsnd_mod *mod)
    257{
    258	rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU,
    259				  0xd00 + rsnd_mod_id(mod) * 0x40, 0x30);
    260}
    261#define DEBUG_INFO .debug_info = rsnd_mix_debug_info
    262#else
    263#define DEBUG_INFO
    264#endif
    265
    266static struct rsnd_mod_ops rsnd_mix_ops = {
    267	.name		= MIX_NAME,
    268	.probe		= rsnd_mix_probe_,
    269	.init		= rsnd_mix_init,
    270	.quit		= rsnd_mix_quit,
    271	.pcm_new	= rsnd_mix_pcm_new,
    272	.get_status	= rsnd_mod_get_status,
    273	DEBUG_INFO
    274};
    275
    276struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id)
    277{
    278	if (WARN_ON(id < 0 || id >= rsnd_mix_nr(priv)))
    279		id = 0;
    280
    281	return rsnd_mod_get(rsnd_mix_get(priv, id));
    282}
    283
    284int rsnd_mix_probe(struct rsnd_priv *priv)
    285{
    286	struct device_node *node;
    287	struct device_node *np;
    288	struct device *dev = rsnd_priv_to_dev(priv);
    289	struct rsnd_mix *mix;
    290	struct clk *clk;
    291	char name[MIX_NAME_SIZE];
    292	int i, nr, ret;
    293
    294	/* This driver doesn't support Gen1 at this point */
    295	if (rsnd_is_gen1(priv))
    296		return 0;
    297
    298	node = rsnd_mix_of_node(priv);
    299	if (!node)
    300		return 0; /* not used is not error */
    301
    302	nr = of_get_child_count(node);
    303	if (!nr) {
    304		ret = -EINVAL;
    305		goto rsnd_mix_probe_done;
    306	}
    307
    308	mix	= devm_kcalloc(dev, nr, sizeof(*mix), GFP_KERNEL);
    309	if (!mix) {
    310		ret = -ENOMEM;
    311		goto rsnd_mix_probe_done;
    312	}
    313
    314	priv->mix_nr	= nr;
    315	priv->mix	= mix;
    316
    317	i = 0;
    318	ret = 0;
    319	for_each_child_of_node(node, np) {
    320		mix = rsnd_mix_get(priv, i);
    321
    322		snprintf(name, MIX_NAME_SIZE, "%s.%d",
    323			 MIX_NAME, i);
    324
    325		clk = devm_clk_get(dev, name);
    326		if (IS_ERR(clk)) {
    327			ret = PTR_ERR(clk);
    328			of_node_put(np);
    329			goto rsnd_mix_probe_done;
    330		}
    331
    332		ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops,
    333				    clk, RSND_MOD_MIX, i);
    334		if (ret) {
    335			of_node_put(np);
    336			goto rsnd_mix_probe_done;
    337		}
    338
    339		i++;
    340	}
    341
    342rsnd_mix_probe_done:
    343	of_node_put(node);
    344
    345	return ret;
    346}
    347
    348void rsnd_mix_remove(struct rsnd_priv *priv)
    349{
    350	struct rsnd_mix *mix;
    351	int i;
    352
    353	for_each_rsnd_mix(mix, priv, i) {
    354		rsnd_mod_quit(rsnd_mod_get(mix));
    355	}
    356}