Update drm/radeon to Linux 4.7.10 as much as possible...
[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         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
356 done:
357         spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
358
359         return ret;
360 }
361
362 static 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
392 void rv770_start_smc(struct radeon_device *rdev)
393 {
394         WREG32_P(SMC_IO, SMC_RST_N, ~SMC_RST_N);
395 }
396
397 void rv770_reset_smc(struct radeon_device *rdev)
398 {
399         WREG32_P(SMC_IO, 0, ~SMC_RST_N);
400 }
401
402 void rv770_stop_smc_clock(struct radeon_device *rdev)
403 {
404         WREG32_P(SMC_IO, 0, ~SMC_CLK_EN);
405 }
406
407 void rv770_start_smc_clock(struct radeon_device *rdev)
408 {
409         WREG32_P(SMC_IO, SMC_CLK_EN, ~SMC_CLK_EN);
410 }
411
412 bool 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
424 PPSMC_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
450 PPSMC_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
467 static 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
480 int 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
603 int 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
618 int 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 }