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

pruss.c (8698B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * PRU-ICSS platform driver for various TI SoCs
      4 *
      5 * Copyright (C) 2014-2020 Texas Instruments Incorporated - http://www.ti.com/
      6 * Author(s):
      7 *	Suman Anna <s-anna@ti.com>
      8 *	Andrew F. Davis <afd@ti.com>
      9 */
     10
     11#include <linux/clk-provider.h>
     12#include <linux/dma-mapping.h>
     13#include <linux/io.h>
     14#include <linux/mfd/syscon.h>
     15#include <linux/module.h>
     16#include <linux/of_address.h>
     17#include <linux/of_device.h>
     18#include <linux/pm_runtime.h>
     19#include <linux/pruss_driver.h>
     20#include <linux/regmap.h>
     21#include <linux/slab.h>
     22
     23/**
     24 * struct pruss_private_data - PRUSS driver private data
     25 * @has_no_sharedram: flag to indicate the absence of PRUSS Shared Data RAM
     26 * @has_core_mux_clock: flag to indicate the presence of PRUSS core clock
     27 */
     28struct pruss_private_data {
     29	bool has_no_sharedram;
     30	bool has_core_mux_clock;
     31};
     32
     33static void pruss_of_free_clk_provider(void *data)
     34{
     35	struct device_node *clk_mux_np = data;
     36
     37	of_clk_del_provider(clk_mux_np);
     38	of_node_put(clk_mux_np);
     39}
     40
     41static int pruss_clk_mux_setup(struct pruss *pruss, struct clk *clk_mux,
     42			       char *mux_name, struct device_node *clks_np)
     43{
     44	struct device_node *clk_mux_np;
     45	struct device *dev = pruss->dev;
     46	char *clk_mux_name;
     47	unsigned int num_parents;
     48	const char **parent_names;
     49	void __iomem *reg;
     50	u32 reg_offset;
     51	int ret;
     52
     53	clk_mux_np = of_get_child_by_name(clks_np, mux_name);
     54	if (!clk_mux_np) {
     55		dev_err(dev, "%pOF is missing its '%s' node\n", clks_np,
     56			mux_name);
     57		return -ENODEV;
     58	}
     59
     60	num_parents = of_clk_get_parent_count(clk_mux_np);
     61	if (num_parents < 1) {
     62		dev_err(dev, "mux-clock %pOF must have parents\n", clk_mux_np);
     63		ret = -EINVAL;
     64		goto put_clk_mux_np;
     65	}
     66
     67	parent_names = devm_kcalloc(dev, sizeof(*parent_names), num_parents,
     68				    GFP_KERNEL);
     69	if (!parent_names) {
     70		ret = -ENOMEM;
     71		goto put_clk_mux_np;
     72	}
     73
     74	of_clk_parent_fill(clk_mux_np, parent_names, num_parents);
     75
     76	clk_mux_name = devm_kasprintf(dev, GFP_KERNEL, "%s.%pOFn",
     77				      dev_name(dev), clk_mux_np);
     78	if (!clk_mux_name) {
     79		ret = -ENOMEM;
     80		goto put_clk_mux_np;
     81	}
     82
     83	ret = of_property_read_u32(clk_mux_np, "reg", &reg_offset);
     84	if (ret)
     85		goto put_clk_mux_np;
     86
     87	reg = pruss->cfg_base + reg_offset;
     88
     89	clk_mux = clk_register_mux(NULL, clk_mux_name, parent_names,
     90				   num_parents, 0, reg, 0, 1, 0, NULL);
     91	if (IS_ERR(clk_mux)) {
     92		ret = PTR_ERR(clk_mux);
     93		goto put_clk_mux_np;
     94	}
     95
     96	ret = devm_add_action_or_reset(dev, (void(*)(void *))clk_unregister_mux,
     97				       clk_mux);
     98	if (ret) {
     99		dev_err(dev, "failed to add clkmux unregister action %d", ret);
    100		goto put_clk_mux_np;
    101	}
    102
    103	ret = of_clk_add_provider(clk_mux_np, of_clk_src_simple_get, clk_mux);
    104	if (ret)
    105		goto put_clk_mux_np;
    106
    107	ret = devm_add_action_or_reset(dev, pruss_of_free_clk_provider,
    108				       clk_mux_np);
    109	if (ret) {
    110		dev_err(dev, "failed to add clkmux free action %d", ret);
    111		goto put_clk_mux_np;
    112	}
    113
    114	return 0;
    115
    116put_clk_mux_np:
    117	of_node_put(clk_mux_np);
    118	return ret;
    119}
    120
    121static int pruss_clk_init(struct pruss *pruss, struct device_node *cfg_node)
    122{
    123	const struct pruss_private_data *data;
    124	struct device_node *clks_np;
    125	struct device *dev = pruss->dev;
    126	int ret = 0;
    127
    128	data = of_device_get_match_data(dev);
    129
    130	clks_np = of_get_child_by_name(cfg_node, "clocks");
    131	if (!clks_np) {
    132		dev_err(dev, "%pOF is missing its 'clocks' node\n", cfg_node);
    133		return -ENODEV;
    134	}
    135
    136	if (data && data->has_core_mux_clock) {
    137		ret = pruss_clk_mux_setup(pruss, pruss->core_clk_mux,
    138					  "coreclk-mux", clks_np);
    139		if (ret) {
    140			dev_err(dev, "failed to setup coreclk-mux\n");
    141			goto put_clks_node;
    142		}
    143	}
    144
    145	ret = pruss_clk_mux_setup(pruss, pruss->iep_clk_mux, "iepclk-mux",
    146				  clks_np);
    147	if (ret) {
    148		dev_err(dev, "failed to setup iepclk-mux\n");
    149		goto put_clks_node;
    150	}
    151
    152put_clks_node:
    153	of_node_put(clks_np);
    154
    155	return ret;
    156}
    157
    158static struct regmap_config regmap_conf = {
    159	.reg_bits = 32,
    160	.val_bits = 32,
    161	.reg_stride = 4,
    162};
    163
    164static int pruss_cfg_of_init(struct device *dev, struct pruss *pruss)
    165{
    166	struct device_node *np = dev_of_node(dev);
    167	struct device_node *child;
    168	struct resource res;
    169	int ret;
    170
    171	child = of_get_child_by_name(np, "cfg");
    172	if (!child) {
    173		dev_err(dev, "%pOF is missing its 'cfg' node\n", child);
    174		return -ENODEV;
    175	}
    176
    177	if (of_address_to_resource(child, 0, &res)) {
    178		ret = -ENOMEM;
    179		goto node_put;
    180	}
    181
    182	pruss->cfg_base = devm_ioremap(dev, res.start, resource_size(&res));
    183	if (!pruss->cfg_base) {
    184		ret = -ENOMEM;
    185		goto node_put;
    186	}
    187
    188	regmap_conf.name = kasprintf(GFP_KERNEL, "%pOFn@%llx", child,
    189				     (u64)res.start);
    190	regmap_conf.max_register = resource_size(&res) - 4;
    191
    192	pruss->cfg_regmap = devm_regmap_init_mmio(dev, pruss->cfg_base,
    193						  &regmap_conf);
    194	kfree(regmap_conf.name);
    195	if (IS_ERR(pruss->cfg_regmap)) {
    196		dev_err(dev, "regmap_init_mmio failed for cfg, ret = %ld\n",
    197			PTR_ERR(pruss->cfg_regmap));
    198		ret = PTR_ERR(pruss->cfg_regmap);
    199		goto node_put;
    200	}
    201
    202	ret = pruss_clk_init(pruss, child);
    203	if (ret)
    204		dev_err(dev, "pruss_clk_init failed, ret = %d\n", ret);
    205
    206node_put:
    207	of_node_put(child);
    208	return ret;
    209}
    210
    211static int pruss_probe(struct platform_device *pdev)
    212{
    213	struct device *dev = &pdev->dev;
    214	struct device_node *np = dev_of_node(dev);
    215	struct device_node *child;
    216	struct pruss *pruss;
    217	struct resource res;
    218	int ret, i, index;
    219	const struct pruss_private_data *data;
    220	const char *mem_names[PRUSS_MEM_MAX] = { "dram0", "dram1", "shrdram2" };
    221
    222	data = of_device_get_match_data(&pdev->dev);
    223
    224	ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
    225	if (ret) {
    226		dev_err(dev, "failed to set the DMA coherent mask");
    227		return ret;
    228	}
    229
    230	pruss = devm_kzalloc(dev, sizeof(*pruss), GFP_KERNEL);
    231	if (!pruss)
    232		return -ENOMEM;
    233
    234	pruss->dev = dev;
    235
    236	child = of_get_child_by_name(np, "memories");
    237	if (!child) {
    238		dev_err(dev, "%pOF is missing its 'memories' node\n", child);
    239		return -ENODEV;
    240	}
    241
    242	for (i = 0; i < PRUSS_MEM_MAX; i++) {
    243		/*
    244		 * On AM437x one of two PRUSS units don't contain Shared RAM,
    245		 * skip it
    246		 */
    247		if (data && data->has_no_sharedram && i == PRUSS_MEM_SHRD_RAM2)
    248			continue;
    249
    250		index = of_property_match_string(child, "reg-names",
    251						 mem_names[i]);
    252		if (index < 0) {
    253			of_node_put(child);
    254			return index;
    255		}
    256
    257		if (of_address_to_resource(child, index, &res)) {
    258			of_node_put(child);
    259			return -EINVAL;
    260		}
    261
    262		pruss->mem_regions[i].va = devm_ioremap(dev, res.start,
    263							resource_size(&res));
    264		if (!pruss->mem_regions[i].va) {
    265			dev_err(dev, "failed to parse and map memory resource %d %s\n",
    266				i, mem_names[i]);
    267			of_node_put(child);
    268			return -ENOMEM;
    269		}
    270		pruss->mem_regions[i].pa = res.start;
    271		pruss->mem_regions[i].size = resource_size(&res);
    272
    273		dev_dbg(dev, "memory %8s: pa %pa size 0x%zx va %pK\n",
    274			mem_names[i], &pruss->mem_regions[i].pa,
    275			pruss->mem_regions[i].size, pruss->mem_regions[i].va);
    276	}
    277	of_node_put(child);
    278
    279	platform_set_drvdata(pdev, pruss);
    280
    281	pm_runtime_enable(dev);
    282	ret = pm_runtime_resume_and_get(dev);
    283	if (ret < 0) {
    284		dev_err(dev, "couldn't enable module\n");
    285		goto rpm_disable;
    286	}
    287
    288	ret = pruss_cfg_of_init(dev, pruss);
    289	if (ret < 0)
    290		goto rpm_put;
    291
    292	ret = devm_of_platform_populate(dev);
    293	if (ret) {
    294		dev_err(dev, "failed to register child devices\n");
    295		goto rpm_put;
    296	}
    297
    298	return 0;
    299
    300rpm_put:
    301	pm_runtime_put_sync(dev);
    302rpm_disable:
    303	pm_runtime_disable(dev);
    304	return ret;
    305}
    306
    307static int pruss_remove(struct platform_device *pdev)
    308{
    309	struct device *dev = &pdev->dev;
    310
    311	devm_of_platform_depopulate(dev);
    312
    313	pm_runtime_put_sync(dev);
    314	pm_runtime_disable(dev);
    315
    316	return 0;
    317}
    318
    319/* instance-specific driver private data */
    320static const struct pruss_private_data am437x_pruss1_data = {
    321	.has_no_sharedram = false,
    322};
    323
    324static const struct pruss_private_data am437x_pruss0_data = {
    325	.has_no_sharedram = true,
    326};
    327
    328static const struct pruss_private_data am65x_j721e_pruss_data = {
    329	.has_core_mux_clock = true,
    330};
    331
    332static const struct of_device_id pruss_of_match[] = {
    333	{ .compatible = "ti,am3356-pruss" },
    334	{ .compatible = "ti,am4376-pruss0", .data = &am437x_pruss0_data, },
    335	{ .compatible = "ti,am4376-pruss1", .data = &am437x_pruss1_data, },
    336	{ .compatible = "ti,am5728-pruss" },
    337	{ .compatible = "ti,k2g-pruss" },
    338	{ .compatible = "ti,am654-icssg", .data = &am65x_j721e_pruss_data, },
    339	{ .compatible = "ti,j721e-icssg", .data = &am65x_j721e_pruss_data, },
    340	{ .compatible = "ti,am642-icssg", .data = &am65x_j721e_pruss_data, },
    341	{},
    342};
    343MODULE_DEVICE_TABLE(of, pruss_of_match);
    344
    345static struct platform_driver pruss_driver = {
    346	.driver = {
    347		.name = "pruss",
    348		.of_match_table = pruss_of_match,
    349	},
    350	.probe  = pruss_probe,
    351	.remove = pruss_remove,
    352};
    353module_platform_driver(pruss_driver);
    354
    355MODULE_AUTHOR("Suman Anna <s-anna@ti.com>");
    356MODULE_DESCRIPTION("PRU-ICSS Subsystem Driver");
    357MODULE_LICENSE("GPL v2");