Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | /* * Copyright (c) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com> * * SPDX-License-Identifier: GPL-2.0+ */ #include <linux/io.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/sys_soc.h> #include <linux/bitfield.h> #include <linux/regmap.h> #include <linux/mfd/syscon.h> #define MESON_SOCINFO_MAJOR_VER_MESON6 0x16 #define MESON_SOCINFO_MAJOR_VER_MESON8 0x19 #define MESON_SOCINFO_MAJOR_VER_MESON8B 0x1b #define MESON_MX_ASSIST_HW_REV 0x14c #define MESON_MX_ANALOG_TOP_METAL_REVISION 0x0 #define MESON_MX_BOOTROM_MISC_VER 0x4 static const char *meson_mx_socinfo_revision(unsigned int major_ver, unsigned int misc_ver, unsigned int metal_rev) { unsigned int minor_ver; switch (major_ver) { case MESON_SOCINFO_MAJOR_VER_MESON6: minor_ver = 0xa; break; case MESON_SOCINFO_MAJOR_VER_MESON8: if (metal_rev == 0x11111112) major_ver = 0x1d; if (metal_rev == 0x11111111 || metal_rev == 0x11111112) minor_ver = 0xa; else if (metal_rev == 0x11111113) minor_ver = 0xb; else if (metal_rev == 0x11111133) minor_ver = 0xc; else minor_ver = 0xd; break; case MESON_SOCINFO_MAJOR_VER_MESON8B: if (metal_rev == 0x11111111) minor_ver = 0xa; else minor_ver = 0xb; break; default: minor_ver = 0x0; break; } return kasprintf(GFP_KERNEL, "Rev%X (%x - 0:%X)", minor_ver, major_ver, misc_ver); } static const char *meson_mx_socinfo_soc_id(unsigned int major_ver, unsigned int metal_rev) { const char *soc_id; switch (major_ver) { case MESON_SOCINFO_MAJOR_VER_MESON6: soc_id = "Meson6 (AML8726-MX)"; break; case MESON_SOCINFO_MAJOR_VER_MESON8: if (metal_rev == 0x11111112) soc_id = "Meson8m2 (S812)"; else soc_id = "Meson8 (S802)"; break; case MESON_SOCINFO_MAJOR_VER_MESON8B: soc_id = "Meson8b (S805)"; break; default: soc_id = "Unknown"; break; } return kstrdup_const(soc_id, GFP_KERNEL); } static const struct of_device_id meson_mx_socinfo_analog_top_ids[] = { { .compatible = "amlogic,meson8-analog-top", }, { .compatible = "amlogic,meson8b-analog-top", }, { /* sentinel */ } }; static int __init meson_mx_socinfo_init(void) { struct soc_device_attribute *soc_dev_attr; struct soc_device *soc_dev; struct device_node *np; struct regmap *assist_regmap, *bootrom_regmap, *analog_top_regmap; unsigned int major_ver, misc_ver, metal_rev = 0; int ret; assist_regmap = syscon_regmap_lookup_by_compatible("amlogic,meson-mx-assist"); if (IS_ERR(assist_regmap)) return PTR_ERR(assist_regmap); bootrom_regmap = syscon_regmap_lookup_by_compatible("amlogic,meson-mx-bootrom"); if (IS_ERR(bootrom_regmap)) return PTR_ERR(bootrom_regmap); np = of_find_matching_node(NULL, meson_mx_socinfo_analog_top_ids); if (np) { analog_top_regmap = syscon_node_to_regmap(np); if (IS_ERR(analog_top_regmap)) return PTR_ERR(analog_top_regmap); ret = regmap_read(analog_top_regmap, MESON_MX_ANALOG_TOP_METAL_REVISION, &metal_rev); if (ret) return ret; } ret = regmap_read(assist_regmap, MESON_MX_ASSIST_HW_REV, &major_ver); if (ret < 0) return ret; ret = regmap_read(bootrom_regmap, MESON_MX_BOOTROM_MISC_VER, &misc_ver); if (ret < 0) return ret; soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); if (!soc_dev_attr) return -ENODEV; soc_dev_attr->family = "Amlogic Meson"; np = of_find_node_by_path("/"); of_property_read_string(np, "model", &soc_dev_attr->machine); of_node_put(np); soc_dev_attr->revision = meson_mx_socinfo_revision(major_ver, misc_ver, metal_rev); soc_dev_attr->soc_id = meson_mx_socinfo_soc_id(major_ver, metal_rev); soc_dev = soc_device_register(soc_dev_attr); if (IS_ERR(soc_dev)) { kfree_const(soc_dev_attr->revision); kfree_const(soc_dev_attr->soc_id); kfree(soc_dev_attr); return PTR_ERR(soc_dev); } dev_info(soc_device_to_device(soc_dev), "Amlogic %s %s detected\n", soc_dev_attr->soc_id, soc_dev_attr->revision); return 0; } device_initcall(meson_mx_socinfo_init); |