Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5078 serge 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 
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
}