18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2017 BayLibre, SAS 38c2ecf20Sopenharmony_ci * Author: Neil Armstrong <narmstrong@baylibre.com> 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * SPDX-License-Identifier: GPL-2.0+ 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/io.h> 98c2ecf20Sopenharmony_ci#include <linux/of.h> 108c2ecf20Sopenharmony_ci#include <linux/of_address.h> 118c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 128c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <linux/sys_soc.h> 158c2ecf20Sopenharmony_ci#include <linux/bitfield.h> 168c2ecf20Sopenharmony_ci#include <linux/regmap.h> 178c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define AO_SEC_SD_CFG8 0xe0 208c2ecf20Sopenharmony_ci#define AO_SEC_SOCINFO_OFFSET AO_SEC_SD_CFG8 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define SOCINFO_MAJOR GENMASK(31, 24) 238c2ecf20Sopenharmony_ci#define SOCINFO_PACK GENMASK(23, 16) 248c2ecf20Sopenharmony_ci#define SOCINFO_MINOR GENMASK(15, 8) 258c2ecf20Sopenharmony_ci#define SOCINFO_MISC GENMASK(7, 0) 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic const struct meson_gx_soc_id { 288c2ecf20Sopenharmony_ci const char *name; 298c2ecf20Sopenharmony_ci unsigned int id; 308c2ecf20Sopenharmony_ci} soc_ids[] = { 318c2ecf20Sopenharmony_ci { "GXBB", 0x1f }, 328c2ecf20Sopenharmony_ci { "GXTVBB", 0x20 }, 338c2ecf20Sopenharmony_ci { "GXL", 0x21 }, 348c2ecf20Sopenharmony_ci { "GXM", 0x22 }, 358c2ecf20Sopenharmony_ci { "TXL", 0x23 }, 368c2ecf20Sopenharmony_ci { "TXLX", 0x24 }, 378c2ecf20Sopenharmony_ci { "AXG", 0x25 }, 388c2ecf20Sopenharmony_ci { "GXLX", 0x26 }, 398c2ecf20Sopenharmony_ci { "TXHD", 0x27 }, 408c2ecf20Sopenharmony_ci { "G12A", 0x28 }, 418c2ecf20Sopenharmony_ci { "G12B", 0x29 }, 428c2ecf20Sopenharmony_ci { "SM1", 0x2b }, 438c2ecf20Sopenharmony_ci { "A1", 0x2c }, 448c2ecf20Sopenharmony_ci}; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic const struct meson_gx_package_id { 478c2ecf20Sopenharmony_ci const char *name; 488c2ecf20Sopenharmony_ci unsigned int major_id; 498c2ecf20Sopenharmony_ci unsigned int pack_id; 508c2ecf20Sopenharmony_ci unsigned int pack_mask; 518c2ecf20Sopenharmony_ci} soc_packages[] = { 528c2ecf20Sopenharmony_ci { "S905", 0x1f, 0, 0x20 }, /* pack_id != 0x20 */ 538c2ecf20Sopenharmony_ci { "S905H", 0x1f, 0x3, 0xf }, /* pack_id & 0xf == 0x3 */ 548c2ecf20Sopenharmony_ci { "S905M", 0x1f, 0x20, 0xf0 }, /* pack_id == 0x20 */ 558c2ecf20Sopenharmony_ci { "S905D", 0x21, 0, 0xf0 }, 568c2ecf20Sopenharmony_ci { "S905X", 0x21, 0x80, 0xf0 }, 578c2ecf20Sopenharmony_ci { "S905W", 0x21, 0xa0, 0xf0 }, 588c2ecf20Sopenharmony_ci { "S905L", 0x21, 0xc0, 0xf0 }, 598c2ecf20Sopenharmony_ci { "S905M2", 0x21, 0xe0, 0xf0 }, 608c2ecf20Sopenharmony_ci { "S805X", 0x21, 0x30, 0xf0 }, 618c2ecf20Sopenharmony_ci { "S805Y", 0x21, 0xb0, 0xf0 }, 628c2ecf20Sopenharmony_ci { "S912", 0x22, 0, 0x0 }, /* Only S912 is known for GXM */ 638c2ecf20Sopenharmony_ci { "962X", 0x24, 0x10, 0xf0 }, 648c2ecf20Sopenharmony_ci { "962E", 0x24, 0x20, 0xf0 }, 658c2ecf20Sopenharmony_ci { "A113X", 0x25, 0x37, 0xff }, 668c2ecf20Sopenharmony_ci { "A113D", 0x25, 0x22, 0xff }, 678c2ecf20Sopenharmony_ci { "S905D2", 0x28, 0x10, 0xf0 }, 688c2ecf20Sopenharmony_ci { "S905X2", 0x28, 0x40, 0xf0 }, 698c2ecf20Sopenharmony_ci { "A311D", 0x29, 0x10, 0xf0 }, 708c2ecf20Sopenharmony_ci { "S922X", 0x29, 0x40, 0xf0 }, 718c2ecf20Sopenharmony_ci { "S905D3", 0x2b, 0x4, 0xf5 }, 728c2ecf20Sopenharmony_ci { "S905X3", 0x2b, 0x5, 0xf5 }, 738c2ecf20Sopenharmony_ci { "S905X3", 0x2b, 0x10, 0x3f }, 748c2ecf20Sopenharmony_ci { "S905D3", 0x2b, 0x30, 0x3f }, 758c2ecf20Sopenharmony_ci { "A113L", 0x2c, 0x0, 0xf8 }, 768c2ecf20Sopenharmony_ci}; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic inline unsigned int socinfo_to_major(u32 socinfo) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci return FIELD_GET(SOCINFO_MAJOR, socinfo); 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic inline unsigned int socinfo_to_minor(u32 socinfo) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci return FIELD_GET(SOCINFO_MINOR, socinfo); 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic inline unsigned int socinfo_to_pack(u32 socinfo) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci return FIELD_GET(SOCINFO_PACK, socinfo); 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic inline unsigned int socinfo_to_misc(u32 socinfo) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci return FIELD_GET(SOCINFO_MISC, socinfo); 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic const char *socinfo_to_package_id(u32 socinfo) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci unsigned int pack = socinfo_to_pack(socinfo); 1018c2ecf20Sopenharmony_ci unsigned int major = socinfo_to_major(socinfo); 1028c2ecf20Sopenharmony_ci int i; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci for (i = 0 ; i < ARRAY_SIZE(soc_packages) ; ++i) { 1058c2ecf20Sopenharmony_ci if (soc_packages[i].major_id == major && 1068c2ecf20Sopenharmony_ci soc_packages[i].pack_id == 1078c2ecf20Sopenharmony_ci (pack & soc_packages[i].pack_mask)) 1088c2ecf20Sopenharmony_ci return soc_packages[i].name; 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci return "Unknown"; 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic const char *socinfo_to_soc_id(u32 socinfo) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci unsigned int id = socinfo_to_major(socinfo); 1178c2ecf20Sopenharmony_ci int i; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci for (i = 0 ; i < ARRAY_SIZE(soc_ids) ; ++i) { 1208c2ecf20Sopenharmony_ci if (soc_ids[i].id == id) 1218c2ecf20Sopenharmony_ci return soc_ids[i].name; 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci return "Unknown"; 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic int __init meson_gx_socinfo_init(void) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci struct soc_device_attribute *soc_dev_attr; 1308c2ecf20Sopenharmony_ci struct soc_device *soc_dev; 1318c2ecf20Sopenharmony_ci struct device_node *np; 1328c2ecf20Sopenharmony_ci struct regmap *regmap; 1338c2ecf20Sopenharmony_ci unsigned int socinfo; 1348c2ecf20Sopenharmony_ci struct device *dev; 1358c2ecf20Sopenharmony_ci int ret; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* look up for chipid node */ 1388c2ecf20Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, "amlogic,meson-gx-ao-secure"); 1398c2ecf20Sopenharmony_ci if (!np) 1408c2ecf20Sopenharmony_ci return -ENODEV; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci /* check if interface is enabled */ 1438c2ecf20Sopenharmony_ci if (!of_device_is_available(np)) { 1448c2ecf20Sopenharmony_ci of_node_put(np); 1458c2ecf20Sopenharmony_ci return -ENODEV; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci /* check if chip-id is available */ 1498c2ecf20Sopenharmony_ci if (!of_property_read_bool(np, "amlogic,has-chip-id")) { 1508c2ecf20Sopenharmony_ci of_node_put(np); 1518c2ecf20Sopenharmony_ci return -ENODEV; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci /* node should be a syscon */ 1558c2ecf20Sopenharmony_ci regmap = syscon_node_to_regmap(np); 1568c2ecf20Sopenharmony_ci of_node_put(np); 1578c2ecf20Sopenharmony_ci if (IS_ERR(regmap)) { 1588c2ecf20Sopenharmony_ci pr_err("%s: failed to get regmap\n", __func__); 1598c2ecf20Sopenharmony_ci return -ENODEV; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci ret = regmap_read(regmap, AO_SEC_SOCINFO_OFFSET, &socinfo); 1638c2ecf20Sopenharmony_ci if (ret < 0) 1648c2ecf20Sopenharmony_ci return ret; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci if (!socinfo) { 1678c2ecf20Sopenharmony_ci pr_err("%s: invalid chipid value\n", __func__); 1688c2ecf20Sopenharmony_ci return -EINVAL; 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); 1728c2ecf20Sopenharmony_ci if (!soc_dev_attr) 1738c2ecf20Sopenharmony_ci return -ENODEV; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci soc_dev_attr->family = "Amlogic Meson"; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci np = of_find_node_by_path("/"); 1788c2ecf20Sopenharmony_ci of_property_read_string(np, "model", &soc_dev_attr->machine); 1798c2ecf20Sopenharmony_ci of_node_put(np); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%x:%x - %x:%x", 1828c2ecf20Sopenharmony_ci socinfo_to_major(socinfo), 1838c2ecf20Sopenharmony_ci socinfo_to_minor(socinfo), 1848c2ecf20Sopenharmony_ci socinfo_to_pack(socinfo), 1858c2ecf20Sopenharmony_ci socinfo_to_misc(socinfo)); 1868c2ecf20Sopenharmony_ci soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%s (%s)", 1878c2ecf20Sopenharmony_ci socinfo_to_soc_id(socinfo), 1888c2ecf20Sopenharmony_ci socinfo_to_package_id(socinfo)); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci soc_dev = soc_device_register(soc_dev_attr); 1918c2ecf20Sopenharmony_ci if (IS_ERR(soc_dev)) { 1928c2ecf20Sopenharmony_ci kfree(soc_dev_attr->revision); 1938c2ecf20Sopenharmony_ci kfree_const(soc_dev_attr->soc_id); 1948c2ecf20Sopenharmony_ci kfree(soc_dev_attr); 1958c2ecf20Sopenharmony_ci return PTR_ERR(soc_dev); 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci dev = soc_device_to_device(soc_dev); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci dev_info(dev, "Amlogic Meson %s Revision %x:%x (%x:%x) Detected\n", 2008c2ecf20Sopenharmony_ci soc_dev_attr->soc_id, 2018c2ecf20Sopenharmony_ci socinfo_to_major(socinfo), 2028c2ecf20Sopenharmony_ci socinfo_to_minor(socinfo), 2038c2ecf20Sopenharmony_ci socinfo_to_pack(socinfo), 2048c2ecf20Sopenharmony_ci socinfo_to_misc(socinfo)); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci return 0; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_cidevice_initcall(meson_gx_socinfo_init); 209