Subversion Repositories Kolibri OS

Rev

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