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