xref: /linux/drivers/gpu/drm/radeon/rv770_smc.c (revision 93df8a1ed6231727c5db94a80b1a6bd5ee67cec3)
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 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 }
632