linux/drivers/gpu/drm/radeon/si_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#include "drmP.h"
  27#include "radeon.h"
  28#include "sid.h"
  29#include "ppsmc.h"
  30#include "radeon_ucode.h"
  31#include "sislands_smc.h"
  32
  33static int si_set_smc_sram_address(struct radeon_device *rdev,
  34                                   u32 smc_address, u32 limit)
  35{
  36        if (smc_address & 3)
  37                return -EINVAL;
  38        if ((smc_address + 3) > limit)
  39                return -EINVAL;
  40
  41        WREG32(SMC_IND_INDEX_0, smc_address);
  42        WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0);
  43
  44        return 0;
  45}
  46
  47int si_copy_bytes_to_smc(struct radeon_device *rdev,
  48                         u32 smc_start_address,
  49                         const u8 *src, u32 byte_count, u32 limit)
  50{
  51        unsigned long flags;
  52        int ret = 0;
  53        u32 data, original_data, addr, extra_shift;
  54
  55        if (smc_start_address & 3)
  56                return -EINVAL;
  57        if ((smc_start_address + byte_count) > limit)
  58                return -EINVAL;
  59
  60        addr = smc_start_address;
  61
  62        spin_lock_irqsave(&rdev->smc_idx_lock, flags);
  63        while (byte_count >= 4) {
  64                /* SMC address space is BE */
  65                data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
  66
  67                ret = si_set_smc_sram_address(rdev, addr, limit);
  68                if (ret)
  69                        goto done;
  70
  71                WREG32(SMC_IND_DATA_0, data);
  72
  73                src += 4;
  74                byte_count -= 4;
  75                addr += 4;
  76        }
  77
  78        /* RMW for the final bytes */
  79        if (byte_count > 0) {
  80                data = 0;
  81
  82                ret = si_set_smc_sram_address(rdev, addr, limit);
  83                if (ret)
  84                        goto done;
  85
  86                original_data = RREG32(SMC_IND_DATA_0);
  87
  88                extra_shift = 8 * (4 - byte_count);
  89
  90                while (byte_count > 0) {
  91                        /* SMC address space is BE */
  92                        data = (data << 8) + *src++;
  93                        byte_count--;
  94                }
  95
  96                data <<= extra_shift;
  97
  98                data |= (original_data & ~((~0UL) << extra_shift));
  99
 100                ret = si_set_smc_sram_address(rdev, addr, limit);
 101                if (ret)
 102                        goto done;
 103
 104                WREG32(SMC_IND_DATA_0, data);
 105        }
 106
 107done:
 108        spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
 109
 110        return ret;
 111}
 112
 113void si_start_smc(struct radeon_device *rdev)
 114{
 115        u32 tmp = RREG32_SMC(SMC_SYSCON_RESET_CNTL);
 116
 117        tmp &= ~RST_REG;
 118
 119        WREG32_SMC(SMC_SYSCON_RESET_CNTL, tmp);
 120}
 121
 122void si_reset_smc(struct radeon_device *rdev)
 123{
 124        u32 tmp;
 125
 126        RREG32(CB_CGTT_SCLK_CTRL);
 127        RREG32(CB_CGTT_SCLK_CTRL);
 128        RREG32(CB_CGTT_SCLK_CTRL);
 129        RREG32(CB_CGTT_SCLK_CTRL);
 130
 131        tmp = RREG32_SMC(SMC_SYSCON_RESET_CNTL);
 132        tmp |= RST_REG;
 133        WREG32_SMC(SMC_SYSCON_RESET_CNTL, tmp);
 134}
 135
 136int si_program_jump_on_start(struct radeon_device *rdev)
 137{
 138        static const u8 data[] = { 0x0E, 0x00, 0x40, 0x40 };
 139
 140        return si_copy_bytes_to_smc(rdev, 0x0, data, 4, sizeof(data)+1);
 141}
 142
 143void si_stop_smc_clock(struct radeon_device *rdev)
 144{
 145        u32 tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
 146
 147        tmp |= CK_DISABLE;
 148
 149        WREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0, tmp);
 150}
 151
 152void si_start_smc_clock(struct radeon_device *rdev)
 153{
 154        u32 tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
 155
 156        tmp &= ~CK_DISABLE;
 157
 158        WREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0, tmp);
 159}
 160
 161bool si_is_smc_running(struct radeon_device *rdev)
 162{
 163        u32 rst = RREG32_SMC(SMC_SYSCON_RESET_CNTL);
 164        u32 clk = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
 165
 166        if (!(rst & RST_REG) && !(clk & CK_DISABLE))
 167                return true;
 168
 169        return false;
 170}
 171
 172PPSMC_Result si_send_msg_to_smc(struct radeon_device *rdev, PPSMC_Msg msg)
 173{
 174        u32 tmp;
 175        int i;
 176
 177        if (!si_is_smc_running(rdev))
 178                return PPSMC_Result_Failed;
 179
 180        WREG32(SMC_MESSAGE_0, msg);
 181
 182        for (i = 0; i < rdev->usec_timeout; i++) {
 183                tmp = RREG32(SMC_RESP_0);
 184                if (tmp != 0)
 185                        break;
 186                udelay(1);
 187        }
 188        tmp = RREG32(SMC_RESP_0);
 189
 190        return (PPSMC_Result)tmp;
 191}
 192
 193PPSMC_Result si_wait_for_smc_inactive(struct radeon_device *rdev)
 194{
 195        u32 tmp;
 196        int i;
 197
 198        if (!si_is_smc_running(rdev))
 199                return PPSMC_Result_OK;
 200
 201        for (i = 0; i < rdev->usec_timeout; i++) {
 202                tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
 203                if ((tmp & CKEN) == 0)
 204                        break;
 205                udelay(1);
 206        }
 207
 208        return PPSMC_Result_OK;
 209}
 210
 211int si_load_smc_ucode(struct radeon_device *rdev, u32 limit)
 212{
 213        unsigned long flags;
 214        u32 ucode_start_address;
 215        u32 ucode_size;
 216        const u8 *src;
 217        u32 data;
 218
 219        if (!rdev->smc_fw)
 220                return -EINVAL;
 221
 222        if (rdev->new_fw) {
 223                const struct smc_firmware_header_v1_0 *hdr =
 224                        (const struct smc_firmware_header_v1_0 *)rdev->smc_fw->data;
 225
 226                radeon_ucode_print_smc_hdr(&hdr->header);
 227
 228                ucode_start_address = le32_to_cpu(hdr->ucode_start_addr);
 229                ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes);
 230                src = (const u8 *)
 231                        (rdev->smc_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes));
 232        } else {
 233                switch (rdev->family) {
 234                case CHIP_TAHITI:
 235                        ucode_start_address = TAHITI_SMC_UCODE_START;
 236                        ucode_size = TAHITI_SMC_UCODE_SIZE;
 237                        break;
 238                case CHIP_PITCAIRN:
 239                        ucode_start_address = PITCAIRN_SMC_UCODE_START;
 240                        ucode_size = PITCAIRN_SMC_UCODE_SIZE;
 241                        break;
 242                case CHIP_VERDE:
 243                        ucode_start_address = VERDE_SMC_UCODE_START;
 244                        ucode_size = VERDE_SMC_UCODE_SIZE;
 245                        break;
 246                case CHIP_OLAND:
 247                        ucode_start_address = OLAND_SMC_UCODE_START;
 248                        ucode_size = OLAND_SMC_UCODE_SIZE;
 249                        break;
 250                case CHIP_HAINAN:
 251                        ucode_start_address = HAINAN_SMC_UCODE_START;
 252                        ucode_size = HAINAN_SMC_UCODE_SIZE;
 253                        break;
 254                default:
 255                        DRM_ERROR("unknown asic in smc ucode loader\n");
 256                        BUG();
 257                }
 258                src = (const u8 *)rdev->smc_fw->data;
 259        }
 260
 261        if (ucode_size & 3)
 262                return -EINVAL;
 263
 264        spin_lock_irqsave(&rdev->smc_idx_lock, flags);
 265        WREG32(SMC_IND_INDEX_0, ucode_start_address);
 266        WREG32_P(SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, ~AUTO_INCREMENT_IND_0);
 267        while (ucode_size >= 4) {
 268                /* SMC address space is BE */
 269                data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
 270
 271                WREG32(SMC_IND_DATA_0, data);
 272
 273                src += 4;
 274                ucode_size -= 4;
 275        }
 276        WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0);
 277        spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
 278
 279        return 0;
 280}
 281
 282int si_read_smc_sram_dword(struct radeon_device *rdev, u32 smc_address,
 283                           u32 *value, u32 limit)
 284{
 285        unsigned long flags;
 286        int ret;
 287
 288        spin_lock_irqsave(&rdev->smc_idx_lock, flags);
 289        ret = si_set_smc_sram_address(rdev, smc_address, limit);
 290        if (ret == 0)
 291                *value = RREG32(SMC_IND_DATA_0);
 292        spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
 293
 294        return ret;
 295}
 296
 297int si_write_smc_sram_dword(struct radeon_device *rdev, u32 smc_address,
 298                            u32 value, u32 limit)
 299{
 300        unsigned long flags;
 301        int ret;
 302
 303        spin_lock_irqsave(&rdev->smc_idx_lock, flags);
 304        ret = si_set_smc_sram_address(rdev, smc_address, limit);
 305        if (ret == 0)
 306                WREG32(SMC_IND_DATA_0, value);
 307        spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
 308
 309        return ret;
 310}
 311