1/* $NetBSD: radeon_rv770_smc.c,v 1.3 2021/12/18 23:45:43 riastradh Exp $ */ 2 3/* 4 * Copyright 2011 Advanced Micro Devices, Inc. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 * 24 * Authors: Alex Deucher 25 */ 26 27#include <sys/cdefs.h> 28__KERNEL_RCSID(0, "$NetBSD: radeon_rv770_smc.c,v 1.3 2021/12/18 23:45:43 riastradh Exp $"); 29 30#include <linux/firmware.h> 31 32#include "radeon.h" 33#include "rv770d.h" 34#include "rv770_dpm.h" 35#include "rv770_smc.h" 36#include "atom.h" 37#include "radeon_ucode.h" 38 39#define FIRST_SMC_INT_VECT_REG 0xFFD8 40#define FIRST_INT_VECT_S19 0xFFC0 41 42static const u8 rv770_smc_int_vectors[] = 43{ 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, 0x08, 0x10, 52 0x08, 0x10, 0x08, 0x10, 53 0x08, 0x10, 0x08, 0x10, 54 0x08, 0x10, 0x08, 0x10, 55 0x08, 0x10, 0x08, 0x10, 56 0x08, 0x10, 0x0C, 0xD7, 57 0x08, 0x2B, 0x08, 0x10, 58 0x03, 0x51, 0x03, 0x51, 59 0x03, 0x51, 0x03, 0x51 60}; 61 62static const u8 rv730_smc_int_vectors[] = 63{ 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, 0x08, 0x15, 72 0x08, 0x15, 0x08, 0x15, 73 0x08, 0x15, 0x08, 0x15, 74 0x08, 0x15, 0x08, 0x15, 75 0x08, 0x15, 0x08, 0x15, 76 0x08, 0x15, 0x0C, 0xBB, 77 0x08, 0x30, 0x08, 0x15, 78 0x03, 0x56, 0x03, 0x56, 79 0x03, 0x56, 0x03, 0x56 80}; 81 82static const u8 rv710_smc_int_vectors[] = 83{ 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, 0x08, 0x04, 92 0x08, 0x04, 0x08, 0x04, 93 0x08, 0x04, 0x08, 0x04, 94 0x08, 0x04, 0x08, 0x04, 95 0x08, 0x04, 0x08, 0x04, 96 0x08, 0x04, 0x0C, 0xCB, 97 0x08, 0x1F, 0x08, 0x04, 98 0x03, 0x51, 0x03, 0x51, 99 0x03, 0x51, 0x03, 0x51 100}; 101 102static const u8 rv740_smc_int_vectors[] = 103{ 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, 0x08, 0x10, 112 0x08, 0x10, 0x08, 0x10, 113 0x08, 0x10, 0x08, 0x10, 114 0x08, 0x10, 0x08, 0x10, 115 0x08, 0x10, 0x08, 0x10, 116 0x08, 0x10, 0x0C, 0xD7, 117 0x08, 0x2B, 0x08, 0x10, 118 0x03, 0x51, 0x03, 0x51, 119 0x03, 0x51, 0x03, 0x51 120}; 121 122static const u8 cedar_smc_int_vectors[] = 123{ 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, 0x0B, 0x05, 132 0x0B, 0x05, 0x0B, 0x05, 133 0x0B, 0x05, 0x0B, 0x05, 134 0x0B, 0x05, 0x0B, 0x05, 135 0x0B, 0x05, 0x0B, 0x05, 136 0x0B, 0x05, 0x11, 0x8B, 137 0x0B, 0x20, 0x0B, 0x05, 138 0x04, 0xF6, 0x04, 0xF6, 139 0x04, 0xF6, 0x04, 0xF6 140}; 141 142static const u8 redwood_smc_int_vectors[] = 143{ 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, 0x0B, 0x05, 152 0x0B, 0x05, 0x0B, 0x05, 153 0x0B, 0x05, 0x0B, 0x05, 154 0x0B, 0x05, 0x0B, 0x05, 155 0x0B, 0x05, 0x0B, 0x05, 156 0x0B, 0x05, 0x11, 0x8B, 157 0x0B, 0x20, 0x0B, 0x05, 158 0x04, 0xF6, 0x04, 0xF6, 159 0x04, 0xF6, 0x04, 0xF6 160}; 161 162static const u8 juniper_smc_int_vectors[] = 163{ 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, 0x0B, 0x05, 172 0x0B, 0x05, 0x0B, 0x05, 173 0x0B, 0x05, 0x0B, 0x05, 174 0x0B, 0x05, 0x0B, 0x05, 175 0x0B, 0x05, 0x0B, 0x05, 176 0x0B, 0x05, 0x11, 0x8B, 177 0x0B, 0x20, 0x0B, 0x05, 178 0x04, 0xF6, 0x04, 0xF6, 179 0x04, 0xF6, 0x04, 0xF6 180}; 181 182static const u8 cypress_smc_int_vectors[] = 183{ 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, 0x0B, 0x05, 192 0x0B, 0x05, 0x0B, 0x05, 193 0x0B, 0x05, 0x0B, 0x05, 194 0x0B, 0x05, 0x0B, 0x05, 195 0x0B, 0x05, 0x0B, 0x05, 196 0x0B, 0x05, 0x11, 0x8B, 197 0x0B, 0x20, 0x0B, 0x05, 198 0x04, 0xF6, 0x04, 0xF6, 199 0x04, 0xF6, 0x04, 0xF6 200}; 201 202static const u8 barts_smc_int_vectors[] = 203{ 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, 0x0C, 0x14, 212 0x0C, 0x14, 0x0C, 0x14, 213 0x0C, 0x14, 0x0C, 0x14, 214 0x0C, 0x14, 0x0C, 0x14, 215 0x0C, 0x14, 0x0C, 0x14, 216 0x0C, 0x14, 0x12, 0xAA, 217 0x0C, 0x2F, 0x15, 0xF6, 218 0x15, 0xF6, 0x05, 0x0A, 219 0x05, 0x0A, 0x05, 0x0A 220}; 221 222static const u8 turks_smc_int_vectors[] = 223{ 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, 0x0C, 0x14, 232 0x0C, 0x14, 0x0C, 0x14, 233 0x0C, 0x14, 0x0C, 0x14, 234 0x0C, 0x14, 0x0C, 0x14, 235 0x0C, 0x14, 0x0C, 0x14, 236 0x0C, 0x14, 0x12, 0xAA, 237 0x0C, 0x2F, 0x15, 0xF6, 238 0x15, 0xF6, 0x05, 0x0A, 239 0x05, 0x0A, 0x05, 0x0A 240}; 241 242static const u8 caicos_smc_int_vectors[] = 243{ 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, 0x0C, 0x14, 252 0x0C, 0x14, 0x0C, 0x14, 253 0x0C, 0x14, 0x0C, 0x14, 254 0x0C, 0x14, 0x0C, 0x14, 255 0x0C, 0x14, 0x0C, 0x14, 256 0x0C, 0x14, 0x12, 0xAA, 257 0x0C, 0x2F, 0x15, 0xF6, 258 0x15, 0xF6, 0x05, 0x0A, 259 0x05, 0x0A, 0x05, 0x0A 260}; 261 262static const u8 cayman_smc_int_vectors[] = 263{ 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, 0x12, 0x05, 272 0x12, 0x05, 0x12, 0x05, 273 0x12, 0x05, 0x12, 0x05, 274 0x12, 0x05, 0x12, 0x05, 275 0x12, 0x05, 0x12, 0x05, 276 0x12, 0x05, 0x18, 0xEA, 277 0x12, 0x20, 0x1C, 0x34, 278 0x1C, 0x34, 0x08, 0x72, 279 0x08, 0x72, 0x08, 0x72 280}; 281 282static int rv770_set_smc_sram_address(struct radeon_device *rdev, 283 u16 smc_address, u16 limit) 284{ 285 u32 addr; 286 287 if (smc_address & 3) 288 return -EINVAL; 289 if ((smc_address + 3) > limit) 290 return -EINVAL; 291 292 addr = smc_address; 293 addr |= SMC_SRAM_AUTO_INC_DIS; 294 295 WREG32(SMC_SRAM_ADDR, addr); 296 297 return 0; 298} 299 300int rv770_copy_bytes_to_smc(struct radeon_device *rdev, 301 u16 smc_start_address, const u8 *src, 302 u16 byte_count, u16 limit) 303{ 304 unsigned long flags; 305 u32 data, original_data, extra_shift; 306 u16 addr; 307 int ret = 0; 308 309 if (smc_start_address & 3) 310 return -EINVAL; 311 if ((smc_start_address + byte_count) > limit) 312 return -EINVAL; 313 314 addr = smc_start_address; 315 316 spin_lock_irqsave(&rdev->smc_idx_lock, flags); 317 while (byte_count >= 4) { 318 /* SMC address space is BE */ 319 data = ((u32)src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3]; 320 321 ret = rv770_set_smc_sram_address(rdev, addr, limit); 322 if (ret) 323 goto done; 324 325 WREG32(SMC_SRAM_DATA, data); 326 327 src += 4; 328 byte_count -= 4; 329 addr += 4; 330 } 331 332 /* RMW for final bytes */ 333 if (byte_count > 0) { 334 data = 0; 335 336 ret = rv770_set_smc_sram_address(rdev, addr, limit); 337 if (ret) 338 goto done; 339 340 original_data = RREG32(SMC_SRAM_DATA); 341 342 extra_shift = 8 * (4 - byte_count); 343 344 while (byte_count > 0) { 345 /* SMC address space is BE */ 346 data = (data << 8) + *src++; 347 byte_count--; 348 } 349 350 data <<= extra_shift; 351 352 data |= (original_data & ~((~0UL) << extra_shift)); 353 354 ret = rv770_set_smc_sram_address(rdev, addr, limit); 355 if (ret) 356 goto done; 357 358 WREG32(SMC_SRAM_DATA, data); 359 } 360 361done: 362 spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); 363 364 return ret; 365} 366 367static int rv770_program_interrupt_vectors(struct radeon_device *rdev, 368 u32 smc_first_vector, const u8 *src, 369 u32 byte_count) 370{ 371 u32 tmp, i; 372 373 if (byte_count % 4) 374 return -EINVAL; 375 376 if (smc_first_vector < FIRST_SMC_INT_VECT_REG) { 377 tmp = FIRST_SMC_INT_VECT_REG - smc_first_vector; 378 379 if (tmp > byte_count) 380 return 0; 381 382 byte_count -= tmp; 383 src += tmp; 384 smc_first_vector = FIRST_SMC_INT_VECT_REG; 385 } 386 387 for (i = 0; i < byte_count; i += 4) { 388 /* SMC address space is BE */ 389 tmp = (src[i] << 24) | (src[i + 1] << 16) | (src[i + 2] << 8) | src[i + 3]; 390 391 WREG32(SMC_ISR_FFD8_FFDB + i, tmp); 392 } 393 394 return 0; 395} 396 397void rv770_start_smc(struct radeon_device *rdev) 398{ 399 WREG32_P(SMC_IO, SMC_RST_N, ~SMC_RST_N); 400} 401 402void rv770_reset_smc(struct radeon_device *rdev) 403{ 404 WREG32_P(SMC_IO, 0, ~SMC_RST_N); 405} 406 407void rv770_stop_smc_clock(struct radeon_device *rdev) 408{ 409 WREG32_P(SMC_IO, 0, ~SMC_CLK_EN); 410} 411 412void rv770_start_smc_clock(struct radeon_device *rdev) 413{ 414 WREG32_P(SMC_IO, SMC_CLK_EN, ~SMC_CLK_EN); 415} 416 417bool rv770_is_smc_running(struct radeon_device *rdev) 418{ 419 u32 tmp; 420 421 tmp = RREG32(SMC_IO); 422 423 if ((tmp & SMC_RST_N) && (tmp & SMC_CLK_EN)) 424 return true; 425 else 426 return false; 427} 428 429PPSMC_Result rv770_send_msg_to_smc(struct radeon_device *rdev, PPSMC_Msg msg) 430{ 431 u32 tmp; 432 int i; 433 PPSMC_Result result; 434 435 if (!rv770_is_smc_running(rdev)) 436 return PPSMC_Result_Failed; 437 438 WREG32_P(SMC_MSG, HOST_SMC_MSG(msg), ~HOST_SMC_MSG_MASK); 439 440 for (i = 0; i < rdev->usec_timeout; i++) { 441 tmp = RREG32(SMC_MSG) & HOST_SMC_RESP_MASK; 442 tmp >>= HOST_SMC_RESP_SHIFT; 443 if (tmp != 0) 444 break; 445 udelay(1); 446 } 447 448 tmp = RREG32(SMC_MSG) & HOST_SMC_RESP_MASK; 449 tmp >>= HOST_SMC_RESP_SHIFT; 450 451 result = (PPSMC_Result)tmp; 452 return result; 453} 454 455PPSMC_Result rv770_wait_for_smc_inactive(struct radeon_device *rdev) 456{ 457 int i; 458 PPSMC_Result result = PPSMC_Result_OK; 459 460 if (!rv770_is_smc_running(rdev)) 461 return result; 462 463 for (i = 0; i < rdev->usec_timeout; i++) { 464 if (RREG32(SMC_IO) & SMC_STOP_MODE) 465 break; 466 udelay(1); 467 } 468 469 return result; 470} 471 472static void rv770_clear_smc_sram(struct radeon_device *rdev, u16 limit) 473{ 474 unsigned long flags; 475 u16 i; 476 477 spin_lock_irqsave(&rdev->smc_idx_lock, flags); 478 for (i = 0; i < limit; i += 4) { 479 rv770_set_smc_sram_address(rdev, i, limit); 480 WREG32(SMC_SRAM_DATA, 0); 481 } 482 spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); 483} 484 485int rv770_load_smc_ucode(struct radeon_device *rdev, 486 u16 limit) 487{ 488 int ret; 489 const u8 *int_vect; 490 u16 int_vect_start_address; 491 u16 int_vect_size; 492 const u8 *ucode_data; 493 u16 ucode_start_address; 494 u16 ucode_size; 495 496 if (!rdev->smc_fw) 497 return -EINVAL; 498 499 rv770_clear_smc_sram(rdev, limit); 500 501 switch (rdev->family) { 502 case CHIP_RV770: 503 ucode_start_address = RV770_SMC_UCODE_START; 504 ucode_size = RV770_SMC_UCODE_SIZE; 505 int_vect = (const u8 *)&rv770_smc_int_vectors; 506 int_vect_start_address = RV770_SMC_INT_VECTOR_START; 507 int_vect_size = RV770_SMC_INT_VECTOR_SIZE; 508 break; 509 case CHIP_RV730: 510 ucode_start_address = RV730_SMC_UCODE_START; 511 ucode_size = RV730_SMC_UCODE_SIZE; 512 int_vect = (const u8 *)&rv730_smc_int_vectors; 513 int_vect_start_address = RV730_SMC_INT_VECTOR_START; 514 int_vect_size = RV730_SMC_INT_VECTOR_SIZE; 515 break; 516 case CHIP_RV710: 517 ucode_start_address = RV710_SMC_UCODE_START; 518 ucode_size = RV710_SMC_UCODE_SIZE; 519 int_vect = (const u8 *)&rv710_smc_int_vectors; 520 int_vect_start_address = RV710_SMC_INT_VECTOR_START; 521 int_vect_size = RV710_SMC_INT_VECTOR_SIZE; 522 break; 523 case CHIP_RV740: 524 ucode_start_address = RV740_SMC_UCODE_START; 525 ucode_size = RV740_SMC_UCODE_SIZE; 526 int_vect = (const u8 *)&rv740_smc_int_vectors; 527 int_vect_start_address = RV740_SMC_INT_VECTOR_START; 528 int_vect_size = RV740_SMC_INT_VECTOR_SIZE; 529 break; 530 case CHIP_CEDAR: 531 ucode_start_address = CEDAR_SMC_UCODE_START; 532 ucode_size = CEDAR_SMC_UCODE_SIZE; 533 int_vect = (const u8 *)&cedar_smc_int_vectors; 534 int_vect_start_address = CEDAR_SMC_INT_VECTOR_START; 535 int_vect_size = CEDAR_SMC_INT_VECTOR_SIZE; 536 break; 537 case CHIP_REDWOOD: 538 ucode_start_address = REDWOOD_SMC_UCODE_START; 539 ucode_size = REDWOOD_SMC_UCODE_SIZE; 540 int_vect = (const u8 *)&redwood_smc_int_vectors; 541 int_vect_start_address = REDWOOD_SMC_INT_VECTOR_START; 542 int_vect_size = REDWOOD_SMC_INT_VECTOR_SIZE; 543 break; 544 case CHIP_JUNIPER: 545 ucode_start_address = JUNIPER_SMC_UCODE_START; 546 ucode_size = JUNIPER_SMC_UCODE_SIZE; 547 int_vect = (const u8 *)&juniper_smc_int_vectors; 548 int_vect_start_address = JUNIPER_SMC_INT_VECTOR_START; 549 int_vect_size = JUNIPER_SMC_INT_VECTOR_SIZE; 550 break; 551 case CHIP_CYPRESS: 552 case CHIP_HEMLOCK: 553 ucode_start_address = CYPRESS_SMC_UCODE_START; 554 ucode_size = CYPRESS_SMC_UCODE_SIZE; 555 int_vect = (const u8 *)&cypress_smc_int_vectors; 556 int_vect_start_address = CYPRESS_SMC_INT_VECTOR_START; 557 int_vect_size = CYPRESS_SMC_INT_VECTOR_SIZE; 558 break; 559 case CHIP_BARTS: 560 ucode_start_address = BARTS_SMC_UCODE_START; 561 ucode_size = BARTS_SMC_UCODE_SIZE; 562 int_vect = (const u8 *)&barts_smc_int_vectors; 563 int_vect_start_address = BARTS_SMC_INT_VECTOR_START; 564 int_vect_size = BARTS_SMC_INT_VECTOR_SIZE; 565 break; 566 case CHIP_TURKS: 567 ucode_start_address = TURKS_SMC_UCODE_START; 568 ucode_size = TURKS_SMC_UCODE_SIZE; 569 int_vect = (const u8 *)&turks_smc_int_vectors; 570 int_vect_start_address = TURKS_SMC_INT_VECTOR_START; 571 int_vect_size = TURKS_SMC_INT_VECTOR_SIZE; 572 break; 573 case CHIP_CAICOS: 574 ucode_start_address = CAICOS_SMC_UCODE_START; 575 ucode_size = CAICOS_SMC_UCODE_SIZE; 576 int_vect = (const u8 *)&caicos_smc_int_vectors; 577 int_vect_start_address = CAICOS_SMC_INT_VECTOR_START; 578 int_vect_size = CAICOS_SMC_INT_VECTOR_SIZE; 579 break; 580 case CHIP_CAYMAN: 581 ucode_start_address = CAYMAN_SMC_UCODE_START; 582 ucode_size = CAYMAN_SMC_UCODE_SIZE; 583 int_vect = (const u8 *)&cayman_smc_int_vectors; 584 int_vect_start_address = CAYMAN_SMC_INT_VECTOR_START; 585 int_vect_size = CAYMAN_SMC_INT_VECTOR_SIZE; 586 break; 587 default: 588 DRM_ERROR("unknown asic in smc ucode loader\n"); 589 BUG(); 590 } 591 592 /* load the ucode */ 593 ucode_data = (const u8 *)rdev->smc_fw->data; 594 ret = rv770_copy_bytes_to_smc(rdev, ucode_start_address, 595 ucode_data, ucode_size, limit); 596 if (ret) 597 return ret; 598 599 /* set up the int vectors */ 600 ret = rv770_program_interrupt_vectors(rdev, int_vect_start_address, 601 int_vect, int_vect_size); 602 if (ret) 603 return ret; 604 605 return 0; 606} 607 608int rv770_read_smc_sram_dword(struct radeon_device *rdev, 609 u16 smc_address, u32 *value, u16 limit) 610{ 611 unsigned long flags; 612 int ret; 613 614 spin_lock_irqsave(&rdev->smc_idx_lock, flags); 615 ret = rv770_set_smc_sram_address(rdev, smc_address, limit); 616 if (ret == 0) 617 *value = RREG32(SMC_SRAM_DATA); 618 spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); 619 620 return ret; 621} 622 623int rv770_write_smc_sram_dword(struct radeon_device *rdev, 624 u16 smc_address, u32 value, u16 limit) 625{ 626 unsigned long flags; 627 int ret; 628 629 spin_lock_irqsave(&rdev->smc_idx_lock, flags); 630 ret = rv770_set_smc_sram_address(rdev, smc_address, limit); 631 if (ret == 0) 632 WREG32(SMC_SRAM_DATA, value); 633 spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); 634 635 return ret; 636} 637