~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/arm/mach-mvebu/mvebu-soc-id.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php