Line data Source code
1 : /*
2 : * Copyright 2011 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 "sid.h"
28 : #include "ppsmc.h"
29 : #include "radeon_ucode.h"
30 : #include "sislands_smc.h"
31 :
32 0 : static int si_set_smc_sram_address(struct radeon_device *rdev,
33 : u32 smc_address, u32 limit)
34 : {
35 0 : if (smc_address & 3)
36 0 : return -EINVAL;
37 0 : if ((smc_address + 3) > limit)
38 0 : return -EINVAL;
39 :
40 0 : WREG32(SMC_IND_INDEX_0, smc_address);
41 0 : WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0);
42 :
43 0 : return 0;
44 0 : }
45 :
46 0 : int si_copy_bytes_to_smc(struct radeon_device *rdev,
47 : u32 smc_start_address,
48 : const u8 *src, u32 byte_count, u32 limit)
49 : {
50 : unsigned long flags;
51 : int ret = 0;
52 : u32 data, original_data, addr, extra_shift;
53 :
54 0 : if (smc_start_address & 3)
55 0 : return -EINVAL;
56 0 : if ((smc_start_address + byte_count) > limit)
57 0 : return -EINVAL;
58 :
59 : addr = smc_start_address;
60 :
61 0 : spin_lock_irqsave(&rdev->smc_idx_lock, flags);
62 0 : while (byte_count >= 4) {
63 : /* SMC address space is BE */
64 0 : data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
65 :
66 0 : ret = si_set_smc_sram_address(rdev, addr, limit);
67 0 : if (ret)
68 : goto done;
69 :
70 0 : WREG32(SMC_IND_DATA_0, data);
71 :
72 0 : src += 4;
73 0 : byte_count -= 4;
74 0 : addr += 4;
75 : }
76 :
77 : /* RMW for the final bytes */
78 0 : if (byte_count > 0) {
79 : data = 0;
80 :
81 0 : ret = si_set_smc_sram_address(rdev, addr, limit);
82 0 : if (ret)
83 : goto done;
84 :
85 0 : original_data = RREG32(SMC_IND_DATA_0);
86 :
87 0 : extra_shift = 8 * (4 - byte_count);
88 :
89 0 : while (byte_count > 0) {
90 : /* SMC address space is BE */
91 0 : data = (data << 8) + *src++;
92 0 : byte_count--;
93 : }
94 :
95 0 : data <<= extra_shift;
96 :
97 0 : data |= (original_data & ~((~0UL) << extra_shift));
98 :
99 0 : ret = si_set_smc_sram_address(rdev, addr, limit);
100 0 : if (ret)
101 : goto done;
102 :
103 0 : WREG32(SMC_IND_DATA_0, data);
104 0 : }
105 :
106 : done:
107 0 : spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
108 :
109 0 : return ret;
110 0 : }
111 :
112 0 : void si_start_smc(struct radeon_device *rdev)
113 : {
114 0 : u32 tmp = RREG32_SMC(SMC_SYSCON_RESET_CNTL);
115 :
116 0 : tmp &= ~RST_REG;
117 :
118 0 : WREG32_SMC(SMC_SYSCON_RESET_CNTL, tmp);
119 0 : }
120 :
121 0 : void si_reset_smc(struct radeon_device *rdev)
122 : {
123 : u32 tmp;
124 :
125 0 : RREG32(CB_CGTT_SCLK_CTRL);
126 0 : RREG32(CB_CGTT_SCLK_CTRL);
127 0 : RREG32(CB_CGTT_SCLK_CTRL);
128 0 : RREG32(CB_CGTT_SCLK_CTRL);
129 :
130 0 : tmp = RREG32_SMC(SMC_SYSCON_RESET_CNTL);
131 0 : tmp |= RST_REG;
132 0 : WREG32_SMC(SMC_SYSCON_RESET_CNTL, tmp);
133 0 : }
134 :
135 0 : int si_program_jump_on_start(struct radeon_device *rdev)
136 : {
137 : static const u8 data[] = { 0x0E, 0x00, 0x40, 0x40 };
138 :
139 0 : return si_copy_bytes_to_smc(rdev, 0x0, data, 4, sizeof(data)+1);
140 : }
141 :
142 0 : void si_stop_smc_clock(struct radeon_device *rdev)
143 : {
144 0 : u32 tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
145 :
146 0 : tmp |= CK_DISABLE;
147 :
148 0 : WREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0, tmp);
149 0 : }
150 :
151 0 : void si_start_smc_clock(struct radeon_device *rdev)
152 : {
153 0 : u32 tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
154 :
155 0 : tmp &= ~CK_DISABLE;
156 :
157 0 : WREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0, tmp);
158 0 : }
159 :
160 0 : bool si_is_smc_running(struct radeon_device *rdev)
161 : {
162 0 : u32 rst = RREG32_SMC(SMC_SYSCON_RESET_CNTL);
163 0 : u32 clk = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
164 :
165 0 : if (!(rst & RST_REG) && !(clk & CK_DISABLE))
166 0 : return true;
167 :
168 0 : return false;
169 0 : }
170 :
171 0 : PPSMC_Result si_send_msg_to_smc(struct radeon_device *rdev, PPSMC_Msg msg)
172 : {
173 : u32 tmp;
174 : int i;
175 :
176 0 : if (!si_is_smc_running(rdev))
177 0 : return PPSMC_Result_Failed;
178 :
179 0 : WREG32(SMC_MESSAGE_0, msg);
180 :
181 0 : for (i = 0; i < rdev->usec_timeout; i++) {
182 0 : tmp = RREG32(SMC_RESP_0);
183 0 : if (tmp != 0)
184 : break;
185 0 : udelay(1);
186 : }
187 0 : tmp = RREG32(SMC_RESP_0);
188 :
189 0 : return (PPSMC_Result)tmp;
190 0 : }
191 :
192 0 : PPSMC_Result si_wait_for_smc_inactive(struct radeon_device *rdev)
193 : {
194 : u32 tmp;
195 : int i;
196 :
197 0 : if (!si_is_smc_running(rdev))
198 0 : return PPSMC_Result_OK;
199 :
200 0 : for (i = 0; i < rdev->usec_timeout; i++) {
201 0 : tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
202 0 : if ((tmp & CKEN) == 0)
203 : break;
204 0 : udelay(1);
205 : }
206 :
207 0 : return PPSMC_Result_OK;
208 0 : }
209 :
210 0 : int si_load_smc_ucode(struct radeon_device *rdev, u32 limit)
211 : {
212 : unsigned long flags;
213 : u32 ucode_start_address;
214 : u32 ucode_size;
215 : const u8 *src;
216 : u32 data;
217 :
218 0 : if (!rdev->smc_fw)
219 0 : return -EINVAL;
220 :
221 0 : if (rdev->new_fw) {
222 : const struct smc_firmware_header_v1_0 *hdr =
223 0 : (const struct smc_firmware_header_v1_0 *)rdev->smc_fw->data;
224 :
225 0 : radeon_ucode_print_smc_hdr(&hdr->header);
226 :
227 0 : ucode_start_address = le32_to_cpu(hdr->ucode_start_addr);
228 0 : ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes);
229 : src = (const u8 *)
230 0 : (rdev->smc_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes));
231 0 : } else {
232 0 : switch (rdev->family) {
233 : case CHIP_TAHITI:
234 : ucode_start_address = TAHITI_SMC_UCODE_START;
235 : ucode_size = TAHITI_SMC_UCODE_SIZE;
236 0 : break;
237 : case CHIP_PITCAIRN:
238 : ucode_start_address = PITCAIRN_SMC_UCODE_START;
239 : ucode_size = PITCAIRN_SMC_UCODE_SIZE;
240 0 : break;
241 : case CHIP_VERDE:
242 : ucode_start_address = VERDE_SMC_UCODE_START;
243 : ucode_size = VERDE_SMC_UCODE_SIZE;
244 0 : break;
245 : case CHIP_OLAND:
246 : ucode_start_address = OLAND_SMC_UCODE_START;
247 : ucode_size = OLAND_SMC_UCODE_SIZE;
248 0 : break;
249 : case CHIP_HAINAN:
250 : ucode_start_address = HAINAN_SMC_UCODE_START;
251 : ucode_size = HAINAN_SMC_UCODE_SIZE;
252 0 : break;
253 : default:
254 0 : DRM_ERROR("unknown asic in smc ucode loader\n");
255 0 : BUG();
256 : }
257 0 : src = (const u8 *)rdev->smc_fw->data;
258 : }
259 :
260 0 : if (ucode_size & 3)
261 0 : return -EINVAL;
262 :
263 0 : spin_lock_irqsave(&rdev->smc_idx_lock, flags);
264 0 : WREG32(SMC_IND_INDEX_0, ucode_start_address);
265 0 : WREG32_P(SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, ~AUTO_INCREMENT_IND_0);
266 0 : while (ucode_size >= 4) {
267 : /* SMC address space is BE */
268 0 : data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
269 :
270 0 : WREG32(SMC_IND_DATA_0, data);
271 :
272 0 : src += 4;
273 0 : ucode_size -= 4;
274 : }
275 0 : WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0);
276 0 : spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
277 :
278 0 : return 0;
279 0 : }
280 :
281 0 : int si_read_smc_sram_dword(struct radeon_device *rdev, u32 smc_address,
282 : u32 *value, u32 limit)
283 : {
284 : unsigned long flags;
285 : int ret;
286 :
287 0 : spin_lock_irqsave(&rdev->smc_idx_lock, flags);
288 0 : ret = si_set_smc_sram_address(rdev, smc_address, limit);
289 0 : if (ret == 0)
290 0 : *value = RREG32(SMC_IND_DATA_0);
291 0 : spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
292 :
293 0 : return ret;
294 : }
295 :
296 0 : int si_write_smc_sram_dword(struct radeon_device *rdev, u32 smc_address,
297 : u32 value, u32 limit)
298 : {
299 : unsigned long flags;
300 : int ret;
301 :
302 0 : spin_lock_irqsave(&rdev->smc_idx_lock, flags);
303 0 : ret = si_set_smc_sram_address(rdev, smc_address, limit);
304 0 : if (ret == 0)
305 0 : WREG32(SMC_IND_DATA_0, value);
306 0 : spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
307 :
308 0 : return ret;
309 : }
|