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

ssiu.c (12849B)


      1// SPDX-License-Identifier: GPL-2.0
      2//
      3// Renesas R-Car SSIU support
      4//
      5// Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
      6
      7#include "rsnd.h"
      8
      9#define SSIU_NAME "ssiu"
     10
     11struct rsnd_ssiu {
     12	struct rsnd_mod mod;
     13	u32 busif_status[8]; /* for BUSIF0 - BUSIF7 */
     14	unsigned int usrcnt;
     15	int id;
     16	int id_sub;
     17};
     18
     19/* SSI_MODE */
     20#define TDM_EXT		(1 << 0)
     21#define TDM_SPLIT	(1 << 8)
     22
     23#define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr)
     24#define rsnd_mod_to_ssiu(_mod) container_of((_mod), struct rsnd_ssiu, mod)
     25#define for_each_rsnd_ssiu(pos, priv, i)				\
     26	for (i = 0;							\
     27	     (i < rsnd_ssiu_nr(priv)) &&				\
     28		     ((pos) = ((struct rsnd_ssiu *)(priv)->ssiu + i));	\
     29	     i++)
     30
     31/*
     32 *	SSI	Gen2		Gen3
     33 *	0	BUSIF0-3	BUSIF0-7
     34 *	1	BUSIF0-3	BUSIF0-7
     35 *	2	BUSIF0-3	BUSIF0-7
     36 *	3	BUSIF0		BUSIF0-7
     37 *	4	BUSIF0		BUSIF0-7
     38 *	5	BUSIF0		BUSIF0
     39 *	6	BUSIF0		BUSIF0
     40 *	7	BUSIF0		BUSIF0
     41 *	8	BUSIF0		BUSIF0
     42 *	9	BUSIF0-3	BUSIF0-7
     43 *	total	22		52
     44 */
     45static const int gen2_id[] = { 0, 4,  8, 12, 13, 14, 15, 16, 17, 18 };
     46static const int gen3_id[] = { 0, 8, 16, 24, 32, 40, 41, 42, 43, 44 };
     47
     48/* enable busif buffer over/under run interrupt. */
     49#define rsnd_ssiu_busif_err_irq_enable(mod)  rsnd_ssiu_busif_err_irq_ctrl(mod, 1)
     50#define rsnd_ssiu_busif_err_irq_disable(mod) rsnd_ssiu_busif_err_irq_ctrl(mod, 0)
     51static void rsnd_ssiu_busif_err_irq_ctrl(struct rsnd_mod *mod, int enable)
     52{
     53	int id = rsnd_mod_id(mod);
     54	int shift, offset;
     55	int i;
     56
     57	switch (id) {
     58	case 0:
     59	case 1:
     60	case 2:
     61	case 3:
     62	case 4:
     63		shift  = id;
     64		offset = 0;
     65		break;
     66	case 9:
     67		shift  = 1;
     68		offset = 1;
     69		break;
     70	}
     71
     72	for (i = 0; i < 4; i++) {
     73		enum rsnd_reg reg = SSI_SYS_INT_ENABLE((i * 2) + offset);
     74		u32 val = 0xf << (shift * 4);
     75		u32 sys_int_enable = rsnd_mod_read(mod, reg);
     76
     77		if (enable)
     78			sys_int_enable |= val;
     79		else
     80			sys_int_enable &= ~val;
     81		rsnd_mod_write(mod, reg, sys_int_enable);
     82	}
     83}
     84
     85bool rsnd_ssiu_busif_err_status_clear(struct rsnd_mod *mod)
     86{
     87	bool error = false;
     88	int id = rsnd_mod_id(mod);
     89	int shift, offset;
     90	int i;
     91
     92	switch (id) {
     93	case 0:
     94	case 1:
     95	case 2:
     96	case 3:
     97	case 4:
     98		shift  = id;
     99		offset = 0;
    100		break;
    101	case 9:
    102		shift  = 1;
    103		offset = 1;
    104		break;
    105	default:
    106		goto out;
    107	}
    108
    109	for (i = 0; i < 4; i++) {
    110		u32 reg = SSI_SYS_STATUS(i * 2) + offset;
    111		u32 status = rsnd_mod_read(mod, reg);
    112		u32 val = 0xf << (shift * 4);
    113
    114		status &= val;
    115		if (status) {
    116			struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
    117			struct device *dev = rsnd_priv_to_dev(priv);
    118
    119			rsnd_print_irq_status(dev, "%s err status : 0x%08x\n",
    120					      rsnd_mod_name(mod), status);
    121			error = true;
    122		}
    123		rsnd_mod_write(mod, reg, val);
    124	}
    125out:
    126	return error;
    127}
    128
    129static u32 *rsnd_ssiu_get_status(struct rsnd_mod *mod,
    130				 struct rsnd_dai_stream *io,
    131				 enum rsnd_mod_type type)
    132{
    133	struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
    134	int busif = rsnd_mod_id_sub(mod);
    135
    136	return &ssiu->busif_status[busif];
    137}
    138
    139static int rsnd_ssiu_init(struct rsnd_mod *mod,
    140			  struct rsnd_dai_stream *io,
    141			  struct rsnd_priv *priv)
    142{
    143	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
    144	u32 ssis = rsnd_ssi_multi_secondaries_runtime(io);
    145	int use_busif = rsnd_ssi_use_busif(io);
    146	int id = rsnd_mod_id(mod);
    147	int is_clk_master = rsnd_rdai_is_clk_master(rdai);
    148	u32 val1, val2;
    149
    150	/* clear status */
    151	rsnd_ssiu_busif_err_status_clear(mod);
    152
    153	/*
    154	 * SSI_MODE0
    155	 */
    156	rsnd_mod_bset(mod, SSI_MODE0, (1 << id), !use_busif << id);
    157
    158	/*
    159	 * SSI_MODE1 / SSI_MODE2
    160	 *
    161	 * FIXME
    162	 * sharing/multi with SSI0 are mainly supported
    163	 */
    164	val1 = rsnd_mod_read(mod, SSI_MODE1);
    165	val2 = rsnd_mod_read(mod, SSI_MODE2);
    166	if (rsnd_ssi_is_pin_sharing(io)) {
    167
    168		ssis |= (1 << id);
    169
    170	} else if (ssis) {
    171		/*
    172		 * Multi SSI
    173		 *
    174		 * set synchronized bit here
    175		 */
    176
    177		/* SSI4 is synchronized with SSI3 */
    178		if (ssis & (1 << 4))
    179			val1 |= (1 << 20);
    180		/* SSI012 are synchronized */
    181		if (ssis == 0x0006)
    182			val1 |= (1 << 4);
    183		/* SSI0129 are synchronized */
    184		if (ssis == 0x0206)
    185			val2 |= (1 << 4);
    186	}
    187
    188	/* SSI1 is sharing pin with SSI0 */
    189	if (ssis & (1 << 1))
    190		val1 |= is_clk_master ? 0x2 : 0x1;
    191
    192	/* SSI2 is sharing pin with SSI0 */
    193	if (ssis & (1 << 2))
    194		val1 |= is_clk_master ?	0x2 << 2 :
    195					0x1 << 2;
    196	/* SSI4 is sharing pin with SSI3 */
    197	if (ssis & (1 << 4))
    198		val1 |= is_clk_master ? 0x2 << 16 :
    199					0x1 << 16;
    200	/* SSI9 is sharing pin with SSI0 */
    201	if (ssis & (1 << 9))
    202		val2 |= is_clk_master ? 0x2 : 0x1;
    203
    204	rsnd_mod_bset(mod, SSI_MODE1, 0x0013001f, val1);
    205	rsnd_mod_bset(mod, SSI_MODE2, 0x00000017, val2);
    206
    207	/*
    208	 * Enable busif buffer over/under run interrupt.
    209	 * It will be handled from ssi.c
    210	 * see
    211	 *	__rsnd_ssi_interrupt()
    212	 */
    213	rsnd_ssiu_busif_err_irq_enable(mod);
    214
    215	return 0;
    216}
    217
    218static int rsnd_ssiu_quit(struct rsnd_mod *mod,
    219			  struct rsnd_dai_stream *io,
    220			  struct rsnd_priv *priv)
    221{
    222	/* disable busif buffer over/under run interrupt. */
    223	rsnd_ssiu_busif_err_irq_disable(mod);
    224
    225	return 0;
    226}
    227
    228static struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = {
    229	.name		= SSIU_NAME,
    230	.init		= rsnd_ssiu_init,
    231	.quit		= rsnd_ssiu_quit,
    232	.get_status	= rsnd_ssiu_get_status,
    233};
    234
    235static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
    236			       struct rsnd_dai_stream *io,
    237			       struct rsnd_priv *priv)
    238{
    239	struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
    240	u32 has_hdmi0 = rsnd_flags_has(io, RSND_STREAM_HDMI0);
    241	u32 has_hdmi1 = rsnd_flags_has(io, RSND_STREAM_HDMI1);
    242	int ret;
    243	u32 mode = 0;
    244
    245	ret = rsnd_ssiu_init(mod, io, priv);
    246	if (ret < 0)
    247		return ret;
    248
    249	ssiu->usrcnt++;
    250
    251	/*
    252	 * TDM Extend/Split Mode
    253	 * see
    254	 *	rsnd_ssi_config_init()
    255	 */
    256	if (rsnd_runtime_is_tdm(io))
    257		mode = TDM_EXT;
    258	else if (rsnd_runtime_is_tdm_split(io))
    259		mode = TDM_SPLIT;
    260
    261	rsnd_mod_write(mod, SSI_MODE, mode);
    262
    263	if (rsnd_ssi_use_busif(io)) {
    264		int id = rsnd_mod_id(mod);
    265		int busif = rsnd_mod_id_sub(mod);
    266		enum rsnd_reg adinr_reg, mode_reg, dalign_reg;
    267
    268		if ((id == 9) && (busif >= 4)) {
    269			adinr_reg = SSI9_BUSIF_ADINR(busif);
    270			mode_reg = SSI9_BUSIF_MODE(busif);
    271			dalign_reg = SSI9_BUSIF_DALIGN(busif);
    272		} else {
    273			adinr_reg = SSI_BUSIF_ADINR(busif);
    274			mode_reg = SSI_BUSIF_MODE(busif);
    275			dalign_reg = SSI_BUSIF_DALIGN(busif);
    276		}
    277
    278		rsnd_mod_write(mod, adinr_reg,
    279			       rsnd_get_adinr_bit(mod, io) |
    280			       (rsnd_io_is_play(io) ?
    281				rsnd_runtime_channel_after_ctu(io) :
    282				rsnd_runtime_channel_original(io)));
    283		rsnd_mod_write(mod, mode_reg,
    284			       rsnd_get_busif_shift(io, mod) | 1);
    285		rsnd_mod_write(mod, dalign_reg,
    286			       rsnd_get_dalign(mod, io));
    287	}
    288
    289	if (has_hdmi0 || has_hdmi1) {
    290		enum rsnd_mod_type rsnd_ssi_array[] = {
    291			RSND_MOD_SSIM1,
    292			RSND_MOD_SSIM2,
    293			RSND_MOD_SSIM3,
    294		};
    295		struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
    296		struct rsnd_mod *pos;
    297		u32 val;
    298		int i;
    299
    300		i = rsnd_mod_id(ssi_mod);
    301
    302		/* output all same SSI as default */
    303		val =	i << 16 |
    304			i << 20 |
    305			i << 24 |
    306			i << 28 |
    307			i;
    308
    309		for_each_rsnd_mod_array(i, pos, io, rsnd_ssi_array) {
    310			int shift = (i * 4) + 20;
    311
    312			val	= (val & ~(0xF << shift)) |
    313				rsnd_mod_id(pos) << shift;
    314		}
    315
    316		if (has_hdmi0)
    317			rsnd_mod_write(mod, HDMI0_SEL, val);
    318		if (has_hdmi1)
    319			rsnd_mod_write(mod, HDMI1_SEL, val);
    320	}
    321
    322	return 0;
    323}
    324
    325static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod,
    326				struct rsnd_dai_stream *io,
    327				struct rsnd_priv *priv)
    328{
    329	int busif = rsnd_mod_id_sub(mod);
    330
    331	if (!rsnd_ssi_use_busif(io))
    332		return 0;
    333
    334	rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 1 << (busif * 4));
    335
    336	if (rsnd_ssi_multi_secondaries_runtime(io))
    337		rsnd_mod_write(mod, SSI_CONTROL, 0x1);
    338
    339	return 0;
    340}
    341
    342static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod,
    343			       struct rsnd_dai_stream *io,
    344			       struct rsnd_priv *priv)
    345{
    346	struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
    347	int busif = rsnd_mod_id_sub(mod);
    348
    349	if (!rsnd_ssi_use_busif(io))
    350		return 0;
    351
    352	rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 0);
    353
    354	if (--ssiu->usrcnt)
    355		return 0;
    356
    357	if (rsnd_ssi_multi_secondaries_runtime(io))
    358		rsnd_mod_write(mod, SSI_CONTROL, 0);
    359
    360	return 0;
    361}
    362
    363static int rsnd_ssiu_id(struct rsnd_mod *mod)
    364{
    365	struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
    366
    367	/* see rsnd_ssiu_probe() */
    368	return ssiu->id;
    369}
    370
    371static int rsnd_ssiu_id_sub(struct rsnd_mod *mod)
    372{
    373	struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
    374
    375	/* see rsnd_ssiu_probe() */
    376	return ssiu->id_sub;
    377}
    378
    379static struct dma_chan *rsnd_ssiu_dma_req(struct rsnd_dai_stream *io,
    380					  struct rsnd_mod *mod)
    381{
    382	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
    383	int is_play = rsnd_io_is_play(io);
    384	char *name;
    385
    386	/*
    387	 * It should use "rcar_sound,ssiu" on DT.
    388	 * But, we need to keep compatibility for old version.
    389	 *
    390	 * If it has "rcar_sound.ssiu", it will be used.
    391	 * If not, "rcar_sound.ssi" will be used.
    392	 * see
    393	 *	rsnd_ssi_dma_req()
    394	 *	rsnd_dma_of_path()
    395	 */
    396
    397	name = is_play ? "rx" : "tx";
    398
    399	return rsnd_dma_request_channel(rsnd_ssiu_of_node(priv),
    400					SSIU_NAME, mod, name);
    401}
    402
    403#ifdef CONFIG_DEBUG_FS
    404static void rsnd_ssiu_debug_info(struct seq_file *m,
    405				 struct rsnd_dai_stream *io,
    406				struct rsnd_mod *mod)
    407{
    408	rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SSIU,
    409				  rsnd_mod_id(mod) * 0x80, 0x80);
    410}
    411#define DEBUG_INFO .debug_info = rsnd_ssiu_debug_info
    412#else
    413#define DEBUG_INFO
    414#endif
    415
    416static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = {
    417	.name		= SSIU_NAME,
    418	.dma_req	= rsnd_ssiu_dma_req,
    419	.init		= rsnd_ssiu_init_gen2,
    420	.start		= rsnd_ssiu_start_gen2,
    421	.stop		= rsnd_ssiu_stop_gen2,
    422	.get_status	= rsnd_ssiu_get_status,
    423	DEBUG_INFO
    424};
    425
    426static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id)
    427{
    428	if (WARN_ON(id < 0 || id >= rsnd_ssiu_nr(priv)))
    429		id = 0;
    430
    431	return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id);
    432}
    433
    434static void rsnd_parse_connect_ssiu_compatible(struct rsnd_priv *priv,
    435					       struct rsnd_dai_stream *io)
    436{
    437	struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
    438	struct rsnd_ssiu *ssiu;
    439	int is_dma_mode;
    440	int i;
    441
    442	if (!ssi_mod)
    443		return;
    444
    445	is_dma_mode = rsnd_ssi_is_dma_mode(ssi_mod);
    446
    447	/* select BUSIF0 */
    448	for_each_rsnd_ssiu(ssiu, priv, i) {
    449		struct rsnd_mod *mod = rsnd_mod_get(ssiu);
    450
    451		if (is_dma_mode &&
    452		    (rsnd_mod_id(ssi_mod) == rsnd_mod_id(mod)) &&
    453		    (rsnd_mod_id_sub(mod) == 0)) {
    454			rsnd_dai_connect(mod, io, mod->type);
    455			return;
    456		}
    457	}
    458}
    459
    460void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai,
    461			     struct device_node *playback,
    462			     struct device_node *capture)
    463{
    464	struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
    465	struct device *dev = rsnd_priv_to_dev(priv);
    466	struct device_node *node = rsnd_ssiu_of_node(priv);
    467	struct rsnd_dai_stream *io_p = &rdai->playback;
    468	struct rsnd_dai_stream *io_c = &rdai->capture;
    469
    470	/* use rcar_sound,ssiu if exist */
    471	if (node) {
    472		struct device_node *np;
    473		int i = 0;
    474
    475		for_each_child_of_node(node, np) {
    476			struct rsnd_mod *mod;
    477
    478			i = rsnd_node_fixed_index(dev, np, SSIU_NAME, i);
    479			if (i < 0) {
    480				of_node_put(np);
    481				break;
    482			}
    483
    484			mod = rsnd_ssiu_mod_get(priv, i);
    485
    486			if (np == playback)
    487				rsnd_dai_connect(mod, io_p, mod->type);
    488			if (np == capture)
    489				rsnd_dai_connect(mod, io_c, mod->type);
    490			i++;
    491		}
    492
    493		of_node_put(node);
    494	}
    495
    496	/* Keep DT compatibility */
    497	if (!rsnd_io_to_mod_ssiu(io_p))
    498		rsnd_parse_connect_ssiu_compatible(priv, io_p);
    499	if (!rsnd_io_to_mod_ssiu(io_c))
    500		rsnd_parse_connect_ssiu_compatible(priv, io_c);
    501}
    502
    503int rsnd_ssiu_probe(struct rsnd_priv *priv)
    504{
    505	struct device *dev = rsnd_priv_to_dev(priv);
    506	struct device_node *node;
    507	struct rsnd_ssiu *ssiu;
    508	struct rsnd_mod_ops *ops;
    509	const int *list = NULL;
    510	int i, nr;
    511
    512	/*
    513	 * Keep DT compatibility.
    514	 * if it has "rcar_sound,ssiu", use it.
    515	 * if not, use "rcar_sound,ssi"
    516	 * see
    517	 *	rsnd_ssiu_bufsif_to_id()
    518	 */
    519	node = rsnd_ssiu_of_node(priv);
    520	if (node)
    521		nr = rsnd_node_count(priv, node, SSIU_NAME);
    522	else
    523		nr = priv->ssi_nr;
    524
    525	if (!nr)
    526		return -EINVAL;
    527
    528	ssiu	= devm_kcalloc(dev, nr, sizeof(*ssiu), GFP_KERNEL);
    529	if (!ssiu)
    530		return -ENOMEM;
    531
    532	priv->ssiu	= ssiu;
    533	priv->ssiu_nr	= nr;
    534
    535	if (rsnd_is_gen1(priv))
    536		ops = &rsnd_ssiu_ops_gen1;
    537	else
    538		ops = &rsnd_ssiu_ops_gen2;
    539
    540	/* Keep compatibility */
    541	nr = 0;
    542	if ((node) &&
    543	    (ops == &rsnd_ssiu_ops_gen2)) {
    544		ops->id		= rsnd_ssiu_id;
    545		ops->id_sub	= rsnd_ssiu_id_sub;
    546
    547		if (rsnd_is_gen2(priv)) {
    548			list	= gen2_id;
    549			nr	= ARRAY_SIZE(gen2_id);
    550		} else if (rsnd_is_gen3(priv)) {
    551			list	= gen3_id;
    552			nr	= ARRAY_SIZE(gen3_id);
    553		} else {
    554			dev_err(dev, "unknown SSIU\n");
    555			return -ENODEV;
    556		}
    557	}
    558
    559	for_each_rsnd_ssiu(ssiu, priv, i) {
    560		int ret;
    561
    562		if (node) {
    563			int j;
    564
    565			/*
    566			 * see
    567			 *	rsnd_ssiu_get_id()
    568			 *	rsnd_ssiu_get_id_sub()
    569			 */
    570			for (j = 0; j < nr; j++) {
    571				if (list[j] > i)
    572					break;
    573				ssiu->id	= j;
    574				ssiu->id_sub	= i - list[ssiu->id];
    575			}
    576		} else {
    577			ssiu->id = i;
    578		}
    579
    580		ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu),
    581				    ops, NULL, RSND_MOD_SSIU, i);
    582		if (ret)
    583			return ret;
    584	}
    585
    586	return 0;
    587}
    588
    589void rsnd_ssiu_remove(struct rsnd_priv *priv)
    590{
    591	struct rsnd_ssiu *ssiu;
    592	int i;
    593
    594	for_each_rsnd_ssiu(ssiu, priv, i) {
    595		rsnd_mod_quit(rsnd_mod_get(ssiu));
    596	}
    597}