Merge branch 'address-masking'
[linux-2.6-microblaze.git] / drivers / gpu / 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
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         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         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
75 static 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
94 static 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
113 static 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
132 static 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
151 static 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
170 static 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
189 static 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
208 static 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
227 static 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
246 static 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
265 static 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
283 int 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, 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, 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, addr, limit);
338                 if (ret)
339                         goto done;
340
341                 WREG32(SMC_SRAM_DATA, data);
342         }
343
344 done:
345         spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
346
347         return ret;
348 }
349
350 static 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
380 void rv770_start_smc(struct radeon_device *rdev)
381 {
382         WREG32_P(SMC_IO, SMC_RST_N, ~SMC_RST_N);
383 }
384
385 void rv770_reset_smc(struct radeon_device *rdev)
386 {
387         WREG32_P(SMC_IO, 0, ~SMC_RST_N);
388 }
389
390 void rv770_stop_smc_clock(struct radeon_device *rdev)
391 {
392         WREG32_P(SMC_IO, 0, ~SMC_CLK_EN);
393 }
394
395 void rv770_start_smc_clock(struct radeon_device *rdev)
396 {
397         WREG32_P(SMC_IO, SMC_CLK_EN, ~SMC_CLK_EN);
398 }
399
400 bool 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
412 PPSMC_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
438 PPSMC_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
455 static 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, i, limit);
463                 WREG32(SMC_SRAM_DATA, 0);
464         }
465         spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
466 }
467
468 int 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, ucode_start_address,
578                                       ucode_data, ucode_size, limit);
579         if (ret)
580                 return ret;
581
582         /* set up the int vectors */
583         ret = rv770_program_interrupt_vectors(rdev, int_vect_start_address,
584                                               int_vect, int_vect_size);
585         if (ret)
586                 return ret;
587
588         return 0;
589 }
590
591 int 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(&rdev->smc_idx_lock, flags);
602
603         return ret;
604 }
605
606 int 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(&rdev->smc_idx_lock, flags);
617
618         return ret;
619 }