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