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