Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * ID and revision information for mvebu SoCs
0004  *
0005  * Copyright (C) 2014 Marvell
0006  *
0007  * Gregory CLEMENT <gregory.clement@free-electrons.com>
0008  *
0009  * All the mvebu SoCs have information related to their variant and
0010  * revision that can be read from the PCI control register. This is
0011  * done before the PCI initialization to avoid any conflict. Once the
0012  * ID and revision are retrieved, the mapping is freed.
0013  */
0014 
0015 #define pr_fmt(fmt) "mvebu-soc-id: " fmt
0016 
0017 #include <linux/clk.h>
0018 #include <linux/init.h>
0019 #include <linux/io.h>
0020 #include <linux/kernel.h>
0021 #include <linux/of.h>
0022 #include <linux/of_address.h>
0023 #include <linux/slab.h>
0024 #include <linux/sys_soc.h>
0025 #include "common.h"
0026 #include "mvebu-soc-id.h"
0027 
0028 #define PCIE_DEV_ID_OFF     0x0
0029 #define PCIE_DEV_REV_OFF    0x8
0030 
0031 #define SOC_ID_MASK     0xFFFF0000
0032 #define SOC_REV_MASK        0xFF
0033 
0034 static u32 soc_dev_id;
0035 static u32 soc_rev;
0036 static bool is_id_valid;
0037 
0038 static const struct of_device_id mvebu_pcie_of_match_table[] = {
0039     { .compatible = "marvell,armada-xp-pcie", },
0040     { .compatible = "marvell,armada-370-pcie", },
0041     { .compatible = "marvell,kirkwood-pcie" },
0042     {},
0043 };
0044 
0045 int mvebu_get_soc_id(u32 *dev, u32 *rev)
0046 {
0047     if (is_id_valid) {
0048         *dev = soc_dev_id;
0049         *rev = soc_rev;
0050         return 0;
0051     } else
0052         return -ENODEV;
0053 }
0054 
0055 static int __init get_soc_id_by_pci(void)
0056 {
0057     struct device_node *np;
0058     int ret = 0;
0059     void __iomem *pci_base;
0060     struct clk *clk;
0061     struct device_node *child;
0062 
0063     np = of_find_matching_node(NULL, mvebu_pcie_of_match_table);
0064     if (!np)
0065         return ret;
0066 
0067     /*
0068      * ID and revision are available from any port, so we
0069      * just pick the first one
0070      */
0071     child = of_get_next_child(np, NULL);
0072     if (child == NULL) {
0073         pr_err("cannot get pci node\n");
0074         ret = -ENOMEM;
0075         goto clk_err;
0076     }
0077 
0078     clk = of_clk_get_by_name(child, NULL);
0079     if (IS_ERR(clk)) {
0080         pr_err("cannot get clock\n");
0081         ret = -ENOMEM;
0082         goto clk_err;
0083     }
0084 
0085     ret = clk_prepare_enable(clk);
0086     if (ret) {
0087         pr_err("cannot enable clock\n");
0088         goto clk_err;
0089     }
0090 
0091     pci_base = of_iomap(child, 0);
0092     if (pci_base == NULL) {
0093         pr_err("cannot map registers\n");
0094         ret = -ENOMEM;
0095         goto res_ioremap;
0096     }
0097 
0098     /* SoC ID */
0099     soc_dev_id = readl(pci_base + PCIE_DEV_ID_OFF) >> 16;
0100 
0101     /* SoC revision */
0102     soc_rev = readl(pci_base + PCIE_DEV_REV_OFF) & SOC_REV_MASK;
0103 
0104     is_id_valid = true;
0105 
0106     pr_info("MVEBU SoC ID=0x%X, Rev=0x%X\n", soc_dev_id, soc_rev);
0107 
0108     iounmap(pci_base);
0109 
0110 res_ioremap:
0111     /*
0112      * If the PCIe unit is actually enabled and we have PCI
0113      * support in the kernel, we intentionally do not release the
0114      * reference to the clock. We want to keep it running since
0115      * the bootloader does some PCIe link configuration that the
0116      * kernel is for now unable to do, and gating the clock would
0117      * make us loose this precious configuration.
0118      */
0119     if (!of_device_is_available(child) || !IS_ENABLED(CONFIG_PCI_MVEBU)) {
0120         clk_disable_unprepare(clk);
0121         clk_put(clk);
0122     }
0123 
0124 clk_err:
0125     of_node_put(child);
0126     of_node_put(np);
0127 
0128     return ret;
0129 }
0130 
0131 static int __init mvebu_soc_id_init(void)
0132 {
0133 
0134     /*
0135      * First try to get the ID and the revision by the system
0136      * register and use PCI registers only if it is not possible
0137      */
0138     if (!mvebu_system_controller_get_soc_id(&soc_dev_id, &soc_rev)) {
0139         is_id_valid = true;
0140         pr_info("MVEBU SoC ID=0x%X, Rev=0x%X\n", soc_dev_id, soc_rev);
0141         return 0;
0142     }
0143 
0144     return get_soc_id_by_pci();
0145 }
0146 early_initcall(mvebu_soc_id_init);
0147 
0148 static int __init mvebu_soc_device(void)
0149 {
0150     struct soc_device_attribute *soc_dev_attr;
0151     struct soc_device *soc_dev;
0152 
0153     /* Also protects against running on non-mvebu systems */
0154     if (!is_id_valid)
0155         return 0;
0156 
0157     soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
0158     if (!soc_dev_attr)
0159         return -ENOMEM;
0160 
0161     soc_dev_attr->family = kasprintf(GFP_KERNEL, "Marvell");
0162     soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%X", soc_rev);
0163     soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%X", soc_dev_id);
0164 
0165     soc_dev = soc_device_register(soc_dev_attr);
0166     if (IS_ERR(soc_dev)) {
0167         kfree(soc_dev_attr->family);
0168         kfree(soc_dev_attr->revision);
0169         kfree(soc_dev_attr->soc_id);
0170         kfree(soc_dev_attr);
0171     }
0172 
0173     return 0;
0174 }
0175 postcore_initcall(mvebu_soc_device);