// SPDX-License-Identifier: GPL-2.0 /* * TI K3 SoC info driver * * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com */ #include #include #include #include #include #include #include #include #define CTRLMMR_WKUP_JTAGID_REG 0 /* * Bits: * 31-28 VARIANT Device variant * 27-12 PARTNO Part number * 11-1 MFG Indicates TI as manufacturer (0x17) * 1 Always 1 */ #define CTRLMMR_WKUP_JTAGID_VARIANT_SHIFT (28) #define CTRLMMR_WKUP_JTAGID_VARIANT_MASK GENMASK(31, 28) #define CTRLMMR_WKUP_JTAGID_PARTNO_SHIFT (12) #define CTRLMMR_WKUP_JTAGID_PARTNO_MASK GENMASK(27, 12) #define CTRLMMR_WKUP_JTAGID_MFG_SHIFT (1) #define CTRLMMR_WKUP_JTAGID_MFG_MASK GENMASK(11, 1) #define CTRLMMR_WKUP_JTAGID_MFG_TI 0x17 static const struct k3_soc_id { unsigned int id; const char *family_name; } k3_soc_ids[] = { { 0xBB5A, "AM65X" }, { 0xBB64, "J721E" }, { 0xBB6D, "J7200" }, { 0xBB38, "AM64X" }, { 0xBB75, "J721S2"}, { 0xBB7E, "AM62X" }, }; static int k3_chipinfo_partno_to_names(unsigned int partno, struct soc_device_attribute *soc_dev_attr) { int i; for (i = 0; i < ARRAY_SIZE(k3_soc_ids); i++) if (partno == k3_soc_ids[i].id) { soc_dev_attr->family = k3_soc_ids[i].family_name; return 0; } return -EINVAL; } static int k3_chipinfo_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; struct soc_device_attribute *soc_dev_attr; struct device *dev = &pdev->dev; struct soc_device *soc_dev; struct regmap *regmap; u32 partno_id; u32 variant; u32 jtag_id; u32 mfg; int ret; regmap = device_node_to_regmap(node); if (IS_ERR(regmap)) return PTR_ERR(regmap); ret = regmap_read(regmap, CTRLMMR_WKUP_JTAGID_REG, &jtag_id); if (ret < 0) return ret; mfg = (jtag_id & CTRLMMR_WKUP_JTAGID_MFG_MASK) >> CTRLMMR_WKUP_JTAGID_MFG_SHIFT; if (mfg != CTRLMMR_WKUP_JTAGID_MFG_TI) { dev_err(dev, "Invalid MFG SoC\n"); return -ENODEV; } variant = (jtag_id & CTRLMMR_WKUP_JTAGID_VARIANT_MASK) >> CTRLMMR_WKUP_JTAGID_VARIANT_SHIFT; variant++; partno_id = (jtag_id & CTRLMMR_WKUP_JTAGID_PARTNO_MASK) >> CTRLMMR_WKUP_JTAGID_PARTNO_SHIFT; soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); if (!soc_dev_attr) return -ENOMEM; soc_dev_attr->revision = kasprintf(GFP_KERNEL, "SR%x.0", variant); if (!soc_dev_attr->revision) { ret = -ENOMEM; goto err; } ret = k3_chipinfo_partno_to_names(partno_id, soc_dev_attr); if (ret) { dev_err(dev, "Unknown SoC JTAGID[0x%08X]\n", jtag_id); ret = -ENODEV; goto err_free_rev; } node = of_find_node_by_path("/"); of_property_read_string(node, "model", &soc_dev_attr->machine); of_node_put(node); soc_dev = soc_device_register(soc_dev_attr); if (IS_ERR(soc_dev)) { ret = PTR_ERR(soc_dev); goto err_free_rev; } dev_info(dev, "Family:%s rev:%s JTAGID[0x%08x] Detected\n", soc_dev_attr->family, soc_dev_attr->revision, jtag_id); return 0; err_free_rev: kfree(soc_dev_attr->revision); err: kfree(soc_dev_attr); return ret; } static const struct of_device_id k3_chipinfo_of_match[] = { { .compatible = "ti,am654-chipid", }, { /* sentinel */ }, }; static struct platform_driver k3_chipinfo_driver = { .driver = { .name = "k3-chipinfo", .of_match_table = k3_chipinfo_of_match, }, .probe = k3_chipinfo_probe, }; static int __init k3_chipinfo_init(void) { return platform_driver_register(&k3_chipinfo_driver); } subsys_initcall(k3_chipinfo_init);