xref: /dragonfly/sys/dev/drm/radeon/rv770_smc.c (revision 4bab7bf3)
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 }
628