linux/drivers/soc/aspeed/aspeed-socinfo.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/* Copyright 2019 IBM Corp. */
   3
   4#include <linux/io.h>
   5#include <linux/of.h>
   6#include <linux/of_address.h>
   7#include <linux/of_platform.h>
   8#include <linux/platform_device.h>
   9#include <linux/slab.h>
  10#include <linux/sys_soc.h>
  11
  12static struct {
  13        const char *name;
  14        const u32 id;
  15} const rev_table[] = {
  16        /* AST2400 */
  17        { "AST2400", 0x02000303 },
  18        { "AST1400", 0x02010103 },
  19        { "AST1250", 0x02010303 },
  20        /* AST2500 */
  21        { "AST2500", 0x04000303 },
  22        { "AST2510", 0x04000103 },
  23        { "AST2520", 0x04000203 },
  24        { "AST2530", 0x04000403 },
  25        /* AST2600 */
  26        { "AST2600", 0x05000303 },
  27        { "AST2620", 0x05010203 },
  28        { "AST2605", 0x05030103 },
  29};
  30
  31static const char *siliconid_to_name(u32 siliconid)
  32{
  33        unsigned int id = siliconid & 0xff00ffff;
  34        unsigned int i;
  35
  36        for (i = 0 ; i < ARRAY_SIZE(rev_table) ; ++i) {
  37                if (rev_table[i].id == id)
  38                        return rev_table[i].name;
  39        }
  40
  41        return "Unknown";
  42}
  43
  44static const char *siliconid_to_rev(u32 siliconid)
  45{
  46        unsigned int rev = (siliconid >> 16) & 0xff;
  47        unsigned int gen = (siliconid >> 24) & 0xff;
  48
  49        if (gen < 0x5) {
  50                /* AST2500 and below */
  51                switch (rev) {
  52                case 0:
  53                        return "A0";
  54                case 1:
  55                        return "A1";
  56                case 3:
  57                        return "A2";
  58                }
  59        } else {
  60                /* AST2600 */
  61                switch (rev) {
  62                case 0:
  63                        return "A0";
  64                case 1:
  65                        return "A1";
  66                case 2:
  67                        return "A2";
  68                case 3:
  69                        return "A3";
  70                }
  71        }
  72
  73        return "??";
  74}
  75
  76static int __init aspeed_socinfo_init(void)
  77{
  78        struct soc_device_attribute *attrs;
  79        struct soc_device *soc_dev;
  80        struct device_node *np;
  81        void __iomem *reg;
  82        bool has_chipid = false;
  83        u32 siliconid;
  84        u32 chipid[2];
  85        const char *machine = NULL;
  86
  87        np = of_find_compatible_node(NULL, NULL, "aspeed,silicon-id");
  88        if (!of_device_is_available(np)) {
  89                of_node_put(np);
  90                return -ENODEV;
  91        }
  92
  93        reg = of_iomap(np, 0);
  94        if (!reg) {
  95                of_node_put(np);
  96                return -ENODEV;
  97        }
  98        siliconid = readl(reg);
  99        iounmap(reg);
 100
 101        /* This is optional, the ast2400 does not have it */
 102        reg = of_iomap(np, 1);
 103        if (reg) {
 104                has_chipid = true;
 105                chipid[0] = readl(reg);
 106                chipid[1] = readl(reg + 4);
 107                iounmap(reg);
 108        }
 109        of_node_put(np);
 110
 111        attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
 112        if (!attrs)
 113                return -ENODEV;
 114
 115        /*
 116         * Machine: Romulus BMC
 117         * Family: AST2500
 118         * Revision: A1
 119         * SoC ID: raw silicon revision id
 120         * Serial Number: 64-bit chipid
 121         */
 122
 123        np = of_find_node_by_path("/");
 124        of_property_read_string(np, "model", &machine);
 125        if (machine)
 126                attrs->machine = kstrdup(machine, GFP_KERNEL);
 127        of_node_put(np);
 128
 129        attrs->family = siliconid_to_name(siliconid);
 130        attrs->revision = siliconid_to_rev(siliconid);
 131        attrs->soc_id = kasprintf(GFP_KERNEL, "%08x", siliconid);
 132
 133        if (has_chipid)
 134                attrs->serial_number = kasprintf(GFP_KERNEL, "%08x%08x",
 135                                                 chipid[1], chipid[0]);
 136
 137        soc_dev = soc_device_register(attrs);
 138        if (IS_ERR(soc_dev)) {
 139                kfree(attrs->soc_id);
 140                kfree(attrs->serial_number);
 141                kfree(attrs);
 142                return PTR_ERR(soc_dev);
 143        }
 144
 145        pr_info("ASPEED %s rev %s (%s)\n",
 146                        attrs->family,
 147                        attrs->revision,
 148                        attrs->soc_id);
 149
 150        return 0;
 151}
 152early_initcall(aspeed_socinfo_init);
 153