xref: /openbmc/linux/drivers/gpu/drm/radeon/si_smc.c (revision 0898782247ae533d1f4e47a06bc5d4870931b284)
1a9e61410SAlex Deucher /*
2a9e61410SAlex Deucher  * Copyright 2011 Advanced Micro Devices, Inc.
3a9e61410SAlex Deucher  *
4a9e61410SAlex Deucher  * Permission is hereby granted, free of charge, to any person obtaining a
5a9e61410SAlex Deucher  * copy of this software and associated documentation files (the "Software"),
6a9e61410SAlex Deucher  * to deal in the Software without restriction, including without limitation
7a9e61410SAlex Deucher  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8a9e61410SAlex Deucher  * and/or sell copies of the Software, and to permit persons to whom the
9a9e61410SAlex Deucher  * Software is furnished to do so, subject to the following conditions:
10a9e61410SAlex Deucher  *
11a9e61410SAlex Deucher  * The above copyright notice and this permission notice shall be included in
12a9e61410SAlex Deucher  * all copies or substantial portions of the Software.
13a9e61410SAlex Deucher  *
14a9e61410SAlex Deucher  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15a9e61410SAlex Deucher  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16a9e61410SAlex Deucher  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17a9e61410SAlex Deucher  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18a9e61410SAlex Deucher  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19a9e61410SAlex Deucher  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20a9e61410SAlex Deucher  * OTHER DEALINGS IN THE SOFTWARE.
21a9e61410SAlex Deucher  *
22a9e61410SAlex Deucher  * Authors: Alex Deucher
23a9e61410SAlex Deucher  */
24a9e61410SAlex Deucher 
25a9e61410SAlex Deucher #include <linux/firmware.h>
26*c182615fSSam Ravnborg 
27a9e61410SAlex Deucher #include "radeon.h"
28a9e61410SAlex Deucher #include "sid.h"
29a9e61410SAlex Deucher #include "ppsmc.h"
30a9e61410SAlex Deucher #include "radeon_ucode.h"
316c149d96SRashika Kheria #include "sislands_smc.h"
32a9e61410SAlex Deucher 
si_set_smc_sram_address(struct radeon_device * rdev,u32 smc_address,u32 limit)33fe78118cSAlex Deucher static int si_set_smc_sram_address(struct radeon_device *rdev,
34a9e61410SAlex Deucher 				   u32 smc_address, u32 limit)
35a9e61410SAlex Deucher {
36a9e61410SAlex Deucher 	if (smc_address & 3)
37a9e61410SAlex Deucher 		return -EINVAL;
38a9e61410SAlex Deucher 	if ((smc_address + 3) > limit)
39a9e61410SAlex Deucher 		return -EINVAL;
40a9e61410SAlex Deucher 
41a9e61410SAlex Deucher 	WREG32(SMC_IND_INDEX_0, smc_address);
42a9e61410SAlex Deucher 	WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0);
43a9e61410SAlex Deucher 
44a9e61410SAlex Deucher 	return 0;
45a9e61410SAlex Deucher }
46a9e61410SAlex Deucher 
si_copy_bytes_to_smc(struct radeon_device * rdev,u32 smc_start_address,const u8 * src,u32 byte_count,u32 limit)47a9e61410SAlex Deucher int si_copy_bytes_to_smc(struct radeon_device *rdev,
48a9e61410SAlex Deucher 			 u32 smc_start_address,
49a9e61410SAlex Deucher 			 const u8 *src, u32 byte_count, u32 limit)
50a9e61410SAlex Deucher {
51fe78118cSAlex Deucher 	unsigned long flags;
52fe78118cSAlex Deucher 	int ret = 0;
53a9e61410SAlex Deucher 	u32 data, original_data, addr, extra_shift;
54a9e61410SAlex Deucher 
55a9e61410SAlex Deucher 	if (smc_start_address & 3)
56a9e61410SAlex Deucher 		return -EINVAL;
57a9e61410SAlex Deucher 	if ((smc_start_address + byte_count) > limit)
58a9e61410SAlex Deucher 		return -EINVAL;
59a9e61410SAlex Deucher 
60a9e61410SAlex Deucher 	addr = smc_start_address;
61a9e61410SAlex Deucher 
62fe78118cSAlex Deucher 	spin_lock_irqsave(&rdev->smc_idx_lock, flags);
63a9e61410SAlex Deucher 	while (byte_count >= 4) {
64a9e61410SAlex Deucher 		/* SMC address space is BE */
65a9e61410SAlex Deucher 		data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
66a9e61410SAlex Deucher 
67a9e61410SAlex Deucher 		ret = si_set_smc_sram_address(rdev, addr, limit);
68a9e61410SAlex Deucher 		if (ret)
69fe78118cSAlex Deucher 			goto done;
70a9e61410SAlex Deucher 
71a9e61410SAlex Deucher 		WREG32(SMC_IND_DATA_0, data);
72a9e61410SAlex Deucher 
73a9e61410SAlex Deucher 		src += 4;
74a9e61410SAlex Deucher 		byte_count -= 4;
75a9e61410SAlex Deucher 		addr += 4;
76a9e61410SAlex Deucher 	}
77a9e61410SAlex Deucher 
78a9e61410SAlex Deucher 	/* RMW for the final bytes */
79a9e61410SAlex Deucher 	if (byte_count > 0) {
80a9e61410SAlex Deucher 		data = 0;
81a9e61410SAlex Deucher 
82a9e61410SAlex Deucher 		ret = si_set_smc_sram_address(rdev, addr, limit);
83a9e61410SAlex Deucher 		if (ret)
84fe78118cSAlex Deucher 			goto done;
85a9e61410SAlex Deucher 
86a9e61410SAlex Deucher 		original_data = RREG32(SMC_IND_DATA_0);
87a9e61410SAlex Deucher 
88a9e61410SAlex Deucher 		extra_shift = 8 * (4 - byte_count);
89a9e61410SAlex Deucher 
90a9e61410SAlex Deucher 		while (byte_count > 0) {
91a9e61410SAlex Deucher 			/* SMC address space is BE */
92a9e61410SAlex Deucher 			data = (data << 8) + *src++;
93a9e61410SAlex Deucher 			byte_count--;
94a9e61410SAlex Deucher 		}
95a9e61410SAlex Deucher 
96a9e61410SAlex Deucher 		data <<= extra_shift;
97a9e61410SAlex Deucher 
98a9e61410SAlex Deucher 		data |= (original_data & ~((~0UL) << extra_shift));
99a9e61410SAlex Deucher 
100a9e61410SAlex Deucher 		ret = si_set_smc_sram_address(rdev, addr, limit);
101a9e61410SAlex Deucher 		if (ret)
102fe78118cSAlex Deucher 			goto done;
103a9e61410SAlex Deucher 
104a9e61410SAlex Deucher 		WREG32(SMC_IND_DATA_0, data);
105a9e61410SAlex Deucher 	}
106fe78118cSAlex Deucher 
107fe78118cSAlex Deucher done:
108fe78118cSAlex Deucher 	spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
109fe78118cSAlex Deucher 
110fe78118cSAlex Deucher 	return ret;
111a9e61410SAlex Deucher }
112a9e61410SAlex Deucher 
si_start_smc(struct radeon_device * rdev)113a9e61410SAlex Deucher void si_start_smc(struct radeon_device *rdev)
114a9e61410SAlex Deucher {
115a9e61410SAlex Deucher 	u32 tmp = RREG32_SMC(SMC_SYSCON_RESET_CNTL);
116a9e61410SAlex Deucher 
117a9e61410SAlex Deucher 	tmp &= ~RST_REG;
118a9e61410SAlex Deucher 
119a9e61410SAlex Deucher 	WREG32_SMC(SMC_SYSCON_RESET_CNTL, tmp);
120a9e61410SAlex Deucher }
121a9e61410SAlex Deucher 
si_reset_smc(struct radeon_device * rdev)122a9e61410SAlex Deucher void si_reset_smc(struct radeon_device *rdev)
123a9e61410SAlex Deucher {
124a9e61410SAlex Deucher 	u32 tmp;
125a9e61410SAlex Deucher 
126a9e61410SAlex Deucher 	RREG32(CB_CGTT_SCLK_CTRL);
127a9e61410SAlex Deucher 	RREG32(CB_CGTT_SCLK_CTRL);
128a9e61410SAlex Deucher 	RREG32(CB_CGTT_SCLK_CTRL);
129a9e61410SAlex Deucher 	RREG32(CB_CGTT_SCLK_CTRL);
130a9e61410SAlex Deucher 
131a9e61410SAlex Deucher 	tmp = RREG32_SMC(SMC_SYSCON_RESET_CNTL);
132a9e61410SAlex Deucher 	tmp |= RST_REG;
133a9e61410SAlex Deucher 	WREG32_SMC(SMC_SYSCON_RESET_CNTL, tmp);
134a9e61410SAlex Deucher }
135a9e61410SAlex Deucher 
si_program_jump_on_start(struct radeon_device * rdev)136a9e61410SAlex Deucher int si_program_jump_on_start(struct radeon_device *rdev)
137a9e61410SAlex Deucher {
138c81b9942SDave Airlie 	static const u8 data[] = { 0x0E, 0x00, 0x40, 0x40 };
139a9e61410SAlex Deucher 
140a9e61410SAlex Deucher 	return si_copy_bytes_to_smc(rdev, 0x0, data, 4, sizeof(data)+1);
141a9e61410SAlex Deucher }
142a9e61410SAlex Deucher 
si_stop_smc_clock(struct radeon_device * rdev)143a9e61410SAlex Deucher void si_stop_smc_clock(struct radeon_device *rdev)
144a9e61410SAlex Deucher {
145a9e61410SAlex Deucher 	u32 tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
146a9e61410SAlex Deucher 
147a9e61410SAlex Deucher 	tmp |= CK_DISABLE;
148a9e61410SAlex Deucher 
149a9e61410SAlex Deucher 	WREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0, tmp);
150a9e61410SAlex Deucher }
151a9e61410SAlex Deucher 
si_start_smc_clock(struct radeon_device * rdev)152a9e61410SAlex Deucher void si_start_smc_clock(struct radeon_device *rdev)
153a9e61410SAlex Deucher {
154a9e61410SAlex Deucher 	u32 tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
155a9e61410SAlex Deucher 
156a9e61410SAlex Deucher 	tmp &= ~CK_DISABLE;
157a9e61410SAlex Deucher 
158a9e61410SAlex Deucher 	WREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0, tmp);
159a9e61410SAlex Deucher }
160a9e61410SAlex Deucher 
si_is_smc_running(struct radeon_device * rdev)161a9e61410SAlex Deucher bool si_is_smc_running(struct radeon_device *rdev)
162a9e61410SAlex Deucher {
163a9e61410SAlex Deucher 	u32 rst = RREG32_SMC(SMC_SYSCON_RESET_CNTL);
164a9e61410SAlex Deucher 	u32 clk = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
165a9e61410SAlex Deucher 
166a9e61410SAlex Deucher 	if (!(rst & RST_REG) && !(clk & CK_DISABLE))
167a9e61410SAlex Deucher 		return true;
168a9e61410SAlex Deucher 
169a9e61410SAlex Deucher 	return false;
170a9e61410SAlex Deucher }
171a9e61410SAlex Deucher 
si_send_msg_to_smc(struct radeon_device * rdev,PPSMC_Msg msg)172a9e61410SAlex Deucher PPSMC_Result si_send_msg_to_smc(struct radeon_device *rdev, PPSMC_Msg msg)
173a9e61410SAlex Deucher {
174a9e61410SAlex Deucher 	u32 tmp;
175a9e61410SAlex Deucher 	int i;
176a9e61410SAlex Deucher 
177a9e61410SAlex Deucher 	if (!si_is_smc_running(rdev))
178a9e61410SAlex Deucher 		return PPSMC_Result_Failed;
179a9e61410SAlex Deucher 
180a9e61410SAlex Deucher 	WREG32(SMC_MESSAGE_0, msg);
181a9e61410SAlex Deucher 
182a9e61410SAlex Deucher 	for (i = 0; i < rdev->usec_timeout; i++) {
183a9e61410SAlex Deucher 		tmp = RREG32(SMC_RESP_0);
184a9e61410SAlex Deucher 		if (tmp != 0)
185a9e61410SAlex Deucher 			break;
186a9e61410SAlex Deucher 		udelay(1);
187a9e61410SAlex Deucher 	}
188a9e61410SAlex Deucher 	tmp = RREG32(SMC_RESP_0);
189a9e61410SAlex Deucher 
190a9e61410SAlex Deucher 	return (PPSMC_Result)tmp;
191a9e61410SAlex Deucher }
192a9e61410SAlex Deucher 
si_wait_for_smc_inactive(struct radeon_device * rdev)193a9e61410SAlex Deucher PPSMC_Result si_wait_for_smc_inactive(struct radeon_device *rdev)
194a9e61410SAlex Deucher {
195a9e61410SAlex Deucher 	u32 tmp;
196a9e61410SAlex Deucher 	int i;
197a9e61410SAlex Deucher 
198a9e61410SAlex Deucher 	if (!si_is_smc_running(rdev))
199a9e61410SAlex Deucher 		return PPSMC_Result_OK;
200a9e61410SAlex Deucher 
201a9e61410SAlex Deucher 	for (i = 0; i < rdev->usec_timeout; i++) {
202a9e61410SAlex Deucher 		tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
203a9e61410SAlex Deucher 		if ((tmp & CKEN) == 0)
204a9e61410SAlex Deucher 			break;
205a9e61410SAlex Deucher 		udelay(1);
206a9e61410SAlex Deucher 	}
207a9e61410SAlex Deucher 
208a9e61410SAlex Deucher 	return PPSMC_Result_OK;
209a9e61410SAlex Deucher }
210a9e61410SAlex Deucher 
si_load_smc_ucode(struct radeon_device * rdev,u32 limit)211a9e61410SAlex Deucher int si_load_smc_ucode(struct radeon_device *rdev, u32 limit)
212a9e61410SAlex Deucher {
213fe78118cSAlex Deucher 	unsigned long flags;
214a9e61410SAlex Deucher 	u32 ucode_start_address;
215a9e61410SAlex Deucher 	u32 ucode_size;
216a9e61410SAlex Deucher 	const u8 *src;
217a9e61410SAlex Deucher 	u32 data;
218a9e61410SAlex Deucher 
219a9e61410SAlex Deucher 	if (!rdev->smc_fw)
220a9e61410SAlex Deucher 		return -EINVAL;
221a9e61410SAlex Deucher 
222629bd33cSAlex Deucher 	if (rdev->new_fw) {
223629bd33cSAlex Deucher 		const struct smc_firmware_header_v1_0 *hdr =
224629bd33cSAlex Deucher 			(const struct smc_firmware_header_v1_0 *)rdev->smc_fw->data;
225629bd33cSAlex Deucher 
226629bd33cSAlex Deucher 		radeon_ucode_print_smc_hdr(&hdr->header);
227629bd33cSAlex Deucher 
228629bd33cSAlex Deucher 		ucode_start_address = le32_to_cpu(hdr->ucode_start_addr);
229629bd33cSAlex Deucher 		ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes);
230629bd33cSAlex Deucher 		src = (const u8 *)
231629bd33cSAlex Deucher 			(rdev->smc_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes));
232629bd33cSAlex Deucher 	} else {
233a9e61410SAlex Deucher 		switch (rdev->family) {
234a9e61410SAlex Deucher 		case CHIP_TAHITI:
235a9e61410SAlex Deucher 			ucode_start_address = TAHITI_SMC_UCODE_START;
236a9e61410SAlex Deucher 			ucode_size = TAHITI_SMC_UCODE_SIZE;
237a9e61410SAlex Deucher 			break;
238a9e61410SAlex Deucher 		case CHIP_PITCAIRN:
239a9e61410SAlex Deucher 			ucode_start_address = PITCAIRN_SMC_UCODE_START;
240a9e61410SAlex Deucher 			ucode_size = PITCAIRN_SMC_UCODE_SIZE;
241a9e61410SAlex Deucher 			break;
242a9e61410SAlex Deucher 		case CHIP_VERDE:
243a9e61410SAlex Deucher 			ucode_start_address = VERDE_SMC_UCODE_START;
244a9e61410SAlex Deucher 			ucode_size = VERDE_SMC_UCODE_SIZE;
245a9e61410SAlex Deucher 			break;
246a9e61410SAlex Deucher 		case CHIP_OLAND:
247a9e61410SAlex Deucher 			ucode_start_address = OLAND_SMC_UCODE_START;
248a9e61410SAlex Deucher 			ucode_size = OLAND_SMC_UCODE_SIZE;
249a9e61410SAlex Deucher 			break;
250a9e61410SAlex Deucher 		case CHIP_HAINAN:
251a9e61410SAlex Deucher 			ucode_start_address = HAINAN_SMC_UCODE_START;
252a9e61410SAlex Deucher 			ucode_size = HAINAN_SMC_UCODE_SIZE;
253a9e61410SAlex Deucher 			break;
254a9e61410SAlex Deucher 		default:
255a9e61410SAlex Deucher 			DRM_ERROR("unknown asic in smc ucode loader\n");
256a9e61410SAlex Deucher 			BUG();
257a9e61410SAlex Deucher 		}
258629bd33cSAlex Deucher 		src = (const u8 *)rdev->smc_fw->data;
259629bd33cSAlex Deucher 	}
260a9e61410SAlex Deucher 
261a9e61410SAlex Deucher 	if (ucode_size & 3)
262a9e61410SAlex Deucher 		return -EINVAL;
263a9e61410SAlex Deucher 
264fe78118cSAlex Deucher 	spin_lock_irqsave(&rdev->smc_idx_lock, flags);
265a9e61410SAlex Deucher 	WREG32(SMC_IND_INDEX_0, ucode_start_address);
266a9e61410SAlex Deucher 	WREG32_P(SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, ~AUTO_INCREMENT_IND_0);
267a9e61410SAlex Deucher 	while (ucode_size >= 4) {
268a9e61410SAlex Deucher 		/* SMC address space is BE */
269a9e61410SAlex Deucher 		data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
270a9e61410SAlex Deucher 
271a9e61410SAlex Deucher 		WREG32(SMC_IND_DATA_0, data);
272a9e61410SAlex Deucher 
273a9e61410SAlex Deucher 		src += 4;
274a9e61410SAlex Deucher 		ucode_size -= 4;
275a9e61410SAlex Deucher 	}
276a9e61410SAlex Deucher 	WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0);
277fe78118cSAlex Deucher 	spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
278a9e61410SAlex Deucher 
279a9e61410SAlex Deucher 	return 0;
280a9e61410SAlex Deucher }
281a9e61410SAlex Deucher 
si_read_smc_sram_dword(struct radeon_device * rdev,u32 smc_address,u32 * value,u32 limit)282a9e61410SAlex Deucher int si_read_smc_sram_dword(struct radeon_device *rdev, u32 smc_address,
283a9e61410SAlex Deucher 			   u32 *value, u32 limit)
284a9e61410SAlex Deucher {
285fe78118cSAlex Deucher 	unsigned long flags;
286a9e61410SAlex Deucher 	int ret;
287a9e61410SAlex Deucher 
288fe78118cSAlex Deucher 	spin_lock_irqsave(&rdev->smc_idx_lock, flags);
289a9e61410SAlex Deucher 	ret = si_set_smc_sram_address(rdev, smc_address, limit);
290fe78118cSAlex Deucher 	if (ret == 0)
291a9e61410SAlex Deucher 		*value = RREG32(SMC_IND_DATA_0);
292fe78118cSAlex Deucher 	spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
293fe78118cSAlex Deucher 
294fe78118cSAlex Deucher 	return ret;
295a9e61410SAlex Deucher }
296a9e61410SAlex Deucher 
si_write_smc_sram_dword(struct radeon_device * rdev,u32 smc_address,u32 value,u32 limit)297a9e61410SAlex Deucher int si_write_smc_sram_dword(struct radeon_device *rdev, u32 smc_address,
298a9e61410SAlex Deucher 			    u32 value, u32 limit)
299a9e61410SAlex Deucher {
300fe78118cSAlex Deucher 	unsigned long flags;
301a9e61410SAlex Deucher 	int ret;
302a9e61410SAlex Deucher 
303fe78118cSAlex Deucher 	spin_lock_irqsave(&rdev->smc_idx_lock, flags);
304a9e61410SAlex Deucher 	ret = si_set_smc_sram_address(rdev, smc_address, limit);
305fe78118cSAlex Deucher 	if (ret == 0)
306a9e61410SAlex Deucher 		WREG32(SMC_IND_DATA_0, value);
307fe78118cSAlex Deucher 	spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
308fe78118cSAlex Deucher 
309fe78118cSAlex Deucher 	return ret;
310a9e61410SAlex Deucher }
311