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

axg-frddr.c (13773B)


      1// SPDX-License-Identifier: (GPL-2.0 OR MIT)
      2//
      3// Copyright (c) 2018 BayLibre, SAS.
      4// Author: Jerome Brunet <jbrunet@baylibre.com>
      5
      6/*
      7 * This driver implements the frontend playback DAI of AXG and G12A based SoCs
      8 */
      9
     10#include <linux/clk.h>
     11#include <linux/regmap.h>
     12#include <linux/module.h>
     13#include <linux/of_platform.h>
     14#include <sound/pcm_params.h>
     15#include <sound/soc.h>
     16#include <sound/soc-dai.h>
     17
     18#include "axg-fifo.h"
     19
     20#define CTRL0_FRDDR_PP_MODE		BIT(30)
     21#define CTRL0_SEL1_EN_SHIFT		3
     22#define CTRL0_SEL2_SHIFT		4
     23#define CTRL0_SEL2_EN_SHIFT		7
     24#define CTRL0_SEL3_SHIFT		8
     25#define CTRL0_SEL3_EN_SHIFT		11
     26#define CTRL1_FRDDR_FORCE_FINISH	BIT(12)
     27#define CTRL2_SEL1_SHIFT		0
     28#define CTRL2_SEL1_EN_SHIFT		4
     29#define CTRL2_SEL2_SHIFT		8
     30#define CTRL2_SEL2_EN_SHIFT		12
     31#define CTRL2_SEL3_SHIFT		16
     32#define CTRL2_SEL3_EN_SHIFT		20
     33
     34static int g12a_frddr_dai_prepare(struct snd_pcm_substream *substream,
     35				  struct snd_soc_dai *dai)
     36{
     37	struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
     38
     39	/* Reset the read pointer to the FIFO_INIT_ADDR */
     40	regmap_update_bits(fifo->map, FIFO_CTRL1,
     41			   CTRL1_FRDDR_FORCE_FINISH, 0);
     42	regmap_update_bits(fifo->map, FIFO_CTRL1,
     43			   CTRL1_FRDDR_FORCE_FINISH, CTRL1_FRDDR_FORCE_FINISH);
     44	regmap_update_bits(fifo->map, FIFO_CTRL1,
     45			   CTRL1_FRDDR_FORCE_FINISH, 0);
     46
     47	return 0;
     48}
     49
     50static int axg_frddr_dai_hw_params(struct snd_pcm_substream *substream,
     51				   struct snd_pcm_hw_params *params,
     52				   struct snd_soc_dai *dai)
     53{
     54	struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
     55	unsigned int period, depth, val;
     56
     57	period = params_period_bytes(params);
     58
     59	/* Trim the FIFO depth if the period is small to improve latency */
     60	depth = min(period, fifo->depth);
     61	val = (depth / AXG_FIFO_BURST) - 1;
     62	regmap_update_bits(fifo->map, FIFO_CTRL1, CTRL1_FRDDR_DEPTH_MASK,
     63			   CTRL1_FRDDR_DEPTH(val));
     64
     65	return 0;
     66}
     67
     68static int axg_frddr_dai_startup(struct snd_pcm_substream *substream,
     69				 struct snd_soc_dai *dai)
     70{
     71	struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
     72	int ret;
     73
     74	/* Enable pclk to access registers and clock the fifo ip */
     75	ret = clk_prepare_enable(fifo->pclk);
     76	if (ret)
     77		return ret;
     78
     79	/* Apply single buffer mode to the interface */
     80	regmap_update_bits(fifo->map, FIFO_CTRL0, CTRL0_FRDDR_PP_MODE, 0);
     81
     82	return 0;
     83}
     84
     85static void axg_frddr_dai_shutdown(struct snd_pcm_substream *substream,
     86				   struct snd_soc_dai *dai)
     87{
     88	struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
     89
     90	clk_disable_unprepare(fifo->pclk);
     91}
     92
     93static int axg_frddr_pcm_new(struct snd_soc_pcm_runtime *rtd,
     94			     struct snd_soc_dai *dai)
     95{
     96	return axg_fifo_pcm_new(rtd, SNDRV_PCM_STREAM_PLAYBACK);
     97}
     98
     99static const struct snd_soc_dai_ops axg_frddr_ops = {
    100	.hw_params	= axg_frddr_dai_hw_params,
    101	.startup	= axg_frddr_dai_startup,
    102	.shutdown	= axg_frddr_dai_shutdown,
    103};
    104
    105static struct snd_soc_dai_driver axg_frddr_dai_drv = {
    106	.name = "FRDDR",
    107	.playback = {
    108		.stream_name	= "Playback",
    109		.channels_min	= 1,
    110		.channels_max	= AXG_FIFO_CH_MAX,
    111		.rates		= AXG_FIFO_RATES,
    112		.formats	= AXG_FIFO_FORMATS,
    113	},
    114	.ops		= &axg_frddr_ops,
    115	.pcm_new	= axg_frddr_pcm_new,
    116};
    117
    118static const char * const axg_frddr_sel_texts[] = {
    119	"OUT 0", "OUT 1", "OUT 2", "OUT 3", "OUT 4", "OUT 5", "OUT 6", "OUT 7",
    120};
    121
    122static SOC_ENUM_SINGLE_DECL(axg_frddr_sel_enum, FIFO_CTRL0, CTRL0_SEL_SHIFT,
    123			    axg_frddr_sel_texts);
    124
    125static const struct snd_kcontrol_new axg_frddr_out_demux =
    126	SOC_DAPM_ENUM("Output Sink", axg_frddr_sel_enum);
    127
    128static const struct snd_soc_dapm_widget axg_frddr_dapm_widgets[] = {
    129	SND_SOC_DAPM_DEMUX("SINK SEL", SND_SOC_NOPM, 0, 0,
    130			   &axg_frddr_out_demux),
    131	SND_SOC_DAPM_AIF_OUT("OUT 0", NULL, 0, SND_SOC_NOPM, 0, 0),
    132	SND_SOC_DAPM_AIF_OUT("OUT 1", NULL, 0, SND_SOC_NOPM, 0, 0),
    133	SND_SOC_DAPM_AIF_OUT("OUT 2", NULL, 0, SND_SOC_NOPM, 0, 0),
    134	SND_SOC_DAPM_AIF_OUT("OUT 3", NULL, 0, SND_SOC_NOPM, 0, 0),
    135	SND_SOC_DAPM_AIF_OUT("OUT 4", NULL, 0, SND_SOC_NOPM, 0, 0),
    136	SND_SOC_DAPM_AIF_OUT("OUT 5", NULL, 0, SND_SOC_NOPM, 0, 0),
    137	SND_SOC_DAPM_AIF_OUT("OUT 6", NULL, 0, SND_SOC_NOPM, 0, 0),
    138	SND_SOC_DAPM_AIF_OUT("OUT 7", NULL, 0, SND_SOC_NOPM, 0, 0),
    139};
    140
    141static const struct snd_soc_dapm_route axg_frddr_dapm_routes[] = {
    142	{ "SINK SEL", NULL, "Playback" },
    143	{ "OUT 0", "OUT 0",  "SINK SEL" },
    144	{ "OUT 1", "OUT 1",  "SINK SEL" },
    145	{ "OUT 2", "OUT 2",  "SINK SEL" },
    146	{ "OUT 3", "OUT 3",  "SINK SEL" },
    147	{ "OUT 4", "OUT 4",  "SINK SEL" },
    148	{ "OUT 5", "OUT 5",  "SINK SEL" },
    149	{ "OUT 6", "OUT 6",  "SINK SEL" },
    150	{ "OUT 7", "OUT 7",  "SINK SEL" },
    151};
    152
    153static const struct snd_soc_component_driver axg_frddr_component_drv = {
    154	.dapm_widgets		= axg_frddr_dapm_widgets,
    155	.num_dapm_widgets	= ARRAY_SIZE(axg_frddr_dapm_widgets),
    156	.dapm_routes		= axg_frddr_dapm_routes,
    157	.num_dapm_routes	= ARRAY_SIZE(axg_frddr_dapm_routes),
    158	.open			= axg_fifo_pcm_open,
    159	.close			= axg_fifo_pcm_close,
    160	.hw_params		= axg_fifo_pcm_hw_params,
    161	.hw_free		= axg_fifo_pcm_hw_free,
    162	.pointer		= axg_fifo_pcm_pointer,
    163	.trigger		= axg_fifo_pcm_trigger,
    164};
    165
    166static const struct axg_fifo_match_data axg_frddr_match_data = {
    167	.field_threshold	= REG_FIELD(FIFO_CTRL1, 16, 23),
    168	.component_drv		= &axg_frddr_component_drv,
    169	.dai_drv		= &axg_frddr_dai_drv
    170};
    171
    172static const struct snd_soc_dai_ops g12a_frddr_ops = {
    173	.prepare	= g12a_frddr_dai_prepare,
    174	.hw_params	= axg_frddr_dai_hw_params,
    175	.startup	= axg_frddr_dai_startup,
    176	.shutdown	= axg_frddr_dai_shutdown,
    177};
    178
    179static struct snd_soc_dai_driver g12a_frddr_dai_drv = {
    180	.name = "FRDDR",
    181	.playback = {
    182		.stream_name	= "Playback",
    183		.channels_min	= 1,
    184		.channels_max	= AXG_FIFO_CH_MAX,
    185		.rates		= AXG_FIFO_RATES,
    186		.formats	= AXG_FIFO_FORMATS,
    187	},
    188	.ops		= &g12a_frddr_ops,
    189	.pcm_new	= axg_frddr_pcm_new,
    190};
    191
    192static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel1_enum, FIFO_CTRL0, CTRL0_SEL_SHIFT,
    193			    axg_frddr_sel_texts);
    194static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel2_enum, FIFO_CTRL0, CTRL0_SEL2_SHIFT,
    195			    axg_frddr_sel_texts);
    196static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel3_enum, FIFO_CTRL0, CTRL0_SEL3_SHIFT,
    197			    axg_frddr_sel_texts);
    198
    199static const struct snd_kcontrol_new g12a_frddr_out1_demux =
    200	SOC_DAPM_ENUM("Output Src 1", g12a_frddr_sel1_enum);
    201static const struct snd_kcontrol_new g12a_frddr_out2_demux =
    202	SOC_DAPM_ENUM("Output Src 2", g12a_frddr_sel2_enum);
    203static const struct snd_kcontrol_new g12a_frddr_out3_demux =
    204	SOC_DAPM_ENUM("Output Src 3", g12a_frddr_sel3_enum);
    205
    206static const struct snd_kcontrol_new g12a_frddr_out1_enable =
    207	SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL0,
    208				    CTRL0_SEL1_EN_SHIFT, 1, 0);
    209static const struct snd_kcontrol_new g12a_frddr_out2_enable =
    210	SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL0,
    211				    CTRL0_SEL2_EN_SHIFT, 1, 0);
    212static const struct snd_kcontrol_new g12a_frddr_out3_enable =
    213	SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL0,
    214				    CTRL0_SEL3_EN_SHIFT, 1, 0);
    215
    216static const struct snd_soc_dapm_widget g12a_frddr_dapm_widgets[] = {
    217	SND_SOC_DAPM_AIF_OUT("SRC 1", NULL, 0, SND_SOC_NOPM, 0, 0),
    218	SND_SOC_DAPM_AIF_OUT("SRC 2", NULL, 0, SND_SOC_NOPM, 0, 0),
    219	SND_SOC_DAPM_AIF_OUT("SRC 3", NULL, 0, SND_SOC_NOPM, 0, 0),
    220	SND_SOC_DAPM_SWITCH("SRC 1 EN", SND_SOC_NOPM, 0, 0,
    221			    &g12a_frddr_out1_enable),
    222	SND_SOC_DAPM_SWITCH("SRC 2 EN", SND_SOC_NOPM, 0, 0,
    223			    &g12a_frddr_out2_enable),
    224	SND_SOC_DAPM_SWITCH("SRC 3 EN", SND_SOC_NOPM, 0, 0,
    225			    &g12a_frddr_out3_enable),
    226	SND_SOC_DAPM_DEMUX("SINK 1 SEL", SND_SOC_NOPM, 0, 0,
    227			   &g12a_frddr_out1_demux),
    228	SND_SOC_DAPM_DEMUX("SINK 2 SEL", SND_SOC_NOPM, 0, 0,
    229			   &g12a_frddr_out2_demux),
    230	SND_SOC_DAPM_DEMUX("SINK 3 SEL", SND_SOC_NOPM, 0, 0,
    231			   &g12a_frddr_out3_demux),
    232	SND_SOC_DAPM_AIF_OUT("OUT 0", NULL, 0, SND_SOC_NOPM, 0, 0),
    233	SND_SOC_DAPM_AIF_OUT("OUT 1", NULL, 0, SND_SOC_NOPM, 0, 0),
    234	SND_SOC_DAPM_AIF_OUT("OUT 2", NULL, 0, SND_SOC_NOPM, 0, 0),
    235	SND_SOC_DAPM_AIF_OUT("OUT 3", NULL, 0, SND_SOC_NOPM, 0, 0),
    236	SND_SOC_DAPM_AIF_OUT("OUT 4", NULL, 0, SND_SOC_NOPM, 0, 0),
    237	SND_SOC_DAPM_AIF_OUT("OUT 5", NULL, 0, SND_SOC_NOPM, 0, 0),
    238	SND_SOC_DAPM_AIF_OUT("OUT 6", NULL, 0, SND_SOC_NOPM, 0, 0),
    239	SND_SOC_DAPM_AIF_OUT("OUT 7", NULL, 0, SND_SOC_NOPM, 0, 0),
    240};
    241
    242static const struct snd_soc_dapm_route g12a_frddr_dapm_routes[] = {
    243	{ "SRC 1", NULL, "Playback" },
    244	{ "SRC 2", NULL, "Playback" },
    245	{ "SRC 3", NULL, "Playback" },
    246	{ "SRC 1 EN", "Switch", "SRC 1" },
    247	{ "SRC 2 EN", "Switch", "SRC 2" },
    248	{ "SRC 3 EN", "Switch", "SRC 3" },
    249	{ "SINK 1 SEL", NULL, "SRC 1 EN" },
    250	{ "SINK 2 SEL", NULL, "SRC 2 EN" },
    251	{ "SINK 3 SEL", NULL, "SRC 3 EN" },
    252	{ "OUT 0", "OUT 0", "SINK 1 SEL" },
    253	{ "OUT 1", "OUT 1", "SINK 1 SEL" },
    254	{ "OUT 2", "OUT 2", "SINK 1 SEL" },
    255	{ "OUT 3", "OUT 3", "SINK 1 SEL" },
    256	{ "OUT 4", "OUT 4", "SINK 1 SEL" },
    257	{ "OUT 5", "OUT 5", "SINK 1 SEL" },
    258	{ "OUT 6", "OUT 6", "SINK 1 SEL" },
    259	{ "OUT 7", "OUT 7", "SINK 1 SEL" },
    260	{ "OUT 0", "OUT 0", "SINK 2 SEL" },
    261	{ "OUT 1", "OUT 1", "SINK 2 SEL" },
    262	{ "OUT 2", "OUT 2", "SINK 2 SEL" },
    263	{ "OUT 3", "OUT 3", "SINK 2 SEL" },
    264	{ "OUT 4", "OUT 4", "SINK 2 SEL" },
    265	{ "OUT 5", "OUT 5", "SINK 2 SEL" },
    266	{ "OUT 6", "OUT 6", "SINK 2 SEL" },
    267	{ "OUT 7", "OUT 7", "SINK 2 SEL" },
    268	{ "OUT 0", "OUT 0", "SINK 3 SEL" },
    269	{ "OUT 1", "OUT 1", "SINK 3 SEL" },
    270	{ "OUT 2", "OUT 2", "SINK 3 SEL" },
    271	{ "OUT 3", "OUT 3", "SINK 3 SEL" },
    272	{ "OUT 4", "OUT 4", "SINK 3 SEL" },
    273	{ "OUT 5", "OUT 5", "SINK 3 SEL" },
    274	{ "OUT 6", "OUT 6", "SINK 3 SEL" },
    275	{ "OUT 7", "OUT 7", "SINK 3 SEL" },
    276};
    277
    278static const struct snd_soc_component_driver g12a_frddr_component_drv = {
    279	.dapm_widgets		= g12a_frddr_dapm_widgets,
    280	.num_dapm_widgets	= ARRAY_SIZE(g12a_frddr_dapm_widgets),
    281	.dapm_routes		= g12a_frddr_dapm_routes,
    282	.num_dapm_routes	= ARRAY_SIZE(g12a_frddr_dapm_routes),
    283	.open			= axg_fifo_pcm_open,
    284	.close			= axg_fifo_pcm_close,
    285	.hw_params		= g12a_fifo_pcm_hw_params,
    286	.hw_free		= axg_fifo_pcm_hw_free,
    287	.pointer		= axg_fifo_pcm_pointer,
    288	.trigger		= axg_fifo_pcm_trigger,
    289};
    290
    291static const struct axg_fifo_match_data g12a_frddr_match_data = {
    292	.field_threshold	= REG_FIELD(FIFO_CTRL1, 16, 23),
    293	.component_drv		= &g12a_frddr_component_drv,
    294	.dai_drv		= &g12a_frddr_dai_drv
    295};
    296
    297/* On SM1, the output selection in on CTRL2 */
    298static const struct snd_kcontrol_new sm1_frddr_out1_enable =
    299	SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL2,
    300				    CTRL2_SEL1_EN_SHIFT, 1, 0);
    301static const struct snd_kcontrol_new sm1_frddr_out2_enable =
    302	SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL2,
    303				    CTRL2_SEL2_EN_SHIFT, 1, 0);
    304static const struct snd_kcontrol_new sm1_frddr_out3_enable =
    305	SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL2,
    306				    CTRL2_SEL3_EN_SHIFT, 1, 0);
    307
    308static SOC_ENUM_SINGLE_DECL(sm1_frddr_sel1_enum, FIFO_CTRL2, CTRL2_SEL1_SHIFT,
    309			    axg_frddr_sel_texts);
    310static SOC_ENUM_SINGLE_DECL(sm1_frddr_sel2_enum, FIFO_CTRL2, CTRL2_SEL2_SHIFT,
    311			    axg_frddr_sel_texts);
    312static SOC_ENUM_SINGLE_DECL(sm1_frddr_sel3_enum, FIFO_CTRL2, CTRL2_SEL3_SHIFT,
    313			    axg_frddr_sel_texts);
    314
    315static const struct snd_kcontrol_new sm1_frddr_out1_demux =
    316	SOC_DAPM_ENUM("Output Src 1", sm1_frddr_sel1_enum);
    317static const struct snd_kcontrol_new sm1_frddr_out2_demux =
    318	SOC_DAPM_ENUM("Output Src 2", sm1_frddr_sel2_enum);
    319static const struct snd_kcontrol_new sm1_frddr_out3_demux =
    320	SOC_DAPM_ENUM("Output Src 3", sm1_frddr_sel3_enum);
    321
    322static const struct snd_soc_dapm_widget sm1_frddr_dapm_widgets[] = {
    323	SND_SOC_DAPM_AIF_OUT("SRC 1", NULL, 0, SND_SOC_NOPM, 0, 0),
    324	SND_SOC_DAPM_AIF_OUT("SRC 2", NULL, 0, SND_SOC_NOPM, 0, 0),
    325	SND_SOC_DAPM_AIF_OUT("SRC 3", NULL, 0, SND_SOC_NOPM, 0, 0),
    326	SND_SOC_DAPM_SWITCH("SRC 1 EN", SND_SOC_NOPM, 0, 0,
    327			    &sm1_frddr_out1_enable),
    328	SND_SOC_DAPM_SWITCH("SRC 2 EN", SND_SOC_NOPM, 0, 0,
    329			    &sm1_frddr_out2_enable),
    330	SND_SOC_DAPM_SWITCH("SRC 3 EN", SND_SOC_NOPM, 0, 0,
    331			    &sm1_frddr_out3_enable),
    332	SND_SOC_DAPM_DEMUX("SINK 1 SEL", SND_SOC_NOPM, 0, 0,
    333			   &sm1_frddr_out1_demux),
    334	SND_SOC_DAPM_DEMUX("SINK 2 SEL", SND_SOC_NOPM, 0, 0,
    335			   &sm1_frddr_out2_demux),
    336	SND_SOC_DAPM_DEMUX("SINK 3 SEL", SND_SOC_NOPM, 0, 0,
    337			   &sm1_frddr_out3_demux),
    338	SND_SOC_DAPM_AIF_OUT("OUT 0", NULL, 0, SND_SOC_NOPM, 0, 0),
    339	SND_SOC_DAPM_AIF_OUT("OUT 1", NULL, 0, SND_SOC_NOPM, 0, 0),
    340	SND_SOC_DAPM_AIF_OUT("OUT 2", NULL, 0, SND_SOC_NOPM, 0, 0),
    341	SND_SOC_DAPM_AIF_OUT("OUT 3", NULL, 0, SND_SOC_NOPM, 0, 0),
    342	SND_SOC_DAPM_AIF_OUT("OUT 4", NULL, 0, SND_SOC_NOPM, 0, 0),
    343	SND_SOC_DAPM_AIF_OUT("OUT 5", NULL, 0, SND_SOC_NOPM, 0, 0),
    344	SND_SOC_DAPM_AIF_OUT("OUT 6", NULL, 0, SND_SOC_NOPM, 0, 0),
    345	SND_SOC_DAPM_AIF_OUT("OUT 7", NULL, 0, SND_SOC_NOPM, 0, 0),
    346};
    347
    348static const struct snd_soc_component_driver sm1_frddr_component_drv = {
    349	.dapm_widgets		= sm1_frddr_dapm_widgets,
    350	.num_dapm_widgets	= ARRAY_SIZE(sm1_frddr_dapm_widgets),
    351	.dapm_routes		= g12a_frddr_dapm_routes,
    352	.num_dapm_routes	= ARRAY_SIZE(g12a_frddr_dapm_routes),
    353	.open			= axg_fifo_pcm_open,
    354	.close			= axg_fifo_pcm_close,
    355	.hw_params		= g12a_fifo_pcm_hw_params,
    356	.hw_free		= axg_fifo_pcm_hw_free,
    357	.pointer		= axg_fifo_pcm_pointer,
    358	.trigger		= axg_fifo_pcm_trigger,
    359};
    360
    361static const struct axg_fifo_match_data sm1_frddr_match_data = {
    362	.field_threshold	= REG_FIELD(FIFO_CTRL1, 16, 23),
    363	.component_drv		= &sm1_frddr_component_drv,
    364	.dai_drv		= &g12a_frddr_dai_drv
    365};
    366
    367static const struct of_device_id axg_frddr_of_match[] = {
    368	{
    369		.compatible = "amlogic,axg-frddr",
    370		.data = &axg_frddr_match_data,
    371	}, {
    372		.compatible = "amlogic,g12a-frddr",
    373		.data = &g12a_frddr_match_data,
    374	}, {
    375		.compatible = "amlogic,sm1-frddr",
    376		.data = &sm1_frddr_match_data,
    377	}, {}
    378};
    379MODULE_DEVICE_TABLE(of, axg_frddr_of_match);
    380
    381static struct platform_driver axg_frddr_pdrv = {
    382	.probe = axg_fifo_probe,
    383	.driver = {
    384		.name = "axg-frddr",
    385		.of_match_table = axg_frddr_of_match,
    386	},
    387};
    388module_platform_driver(axg_frddr_pdrv);
    389
    390MODULE_DESCRIPTION("Amlogic AXG/G12A playback fifo driver");
    391MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
    392MODULE_LICENSE("GPL v2");