cppc.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Implement CPPC FFH helper routines for RISC-V.
  4. *
  5. * Copyright (C) 2024 Ventana Micro Systems Inc.
  6. */
  7. #include <acpi/cppc_acpi.h>
  8. #include <asm/csr.h>
  9. #include <asm/sbi.h>
  10. #define SBI_EXT_CPPC 0x43505043
  11. /* CPPC interfaces defined in SBI spec */
  12. #define SBI_CPPC_PROBE 0x0
  13. #define SBI_CPPC_READ 0x1
  14. #define SBI_CPPC_READ_HI 0x2
  15. #define SBI_CPPC_WRITE 0x3
  16. /* RISC-V FFH definitions from RISC-V FFH spec */
  17. #define FFH_CPPC_TYPE(r) (((r) & GENMASK_ULL(63, 60)) >> 60)
  18. #define FFH_CPPC_SBI_REG(r) ((r) & GENMASK(31, 0))
  19. #define FFH_CPPC_CSR_NUM(r) ((r) & GENMASK(11, 0))
  20. #define FFH_CPPC_SBI 0x1
  21. #define FFH_CPPC_CSR 0x2
  22. struct sbi_cppc_data {
  23. u64 val;
  24. u32 reg;
  25. struct sbiret ret;
  26. };
  27. static bool cppc_ext_present;
  28. static int __init sbi_cppc_init(void)
  29. {
  30. if (sbi_spec_version >= sbi_mk_version(2, 0) &&
  31. sbi_probe_extension(SBI_EXT_CPPC) > 0) {
  32. cppc_ext_present = true;
  33. } else {
  34. cppc_ext_present = false;
  35. }
  36. return 0;
  37. }
  38. device_initcall(sbi_cppc_init);
  39. static void sbi_cppc_read(void *read_data)
  40. {
  41. struct sbi_cppc_data *data = (struct sbi_cppc_data *)read_data;
  42. data->ret = sbi_ecall(SBI_EXT_CPPC, SBI_CPPC_READ,
  43. data->reg, 0, 0, 0, 0, 0);
  44. }
  45. static void sbi_cppc_write(void *write_data)
  46. {
  47. struct sbi_cppc_data *data = (struct sbi_cppc_data *)write_data;
  48. data->ret = sbi_ecall(SBI_EXT_CPPC, SBI_CPPC_WRITE,
  49. data->reg, data->val, 0, 0, 0, 0);
  50. }
  51. static void cppc_ffh_csr_read(void *read_data)
  52. {
  53. struct sbi_cppc_data *data = (struct sbi_cppc_data *)read_data;
  54. switch (data->reg) {
  55. /* Support only TIME CSR for now */
  56. case CSR_TIME:
  57. data->ret.value = csr_read(CSR_TIME);
  58. data->ret.error = 0;
  59. break;
  60. default:
  61. data->ret.error = -EINVAL;
  62. break;
  63. }
  64. }
  65. static void cppc_ffh_csr_write(void *write_data)
  66. {
  67. struct sbi_cppc_data *data = (struct sbi_cppc_data *)write_data;
  68. data->ret.error = -EINVAL;
  69. }
  70. /*
  71. * Refer to drivers/acpi/cppc_acpi.c for the description of the functions
  72. * below.
  73. */
  74. bool cpc_ffh_supported(void)
  75. {
  76. return true;
  77. }
  78. int cpc_read_ffh(int cpu, struct cpc_reg *reg, u64 *val)
  79. {
  80. struct sbi_cppc_data data;
  81. if (WARN_ON_ONCE(irqs_disabled()))
  82. return -EPERM;
  83. if (FFH_CPPC_TYPE(reg->address) == FFH_CPPC_SBI) {
  84. if (!cppc_ext_present)
  85. return -EINVAL;
  86. data.reg = FFH_CPPC_SBI_REG(reg->address);
  87. smp_call_function_single(cpu, sbi_cppc_read, &data, 1);
  88. *val = data.ret.value;
  89. return (data.ret.error) ? sbi_err_map_linux_errno(data.ret.error) : 0;
  90. } else if (FFH_CPPC_TYPE(reg->address) == FFH_CPPC_CSR) {
  91. data.reg = FFH_CPPC_CSR_NUM(reg->address);
  92. smp_call_function_single(cpu, cppc_ffh_csr_read, &data, 1);
  93. *val = data.ret.value;
  94. return data.ret.error;
  95. }
  96. return -EINVAL;
  97. }
  98. int cpc_write_ffh(int cpu, struct cpc_reg *reg, u64 val)
  99. {
  100. struct sbi_cppc_data data;
  101. if (WARN_ON_ONCE(irqs_disabled()))
  102. return -EPERM;
  103. if (FFH_CPPC_TYPE(reg->address) == FFH_CPPC_SBI) {
  104. if (!cppc_ext_present)
  105. return -EINVAL;
  106. data.reg = FFH_CPPC_SBI_REG(reg->address);
  107. data.val = val;
  108. smp_call_function_single(cpu, sbi_cppc_write, &data, 1);
  109. return (data.ret.error) ? sbi_err_map_linux_errno(data.ret.error) : 0;
  110. } else if (FFH_CPPC_TYPE(reg->address) == FFH_CPPC_CSR) {
  111. data.reg = FFH_CPPC_CSR_NUM(reg->address);
  112. data.val = val;
  113. smp_call_function_single(cpu, cppc_ffh_csr_write, &data, 1);
  114. return data.ret.error;
  115. }
  116. return -EINVAL;
  117. }