Subversion Repositories Kolibri OS

Rev

Rev 5078 | 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 "sid.h"
  29. #include "ppsmc.h"
  30. #include "radeon_ucode.h"
  31. #include "sislands_smc.h"
  32.  
  33. static 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.  
  47. int 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.  
  107. done:
  108.         spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
  109.  
  110.         return ret;
  111. }
  112.  
  113. void 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.  
  122. void 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.  
  136. int 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.  
  143. void 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.  
  152. void 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.  
  161. bool 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.  
  172. PPSMC_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.  
  193. PPSMC_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.  
  211. int 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.  
  282. int 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.  
  297. int 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.