18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com> 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * SPDX-License-Identifier: GPL-2.0+ 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/io.h> 88c2ecf20Sopenharmony_ci#include <linux/of.h> 98c2ecf20Sopenharmony_ci#include <linux/of_address.h> 108c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 118c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include <linux/sys_soc.h> 148c2ecf20Sopenharmony_ci#include <linux/bitfield.h> 158c2ecf20Sopenharmony_ci#include <linux/regmap.h> 168c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define MESON_SOCINFO_MAJOR_VER_MESON6 0x16 198c2ecf20Sopenharmony_ci#define MESON_SOCINFO_MAJOR_VER_MESON8 0x19 208c2ecf20Sopenharmony_ci#define MESON_SOCINFO_MAJOR_VER_MESON8B 0x1b 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define MESON_MX_ASSIST_HW_REV 0x14c 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define MESON_MX_ANALOG_TOP_METAL_REVISION 0x0 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define MESON_MX_BOOTROM_MISC_VER 0x4 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic const char *meson_mx_socinfo_revision(unsigned int major_ver, 298c2ecf20Sopenharmony_ci unsigned int misc_ver, 308c2ecf20Sopenharmony_ci unsigned int metal_rev) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci unsigned int minor_ver; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci switch (major_ver) { 358c2ecf20Sopenharmony_ci case MESON_SOCINFO_MAJOR_VER_MESON6: 368c2ecf20Sopenharmony_ci minor_ver = 0xa; 378c2ecf20Sopenharmony_ci break; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci case MESON_SOCINFO_MAJOR_VER_MESON8: 408c2ecf20Sopenharmony_ci if (metal_rev == 0x11111112) 418c2ecf20Sopenharmony_ci major_ver = 0x1d; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci if (metal_rev == 0x11111111 || metal_rev == 0x11111112) 448c2ecf20Sopenharmony_ci minor_ver = 0xa; 458c2ecf20Sopenharmony_ci else if (metal_rev == 0x11111113) 468c2ecf20Sopenharmony_ci minor_ver = 0xb; 478c2ecf20Sopenharmony_ci else if (metal_rev == 0x11111133) 488c2ecf20Sopenharmony_ci minor_ver = 0xc; 498c2ecf20Sopenharmony_ci else 508c2ecf20Sopenharmony_ci minor_ver = 0xd; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci break; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci case MESON_SOCINFO_MAJOR_VER_MESON8B: 558c2ecf20Sopenharmony_ci if (metal_rev == 0x11111111) 568c2ecf20Sopenharmony_ci minor_ver = 0xa; 578c2ecf20Sopenharmony_ci else 588c2ecf20Sopenharmony_ci minor_ver = 0xb; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci break; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci default: 638c2ecf20Sopenharmony_ci minor_ver = 0x0; 648c2ecf20Sopenharmony_ci break; 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci return kasprintf(GFP_KERNEL, "Rev%X (%x - 0:%X)", minor_ver, major_ver, 688c2ecf20Sopenharmony_ci misc_ver); 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic const char *meson_mx_socinfo_soc_id(unsigned int major_ver, 728c2ecf20Sopenharmony_ci unsigned int metal_rev) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci const char *soc_id; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci switch (major_ver) { 778c2ecf20Sopenharmony_ci case MESON_SOCINFO_MAJOR_VER_MESON6: 788c2ecf20Sopenharmony_ci soc_id = "Meson6 (AML8726-MX)"; 798c2ecf20Sopenharmony_ci break; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci case MESON_SOCINFO_MAJOR_VER_MESON8: 828c2ecf20Sopenharmony_ci if (metal_rev == 0x11111112) 838c2ecf20Sopenharmony_ci soc_id = "Meson8m2 (S812)"; 848c2ecf20Sopenharmony_ci else 858c2ecf20Sopenharmony_ci soc_id = "Meson8 (S802)"; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci break; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci case MESON_SOCINFO_MAJOR_VER_MESON8B: 908c2ecf20Sopenharmony_ci soc_id = "Meson8b (S805)"; 918c2ecf20Sopenharmony_ci break; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci default: 948c2ecf20Sopenharmony_ci soc_id = "Unknown"; 958c2ecf20Sopenharmony_ci break; 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci return kstrdup_const(soc_id, GFP_KERNEL); 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic const struct of_device_id meson_mx_socinfo_analog_top_ids[] = { 1028c2ecf20Sopenharmony_ci { .compatible = "amlogic,meson8-analog-top", }, 1038c2ecf20Sopenharmony_ci { .compatible = "amlogic,meson8b-analog-top", }, 1048c2ecf20Sopenharmony_ci { /* sentinel */ } 1058c2ecf20Sopenharmony_ci}; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic int __init meson_mx_socinfo_init(void) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci struct soc_device_attribute *soc_dev_attr; 1108c2ecf20Sopenharmony_ci struct soc_device *soc_dev; 1118c2ecf20Sopenharmony_ci struct device_node *np; 1128c2ecf20Sopenharmony_ci struct regmap *assist_regmap, *bootrom_regmap, *analog_top_regmap; 1138c2ecf20Sopenharmony_ci unsigned int major_ver, misc_ver, metal_rev = 0; 1148c2ecf20Sopenharmony_ci int ret; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci assist_regmap = 1178c2ecf20Sopenharmony_ci syscon_regmap_lookup_by_compatible("amlogic,meson-mx-assist"); 1188c2ecf20Sopenharmony_ci if (IS_ERR(assist_regmap)) 1198c2ecf20Sopenharmony_ci return PTR_ERR(assist_regmap); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci bootrom_regmap = 1228c2ecf20Sopenharmony_ci syscon_regmap_lookup_by_compatible("amlogic,meson-mx-bootrom"); 1238c2ecf20Sopenharmony_ci if (IS_ERR(bootrom_regmap)) 1248c2ecf20Sopenharmony_ci return PTR_ERR(bootrom_regmap); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci np = of_find_matching_node(NULL, meson_mx_socinfo_analog_top_ids); 1278c2ecf20Sopenharmony_ci if (np) { 1288c2ecf20Sopenharmony_ci analog_top_regmap = syscon_node_to_regmap(np); 1298c2ecf20Sopenharmony_ci of_node_put(np); 1308c2ecf20Sopenharmony_ci if (IS_ERR(analog_top_regmap)) 1318c2ecf20Sopenharmony_ci return PTR_ERR(analog_top_regmap); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci ret = regmap_read(analog_top_regmap, 1348c2ecf20Sopenharmony_ci MESON_MX_ANALOG_TOP_METAL_REVISION, 1358c2ecf20Sopenharmony_ci &metal_rev); 1368c2ecf20Sopenharmony_ci if (ret) 1378c2ecf20Sopenharmony_ci return ret; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci ret = regmap_read(assist_regmap, MESON_MX_ASSIST_HW_REV, &major_ver); 1418c2ecf20Sopenharmony_ci if (ret < 0) 1428c2ecf20Sopenharmony_ci return ret; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci ret = regmap_read(bootrom_regmap, MESON_MX_BOOTROM_MISC_VER, 1458c2ecf20Sopenharmony_ci &misc_ver); 1468c2ecf20Sopenharmony_ci if (ret < 0) 1478c2ecf20Sopenharmony_ci return ret; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); 1508c2ecf20Sopenharmony_ci if (!soc_dev_attr) 1518c2ecf20Sopenharmony_ci return -ENODEV; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci soc_dev_attr->family = "Amlogic Meson"; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci np = of_find_node_by_path("/"); 1568c2ecf20Sopenharmony_ci of_property_read_string(np, "model", &soc_dev_attr->machine); 1578c2ecf20Sopenharmony_ci of_node_put(np); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci soc_dev_attr->revision = meson_mx_socinfo_revision(major_ver, misc_ver, 1608c2ecf20Sopenharmony_ci metal_rev); 1618c2ecf20Sopenharmony_ci soc_dev_attr->soc_id = meson_mx_socinfo_soc_id(major_ver, metal_rev); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci soc_dev = soc_device_register(soc_dev_attr); 1648c2ecf20Sopenharmony_ci if (IS_ERR(soc_dev)) { 1658c2ecf20Sopenharmony_ci kfree_const(soc_dev_attr->revision); 1668c2ecf20Sopenharmony_ci kfree_const(soc_dev_attr->soc_id); 1678c2ecf20Sopenharmony_ci kfree(soc_dev_attr); 1688c2ecf20Sopenharmony_ci return PTR_ERR(soc_dev); 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci dev_info(soc_device_to_device(soc_dev), "Amlogic %s %s detected\n", 1728c2ecf20Sopenharmony_ci soc_dev_attr->soc_id, soc_dev_attr->revision); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci return 0; 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_cidevice_initcall(meson_mx_socinfo_init); 177