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:
George Shen 2016-08-29 11:34:41 -07:00
parent 1fac7f53bd
commit 19baa2bf45
4 changed files with 160 additions and 159 deletions

View file

@ -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,

View file

@ -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 */

View file

@ -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,

View file

@ -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;