Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2011 Advanced Micro Devices, Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  * Authors: Alex Deucher
0023  */
0024 
0025 #include <linux/firmware.h>
0026 
0027 #include "radeon.h"
0028 #include "rv770d.h"
0029 #include "rv770_dpm.h"
0030 #include "rv770_smc.h"
0031 #include "atom.h"
0032 #include "radeon_ucode.h"
0033 
0034 #define FIRST_SMC_INT_VECT_REG 0xFFD8
0035 #define FIRST_INT_VECT_S19     0xFFC0
0036 
0037 static const u8 rv770_smc_int_vectors[] =
0038 {
0039     0x08, 0x10, 0x08, 0x10,
0040     0x08, 0x10, 0x08, 0x10,
0041     0x08, 0x10, 0x08, 0x10,
0042     0x08, 0x10, 0x08, 0x10,
0043     0x08, 0x10, 0x08, 0x10,
0044     0x08, 0x10, 0x08, 0x10,
0045     0x08, 0x10, 0x08, 0x10,
0046     0x08, 0x10, 0x08, 0x10,
0047     0x08, 0x10, 0x08, 0x10,
0048     0x08, 0x10, 0x08, 0x10,
0049     0x08, 0x10, 0x08, 0x10,
0050     0x08, 0x10, 0x08, 0x10,
0051     0x08, 0x10, 0x0C, 0xD7,
0052     0x08, 0x2B, 0x08, 0x10,
0053     0x03, 0x51, 0x03, 0x51,
0054     0x03, 0x51, 0x03, 0x51
0055 };
0056 
0057 static const u8 rv730_smc_int_vectors[] =
0058 {
0059     0x08, 0x15, 0x08, 0x15,
0060     0x08, 0x15, 0x08, 0x15,
0061     0x08, 0x15, 0x08, 0x15,
0062     0x08, 0x15, 0x08, 0x15,
0063     0x08, 0x15, 0x08, 0x15,
0064     0x08, 0x15, 0x08, 0x15,
0065     0x08, 0x15, 0x08, 0x15,
0066     0x08, 0x15, 0x08, 0x15,
0067     0x08, 0x15, 0x08, 0x15,
0068     0x08, 0x15, 0x08, 0x15,
0069     0x08, 0x15, 0x08, 0x15,
0070     0x08, 0x15, 0x08, 0x15,
0071     0x08, 0x15, 0x0C, 0xBB,
0072     0x08, 0x30, 0x08, 0x15,
0073     0x03, 0x56, 0x03, 0x56,
0074     0x03, 0x56, 0x03, 0x56
0075 };
0076 
0077 static const u8 rv710_smc_int_vectors[] =
0078 {
0079     0x08, 0x04, 0x08, 0x04,
0080     0x08, 0x04, 0x08, 0x04,
0081     0x08, 0x04, 0x08, 0x04,
0082     0x08, 0x04, 0x08, 0x04,
0083     0x08, 0x04, 0x08, 0x04,
0084     0x08, 0x04, 0x08, 0x04,
0085     0x08, 0x04, 0x08, 0x04,
0086     0x08, 0x04, 0x08, 0x04,
0087     0x08, 0x04, 0x08, 0x04,
0088     0x08, 0x04, 0x08, 0x04,
0089     0x08, 0x04, 0x08, 0x04,
0090     0x08, 0x04, 0x08, 0x04,
0091     0x08, 0x04, 0x0C, 0xCB,
0092     0x08, 0x1F, 0x08, 0x04,
0093     0x03, 0x51, 0x03, 0x51,
0094     0x03, 0x51, 0x03, 0x51
0095 };
0096 
0097 static const u8 rv740_smc_int_vectors[] =
0098 {
0099     0x08, 0x10, 0x08, 0x10,
0100     0x08, 0x10, 0x08, 0x10,
0101     0x08, 0x10, 0x08, 0x10,
0102     0x08, 0x10, 0x08, 0x10,
0103     0x08, 0x10, 0x08, 0x10,
0104     0x08, 0x10, 0x08, 0x10,
0105     0x08, 0x10, 0x08, 0x10,
0106     0x08, 0x10, 0x08, 0x10,
0107     0x08, 0x10, 0x08, 0x10,
0108     0x08, 0x10, 0x08, 0x10,
0109     0x08, 0x10, 0x08, 0x10,
0110     0x08, 0x10, 0x08, 0x10,
0111     0x08, 0x10, 0x0C, 0xD7,
0112     0x08, 0x2B, 0x08, 0x10,
0113     0x03, 0x51, 0x03, 0x51,
0114     0x03, 0x51, 0x03, 0x51
0115 };
0116 
0117 static const u8 cedar_smc_int_vectors[] =
0118 {
0119     0x0B, 0x05, 0x0B, 0x05,
0120     0x0B, 0x05, 0x0B, 0x05,
0121     0x0B, 0x05, 0x0B, 0x05,
0122     0x0B, 0x05, 0x0B, 0x05,
0123     0x0B, 0x05, 0x0B, 0x05,
0124     0x0B, 0x05, 0x0B, 0x05,
0125     0x0B, 0x05, 0x0B, 0x05,
0126     0x0B, 0x05, 0x0B, 0x05,
0127     0x0B, 0x05, 0x0B, 0x05,
0128     0x0B, 0x05, 0x0B, 0x05,
0129     0x0B, 0x05, 0x0B, 0x05,
0130     0x0B, 0x05, 0x0B, 0x05,
0131     0x0B, 0x05, 0x11, 0x8B,
0132     0x0B, 0x20, 0x0B, 0x05,
0133     0x04, 0xF6, 0x04, 0xF6,
0134     0x04, 0xF6, 0x04, 0xF6
0135 };
0136 
0137 static const u8 redwood_smc_int_vectors[] =
0138 {
0139     0x0B, 0x05, 0x0B, 0x05,
0140     0x0B, 0x05, 0x0B, 0x05,
0141     0x0B, 0x05, 0x0B, 0x05,
0142     0x0B, 0x05, 0x0B, 0x05,
0143     0x0B, 0x05, 0x0B, 0x05,
0144     0x0B, 0x05, 0x0B, 0x05,
0145     0x0B, 0x05, 0x0B, 0x05,
0146     0x0B, 0x05, 0x0B, 0x05,
0147     0x0B, 0x05, 0x0B, 0x05,
0148     0x0B, 0x05, 0x0B, 0x05,
0149     0x0B, 0x05, 0x0B, 0x05,
0150     0x0B, 0x05, 0x0B, 0x05,
0151     0x0B, 0x05, 0x11, 0x8B,
0152     0x0B, 0x20, 0x0B, 0x05,
0153     0x04, 0xF6, 0x04, 0xF6,
0154     0x04, 0xF6, 0x04, 0xF6
0155 };
0156 
0157 static const u8 juniper_smc_int_vectors[] =
0158 {
0159     0x0B, 0x05, 0x0B, 0x05,
0160     0x0B, 0x05, 0x0B, 0x05,
0161     0x0B, 0x05, 0x0B, 0x05,
0162     0x0B, 0x05, 0x0B, 0x05,
0163     0x0B, 0x05, 0x0B, 0x05,
0164     0x0B, 0x05, 0x0B, 0x05,
0165     0x0B, 0x05, 0x0B, 0x05,
0166     0x0B, 0x05, 0x0B, 0x05,
0167     0x0B, 0x05, 0x0B, 0x05,
0168     0x0B, 0x05, 0x0B, 0x05,
0169     0x0B, 0x05, 0x0B, 0x05,
0170     0x0B, 0x05, 0x0B, 0x05,
0171     0x0B, 0x05, 0x11, 0x8B,
0172     0x0B, 0x20, 0x0B, 0x05,
0173     0x04, 0xF6, 0x04, 0xF6,
0174     0x04, 0xF6, 0x04, 0xF6
0175 };
0176 
0177 static const u8 cypress_smc_int_vectors[] =
0178 {
0179     0x0B, 0x05, 0x0B, 0x05,
0180     0x0B, 0x05, 0x0B, 0x05,
0181     0x0B, 0x05, 0x0B, 0x05,
0182     0x0B, 0x05, 0x0B, 0x05,
0183     0x0B, 0x05, 0x0B, 0x05,
0184     0x0B, 0x05, 0x0B, 0x05,
0185     0x0B, 0x05, 0x0B, 0x05,
0186     0x0B, 0x05, 0x0B, 0x05,
0187     0x0B, 0x05, 0x0B, 0x05,
0188     0x0B, 0x05, 0x0B, 0x05,
0189     0x0B, 0x05, 0x0B, 0x05,
0190     0x0B, 0x05, 0x0B, 0x05,
0191     0x0B, 0x05, 0x11, 0x8B,
0192     0x0B, 0x20, 0x0B, 0x05,
0193     0x04, 0xF6, 0x04, 0xF6,
0194     0x04, 0xF6, 0x04, 0xF6
0195 };
0196 
0197 static const u8 barts_smc_int_vectors[] =
0198 {
0199     0x0C, 0x14, 0x0C, 0x14,
0200     0x0C, 0x14, 0x0C, 0x14,
0201     0x0C, 0x14, 0x0C, 0x14,
0202     0x0C, 0x14, 0x0C, 0x14,
0203     0x0C, 0x14, 0x0C, 0x14,
0204     0x0C, 0x14, 0x0C, 0x14,
0205     0x0C, 0x14, 0x0C, 0x14,
0206     0x0C, 0x14, 0x0C, 0x14,
0207     0x0C, 0x14, 0x0C, 0x14,
0208     0x0C, 0x14, 0x0C, 0x14,
0209     0x0C, 0x14, 0x0C, 0x14,
0210     0x0C, 0x14, 0x0C, 0x14,
0211     0x0C, 0x14, 0x12, 0xAA,
0212     0x0C, 0x2F, 0x15, 0xF6,
0213     0x15, 0xF6, 0x05, 0x0A,
0214     0x05, 0x0A, 0x05, 0x0A
0215 };
0216 
0217 static const u8 turks_smc_int_vectors[] =
0218 {
0219     0x0C, 0x14, 0x0C, 0x14,
0220     0x0C, 0x14, 0x0C, 0x14,
0221     0x0C, 0x14, 0x0C, 0x14,
0222     0x0C, 0x14, 0x0C, 0x14,
0223     0x0C, 0x14, 0x0C, 0x14,
0224     0x0C, 0x14, 0x0C, 0x14,
0225     0x0C, 0x14, 0x0C, 0x14,
0226     0x0C, 0x14, 0x0C, 0x14,
0227     0x0C, 0x14, 0x0C, 0x14,
0228     0x0C, 0x14, 0x0C, 0x14,
0229     0x0C, 0x14, 0x0C, 0x14,
0230     0x0C, 0x14, 0x0C, 0x14,
0231     0x0C, 0x14, 0x12, 0xAA,
0232     0x0C, 0x2F, 0x15, 0xF6,
0233     0x15, 0xF6, 0x05, 0x0A,
0234     0x05, 0x0A, 0x05, 0x0A
0235 };
0236 
0237 static const u8 caicos_smc_int_vectors[] =
0238 {
0239     0x0C, 0x14, 0x0C, 0x14,
0240     0x0C, 0x14, 0x0C, 0x14,
0241     0x0C, 0x14, 0x0C, 0x14,
0242     0x0C, 0x14, 0x0C, 0x14,
0243     0x0C, 0x14, 0x0C, 0x14,
0244     0x0C, 0x14, 0x0C, 0x14,
0245     0x0C, 0x14, 0x0C, 0x14,
0246     0x0C, 0x14, 0x0C, 0x14,
0247     0x0C, 0x14, 0x0C, 0x14,
0248     0x0C, 0x14, 0x0C, 0x14,
0249     0x0C, 0x14, 0x0C, 0x14,
0250     0x0C, 0x14, 0x0C, 0x14,
0251     0x0C, 0x14, 0x12, 0xAA,
0252     0x0C, 0x2F, 0x15, 0xF6,
0253     0x15, 0xF6, 0x05, 0x0A,
0254     0x05, 0x0A, 0x05, 0x0A
0255 };
0256 
0257 static const u8 cayman_smc_int_vectors[] =
0258 {
0259     0x12, 0x05, 0x12, 0x05,
0260     0x12, 0x05, 0x12, 0x05,
0261     0x12, 0x05, 0x12, 0x05,
0262     0x12, 0x05, 0x12, 0x05,
0263     0x12, 0x05, 0x12, 0x05,
0264     0x12, 0x05, 0x12, 0x05,
0265     0x12, 0x05, 0x12, 0x05,
0266     0x12, 0x05, 0x12, 0x05,
0267     0x12, 0x05, 0x12, 0x05,
0268     0x12, 0x05, 0x12, 0x05,
0269     0x12, 0x05, 0x12, 0x05,
0270     0x12, 0x05, 0x12, 0x05,
0271     0x12, 0x05, 0x18, 0xEA,
0272     0x12, 0x20, 0x1C, 0x34,
0273     0x1C, 0x34, 0x08, 0x72,
0274     0x08, 0x72, 0x08, 0x72
0275 };
0276 
0277 static int rv770_set_smc_sram_address(struct radeon_device *rdev,
0278                       u16 smc_address, u16 limit)
0279 {
0280     u32 addr;
0281 
0282     if (smc_address & 3)
0283         return -EINVAL;
0284     if ((smc_address + 3) > limit)
0285         return -EINVAL;
0286 
0287     addr = smc_address;
0288     addr |= SMC_SRAM_AUTO_INC_DIS;
0289 
0290     WREG32(SMC_SRAM_ADDR, addr);
0291 
0292     return 0;
0293 }
0294 
0295 int rv770_copy_bytes_to_smc(struct radeon_device *rdev,
0296                 u16 smc_start_address, const u8 *src,
0297                 u16 byte_count, u16 limit)
0298 {
0299     unsigned long flags;
0300     u32 data, original_data, extra_shift;
0301     u16 addr;
0302     int ret = 0;
0303 
0304     if (smc_start_address & 3)
0305         return -EINVAL;
0306     if ((smc_start_address + byte_count) > limit)
0307         return -EINVAL;
0308 
0309     addr = smc_start_address;
0310 
0311     spin_lock_irqsave(&rdev->smc_idx_lock, flags);
0312     while (byte_count >= 4) {
0313         /* SMC address space is BE */
0314         data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
0315 
0316         ret = rv770_set_smc_sram_address(rdev, addr, limit);
0317         if (ret)
0318             goto done;
0319 
0320         WREG32(SMC_SRAM_DATA, data);
0321 
0322         src += 4;
0323         byte_count -= 4;
0324         addr += 4;
0325     }
0326 
0327     /* RMW for final bytes */
0328     if (byte_count > 0) {
0329         data = 0;
0330 
0331         ret = rv770_set_smc_sram_address(rdev, addr, limit);
0332         if (ret)
0333             goto done;
0334 
0335         original_data = RREG32(SMC_SRAM_DATA);
0336 
0337         extra_shift = 8 * (4 - byte_count);
0338 
0339         while (byte_count > 0) {
0340             /* SMC address space is BE */
0341             data = (data << 8) + *src++;
0342             byte_count--;
0343         }
0344 
0345         data <<= extra_shift;
0346 
0347         data |= (original_data & ~((~0UL) << extra_shift));
0348 
0349         ret = rv770_set_smc_sram_address(rdev, addr, limit);
0350         if (ret)
0351             goto done;
0352 
0353         WREG32(SMC_SRAM_DATA, data);
0354     }
0355 
0356 done:
0357     spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
0358 
0359     return ret;
0360 }
0361 
0362 static int rv770_program_interrupt_vectors(struct radeon_device *rdev,
0363                        u32 smc_first_vector, const u8 *src,
0364                        u32 byte_count)
0365 {
0366     u32 tmp, i;
0367 
0368     if (byte_count % 4)
0369         return -EINVAL;
0370 
0371     if (smc_first_vector < FIRST_SMC_INT_VECT_REG) {
0372         tmp = FIRST_SMC_INT_VECT_REG - smc_first_vector;
0373 
0374         if (tmp > byte_count)
0375             return 0;
0376 
0377         byte_count -= tmp;
0378         src += tmp;
0379         smc_first_vector = FIRST_SMC_INT_VECT_REG;
0380     }
0381 
0382     for (i = 0; i < byte_count; i += 4) {
0383         /* SMC address space is BE */
0384         tmp = (src[i] << 24) | (src[i + 1] << 16) | (src[i + 2] << 8) | src[i + 3];
0385 
0386         WREG32(SMC_ISR_FFD8_FFDB + i, tmp);
0387     }
0388 
0389     return 0;
0390 }
0391 
0392 void rv770_start_smc(struct radeon_device *rdev)
0393 {
0394     WREG32_P(SMC_IO, SMC_RST_N, ~SMC_RST_N);
0395 }
0396 
0397 void rv770_reset_smc(struct radeon_device *rdev)
0398 {
0399     WREG32_P(SMC_IO, 0, ~SMC_RST_N);
0400 }
0401 
0402 void rv770_stop_smc_clock(struct radeon_device *rdev)
0403 {
0404     WREG32_P(SMC_IO, 0, ~SMC_CLK_EN);
0405 }
0406 
0407 void rv770_start_smc_clock(struct radeon_device *rdev)
0408 {
0409     WREG32_P(SMC_IO, SMC_CLK_EN, ~SMC_CLK_EN);
0410 }
0411 
0412 bool rv770_is_smc_running(struct radeon_device *rdev)
0413 {
0414     u32 tmp;
0415 
0416     tmp = RREG32(SMC_IO);
0417 
0418     if ((tmp & SMC_RST_N) && (tmp & SMC_CLK_EN))
0419         return true;
0420     else
0421         return false;
0422 }
0423 
0424 PPSMC_Result rv770_send_msg_to_smc(struct radeon_device *rdev, PPSMC_Msg msg)
0425 {
0426     u32 tmp;
0427     int i;
0428     PPSMC_Result result;
0429 
0430     if (!rv770_is_smc_running(rdev))
0431         return PPSMC_Result_Failed;
0432 
0433     WREG32_P(SMC_MSG, HOST_SMC_MSG(msg), ~HOST_SMC_MSG_MASK);
0434 
0435     for (i = 0; i < rdev->usec_timeout; i++) {
0436         tmp = RREG32(SMC_MSG) & HOST_SMC_RESP_MASK;
0437         tmp >>= HOST_SMC_RESP_SHIFT;
0438         if (tmp != 0)
0439             break;
0440         udelay(1);
0441     }
0442 
0443     tmp = RREG32(SMC_MSG) & HOST_SMC_RESP_MASK;
0444     tmp >>= HOST_SMC_RESP_SHIFT;
0445 
0446     result = (PPSMC_Result)tmp;
0447     return result;
0448 }
0449 
0450 PPSMC_Result rv770_wait_for_smc_inactive(struct radeon_device *rdev)
0451 {
0452     int i;
0453     PPSMC_Result result = PPSMC_Result_OK;
0454 
0455     if (!rv770_is_smc_running(rdev))
0456         return result;
0457 
0458     for (i = 0; i < rdev->usec_timeout; i++) {
0459         if (RREG32(SMC_IO) & SMC_STOP_MODE)
0460             break;
0461         udelay(1);
0462     }
0463 
0464     return result;
0465 }
0466 
0467 static void rv770_clear_smc_sram(struct radeon_device *rdev, u16 limit)
0468 {
0469     unsigned long flags;
0470     u16 i;
0471 
0472     spin_lock_irqsave(&rdev->smc_idx_lock, flags);
0473     for (i = 0;  i < limit; i += 4) {
0474         rv770_set_smc_sram_address(rdev, i, limit);
0475         WREG32(SMC_SRAM_DATA, 0);
0476     }
0477     spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
0478 }
0479 
0480 int rv770_load_smc_ucode(struct radeon_device *rdev,
0481              u16 limit)
0482 {
0483     int ret;
0484     const u8 *int_vect;
0485     u16 int_vect_start_address;
0486     u16 int_vect_size;
0487     const u8 *ucode_data;
0488     u16 ucode_start_address;
0489     u16 ucode_size;
0490 
0491     if (!rdev->smc_fw)
0492         return -EINVAL;
0493 
0494     rv770_clear_smc_sram(rdev, limit);
0495 
0496     switch (rdev->family) {
0497     case CHIP_RV770:
0498         ucode_start_address = RV770_SMC_UCODE_START;
0499         ucode_size = RV770_SMC_UCODE_SIZE;
0500         int_vect = (const u8 *)&rv770_smc_int_vectors;
0501         int_vect_start_address = RV770_SMC_INT_VECTOR_START;
0502         int_vect_size = RV770_SMC_INT_VECTOR_SIZE;
0503         break;
0504     case CHIP_RV730:
0505         ucode_start_address = RV730_SMC_UCODE_START;
0506         ucode_size = RV730_SMC_UCODE_SIZE;
0507         int_vect = (const u8 *)&rv730_smc_int_vectors;
0508         int_vect_start_address = RV730_SMC_INT_VECTOR_START;
0509         int_vect_size = RV730_SMC_INT_VECTOR_SIZE;
0510         break;
0511     case CHIP_RV710:
0512         ucode_start_address = RV710_SMC_UCODE_START;
0513         ucode_size = RV710_SMC_UCODE_SIZE;
0514         int_vect = (const u8 *)&rv710_smc_int_vectors;
0515         int_vect_start_address = RV710_SMC_INT_VECTOR_START;
0516         int_vect_size = RV710_SMC_INT_VECTOR_SIZE;
0517         break;
0518     case CHIP_RV740:
0519         ucode_start_address = RV740_SMC_UCODE_START;
0520         ucode_size = RV740_SMC_UCODE_SIZE;
0521         int_vect = (const u8 *)&rv740_smc_int_vectors;
0522         int_vect_start_address = RV740_SMC_INT_VECTOR_START;
0523         int_vect_size = RV740_SMC_INT_VECTOR_SIZE;
0524         break;
0525     case CHIP_CEDAR:
0526         ucode_start_address = CEDAR_SMC_UCODE_START;
0527         ucode_size = CEDAR_SMC_UCODE_SIZE;
0528         int_vect = (const u8 *)&cedar_smc_int_vectors;
0529         int_vect_start_address = CEDAR_SMC_INT_VECTOR_START;
0530         int_vect_size = CEDAR_SMC_INT_VECTOR_SIZE;
0531         break;
0532     case CHIP_REDWOOD:
0533         ucode_start_address = REDWOOD_SMC_UCODE_START;
0534         ucode_size = REDWOOD_SMC_UCODE_SIZE;
0535         int_vect = (const u8 *)&redwood_smc_int_vectors;
0536         int_vect_start_address = REDWOOD_SMC_INT_VECTOR_START;
0537         int_vect_size = REDWOOD_SMC_INT_VECTOR_SIZE;
0538         break;
0539     case CHIP_JUNIPER:
0540         ucode_start_address = JUNIPER_SMC_UCODE_START;
0541         ucode_size = JUNIPER_SMC_UCODE_SIZE;
0542         int_vect = (const u8 *)&juniper_smc_int_vectors;
0543         int_vect_start_address = JUNIPER_SMC_INT_VECTOR_START;
0544         int_vect_size = JUNIPER_SMC_INT_VECTOR_SIZE;
0545         break;
0546     case CHIP_CYPRESS:
0547     case CHIP_HEMLOCK:
0548         ucode_start_address = CYPRESS_SMC_UCODE_START;
0549         ucode_size = CYPRESS_SMC_UCODE_SIZE;
0550         int_vect = (const u8 *)&cypress_smc_int_vectors;
0551         int_vect_start_address = CYPRESS_SMC_INT_VECTOR_START;
0552         int_vect_size = CYPRESS_SMC_INT_VECTOR_SIZE;
0553         break;
0554     case CHIP_BARTS:
0555         ucode_start_address = BARTS_SMC_UCODE_START;
0556         ucode_size = BARTS_SMC_UCODE_SIZE;
0557         int_vect = (const u8 *)&barts_smc_int_vectors;
0558         int_vect_start_address = BARTS_SMC_INT_VECTOR_START;
0559         int_vect_size = BARTS_SMC_INT_VECTOR_SIZE;
0560         break;
0561     case CHIP_TURKS:
0562         ucode_start_address = TURKS_SMC_UCODE_START;
0563         ucode_size = TURKS_SMC_UCODE_SIZE;
0564         int_vect = (const u8 *)&turks_smc_int_vectors;
0565         int_vect_start_address = TURKS_SMC_INT_VECTOR_START;
0566         int_vect_size = TURKS_SMC_INT_VECTOR_SIZE;
0567         break;
0568     case CHIP_CAICOS:
0569         ucode_start_address = CAICOS_SMC_UCODE_START;
0570         ucode_size = CAICOS_SMC_UCODE_SIZE;
0571         int_vect = (const u8 *)&caicos_smc_int_vectors;
0572         int_vect_start_address = CAICOS_SMC_INT_VECTOR_START;
0573         int_vect_size = CAICOS_SMC_INT_VECTOR_SIZE;
0574         break;
0575     case CHIP_CAYMAN:
0576         ucode_start_address = CAYMAN_SMC_UCODE_START;
0577         ucode_size = CAYMAN_SMC_UCODE_SIZE;
0578         int_vect = (const u8 *)&cayman_smc_int_vectors;
0579         int_vect_start_address = CAYMAN_SMC_INT_VECTOR_START;
0580         int_vect_size = CAYMAN_SMC_INT_VECTOR_SIZE;
0581         break;
0582     default:
0583         DRM_ERROR("unknown asic in smc ucode loader\n");
0584         BUG();
0585     }
0586 
0587     /* load the ucode */
0588     ucode_data = (const u8 *)rdev->smc_fw->data;
0589     ret = rv770_copy_bytes_to_smc(rdev, ucode_start_address,
0590                       ucode_data, ucode_size, limit);
0591     if (ret)
0592         return ret;
0593 
0594     /* set up the int vectors */
0595     ret = rv770_program_interrupt_vectors(rdev, int_vect_start_address,
0596                           int_vect, int_vect_size);
0597     if (ret)
0598         return ret;
0599 
0600     return 0;
0601 }
0602 
0603 int rv770_read_smc_sram_dword(struct radeon_device *rdev,
0604                   u16 smc_address, u32 *value, u16 limit)
0605 {
0606     unsigned long flags;
0607     int ret;
0608 
0609     spin_lock_irqsave(&rdev->smc_idx_lock, flags);
0610     ret = rv770_set_smc_sram_address(rdev, smc_address, limit);
0611     if (ret == 0)
0612         *value = RREG32(SMC_SRAM_DATA);
0613     spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
0614 
0615     return ret;
0616 }
0617 
0618 int rv770_write_smc_sram_dword(struct radeon_device *rdev,
0619                    u16 smc_address, u32 value, u16 limit)
0620 {
0621     unsigned long flags;
0622     int ret;
0623 
0624     spin_lock_irqsave(&rdev->smc_idx_lock, flags);
0625     ret = rv770_set_smc_sram_address(rdev, smc_address, limit);
0626     if (ret == 0)
0627         WREG32(SMC_SRAM_DATA, value);
0628     spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
0629 
0630     return ret;
0631 }