0001
0002
0003
0004
0005
0006
0007 #include <linux/io.h>
0008 #include <linux/of.h>
0009 #include <linux/of_address.h>
0010 #include <linux/of_platform.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/slab.h>
0013 #include <linux/sys_soc.h>
0014 #include <linux/bitfield.h>
0015 #include <linux/regmap.h>
0016 #include <linux/mfd/syscon.h>
0017
0018 #define MESON_SOCINFO_MAJOR_VER_MESON6 0x16
0019 #define MESON_SOCINFO_MAJOR_VER_MESON8 0x19
0020 #define MESON_SOCINFO_MAJOR_VER_MESON8B 0x1b
0021
0022 #define MESON_MX_ASSIST_HW_REV 0x14c
0023
0024 #define MESON_MX_ANALOG_TOP_METAL_REVISION 0x0
0025
0026 #define MESON_MX_BOOTROM_MISC_VER 0x4
0027
0028 static const char *meson_mx_socinfo_revision(unsigned int major_ver,
0029 unsigned int misc_ver,
0030 unsigned int metal_rev)
0031 {
0032 unsigned int minor_ver;
0033
0034 switch (major_ver) {
0035 case MESON_SOCINFO_MAJOR_VER_MESON6:
0036 minor_ver = 0xa;
0037 break;
0038
0039 case MESON_SOCINFO_MAJOR_VER_MESON8:
0040 if (metal_rev == 0x11111112)
0041 major_ver = 0x1d;
0042
0043 if (metal_rev == 0x11111111 || metal_rev == 0x11111112)
0044 minor_ver = 0xa;
0045 else if (metal_rev == 0x11111113)
0046 minor_ver = 0xb;
0047 else if (metal_rev == 0x11111133)
0048 minor_ver = 0xc;
0049 else
0050 minor_ver = 0xd;
0051
0052 break;
0053
0054 case MESON_SOCINFO_MAJOR_VER_MESON8B:
0055 if (metal_rev == 0x11111111)
0056 minor_ver = 0xa;
0057 else
0058 minor_ver = 0xb;
0059
0060 break;
0061
0062 default:
0063 minor_ver = 0x0;
0064 break;
0065 }
0066
0067 return kasprintf(GFP_KERNEL, "Rev%X (%x - 0:%X)", minor_ver, major_ver,
0068 misc_ver);
0069 }
0070
0071 static const char *meson_mx_socinfo_soc_id(unsigned int major_ver,
0072 unsigned int metal_rev)
0073 {
0074 const char *soc_id;
0075
0076 switch (major_ver) {
0077 case MESON_SOCINFO_MAJOR_VER_MESON6:
0078 soc_id = "Meson6 (AML8726-MX)";
0079 break;
0080
0081 case MESON_SOCINFO_MAJOR_VER_MESON8:
0082 if (metal_rev == 0x11111112)
0083 soc_id = "Meson8m2 (S812)";
0084 else
0085 soc_id = "Meson8 (S802)";
0086
0087 break;
0088
0089 case MESON_SOCINFO_MAJOR_VER_MESON8B:
0090 soc_id = "Meson8b (S805)";
0091 break;
0092
0093 default:
0094 soc_id = "Unknown";
0095 break;
0096 }
0097
0098 return kstrdup_const(soc_id, GFP_KERNEL);
0099 }
0100
0101 static const struct of_device_id meson_mx_socinfo_analog_top_ids[] = {
0102 { .compatible = "amlogic,meson8-analog-top", },
0103 { .compatible = "amlogic,meson8b-analog-top", },
0104 { }
0105 };
0106
0107 static int __init meson_mx_socinfo_init(void)
0108 {
0109 struct soc_device_attribute *soc_dev_attr;
0110 struct soc_device *soc_dev;
0111 struct device_node *np;
0112 struct regmap *assist_regmap, *bootrom_regmap, *analog_top_regmap;
0113 unsigned int major_ver, misc_ver, metal_rev = 0;
0114 int ret;
0115
0116 assist_regmap =
0117 syscon_regmap_lookup_by_compatible("amlogic,meson-mx-assist");
0118 if (IS_ERR(assist_regmap))
0119 return PTR_ERR(assist_regmap);
0120
0121 bootrom_regmap =
0122 syscon_regmap_lookup_by_compatible("amlogic,meson-mx-bootrom");
0123 if (IS_ERR(bootrom_regmap))
0124 return PTR_ERR(bootrom_regmap);
0125
0126 np = of_find_matching_node(NULL, meson_mx_socinfo_analog_top_ids);
0127 if (np) {
0128 analog_top_regmap = syscon_node_to_regmap(np);
0129 of_node_put(np);
0130 if (IS_ERR(analog_top_regmap))
0131 return PTR_ERR(analog_top_regmap);
0132
0133 ret = regmap_read(analog_top_regmap,
0134 MESON_MX_ANALOG_TOP_METAL_REVISION,
0135 &metal_rev);
0136 if (ret)
0137 return ret;
0138 }
0139
0140 ret = regmap_read(assist_regmap, MESON_MX_ASSIST_HW_REV, &major_ver);
0141 if (ret < 0)
0142 return ret;
0143
0144 ret = regmap_read(bootrom_regmap, MESON_MX_BOOTROM_MISC_VER,
0145 &misc_ver);
0146 if (ret < 0)
0147 return ret;
0148
0149 soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
0150 if (!soc_dev_attr)
0151 return -ENODEV;
0152
0153 soc_dev_attr->family = "Amlogic Meson";
0154
0155 np = of_find_node_by_path("/");
0156 of_property_read_string(np, "model", &soc_dev_attr->machine);
0157 of_node_put(np);
0158
0159 soc_dev_attr->revision = meson_mx_socinfo_revision(major_ver, misc_ver,
0160 metal_rev);
0161 soc_dev_attr->soc_id = meson_mx_socinfo_soc_id(major_ver, metal_rev);
0162
0163 soc_dev = soc_device_register(soc_dev_attr);
0164 if (IS_ERR(soc_dev)) {
0165 kfree_const(soc_dev_attr->revision);
0166 kfree_const(soc_dev_attr->soc_id);
0167 kfree(soc_dev_attr);
0168 return PTR_ERR(soc_dev);
0169 }
0170
0171 dev_info(soc_device_to_device(soc_dev), "Amlogic %s %s detected\n",
0172 soc_dev_attr->soc_id, soc_dev_attr->revision);
0173
0174 return 0;
0175 }
0176 device_initcall(meson_mx_socinfo_init);