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 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 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 u32 data, original_data, extra_shift; 300 u16 addr; 301 int ret = 0; 302 303 if (smc_start_address & 3) 304 return -EINVAL; 305 if ((smc_start_address + byte_count) > limit) 306 return -EINVAL; 307 308 addr = smc_start_address; 309 310 lockmgr(&rdev->smc_idx_lock, LK_EXCLUSIVE); 311 while (byte_count >= 4) { 312 /* SMC address space is BE */ 313 data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3]; 314 315 ret = rv770_set_smc_sram_address(rdev, addr, limit); 316 if (ret) 317 goto done; 318 319 WREG32(SMC_SRAM_DATA, data); 320 321 src += 4; 322 byte_count -= 4; 323 addr += 4; 324 } 325 326 /* RMW for final bytes */ 327 if (byte_count > 0) { 328 data = 0; 329 330 ret = rv770_set_smc_sram_address(rdev, addr, limit); 331 if (ret) 332 goto done; 333 334 original_data = RREG32(SMC_SRAM_DATA); 335 336 extra_shift = 8 * (4 - byte_count); 337 338 while (byte_count > 0) { 339 /* SMC address space is BE */ 340 data = (data << 8) + *src++; 341 byte_count--; 342 } 343 344 data <<= extra_shift; 345 346 data |= (original_data & ~((~0UL) << extra_shift)); 347 348 ret = rv770_set_smc_sram_address(rdev, addr, limit); 349 if (ret) 350 goto done; 351 352 WREG32(SMC_SRAM_DATA, data); 353 } 354 355 done: 356 lockmgr(&rdev->smc_idx_lock, LK_RELEASE); 357 358 return ret; 359 } 360 361 static int rv770_program_interrupt_vectors(struct radeon_device *rdev, 362 u32 smc_first_vector, const u8 *src, 363 u32 byte_count) 364 { 365 u32 tmp, i; 366 367 if (byte_count % 4) 368 return -EINVAL; 369 370 if (smc_first_vector < FIRST_SMC_INT_VECT_REG) { 371 tmp = FIRST_SMC_INT_VECT_REG - smc_first_vector; 372 373 if (tmp > byte_count) 374 return 0; 375 376 byte_count -= tmp; 377 src += tmp; 378 smc_first_vector = FIRST_SMC_INT_VECT_REG; 379 } 380 381 for (i = 0; i < byte_count; i += 4) { 382 /* SMC address space is BE */ 383 tmp = (src[i] << 24) | (src[i + 1] << 16) | (src[i + 2] << 8) | src[i + 3]; 384 385 WREG32(SMC_ISR_FFD8_FFDB + i, tmp); 386 } 387 388 return 0; 389 } 390 391 void rv770_start_smc(struct radeon_device *rdev) 392 { 393 WREG32_P(SMC_IO, SMC_RST_N, ~SMC_RST_N); 394 } 395 396 void rv770_reset_smc(struct radeon_device *rdev) 397 { 398 WREG32_P(SMC_IO, 0, ~SMC_RST_N); 399 } 400 401 void rv770_stop_smc_clock(struct radeon_device *rdev) 402 { 403 WREG32_P(SMC_IO, 0, ~SMC_CLK_EN); 404 } 405 406 void rv770_start_smc_clock(struct radeon_device *rdev) 407 { 408 WREG32_P(SMC_IO, SMC_CLK_EN, ~SMC_CLK_EN); 409 } 410 411 bool rv770_is_smc_running(struct radeon_device *rdev) 412 { 413 u32 tmp; 414 415 tmp = RREG32(SMC_IO); 416 417 if ((tmp & SMC_RST_N) && (tmp & SMC_CLK_EN)) 418 return true; 419 else 420 return false; 421 } 422 423 PPSMC_Result rv770_send_msg_to_smc(struct radeon_device *rdev, PPSMC_Msg msg) 424 { 425 u32 tmp; 426 int i; 427 PPSMC_Result result; 428 429 if (!rv770_is_smc_running(rdev)) 430 return PPSMC_Result_Failed; 431 432 WREG32_P(SMC_MSG, HOST_SMC_MSG(msg), ~HOST_SMC_MSG_MASK); 433 434 for (i = 0; i < rdev->usec_timeout; i++) { 435 tmp = RREG32(SMC_MSG) & HOST_SMC_RESP_MASK; 436 tmp >>= HOST_SMC_RESP_SHIFT; 437 if (tmp != 0) 438 break; 439 udelay(1); 440 } 441 442 tmp = RREG32(SMC_MSG) & HOST_SMC_RESP_MASK; 443 tmp >>= HOST_SMC_RESP_SHIFT; 444 445 result = (PPSMC_Result)tmp; 446 return result; 447 } 448 449 PPSMC_Result rv770_wait_for_smc_inactive(struct radeon_device *rdev) 450 { 451 int i; 452 PPSMC_Result result = PPSMC_Result_OK; 453 454 if (!rv770_is_smc_running(rdev)) 455 return result; 456 457 for (i = 0; i < rdev->usec_timeout; i++) { 458 if (RREG32(SMC_IO) & SMC_STOP_MODE) 459 break; 460 udelay(1); 461 } 462 463 return result; 464 } 465 466 static void rv770_clear_smc_sram(struct radeon_device *rdev, u16 limit) 467 { 468 u16 i; 469 470 lockmgr(&rdev->smc_idx_lock, LK_EXCLUSIVE); 471 for (i = 0; i < limit; i += 4) { 472 rv770_set_smc_sram_address(rdev, i, limit); 473 WREG32(SMC_SRAM_DATA, 0); 474 } 475 lockmgr(&rdev->smc_idx_lock, LK_RELEASE); 476 } 477 478 int rv770_load_smc_ucode(struct radeon_device *rdev, 479 u16 limit) 480 { 481 int ret; 482 const u8 *int_vect; 483 u16 int_vect_start_address; 484 u16 int_vect_size; 485 const u8 *ucode_data; 486 u16 ucode_start_address; 487 u16 ucode_size; 488 489 if (!rdev->smc_fw) 490 return -EINVAL; 491 492 rv770_clear_smc_sram(rdev, limit); 493 494 switch (rdev->family) { 495 case CHIP_RV770: 496 ucode_start_address = RV770_SMC_UCODE_START; 497 ucode_size = RV770_SMC_UCODE_SIZE; 498 int_vect = (const u8 *)&rv770_smc_int_vectors; 499 int_vect_start_address = RV770_SMC_INT_VECTOR_START; 500 int_vect_size = RV770_SMC_INT_VECTOR_SIZE; 501 break; 502 case CHIP_RV730: 503 ucode_start_address = RV730_SMC_UCODE_START; 504 ucode_size = RV730_SMC_UCODE_SIZE; 505 int_vect = (const u8 *)&rv730_smc_int_vectors; 506 int_vect_start_address = RV730_SMC_INT_VECTOR_START; 507 int_vect_size = RV730_SMC_INT_VECTOR_SIZE; 508 break; 509 case CHIP_RV710: 510 ucode_start_address = RV710_SMC_UCODE_START; 511 ucode_size = RV710_SMC_UCODE_SIZE; 512 int_vect = (const u8 *)&rv710_smc_int_vectors; 513 int_vect_start_address = RV710_SMC_INT_VECTOR_START; 514 int_vect_size = RV710_SMC_INT_VECTOR_SIZE; 515 break; 516 case CHIP_RV740: 517 ucode_start_address = RV740_SMC_UCODE_START; 518 ucode_size = RV740_SMC_UCODE_SIZE; 519 int_vect = (const u8 *)&rv740_smc_int_vectors; 520 int_vect_start_address = RV740_SMC_INT_VECTOR_START; 521 int_vect_size = RV740_SMC_INT_VECTOR_SIZE; 522 break; 523 case CHIP_CEDAR: 524 ucode_start_address = CEDAR_SMC_UCODE_START; 525 ucode_size = CEDAR_SMC_UCODE_SIZE; 526 int_vect = (const u8 *)&cedar_smc_int_vectors; 527 int_vect_start_address = CEDAR_SMC_INT_VECTOR_START; 528 int_vect_size = CEDAR_SMC_INT_VECTOR_SIZE; 529 break; 530 case CHIP_REDWOOD: 531 ucode_start_address = REDWOOD_SMC_UCODE_START; 532 ucode_size = REDWOOD_SMC_UCODE_SIZE; 533 int_vect = (const u8 *)&redwood_smc_int_vectors; 534 int_vect_start_address = REDWOOD_SMC_INT_VECTOR_START; 535 int_vect_size = REDWOOD_SMC_INT_VECTOR_SIZE; 536 break; 537 case CHIP_JUNIPER: 538 ucode_start_address = JUNIPER_SMC_UCODE_START; 539 ucode_size = JUNIPER_SMC_UCODE_SIZE; 540 int_vect = (const u8 *)&juniper_smc_int_vectors; 541 int_vect_start_address = JUNIPER_SMC_INT_VECTOR_START; 542 int_vect_size = JUNIPER_SMC_INT_VECTOR_SIZE; 543 break; 544 case CHIP_CYPRESS: 545 case CHIP_HEMLOCK: 546 ucode_start_address = CYPRESS_SMC_UCODE_START; 547 ucode_size = CYPRESS_SMC_UCODE_SIZE; 548 int_vect = (const u8 *)&cypress_smc_int_vectors; 549 int_vect_start_address = CYPRESS_SMC_INT_VECTOR_START; 550 int_vect_size = CYPRESS_SMC_INT_VECTOR_SIZE; 551 break; 552 case CHIP_BARTS: 553 ucode_start_address = BARTS_SMC_UCODE_START; 554 ucode_size = BARTS_SMC_UCODE_SIZE; 555 int_vect = (const u8 *)&barts_smc_int_vectors; 556 int_vect_start_address = BARTS_SMC_INT_VECTOR_START; 557 int_vect_size = BARTS_SMC_INT_VECTOR_SIZE; 558 break; 559 case CHIP_TURKS: 560 ucode_start_address = TURKS_SMC_UCODE_START; 561 ucode_size = TURKS_SMC_UCODE_SIZE; 562 int_vect = (const u8 *)&turks_smc_int_vectors; 563 int_vect_start_address = TURKS_SMC_INT_VECTOR_START; 564 int_vect_size = TURKS_SMC_INT_VECTOR_SIZE; 565 break; 566 case CHIP_CAICOS: 567 ucode_start_address = CAICOS_SMC_UCODE_START; 568 ucode_size = CAICOS_SMC_UCODE_SIZE; 569 int_vect = (const u8 *)&caicos_smc_int_vectors; 570 int_vect_start_address = CAICOS_SMC_INT_VECTOR_START; 571 int_vect_size = CAICOS_SMC_INT_VECTOR_SIZE; 572 break; 573 case CHIP_CAYMAN: 574 ucode_start_address = CAYMAN_SMC_UCODE_START; 575 ucode_size = CAYMAN_SMC_UCODE_SIZE; 576 int_vect = (const u8 *)&cayman_smc_int_vectors; 577 int_vect_start_address = CAYMAN_SMC_INT_VECTOR_START; 578 int_vect_size = CAYMAN_SMC_INT_VECTOR_SIZE; 579 break; 580 default: 581 DRM_ERROR("unknown asic in smc ucode loader\n"); 582 BUG(); 583 } 584 585 /* load the ucode */ 586 ucode_data = (const u8 *)rdev->smc_fw->data; 587 ret = rv770_copy_bytes_to_smc(rdev, ucode_start_address, 588 ucode_data, ucode_size, limit); 589 if (ret) 590 return ret; 591 592 /* set up the int vectors */ 593 ret = rv770_program_interrupt_vectors(rdev, int_vect_start_address, 594 int_vect, int_vect_size); 595 if (ret) 596 return ret; 597 598 return 0; 599 } 600 601 int rv770_read_smc_sram_dword(struct radeon_device *rdev, 602 u16 smc_address, u32 *value, u16 limit) 603 { 604 int ret; 605 606 lockmgr(&rdev->smc_idx_lock, LK_EXCLUSIVE); 607 ret = rv770_set_smc_sram_address(rdev, smc_address, limit); 608 if (ret == 0) 609 *value = RREG32(SMC_SRAM_DATA); 610 lockmgr(&rdev->smc_idx_lock, LK_RELEASE); 611 612 return ret; 613 } 614 615 int rv770_write_smc_sram_dword(struct radeon_device *rdev, 616 u16 smc_address, u32 value, u16 limit) 617 { 618 int ret; 619 620 lockmgr(&rdev->smc_idx_lock, LK_EXCLUSIVE); 621 ret = rv770_set_smc_sram_address(rdev, smc_address, limit); 622 if (ret == 0) 623 WREG32(SMC_SRAM_DATA, value); 624 lockmgr(&rdev->smc_idx_lock, LK_RELEASE); 625 626 return ret; 627 } 628