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

tegra-gmi.c (8449B)


      1/*
      2 * Driver for NVIDIA Generic Memory Interface
      3 *
      4 * Copyright (C) 2016 Host Mobility AB. All rights reserved.
      5 *
      6 * This file is licensed under the terms of the GNU General Public
      7 * License version 2. This program is licensed "as is" without any
      8 * warranty of any kind, whether express or implied.
      9 */
     10
     11#include <linux/clk.h>
     12#include <linux/delay.h>
     13#include <linux/io.h>
     14#include <linux/module.h>
     15#include <linux/of_device.h>
     16#include <linux/pm_runtime.h>
     17#include <linux/reset.h>
     18
     19#include <soc/tegra/common.h>
     20
     21#define TEGRA_GMI_CONFIG		0x00
     22#define TEGRA_GMI_CONFIG_GO		BIT(31)
     23#define TEGRA_GMI_BUS_WIDTH_32BIT	BIT(30)
     24#define TEGRA_GMI_MUX_MODE		BIT(28)
     25#define TEGRA_GMI_RDY_BEFORE_DATA	BIT(24)
     26#define TEGRA_GMI_RDY_ACTIVE_HIGH	BIT(23)
     27#define TEGRA_GMI_ADV_ACTIVE_HIGH	BIT(22)
     28#define TEGRA_GMI_OE_ACTIVE_HIGH	BIT(21)
     29#define TEGRA_GMI_CS_ACTIVE_HIGH	BIT(20)
     30#define TEGRA_GMI_CS_SELECT(x)		((x & 0x7) << 4)
     31
     32#define TEGRA_GMI_TIMING0		0x10
     33#define TEGRA_GMI_MUXED_WIDTH(x)	((x & 0xf) << 12)
     34#define TEGRA_GMI_HOLD_WIDTH(x)		((x & 0xf) << 8)
     35#define TEGRA_GMI_ADV_WIDTH(x)		((x & 0xf) << 4)
     36#define TEGRA_GMI_CE_WIDTH(x)		(x & 0xf)
     37
     38#define TEGRA_GMI_TIMING1		0x14
     39#define TEGRA_GMI_WE_WIDTH(x)		((x & 0xff) << 16)
     40#define TEGRA_GMI_OE_WIDTH(x)		((x & 0xff) << 8)
     41#define TEGRA_GMI_WAIT_WIDTH(x)		(x & 0xff)
     42
     43#define TEGRA_GMI_MAX_CHIP_SELECT	8
     44
     45struct tegra_gmi {
     46	struct device *dev;
     47	void __iomem *base;
     48	struct clk *clk;
     49	struct reset_control *rst;
     50
     51	u32 snor_config;
     52	u32 snor_timing0;
     53	u32 snor_timing1;
     54};
     55
     56static int tegra_gmi_enable(struct tegra_gmi *gmi)
     57{
     58	int err;
     59
     60	pm_runtime_enable(gmi->dev);
     61	err = pm_runtime_resume_and_get(gmi->dev);
     62	if (err) {
     63		pm_runtime_disable(gmi->dev);
     64		return err;
     65	}
     66
     67	reset_control_assert(gmi->rst);
     68	usleep_range(2000, 4000);
     69	reset_control_deassert(gmi->rst);
     70
     71	writel(gmi->snor_timing0, gmi->base + TEGRA_GMI_TIMING0);
     72	writel(gmi->snor_timing1, gmi->base + TEGRA_GMI_TIMING1);
     73
     74	gmi->snor_config |= TEGRA_GMI_CONFIG_GO;
     75	writel(gmi->snor_config, gmi->base + TEGRA_GMI_CONFIG);
     76
     77	return 0;
     78}
     79
     80static void tegra_gmi_disable(struct tegra_gmi *gmi)
     81{
     82	u32 config;
     83
     84	/* stop GMI operation */
     85	config = readl(gmi->base + TEGRA_GMI_CONFIG);
     86	config &= ~TEGRA_GMI_CONFIG_GO;
     87	writel(config, gmi->base + TEGRA_GMI_CONFIG);
     88
     89	reset_control_assert(gmi->rst);
     90
     91	pm_runtime_put_sync_suspend(gmi->dev);
     92	pm_runtime_force_suspend(gmi->dev);
     93}
     94
     95static int tegra_gmi_parse_dt(struct tegra_gmi *gmi)
     96{
     97	struct device_node *child;
     98	u32 property, ranges[4];
     99	int err;
    100
    101	child = of_get_next_available_child(gmi->dev->of_node, NULL);
    102	if (!child) {
    103		dev_err(gmi->dev, "no child nodes found\n");
    104		return -ENODEV;
    105	}
    106
    107	/*
    108	 * We currently only support one child device due to lack of
    109	 * chip-select address decoding. Which means that we only have one
    110	 * chip-select line from the GMI controller.
    111	 */
    112	if (of_get_child_count(gmi->dev->of_node) > 1)
    113		dev_warn(gmi->dev, "only one child device is supported.");
    114
    115	if (of_property_read_bool(child, "nvidia,snor-data-width-32bit"))
    116		gmi->snor_config |= TEGRA_GMI_BUS_WIDTH_32BIT;
    117
    118	if (of_property_read_bool(child, "nvidia,snor-mux-mode"))
    119		gmi->snor_config |= TEGRA_GMI_MUX_MODE;
    120
    121	if (of_property_read_bool(child, "nvidia,snor-rdy-active-before-data"))
    122		gmi->snor_config |= TEGRA_GMI_RDY_BEFORE_DATA;
    123
    124	if (of_property_read_bool(child, "nvidia,snor-rdy-active-high"))
    125		gmi->snor_config |= TEGRA_GMI_RDY_ACTIVE_HIGH;
    126
    127	if (of_property_read_bool(child, "nvidia,snor-adv-active-high"))
    128		gmi->snor_config |= TEGRA_GMI_ADV_ACTIVE_HIGH;
    129
    130	if (of_property_read_bool(child, "nvidia,snor-oe-active-high"))
    131		gmi->snor_config |= TEGRA_GMI_OE_ACTIVE_HIGH;
    132
    133	if (of_property_read_bool(child, "nvidia,snor-cs-active-high"))
    134		gmi->snor_config |= TEGRA_GMI_CS_ACTIVE_HIGH;
    135
    136	/* Decode the CS# */
    137	err = of_property_read_u32_array(child, "ranges", ranges, 4);
    138	if (err < 0) {
    139		/* Invalid binding */
    140		if (err == -EOVERFLOW) {
    141			dev_err(gmi->dev,
    142				"failed to decode CS: invalid ranges length\n");
    143			goto error_cs;
    144		}
    145
    146		/*
    147		 * If we reach here it means that the child node has an empty
    148		 * ranges or it does not exist at all. Attempt to decode the
    149		 * CS# from the reg property instead.
    150		 */
    151		err = of_property_read_u32(child, "reg", &property);
    152		if (err < 0) {
    153			dev_err(gmi->dev,
    154				"failed to decode CS: no reg property found\n");
    155			goto error_cs;
    156		}
    157	} else {
    158		property = ranges[1];
    159	}
    160
    161	/* Valid chip selects are CS0-CS7 */
    162	if (property >= TEGRA_GMI_MAX_CHIP_SELECT) {
    163		dev_err(gmi->dev, "invalid chip select: %d", property);
    164		err = -EINVAL;
    165		goto error_cs;
    166	}
    167
    168	gmi->snor_config |= TEGRA_GMI_CS_SELECT(property);
    169
    170	/* The default values that are provided below are reset values */
    171	if (!of_property_read_u32(child, "nvidia,snor-muxed-width", &property))
    172		gmi->snor_timing0 |= TEGRA_GMI_MUXED_WIDTH(property);
    173	else
    174		gmi->snor_timing0 |= TEGRA_GMI_MUXED_WIDTH(1);
    175
    176	if (!of_property_read_u32(child, "nvidia,snor-hold-width", &property))
    177		gmi->snor_timing0 |= TEGRA_GMI_HOLD_WIDTH(property);
    178	else
    179		gmi->snor_timing0 |= TEGRA_GMI_HOLD_WIDTH(1);
    180
    181	if (!of_property_read_u32(child, "nvidia,snor-adv-width", &property))
    182		gmi->snor_timing0 |= TEGRA_GMI_ADV_WIDTH(property);
    183	else
    184		gmi->snor_timing0 |= TEGRA_GMI_ADV_WIDTH(1);
    185
    186	if (!of_property_read_u32(child, "nvidia,snor-ce-width", &property))
    187		gmi->snor_timing0 |= TEGRA_GMI_CE_WIDTH(property);
    188	else
    189		gmi->snor_timing0 |= TEGRA_GMI_CE_WIDTH(4);
    190
    191	if (!of_property_read_u32(child, "nvidia,snor-we-width", &property))
    192		gmi->snor_timing1 |= TEGRA_GMI_WE_WIDTH(property);
    193	else
    194		gmi->snor_timing1 |= TEGRA_GMI_WE_WIDTH(1);
    195
    196	if (!of_property_read_u32(child, "nvidia,snor-oe-width", &property))
    197		gmi->snor_timing1 |= TEGRA_GMI_OE_WIDTH(property);
    198	else
    199		gmi->snor_timing1 |= TEGRA_GMI_OE_WIDTH(1);
    200
    201	if (!of_property_read_u32(child, "nvidia,snor-wait-width", &property))
    202		gmi->snor_timing1 |= TEGRA_GMI_WAIT_WIDTH(property);
    203	else
    204		gmi->snor_timing1 |= TEGRA_GMI_WAIT_WIDTH(3);
    205
    206error_cs:
    207	of_node_put(child);
    208	return err;
    209}
    210
    211static int tegra_gmi_probe(struct platform_device *pdev)
    212{
    213	struct device *dev = &pdev->dev;
    214	struct tegra_gmi *gmi;
    215	struct resource *res;
    216	int err;
    217
    218	gmi = devm_kzalloc(dev, sizeof(*gmi), GFP_KERNEL);
    219	if (!gmi)
    220		return -ENOMEM;
    221
    222	platform_set_drvdata(pdev, gmi);
    223	gmi->dev = dev;
    224
    225	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    226	gmi->base = devm_ioremap_resource(dev, res);
    227	if (IS_ERR(gmi->base))
    228		return PTR_ERR(gmi->base);
    229
    230	gmi->clk = devm_clk_get(dev, "gmi");
    231	if (IS_ERR(gmi->clk)) {
    232		dev_err(dev, "can not get clock\n");
    233		return PTR_ERR(gmi->clk);
    234	}
    235
    236	gmi->rst = devm_reset_control_get(dev, "gmi");
    237	if (IS_ERR(gmi->rst)) {
    238		dev_err(dev, "can not get reset\n");
    239		return PTR_ERR(gmi->rst);
    240	}
    241
    242	err = devm_tegra_core_dev_init_opp_table_common(&pdev->dev);
    243	if (err)
    244		return err;
    245
    246	err = tegra_gmi_parse_dt(gmi);
    247	if (err)
    248		return err;
    249
    250	err = tegra_gmi_enable(gmi);
    251	if (err < 0)
    252		return err;
    253
    254	err = of_platform_default_populate(dev->of_node, NULL, dev);
    255	if (err < 0) {
    256		dev_err(dev, "fail to create devices.\n");
    257		tegra_gmi_disable(gmi);
    258		return err;
    259	}
    260
    261	return 0;
    262}
    263
    264static int tegra_gmi_remove(struct platform_device *pdev)
    265{
    266	struct tegra_gmi *gmi = platform_get_drvdata(pdev);
    267
    268	of_platform_depopulate(gmi->dev);
    269	tegra_gmi_disable(gmi);
    270
    271	return 0;
    272}
    273
    274static int __maybe_unused tegra_gmi_runtime_resume(struct device *dev)
    275{
    276	struct tegra_gmi *gmi = dev_get_drvdata(dev);
    277	int err;
    278
    279	err = clk_prepare_enable(gmi->clk);
    280	if (err < 0) {
    281		dev_err(gmi->dev, "failed to enable clock: %d\n", err);
    282		return err;
    283	}
    284
    285	return 0;
    286}
    287
    288static int __maybe_unused tegra_gmi_runtime_suspend(struct device *dev)
    289{
    290	struct tegra_gmi *gmi = dev_get_drvdata(dev);
    291
    292	clk_disable_unprepare(gmi->clk);
    293
    294	return 0;
    295}
    296
    297static const struct dev_pm_ops tegra_gmi_pm = {
    298	SET_RUNTIME_PM_OPS(tegra_gmi_runtime_suspend, tegra_gmi_runtime_resume,
    299			   NULL)
    300};
    301
    302static const struct of_device_id tegra_gmi_id_table[] = {
    303	{ .compatible = "nvidia,tegra20-gmi", },
    304	{ .compatible = "nvidia,tegra30-gmi", },
    305	{ }
    306};
    307MODULE_DEVICE_TABLE(of, tegra_gmi_id_table);
    308
    309static struct platform_driver tegra_gmi_driver = {
    310	.probe = tegra_gmi_probe,
    311	.remove = tegra_gmi_remove,
    312	.driver = {
    313		.name		= "tegra-gmi",
    314		.of_match_table	= tegra_gmi_id_table,
    315		.pm = &tegra_gmi_pm,
    316	},
    317};
    318module_platform_driver(tegra_gmi_driver);
    319
    320MODULE_AUTHOR("Mirza Krak <mirza.krak@gmail.com");
    321MODULE_DESCRIPTION("NVIDIA Tegra GMI Bus Driver");
    322MODULE_LICENSE("GPL v2");