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