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

mvebu-soc-id.c (4236B)


      1/*
      2 * ID and revision information for mvebu SoCs
      3 *
      4 * Copyright (C) 2014 Marvell
      5 *
      6 * Gregory CLEMENT <gregory.clement@free-electrons.com>
      7 *
      8 * This file is licensed under the terms of the GNU General Public
      9 * License version 2.  This program is licensed "as is" without any
     10 * warranty of any kind, whether express or implied.
     11 *
     12 * All the mvebu SoCs have information related to their variant and
     13 * revision that can be read from the PCI control register. This is
     14 * done before the PCI initialization to avoid any conflict. Once the
     15 * ID and revision are retrieved, the mapping is freed.
     16 */
     17
     18#define pr_fmt(fmt) "mvebu-soc-id: " fmt
     19
     20#include <linux/clk.h>
     21#include <linux/init.h>
     22#include <linux/io.h>
     23#include <linux/kernel.h>
     24#include <linux/of.h>
     25#include <linux/of_address.h>
     26#include <linux/slab.h>
     27#include <linux/sys_soc.h>
     28#include "common.h"
     29#include "mvebu-soc-id.h"
     30
     31#define PCIE_DEV_ID_OFF		0x0
     32#define PCIE_DEV_REV_OFF	0x8
     33
     34#define SOC_ID_MASK	    0xFFFF0000
     35#define SOC_REV_MASK	    0xFF
     36
     37static u32 soc_dev_id;
     38static u32 soc_rev;
     39static bool is_id_valid;
     40
     41static const struct of_device_id mvebu_pcie_of_match_table[] = {
     42	{ .compatible = "marvell,armada-xp-pcie", },
     43	{ .compatible = "marvell,armada-370-pcie", },
     44	{ .compatible = "marvell,kirkwood-pcie" },
     45	{},
     46};
     47
     48int mvebu_get_soc_id(u32 *dev, u32 *rev)
     49{
     50	if (is_id_valid) {
     51		*dev = soc_dev_id;
     52		*rev = soc_rev;
     53		return 0;
     54	} else
     55		return -ENODEV;
     56}
     57
     58static int __init get_soc_id_by_pci(void)
     59{
     60	struct device_node *np;
     61	int ret = 0;
     62	void __iomem *pci_base;
     63	struct clk *clk;
     64	struct device_node *child;
     65
     66	np = of_find_matching_node(NULL, mvebu_pcie_of_match_table);
     67	if (!np)
     68		return ret;
     69
     70	/*
     71	 * ID and revision are available from any port, so we
     72	 * just pick the first one
     73	 */
     74	child = of_get_next_child(np, NULL);
     75	if (child == NULL) {
     76		pr_err("cannot get pci node\n");
     77		ret = -ENOMEM;
     78		goto clk_err;
     79	}
     80
     81	clk = of_clk_get_by_name(child, NULL);
     82	if (IS_ERR(clk)) {
     83		pr_err("cannot get clock\n");
     84		ret = -ENOMEM;
     85		goto clk_err;
     86	}
     87
     88	ret = clk_prepare_enable(clk);
     89	if (ret) {
     90		pr_err("cannot enable clock\n");
     91		goto clk_err;
     92	}
     93
     94	pci_base = of_iomap(child, 0);
     95	if (pci_base == NULL) {
     96		pr_err("cannot map registers\n");
     97		ret = -ENOMEM;
     98		goto res_ioremap;
     99	}
    100
    101	/* SoC ID */
    102	soc_dev_id = readl(pci_base + PCIE_DEV_ID_OFF) >> 16;
    103
    104	/* SoC revision */
    105	soc_rev = readl(pci_base + PCIE_DEV_REV_OFF) & SOC_REV_MASK;
    106
    107	is_id_valid = true;
    108
    109	pr_info("MVEBU SoC ID=0x%X, Rev=0x%X\n", soc_dev_id, soc_rev);
    110
    111	iounmap(pci_base);
    112
    113res_ioremap:
    114	/*
    115	 * If the PCIe unit is actually enabled and we have PCI
    116	 * support in the kernel, we intentionally do not release the
    117	 * reference to the clock. We want to keep it running since
    118	 * the bootloader does some PCIe link configuration that the
    119	 * kernel is for now unable to do, and gating the clock would
    120	 * make us loose this precious configuration.
    121	 */
    122	if (!of_device_is_available(child) || !IS_ENABLED(CONFIG_PCI_MVEBU)) {
    123		clk_disable_unprepare(clk);
    124		clk_put(clk);
    125	}
    126
    127clk_err:
    128	of_node_put(child);
    129	of_node_put(np);
    130
    131	return ret;
    132}
    133
    134static int __init mvebu_soc_id_init(void)
    135{
    136
    137	/*
    138	 * First try to get the ID and the revision by the system
    139	 * register and use PCI registers only if it is not possible
    140	 */
    141	if (!mvebu_system_controller_get_soc_id(&soc_dev_id, &soc_rev)) {
    142		is_id_valid = true;
    143		pr_info("MVEBU SoC ID=0x%X, Rev=0x%X\n", soc_dev_id, soc_rev);
    144		return 0;
    145	}
    146
    147	return get_soc_id_by_pci();
    148}
    149early_initcall(mvebu_soc_id_init);
    150
    151static int __init mvebu_soc_device(void)
    152{
    153	struct soc_device_attribute *soc_dev_attr;
    154	struct soc_device *soc_dev;
    155
    156	/* Also protects against running on non-mvebu systems */
    157	if (!is_id_valid)
    158		return 0;
    159
    160	soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
    161	if (!soc_dev_attr)
    162		return -ENOMEM;
    163
    164	soc_dev_attr->family = kasprintf(GFP_KERNEL, "Marvell");
    165	soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%X", soc_rev);
    166	soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%X", soc_dev_id);
    167
    168	soc_dev = soc_device_register(soc_dev_attr);
    169	if (IS_ERR(soc_dev)) {
    170		kfree(soc_dev_attr->family);
    171		kfree(soc_dev_attr->revision);
    172		kfree(soc_dev_attr->soc_id);
    173		kfree(soc_dev_attr);
    174	}
    175
    176	return 0;
    177}
    178postcore_initcall(mvebu_soc_device);