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