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