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