root/drivers/soc/imx/soc-imx8.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. soc_uid_show
  2. imx8mq_soc_revision
  3. imx8mm_soc_uid
  4. imx8mm_soc_revision
  5. imx8_soc_init

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Copyright 2019 NXP.
   4  */
   5 
   6 #include <linux/init.h>
   7 #include <linux/io.h>
   8 #include <linux/of_address.h>
   9 #include <linux/slab.h>
  10 #include <linux/sys_soc.h>
  11 #include <linux/platform_device.h>
  12 #include <linux/of.h>
  13 
  14 #define REV_B1                          0x21
  15 
  16 #define IMX8MQ_SW_INFO_B1               0x40
  17 #define IMX8MQ_SW_MAGIC_B1              0xff0055aa
  18 
  19 #define OCOTP_UID_LOW                   0x410
  20 #define OCOTP_UID_HIGH                  0x420
  21 
  22 /* Same as ANADIG_DIGPROG_IMX7D */
  23 #define ANADIG_DIGPROG_IMX8MM   0x800
  24 
  25 struct imx8_soc_data {
  26         char *name;
  27         u32 (*soc_revision)(void);
  28 };
  29 
  30 static u64 soc_uid;
  31 
  32 static ssize_t soc_uid_show(struct device *dev,
  33                             struct device_attribute *attr, char *buf)
  34 {
  35         return sprintf(buf, "%016llX\n", soc_uid);
  36 }
  37 
  38 static DEVICE_ATTR_RO(soc_uid);
  39 
  40 static u32 __init imx8mq_soc_revision(void)
  41 {
  42         struct device_node *np;
  43         void __iomem *ocotp_base;
  44         u32 magic;
  45         u32 rev = 0;
  46 
  47         np = of_find_compatible_node(NULL, NULL, "fsl,imx8mq-ocotp");
  48         if (!np)
  49                 goto out;
  50 
  51         ocotp_base = of_iomap(np, 0);
  52         WARN_ON(!ocotp_base);
  53 
  54         magic = readl_relaxed(ocotp_base + IMX8MQ_SW_INFO_B1);
  55         if (magic == IMX8MQ_SW_MAGIC_B1)
  56                 rev = REV_B1;
  57 
  58         soc_uid = readl_relaxed(ocotp_base + OCOTP_UID_HIGH);
  59         soc_uid <<= 32;
  60         soc_uid |= readl_relaxed(ocotp_base + OCOTP_UID_LOW);
  61 
  62         iounmap(ocotp_base);
  63 
  64 out:
  65         of_node_put(np);
  66         return rev;
  67 }
  68 
  69 static void __init imx8mm_soc_uid(void)
  70 {
  71         void __iomem *ocotp_base;
  72         struct device_node *np;
  73 
  74         np = of_find_compatible_node(NULL, NULL, "fsl,imx8mm-ocotp");
  75         if (!np)
  76                 return;
  77 
  78         ocotp_base = of_iomap(np, 0);
  79         WARN_ON(!ocotp_base);
  80 
  81         soc_uid = readl_relaxed(ocotp_base + OCOTP_UID_HIGH);
  82         soc_uid <<= 32;
  83         soc_uid |= readl_relaxed(ocotp_base + OCOTP_UID_LOW);
  84 
  85         iounmap(ocotp_base);
  86         of_node_put(np);
  87 }
  88 
  89 static u32 __init imx8mm_soc_revision(void)
  90 {
  91         struct device_node *np;
  92         void __iomem *anatop_base;
  93         u32 rev;
  94 
  95         np = of_find_compatible_node(NULL, NULL, "fsl,imx8mm-anatop");
  96         if (!np)
  97                 return 0;
  98 
  99         anatop_base = of_iomap(np, 0);
 100         WARN_ON(!anatop_base);
 101 
 102         rev = readl_relaxed(anatop_base + ANADIG_DIGPROG_IMX8MM);
 103 
 104         iounmap(anatop_base);
 105         of_node_put(np);
 106 
 107         imx8mm_soc_uid();
 108 
 109         return rev;
 110 }
 111 
 112 static const struct imx8_soc_data imx8mq_soc_data = {
 113         .name = "i.MX8MQ",
 114         .soc_revision = imx8mq_soc_revision,
 115 };
 116 
 117 static const struct imx8_soc_data imx8mm_soc_data = {
 118         .name = "i.MX8MM",
 119         .soc_revision = imx8mm_soc_revision,
 120 };
 121 
 122 static const struct imx8_soc_data imx8mn_soc_data = {
 123         .name = "i.MX8MN",
 124         .soc_revision = imx8mm_soc_revision,
 125 };
 126 
 127 static const struct of_device_id imx8_soc_match[] = {
 128         { .compatible = "fsl,imx8mq", .data = &imx8mq_soc_data, },
 129         { .compatible = "fsl,imx8mm", .data = &imx8mm_soc_data, },
 130         { .compatible = "fsl,imx8mn", .data = &imx8mn_soc_data, },
 131         { }
 132 };
 133 
 134 #define imx8_revision(soc_rev) \
 135         soc_rev ? \
 136         kasprintf(GFP_KERNEL, "%d.%d", (soc_rev >> 4) & 0xf,  soc_rev & 0xf) : \
 137         "unknown"
 138 
 139 static int __init imx8_soc_init(void)
 140 {
 141         struct soc_device_attribute *soc_dev_attr;
 142         struct soc_device *soc_dev;
 143         const struct of_device_id *id;
 144         u32 soc_rev = 0;
 145         const struct imx8_soc_data *data;
 146         int ret;
 147 
 148         soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
 149         if (!soc_dev_attr)
 150                 return -ENOMEM;
 151 
 152         soc_dev_attr->family = "Freescale i.MX";
 153 
 154         ret = of_property_read_string(of_root, "model", &soc_dev_attr->machine);
 155         if (ret)
 156                 goto free_soc;
 157 
 158         id = of_match_node(imx8_soc_match, of_root);
 159         if (!id) {
 160                 ret = -ENODEV;
 161                 goto free_soc;
 162         }
 163 
 164         data = id->data;
 165         if (data) {
 166                 soc_dev_attr->soc_id = data->name;
 167                 if (data->soc_revision)
 168                         soc_rev = data->soc_revision();
 169         }
 170 
 171         soc_dev_attr->revision = imx8_revision(soc_rev);
 172         if (!soc_dev_attr->revision) {
 173                 ret = -ENOMEM;
 174                 goto free_soc;
 175         }
 176 
 177         soc_dev = soc_device_register(soc_dev_attr);
 178         if (IS_ERR(soc_dev)) {
 179                 ret = PTR_ERR(soc_dev);
 180                 goto free_rev;
 181         }
 182 
 183         ret = device_create_file(soc_device_to_device(soc_dev),
 184                                  &dev_attr_soc_uid);
 185         if (ret)
 186                 goto free_rev;
 187 
 188         if (IS_ENABLED(CONFIG_ARM_IMX_CPUFREQ_DT))
 189                 platform_device_register_simple("imx-cpufreq-dt", -1, NULL, 0);
 190 
 191         return 0;
 192 
 193 free_rev:
 194         if (strcmp(soc_dev_attr->revision, "unknown"))
 195                 kfree(soc_dev_attr->revision);
 196 free_soc:
 197         kfree(soc_dev_attr);
 198         return ret;
 199 }
 200 device_initcall(imx8_soc_init);

/* [<][>][^][v][top][bottom][index][help] */