]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/gpu/drm/radeon/ci_smc.c
ARM: 7805/1: mm: change max*pfn to include the physical offset of memory
[karo-tx-linux.git] / drivers / gpu / drm / radeon / ci_smc.c
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 <linux/firmware.h>
26 #include "drmP.h"
27 #include "radeon.h"
28 #include "cikd.h"
29 #include "ppsmc.h"
30 #include "radeon_ucode.h"
31
32 static int ci_set_smc_sram_address(struct radeon_device *rdev,
33                                    u32 smc_address, u32 limit)
34 {
35         if (smc_address & 3)
36                 return -EINVAL;
37         if ((smc_address + 3) > limit)
38                 return -EINVAL;
39
40         WREG32(SMC_IND_INDEX_0, smc_address);
41         WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0);
42
43         return 0;
44 }
45
46 int ci_copy_bytes_to_smc(struct radeon_device *rdev,
47                          u32 smc_start_address,
48                          const u8 *src, u32 byte_count, u32 limit)
49 {
50         u32 data, original_data;
51         u32 addr;
52         u32 extra_shift;
53         int ret;
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         while (byte_count >= 4) {
63                 /* SMC address space is BE */
64                 data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
65
66                 ret = ci_set_smc_sram_address(rdev, addr, limit);
67                 if (ret)
68                         return ret;
69
70                 WREG32(SMC_IND_DATA_0, data);
71
72                 src += 4;
73                 byte_count -= 4;
74                 addr += 4;
75         }
76
77         /* RMW for the final bytes */
78         if (byte_count > 0) {
79                 data = 0;
80
81                 ret = ci_set_smc_sram_address(rdev, addr, limit);
82                 if (ret)
83                         return ret;
84
85                 original_data = RREG32(SMC_IND_DATA_0);
86
87                 extra_shift = 8 * (4 - byte_count);
88
89                 while (byte_count > 0) {
90                         data = (data << 8) + *src++;
91                         byte_count--;
92                 }
93
94                 data <<= extra_shift;
95
96                 data |= (original_data & ~((~0UL) << extra_shift));
97
98                 ret = ci_set_smc_sram_address(rdev, addr, limit);
99                 if (ret)
100                         return ret;
101
102                 WREG32(SMC_IND_DATA_0, data);
103         }
104         return 0;
105 }
106
107 void ci_start_smc(struct radeon_device *rdev)
108 {
109         u32 tmp = RREG32_SMC(SMC_SYSCON_RESET_CNTL);
110
111         tmp &= ~RST_REG;
112         WREG32_SMC(SMC_SYSCON_RESET_CNTL, tmp);
113 }
114
115 void ci_reset_smc(struct radeon_device *rdev)
116 {
117         u32 tmp = RREG32_SMC(SMC_SYSCON_RESET_CNTL);
118
119         tmp |= RST_REG;
120         WREG32_SMC(SMC_SYSCON_RESET_CNTL, tmp);
121 }
122
123 int ci_program_jump_on_start(struct radeon_device *rdev)
124 {
125         static u8 data[] = { 0xE0, 0x00, 0x80, 0x40 };
126
127         return ci_copy_bytes_to_smc(rdev, 0x0, data, 4, sizeof(data)+1);
128 }
129
130 void ci_stop_smc_clock(struct radeon_device *rdev)
131 {
132         u32 tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
133
134         tmp |= CK_DISABLE;
135
136         WREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0, tmp);
137 }
138
139 void ci_start_smc_clock(struct radeon_device *rdev)
140 {
141         u32 tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
142
143         tmp &= ~CK_DISABLE;
144
145         WREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0, tmp);
146 }
147
148 bool ci_is_smc_running(struct radeon_device *rdev)
149 {
150         u32 clk = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
151         u32 pc_c = RREG32_SMC(SMC_PC_C);
152
153         if (!(clk & CK_DISABLE) && (0x20100 <= pc_c))
154                 return true;
155
156         return false;
157 }
158
159 PPSMC_Result ci_send_msg_to_smc(struct radeon_device *rdev, PPSMC_Msg msg)
160 {
161         u32 tmp;
162         int i;
163
164         if (!ci_is_smc_running(rdev))
165                 return PPSMC_Result_Failed;
166
167         WREG32(SMC_MESSAGE_0, msg);
168
169         for (i = 0; i < rdev->usec_timeout; i++) {
170                 tmp = RREG32(SMC_RESP_0);
171                 if (tmp != 0)
172                         break;
173                 udelay(1);
174         }
175         tmp = RREG32(SMC_RESP_0);
176
177         return (PPSMC_Result)tmp;
178 }
179
180 PPSMC_Result ci_wait_for_smc_inactive(struct radeon_device *rdev)
181 {
182         u32 tmp;
183         int i;
184
185         if (!ci_is_smc_running(rdev))
186                 return PPSMC_Result_OK;
187
188         for (i = 0; i < rdev->usec_timeout; i++) {
189                 tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
190                 if ((tmp & CKEN) == 0)
191                         break;
192                 udelay(1);
193         }
194
195         return PPSMC_Result_OK;
196 }
197
198 int ci_load_smc_ucode(struct radeon_device *rdev, u32 limit)
199 {
200         u32 ucode_start_address;
201         u32 ucode_size;
202         const u8 *src;
203         u32 data;
204
205         if (!rdev->smc_fw)
206                 return -EINVAL;
207
208         switch (rdev->family) {
209         case CHIP_BONAIRE:
210                 ucode_start_address = BONAIRE_SMC_UCODE_START;
211                 ucode_size = BONAIRE_SMC_UCODE_SIZE;
212                 break;
213         default:
214                 DRM_ERROR("unknown asic in smc ucode loader\n");
215                 BUG();
216         }
217
218         if (ucode_size & 3)
219                 return -EINVAL;
220
221         src = (const u8 *)rdev->smc_fw->data;
222         WREG32(SMC_IND_INDEX_0, ucode_start_address);
223         WREG32_P(SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, ~AUTO_INCREMENT_IND_0);
224         while (ucode_size >= 4) {
225                 /* SMC address space is BE */
226                 data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
227
228                 WREG32(SMC_IND_DATA_0, data);
229
230                 src += 4;
231                 ucode_size -= 4;
232         }
233         WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0);
234
235         return 0;
236 }
237
238 int ci_read_smc_sram_dword(struct radeon_device *rdev,
239                            u32 smc_address, u32 *value, u32 limit)
240 {
241         int ret;
242
243         ret = ci_set_smc_sram_address(rdev, smc_address, limit);
244         if (ret)
245                 return ret;
246
247         *value = RREG32(SMC_IND_DATA_0);
248         return 0;
249 }
250
251 int ci_write_smc_sram_dword(struct radeon_device *rdev,
252                             u32 smc_address, u32 value, u32 limit)
253 {
254         int ret;
255
256         ret = ci_set_smc_sram_address(rdev, smc_address, limit);
257         if (ret)
258                 return ret;
259
260         WREG32(SMC_IND_DATA_0, value);
261         return 0;
262 }