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#define INTEGRATOR_HDR_ID_OFFSET 0x00 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic u32 integrator_coreid; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic const struct of_device_id integrator_cm_match[] = { 218c2ecf20Sopenharmony_ci { .compatible = "arm,core-module-integrator", }, 228c2ecf20Sopenharmony_ci { } 238c2ecf20Sopenharmony_ci}; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic const char *integrator_arch_str(u32 id) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci switch ((id >> 16) & 0xff) { 288c2ecf20Sopenharmony_ci case 0x00: 298c2ecf20Sopenharmony_ci return "ASB little-endian"; 308c2ecf20Sopenharmony_ci case 0x01: 318c2ecf20Sopenharmony_ci return "AHB little-endian"; 328c2ecf20Sopenharmony_ci case 0x03: 338c2ecf20Sopenharmony_ci return "AHB-Lite system bus, bi-endian"; 348c2ecf20Sopenharmony_ci case 0x04: 358c2ecf20Sopenharmony_ci return "AHB"; 368c2ecf20Sopenharmony_ci case 0x08: 378c2ecf20Sopenharmony_ci return "AHB system bus, ASB processor bus"; 388c2ecf20Sopenharmony_ci default: 398c2ecf20Sopenharmony_ci return "Unknown"; 408c2ecf20Sopenharmony_ci } 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic const char *integrator_fpga_str(u32 id) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci switch ((id >> 12) & 0xf) { 468c2ecf20Sopenharmony_ci case 0x01: 478c2ecf20Sopenharmony_ci return "XC4062"; 488c2ecf20Sopenharmony_ci case 0x02: 498c2ecf20Sopenharmony_ci return "XC4085"; 508c2ecf20Sopenharmony_ci case 0x03: 518c2ecf20Sopenharmony_ci return "XVC600"; 528c2ecf20Sopenharmony_ci case 0x04: 538c2ecf20Sopenharmony_ci return "EPM7256AE (Altera PLD)"; 548c2ecf20Sopenharmony_ci default: 558c2ecf20Sopenharmony_ci return "Unknown"; 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic ssize_t 608c2ecf20Sopenharmony_cimanufacturer_show(struct device *dev, struct device_attribute *attr, char *buf) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci return sprintf(buf, "%02x\n", integrator_coreid >> 24); 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(manufacturer); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic ssize_t 688c2ecf20Sopenharmony_ciarch_show(struct device *dev, struct device_attribute *attr, char *buf) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci return sprintf(buf, "%s\n", integrator_arch_str(integrator_coreid)); 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(arch); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic ssize_t 768c2ecf20Sopenharmony_cifpga_show(struct device *dev, struct device_attribute *attr, char *buf) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci return sprintf(buf, "%s\n", integrator_fpga_str(integrator_coreid)); 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(fpga); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic ssize_t 848c2ecf20Sopenharmony_cibuild_show(struct device *dev, struct device_attribute *attr, char *buf) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci return sprintf(buf, "%02x\n", (integrator_coreid >> 4) & 0xFF); 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(build); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic struct attribute *integrator_attrs[] = { 928c2ecf20Sopenharmony_ci &dev_attr_manufacturer.attr, 938c2ecf20Sopenharmony_ci &dev_attr_arch.attr, 948c2ecf20Sopenharmony_ci &dev_attr_fpga.attr, 958c2ecf20Sopenharmony_ci &dev_attr_build.attr, 968c2ecf20Sopenharmony_ci NULL 978c2ecf20Sopenharmony_ci}; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ciATTRIBUTE_GROUPS(integrator); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic int __init integrator_soc_init(void) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci struct regmap *syscon_regmap; 1048c2ecf20Sopenharmony_ci struct soc_device *soc_dev; 1058c2ecf20Sopenharmony_ci struct soc_device_attribute *soc_dev_attr; 1068c2ecf20Sopenharmony_ci struct device_node *np; 1078c2ecf20Sopenharmony_ci struct device *dev; 1088c2ecf20Sopenharmony_ci u32 val; 1098c2ecf20Sopenharmony_ci int ret; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci np = of_find_matching_node(NULL, integrator_cm_match); 1128c2ecf20Sopenharmony_ci if (!np) 1138c2ecf20Sopenharmony_ci return -ENODEV; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci syscon_regmap = syscon_node_to_regmap(np); 1168c2ecf20Sopenharmony_ci if (IS_ERR(syscon_regmap)) 1178c2ecf20Sopenharmony_ci return PTR_ERR(syscon_regmap); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci ret = regmap_read(syscon_regmap, INTEGRATOR_HDR_ID_OFFSET, 1208c2ecf20Sopenharmony_ci &val); 1218c2ecf20Sopenharmony_ci if (ret) 1228c2ecf20Sopenharmony_ci return -ENODEV; 1238c2ecf20Sopenharmony_ci integrator_coreid = val; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); 1268c2ecf20Sopenharmony_ci if (!soc_dev_attr) 1278c2ecf20Sopenharmony_ci return -ENOMEM; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci soc_dev_attr->soc_id = "Integrator"; 1308c2ecf20Sopenharmony_ci soc_dev_attr->machine = "Integrator"; 1318c2ecf20Sopenharmony_ci soc_dev_attr->family = "Versatile"; 1328c2ecf20Sopenharmony_ci soc_dev_attr->custom_attr_group = integrator_groups[0]; 1338c2ecf20Sopenharmony_ci soc_dev = soc_device_register(soc_dev_attr); 1348c2ecf20Sopenharmony_ci if (IS_ERR(soc_dev)) { 1358c2ecf20Sopenharmony_ci kfree(soc_dev_attr); 1368c2ecf20Sopenharmony_ci return -ENODEV; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci dev = soc_device_to_device(soc_dev); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci dev_info(dev, "Detected ARM core module:\n"); 1418c2ecf20Sopenharmony_ci dev_info(dev, " Manufacturer: %02x\n", (val >> 24)); 1428c2ecf20Sopenharmony_ci dev_info(dev, " Architecture: %s\n", integrator_arch_str(val)); 1438c2ecf20Sopenharmony_ci dev_info(dev, " FPGA: %s\n", integrator_fpga_str(val)); 1448c2ecf20Sopenharmony_ci dev_info(dev, " Build: %02x\n", (val >> 4) & 0xFF); 1458c2ecf20Sopenharmony_ci dev_info(dev, " Rev: %c\n", ('A' + (val & 0x03))); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci return 0; 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_cidevice_initcall(integrator_soc_init); 150