Merge branch 'vendor/GCC50'
[dragonfly.git] / sys / dev / drm / radeon / rv770_smc.c
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
37 static 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
57 static 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
77 static 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
97 static 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
117 static 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
137 static 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
157 static 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
177 static 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
197 static 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
217 static 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
237 static 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
257 static 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
277 static 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
295 int 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         u32 data, original_data, extra_shift;
300         u16 addr;
301         int ret = 0;
302
303         if (smc_start_address & 3)
304                 return -EINVAL;
305         if ((smc_start_address + byte_count) > limit)
306                 return -EINVAL;
307
308         addr = smc_start_address;
309
310         spin_lock(&rdev->smc_idx_lock);
311         while (byte_count >= 4) {
312                 /* SMC address space is BE */
313                 data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
314
315                 ret = rv770_set_smc_sram_address(rdev, addr, limit);
316                 if (ret)
317                         goto done;
318
319                 WREG32(SMC_SRAM_DATA, data);
320
321                 src += 4;
322                 byte_count -= 4;
323                 addr += 4;
324         }
325
326         /* RMW for final bytes */
327         if (byte_count > 0) {
328                 data = 0;
329
330                 ret = rv770_set_smc_sram_address(rdev, addr, limit);
331                 if (ret)
332                         goto done;
333
334                 original_data = RREG32(SMC_SRAM_DATA);
335
336                 extra_shift = 8 * (4 - byte_count);
337
338                 while (byte_count > 0) {
339                         /* SMC address space is BE */
340                         data = (data << 8) + *src++;
341                         byte_count--;
342                 }
343
344                 data <<= extra_shift;
345
346                 data |= (original_data & ~((~0UL) << extra_shift));
347
348                 ret = rv770_set_smc_sram_address(rdev, addr, limit);
349                 if (ret)
350                         goto done;
351
352                 WREG32(SMC_SRAM_DATA, data);
353         }
354
355 done:
356         spin_unlock(&rdev->smc_idx_lock);
357
358         return ret;
359 }
360
361 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         if (byte_count % 4)
368                 return -EINVAL;
369
370         if (smc_first_vector < FIRST_SMC_INT_VECT_REG) {
371                 tmp = FIRST_SMC_INT_VECT_REG - smc_first_vector;
372
373                 if (tmp > byte_count)
374                         return 0;
375
376                 byte_count -= tmp;
377                 src += tmp;
378                 smc_first_vector = FIRST_SMC_INT_VECT_REG;
379         }
380
381         for (i = 0; i < byte_count; i += 4) {
382                 /* SMC address space is BE */
383                 tmp = (src[i] << 24) | (src[i + 1] << 16) | (src[i + 2] << 8) | src[i + 3];
384
385                 WREG32(SMC_ISR_FFD8_FFDB + i, tmp);
386         }
387
388         return 0;
389 }
390
391 void rv770_start_smc(struct radeon_device *rdev)
392 {
393         WREG32_P(SMC_IO, SMC_RST_N, ~SMC_RST_N);
394 }
395
396 void rv770_reset_smc(struct radeon_device *rdev)
397 {
398         WREG32_P(SMC_IO, 0, ~SMC_RST_N);
399 }
400
401 void rv770_stop_smc_clock(struct radeon_device *rdev)
402 {
403         WREG32_P(SMC_IO, 0, ~SMC_CLK_EN);
404 }
405
406 void rv770_start_smc_clock(struct radeon_device *rdev)
407 {
408         WREG32_P(SMC_IO, SMC_CLK_EN, ~SMC_CLK_EN);
409 }
410
411 bool rv770_is_smc_running(struct radeon_device *rdev)
412 {
413         u32 tmp;
414
415         tmp = RREG32(SMC_IO);
416
417         if ((tmp & SMC_RST_N) && (tmp & SMC_CLK_EN))
418                 return true;
419         else
420                 return false;
421 }
422
423 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         if (!rv770_is_smc_running(rdev))
430                 return PPSMC_Result_Failed;
431
432         WREG32_P(SMC_MSG, HOST_SMC_MSG(msg), ~HOST_SMC_MSG_MASK);
433
434         for (i = 0; i < rdev->usec_timeout; i++) {
435                 tmp = RREG32(SMC_MSG) & HOST_SMC_RESP_MASK;
436                 tmp >>= HOST_SMC_RESP_SHIFT;
437                 if (tmp != 0)
438                         break;
439                 udelay(1);
440         }
441
442         tmp = RREG32(SMC_MSG) & HOST_SMC_RESP_MASK;
443         tmp >>= HOST_SMC_RESP_SHIFT;
444
445         result = (PPSMC_Result)tmp;
446         return result;
447 }
448
449 PPSMC_Result rv770_wait_for_smc_inactive(struct radeon_device *rdev)
450 {
451         int i;
452         PPSMC_Result result = PPSMC_Result_OK;
453
454         if (!rv770_is_smc_running(rdev))
455                 return result;
456
457         for (i = 0; i < rdev->usec_timeout; i++) {
458                 if (RREG32(SMC_IO) & SMC_STOP_MODE)
459                         break;
460                 udelay(1);
461         }
462
463         return result;
464 }
465
466 static void rv770_clear_smc_sram(struct radeon_device *rdev, u16 limit)
467 {
468         u16 i;
469
470         spin_lock(&rdev->smc_idx_lock);
471         for (i = 0;  i < limit; i += 4) {
472                 rv770_set_smc_sram_address(rdev, i, limit);
473                 WREG32(SMC_SRAM_DATA, 0);
474         }
475         spin_unlock(&rdev->smc_idx_lock);
476 }
477
478 int rv770_load_smc_ucode(struct radeon_device *rdev,
479                          u16 limit)
480 {
481         int ret;
482         const u8 *int_vect;
483         u16 int_vect_start_address;
484         u16 int_vect_size;
485         const u8 *ucode_data;
486         u16 ucode_start_address;
487         u16 ucode_size;
488
489         if (!rdev->smc_fw)
490                 return -EINVAL;
491
492         rv770_clear_smc_sram(rdev, limit);
493
494         switch (rdev->family) {
495         case CHIP_RV770:
496                 ucode_start_address = RV770_SMC_UCODE_START;
497                 ucode_size = RV770_SMC_UCODE_SIZE;
498                 int_vect = (const u8 *)&rv770_smc_int_vectors;
499                 int_vect_start_address = RV770_SMC_INT_VECTOR_START;
500                 int_vect_size = RV770_SMC_INT_VECTOR_SIZE;
501                 break;
502         case CHIP_RV730:
503                 ucode_start_address = RV730_SMC_UCODE_START;
504                 ucode_size = RV730_SMC_UCODE_SIZE;
505                 int_vect = (const u8 *)&rv730_smc_int_vectors;
506                 int_vect_start_address = RV730_SMC_INT_VECTOR_START;
507                 int_vect_size = RV730_SMC_INT_VECTOR_SIZE;
508                 break;
509         case CHIP_RV710:
510                 ucode_start_address = RV710_SMC_UCODE_START;
511                 ucode_size = RV710_SMC_UCODE_SIZE;
512                 int_vect = (const u8 *)&rv710_smc_int_vectors;
513                 int_vect_start_address = RV710_SMC_INT_VECTOR_START;
514                 int_vect_size = RV710_SMC_INT_VECTOR_SIZE;
515                 break;
516         case CHIP_RV740:
517                 ucode_start_address = RV740_SMC_UCODE_START;
518                 ucode_size = RV740_SMC_UCODE_SIZE;
519                 int_vect = (const u8 *)&rv740_smc_int_vectors;
520                 int_vect_start_address = RV740_SMC_INT_VECTOR_START;
521                 int_vect_size = RV740_SMC_INT_VECTOR_SIZE;
522                 break;
523         case CHIP_CEDAR:
524                 ucode_start_address = CEDAR_SMC_UCODE_START;
525                 ucode_size = CEDAR_SMC_UCODE_SIZE;
526                 int_vect = (const u8 *)&cedar_smc_int_vectors;
527                 int_vect_start_address = CEDAR_SMC_INT_VECTOR_START;
528                 int_vect_size = CEDAR_SMC_INT_VECTOR_SIZE;
529                 break;
530         case CHIP_REDWOOD:
531                 ucode_start_address = REDWOOD_SMC_UCODE_START;
532                 ucode_size = REDWOOD_SMC_UCODE_SIZE;
533                 int_vect = (const u8 *)&redwood_smc_int_vectors;
534                 int_vect_start_address = REDWOOD_SMC_INT_VECTOR_START;
535                 int_vect_size = REDWOOD_SMC_INT_VECTOR_SIZE;
536                 break;
537         case CHIP_JUNIPER:
538                 ucode_start_address = JUNIPER_SMC_UCODE_START;
539                 ucode_size = JUNIPER_SMC_UCODE_SIZE;
540                 int_vect = (const u8 *)&juniper_smc_int_vectors;
541                 int_vect_start_address = JUNIPER_SMC_INT_VECTOR_START;
542                 int_vect_size = JUNIPER_SMC_INT_VECTOR_SIZE;
543                 break;
544         case CHIP_CYPRESS:
545         case CHIP_HEMLOCK:
546                 ucode_start_address = CYPRESS_SMC_UCODE_START;
547                 ucode_size = CYPRESS_SMC_UCODE_SIZE;
548                 int_vect = (const u8 *)&cypress_smc_int_vectors;
549                 int_vect_start_address = CYPRESS_SMC_INT_VECTOR_START;
550                 int_vect_size = CYPRESS_SMC_INT_VECTOR_SIZE;
551                 break;
552         case CHIP_BARTS:
553                 ucode_start_address = BARTS_SMC_UCODE_START;
554                 ucode_size = BARTS_SMC_UCODE_SIZE;
555                 int_vect = (const u8 *)&barts_smc_int_vectors;
556                 int_vect_start_address = BARTS_SMC_INT_VECTOR_START;
557                 int_vect_size = BARTS_SMC_INT_VECTOR_SIZE;
558                 break;
559         case CHIP_TURKS:
560                 ucode_start_address = TURKS_SMC_UCODE_START;
561                 ucode_size = TURKS_SMC_UCODE_SIZE;
562                 int_vect = (const u8 *)&turks_smc_int_vectors;
563                 int_vect_start_address = TURKS_SMC_INT_VECTOR_START;
564                 int_vect_size = TURKS_SMC_INT_VECTOR_SIZE;
565                 break;
566         case CHIP_CAICOS:
567                 ucode_start_address = CAICOS_SMC_UCODE_START;
568                 ucode_size = CAICOS_SMC_UCODE_SIZE;
569                 int_vect = (const u8 *)&caicos_smc_int_vectors;
570                 int_vect_start_address = CAICOS_SMC_INT_VECTOR_START;
571                 int_vect_size = CAICOS_SMC_INT_VECTOR_SIZE;
572                 break;
573         case CHIP_CAYMAN:
574                 ucode_start_address = CAYMAN_SMC_UCODE_START;
575                 ucode_size = CAYMAN_SMC_UCODE_SIZE;
576                 int_vect = (const u8 *)&cayman_smc_int_vectors;
577                 int_vect_start_address = CAYMAN_SMC_INT_VECTOR_START;
578                 int_vect_size = CAYMAN_SMC_INT_VECTOR_SIZE;
579                 break;
580         default:
581                 DRM_ERROR("unknown asic in smc ucode loader\n");
582                 BUG();
583         }
584
585         /* load the ucode */
586         ucode_data = (const u8 *)rdev->smc_fw->data;
587         ret = rv770_copy_bytes_to_smc(rdev, ucode_start_address,
588                                       ucode_data, ucode_size, limit);
589         if (ret)
590                 return ret;
591
592         /* set up the int vectors */
593         ret = rv770_program_interrupt_vectors(rdev, int_vect_start_address,
594                                               int_vect, int_vect_size);
595         if (ret)
596                 return ret;
597
598         return 0;
599 }
600
601 int rv770_read_smc_sram_dword(struct radeon_device *rdev,
602                               u16 smc_address, u32 *value, u16 limit)
603 {
604         int ret;
605
606         spin_lock(&rdev->smc_idx_lock);
607         ret = rv770_set_smc_sram_address(rdev, smc_address, limit);
608         if (ret == 0)
609                 *value = RREG32(SMC_SRAM_DATA);
610         spin_unlock(&rdev->smc_idx_lock);
611
612         return ret;
613 }
614
615 int rv770_write_smc_sram_dword(struct radeon_device *rdev,
616                                u16 smc_address, u32 value, u16 limit)
617 {
618         int ret;
619
620         spin_lock(&rdev->smc_idx_lock);
621         ret = rv770_set_smc_sram_address(rdev, smc_address, limit);
622         if (ret == 0)
623                 WREG32(SMC_SRAM_DATA, value);
624         spin_unlock(&rdev->smc_idx_lock);
625
626         return ret;
627 }