Subversion Repositories Kolibri OS

Rev

Rev 5271 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  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 "cikd.h"
  29. #include "ppsmc.h"
  30. #include "radeon_ucode.h"
  31. #include "ci_dpm.h"
  32.  
  33. static int ci_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.  
  47. int ci_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.         u32 data, original_data;
  53.         u32 addr;
  54.         u32 extra_shift;
  55.         int ret = 0;
  56.  
  57.         if (smc_start_address & 3)
  58.                 return -EINVAL;
  59.         if ((smc_start_address + byte_count) > limit)
  60.                 return -EINVAL;
  61.  
  62.         addr = smc_start_address;
  63.  
  64.         spin_lock_irqsave(&rdev->smc_idx_lock, flags);
  65.         while (byte_count >= 4) {
  66.                 /* SMC address space is BE */
  67.                 data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
  68.  
  69.                 ret = ci_set_smc_sram_address(rdev, addr, limit);
  70.                 if (ret)
  71.                         goto done;
  72.  
  73.                 WREG32(SMC_IND_DATA_0, data);
  74.  
  75.                 src += 4;
  76.                 byte_count -= 4;
  77.                 addr += 4;
  78.         }
  79.  
  80.         /* RMW for the final bytes */
  81.         if (byte_count > 0) {
  82.                 data = 0;
  83.  
  84.                 ret = ci_set_smc_sram_address(rdev, addr, limit);
  85.                 if (ret)
  86.                         goto done;
  87.  
  88.                 original_data = RREG32(SMC_IND_DATA_0);
  89.  
  90.                 extra_shift = 8 * (4 - byte_count);
  91.  
  92.                 while (byte_count > 0) {
  93.                         data = (data << 8) + *src++;
  94.                         byte_count--;
  95.                 }
  96.  
  97.                 data <<= extra_shift;
  98.  
  99.                 data |= (original_data & ~((~0UL) << extra_shift));
  100.  
  101.                 ret = ci_set_smc_sram_address(rdev, addr, limit);
  102.                 if (ret)
  103.                         goto done;
  104.  
  105.                 WREG32(SMC_IND_DATA_0, data);
  106.         }
  107.  
  108. done:
  109.         spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
  110.  
  111.         return ret;
  112. }
  113.  
  114. void ci_start_smc(struct radeon_device *rdev)
  115. {
  116.         u32 tmp = RREG32_SMC(SMC_SYSCON_RESET_CNTL);
  117.  
  118.         tmp &= ~RST_REG;
  119.         WREG32_SMC(SMC_SYSCON_RESET_CNTL, tmp);
  120. }
  121.  
  122. void ci_reset_smc(struct radeon_device *rdev)
  123. {
  124.         u32 tmp = RREG32_SMC(SMC_SYSCON_RESET_CNTL);
  125.  
  126.         tmp |= RST_REG;
  127.         WREG32_SMC(SMC_SYSCON_RESET_CNTL, tmp);
  128. }
  129.  
  130. int ci_program_jump_on_start(struct radeon_device *rdev)
  131. {
  132.         static const u8 data[] = { 0xE0, 0x00, 0x80, 0x40 };
  133.  
  134.         return ci_copy_bytes_to_smc(rdev, 0x0, data, 4, sizeof(data)+1);
  135. }
  136.  
  137. void ci_stop_smc_clock(struct radeon_device *rdev)
  138. {
  139.         u32 tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
  140.  
  141.         tmp |= CK_DISABLE;
  142.  
  143.         WREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0, tmp);
  144. }
  145.  
  146. void ci_start_smc_clock(struct radeon_device *rdev)
  147. {
  148.         u32 tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
  149.  
  150.         tmp &= ~CK_DISABLE;
  151.  
  152.         WREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0, tmp);
  153. }
  154.  
  155. bool ci_is_smc_running(struct radeon_device *rdev)
  156. {
  157.         u32 clk = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
  158.         u32 pc_c = RREG32_SMC(SMC_PC_C);
  159.  
  160.         if (!(clk & CK_DISABLE) && (0x20100 <= pc_c))
  161.                 return true;
  162.  
  163.         return false;
  164. }
  165.  
  166. PPSMC_Result ci_send_msg_to_smc(struct radeon_device *rdev, PPSMC_Msg msg)
  167. {
  168.         u32 tmp;
  169.         int i;
  170.  
  171.         if (!ci_is_smc_running(rdev))
  172.                 return PPSMC_Result_Failed;
  173.  
  174.         WREG32(SMC_MESSAGE_0, msg);
  175.  
  176.         for (i = 0; i < rdev->usec_timeout; i++) {
  177.                 tmp = RREG32(SMC_RESP_0);
  178.                 if (tmp != 0)
  179.                         break;
  180.                 udelay(1);
  181.         }
  182.         tmp = RREG32(SMC_RESP_0);
  183.  
  184.         return (PPSMC_Result)tmp;
  185. }
  186.  
  187. #if 0
  188. PPSMC_Result ci_wait_for_smc_inactive(struct radeon_device *rdev)
  189. {
  190.         u32 tmp;
  191.         int i;
  192.  
  193.         if (!ci_is_smc_running(rdev))
  194.                 return PPSMC_Result_OK;
  195.  
  196.         for (i = 0; i < rdev->usec_timeout; i++) {
  197.                 tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
  198.                 if ((tmp & CKEN) == 0)
  199.                         break;
  200.                 udelay(1);
  201.         }
  202.  
  203.         return PPSMC_Result_OK;
  204. }
  205. #endif
  206.  
  207. int ci_load_smc_ucode(struct radeon_device *rdev, u32 limit)
  208. {
  209.         unsigned long flags;
  210.         u32 ucode_start_address;
  211.         u32 ucode_size;
  212.         const u8 *src;
  213.         u32 data;
  214.  
  215.         if (!rdev->smc_fw)
  216.                 return -EINVAL;
  217.  
  218.         if (rdev->new_fw) {
  219.                 const struct smc_firmware_header_v1_0 *hdr =
  220.                         (const struct smc_firmware_header_v1_0 *)rdev->smc_fw->data;
  221.  
  222.                 radeon_ucode_print_smc_hdr(&hdr->header);
  223.  
  224.                 ucode_start_address = le32_to_cpu(hdr->ucode_start_addr);
  225.                 ucode_size = le32_to_cpu(hdr->header.ucode_size_bytes);
  226.                 src = (const u8 *)
  227.                         (rdev->smc_fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes));
  228.         } else {
  229.                 switch (rdev->family) {
  230.                 case CHIP_BONAIRE:
  231.                         ucode_start_address = BONAIRE_SMC_UCODE_START;
  232.                         ucode_size = BONAIRE_SMC_UCODE_SIZE;
  233.                         break;
  234.                 case CHIP_HAWAII:
  235.                         ucode_start_address = HAWAII_SMC_UCODE_START;
  236.                         ucode_size = HAWAII_SMC_UCODE_SIZE;
  237.                         break;
  238.                 default:
  239.                         DRM_ERROR("unknown asic in smc ucode loader\n");
  240.                         BUG();
  241.                 }
  242.  
  243.                 src = (const u8 *)rdev->smc_fw->data;
  244.         }
  245.  
  246.         if (ucode_size & 3)
  247.                 return -EINVAL;
  248.  
  249.         spin_lock_irqsave(&rdev->smc_idx_lock, flags);
  250.         WREG32(SMC_IND_INDEX_0, ucode_start_address);
  251.         WREG32_P(SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, ~AUTO_INCREMENT_IND_0);
  252.         while (ucode_size >= 4) {
  253.                 /* SMC address space is BE */
  254.                 data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
  255.  
  256.                 WREG32(SMC_IND_DATA_0, data);
  257.  
  258.                 src += 4;
  259.                 ucode_size -= 4;
  260.         }
  261.         WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0);
  262.         spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
  263.  
  264.         return 0;
  265. }
  266.  
  267. int ci_read_smc_sram_dword(struct radeon_device *rdev,
  268.                            u32 smc_address, u32 *value, u32 limit)
  269. {
  270.         unsigned long flags;
  271.         int ret;
  272.  
  273.         spin_lock_irqsave(&rdev->smc_idx_lock, flags);
  274.         ret = ci_set_smc_sram_address(rdev, smc_address, limit);
  275.         if (ret == 0)
  276.                 *value = RREG32(SMC_IND_DATA_0);
  277.         spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
  278.  
  279.         return ret;
  280. }
  281.  
  282. int ci_write_smc_sram_dword(struct radeon_device *rdev,
  283.                             u32 smc_address, u32 value, u32 limit)
  284. {
  285.         unsigned long flags;
  286.         int ret;
  287.  
  288.         spin_lock_irqsave(&rdev->smc_idx_lock, flags);
  289.         ret = ci_set_smc_sram_address(rdev, smc_address, limit);
  290.         if (ret == 0)
  291.                 WREG32(SMC_IND_DATA_0, value);
  292.         spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
  293.  
  294.         return ret;
  295. }
  296.