1 /*	$NetBSD: radeon_rv770_smc.c,v 1.3 2021/12/18 23:45:43 riastradh Exp $	*/
2 
3 /*
4  * Copyright 2011 Advanced Micro Devices, Inc.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22  * OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * Authors: Alex Deucher
25  */
26 
27 #include <sys/cdefs.h>
28 __KERNEL_RCSID(0, "$NetBSD: radeon_rv770_smc.c,v 1.3 2021/12/18 23:45:43 riastradh Exp $");
29 
30 #include <linux/firmware.h>
31 
32 #include "radeon.h"
33 #include "rv770d.h"
34 #include "rv770_dpm.h"
35 #include "rv770_smc.h"
36 #include "atom.h"
37 #include "radeon_ucode.h"
38 
39 #define FIRST_SMC_INT_VECT_REG 0xFFD8
40 #define FIRST_INT_VECT_S19     0xFFC0
41 
42 static const u8 rv770_smc_int_vectors[] =
43 {
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, 0x08, 0x10,
52 	0x08, 0x10, 0x08, 0x10,
53 	0x08, 0x10, 0x08, 0x10,
54 	0x08, 0x10, 0x08, 0x10,
55 	0x08, 0x10, 0x08, 0x10,
56 	0x08, 0x10, 0x0C, 0xD7,
57 	0x08, 0x2B, 0x08, 0x10,
58 	0x03, 0x51, 0x03, 0x51,
59 	0x03, 0x51, 0x03, 0x51
60 };
61 
62 static const u8 rv730_smc_int_vectors[] =
63 {
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, 0x08, 0x15,
72 	0x08, 0x15, 0x08, 0x15,
73 	0x08, 0x15, 0x08, 0x15,
74 	0x08, 0x15, 0x08, 0x15,
75 	0x08, 0x15, 0x08, 0x15,
76 	0x08, 0x15, 0x0C, 0xBB,
77 	0x08, 0x30, 0x08, 0x15,
78 	0x03, 0x56, 0x03, 0x56,
79 	0x03, 0x56, 0x03, 0x56
80 };
81 
82 static const u8 rv710_smc_int_vectors[] =
83 {
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, 0x08, 0x04,
92 	0x08, 0x04, 0x08, 0x04,
93 	0x08, 0x04, 0x08, 0x04,
94 	0x08, 0x04, 0x08, 0x04,
95 	0x08, 0x04, 0x08, 0x04,
96 	0x08, 0x04, 0x0C, 0xCB,
97 	0x08, 0x1F, 0x08, 0x04,
98 	0x03, 0x51, 0x03, 0x51,
99 	0x03, 0x51, 0x03, 0x51
100 };
101 
102 static const u8 rv740_smc_int_vectors[] =
103 {
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, 0x08, 0x10,
112 	0x08, 0x10, 0x08, 0x10,
113 	0x08, 0x10, 0x08, 0x10,
114 	0x08, 0x10, 0x08, 0x10,
115 	0x08, 0x10, 0x08, 0x10,
116 	0x08, 0x10, 0x0C, 0xD7,
117 	0x08, 0x2B, 0x08, 0x10,
118 	0x03, 0x51, 0x03, 0x51,
119 	0x03, 0x51, 0x03, 0x51
120 };
121 
122 static const u8 cedar_smc_int_vectors[] =
123 {
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, 0x0B, 0x05,
132 	0x0B, 0x05, 0x0B, 0x05,
133 	0x0B, 0x05, 0x0B, 0x05,
134 	0x0B, 0x05, 0x0B, 0x05,
135 	0x0B, 0x05, 0x0B, 0x05,
136 	0x0B, 0x05, 0x11, 0x8B,
137 	0x0B, 0x20, 0x0B, 0x05,
138 	0x04, 0xF6, 0x04, 0xF6,
139 	0x04, 0xF6, 0x04, 0xF6
140 };
141 
142 static const u8 redwood_smc_int_vectors[] =
143 {
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, 0x0B, 0x05,
152 	0x0B, 0x05, 0x0B, 0x05,
153 	0x0B, 0x05, 0x0B, 0x05,
154 	0x0B, 0x05, 0x0B, 0x05,
155 	0x0B, 0x05, 0x0B, 0x05,
156 	0x0B, 0x05, 0x11, 0x8B,
157 	0x0B, 0x20, 0x0B, 0x05,
158 	0x04, 0xF6, 0x04, 0xF6,
159 	0x04, 0xF6, 0x04, 0xF6
160 };
161 
162 static const u8 juniper_smc_int_vectors[] =
163 {
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, 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, 0x11, 0x8B,
177 	0x0B, 0x20, 0x0B, 0x05,
178 	0x04, 0xF6, 0x04, 0xF6,
179 	0x04, 0xF6, 0x04, 0xF6
180 };
181 
182 static const u8 cypress_smc_int_vectors[] =
183 {
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, 0x0B, 0x05,
192 	0x0B, 0x05, 0x0B, 0x05,
193 	0x0B, 0x05, 0x0B, 0x05,
194 	0x0B, 0x05, 0x0B, 0x05,
195 	0x0B, 0x05, 0x0B, 0x05,
196 	0x0B, 0x05, 0x11, 0x8B,
197 	0x0B, 0x20, 0x0B, 0x05,
198 	0x04, 0xF6, 0x04, 0xF6,
199 	0x04, 0xF6, 0x04, 0xF6
200 };
201 
202 static const u8 barts_smc_int_vectors[] =
203 {
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, 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, 0x12, 0xAA,
217 	0x0C, 0x2F, 0x15, 0xF6,
218 	0x15, 0xF6, 0x05, 0x0A,
219 	0x05, 0x0A, 0x05, 0x0A
220 };
221 
222 static const u8 turks_smc_int_vectors[] =
223 {
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, 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, 0x12, 0xAA,
237 	0x0C, 0x2F, 0x15, 0xF6,
238 	0x15, 0xF6, 0x05, 0x0A,
239 	0x05, 0x0A, 0x05, 0x0A
240 };
241 
242 static const u8 caicos_smc_int_vectors[] =
243 {
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, 0x0C, 0x14,
252 	0x0C, 0x14, 0x0C, 0x14,
253 	0x0C, 0x14, 0x0C, 0x14,
254 	0x0C, 0x14, 0x0C, 0x14,
255 	0x0C, 0x14, 0x0C, 0x14,
256 	0x0C, 0x14, 0x12, 0xAA,
257 	0x0C, 0x2F, 0x15, 0xF6,
258 	0x15, 0xF6, 0x05, 0x0A,
259 	0x05, 0x0A, 0x05, 0x0A
260 };
261 
262 static const u8 cayman_smc_int_vectors[] =
263 {
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, 0x12, 0x05,
272 	0x12, 0x05, 0x12, 0x05,
273 	0x12, 0x05, 0x12, 0x05,
274 	0x12, 0x05, 0x12, 0x05,
275 	0x12, 0x05, 0x12, 0x05,
276 	0x12, 0x05, 0x18, 0xEA,
277 	0x12, 0x20, 0x1C, 0x34,
278 	0x1C, 0x34, 0x08, 0x72,
279 	0x08, 0x72, 0x08, 0x72
280 };
281 
rv770_set_smc_sram_address(struct radeon_device * rdev,u16 smc_address,u16 limit)282 static int rv770_set_smc_sram_address(struct radeon_device *rdev,
283 				      u16 smc_address, u16 limit)
284 {
285 	u32 addr;
286 
287 	if (smc_address & 3)
288 		return -EINVAL;
289 	if ((smc_address + 3) > limit)
290 		return -EINVAL;
291 
292 	addr = smc_address;
293 	addr |= SMC_SRAM_AUTO_INC_DIS;
294 
295 	WREG32(SMC_SRAM_ADDR, addr);
296 
297 	return 0;
298 }
299 
rv770_copy_bytes_to_smc(struct radeon_device * rdev,u16 smc_start_address,const u8 * src,u16 byte_count,u16 limit)300 int rv770_copy_bytes_to_smc(struct radeon_device *rdev,
301 			    u16 smc_start_address, const u8 *src,
302 			    u16 byte_count, u16 limit)
303 {
304 	unsigned long flags;
305 	u32 data, original_data, extra_shift;
306 	u16 addr;
307 	int ret = 0;
308 
309 	if (smc_start_address & 3)
310 		return -EINVAL;
311 	if ((smc_start_address + byte_count) > limit)
312 		return -EINVAL;
313 
314 	addr = smc_start_address;
315 
316 	spin_lock_irqsave(&rdev->smc_idx_lock, flags);
317 	while (byte_count >= 4) {
318 		/* SMC address space is BE */
319 		data = ((u32)src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
320 
321 		ret = rv770_set_smc_sram_address(rdev, addr, limit);
322 		if (ret)
323 			goto done;
324 
325 		WREG32(SMC_SRAM_DATA, data);
326 
327 		src += 4;
328 		byte_count -= 4;
329 		addr += 4;
330 	}
331 
332 	/* RMW for final bytes */
333 	if (byte_count > 0) {
334 		data = 0;
335 
336 		ret = rv770_set_smc_sram_address(rdev, addr, limit);
337 		if (ret)
338 			goto done;
339 
340 		original_data = RREG32(SMC_SRAM_DATA);
341 
342 		extra_shift = 8 * (4 - byte_count);
343 
344 		while (byte_count > 0) {
345 			/* SMC address space is BE */
346 			data = (data << 8) + *src++;
347 			byte_count--;
348 		}
349 
350 		data <<= extra_shift;
351 
352 		data |= (original_data & ~((~0UL) << extra_shift));
353 
354 		ret = rv770_set_smc_sram_address(rdev, addr, limit);
355 		if (ret)
356 			goto done;
357 
358 		WREG32(SMC_SRAM_DATA, data);
359 	}
360 
361 done:
362 	spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
363 
364 	return ret;
365 }
366 
rv770_program_interrupt_vectors(struct radeon_device * rdev,u32 smc_first_vector,const u8 * src,u32 byte_count)367 static int rv770_program_interrupt_vectors(struct radeon_device *rdev,
368 					   u32 smc_first_vector, const u8 *src,
369 					   u32 byte_count)
370 {
371 	u32 tmp, i;
372 
373 	if (byte_count % 4)
374 		return -EINVAL;
375 
376 	if (smc_first_vector < FIRST_SMC_INT_VECT_REG) {
377 		tmp = FIRST_SMC_INT_VECT_REG - smc_first_vector;
378 
379 		if (tmp > byte_count)
380 			return 0;
381 
382 		byte_count -= tmp;
383 		src += tmp;
384 		smc_first_vector = FIRST_SMC_INT_VECT_REG;
385 	}
386 
387 	for (i = 0; i < byte_count; i += 4) {
388 		/* SMC address space is BE */
389 		tmp = (src[i] << 24) | (src[i + 1] << 16) | (src[i + 2] << 8) | src[i + 3];
390 
391 		WREG32(SMC_ISR_FFD8_FFDB + i, tmp);
392 	}
393 
394 	return 0;
395 }
396 
rv770_start_smc(struct radeon_device * rdev)397 void rv770_start_smc(struct radeon_device *rdev)
398 {
399 	WREG32_P(SMC_IO, SMC_RST_N, ~SMC_RST_N);
400 }
401 
rv770_reset_smc(struct radeon_device * rdev)402 void rv770_reset_smc(struct radeon_device *rdev)
403 {
404 	WREG32_P(SMC_IO, 0, ~SMC_RST_N);
405 }
406 
rv770_stop_smc_clock(struct radeon_device * rdev)407 void rv770_stop_smc_clock(struct radeon_device *rdev)
408 {
409 	WREG32_P(SMC_IO, 0, ~SMC_CLK_EN);
410 }
411 
rv770_start_smc_clock(struct radeon_device * rdev)412 void rv770_start_smc_clock(struct radeon_device *rdev)
413 {
414 	WREG32_P(SMC_IO, SMC_CLK_EN, ~SMC_CLK_EN);
415 }
416 
rv770_is_smc_running(struct radeon_device * rdev)417 bool rv770_is_smc_running(struct radeon_device *rdev)
418 {
419 	u32 tmp;
420 
421 	tmp = RREG32(SMC_IO);
422 
423 	if ((tmp & SMC_RST_N) && (tmp & SMC_CLK_EN))
424 		return true;
425 	else
426 		return false;
427 }
428 
rv770_send_msg_to_smc(struct radeon_device * rdev,PPSMC_Msg msg)429 PPSMC_Result rv770_send_msg_to_smc(struct radeon_device *rdev, PPSMC_Msg msg)
430 {
431 	u32 tmp;
432 	int i;
433 	PPSMC_Result result;
434 
435 	if (!rv770_is_smc_running(rdev))
436 		return PPSMC_Result_Failed;
437 
438 	WREG32_P(SMC_MSG, HOST_SMC_MSG(msg), ~HOST_SMC_MSG_MASK);
439 
440 	for (i = 0; i < rdev->usec_timeout; i++) {
441 		tmp = RREG32(SMC_MSG) & HOST_SMC_RESP_MASK;
442 		tmp >>= HOST_SMC_RESP_SHIFT;
443 		if (tmp != 0)
444 			break;
445 		udelay(1);
446 	}
447 
448 	tmp = RREG32(SMC_MSG) & HOST_SMC_RESP_MASK;
449 	tmp >>= HOST_SMC_RESP_SHIFT;
450 
451 	result = (PPSMC_Result)tmp;
452 	return result;
453 }
454 
rv770_wait_for_smc_inactive(struct radeon_device * rdev)455 PPSMC_Result rv770_wait_for_smc_inactive(struct radeon_device *rdev)
456 {
457 	int i;
458 	PPSMC_Result result = PPSMC_Result_OK;
459 
460 	if (!rv770_is_smc_running(rdev))
461 		return result;
462 
463 	for (i = 0; i < rdev->usec_timeout; i++) {
464 		if (RREG32(SMC_IO) & SMC_STOP_MODE)
465 			break;
466 		udelay(1);
467 	}
468 
469 	return result;
470 }
471 
rv770_clear_smc_sram(struct radeon_device * rdev,u16 limit)472 static void rv770_clear_smc_sram(struct radeon_device *rdev, u16 limit)
473 {
474 	unsigned long flags;
475 	u16 i;
476 
477 	spin_lock_irqsave(&rdev->smc_idx_lock, flags);
478 	for (i = 0;  i < limit; i += 4) {
479 		rv770_set_smc_sram_address(rdev, i, limit);
480 		WREG32(SMC_SRAM_DATA, 0);
481 	}
482 	spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
483 }
484 
rv770_load_smc_ucode(struct radeon_device * rdev,u16 limit)485 int rv770_load_smc_ucode(struct radeon_device *rdev,
486 			 u16 limit)
487 {
488 	int ret;
489 	const u8 *int_vect;
490 	u16 int_vect_start_address;
491 	u16 int_vect_size;
492 	const u8 *ucode_data;
493 	u16 ucode_start_address;
494 	u16 ucode_size;
495 
496 	if (!rdev->smc_fw)
497 		return -EINVAL;
498 
499 	rv770_clear_smc_sram(rdev, limit);
500 
501 	switch (rdev->family) {
502 	case CHIP_RV770:
503 		ucode_start_address = RV770_SMC_UCODE_START;
504 		ucode_size = RV770_SMC_UCODE_SIZE;
505 		int_vect = (const u8 *)&rv770_smc_int_vectors;
506 		int_vect_start_address = RV770_SMC_INT_VECTOR_START;
507 		int_vect_size = RV770_SMC_INT_VECTOR_SIZE;
508 		break;
509 	case CHIP_RV730:
510 		ucode_start_address = RV730_SMC_UCODE_START;
511 		ucode_size = RV730_SMC_UCODE_SIZE;
512 		int_vect = (const u8 *)&rv730_smc_int_vectors;
513 		int_vect_start_address = RV730_SMC_INT_VECTOR_START;
514 		int_vect_size = RV730_SMC_INT_VECTOR_SIZE;
515 		break;
516 	case CHIP_RV710:
517 		ucode_start_address = RV710_SMC_UCODE_START;
518 		ucode_size = RV710_SMC_UCODE_SIZE;
519 		int_vect = (const u8 *)&rv710_smc_int_vectors;
520 		int_vect_start_address = RV710_SMC_INT_VECTOR_START;
521 		int_vect_size = RV710_SMC_INT_VECTOR_SIZE;
522 		break;
523 	case CHIP_RV740:
524 		ucode_start_address = RV740_SMC_UCODE_START;
525 		ucode_size = RV740_SMC_UCODE_SIZE;
526 		int_vect = (const u8 *)&rv740_smc_int_vectors;
527 		int_vect_start_address = RV740_SMC_INT_VECTOR_START;
528 		int_vect_size = RV740_SMC_INT_VECTOR_SIZE;
529 		break;
530 	case CHIP_CEDAR:
531 		ucode_start_address = CEDAR_SMC_UCODE_START;
532 		ucode_size = CEDAR_SMC_UCODE_SIZE;
533 		int_vect = (const u8 *)&cedar_smc_int_vectors;
534 		int_vect_start_address = CEDAR_SMC_INT_VECTOR_START;
535 		int_vect_size = CEDAR_SMC_INT_VECTOR_SIZE;
536 		break;
537 	case CHIP_REDWOOD:
538 		ucode_start_address = REDWOOD_SMC_UCODE_START;
539 		ucode_size = REDWOOD_SMC_UCODE_SIZE;
540 		int_vect = (const u8 *)&redwood_smc_int_vectors;
541 		int_vect_start_address = REDWOOD_SMC_INT_VECTOR_START;
542 		int_vect_size = REDWOOD_SMC_INT_VECTOR_SIZE;
543 		break;
544 	case CHIP_JUNIPER:
545 		ucode_start_address = JUNIPER_SMC_UCODE_START;
546 		ucode_size = JUNIPER_SMC_UCODE_SIZE;
547 		int_vect = (const u8 *)&juniper_smc_int_vectors;
548 		int_vect_start_address = JUNIPER_SMC_INT_VECTOR_START;
549 		int_vect_size = JUNIPER_SMC_INT_VECTOR_SIZE;
550 		break;
551 	case CHIP_CYPRESS:
552 	case CHIP_HEMLOCK:
553 		ucode_start_address = CYPRESS_SMC_UCODE_START;
554 		ucode_size = CYPRESS_SMC_UCODE_SIZE;
555 		int_vect = (const u8 *)&cypress_smc_int_vectors;
556 		int_vect_start_address = CYPRESS_SMC_INT_VECTOR_START;
557 		int_vect_size = CYPRESS_SMC_INT_VECTOR_SIZE;
558 		break;
559 	case CHIP_BARTS:
560 		ucode_start_address = BARTS_SMC_UCODE_START;
561 		ucode_size = BARTS_SMC_UCODE_SIZE;
562 		int_vect = (const u8 *)&barts_smc_int_vectors;
563 		int_vect_start_address = BARTS_SMC_INT_VECTOR_START;
564 		int_vect_size = BARTS_SMC_INT_VECTOR_SIZE;
565 		break;
566 	case CHIP_TURKS:
567 		ucode_start_address = TURKS_SMC_UCODE_START;
568 		ucode_size = TURKS_SMC_UCODE_SIZE;
569 		int_vect = (const u8 *)&turks_smc_int_vectors;
570 		int_vect_start_address = TURKS_SMC_INT_VECTOR_START;
571 		int_vect_size = TURKS_SMC_INT_VECTOR_SIZE;
572 		break;
573 	case CHIP_CAICOS:
574 		ucode_start_address = CAICOS_SMC_UCODE_START;
575 		ucode_size = CAICOS_SMC_UCODE_SIZE;
576 		int_vect = (const u8 *)&caicos_smc_int_vectors;
577 		int_vect_start_address = CAICOS_SMC_INT_VECTOR_START;
578 		int_vect_size = CAICOS_SMC_INT_VECTOR_SIZE;
579 		break;
580 	case CHIP_CAYMAN:
581 		ucode_start_address = CAYMAN_SMC_UCODE_START;
582 		ucode_size = CAYMAN_SMC_UCODE_SIZE;
583 		int_vect = (const u8 *)&cayman_smc_int_vectors;
584 		int_vect_start_address = CAYMAN_SMC_INT_VECTOR_START;
585 		int_vect_size = CAYMAN_SMC_INT_VECTOR_SIZE;
586 		break;
587 	default:
588 		DRM_ERROR("unknown asic in smc ucode loader\n");
589 		BUG();
590 	}
591 
592 	/* load the ucode */
593 	ucode_data = (const u8 *)rdev->smc_fw->data;
594 	ret = rv770_copy_bytes_to_smc(rdev, ucode_start_address,
595 				      ucode_data, ucode_size, limit);
596 	if (ret)
597 		return ret;
598 
599 	/* set up the int vectors */
600 	ret = rv770_program_interrupt_vectors(rdev, int_vect_start_address,
601 					      int_vect, int_vect_size);
602 	if (ret)
603 		return ret;
604 
605 	return 0;
606 }
607 
rv770_read_smc_sram_dword(struct radeon_device * rdev,u16 smc_address,u32 * value,u16 limit)608 int rv770_read_smc_sram_dword(struct radeon_device *rdev,
609 			      u16 smc_address, u32 *value, u16 limit)
610 {
611 	unsigned long flags;
612 	int ret;
613 
614 	spin_lock_irqsave(&rdev->smc_idx_lock, flags);
615 	ret = rv770_set_smc_sram_address(rdev, smc_address, limit);
616 	if (ret == 0)
617 		*value = RREG32(SMC_SRAM_DATA);
618 	spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
619 
620 	return ret;
621 }
622 
rv770_write_smc_sram_dword(struct radeon_device * rdev,u16 smc_address,u32 value,u16 limit)623 int rv770_write_smc_sram_dword(struct radeon_device *rdev,
624 			       u16 smc_address, u32 value, u16 limit)
625 {
626 	unsigned long flags;
627 	int ret;
628 
629 	spin_lock_irqsave(&rdev->smc_idx_lock, flags);
630 	ret = rv770_set_smc_sram_address(rdev, smc_address, limit);
631 	if (ret == 0)
632 		WREG32(SMC_SRAM_DATA, value);
633 	spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
634 
635 	return ret;
636 }
637