msm: kgsl: Modernize bus scaling
Replace all of the legacy bus scaling code with the new interconnect API. This includes removing all msm_bus support as well as the devbw interface which is not needed since icc can set both the IB and the AB on our behalf. As part of this, move most of the bus specific code into its own file, add support for parsing a table of our own from the device tree and handle both the GPU and GMU bus setting paths properly. Change-Id: Ic0dedbadfbb3c48ec414ec60e3032b2204b4e724 Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
This commit is contained in:
parent
ada604f08f
commit
d50bb36c78
@ -5,6 +5,7 @@ obj-$(CONFIG_QCOM_KGSL) += msm_kgsl.o
|
||||
|
||||
msm_kgsl-y = \
|
||||
kgsl.o \
|
||||
kgsl_bus.o \
|
||||
kgsl_drawobj.o \
|
||||
kgsl_events.o \
|
||||
kgsl_ioctl.o \
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "adreno_compat.h"
|
||||
#include "adreno_iommu.h"
|
||||
#include "adreno_trace.h"
|
||||
#include "kgsl_bus.h"
|
||||
#include "kgsl_trace.h"
|
||||
#include "kgsl_util.h"
|
||||
|
||||
@ -1450,6 +1451,12 @@ static int adreno_probe(struct platform_device *pdev)
|
||||
return status;
|
||||
}
|
||||
|
||||
status = kgsl_bus_init(device, pdev);
|
||||
if (status) {
|
||||
device->pdev = NULL;
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Probe/init GMU after initial gpu power probe
|
||||
* Another part of GPU power probe in platform_probe
|
||||
|
185
drivers/gpu/msm/kgsl_bus.c
Normal file
185
drivers/gpu/msm/kgsl_bus.c
Normal file
@ -0,0 +1,185 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/interconnect.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include "kgsl_bus.h"
|
||||
#include "kgsl_device.h"
|
||||
#include "kgsl_trace.h"
|
||||
|
||||
static int gmu_bus_set(struct kgsl_device *device, int buslevel,
|
||||
u32 ab)
|
||||
{
|
||||
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
|
||||
int ret;
|
||||
|
||||
ret = gmu_core_dcvs_set(device, INVALID_DCVS_IDX, buslevel);
|
||||
|
||||
if (!ret)
|
||||
icc_set_bw(pwr->icc_path, MBps_to_icc(ab), 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int interconnect_bus_set(struct kgsl_device *device, int level,
|
||||
u32 ab)
|
||||
{
|
||||
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
|
||||
|
||||
icc_set_bw(pwr->icc_path, MBps_to_icc(ab),
|
||||
KBps_to_icc(pwr->ddr_table[level]));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 _ab_buslevel_update(struct kgsl_pwrctrl *pwr,
|
||||
u32 ib)
|
||||
{
|
||||
if (!ib)
|
||||
return 0;
|
||||
|
||||
/* In the absence of any other settings, make ab 25% of ib */
|
||||
if ((!pwr->bus_percent_ab) && (!pwr->bus_ab_mbytes))
|
||||
return 25 * ib / 100;
|
||||
|
||||
if (pwr->bus_width)
|
||||
return pwr->bus_ab_mbytes;
|
||||
|
||||
return (pwr->bus_percent_ab * pwr->bus_max) / 100;
|
||||
}
|
||||
|
||||
|
||||
void kgsl_bus_update(struct kgsl_device *device, bool on)
|
||||
{
|
||||
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
|
||||
/* FIXME: this might be wrong? */
|
||||
int cur = pwr->pwrlevels[pwr->active_pwrlevel].bus_freq;
|
||||
int buslevel = 0;
|
||||
u32 ab;
|
||||
|
||||
/* the bus should be ON to update the active frequency */
|
||||
if (on && !(test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)))
|
||||
return;
|
||||
/*
|
||||
* If the bus should remain on calculate our request and submit it,
|
||||
* otherwise request bus level 0, off.
|
||||
*/
|
||||
if (on) {
|
||||
buslevel = min_t(int, pwr->pwrlevels[0].bus_max,
|
||||
cur + pwr->bus_mod);
|
||||
buslevel = max_t(int, buslevel, 1);
|
||||
} else {
|
||||
/* If the bus is being turned off, reset to default level */
|
||||
pwr->bus_mod = 0;
|
||||
pwr->bus_percent_ab = 0;
|
||||
pwr->bus_ab_mbytes = 0;
|
||||
}
|
||||
trace_kgsl_buslevel(device, pwr->active_pwrlevel, buslevel);
|
||||
pwr->cur_buslevel = buslevel;
|
||||
|
||||
/* buslevel is the IB vote, update the AB */
|
||||
ab = _ab_buslevel_update(pwr, pwr->ddr_table[buslevel]);
|
||||
|
||||
pwr->bus_set(device, buslevel, ab);
|
||||
}
|
||||
|
||||
static void validate_pwrlevels(struct kgsl_device *device, u32 *ibs,
|
||||
int count)
|
||||
{
|
||||
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < pwr->num_pwrlevels - 1; i++) {
|
||||
struct kgsl_pwrlevel *pwrlevel = &pwr->pwrlevels[i];
|
||||
|
||||
if (pwrlevel->bus_freq >= count) {
|
||||
dev_err(device->dev, "Bus setting for GPU freq %d is out of bounds\n",
|
||||
pwrlevel->gpu_freq);
|
||||
pwrlevel->bus_freq = count - 1;
|
||||
}
|
||||
|
||||
if (pwrlevel->bus_max >= count) {
|
||||
dev_err(device->dev, "Bus max for GPU freq %d is out of bounds\n",
|
||||
pwrlevel->gpu_freq);
|
||||
pwrlevel->bus_max = count - 1;
|
||||
}
|
||||
|
||||
if (pwrlevel->bus_min >= count) {
|
||||
dev_err(device->dev, "Bus min for GPU freq %d is out of bounds\n",
|
||||
pwrlevel->gpu_freq);
|
||||
pwrlevel->bus_min = count - 1;
|
||||
}
|
||||
|
||||
if (pwrlevel->bus_min > pwrlevel->bus_max) {
|
||||
dev_err(device->dev, "Bus min is bigger than bus max for GPU freq %d\n",
|
||||
pwrlevel->gpu_freq);
|
||||
pwrlevel->bus_min = pwrlevel->bus_max;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 *kgsl_bus_get_table(struct platform_device *pdev,
|
||||
const char *name, int *count)
|
||||
{
|
||||
u32 *levels;
|
||||
int i, num = of_property_count_elems_of_size(pdev->dev.of_node,
|
||||
name, sizeof(u32));
|
||||
|
||||
/* If the bus wasn't specified, then build a static table */
|
||||
if (num <= 0)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
levels = kcalloc(num, sizeof(*levels), GFP_KERNEL);
|
||||
if (!levels)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
of_property_read_u32_index(pdev->dev.of_node,
|
||||
name, i, &levels[i]);
|
||||
|
||||
*count = num;
|
||||
return levels;
|
||||
}
|
||||
|
||||
int kgsl_bus_init(struct kgsl_device *device, struct platform_device *pdev)
|
||||
{
|
||||
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
|
||||
int ret, count;
|
||||
|
||||
pwr->ddr_table = kgsl_bus_get_table(pdev, "qcom,bus-table-ddr", &count);
|
||||
if (IS_ERR(pwr->ddr_table)) {
|
||||
ret = PTR_ERR(pwr->ddr_table);
|
||||
pwr->ddr_table = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
pwr->ddr_table_count = count;
|
||||
|
||||
validate_pwrlevels(device, pwr->ddr_table, pwr->ddr_table_count);
|
||||
|
||||
pwr->icc_path = of_icc_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(pwr->icc_path) && !gmu_core_scales_bandwidth(device)) {
|
||||
WARN(1, "The CPU has no way to set the GPU bus levels\n");
|
||||
return PTR_ERR(pwr->icc_path);
|
||||
}
|
||||
|
||||
if (gmu_core_scales_bandwidth(device))
|
||||
pwr->bus_set = gmu_bus_set;
|
||||
else
|
||||
pwr->bus_set = interconnect_bus_set;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kgsl_bus_close(struct kgsl_device *device)
|
||||
{
|
||||
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
|
||||
|
||||
kfree(pwr->ddr_table);
|
||||
|
||||
/* FIXME: Make sure icc put can handle NULL or IS_ERR */
|
||||
icc_put(pwr->icc_path);
|
||||
}
|
19
drivers/gpu/msm/kgsl_bus.h
Normal file
19
drivers/gpu/msm/kgsl_bus.h
Normal file
@ -0,0 +1,19 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _KGSL_BUS_H
|
||||
#define _KGSL_BUS_H
|
||||
|
||||
struct kgsl_device;
|
||||
struct platform_device;
|
||||
|
||||
int kgsl_bus_init(struct kgsl_device *device, struct platform_device *pdev);
|
||||
void kgsl_bus_close(struct kgsl_device *device);
|
||||
void kgsl_bus_update(struct kgsl_device *device, bool on);
|
||||
|
||||
u32 *kgsl_bus_get_table(struct platform_device *pdev,
|
||||
const char *name, int *count);
|
||||
|
||||
#endif
|
@ -7,9 +7,9 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/interconnect.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iommu.h>
|
||||
#include <linux/msm-bus.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
@ -490,6 +490,7 @@ static int gmu_dcvs_set(struct kgsl_device *device,
|
||||
int gpu_pwrlevel, int bus_level)
|
||||
{
|
||||
int ret = 0;
|
||||
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
|
||||
struct gmu_device *gmu = KGSL_GMU_DEVICE(device);
|
||||
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
|
||||
struct gmu_dev_ops *gmu_dev_ops = GMU_DEVICE_OPS(device);
|
||||
@ -515,7 +516,7 @@ static int gmu_dcvs_set(struct kgsl_device *device,
|
||||
if (gpu_pwrlevel < gmu->num_gpupwrlevels - 1)
|
||||
req.freq = gmu->num_gpupwrlevels - gpu_pwrlevel - 1;
|
||||
|
||||
if (bus_level < gmu->num_bwlevels && bus_level > 0)
|
||||
if (bus_level < pwr->ddr_table_count && bus_level > 0)
|
||||
req.bw = bus_level;
|
||||
|
||||
/* GMU will vote for slumber levels through the sleep sequence */
|
||||
@ -794,6 +795,9 @@ static int gmu_bus_vote_init(struct gmu_device *gmu, struct kgsl_pwrctrl *pwr)
|
||||
struct rpmh_votes_t *votes = &gmu->rpmh_votes;
|
||||
int ret;
|
||||
|
||||
if (!gmu->num_bwlevels)
|
||||
return 0;
|
||||
|
||||
usecases = kcalloc(gmu->num_bwlevels, sizeof(*usecases), GFP_KERNEL);
|
||||
if (!usecases)
|
||||
return -ENOMEM;
|
||||
@ -1418,6 +1422,7 @@ static int gmu_start(struct kgsl_device *device)
|
||||
struct gmu_dev_ops *gmu_dev_ops = GMU_DEVICE_OPS(device);
|
||||
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
|
||||
struct gmu_device *gmu = KGSL_GMU_DEVICE(device);
|
||||
unsigned long ib;
|
||||
|
||||
switch (device->state) {
|
||||
case KGSL_STATE_INIT:
|
||||
@ -1432,7 +1437,9 @@ static int gmu_start(struct kgsl_device *device)
|
||||
gmu_dev_ops->irq_enable(device);
|
||||
|
||||
/* Vote for minimal DDR BW for GMU to init */
|
||||
icc_set_bw(gmu->icc_path, 0, MBps_to_icc(1171));
|
||||
level = pwr->pwrlevels[pwr->default_pwrlevel].bus_min;
|
||||
icc_set_bw(gmu->icc_path, 0,
|
||||
MBps_to_icc(pwr->ddr_table[level]));
|
||||
|
||||
ret = gmu_dev_ops->rpmh_gpu_pwrctrl(device, GMU_FW_START,
|
||||
GMU_COLD_BOOT, 0);
|
||||
@ -1447,8 +1454,6 @@ static int gmu_start(struct kgsl_device *device)
|
||||
ret = kgsl_pwrctrl_set_default_gpu_pwrlevel(device);
|
||||
if (ret)
|
||||
goto error_gmu;
|
||||
|
||||
icc_set_bw(gmu->icc_path, 0, 0);
|
||||
break;
|
||||
|
||||
case KGSL_STATE_SLUMBER:
|
||||
|
@ -169,8 +169,6 @@ struct icc_path;
|
||||
* @load_mode: GMU FW load/boot mode
|
||||
* @wakeup_pwrlevel: GPU wake up power/DCVS level in case different
|
||||
* than default power level
|
||||
* @pcl: GPU BW scaling client
|
||||
* @ccl: CNOC BW scaling client
|
||||
* @idle_level: Minimal GPU idle power level
|
||||
* @fault_count: GMU fault count
|
||||
* @mailbox: Messages to AOP for ACD enable/disable go through this
|
||||
@ -213,8 +211,6 @@ struct gmu_device {
|
||||
struct clk *gmu_clk;
|
||||
enum gmu_load_mode load_mode;
|
||||
unsigned int wakeup_pwrlevel;
|
||||
unsigned int pcl;
|
||||
unsigned int ccl;
|
||||
unsigned int idle_level;
|
||||
unsigned int fault_count;
|
||||
struct kgsl_mailbox mailbox;
|
||||
|
@ -10,21 +10,14 @@
|
||||
#include <linux/thermal.h>
|
||||
|
||||
#include "kgsl_device.h"
|
||||
#include "kgsl_bus.h"
|
||||
#include "kgsl_pwrscale.h"
|
||||
#include "kgsl_trace.h"
|
||||
|
||||
#define KGSL_PWRFLAGS_POWER_ON 0
|
||||
#define KGSL_PWRFLAGS_CLK_ON 1
|
||||
#define KGSL_PWRFLAGS_AXI_ON 2
|
||||
#define KGSL_PWRFLAGS_IRQ_ON 3
|
||||
#define KGSL_PWRFLAGS_NAP_OFF 5
|
||||
|
||||
#define UPDATE_BUSY_VAL 1000000
|
||||
|
||||
#define KGSL_MAX_BUSLEVELS 20
|
||||
|
||||
#define DEFAULT_BUS_P 25
|
||||
|
||||
/* Order deeply matters here because reasons. New entries go on the end */
|
||||
static const char * const clocks[] = {
|
||||
"src_clk",
|
||||
@ -62,41 +55,6 @@ static void _gpu_clk_prepare_enable(struct kgsl_device *device,
|
||||
static void _bimc_clk_prepare_enable(struct kgsl_device *device,
|
||||
struct clk *clk, const char *name);
|
||||
|
||||
#ifdef CONFIG_DEVFREQ_GOV_QCOM_GPUBW_MON
|
||||
#include <soc/qcom/devfreq_devbw.h>
|
||||
|
||||
/**
|
||||
* kgsl_get_bw() - Return latest msm bus IB vote
|
||||
*/
|
||||
static void kgsl_get_bw(unsigned long *ib, unsigned long *ab, void *data)
|
||||
{
|
||||
struct kgsl_device *device = (struct kgsl_device *)data;
|
||||
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
|
||||
|
||||
if (gmu_core_scales_bandwidth(device))
|
||||
*ib = 0;
|
||||
else
|
||||
*ib = (unsigned long)
|
||||
device->pwrctrl.bus_ibs[pwr->cur_buslevel];
|
||||
|
||||
*ab = last_ab;
|
||||
}
|
||||
#endif
|
||||
|
||||
static u32 _ab_buslevel_update(struct kgsl_pwrctrl *pwr, u32 ib)
|
||||
{
|
||||
if (!ib)
|
||||
return 0;
|
||||
|
||||
if ((!pwr->bus_percent_ab) && (!pwr->bus_ab_mbytes))
|
||||
return DEFAULT_BUS_P * ib / 100;
|
||||
|
||||
if (pwr->bus_width)
|
||||
return pwr->bus_ab_mbytes;
|
||||
|
||||
return (pwr->bus_percent_ab * pwr->bus_max) / 100;
|
||||
}
|
||||
|
||||
/**
|
||||
* _adjust_pwrlevel() - Given a requested power level do bounds checking on the
|
||||
* constraints and return the nearest possible level
|
||||
@ -144,42 +102,6 @@ static unsigned int _adjust_pwrlevel(struct kgsl_pwrctrl *pwr, int level,
|
||||
return level;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEVFREQ_GOV_QCOM_GPUBW_MON
|
||||
static void kgsl_pwrctrl_vbif_update(u32 ib, u32 ab)
|
||||
{
|
||||
/* ask a governor to vote on behalf of us */
|
||||
devfreq_vbif_update_bw((unsigned long) ib, (unsigned long) ab);
|
||||
}
|
||||
#else
|
||||
static void kgsl_pwrctrl_vbif_update(u32 ib, u32 ab)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* kgsl_bus_scale_request() - set GPU BW vote
|
||||
* @device: Pointer to the kgsl_device struct
|
||||
* @buslevel: index of bw vector[] table
|
||||
*/
|
||||
static int kgsl_bus_scale_request(struct kgsl_device *device,
|
||||
unsigned int buslevel)
|
||||
{
|
||||
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
|
||||
int ret = 0;
|
||||
|
||||
/* GMU scales BW */
|
||||
if (gmu_core_scales_bandwidth(device))
|
||||
ret = gmu_core_dcvs_set(device, INVALID_DCVS_IDX, buslevel);
|
||||
else if (pwr->pcl)
|
||||
/* Linux bus driver scales BW */
|
||||
icc_set_bw(pwr->icc_path, 0, MBps_to_icc(pwr->bus_ibs[i]));
|
||||
|
||||
if (ret)
|
||||
dev_err(device->dev, "GPU BW scaling failure: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* kgsl_clk_set_rate() - set GPU clock rate
|
||||
* @device: Pointer to the kgsl_device struct
|
||||
@ -207,49 +129,6 @@ int kgsl_clk_set_rate(struct kgsl_device *device,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* kgsl_pwrctrl_buslevel_update() - Recalculate the bus vote and send it
|
||||
* @device: Pointer to the kgsl_device struct
|
||||
* @on: true for setting and active bus vote, false to turn off the vote
|
||||
*/
|
||||
void kgsl_pwrctrl_buslevel_update(struct kgsl_device *device,
|
||||
bool on)
|
||||
{
|
||||
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
|
||||
int cur = pwr->pwrlevels[pwr->active_pwrlevel].bus_freq;
|
||||
int buslevel = 0;
|
||||
u32 ab;
|
||||
|
||||
/* the bus should be ON to update the active frequency */
|
||||
if (on && !(test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)))
|
||||
return;
|
||||
/*
|
||||
* If the bus should remain on calculate our request and submit it,
|
||||
* otherwise request bus level 0, off.
|
||||
*/
|
||||
if (on) {
|
||||
buslevel = min_t(int, pwr->pwrlevels[0].bus_max,
|
||||
cur + pwr->bus_mod);
|
||||
buslevel = max_t(int, buslevel, 1);
|
||||
} else {
|
||||
/* If the bus is being turned off, reset to default level */
|
||||
pwr->bus_mod = 0;
|
||||
pwr->bus_percent_ab = 0;
|
||||
pwr->bus_ab_mbytes = 0;
|
||||
}
|
||||
trace_kgsl_buslevel(device, pwr->active_pwrlevel, buslevel);
|
||||
pwr->cur_buslevel = buslevel;
|
||||
|
||||
/* buslevel is the IB vote, update the AB */
|
||||
ab = _ab_buslevel_update(pwr, pwr->bus_ibs[buslevel]);
|
||||
|
||||
last_ab = ab;
|
||||
|
||||
kgsl_bus_scale_request(device, buslevel);
|
||||
|
||||
kgsl_pwrctrl_vbif_update(pwr->bus_ibs[buslevel], ab);
|
||||
}
|
||||
|
||||
/**
|
||||
* kgsl_pwrctrl_pwrlevel_change_settings() - Program h/w during powerlevel
|
||||
* transitions
|
||||
@ -350,7 +229,7 @@ void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device,
|
||||
* Update the bus before the GPU clock to prevent underrun during
|
||||
* frequency increases.
|
||||
*/
|
||||
kgsl_pwrctrl_buslevel_update(device, true);
|
||||
kgsl_bus_update(device, true);
|
||||
|
||||
pwrlevel = &pwr->pwrlevels[pwr->active_pwrlevel];
|
||||
/* Change register settings if any BEFORE pwrlevel change*/
|
||||
@ -1340,28 +1219,6 @@ static void kgsl_pwrctrl_clk(struct kgsl_device *device, int state,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEVFREQ_GOV_QCOM_GPUBW_MON
|
||||
static void kgsl_pwrctrl_suspend_devbw(struct kgsl_pwrctrl *pwr)
|
||||
{
|
||||
if (pwr->devbw)
|
||||
devfreq_suspend_devbw(pwr->devbw);
|
||||
}
|
||||
|
||||
static void kgsl_pwrctrl_resume_devbw(struct kgsl_pwrctrl *pwr)
|
||||
{
|
||||
if (pwr->devbw)
|
||||
devfreq_resume_devbw(pwr->devbw);
|
||||
}
|
||||
#else
|
||||
static void kgsl_pwrctrl_suspend_devbw(struct kgsl_pwrctrl *pwr)
|
||||
{
|
||||
}
|
||||
|
||||
static void kgsl_pwrctrl_resume_devbw(struct kgsl_pwrctrl *pwr)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static void kgsl_pwrctrl_axi(struct kgsl_device *device, int state)
|
||||
{
|
||||
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
|
||||
@ -1373,17 +1230,13 @@ static void kgsl_pwrctrl_axi(struct kgsl_device *device, int state)
|
||||
if (test_and_clear_bit(KGSL_PWRFLAGS_AXI_ON,
|
||||
&pwr->power_flags)) {
|
||||
trace_kgsl_bus(device, state);
|
||||
kgsl_pwrctrl_buslevel_update(device, false);
|
||||
|
||||
kgsl_pwrctrl_suspend_devbw(pwr);
|
||||
kgsl_bus_update(device, false);
|
||||
}
|
||||
} else if (state == KGSL_PWRFLAGS_ON) {
|
||||
if (!test_and_set_bit(KGSL_PWRFLAGS_AXI_ON,
|
||||
&pwr->power_flags)) {
|
||||
trace_kgsl_bus(device, state);
|
||||
kgsl_pwrctrl_buslevel_update(device, true);
|
||||
|
||||
kgsl_pwrctrl_resume_devbw(pwr);
|
||||
kgsl_bus_update(device, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1472,17 +1325,6 @@ static void kgsl_pwrctrl_irq(struct kgsl_device *device, int state)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEVFREQ_GOV_QCOM_GPUBW_MON
|
||||
static void kgsl_pwrctrl_vbif_init(struct kgsl_device *device)
|
||||
{
|
||||
devfreq_vbif_register_callback(kgsl_get_bw, device);
|
||||
}
|
||||
#else
|
||||
static void kgsl_pwrctrl_vbif_init(struct kgsl_device *device)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static int _get_clocks(struct kgsl_device *device)
|
||||
{
|
||||
struct device *dev = &device->pdev->dev;
|
||||
@ -1584,41 +1426,13 @@ static int kgsl_pwrctrl_clk_set_rate(struct clk *grp_clk, unsigned int freq,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 *kgsl_bus_get_table(struct platform_device *pdev, int *count)
|
||||
{
|
||||
u32 *levels;
|
||||
int i, num = of_property_count_elems_of_size(pdev->dev.of_node,
|
||||
"qcom,bus-table-ddr", sizeof(u32));
|
||||
|
||||
if (num <= 0)
|
||||
return NULL;
|
||||
|
||||
levels = kcalloc(num, sizeof(*levels), GFP_KERNEL);
|
||||
if (!levels)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
of_property_read_u32_index(pdev->dev.of_node,
|
||||
"qcom,bus-table-ddr", i, &levels[i]);
|
||||
|
||||
*count = num;
|
||||
return levels;
|
||||
}
|
||||
|
||||
static void kgsl_idle_check(struct work_struct *work);
|
||||
|
||||
int kgsl_pwrctrl_init(struct kgsl_device *device)
|
||||
{
|
||||
int i, result, freq, levels_count;
|
||||
int i, result, freq;
|
||||
struct platform_device *pdev = device->pdev;
|
||||
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
|
||||
struct device_node *gpubw_dev_node = NULL;
|
||||
struct platform_device *p2dev;
|
||||
u32 *levels;
|
||||
|
||||
levels = kgsl_bus_get_table(pdev, &levels_count);
|
||||
if (!levels)
|
||||
return -EINVAL;
|
||||
|
||||
result = _get_clocks(device);
|
||||
if (result)
|
||||
@ -1681,61 +1495,11 @@ int kgsl_pwrctrl_init(struct kgsl_device *device)
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
/* Check if gpu bandwidth vote device is defined in dts */
|
||||
if (pwr->bus_control)
|
||||
/* Check if gpu bandwidth vote device is defined in dts */
|
||||
gpubw_dev_node = of_parse_phandle(pdev->dev.of_node,
|
||||
"qcom,gpubw-dev", 0);
|
||||
|
||||
/*
|
||||
* Governor support enables the gpu bus scaling via governor
|
||||
* and hence no need to register for bus scaling client
|
||||
* if gpubw-dev is defined.
|
||||
*/
|
||||
if (gpubw_dev_node) {
|
||||
p2dev = of_find_device_by_node(gpubw_dev_node);
|
||||
if (p2dev)
|
||||
pwr->devbw = &p2dev->dev;
|
||||
} else {
|
||||
/* Register for interconnect */
|
||||
pwr->icc_path = of_icc_get(&pdev->dev, NULL);
|
||||
}
|
||||
|
||||
pwr->bus_ibs = kzalloc(levels_count, sizeof(*pwr->bus_ib), GFP_KERNEL);
|
||||
if (pwr->bus_ibs == NULL) {
|
||||
result = -ENOMEM;
|
||||
goto error_disable_pm;
|
||||
}
|
||||
|
||||
pwr->bus_ibs_count = levels_count;
|
||||
|
||||
/*
|
||||
* Pull the BW vote out of the bus table. They will be used to
|
||||
* calculate the ratio between the votes.
|
||||
*/
|
||||
|
||||
for (i = 0; i < levels_count; i++) {
|
||||
/* Convert the KBps value from the table to MBps */
|
||||
pwr->bus_ibs[i] = DIV_ROUND_UP_ULL(levels[i], 1000);
|
||||
|
||||
pwr->bus_max = max(pwr->bus_max, pwr->bus_ibs[i]);
|
||||
}
|
||||
|
||||
kfree(levels);
|
||||
|
||||
kgsl_pwrctrl_vbif_init(device);
|
||||
|
||||
/* temperature sensor name */
|
||||
of_property_read_string(pdev->dev.of_node, "qcom,tzone-name",
|
||||
&pwr->tzone_name);
|
||||
|
||||
return result;
|
||||
|
||||
error_disable_pm:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
kfree(levels);
|
||||
|
||||
return result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kgsl_pwrctrl_close(struct kgsl_device *device)
|
||||
@ -1744,9 +1508,7 @@ void kgsl_pwrctrl_close(struct kgsl_device *device)
|
||||
|
||||
pwr->power_flags = 0;
|
||||
|
||||
kfree(pwr->bus_ibs);
|
||||
|
||||
icc_put(pwr->icc_path);
|
||||
kgsl_bus_close(device);
|
||||
|
||||
pm_runtime_disable(&device->pdev->dev);
|
||||
}
|
||||
|
@ -21,6 +21,12 @@
|
||||
|
||||
#define KGSL_MAX_PWRLEVELS 10
|
||||
|
||||
#define KGSL_PWRFLAGS_POWER_ON 0
|
||||
#define KGSL_PWRFLAGS_CLK_ON 1
|
||||
#define KGSL_PWRFLAGS_AXI_ON 2
|
||||
#define KGSL_PWRFLAGS_IRQ_ON 3
|
||||
#define KGSL_PWRFLAGS_NAP_OFF 5
|
||||
|
||||
/* Only two supported levels, min & max */
|
||||
#define KGSL_CONSTRAINT_PWR_MAXLEVELS 2
|
||||
|
||||
@ -35,6 +41,7 @@ enum kgsl_pwrctrl_timer_type {
|
||||
};
|
||||
|
||||
struct platform_device;
|
||||
struct icc_path;
|
||||
|
||||
struct kgsl_clk_stats {
|
||||
unsigned int busy;
|
||||
@ -91,7 +98,6 @@ struct kgsl_pwrlevel {
|
||||
* @throttle_mask - LM throttle mask
|
||||
* @interval_timeout - timeout in jiffies to be idle before a power event
|
||||
* @clock_times - Each GPU frequency's accumulated active time in us
|
||||
* @pcl - bus scale identifier
|
||||
* @clk_stats - structure of clock statistics
|
||||
* @input_disable - To disable GPU wakeup on touch input event
|
||||
* @bus_control - true if the bus calculation is independent
|
||||
@ -133,7 +139,6 @@ struct kgsl_pwrctrl {
|
||||
unsigned int throttle_mask;
|
||||
unsigned long interval_timeout;
|
||||
u64 clock_times[KGSL_MAX_PWRLEVELS];
|
||||
uint32_t pcl;
|
||||
struct kgsl_clk_stats clk_stats;
|
||||
bool input_disable;
|
||||
bool bus_control;
|
||||
@ -141,15 +146,16 @@ struct kgsl_pwrctrl {
|
||||
unsigned int bus_percent_ab;
|
||||
unsigned int bus_width;
|
||||
unsigned long bus_ab_mbytes;
|
||||
struct device *devbw;
|
||||
/** @bus_ibs: List of the bus bandwidths in use by our target */
|
||||
u32 *bus_ibs;
|
||||
/** @bus_ibs_count: Number of objects in @bus_ibs */
|
||||
int bus_ibs_count;
|
||||
/** @ddr_table: List of the DDR bandwidths in KBps for the target */
|
||||
u32 *ddr_table;
|
||||
/** @ddr_table_count: Number of objects in @ddr_table */
|
||||
int ddr_table_count;
|
||||
/** cur_buslevel: The last buslevel voted by the driver */
|
||||
int cur_buslevel;
|
||||
/** @bus_max: The maximum bandwidth available to the device */
|
||||
unsigned long bus_max;
|
||||
/** @bus_set: Function for setting the bus constraints */
|
||||
int (*bus_set)(struct kgsl_device *device, int buslevel, u32 ab);
|
||||
struct kgsl_pwr_constraint constraint;
|
||||
bool superfast;
|
||||
unsigned int gpu_bimc_int_clk_freq;
|
||||
@ -165,8 +171,6 @@ void kgsl_timer(struct timer_list *t);
|
||||
void kgsl_pre_hwaccess(struct kgsl_device *device);
|
||||
void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device,
|
||||
unsigned int level);
|
||||
void kgsl_pwrctrl_buslevel_update(struct kgsl_device *device,
|
||||
bool on);
|
||||
int kgsl_pwrctrl_init_sysfs(struct kgsl_device *device);
|
||||
int kgsl_pwrctrl_change_state(struct kgsl_device *device, int state);
|
||||
int kgsl_clk_set_rate(struct kgsl_device *device,
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <linux/devfreq_cooling.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "kgsl_bus.h"
|
||||
#include "kgsl_device.h"
|
||||
#include "kgsl_pwrscale.h"
|
||||
#include "kgsl_trace.h"
|
||||
@ -586,7 +587,7 @@ int kgsl_busmon_target(struct device *dev, unsigned long *freq, u32 flags)
|
||||
if ((pwr->bus_mod != b) || (pwr->bus_ab_mbytes != ab_mbytes)) {
|
||||
pwr->bus_percent_ab = device->pwrscale.bus_profile.percent_ab;
|
||||
pwr->bus_ab_mbytes = ab_mbytes;
|
||||
kgsl_pwrctrl_buslevel_update(device, true);
|
||||
kgsl_bus_update(device, true);
|
||||
}
|
||||
|
||||
mutex_unlock(&device->mutex);
|
||||
@ -786,8 +787,8 @@ int kgsl_pwrscale_init(struct kgsl_device *device, struct platform_device *pdev,
|
||||
* the bus bandwidth vote.
|
||||
*/
|
||||
if (pwr->bus_control) {
|
||||
adreno_tz_data.bus.num = pwr->bus_ibs_count;
|
||||
adreno_tz_data.bus.ib_mbps = pwr->bus_ibs;
|
||||
adreno_tz_data.bus.num = pwr->ddr_table_count;
|
||||
adreno_tz_data.bus.ib_kbps = pwr->ddr_table;
|
||||
adreno_tz_data.bus.width = pwr->bus_width;
|
||||
|
||||
if (!kgsl_of_property_read_ddrtype(device->pdev->dev.of_node,
|
||||
|
@ -55,7 +55,7 @@ struct devfreq_msm_adreno_tz_data {
|
||||
u32 *down;
|
||||
s32 *p_up;
|
||||
s32 *p_down;
|
||||
u32 *ib_mbps;
|
||||
u32 *ib_kbps;
|
||||
bool floating;
|
||||
} bus;
|
||||
unsigned int device_id;
|
||||
|
Loading…
Reference in New Issue
Block a user