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
42static 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
62static 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
82static 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
102static 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
122static 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
142static 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
162static 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
182static 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
202static 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
222static 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
242static 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
262static 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
282static 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
300int 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
361done:
362	spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
363
364	return ret;
365}
366
367static 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
397void rv770_start_smc(struct radeon_device *rdev)
398{
399	WREG32_P(SMC_IO, SMC_RST_N, ~SMC_RST_N);
400}
401
402void rv770_reset_smc(struct radeon_device *rdev)
403{
404	WREG32_P(SMC_IO, 0, ~SMC_RST_N);
405}
406
407void rv770_stop_smc_clock(struct radeon_device *rdev)
408{
409	WREG32_P(SMC_IO, 0, ~SMC_CLK_EN);
410}
411
412void rv770_start_smc_clock(struct radeon_device *rdev)
413{
414	WREG32_P(SMC_IO, SMC_CLK_EN, ~SMC_CLK_EN);
415}
416
417bool 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
429PPSMC_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
455PPSMC_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
472static 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
485int 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
608int 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
623int 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