18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2014 Linaro Ltd. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author: Linus Walleij <linus.walleij@linaro.org> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci#include <linux/init.h> 88c2ecf20Sopenharmony_ci#include <linux/io.h> 98c2ecf20Sopenharmony_ci#include <linux/slab.h> 108c2ecf20Sopenharmony_ci#include <linux/sys_soc.h> 118c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 128c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 138c2ecf20Sopenharmony_ci#include <linux/regmap.h> 148c2ecf20Sopenharmony_ci#include <linux/of.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci/* System ID in syscon */ 178c2ecf20Sopenharmony_ci#define REALVIEW_SYS_ID_OFFSET 0x00 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic const struct of_device_id realview_soc_of_match[] = { 208c2ecf20Sopenharmony_ci { .compatible = "arm,realview-eb-soc", }, 218c2ecf20Sopenharmony_ci { .compatible = "arm,realview-pb1176-soc", }, 228c2ecf20Sopenharmony_ci { .compatible = "arm,realview-pb11mp-soc", }, 238c2ecf20Sopenharmony_ci { .compatible = "arm,realview-pba8-soc", }, 248c2ecf20Sopenharmony_ci { .compatible = "arm,realview-pbx-soc", }, 258c2ecf20Sopenharmony_ci { } 268c2ecf20Sopenharmony_ci}; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic u32 realview_coreid; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic const char *realview_arch_str(u32 id) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci switch ((id >> 8) & 0xf) { 338c2ecf20Sopenharmony_ci case 0x04: 348c2ecf20Sopenharmony_ci return "AHB"; 358c2ecf20Sopenharmony_ci case 0x05: 368c2ecf20Sopenharmony_ci return "Multi-layer AXI"; 378c2ecf20Sopenharmony_ci default: 388c2ecf20Sopenharmony_ci return "Unknown"; 398c2ecf20Sopenharmony_ci } 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic ssize_t 438c2ecf20Sopenharmony_cimanufacturer_show(struct device *dev, struct device_attribute *attr, char *buf) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci return sprintf(buf, "%02x\n", realview_coreid >> 24); 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(manufacturer); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic ssize_t 518c2ecf20Sopenharmony_ciboard_show(struct device *dev, struct device_attribute *attr, char *buf) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci return sprintf(buf, "HBI-%03x\n", ((realview_coreid >> 16) & 0xfff)); 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(board); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic ssize_t 598c2ecf20Sopenharmony_cifpga_show(struct device *dev, struct device_attribute *attr, char *buf) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci return sprintf(buf, "%s\n", realview_arch_str(realview_coreid)); 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(fpga); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic ssize_t 678c2ecf20Sopenharmony_cibuild_show(struct device *dev, struct device_attribute *attr, char *buf) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci return sprintf(buf, "%02x\n", (realview_coreid & 0xFF)); 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(build); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic struct attribute *realview_attrs[] = { 758c2ecf20Sopenharmony_ci &dev_attr_manufacturer.attr, 768c2ecf20Sopenharmony_ci &dev_attr_board.attr, 778c2ecf20Sopenharmony_ci &dev_attr_fpga.attr, 788c2ecf20Sopenharmony_ci &dev_attr_build.attr, 798c2ecf20Sopenharmony_ci NULL 808c2ecf20Sopenharmony_ci}; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ciATTRIBUTE_GROUPS(realview); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic int realview_soc_probe(struct platform_device *pdev) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci struct regmap *syscon_regmap; 878c2ecf20Sopenharmony_ci struct soc_device *soc_dev; 888c2ecf20Sopenharmony_ci struct soc_device_attribute *soc_dev_attr; 898c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 908c2ecf20Sopenharmony_ci int ret; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci syscon_regmap = syscon_regmap_lookup_by_phandle(np, "regmap"); 938c2ecf20Sopenharmony_ci if (IS_ERR(syscon_regmap)) 948c2ecf20Sopenharmony_ci return PTR_ERR(syscon_regmap); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); 978c2ecf20Sopenharmony_ci if (!soc_dev_attr) 988c2ecf20Sopenharmony_ci return -ENOMEM; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci ret = of_property_read_string(np, "compatible", 1018c2ecf20Sopenharmony_ci &soc_dev_attr->soc_id); 1028c2ecf20Sopenharmony_ci if (ret) 1038c2ecf20Sopenharmony_ci return -EINVAL; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci soc_dev_attr->machine = "RealView"; 1068c2ecf20Sopenharmony_ci soc_dev_attr->family = "Versatile"; 1078c2ecf20Sopenharmony_ci soc_dev_attr->custom_attr_group = realview_groups[0]; 1088c2ecf20Sopenharmony_ci soc_dev = soc_device_register(soc_dev_attr); 1098c2ecf20Sopenharmony_ci if (IS_ERR(soc_dev)) { 1108c2ecf20Sopenharmony_ci kfree(soc_dev_attr); 1118c2ecf20Sopenharmony_ci return -ENODEV; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci ret = regmap_read(syscon_regmap, REALVIEW_SYS_ID_OFFSET, 1148c2ecf20Sopenharmony_ci &realview_coreid); 1158c2ecf20Sopenharmony_ci if (ret) 1168c2ecf20Sopenharmony_ci return -ENODEV; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "RealView Syscon Core ID: 0x%08x, HBI-%03x\n", 1198c2ecf20Sopenharmony_ci realview_coreid, 1208c2ecf20Sopenharmony_ci ((realview_coreid >> 16) & 0xfff)); 1218c2ecf20Sopenharmony_ci /* FIXME: add attributes for SoC to sysfs */ 1228c2ecf20Sopenharmony_ci return 0; 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic struct platform_driver realview_soc_driver = { 1268c2ecf20Sopenharmony_ci .probe = realview_soc_probe, 1278c2ecf20Sopenharmony_ci .driver = { 1288c2ecf20Sopenharmony_ci .name = "realview-soc", 1298c2ecf20Sopenharmony_ci .of_match_table = realview_soc_of_match, 1308c2ecf20Sopenharmony_ci }, 1318c2ecf20Sopenharmony_ci}; 1328c2ecf20Sopenharmony_cibuiltin_platform_driver(realview_soc_driver); 133