diff options
Diffstat (limited to 'drivers/gpu/drm/radeon/ni.c')
-rw-r--r-- | drivers/gpu/drm/radeon/ni.c | 316 |
1 files changed, 316 insertions, 0 deletions
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c new file mode 100644 index 000000000000..5e0bef80ad7f --- /dev/null +++ b/drivers/gpu/drm/radeon/ni.c | |||
@@ -0,0 +1,316 @@ | |||
1 | /* | ||
2 | * Copyright 2010 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 | #include <linux/firmware.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include "drmP.h" | ||
28 | #include "radeon.h" | ||
29 | #include "radeon_asic.h" | ||
30 | #include "radeon_drm.h" | ||
31 | #include "nid.h" | ||
32 | #include "atom.h" | ||
33 | #include "ni_reg.h" | ||
34 | |||
35 | #define EVERGREEN_PFP_UCODE_SIZE 1120 | ||
36 | #define EVERGREEN_PM4_UCODE_SIZE 1376 | ||
37 | #define EVERGREEN_RLC_UCODE_SIZE 768 | ||
38 | #define BTC_MC_UCODE_SIZE 6024 | ||
39 | |||
40 | /* Firmware Names */ | ||
41 | MODULE_FIRMWARE("radeon/BARTS_pfp.bin"); | ||
42 | MODULE_FIRMWARE("radeon/BARTS_me.bin"); | ||
43 | MODULE_FIRMWARE("radeon/BARTS_mc.bin"); | ||
44 | MODULE_FIRMWARE("radeon/BTC_rlc.bin"); | ||
45 | MODULE_FIRMWARE("radeon/TURKS_pfp.bin"); | ||
46 | MODULE_FIRMWARE("radeon/TURKS_me.bin"); | ||
47 | MODULE_FIRMWARE("radeon/TURKS_mc.bin"); | ||
48 | MODULE_FIRMWARE("radeon/CAICOS_pfp.bin"); | ||
49 | MODULE_FIRMWARE("radeon/CAICOS_me.bin"); | ||
50 | MODULE_FIRMWARE("radeon/CAICOS_mc.bin"); | ||
51 | |||
52 | #define BTC_IO_MC_REGS_SIZE 29 | ||
53 | |||
54 | static const u32 barts_io_mc_regs[BTC_IO_MC_REGS_SIZE][2] = { | ||
55 | {0x00000077, 0xff010100}, | ||
56 | {0x00000078, 0x00000000}, | ||
57 | {0x00000079, 0x00001434}, | ||
58 | {0x0000007a, 0xcc08ec08}, | ||
59 | {0x0000007b, 0x00040000}, | ||
60 | {0x0000007c, 0x000080c0}, | ||
61 | {0x0000007d, 0x09000000}, | ||
62 | {0x0000007e, 0x00210404}, | ||
63 | {0x00000081, 0x08a8e800}, | ||
64 | {0x00000082, 0x00030444}, | ||
65 | {0x00000083, 0x00000000}, | ||
66 | {0x00000085, 0x00000001}, | ||
67 | {0x00000086, 0x00000002}, | ||
68 | {0x00000087, 0x48490000}, | ||
69 | {0x00000088, 0x20244647}, | ||
70 | {0x00000089, 0x00000005}, | ||
71 | {0x0000008b, 0x66030000}, | ||
72 | {0x0000008c, 0x00006603}, | ||
73 | {0x0000008d, 0x00000100}, | ||
74 | {0x0000008f, 0x00001c0a}, | ||
75 | {0x00000090, 0xff000001}, | ||
76 | {0x00000094, 0x00101101}, | ||
77 | {0x00000095, 0x00000fff}, | ||
78 | {0x00000096, 0x00116fff}, | ||
79 | {0x00000097, 0x60010000}, | ||
80 | {0x00000098, 0x10010000}, | ||
81 | {0x00000099, 0x00006000}, | ||
82 | {0x0000009a, 0x00001000}, | ||
83 | {0x0000009f, 0x00946a00} | ||
84 | }; | ||
85 | |||
86 | static const u32 turks_io_mc_regs[BTC_IO_MC_REGS_SIZE][2] = { | ||
87 | {0x00000077, 0xff010100}, | ||
88 | {0x00000078, 0x00000000}, | ||
89 | {0x00000079, 0x00001434}, | ||
90 | {0x0000007a, 0xcc08ec08}, | ||
91 | {0x0000007b, 0x00040000}, | ||
92 | {0x0000007c, 0x000080c0}, | ||
93 | {0x0000007d, 0x09000000}, | ||
94 | {0x0000007e, 0x00210404}, | ||
95 | {0x00000081, 0x08a8e800}, | ||
96 | {0x00000082, 0x00030444}, | ||
97 | {0x00000083, 0x00000000}, | ||
98 | {0x00000085, 0x00000001}, | ||
99 | {0x00000086, 0x00000002}, | ||
100 | {0x00000087, 0x48490000}, | ||
101 | {0x00000088, 0x20244647}, | ||
102 | {0x00000089, 0x00000005}, | ||
103 | {0x0000008b, 0x66030000}, | ||
104 | {0x0000008c, 0x00006603}, | ||
105 | {0x0000008d, 0x00000100}, | ||
106 | {0x0000008f, 0x00001c0a}, | ||
107 | {0x00000090, 0xff000001}, | ||
108 | {0x00000094, 0x00101101}, | ||
109 | {0x00000095, 0x00000fff}, | ||
110 | {0x00000096, 0x00116fff}, | ||
111 | {0x00000097, 0x60010000}, | ||
112 | {0x00000098, 0x10010000}, | ||
113 | {0x00000099, 0x00006000}, | ||
114 | {0x0000009a, 0x00001000}, | ||
115 | {0x0000009f, 0x00936a00} | ||
116 | }; | ||
117 | |||
118 | static const u32 caicos_io_mc_regs[BTC_IO_MC_REGS_SIZE][2] = { | ||
119 | {0x00000077, 0xff010100}, | ||
120 | {0x00000078, 0x00000000}, | ||
121 | {0x00000079, 0x00001434}, | ||
122 | {0x0000007a, 0xcc08ec08}, | ||
123 | {0x0000007b, 0x00040000}, | ||
124 | {0x0000007c, 0x000080c0}, | ||
125 | {0x0000007d, 0x09000000}, | ||
126 | {0x0000007e, 0x00210404}, | ||
127 | {0x00000081, 0x08a8e800}, | ||
128 | {0x00000082, 0x00030444}, | ||
129 | {0x00000083, 0x00000000}, | ||
130 | {0x00000085, 0x00000001}, | ||
131 | {0x00000086, 0x00000002}, | ||
132 | {0x00000087, 0x48490000}, | ||
133 | {0x00000088, 0x20244647}, | ||
134 | {0x00000089, 0x00000005}, | ||
135 | {0x0000008b, 0x66030000}, | ||
136 | {0x0000008c, 0x00006603}, | ||
137 | {0x0000008d, 0x00000100}, | ||
138 | {0x0000008f, 0x00001c0a}, | ||
139 | {0x00000090, 0xff000001}, | ||
140 | {0x00000094, 0x00101101}, | ||
141 | {0x00000095, 0x00000fff}, | ||
142 | {0x00000096, 0x00116fff}, | ||
143 | {0x00000097, 0x60010000}, | ||
144 | {0x00000098, 0x10010000}, | ||
145 | {0x00000099, 0x00006000}, | ||
146 | {0x0000009a, 0x00001000}, | ||
147 | {0x0000009f, 0x00916a00} | ||
148 | }; | ||
149 | |||
150 | int btc_mc_load_microcode(struct radeon_device *rdev) | ||
151 | { | ||
152 | const __be32 *fw_data; | ||
153 | u32 mem_type, running, blackout = 0; | ||
154 | u32 *io_mc_regs; | ||
155 | int i; | ||
156 | |||
157 | if (!rdev->mc_fw) | ||
158 | return -EINVAL; | ||
159 | |||
160 | switch (rdev->family) { | ||
161 | case CHIP_BARTS: | ||
162 | io_mc_regs = (u32 *)&barts_io_mc_regs; | ||
163 | break; | ||
164 | case CHIP_TURKS: | ||
165 | io_mc_regs = (u32 *)&turks_io_mc_regs; | ||
166 | break; | ||
167 | case CHIP_CAICOS: | ||
168 | default: | ||
169 | io_mc_regs = (u32 *)&caicos_io_mc_regs; | ||
170 | break; | ||
171 | } | ||
172 | |||
173 | mem_type = (RREG32(MC_SEQ_MISC0) & MC_SEQ_MISC0_GDDR5_MASK) >> MC_SEQ_MISC0_GDDR5_SHIFT; | ||
174 | running = RREG32(MC_SEQ_SUP_CNTL) & RUN_MASK; | ||
175 | |||
176 | if ((mem_type == MC_SEQ_MISC0_GDDR5_VALUE) && (running == 0)) { | ||
177 | if (running) { | ||
178 | blackout = RREG32(MC_SHARED_BLACKOUT_CNTL); | ||
179 | WREG32(MC_SHARED_BLACKOUT_CNTL, 1); | ||
180 | } | ||
181 | |||
182 | /* reset the engine and set to writable */ | ||
183 | WREG32(MC_SEQ_SUP_CNTL, 0x00000008); | ||
184 | WREG32(MC_SEQ_SUP_CNTL, 0x00000010); | ||
185 | |||
186 | /* load mc io regs */ | ||
187 | for (i = 0; i < BTC_IO_MC_REGS_SIZE; i++) { | ||
188 | WREG32(MC_SEQ_IO_DEBUG_INDEX, io_mc_regs[(i << 1)]); | ||
189 | WREG32(MC_SEQ_IO_DEBUG_DATA, io_mc_regs[(i << 1) + 1]); | ||
190 | } | ||
191 | /* load the MC ucode */ | ||
192 | fw_data = (const __be32 *)rdev->mc_fw->data; | ||
193 | for (i = 0; i < BTC_MC_UCODE_SIZE; i++) | ||
194 | WREG32(MC_SEQ_SUP_PGM, be32_to_cpup(fw_data++)); | ||
195 | |||
196 | /* put the engine back into the active state */ | ||
197 | WREG32(MC_SEQ_SUP_CNTL, 0x00000008); | ||
198 | WREG32(MC_SEQ_SUP_CNTL, 0x00000004); | ||
199 | WREG32(MC_SEQ_SUP_CNTL, 0x00000001); | ||
200 | |||
201 | /* wait for training to complete */ | ||
202 | while (!(RREG32(MC_IO_PAD_CNTL_D0) & MEM_FALL_OUT_CMD)) | ||
203 | udelay(10); | ||
204 | |||
205 | if (running) | ||
206 | WREG32(MC_SHARED_BLACKOUT_CNTL, blackout); | ||
207 | } | ||
208 | |||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | int ni_init_microcode(struct radeon_device *rdev) | ||
213 | { | ||
214 | struct platform_device *pdev; | ||
215 | const char *chip_name; | ||
216 | const char *rlc_chip_name; | ||
217 | size_t pfp_req_size, me_req_size, rlc_req_size, mc_req_size; | ||
218 | char fw_name[30]; | ||
219 | int err; | ||
220 | |||
221 | DRM_DEBUG("\n"); | ||
222 | |||
223 | pdev = platform_device_register_simple("radeon_cp", 0, NULL, 0); | ||
224 | err = IS_ERR(pdev); | ||
225 | if (err) { | ||
226 | printk(KERN_ERR "radeon_cp: Failed to register firmware\n"); | ||
227 | return -EINVAL; | ||
228 | } | ||
229 | |||
230 | switch (rdev->family) { | ||
231 | case CHIP_BARTS: | ||
232 | chip_name = "BARTS"; | ||
233 | rlc_chip_name = "BTC"; | ||
234 | break; | ||
235 | case CHIP_TURKS: | ||
236 | chip_name = "TURKS"; | ||
237 | rlc_chip_name = "BTC"; | ||
238 | break; | ||
239 | case CHIP_CAICOS: | ||
240 | chip_name = "CAICOS"; | ||
241 | rlc_chip_name = "BTC"; | ||
242 | break; | ||
243 | default: BUG(); | ||
244 | } | ||
245 | |||
246 | pfp_req_size = EVERGREEN_PFP_UCODE_SIZE * 4; | ||
247 | me_req_size = EVERGREEN_PM4_UCODE_SIZE * 4; | ||
248 | rlc_req_size = EVERGREEN_RLC_UCODE_SIZE * 4; | ||
249 | mc_req_size = BTC_MC_UCODE_SIZE * 4; | ||
250 | |||
251 | DRM_INFO("Loading %s Microcode\n", chip_name); | ||
252 | |||
253 | snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name); | ||
254 | err = request_firmware(&rdev->pfp_fw, fw_name, &pdev->dev); | ||
255 | if (err) | ||
256 | goto out; | ||
257 | if (rdev->pfp_fw->size != pfp_req_size) { | ||
258 | printk(KERN_ERR | ||
259 | "ni_cp: Bogus length %zu in firmware \"%s\"\n", | ||
260 | rdev->pfp_fw->size, fw_name); | ||
261 | err = -EINVAL; | ||
262 | goto out; | ||
263 | } | ||
264 | |||
265 | snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name); | ||
266 | err = request_firmware(&rdev->me_fw, fw_name, &pdev->dev); | ||
267 | if (err) | ||
268 | goto out; | ||
269 | if (rdev->me_fw->size != me_req_size) { | ||
270 | printk(KERN_ERR | ||
271 | "ni_cp: Bogus length %zu in firmware \"%s\"\n", | ||
272 | rdev->me_fw->size, fw_name); | ||
273 | err = -EINVAL; | ||
274 | } | ||
275 | |||
276 | snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", rlc_chip_name); | ||
277 | err = request_firmware(&rdev->rlc_fw, fw_name, &pdev->dev); | ||
278 | if (err) | ||
279 | goto out; | ||
280 | if (rdev->rlc_fw->size != rlc_req_size) { | ||
281 | printk(KERN_ERR | ||
282 | "ni_rlc: Bogus length %zu in firmware \"%s\"\n", | ||
283 | rdev->rlc_fw->size, fw_name); | ||
284 | err = -EINVAL; | ||
285 | } | ||
286 | |||
287 | snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name); | ||
288 | err = request_firmware(&rdev->mc_fw, fw_name, &pdev->dev); | ||
289 | if (err) | ||
290 | goto out; | ||
291 | if (rdev->mc_fw->size != mc_req_size) { | ||
292 | printk(KERN_ERR | ||
293 | "ni_mc: Bogus length %zu in firmware \"%s\"\n", | ||
294 | rdev->mc_fw->size, fw_name); | ||
295 | err = -EINVAL; | ||
296 | } | ||
297 | out: | ||
298 | platform_device_unregister(pdev); | ||
299 | |||
300 | if (err) { | ||
301 | if (err != -EINVAL) | ||
302 | printk(KERN_ERR | ||
303 | "ni_cp: Failed to load firmware \"%s\"\n", | ||
304 | fw_name); | ||
305 | release_firmware(rdev->pfp_fw); | ||
306 | rdev->pfp_fw = NULL; | ||
307 | release_firmware(rdev->me_fw); | ||
308 | rdev->me_fw = NULL; | ||
309 | release_firmware(rdev->rlc_fw); | ||
310 | rdev->rlc_fw = NULL; | ||
311 | release_firmware(rdev->mc_fw); | ||
312 | rdev->mc_fw = NULL; | ||
313 | } | ||
314 | return err; | ||
315 | } | ||
316 | |||