1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
//! Chapter 14. CPPC Extension (EID #0x43505043 "CPPC")

use crate::binary::sbi_call_1;
#[cfg(target_pointer_width = "64")]
use crate::binary::sbi_call_2;
#[cfg(target_pointer_width = "32")]
use crate::binary::sbi_call_3;
use sbi_spec::{
    binary::SbiRet,
    cppc::{EID_CPPC, PROBE, READ, READ_HI, WRITE},
};

/// Probe whether the CPPC register is implemented or not by the platform.
///
/// # Parameters
///
/// The `cppc_reg_id` parameter specifies the CPPC register ID.
///
/// # Return value
///
/// If the register is implemented, `SbiRet.value` will contain the register width.
/// If the register is not implemented, `SbiRet.value` will be set to 0.
///
/// The possible error codes returned in `SbiRet.error` are shown in the table below:
///
/// | Return code               | Description
/// |:--------------------------|:----------------------------------------------
/// | `SbiRet::success()`       | Probe completed successfully.
/// | `SbiRet::invalid_param()` | `cppc_reg_id` is reserved.
/// | `SbiRet::failed()`        | The probe request failed for unspecified or unknown other reasons.
///
/// This function is defined in RISC-V SBI Specification chapter 14.1.
#[inline]
pub fn cppc_probe(cppc_reg_id: u32) -> SbiRet {
    sbi_call_1(EID_CPPC, PROBE, cppc_reg_id as _)
}

/// Read the CPPC register identified by given `cppc_reg_id`.
///
/// # Parameters
///
/// The `cppc_reg_id` parameter specifies the CPPC register ID.
///
/// # Return value
///
/// `SbiRet.value` will contain the register value. When supervisor mode XLEN is 32, the `SbiRet.value`
/// will only contain the lower 32 bits of the CPPC register value.
///
/// The possible error codes returned in `SbiRet.error` are shown in the table below:
///
/// | Return code               | Description
/// |:--------------------------|:----------------------------------------------
/// | `SbiRet::success()`       | Read completed successfully.
/// | `SbiRet::invalid_param()` | `cppc_reg_id` is reserved.
/// | `SbiRet::not_supported()` | `cppc_reg_id` is not implemented by the platform.
/// | `SbiRet::denied()`        | `cppc_reg_id` is a write-only register.
/// | `SbiRet::failed()`        | The read request failed for unspecified or unknown other reasons.
///
/// This function is defined in RISC-V SBI Specification chapter 14.2.
#[inline]
pub fn cppc_read(cppc_reg_id: u32) -> SbiRet {
    sbi_call_1(EID_CPPC, READ, cppc_reg_id as _)
}

/// Read the upper 32-bit value of the CPPC register identified by `cppc_reg_id`.
///
/// # Parameters
///
/// The `cppc_reg_id` parameter specifies the CPPC register ID.
///
/// # Return value
///
/// `SbiRet.value` will contain the upper 32 bits of the register value. This function always
/// returns zero in `SbiRet.value` when supervisor mode XLEN is 64 or higher.
///
/// The possible error codes returned in `SbiRet.error` are shown in the table below:
///
/// | Return code               | Description
/// |:--------------------------|:----------------------------------------------
/// | `SbiRet::success()`       | Read completed successfully.
/// | `SbiRet::invalid_param()` | `cppc_reg_id` is reserved.
/// | `SbiRet::not_supported()` | `cppc_reg_id` is not implemented by the platform.
/// | `SbiRet::denied()`        | `cppc_reg_id` is a write-only register.
/// | `SbiRet::failed()`        | The read operation request failed for unspecified or unknown other reasons.
///
/// This function is defined in RISC-V SBI Specification chapter 14.3.
#[inline]
pub fn cppc_read_hi(cppc_reg_id: u32) -> SbiRet {
    sbi_call_1(EID_CPPC, READ_HI, cppc_reg_id as _)
}

/// Write 64-bit value to the CPPC register identified by given `cppc_reg_id`.
///
/// # Parameters
///
/// The `cppc_reg_id` parameter specifies the CPPC register ID.
///
/// The `value` parameter specifies the value to be written to the register.
///
/// # Return value
///
/// The possible error codes returned in `SbiRet.error` are shown in the table below:
///
/// | Return code               | Description
/// |:--------------------------|:----------------------------------------------
/// | `SbiRet::success()`       | Write completed successfully.
/// | `SbiRet::invalid_param()` | `cppc_reg_id` is reserved.
/// | `SbiRet::not_supported()` | `cppc_reg_id` is not implemented by the platform.
/// | `SbiRet::denied()`        | `cppc_reg_id` is a read-only register.
/// | `SbiRet::failed()`        | The write operation request failed for unspecified or unknown other reasons.
///
/// This function is defined in RISC-V SBI Specification chapter 14.4.
#[inline]
pub fn cppc_write(cppc_reg_id: u32, value: u64) -> SbiRet {
    match () {
        #[cfg(target_pointer_width = "32")]
        () => sbi_call_3(
            EID_CPPC,
            WRITE,
            cppc_reg_id as _,
            value as _,
            (value >> 32) as _,
        ),
        #[cfg(target_pointer_width = "64")]
        () => sbi_call_2(EID_CPPC, WRITE, cppc_reg_id as _, value as _),
    }
}