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 "rv770d.h"
28 : #include "rv770_dpm.h"
29 : #include "rv770_smc.h"
30 : #include "atom.h"
31 : #include "radeon_ucode.h"
32 :
33 : #define FIRST_SMC_INT_VECT_REG 0xFFD8
34 : #define FIRST_INT_VECT_S19 0xFFC0
35 :
36 : static const u8 rv770_smc_int_vectors[] =
37 : {
38 : 0x08, 0x10, 0x08, 0x10,
39 : 0x08, 0x10, 0x08, 0x10,
40 : 0x08, 0x10, 0x08, 0x10,
41 : 0x08, 0x10, 0x08, 0x10,
42 : 0x08, 0x10, 0x08, 0x10,
43 : 0x08, 0x10, 0x08, 0x10,
44 : 0x08, 0x10, 0x08, 0x10,
45 : 0x08, 0x10, 0x08, 0x10,
46 : 0x08, 0x10, 0x08, 0x10,
47 : 0x08, 0x10, 0x08, 0x10,
48 : 0x08, 0x10, 0x08, 0x10,
49 : 0x08, 0x10, 0x08, 0x10,
50 : 0x08, 0x10, 0x0C, 0xD7,
51 : 0x08, 0x2B, 0x08, 0x10,
52 : 0x03, 0x51, 0x03, 0x51,
53 : 0x03, 0x51, 0x03, 0x51
54 : };
55 :
56 : static const u8 rv730_smc_int_vectors[] =
57 : {
58 : 0x08, 0x15, 0x08, 0x15,
59 : 0x08, 0x15, 0x08, 0x15,
60 : 0x08, 0x15, 0x08, 0x15,
61 : 0x08, 0x15, 0x08, 0x15,
62 : 0x08, 0x15, 0x08, 0x15,
63 : 0x08, 0x15, 0x08, 0x15,
64 : 0x08, 0x15, 0x08, 0x15,
65 : 0x08, 0x15, 0x08, 0x15,
66 : 0x08, 0x15, 0x08, 0x15,
67 : 0x08, 0x15, 0x08, 0x15,
68 : 0x08, 0x15, 0x08, 0x15,
69 : 0x08, 0x15, 0x08, 0x15,
70 : 0x08, 0x15, 0x0C, 0xBB,
71 : 0x08, 0x30, 0x08, 0x15,
72 : 0x03, 0x56, 0x03, 0x56,
73 : 0x03, 0x56, 0x03, 0x56
74 : };
75 :
76 : static const u8 rv710_smc_int_vectors[] =
77 : {
78 : 0x08, 0x04, 0x08, 0x04,
79 : 0x08, 0x04, 0x08, 0x04,
80 : 0x08, 0x04, 0x08, 0x04,
81 : 0x08, 0x04, 0x08, 0x04,
82 : 0x08, 0x04, 0x08, 0x04,
83 : 0x08, 0x04, 0x08, 0x04,
84 : 0x08, 0x04, 0x08, 0x04,
85 : 0x08, 0x04, 0x08, 0x04,
86 : 0x08, 0x04, 0x08, 0x04,
87 : 0x08, 0x04, 0x08, 0x04,
88 : 0x08, 0x04, 0x08, 0x04,
89 : 0x08, 0x04, 0x08, 0x04,
90 : 0x08, 0x04, 0x0C, 0xCB,
91 : 0x08, 0x1F, 0x08, 0x04,
92 : 0x03, 0x51, 0x03, 0x51,
93 : 0x03, 0x51, 0x03, 0x51
94 : };
95 :
96 : static const u8 rv740_smc_int_vectors[] =
97 : {
98 : 0x08, 0x10, 0x08, 0x10,
99 : 0x08, 0x10, 0x08, 0x10,
100 : 0x08, 0x10, 0x08, 0x10,
101 : 0x08, 0x10, 0x08, 0x10,
102 : 0x08, 0x10, 0x08, 0x10,
103 : 0x08, 0x10, 0x08, 0x10,
104 : 0x08, 0x10, 0x08, 0x10,
105 : 0x08, 0x10, 0x08, 0x10,
106 : 0x08, 0x10, 0x08, 0x10,
107 : 0x08, 0x10, 0x08, 0x10,
108 : 0x08, 0x10, 0x08, 0x10,
109 : 0x08, 0x10, 0x08, 0x10,
110 : 0x08, 0x10, 0x0C, 0xD7,
111 : 0x08, 0x2B, 0x08, 0x10,
112 : 0x03, 0x51, 0x03, 0x51,
113 : 0x03, 0x51, 0x03, 0x51
114 : };
115 :
116 : static const u8 cedar_smc_int_vectors[] =
117 : {
118 : 0x0B, 0x05, 0x0B, 0x05,
119 : 0x0B, 0x05, 0x0B, 0x05,
120 : 0x0B, 0x05, 0x0B, 0x05,
121 : 0x0B, 0x05, 0x0B, 0x05,
122 : 0x0B, 0x05, 0x0B, 0x05,
123 : 0x0B, 0x05, 0x0B, 0x05,
124 : 0x0B, 0x05, 0x0B, 0x05,
125 : 0x0B, 0x05, 0x0B, 0x05,
126 : 0x0B, 0x05, 0x0B, 0x05,
127 : 0x0B, 0x05, 0x0B, 0x05,
128 : 0x0B, 0x05, 0x0B, 0x05,
129 : 0x0B, 0x05, 0x0B, 0x05,
130 : 0x0B, 0x05, 0x11, 0x8B,
131 : 0x0B, 0x20, 0x0B, 0x05,
132 : 0x04, 0xF6, 0x04, 0xF6,
133 : 0x04, 0xF6, 0x04, 0xF6
134 : };
135 :
136 : static const u8 redwood_smc_int_vectors[] =
137 : {
138 : 0x0B, 0x05, 0x0B, 0x05,
139 : 0x0B, 0x05, 0x0B, 0x05,
140 : 0x0B, 0x05, 0x0B, 0x05,
141 : 0x0B, 0x05, 0x0B, 0x05,
142 : 0x0B, 0x05, 0x0B, 0x05,
143 : 0x0B, 0x05, 0x0B, 0x05,
144 : 0x0B, 0x05, 0x0B, 0x05,
145 : 0x0B, 0x05, 0x0B, 0x05,
146 : 0x0B, 0x05, 0x0B, 0x05,
147 : 0x0B, 0x05, 0x0B, 0x05,
148 : 0x0B, 0x05, 0x0B, 0x05,
149 : 0x0B, 0x05, 0x0B, 0x05,
150 : 0x0B, 0x05, 0x11, 0x8B,
151 : 0x0B, 0x20, 0x0B, 0x05,
152 : 0x04, 0xF6, 0x04, 0xF6,
153 : 0x04, 0xF6, 0x04, 0xF6
154 : };
155 :
156 : static const u8 juniper_smc_int_vectors[] =
157 : {
158 : 0x0B, 0x05, 0x0B, 0x05,
159 : 0x0B, 0x05, 0x0B, 0x05,
160 : 0x0B, 0x05, 0x0B, 0x05,
161 : 0x0B, 0x05, 0x0B, 0x05,
162 : 0x0B, 0x05, 0x0B, 0x05,
163 : 0x0B, 0x05, 0x0B, 0x05,
164 : 0x0B, 0x05, 0x0B, 0x05,
165 : 0x0B, 0x05, 0x0B, 0x05,
166 : 0x0B, 0x05, 0x0B, 0x05,
167 : 0x0B, 0x05, 0x0B, 0x05,
168 : 0x0B, 0x05, 0x0B, 0x05,
169 : 0x0B, 0x05, 0x0B, 0x05,
170 : 0x0B, 0x05, 0x11, 0x8B,
171 : 0x0B, 0x20, 0x0B, 0x05,
172 : 0x04, 0xF6, 0x04, 0xF6,
173 : 0x04, 0xF6, 0x04, 0xF6
174 : };
175 :
176 : static const u8 cypress_smc_int_vectors[] =
177 : {
178 : 0x0B, 0x05, 0x0B, 0x05,
179 : 0x0B, 0x05, 0x0B, 0x05,
180 : 0x0B, 0x05, 0x0B, 0x05,
181 : 0x0B, 0x05, 0x0B, 0x05,
182 : 0x0B, 0x05, 0x0B, 0x05,
183 : 0x0B, 0x05, 0x0B, 0x05,
184 : 0x0B, 0x05, 0x0B, 0x05,
185 : 0x0B, 0x05, 0x0B, 0x05,
186 : 0x0B, 0x05, 0x0B, 0x05,
187 : 0x0B, 0x05, 0x0B, 0x05,
188 : 0x0B, 0x05, 0x0B, 0x05,
189 : 0x0B, 0x05, 0x0B, 0x05,
190 : 0x0B, 0x05, 0x11, 0x8B,
191 : 0x0B, 0x20, 0x0B, 0x05,
192 : 0x04, 0xF6, 0x04, 0xF6,
193 : 0x04, 0xF6, 0x04, 0xF6
194 : };
195 :
196 : static const u8 barts_smc_int_vectors[] =
197 : {
198 : 0x0C, 0x14, 0x0C, 0x14,
199 : 0x0C, 0x14, 0x0C, 0x14,
200 : 0x0C, 0x14, 0x0C, 0x14,
201 : 0x0C, 0x14, 0x0C, 0x14,
202 : 0x0C, 0x14, 0x0C, 0x14,
203 : 0x0C, 0x14, 0x0C, 0x14,
204 : 0x0C, 0x14, 0x0C, 0x14,
205 : 0x0C, 0x14, 0x0C, 0x14,
206 : 0x0C, 0x14, 0x0C, 0x14,
207 : 0x0C, 0x14, 0x0C, 0x14,
208 : 0x0C, 0x14, 0x0C, 0x14,
209 : 0x0C, 0x14, 0x0C, 0x14,
210 : 0x0C, 0x14, 0x12, 0xAA,
211 : 0x0C, 0x2F, 0x15, 0xF6,
212 : 0x15, 0xF6, 0x05, 0x0A,
213 : 0x05, 0x0A, 0x05, 0x0A
214 : };
215 :
216 : static const u8 turks_smc_int_vectors[] =
217 : {
218 : 0x0C, 0x14, 0x0C, 0x14,
219 : 0x0C, 0x14, 0x0C, 0x14,
220 : 0x0C, 0x14, 0x0C, 0x14,
221 : 0x0C, 0x14, 0x0C, 0x14,
222 : 0x0C, 0x14, 0x0C, 0x14,
223 : 0x0C, 0x14, 0x0C, 0x14,
224 : 0x0C, 0x14, 0x0C, 0x14,
225 : 0x0C, 0x14, 0x0C, 0x14,
226 : 0x0C, 0x14, 0x0C, 0x14,
227 : 0x0C, 0x14, 0x0C, 0x14,
228 : 0x0C, 0x14, 0x0C, 0x14,
229 : 0x0C, 0x14, 0x0C, 0x14,
230 : 0x0C, 0x14, 0x12, 0xAA,
231 : 0x0C, 0x2F, 0x15, 0xF6,
232 : 0x15, 0xF6, 0x05, 0x0A,
233 : 0x05, 0x0A, 0x05, 0x0A
234 : };
235 :
236 : static const u8 caicos_smc_int_vectors[] =
237 : {
238 : 0x0C, 0x14, 0x0C, 0x14,
239 : 0x0C, 0x14, 0x0C, 0x14,
240 : 0x0C, 0x14, 0x0C, 0x14,
241 : 0x0C, 0x14, 0x0C, 0x14,
242 : 0x0C, 0x14, 0x0C, 0x14,
243 : 0x0C, 0x14, 0x0C, 0x14,
244 : 0x0C, 0x14, 0x0C, 0x14,
245 : 0x0C, 0x14, 0x0C, 0x14,
246 : 0x0C, 0x14, 0x0C, 0x14,
247 : 0x0C, 0x14, 0x0C, 0x14,
248 : 0x0C, 0x14, 0x0C, 0x14,
249 : 0x0C, 0x14, 0x0C, 0x14,
250 : 0x0C, 0x14, 0x12, 0xAA,
251 : 0x0C, 0x2F, 0x15, 0xF6,
252 : 0x15, 0xF6, 0x05, 0x0A,
253 : 0x05, 0x0A, 0x05, 0x0A
254 : };
255 :
256 : static const u8 cayman_smc_int_vectors[] =
257 : {
258 : 0x12, 0x05, 0x12, 0x05,
259 : 0x12, 0x05, 0x12, 0x05,
260 : 0x12, 0x05, 0x12, 0x05,
261 : 0x12, 0x05, 0x12, 0x05,
262 : 0x12, 0x05, 0x12, 0x05,
263 : 0x12, 0x05, 0x12, 0x05,
264 : 0x12, 0x05, 0x12, 0x05,
265 : 0x12, 0x05, 0x12, 0x05,
266 : 0x12, 0x05, 0x12, 0x05,
267 : 0x12, 0x05, 0x12, 0x05,
268 : 0x12, 0x05, 0x12, 0x05,
269 : 0x12, 0x05, 0x12, 0x05,
270 : 0x12, 0x05, 0x18, 0xEA,
271 : 0x12, 0x20, 0x1C, 0x34,
272 : 0x1C, 0x34, 0x08, 0x72,
273 : 0x08, 0x72, 0x08, 0x72
274 : };
275 :
276 0 : static int rv770_set_smc_sram_address(struct radeon_device *rdev,
277 : u16 smc_address, u16 limit)
278 : {
279 : u32 addr;
280 :
281 0 : if (smc_address & 3)
282 0 : return -EINVAL;
283 0 : if ((smc_address + 3) > limit)
284 0 : return -EINVAL;
285 :
286 : addr = smc_address;
287 0 : addr |= SMC_SRAM_AUTO_INC_DIS;
288 :
289 0 : WREG32(SMC_SRAM_ADDR, addr);
290 :
291 0 : return 0;
292 0 : }
293 :
294 0 : int rv770_copy_bytes_to_smc(struct radeon_device *rdev,
295 : u16 smc_start_address, const u8 *src,
296 : u16 byte_count, u16 limit)
297 : {
298 : unsigned long flags;
299 : u32 data, original_data, extra_shift;
300 : u16 addr;
301 : int ret = 0;
302 :
303 0 : if (smc_start_address & 3)
304 0 : return -EINVAL;
305 0 : if ((smc_start_address + byte_count) > limit)
306 0 : return -EINVAL;
307 :
308 : addr = smc_start_address;
309 :
310 0 : spin_lock_irqsave(&rdev->smc_idx_lock, flags);
311 0 : while (byte_count >= 4) {
312 : /* SMC address space is BE */
313 0 : data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
314 :
315 0 : ret = rv770_set_smc_sram_address(rdev, addr, limit);
316 0 : if (ret)
317 : goto done;
318 :
319 0 : WREG32(SMC_SRAM_DATA, data);
320 :
321 0 : src += 4;
322 0 : byte_count -= 4;
323 0 : addr += 4;
324 : }
325 :
326 : /* RMW for final bytes */
327 0 : if (byte_count > 0) {
328 : data = 0;
329 :
330 0 : ret = rv770_set_smc_sram_address(rdev, addr, limit);
331 0 : if (ret)
332 : goto done;
333 :
334 0 : original_data = RREG32(SMC_SRAM_DATA);
335 :
336 0 : extra_shift = 8 * (4 - byte_count);
337 :
338 0 : while (byte_count > 0) {
339 : /* SMC address space is BE */
340 0 : data = (data << 8) + *src++;
341 0 : byte_count--;
342 : }
343 :
344 0 : data <<= extra_shift;
345 :
346 0 : data |= (original_data & ~((~0UL) << extra_shift));
347 :
348 0 : ret = rv770_set_smc_sram_address(rdev, addr, limit);
349 0 : if (ret)
350 : goto done;
351 :
352 0 : WREG32(SMC_SRAM_DATA, data);
353 0 : }
354 :
355 : done:
356 0 : spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
357 :
358 0 : return ret;
359 0 : }
360 :
361 0 : static int rv770_program_interrupt_vectors(struct radeon_device *rdev,
362 : u32 smc_first_vector, const u8 *src,
363 : u32 byte_count)
364 : {
365 : u32 tmp, i;
366 :
367 0 : if (byte_count % 4)
368 0 : return -EINVAL;
369 :
370 0 : if (smc_first_vector < FIRST_SMC_INT_VECT_REG) {
371 0 : tmp = FIRST_SMC_INT_VECT_REG - smc_first_vector;
372 :
373 0 : if (tmp > byte_count)
374 0 : return 0;
375 :
376 0 : byte_count -= tmp;
377 0 : src += tmp;
378 : smc_first_vector = FIRST_SMC_INT_VECT_REG;
379 0 : }
380 :
381 0 : for (i = 0; i < byte_count; i += 4) {
382 : /* SMC address space is BE */
383 0 : tmp = (src[i] << 24) | (src[i + 1] << 16) | (src[i + 2] << 8) | src[i + 3];
384 :
385 0 : WREG32(SMC_ISR_FFD8_FFDB + i, tmp);
386 : }
387 :
388 0 : return 0;
389 0 : }
390 :
391 0 : void rv770_start_smc(struct radeon_device *rdev)
392 : {
393 0 : WREG32_P(SMC_IO, SMC_RST_N, ~SMC_RST_N);
394 0 : }
395 :
396 0 : void rv770_reset_smc(struct radeon_device *rdev)
397 : {
398 0 : WREG32_P(SMC_IO, 0, ~SMC_RST_N);
399 0 : }
400 :
401 0 : void rv770_stop_smc_clock(struct radeon_device *rdev)
402 : {
403 0 : WREG32_P(SMC_IO, 0, ~SMC_CLK_EN);
404 0 : }
405 :
406 0 : void rv770_start_smc_clock(struct radeon_device *rdev)
407 : {
408 0 : WREG32_P(SMC_IO, SMC_CLK_EN, ~SMC_CLK_EN);
409 0 : }
410 :
411 0 : bool rv770_is_smc_running(struct radeon_device *rdev)
412 : {
413 : u32 tmp;
414 :
415 0 : tmp = RREG32(SMC_IO);
416 :
417 0 : if ((tmp & SMC_RST_N) && (tmp & SMC_CLK_EN))
418 0 : return true;
419 : else
420 0 : return false;
421 0 : }
422 :
423 0 : PPSMC_Result rv770_send_msg_to_smc(struct radeon_device *rdev, PPSMC_Msg msg)
424 : {
425 : u32 tmp;
426 : int i;
427 : PPSMC_Result result;
428 :
429 0 : if (!rv770_is_smc_running(rdev))
430 0 : return PPSMC_Result_Failed;
431 :
432 0 : WREG32_P(SMC_MSG, HOST_SMC_MSG(msg), ~HOST_SMC_MSG_MASK);
433 :
434 0 : for (i = 0; i < rdev->usec_timeout; i++) {
435 0 : tmp = RREG32(SMC_MSG) & HOST_SMC_RESP_MASK;
436 0 : tmp >>= HOST_SMC_RESP_SHIFT;
437 0 : if (tmp != 0)
438 : break;
439 0 : udelay(1);
440 : }
441 :
442 0 : tmp = RREG32(SMC_MSG) & HOST_SMC_RESP_MASK;
443 0 : tmp >>= HOST_SMC_RESP_SHIFT;
444 :
445 0 : result = (PPSMC_Result)tmp;
446 0 : return result;
447 0 : }
448 :
449 0 : PPSMC_Result rv770_wait_for_smc_inactive(struct radeon_device *rdev)
450 : {
451 : int i;
452 : PPSMC_Result result = PPSMC_Result_OK;
453 :
454 0 : if (!rv770_is_smc_running(rdev))
455 0 : return result;
456 :
457 0 : for (i = 0; i < rdev->usec_timeout; i++) {
458 0 : if (RREG32(SMC_IO) & SMC_STOP_MODE)
459 : break;
460 0 : udelay(1);
461 : }
462 :
463 0 : return result;
464 0 : }
465 :
466 0 : static void rv770_clear_smc_sram(struct radeon_device *rdev, u16 limit)
467 : {
468 : unsigned long flags;
469 : u16 i;
470 :
471 0 : spin_lock_irqsave(&rdev->smc_idx_lock, flags);
472 0 : for (i = 0; i < limit; i += 4) {
473 0 : rv770_set_smc_sram_address(rdev, i, limit);
474 0 : WREG32(SMC_SRAM_DATA, 0);
475 : }
476 0 : spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
477 0 : }
478 :
479 0 : int rv770_load_smc_ucode(struct radeon_device *rdev,
480 : u16 limit)
481 : {
482 : int ret;
483 : const u8 *int_vect;
484 : u16 int_vect_start_address;
485 : u16 int_vect_size;
486 : const u8 *ucode_data;
487 : u16 ucode_start_address;
488 : u16 ucode_size;
489 :
490 0 : if (!rdev->smc_fw)
491 0 : return -EINVAL;
492 :
493 0 : rv770_clear_smc_sram(rdev, limit);
494 :
495 0 : switch (rdev->family) {
496 : case CHIP_RV770:
497 : ucode_start_address = RV770_SMC_UCODE_START;
498 : ucode_size = RV770_SMC_UCODE_SIZE;
499 : int_vect = (const u8 *)&rv770_smc_int_vectors;
500 : int_vect_start_address = RV770_SMC_INT_VECTOR_START;
501 : int_vect_size = RV770_SMC_INT_VECTOR_SIZE;
502 0 : break;
503 : case CHIP_RV730:
504 : ucode_start_address = RV730_SMC_UCODE_START;
505 : ucode_size = RV730_SMC_UCODE_SIZE;
506 : int_vect = (const u8 *)&rv730_smc_int_vectors;
507 : int_vect_start_address = RV730_SMC_INT_VECTOR_START;
508 : int_vect_size = RV730_SMC_INT_VECTOR_SIZE;
509 0 : break;
510 : case CHIP_RV710:
511 : ucode_start_address = RV710_SMC_UCODE_START;
512 : ucode_size = RV710_SMC_UCODE_SIZE;
513 : int_vect = (const u8 *)&rv710_smc_int_vectors;
514 : int_vect_start_address = RV710_SMC_INT_VECTOR_START;
515 : int_vect_size = RV710_SMC_INT_VECTOR_SIZE;
516 0 : break;
517 : case CHIP_RV740:
518 : ucode_start_address = RV740_SMC_UCODE_START;
519 : ucode_size = RV740_SMC_UCODE_SIZE;
520 : int_vect = (const u8 *)&rv740_smc_int_vectors;
521 : int_vect_start_address = RV740_SMC_INT_VECTOR_START;
522 : int_vect_size = RV740_SMC_INT_VECTOR_SIZE;
523 0 : break;
524 : case CHIP_CEDAR:
525 : ucode_start_address = CEDAR_SMC_UCODE_START;
526 : ucode_size = CEDAR_SMC_UCODE_SIZE;
527 : int_vect = (const u8 *)&cedar_smc_int_vectors;
528 : int_vect_start_address = CEDAR_SMC_INT_VECTOR_START;
529 : int_vect_size = CEDAR_SMC_INT_VECTOR_SIZE;
530 0 : break;
531 : case CHIP_REDWOOD:
532 : ucode_start_address = REDWOOD_SMC_UCODE_START;
533 : ucode_size = REDWOOD_SMC_UCODE_SIZE;
534 : int_vect = (const u8 *)&redwood_smc_int_vectors;
535 : int_vect_start_address = REDWOOD_SMC_INT_VECTOR_START;
536 : int_vect_size = REDWOOD_SMC_INT_VECTOR_SIZE;
537 0 : break;
538 : case CHIP_JUNIPER:
539 : ucode_start_address = JUNIPER_SMC_UCODE_START;
540 : ucode_size = JUNIPER_SMC_UCODE_SIZE;
541 : int_vect = (const u8 *)&juniper_smc_int_vectors;
542 : int_vect_start_address = JUNIPER_SMC_INT_VECTOR_START;
543 : int_vect_size = JUNIPER_SMC_INT_VECTOR_SIZE;
544 0 : break;
545 : case CHIP_CYPRESS:
546 : case CHIP_HEMLOCK:
547 : ucode_start_address = CYPRESS_SMC_UCODE_START;
548 : ucode_size = CYPRESS_SMC_UCODE_SIZE;
549 : int_vect = (const u8 *)&cypress_smc_int_vectors;
550 : int_vect_start_address = CYPRESS_SMC_INT_VECTOR_START;
551 : int_vect_size = CYPRESS_SMC_INT_VECTOR_SIZE;
552 0 : break;
553 : case CHIP_BARTS:
554 : ucode_start_address = BARTS_SMC_UCODE_START;
555 : ucode_size = BARTS_SMC_UCODE_SIZE;
556 : int_vect = (const u8 *)&barts_smc_int_vectors;
557 : int_vect_start_address = BARTS_SMC_INT_VECTOR_START;
558 : int_vect_size = BARTS_SMC_INT_VECTOR_SIZE;
559 0 : break;
560 : case CHIP_TURKS:
561 : ucode_start_address = TURKS_SMC_UCODE_START;
562 : ucode_size = TURKS_SMC_UCODE_SIZE;
563 : int_vect = (const u8 *)&turks_smc_int_vectors;
564 : int_vect_start_address = TURKS_SMC_INT_VECTOR_START;
565 : int_vect_size = TURKS_SMC_INT_VECTOR_SIZE;
566 0 : break;
567 : case CHIP_CAICOS:
568 : ucode_start_address = CAICOS_SMC_UCODE_START;
569 : ucode_size = CAICOS_SMC_UCODE_SIZE;
570 : int_vect = (const u8 *)&caicos_smc_int_vectors;
571 : int_vect_start_address = CAICOS_SMC_INT_VECTOR_START;
572 : int_vect_size = CAICOS_SMC_INT_VECTOR_SIZE;
573 0 : break;
574 : case CHIP_CAYMAN:
575 : ucode_start_address = CAYMAN_SMC_UCODE_START;
576 : ucode_size = CAYMAN_SMC_UCODE_SIZE;
577 : int_vect = (const u8 *)&cayman_smc_int_vectors;
578 : int_vect_start_address = CAYMAN_SMC_INT_VECTOR_START;
579 : int_vect_size = CAYMAN_SMC_INT_VECTOR_SIZE;
580 0 : break;
581 : default:
582 0 : DRM_ERROR("unknown asic in smc ucode loader\n");
583 0 : BUG();
584 : }
585 :
586 : /* load the ucode */
587 0 : ucode_data = (const u8 *)rdev->smc_fw->data;
588 0 : ret = rv770_copy_bytes_to_smc(rdev, ucode_start_address,
589 : ucode_data, ucode_size, limit);
590 0 : if (ret)
591 0 : return ret;
592 :
593 : /* set up the int vectors */
594 0 : ret = rv770_program_interrupt_vectors(rdev, int_vect_start_address,
595 : int_vect, int_vect_size);
596 0 : if (ret)
597 0 : return ret;
598 :
599 0 : return 0;
600 0 : }
601 :
602 0 : int rv770_read_smc_sram_dword(struct radeon_device *rdev,
603 : u16 smc_address, u32 *value, u16 limit)
604 : {
605 : unsigned long flags;
606 : int ret;
607 :
608 0 : spin_lock_irqsave(&rdev->smc_idx_lock, flags);
609 0 : ret = rv770_set_smc_sram_address(rdev, smc_address, limit);
610 0 : if (ret == 0)
611 0 : *value = RREG32(SMC_SRAM_DATA);
612 0 : spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
613 :
614 0 : return ret;
615 : }
616 :
617 0 : int rv770_write_smc_sram_dword(struct radeon_device *rdev,
618 : u16 smc_address, u32 value, u16 limit)
619 : {
620 : unsigned long flags;
621 : int ret;
622 :
623 0 : spin_lock_irqsave(&rdev->smc_idx_lock, flags);
624 0 : ret = rv770_set_smc_sram_address(rdev, smc_address, limit);
625 0 : if (ret == 0)
626 0 : WREG32(SMC_SRAM_DATA, value);
627 0 : spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
628 :
629 0 : return ret;
630 : }
|