linux/drivers/gpu/drm/radeon/sumo_smc.c
<<
>>
Prefs
   1/*
   2 * Copyright 2012 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 */
  23
  24#include "radeon.h"
  25#include "sumod.h"
  26#include "sumo_dpm.h"
  27#include "ppsmc.h"
  28
  29#define SUMO_SMU_SERVICE_ROUTINE_PG_INIT        1
  30#define SUMO_SMU_SERVICE_ROUTINE_ALTVDDNB_NOTIFY  27
  31#define SUMO_SMU_SERVICE_ROUTINE_GFX_SRV_ID_20  20
  32
  33static void sumo_send_msg_to_smu(struct radeon_device *rdev, u32 id)
  34{
  35        u32 gfx_int_req;
  36        int i;
  37
  38        for (i = 0; i < rdev->usec_timeout; i++) {
  39                if (RREG32(GFX_INT_STATUS) & INT_DONE)
  40                        break;
  41                udelay(1);
  42        }
  43
  44        gfx_int_req = SERV_INDEX(id) | INT_REQ;
  45        WREG32(GFX_INT_REQ, gfx_int_req);
  46
  47        for (i = 0; i < rdev->usec_timeout; i++) {
  48                if (RREG32(GFX_INT_REQ) & INT_REQ)
  49                        break;
  50                udelay(1);
  51        }
  52
  53        for (i = 0; i < rdev->usec_timeout; i++) {
  54                if (RREG32(GFX_INT_STATUS) & INT_ACK)
  55                        break;
  56                udelay(1);
  57        }
  58
  59        for (i = 0; i < rdev->usec_timeout; i++) {
  60                if (RREG32(GFX_INT_STATUS) & INT_DONE)
  61                        break;
  62                udelay(1);
  63        }
  64
  65        gfx_int_req &= ~INT_REQ;
  66        WREG32(GFX_INT_REQ, gfx_int_req);
  67}
  68
  69void sumo_initialize_m3_arb(struct radeon_device *rdev)
  70{
  71        struct sumo_power_info *pi = sumo_get_pi(rdev);
  72        u32 i;
  73
  74        if (!pi->enable_dynamic_m3_arbiter)
  75                return;
  76
  77        for (i = 0; i < NUMBER_OF_M3ARB_PARAM_SETS; i++)
  78                WREG32_RCU(MCU_M3ARB_PARAMS + (i * 4),
  79                           pi->sys_info.csr_m3_arb_cntl_default[i]);
  80
  81        for (; i < NUMBER_OF_M3ARB_PARAM_SETS * 2; i++)
  82                WREG32_RCU(MCU_M3ARB_PARAMS + (i * 4),
  83                           pi->sys_info.csr_m3_arb_cntl_uvd[i % NUMBER_OF_M3ARB_PARAM_SETS]);
  84
  85        for (; i < NUMBER_OF_M3ARB_PARAM_SETS * 3; i++)
  86                WREG32_RCU(MCU_M3ARB_PARAMS + (i * 4),
  87                           pi->sys_info.csr_m3_arb_cntl_fs3d[i % NUMBER_OF_M3ARB_PARAM_SETS]);
  88}
  89
  90static bool sumo_is_alt_vddnb_supported(struct radeon_device *rdev)
  91{
  92        struct sumo_power_info *pi = sumo_get_pi(rdev);
  93        bool return_code = false;
  94
  95        if (!pi->enable_alt_vddnb)
  96                return return_code;
  97
  98        if ((rdev->family == CHIP_SUMO) || (rdev->family == CHIP_SUMO2)) {
  99                if (pi->fw_version >= 0x00010C00)
 100                        return_code = true;
 101        }
 102
 103        return return_code;
 104}
 105
 106void sumo_smu_notify_alt_vddnb_change(struct radeon_device *rdev,
 107                                      bool powersaving, bool force_nbps1)
 108{
 109        u32 param = 0;
 110
 111        if (!sumo_is_alt_vddnb_supported(rdev))
 112                return;
 113
 114        if (powersaving)
 115                param |= 1;
 116
 117        if (force_nbps1)
 118                param |= 2;
 119
 120        WREG32_RCU(RCU_ALTVDDNB_NOTIFY, param);
 121
 122        sumo_send_msg_to_smu(rdev, SUMO_SMU_SERVICE_ROUTINE_ALTVDDNB_NOTIFY);
 123}
 124
 125void sumo_smu_pg_init(struct radeon_device *rdev)
 126{
 127        sumo_send_msg_to_smu(rdev, SUMO_SMU_SERVICE_ROUTINE_PG_INIT);
 128}
 129
 130static u32 sumo_power_of_4(u32 unit)
 131{
 132        u32 ret = 1;
 133        u32 i;
 134
 135        for (i = 0; i < unit; i++)
 136                ret *= 4;
 137
 138        return ret;
 139}
 140
 141void sumo_enable_boost_timer(struct radeon_device *rdev)
 142{
 143        struct sumo_power_info *pi = sumo_get_pi(rdev);
 144        u32 period, unit, timer_value;
 145        u32 xclk = radeon_get_xclk(rdev);
 146
 147        unit = (RREG32_RCU(RCU_LCLK_SCALING_CNTL) & LCLK_SCALING_TIMER_PRESCALER_MASK)
 148                >> LCLK_SCALING_TIMER_PRESCALER_SHIFT;
 149
 150        period = 100 * (xclk / 100 / sumo_power_of_4(unit));
 151
 152        timer_value = (period << 16) | (unit << 4);
 153
 154        WREG32_RCU(RCU_GNB_PWR_REP_TIMER_CNTL, timer_value);
 155        WREG32_RCU(RCU_BOOST_MARGIN, pi->sys_info.sclk_dpm_boost_margin);
 156        WREG32_RCU(RCU_THROTTLE_MARGIN, pi->sys_info.sclk_dpm_throttle_margin);
 157        WREG32_RCU(GNB_TDP_LIMIT, pi->sys_info.gnb_tdp_limit);
 158        WREG32_RCU(RCU_SclkDpmTdpLimitPG, pi->sys_info.sclk_dpm_tdp_limit_pg);
 159
 160        sumo_send_msg_to_smu(rdev, SUMO_SMU_SERVICE_ROUTINE_GFX_SRV_ID_20);
 161}
 162
 163void sumo_set_tdp_limit(struct radeon_device *rdev, u32 index, u32 tdp_limit)
 164{
 165        u32 regoffset = 0;
 166        u32 shift = 0;
 167        u32 mask = 0xFFF;
 168        u32 sclk_dpm_tdp_limit;
 169
 170        switch (index) {
 171        case 0:
 172                regoffset = RCU_SclkDpmTdpLimit01;
 173                shift = 16;
 174                break;
 175        case 1:
 176                regoffset = RCU_SclkDpmTdpLimit01;
 177                shift = 0;
 178                break;
 179        case 2:
 180                regoffset = RCU_SclkDpmTdpLimit23;
 181                shift = 16;
 182                break;
 183        case 3:
 184                regoffset = RCU_SclkDpmTdpLimit23;
 185                shift = 0;
 186                break;
 187        case 4:
 188                regoffset = RCU_SclkDpmTdpLimit47;
 189                shift = 16;
 190                break;
 191        case 7:
 192                regoffset = RCU_SclkDpmTdpLimit47;
 193                shift = 0;
 194                break;
 195        default:
 196                break;
 197        }
 198
 199        sclk_dpm_tdp_limit = RREG32_RCU(regoffset);
 200        sclk_dpm_tdp_limit &= ~(mask << shift);
 201        sclk_dpm_tdp_limit |= (tdp_limit << shift);
 202        WREG32_RCU(regoffset, sclk_dpm_tdp_limit);
 203}
 204
 205void sumo_boost_state_enable(struct radeon_device *rdev, bool enable)
 206{
 207        u32 boost_disable = RREG32_RCU(RCU_GPU_BOOST_DISABLE);
 208
 209        boost_disable &= 0xFFFFFFFE;
 210        boost_disable |= (enable ? 0 : 1);
 211        WREG32_RCU(RCU_GPU_BOOST_DISABLE, boost_disable);
 212}
 213
 214u32 sumo_get_running_fw_version(struct radeon_device *rdev)
 215{
 216        return RREG32_RCU(RCU_FW_VERSION);
 217}
 218
 219