msm: kgsl: restructure GPU power initialization
Move target specific initialization and setup into target specific init functions. The change is required to port the GPU driver to support future generation GPUs. CRs-Fixed: 1053516 Change-Id: I808e247669fab61a6a64131858fe2f9e19754242 Signed-off-by: George Shen <sqiao@codeaurora.org>
This commit is contained in:
parent
1fac7f53bd
commit
19baa2bf45
4 changed files with 160 additions and 159 deletions
|
@ -1242,86 +1242,6 @@ static bool regulators_left_on(struct kgsl_device *device)
|
|||
return false;
|
||||
}
|
||||
|
||||
static void _setup_throttling_counters(struct adreno_device *adreno_dev)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
if (!adreno_is_a540(adreno_dev))
|
||||
return;
|
||||
|
||||
if (!ADRENO_FEATURE(adreno_dev, ADRENO_GPMU))
|
||||
return;
|
||||
|
||||
for (i = 0; i < ADRENO_GPMU_THROTTLE_COUNTERS; i++) {
|
||||
/* reset throttled cycles ivalue */
|
||||
adreno_dev->busy_data.throttle_cycles[i] = 0;
|
||||
|
||||
if (adreno_dev->gpmu_throttle_counters[i] != 0)
|
||||
continue;
|
||||
ret = adreno_perfcounter_get(adreno_dev,
|
||||
KGSL_PERFCOUNTER_GROUP_GPMU_PWR,
|
||||
ADRENO_GPMU_THROTTLE_COUNTERS_BASE_REG + i,
|
||||
&adreno_dev->gpmu_throttle_counters[i],
|
||||
NULL,
|
||||
PERFCOUNTER_FLAG_KERNEL);
|
||||
WARN_ONCE(ret, "Unable to get clock throttling counter %x\n",
|
||||
ADRENO_GPMU_THROTTLE_COUNTERS_BASE_REG + i);
|
||||
}
|
||||
}
|
||||
|
||||
/* FW driven idle 10% throttle */
|
||||
#define IDLE_10PCT 0
|
||||
/* number of cycles when clock is throttled by 50% (CRC) */
|
||||
#define CRC_50PCT 1
|
||||
/* number of cycles when clock is throttled by more than 50% (CRC) */
|
||||
#define CRC_MORE50PCT 2
|
||||
/* number of cycles when clock is throttle by less than 50% (CRC) */
|
||||
#define CRC_LESS50PCT 3
|
||||
|
||||
static uint64_t _read_throttling_counters(struct adreno_device *adreno_dev)
|
||||
{
|
||||
int i, adj;
|
||||
uint32_t th[ADRENO_GPMU_THROTTLE_COUNTERS];
|
||||
struct adreno_busy_data *busy = &adreno_dev->busy_data;
|
||||
|
||||
if (!adreno_is_a540(adreno_dev))
|
||||
return 0;
|
||||
|
||||
if (!ADRENO_FEATURE(adreno_dev, ADRENO_GPMU))
|
||||
return 0;
|
||||
|
||||
if (!test_bit(ADRENO_THROTTLING_CTRL, &adreno_dev->pwrctrl_flag))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < ADRENO_GPMU_THROTTLE_COUNTERS; i++) {
|
||||
if (!adreno_dev->gpmu_throttle_counters[i])
|
||||
return 0;
|
||||
|
||||
th[i] = counter_delta(KGSL_DEVICE(adreno_dev),
|
||||
adreno_dev->gpmu_throttle_counters[i],
|
||||
&busy->throttle_cycles[i]);
|
||||
}
|
||||
adj = th[CRC_MORE50PCT] - th[IDLE_10PCT];
|
||||
adj = th[CRC_50PCT] + th[CRC_LESS50PCT] / 3 + (adj < 0 ? 0 : adj) * 3;
|
||||
|
||||
trace_kgsl_clock_throttling(
|
||||
th[IDLE_10PCT], th[CRC_50PCT],
|
||||
th[CRC_MORE50PCT], th[CRC_LESS50PCT],
|
||||
adj);
|
||||
return adj;
|
||||
}
|
||||
|
||||
static void _update_threshold_count(struct adreno_device *adreno_dev,
|
||||
uint64_t adj)
|
||||
{
|
||||
if (adreno_is_a530(adreno_dev))
|
||||
kgsl_regread(KGSL_DEVICE(adreno_dev),
|
||||
adreno_dev->lm_threshold_count,
|
||||
&adreno_dev->lm_threshold_cross);
|
||||
else if (adreno_is_a540(adreno_dev))
|
||||
adreno_dev->lm_threshold_cross = adj;
|
||||
}
|
||||
|
||||
static void _set_secvid(struct kgsl_device *device)
|
||||
{
|
||||
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
|
||||
|
@ -1418,8 +1338,8 @@ static int _adreno_start(struct adreno_device *adreno_dev)
|
|||
}
|
||||
}
|
||||
|
||||
if (device->pwrctrl.bus_control) {
|
||||
|
||||
if (device->pwrctrl.bus_control) {
|
||||
/* VBIF waiting for RAM */
|
||||
if (adreno_dev->starved_ram_lo == 0) {
|
||||
ret = adreno_perfcounter_get(adreno_dev,
|
||||
|
@ -1455,20 +1375,6 @@ static int _adreno_start(struct adreno_device *adreno_dev)
|
|||
adreno_dev->busy_data.vbif_ram_cycles = 0;
|
||||
adreno_dev->busy_data.vbif_starved_ram = 0;
|
||||
|
||||
if (adreno_is_a530(adreno_dev) && ADRENO_FEATURE(adreno_dev, ADRENO_LM)
|
||||
&& adreno_dev->lm_threshold_count == 0) {
|
||||
|
||||
ret = adreno_perfcounter_get(adreno_dev,
|
||||
KGSL_PERFCOUNTER_GROUP_GPMU_PWR, 27,
|
||||
&adreno_dev->lm_threshold_count, NULL,
|
||||
PERFCOUNTER_FLAG_KERNEL);
|
||||
/* Ignore noncritical ret - used for debugfs */
|
||||
if (ret)
|
||||
adreno_dev->lm_threshold_count = 0;
|
||||
}
|
||||
|
||||
_setup_throttling_counters(adreno_dev);
|
||||
|
||||
/* Restore performance counter registers with saved values */
|
||||
adreno_perfcounter_restore(adreno_dev);
|
||||
|
||||
|
@ -2580,27 +2486,6 @@ static inline s64 adreno_ticks_to_us(u32 ticks, u32 freq)
|
|||
return ticks / freq;
|
||||
}
|
||||
|
||||
static unsigned int counter_delta(struct kgsl_device *device,
|
||||
unsigned int reg, unsigned int *counter)
|
||||
{
|
||||
unsigned int val;
|
||||
unsigned int ret = 0;
|
||||
|
||||
/* Read the value */
|
||||
kgsl_regread(device, reg, &val);
|
||||
|
||||
/* Return 0 for the first read */
|
||||
if (*counter != 0) {
|
||||
if (val < *counter)
|
||||
ret = (0xFFFFFFFF - *counter) + val;
|
||||
else
|
||||
ret = val - *counter;
|
||||
}
|
||||
|
||||
*counter = val;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* adreno_power_stats() - Reads the counters needed for freq decisions
|
||||
* @device: Pointer to device whose counters are read
|
||||
|
@ -2612,6 +2497,7 @@ static void adreno_power_stats(struct kgsl_device *device,
|
|||
struct kgsl_power_stats *stats)
|
||||
{
|
||||
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
|
||||
struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
|
||||
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
|
||||
struct adreno_busy_data *busy = &adreno_dev->busy_data;
|
||||
uint64_t adj = 0;
|
||||
|
@ -2625,8 +2511,11 @@ static void adreno_power_stats(struct kgsl_device *device,
|
|||
gpu_busy = counter_delta(device, adreno_dev->perfctr_pwr_lo,
|
||||
&busy->gpu_busy);
|
||||
|
||||
adj = _read_throttling_counters(adreno_dev);
|
||||
gpu_busy += adj;
|
||||
if (gpudev->read_throttling_counters) {
|
||||
adj = gpudev->read_throttling_counters(adreno_dev);
|
||||
gpu_busy += adj;
|
||||
}
|
||||
|
||||
stats->busy_time = adreno_ticks_to_us(gpu_busy,
|
||||
kgsl_pwrctrl_active_freq(pwr));
|
||||
}
|
||||
|
@ -2647,8 +2536,9 @@ static void adreno_power_stats(struct kgsl_device *device,
|
|||
stats->ram_time = ram_cycles;
|
||||
stats->ram_wait = starved_ram;
|
||||
}
|
||||
if (adreno_dev->lm_threshold_count)
|
||||
_update_threshold_count(adreno_dev, adj);
|
||||
if (adreno_dev->lm_threshold_count &&
|
||||
gpudev->count_throttles)
|
||||
gpudev->count_throttles(adreno_dev, adj);
|
||||
}
|
||||
|
||||
static unsigned int adreno_gpuid(struct kgsl_device *device,
|
||||
|
|
|
@ -756,6 +756,10 @@ struct adreno_gpudev {
|
|||
void (*pwrlevel_change_settings)(struct adreno_device *,
|
||||
unsigned int prelevel, unsigned int postlevel,
|
||||
bool post);
|
||||
uint64_t (*read_throttling_counters)(struct adreno_device *);
|
||||
void (*count_throttles)(struct adreno_device *, uint64_t adj);
|
||||
int (*enable_pwr_counters)(struct adreno_device *,
|
||||
unsigned int counter);
|
||||
unsigned int (*preemption_pre_ibsubmit)(struct adreno_device *,
|
||||
struct adreno_ringbuffer *rb,
|
||||
unsigned int *, struct kgsl_context *);
|
||||
|
@ -1467,4 +1471,24 @@ static inline void adreno_ringbuffer_set_pagetable(struct adreno_ringbuffer *rb,
|
|||
spin_unlock_irqrestore(&rb->preempt_lock, flags);
|
||||
}
|
||||
|
||||
static inline unsigned int counter_delta(struct kgsl_device *device,
|
||||
unsigned int reg, unsigned int *counter)
|
||||
{
|
||||
unsigned int val;
|
||||
unsigned int ret = 0;
|
||||
|
||||
/* Read the value */
|
||||
kgsl_regread(device, reg, &val);
|
||||
|
||||
/* Return 0 for the first read */
|
||||
if (*counter != 0) {
|
||||
if (val < *counter)
|
||||
ret = (0xFFFFFFFF - *counter) + val;
|
||||
else
|
||||
ret = val - *counter;
|
||||
}
|
||||
|
||||
*counter = val;
|
||||
return ret;
|
||||
}
|
||||
#endif /*__ADRENO_H */
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "kgsl_sharedmem.h"
|
||||
#include "kgsl_log.h"
|
||||
#include "kgsl.h"
|
||||
#include "kgsl_trace.h"
|
||||
#include "adreno_a5xx_packets.h"
|
||||
|
||||
static int zap_ucode_loaded;
|
||||
|
@ -1646,6 +1647,76 @@ static void a5xx_clk_set_options(struct adreno_device *adreno_dev,
|
|||
}
|
||||
}
|
||||
|
||||
static void a5xx_count_throttles(struct adreno_device *adreno_dev,
|
||||
uint64_t adj)
|
||||
{
|
||||
if (adreno_is_a530(adreno_dev))
|
||||
kgsl_regread(KGSL_DEVICE(adreno_dev),
|
||||
adreno_dev->lm_threshold_count,
|
||||
&adreno_dev->lm_threshold_cross);
|
||||
else if (adreno_is_a540(adreno_dev))
|
||||
adreno_dev->lm_threshold_cross = adj;
|
||||
}
|
||||
|
||||
static int a5xx_enable_pwr_counters(struct adreno_device *adreno_dev,
|
||||
unsigned int counter)
|
||||
{
|
||||
/*
|
||||
* On 5XX we have to emulate the PWR counters which are physically
|
||||
* missing. Program countable 6 on RBBM_PERFCTR_RBBM_0 as a substitute
|
||||
* for PWR:1. Don't emulate PWR:0 as nobody uses it and we don't want
|
||||
* to take away too many of the generic RBBM counters.
|
||||
*/
|
||||
|
||||
if (counter == 0)
|
||||
return -EINVAL;
|
||||
|
||||
kgsl_regwrite(KGSL_DEVICE(adreno_dev), A5XX_RBBM_PERFCTR_RBBM_SEL_0, 6);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FW driven idle 10% throttle */
|
||||
#define IDLE_10PCT 0
|
||||
/* number of cycles when clock is throttled by 50% (CRC) */
|
||||
#define CRC_50PCT 1
|
||||
/* number of cycles when clock is throttled by more than 50% (CRC) */
|
||||
#define CRC_MORE50PCT 2
|
||||
/* number of cycles when clock is throttle by less than 50% (CRC) */
|
||||
#define CRC_LESS50PCT 3
|
||||
|
||||
static uint64_t a5xx_read_throttling_counters(struct adreno_device *adreno_dev)
|
||||
{
|
||||
int i, adj;
|
||||
uint32_t th[ADRENO_GPMU_THROTTLE_COUNTERS];
|
||||
struct adreno_busy_data *busy = &adreno_dev->busy_data;
|
||||
|
||||
if (!adreno_is_a540(adreno_dev))
|
||||
return 0;
|
||||
|
||||
if (!ADRENO_FEATURE(adreno_dev, ADRENO_GPMU))
|
||||
return 0;
|
||||
|
||||
if (!test_bit(ADRENO_THROTTLING_CTRL, &adreno_dev->pwrctrl_flag))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < ADRENO_GPMU_THROTTLE_COUNTERS; i++) {
|
||||
if (!adreno_dev->gpmu_throttle_counters[i])
|
||||
return 0;
|
||||
|
||||
th[i] = counter_delta(KGSL_DEVICE(adreno_dev),
|
||||
adreno_dev->gpmu_throttle_counters[i],
|
||||
&busy->throttle_cycles[i]);
|
||||
}
|
||||
adj = th[CRC_MORE50PCT] - th[IDLE_10PCT];
|
||||
adj = th[CRC_50PCT] + th[CRC_LESS50PCT] / 3 + (adj < 0 ? 0 : adj) * 3;
|
||||
|
||||
trace_kgsl_clock_throttling(
|
||||
th[IDLE_10PCT], th[CRC_50PCT],
|
||||
th[CRC_MORE50PCT], th[CRC_LESS50PCT],
|
||||
adj);
|
||||
return adj;
|
||||
}
|
||||
|
||||
static void a5xx_enable_64bit(struct adreno_device *adreno_dev)
|
||||
{
|
||||
|
@ -1712,12 +1783,44 @@ static void a5xx_gpmu_reset(struct work_struct *work)
|
|||
/* Soft reset of the GPMU block */
|
||||
kgsl_regwrite(device, A5XX_RBBM_BLOCK_SW_RESET_CMD, BIT(16));
|
||||
|
||||
/* GPU comes up in secured mode, make it unsecured by default */
|
||||
if (!ADRENO_FEATURE(adreno_dev, ADRENO_CONTENT_PROTECTION))
|
||||
kgsl_regwrite(device, A5XX_RBBM_SECVID_TRUST_CNTL, 0x0);
|
||||
|
||||
|
||||
a5xx_gpmu_init(adreno_dev);
|
||||
|
||||
out:
|
||||
mutex_unlock(&device->mutex);
|
||||
}
|
||||
|
||||
static void _setup_throttling_counters(struct adreno_device *adreno_dev)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
if (!adreno_is_a540(adreno_dev))
|
||||
return;
|
||||
|
||||
if (!ADRENO_FEATURE(adreno_dev, ADRENO_GPMU))
|
||||
return;
|
||||
|
||||
for (i = 0; i < ADRENO_GPMU_THROTTLE_COUNTERS; i++) {
|
||||
/* reset throttled cycles ivalue */
|
||||
adreno_dev->busy_data.throttle_cycles[i] = 0;
|
||||
|
||||
if (adreno_dev->gpmu_throttle_counters[i] != 0)
|
||||
continue;
|
||||
ret = adreno_perfcounter_get(adreno_dev,
|
||||
KGSL_PERFCOUNTER_GROUP_GPMU_PWR,
|
||||
ADRENO_GPMU_THROTTLE_COUNTERS_BASE_REG + i,
|
||||
&adreno_dev->gpmu_throttle_counters[i],
|
||||
NULL,
|
||||
PERFCOUNTER_FLAG_KERNEL);
|
||||
WARN_ONCE(ret, "Unable to get clock throttling counter %x\n",
|
||||
ADRENO_GPMU_THROTTLE_COUNTERS_BASE_REG + i);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* a5xx_start() - Device start
|
||||
* @adreno_dev: Pointer to adreno device
|
||||
|
@ -1729,6 +1832,21 @@ static void a5xx_start(struct adreno_device *adreno_dev)
|
|||
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
|
||||
struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
|
||||
unsigned int bit;
|
||||
int ret;
|
||||
|
||||
if (adreno_is_a530(adreno_dev) && ADRENO_FEATURE(adreno_dev, ADRENO_LM)
|
||||
&& adreno_dev->lm_threshold_count == 0) {
|
||||
|
||||
ret = adreno_perfcounter_get(adreno_dev,
|
||||
KGSL_PERFCOUNTER_GROUP_GPMU_PWR, 27,
|
||||
&adreno_dev->lm_threshold_count, NULL,
|
||||
PERFCOUNTER_FLAG_KERNEL);
|
||||
/* Ignore noncritical ret - used for debugfs */
|
||||
if (ret)
|
||||
adreno_dev->lm_threshold_count = 0;
|
||||
}
|
||||
|
||||
_setup_throttling_counters(adreno_dev);
|
||||
|
||||
adreno_vbif_start(adreno_dev, a5xx_vbif_platforms,
|
||||
ARRAY_SIZE(a5xx_vbif_platforms));
|
||||
|
@ -2034,11 +2152,6 @@ static int a5xx_post_start(struct adreno_device *adreno_dev)
|
|||
static int a5xx_gpmu_init(struct adreno_device *adreno_dev)
|
||||
{
|
||||
int ret;
|
||||
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
|
||||
|
||||
/* GPU comes up in secured mode, make it unsecured by default */
|
||||
if (!ADRENO_FEATURE(adreno_dev, ADRENO_CONTENT_PROTECTION))
|
||||
kgsl_regwrite(device, A5XX_RBBM_SECVID_TRUST_CNTL, 0x0);
|
||||
|
||||
/* Set up LM before initializing the GPMU */
|
||||
a5xx_lm_init(adreno_dev);
|
||||
|
@ -2359,20 +2472,10 @@ static int a5xx_rb_start(struct adreno_device *adreno_dev,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Set up LM before initializing the GPMU */
|
||||
a5xx_lm_init(adreno_dev);
|
||||
|
||||
/* Enable SPTP based power collapse before enabling GPMU */
|
||||
a5xx_enable_pc(adreno_dev);
|
||||
|
||||
/* Program the GPMU */
|
||||
ret = a5xx_gpmu_start(adreno_dev);
|
||||
ret = a5xx_gpmu_init(adreno_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Enable limits management */
|
||||
a5xx_lm_enable(adreno_dev);
|
||||
|
||||
a5xx_post_start(adreno_dev);
|
||||
|
||||
return 0;
|
||||
|
@ -3534,6 +3637,9 @@ struct adreno_gpudev adreno_a5xx_gpudev = {
|
|||
.regulator_enable = a5xx_regulator_enable,
|
||||
.regulator_disable = a5xx_regulator_disable,
|
||||
.pwrlevel_change_settings = a5xx_pwrlevel_change_settings,
|
||||
.read_throttling_counters = a5xx_read_throttling_counters,
|
||||
.count_throttles = a5xx_count_throttles,
|
||||
.enable_pwr_counters = a5xx_enable_pwr_counters,
|
||||
.preemption_pre_ibsubmit = a5xx_preemption_pre_ibsubmit,
|
||||
.preemption_yield_enable =
|
||||
a5xx_preemption_yield_enable,
|
||||
|
|
|
@ -598,28 +598,6 @@ int adreno_perfcounter_put(struct adreno_device *adreno_dev,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int _perfcounter_enable_pwr(struct adreno_device *adreno_dev,
|
||||
unsigned int counter)
|
||||
{
|
||||
/* PWR counters enabled by default on A3XX/A4XX so nothing to do */
|
||||
if (adreno_is_a3xx(adreno_dev) || adreno_is_a4xx(adreno_dev))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* On 5XX we have to emulate the PWR counters which are physically
|
||||
* missing. Program countable 6 on RBBM_PERFCTR_RBBM_0 as a substitute
|
||||
* for PWR:1. Don't emulate PWR:0 as nobody uses it and we don't want
|
||||
* to take away too many of the generic RBBM counters.
|
||||
*/
|
||||
|
||||
if (counter == 0)
|
||||
return -EINVAL;
|
||||
|
||||
kgsl_regwrite(KGSL_DEVICE(adreno_dev), A5XX_RBBM_PERFCTR_RBBM_SEL_0, 6);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _perfcounter_enable_vbif(struct adreno_device *adreno_dev,
|
||||
struct adreno_perfcounters *counters, unsigned int counter,
|
||||
unsigned int countable)
|
||||
|
@ -771,6 +749,7 @@ static int adreno_perfcounter_enable(struct adreno_device *adreno_dev,
|
|||
unsigned int group, unsigned int counter, unsigned int countable)
|
||||
{
|
||||
struct adreno_perfcounters *counters = ADRENO_PERFCOUNTERS(adreno_dev);
|
||||
struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
|
||||
|
||||
if (counters == NULL)
|
||||
return -EINVAL;
|
||||
|
@ -786,7 +765,9 @@ static int adreno_perfcounter_enable(struct adreno_device *adreno_dev,
|
|||
/* alwayson counter is global, so init value is 0 */
|
||||
break;
|
||||
case KGSL_PERFCOUNTER_GROUP_PWR:
|
||||
return _perfcounter_enable_pwr(adreno_dev, counter);
|
||||
if (gpudev->enable_pwr_counters)
|
||||
return gpudev->enable_pwr_counters(adreno_dev, counter);
|
||||
return 0;
|
||||
case KGSL_PERFCOUNTER_GROUP_VBIF:
|
||||
if (countable > VBIF2_PERF_CNT_SEL_MASK)
|
||||
return -EINVAL;
|
||||
|
|
Loading…
Add table
Reference in a new issue