xref: /dragonfly/sys/dev/drm/radeon/rv770_smc.c (revision 3f2dd94a569761201b5b0a18b2f697f97fe1b9dc)
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 <drm/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 
rv770_set_smc_sram_address(struct radeon_device * rdev,u16 smc_address,u16 limit)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 
rv770_copy_bytes_to_smc(struct radeon_device * rdev,u16 smc_start_address,const u8 * src,u16 byte_count,u16 limit)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 
rv770_program_interrupt_vectors(struct radeon_device * rdev,u32 smc_first_vector,const u8 * src,u32 byte_count)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 
rv770_start_smc(struct radeon_device * rdev)392 void rv770_start_smc(struct radeon_device *rdev)
393 {
394           WREG32_P(SMC_IO, SMC_RST_N, ~SMC_RST_N);
395 }
396 
rv770_reset_smc(struct radeon_device * rdev)397 void rv770_reset_smc(struct radeon_device *rdev)
398 {
399           WREG32_P(SMC_IO, 0, ~SMC_RST_N);
400 }
401 
rv770_stop_smc_clock(struct radeon_device * rdev)402 void rv770_stop_smc_clock(struct radeon_device *rdev)
403 {
404           WREG32_P(SMC_IO, 0, ~SMC_CLK_EN);
405 }
406 
rv770_start_smc_clock(struct radeon_device * rdev)407 void rv770_start_smc_clock(struct radeon_device *rdev)
408 {
409           WREG32_P(SMC_IO, SMC_CLK_EN, ~SMC_CLK_EN);
410 }
411 
rv770_is_smc_running(struct radeon_device * rdev)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 
rv770_send_msg_to_smc(struct radeon_device * rdev,PPSMC_Msg msg)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 
rv770_wait_for_smc_inactive(struct radeon_device * rdev)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 
rv770_clear_smc_sram(struct radeon_device * rdev,u16 limit)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 
rv770_load_smc_ucode(struct radeon_device * rdev,u16 limit)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 
rv770_read_smc_sram_dword(struct radeon_device * rdev,u16 smc_address,u32 * value,u16 limit)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 
rv770_write_smc_sram_dword(struct radeon_device * rdev,u16 smc_address,u32 value,u16 limit)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 }
632