Line data Source code
1 : /*
2 : * Copyright 2013 Advanced Micro Devices, Inc.
3 : *
4 : * Permission is hereby granted, free of charge, to any person obtaining a
5 : * copy of this software and associated documentation files (the "Software"),
6 : * to deal in the Software without restriction, including without limitation
7 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 : * and/or sell copies of the Software, and to permit persons to whom the
9 : * Software is furnished to do so, subject to the following conditions:
10 : *
11 : * The above copyright notice and this permission notice shall be included in
12 : * all copies or substantial portions of the Software.
13 : *
14 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 : * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 : * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 : * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 : * OTHER DEALINGS IN THE SOFTWARE.
21 : *
22 : * Authors: Alex Deucher
23 : */
24 :
25 : #include <dev/pci/drm/drmP.h>
26 : #include "radeon.h"
27 : #include "cikd.h"
28 : #include "kv_dpm.h"
29 :
30 0 : int kv_notify_message_to_smu(struct radeon_device *rdev, u32 id)
31 : {
32 : u32 i;
33 : u32 tmp = 0;
34 :
35 0 : WREG32(SMC_MESSAGE_0, id & SMC_MSG_MASK);
36 :
37 0 : for (i = 0; i < rdev->usec_timeout; i++) {
38 0 : if ((RREG32(SMC_RESP_0) & SMC_RESP_MASK) != 0)
39 : break;
40 0 : udelay(1);
41 : }
42 0 : tmp = RREG32(SMC_RESP_0) & SMC_RESP_MASK;
43 :
44 0 : if (tmp != 1) {
45 0 : if (tmp == 0xFF)
46 0 : return -EINVAL;
47 0 : else if (tmp == 0xFE)
48 0 : return -EINVAL;
49 : }
50 :
51 0 : return 0;
52 0 : }
53 :
54 0 : int kv_dpm_get_enable_mask(struct radeon_device *rdev, u32 *enable_mask)
55 : {
56 : int ret;
57 :
58 0 : ret = kv_notify_message_to_smu(rdev, PPSMC_MSG_SCLKDPM_GetEnabledMask);
59 :
60 0 : if (ret == 0)
61 0 : *enable_mask = RREG32_SMC(SMC_SYSCON_MSG_ARG_0);
62 :
63 0 : return ret;
64 : }
65 :
66 0 : int kv_send_msg_to_smc_with_parameter(struct radeon_device *rdev,
67 : PPSMC_Msg msg, u32 parameter)
68 : {
69 :
70 0 : WREG32(SMC_MSG_ARG_0, parameter);
71 :
72 0 : return kv_notify_message_to_smu(rdev, msg);
73 : }
74 :
75 0 : static int kv_set_smc_sram_address(struct radeon_device *rdev,
76 : u32 smc_address, u32 limit)
77 : {
78 0 : if (smc_address & 3)
79 0 : return -EINVAL;
80 0 : if ((smc_address + 3) > limit)
81 0 : return -EINVAL;
82 :
83 0 : WREG32(SMC_IND_INDEX_0, smc_address);
84 0 : WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0);
85 :
86 0 : return 0;
87 0 : }
88 :
89 0 : int kv_read_smc_sram_dword(struct radeon_device *rdev, u32 smc_address,
90 : u32 *value, u32 limit)
91 : {
92 : int ret;
93 :
94 0 : ret = kv_set_smc_sram_address(rdev, smc_address, limit);
95 0 : if (ret)
96 0 : return ret;
97 :
98 0 : *value = RREG32(SMC_IND_DATA_0);
99 0 : return 0;
100 0 : }
101 :
102 0 : int kv_smc_dpm_enable(struct radeon_device *rdev, bool enable)
103 : {
104 0 : if (enable)
105 0 : return kv_notify_message_to_smu(rdev, PPSMC_MSG_DPM_Enable);
106 : else
107 0 : return kv_notify_message_to_smu(rdev, PPSMC_MSG_DPM_Disable);
108 0 : }
109 :
110 0 : int kv_smc_bapm_enable(struct radeon_device *rdev, bool enable)
111 : {
112 0 : if (enable)
113 0 : return kv_notify_message_to_smu(rdev, PPSMC_MSG_EnableBAPM);
114 : else
115 0 : return kv_notify_message_to_smu(rdev, PPSMC_MSG_DisableBAPM);
116 0 : }
117 :
118 0 : int kv_copy_bytes_to_smc(struct radeon_device *rdev,
119 : u32 smc_start_address,
120 : const u8 *src, u32 byte_count, u32 limit)
121 : {
122 : int ret;
123 : u32 data, original_data, addr, extra_shift, t_byte, count, mask;
124 :
125 0 : if ((smc_start_address + byte_count) > limit)
126 0 : return -EINVAL;
127 :
128 : addr = smc_start_address;
129 0 : t_byte = addr & 3;
130 :
131 : /* RMW for the initial bytes */
132 0 : if (t_byte != 0) {
133 0 : addr -= t_byte;
134 :
135 0 : ret = kv_set_smc_sram_address(rdev, addr, limit);
136 0 : if (ret)
137 0 : return ret;
138 :
139 0 : original_data = RREG32(SMC_IND_DATA_0);
140 :
141 : data = 0;
142 : mask = 0;
143 : count = 4;
144 0 : while (count > 0) {
145 0 : if (t_byte > 0) {
146 0 : mask = (mask << 8) | 0xff;
147 0 : t_byte--;
148 0 : } else if (byte_count > 0) {
149 0 : data = (data << 8) + *src++;
150 0 : byte_count--;
151 0 : mask <<= 8;
152 0 : } else {
153 : data <<= 8;
154 0 : mask = (mask << 8) | 0xff;
155 : }
156 0 : count--;
157 : }
158 :
159 0 : data |= original_data & mask;
160 :
161 0 : ret = kv_set_smc_sram_address(rdev, addr, limit);
162 0 : if (ret)
163 0 : return ret;
164 :
165 0 : WREG32(SMC_IND_DATA_0, data);
166 :
167 0 : addr += 4;
168 0 : }
169 :
170 0 : while (byte_count >= 4) {
171 : /* SMC address space is BE */
172 0 : data = (src[0] << 24) + (src[1] << 16) + (src[2] << 8) + src[3];
173 :
174 0 : ret = kv_set_smc_sram_address(rdev, addr, limit);
175 0 : if (ret)
176 0 : return ret;
177 :
178 0 : WREG32(SMC_IND_DATA_0, data);
179 :
180 0 : src += 4;
181 0 : byte_count -= 4;
182 0 : addr += 4;
183 : }
184 :
185 : /* RMW for the final bytes */
186 0 : if (byte_count > 0) {
187 : data = 0;
188 :
189 0 : ret = kv_set_smc_sram_address(rdev, addr, limit);
190 0 : if (ret)
191 0 : return ret;
192 :
193 0 : original_data= RREG32(SMC_IND_DATA_0);
194 :
195 0 : extra_shift = 8 * (4 - byte_count);
196 :
197 0 : while (byte_count > 0) {
198 : /* SMC address space is BE */
199 0 : data = (data << 8) + *src++;
200 0 : byte_count--;
201 : }
202 :
203 0 : data <<= extra_shift;
204 :
205 0 : data |= (original_data & ~((~0UL) << extra_shift));
206 :
207 0 : ret = kv_set_smc_sram_address(rdev, addr, limit);
208 0 : if (ret)
209 0 : return ret;
210 :
211 0 : WREG32(SMC_IND_DATA_0, data);
212 0 : }
213 0 : return 0;
214 0 : }
215 :
|