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

source code of linux/drivers/gpu/drm/radeon/rv770_smc.c