Subversion Repositories Kolibri OS

Rev

Rev 5078 | Details | Compare with Previous | 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 "sid.h"
29
#include "ppsmc.h"
30
#include "radeon_ucode.h"
31
#include "sislands_smc.h"
32
 
33
static int si_set_smc_sram_address(struct radeon_device *rdev,
34
				   u32 smc_address, u32 limit)
35
{
36
	if (smc_address & 3)
37
		return -EINVAL;
38
	if ((smc_address + 3) > limit)
39
		return -EINVAL;
40
 
41
	WREG32(SMC_IND_INDEX_0, smc_address);
42
	WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0);
43
 
44
	return 0;
45
}
46
 
47
int si_copy_bytes_to_smc(struct radeon_device *rdev,
48
			 u32 smc_start_address,
49
			 const u8 *src, u32 byte_count, u32 limit)
50
{
51
	unsigned long flags;
52
	int ret = 0;
53
	u32 data, original_data, addr, extra_shift;
54
 
55
	if (smc_start_address & 3)
56
		return -EINVAL;
57
	if ((smc_start_address + byte_count) > limit)
58
		return -EINVAL;
59
 
60
	addr = smc_start_address;
61
 
62
	spin_lock_irqsave(&rdev->smc_idx_lock, flags);
63
	while (byte_count >= 4) {
64
		/* SMC address space is BE */
65
		data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
66
 
67
		ret = si_set_smc_sram_address(rdev, addr, limit);
68
		if (ret)
69
			goto done;
70
 
71
		WREG32(SMC_IND_DATA_0, data);
72
 
73
		src += 4;
74
		byte_count -= 4;
75
		addr += 4;
76
	}
77
 
78
	/* RMW for the final bytes */
79
	if (byte_count > 0) {
80
		data = 0;
81
 
82
		ret = si_set_smc_sram_address(rdev, addr, limit);
83
		if (ret)
84
			goto done;
85
 
86
		original_data = RREG32(SMC_IND_DATA_0);
87
 
88
		extra_shift = 8 * (4 - byte_count);
89
 
90
		while (byte_count > 0) {
91
			/* SMC address space is BE */
92
			data = (data << 8) + *src++;
93
			byte_count--;
94
		}
95
 
96
		data <<= extra_shift;
97
 
98
		data |= (original_data & ~((~0UL) << extra_shift));
99
 
100
		ret = si_set_smc_sram_address(rdev, addr, limit);
101
		if (ret)
102
			goto done;
103
 
104
		WREG32(SMC_IND_DATA_0, data);
105
	}
106
 
107
done:
108
	spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
109
 
110
	return ret;
111
}
112
 
113
void si_start_smc(struct radeon_device *rdev)
114
{
115
	u32 tmp = RREG32_SMC(SMC_SYSCON_RESET_CNTL);
116
 
117
	tmp &= ~RST_REG;
118
 
119
	WREG32_SMC(SMC_SYSCON_RESET_CNTL, tmp);
120
}
121
 
122
void si_reset_smc(struct radeon_device *rdev)
123
{
124
	u32 tmp;
125
 
126
	RREG32(CB_CGTT_SCLK_CTRL);
127
	RREG32(CB_CGTT_SCLK_CTRL);
128
	RREG32(CB_CGTT_SCLK_CTRL);
129
	RREG32(CB_CGTT_SCLK_CTRL);
130
 
131
	tmp = RREG32_SMC(SMC_SYSCON_RESET_CNTL);
132
	tmp |= RST_REG;
133
	WREG32_SMC(SMC_SYSCON_RESET_CNTL, tmp);
134
}
135
 
136
int si_program_jump_on_start(struct radeon_device *rdev)
137
{
5271 serge 138
	static const u8 data[] = { 0x0E, 0x00, 0x40, 0x40 };
5078 serge 139
 
140
	return si_copy_bytes_to_smc(rdev, 0x0, data, 4, sizeof(data)+1);
141
}
142
 
143
void si_stop_smc_clock(struct radeon_device *rdev)
144
{
145
	u32 tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
146
 
147
	tmp |= CK_DISABLE;
148
 
149
	WREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0, tmp);
150
}
151
 
152
void si_start_smc_clock(struct radeon_device *rdev)
153
{
154
	u32 tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
155
 
156
	tmp &= ~CK_DISABLE;
157
 
158
	WREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0, tmp);
159
}
160
 
161
bool si_is_smc_running(struct radeon_device *rdev)
162
{
163
	u32 rst = RREG32_SMC(SMC_SYSCON_RESET_CNTL);
164
	u32 clk = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
165
 
166
	if (!(rst & RST_REG) && !(clk & CK_DISABLE))
167
		return true;
168
 
169
	return false;
170
}
171
 
