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

aiu.c (9293B)


      1// SPDX-License-Identifier: GPL-2.0
      2//
      3// Copyright (c) 2020 BayLibre, SAS.
      4// Author: Jerome Brunet <jbrunet@baylibre.com>
      5
      6#include <linux/bitfield.h>
      7#include <linux/clk.h>
      8#include <linux/module.h>
      9#include <linux/of_platform.h>
     10#include <linux/regmap.h>
     11#include <linux/reset.h>
     12#include <sound/soc.h>
     13#include <sound/soc-dai.h>
     14
     15#include <dt-bindings/sound/meson-aiu.h>
     16#include "aiu.h"
     17#include "aiu-fifo.h"
     18
     19#define AIU_I2S_MISC_958_SRC_SHIFT 3
     20
     21static const char * const aiu_spdif_encode_sel_texts[] = {
     22	"SPDIF", "I2S",
     23};
     24
     25static SOC_ENUM_SINGLE_DECL(aiu_spdif_encode_sel_enum, AIU_I2S_MISC,
     26			    AIU_I2S_MISC_958_SRC_SHIFT,
     27			    aiu_spdif_encode_sel_texts);
     28
     29static const struct snd_kcontrol_new aiu_spdif_encode_mux =
     30	SOC_DAPM_ENUM("SPDIF Buffer Src", aiu_spdif_encode_sel_enum);
     31
     32static const struct snd_soc_dapm_widget aiu_cpu_dapm_widgets[] = {
     33	SND_SOC_DAPM_MUX("SPDIF SRC SEL", SND_SOC_NOPM, 0, 0,
     34			 &aiu_spdif_encode_mux),
     35};
     36
     37static const struct snd_soc_dapm_route aiu_cpu_dapm_routes[] = {
     38	{ "I2S Encoder Playback", NULL, "I2S FIFO Playback" },
     39	{ "SPDIF SRC SEL", "SPDIF", "SPDIF FIFO Playback" },
     40	{ "SPDIF SRC SEL", "I2S", "I2S FIFO Playback" },
     41	{ "SPDIF Encoder Playback", NULL, "SPDIF SRC SEL" },
     42};
     43
     44int aiu_of_xlate_dai_name(struct snd_soc_component *component,
     45			  const struct of_phandle_args *args,
     46			  const char **dai_name,
     47			  unsigned int component_id)
     48{
     49	struct snd_soc_dai *dai;
     50	int id;
     51
     52	if (args->args_count != 2)
     53		return -EINVAL;
     54
     55	if (args->args[0] != component_id)
     56		return -EINVAL;
     57
     58	id = args->args[1];
     59
     60	if (id < 0 || id >= component->num_dai)
     61		return -EINVAL;
     62
     63	for_each_component_dais(component, dai) {
     64		if (id == 0)
     65			break;
     66		id--;
     67	}
     68
     69	*dai_name = dai->driver->name;
     70
     71	return 0;
     72}
     73
     74static int aiu_cpu_of_xlate_dai_name(struct snd_soc_component *component,
     75				     const struct of_phandle_args *args,
     76				     const char **dai_name)
     77{
     78	return aiu_of_xlate_dai_name(component, args, dai_name, AIU_CPU);
     79}
     80
     81static int aiu_cpu_component_probe(struct snd_soc_component *component)
     82{
     83	struct aiu *aiu = snd_soc_component_get_drvdata(component);
     84
     85	/* Required for the SPDIF Source control operation */
     86	return clk_prepare_enable(aiu->i2s.clks[PCLK].clk);
     87}
     88
     89static void aiu_cpu_component_remove(struct snd_soc_component *component)
     90{
     91	struct aiu *aiu = snd_soc_component_get_drvdata(component);
     92
     93	clk_disable_unprepare(aiu->i2s.clks[PCLK].clk);
     94}
     95
     96static const struct snd_soc_component_driver aiu_cpu_component = {
     97	.name			= "AIU CPU",
     98	.dapm_widgets		= aiu_cpu_dapm_widgets,
     99	.num_dapm_widgets	= ARRAY_SIZE(aiu_cpu_dapm_widgets),
    100	.dapm_routes		= aiu_cpu_dapm_routes,
    101	.num_dapm_routes	= ARRAY_SIZE(aiu_cpu_dapm_routes),
    102	.of_xlate_dai_name	= aiu_cpu_of_xlate_dai_name,
    103	.pointer		= aiu_fifo_pointer,
    104	.probe			= aiu_cpu_component_probe,
    105	.remove			= aiu_cpu_component_remove,
    106#ifdef CONFIG_DEBUG_FS
    107	.debugfs_prefix		= "cpu",
    108#endif
    109};
    110
    111static struct snd_soc_dai_driver aiu_cpu_dai_drv[] = {
    112	[CPU_I2S_FIFO] = {
    113		.name = "I2S FIFO",
    114		.playback = {
    115			.stream_name	= "I2S FIFO Playback",
    116			.channels_min	= 2,
    117			.channels_max	= 8,
    118			.rates		= SNDRV_PCM_RATE_CONTINUOUS,
    119			.rate_min	= 5512,
    120			.rate_max	= 192000,
    121			.formats	= AIU_FORMATS,
    122		},
    123		.ops		= &aiu_fifo_i2s_dai_ops,
    124		.pcm_new	= aiu_fifo_pcm_new,
    125		.probe		= aiu_fifo_i2s_dai_probe,
    126		.remove		= aiu_fifo_dai_remove,
    127	},
    128	[CPU_SPDIF_FIFO] = {
    129		.name = "SPDIF FIFO",
    130		.playback = {
    131			.stream_name	= "SPDIF FIFO Playback",
    132			.channels_min	= 2,
    133			.channels_max	= 2,
    134			.rates		= SNDRV_PCM_RATE_CONTINUOUS,
    135			.rate_min	= 5512,
    136			.rate_max	= 192000,
    137			.formats	= AIU_FORMATS,
    138		},
    139		.ops		= &aiu_fifo_spdif_dai_ops,
    140		.pcm_new	= aiu_fifo_pcm_new,
    141		.probe		= aiu_fifo_spdif_dai_probe,
    142		.remove		= aiu_fifo_dai_remove,
    143	},
    144	[CPU_I2S_ENCODER] = {
    145		.name = "I2S Encoder",
    146		.playback = {
    147			.stream_name = "I2S Encoder Playback",
    148			.channels_min = 2,
    149			.channels_max = 8,
    150			.rates = SNDRV_PCM_RATE_8000_192000,
    151			.formats = AIU_FORMATS,
    152		},
    153		.ops = &aiu_encoder_i2s_dai_ops,
    154	},
    155	[CPU_SPDIF_ENCODER] = {
    156		.name = "SPDIF Encoder",
    157		.playback = {
    158			.stream_name = "SPDIF Encoder Playback",
    159			.channels_min = 2,
    160			.channels_max = 2,
    161			.rates = (SNDRV_PCM_RATE_32000  |
    162				  SNDRV_PCM_RATE_44100  |
    163				  SNDRV_PCM_RATE_48000  |
    164				  SNDRV_PCM_RATE_88200  |
    165				  SNDRV_PCM_RATE_96000  |
    166				  SNDRV_PCM_RATE_176400 |
    167				  SNDRV_PCM_RATE_192000),
    168			.formats = AIU_FORMATS,
    169		},
    170		.ops = &aiu_encoder_spdif_dai_ops,
    171	}
    172};
    173
    174static const struct regmap_config aiu_regmap_cfg = {
    175	.reg_bits	= 32,
    176	.val_bits	= 32,
    177	.reg_stride	= 4,
    178	.max_register	= 0x2ac,
    179};
    180
    181static int aiu_clk_bulk_get(struct device *dev,
    182			    const char * const *ids,
    183			    unsigned int num,
    184			    struct aiu_interface *interface)
    185{
    186	struct clk_bulk_data *clks;
    187	int i, ret;
    188
    189	clks = devm_kcalloc(dev, num, sizeof(*clks), GFP_KERNEL);
    190	if (!clks)
    191		return -ENOMEM;
    192
    193	for (i = 0; i < num; i++)
    194		clks[i].id = ids[i];
    195
    196	ret = devm_clk_bulk_get(dev, num, clks);
    197	if (ret < 0)
    198		return ret;
    199
    200	interface->clks = clks;
    201	interface->clk_num = num;
    202	return 0;
    203}
    204
    205static const char * const aiu_i2s_ids[] = {
    206	[PCLK]	= "i2s_pclk",
    207	[AOCLK]	= "i2s_aoclk",
    208	[MCLK]	= "i2s_mclk",
    209	[MIXER]	= "i2s_mixer",
    210};
    211
    212static const char * const aiu_spdif_ids[] = {
    213	[PCLK]	= "spdif_pclk",
    214	[AOCLK]	= "spdif_aoclk",
    215	[MCLK]	= "spdif_mclk_sel"
    216};
    217
    218static int aiu_clk_get(struct device *dev)
    219{
    220	struct aiu *aiu = dev_get_drvdata(dev);
    221	int ret;
    222
    223	aiu->pclk = devm_clk_get(dev, "pclk");
    224	if (IS_ERR(aiu->pclk))
    225		return dev_err_probe(dev, PTR_ERR(aiu->pclk), "Can't get the aiu pclk\n");
    226
    227	aiu->spdif_mclk = devm_clk_get(dev, "spdif_mclk");
    228	if (IS_ERR(aiu->spdif_mclk))
    229		return dev_err_probe(dev, PTR_ERR(aiu->spdif_mclk),
    230				     "Can't get the aiu spdif master clock\n");
    231
    232	ret = aiu_clk_bulk_get(dev, aiu_i2s_ids, ARRAY_SIZE(aiu_i2s_ids),
    233			       &aiu->i2s);
    234	if (ret)
    235		return dev_err_probe(dev, ret, "Can't get the i2s clocks\n");
    236
    237	ret = aiu_clk_bulk_get(dev, aiu_spdif_ids, ARRAY_SIZE(aiu_spdif_ids),
    238			       &aiu->spdif);
    239	if (ret)
    240		return dev_err_probe(dev, ret, "Can't get the spdif clocks\n");
    241
    242	ret = clk_prepare_enable(aiu->pclk);
    243	if (ret) {
    244		dev_err(dev, "peripheral clock enable failed\n");
    245		return ret;
    246	}
    247
    248	ret = devm_add_action_or_reset(dev,
    249				       (void(*)(void *))clk_disable_unprepare,
    250				       aiu->pclk);
    251	if (ret)
    252		dev_err(dev, "failed to add reset action on pclk");
    253
    254	return ret;
    255}
    256
    257static int aiu_probe(struct platform_device *pdev)
    258{
    259	struct device *dev = &pdev->dev;
    260	void __iomem *regs;
    261	struct regmap *map;
    262	struct aiu *aiu;
    263	int ret;
    264
    265	aiu = devm_kzalloc(dev, sizeof(*aiu), GFP_KERNEL);
    266	if (!aiu)
    267		return -ENOMEM;
    268
    269	aiu->platform = device_get_match_data(dev);
    270	if (!aiu->platform)
    271		return -ENODEV;
    272
    273	platform_set_drvdata(pdev, aiu);
    274
    275	ret = device_reset(dev);
    276	if (ret)
    277		return dev_err_probe(dev, ret, "Failed to reset device\n");
    278
    279	regs = devm_platform_ioremap_resource(pdev, 0);
    280	if (IS_ERR(regs))
    281		return PTR_ERR(regs);
    282
    283	map = devm_regmap_init_mmio(dev, regs, &aiu_regmap_cfg);
    284	if (IS_ERR(map)) {
    285		dev_err(dev, "failed to init regmap: %ld\n",
    286			PTR_ERR(map));
    287		return PTR_ERR(map);
    288	}
    289
    290	aiu->i2s.irq = platform_get_irq_byname(pdev, "i2s");
    291	if (aiu->i2s.irq < 0)
    292		return aiu->i2s.irq;
    293
    294	aiu->spdif.irq = platform_get_irq_byname(pdev, "spdif");
    295	if (aiu->spdif.irq < 0)
    296		return aiu->spdif.irq;
    297
    298	ret = aiu_clk_get(dev);
    299	if (ret)
    300		return ret;
    301
    302	/* Register the cpu component of the aiu */
    303	ret = snd_soc_register_component(dev, &aiu_cpu_component,
    304					 aiu_cpu_dai_drv,
    305					 ARRAY_SIZE(aiu_cpu_dai_drv));
    306	if (ret) {
    307		dev_err(dev, "Failed to register cpu component\n");
    308		return ret;
    309	}
    310
    311	/* Register the hdmi codec control component */
    312	ret = aiu_hdmi_ctrl_register_component(dev);
    313	if (ret) {
    314		dev_err(dev, "Failed to register hdmi control component\n");
    315		goto err;
    316	}
    317
    318	/* Register the internal dac control component on gxl */
    319	if (aiu->platform->has_acodec) {
    320		ret = aiu_acodec_ctrl_register_component(dev);
    321		if (ret) {
    322			dev_err(dev,
    323			    "Failed to register acodec control component\n");
    324			goto err;
    325		}
    326	}
    327
    328	return 0;
    329err:
    330	snd_soc_unregister_component(dev);
    331	return ret;
    332}
    333
    334static int aiu_remove(struct platform_device *pdev)
    335{
    336	snd_soc_unregister_component(&pdev->dev);
    337
    338	return 0;
    339}
    340
    341static const struct aiu_platform_data aiu_gxbb_pdata = {
    342	.has_acodec = false,
    343	.has_clk_ctrl_more_i2s_div = true,
    344};
    345
    346static const struct aiu_platform_data aiu_gxl_pdata = {
    347	.has_acodec = true,
    348	.has_clk_ctrl_more_i2s_div = true,
    349};
    350
    351static const struct aiu_platform_data aiu_meson8_pdata = {
    352	.has_acodec = false,
    353	.has_clk_ctrl_more_i2s_div = false,
    354};
    355
    356static const struct of_device_id aiu_of_match[] = {
    357	{ .compatible = "amlogic,aiu-gxbb", .data = &aiu_gxbb_pdata },
    358	{ .compatible = "amlogic,aiu-gxl", .data = &aiu_gxl_pdata },
    359	{ .compatible = "amlogic,aiu-meson8", .data = &aiu_meson8_pdata },
    360	{ .compatible = "amlogic,aiu-meson8b", .data = &aiu_meson8_pdata },
    361	{}
    362};
    363MODULE_DEVICE_TABLE(of, aiu_of_match);
    364
    365static struct platform_driver aiu_pdrv = {
    366	.probe = aiu_probe,
    367	.remove = aiu_remove,
    368	.driver = {
    369		.name = "meson-aiu",
    370		.of_match_table = aiu_of_match,
    371	},
    372};
    373module_platform_driver(aiu_pdrv);
    374
    375MODULE_DESCRIPTION("Meson AIU Driver");
    376MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
    377MODULE_LICENSE("GPL v2");