Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2011 Advanced Micro Devices, Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  * Authors: Alex Deucher
0023  */
0024 
0025 #include <linux/firmware.h>
0026 
0027 #include "radeon.h"
0028 #include "cikd.h"
0029 #include "ppsmc.h"
0030 #include "radeon_ucode.h"
0031 #include "ci_dpm.h"
0032 
0033 static int ci_set_smc_sram_address(struct radeon_device *rdev,
0034                    u32 smc_address, u32 limit)
0035 {
0036     if (smc_address & 3)
0037         return -EINVAL;
0038     if ((smc_address + 3) > limit)
0039         return -EINVAL;
0040 
0041     WREG32(SMC_IND_INDEX_0, smc_address);
0042     WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0);
0043 
0044     return 0;
0045 }
0046 
0047 int ci_copy_bytes_to_smc(struct radeon_device *rdev,
0048              u32 smc_start_address,
0049              const u8 *src, u32 byte_count, u32 limit)
0050 {
0051     unsigned long flags;
0052     u32 data, original_data;
0053     u32 addr;
0054     u32 extra_shift;
0055     int ret = 0;
0056 
0057     if (smc_start_address & 3)
0058         return -EINVAL;
0059     if ((smc_start_address + byte_count) > limit)
0060         return -EINVAL;
0061 
0062     addr = smc_start_address;
0063 
0064     spin_lock_irqsave(&rdev->smc_idx_lock, flags);
0065     while (byte_count >= 4) {
0066         /* SMC address space is BE */
0067         data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
0068 
0069         ret = ci_set_smc_sram_address(rdev, addr, limit);
0070         if (ret)
0071             goto done;
0072 
0073         WREG32(SMC_IND_DATA_0, data);
0074 
0075         src += 4;
0076         byte_count -= 4;
0077         addr += 4;
0078     }
0079 
0080     /* RMW for the final bytes */
0081     if (byte_count > 0) {
0082         data = 0;
0083 
0084         ret = ci_set_smc_sram_address(rdev, addr, limit);
0085         if (ret)
0086             goto done;
0087 
0088         original_data = RREG32(SMC_IND_DATA_0);
0089 
0090         extra_shift = 8 * (4 - byte_count);
0091 
0092         while (byte_count > 0) {
0093             data = (data << 8) + *src++;
0094             byte_count--;
0095         }
0096 
0097         data <<= extra_shift;
0098 
0099         data |= (original_data & ~((~0UL) << extra_shift));
0100 
0101         ret = ci_set_smc_sram_address(rdev, addr, limit);
0102         if (ret)
0103             goto done;
0104 
0105         WREG32(SMC_IND_DATA_0, data);
0106     }
0107 
0108 done:
0109     spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
0110 
0111     return ret;
0112 }
0113 
0114 void ci_start_smc(struct radeon_device *rdev)
0115 {
0116     u32 tmp = RREG32_SMC(SMC_SYSCON_RESET_CNTL);
0117 
0118     tmp &= ~RST_REG;
0119     WREG32_SMC(SMC_SYSCON_RESET_CNTL, tmp);
0120 }
0121 
0122 void ci_reset_smc(struct radeon_device *rdev)
0123 {
0124     u32 tmp = RREG32_SMC(SMC_SYSCON_RESET_CNTL);
0125 
0126     tmp |= RST_REG;
0127     WREG32_SMC(SMC_SYSCON_RESET_CNTL, tmp);
0128 }
0129 
0130 int ci_program_jump_on_start(struct radeon_device *rdev)
0131 {
0132     static const u8 data[] = { 0xE0, 0x00, 0x80, 0x40 };
0133 
0134     return ci_copy_bytes_to_smc(rdev, 0x0, data, 4, sizeof(data)+1);
0135 }
0136 
0137 void ci_stop_smc_clock(struct radeon_device *rdev)
0138 {
0139     u32 tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
0140 
0141     tmp |= CK_DISABLE;
0142 
0143     WREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0, tmp);
0144 }
0145 
0146 void ci_start_smc_clock(struct radeon_device *rdev)
0147 {
0148     u32 tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
0149 
0150     tmp &= ~CK_DISABLE;
0151 
0152     WREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0, tmp);
0153 }
0154 
0155 bool ci_is_smc_running(struct radeon_device *rdev)
0156 {
0157     u32 clk = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
0158     u32 pc_c = RREG32_SMC(SMC_PC_C);
0159 
0160     if (!(clk & CK_DISABLE) && (0x20100 <= pc_c))
0161         return true;
0162 
0163     return false;
0164 }
0165 
0166 #if 0
0167 PPSMC_Result ci_wait_for_smc_inactive(struct radeon_device *rdev)
0168 {
0169     u32 tmp;
0170     int i;
0171 
0172     if (!ci_is_smc_running(rdev))
0173         return PPSMC_Result_OK;
0174 
0175     for (i = 0; i < rdev->usec_timeout; i++) {
0176         tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
0177         if ((tmp & CKEN) == 0)
0178             break;
0179         udelay(1);
0180     }
0181 
0182     return PPSMC_Result_OK;
0183 }
0184 #endif
0185 
0186 int ci_load_smc_ucode(struct radeon_device *rdev, u32 limit)
0187 {
0188     unsigned long flags;
0189     u32 ucode_start_address;
0190     u32 ucode_size;
0191     const u8 *src;
0192     u32 data;
0193 
0194     if (!rdev->smc_fw)
0195         return -EINVAL;
0196 
0197     if (rdev->new_fw) {
0198         const struct smc_firmware_header_v1_0 *hdr =
0199             (const struct smc_firmware_header_v1_0 *)rdev->smc_fw->data;
0200 
0201         radeon_ucode_print_smc_hdr(&hdr->header);
0202 
0203         ucode_start_address = le32_to_cpu(hdr->ucode_start_addr);
0204         ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes);
0205         src = (const u8 *)
0206             (rdev->smc_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes));
0207     } else {
0208         switch (rdev->family) {
0209         case CHIP_BONAIRE:
0210             ucode_start_address = BONAIRE_SMC_UCODE_START;
0211             ucode_size = BONAIRE_SMC_UCODE_SIZE;
0212             break;
0213         case CHIP_HAWAII:
0214             ucode_start_address = HAWAII_SMC_UCODE_START;
0215             ucode_size = HAWAII_SMC_UCODE_SIZE;
0216             break;
0217         default:
0218             DRM_ERROR("unknown asic in smc ucode loader\n");
0219             BUG();
0220         }
0221 
0222         src = (const u8 *)rdev->smc_fw->data;
0223     }
0224 
0225     if (ucode_size & 3)
0226         return -EINVAL;
0227 
0228     spin_lock_irqsave(&rdev->smc_idx_lock, flags);
0229     WREG32(SMC_IND_INDEX_0, ucode_start_address);
0230     WREG32_P(SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, ~AUTO_INCREMENT_IND_0);
0231     while (ucode_size >= 4) {
0232         /* SMC address space is BE */
0233         data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
0234 
0235         WREG32(SMC_IND_DATA_0, data);
0236 
0237         src += 4;
0238         ucode_size -= 4;
0239     }
0240     WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0);
0241     spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
0242 
0243     return 0;
0244 }
0245 
0246 int ci_read_smc_sram_dword(struct radeon_device *rdev,
0247                u32 smc_address, u32 *value, u32 limit)
0248 {
0249     unsigned long flags;
0250     int ret;
0251 
0252     spin_lock_irqsave(&rdev->smc_idx_lock, flags);
0253     ret = ci_set_smc_sram_address(rdev, smc_address, limit);
0254     if (ret == 0)
0255         *value = RREG32(SMC_IND_DATA_0);
0256     spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
0257 
0258     return ret;
0259 }
0260 
0261 int ci_write_smc_sram_dword(struct radeon_device *rdev,
0262                 u32 smc_address, u32 value, u32 limit)
0263 {
0264     unsigned long flags;
0265     int ret;
0266 
0267     spin_lock_irqsave(&rdev->smc_idx_lock, flags);
0268     ret = ci_set_smc_sram_address(rdev, smc_address, limit);
0269     if (ret == 0)
0270         WREG32(SMC_IND_DATA_0, value);
0271     spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
0272 
0273     return ret;
0274 }