0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
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
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
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
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
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
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
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 }