15e68c0fcSMartin Blumenstingl /* 25e68c0fcSMartin Blumenstingl * Copyright (c) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com> 35e68c0fcSMartin Blumenstingl * 45e68c0fcSMartin Blumenstingl * SPDX-License-Identifier: GPL-2.0+ 55e68c0fcSMartin Blumenstingl */ 65e68c0fcSMartin Blumenstingl 75e68c0fcSMartin Blumenstingl #include <linux/io.h> 85e68c0fcSMartin Blumenstingl #include <linux/of.h> 95e68c0fcSMartin Blumenstingl #include <linux/of_address.h> 105e68c0fcSMartin Blumenstingl #include <linux/of_platform.h> 115e68c0fcSMartin Blumenstingl #include <linux/platform_device.h> 125e68c0fcSMartin Blumenstingl #include <linux/slab.h> 135e68c0fcSMartin Blumenstingl #include <linux/sys_soc.h> 145e68c0fcSMartin Blumenstingl #include <linux/bitfield.h> 155e68c0fcSMartin Blumenstingl #include <linux/regmap.h> 165e68c0fcSMartin Blumenstingl #include <linux/mfd/syscon.h> 175e68c0fcSMartin Blumenstingl 185e68c0fcSMartin Blumenstingl #define MESON_SOCINFO_MAJOR_VER_MESON6 0x16 195e68c0fcSMartin Blumenstingl #define MESON_SOCINFO_MAJOR_VER_MESON8 0x19 205e68c0fcSMartin Blumenstingl #define MESON_SOCINFO_MAJOR_VER_MESON8B 0x1b 215e68c0fcSMartin Blumenstingl 225e68c0fcSMartin Blumenstingl #define MESON_MX_ASSIST_HW_REV 0x14c 235e68c0fcSMartin Blumenstingl 245e68c0fcSMartin Blumenstingl #define MESON_MX_ANALOG_TOP_METAL_REVISION 0x0 255e68c0fcSMartin Blumenstingl 265e68c0fcSMartin Blumenstingl #define MESON_MX_BOOTROM_MISC_VER 0x4 275e68c0fcSMartin Blumenstingl 285e68c0fcSMartin Blumenstingl static const char *meson_mx_socinfo_revision(unsigned int major_ver, 295e68c0fcSMartin Blumenstingl unsigned int misc_ver, 305e68c0fcSMartin Blumenstingl unsigned int metal_rev) 315e68c0fcSMartin Blumenstingl { 325e68c0fcSMartin Blumenstingl unsigned int minor_ver; 335e68c0fcSMartin Blumenstingl 345e68c0fcSMartin Blumenstingl switch (major_ver) { 355e68c0fcSMartin Blumenstingl case MESON_SOCINFO_MAJOR_VER_MESON6: 365e68c0fcSMartin Blumenstingl minor_ver = 0xa; 375e68c0fcSMartin Blumenstingl break; 385e68c0fcSMartin Blumenstingl 395e68c0fcSMartin Blumenstingl case MESON_SOCINFO_MAJOR_VER_MESON8: 405e68c0fcSMartin Blumenstingl if (metal_rev == 0x11111112) 415e68c0fcSMartin Blumenstingl major_ver = 0x1d; 425e68c0fcSMartin Blumenstingl 435e68c0fcSMartin Blumenstingl if (metal_rev == 0x11111111 || metal_rev == 0x11111112) 445e68c0fcSMartin Blumenstingl minor_ver = 0xa; 455e68c0fcSMartin Blumenstingl else if (metal_rev == 0x11111113) 465e68c0fcSMartin Blumenstingl minor_ver = 0xb; 475e68c0fcSMartin Blumenstingl else if (metal_rev == 0x11111133) 485e68c0fcSMartin Blumenstingl minor_ver = 0xc; 495e68c0fcSMartin Blumenstingl else 505e68c0fcSMartin Blumenstingl minor_ver = 0xd; 515e68c0fcSMartin Blumenstingl 525e68c0fcSMartin Blumenstingl break; 535e68c0fcSMartin Blumenstingl 545e68c0fcSMartin Blumenstingl case MESON_SOCINFO_MAJOR_VER_MESON8B: 555e68c0fcSMartin Blumenstingl if (metal_rev == 0x11111111) 565e68c0fcSMartin Blumenstingl minor_ver = 0xa; 575e68c0fcSMartin Blumenstingl else 585e68c0fcSMartin Blumenstingl minor_ver = 0xb; 595e68c0fcSMartin Blumenstingl 605e68c0fcSMartin Blumenstingl break; 615e68c0fcSMartin Blumenstingl 625e68c0fcSMartin Blumenstingl default: 635e68c0fcSMartin Blumenstingl minor_ver = 0x0; 645e68c0fcSMartin Blumenstingl break; 655e68c0fcSMartin Blumenstingl } 665e68c0fcSMartin Blumenstingl 675e68c0fcSMartin Blumenstingl return kasprintf(GFP_KERNEL, "Rev%X (%x - 0:%X)", minor_ver, major_ver, 685e68c0fcSMartin Blumenstingl misc_ver); 695e68c0fcSMartin Blumenstingl } 705e68c0fcSMartin Blumenstingl 715e68c0fcSMartin Blumenstingl static const char *meson_mx_socinfo_soc_id(unsigned int major_ver, 725e68c0fcSMartin Blumenstingl unsigned int metal_rev) 735e68c0fcSMartin Blumenstingl { 745e68c0fcSMartin Blumenstingl const char *soc_id; 755e68c0fcSMartin Blumenstingl 765e68c0fcSMartin Blumenstingl switch (major_ver) { 775e68c0fcSMartin Blumenstingl case MESON_SOCINFO_MAJOR_VER_MESON6: 785e68c0fcSMartin Blumenstingl soc_id = "Meson6 (AML8726-MX)"; 795e68c0fcSMartin Blumenstingl break; 805e68c0fcSMartin Blumenstingl 815e68c0fcSMartin Blumenstingl case MESON_SOCINFO_MAJOR_VER_MESON8: 825e68c0fcSMartin Blumenstingl if (metal_rev == 0x11111112) 835e68c0fcSMartin Blumenstingl soc_id = "Meson8m2 (S812)"; 845e68c0fcSMartin Blumenstingl else 855e68c0fcSMartin Blumenstingl soc_id = "Meson8 (S802)"; 865e68c0fcSMartin Blumenstingl 875e68c0fcSMartin Blumenstingl break; 885e68c0fcSMartin Blumenstingl 895e68c0fcSMartin Blumenstingl case MESON_SOCINFO_MAJOR_VER_MESON8B: 905e68c0fcSMartin Blumenstingl soc_id = "Meson8b (S805)"; 915e68c0fcSMartin Blumenstingl break; 925e68c0fcSMartin Blumenstingl 935e68c0fcSMartin Blumenstingl default: 945e68c0fcSMartin Blumenstingl soc_id = "Unknown"; 955e68c0fcSMartin Blumenstingl break; 965e68c0fcSMartin Blumenstingl } 975e68c0fcSMartin Blumenstingl 985e68c0fcSMartin Blumenstingl return kstrdup_const(soc_id, GFP_KERNEL); 995e68c0fcSMartin Blumenstingl } 1005e68c0fcSMartin Blumenstingl 1015e68c0fcSMartin Blumenstingl static const struct of_device_id meson_mx_socinfo_analog_top_ids[] = { 1025e68c0fcSMartin Blumenstingl { .compatible = "amlogic,meson8-analog-top", }, 1035e68c0fcSMartin Blumenstingl { .compatible = "amlogic,meson8b-analog-top", }, 1045e68c0fcSMartin Blumenstingl { /* sentinel */ } 1055e68c0fcSMartin Blumenstingl }; 1065e68c0fcSMartin Blumenstingl 10782a759c9Sweiyongjun (A) static int __init meson_mx_socinfo_init(void) 1085e68c0fcSMartin Blumenstingl { 1095e68c0fcSMartin Blumenstingl struct soc_device_attribute *soc_dev_attr; 1105e68c0fcSMartin Blumenstingl struct soc_device *soc_dev; 1115e68c0fcSMartin Blumenstingl struct device_node *np; 1125e68c0fcSMartin Blumenstingl struct regmap *assist_regmap, *bootrom_regmap, *analog_top_regmap; 1135e68c0fcSMartin Blumenstingl unsigned int major_ver, misc_ver, metal_rev = 0; 1145e68c0fcSMartin Blumenstingl int ret; 1155e68c0fcSMartin Blumenstingl 1165e68c0fcSMartin Blumenstingl assist_regmap = 1175e68c0fcSMartin Blumenstingl syscon_regmap_lookup_by_compatible("amlogic,meson-mx-assist"); 1185e68c0fcSMartin Blumenstingl if (IS_ERR(assist_regmap)) 1195e68c0fcSMartin Blumenstingl return PTR_ERR(assist_regmap); 1205e68c0fcSMartin Blumenstingl 1215e68c0fcSMartin Blumenstingl bootrom_regmap = 1225e68c0fcSMartin Blumenstingl syscon_regmap_lookup_by_compatible("amlogic,meson-mx-bootrom"); 1235e68c0fcSMartin Blumenstingl if (IS_ERR(bootrom_regmap)) 1245e68c0fcSMartin Blumenstingl return PTR_ERR(bootrom_regmap); 1255e68c0fcSMartin Blumenstingl 1265e68c0fcSMartin Blumenstingl np = of_find_matching_node(NULL, meson_mx_socinfo_analog_top_ids); 1275e68c0fcSMartin Blumenstingl if (np) { 1285e68c0fcSMartin Blumenstingl analog_top_regmap = syscon_node_to_regmap(np); 129*a2106f38SMiaoqian Lin of_node_put(np); 1305e68c0fcSMartin Blumenstingl if (IS_ERR(analog_top_regmap)) 1315e68c0fcSMartin Blumenstingl return PTR_ERR(analog_top_regmap); 1325e68c0fcSMartin Blumenstingl 1335e68c0fcSMartin Blumenstingl ret = regmap_read(analog_top_regmap, 1345e68c0fcSMartin Blumenstingl MESON_MX_ANALOG_TOP_METAL_REVISION, 1355e68c0fcSMartin Blumenstingl &metal_rev); 1365e68c0fcSMartin Blumenstingl if (ret) 1375e68c0fcSMartin Blumenstingl return ret; 1385e68c0fcSMartin Blumenstingl } 1395e68c0fcSMartin Blumenstingl 1405e68c0fcSMartin Blumenstingl ret = regmap_read(assist_regmap, MESON_MX_ASSIST_HW_REV, &major_ver); 1415e68c0fcSMartin Blumenstingl if (ret < 0) 1425e68c0fcSMartin Blumenstingl return ret; 1435e68c0fcSMartin Blumenstingl 1445e68c0fcSMartin Blumenstingl ret = regmap_read(bootrom_regmap, MESON_MX_BOOTROM_MISC_VER, 1455e68c0fcSMartin Blumenstingl &misc_ver); 1465e68c0fcSMartin Blumenstingl if (ret < 0) 1475e68c0fcSMartin Blumenstingl return ret; 1485e68c0fcSMartin Blumenstingl 1495e68c0fcSMartin Blumenstingl soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); 1505e68c0fcSMartin Blumenstingl if (!soc_dev_attr) 1515e68c0fcSMartin Blumenstingl return -ENODEV; 1525e68c0fcSMartin Blumenstingl 1535e68c0fcSMartin Blumenstingl soc_dev_attr->family = "Amlogic Meson"; 1545e68c0fcSMartin Blumenstingl 1555e68c0fcSMartin Blumenstingl np = of_find_node_by_path("/"); 1565e68c0fcSMartin Blumenstingl of_property_read_string(np, "model", &soc_dev_attr->machine); 1575e68c0fcSMartin Blumenstingl of_node_put(np); 1585e68c0fcSMartin Blumenstingl 1595e68c0fcSMartin Blumenstingl soc_dev_attr->revision = meson_mx_socinfo_revision(major_ver, misc_ver, 1605e68c0fcSMartin Blumenstingl metal_rev); 1615e68c0fcSMartin Blumenstingl soc_dev_attr->soc_id = meson_mx_socinfo_soc_id(major_ver, metal_rev); 1625e68c0fcSMartin Blumenstingl 1635e68c0fcSMartin Blumenstingl soc_dev = soc_device_register(soc_dev_attr); 1645e68c0fcSMartin Blumenstingl if (IS_ERR(soc_dev)) { 1655e68c0fcSMartin Blumenstingl kfree_const(soc_dev_attr->revision); 1665e68c0fcSMartin Blumenstingl kfree_const(soc_dev_attr->soc_id); 1675e68c0fcSMartin Blumenstingl kfree(soc_dev_attr); 1685e68c0fcSMartin Blumenstingl return PTR_ERR(soc_dev); 1695e68c0fcSMartin Blumenstingl } 1705e68c0fcSMartin Blumenstingl 1715e68c0fcSMartin Blumenstingl dev_info(soc_device_to_device(soc_dev), "Amlogic %s %s detected\n", 1725e68c0fcSMartin Blumenstingl soc_dev_attr->soc_id, soc_dev_attr->revision); 1735e68c0fcSMartin Blumenstingl 1745e68c0fcSMartin Blumenstingl return 0; 1755e68c0fcSMartin Blumenstingl } 1765e68c0fcSMartin Blumenstingl device_initcall(meson_mx_socinfo_init); 177