linux/drivers/gpu/drm/radeon/rv770_smc.c
<<
>>
Prefs
   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
  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
  37static 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
  57static 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
  77static 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
  97static 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
 117static 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
 137static 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
 157static 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
 177static 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
 197static 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
 217static 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
 237static 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
 257static 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
 277static 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
 295int 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
 356done:
 357        spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
 358
 359        return ret;
 360}
 361
 362static 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
 392void rv770_start_smc(struct radeon_device *rdev)
 393{
 394        WREG32_P(SMC_IO, SMC_RST_N, ~SMC_RST_N);
 395}
 396
 397void rv770_reset_smc(struct radeon_device *rdev)
 398{
 399        WREG32_P(SMC_IO, 0, ~SMC_RST_N);
 400}
 401
 402void rv770_stop_smc_clock(struct radeon_device *rdev)
 403{
 404        WREG32_P(SMC_IO, 0, ~SMC_CLK_EN);
 405}
 406
 407void rv770_start_smc_clock(struct radeon_device *rdev)
 408{
 409        WREG32_P(SMC_IO, SMC_CLK_EN, ~SMC_CLK_EN);
 410}
 411
 412bool 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
 424PPSMC_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
 450PPSMC_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
 467static 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
 480int 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
 603int 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
 618int 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