soc_id.c 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright 2020 Arm Limited
  4. */
  5. #define pr_fmt(fmt) "SMCCC: SOC_ID: " fmt
  6. #include <linux/arm-smccc.h>
  7. #include <linux/bitfield.h>
  8. #include <linux/device.h>
  9. #include <linux/module.h>
  10. #include <linux/kernel.h>
  11. #include <linux/slab.h>
  12. #include <linux/sys_soc.h>
  13. #define SMCCC_SOC_ID_JEP106_BANK_IDX_MASK GENMASK(30, 24)
  14. /*
  15. * As per the SMC Calling Convention specification v1.2 (ARM DEN 0028C)
  16. * Section 7.4 SMCCC_ARCH_SOC_ID bits[23:16] are JEP-106 identification
  17. * code with parity bit for the SiP. We can drop the parity bit.
  18. */
  19. #define SMCCC_SOC_ID_JEP106_ID_CODE_MASK GENMASK(22, 16)
  20. #define SMCCC_SOC_ID_IMP_DEF_SOC_ID_MASK GENMASK(15, 0)
  21. #define JEP106_BANK_CONT_CODE(x) \
  22. (u8)(FIELD_GET(SMCCC_SOC_ID_JEP106_BANK_IDX_MASK, (x)))
  23. #define JEP106_ID_CODE(x) \
  24. (u8)(FIELD_GET(SMCCC_SOC_ID_JEP106_ID_CODE_MASK, (x)))
  25. #define IMP_DEF_SOC_ID(x) \
  26. (u16)(FIELD_GET(SMCCC_SOC_ID_IMP_DEF_SOC_ID_MASK, (x)))
  27. static struct soc_device *soc_dev;
  28. static struct soc_device_attribute *soc_dev_attr;
  29. static int __init smccc_soc_init(void)
  30. {
  31. struct arm_smccc_res res;
  32. int soc_id_rev, soc_id_version;
  33. static char soc_id_str[20], soc_id_rev_str[12];
  34. static char soc_id_jep106_id_str[12];
  35. if (arm_smccc_get_version() < ARM_SMCCC_VERSION_1_2)
  36. return 0;
  37. if (arm_smccc_1_1_get_conduit() == SMCCC_CONDUIT_NONE) {
  38. pr_err("%s: invalid SMCCC conduit\n", __func__);
  39. return -EOPNOTSUPP;
  40. }
  41. arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
  42. ARM_SMCCC_ARCH_SOC_ID, &res);
  43. if ((int)res.a0 == SMCCC_RET_NOT_SUPPORTED) {
  44. pr_info("ARCH_SOC_ID not implemented, skipping ....\n");
  45. return 0;
  46. }
  47. soc_id_version = arm_smccc_get_version();
  48. soc_id_rev = res.a0;
  49. soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
  50. if (!soc_dev_attr)
  51. return -ENOMEM;
  52. sprintf(soc_id_rev_str, "0x%08x", soc_id_rev);
  53. sprintf(soc_id_jep106_id_str, "jep106:%02x%02x",
  54. JEP106_BANK_CONT_CODE(soc_id_version),
  55. JEP106_ID_CODE(soc_id_version));
  56. sprintf(soc_id_str, "%s:%04x", soc_id_jep106_id_str,
  57. IMP_DEF_SOC_ID(soc_id_version));
  58. soc_dev_attr->soc_id = soc_id_str;
  59. soc_dev_attr->revision = soc_id_rev_str;
  60. soc_dev_attr->family = soc_id_jep106_id_str;
  61. soc_dev = soc_device_register(soc_dev_attr);
  62. if (IS_ERR(soc_dev)) {
  63. kfree(soc_dev_attr);
  64. return PTR_ERR(soc_dev);
  65. }
  66. pr_info("ID = %s Revision = %s\n", soc_dev_attr->soc_id,
  67. soc_dev_attr->revision);
  68. return 0;
  69. }
  70. module_init(smccc_soc_init);
  71. static void __exit smccc_soc_exit(void)
  72. {
  73. if (soc_dev)
  74. soc_device_unregister(soc_dev);
  75. kfree(soc_dev_attr);
  76. }
  77. module_exit(smccc_soc_exit);