172
PPSMC_Result si_send_msg_to_smc(struct radeon_device *rdev, PPSMC_Msg msg)
173
{
174
	u32 tmp;
175
	int i;
176
 
177
	if (!si_is_smc_running(rdev))
178
		return PPSMC_Result_Failed;
179
 
180
	WREG32(SMC_MESSAGE_0, msg);
181
 
182
	for (i = 0; i < rdev->usec_timeout; i++) {
183
		tmp = RREG32(SMC_RESP_0);
184
		if (tmp != 0)
185
			break;
186
		udelay(1);
187
	}
188
	tmp = RREG32(SMC_RESP_0);
189
 
190
	return (PPSMC_Result)tmp;
191
}
192
 
193
PPSMC_Result si_wait_for_smc_inactive(struct radeon_device *rdev)
194
{
195
	u32 tmp;
196
	int i;
197
 
198
	if (!si_is_smc_running(rdev))
199
		return PPSMC_Result_OK;
200
 
201
	for (i = 0; i < rdev->usec_timeout; i++) {
202
		tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
203
		if ((tmp & CKEN) == 0)
204
			break;
205
		udelay(1);
206
	}
207
 
208
	return PPSMC_Result_OK;
209
}
210
 
211
int si_load_smc_ucode(struct radeon_device *rdev, u32 limit)
212
{
213
	unsigned long flags;
214
	u32 ucode_start_address;
215
	u32 ucode_size;
216
	const u8 *src;
217
	u32 data;
218
 
219
	if (!rdev->smc_fw)
220
		return -EINVAL;
221
 
222
	if (rdev->new_fw) {
223
		const struct smc_firmware_header_v1_0 *hdr =
224
			(const struct smc_firmware_header_v1_0 *)rdev->smc_fw->data;
225
 
226
		radeon_ucode_print_smc_hdr(&hdr->header);
227
 
228
		ucode_start_address = le32_to_cpu(hdr->ucode_start_addr);
229
		ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes);
230
		src = (const u8 *)
231
			(rdev->smc_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes));
232
	} else {
233
		switch (rdev->family) {
234
		case CHIP_TAHITI:
235
			ucode_start_address = TAHITI_SMC_UCODE_START;
236
			ucode_size = TAHITI_SMC_UCODE_SIZE;
237
			break;
238
		case CHIP_PITCAIRN:
239
			ucode_start_address = PITCAIRN_SMC_UCODE_START;
240
			ucode_size = PITCAIRN_SMC_UCODE_SIZE;
241
			break;
242
		case CHIP_VERDE:
243
			ucode_start_address = VERDE_SMC_UCODE_START;
244
			ucode_size = VERDE_SMC_UCODE_SIZE;
245
			break;
246
		case CHIP_OLAND:
247
			ucode_start_address = OLAND_SMC_UCODE_START;
248
			ucode_size = OLAND_SMC_UCODE_SIZE;
249
			break;
250
		case CHIP_HAINAN:
251
			ucode_start_address = HAINAN_SMC_UCODE_START;
252
			ucode_size = HAINAN_SMC_UCODE_SIZE;
253
			break;
254
		default:
255
			DRM_ERROR("unknown asic in smc ucode loader\n");
256
			BUG();
257
		}
258
		src = (const u8 *)rdev->smc_fw->data;
259
	}
260
 
261
	if (ucode_size & 3)
262
		return -EINVAL;
263
 
264
	spin_lock_irqsave(&rdev->smc_idx_lock, flags);
265
	WREG32(SMC_IND_INDEX_0, ucode_start_address);
266
	WREG32_P(SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, ~AUTO_INCREMENT_IND_0);
267
	while (ucode_size >= 4) {
268
		/* SMC address space is BE */
269
		data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
270
 
271
		WREG32(SMC_IND_DATA_0, data);
272
 
273
		src += 4;
274
		ucode_size -= 4;
275
	}
276
	WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0);
277
	spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
278
 
279
	return 0;
280
}
281
 
282
int si_read_smc_sram_dword(struct radeon_device *rdev, u32 smc_address,
283
			   u32 *value, u32 limit)
284
{
285
	unsigned long flags;
286
	int ret;
287
 
288
	spin_lock_irqsave(&rdev->smc_idx_lock, flags);
289
	ret = si_set_smc_sram_address(rdev, smc_address, limit);
290
	if (ret == 0)
291
		*value = RREG32(SMC_IND_DATA_0);
292
	spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
293
 
294
	return ret;
295
}
296
 
297
int si_write_smc_sram_dword(struct radeon_device *rdev, u32 smc_address,
298
			    u32 value, u32 limit)
299
{
300
	unsigned long flags;
301
	int ret;
302
 
303
	spin_lock_irqsave(&rdev->smc_idx_lock, flags);
304
	ret = si_set_smc_sram_address(rdev, smc_address, limit);
305
	if (ret == 0)
306
		WREG32(SMC_IND_DATA_0, value);
307
	spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
308
 
309
	return ret;
310
}