mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-12 07:37:31 -04:00
Merge "msm: kgsl: Fix kgsl_state_is_awake for gmu targets"
This commit is contained in:
commit
52c24cbf41
39 changed files with 5532 additions and 2926 deletions
|
|
@ -9,14 +9,11 @@ msm_kgsl-y = \
|
|||
kgsl_drawobj.o \
|
||||
kgsl_events.o \
|
||||
kgsl_ioctl.o \
|
||||
kgsl_gmu.o \
|
||||
kgsl_gmu_core.o \
|
||||
kgsl_hfi.o \
|
||||
kgsl_mmu.o \
|
||||
kgsl_pool.o \
|
||||
kgsl_pwrctrl.o \
|
||||
kgsl_pwrscale.o \
|
||||
kgsl_rgmu.o \
|
||||
kgsl_sharedmem.o \
|
||||
kgsl_snapshot.o \
|
||||
kgsl_trace.o \
|
||||
|
|
@ -36,8 +33,11 @@ msm_kgsl-y += \
|
|||
adreno_a5xx_snapshot.o \
|
||||
adreno_a6xx.o \
|
||||
adreno_a6xx_gmu.o \
|
||||
adreno_a6xx_gmu_snapshot.o \
|
||||
adreno_a6xx_hfi.o \
|
||||
adreno_a6xx_preempt.o \
|
||||
adreno_a6xx_rgmu.o \
|
||||
adreno_a6xx_rpmh.o \
|
||||
adreno_a6xx_snapshot.o \
|
||||
adreno_cp_parser.o \
|
||||
adreno_dispatch.o \
|
||||
|
|
|
|||
|
|
@ -971,8 +971,6 @@
|
|||
#define A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_4_H 0x1F84D
|
||||
#define A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_5_L 0x1F84E
|
||||
#define A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_5_H 0x1F84F
|
||||
#define A6XX_GMU_CX_GMU_ALWAYS_ON_COUNTER_L 0x1F888
|
||||
#define A6XX_GMU_CX_GMU_ALWAYS_ON_COUNTER_H 0x1F889
|
||||
#define A6XX_GMU_PWR_COL_INTER_FRAME_CTRL 0x1F8C0
|
||||
#define A6XX_GMU_PWR_COL_INTER_FRAME_HYST 0x1F8C1
|
||||
#define A6XX_GMU_PWR_COL_SPTPRAC_HYST 0x1F8C2
|
||||
|
|
@ -1124,7 +1122,7 @@
|
|||
* now we are using a separate section for RSCC regsiters. Add the
|
||||
* offset for backward compatibility.
|
||||
*/
|
||||
#define RSCC_OFFSET_LEGACY 0x23400
|
||||
#define RSCC_OFFSET_LEGACY 0x23000
|
||||
|
||||
/* RGMU(PCC) registers in A6X_GMU_CX_0_NON_CONTEXT_DEC domain */
|
||||
#define A6XX_RGMU_CX_INTR_GEN_EN 0x1F80F
|
||||
|
|
|
|||
|
|
@ -782,7 +782,7 @@ static const struct adreno_a6xx_core adreno_gpu_core_a630v2 = {
|
|||
.features = ADRENO_RPMH | ADRENO_IFPC |
|
||||
ADRENO_GPMU | ADRENO_CONTENT_PROTECTION |
|
||||
ADRENO_IOCOHERENT | ADRENO_PREEMPTION,
|
||||
.gpudev = &adreno_a6xx_gpudev,
|
||||
.gpudev = &adreno_a630_gpudev,
|
||||
.gmem_base = 0x100000,
|
||||
.gmem_size = SZ_1M,
|
||||
.bus_width = 32,
|
||||
|
|
@ -881,7 +881,7 @@ static const struct adreno_a6xx_core adreno_gpu_core_a615 = {
|
|||
.features = ADRENO_RPMH | ADRENO_PREEMPTION |
|
||||
ADRENO_GPMU | ADRENO_CONTENT_PROTECTION | ADRENO_IFPC |
|
||||
ADRENO_IOCOHERENT,
|
||||
.gpudev = &adreno_a6xx_gpudev,
|
||||
.gpudev = &adreno_a630_gpudev,
|
||||
.gmem_base = 0x100000,
|
||||
.gmem_size = SZ_512K,
|
||||
.bus_width = 32,
|
||||
|
|
@ -908,7 +908,7 @@ static const struct adreno_a6xx_core adreno_gpu_core_a618 = {
|
|||
.features = ADRENO_RPMH | ADRENO_PREEMPTION |
|
||||
ADRENO_GPMU | ADRENO_CONTENT_PROTECTION | ADRENO_IFPC |
|
||||
ADRENO_IOCOHERENT,
|
||||
.gpudev = &adreno_a6xx_gpudev,
|
||||
.gpudev = &adreno_a630_gpudev,
|
||||
.gmem_base = 0x100000,
|
||||
.gmem_size = SZ_512K,
|
||||
.bus_width = 32,
|
||||
|
|
@ -935,7 +935,7 @@ static const struct adreno_a6xx_core adreno_gpu_core_a619 = {
|
|||
.features = ADRENO_RPMH | ADRENO_PREEMPTION |
|
||||
ADRENO_GPMU | ADRENO_CONTENT_PROTECTION | ADRENO_IFPC |
|
||||
ADRENO_IOCOHERENT,
|
||||
.gpudev = &adreno_a6xx_gpudev,
|
||||
.gpudev = &adreno_a630_gpudev,
|
||||
.gmem_size = SZ_512K,
|
||||
.bus_width = 32,
|
||||
},
|
||||
|
|
@ -1081,7 +1081,7 @@ static const struct adreno_a6xx_core adreno_gpu_core_a620 = {
|
|||
ADRENO_CONTENT_PROTECTION | ADRENO_IOCOHERENT |
|
||||
ADRENO_IFPC | ADRENO_PREEMPTION | ADRENO_ACD |
|
||||
ADRENO_APRIV,
|
||||
.gpudev = &adreno_a6xx_gpudev,
|
||||
.gpudev = &adreno_a630_gpudev,
|
||||
.gmem_base = 0,
|
||||
.gmem_size = SZ_512K,
|
||||
.bus_width = 32,
|
||||
|
|
@ -1171,7 +1171,7 @@ static const struct adreno_a6xx_core adreno_gpu_core_a640 = {
|
|||
.features = ADRENO_RPMH | ADRENO_GPMU |
|
||||
ADRENO_CONTENT_PROTECTION | ADRENO_IOCOHERENT |
|
||||
ADRENO_IFPC | ADRENO_PREEMPTION,
|
||||
.gpudev = &adreno_a6xx_gpudev,
|
||||
.gpudev = &adreno_a6xx_gmu_gpudev,
|
||||
.gmem_base = 0x100000,
|
||||
.gmem_size = SZ_1M, //Verified 1MB
|
||||
.bus_width = 32,
|
||||
|
|
@ -1251,7 +1251,7 @@ static const struct adreno_a6xx_core adreno_gpu_core_a650 = {
|
|||
.features = ADRENO_RPMH | ADRENO_GPMU |
|
||||
ADRENO_IOCOHERENT | ADRENO_CONTENT_PROTECTION |
|
||||
ADRENO_IFPC | ADRENO_APRIV,
|
||||
.gpudev = &adreno_a6xx_gpudev,
|
||||
.gpudev = &adreno_a6xx_gmu_gpudev,
|
||||
.gmem_base = 0,
|
||||
.gmem_size = SZ_1M + SZ_128K, /* verified 1152kB */
|
||||
.bus_width = 32,
|
||||
|
|
@ -1280,7 +1280,7 @@ static const struct adreno_a6xx_core adreno_gpu_core_a650v2 = {
|
|||
ADRENO_IOCOHERENT | ADRENO_CONTENT_PROTECTION |
|
||||
ADRENO_IFPC | ADRENO_PREEMPTION | ADRENO_ACD |
|
||||
ADRENO_LM | ADRENO_APRIV,
|
||||
.gpudev = &adreno_a6xx_gpudev,
|
||||
.gpudev = &adreno_a6xx_gmu_gpudev,
|
||||
.gmem_base = 0,
|
||||
.gmem_size = SZ_1M + SZ_128K, /* verified 1152kB */
|
||||
.bus_width = 32,
|
||||
|
|
@ -1306,7 +1306,7 @@ static const struct adreno_a6xx_core adreno_gpu_core_a680 = {
|
|||
.base = {
|
||||
DEFINE_ADRENO_REV(ADRENO_REV_A680, 6, 8, 0, ANY_ID),
|
||||
.features = ADRENO_RPMH | ADRENO_GPMU,
|
||||
.gpudev = &adreno_a6xx_gpudev,
|
||||
.gpudev = &adreno_a6xx_gmu_gpudev,
|
||||
.gmem_base = 0x100000,
|
||||
.gmem_size = SZ_2M,
|
||||
.bus_width = 32,
|
||||
|
|
@ -1383,7 +1383,7 @@ static const struct adreno_a6xx_core adreno_gpu_core_a612 = {
|
|||
.features = ADRENO_CONTENT_PROTECTION |
|
||||
ADRENO_IOCOHERENT | ADRENO_PREEMPTION | ADRENO_GPMU |
|
||||
ADRENO_IFPC,
|
||||
.gpudev = &adreno_a6xx_gpudev,
|
||||
.gpudev = &adreno_a6xx_rgmu_gpudev,
|
||||
.gmem_base = 0x100000,
|
||||
.gmem_size = (SZ_128K + SZ_4K),
|
||||
.bus_width = 32,
|
||||
|
|
@ -1408,7 +1408,7 @@ static const struct adreno_a6xx_core adreno_gpu_core_a616 = {
|
|||
.features = ADRENO_RPMH | ADRENO_PREEMPTION |
|
||||
ADRENO_GPMU | ADRENO_CONTENT_PROTECTION | ADRENO_IFPC |
|
||||
ADRENO_IOCOHERENT,
|
||||
.gpudev = &adreno_a6xx_gpudev,
|
||||
.gpudev = &adreno_a630_gpudev,
|
||||
.gmem_base = 0x100000,
|
||||
.gmem_size = SZ_512K,
|
||||
.bus_width = 32,
|
||||
|
|
@ -1549,7 +1549,7 @@ static const struct adreno_a6xx_core adreno_gpu_core_a660 = {
|
|||
.features = ADRENO_RPMH | ADRENO_GPMU | ADRENO_APRIV |
|
||||
ADRENO_IOCOHERENT | ADRENO_CONTENT_PROTECTION |
|
||||
ADRENO_IFPC,
|
||||
.gpudev = &adreno_a6xx_gpudev,
|
||||
.gpudev = &adreno_a6xx_gmu_gpudev,
|
||||
.gmem_base = 0,
|
||||
.gmem_size = SZ_1M + SZ_512K,
|
||||
.bus_width = 32,
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -27,6 +27,12 @@
|
|||
/* ADRENO_GPU_DEVICE - Given an adreno device return the GPU specific struct */
|
||||
#define ADRENO_GPU_DEVICE(_a) ((_a)->gpucore->gpudev)
|
||||
|
||||
/*
|
||||
* ADRENO_POWER_OPS - Given an adreno device return the GPU specific power
|
||||
* ops
|
||||
*/
|
||||
#define ADRENO_POWER_OPS(_a) ((_a)->gpucore->gpudev->power_ops)
|
||||
|
||||
#define ADRENO_CHIPID_CORE(_id) (((_id) >> 24) & 0xFF)
|
||||
#define ADRENO_CHIPID_MAJOR(_id) (((_id) >> 16) & 0xFF)
|
||||
#define ADRENO_CHIPID_MINOR(_id) (((_id) >> 8) & 0xFF)
|
||||
|
|
@ -97,14 +103,12 @@
|
|||
* for droop mitigation
|
||||
*/
|
||||
#define ADRENO_ACD BIT(17)
|
||||
/* ECP enabled GMU */
|
||||
#define ADRENO_ECP BIT(18)
|
||||
/* Cooperative reset enabled GMU */
|
||||
#define ADRENO_COOP_RESET BIT(19)
|
||||
#define ADRENO_COOP_RESET BIT(18)
|
||||
/* Indicates that the specific target is no longer supported */
|
||||
#define ADRENO_DEPRECATED BIT(20)
|
||||
#define ADRENO_DEPRECATED BIT(19)
|
||||
/* The target supports ringbuffer level APRIV */
|
||||
#define ADRENO_APRIV BIT(21)
|
||||
#define ADRENO_APRIV BIT(20)
|
||||
/*
|
||||
* Adreno GPU quirks - control bits for various workarounds
|
||||
*/
|
||||
|
|
@ -324,6 +328,46 @@ struct adreno_reglist {
|
|||
u32 value;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct adreno_power_ops - Container for target specific power up/down
|
||||
* sequences
|
||||
*/
|
||||
struct adreno_power_ops {
|
||||
/**
|
||||
* @first_open: Target specific function triggered when first kgsl
|
||||
* instance is opened
|
||||
*/
|
||||
int (*first_open)(struct adreno_device *adreno_dev);
|
||||
/**
|
||||
* @last_close: Target specific function triggered when last kgsl
|
||||
* instance is closed
|
||||
*/
|
||||
int (*last_close)(struct adreno_device *adreno_dev);
|
||||
/**
|
||||
* @active_count_get: Target specific function to keep gpu from power
|
||||
* collapsing
|
||||
*/
|
||||
int (*active_count_get)(struct adreno_device *adreno_dev);
|
||||
/**
|
||||
* @active_count_put: Target specific function to allow gpu to power
|
||||
* collapse
|
||||
*/
|
||||
void (*active_count_put)(struct adreno_device *adreno_dev);
|
||||
/** @pm_suspend: Target specific function to suspend the driver */
|
||||
int (*pm_suspend)(struct adreno_device *adreno_dev);
|
||||
/** @pm_resume: Target specific function to resume the driver */
|
||||
void (*pm_resume)(struct adreno_device *adreno_dev);
|
||||
/**
|
||||
* @touch_wakeup: Target specific function to start gpu on touch event
|
||||
*/
|
||||
void (*touch_wakeup)(struct adreno_device *adreno_dev);
|
||||
/** @gpu_clock_set: Target specific function to set gpu frequency */
|
||||
int (*gpu_clock_set)(struct adreno_device *adreno_dev, u32 pwrlevel);
|
||||
/** @gpu_bus_set: Target specific function to set gpu bandwidth */
|
||||
int (*gpu_bus_set)(struct adreno_device *adreno_dev, int bus_level,
|
||||
u32 ab);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct adreno_gpu_core - A specific GPU core definition
|
||||
* @gpurev: Unique GPU revision identifier
|
||||
|
|
@ -361,9 +405,6 @@ struct adreno_gpu_core {
|
|||
* @chipid: Chip ID specific to the GPU
|
||||
* @cx_misc_len: Length of the CX MISC register block
|
||||
* @cx_misc_virt: Pointer where the CX MISC block is mapped
|
||||
* @rscc_base: Base physical address of the RSCC
|
||||
* @rscc_len: Length of the RSCC register block
|
||||
* @rscc_virt: Pointer where RSCC block is mapped
|
||||
* @isense_base: Base physical address of isense block
|
||||
* @isense_len: Length of the isense register block
|
||||
* @isense_virt: Pointer where isense block is mapped
|
||||
|
|
@ -443,9 +484,6 @@ struct adreno_device {
|
|||
void __iomem *cx_dbgc_virt;
|
||||
unsigned int cx_misc_len;
|
||||
void __iomem *cx_misc_virt;
|
||||
unsigned long rscc_base;
|
||||
unsigned int rscc_len;
|
||||
void __iomem *rscc_virt;
|
||||
unsigned long isense_base;
|
||||
unsigned int isense_len;
|
||||
void __iomem *isense_virt;
|
||||
|
|
@ -665,24 +703,9 @@ enum adreno_regs {
|
|||
ADRENO_REG_VBIF_VERSION,
|
||||
ADRENO_REG_GBIF_HALT,
|
||||
ADRENO_REG_GBIF_HALT_ACK,
|
||||
ADRENO_REG_GMU_AO_INTERRUPT_EN,
|
||||
ADRENO_REG_GMU_AO_HOST_INTERRUPT_CLR,
|
||||
ADRENO_REG_GMU_AO_HOST_INTERRUPT_STATUS,
|
||||
ADRENO_REG_GMU_AO_HOST_INTERRUPT_MASK,
|
||||
ADRENO_REG_GMU_PWR_COL_KEEPALIVE,
|
||||
ADRENO_REG_GMU_AHB_FENCE_STATUS,
|
||||
ADRENO_REG_GMU_RPMH_POWER_STATE,
|
||||
ADRENO_REG_GMU_HFI_CTRL_STATUS,
|
||||
ADRENO_REG_GMU_HFI_VERSION_INFO,
|
||||
ADRENO_REG_GMU_HFI_SFR_ADDR,
|
||||
ADRENO_REG_GMU_GMU2HOST_INTR_CLR,
|
||||
ADRENO_REG_GMU_GMU2HOST_INTR_INFO,
|
||||
ADRENO_REG_GMU_GMU2HOST_INTR_MASK,
|
||||
ADRENO_REG_GMU_HOST2GMU_INTR_SET,
|
||||
ADRENO_REG_GMU_HOST2GMU_INTR_CLR,
|
||||
ADRENO_REG_GMU_HOST2GMU_INTR_RAW_INFO,
|
||||
ADRENO_REG_GMU_NMI_CONTROL_STATUS,
|
||||
ADRENO_REG_GMU_CM3_CFG,
|
||||
ADRENO_REG_GPMU_POWER_COUNTER_ENABLE,
|
||||
ADRENO_REG_REGISTER_MAX,
|
||||
};
|
||||
|
|
@ -746,9 +769,10 @@ struct adreno_gpudev {
|
|||
unsigned int gbif_arb_halt_mask;
|
||||
unsigned int gbif_gx_halt_mask;
|
||||
/* GPU specific function hooks */
|
||||
int (*probe)(struct platform_device *pdev, u32 chipid,
|
||||
const struct adreno_gpu_core *gpucore);
|
||||
void (*snapshot)(struct adreno_device *adreno_dev,
|
||||
struct kgsl_snapshot *snapshot);
|
||||
void (*platform_setup)(struct adreno_device *adreno_dev);
|
||||
irqreturn_t (*irq_handler)(struct adreno_device *adreno_dev);
|
||||
int (*init)(struct adreno_device *adreno_dev);
|
||||
void (*remove)(struct adreno_device *adreno_dev);
|
||||
|
|
@ -787,7 +811,7 @@ struct adreno_gpudev {
|
|||
bool (*hw_isidle)(struct adreno_device *adreno_dev);
|
||||
const char *(*iommu_fault_block)(struct kgsl_device *device,
|
||||
unsigned int fsynr1);
|
||||
int (*reset)(struct kgsl_device *device, int fault);
|
||||
int (*reset)(struct kgsl_device *device);
|
||||
bool (*sptprac_is_on)(struct adreno_device *adreno_dev);
|
||||
unsigned int (*ccu_invalidate)(struct adreno_device *adreno_dev,
|
||||
unsigned int *cmds);
|
||||
|
|
@ -796,6 +820,11 @@ struct adreno_gpudev {
|
|||
bool update_reg);
|
||||
/** @read_alwayson: Return the current value of the alwayson counter */
|
||||
u64 (*read_alwayson)(struct adreno_device *adreno_dev);
|
||||
/**
|
||||
* @power_ops: Target specific function pointers to power up/down the
|
||||
* gpu
|
||||
*/
|
||||
const struct adreno_power_ops *power_ops;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -857,6 +886,7 @@ struct adreno_ft_perf_counters {
|
|||
unsigned int countable;
|
||||
};
|
||||
|
||||
extern const struct adreno_power_ops adreno_power_operations;
|
||||
extern unsigned int *adreno_ft_regs;
|
||||
extern unsigned int adreno_ft_regs_num;
|
||||
extern unsigned int *adreno_ft_regs_val;
|
||||
|
|
@ -864,6 +894,9 @@ extern unsigned int *adreno_ft_regs_val;
|
|||
extern struct adreno_gpudev adreno_a3xx_gpudev;
|
||||
extern struct adreno_gpudev adreno_a5xx_gpudev;
|
||||
extern struct adreno_gpudev adreno_a6xx_gpudev;
|
||||
extern struct adreno_gpudev adreno_a6xx_gmu_gpudev;
|
||||
extern struct adreno_gpudev adreno_a6xx_rgmu_gpudev;
|
||||
extern struct adreno_gpudev adreno_a630_gpudev;
|
||||
|
||||
extern int adreno_wake_nice;
|
||||
extern unsigned int adreno_wake_timeout;
|
||||
|
|
@ -939,8 +972,6 @@ void adreno_cx_misc_regwrite(struct adreno_device *adreno_dev,
|
|||
void adreno_cx_misc_regrmw(struct adreno_device *adreno_dev,
|
||||
unsigned int offsetwords,
|
||||
unsigned int mask, unsigned int bits);
|
||||
void adreno_rscc_regread(struct adreno_device *adreno_dev,
|
||||
unsigned int offsetwords, unsigned int *value);
|
||||
void adreno_isense_regread(struct adreno_device *adreno_dev,
|
||||
unsigned int offsetwords, unsigned int *value);
|
||||
|
||||
|
|
@ -952,6 +983,30 @@ void adreno_isense_regread(struct adreno_device *adreno_dev,
|
|||
*/
|
||||
bool adreno_irq_pending(struct adreno_device *adreno_dev);
|
||||
|
||||
/**
|
||||
* adreno_active_count_get - Wrapper for target specific active count get
|
||||
* @adreno_dev: pointer to the adreno device
|
||||
*
|
||||
* Increase the active count for the KGSL device and execute slumber exit
|
||||
* sequence if this is the first reference. Code paths that need to touch the
|
||||
* hardware or wait for the hardware to complete an operation must hold an
|
||||
* active count reference until they are finished. The device mutex must be held
|
||||
* while calling this function.
|
||||
*
|
||||
* Return: 0 on success or negative error on failure to wake up the device
|
||||
*/
|
||||
int adreno_active_count_get(struct adreno_device *adreno_dev);
|
||||
|
||||
/**
|
||||
* adreno_active_count_put - Wrapper for target specific active count put
|
||||
* @adreno_dev: pointer to the adreno device
|
||||
*
|
||||
* Decrease the active or the KGSL device and schedule the idle thread to
|
||||
* execute the slumber sequence if there are no remaining references. The
|
||||
* device mutex must be held while calling this function.
|
||||
*/
|
||||
void adreno_active_count_put(struct adreno_device *adreno_dev);
|
||||
|
||||
#define ADRENO_TARGET(_name, _id) \
|
||||
static inline int adreno_is_##_name(struct adreno_device *adreno_dev) \
|
||||
{ \
|
||||
|
|
@ -1558,28 +1613,32 @@ static inline unsigned int counter_delta(struct kgsl_device *device,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static inline int adreno_perfcntr_active_oob_get(struct kgsl_device *device)
|
||||
static inline int adreno_perfcntr_active_oob_get(
|
||||
struct adreno_device *adreno_dev)
|
||||
{
|
||||
int ret = kgsl_active_count_get(device);
|
||||
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
|
||||
int ret = adreno_active_count_get(adreno_dev);
|
||||
|
||||
if (!ret) {
|
||||
ret = gmu_core_dev_oob_set(device, oob_perfcntr);
|
||||
if (ret) {
|
||||
gmu_core_snapshot(device);
|
||||
adreno_set_gpu_fault(ADRENO_DEVICE(device),
|
||||
adreno_set_gpu_fault(adreno_dev,
|
||||
ADRENO_GMU_FAULT_SKIP_SNAPSHOT);
|
||||
adreno_dispatcher_schedule(device);
|
||||
kgsl_active_count_put(device);
|
||||
adreno_active_count_put(adreno_dev);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void adreno_perfcntr_active_oob_put(struct kgsl_device *device)
|
||||
static inline void adreno_perfcntr_active_oob_put(
|
||||
struct adreno_device *adreno_dev)
|
||||
{
|
||||
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
|
||||
|
||||
gmu_core_dev_oob_clear(device, oob_perfcntr);
|
||||
kgsl_active_count_put(device);
|
||||
adreno_active_count_put(adreno_dev);
|
||||
}
|
||||
|
||||
static inline bool adreno_has_sptprac_gdsc(struct adreno_device *adreno_dev)
|
||||
|
|
@ -1660,13 +1719,31 @@ static inline bool adreno_move_preempt_state(struct adreno_device *adreno_dev,
|
|||
return (atomic_cmpxchg(&adreno_dev->preempt.state, old, new) == old);
|
||||
}
|
||||
|
||||
void adreno_gmu_clear_and_unmask_irqs(struct adreno_device *adreno_dev);
|
||||
void adreno_gmu_mask_and_clear_irqs(struct adreno_device *adreno_dev);
|
||||
/**
|
||||
* adreno_reg_offset_init - Helper function to initialize reg_offsets
|
||||
* @reg_offsets: Pointer to an array of register offsets
|
||||
*
|
||||
* Helper function to setup register_offsets for a target. Go through
|
||||
* and set ADRENO_REG_UNUSED for all unused entries in the list.
|
||||
*/
|
||||
static inline void adreno_reg_offset_init(u32 *reg_offsets)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Initialize uninitialzed gpu registers, only needs to be done once.
|
||||
* Make all offsets that are not initialized to ADRENO_REG_UNUSED
|
||||
*/
|
||||
for (i = 0; i < ADRENO_REG_REGISTER_MAX; i++) {
|
||||
if (!reg_offsets[i])
|
||||
reg_offsets[i] = ADRENO_REG_UNUSED;
|
||||
}
|
||||
}
|
||||
|
||||
int adreno_gmu_fenced_write(struct adreno_device *adreno_dev,
|
||||
enum adreno_regs offset, unsigned int val,
|
||||
unsigned int fence_mask);
|
||||
int adreno_clear_pending_transactions(struct kgsl_device *device);
|
||||
void adreno_gmu_send_nmi(struct adreno_device *adreno_dev);
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -1706,4 +1783,98 @@ int adreno_zap_shader_load(struct adreno_device *adreno_dev,
|
|||
irqreturn_t adreno_irq_callbacks(struct adreno_device *adreno_dev,
|
||||
struct adreno_irq_funcs *funcs, u32 status);
|
||||
|
||||
|
||||
/**
|
||||
* adreno_device_probe - Generic adreno device probe function
|
||||
* @pdev: Pointer to the platform device
|
||||
* @adreno_dev: Adreno GPU device handle
|
||||
*
|
||||
* Do the generic setup for the Adreno device. Called from the target specific
|
||||
* probe functions.
|
||||
*
|
||||
* Return: 0 on success or negative on failure
|
||||
*/
|
||||
int adreno_device_probe(struct platform_device *pdev,
|
||||
struct adreno_device *adreno_dev);
|
||||
|
||||
/**
|
||||
* adreno_power_cycle - Suspend and resume the device
|
||||
* @adreno_dev: Pointer to the adreno device
|
||||
* @callback: Function that needs to be executed
|
||||
* @priv: Argument to be passed to the callback
|
||||
*
|
||||
* Certain properties that can be set via sysfs need to power
|
||||
* cycle the device to take effect. This function suspends
|
||||
* the device, executes the callback, and resumes the device.
|
||||
*
|
||||
* Return: 0 on success or negative on failure
|
||||
*/
|
||||
int adreno_power_cycle(struct adreno_device *adreno_dev,
|
||||
void (*callback)(struct adreno_device *adreno_dev, void *priv),
|
||||
void *priv);
|
||||
|
||||
/**
|
||||
* adreno_power_cycle_bool - Power cycle the device to change device setting
|
||||
* @adreno_dev: Pointer to the adreno device
|
||||
* @flag: Flag that needs to be set
|
||||
* @val: The value flag should be set to
|
||||
*
|
||||
* Certain properties that can be set via sysfs need to power cycle the device
|
||||
* to take effect. This function suspends the device, sets the flag, and
|
||||
* resumes the device.
|
||||
*
|
||||
* Return: 0 on success or negative on failure
|
||||
*/
|
||||
int adreno_power_cycle_bool(struct adreno_device *adreno_dev,
|
||||
bool *flag, bool val);
|
||||
|
||||
/**
|
||||
* adreno_power_cycle_u32 - Power cycle the device to change device setting
|
||||
* @adreno_dev: Pointer to the adreno device
|
||||
* @flag: Flag that needs to be set
|
||||
* @val: The value flag should be set to
|
||||
*
|
||||
* Certain properties that can be set via sysfs need to power cycle the device
|
||||
* to take effect. This function suspends the device, sets the flag, and
|
||||
* resumes the device.
|
||||
*
|
||||
* Return: 0 on success or negative on failure
|
||||
*/
|
||||
int adreno_power_cycle_u32(struct adreno_device *adreno_dev,
|
||||
u32 *flag, u32 val);
|
||||
|
||||
/**
|
||||
* adreno_set_active_ctxs_null - Give up active context refcount
|
||||
* @adreno_dev: Adreno GPU device handle
|
||||
*
|
||||
* This puts back the reference for that last active context on
|
||||
* each ringbuffer when going in and out of slumber.
|
||||
*/
|
||||
void adreno_set_active_ctxs_null(struct adreno_device *adreno_dev);
|
||||
|
||||
/**
|
||||
* adreno_get_bus_counters - Allocate the bus dcvs counters
|
||||
* @adreno_dev: Adreno GPU device handle
|
||||
*
|
||||
* This function allocates the various gpu counters to measure
|
||||
* gpu bus usage for bus dcvs
|
||||
*/
|
||||
void adreno_get_bus_counters(struct adreno_device *adreno_dev);
|
||||
|
||||
/**
|
||||
* adreno_clear_dcvs_counters - Clear the dcvs measurements
|
||||
* @adreno_dev: Adreno GPU device handle
|
||||
*
|
||||
* The various dcvs statistics need to be cleared everytime we
|
||||
* power up the gpu
|
||||
*/
|
||||
void adreno_clear_dcvs_counters(struct adreno_device *adreno_dev);
|
||||
|
||||
/**
|
||||
* gmu_fault_snapshot - Set gmu fault and trigger snapshot
|
||||
* @device: Pointer to the kgsl device
|
||||
*
|
||||
* Set the gmu fault and take snapshot when we hit a gmu fault
|
||||
*/
|
||||
void gmu_fault_snapshot(struct kgsl_device *device);
|
||||
#endif /*__ADRENO_H */
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "adreno.h"
|
||||
|
|
@ -567,10 +568,32 @@ static int _a3xx_pwron_fixup(struct adreno_device *adreno_dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void a3xx_platform_setup(struct adreno_device *adreno_dev)
|
||||
static int a3xx_probe(struct platform_device *pdev,
|
||||
u32 chipid, const struct adreno_gpu_core *gpucore)
|
||||
{
|
||||
struct adreno_device *adreno_dev;
|
||||
struct kgsl_device *device;
|
||||
|
||||
adreno_dev = (struct adreno_device *)
|
||||
of_device_get_match_data(&pdev->dev);
|
||||
|
||||
memset(adreno_dev, 0, sizeof(*adreno_dev));
|
||||
|
||||
adreno_dev->gpucore = gpucore;
|
||||
adreno_dev->chipid = chipid;
|
||||
|
||||
adreno_reg_offset_init(gpucore->gpudev->reg_offsets);
|
||||
|
||||
/* Set the GPU busy counter for frequency scaling */
|
||||
adreno_dev->perfctr_pwr_lo = A3XX_RBBM_PERFCTR_PWR_1_LO;
|
||||
|
||||
device = KGSL_DEVICE(adreno_dev);
|
||||
|
||||
timer_setup(&device->idle_timer, kgsl_timer, 0);
|
||||
|
||||
INIT_WORK(&device->idle_check_ws, kgsl_idle_check);
|
||||
|
||||
return adreno_device_probe(pdev, adreno_dev);
|
||||
}
|
||||
|
||||
static int a3xx_send_me_init(struct adreno_device *adreno_dev,
|
||||
|
|
@ -1406,7 +1429,7 @@ struct adreno_gpudev adreno_a3xx_gpudev = {
|
|||
.perfcounters = &a3xx_perfcounters,
|
||||
.irq_handler = a3xx_irq_handler,
|
||||
.vbif_xin_halt_ctrl0_mask = A30X_VBIF_XIN_HALT_CTRL0_MASK,
|
||||
.platform_setup = a3xx_platform_setup,
|
||||
.probe = a3xx_probe,
|
||||
.rb_start = a3xx_rb_start,
|
||||
.init = a3xx_init,
|
||||
.microcode_read = a3xx_microcode_read,
|
||||
|
|
@ -1418,4 +1441,5 @@ struct adreno_gpudev adreno_a3xx_gpudev = {
|
|||
.clk_set_options = a3xx_clk_set_options,
|
||||
.read_alwayson = a3xx_read_alwayson,
|
||||
.hw_isidle = a3xx_hw_isidle,
|
||||
.power_ops = &adreno_power_operations,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/qcom_scm.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
|
|
@ -87,8 +88,22 @@ static void a530_efuse_leakage(struct adreno_device *adreno_dev)
|
|||
adreno_efuse_unmap();
|
||||
}
|
||||
|
||||
static void a5xx_platform_setup(struct adreno_device *adreno_dev)
|
||||
static int a5xx_probe(struct platform_device *pdev,
|
||||
u32 chipid, const struct adreno_gpu_core *gpucore)
|
||||
{
|
||||
struct adreno_device *adreno_dev;
|
||||
struct kgsl_device *device;
|
||||
|
||||
adreno_dev = (struct adreno_device *)
|
||||
of_device_get_match_data(&pdev->dev);
|
||||
|
||||
memset(adreno_dev, 0, sizeof(*adreno_dev));
|
||||
|
||||
adreno_dev->gpucore = gpucore;
|
||||
adreno_dev->chipid = chipid;
|
||||
|
||||
adreno_reg_offset_init(gpucore->gpudev->reg_offsets);
|
||||
|
||||
adreno_dev->sptp_pc_enabled =
|
||||
ADRENO_FEATURE(adreno_dev, ADRENO_SPTP_PC);
|
||||
|
||||
|
|
@ -107,6 +122,14 @@ static void a5xx_platform_setup(struct adreno_device *adreno_dev)
|
|||
|
||||
if (adreno_is_a530(adreno_dev))
|
||||
a530_efuse_leakage(adreno_dev);
|
||||
|
||||
device = KGSL_DEVICE(adreno_dev);
|
||||
|
||||
timer_setup(&device->idle_timer, kgsl_timer, 0);
|
||||
|
||||
INIT_WORK(&device->idle_check_ws, kgsl_idle_check);
|
||||
|
||||
return adreno_device_probe(pdev, adreno_dev);
|
||||
}
|
||||
|
||||
static void _do_fixup(const struct adreno_critical_fixup *fixups, int count,
|
||||
|
|
@ -1433,7 +1456,7 @@ static void a5xx_start(struct adreno_device *adreno_dev)
|
|||
|
||||
/* Enable ISDB mode if requested */
|
||||
if (test_bit(ADRENO_DEVICE_ISDB_ENABLED, &adreno_dev->priv)) {
|
||||
if (!kgsl_active_count_get(device)) {
|
||||
if (!adreno_active_count_get(adreno_dev)) {
|
||||
/*
|
||||
* Disable ME/PFP split timeouts when the debugger is
|
||||
* enabled because the CP doesn't know when a shader is
|
||||
|
|
@ -2970,9 +2993,9 @@ struct adreno_gpudev adreno_a5xx_gpudev = {
|
|||
#ifdef CONFIG_QCOM_KGSL_CORESIGHT
|
||||
.coresight = {&a5xx_coresight},
|
||||
#endif
|
||||
.probe = a5xx_probe,
|
||||
.start = a5xx_start,
|
||||
.snapshot = a5xx_snapshot,
|
||||
.platform_setup = a5xx_platform_setup,
|
||||
.init = a5xx_init,
|
||||
.irq_handler = a5xx_irq_handler,
|
||||
.rb_start = a5xx_rb_start,
|
||||
|
|
@ -2995,4 +3018,5 @@ struct adreno_gpudev adreno_a5xx_gpudev = {
|
|||
.clk_set_options = a5xx_clk_set_options,
|
||||
.read_alwayson = a5xx_read_alwayson,
|
||||
.hw_isidle = a5xx_hw_isidle,
|
||||
.power_ops = &adreno_power_operations,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_fdt.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/soc/qcom/llcc-qcom.h>
|
||||
|
||||
#include "adreno.h"
|
||||
|
|
@ -119,7 +120,7 @@ static u32 a615_pwrup_reglist[] = {
|
|||
|
||||
static int a6xx_get_cp_init_cmds(struct adreno_device *adreno_dev);
|
||||
|
||||
static int a6xx_init(struct adreno_device *adreno_dev)
|
||||
int a6xx_init(struct adreno_device *adreno_dev)
|
||||
{
|
||||
const struct adreno_a6xx_core *a6xx_core = to_a6xx_core(adreno_dev);
|
||||
|
||||
|
|
@ -400,13 +401,7 @@ static void a6xx_set_secvid(struct kgsl_device *device)
|
|||
#define A6XX_APRIV_DEFAULT \
|
||||
((1 << 6) | (1 << 5) | (1 << 3) | (1 << 2) | (1 << 1))
|
||||
|
||||
/*
|
||||
* a6xx_start() - Device start
|
||||
* @adreno_dev: Pointer to adreno device
|
||||
*
|
||||
* a6xx device start
|
||||
*/
|
||||
static void a6xx_start(struct adreno_device *adreno_dev)
|
||||
void a6xx_start(struct adreno_device *adreno_dev)
|
||||
{
|
||||
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
|
||||
const struct adreno_a6xx_core *a6xx_core = to_a6xx_core(adreno_dev);
|
||||
|
|
@ -617,7 +612,6 @@ static void a6xx_start(struct adreno_device *adreno_dev)
|
|||
* 3. HFI
|
||||
* At this point, we are guaranteed all.
|
||||
*/
|
||||
gmu_core_dev_enable_lm(device);
|
||||
|
||||
/* Configure LLCC */
|
||||
a6xx_llc_configure_gpu_scid(adreno_dev);
|
||||
|
|
@ -861,11 +855,7 @@ static int a6xx_post_start(struct adreno_device *adreno_dev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* a6xx_rb_start() - Start the ringbuffer
|
||||
* @adreno_dev: Pointer to adreno device
|
||||
*/
|
||||
static int a6xx_rb_start(struct adreno_device *adreno_dev)
|
||||
int a6xx_rb_start(struct adreno_device *adreno_dev)
|
||||
{
|
||||
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
|
||||
struct adreno_ringbuffer *rb;
|
||||
|
|
@ -1031,11 +1021,7 @@ static bool a6xx_hw_isidle(struct adreno_device *adreno_dev)
|
|||
return (reg & BIT(23)) ? false : true;
|
||||
}
|
||||
|
||||
/*
|
||||
* a6xx_microcode_read() - Read microcode
|
||||
* @adreno_dev: Pointer to adreno device
|
||||
*/
|
||||
static int a6xx_microcode_read(struct adreno_device *adreno_dev)
|
||||
int a6xx_microcode_read(struct adreno_device *adreno_dev)
|
||||
{
|
||||
struct adreno_firmware *sqe_fw = ADRENO_FW(adreno_dev, ADRENO_FW_SQE);
|
||||
const struct adreno_a6xx_core *a6xx_core = to_a6xx_core(adreno_dev);
|
||||
|
|
@ -1139,25 +1125,16 @@ void a6xx_gx_cpr_toggle(struct kgsl_device *device)
|
|||
/**
|
||||
* a6xx_reset() - Helper function to reset the GPU
|
||||
* @device: Pointer to the KGSL device structure for the GPU
|
||||
* @fault: Type of fault. Needed to skip soft reset for MMU fault
|
||||
*
|
||||
* Try to reset the GPU to recover from a fault. First, try to do a low latency
|
||||
* soft reset. If the soft reset fails for some reason, then bring out the big
|
||||
* guns and toggle the footswitch.
|
||||
* Try to reset the GPU to recover from a fault for targets without
|
||||
* a GMU.
|
||||
*/
|
||||
static int a6xx_reset(struct kgsl_device *device, int fault)
|
||||
static int a6xx_reset(struct kgsl_device *device)
|
||||
{
|
||||
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* GMU devices transition to KGSL_STATE_RESET, non GMU devices go
|
||||
* directly to KGSL_STATE_INIT
|
||||
*/
|
||||
if (gmu_core_isenabled(device))
|
||||
kgsl_pwrctrl_change_state(device, KGSL_STATE_RESET);
|
||||
else
|
||||
kgsl_pwrctrl_change_state(device, KGSL_STATE_INIT);
|
||||
kgsl_pwrctrl_change_state(device, KGSL_STATE_INIT);
|
||||
|
||||
/* since device is officially off now clear start bit */
|
||||
clear_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv);
|
||||
|
|
@ -2382,9 +2359,16 @@ static struct adreno_perfcounters a6xx_perfcounters = {
|
|||
ARRAY_SIZE(a6xx_perfcounter_groups),
|
||||
};
|
||||
|
||||
static void a6xx_platform_setup(struct adreno_device *adreno_dev)
|
||||
int a6xx_probe_common(struct platform_device *pdev,
|
||||
struct adreno_device *adreno_dev, u32 chipid,
|
||||
const struct adreno_gpu_core *gpucore)
|
||||
{
|
||||
struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
|
||||
struct adreno_gpudev *gpudev = gpucore->gpudev;
|
||||
|
||||
adreno_dev->gpucore = gpucore;
|
||||
adreno_dev->chipid = chipid;
|
||||
|
||||
adreno_reg_offset_init(gpudev->reg_offsets);
|
||||
|
||||
adreno_dev->hwcg_enabled = true;
|
||||
|
||||
|
|
@ -2421,6 +2405,34 @@ static void a6xx_platform_setup(struct adreno_device *adreno_dev)
|
|||
if (ADRENO_FEATURE(adreno_dev, ADRENO_IFPC))
|
||||
adreno_dev->perfctr_ifpc_lo =
|
||||
A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_4_L;
|
||||
|
||||
|
||||
return adreno_device_probe(pdev, adreno_dev);
|
||||
}
|
||||
|
||||
static int a6xx_probe(struct platform_device *pdev,
|
||||
u32 chipid, const struct adreno_gpu_core *gpucore)
|
||||
{
|
||||
struct adreno_device *adreno_dev;
|
||||
struct kgsl_device *device;
|
||||
int ret;
|
||||
|
||||
adreno_dev = (struct adreno_device *)
|
||||
of_device_get_match_data(&pdev->dev);
|
||||
|
||||
memset(adreno_dev, 0, sizeof(*adreno_dev));
|
||||
|
||||
ret = a6xx_probe_common(pdev, adreno_dev, chipid, gpucore);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
device = KGSL_DEVICE(adreno_dev);
|
||||
|
||||
timer_setup(&device->idle_timer, kgsl_timer, 0);
|
||||
|
||||
INIT_WORK(&device->idle_check_ws, kgsl_idle_check);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -2516,42 +2528,12 @@ static unsigned int a6xx_register_offsets[ADRENO_REG_REGISTER_MAX] = {
|
|||
A6XX_RBBM_GBIF_HALT_ACK),
|
||||
ADRENO_REG_DEFINE(ADRENO_REG_GBIF_HALT, A6XX_GBIF_HALT),
|
||||
ADRENO_REG_DEFINE(ADRENO_REG_GBIF_HALT_ACK, A6XX_GBIF_HALT_ACK),
|
||||
ADRENO_REG_DEFINE(ADRENO_REG_GMU_AO_INTERRUPT_EN,
|
||||
A6XX_GMU_AO_INTERRUPT_EN),
|
||||
ADRENO_REG_DEFINE(ADRENO_REG_GMU_AO_HOST_INTERRUPT_CLR,
|
||||
A6XX_GMU_AO_HOST_INTERRUPT_CLR),
|
||||
ADRENO_REG_DEFINE(ADRENO_REG_GMU_AO_HOST_INTERRUPT_STATUS,
|
||||
A6XX_GMU_AO_HOST_INTERRUPT_STATUS),
|
||||
ADRENO_REG_DEFINE(ADRENO_REG_GMU_AO_HOST_INTERRUPT_MASK,
|
||||
A6XX_GMU_AO_HOST_INTERRUPT_MASK),
|
||||
ADRENO_REG_DEFINE(ADRENO_REG_GMU_PWR_COL_KEEPALIVE,
|
||||
A6XX_GMU_GMU_PWR_COL_KEEPALIVE),
|
||||
ADRENO_REG_DEFINE(ADRENO_REG_GMU_AHB_FENCE_STATUS,
|
||||
A6XX_GMU_AHB_FENCE_STATUS),
|
||||
ADRENO_REG_DEFINE(ADRENO_REG_GMU_HFI_CTRL_STATUS,
|
||||
A6XX_GMU_HFI_CTRL_STATUS),
|
||||
ADRENO_REG_DEFINE(ADRENO_REG_GMU_HFI_VERSION_INFO,
|
||||
A6XX_GMU_HFI_VERSION_INFO),
|
||||
ADRENO_REG_DEFINE(ADRENO_REG_GMU_HFI_SFR_ADDR,
|
||||
A6XX_GMU_HFI_SFR_ADDR),
|
||||
ADRENO_REG_DEFINE(ADRENO_REG_GMU_RPMH_POWER_STATE,
|
||||
A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE),
|
||||
ADRENO_REG_DEFINE(ADRENO_REG_GMU_GMU2HOST_INTR_CLR,
|
||||
A6XX_GMU_GMU2HOST_INTR_CLR),
|
||||
ADRENO_REG_DEFINE(ADRENO_REG_GMU_GMU2HOST_INTR_INFO,
|
||||
A6XX_GMU_GMU2HOST_INTR_INFO),
|
||||
ADRENO_REG_DEFINE(ADRENO_REG_GMU_GMU2HOST_INTR_MASK,
|
||||
A6XX_GMU_GMU2HOST_INTR_MASK),
|
||||
ADRENO_REG_DEFINE(ADRENO_REG_GMU_HOST2GMU_INTR_SET,
|
||||
A6XX_GMU_HOST2GMU_INTR_SET),
|
||||
ADRENO_REG_DEFINE(ADRENO_REG_GMU_HOST2GMU_INTR_CLR,
|
||||
A6XX_GMU_HOST2GMU_INTR_CLR),
|
||||
ADRENO_REG_DEFINE(ADRENO_REG_GMU_HOST2GMU_INTR_RAW_INFO,
|
||||
A6XX_GMU_HOST2GMU_INTR_RAW_INFO),
|
||||
ADRENO_REG_DEFINE(ADRENO_REG_GMU_NMI_CONTROL_STATUS,
|
||||
A6XX_GMU_NMI_CONTROL_STATUS),
|
||||
ADRENO_REG_DEFINE(ADRENO_REG_GMU_CM3_CFG,
|
||||
A6XX_GMU_CM3_CFG),
|
||||
};
|
||||
|
||||
static int cpu_gpu_lock(struct cpu_gpu_lock *lock)
|
||||
|
|
@ -2684,9 +2666,9 @@ u64 a6xx_read_alwayson(struct adreno_device *adreno_dev)
|
|||
|
||||
struct adreno_gpudev adreno_a6xx_gpudev = {
|
||||
.reg_offsets = a6xx_register_offsets,
|
||||
.probe = a6xx_probe,
|
||||
.start = a6xx_start,
|
||||
.snapshot = a6xx_snapshot,
|
||||
.platform_setup = a6xx_platform_setup,
|
||||
.init = a6xx_init,
|
||||
.irq_handler = a6xx_irq_handler,
|
||||
.rb_start = a6xx_rb_start,
|
||||
|
|
@ -2714,4 +2696,110 @@ struct adreno_gpudev adreno_a6xx_gpudev = {
|
|||
#endif
|
||||
.clk_set_options = a6xx_clk_set_options,
|
||||
.read_alwayson = a6xx_read_alwayson,
|
||||
.power_ops = &adreno_power_operations,
|
||||
};
|
||||
|
||||
struct adreno_gpudev adreno_a6xx_gmu_gpudev = {
|
||||
.reg_offsets = a6xx_register_offsets,
|
||||
.probe = a6xx_gmu_device_probe,
|
||||
.start = a6xx_start,
|
||||
.snapshot = a6xx_gmu_snapshot,
|
||||
.init = a6xx_init,
|
||||
.irq_handler = a6xx_irq_handler,
|
||||
.rb_start = a6xx_rb_start,
|
||||
.regulator_enable = a6xx_sptprac_enable,
|
||||
.regulator_disable = a6xx_sptprac_disable,
|
||||
.perfcounters = &a6xx_perfcounters,
|
||||
.read_throttling_counters = a6xx_read_throttling_counters,
|
||||
.microcode_read = a6xx_microcode_read,
|
||||
.gpu_keepalive = a6xx_gpu_keepalive,
|
||||
.hw_isidle = a6xx_hw_isidle,
|
||||
.iommu_fault_block = a6xx_iommu_fault_block,
|
||||
.reset = a6xx_gmu_restart,
|
||||
.preemption_pre_ibsubmit = a6xx_preemption_pre_ibsubmit,
|
||||
.preemption_post_ibsubmit = a6xx_preemption_post_ibsubmit,
|
||||
.preemption_init = a6xx_preemption_init,
|
||||
.preemption_schedule = a6xx_preemption_schedule,
|
||||
.set_marker = a6xx_set_marker,
|
||||
.preemption_context_init = a6xx_preemption_context_init,
|
||||
.preemption_context_destroy = a6xx_preemption_context_destroy,
|
||||
.sptprac_is_on = a6xx_sptprac_is_on,
|
||||
.ccu_invalidate = a6xx_ccu_invalidate,
|
||||
.perfcounter_update = a6xx_perfcounter_update,
|
||||
#ifdef CONFIG_QCOM_KGSL_CORESIGHT
|
||||
.coresight = {&a6xx_coresight, &a6xx_coresight_cx},
|
||||
#endif
|
||||
.clk_set_options = a6xx_clk_set_options,
|
||||
.read_alwayson = a6xx_read_alwayson,
|
||||
.power_ops = &a6xx_gmu_power_ops,
|
||||
};
|
||||
|
||||
struct adreno_gpudev adreno_a6xx_rgmu_gpudev = {
|
||||
.reg_offsets = a6xx_register_offsets,
|
||||
.probe = a6xx_rgmu_device_probe,
|
||||
.start = a6xx_start,
|
||||
.snapshot = a6xx_rgmu_snapshot,
|
||||
.init = a6xx_init,
|
||||
.irq_handler = a6xx_irq_handler,
|
||||
.rb_start = a6xx_rb_start,
|
||||
.regulator_enable = a6xx_sptprac_enable,
|
||||
.regulator_disable = a6xx_sptprac_disable,
|
||||
.perfcounters = &a6xx_perfcounters,
|
||||
.read_throttling_counters = a6xx_read_throttling_counters,
|
||||
.microcode_read = a6xx_microcode_read,
|
||||
.gpu_keepalive = a6xx_gpu_keepalive,
|
||||
.hw_isidle = a6xx_hw_isidle,
|
||||
.iommu_fault_block = a6xx_iommu_fault_block,
|
||||
.reset = a6xx_rgmu_restart,
|
||||
.preemption_pre_ibsubmit = a6xx_preemption_pre_ibsubmit,
|
||||
.preemption_post_ibsubmit = a6xx_preemption_post_ibsubmit,
|
||||
.preemption_init = a6xx_preemption_init,
|
||||
.preemption_schedule = a6xx_preemption_schedule,
|
||||
.set_marker = a6xx_set_marker,
|
||||
.preemption_context_init = a6xx_preemption_context_init,
|
||||
.preemption_context_destroy = a6xx_preemption_context_destroy,
|
||||
.sptprac_is_on = a6xx_sptprac_is_on,
|
||||
.ccu_invalidate = a6xx_ccu_invalidate,
|
||||
.perfcounter_update = a6xx_perfcounter_update,
|
||||
#ifdef CONFIG_QCOM_KGSL_CORESIGHT
|
||||
.coresight = {&a6xx_coresight, &a6xx_coresight_cx},
|
||||
#endif
|
||||
.clk_set_options = a6xx_clk_set_options,
|
||||
.read_alwayson = a6xx_read_alwayson,
|
||||
.power_ops = &a6xx_rgmu_power_ops,
|
||||
};
|
||||
|
||||
struct adreno_gpudev adreno_a630_gpudev = {
|
||||
.reg_offsets = a6xx_register_offsets,
|
||||
.probe = a6xx_gmu_device_probe,
|
||||
.start = a6xx_start,
|
||||
.snapshot = a6xx_gmu_snapshot,
|
||||
.init = a6xx_init,
|
||||
.irq_handler = a6xx_irq_handler,
|
||||
.rb_start = a6xx_rb_start,
|
||||
.regulator_enable = a6xx_sptprac_enable,
|
||||
.regulator_disable = a6xx_sptprac_disable,
|
||||
.perfcounters = &a6xx_perfcounters,
|
||||
.read_throttling_counters = a6xx_read_throttling_counters,
|
||||
.microcode_read = a6xx_microcode_read,
|
||||
.gpu_keepalive = a6xx_gpu_keepalive,
|
||||
.hw_isidle = a6xx_hw_isidle,
|
||||
.iommu_fault_block = a6xx_iommu_fault_block,
|
||||
.reset = a6xx_gmu_restart,
|
||||
.preemption_pre_ibsubmit = a6xx_preemption_pre_ibsubmit,
|
||||
.preemption_post_ibsubmit = a6xx_preemption_post_ibsubmit,
|
||||
.preemption_init = a6xx_preemption_init,
|
||||
.preemption_schedule = a6xx_preemption_schedule,
|
||||
.set_marker = a6xx_set_marker,
|
||||
.preemption_context_init = a6xx_preemption_context_init,
|
||||
.preemption_context_destroy = a6xx_preemption_context_destroy,
|
||||
.sptprac_is_on = a6xx_sptprac_is_on,
|
||||
.ccu_invalidate = a6xx_ccu_invalidate,
|
||||
.perfcounter_update = a6xx_perfcounter_update,
|
||||
#ifdef CONFIG_QCOM_KGSL_CORESIGHT
|
||||
.coresight = {&a6xx_coresight, &a6xx_coresight_cx},
|
||||
#endif
|
||||
.clk_set_options = a6xx_clk_set_options,
|
||||
.read_alwayson = a6xx_read_alwayson,
|
||||
.power_ops = &a630_gmu_power_ops,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,8 +7,27 @@
|
|||
#define _ADRENO_A6XX_H_
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iopoll.h>
|
||||
|
||||
#include "a6xx_reg.h"
|
||||
#include "adreno_a6xx_gmu.h"
|
||||
#include "adreno_a6xx_rgmu.h"
|
||||
|
||||
extern const struct adreno_power_ops a6xx_gmu_power_ops;
|
||||
extern const struct adreno_power_ops a6xx_rgmu_power_ops;
|
||||
extern const struct adreno_power_ops a630_gmu_power_ops;
|
||||
|
||||
/**
|
||||
* struct a6xx_device - Container for the a6xx_device
|
||||
*/
|
||||
struct a6xx_device {
|
||||
/** @gmu: Container for the a6xx GMU device */
|
||||
struct a6xx_gmu_device gmu;
|
||||
/** @rgmu: Container for the a6xx rGMU device */
|
||||
struct a6xx_rgmu_device rgmu;
|
||||
/** @adreno_dev: Container for the generic adreno device */
|
||||
struct adreno_device adreno_dev;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct a6xx_protected_regs - container for a protect register span
|
||||
|
|
@ -176,74 +195,35 @@ to_a6xx_core(struct adreno_device *adreno_dev)
|
|||
return container_of(core, struct adreno_a6xx_core, base);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* timed_poll_check() - polling *gmu* register at given offset until
|
||||
* its value changed to match expected value. The function times
|
||||
* out and returns after given duration if register is not updated
|
||||
* as expected.
|
||||
*
|
||||
* @device: Pointer to KGSL device
|
||||
* @offset: Register offset
|
||||
* @offset: Register offset in dwords
|
||||
* @expected_ret: expected register value that stops polling
|
||||
* @timout: number of jiffies to abort the polling
|
||||
* @timeout_ms: time in milliseconds to poll the register
|
||||
* @mask: bitmask to filter register value to match expected_ret
|
||||
*/
|
||||
static inline int timed_poll_check(struct kgsl_device *device,
|
||||
unsigned int offset, unsigned int expected_ret,
|
||||
unsigned int timeout, unsigned int mask)
|
||||
unsigned int timeout_ms, unsigned int mask)
|
||||
{
|
||||
unsigned long t;
|
||||
unsigned int value;
|
||||
u32 val;
|
||||
void __iomem *addr = device->gmu_core.reg_virt +
|
||||
((offset - device->gmu_core.gmu2gpu_offset) << 2);
|
||||
|
||||
t = jiffies + msecs_to_jiffies(timeout);
|
||||
if (WARN(!gmu_core_is_register_offset(device, offset),
|
||||
"Out of bounds register read: 0x%x\n", offset))
|
||||
return -EINVAL;
|
||||
|
||||
do {
|
||||
gmu_core_regread(device, offset, &value);
|
||||
if ((value & mask) == expected_ret)
|
||||
return 0;
|
||||
/* Wait 100us to reduce unnecessary AHB bus traffic */
|
||||
usleep_range(10, 100);
|
||||
} while (!time_after(jiffies, t));
|
||||
if (readl_poll_timeout(addr, val, (val & mask) == expected_ret, 100,
|
||||
timeout_ms * 1000))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
/* Double check one last time */
|
||||
gmu_core_regread(device, offset, &value);
|
||||
if ((value & mask) == expected_ret)
|
||||
return 0;
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static inline int timed_poll_check_rscc(struct kgsl_device *device,
|
||||
unsigned int offset, unsigned int expected_ret,
|
||||
unsigned int timeout, unsigned int mask)
|
||||
{
|
||||
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
|
||||
unsigned long t;
|
||||
unsigned int value;
|
||||
|
||||
t = jiffies + msecs_to_jiffies(timeout);
|
||||
|
||||
do {
|
||||
if (adreno_is_a650_family(adreno_dev))
|
||||
adreno_rscc_regread(adreno_dev, offset, &value);
|
||||
else
|
||||
gmu_core_regread(device, offset + RSCC_OFFSET_LEGACY,
|
||||
&value);
|
||||
if ((value & mask) == expected_ret)
|
||||
return 0;
|
||||
/* Wait 100us to reduce unnecessary AHB bus traffic */
|
||||
usleep_range(10, 100);
|
||||
} while (!time_after(jiffies, t));
|
||||
|
||||
/* Double check one last time */
|
||||
if (adreno_is_a650_family(adreno_dev))
|
||||
adreno_rscc_regread(adreno_dev, offset, &value);
|
||||
else
|
||||
gmu_core_regread(device, offset + RSCC_OFFSET_LEGACY, &value);
|
||||
if ((value & mask) == expected_ret)
|
||||
return 0;
|
||||
|
||||
return -ETIMEDOUT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Preemption functions */
|
||||
|
|
@ -275,10 +255,67 @@ void a6xx_gmu_sptprac_disable(struct adreno_device *adreno_dev);
|
|||
bool a6xx_gmu_sptprac_is_on(struct adreno_device *adreno_dev);
|
||||
|
||||
/**
|
||||
* a6xx_read_alwayson: Read the current always on clock value
|
||||
* a6xx_read_alwayson - Read the current always on clock value
|
||||
* @adreno_dev: An Adreno GPU handle
|
||||
*
|
||||
* Return: The current value of the GMU always on counter
|
||||
*/
|
||||
u64 a6xx_read_alwayson(struct adreno_device *adreno_dev);
|
||||
|
||||
/**
|
||||
* a6xx_start - Program a6xx registers
|
||||
* @adreno_dev: An Adreno GPU handle
|
||||
*
|
||||
* This function does all a6xx register programming every
|
||||
* time we boot the gpu
|
||||
*/
|
||||
void a6xx_start(struct adreno_device *adreno_dev);
|
||||
|
||||
/**
|
||||
* a6xx_init - Initialize a6xx resources
|
||||
* @adreno_dev: An Adreno GPU handle
|
||||
*
|
||||
* This function does a6xx specific one time initialization
|
||||
* and is invoked when the very first client opens a
|
||||
* kgsl instance
|
||||
*
|
||||
* Return: Zero on success and negative error on failure
|
||||
*/
|
||||
int a6xx_init(struct adreno_device *adreno_dev);
|
||||
|
||||
/**
|
||||
* a6xx_rb_start - A6xx specific ringbuffer setup
|
||||
* @adreno_dev: An Adreno GPU handle
|
||||
*
|
||||
* This function does a6xx specific ringbuffer setup and
|
||||
* attempts to submit CP INIT and bring GPU out of secure mode
|
||||
*
|
||||
* Return: Zero on success and negative error on failure
|
||||
*/
|
||||
int a6xx_rb_start(struct adreno_device *adreno_dev);
|
||||
|
||||
/**
|
||||
* a6xx_microcode_read - Get the cp microcode from the filesystem
|
||||
* @adreno_dev: An Adreno GPU handle
|
||||
*
|
||||
* This function gets the firmware from filesystem and sets up
|
||||
* the micorocode global buffer
|
||||
*
|
||||
* Return: Zero on success and negative error on failure
|
||||
*/
|
||||
int a6xx_microcode_read(struct adreno_device *adreno_dev);
|
||||
|
||||
/**
|
||||
* a6xx_probe_common - Probe common a6xx resources
|
||||
* @pdev: Pointer to the platform device
|
||||
* @adreno_dev: Pointer to the adreno device
|
||||
* @chipid: Chipid of the target
|
||||
* @gpucore: Pointer to the gpucore strucure
|
||||
*
|
||||
* This function sets up the a6xx resources common across all
|
||||
* a6xx targets
|
||||
*/
|
||||
int a6xx_probe_common(struct platform_device *pdev,
|
||||
struct adreno_device *adreno_dev, u32 chipid,
|
||||
const struct adreno_gpu_core *gpucore);
|
||||
#endif
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -2,20 +2,19 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
#ifndef __KGSL_GMU_H
|
||||
#define __KGSL_GMU_H
|
||||
#ifndef __ADRENO_A6XX_GMU_H
|
||||
#define __ADRENO_A6XX_GMU_H
|
||||
|
||||
#include <linux/mailbox_client.h>
|
||||
|
||||
#include "adreno_a6xx_hfi.h"
|
||||
#include "kgsl_gmu_core.h"
|
||||
#include "kgsl_hfi.h"
|
||||
|
||||
#define GMU_FREQUENCY 200000000
|
||||
|
||||
#define GMU_PWR_LEVELS 2
|
||||
#define GMU_FREQUENCY 200000000
|
||||
#define MAX_GMUFW_SIZE 0x8000 /* in bytes */
|
||||
|
||||
#define BWMEM_SIZE (12 + (4 * NUM_BW_LEVELS)) /*in bytes*/
|
||||
|
||||
#define GMU_VER_MAJOR(ver) (((ver) >> 28) & 0xF)
|
||||
#define GMU_VER_MINOR(ver) (((ver) >> 16) & 0xFFF)
|
||||
#define GMU_VER_STEP(ver) ((ver) & 0xFFFF)
|
||||
|
|
@ -81,9 +80,6 @@ struct gmu_block_header {
|
|||
/* GMU memdesc entries */
|
||||
#define GMU_KERNEL_ENTRIES 16
|
||||
|
||||
extern struct gmu_dev_ops adreno_a6xx_gmudev;
|
||||
#define KGSL_GMU_DEVICE(_a) ((struct gmu_device *)((_a)->gmu_core.ptr))
|
||||
|
||||
enum gmu_mem_type {
|
||||
GMU_ITCM = 0,
|
||||
GMU_ICACHE,
|
||||
|
|
@ -96,7 +92,7 @@ enum gmu_mem_type {
|
|||
};
|
||||
|
||||
enum gmu_context_index {
|
||||
GMU_CONTEXT_USER = 0,
|
||||
GMU_CONTEXT_USER,
|
||||
GMU_CONTEXT_KERNEL,
|
||||
};
|
||||
|
||||
|
|
@ -106,16 +102,12 @@ enum gmu_context_index {
|
|||
* @gmuaddr: GPU virtual address
|
||||
* @physaddr: Physical address of the memory object
|
||||
* @size: Size of the memory object
|
||||
* @mem_type: memory type for this memory
|
||||
* @ctx_idx: GMU IOMMU context idx
|
||||
*/
|
||||
struct gmu_memdesc {
|
||||
void *hostptr;
|
||||
uint64_t gmuaddr;
|
||||
u32 gmuaddr;
|
||||
phys_addr_t physaddr;
|
||||
uint64_t size;
|
||||
enum gmu_mem_type mem_type;
|
||||
enum gmu_context_index ctx_idx;
|
||||
u32 size;
|
||||
};
|
||||
|
||||
struct rpmh_votes_t {
|
||||
|
|
@ -123,14 +115,6 @@ struct rpmh_votes_t {
|
|||
uint32_t cx_votes[MAX_CX_LEVELS];
|
||||
};
|
||||
|
||||
enum gmu_load_mode {
|
||||
CACHED_LOAD_BOOT,
|
||||
CACHED_BOOT,
|
||||
TCM_BOOT,
|
||||
TCM_LOAD_BOOT,
|
||||
INVALID_LOAD
|
||||
};
|
||||
|
||||
struct kgsl_mailbox {
|
||||
struct mbox_client client;
|
||||
struct mbox_chan *channel;
|
||||
|
|
@ -138,10 +122,27 @@ struct kgsl_mailbox {
|
|||
|
||||
struct icc_path;
|
||||
|
||||
struct gmu_vma_entry {
|
||||
/** @start: Starting virtual address of the vma */
|
||||
u32 start;
|
||||
/** @size: Size of this vma */
|
||||
u32 size;
|
||||
/** @next_va: Next available virtual address in this vma */
|
||||
u32 next_va;
|
||||
};
|
||||
|
||||
enum {
|
||||
GMU_PRIV_FIRST_BOOT_DONE = 0,
|
||||
GMU_PRIV_GPU_STARTED,
|
||||
GMU_PRIV_HFI_STARTED,
|
||||
GMU_PRIV_RSCC_SLEEP_DONE,
|
||||
GMU_PRIV_PM_SUSPEND,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct gmu_device - GMU device structure
|
||||
* struct a6xx_gmu_device - GMU device structure
|
||||
* @ver: GMU Version information
|
||||
* @gmu_interrupt_num: GMU interrupt number
|
||||
* @irq: GMU interrupt number
|
||||
* @fw_image: GMU FW image
|
||||
* @hfi_mem: pointer to HFI shared memory
|
||||
* @dump_mem: pointer to GMU debug dump memory
|
||||
|
|
@ -155,7 +156,6 @@ struct icc_path;
|
|||
subsystem peripherals
|
||||
* @gx_gdsc: GX headswitch that controls power of GPU subsystem
|
||||
* @clks: GPU subsystem clocks required for GMU functionality
|
||||
* @load_mode: GMU FW load/boot mode
|
||||
* @wakeup_pwrlevel: GPU wake up power/DCVS level in case different
|
||||
* than default power level
|
||||
* @idle_level: Minimal GPU idle power level
|
||||
|
|
@ -163,7 +163,7 @@ struct icc_path;
|
|||
* @mailbox: Messages to AOP for ACD enable/disable go through this
|
||||
* @log_wptr_retention: Store the log wptr offset on slumber
|
||||
*/
|
||||
struct gmu_device {
|
||||
struct a6xx_gmu_device {
|
||||
struct {
|
||||
u32 core;
|
||||
u32 core_dev;
|
||||
|
|
@ -172,48 +172,129 @@ struct gmu_device {
|
|||
u32 hfi;
|
||||
} ver;
|
||||
struct platform_device *pdev;
|
||||
int gmu_interrupt_num;
|
||||
int irq;
|
||||
const struct firmware *fw_image;
|
||||
struct gmu_memdesc *hfi_mem;
|
||||
struct gmu_memdesc *dump_mem;
|
||||
struct gmu_memdesc *gmu_log;
|
||||
struct kgsl_hfi hfi;
|
||||
struct a6xx_hfi hfi;
|
||||
/** @pwrlevels: Array of GMU power levels */
|
||||
struct {
|
||||
/** @freq: GPU frequency */
|
||||
unsigned long freq;
|
||||
/** @level: Voltage level */
|
||||
u32 level;
|
||||
} pwrlevels[MAX_GX_LEVELS];
|
||||
unsigned int num_gpupwrlevels;
|
||||
unsigned int num_bwlevels;
|
||||
unsigned int num_cnocbwlevels;
|
||||
struct rpmh_votes_t rpmh_votes;
|
||||
struct regulator *cx_gdsc;
|
||||
struct regulator *gx_gdsc;
|
||||
struct clk_bulk_data *clks;
|
||||
/** @num_clks: Number of entries in the @clks array */
|
||||
int num_clks;
|
||||
enum gmu_load_mode load_mode;
|
||||
unsigned int wakeup_pwrlevel;
|
||||
unsigned int idle_level;
|
||||
unsigned int fault_count;
|
||||
struct kgsl_mailbox mailbox;
|
||||
bool preallocations;
|
||||
struct gmu_memdesc kmem_entries[GMU_KERNEL_ENTRIES];
|
||||
unsigned long kmem_bitmap;
|
||||
const struct gmu_vma_entry *vma;
|
||||
/** @gmu_globals: Array to store gmu global buffers */
|
||||
struct gmu_memdesc gmu_globals[GMU_KERNEL_ENTRIES];
|
||||
/** @global_entries: To keep track of number of gmu buffers */
|
||||
u32 global_entries;
|
||||
struct gmu_vma_entry *vma;
|
||||
unsigned int log_wptr_retention;
|
||||
/** @cm3_fault: whether gmu received a cm3 fault interrupt */
|
||||
atomic_t cm3_fault;
|
||||
/**
|
||||
* @itcm_shadow: Copy of the itcm block in firmware binary used for
|
||||
* snapshot
|
||||
*/
|
||||
void *itcm_shadow;
|
||||
/** @flags: Internal gmu flags */
|
||||
unsigned long flags;
|
||||
/** @rscc_virt: Pointer where RSCC block is mapped */
|
||||
void __iomem *rscc_virt;
|
||||
};
|
||||
|
||||
struct gmu_memdesc *gmu_get_memdesc(struct gmu_device *gmu,
|
||||
unsigned int addr, unsigned int size);
|
||||
unsigned int gmu_get_memtype_base(struct gmu_device *gmu,
|
||||
enum gmu_mem_type type);
|
||||
/* Helper function to get to a6xx gmu device from adreno device */
|
||||
struct a6xx_gmu_device *to_a6xx_gmu(struct adreno_device *adreno_dev);
|
||||
|
||||
int gmu_prealloc_req(struct kgsl_device *device, struct gmu_block_header *blk);
|
||||
int gmu_cache_finalize(struct kgsl_device *device);
|
||||
/* Helper function to get to adreno device from a6xx gmu device */
|
||||
struct adreno_device *a6xx_gmu_to_adreno(struct a6xx_gmu_device *gmu);
|
||||
|
||||
#endif /* __KGSL_GMU_H */
|
||||
/**
|
||||
* reserve_gmu_kernel_block() - Allocate a gmu buffer
|
||||
* @gmu: Pointer to the a6xx gmu device
|
||||
* @addr: Desired gmu virtual address
|
||||
* @size: Size of the buffer in bytes
|
||||
* @vma_id: Target gmu vma where this bufer should be mapped
|
||||
*
|
||||
* This function allocates a buffer and maps it in
|
||||
* the desired gmu vma
|
||||
*
|
||||
* Return: Pointer to the memory descriptor or error pointer on failure
|
||||
*/
|
||||
struct gmu_memdesc *reserve_gmu_kernel_block(struct a6xx_gmu_device *gmu,
|
||||
u32 addr, u32 size, u32 vma_id);
|
||||
|
||||
/**
|
||||
* a6xx_build_rpmh_tables - Build the rpmh tables
|
||||
* @adreno_dev: Pointer to the adreno device
|
||||
*
|
||||
* This function creates the gpu dcvs and bw tables
|
||||
*
|
||||
* Return: 0 on success and negative error on failure
|
||||
*/
|
||||
int a6xx_build_rpmh_tables(struct adreno_device *adreno_dev);
|
||||
|
||||
/**
|
||||
* a6xx_gmu_gx_is_on - Check if GX is on
|
||||
* @device: Pointer to KGSL device
|
||||
*
|
||||
* This function reads pwr status registers to check if GX
|
||||
* is on or off
|
||||
*/
|
||||
bool a6xx_gmu_gx_is_on(struct kgsl_device *device);
|
||||
|
||||
/**
|
||||
* a6xx_gmu_device_snapshot - A6XX GMU snapshot function
|
||||
* @device: Device being snapshotted
|
||||
* @snapshot: Pointer to the snapshot instance
|
||||
*
|
||||
* This is where all of the A6XX GMU specific bits and pieces are grabbed
|
||||
* into the snapshot memory
|
||||
*/
|
||||
void a6xx_gmu_device_snapshot(struct kgsl_device *device,
|
||||
struct kgsl_snapshot *snapshot);
|
||||
|
||||
/**
|
||||
* a6xx_gmu_device_probe - A6XX GMU snapshot function
|
||||
* @pdev: Pointer to the platform device
|
||||
* @chipid: Chipid of the target
|
||||
* @gpucore: Pointer to the gpucore
|
||||
*
|
||||
* The target specific probe function for gmu based a6xx targets.
|
||||
*/
|
||||
int a6xx_gmu_device_probe(struct platform_device *pdev,
|
||||
u32 chipid, const struct adreno_gpu_core *gpucore);
|
||||
|
||||
/**
|
||||
* a6xx_gmu_restart - Reset and restart the gmu
|
||||
* @device: Pointer to the kgsl device
|
||||
*
|
||||
* Return: 0 on success or negative error on failure
|
||||
*/
|
||||
int a6xx_gmu_restart(struct kgsl_device *device);
|
||||
|
||||
/**
|
||||
* a6xx_enable_gpu_irq - Enable gpu interrupt
|
||||
* @adreno_dev: Pointer to the adreno device
|
||||
*/
|
||||
void a6xx_enable_gpu_irq(struct adreno_device *adreno_dev);
|
||||
|
||||
/**
|
||||
* a6xx_disable_gpu_irq - Disable gpu interrupt
|
||||
* @adreno_dev: Pointer to the adreno device
|
||||
*/
|
||||
void a6xx_disable_gpu_irq(struct adreno_device *adreno_dev);
|
||||
|
||||
/**
|
||||
* a6xx_gmu_snapshot- Take snapshot for gmu targets
|
||||
* @adreno_dev: Pointer to the adreno device
|
||||
* @snapshot: Pointer to the snapshot structure
|
||||
*
|
||||
* Send an NMI to gmu if we hit a gmu fault. Then take gmu
|
||||
* snapshot and carry on with rest of the a6xx snapshot
|
||||
*/
|
||||
void a6xx_gmu_snapshot(struct adreno_device *adreno_dev,
|
||||
struct kgsl_snapshot *snapshot);
|
||||
#endif
|
||||
421
drivers/gpu/msm/adreno_a6xx_gmu_snapshot.c
Normal file
421
drivers/gpu/msm/adreno_a6xx_gmu_snapshot.c
Normal file
|
|
@ -0,0 +1,421 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "a6xx_reg.h"
|
||||
#include "adreno.h"
|
||||
#include "adreno_a6xx_gmu.h"
|
||||
#include "adreno_snapshot.h"
|
||||
#include "kgsl_device.h"
|
||||
|
||||
static const unsigned int a6xx_gmu_gx_registers[] = {
|
||||
/* GMU GX */
|
||||
0x1A800, 0x1A800, 0x1A810, 0x1A813, 0x1A816, 0x1A816, 0x1A818, 0x1A81B,
|
||||
0x1A81E, 0x1A81E, 0x1A820, 0x1A823, 0x1A826, 0x1A826, 0x1A828, 0x1A82B,
|
||||
0x1A82E, 0x1A82E, 0x1A830, 0x1A833, 0x1A836, 0x1A836, 0x1A838, 0x1A83B,
|
||||
0x1A83E, 0x1A83E, 0x1A840, 0x1A843, 0x1A846, 0x1A846, 0x1A880, 0x1A884,
|
||||
0x1A900, 0x1A92B, 0x1A940, 0x1A940,
|
||||
};
|
||||
|
||||
static const unsigned int a6xx_gmu_tcm_registers[] = {
|
||||
/* ITCM */
|
||||
0x1B400, 0x1C3FF,
|
||||
/* DTCM */
|
||||
0x1C400, 0x1D3FF,
|
||||
};
|
||||
|
||||
static const unsigned int a6xx_gmu_registers[] = {
|
||||
/* GMU CX */
|
||||
0x1F400, 0x1F407, 0x1F410, 0x1F412, 0x1F500, 0x1F500, 0x1F507, 0x1F50A,
|
||||
0x1F800, 0x1F804, 0x1F807, 0x1F808, 0x1F80B, 0x1F80C, 0x1F80F, 0x1F81C,
|
||||
0x1F824, 0x1F82A, 0x1F82D, 0x1F830, 0x1F840, 0x1F853, 0x1F887, 0x1F889,
|
||||
0x1F8A0, 0x1F8A2, 0x1F8A4, 0x1F8AF, 0x1F8C0, 0x1F8C3, 0x1F8D0, 0x1F8D0,
|
||||
0x1F8E4, 0x1F8E4, 0x1F8E8, 0x1F8EC, 0x1F900, 0x1F903, 0x1F940, 0x1F940,
|
||||
0x1F942, 0x1F944, 0x1F94C, 0x1F94D, 0x1F94F, 0x1F951, 0x1F954, 0x1F954,
|
||||
0x1F957, 0x1F958, 0x1F95D, 0x1F95D, 0x1F962, 0x1F962, 0x1F964, 0x1F965,
|
||||
0x1F980, 0x1F986, 0x1F990, 0x1F99E, 0x1F9C0, 0x1F9C0, 0x1F9C5, 0x1F9CC,
|
||||
0x1F9E0, 0x1F9E2, 0x1F9F0, 0x1F9F0, 0x1FA00, 0x1FA01,
|
||||
/* GMU AO */
|
||||
0x23B00, 0x23B16,
|
||||
/* GPU CC */
|
||||
0x24000, 0x24012, 0x24040, 0x24052, 0x24400, 0x24404, 0x24407, 0x2440B,
|
||||
0x24415, 0x2441C, 0x2441E, 0x2442D, 0x2443C, 0x2443D, 0x2443F, 0x24440,
|
||||
0x24442, 0x24449, 0x24458, 0x2445A, 0x24540, 0x2455E, 0x24800, 0x24802,
|
||||
0x24C00, 0x24C02, 0x25400, 0x25402, 0x25800, 0x25802, 0x25C00, 0x25C02,
|
||||
0x26000, 0x26002,
|
||||
/* GPU CC ACD */
|
||||
0x26400, 0x26416, 0x26420, 0x26427,
|
||||
};
|
||||
|
||||
static const unsigned int a660_gmu_registers[] = {
|
||||
/* GMU CX */
|
||||
0x1F408, 0x1F40D, 0x1F40F, 0x1F40F, 0x1F50B, 0x1F50B, 0x1F860, 0x1F860,
|
||||
0x1F870, 0x1F877, 0x1F8C4, 0x1F8C4, 0x1F8F0, 0x1F8F1, 0x1F948, 0x1F94A,
|
||||
0x1F966, 0x1F96B, 0x1F970, 0x1F970, 0x1F972, 0x1F979, 0x1F9CD, 0x1F9D4,
|
||||
0x1FA02, 0x1FA03, 0x20000, 0x20001, 0x20004, 0x20004, 0x20008, 0x20012,
|
||||
0x20018, 0x20018,
|
||||
};
|
||||
|
||||
static const unsigned int a630_rscc_snapshot_registers[] = {
|
||||
0x23400, 0x23434, 0x23436, 0x23436, 0x23480, 0x23484, 0x23489, 0x2348C,
|
||||
0x23491, 0x23494, 0x23499, 0x2349C, 0x234A1, 0x234A4, 0x234A9, 0x234AC,
|
||||
0x23500, 0x23502, 0x23504, 0x23507, 0x23514, 0x23519, 0x23524, 0x2352B,
|
||||
0x23580, 0x23597, 0x23740, 0x23741, 0x23744, 0x23747, 0x2374C, 0x23787,
|
||||
0x237EC, 0x237EF, 0x237F4, 0x2382F, 0x23894, 0x23897, 0x2389C, 0x238D7,
|
||||
0x2393C, 0x2393F, 0x23944, 0x2397F,
|
||||
};
|
||||
|
||||
static const unsigned int a6xx_rscc_snapshot_registers[] = {
|
||||
0x23400, 0x23434, 0x23436, 0x23436, 0x23440, 0x23440, 0x23480, 0x23484,
|
||||
0x23489, 0x2348C, 0x23491, 0x23494, 0x23499, 0x2349C, 0x234A1, 0x234A4,
|
||||
0x234A9, 0x234AC, 0x23500, 0x23502, 0x23504, 0x23507, 0x23514, 0x23519,
|
||||
0x23524, 0x2352B, 0x23580, 0x23597, 0x23740, 0x23741, 0x23744, 0x23747,
|
||||
0x2374C, 0x23787, 0x237EC, 0x237EF, 0x237F4, 0x2382F, 0x23894, 0x23897,
|
||||
0x2389C, 0x238D7, 0x2393C, 0x2393F, 0x23944, 0x2397F,
|
||||
};
|
||||
|
||||
static const unsigned int a650_rscc_registers[] = {
|
||||
0x38000, 0x38034, 0x38036, 0x38036, 0x38040, 0x38042, 0x38080, 0x38084,
|
||||
0x38089, 0x3808C, 0x38091, 0x38094, 0x38099, 0x3809C, 0x380A1, 0x380A4,
|
||||
0x380A9, 0x380AC, 0x38100, 0x38102, 0x38104, 0x38107, 0x38114, 0x38119,
|
||||
0x38124, 0x3812E, 0x38180, 0x38197, 0x38340, 0x38341, 0x38344, 0x38347,
|
||||
0x3834C, 0x3834F, 0x38351, 0x38354, 0x38356, 0x38359, 0x3835B, 0x3835E,
|
||||
0x38360, 0x38363, 0x38365, 0x38368, 0x3836A, 0x3836D, 0x3836F, 0x38372,
|
||||
0x383EC, 0x383EF, 0x383F4, 0x383F7, 0x383F9, 0x383FC, 0x383FE, 0x38401,
|
||||
0x38403, 0x38406, 0x38408, 0x3840B, 0x3840D, 0x38410, 0x38412, 0x38415,
|
||||
0x38417, 0x3841A, 0x38494, 0x38497, 0x3849C, 0x3849F, 0x384A1, 0x384A4,
|
||||
0x384A6, 0x384A9, 0x384AB, 0x384AE, 0x384B0, 0x384B3, 0x384B5, 0x384B8,
|
||||
0x384BA, 0x384BD, 0x384BF, 0x384C2, 0x3853C, 0x3853F, 0x38544, 0x38547,
|
||||
0x38549, 0x3854C, 0x3854E, 0x38551, 0x38553, 0x38556, 0x38558, 0x3855B,
|
||||
0x3855D, 0x38560, 0x38562, 0x38565, 0x38567, 0x3856A, 0x385E4, 0x385E7,
|
||||
0x385EC, 0x385EF, 0x385F1, 0x385F4, 0x385F6, 0x385F9, 0x385FB, 0x385FE,
|
||||
0x38600, 0x38603, 0x38605, 0x38608, 0x3860A, 0x3860D, 0x3860F, 0x38612,
|
||||
0x3868C, 0x3868F, 0x38694, 0x38697, 0x38699, 0x3869C, 0x3869E, 0x386A1,
|
||||
0x386A3, 0x386A6, 0x386A8, 0x386AB, 0x386AD, 0x386B0, 0x386B2, 0x386B5,
|
||||
0x386B7, 0x386BA, 0x38734, 0x38737, 0x3873C, 0x3873F, 0x38741, 0x38744,
|
||||
0x38746, 0x38749, 0x3874B, 0x3874E, 0x38750, 0x38753, 0x38755, 0x38758,
|
||||
0x3875A, 0x3875D, 0x3875F, 0x38762, 0x387DC, 0x387DF, 0x387E4, 0x387E7,
|
||||
0x387E9, 0x387EC, 0x387EE, 0x387F1, 0x387F3, 0x387F6, 0x387F8, 0x387FB,
|
||||
0x387FD, 0x38800, 0x38802, 0x38805, 0x38807, 0x3880A, 0x38884, 0x38887,
|
||||
0x3888C, 0x3888F, 0x38891, 0x38894, 0x38896, 0x38899, 0x3889B, 0x3889E,
|
||||
0x388A0, 0x388A3, 0x388A5, 0x388A8, 0x388AA, 0x388AD, 0x388AF, 0x388B2,
|
||||
0x3892C, 0x3892F, 0x38934, 0x38937, 0x38939, 0x3893C, 0x3893E, 0x38941,
|
||||
0x38943, 0x38946, 0x38948, 0x3894B, 0x3894D, 0x38950, 0x38952, 0x38955,
|
||||
0x38957, 0x3895A, 0x38B50, 0x38B51, 0x38B53, 0x38B55, 0x38B5A, 0x38B5A,
|
||||
0x38B5F, 0x38B5F, 0x38B64, 0x38B64, 0x38B69, 0x38B69, 0x38B6E, 0x38B6E,
|
||||
0x38B73, 0x38B73, 0x38BF8, 0x38BF8, 0x38BFD, 0x38BFD, 0x38C02, 0x38C02,
|
||||
0x38C07, 0x38C07, 0x38C0C, 0x38C0C, 0x38C11, 0x38C11, 0x38C16, 0x38C16,
|
||||
0x38C1B, 0x38C1B, 0x38CA0, 0x38CA0, 0x38CA5, 0x38CA5, 0x38CAA, 0x38CAA,
|
||||
0x38CAF, 0x38CAF, 0x38CB4, 0x38CB4, 0x38CB9, 0x38CB9, 0x38CBE, 0x38CBE,
|
||||
0x38CC3, 0x38CC3, 0x38D48, 0x38D48, 0x38D4D, 0x38D4D, 0x38D52, 0x38D52,
|
||||
0x38D57, 0x38D57, 0x38D5C, 0x38D5C, 0x38D61, 0x38D61, 0x38D66, 0x38D66,
|
||||
0x38D6B, 0x38D6B, 0x38DF0, 0x38DF0, 0x38DF5, 0x38DF5, 0x38DFA, 0x38DFA,
|
||||
0x38DFF, 0x38DFF, 0x38E04, 0x38E04, 0x38E09, 0x38E09, 0x38E0E, 0x38E0E,
|
||||
0x38E13, 0x38E13, 0x38E98, 0x38E98, 0x38E9D, 0x38E9D, 0x38EA2, 0x38EA2,
|
||||
0x38EA7, 0x38EA7, 0x38EAC, 0x38EAC, 0x38EB1, 0x38EB1, 0x38EB6, 0x38EB6,
|
||||
0x38EBB, 0x38EBB, 0x38F40, 0x38F40, 0x38F45, 0x38F45, 0x38F4A, 0x38F4A,
|
||||
0x38F4F, 0x38F4F, 0x38F54, 0x38F54, 0x38F59, 0x38F59, 0x38F5E, 0x38F5E,
|
||||
0x38F63, 0x38F63, 0x38FE8, 0x38FE8, 0x38FED, 0x38FED, 0x38FF2, 0x38FF2,
|
||||
0x38FF7, 0x38FF7, 0x38FFC, 0x38FFC, 0x39001, 0x39001, 0x39006, 0x39006,
|
||||
0x3900B, 0x3900B, 0x39090, 0x39090, 0x39095, 0x39095, 0x3909A, 0x3909A,
|
||||
0x3909F, 0x3909F, 0x390A4, 0x390A4, 0x390A9, 0x390A9, 0x390AE, 0x390AE,
|
||||
0x390B3, 0x390B3, 0x39138, 0x39138, 0x3913D, 0x3913D, 0x39142, 0x39142,
|
||||
0x39147, 0x39147, 0x3914C, 0x3914C, 0x39151, 0x39151, 0x39156, 0x39156,
|
||||
0x3915B, 0x3915B,
|
||||
};
|
||||
|
||||
struct gmu_mem_type_desc {
|
||||
struct gmu_memdesc *memdesc;
|
||||
uint32_t type;
|
||||
};
|
||||
|
||||
static size_t a6xx_snapshot_gmu_mem(struct kgsl_device *device,
|
||||
u8 *buf, size_t remain, void *priv)
|
||||
{
|
||||
struct kgsl_snapshot_gmu_mem *mem_hdr =
|
||||
(struct kgsl_snapshot_gmu_mem *)buf;
|
||||
unsigned int *data = (unsigned int *)
|
||||
(buf + sizeof(*mem_hdr));
|
||||
struct gmu_mem_type_desc *desc = priv;
|
||||
|
||||
if (priv == NULL)
|
||||
return 0;
|
||||
|
||||
if (remain < desc->memdesc->size + sizeof(*mem_hdr)) {
|
||||
dev_err(device->dev,
|
||||
"snapshot: Not enough memory for the gmu section %d\n",
|
||||
desc->type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(mem_hdr, 0, sizeof(*mem_hdr));
|
||||
mem_hdr->type = desc->type;
|
||||
mem_hdr->hostaddr = (uintptr_t)desc->memdesc->hostptr;
|
||||
mem_hdr->gmuaddr = desc->memdesc->gmuaddr;
|
||||
mem_hdr->gpuaddr = 0;
|
||||
|
||||
/* Just copy the ringbuffer, there are no active IBs */
|
||||
memcpy(data, desc->memdesc->hostptr, desc->memdesc->size);
|
||||
|
||||
return desc->memdesc->size + sizeof(*mem_hdr);
|
||||
}
|
||||
|
||||
static size_t a6xx_gmu_snapshot_dtcm(struct kgsl_device *device,
|
||||
u8 *buf, size_t remain, void *priv)
|
||||
{
|
||||
struct kgsl_snapshot_gmu_mem *mem_hdr =
|
||||
(struct kgsl_snapshot_gmu_mem *)buf;
|
||||
struct a6xx_gmu_device *gmu = (struct a6xx_gmu_device *)priv;
|
||||
u32 *data = (u32 *)(buf + sizeof(*mem_hdr));
|
||||
u32 i;
|
||||
|
||||
if (remain < gmu->vma[GMU_DTCM].size + sizeof(*mem_hdr)) {
|
||||
SNAPSHOT_ERR_NOMEM(device, "GMU DTCM Memory");
|
||||
return 0;
|
||||
}
|
||||
|
||||
mem_hdr->type = SNAPSHOT_GMU_MEM_BIN_BLOCK;
|
||||
mem_hdr->hostaddr = 0;
|
||||
mem_hdr->gmuaddr = gmu->vma[GMU_DTCM].start;
|
||||
mem_hdr->gpuaddr = 0;
|
||||
|
||||
for (i = 0; i < (gmu->vma[GMU_DTCM].size >> 2); i++)
|
||||
gmu_core_regread(device, A6XX_GMU_CM3_DTCM_START + i, data++);
|
||||
|
||||
return gmu->vma[GMU_DTCM].size + sizeof(*mem_hdr);
|
||||
}
|
||||
|
||||
static size_t a6xx_gmu_snapshot_itcm(struct kgsl_device *device,
|
||||
u8 *buf, size_t remain, void *priv)
|
||||
{
|
||||
struct kgsl_snapshot_gmu_mem *mem_hdr =
|
||||
(struct kgsl_snapshot_gmu_mem *)buf;
|
||||
void *dest = buf + sizeof(*mem_hdr);
|
||||
struct a6xx_gmu_device *gmu = (struct a6xx_gmu_device *)priv;
|
||||
|
||||
if (!gmu->itcm_shadow) {
|
||||
dev_err(&gmu->pdev->dev, "ITCM not captured\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (remain < gmu->vma[GMU_ITCM].size + sizeof(*mem_hdr)) {
|
||||
SNAPSHOT_ERR_NOMEM(device, "GMU ITCM Memory");
|
||||
return 0;
|
||||
}
|
||||
|
||||
mem_hdr->type = SNAPSHOT_GMU_MEM_BIN_BLOCK;
|
||||
mem_hdr->hostaddr = 0;
|
||||
mem_hdr->gmuaddr = gmu->vma[GMU_ITCM].start;
|
||||
mem_hdr->gpuaddr = 0;
|
||||
|
||||
memcpy(dest, gmu->itcm_shadow, gmu->vma[GMU_ITCM].size);
|
||||
|
||||
return gmu->vma[GMU_ITCM].size + sizeof(*mem_hdr);
|
||||
}
|
||||
|
||||
static void a6xx_gmu_snapshot_memories(struct kgsl_device *device,
|
||||
struct a6xx_gmu_device *gmu, struct kgsl_snapshot *snapshot)
|
||||
{
|
||||
struct gmu_mem_type_desc desc;
|
||||
struct gmu_memdesc *md;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(gmu->gmu_globals); i++) {
|
||||
|
||||
md = &gmu->gmu_globals[i];
|
||||
if (!md->size)
|
||||
continue;
|
||||
|
||||
desc.memdesc = md;
|
||||
if (md == gmu->hfi.hfi_mem)
|
||||
desc.type = SNAPSHOT_GMU_MEM_HFI;
|
||||
else if (md == gmu->gmu_log)
|
||||
desc.type = SNAPSHOT_GMU_MEM_LOG;
|
||||
else if (md == gmu->dump_mem)
|
||||
desc.type = SNAPSHOT_GMU_MEM_DEBUG;
|
||||
else
|
||||
desc.type = SNAPSHOT_GMU_MEM_BIN_BLOCK;
|
||||
|
||||
kgsl_snapshot_add_section(device,
|
||||
KGSL_SNAPSHOT_SECTION_GMU_MEMORY,
|
||||
snapshot, a6xx_snapshot_gmu_mem, &desc);
|
||||
}
|
||||
}
|
||||
|
||||
struct kgsl_snapshot_gmu_version {
|
||||
uint32_t type;
|
||||
uint32_t value;
|
||||
};
|
||||
|
||||
static size_t a6xx_snapshot_gmu_version(struct kgsl_device *device,
|
||||
u8 *buf, size_t remain, void *priv)
|
||||
{
|
||||
struct kgsl_snapshot_debug *header = (struct kgsl_snapshot_debug *)buf;
|
||||
uint32_t *data = (uint32_t *) (buf + sizeof(*header));
|
||||
struct kgsl_snapshot_gmu_version *ver = priv;
|
||||
|
||||
if (remain < DEBUG_SECTION_SZ(1)) {
|
||||
SNAPSHOT_ERR_NOMEM(device, "GMU Version");
|
||||
return 0;
|
||||
}
|
||||
|
||||
header->type = ver->type;
|
||||
header->size = 1;
|
||||
|
||||
*data = ver->value;
|
||||
|
||||
return DEBUG_SECTION_SZ(1);
|
||||
}
|
||||
|
||||
static void a6xx_gmu_snapshot_versions(struct kgsl_device *device,
|
||||
struct a6xx_gmu_device *gmu,
|
||||
struct kgsl_snapshot *snapshot)
|
||||
{
|
||||
int i;
|
||||
|
||||
struct kgsl_snapshot_gmu_version gmu_vers[] = {
|
||||
{ .type = SNAPSHOT_DEBUG_GMU_CORE_VERSION,
|
||||
.value = gmu->ver.core, },
|
||||
{ .type = SNAPSHOT_DEBUG_GMU_CORE_DEV_VERSION,
|
||||
.value = gmu->ver.core_dev, },
|
||||
{ .type = SNAPSHOT_DEBUG_GMU_PWR_VERSION,
|
||||
.value = gmu->ver.pwr, },
|
||||
{ .type = SNAPSHOT_DEBUG_GMU_PWR_DEV_VERSION,
|
||||
.value = gmu->ver.pwr_dev, },
|
||||
{ .type = SNAPSHOT_DEBUG_GMU_HFI_VERSION,
|
||||
.value = gmu->ver.hfi, },
|
||||
};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(gmu_vers); i++)
|
||||
kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_DEBUG,
|
||||
snapshot, a6xx_snapshot_gmu_version,
|
||||
&gmu_vers[i]);
|
||||
}
|
||||
|
||||
#define RSCC_OFFSET_DWORDS 0x38000
|
||||
|
||||
static size_t a6xx_snapshot_rscc_registers(struct kgsl_device *device, u8 *buf,
|
||||
size_t remain, void *priv)
|
||||
{
|
||||
struct kgsl_snapshot_regs *header = (struct kgsl_snapshot_regs *)buf;
|
||||
struct kgsl_snapshot_registers *regs = priv;
|
||||
unsigned int *data = (unsigned int *)(buf + sizeof(*header));
|
||||
int count = 0, j, k;
|
||||
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
|
||||
struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev);
|
||||
|
||||
/* Figure out how many registers we are going to dump */
|
||||
for (j = 0; j < regs->count; j++) {
|
||||
int start = regs->regs[j * 2];
|
||||
int end = regs->regs[j * 2 + 1];
|
||||
|
||||
count += (end - start + 1);
|
||||
}
|
||||
|
||||
if (remain < (count * 8) + sizeof(*header)) {
|
||||
SNAPSHOT_ERR_NOMEM(device, "RSCC REGISTERS");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (j = 0; j < regs->count; j++) {
|
||||
unsigned int start = regs->regs[j * 2];
|
||||
unsigned int end = regs->regs[j * 2 + 1];
|
||||
|
||||
for (k = start; k <= end; k++) {
|
||||
unsigned int val;
|
||||
|
||||
val = __raw_readl(gmu->rscc_virt +
|
||||
((k - RSCC_OFFSET_DWORDS) << 2));
|
||||
*data++ = k;
|
||||
*data++ = val;
|
||||
}
|
||||
}
|
||||
|
||||
header->count = count;
|
||||
|
||||
/* Return the size of the section */
|
||||
return (count * 8) + sizeof(*header);
|
||||
}
|
||||
|
||||
static void snapshot_rscc_registers(struct adreno_device *adreno_dev,
|
||||
struct kgsl_snapshot *snapshot)
|
||||
{
|
||||
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
|
||||
|
||||
/* RSCC registers are on cx */
|
||||
if (adreno_is_a650_family(adreno_dev)) {
|
||||
struct kgsl_snapshot_registers r;
|
||||
|
||||
r.regs = a650_rscc_registers;
|
||||
r.count = ARRAY_SIZE(a650_rscc_registers) / 2;
|
||||
|
||||
kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_REGS,
|
||||
snapshot, a6xx_snapshot_rscc_registers, &r);
|
||||
} else if (adreno_is_a615_family(adreno_dev) ||
|
||||
adreno_is_a630(adreno_dev)) {
|
||||
adreno_snapshot_registers(device, snapshot,
|
||||
a630_rscc_snapshot_registers,
|
||||
ARRAY_SIZE(a630_rscc_snapshot_registers) / 2);
|
||||
} else if (adreno_is_a640(adreno_dev) || adreno_is_a680(adreno_dev)) {
|
||||
adreno_snapshot_registers(device, snapshot,
|
||||
a6xx_rscc_snapshot_registers,
|
||||
ARRAY_SIZE(a6xx_rscc_snapshot_registers) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* a6xx_gmu_device_snapshot() - A6XX GMU snapshot function
|
||||
* @device: Device being snapshotted
|
||||
* @snapshot: Pointer to the snapshot instance
|
||||
*
|
||||
* This is where all of the A6XX GMU specific bits and pieces are grabbed
|
||||
* into the snapshot memory
|
||||
*/
|
||||
void a6xx_gmu_device_snapshot(struct kgsl_device *device,
|
||||
struct kgsl_snapshot *snapshot)
|
||||
{
|
||||
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
|
||||
struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev);
|
||||
unsigned int val;
|
||||
|
||||
kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_GMU_MEMORY,
|
||||
snapshot, a6xx_gmu_snapshot_itcm, gmu);
|
||||
|
||||
kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_GMU_MEMORY,
|
||||
snapshot, a6xx_gmu_snapshot_dtcm, gmu);
|
||||
|
||||
a6xx_gmu_snapshot_versions(device, gmu, snapshot);
|
||||
|
||||
a6xx_gmu_snapshot_memories(device, gmu, snapshot);
|
||||
|
||||
/* Snapshot tcms as registers for legacy targets */
|
||||
if (adreno_is_a630(adreno_dev) ||
|
||||
adreno_is_a615_family(adreno_dev))
|
||||
adreno_snapshot_registers(device, snapshot,
|
||||
a6xx_gmu_tcm_registers,
|
||||
ARRAY_SIZE(a6xx_gmu_tcm_registers) / 2);
|
||||
|
||||
adreno_snapshot_registers(device, snapshot, a6xx_gmu_registers,
|
||||
ARRAY_SIZE(a6xx_gmu_registers) / 2);
|
||||
|
||||
/* Snapshot A660 specific GMU registers */
|
||||
if (adreno_is_a660(adreno_dev))
|
||||
adreno_snapshot_registers(device, snapshot, a660_gmu_registers,
|
||||
ARRAY_SIZE(a660_gmu_registers) / 2);
|
||||
|
||||
snapshot_rscc_registers(adreno_dev, snapshot);
|
||||
|
||||
if (!a6xx_gmu_gx_is_on(device))
|
||||
return;
|
||||
|
||||
/* Set fence to ALLOW mode so registers can be read */
|
||||
kgsl_regwrite(device, A6XX_GMU_AO_AHB_FENCE_CTRL, 0);
|
||||
/* Make sure the previous write posted before reading */
|
||||
wmb();
|
||||
kgsl_regread(device, A6XX_GMU_AO_AHB_FENCE_CTRL, &val);
|
||||
|
||||
adreno_snapshot_registers(device, snapshot,
|
||||
a6xx_gmu_gx_registers,
|
||||
ARRAY_SIZE(a6xx_gmu_gx_registers) / 2);
|
||||
}
|
||||
|
|
@ -9,10 +9,22 @@
|
|||
#include "adreno.h"
|
||||
#include "adreno_a6xx.h"
|
||||
#include "kgsl_device.h"
|
||||
#include "kgsl_gmu.h"
|
||||
#include "kgsl_hfi.h"
|
||||
#include "kgsl_trace.h"
|
||||
|
||||
/* Below section is for all structures related to HFI queues */
|
||||
#define HFI_QUEUE_DEFAULT_CNT 3
|
||||
#define HFI_QUEUE_DISPATCH_CNT 1
|
||||
#define HFI_QUEUE_MAX (HFI_QUEUE_DEFAULT_CNT + HFI_QUEUE_DISPATCH_CNT)
|
||||
|
||||
struct hfi_queue_table {
|
||||
struct hfi_queue_table_header qtbl_hdr;
|
||||
struct hfi_queue_header qhdr[HFI_QUEUE_MAX];
|
||||
};
|
||||
|
||||
/* Total header sizes + queue sizes + 16 for alignment */
|
||||
#define HFIMEM_SIZE (sizeof(struct hfi_queue_table) + 16 + \
|
||||
(HFI_QUEUE_SIZE * HFI_QUEUE_MAX))
|
||||
|
||||
#define HFI_QUEUE_OFFSET(i) \
|
||||
(ALIGN(sizeof(struct hfi_queue_table), SZ_16) + \
|
||||
((i) * HFI_QUEUE_SIZE))
|
||||
|
|
@ -28,20 +40,14 @@
|
|||
#define MSG_HDR_GET_TYPE(hdr) (((hdr) >> 16) & 0xF)
|
||||
#define MSG_HDR_GET_SEQNUM(hdr) (((hdr) >> 20) & 0xFFF)
|
||||
|
||||
/* Size is converted from Bytes to DWords */
|
||||
#define CREATE_MSG_HDR(id, size, type) \
|
||||
(((type) << 16) | ((((size) >> 2) & 0xFF) << 8) | ((id) & 0xFF))
|
||||
#define CMD_MSG_HDR(id, size) CREATE_MSG_HDR(id, size, HFI_MSG_CMD)
|
||||
#define ACK_MSG_HDR(id, size) CREATE_MSG_HDR(id, size, HFI_MSG_ACK)
|
||||
|
||||
static void hfi_process_queue(struct gmu_device *gmu, uint32_t queue_idx,
|
||||
struct pending_cmd *ret_cmd);
|
||||
static int a6xx_hfi_process_queue(struct a6xx_gmu_device *gmu,
|
||||
uint32_t queue_idx, struct pending_cmd *ret_cmd);
|
||||
|
||||
/* Size in below functions are in unit of dwords */
|
||||
static int hfi_queue_read(struct gmu_device *gmu, uint32_t queue_idx,
|
||||
static int a6xx_hfi_queue_read(struct a6xx_gmu_device *gmu, uint32_t queue_idx,
|
||||
unsigned int *output, unsigned int max_size)
|
||||
{
|
||||
struct gmu_memdesc *mem_addr = gmu->hfi_mem;
|
||||
struct gmu_memdesc *mem_addr = gmu->hfi.hfi_mem;
|
||||
struct hfi_queue_table *tbl = mem_addr->hostptr;
|
||||
struct hfi_queue_header *hdr = &tbl->qhdr[queue_idx];
|
||||
uint32_t *queue;
|
||||
|
|
@ -97,15 +103,16 @@ done:
|
|||
}
|
||||
|
||||
/* Size in below functions are in unit of dwords */
|
||||
static int hfi_queue_write(struct gmu_device *gmu, uint32_t queue_idx,
|
||||
uint32_t *msg)
|
||||
static int a6xx_hfi_queue_write(struct adreno_device *adreno_dev,
|
||||
uint32_t queue_idx, uint32_t *msg)
|
||||
{
|
||||
struct hfi_queue_table *tbl = gmu->hfi_mem->hostptr;
|
||||
struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev);
|
||||
struct hfi_queue_table *tbl = gmu->hfi.hfi_mem->hostptr;
|
||||
struct hfi_queue_header *hdr = &tbl->qhdr[queue_idx];
|
||||
uint32_t *queue;
|
||||
struct kgsl_hfi *hfi = &gmu->hfi;
|
||||
uint32_t i, write, empty_space;
|
||||
uint32_t size = MSG_HDR_GET_SIZE(*msg);
|
||||
u32 align_size = ALIGN(size, SZ_4);
|
||||
uint32_t id = MSG_HDR_GET_ID(*msg);
|
||||
|
||||
if (hdr->status == HFI_QUEUE_STATUS_DISABLED)
|
||||
|
|
@ -118,24 +125,16 @@ static int hfi_queue_write(struct gmu_device *gmu, uint32_t queue_idx,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
queue = HOST_QUEUE_START_ADDR(gmu->hfi_mem, queue_idx);
|
||||
queue = HOST_QUEUE_START_ADDR(gmu->hfi.hfi_mem, queue_idx);
|
||||
|
||||
trace_kgsl_hfi_send(id, size, MSG_HDR_GET_SEQNUM(*msg));
|
||||
|
||||
mutex_lock(&hfi->cmdq_mutex);
|
||||
|
||||
empty_space = (hdr->write_index >= hdr->read_index) ?
|
||||
(hdr->queue_size - (hdr->write_index - hdr->read_index))
|
||||
: (hdr->read_index - hdr->write_index);
|
||||
|
||||
if (empty_space < size) {
|
||||
dev_err(&gmu->pdev->dev,
|
||||
"Insufficient bufsize %d for msg id=%d of size %d\n",
|
||||
empty_space, id, size);
|
||||
|
||||
mutex_unlock(&hfi->cmdq_mutex);
|
||||
if (empty_space <= align_size)
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
write = hdr->write_index;
|
||||
|
||||
|
|
@ -146,14 +145,14 @@ static int hfi_queue_write(struct gmu_device *gmu, uint32_t queue_idx,
|
|||
|
||||
/* Cookify any non used data at the end of the write buffer */
|
||||
if (GMU_VER_MAJOR(gmu->ver.hfi) >= 2) {
|
||||
for (; write % 4; write = (write + 1) % hdr->queue_size)
|
||||
for (; i < align_size; i++) {
|
||||
queue[write] = 0xFAFAFAFA;
|
||||
write = (write + 1) % hdr->queue_size;
|
||||
}
|
||||
}
|
||||
|
||||
hdr->write_index = write;
|
||||
|
||||
mutex_unlock(&hfi->cmdq_mutex);
|
||||
|
||||
/*
|
||||
* Memory barrier to make sure packet and write index are written before
|
||||
* an interrupt is raised
|
||||
|
|
@ -161,8 +160,8 @@ static int hfi_queue_write(struct gmu_device *gmu, uint32_t queue_idx,
|
|||
wmb();
|
||||
|
||||
/* Send interrupt to GMU to receive the message */
|
||||
adreno_write_gmureg(ADRENO_DEVICE(hfi->kgsldev),
|
||||
ADRENO_REG_GMU_HOST2GMU_INTR_SET, 0x1);
|
||||
gmu_core_regwrite(KGSL_DEVICE(adreno_dev), A6XX_GMU_HOST2GMU_INTR_SET,
|
||||
0x1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -173,11 +172,10 @@ static int hfi_queue_write(struct gmu_device *gmu, uint32_t queue_idx,
|
|||
|
||||
|
||||
/* Sizes of the queue and message are in unit of dwords */
|
||||
void hfi_init(struct gmu_device *gmu)
|
||||
static void init_queues(struct adreno_device *adreno_dev)
|
||||
{
|
||||
struct kgsl_hfi *hfi = &gmu->hfi;
|
||||
struct adreno_device *adreno_dev = ADRENO_DEVICE(hfi->kgsldev);
|
||||
struct gmu_memdesc *mem_addr = gmu->hfi_mem;
|
||||
struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev);
|
||||
struct gmu_memdesc *mem_addr = gmu->hfi.hfi_mem;
|
||||
int i;
|
||||
struct hfi_queue_table *tbl;
|
||||
struct hfi_queue_header *hdr;
|
||||
|
|
@ -222,23 +220,38 @@ void hfi_init(struct gmu_device *gmu)
|
|||
hdr->status = queue[i].status;
|
||||
hdr->queue_size = HFI_QUEUE_SIZE >> 2; /* convert to dwords */
|
||||
}
|
||||
}
|
||||
|
||||
mutex_init(&hfi->cmdq_mutex);
|
||||
int a6xx_hfi_init(struct adreno_device *adreno_dev)
|
||||
{
|
||||
struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev);
|
||||
struct a6xx_hfi *hfi = &gmu->hfi;
|
||||
|
||||
/* Allocates & maps memory for HFI */
|
||||
if (IS_ERR_OR_NULL(hfi->hfi_mem)) {
|
||||
hfi->hfi_mem = reserve_gmu_kernel_block(gmu, 0, HFIMEM_SIZE,
|
||||
GMU_NONCACHED_KERNEL);
|
||||
if (!IS_ERR(hfi->hfi_mem))
|
||||
init_queues(adreno_dev);
|
||||
}
|
||||
|
||||
return PTR_ERR_OR_ZERO(hfi->hfi_mem);
|
||||
}
|
||||
|
||||
#define HDR_CMP_SEQNUM(out_hdr, in_hdr) \
|
||||
(MSG_HDR_GET_SEQNUM(out_hdr) == MSG_HDR_GET_SEQNUM(in_hdr))
|
||||
|
||||
static void receive_ack_cmd(struct gmu_device *gmu, void *rcvd,
|
||||
static int receive_ack_cmd(struct a6xx_gmu_device *gmu, void *rcvd,
|
||||
struct pending_cmd *ret_cmd)
|
||||
{
|
||||
struct adreno_device *adreno_dev = a6xx_gmu_to_adreno(gmu);
|
||||
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
|
||||
uint32_t *ack = rcvd;
|
||||
uint32_t hdr = ack[0];
|
||||
uint32_t req_hdr = ack[1];
|
||||
struct kgsl_hfi *hfi = &gmu->hfi;
|
||||
|
||||
if (ret_cmd == NULL)
|
||||
return;
|
||||
return -EINVAL;
|
||||
|
||||
trace_kgsl_hfi_receive(MSG_HDR_GET_ID(req_hdr),
|
||||
MSG_HDR_GET_SIZE(req_hdr),
|
||||
|
|
@ -246,7 +259,7 @@ static void receive_ack_cmd(struct gmu_device *gmu, void *rcvd,
|
|||
|
||||
if (HDR_CMP_SEQNUM(ret_cmd->sent_hdr, req_hdr)) {
|
||||
memcpy(&ret_cmd->results, ack, MSG_HDR_GET_SIZE(hdr) << 2);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Didn't find the sender, list the waiter */
|
||||
|
|
@ -254,36 +267,37 @@ static void receive_ack_cmd(struct gmu_device *gmu, void *rcvd,
|
|||
"HFI ACK: Cannot find sender for 0x%8.8x Waiter: 0x%8.8x\n",
|
||||
req_hdr, ret_cmd->sent_hdr);
|
||||
|
||||
adreno_set_gpu_fault(ADRENO_DEVICE(hfi->kgsldev), ADRENO_GMU_FAULT);
|
||||
adreno_dispatcher_schedule(hfi->kgsldev);
|
||||
gmu_fault_snapshot(device);
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
#define MSG_HDR_SET_SEQNUM(hdr, num) \
|
||||
(((hdr) & 0xFFFFF) | ((num) << 20))
|
||||
|
||||
static int poll_adreno_gmu_reg(struct adreno_device *adreno_dev,
|
||||
enum adreno_regs offset_name, unsigned int expected_val,
|
||||
static int poll_gmu_reg(struct adreno_device *adreno_dev,
|
||||
u32 offsetdwords, unsigned int expected_val,
|
||||
unsigned int mask, unsigned int timeout_ms)
|
||||
{
|
||||
unsigned int val;
|
||||
struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev);
|
||||
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
|
||||
struct gmu_device *gmu = KGSL_GMU_DEVICE(device);
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
|
||||
u64 ao_pre_poll, ao_post_poll;
|
||||
|
||||
ao_pre_poll = gmu_core_dev_read_alwayson(device);
|
||||
ao_pre_poll = a6xx_read_alwayson(adreno_dev);
|
||||
|
||||
while (time_is_after_jiffies(timeout)) {
|
||||
adreno_read_gmureg(adreno_dev, offset_name, &val);
|
||||
gmu_core_regread(device, offsetdwords, &val);
|
||||
if ((val & mask) == expected_val)
|
||||
return 0;
|
||||
usleep_range(10, 100);
|
||||
}
|
||||
|
||||
ao_post_poll = gmu_core_dev_read_alwayson(device);
|
||||
ao_post_poll = a6xx_read_alwayson(adreno_dev);
|
||||
|
||||
/* Check one last time */
|
||||
adreno_read_gmureg(adreno_dev, offset_name, &val);
|
||||
gmu_core_regread(device, offsetdwords, &val);
|
||||
if ((val & mask) == expected_val)
|
||||
return 0;
|
||||
|
||||
|
|
@ -293,29 +307,31 @@ static int poll_adreno_gmu_reg(struct adreno_device *adreno_dev,
|
|||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int hfi_send_cmd(struct gmu_device *gmu, uint32_t queue_idx,
|
||||
void *data, struct pending_cmd *ret_cmd)
|
||||
static int a6xx_hfi_send_cmd(struct adreno_device *adreno_dev,
|
||||
uint32_t queue_idx, void *data, struct pending_cmd *ret_cmd)
|
||||
{
|
||||
struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev);
|
||||
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
|
||||
int rc;
|
||||
uint32_t *cmd = data;
|
||||
struct kgsl_hfi *hfi = &gmu->hfi;
|
||||
struct a6xx_hfi *hfi = &gmu->hfi;
|
||||
unsigned int seqnum = atomic_inc_return(&hfi->seqnum);
|
||||
struct adreno_device *adreno_dev = ADRENO_DEVICE(hfi->kgsldev);
|
||||
|
||||
*cmd = MSG_HDR_SET_SEQNUM(*cmd, seqnum);
|
||||
if (ret_cmd == NULL)
|
||||
return hfi_queue_write(gmu, queue_idx, cmd);
|
||||
return a6xx_hfi_queue_write(adreno_dev, queue_idx, cmd);
|
||||
|
||||
ret_cmd->sent_hdr = cmd[0];
|
||||
|
||||
rc = hfi_queue_write(gmu, queue_idx, cmd);
|
||||
rc = a6xx_hfi_queue_write(adreno_dev, queue_idx, cmd);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = poll_adreno_gmu_reg(adreno_dev, ADRENO_REG_GMU_GMU2HOST_INTR_INFO,
|
||||
rc = poll_gmu_reg(adreno_dev, A6XX_GMU_GMU2HOST_INTR_INFO,
|
||||
HFI_IRQ_MSGQ_MASK, HFI_IRQ_MSGQ_MASK, HFI_RSP_TIMEOUT);
|
||||
|
||||
if (rc) {
|
||||
gmu_fault_snapshot(device);
|
||||
dev_err(&gmu->pdev->dev,
|
||||
"Timed out waiting on ack for 0x%8.8x (id %d, sequence %d)\n",
|
||||
cmd[0], MSG_HDR_GET_ID(*cmd), MSG_HDR_GET_SEQNUM(*cmd));
|
||||
|
|
@ -323,27 +339,31 @@ static int hfi_send_cmd(struct gmu_device *gmu, uint32_t queue_idx,
|
|||
}
|
||||
|
||||
/* Clear the interrupt */
|
||||
adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_GMU2HOST_INTR_CLR,
|
||||
gmu_core_regwrite(device, A6XX_GMU_GMU2HOST_INTR_CLR,
|
||||
HFI_IRQ_MSGQ_MASK);
|
||||
|
||||
hfi_process_queue(gmu, HFI_MSG_ID, ret_cmd);
|
||||
rc = a6xx_hfi_process_queue(gmu, HFI_MSG_ID, ret_cmd);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#define HFI_ACK_ERROR 0xffffffff
|
||||
|
||||
static int hfi_send_generic_req(struct gmu_device *gmu, uint32_t queue,
|
||||
void *cmd)
|
||||
static int a6xx_hfi_send_generic_req(struct adreno_device *adreno_dev,
|
||||
uint32_t queue, void *cmd)
|
||||
{
|
||||
struct pending_cmd ret_cmd;
|
||||
int rc;
|
||||
|
||||
memset(&ret_cmd, 0, sizeof(ret_cmd));
|
||||
|
||||
rc = hfi_send_cmd(gmu, queue, cmd, &ret_cmd);
|
||||
rc = a6xx_hfi_send_cmd(adreno_dev, queue, cmd, &ret_cmd);
|
||||
|
||||
if (!rc && ret_cmd.results[2] == HFI_ACK_ERROR) {
|
||||
struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev);
|
||||
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
|
||||
|
||||
gmu_fault_snapshot(device);
|
||||
dev_err(&gmu->pdev->dev, "HFI ACK failure: Req 0x%8.8X\n",
|
||||
ret_cmd.results[1]);
|
||||
return -EINVAL;
|
||||
|
|
@ -352,22 +372,24 @@ static int hfi_send_generic_req(struct gmu_device *gmu, uint32_t queue,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int hfi_send_gmu_init(struct gmu_device *gmu, uint32_t boot_state)
|
||||
static int a6xx_hfi_send_gmu_init(struct adreno_device *adreno_dev)
|
||||
{
|
||||
struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev);
|
||||
struct hfi_gmu_init_cmd cmd = {
|
||||
.hdr = CMD_MSG_HDR(H2F_MSG_INIT, sizeof(cmd)),
|
||||
.seg_id = 0,
|
||||
.dbg_buffer_addr = (unsigned int) gmu->dump_mem->gmuaddr,
|
||||
.dbg_buffer_size = (unsigned int) gmu->dump_mem->size,
|
||||
.boot_state = boot_state,
|
||||
.boot_state = 0x1,
|
||||
};
|
||||
|
||||
return hfi_send_generic_req(gmu, HFI_CMD_ID, &cmd);
|
||||
return a6xx_hfi_send_generic_req(adreno_dev, HFI_CMD_ID, &cmd);
|
||||
}
|
||||
|
||||
static int hfi_get_fw_version(struct gmu_device *gmu,
|
||||
static int a6xx_hfi_get_fw_version(struct adreno_device *adreno_dev,
|
||||
uint32_t expected_ver, uint32_t *ver)
|
||||
{
|
||||
struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev);
|
||||
struct hfi_fw_version_cmd cmd = {
|
||||
.hdr = CMD_MSG_HDR(H2F_MSG_FW_VER, sizeof(cmd)),
|
||||
.supported_ver = expected_ver,
|
||||
|
|
@ -377,7 +399,7 @@ static int hfi_get_fw_version(struct gmu_device *gmu,
|
|||
|
||||
memset(&ret_cmd, 0, sizeof(ret_cmd));
|
||||
|
||||
rc = hfi_send_cmd(gmu, HFI_CMD_ID, &cmd, &ret_cmd);
|
||||
rc = a6xx_hfi_send_cmd(adreno_dev, HFI_CMD_ID, &cmd, &ret_cmd);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
|
@ -391,33 +413,34 @@ static int hfi_get_fw_version(struct gmu_device *gmu,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int hfi_send_core_fw_start(struct gmu_device *gmu)
|
||||
static int a6xx_hfi_send_core_fw_start(struct adreno_device *adreno_dev)
|
||||
{
|
||||
struct hfi_core_fw_start_cmd cmd = {
|
||||
.hdr = CMD_MSG_HDR(H2F_MSG_CORE_FW_START, sizeof(cmd)),
|
||||
.handle = 0x0,
|
||||
};
|
||||
|
||||
return hfi_send_generic_req(gmu, HFI_CMD_ID, &cmd);
|
||||
return a6xx_hfi_send_generic_req(adreno_dev, HFI_CMD_ID, &cmd);
|
||||
}
|
||||
|
||||
static const char * const hfi_features[] = {
|
||||
[HFI_FEATURE_ECP] = "ECP",
|
||||
static const char * const a6xx_hfi_features[] = {
|
||||
[HFI_FEATURE_ACD] = "ACD",
|
||||
[HFI_FEATURE_LM] = "LM",
|
||||
};
|
||||
|
||||
static const char *feature_to_string(uint32_t feature)
|
||||
{
|
||||
if (feature < ARRAY_SIZE(hfi_features) && hfi_features[feature])
|
||||
return hfi_features[feature];
|
||||
if (feature < ARRAY_SIZE(a6xx_hfi_features) &&
|
||||
a6xx_hfi_features[feature])
|
||||
return a6xx_hfi_features[feature];
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
static int hfi_send_feature_ctrl(struct gmu_device *gmu,
|
||||
uint32_t feature, uint32_t enable, uint32_t data)
|
||||
static int a6xx_hfi_send_feature_ctrl(struct adreno_device *adreno_dev,
|
||||
uint32_t feature, uint32_t enable, uint32_t data)
|
||||
{
|
||||
struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev);
|
||||
struct hfi_feature_ctrl_cmd cmd = {
|
||||
.hdr = CMD_MSG_HDR(H2F_MSG_FEATURE_CTRL, sizeof(cmd)),
|
||||
.feature = feature,
|
||||
|
|
@ -426,7 +449,7 @@ static int hfi_send_feature_ctrl(struct gmu_device *gmu,
|
|||
};
|
||||
int ret;
|
||||
|
||||
ret = hfi_send_generic_req(gmu, HFI_CMD_ID, &cmd);
|
||||
ret = a6xx_hfi_send_generic_req(adreno_dev, HFI_CMD_ID, &cmd);
|
||||
if (ret)
|
||||
dev_err(&gmu->pdev->dev,
|
||||
"Unable to %s feature %s (%d)\n",
|
||||
|
|
@ -436,30 +459,31 @@ static int hfi_send_feature_ctrl(struct gmu_device *gmu,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int hfi_send_dcvstbl_v1(struct gmu_device *gmu)
|
||||
static int a6xx_hfi_send_dcvstbl_v1(struct adreno_device *adreno_dev)
|
||||
{
|
||||
struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev);
|
||||
struct hfi_dcvstable_cmd *table = &gmu->hfi.dcvs_table;
|
||||
struct hfi_dcvstable_v1_cmd cmd = {
|
||||
.hdr = CMD_MSG_HDR(H2F_MSG_PERF_TBL, sizeof(cmd)),
|
||||
.gpu_level_num = gmu->num_gpupwrlevels,
|
||||
.gmu_level_num = GMU_PWR_LEVELS,
|
||||
.gpu_level_num = table->gpu_level_num,
|
||||
.gmu_level_num = table->gmu_level_num,
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; i < gmu->num_gpupwrlevels; i++) {
|
||||
cmd.gx_votes[i].vote = gmu->rpmh_votes.gx_votes[i];
|
||||
/* Divide by 1000 to convert to kHz */
|
||||
cmd.gx_votes[i].freq = gmu->pwrlevels[i].freq / 1000;
|
||||
for (i = 0; i < table->gpu_level_num; i++) {
|
||||
cmd.gx_votes[i].vote = table->gx_votes[i].vote;
|
||||
cmd.gx_votes[i].freq = table->gx_votes[i].freq;
|
||||
}
|
||||
|
||||
cmd.cx_votes[0].vote = gmu->rpmh_votes.cx_votes[0];
|
||||
cmd.cx_votes[0].freq = 0;
|
||||
cmd.cx_votes[1].vote = gmu->rpmh_votes.cx_votes[1];
|
||||
cmd.cx_votes[1].freq = GMU_FREQUENCY / 1000;
|
||||
cmd.cx_votes[0].vote = table->cx_votes[0].vote;
|
||||
cmd.cx_votes[0].freq = table->cx_votes[0].freq;
|
||||
cmd.cx_votes[1].vote = table->cx_votes[1].vote;
|
||||
cmd.cx_votes[1].freq = table->cx_votes[1].freq;
|
||||
|
||||
return hfi_send_generic_req(gmu, HFI_CMD_ID, &cmd);
|
||||
return a6xx_hfi_send_generic_req(adreno_dev, HFI_CMD_ID, &cmd);
|
||||
}
|
||||
|
||||
static int hfi_send_get_value(struct gmu_device *gmu,
|
||||
static int a6xx_hfi_send_get_value(struct adreno_device *adreno_dev,
|
||||
struct hfi_get_value_req *req)
|
||||
{
|
||||
struct hfi_get_value_cmd *cmd = &req->cmd;
|
||||
|
|
@ -470,7 +494,7 @@ static int hfi_send_get_value(struct gmu_device *gmu,
|
|||
|
||||
cmd->hdr = CMD_MSG_HDR(H2F_MSG_GET_VALUE, sizeof(*cmd));
|
||||
|
||||
rc = hfi_send_cmd(gmu, HFI_CMD_ID, cmd, &ret_cmd);
|
||||
rc = a6xx_hfi_send_cmd(adreno_dev, HFI_CMD_ID, cmd, &ret_cmd);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
|
@ -480,59 +504,16 @@ static int hfi_send_get_value(struct gmu_device *gmu,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int hfi_send_dcvstbl(struct gmu_device *gmu)
|
||||
{
|
||||
struct hfi_dcvstable_cmd cmd = {
|
||||
.hdr = CMD_MSG_HDR(H2F_MSG_PERF_TBL, sizeof(cmd)),
|
||||
.gpu_level_num = gmu->num_gpupwrlevels,
|
||||
.gmu_level_num = GMU_PWR_LEVELS,
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; i < gmu->num_gpupwrlevels; i++) {
|
||||
cmd.gx_votes[i].vote = gmu->rpmh_votes.gx_votes[i];
|
||||
/* Hardcode this to the max threshold since it is not used */
|
||||
cmd.gx_votes[i].acd = 0xFFFFFFFF;
|
||||
/* Divide by 1000 to convert to kHz */
|
||||
cmd.gx_votes[i].freq = gmu->pwrlevels[i].freq / 1000;
|
||||
}
|
||||
|
||||
cmd.cx_votes[0].vote = gmu->rpmh_votes.cx_votes[0];
|
||||
cmd.cx_votes[0].freq = 0;
|
||||
cmd.cx_votes[1].vote = gmu->rpmh_votes.cx_votes[1];
|
||||
cmd.cx_votes[1].freq = GMU_FREQUENCY / 1000;
|
||||
|
||||
return hfi_send_generic_req(gmu, HFI_CMD_ID, &cmd);
|
||||
}
|
||||
|
||||
static int hfi_send_bwtbl(struct gmu_device *gmu)
|
||||
{
|
||||
struct hfi_bwtable_cmd *cmd = &gmu->hfi.bwtbl_cmd;
|
||||
|
||||
cmd->hdr = CMD_MSG_HDR(H2F_MSG_BW_VOTE_TBL, sizeof(*cmd));
|
||||
|
||||
return hfi_send_generic_req(gmu, HFI_CMD_ID, cmd);
|
||||
}
|
||||
|
||||
static int hfi_send_acd_tbl(struct gmu_device *gmu)
|
||||
{
|
||||
struct hfi_acd_table_cmd *cmd = &gmu->hfi.acd_tbl_cmd;
|
||||
|
||||
cmd->hdr = CMD_MSG_HDR(H2F_MSG_ACD_TBL, sizeof(*cmd));
|
||||
|
||||
return hfi_send_generic_req(gmu, HFI_CMD_IDX, cmd);
|
||||
}
|
||||
|
||||
static int hfi_send_test(struct gmu_device *gmu)
|
||||
static int a6xx_hfi_send_test(struct adreno_device *adreno_dev)
|
||||
{
|
||||
struct hfi_test_cmd cmd = {
|
||||
.hdr = CMD_MSG_HDR(H2F_MSG_TEST, sizeof(cmd)),
|
||||
};
|
||||
|
||||
return hfi_send_generic_req(gmu, HFI_CMD_ID, &cmd);
|
||||
return a6xx_hfi_send_generic_req(adreno_dev, HFI_CMD_ID, &cmd);
|
||||
}
|
||||
|
||||
static void receive_err_req(struct gmu_device *gmu, void *rcvd)
|
||||
static void receive_err_req(struct a6xx_gmu_device *gmu, void *rcvd)
|
||||
{
|
||||
struct hfi_err_cmd *cmd = rcvd;
|
||||
|
||||
|
|
@ -542,7 +523,7 @@ static void receive_err_req(struct gmu_device *gmu, void *rcvd)
|
|||
(char *) cmd->data);
|
||||
}
|
||||
|
||||
static void receive_debug_req(struct gmu_device *gmu, void *rcvd)
|
||||
static void receive_debug_req(struct a6xx_gmu_device *gmu, void *rcvd)
|
||||
{
|
||||
struct hfi_debug_cmd *cmd = rcvd;
|
||||
|
||||
|
|
@ -550,7 +531,7 @@ static void receive_debug_req(struct gmu_device *gmu, void *rcvd)
|
|||
cmd->type, cmd->timestamp, cmd->data);
|
||||
}
|
||||
|
||||
static void hfi_v1_receiver(struct gmu_device *gmu, uint32_t *rcvd,
|
||||
static void a6xx_hfi_v1_receiver(struct a6xx_gmu_device *gmu, uint32_t *rcvd,
|
||||
struct pending_cmd *ret_cmd)
|
||||
{
|
||||
/* V1 ACK Handler */
|
||||
|
|
@ -575,21 +556,24 @@ static void hfi_v1_receiver(struct gmu_device *gmu, uint32_t *rcvd,
|
|||
}
|
||||
}
|
||||
|
||||
static void hfi_process_queue(struct gmu_device *gmu, uint32_t queue_idx,
|
||||
struct pending_cmd *ret_cmd)
|
||||
static int a6xx_hfi_process_queue(struct a6xx_gmu_device *gmu,
|
||||
uint32_t queue_idx, struct pending_cmd *ret_cmd)
|
||||
{
|
||||
uint32_t rcvd[MAX_RCVD_SIZE];
|
||||
|
||||
while (hfi_queue_read(gmu, queue_idx, rcvd, sizeof(rcvd)) > 0) {
|
||||
while (a6xx_hfi_queue_read(gmu, queue_idx, rcvd, sizeof(rcvd)) > 0) {
|
||||
/* Special case if we're v1 */
|
||||
if (GMU_VER_MAJOR(gmu->ver.hfi) < 2) {
|
||||
hfi_v1_receiver(gmu, rcvd, ret_cmd);
|
||||
a6xx_hfi_v1_receiver(gmu, rcvd, ret_cmd);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* V2 ACK Handler */
|
||||
if (MSG_HDR_GET_TYPE(rcvd[0]) == HFI_MSG_ACK) {
|
||||
receive_ack_cmd(gmu, rcvd, ret_cmd);
|
||||
int ret = receive_ack_cmd(gmu, rcvd, ret_cmd);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -608,18 +592,13 @@ static void hfi_process_queue(struct gmu_device *gmu, uint32_t queue_idx,
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hfi_receiver(unsigned long data)
|
||||
static int a6xx_hfi_verify_fw_version(struct adreno_device *adreno_dev)
|
||||
{
|
||||
/* Process all asynchronous read (firmware to host) queues */
|
||||
hfi_process_queue((struct gmu_device *) data, HFI_DBG_ID, NULL);
|
||||
}
|
||||
|
||||
static int hfi_verify_fw_version(struct kgsl_device *device,
|
||||
struct gmu_device *gmu)
|
||||
{
|
||||
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
|
||||
struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev);
|
||||
const struct adreno_a6xx_core *a6xx_core = to_a6xx_core(adreno_dev);
|
||||
int result;
|
||||
unsigned int ver, major, minor;
|
||||
|
|
@ -631,7 +610,8 @@ static int hfi_verify_fw_version(struct kgsl_device *device,
|
|||
major = a6xx_core->gmu_major;
|
||||
minor = a6xx_core->gmu_minor;
|
||||
|
||||
result = hfi_get_fw_version(gmu, GMU_VERSION(major, minor), &ver);
|
||||
result = a6xx_hfi_get_fw_version(adreno_dev, GMU_VERSION(major, minor),
|
||||
&ver);
|
||||
if (result) {
|
||||
dev_err_once(&gmu->pdev->dev,
|
||||
"Failed to get FW version via HFI\n");
|
||||
|
|
@ -655,8 +635,7 @@ static int hfi_verify_fw_version(struct kgsl_device *device,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int hfi_send_lm_feature_ctrl(struct gmu_device *gmu,
|
||||
struct adreno_device *adreno_dev)
|
||||
static int a6xx_hfi_send_lm_feature_ctrl(struct adreno_device *adreno_dev)
|
||||
{
|
||||
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
|
||||
struct hfi_set_value_cmd req;
|
||||
|
|
@ -674,41 +653,40 @@ static int hfi_send_lm_feature_ctrl(struct gmu_device *gmu,
|
|||
req.subtype = 0;
|
||||
req.data = slope;
|
||||
|
||||
ret = hfi_send_feature_ctrl(gmu, HFI_FEATURE_LM, 1,
|
||||
ret = a6xx_hfi_send_feature_ctrl(adreno_dev, HFI_FEATURE_LM, 1,
|
||||
device->pwrctrl.throttle_mask);
|
||||
|
||||
if (!ret)
|
||||
ret = hfi_send_req(gmu, H2F_MSG_SET_VALUE, &req);
|
||||
ret = a6xx_hfi_send_req(adreno_dev, H2F_MSG_SET_VALUE, &req);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int hfi_send_acd_feature_ctrl(struct gmu_device *gmu,
|
||||
struct adreno_device *adreno_dev)
|
||||
static int a6xx_hfi_send_acd_feature_ctrl(struct adreno_device *adreno_dev)
|
||||
{
|
||||
struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev);
|
||||
int ret = 0;
|
||||
|
||||
if (adreno_dev->acd_enabled) {
|
||||
ret = hfi_send_acd_tbl(gmu);
|
||||
ret = a6xx_hfi_send_generic_req(adreno_dev, HFI_CMD_ID,
|
||||
&gmu->hfi.acd_table);
|
||||
if (!ret)
|
||||
ret = hfi_send_feature_ctrl(gmu, HFI_FEATURE_ACD, 1, 0);
|
||||
ret = a6xx_hfi_send_feature_ctrl(adreno_dev,
|
||||
HFI_FEATURE_ACD, 1, 0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int hfi_start(struct kgsl_device *device,
|
||||
struct gmu_device *gmu, uint32_t boot_state)
|
||||
int a6xx_hfi_start(struct adreno_device *adreno_dev)
|
||||
{
|
||||
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
|
||||
struct gmu_memdesc *mem_addr = gmu->hfi_mem;
|
||||
struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev);
|
||||
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
|
||||
struct gmu_memdesc *mem_addr = gmu->hfi.hfi_mem;
|
||||
struct hfi_queue_table *tbl = mem_addr->hostptr;
|
||||
struct hfi_queue_header *hdr;
|
||||
int result, i;
|
||||
|
||||
if (test_bit(GMU_HFI_ON, &device->gmu_core.flags))
|
||||
return 0;
|
||||
|
||||
/* Force read_index to the write_index no matter what */
|
||||
for (i = 0; i < HFI_QUEUE_MAX; i++) {
|
||||
hdr = &tbl->qhdr[i];
|
||||
|
|
@ -725,25 +703,27 @@ int hfi_start(struct kgsl_device *device,
|
|||
|
||||
/* This is legacy HFI message for A630 and A615 family firmware */
|
||||
if (adreno_is_a630(adreno_dev) || adreno_is_a615_family(adreno_dev)) {
|
||||
result = hfi_send_gmu_init(gmu, boot_state);
|
||||
result = a6xx_hfi_send_gmu_init(adreno_dev);
|
||||
if (result)
|
||||
return result;
|
||||
goto err;
|
||||
}
|
||||
|
||||
result = hfi_verify_fw_version(device, gmu);
|
||||
result = a6xx_hfi_verify_fw_version(adreno_dev);
|
||||
if (result)
|
||||
return result;
|
||||
goto err;
|
||||
|
||||
if (GMU_VER_MAJOR(gmu->ver.hfi) < 2)
|
||||
result = hfi_send_dcvstbl_v1(gmu);
|
||||
result = a6xx_hfi_send_dcvstbl_v1(adreno_dev);
|
||||
else
|
||||
result = hfi_send_dcvstbl(gmu);
|
||||
result = a6xx_hfi_send_generic_req(adreno_dev, HFI_CMD_ID,
|
||||
&gmu->hfi.dcvs_table);
|
||||
if (result)
|
||||
return result;
|
||||
goto err;
|
||||
|
||||
result = hfi_send_bwtbl(gmu);
|
||||
result = a6xx_hfi_send_generic_req(adreno_dev, HFI_CMD_ID,
|
||||
&gmu->hfi.bw_table);
|
||||
if (result)
|
||||
return result;
|
||||
goto err;
|
||||
|
||||
/*
|
||||
* If quirk is enabled send H2F_MSG_TEST and tell the GMU
|
||||
|
|
@ -751,48 +731,52 @@ int hfi_start(struct kgsl_device *device,
|
|||
* send H2F_MSG_CORE_FW_START and features for A640 devices
|
||||
*/
|
||||
if (GMU_VER_MAJOR(gmu->ver.hfi) >= 2) {
|
||||
if (ADRENO_FEATURE(adreno_dev, ADRENO_ECP)) {
|
||||
result = hfi_send_feature_ctrl(gmu,
|
||||
HFI_FEATURE_ECP, 1, 0);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
|
||||
result = hfi_send_acd_feature_ctrl(gmu, adreno_dev);
|
||||
result = a6xx_hfi_send_acd_feature_ctrl(adreno_dev);
|
||||
if (result)
|
||||
return result;
|
||||
goto err;
|
||||
|
||||
result = hfi_send_lm_feature_ctrl(gmu, adreno_dev);
|
||||
result = a6xx_hfi_send_lm_feature_ctrl(adreno_dev);
|
||||
if (result)
|
||||
return result;
|
||||
goto err;
|
||||
|
||||
result = hfi_send_core_fw_start(gmu);
|
||||
result = a6xx_hfi_send_core_fw_start(adreno_dev);
|
||||
if (result)
|
||||
return result;
|
||||
goto err;
|
||||
} else {
|
||||
if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) {
|
||||
result = hfi_send_test(gmu);
|
||||
result = a6xx_hfi_send_test(adreno_dev);
|
||||
if (result)
|
||||
return result;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
set_bit(GMU_HFI_ON, &device->gmu_core.flags);
|
||||
return 0;
|
||||
|
||||
set_bit(GMU_PRIV_HFI_STARTED, &gmu->flags);
|
||||
|
||||
/* Request default DCVS level */
|
||||
result = kgsl_pwrctrl_set_default_gpu_pwrlevel(device);
|
||||
if (result)
|
||||
goto err;
|
||||
|
||||
/* Request default BW vote */
|
||||
result = kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON);
|
||||
|
||||
err:
|
||||
if (result)
|
||||
a6xx_hfi_stop(adreno_dev);
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
void hfi_stop(struct gmu_device *gmu)
|
||||
void a6xx_hfi_stop(struct adreno_device *adreno_dev)
|
||||
{
|
||||
struct gmu_memdesc *mem_addr = gmu->hfi_mem;
|
||||
struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev);
|
||||
struct gmu_memdesc *mem_addr = gmu->hfi.hfi_mem;
|
||||
struct hfi_queue_table *tbl = mem_addr->hostptr;
|
||||
struct hfi_queue_header *hdr;
|
||||
struct kgsl_hfi *hfi = &gmu->hfi;
|
||||
struct kgsl_device *device = hfi->kgsldev;
|
||||
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
|
||||
unsigned int i;
|
||||
|
||||
|
||||
if (!test_bit(GMU_HFI_ON, &device->gmu_core.flags))
|
||||
return;
|
||||
|
||||
/* Flush HFI queues */
|
||||
for (i = 0; i < HFI_QUEUE_MAX; i++) {
|
||||
hdr = &tbl->qhdr[i];
|
||||
|
|
@ -805,11 +789,14 @@ void hfi_stop(struct gmu_device *gmu)
|
|||
i, hdr->read_index, hdr->write_index);
|
||||
}
|
||||
|
||||
clear_bit(GMU_HFI_ON, &device->gmu_core.flags);
|
||||
kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_OFF);
|
||||
|
||||
clear_bit(GMU_PRIV_HFI_STARTED, &gmu->flags);
|
||||
|
||||
}
|
||||
|
||||
/* Entry point for external HFI requests */
|
||||
int hfi_send_req(struct gmu_device *gmu, unsigned int id, void *data)
|
||||
int a6xx_hfi_send_req(struct adreno_device *adreno_dev, unsigned int id,
|
||||
void *data)
|
||||
{
|
||||
switch (id) {
|
||||
case H2F_MSG_GX_BW_PERF_VOTE: {
|
||||
|
|
@ -817,7 +804,7 @@ int hfi_send_req(struct gmu_device *gmu, unsigned int id, void *data)
|
|||
|
||||
cmd->hdr = CMD_MSG_HDR(id, sizeof(*cmd));
|
||||
|
||||
return hfi_send_generic_req(gmu, HFI_CMD_ID, cmd);
|
||||
return a6xx_hfi_send_generic_req(adreno_dev, HFI_CMD_ID, cmd);
|
||||
}
|
||||
case H2F_MSG_PREPARE_SLUMBER: {
|
||||
struct hfi_prep_slumber_cmd *cmd = data;
|
||||
|
|
@ -827,24 +814,24 @@ int hfi_send_req(struct gmu_device *gmu, unsigned int id, void *data)
|
|||
|
||||
cmd->hdr = CMD_MSG_HDR(id, sizeof(*cmd));
|
||||
|
||||
return hfi_send_generic_req(gmu, HFI_CMD_ID, cmd);
|
||||
return a6xx_hfi_send_generic_req(adreno_dev, HFI_CMD_ID, cmd);
|
||||
}
|
||||
case H2F_MSG_START: {
|
||||
struct hfi_start_cmd *cmd = data;
|
||||
|
||||
cmd->hdr = CMD_MSG_HDR(id, sizeof(*cmd));
|
||||
|
||||
return hfi_send_generic_req(gmu, HFI_CMD_ID, cmd);
|
||||
return a6xx_hfi_send_generic_req(adreno_dev, HFI_CMD_ID, cmd);
|
||||
}
|
||||
case H2F_MSG_GET_VALUE: {
|
||||
return hfi_send_get_value(gmu, data);
|
||||
return a6xx_hfi_send_get_value(adreno_dev, data);
|
||||
}
|
||||
case H2F_MSG_SET_VALUE: {
|
||||
struct hfi_set_value_cmd *cmd = data;
|
||||
|
||||
cmd->hdr = CMD_MSG_HDR(id, sizeof(*cmd));
|
||||
|
||||
return hfi_send_generic_req(gmu, HFI_CMD_ID, cmd);
|
||||
return a6xx_hfi_send_generic_req(adreno_dev, HFI_CMD_ID, cmd);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
|
|
@ -854,20 +841,17 @@ int hfi_send_req(struct gmu_device *gmu, unsigned int id, void *data)
|
|||
}
|
||||
|
||||
/* HFI interrupt handler */
|
||||
irqreturn_t hfi_irq_handler(int irq, void *data)
|
||||
irqreturn_t a6xx_hfi_irq_handler(int irq, void *data)
|
||||
{
|
||||
struct kgsl_device *device = data;
|
||||
struct gmu_device *gmu = KGSL_GMU_DEVICE(device);
|
||||
struct kgsl_hfi *hfi = &gmu->hfi;
|
||||
struct a6xx_gmu_device *gmu = to_a6xx_gmu(ADRENO_DEVICE(device));
|
||||
unsigned int status = 0;
|
||||
|
||||
adreno_read_gmureg(ADRENO_DEVICE(device),
|
||||
ADRENO_REG_GMU_GMU2HOST_INTR_INFO, &status);
|
||||
adreno_write_gmureg(ADRENO_DEVICE(device),
|
||||
ADRENO_REG_GMU_GMU2HOST_INTR_CLR, HFI_IRQ_MASK);
|
||||
gmu_core_regread(device, A6XX_GMU_GMU2HOST_INTR_INFO, &status);
|
||||
gmu_core_regwrite(device, A6XX_GMU_GMU2HOST_INTR_CLR, HFI_IRQ_MASK);
|
||||
|
||||
if (status & HFI_IRQ_DBGQ_MASK)
|
||||
tasklet_hi_schedule(&hfi->tasklet);
|
||||
a6xx_hfi_process_queue(gmu, HFI_DBG_ID, NULL);
|
||||
if (status & HFI_IRQ_CM3_FAULT_MASK) {
|
||||
dev_err_ratelimited(&gmu->pdev->dev,
|
||||
"GMU CM3 fault interrupt received\n");
|
||||
|
|
@ -1,26 +1,15 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
#ifndef __KGSL_HFI_H
|
||||
#define __KGSL_HFI_H
|
||||
#ifndef __ADRENO_A6XX_HFI_H
|
||||
#define __ADRENO_A6XX_HFI_H
|
||||
|
||||
#define HFI_QUEUE_SIZE SZ_4K /* bytes, must be base 4dw */
|
||||
#define MAX_RCVD_PAYLOAD_SIZE 16 /* dwords */
|
||||
#define MAX_RCVD_SIZE (MAX_RCVD_PAYLOAD_SIZE + 3) /* dwords */
|
||||
#define HFI_MAX_MSG_SIZE (SZ_1K>>2) /* dwords */
|
||||
|
||||
/* Below section is for all structures related to HFI queues */
|
||||
#define HFI_QUEUE_DEFAULT_CNT 3
|
||||
#define HFI_QUEUE_DISPATCH_CNT 1
|
||||
#define HFI_QUEUE_MAX (HFI_QUEUE_DEFAULT_CNT + HFI_QUEUE_DISPATCH_CNT)
|
||||
|
||||
struct hfi_queue_table;
|
||||
|
||||
/* Total header sizes + queue sizes + 16 for alignment */
|
||||
#define HFIMEM_SIZE (sizeof(struct hfi_queue_table) + 16 + \
|
||||
(HFI_QUEUE_SIZE * HFI_QUEUE_MAX))
|
||||
|
||||
#define HFI_CMD_ID 0
|
||||
#define HFI_MSG_ID 1
|
||||
#define HFI_DBG_ID 2
|
||||
|
|
@ -47,7 +36,6 @@ struct hfi_queue_table;
|
|||
#define HFI_DSP_PRI_0 20
|
||||
|
||||
#define HFI_RSP_TIMEOUT 100 /* msec */
|
||||
#define HFI_H2F_CMD_IRQ_MASK BIT(0)
|
||||
|
||||
#define HFI_IRQ_MSGQ_MASK BIT(0)
|
||||
#define HFI_IRQ_SIDEMSGQ_MASK BIT(1)
|
||||
|
|
@ -58,16 +46,11 @@ struct hfi_queue_table;
|
|||
HFI_IRQ_DBGQ_MASK |\
|
||||
HFI_IRQ_CM3_FAULT_MASK)
|
||||
|
||||
#define CLKSET_OPTION_DEFAULT 0
|
||||
#define CLKSET_OPTION_CLOSEST 1
|
||||
#define CLKSET_OPTION_ATMOST 2
|
||||
#define CLKSET_OPTION_ATLEAST 3
|
||||
|
||||
#define DCVS_ACK_NONBLOCK 0
|
||||
#define DCVS_ACK_BLOCK 1
|
||||
|
||||
#define HFI_FEATURE_DCVS 0
|
||||
#define HFI_FEATURE_ECP 1
|
||||
#define HFI_FEATURE_HWSCHED 1
|
||||
#define HFI_FEATURE_PREEMPTION 2
|
||||
#define HFI_FEATURE_CLOCKS_ON 3
|
||||
#define HFI_FEATURE_BUS_ON 4
|
||||
|
|
@ -144,17 +127,16 @@ struct hfi_queue_header {
|
|||
uint32_t write_index;
|
||||
};
|
||||
|
||||
struct hfi_queue_table {
|
||||
struct hfi_queue_table_header qtbl_hdr;
|
||||
struct hfi_queue_header qhdr[HFI_QUEUE_MAX];
|
||||
};
|
||||
#define HFI_MSG_CMD 0 /* V1 and V2 */
|
||||
#define HFI_MSG_ACK 1 /* V2 only */
|
||||
#define HFI_V1_MSG_POST 1 /* V1 only */
|
||||
#define HFI_V1_MSG_ACK 2/* V1 only */
|
||||
|
||||
enum hfi_msg_type {
|
||||
HFI_MSG_CMD = 0, /* V1 and V2 */
|
||||
HFI_MSG_ACK = 1, /* V2 only */
|
||||
HFI_V1_MSG_POST = 1, /* V1 only */
|
||||
HFI_V1_MSG_ACK = 2, /* V1 only */
|
||||
};
|
||||
/* Size is converted from Bytes to DWords */
|
||||
#define CREATE_MSG_HDR(id, size, type) \
|
||||
(((type) << 16) | ((((size) >> 2) & 0xFF) << 8) | ((id) & 0xFF))
|
||||
#define CMD_MSG_HDR(id, size) CREATE_MSG_HDR(id, size, HFI_MSG_CMD)
|
||||
#define ACK_MSG_HDR(id, size) CREATE_MSG_HDR(id, size, HFI_MSG_ACK)
|
||||
|
||||
#define H2F_MSG_INIT 0
|
||||
#define H2F_MSG_FW_VER 1
|
||||
|
|
@ -174,6 +156,7 @@ enum hfi_msg_type {
|
|||
#define H2F_MSG_PREPARE_SLUMBER 33
|
||||
#define F2H_MSG_ERR 100
|
||||
#define F2H_MSG_DEBUG 101
|
||||
#define F2H_MSG_LOG_BLOCK 102
|
||||
#define F2H_MSG_GMU_CNTR_REGISTER 110
|
||||
#define F2H_MSG_GMU_CNTR_RELEASE 111
|
||||
#define F2H_MSG_ACK 126 /* Deprecated for v2.0*/
|
||||
|
|
@ -195,20 +178,13 @@ struct hfi_gmu_init_cmd {
|
|||
uint32_t dbg_buffer_addr;
|
||||
uint32_t dbg_buffer_size;
|
||||
uint32_t boot_state;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* H2F */
|
||||
struct hfi_fw_version_cmd {
|
||||
uint32_t hdr;
|
||||
uint32_t supported_ver;
|
||||
};
|
||||
|
||||
#define ARC_VOTE_GET_PRI(_v) ((_v) & 0xFF)
|
||||
#define ARC_VOTE_GET_SEC(_v) (((_v) >> 8) & 0xFF)
|
||||
#define ARC_VOTE_GET_VLVL(_v) (((_v) >> 16) & 0xFFFF)
|
||||
|
||||
#define ARC_VOTE_SET(pri, sec, vlvl) \
|
||||
((((vlvl) & 0xFFFF) << 16) | (((sec) & 0xFF) << 8) | ((pri) & 0xFF))
|
||||
} __packed;
|
||||
|
||||
/* H2F */
|
||||
struct hfi_bwtable_cmd {
|
||||
|
|
@ -222,7 +198,7 @@ struct hfi_bwtable_cmd {
|
|||
uint32_t cnoc_cmd_data[MAX_CNOC_LEVELS][MAX_CNOC_CMDS];
|
||||
uint32_t ddr_cmd_addrs[MAX_BW_CMDS];
|
||||
uint32_t ddr_cmd_data[MAX_GX_LEVELS][MAX_BW_CMDS];
|
||||
};
|
||||
} __packed;
|
||||
|
||||
struct opp_gx_desc {
|
||||
uint32_t vote;
|
||||
|
|
@ -242,7 +218,7 @@ struct hfi_dcvstable_v1_cmd {
|
|||
uint32_t gmu_level_num;
|
||||
struct opp_desc gx_votes[MAX_GX_LEVELS];
|
||||
struct opp_desc cx_votes[MAX_CX_LEVELS];
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* H2F */
|
||||
struct hfi_dcvstable_cmd {
|
||||
|
|
@ -251,9 +227,8 @@ struct hfi_dcvstable_cmd {
|
|||
uint32_t gmu_level_num;
|
||||
struct opp_gx_desc gx_votes[MAX_GX_LEVELS];
|
||||
struct opp_desc cx_votes[MAX_CX_LEVELS];
|
||||
};
|
||||
} __packed;
|
||||
|
||||
#define HFI_ACD_INIT_VERSION 1
|
||||
#define MAX_ACD_STRIDE 2
|
||||
#define MAX_ACD_NUM_LEVELS 6
|
||||
|
||||
|
|
@ -265,18 +240,18 @@ struct hfi_acd_table_cmd {
|
|||
uint32_t stride;
|
||||
uint32_t num_levels;
|
||||
uint32_t data[MAX_ACD_NUM_LEVELS * MAX_ACD_STRIDE];
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* H2F */
|
||||
struct hfi_test_cmd {
|
||||
uint32_t hdr;
|
||||
uint32_t data;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* H2F */
|
||||
struct hfi_start_cmd {
|
||||
uint32_t hdr;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* H2F */
|
||||
struct hfi_feature_ctrl_cmd {
|
||||
|
|
@ -284,27 +259,27 @@ struct hfi_feature_ctrl_cmd {
|
|||
uint32_t feature;
|
||||
uint32_t enable;
|
||||
uint32_t data;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* H2F */
|
||||
struct hfi_get_value_cmd {
|
||||
uint32_t hdr;
|
||||
uint32_t type;
|
||||
uint32_t subtype;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* Internal */
|
||||
struct hfi_get_value_req {
|
||||
struct hfi_get_value_cmd cmd;
|
||||
uint32_t data[16];
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* F2H */
|
||||
struct hfi_get_value_reply_cmd {
|
||||
uint32_t hdr;
|
||||
uint32_t req_hdr;
|
||||
uint32_t data[16];
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* H2F */
|
||||
struct hfi_set_value_cmd {
|
||||
|
|
@ -312,53 +287,13 @@ struct hfi_set_value_cmd {
|
|||
uint32_t type;
|
||||
uint32_t subtype;
|
||||
uint32_t data;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* H2F */
|
||||
struct hfi_core_fw_start_cmd {
|
||||
uint32_t hdr;
|
||||
uint32_t handle;
|
||||
};
|
||||
|
||||
/* CP/GFX pipeline can access, The mem_kind may imply restrictions for non-CP */
|
||||
#define MEMFLAG_GFX_ACC BIT(0)
|
||||
/* Buffer has APRIV protection in GFX PTEs */
|
||||
#define MEMFLAG_GFX_PRIV BIT(1)
|
||||
/* Buffer is read-write for GFX PTEs. A 0 indicates read-only */
|
||||
#define MEMFLAG_GFX_WRITEABLE BIT(2)
|
||||
/* GMU can access */
|
||||
#define MEMFLAG_GMU_ACC BIT(3)
|
||||
/* Buffer has APRIV protection in GMU PTEs */
|
||||
#define MEMFLAG_GMU_PRIV BIT(4)
|
||||
/* Buffer is read-write for GMU PTEs. A 0 indicates read-only */
|
||||
#define MEMFLAG_GMU_WRITEABLE BIT(5)
|
||||
/* Buffer is located in GMU's non-cached bufferable VA range */
|
||||
#define MEMFLAG_GMU_BUFFERABLE BIT(6)
|
||||
/* Buffer is located in GMU's cacheable VA range */
|
||||
#define MEMFLAG_GMU_CACHEABLE BIT(7)
|
||||
/* Host can access */
|
||||
#define MEMFLAG_HOST_ACC BIT(8)
|
||||
/*
|
||||
* Request that Host initialize the buffer.
|
||||
* Implies zero-init, unless Memkind implies otherwise
|
||||
*/
|
||||
#define MEMFLAG_HOST_INIT BIT(9)
|
||||
|
||||
#define HFI_MEMKIND_GENERIC 0
|
||||
#define HFI_MEMKIND_RB 1
|
||||
#define HFI_MEMKIND_MEMSTORE 2
|
||||
#define HFI_MEMKIND_CSW_SMMU_INFO 3
|
||||
#define HFI_MEMKIND_CSW_PRIV_NON_SECURE 4
|
||||
#define HFI_MEMKIND_CSW_PRIV_SECURE 5
|
||||
#define HFI_MEMKIND_CSW_NON_PRIV 6
|
||||
#define HFI_MEMKIND_CSW_COUNTER 7
|
||||
#define HFI_MEMKIND_CTXTREC_PERF_CNTR_SAVE_RESTORE 8
|
||||
#define HFI_MEMKIND_CTXTREC_PREEMPT_CNTR 9
|
||||
#define HFI_MEMKIND_SYS_LOG 10
|
||||
#define HFI_MEMKIND_CRASH_DUMP 11
|
||||
#define HFI_MEMKIND_MMIO_DPU 12
|
||||
#define HFI_MEMKIND_MMIO_TCSR 13
|
||||
#define HFI_MEMKIND_MMIO_QDSS_STM 14
|
||||
} __packed;
|
||||
|
||||
struct hfi_mem_alloc_desc {
|
||||
uint64_t gpu_addr;
|
||||
|
|
@ -368,21 +303,21 @@ struct hfi_mem_alloc_desc {
|
|||
uint32_t gmu_mem_handle;
|
||||
uint32_t gmu_addr;
|
||||
uint32_t size; /* Bytes */
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* F2H */
|
||||
struct hfi_mem_alloc_cmd {
|
||||
uint32_t hdr;
|
||||
uint32_t reserved; /* Padding to ensure alignment of 'desc' below */
|
||||
struct hfi_mem_alloc_desc desc;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* H2F */
|
||||
struct hfi_mem_alloc_reply_cmd {
|
||||
uint32_t hdr;
|
||||
uint32_t req_hdr;
|
||||
struct hfi_mem_alloc_desc desc;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* H2F */
|
||||
struct hfi_gx_bw_perf_vote_cmd {
|
||||
|
|
@ -390,27 +325,27 @@ struct hfi_gx_bw_perf_vote_cmd {
|
|||
uint32_t ack_type;
|
||||
uint32_t freq;
|
||||
uint32_t bw;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* H2F */
|
||||
struct hfi_fw_halt_cmd {
|
||||
uint32_t hdr;
|
||||
uint32_t en_halt;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* H2F */
|
||||
struct hfi_prep_slumber_cmd {
|
||||
uint32_t hdr;
|
||||
uint32_t bw;
|
||||
uint32_t freq;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* F2H */
|
||||
struct hfi_err_cmd {
|
||||
uint32_t hdr;
|
||||
uint32_t error_code;
|
||||
uint32_t data[16];
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* F2H */
|
||||
struct hfi_debug_cmd {
|
||||
|
|
@ -418,14 +353,14 @@ struct hfi_debug_cmd {
|
|||
uint32_t type;
|
||||
uint32_t timestamp;
|
||||
uint32_t data;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* F2H */
|
||||
struct hfi_gmu_cntr_register_cmd {
|
||||
uint32_t hdr;
|
||||
uint32_t group_id;
|
||||
uint32_t countable;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* H2F */
|
||||
struct hfi_gmu_cntr_register_reply_cmd {
|
||||
|
|
@ -434,37 +369,14 @@ struct hfi_gmu_cntr_register_reply_cmd {
|
|||
uint32_t group_id;
|
||||
uint32_t countable;
|
||||
uint64_t counter_addr;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* F2H */
|
||||
struct hfi_gmu_cntr_release_cmd {
|
||||
uint32_t hdr;
|
||||
uint32_t group_id;
|
||||
uint32_t countable;
|
||||
};
|
||||
|
||||
#define CTXT_FLAG_PMODE 0x00000001
|
||||
#define CTXT_FLAG_SWITCH_INTERNAL 0x00000002
|
||||
#define CTXT_FLAG_SWITCH 0x00000008
|
||||
#define CTXT_FLAG_NOTIFY 0x00000020
|
||||
#define CTXT_FLAG_NO_FAULT_TOLERANCE 0x00000200
|
||||
#define CTXT_FLAG_PWR_RULE 0x00000800
|
||||
#define CTXT_FLAG_PRIORITY_MASK 0x0000F000
|
||||
#define CTXT_FLAG_IFH_NOP 0x00010000
|
||||
#define CTXT_FLAG_SECURE 0x00020000
|
||||
#define CTXT_FLAG_TYPE_MASK 0x01F00000
|
||||
#define CTXT_FLAG_TYPE_SHIFT 20
|
||||
#define CTXT_FLAG_TYPE_ANY 0
|
||||
#define CTXT_FLAG_TYPE_GL 1
|
||||
#define CTXT_FLAG_TYPE_CL 2
|
||||
#define CTXT_FLAG_TYPE_C2D 3
|
||||
#define CTXT_FLAG_TYPE_RS 4
|
||||
#define CTXT_FLAG_TYPE_UNKNOWN 0x1E
|
||||
#define CTXT_FLAG_PREEMPT_STYLE_MASK 0x0E000000
|
||||
#define CTXT_FLAG_PREEMPT_STYLE_SHIFT 25
|
||||
#define CTXT_FLAG_PREEMPT_STYLE_ANY 0
|
||||
#define CTXT_FLAG_PREEMPT_STYLE_RB 1
|
||||
#define CTXT_FLAG_PREEMPT_STYLE_FG 2
|
||||
} __packed;
|
||||
|
||||
/* H2F */
|
||||
struct hfi_register_ctxt_cmd {
|
||||
|
|
@ -474,25 +386,19 @@ struct hfi_register_ctxt_cmd {
|
|||
uint64_t pt_addr;
|
||||
uint32_t ctxt_idr;
|
||||
uint32_t ctxt_bank;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* H2F */
|
||||
struct hfi_unregister_ctxt_cmd {
|
||||
uint32_t hdr;
|
||||
uint32_t ctxt_id;
|
||||
uint32_t ts;
|
||||
};
|
||||
|
||||
#define CMDBATCH_SWITCH CTXT_FLAG_SWITCH
|
||||
#define CMDBATCH_NOTIFY CTXT_FLAG_NOTIFY
|
||||
#define CMDBATCH_PROFILING 0x00000010
|
||||
#define CMDBATCH_EOF 0x00000100
|
||||
#define CMDBATCH_PWR_STRICT CTXT_FLAG_PWR_RULE
|
||||
} __packed;
|
||||
|
||||
struct hfi_issue_ib {
|
||||
uint64_t addr;
|
||||
uint32_t size;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* H2F */
|
||||
struct hfi_issue_cmd_cmd {
|
||||
|
|
@ -502,21 +408,21 @@ struct hfi_issue_cmd_cmd {
|
|||
uint32_t ts;
|
||||
uint32_t count;
|
||||
struct hfi_issue_ib *ibs[];
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* Internal */
|
||||
struct hfi_issue_cmd_req {
|
||||
uint32_t queue;
|
||||
uint32_t ctxt_id;
|
||||
struct hfi_issue_cmd_cmd cmd;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* H2F */
|
||||
/* The length of *buf will be embedded in the hdr */
|
||||
struct hfi_issue_cmd_raw_cmd {
|
||||
uint32_t hdr;
|
||||
uint32_t *buf;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* Internal */
|
||||
struct hfi_issue_cmd_raw_req {
|
||||
|
|
@ -524,27 +430,27 @@ struct hfi_issue_cmd_raw_req {
|
|||
uint32_t ctxt_id;
|
||||
uint32_t len;
|
||||
uint32_t *buf;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* H2F */
|
||||
struct hfi_ts_notify_cmd {
|
||||
uint32_t hdr;
|
||||
uint32_t ctxt_id;
|
||||
uint32_t ts;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
#define TS_RETIRE_FLUSH 1
|
||||
#define TS_RETIRE_ERROR 2
|
||||
#define TS_RETIRE_PAST 3
|
||||
#define TS_RETIRE_DONE 4
|
||||
#define CMDBATCH_SUCCESS 0
|
||||
#define CMDBATCH_RETIRED 1
|
||||
#define CMDBATCH_ERROR 2
|
||||
#define CMDBATCH_SKIP 3
|
||||
|
||||
/* F2H */
|
||||
struct hfi_ts_retire_cmd {
|
||||
uint32_t hdr;
|
||||
uint32_t ctxt_id;
|
||||
uint32_t ts;
|
||||
uint32_t type;
|
||||
};
|
||||
uint32_t ret;
|
||||
} __packed;
|
||||
|
||||
/* H2F */
|
||||
struct hfi_context_pointers_cmd {
|
||||
|
|
@ -552,7 +458,7 @@ struct hfi_context_pointers_cmd {
|
|||
uint32_t ctxt_id;
|
||||
uint64_t sop_addr;
|
||||
uint64_t eop_addr;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* H2F */
|
||||
struct hfi_context_rule_cmd {
|
||||
|
|
@ -560,7 +466,7 @@ struct hfi_context_rule_cmd {
|
|||
uint32_t ctxt_id;
|
||||
uint32_t type;
|
||||
uint32_t status;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* F2H */
|
||||
struct hfi_context_bad_cmd {
|
||||
|
|
@ -568,13 +474,13 @@ struct hfi_context_bad_cmd {
|
|||
uint32_t ctxt_id;
|
||||
uint32_t status;
|
||||
uint32_t error;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* H2F */
|
||||
struct hfi_context_bad_reply_cmd {
|
||||
uint32_t hdr;
|
||||
uint32_t req_hdr;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct pending_cmd - data structure to track outstanding HFI
|
||||
|
|
@ -588,36 +494,64 @@ struct pending_cmd {
|
|||
};
|
||||
|
||||
/**
|
||||
* struct kgsl_hfi - HFI control structure
|
||||
* @kgsldev: Point to the kgsl device
|
||||
* @hfi_interrupt_num: number of GMU asserted HFI interrupt
|
||||
* @cmdq_mutex: mutex to protect command queue access from multiple senders
|
||||
* @tasklet: the thread handling received messages from GMU
|
||||
* struct a6xx_hfi - HFI control structure
|
||||
* @seqnum: atomic counter that is incremented for each message sent. The
|
||||
* value of the counter is used as sequence number for HFI message
|
||||
* @bwtbl_cmd: HFI BW table buffer
|
||||
* @acd_tbl_cmd: HFI table for ACD data
|
||||
* @bw_table: HFI BW table buffer
|
||||
* @acd_table: HFI table for ACD data
|
||||
*/
|
||||
struct kgsl_hfi {
|
||||
struct kgsl_device *kgsldev;
|
||||
int hfi_interrupt_num;
|
||||
struct mutex cmdq_mutex;
|
||||
struct tasklet_struct tasklet;
|
||||
struct a6xx_hfi {
|
||||
/** @irq: HFI interrupt line */
|
||||
int irq;
|
||||
atomic_t seqnum;
|
||||
struct hfi_bwtable_cmd bwtbl_cmd;
|
||||
struct hfi_acd_table_cmd acd_tbl_cmd;
|
||||
/** @hfi_mem: Memory descriptor for the hfi memory */
|
||||
struct gmu_memdesc *hfi_mem;
|
||||
struct hfi_bwtable_cmd bw_table;
|
||||
struct hfi_acd_table_cmd acd_table;
|
||||
/** @dcvs_table: HFI table for gpu dcvs levels */
|
||||
struct hfi_dcvstable_cmd dcvs_table;
|
||||
};
|
||||
|
||||
struct gmu_device;
|
||||
struct gmu_memdesc;
|
||||
struct a6xx_gmu_device;
|
||||
|
||||
irqreturn_t hfi_irq_handler(int irq, void *data);
|
||||
int hfi_start(struct kgsl_device *device, struct gmu_device *gmu,
|
||||
uint32_t boot_state);
|
||||
void hfi_stop(struct gmu_device *gmu);
|
||||
void hfi_receiver(unsigned long data);
|
||||
void hfi_init(struct gmu_device *gmu);
|
||||
/* a6xx_hfi_irq_handler - IRQ handler for HFI interripts */
|
||||
irqreturn_t a6xx_hfi_irq_handler(int irq, void *data);
|
||||
|
||||
/* hfi_send_req is only for external (to HFI) requests */
|
||||
int hfi_send_req(struct gmu_device *gmu, unsigned int id, void *data);
|
||||
#endif /* __KGSL_HFI_H */
|
||||
/**
|
||||
* a6xx_hfi_start - Send the various HFIs during device boot up
|
||||
* @adreno_dev: Pointer to the adreno device
|
||||
*
|
||||
* Return: 0 on success or negative error on failure
|
||||
*/
|
||||
int a6xx_hfi_start(struct adreno_device *adreno_dev);
|
||||
|
||||
/**
|
||||
* a6xx_hfi_start - Send the various HFIs during device boot up
|
||||
* @adreno_dev: Pointer to the adreno device
|
||||
*
|
||||
* Return: 0 on success or negative error on failure
|
||||
*/
|
||||
void a6xx_hfi_stop(struct adreno_device *adreno_dev);
|
||||
|
||||
/**
|
||||
* a6xx_hfi_init - Initialize hfi resources
|
||||
* @adreno_dev: Pointer to the adreno device
|
||||
*
|
||||
* This function allocates and sets up hfi queues
|
||||
* when a process creates the very first kgsl instance
|
||||
*
|
||||
* Return: 0 on success or negative error on failure
|
||||
*/
|
||||
int a6xx_hfi_init(struct adreno_device *adreno_dev);
|
||||
|
||||
/**
|
||||
* a6xx_hfi_send_req - Send an HFI packet to GMU
|
||||
* @adreno_dev: Pointer to the adreno device
|
||||
* @id: Packet id to be sent
|
||||
* @data: Container for the data sent as part of this pcket
|
||||
*
|
||||
* Return: 0 on success or negative error on failure
|
||||
*/
|
||||
int a6xx_hfi_send_req(struct adreno_device *adreno_dev,
|
||||
unsigned int id, void *data);
|
||||
#endif
|
||||
|
|
@ -375,7 +375,7 @@ void a6xx_preemption_trigger(struct adreno_device *adreno_dev)
|
|||
err:
|
||||
/* If fenced write fails, take inline snapshot and trigger recovery */
|
||||
if (!in_interrupt()) {
|
||||
gmu_core_snapshot(device);
|
||||
gmu_fault_snapshot(device);
|
||||
adreno_set_gpu_fault(adreno_dev,
|
||||
ADRENO_GMU_FAULT_SKIP_SNAPSHOT);
|
||||
} else {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
92
drivers/gpu/msm/adreno_a6xx_rgmu.h
Normal file
92
drivers/gpu/msm/adreno_a6xx_rgmu.h
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
#ifndef __ADRENO_A6XX_RGMU_H
|
||||
#define __ADRENO_A6XX_RGMU_H
|
||||
|
||||
#define RGMU_AO_IRQ_FENCE_ERR BIT(3)
|
||||
#define RGMU_AO_IRQ_MASK RGMU_AO_IRQ_FENCE_ERR
|
||||
|
||||
#define RGMU_OOB_IRQ_ERR_MSG BIT(24)
|
||||
#define RGMU_OOB_IRQ_ACK_MASK GENMASK(23, 16)
|
||||
#define RGMU_OOB_IRQ_ERR_MSG_MASK GENMASK(31, 24)
|
||||
#define RGMU_OOB_IRQ_MASK RGMU_OOB_IRQ_ERR_MSG_MASK
|
||||
|
||||
#define MAX_RGMU_CLKS 8
|
||||
|
||||
enum {
|
||||
/* @RGMU_PRIV_FIRST_BOOT_DONE: The very first ggpu boot is done */
|
||||
RGMU_PRIV_FIRST_BOOT_DONE,
|
||||
/* @RGMU_PRIV_GPU_STARTED: GPU has been started */
|
||||
RGMU_PRIV_GPU_STARTED,
|
||||
/* @RGMU_PRIV_PM_SUSPEND: The rgmu driver is suspended */
|
||||
RGMU_PRIV_PM_SUSPEND,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct a6xx_rgmu_device - rGMU device structure
|
||||
* @ver: RGMU firmware version
|
||||
* @rgmu_interrupt_num: RGMU interrupt number
|
||||
* @oob_interrupt_num: number of RGMU asserted OOB interrupt
|
||||
* @fw_hostptr: Buffer which holds the RGMU firmware
|
||||
* @fw_size: Size of RGMU firmware buffer
|
||||
* @cx_gdsc: CX headswitch that controls power of RGMU and
|
||||
subsystem peripherals
|
||||
* @clks: RGMU clocks including the GPU
|
||||
* @gpu_clk: Pointer to GPU core clock
|
||||
* @rgmu_clk: Pointer to rgmu clock
|
||||
* @flags: RGMU flags
|
||||
* @idle_level: Minimal GPU idle power level
|
||||
* @fault_count: RGMU fault count
|
||||
*/
|
||||
struct a6xx_rgmu_device {
|
||||
u32 ver;
|
||||
struct platform_device *pdev;
|
||||
unsigned int rgmu_interrupt_num;
|
||||
unsigned int oob_interrupt_num;
|
||||
unsigned int *fw_hostptr;
|
||||
uint32_t fw_size;
|
||||
struct regulator *cx_gdsc;
|
||||
struct regulator *gx_gdsc;
|
||||
struct clk_bulk_data *clks;
|
||||
/** @num_clks: Number of clocks in @clks */
|
||||
int num_clks;
|
||||
struct clk *gpu_clk;
|
||||
struct clk *rgmu_clk;
|
||||
unsigned int idle_level;
|
||||
unsigned int fault_count;
|
||||
/** @flags: rgmu internal flags */
|
||||
unsigned long flags;
|
||||
};
|
||||
|
||||
/**
|
||||
* a6xx_rgmu_device_probe - Probe a6xx rgmu resources
|
||||
* @pdev: Pointer to the platform device
|
||||
* @chipid: Chipid of the target
|
||||
* @gpucore: Pointer to the gpucore
|
||||
*
|
||||
* The target specific probe function for rgmu based a6xx targets.
|
||||
*/
|
||||
int a6xx_rgmu_device_probe(struct platform_device *pdev,
|
||||
u32 chipid, const struct adreno_gpu_core *gpucore);
|
||||
|
||||
/**
|
||||
* a6xx_rgmu_restart - Reset and restart the rgmu
|
||||
* @device: Pointer to the kgsl device
|
||||
*
|
||||
* Return: 0 on success or negative error on failure
|
||||
*/
|
||||
int a6xx_rgmu_restart(struct kgsl_device *device);
|
||||
|
||||
/**
|
||||
* a6xx_rgmu_snapshot - Take snapshot for rgmu based targets
|
||||
* @adreno_dev: Pointer to the adreno device
|
||||
* @snapshot: Pointer to the snapshot
|
||||
*
|
||||
* This function halts rgmu execution if we hit a rgmu
|
||||
* fault. And then, it takes rgmu and gpu snapshot.
|
||||
*/
|
||||
void a6xx_rgmu_snapshot(struct adreno_device *adreno_dev,
|
||||
struct kgsl_snapshot *snapshot);
|
||||
#endif
|
||||
462
drivers/gpu/msm/adreno_a6xx_rpmh.c
Normal file
462
drivers/gpu/msm/adreno_a6xx_rpmh.c
Normal file
|
|
@ -0,0 +1,462 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <dt-bindings/regulator/qcom,rpmh-regulator-levels.h>
|
||||
#include <linux/types.h>
|
||||
#include <soc/qcom/cmd-db.h>
|
||||
#include <soc/qcom/tcs.h>
|
||||
|
||||
#include "adreno.h"
|
||||
#include "adreno_a6xx.h"
|
||||
#include "kgsl_bus.h"
|
||||
#include "kgsl_device.h"
|
||||
|
||||
struct rpmh_arc_vals {
|
||||
u32 num;
|
||||
const u16 *val;
|
||||
};
|
||||
|
||||
struct bcm {
|
||||
const char *name;
|
||||
u32 buswidth;
|
||||
u32 channels;
|
||||
u32 unit;
|
||||
u16 width;
|
||||
u8 vcd;
|
||||
bool fixed;
|
||||
};
|
||||
|
||||
struct bcm_data {
|
||||
__le32 unit;
|
||||
__le16 width;
|
||||
u8 vcd;
|
||||
u8 reserved;
|
||||
};
|
||||
|
||||
struct rpmh_bw_votes {
|
||||
u32 wait_bitmask;
|
||||
u32 num_cmds;
|
||||
u32 *addrs;
|
||||
u32 num_levels;
|
||||
u32 **cmds;
|
||||
};
|
||||
|
||||
#define ARC_VOTE_SET(pri, sec, vlvl) \
|
||||
((((vlvl) & 0xFFFF) << 16) | (((sec) & 0xFF) << 8) | ((pri) & 0xFF))
|
||||
|
||||
static int rpmh_arc_cmds(struct rpmh_arc_vals *arc, const char *res_id)
|
||||
{
|
||||
size_t len = 0;
|
||||
|
||||
arc->val = cmd_db_read_aux_data(res_id, &len);
|
||||
|
||||
/*
|
||||
* cmd_db_read_aux_data() gives us a zero-padded table of
|
||||
* size len that contains the arc values. To determine the
|
||||
* number of arc values, we loop through the table and count
|
||||
* them until we get to the end of the buffer or hit the
|
||||
* zero padding.
|
||||
*/
|
||||
for (arc->num = 1; arc->num < (len >> 1); arc->num++) {
|
||||
if (arc->val[arc->num - 1] != 0 && arc->val[arc->num] == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setup_volt_dependency_tbl(uint32_t *votes,
|
||||
struct rpmh_arc_vals *pri_rail, struct rpmh_arc_vals *sec_rail,
|
||||
u16 *vlvl, unsigned int num_entries)
|
||||
{
|
||||
int i, j, k;
|
||||
uint16_t cur_vlvl;
|
||||
bool found_match;
|
||||
|
||||
/* i tracks current KGSL GPU frequency table entry
|
||||
* j tracks secondary rail voltage table entry
|
||||
* k tracks primary rail voltage table entry
|
||||
*/
|
||||
for (i = 0; i < num_entries; i++) {
|
||||
found_match = false;
|
||||
|
||||
/* Look for a primary rail voltage that matches a VLVL level */
|
||||
for (k = 0; k < pri_rail->num; k++) {
|
||||
if (pri_rail->val[k] >= vlvl[i]) {
|
||||
cur_vlvl = pri_rail->val[k];
|
||||
found_match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we did not find a matching VLVL level then abort */
|
||||
if (!found_match)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Look for a secondary rail index whose VLVL value
|
||||
* is greater than or equal to the VLVL value of the
|
||||
* corresponding index of the primary rail
|
||||
*/
|
||||
for (j = 0; j < sec_rail->num; j++) {
|
||||
if (sec_rail->val[j] >= cur_vlvl ||
|
||||
j + 1 == sec_rail->num)
|
||||
break;
|
||||
}
|
||||
|
||||
if (j == sec_rail->num)
|
||||
j = 0;
|
||||
|
||||
votes[i] = ARC_VOTE_SET(k, j, cur_vlvl);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Generate a set of bandwidth votes for the list of BCMs */
|
||||
static void tcs_cmd_data(struct bcm *bcms, int count, u32 ab, u32 ib,
|
||||
u32 *data)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
bool valid = true;
|
||||
bool commit = false;
|
||||
u64 avg, peak, x, y;
|
||||
|
||||
if (i == count - 1 || bcms[i].vcd != bcms[i + 1].vcd)
|
||||
commit = true;
|
||||
|
||||
/*
|
||||
* On a660, the "ACV" y vote should be 0x08 if there is a valid
|
||||
* vote and 0x00 if not. This is kind of hacky and a660 specific
|
||||
* but we can clean it up when we add a new target
|
||||
*/
|
||||
if (bcms[i].fixed) {
|
||||
if (!ab && !ib)
|
||||
data[i] = BCM_TCS_CMD(commit, false, 0x0, 0x0);
|
||||
else
|
||||
data[i] = BCM_TCS_CMD(commit, true, 0x0, 0x8);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Multiple the bandwidth by the width of the connection */
|
||||
avg = ((u64) ab) * bcms[i].width;
|
||||
|
||||
/* And then divide by the total width across channels */
|
||||
do_div(avg, bcms[i].buswidth * bcms[i].channels);
|
||||
|
||||
peak = ((u64) ib) * bcms[i].width;
|
||||
do_div(peak, bcms[i].buswidth);
|
||||
|
||||
/* Input bandwidth value is in KBps */
|
||||
x = avg * 1000ULL;
|
||||
do_div(x, bcms[i].unit);
|
||||
|
||||
/* Input bandwidth value is in KBps */
|
||||
y = peak * 1000ULL;
|
||||
do_div(y, bcms[i].unit);
|
||||
|
||||
/*
|
||||
* If a bandwidth value was specified but the calculation ends
|
||||
* rounding down to zero, set a minimum level
|
||||
*/
|
||||
if (ab && x == 0)
|
||||
x = 1;
|
||||
|
||||
if (ib && y == 0)
|
||||
y = 1;
|
||||
|
||||
x = min_t(u64, x, BCM_TCS_CMD_VOTE_MASK);
|
||||
y = min_t(u64, y, BCM_TCS_CMD_VOTE_MASK);
|
||||
|
||||
if (!x && !y)
|
||||
valid = false;
|
||||
|
||||
data[i] = BCM_TCS_CMD(commit, valid, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
static void free_rpmh_bw_votes(struct rpmh_bw_votes *votes)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!votes)
|
||||
return;
|
||||
|
||||
for (i = 0; votes->cmds && i < votes->num_levels; i++)
|
||||
kfree(votes->cmds[i]);
|
||||
|
||||
kfree(votes->cmds);
|
||||
kfree(votes->addrs);
|
||||
kfree(votes);
|
||||
}
|
||||
|
||||
/* Build the votes table from the specified bandwidth levels */
|
||||
static struct rpmh_bw_votes *build_rpmh_bw_votes(struct bcm *bcms,
|
||||
int bcm_count, u32 *levels, int levels_count)
|
||||
{
|
||||
struct rpmh_bw_votes *votes;
|
||||
int i;
|
||||
|
||||
votes = kzalloc(sizeof(*votes), GFP_KERNEL);
|
||||
if (!votes)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
votes->addrs = kcalloc(bcm_count, sizeof(*votes->cmds), GFP_KERNEL);
|
||||
if (!votes->addrs) {
|
||||
free_rpmh_bw_votes(votes);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
votes->cmds = kcalloc(levels_count, sizeof(*votes->cmds), GFP_KERNEL);
|
||||
if (!votes->cmds) {
|
||||
free_rpmh_bw_votes(votes);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
votes->num_cmds = bcm_count;
|
||||
votes->num_levels = levels_count;
|
||||
|
||||
/* Get the cmd-db information for each BCM */
|
||||
for (i = 0; i < bcm_count; i++) {
|
||||
size_t l;
|
||||
const struct bcm_data *data;
|
||||
|
||||
data = cmd_db_read_aux_data(bcms[i].name, &l);
|
||||
|
||||
votes->addrs[i] = cmd_db_read_addr(bcms[i].name);
|
||||
|
||||
bcms[i].unit = le32_to_cpu(data->unit);
|
||||
bcms[i].width = le16_to_cpu(data->width);
|
||||
bcms[i].vcd = data->vcd;
|
||||
}
|
||||
|
||||
for (i = 0; i < bcm_count; i++) {
|
||||
if (i == (bcm_count - 1) || bcms[i].vcd != bcms[i + 1].vcd)
|
||||
votes->wait_bitmask |= (1 << i);
|
||||
}
|
||||
|
||||
for (i = 0; i < levels_count; i++) {
|
||||
votes->cmds[i] = kcalloc(bcm_count, sizeof(u32), GFP_KERNEL);
|
||||
if (!votes->cmds[i]) {
|
||||
free_rpmh_bw_votes(votes);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
tcs_cmd_data(bcms, bcm_count, 0, levels[i], votes->cmds[i]);
|
||||
}
|
||||
|
||||
return votes;
|
||||
}
|
||||
|
||||
/*
|
||||
* setup_gmu_arc_votes - Build the gmu voting table
|
||||
* @hfi: Pointer to hfi device
|
||||
* @pri_rail: Pointer to primary power rail vlvl table
|
||||
* @sec_rail: Pointer to second/dependent power rail vlvl table
|
||||
*
|
||||
* This function initializes the cx votes for all gmu frequencies
|
||||
* for gmu dcvs
|
||||
*/
|
||||
static int setup_cx_arc_votes(struct a6xx_hfi *hfi,
|
||||
struct rpmh_arc_vals *pri_rail, struct rpmh_arc_vals *sec_rail)
|
||||
{
|
||||
/* Hardcoded values of GMU CX voltage levels */
|
||||
u16 gmu_cx_vlvl[] = { 0, RPMH_REGULATOR_LEVEL_MIN_SVS };
|
||||
u32 cx_votes[MAX_CX_LEVELS];
|
||||
struct hfi_dcvstable_cmd *table = &hfi->dcvs_table;
|
||||
int ret, i;
|
||||
|
||||
table->gmu_level_num = 2;
|
||||
|
||||
table->cx_votes[0].freq = 0;
|
||||
table->cx_votes[1].freq = GMU_FREQUENCY / 1000;
|
||||
|
||||
ret = setup_volt_dependency_tbl(cx_votes, pri_rail,
|
||||
sec_rail, gmu_cx_vlvl, table->gmu_level_num);
|
||||
if (!ret) {
|
||||
for (i = 0; i < table->gmu_level_num; i++)
|
||||
table->cx_votes[i].vote = cx_votes[i];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* setup_gx_arc_votes - Build the gpu dcvs voting table
|
||||
* @hfi: Pointer to hfi device
|
||||
* @pri_rail: Pointer to primary power rail vlvl table
|
||||
* @sec_rail: Pointer to second/dependent power rail vlvl table
|
||||
*
|
||||
* This function initializes the gx votes for all gpu frequencies
|
||||
* for gpu dcvs
|
||||
*/
|
||||
static int setup_gx_arc_votes(struct adreno_device *adreno_dev,
|
||||
struct rpmh_arc_vals *pri_rail, struct rpmh_arc_vals *sec_rail)
|
||||
{
|
||||
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
|
||||
struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev);
|
||||
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
|
||||
struct hfi_dcvstable_cmd *table = &gmu->hfi.dcvs_table;
|
||||
u32 index;
|
||||
u16 vlvl_tbl[MAX_GX_LEVELS];
|
||||
u32 gx_votes[MAX_GX_LEVELS];
|
||||
int ret, i;
|
||||
|
||||
/* Add the zero powerlevel for the perf table */
|
||||
table->gpu_level_num = device->pwrctrl.num_pwrlevels + 1;
|
||||
|
||||
if (table->gpu_level_num > pri_rail->num ||
|
||||
table->gpu_level_num > ARRAY_SIZE(vlvl_tbl)) {
|
||||
dev_err(&gmu->pdev->dev,
|
||||
"Defined more GPU DCVS levels than RPMh can support\n");
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
memset(vlvl_tbl, 0, sizeof(vlvl_tbl));
|
||||
|
||||
table->gx_votes[0].freq = 0;
|
||||
|
||||
/* GMU power levels are in ascending order */
|
||||
for (index = 1, i = pwr->num_pwrlevels - 1; i >= 0; i--, index++) {
|
||||
vlvl_tbl[index] = pwr->pwrlevels[i].voltage_level;
|
||||
table->gx_votes[index].freq = pwr->pwrlevels[i].gpu_freq / 1000;
|
||||
}
|
||||
|
||||
ret = setup_volt_dependency_tbl(gx_votes, pri_rail,
|
||||
sec_rail, vlvl_tbl, table->gpu_level_num);
|
||||
if (!ret) {
|
||||
for (i = 0; i < table->gpu_level_num; i++) {
|
||||
table->gx_votes[i].vote = gx_votes[i];
|
||||
table->gx_votes[i].acd = 0xffffffff;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static int build_dcvs_table(struct adreno_device *adreno_dev)
|
||||
{
|
||||
struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev);
|
||||
struct a6xx_hfi *hfi = &gmu->hfi;
|
||||
struct rpmh_arc_vals gx_arc, cx_arc, mx_arc;
|
||||
int ret;
|
||||
|
||||
hfi->dcvs_table.hdr = CMD_MSG_HDR(H2F_MSG_PERF_TBL,
|
||||
sizeof(hfi->dcvs_table));
|
||||
|
||||
ret = rpmh_arc_cmds(&gx_arc, "gfx.lvl");
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = rpmh_arc_cmds(&cx_arc, "cx.lvl");
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = rpmh_arc_cmds(&mx_arc, "mx.lvl");
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = setup_cx_arc_votes(hfi, &cx_arc, &mx_arc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return setup_gx_arc_votes(adreno_dev, &gx_arc, &mx_arc);
|
||||
}
|
||||
|
||||
/*
|
||||
* List of Bus Control Modules (BCMs) that need to be configured for the GPU
|
||||
* to access DDR. For each bus level we will generate a vote each BC
|
||||
*/
|
||||
static struct bcm a660_ddr_bcms[] = {
|
||||
{ .name = "SH0", .buswidth = 16 },
|
||||
{ .name = "MC0", .buswidth = 4 },
|
||||
{ .name = "ACV", .fixed = true },
|
||||
};
|
||||
|
||||
/* Same as above, but for the CNOC BCMs */
|
||||
static struct bcm a660_cnoc_bcms[] = {
|
||||
{ .name = "CN0", .buswidth = 4 },
|
||||
};
|
||||
|
||||
static void build_bw_table_cmd(struct hfi_bwtable_cmd *cmd,
|
||||
struct rpmh_bw_votes *ddr, struct rpmh_bw_votes *cnoc)
|
||||
{
|
||||
u32 i, j;
|
||||
|
||||
cmd->hdr = CMD_MSG_HDR(H2F_MSG_BW_VOTE_TBL, sizeof(*cmd));
|
||||
cmd->bw_level_num = ddr->num_levels;
|
||||
cmd->ddr_cmds_num = ddr->num_cmds;
|
||||
cmd->ddr_wait_bitmask = ddr->wait_bitmask;
|
||||
|
||||
for (i = 0; i < ddr->num_cmds; i++)
|
||||
cmd->ddr_cmd_addrs[i] = ddr->addrs[i];
|
||||
|
||||
for (i = 0; i < ddr->num_levels; i++)
|
||||
for (j = 0; j < ddr->num_cmds; j++)
|
||||
cmd->ddr_cmd_data[i][j] = (u32) ddr->cmds[i][j];
|
||||
|
||||
if (!cnoc)
|
||||
return;
|
||||
|
||||
cmd->cnoc_cmds_num = cnoc->num_cmds;
|
||||
cmd->cnoc_wait_bitmask = cnoc->wait_bitmask;
|
||||
|
||||
for (i = 0; i < cnoc->num_cmds; i++)
|
||||
cmd->cnoc_cmd_addrs[i] = cnoc->addrs[i];
|
||||
|
||||
for (i = 0; i < cnoc->num_levels; i++)
|
||||
for (j = 0; j < cnoc->num_cmds; j++)
|
||||
cmd->cnoc_cmd_data[i][j] = (u32) cnoc->cmds[i][j];
|
||||
}
|
||||
|
||||
static int build_bw_table(struct adreno_device *adreno_dev)
|
||||
{
|
||||
struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev);
|
||||
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
|
||||
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
|
||||
struct rpmh_bw_votes *ddr, *cnoc = NULL;
|
||||
u32 *cnoc_table;
|
||||
u32 count;
|
||||
|
||||
ddr = build_rpmh_bw_votes(a660_ddr_bcms, ARRAY_SIZE(a660_ddr_bcms),
|
||||
pwr->ddr_table, pwr->ddr_table_count);
|
||||
if (IS_ERR(ddr))
|
||||
return PTR_ERR(ddr);
|
||||
|
||||
cnoc_table = kgsl_bus_get_table(device->pdev, "qcom,bus-table-cnoc",
|
||||
&count);
|
||||
|
||||
if (count > 0)
|
||||
cnoc = build_rpmh_bw_votes(a660_cnoc_bcms,
|
||||
ARRAY_SIZE(a660_cnoc_bcms), cnoc_table, count);
|
||||
|
||||
kfree(cnoc_table);
|
||||
|
||||
if (IS_ERR(cnoc)) {
|
||||
free_rpmh_bw_votes(ddr);
|
||||
return PTR_ERR(cnoc);
|
||||
}
|
||||
|
||||
build_bw_table_cmd(&gmu->hfi.bw_table, ddr, cnoc);
|
||||
|
||||
free_rpmh_bw_votes(ddr);
|
||||
free_rpmh_bw_votes(cnoc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int a6xx_build_rpmh_tables(struct adreno_device *adreno_dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = build_dcvs_table(adreno_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return build_bw_table(adreno_dev);
|
||||
}
|
||||
|
|
@ -46,74 +46,6 @@ static const unsigned int a6xx_pc_vs_cluster[] = {
|
|||
0x9100, 0x9108, 0x9300, 0x9306, 0x9980, 0x9981, 0x9B00, 0x9B07,
|
||||
};
|
||||
|
||||
static const unsigned int a630_rscc_snapshot_registers[] = {
|
||||
0x23400, 0x23434, 0x23436, 0x23436, 0x23480, 0x23484, 0x23489, 0x2348C,
|
||||
0x23491, 0x23494, 0x23499, 0x2349C, 0x234A1, 0x234A4, 0x234A9, 0x234AC,
|
||||
0x23500, 0x23502, 0x23504, 0x23507, 0x23514, 0x23519, 0x23524, 0x2352B,
|
||||
0x23580, 0x23597, 0x23740, 0x23741, 0x23744, 0x23747, 0x2374C, 0x23787,
|
||||
0x237EC, 0x237EF, 0x237F4, 0x2382F, 0x23894, 0x23897, 0x2389C, 0x238D7,
|
||||
0x2393C, 0x2393F, 0x23944, 0x2397F,
|
||||
};
|
||||
|
||||
static const unsigned int a6xx_rscc_snapshot_registers[] = {
|
||||
0x23400, 0x23434, 0x23436, 0x23436, 0x23440, 0x23440, 0x23480, 0x23484,
|
||||
0x23489, 0x2348C, 0x23491, 0x23494, 0x23499, 0x2349C, 0x234A1, 0x234A4,
|
||||
0x234A9, 0x234AC, 0x23500, 0x23502, 0x23504, 0x23507, 0x23514, 0x23519,
|
||||
0x23524, 0x2352B, 0x23580, 0x23597, 0x23740, 0x23741, 0x23744, 0x23747,
|
||||
0x2374C, 0x23787, 0x237EC, 0x237EF, 0x237F4, 0x2382F, 0x23894, 0x23897,
|
||||
0x2389C, 0x238D7, 0x2393C, 0x2393F, 0x23944, 0x2397F,
|
||||
};
|
||||
|
||||
static const unsigned int a650_rscc_registers[] = {
|
||||
0x38000, 0x38034, 0x38036, 0x38036, 0x38040, 0x38042, 0x38080, 0x38084,
|
||||
0x38089, 0x3808C, 0x38091, 0x38094, 0x38099, 0x3809C, 0x380A1, 0x380A4,
|
||||
0x380A9, 0x380AC, 0x38100, 0x38102, 0x38104, 0x38107, 0x38114, 0x38119,
|
||||
0x38124, 0x3812E, 0x38180, 0x38197, 0x38340, 0x38341, 0x38344, 0x38347,
|
||||
0x3834C, 0x3834F, 0x38351, 0x38354, 0x38356, 0x38359, 0x3835B, 0x3835E,
|
||||
0x38360, 0x38363, 0x38365, 0x38368, 0x3836A, 0x3836D, 0x3836F, 0x38372,
|
||||
0x383EC, 0x383EF, 0x383F4, 0x383F7, 0x383F9, 0x383FC, 0x383FE, 0x38401,
|
||||
0x38403, 0x38406, 0x38408, 0x3840B, 0x3840D, 0x38410, 0x38412, 0x38415,
|
||||
0x38417, 0x3841A, 0x38494, 0x38497, 0x3849C, 0x3849F, 0x384A1, 0x384A4,
|
||||
0x384A6, 0x384A9, 0x384AB, 0x384AE, 0x384B0, 0x384B3, 0x384B5, 0x384B8,
|
||||
0x384BA, 0x384BD, 0x384BF, 0x384C2, 0x3853C, 0x3853F, 0x38544, 0x38547,
|
||||
0x38549, 0x3854C, 0x3854E, 0x38551, 0x38553, 0x38556, 0x38558, 0x3855B,
|
||||
0x3855D, 0x38560, 0x38562, 0x38565, 0x38567, 0x3856A, 0x385E4, 0x385E7,
|
||||
0x385EC, 0x385EF, 0x385F1, 0x385F4, 0x385F6, 0x385F9, 0x385FB, 0x385FE,
|
||||
0x38600, 0x38603, 0x38605, 0x38608, 0x3860A, 0x3860D, 0x3860F, 0x38612,
|
||||
0x3868C, 0x3868F, 0x38694, 0x38697, 0x38699, 0x3869C, 0x3869E, 0x386A1,
|
||||
0x386A3, 0x386A6, 0x386A8, 0x386AB, 0x386AD, 0x386B0, 0x386B2, 0x386B5,
|
||||
0x386B7, 0x386BA, 0x38734, 0x38737, 0x3873C, 0x3873F, 0x38741, 0x38744,
|
||||
0x38746, 0x38749, 0x3874B, 0x3874E, 0x38750, 0x38753, 0x38755, 0x38758,
|
||||
0x3875A, 0x3875D, 0x3875F, 0x38762, 0x387DC, 0x387DF, 0x387E4, 0x387E7,
|
||||
0x387E9, 0x387EC, 0x387EE, 0x387F1, 0x387F3, 0x387F6, 0x387F8, 0x387FB,
|
||||
0x387FD, 0x38800, 0x38802, 0x38805, 0x38807, 0x3880A, 0x38884, 0x38887,
|
||||
0x3888C, 0x3888F, 0x38891, 0x38894, 0x38896, 0x38899, 0x3889B, 0x3889E,
|
||||
0x388A0, 0x388A3, 0x388A5, 0x388A8, 0x388AA, 0x388AD, 0x388AF, 0x388B2,
|
||||
0x3892C, 0x3892F, 0x38934, 0x38937, 0x38939, 0x3893C, 0x3893E, 0x38941,
|
||||
0x38943, 0x38946, 0x38948, 0x3894B, 0x3894D, 0x38950, 0x38952, 0x38955,
|
||||
0x38957, 0x3895A, 0x38B50, 0x38B51, 0x38B53, 0x38B55, 0x38B5A, 0x38B5A,
|
||||
0x38B5F, 0x38B5F, 0x38B64, 0x38B64, 0x38B69, 0x38B69, 0x38B6E, 0x38B6E,
|
||||
0x38B73, 0x38B73, 0x38BF8, 0x38BF8, 0x38BFD, 0x38BFD, 0x38C02, 0x38C02,
|
||||
0x38C07, 0x38C07, 0x38C0C, 0x38C0C, 0x38C11, 0x38C11, 0x38C16, 0x38C16,
|
||||
0x38C1B, 0x38C1B, 0x38CA0, 0x38CA0, 0x38CA5, 0x38CA5, 0x38CAA, 0x38CAA,
|
||||
0x38CAF, 0x38CAF, 0x38CB4, 0x38CB4, 0x38CB9, 0x38CB9, 0x38CBE, 0x38CBE,
|
||||
0x38CC3, 0x38CC3, 0x38D48, 0x38D48, 0x38D4D, 0x38D4D, 0x38D52, 0x38D52,
|
||||
0x38D57, 0x38D57, 0x38D5C, 0x38D5C, 0x38D61, 0x38D61, 0x38D66, 0x38D66,
|
||||
0x38D6B, 0x38D6B, 0x38DF0, 0x38DF0, 0x38DF5, 0x38DF5, 0x38DFA, 0x38DFA,
|
||||
0x38DFF, 0x38DFF, 0x38E04, 0x38E04, 0x38E09, 0x38E09, 0x38E0E, 0x38E0E,
|
||||
0x38E13, 0x38E13, 0x38E98, 0x38E98, 0x38E9D, 0x38E9D, 0x38EA2, 0x38EA2,
|
||||
0x38EA7, 0x38EA7, 0x38EAC, 0x38EAC, 0x38EB1, 0x38EB1, 0x38EB6, 0x38EB6,
|
||||
0x38EBB, 0x38EBB, 0x38F40, 0x38F40, 0x38F45, 0x38F45, 0x38F4A, 0x38F4A,
|
||||
0x38F4F, 0x38F4F, 0x38F54, 0x38F54, 0x38F59, 0x38F59, 0x38F5E, 0x38F5E,
|
||||
0x38F63, 0x38F63, 0x38FE8, 0x38FE8, 0x38FED, 0x38FED, 0x38FF2, 0x38FF2,
|
||||
0x38FF7, 0x38FF7, 0x38FFC, 0x38FFC, 0x39001, 0x39001, 0x39006, 0x39006,
|
||||
0x3900B, 0x3900B, 0x39090, 0x39090, 0x39095, 0x39095, 0x3909A, 0x3909A,
|
||||
0x3909F, 0x3909F, 0x390A4, 0x390A4, 0x390A9, 0x390A9, 0x390AE, 0x390AE,
|
||||
0x390B3, 0x390B3, 0x39138, 0x39138, 0x3913D, 0x3913D, 0x39142, 0x39142,
|
||||
0x39147, 0x39147, 0x3914C, 0x3914C, 0x39151, 0x39151, 0x39156, 0x39156,
|
||||
0x3915B, 0x3915B,
|
||||
};
|
||||
|
||||
static const unsigned int a650_isense_registers[] = {
|
||||
0x22C00, 0x22C19, 0x22C26, 0x22C2D, 0x22C2F, 0x22C36, 0x22C40, 0x22C44,
|
||||
0x22C50, 0x22C57, 0x22C60, 0x22C67, 0x22C80, 0x22C87, 0x22D25, 0x22D2A,
|
||||
|
|
@ -1655,48 +1587,6 @@ static void _a6xx_do_crashdump(struct kgsl_device *device)
|
|||
crash_dump_valid = true;
|
||||
}
|
||||
|
||||
static size_t a6xx_snapshot_rscc_registers(struct kgsl_device *device, u8 *buf,
|
||||
size_t remain, void *priv)
|
||||
{
|
||||
struct kgsl_snapshot_regs *header = (struct kgsl_snapshot_regs *)buf;
|
||||
struct kgsl_snapshot_registers *regs = priv;
|
||||
unsigned int *data = (unsigned int *)(buf + sizeof(*header));
|
||||
int count = 0, j, k;
|
||||
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
|
||||
|
||||
/* Figure out how many registers we are going to dump */
|
||||
for (j = 0; j < regs->count; j++) {
|
||||
int start = regs->regs[j * 2];
|
||||
int end = regs->regs[j * 2 + 1];
|
||||
|
||||
count += (end - start + 1);
|
||||
}
|
||||
|
||||
if (remain < (count * 8) + sizeof(*header)) {
|
||||
SNAPSHOT_ERR_NOMEM(device, "RSCC REGISTERS");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (j = 0; j < regs->count; j++) {
|
||||
unsigned int start = regs->regs[j * 2];
|
||||
unsigned int end = regs->regs[j * 2 + 1];
|
||||
|
||||
for (k = start; k <= end; k++) {
|
||||
unsigned int val;
|
||||
|
||||
adreno_rscc_regread(adreno_dev,
|
||||
k - (adreno_dev->rscc_base >> 2), &val);
|
||||
*data++ = k;
|
||||
*data++ = val;
|
||||
}
|
||||
}
|
||||
|
||||
header->count = count;
|
||||
|
||||
/* Return the size of the section */
|
||||
return (count * 8) + sizeof(*header);
|
||||
}
|
||||
|
||||
static size_t a6xx_snapshot_isense_registers(struct kgsl_device *device,
|
||||
u8 *buf, size_t remain, void *priv)
|
||||
{
|
||||
|
|
@ -1784,9 +1674,6 @@ void a6xx_snapshot(struct adreno_device *adreno_dev,
|
|||
unsigned int i, roq_size;
|
||||
u32 hi, lo;
|
||||
|
||||
/* GMU TCM data dumped through AHB */
|
||||
gmu_core_dev_snapshot(device, snapshot);
|
||||
|
||||
/*
|
||||
* Dump debugbus data here to capture it for both
|
||||
* GMU and GPU snapshot. Debugbus data can be accessed
|
||||
|
|
@ -1800,26 +1687,11 @@ void a6xx_snapshot(struct adreno_device *adreno_dev,
|
|||
if (adreno_is_a650_family(adreno_dev)) {
|
||||
struct kgsl_snapshot_registers r;
|
||||
|
||||
r.regs = a650_rscc_registers;
|
||||
r.count = ARRAY_SIZE(a650_rscc_registers) / 2;
|
||||
|
||||
kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_REGS,
|
||||
snapshot, a6xx_snapshot_rscc_registers, &r);
|
||||
|
||||
r.regs = a650_isense_registers;
|
||||
r.count = ARRAY_SIZE(a650_isense_registers) / 2;
|
||||
|
||||
kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_REGS,
|
||||
snapshot, a6xx_snapshot_isense_registers, &r);
|
||||
} else if (adreno_is_a615_family(adreno_dev) ||
|
||||
adreno_is_a630(adreno_dev)) {
|
||||
adreno_snapshot_registers(device, snapshot,
|
||||
a630_rscc_snapshot_registers,
|
||||
ARRAY_SIZE(a630_rscc_snapshot_registers) / 2);
|
||||
} else if (adreno_is_a640(adreno_dev) || adreno_is_a680(adreno_dev)) {
|
||||
adreno_snapshot_registers(device, snapshot,
|
||||
a6xx_rscc_snapshot_registers,
|
||||
ARRAY_SIZE(a6xx_rscc_snapshot_registers) / 2);
|
||||
} else if (adreno_is_a610(adreno_dev)) {
|
||||
adreno_snapshot_registers(device, snapshot,
|
||||
a6xx_gmu_wrapper_registers,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2013-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/coresight.h>
|
||||
|
|
@ -61,7 +61,7 @@ ssize_t adreno_coresight_show_register(struct device *dev,
|
|||
|
||||
if (device->state == KGSL_STATE_ACTIVE ||
|
||||
device->state == KGSL_STATE_NAP) {
|
||||
if (!kgsl_active_count_get(device)) {
|
||||
if (!adreno_active_count_get(adreno_dev)) {
|
||||
if (!is_cx)
|
||||
kgsl_regread(device, cattr->reg->offset,
|
||||
&cattr->reg->value);
|
||||
|
|
@ -69,7 +69,7 @@ ssize_t adreno_coresight_show_register(struct device *dev,
|
|||
adreno_cx_dbgc_regread(device,
|
||||
cattr->reg->offset,
|
||||
&cattr->reg->value);
|
||||
kgsl_active_count_put(device);
|
||||
adreno_active_count_put(adreno_dev);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -116,7 +116,7 @@ ssize_t adreno_coresight_store_register(struct device *dev,
|
|||
/* Program the hardware if it is not power collapsed */
|
||||
if (device->state == KGSL_STATE_ACTIVE ||
|
||||
device->state == KGSL_STATE_NAP) {
|
||||
if (!kgsl_active_count_get(device)) {
|
||||
if (!adreno_active_count_get(adreno_dev)) {
|
||||
if (!is_cx)
|
||||
kgsl_regwrite(device, cattr->reg->offset,
|
||||
cattr->reg->value);
|
||||
|
|
@ -125,7 +125,7 @@ ssize_t adreno_coresight_store_register(struct device *dev,
|
|||
cattr->reg->offset,
|
||||
cattr->reg->value);
|
||||
|
||||
kgsl_active_count_put(device);
|
||||
adreno_active_count_put(adreno_dev);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -166,7 +166,7 @@ static void adreno_coresight_disable(struct coresight_device *csdev,
|
|||
|
||||
mutex_lock(&device->mutex);
|
||||
|
||||
if (!kgsl_active_count_get(device)) {
|
||||
if (!adreno_active_count_get(adreno_dev)) {
|
||||
if (cs_id == GPU_CORESIGHT_GX)
|
||||
for (i = 0; i < coresight->count; i++)
|
||||
kgsl_regwrite(device,
|
||||
|
|
@ -176,7 +176,7 @@ static void adreno_coresight_disable(struct coresight_device *csdev,
|
|||
adreno_cx_dbgc_regwrite(device,
|
||||
coresight->registers[i].offset, 0);
|
||||
|
||||
kgsl_active_count_put(device);
|
||||
adreno_active_count_put(adreno_dev);
|
||||
}
|
||||
|
||||
if (cs_id == GPU_CORESIGHT_GX)
|
||||
|
|
@ -289,10 +289,10 @@ static int adreno_coresight_enable(struct coresight_device *csdev,
|
|||
coresight->registers[i].initial;
|
||||
|
||||
if (kgsl_state_is_awake(device)) {
|
||||
ret = kgsl_active_count_get(device);
|
||||
ret = adreno_active_count_get(adreno_dev);
|
||||
if (!ret) {
|
||||
ret = _adreno_coresight_set(adreno_dev, cs_id);
|
||||
kgsl_active_count_put(device);
|
||||
adreno_active_count_put(adreno_dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,11 @@
|
|||
#include "adreno.h"
|
||||
extern struct dentry *kgsl_debugfs_dir;
|
||||
|
||||
static void set_isdb(struct adreno_device *adreno_dev, void *priv)
|
||||
{
|
||||
set_bit(ADRENO_DEVICE_ISDB_ENABLED, &adreno_dev->priv);
|
||||
}
|
||||
|
||||
static int _isdb_set(void *data, u64 val)
|
||||
{
|
||||
struct kgsl_device *device = data;
|
||||
|
|
@ -17,19 +22,11 @@ static int _isdb_set(void *data, u64 val)
|
|||
if (test_bit(ADRENO_DEVICE_ISDB_ENABLED, &adreno_dev->priv))
|
||||
return 0;
|
||||
|
||||
mutex_lock(&device->mutex);
|
||||
|
||||
/*
|
||||
* Bring down the GPU so we can bring it back up with the correct power
|
||||
* and clock settings
|
||||
*/
|
||||
kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND);
|
||||
set_bit(ADRENO_DEVICE_ISDB_ENABLED, &adreno_dev->priv);
|
||||
kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER);
|
||||
|
||||
mutex_unlock(&device->mutex);
|
||||
|
||||
return 0;
|
||||
return adreno_power_cycle(adreno_dev, set_isdb, NULL);
|
||||
}
|
||||
|
||||
static int _isdb_get(void *data, u64 *val)
|
||||
|
|
@ -57,14 +54,9 @@ static int _lm_limit_set(void *data, u64 val)
|
|||
else if (val < 3000)
|
||||
val = 3000;
|
||||
|
||||
adreno_dev->lm_limit = val;
|
||||
|
||||
if (adreno_dev->lm_enabled) {
|
||||
mutex_lock(&device->mutex);
|
||||
kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND);
|
||||
kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER);
|
||||
mutex_unlock(&device->mutex);
|
||||
}
|
||||
if (adreno_dev->lm_enabled)
|
||||
return adreno_power_cycle_u32(adreno_dev,
|
||||
&adreno_dev->lm_limit, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -557,7 +557,7 @@ static int sendcmd(struct adreno_device *adreno_dev,
|
|||
if (dispatcher->inflight == 1 &&
|
||||
!test_bit(ADRENO_DISPATCHER_POWER, &dispatcher->priv)) {
|
||||
/* Time to make the donuts. Turn on the GPU */
|
||||
ret = kgsl_active_count_get(device);
|
||||
ret = adreno_active_count_get(adreno_dev);
|
||||
if (ret) {
|
||||
dispatcher->inflight--;
|
||||
dispatch_q->inflight--;
|
||||
|
|
@ -608,7 +608,7 @@ static int sendcmd(struct adreno_device *adreno_dev,
|
|||
kgsl_pwrscale_midframe_timer_restart(device);
|
||||
|
||||
} else {
|
||||
kgsl_active_count_put(device);
|
||||
adreno_active_count_put(adreno_dev);
|
||||
clear_bit(ADRENO_DISPATCHER_POWER, &dispatcher->priv);
|
||||
}
|
||||
}
|
||||
|
|
@ -2501,7 +2501,7 @@ static void _dispatcher_power_down(struct adreno_device *adreno_dev)
|
|||
del_timer_sync(&dispatcher->fault_timer);
|
||||
|
||||
if (test_bit(ADRENO_DISPATCHER_POWER, &dispatcher->priv)) {
|
||||
kgsl_active_count_put(device);
|
||||
adreno_active_count_put(adreno_dev);
|
||||
clear_bit(ADRENO_DISPATCHER_POWER, &dispatcher->priv);
|
||||
}
|
||||
|
||||
|
|
@ -2909,7 +2909,7 @@ int adreno_dispatcher_idle(struct adreno_device *adreno_dev)
|
|||
struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
|
||||
int ret;
|
||||
|
||||
if (!test_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv))
|
||||
if (device->state != KGSL_STATE_ACTIVE)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2002,2007-2019, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2002,2007-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
|
|
@ -68,7 +68,7 @@ long adreno_ioctl_perfcounter_get(struct kgsl_device_private *dev_priv,
|
|||
* active count inside that function.
|
||||
*/
|
||||
|
||||
result = adreno_perfcntr_active_oob_get(device);
|
||||
result = adreno_perfcntr_active_oob_get(adreno_dev);
|
||||
if (result) {
|
||||
mutex_unlock(&device->mutex);
|
||||
return (long)result;
|
||||
|
|
@ -87,7 +87,7 @@ long adreno_ioctl_perfcounter_get(struct kgsl_device_private *dev_priv,
|
|||
get->countable, PERFCOUNTER_FLAG_NONE);
|
||||
}
|
||||
|
||||
adreno_perfcntr_active_oob_put(device);
|
||||
adreno_perfcntr_active_oob_put(adreno_dev);
|
||||
|
||||
mutex_unlock(&device->mutex);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2002,2007-2019, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2002,2007-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
|
|
@ -248,7 +248,7 @@ int adreno_perfcounter_read_group(struct adreno_device *adreno_dev,
|
|||
|
||||
mutex_lock(&device->mutex);
|
||||
|
||||
ret = adreno_perfcntr_active_oob_get(device);
|
||||
ret = adreno_perfcntr_active_oob_get(adreno_dev);
|
||||
if (ret) {
|
||||
mutex_unlock(&device->mutex);
|
||||
goto done;
|
||||
|
|
@ -277,7 +277,7 @@ int adreno_perfcounter_read_group(struct adreno_device *adreno_dev,
|
|||
}
|
||||
}
|
||||
|
||||
adreno_perfcntr_active_oob_put(device);
|
||||
adreno_perfcntr_active_oob_put(adreno_dev);
|
||||
|
||||
mutex_unlock(&device->mutex);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2013-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/ctype.h>
|
||||
|
|
@ -691,7 +691,7 @@ static ssize_t profile_assignments_write(struct file *filep,
|
|||
goto error_unlock;
|
||||
}
|
||||
|
||||
ret = adreno_perfcntr_active_oob_get(device);
|
||||
ret = adreno_perfcntr_active_oob_get(adreno_dev);
|
||||
if (ret) {
|
||||
size = ret;
|
||||
goto error_unlock;
|
||||
|
|
@ -738,7 +738,7 @@ static ssize_t profile_assignments_write(struct file *filep,
|
|||
size = len;
|
||||
|
||||
error_put:
|
||||
adreno_perfcntr_active_oob_put(device);
|
||||
adreno_perfcntr_active_oob_put(adreno_dev);
|
||||
error_unlock:
|
||||
mutex_unlock(&device->mutex);
|
||||
error_free:
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ static void adreno_ringbuffer_wptr(struct adreno_device *adreno_dev,
|
|||
* If WPTR update fails, take inline snapshot and trigger
|
||||
* recovery.
|
||||
*/
|
||||
gmu_core_snapshot(device);
|
||||
gmu_fault_snapshot(device);
|
||||
adreno_set_gpu_fault(adreno_dev,
|
||||
ADRENO_GMU_FAULT_SKIP_SNAPSHOT);
|
||||
adreno_dispatcher_schedule(device);
|
||||
|
|
|
|||
|
|
@ -139,43 +139,13 @@ static bool _ft_hang_intr_status_show(struct adreno_device *adreno_dev)
|
|||
return true;
|
||||
}
|
||||
|
||||
static int pwrflag_store(struct adreno_device *adreno_dev,
|
||||
unsigned int val, bool *flag)
|
||||
{
|
||||
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
|
||||
|
||||
if (*flag == val)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&device->mutex);
|
||||
|
||||
/* Power down the GPU before changing the state */
|
||||
kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND);
|
||||
*flag = val;
|
||||
kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER);
|
||||
|
||||
mutex_unlock(&device->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _preemption_store(struct adreno_device *adreno_dev, bool val)
|
||||
static void change_preemption(struct adreno_device *adreno_dev, void *priv)
|
||||
{
|
||||
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
|
||||
struct kgsl_context *context;
|
||||
struct adreno_context *drawctxt;
|
||||
int id;
|
||||
|
||||
mutex_lock(&device->mutex);
|
||||
|
||||
if (!(ADRENO_FEATURE(adreno_dev, ADRENO_PREEMPTION)) ||
|
||||
(test_bit(ADRENO_DEVICE_PREEMPTION,
|
||||
&adreno_dev->priv) == val)) {
|
||||
mutex_unlock(&device->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND);
|
||||
change_bit(ADRENO_DEVICE_PREEMPTION, &adreno_dev->priv);
|
||||
adreno_dev->cur_rb = &(adreno_dev->ringbuffers[0]);
|
||||
|
||||
|
|
@ -186,12 +156,16 @@ static int _preemption_store(struct adreno_device *adreno_dev, bool val)
|
|||
drawctxt->rb = adreno_ctx_get_rb(adreno_dev, drawctxt);
|
||||
}
|
||||
write_unlock(&device->context_lock);
|
||||
}
|
||||
|
||||
kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER);
|
||||
static int _preemption_store(struct adreno_device *adreno_dev, bool val)
|
||||
{
|
||||
if (!(ADRENO_FEATURE(adreno_dev, ADRENO_PREEMPTION)) ||
|
||||
(test_bit(ADRENO_DEVICE_PREEMPTION,
|
||||
&adreno_dev->priv) == val))
|
||||
return 0;
|
||||
|
||||
mutex_unlock(&device->mutex);
|
||||
|
||||
return 0;
|
||||
return adreno_power_cycle(adreno_dev, change_preemption, NULL);
|
||||
}
|
||||
|
||||
static bool _preemption_show(struct adreno_device *adreno_dev)
|
||||
|
|
@ -201,7 +175,11 @@ static bool _preemption_show(struct adreno_device *adreno_dev)
|
|||
|
||||
static int _hwcg_store(struct adreno_device *adreno_dev, bool val)
|
||||
{
|
||||
return pwrflag_store(adreno_dev, val, &adreno_dev->hwcg_enabled);
|
||||
if (adreno_dev->hwcg_enabled == val)
|
||||
return 0;
|
||||
|
||||
return adreno_power_cycle_bool(adreno_dev, &adreno_dev->hwcg_enabled,
|
||||
val);
|
||||
}
|
||||
|
||||
static bool _hwcg_show(struct adreno_device *adreno_dev)
|
||||
|
|
@ -211,10 +189,12 @@ static bool _hwcg_show(struct adreno_device *adreno_dev)
|
|||
|
||||
static int _throttling_store(struct adreno_device *adreno_dev, bool val)
|
||||
{
|
||||
if (!adreno_is_a540(adreno_dev))
|
||||
if (!adreno_is_a540(adreno_dev) ||
|
||||
adreno_dev->throttling_enabled == val)
|
||||
return 0;
|
||||
|
||||
return pwrflag_store(adreno_dev, val, &adreno_dev->throttling_enabled);
|
||||
return adreno_power_cycle_bool(adreno_dev,
|
||||
&adreno_dev->throttling_enabled, val);
|
||||
}
|
||||
|
||||
static bool _throttling_show(struct adreno_device *adreno_dev)
|
||||
|
|
@ -224,10 +204,12 @@ static bool _throttling_show(struct adreno_device *adreno_dev)
|
|||
|
||||
static int _sptp_pc_store(struct adreno_device *adreno_dev, bool val)
|
||||
{
|
||||
if (!ADRENO_FEATURE(adreno_dev, ADRENO_SPTP_PC))
|
||||
if (!ADRENO_FEATURE(adreno_dev, ADRENO_SPTP_PC) ||
|
||||
adreno_dev->sptp_pc_enabled == val)
|
||||
return 0;
|
||||
|
||||
return pwrflag_store(adreno_dev, val, &adreno_dev->sptp_pc_enabled);
|
||||
return adreno_power_cycle_bool(adreno_dev, &adreno_dev->sptp_pc_enabled,
|
||||
val);
|
||||
}
|
||||
|
||||
static bool _sptp_pc_show(struct adreno_device *adreno_dev)
|
||||
|
|
@ -237,10 +219,12 @@ static bool _sptp_pc_show(struct adreno_device *adreno_dev)
|
|||
|
||||
static int _lm_store(struct adreno_device *adreno_dev, bool val)
|
||||
{
|
||||
if (!ADRENO_FEATURE(adreno_dev, ADRENO_LM))
|
||||
if (!ADRENO_FEATURE(adreno_dev, ADRENO_LM) ||
|
||||
adreno_dev->lm_enabled == val)
|
||||
return 0;
|
||||
|
||||
return pwrflag_store(adreno_dev, val, &adreno_dev->lm_enabled);
|
||||
return adreno_power_cycle_bool(adreno_dev, &adreno_dev->lm_enabled,
|
||||
val);
|
||||
}
|
||||
|
||||
static bool _lm_show(struct adreno_device *adreno_dev)
|
||||
|
|
@ -277,7 +261,7 @@ static bool _acd_show(struct adreno_device *adreno_dev)
|
|||
|
||||
static int _acd_store(struct adreno_device *adreno_dev, bool val)
|
||||
{
|
||||
return gmu_core_acd_set(KGSL_DEVICE(adreno_dev), val);
|
||||
return gmu_core_dev_acd_set(KGSL_DEVICE(adreno_dev), val);
|
||||
}
|
||||
|
||||
static ssize_t _sysfs_store_u32(struct device *dev,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2008-2019, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2008-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
#ifndef __KGSL_H
|
||||
#define __KGSL_H
|
||||
|
|
|
|||
|
|
@ -10,24 +10,6 @@
|
|||
#include "kgsl_device.h"
|
||||
#include "kgsl_trace.h"
|
||||
|
||||
static int interconnect_bus_set(struct kgsl_device *device, int level,
|
||||
u32 ab)
|
||||
{
|
||||
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
|
||||
|
||||
if ((level == pwr->cur_buslevel) && (ab == pwr->cur_ab))
|
||||
return 0;
|
||||
|
||||
pwr->cur_buslevel = level;
|
||||
pwr->cur_ab = ab;
|
||||
|
||||
icc_set_bw(pwr->icc_path, MBps_to_icc(ab),
|
||||
kBps_to_icc(pwr->ddr_table[level]));
|
||||
|
||||
trace_kgsl_buslevel(device, pwr->active_pwrlevel, level);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 _ab_buslevel_update(struct kgsl_pwrctrl *pwr,
|
||||
u32 ib)
|
||||
|
|
@ -49,7 +31,7 @@ static u32 _ab_buslevel_update(struct kgsl_pwrctrl *pwr,
|
|||
}
|
||||
|
||||
|
||||
void kgsl_bus_update(struct kgsl_device *device, bool on)
|
||||
int kgsl_bus_update(struct kgsl_device *device, bool on)
|
||||
{
|
||||
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
|
||||
/* FIXME: this might be wrong? */
|
||||
|
|
@ -59,7 +41,7 @@ void kgsl_bus_update(struct kgsl_device *device, bool on)
|
|||
|
||||
/* the bus should be ON to update the active frequency */
|
||||
if (on && !(test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)))
|
||||
return;
|
||||
return 0;
|
||||
/*
|
||||
* If the bus should remain on calculate our request and submit it,
|
||||
* otherwise request bus level 0, off.
|
||||
|
|
@ -78,7 +60,7 @@ void kgsl_bus_update(struct kgsl_device *device, bool on)
|
|||
/* buslevel is the IB vote, update the AB */
|
||||
ab = _ab_buslevel_update(pwr, pwr->ddr_table[buslevel]);
|
||||
|
||||
pwr->bus_set(device, buslevel, ab);
|
||||
return device->ftbl->gpu_bus_set(device, buslevel, ab);
|
||||
}
|
||||
|
||||
static void validate_pwrlevels(struct kgsl_device *device, u32 *ibs,
|
||||
|
|
@ -127,7 +109,7 @@ u32 *kgsl_bus_get_table(struct platform_device *pdev,
|
|||
if (num <= 0)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
levels = devm_kcalloc(&pdev->dev, num, sizeof(*levels), GFP_KERNEL);
|
||||
levels = kcalloc(num, sizeof(*levels), GFP_KERNEL);
|
||||
if (!levels)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
|
|
@ -171,15 +153,16 @@ done:
|
|||
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");
|
||||
|
||||
kfree(pwr->ddr_table);
|
||||
return PTR_ERR(pwr->icc_path);
|
||||
}
|
||||
|
||||
pwr->bus_set = interconnect_bus_set;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kgsl_bus_close(struct kgsl_device *device)
|
||||
{
|
||||
kfree(device->pwrctrl.ddr_table);
|
||||
icc_put(device->pwrctrl.icc_path);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _KGSL_BUS_H
|
||||
|
|
@ -11,7 +11,7 @@ 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);
|
||||
int kgsl_bus_update(struct kgsl_device *device, bool on);
|
||||
|
||||
u32 *kgsl_bus_get_table(struct platform_device *pdev,
|
||||
const char *name, int *count);
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@
|
|||
#define KGSL_STATE_SUSPEND 0x00000010
|
||||
#define KGSL_STATE_AWARE 0x00000020
|
||||
#define KGSL_STATE_SLUMBER 0x00000080
|
||||
#define KGSL_STATE_RESET 0x00000100
|
||||
|
||||
/**
|
||||
* enum kgsl_event_results - result codes passed to an event callback when the
|
||||
|
|
@ -168,6 +167,10 @@ struct kgsl_functable {
|
|||
int (*query_property_list)(struct kgsl_device *device, u32 *list,
|
||||
u32 count);
|
||||
bool (*is_hwcg_on)(struct kgsl_device *device);
|
||||
/** @gpu_clock_set: Target specific function to set gpu frequency */
|
||||
int (*gpu_clock_set)(struct kgsl_device *device, u32 pwrlevel);
|
||||
/** @gpu_bus_set: Target specific function to set gpu bandwidth */
|
||||
int (*gpu_bus_set)(struct kgsl_device *device, int bus_level, u32 ab);
|
||||
};
|
||||
|
||||
struct kgsl_ioctl {
|
||||
|
|
@ -316,6 +319,8 @@ struct kgsl_device {
|
|||
rwlock_t event_groups_lock;
|
||||
/** @speed_bin: Speed bin for the GPU device if applicable */
|
||||
u32 speed_bin;
|
||||
/** @gmu_fault: Set when a gmu or rgmu fault is encountered */
|
||||
bool gmu_fault;
|
||||
};
|
||||
|
||||
#define KGSL_MMU_DEVICE(_mmu) \
|
||||
|
|
@ -481,7 +486,6 @@ struct kgsl_device_private {
|
|||
* @process: the process that caused the hang, if known.
|
||||
* @sysfs_read: Count of current reads via sysfs
|
||||
* @first_read: True until the snapshot read is started
|
||||
* @gmu_fault: Snapshot collected when GMU fault happened
|
||||
* @recovered: True if GPU was recovered after previous snapshot
|
||||
*/
|
||||
struct kgsl_snapshot {
|
||||
|
|
@ -505,7 +509,6 @@ struct kgsl_snapshot {
|
|||
struct kgsl_process_private *process;
|
||||
unsigned int sysfs_read;
|
||||
bool first_read;
|
||||
bool gmu_fault;
|
||||
bool recovered;
|
||||
struct kgsl_device *device;
|
||||
};
|
||||
|
|
@ -589,9 +592,6 @@ static inline int kgsl_state_is_awake(struct kgsl_device *device)
|
|||
if (device->state == KGSL_STATE_ACTIVE ||
|
||||
device->state == KGSL_STATE_AWARE)
|
||||
return true;
|
||||
else if (gmu_core_isenabled(device) &&
|
||||
test_bit(GMU_CLK_ON, &device->gmu_core.flags))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1739,20 +1739,12 @@ static void gmu_remove(struct kgsl_device *device)
|
|||
memset(&device->gmu_core, 0, sizeof(device->gmu_core));
|
||||
}
|
||||
|
||||
static bool gmu_regulator_isenabled(struct kgsl_device *device)
|
||||
{
|
||||
struct gmu_device *gmu = KGSL_GMU_DEVICE(device);
|
||||
|
||||
return (gmu->gx_gdsc && regulator_is_enabled(gmu->gx_gdsc));
|
||||
}
|
||||
|
||||
static struct gmu_core_ops gmu_ops = {
|
||||
.init = gmu_init,
|
||||
.start = gmu_start,
|
||||
.stop = gmu_stop,
|
||||
.dcvs_set = gmu_dcvs_set,
|
||||
.snapshot = gmu_snapshot,
|
||||
.regulator_isenabled = gmu_regulator_isenabled,
|
||||
.suspend = gmu_suspend,
|
||||
.acd_set = gmu_acd_set,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@
|
|||
#include "kgsl_trace.h"
|
||||
|
||||
static const struct of_device_id gmu_match_table[] = {
|
||||
{ .compatible = "qcom,gpu-gmu", .data = &kgsl_gmu_driver },
|
||||
{ .compatible = "qcom,gpu-rgmu", .data = &kgsl_rgmu_driver },
|
||||
{ .compatible = "qcom,gpu-gmu", .data = &a6xx_gmu_driver },
|
||||
{ .compatible = "qcom,gpu-rgmu", .data = &a6xx_rgmu_driver },
|
||||
{},
|
||||
};
|
||||
|
||||
|
|
@ -51,7 +51,7 @@ bool gmu_core_isenabled(struct kgsl_device *device)
|
|||
|
||||
bool gmu_core_gpmu_isenabled(struct kgsl_device *device)
|
||||
{
|
||||
return (device->gmu_core.core_ops != NULL);
|
||||
return (device->gmu_core.dev_ops != NULL);
|
||||
}
|
||||
|
||||
bool gmu_core_scales_bandwidth(struct kgsl_device *device)
|
||||
|
|
@ -64,83 +64,16 @@ bool gmu_core_scales_bandwidth(struct kgsl_device *device)
|
|||
return false;
|
||||
}
|
||||
|
||||
int gmu_core_init(struct kgsl_device *device)
|
||||
int gmu_core_dev_acd_set(struct kgsl_device *device, bool val)
|
||||
{
|
||||
struct gmu_core_ops *gmu_core_ops = GMU_CORE_OPS(device);
|
||||
struct gmu_dev_ops *ops = GMU_DEVICE_OPS(device);
|
||||
|
||||
if (gmu_core_ops && gmu_core_ops->init)
|
||||
return gmu_core_ops->init(device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gmu_core_start(struct kgsl_device *device)
|
||||
{
|
||||
struct gmu_core_ops *gmu_core_ops = GMU_CORE_OPS(device);
|
||||
|
||||
if (gmu_core_ops && gmu_core_ops->start)
|
||||
return gmu_core_ops->start(device);
|
||||
if (ops && ops->acd_set)
|
||||
return ops->acd_set(device, val);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
void gmu_core_stop(struct kgsl_device *device)
|
||||
{
|
||||
struct gmu_core_ops *gmu_core_ops = GMU_CORE_OPS(device);
|
||||
|
||||
if (gmu_core_ops && gmu_core_ops->stop)
|
||||
gmu_core_ops->stop(device);
|
||||
}
|
||||
|
||||
int gmu_core_suspend(struct kgsl_device *device)
|
||||
{
|
||||
struct gmu_core_ops *gmu_core_ops = GMU_CORE_OPS(device);
|
||||
|
||||
if (gmu_core_ops && gmu_core_ops->suspend)
|
||||
return gmu_core_ops->suspend(device);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
void gmu_core_snapshot(struct kgsl_device *device)
|
||||
{
|
||||
struct gmu_core_ops *gmu_core_ops = GMU_CORE_OPS(device);
|
||||
|
||||
if (gmu_core_ops && gmu_core_ops->snapshot)
|
||||
gmu_core_ops->snapshot(device);
|
||||
}
|
||||
|
||||
int gmu_core_dcvs_set(struct kgsl_device *device, int gpu_pwrlevel,
|
||||
int bus_level)
|
||||
{
|
||||
struct gmu_core_ops *gmu_core_ops = GMU_CORE_OPS(device);
|
||||
|
||||
if (gmu_core_ops && gmu_core_ops->dcvs_set)
|
||||
return gmu_core_ops->dcvs_set(device, gpu_pwrlevel, bus_level);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int gmu_core_acd_set(struct kgsl_device *device, bool val)
|
||||
{
|
||||
struct gmu_core_ops *gmu_core_ops = GMU_CORE_OPS(device);
|
||||
|
||||
if (gmu_core_ops && gmu_core_ops->acd_set)
|
||||
return gmu_core_ops->acd_set(device, val);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bool gmu_core_regulator_isenabled(struct kgsl_device *device)
|
||||
{
|
||||
struct gmu_core_ops *gmu_core_ops = GMU_CORE_OPS(device);
|
||||
|
||||
if (gmu_core_ops && gmu_core_ops->regulator_isenabled)
|
||||
return gmu_core_ops->regulator_isenabled(device);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool gmu_core_is_register_offset(struct kgsl_device *device,
|
||||
unsigned int offsetwords)
|
||||
{
|
||||
|
|
@ -241,43 +174,6 @@ void gmu_core_dev_oob_clear(struct kgsl_device *device, enum oob_request req)
|
|||
ops->oob_clear(device, req);
|
||||
}
|
||||
|
||||
int gmu_core_dev_hfi_start_msg(struct kgsl_device *device)
|
||||
{
|
||||
struct gmu_dev_ops *ops = GMU_DEVICE_OPS(device);
|
||||
|
||||
if (ops && ops->hfi_start_msg)
|
||||
return ops->hfi_start_msg(device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gmu_core_dev_wait_for_lowest_idle(struct kgsl_device *device)
|
||||
{
|
||||
struct gmu_dev_ops *ops = GMU_DEVICE_OPS(device);
|
||||
|
||||
if (ops && ops->wait_for_lowest_idle)
|
||||
return ops->wait_for_lowest_idle(device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gmu_core_dev_enable_lm(struct kgsl_device *device)
|
||||
{
|
||||
struct gmu_dev_ops *ops = GMU_DEVICE_OPS(device);
|
||||
|
||||
if (ops && ops->enable_lm)
|
||||
ops->enable_lm(device);
|
||||
}
|
||||
|
||||
void gmu_core_dev_snapshot(struct kgsl_device *device,
|
||||
struct kgsl_snapshot *snapshot)
|
||||
{
|
||||
struct gmu_dev_ops *ops = GMU_DEVICE_OPS(device);
|
||||
|
||||
if (ops && ops->snapshot)
|
||||
ops->snapshot(device, snapshot);
|
||||
}
|
||||
|
||||
void gmu_core_dev_cooperative_reset(struct kgsl_device *device)
|
||||
{
|
||||
|
||||
|
|
@ -317,14 +213,6 @@ int gmu_core_dev_ifpc_store(struct kgsl_device *device, unsigned int val)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
void gmu_core_dev_prepare_stop(struct kgsl_device *device)
|
||||
{
|
||||
struct gmu_dev_ops *ops = GMU_DEVICE_OPS(device);
|
||||
|
||||
if (ops && ops->prepare_stop)
|
||||
ops->prepare_stop(device);
|
||||
}
|
||||
|
||||
int gmu_core_dev_wait_for_active_transition(struct kgsl_device *device)
|
||||
{
|
||||
struct gmu_dev_ops *ops = GMU_DEVICE_OPS(device);
|
||||
|
|
@ -334,13 +222,3 @@ int gmu_core_dev_wait_for_active_transition(struct kgsl_device *device)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u64 gmu_core_dev_read_alwayson(struct kgsl_device *device)
|
||||
{
|
||||
struct gmu_dev_ops *ops = GMU_DEVICE_OPS(device);
|
||||
|
||||
if (ops && ops->read_alwayson)
|
||||
return ops->read_alwayson(device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
/* GMU_DEVICE - Given an KGSL device return the GMU specific struct */
|
||||
#define GMU_DEVICE_OPS(_a) ((_a)->gmu_core.dev_ops)
|
||||
#define GMU_CORE_OPS(_a) ((_a)->gmu_core.core_ops)
|
||||
|
||||
#define NUM_BW_LEVELS 100
|
||||
#define MAX_GX_LEVELS 16
|
||||
|
|
@ -35,7 +34,6 @@ enum gmu_core_boot {
|
|||
/* Bits for the flags field in the gmu structure */
|
||||
enum gmu_core_flags {
|
||||
GMU_BOOT_INIT_DONE = 0,
|
||||
GMU_CLK_ON,
|
||||
GMU_HFI_ON,
|
||||
GMU_FAULT,
|
||||
GMU_DCVS_REPLAY,
|
||||
|
|
@ -100,44 +98,17 @@ struct device_node;
|
|||
struct kgsl_device;
|
||||
struct kgsl_snapshot;
|
||||
|
||||
struct gmu_core_ops {
|
||||
int (*dcvs_set)(struct kgsl_device *device,
|
||||
int gpu_pwrlevel, int bus_level);
|
||||
int (*init)(struct kgsl_device *device);
|
||||
int (*start)(struct kgsl_device *device);
|
||||
void (*stop)(struct kgsl_device *device);
|
||||
void (*snapshot)(struct kgsl_device *device);
|
||||
bool (*regulator_isenabled)(struct kgsl_device *device);
|
||||
int (*suspend)(struct kgsl_device *device);
|
||||
int (*acd_set)(struct kgsl_device *device, bool val);
|
||||
};
|
||||
|
||||
struct gmu_dev_ops {
|
||||
int (*load_firmware)(struct kgsl_device *device);
|
||||
int (*oob_set)(struct kgsl_device *device, enum oob_request req);
|
||||
void (*oob_clear)(struct kgsl_device *device, enum oob_request req);
|
||||
void (*bcl_config)(struct kgsl_device *device, bool on);
|
||||
void (*irq_enable)(struct kgsl_device *device);
|
||||
void (*irq_disable)(struct kgsl_device *device);
|
||||
int (*hfi_start_msg)(struct kgsl_device *device);
|
||||
void (*enable_lm)(struct kgsl_device *device);
|
||||
int (*rpmh_gpu_pwrctrl)(struct kgsl_device *device, unsigned int ops,
|
||||
unsigned int arg1, unsigned int arg2);
|
||||
int (*wait_for_lowest_idle)(struct kgsl_device *device);
|
||||
int (*wait_for_gmu_idle)(struct kgsl_device *device);
|
||||
bool (*gx_is_on)(struct kgsl_device *device);
|
||||
void (*prepare_stop)(struct kgsl_device *device);
|
||||
int (*ifpc_store)(struct kgsl_device *device, unsigned int val);
|
||||
unsigned int (*ifpc_show)(struct kgsl_device *device);
|
||||
void (*snapshot)(struct kgsl_device *device,
|
||||
struct kgsl_snapshot *shapshot);
|
||||
void (*cooperative_reset)(struct kgsl_device *device);
|
||||
void (*halt_execution)(struct kgsl_device *device);
|
||||
int (*wait_for_active_transition)(struct kgsl_device *device);
|
||||
bool (*scales_bandwidth)(struct kgsl_device *device);
|
||||
u64 (*read_alwayson)(struct kgsl_device *device);
|
||||
const unsigned int gmu2host_intr_mask;
|
||||
const unsigned int gmu_ao_intr_mask;
|
||||
int (*acd_set)(struct kgsl_device *device, bool val);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -148,7 +119,6 @@ struct gmu_dev_ops {
|
|||
* gmu registers using offset defined in GPU register space.
|
||||
* @reg_len: GMU registers length
|
||||
* @reg_virt: GMU CSR virtual address
|
||||
* @core_ops: Pointer to gmu core operations
|
||||
* @dev_ops: Pointer to gmu device operations
|
||||
* @flags: GMU flags
|
||||
*/
|
||||
|
|
@ -157,31 +127,22 @@ struct gmu_core_device {
|
|||
unsigned int gmu2gpu_offset;
|
||||
unsigned int reg_len;
|
||||
void __iomem *reg_virt;
|
||||
struct gmu_core_ops *core_ops;
|
||||
struct gmu_dev_ops *dev_ops;
|
||||
unsigned long flags;
|
||||
};
|
||||
|
||||
extern struct platform_driver kgsl_gmu_driver;
|
||||
extern struct platform_driver kgsl_rgmu_driver;
|
||||
extern struct platform_driver a6xx_gmu_driver;
|
||||
extern struct platform_driver a6xx_rgmu_driver;
|
||||
|
||||
/* GMU core functions */
|
||||
|
||||
void __init gmu_core_register(void);
|
||||
void __exit gmu_core_unregister(void);
|
||||
|
||||
int gmu_core_init(struct kgsl_device *device);
|
||||
int gmu_core_start(struct kgsl_device *device);
|
||||
void gmu_core_stop(struct kgsl_device *device);
|
||||
int gmu_core_suspend(struct kgsl_device *device);
|
||||
void gmu_core_snapshot(struct kgsl_device *device);
|
||||
bool gmu_core_gpmu_isenabled(struct kgsl_device *device);
|
||||
bool gmu_core_scales_bandwidth(struct kgsl_device *device);
|
||||
bool gmu_core_isenabled(struct kgsl_device *device);
|
||||
int gmu_core_dcvs_set(struct kgsl_device *device, int gpu_pwrlevel,
|
||||
int bus_level);
|
||||
int gmu_core_acd_set(struct kgsl_device *device, bool val);
|
||||
bool gmu_core_regulator_isenabled(struct kgsl_device *device);
|
||||
int gmu_core_dev_acd_set(struct kgsl_device *device, bool val);
|
||||
bool gmu_core_is_register_offset(struct kgsl_device *device,
|
||||
unsigned int offsetwords);
|
||||
void gmu_core_regread(struct kgsl_device *device, unsigned int offsetwords,
|
||||
|
|
@ -207,17 +168,10 @@ void gmu_core_regrmw(struct kgsl_device *device, unsigned int offsetwords,
|
|||
unsigned int mask, unsigned int bits);
|
||||
int gmu_core_dev_oob_set(struct kgsl_device *device, enum oob_request req);
|
||||
void gmu_core_dev_oob_clear(struct kgsl_device *device, enum oob_request req);
|
||||
int gmu_core_dev_hfi_start_msg(struct kgsl_device *device);
|
||||
int gmu_core_dev_wait_for_lowest_idle(struct kgsl_device *device);
|
||||
void gmu_core_dev_enable_lm(struct kgsl_device *device);
|
||||
void gmu_core_dev_snapshot(struct kgsl_device *device,
|
||||
struct kgsl_snapshot *snapshot);
|
||||
bool gmu_core_dev_gx_is_on(struct kgsl_device *device);
|
||||
int gmu_core_dev_ifpc_show(struct kgsl_device *device);
|
||||
int gmu_core_dev_ifpc_store(struct kgsl_device *device, unsigned int val);
|
||||
void gmu_core_dev_prepare_stop(struct kgsl_device *device);
|
||||
int gmu_core_dev_wait_for_active_transition(struct kgsl_device *device);
|
||||
void gmu_core_dev_cooperative_reset(struct kgsl_device *device);
|
||||
u64 gmu_core_dev_read_alwayson(struct kgsl_device *device);
|
||||
|
||||
#endif /* __KGSL_GMU_CORE_H */
|
||||
|
|
|
|||
|
|
@ -42,12 +42,9 @@ static const char * const clocks[] = {
|
|||
|
||||
static void kgsl_pwrctrl_clk(struct kgsl_device *device, int state,
|
||||
int requested_state);
|
||||
static void kgsl_pwrctrl_axi(struct kgsl_device *device, int state);
|
||||
static int kgsl_pwrctrl_pwrrail(struct kgsl_device *device, int state);
|
||||
static void kgsl_pwrctrl_set_state(struct kgsl_device *device,
|
||||
unsigned int state);
|
||||
static void kgsl_pwrctrl_request_state(struct kgsl_device *device,
|
||||
unsigned int state);
|
||||
static int _isense_clk_set_rate(struct kgsl_pwrctrl *pwr, int level);
|
||||
static int kgsl_pwrctrl_clk_set_rate(struct clk *grp_clk, unsigned int freq,
|
||||
const char *name);
|
||||
|
|
@ -103,33 +100,6 @@ static unsigned int _adjust_pwrlevel(struct kgsl_pwrctrl *pwr, int level,
|
|||
return level;
|
||||
}
|
||||
|
||||
/**
|
||||
* kgsl_clk_set_rate() - set GPU clock rate
|
||||
* @device: Pointer to the kgsl_device struct
|
||||
* @pwrlevel: power level in pwrlevels[] table
|
||||
*/
|
||||
int kgsl_clk_set_rate(struct kgsl_device *device,
|
||||
unsigned int pwrlevel)
|
||||
{
|
||||
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
|
||||
struct kgsl_pwrlevel *pl = &pwr->pwrlevels[pwrlevel];
|
||||
int ret = 0;
|
||||
|
||||
/* GMU scales GPU freq */
|
||||
if (gmu_core_gpmu_isenabled(device))
|
||||
ret = gmu_core_dcvs_set(device, pwrlevel, INVALID_DCVS_IDX);
|
||||
else
|
||||
/* Linux clock driver scales GPU freq */
|
||||
ret = kgsl_pwrctrl_clk_set_rate(pwr->grp_clks[0],
|
||||
pl->gpu_freq, clocks[0]);
|
||||
|
||||
if (ret)
|
||||
dev_err(device->dev, "GPU clk freq set failure: %d\n",
|
||||
ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* kgsl_pwrctrl_pwrlevel_change_settings() - Program h/w during powerlevel
|
||||
* transitions
|
||||
|
|
@ -204,10 +174,6 @@ void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device,
|
|||
|
||||
new_level = kgsl_pwrctrl_adjust_pwrlevel(device, new_level);
|
||||
|
||||
if (new_level == old_level &&
|
||||
!test_bit(GMU_DCVS_REPLAY, &device->gmu_core.flags))
|
||||
return;
|
||||
|
||||
kgsl_pwrscale_update_stats(device);
|
||||
|
||||
/*
|
||||
|
|
@ -235,7 +201,7 @@ void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device,
|
|||
pwrlevel = &pwr->pwrlevels[pwr->active_pwrlevel];
|
||||
/* Change register settings if any BEFORE pwrlevel change*/
|
||||
kgsl_pwrctrl_pwrlevel_change_settings(device, 0);
|
||||
kgsl_clk_set_rate(device, pwr->active_pwrlevel);
|
||||
device->ftbl->gpu_clock_set(device, pwr->active_pwrlevel);
|
||||
_isense_clk_set_rate(pwr, pwr->active_pwrlevel);
|
||||
|
||||
trace_kgsl_pwrlevel(device,
|
||||
|
|
@ -1218,7 +1184,7 @@ static void kgsl_pwrctrl_clk(struct kgsl_device *device, int state,
|
|||
(requested_state != KGSL_STATE_NAP)) {
|
||||
for (i = KGSL_MAX_CLKS - 1; i > 0; i--)
|
||||
clk_unprepare(pwr->grp_clks[i]);
|
||||
kgsl_clk_set_rate(device,
|
||||
device->ftbl->gpu_clock_set(device,
|
||||
pwr->num_pwrlevels - 1);
|
||||
_isense_clk_set_rate(pwr,
|
||||
pwr->num_pwrlevels - 1);
|
||||
|
|
@ -1231,7 +1197,7 @@ static void kgsl_pwrctrl_clk(struct kgsl_device *device, int state,
|
|||
for (i = KGSL_MAX_CLKS - 1; i > 0; i--)
|
||||
clk_unprepare(pwr->grp_clks[i]);
|
||||
if ((pwr->pwrlevels[0].gpu_freq > 0)) {
|
||||
kgsl_clk_set_rate(device,
|
||||
device->ftbl->gpu_clock_set(device,
|
||||
pwr->num_pwrlevels - 1);
|
||||
_isense_clk_set_rate(pwr,
|
||||
pwr->num_pwrlevels - 1);
|
||||
|
|
@ -1245,7 +1211,7 @@ static void kgsl_pwrctrl_clk(struct kgsl_device *device, int state,
|
|||
/* High latency clock maintenance. */
|
||||
if (device->state != KGSL_STATE_NAP) {
|
||||
if (pwr->pwrlevels[0].gpu_freq > 0) {
|
||||
kgsl_clk_set_rate(device,
|
||||
device->ftbl->gpu_clock_set(device,
|
||||
pwr->active_pwrlevel);
|
||||
_isense_clk_set_rate(pwr,
|
||||
pwr->active_pwrlevel);
|
||||
|
|
@ -1278,26 +1244,28 @@ static void kgsl_pwrctrl_clk(struct kgsl_device *device, int state,
|
|||
}
|
||||
}
|
||||
|
||||
static void kgsl_pwrctrl_axi(struct kgsl_device *device, int state)
|
||||
int kgsl_pwrctrl_axi(struct kgsl_device *device, int state)
|
||||
{
|
||||
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
|
||||
|
||||
if (test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->ctrl_flags))
|
||||
return;
|
||||
return 0;
|
||||
|
||||
if (state == KGSL_PWRFLAGS_OFF) {
|
||||
if (test_and_clear_bit(KGSL_PWRFLAGS_AXI_ON,
|
||||
&pwr->power_flags)) {
|
||||
trace_kgsl_bus(device, state);
|
||||
kgsl_bus_update(device, false);
|
||||
return 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_bus_update(device, true);
|
||||
return kgsl_bus_update(device, true);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int enable_regulator(struct device *dev, struct regulator *regulator,
|
||||
|
|
@ -1485,8 +1453,6 @@ static int kgsl_pwrctrl_clk_set_rate(struct clk *grp_clk, unsigned int freq,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void kgsl_idle_check(struct work_struct *work);
|
||||
|
||||
int kgsl_pwrctrl_init(struct kgsl_device *device)
|
||||
{
|
||||
int i, result, freq;
|
||||
|
|
@ -1516,7 +1482,6 @@ int kgsl_pwrctrl_init(struct kgsl_device *device)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
INIT_WORK(&device->idle_check_ws, kgsl_idle_check);
|
||||
init_waitqueue_head(&device->active_cnt_wq);
|
||||
|
||||
/* Initialize the user and thermal clock constraints */
|
||||
|
|
@ -1538,7 +1503,8 @@ int kgsl_pwrctrl_init(struct kgsl_device *device)
|
|||
pwr->pwrlevels[i].gpu_freq = freq;
|
||||
}
|
||||
|
||||
kgsl_clk_set_rate(device, pwr->num_pwrlevels - 1);
|
||||
clk_set_rate(pwr->grp_clks[0],
|
||||
pwr->pwrlevels[pwr->num_pwrlevels - 1].gpu_freq);
|
||||
|
||||
freq = clk_round_rate(pwr->grp_clks[6], KGSL_RBBMTIMER_CLK_FREQ);
|
||||
if (freq > 0)
|
||||
|
|
@ -1575,12 +1541,7 @@ void kgsl_pwrctrl_close(struct kgsl_device *device)
|
|||
pm_runtime_disable(&device->pdev->dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called for work that is queued by the interrupt
|
||||
* handler or the idle timer. It attempts to transition to a clocks
|
||||
* off state if the active_cnt is 0 and the hardware is idle.
|
||||
*/
|
||||
static void kgsl_idle_check(struct work_struct *work)
|
||||
void kgsl_idle_check(struct work_struct *work)
|
||||
{
|
||||
struct kgsl_device *device = container_of(work, struct kgsl_device,
|
||||
idle_check_ws);
|
||||
|
|
@ -1692,14 +1653,6 @@ static int kgsl_pwrctrl_enable(struct kgsl_device *device)
|
|||
|
||||
kgsl_pwrctrl_pwrlevel_change(device, level);
|
||||
|
||||
if (gmu_core_gpmu_isenabled(device)) {
|
||||
int ret = gmu_core_start(device);
|
||||
|
||||
if (!ret)
|
||||
kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Order pwrrail/clk sequence based upon platform */
|
||||
status = kgsl_pwrctrl_pwrrail(device, KGSL_PWRFLAGS_ON);
|
||||
if (status)
|
||||
|
|
@ -1720,11 +1673,6 @@ static void kgsl_pwrctrl_disable(struct kgsl_device *device)
|
|||
dev_err(device->dev, "Could not clear l3_vote: %d\n",
|
||||
status);
|
||||
|
||||
if (gmu_core_gpmu_isenabled(device)) {
|
||||
kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_OFF);
|
||||
return gmu_core_stop(device);
|
||||
}
|
||||
|
||||
/* Order pwrrail/clk sequence based upon platform */
|
||||
device->ftbl->regulator_disable(device);
|
||||
kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_OFF);
|
||||
|
|
@ -1757,18 +1705,6 @@ static int _init(struct kgsl_device *device)
|
|||
int status = 0;
|
||||
|
||||
switch (device->state) {
|
||||
case KGSL_STATE_RESET:
|
||||
if (gmu_core_isenabled(device)) {
|
||||
/*
|
||||
* If we fail a INIT -> AWARE transition, we will
|
||||
* transition back to INIT. However, we must hard reset
|
||||
* the GMU as we go back to INIT. This is done by
|
||||
* forcing a RESET -> INIT transition.
|
||||
*/
|
||||
gmu_core_suspend(device);
|
||||
kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
|
||||
}
|
||||
break;
|
||||
case KGSL_STATE_NAP:
|
||||
/* Force power on to do the stop */
|
||||
status = kgsl_pwrctrl_enable(device);
|
||||
|
|
@ -1878,12 +1814,6 @@ _aware(struct kgsl_device *device)
|
|||
int status = 0;
|
||||
|
||||
switch (device->state) {
|
||||
case KGSL_STATE_RESET:
|
||||
if (!gmu_core_gpmu_isenabled(device))
|
||||
break;
|
||||
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
|
||||
status = gmu_core_start(device);
|
||||
break;
|
||||
case KGSL_STATE_INIT:
|
||||
status = kgsl_pwrctrl_enable(device);
|
||||
break;
|
||||
|
|
@ -1903,18 +1833,7 @@ _aware(struct kgsl_device *device)
|
|||
status = -EINVAL;
|
||||
}
|
||||
|
||||
if (status && gmu_core_isenabled(device))
|
||||
/*
|
||||
* If a SLUMBER/INIT -> AWARE fails, we transition back to
|
||||
* SLUMBER/INIT state. We must hard reset the GMU while
|
||||
* transitioning back to SLUMBER/INIT. A RESET -> AWARE
|
||||
* transition is different. It happens when dispatcher is
|
||||
* attempting reset/recovery as part of fault handling. If it
|
||||
* fails, we should still transition back to RESET in case
|
||||
* we want to attempt another reset/recovery.
|
||||
*/
|
||||
kgsl_pwrctrl_set_state(device, KGSL_STATE_RESET);
|
||||
else
|
||||
if (!status)
|
||||
kgsl_pwrctrl_set_state(device, KGSL_STATE_AWARE);
|
||||
|
||||
return status;
|
||||
|
|
@ -1946,8 +1865,6 @@ _nap(struct kgsl_device *device)
|
|||
kgsl_pwrctrl_set_state(device, KGSL_STATE_NAP);
|
||||
/* fallthrough */
|
||||
case KGSL_STATE_SLUMBER:
|
||||
case KGSL_STATE_RESET:
|
||||
break;
|
||||
case KGSL_STATE_AWARE:
|
||||
dev_warn(device->dev,
|
||||
"transition AWARE -> NAP is not permitted\n");
|
||||
|
|
@ -1993,13 +1910,6 @@ _slumber(struct kgsl_device *device)
|
|||
kgsl_pwrctrl_disable(device);
|
||||
kgsl_pwrctrl_set_state(device, KGSL_STATE_SLUMBER);
|
||||
break;
|
||||
case KGSL_STATE_RESET:
|
||||
if (gmu_core_isenabled(device)) {
|
||||
/* Reset the GMU if we failed to boot the GMU */
|
||||
gmu_core_suspend(device);
|
||||
kgsl_pwrctrl_set_state(device, KGSL_STATE_SLUMBER);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
|
||||
break;
|
||||
|
|
@ -2088,9 +1998,6 @@ int kgsl_pwrctrl_change_state(struct kgsl_device *device, int state)
|
|||
case KGSL_STATE_SUSPEND:
|
||||
status = _suspend(device);
|
||||
break;
|
||||
case KGSL_STATE_RESET:
|
||||
kgsl_pwrctrl_set_state(device, KGSL_STATE_RESET);
|
||||
break;
|
||||
default:
|
||||
dev_err(device->dev, "bad state request 0x%x\n", state);
|
||||
kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
|
||||
|
|
@ -2116,7 +2023,7 @@ static void kgsl_pwrctrl_set_state(struct kgsl_device *device,
|
|||
spin_unlock(&device->submit_lock);
|
||||
}
|
||||
|
||||
static void kgsl_pwrctrl_request_state(struct kgsl_device *device,
|
||||
void kgsl_pwrctrl_request_state(struct kgsl_device *device,
|
||||
unsigned int state)
|
||||
{
|
||||
if (state != KGSL_STATE_NONE && state != device->requested_state)
|
||||
|
|
@ -2141,90 +2048,12 @@ const char *kgsl_pwrstate_to_str(unsigned int state)
|
|||
return "SUSPEND";
|
||||
case KGSL_STATE_SLUMBER:
|
||||
return "SLUMBER";
|
||||
case KGSL_STATE_RESET:
|
||||
return "RESET";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* kgsl_active_count_get() - Increase the device active count
|
||||
* @device: Pointer to a KGSL device
|
||||
*
|
||||
* Increase the active count for the KGSL device and turn on
|
||||
* clocks if this is the first reference. Code paths that need
|
||||
* to touch the hardware or wait for the hardware to complete
|
||||
* an operation must hold an active count reference until they
|
||||
* are finished. An error code will be returned if waking the
|
||||
* device fails. The device mutex must be held while *calling
|
||||
* this function.
|
||||
*/
|
||||
int kgsl_active_count_get(struct kgsl_device *device)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (WARN_ON(!mutex_is_locked(&device->mutex)))
|
||||
return -EINVAL;
|
||||
|
||||
if ((atomic_read(&device->active_cnt) == 0) &&
|
||||
(device->state != KGSL_STATE_ACTIVE)) {
|
||||
mutex_unlock(&device->mutex);
|
||||
wait_for_completion(&device->hwaccess_gate);
|
||||
mutex_lock(&device->mutex);
|
||||
device->pwrctrl.superfast = true;
|
||||
ret = kgsl_pwrctrl_change_state(device, KGSL_STATE_ACTIVE);
|
||||
}
|
||||
if (ret == 0)
|
||||
atomic_inc(&device->active_cnt);
|
||||
trace_kgsl_active_count(device,
|
||||
(unsigned long) __builtin_return_address(0));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* kgsl_active_count_put() - Decrease the device active count
|
||||
* @device: Pointer to a KGSL device
|
||||
*
|
||||
* Decrease the active count for the KGSL device and turn off
|
||||
* clocks if there are no remaining references. This function will
|
||||
* transition the device to NAP if there are no other pending state
|
||||
* changes. It also completes the suspend gate. The device mutex must
|
||||
* be held while calling this function.
|
||||
*/
|
||||
void kgsl_active_count_put(struct kgsl_device *device)
|
||||
{
|
||||
if (WARN_ON(!mutex_is_locked(&device->mutex)))
|
||||
return;
|
||||
|
||||
if (WARN(atomic_read(&device->active_cnt) == 0,
|
||||
"Unbalanced get/put calls to KGSL active count\n"))
|
||||
return;
|
||||
|
||||
if (atomic_dec_and_test(&device->active_cnt)) {
|
||||
bool nap_on = !(device->pwrctrl.ctrl_flags &
|
||||
BIT(KGSL_PWRFLAGS_NAP_OFF));
|
||||
if (nap_on && device->state == KGSL_STATE_ACTIVE &&
|
||||
device->requested_state == KGSL_STATE_NONE) {
|
||||
kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP);
|
||||
kgsl_schedule_work(&device->idle_check_ws);
|
||||
} else if (!nap_on) {
|
||||
kgsl_pwrscale_update_stats(device);
|
||||
kgsl_pwrscale_update(device);
|
||||
}
|
||||
|
||||
mod_timer(&device->idle_timer,
|
||||
jiffies + device->pwrctrl.interval_timeout);
|
||||
}
|
||||
|
||||
trace_kgsl_active_count(device,
|
||||
(unsigned long) __builtin_return_address(0));
|
||||
|
||||
wake_up(&device->active_cnt_wq);
|
||||
}
|
||||
|
||||
static int _check_active_count(struct kgsl_device *device, int count)
|
||||
{
|
||||
/* Return 0 if the active count is greater than the desired value */
|
||||
|
|
@ -2283,5 +2112,5 @@ int kgsl_pwrctrl_set_default_gpu_pwrlevel(struct kgsl_device *device)
|
|||
pwr->previous_pwrlevel = old_level;
|
||||
|
||||
/* Request adjusted DCVS level */
|
||||
return kgsl_clk_set_rate(device, pwr->active_pwrlevel);
|
||||
return device->ftbl->gpu_clock_set(device, pwr->active_pwrlevel);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -154,8 +154,6 @@ struct kgsl_pwrctrl {
|
|||
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;
|
||||
|
|
@ -175,8 +173,7 @@ void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device,
|
|||
unsigned int level);
|
||||
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,
|
||||
unsigned int pwrlevel);
|
||||
|
||||
unsigned int kgsl_pwrctrl_adjust_pwrlevel(struct kgsl_device *device,
|
||||
unsigned int new_level);
|
||||
|
||||
|
|
@ -197,12 +194,38 @@ kgsl_pwrctrl_active_freq(struct kgsl_pwrctrl *pwr)
|
|||
return pwr->pwrlevels[pwr->active_pwrlevel].gpu_freq;
|
||||
}
|
||||
|
||||
int __must_check kgsl_active_count_get(struct kgsl_device *device);
|
||||
void kgsl_active_count_put(struct kgsl_device *device);
|
||||
int kgsl_active_count_wait(struct kgsl_device *device, int count);
|
||||
void kgsl_pwrctrl_busy_time(struct kgsl_device *device, u64 time, u64 busy);
|
||||
void kgsl_pwrctrl_set_constraint(struct kgsl_device *device,
|
||||
struct kgsl_pwr_constraint *pwrc, uint32_t id);
|
||||
int kgsl_pwrctrl_set_default_gpu_pwrlevel(struct kgsl_device *device);
|
||||
|
||||
/**
|
||||
* kgsl_pwrctrl_request_state - Request a specific power state
|
||||
* @device: Pointer to the kgsl device
|
||||
* @state: Power state requested
|
||||
*/
|
||||
void kgsl_pwrctrl_request_state(struct kgsl_device *device, u32 state);
|
||||
|
||||
/**
|
||||
* kgsl_pwrctrl_axi - Propagate bus votes during slumber entry and exit
|
||||
* @device: Pointer to the kgsl device
|
||||
* @state: Whether we are going to slumber or coming out of slumber
|
||||
*
|
||||
* This function will propagate the default bus vote when coming out of
|
||||
* slumber and set bus bandwidth to 0 when going into slumber
|
||||
*
|
||||
* Return: 0 on success or negative error on failure
|
||||
*/
|
||||
int kgsl_pwrctrl_axi(struct kgsl_device *device, int state);
|
||||
|
||||
/**
|
||||
* kgsl_idle_check - kgsl idle function
|
||||
* @work: work item being run by the function
|
||||
*
|
||||
* This function is called for work that is queued by the interrupt
|
||||
* handler or the idle timer. It attempts to transition to a clocks
|
||||
* off state if the active_cnt is 0 and the hardware is idle.
|
||||
*/
|
||||
void kgsl_idle_check(struct work_struct *work);
|
||||
#endif /* __KGSL_PWRCTRL_H */
|
||||
|
|
|
|||
|
|
@ -1,469 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/component.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include "adreno.h"
|
||||
#include "kgsl_device.h"
|
||||
#include "kgsl_rgmu.h"
|
||||
#include "kgsl_util.h"
|
||||
|
||||
#define RGMU_CLK_FREQ 200000000
|
||||
|
||||
static int rgmu_irq_probe(struct kgsl_device *device)
|
||||
{
|
||||
struct rgmu_device *rgmu = KGSL_RGMU_DEVICE(device);
|
||||
int ret;
|
||||
|
||||
ret = kgsl_request_irq(rgmu->pdev, "kgsl_oob", oob_irq_handler, device);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
rgmu->oob_interrupt_num = ret;
|
||||
|
||||
ret = kgsl_request_irq(rgmu->pdev,
|
||||
"kgsl_rgmu", rgmu_irq_handler, device);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
rgmu->rgmu_interrupt_num = ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rgmu_regulators_probe(struct rgmu_device *rgmu)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
rgmu->cx_gdsc = devm_regulator_get(&rgmu->pdev->dev, "vddcx");
|
||||
if (IS_ERR(rgmu->cx_gdsc)) {
|
||||
ret = PTR_ERR(rgmu->cx_gdsc);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(&rgmu->pdev->dev,
|
||||
"Couldn't get CX gdsc error:%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rgmu->gx_gdsc = devm_regulator_get(&rgmu->pdev->dev, "vdd");
|
||||
if (IS_ERR(rgmu->gx_gdsc)) {
|
||||
ret = PTR_ERR(rgmu->gx_gdsc);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(&rgmu->pdev->dev,
|
||||
"Couldn't get GX gdsc error:%d\n", ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rgmu_clocks_probe(struct rgmu_device *rgmu, struct device_node *node)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = devm_clk_bulk_get_all(&rgmu->pdev->dev, &rgmu->clks);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
rgmu->num_clks = ret;
|
||||
|
||||
rgmu->gpu_clk = kgsl_of_clk_by_name(rgmu->clks, ret, "core");
|
||||
if (!rgmu->gpu_clk) {
|
||||
dev_err(&rgmu->pdev->dev, "The GPU clock isn't defined\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
rgmu->rgmu_clk = kgsl_of_clk_by_name(rgmu->clks, ret, "gmu");
|
||||
if (!rgmu->rgmu_clk) {
|
||||
dev_err(&rgmu->pdev->dev, "The RGMU clock isn't defined\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rgmu_disable_clks(struct kgsl_device *device)
|
||||
{
|
||||
struct rgmu_device *rgmu = KGSL_RGMU_DEVICE(device);
|
||||
struct gmu_dev_ops *gmu_dev_ops = GMU_DEVICE_OPS(device);
|
||||
int ret;
|
||||
|
||||
/* Check GX GDSC is status */
|
||||
if (gmu_dev_ops->gx_is_on(device)) {
|
||||
|
||||
if (IS_ERR_OR_NULL(rgmu->gx_gdsc))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Switch gx gdsc control from RGMU to CPU. Force non-zero
|
||||
* reference count in clk driver so next disable call will
|
||||
* turn off the GDSC.
|
||||
*/
|
||||
ret = regulator_enable(rgmu->gx_gdsc);
|
||||
if (ret)
|
||||
dev_err(&rgmu->pdev->dev,
|
||||
"Fail to enable gx gdsc:%d\n", ret);
|
||||
|
||||
ret = regulator_disable(rgmu->gx_gdsc);
|
||||
if (ret)
|
||||
dev_err(&rgmu->pdev->dev,
|
||||
"Fail to disable gx gdsc:%d\n", ret);
|
||||
|
||||
if (gmu_dev_ops->gx_is_on(device))
|
||||
dev_err(&rgmu->pdev->dev, "gx is stuck on\n");
|
||||
}
|
||||
|
||||
clk_bulk_disable_unprepare(rgmu->num_clks, rgmu->clks);
|
||||
|
||||
clear_bit(GMU_CLK_ON, &device->gmu_core.flags);
|
||||
}
|
||||
|
||||
static int rgmu_enable_clks(struct kgsl_device *device)
|
||||
{
|
||||
int ret;
|
||||
struct rgmu_device *rgmu = KGSL_RGMU_DEVICE(device);
|
||||
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
|
||||
|
||||
ret = clk_set_rate(rgmu->rgmu_clk, RGMU_CLK_FREQ);
|
||||
if (ret) {
|
||||
dev_err(&rgmu->pdev->dev, "Couldn't set the RGMU clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_set_rate(rgmu->gpu_clk,
|
||||
pwr->pwrlevels[pwr->default_pwrlevel].gpu_freq);
|
||||
if (ret) {
|
||||
dev_err(&rgmu->pdev->dev, "Couldn't set the GPU clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_bulk_prepare_enable(rgmu->num_clks, rgmu->clks);
|
||||
if (ret) {
|
||||
dev_err(&rgmu->pdev->dev, "Failed to enable RGMU clocks\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
set_bit(GMU_CLK_ON, &device->gmu_core.flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rgmu_disable_gdsc(struct kgsl_device *device)
|
||||
{
|
||||
struct rgmu_device *rgmu = KGSL_RGMU_DEVICE(device);
|
||||
|
||||
/* Wait up to 5 seconds for the regulator to go off */
|
||||
if (kgsl_regulator_disable_wait(rgmu->cx_gdsc, 5000))
|
||||
return 0;
|
||||
|
||||
dev_err(&rgmu->pdev->dev, "RGMU CX gdsc off timeout\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int rgmu_enable_gdsc(struct rgmu_device *rgmu)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (IS_ERR_OR_NULL(rgmu->cx_gdsc))
|
||||
return 0;
|
||||
|
||||
ret = regulator_enable(rgmu->cx_gdsc);
|
||||
if (ret)
|
||||
dev_err(&rgmu->pdev->dev,
|
||||
"Fail to enable CX gdsc:%d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rgmu_snapshot(struct kgsl_device *device)
|
||||
{
|
||||
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
|
||||
struct gmu_dev_ops *gmu_dev_ops = GMU_DEVICE_OPS(device);
|
||||
struct rgmu_device *rgmu = KGSL_RGMU_DEVICE(device);
|
||||
|
||||
/* Mask so there's no interrupt caused by NMI */
|
||||
adreno_write_gmureg(adreno_dev,
|
||||
ADRENO_REG_GMU_GMU2HOST_INTR_MASK, 0xFFFFFFFF);
|
||||
|
||||
/* Make sure the interrupt is masked */
|
||||
wmb();
|
||||
|
||||
/*
|
||||
* Halt RGMU execution so that GX will not
|
||||
* be collapsed while dumping snapshot.
|
||||
*/
|
||||
gmu_dev_ops->halt_execution(device);
|
||||
|
||||
kgsl_device_snapshot(device, NULL, true);
|
||||
|
||||
adreno_write_gmureg(adreno_dev,
|
||||
ADRENO_REG_GMU_GMU2HOST_INTR_CLR, 0xFFFFFFFF);
|
||||
adreno_write_gmureg(adreno_dev,
|
||||
ADRENO_REG_GMU_GMU2HOST_INTR_MASK,
|
||||
~(gmu_dev_ops->gmu2host_intr_mask));
|
||||
|
||||
rgmu->fault_count++;
|
||||
}
|
||||
|
||||
/* Caller shall ensure GPU is ready for SLUMBER */
|
||||
static void rgmu_stop(struct kgsl_device *device)
|
||||
{
|
||||
struct gmu_dev_ops *gmu_dev_ops = GMU_DEVICE_OPS(device);
|
||||
|
||||
if (!test_bit(GMU_CLK_ON, &device->gmu_core.flags))
|
||||
return;
|
||||
|
||||
/* Wait for the lowest idle level we requested */
|
||||
if (gmu_dev_ops->wait_for_lowest_idle(device))
|
||||
goto error;
|
||||
|
||||
gmu_dev_ops->rpmh_gpu_pwrctrl(device,
|
||||
GMU_NOTIFY_SLUMBER, 0, 0);
|
||||
|
||||
gmu_dev_ops->irq_disable(device);
|
||||
rgmu_disable_clks(device);
|
||||
rgmu_disable_gdsc(device);
|
||||
return;
|
||||
|
||||
error:
|
||||
|
||||
/*
|
||||
* The power controller will change state to SLUMBER anyway
|
||||
* Set GMU_FAULT flag to indicate to power contrller
|
||||
* that hang recovery is needed to power on GPU
|
||||
*/
|
||||
set_bit(GMU_FAULT, &device->gmu_core.flags);
|
||||
rgmu_snapshot(device);
|
||||
}
|
||||
|
||||
static struct gmu_core_ops rgmu_ops;
|
||||
|
||||
/* Do not access any RGMU registers in RGMU probe function */
|
||||
static int rgmu_probe(struct kgsl_device *device, struct platform_device *pdev)
|
||||
{
|
||||
struct rgmu_device *rgmu;
|
||||
struct resource *res;
|
||||
int ret = -ENXIO;
|
||||
|
||||
rgmu = devm_kzalloc(&pdev->dev, sizeof(*rgmu), GFP_KERNEL);
|
||||
|
||||
if (rgmu == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
rgmu->pdev = pdev;
|
||||
|
||||
/* Set up RGMU regulators */
|
||||
ret = rgmu_regulators_probe(rgmu);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Set up RGMU clocks */
|
||||
ret = rgmu_clocks_probe(rgmu, pdev->dev.of_node);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Map and reserve RGMU CSRs registers */
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "kgsl_rgmu");
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "The RGMU register region isn't defined\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
device->gmu_core.gmu2gpu_offset = (res->start - device->reg_phys) >> 2;
|
||||
device->gmu_core.reg_len = resource_size(res);
|
||||
device->gmu_core.reg_virt = devm_ioremap_resource(&pdev->dev, res);
|
||||
|
||||
if (IS_ERR(device->gmu_core.reg_virt)) {
|
||||
dev_err(&pdev->dev, "Unable to map the RGMU registers\n");
|
||||
return PTR_ERR(device->gmu_core.reg_virt);
|
||||
}
|
||||
|
||||
device->gmu_core.ptr = (void *)rgmu;
|
||||
|
||||
/* Initialize OOB and RGMU interrupts */
|
||||
ret = rgmu_irq_probe(device);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Don't enable RGMU interrupts until RGMU started */
|
||||
/* We cannot use rgmu_irq_disable because it writes registers */
|
||||
disable_irq(rgmu->rgmu_interrupt_num);
|
||||
disable_irq(rgmu->oob_interrupt_num);
|
||||
|
||||
/* Set up RGMU idle states */
|
||||
if (ADRENO_FEATURE(ADRENO_DEVICE(device), ADRENO_IFPC))
|
||||
rgmu->idle_level = GPU_HW_IFPC;
|
||||
else
|
||||
rgmu->idle_level = GPU_HW_ACTIVE;
|
||||
|
||||
set_bit(GMU_ENABLED, &device->gmu_core.flags);
|
||||
device->gmu_core.core_ops = &rgmu_ops;
|
||||
device->gmu_core.dev_ops = &adreno_a6xx_rgmudev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rgmu_suspend(struct kgsl_device *device)
|
||||
{
|
||||
struct gmu_dev_ops *gmu_dev_ops = GMU_DEVICE_OPS(device);
|
||||
|
||||
if (!test_bit(GMU_CLK_ON, &device->gmu_core.flags))
|
||||
return 0;
|
||||
|
||||
gmu_dev_ops->irq_disable(device);
|
||||
|
||||
if (gmu_dev_ops->rpmh_gpu_pwrctrl(device, GMU_SUSPEND, 0, 0))
|
||||
return -EINVAL;
|
||||
|
||||
rgmu_disable_clks(device);
|
||||
rgmu_disable_gdsc(device);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rgmu_init(struct kgsl_device *device)
|
||||
{
|
||||
struct gmu_dev_ops *ops = GMU_DEVICE_OPS(device);
|
||||
int ret;
|
||||
|
||||
ret = ops->load_firmware(device);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* To be called to power on both GPU and RGMU */
|
||||
static int rgmu_start(struct kgsl_device *device)
|
||||
{
|
||||
int ret = 0;
|
||||
struct gmu_dev_ops *gmu_dev_ops = GMU_DEVICE_OPS(device);
|
||||
struct rgmu_device *rgmu = KGSL_RGMU_DEVICE(device);
|
||||
|
||||
switch (device->state) {
|
||||
case KGSL_STATE_RESET:
|
||||
ret = rgmu_suspend(device);
|
||||
if (ret)
|
||||
goto error_rgmu;
|
||||
/* Fall-thru */
|
||||
case KGSL_STATE_INIT:
|
||||
case KGSL_STATE_SUSPEND:
|
||||
case KGSL_STATE_SLUMBER:
|
||||
rgmu_enable_gdsc(rgmu);
|
||||
rgmu_enable_clks(device);
|
||||
gmu_dev_ops->irq_enable(device);
|
||||
ret = gmu_dev_ops->rpmh_gpu_pwrctrl(device,
|
||||
GMU_FW_START, GMU_COLD_BOOT, 0);
|
||||
if (ret)
|
||||
goto error_rgmu;
|
||||
break;
|
||||
}
|
||||
/* Request default DCVS level */
|
||||
kgsl_pwrctrl_set_default_gpu_pwrlevel(device);
|
||||
return 0;
|
||||
|
||||
error_rgmu:
|
||||
set_bit(GMU_FAULT, &device->gmu_core.flags);
|
||||
rgmu_snapshot(device);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* rgmu_dcvs_set() - Change GPU frequency and/or bandwidth.
|
||||
* @rgmu: Pointer to RGMU device
|
||||
* @pwrlevel: index to GPU DCVS table used by KGSL
|
||||
* @bus_level: index to GPU bus table used by KGSL
|
||||
*
|
||||
* The function converts GPU power level and bus level index used by KGSL
|
||||
* to index being used by GMU/RPMh.
|
||||
*/
|
||||
static int rgmu_dcvs_set(struct kgsl_device *device,
|
||||
int pwrlevel, int bus_level)
|
||||
{
|
||||
struct rgmu_device *rgmu = KGSL_RGMU_DEVICE(device);
|
||||
int ret;
|
||||
unsigned long rate;
|
||||
|
||||
if (pwrlevel == INVALID_DCVS_IDX)
|
||||
return -EINVAL;
|
||||
|
||||
rate = device->pwrctrl.pwrlevels[pwrlevel].gpu_freq;
|
||||
|
||||
ret = clk_set_rate(rgmu->gpu_clk, rate);
|
||||
if (ret)
|
||||
dev_err(&rgmu->pdev->dev, "Couldn't set the GPU clock\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool rgmu_regulator_isenabled(struct kgsl_device *device)
|
||||
{
|
||||
struct rgmu_device *rgmu = KGSL_RGMU_DEVICE(device);
|
||||
|
||||
return (rgmu->gx_gdsc && regulator_is_enabled(rgmu->gx_gdsc));
|
||||
}
|
||||
|
||||
static void rgmu_remove(struct kgsl_device *device)
|
||||
{
|
||||
rgmu_stop(device);
|
||||
|
||||
memset(&device->gmu_core, 0, sizeof(device->gmu_core));
|
||||
}
|
||||
|
||||
static struct gmu_core_ops rgmu_ops = {
|
||||
.init = rgmu_init,
|
||||
.start = rgmu_start,
|
||||
.stop = rgmu_stop,
|
||||
.dcvs_set = rgmu_dcvs_set,
|
||||
.snapshot = rgmu_snapshot,
|
||||
.regulator_isenabled = rgmu_regulator_isenabled,
|
||||
.suspend = rgmu_suspend,
|
||||
};
|
||||
|
||||
static int kgsl_rgmu_bind(struct device *dev, struct device *master, void *data)
|
||||
{
|
||||
struct kgsl_device *device = dev_get_drvdata(master);
|
||||
|
||||
return rgmu_probe(device, to_platform_device(dev));
|
||||
}
|
||||
|
||||
static void kgsl_rgmu_unbind(struct device *dev, struct device *master,
|
||||
void *data)
|
||||
{
|
||||
struct kgsl_device *device = dev_get_drvdata(master);
|
||||
|
||||
rgmu_remove(device);
|
||||
}
|
||||
|
||||
static const struct component_ops kgsl_rgmu_ops = {
|
||||
.bind = kgsl_rgmu_bind,
|
||||
.unbind = kgsl_rgmu_unbind,
|
||||
};
|
||||
|
||||
static int kgsl_rgmu_probe(struct platform_device *pdev)
|
||||
{
|
||||
return component_add(&pdev->dev, &kgsl_rgmu_ops);
|
||||
}
|
||||
|
||||
static int kgsl_rgmu_remove(struct platform_device *pdev)
|
||||
{
|
||||
component_del(&pdev->dev, &kgsl_rgmu_ops);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id kgsl_rgmu_match_table[] = {
|
||||
{ .compatible = "qcom,gpu-rgmu" },
|
||||
{ },
|
||||
};
|
||||
|
||||
struct platform_driver kgsl_rgmu_driver = {
|
||||
.probe = kgsl_rgmu_probe,
|
||||
.remove = kgsl_rgmu_remove,
|
||||
.driver = {
|
||||
.name = "kgsl-rgmu",
|
||||
.of_match_table = kgsl_rgmu_match_table,
|
||||
},
|
||||
};
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
#ifndef __KGSL_RGMU_H
|
||||
#define __KGSL_RGMU_H
|
||||
|
||||
#define RGMU_AO_IRQ_FENCE_ERR BIT(3)
|
||||
#define RGMU_AO_IRQ_MASK RGMU_AO_IRQ_FENCE_ERR
|
||||
|
||||
#define RGMU_OOB_IRQ_ERR_MSG BIT(24)
|
||||
#define RGMU_OOB_IRQ_ACK_MASK GENMASK(23, 16)
|
||||
#define RGMU_OOB_IRQ_ERR_MSG_MASK GENMASK(31, 24)
|
||||
#define RGMU_OOB_IRQ_MASK RGMU_OOB_IRQ_ERR_MSG_MASK
|
||||
|
||||
#define MAX_RGMU_CLKS 8
|
||||
|
||||
/**
|
||||
* struct rgmu_device - rGMU device structure
|
||||
* @ver: RGMU firmware version
|
||||
* @rgmu_interrupt_num: RGMU interrupt number
|
||||
* @oob_interrupt_num: number of RGMU asserted OOB interrupt
|
||||
* @fw_hostptr: Buffer which holds the RGMU firmware
|
||||
* @fw_size: Size of RGMU firmware buffer
|
||||
* @cx_gdsc: CX headswitch that controls power of RGMU and
|
||||
subsystem peripherals
|
||||
* @clks: RGMU clocks including the GPU
|
||||
* @gpu_clk: Pointer to GPU core clock
|
||||
* @rgmu_clk: Pointer to rgmu clock
|
||||
* @flags: RGMU flags
|
||||
* @idle_level: Minimal GPU idle power level
|
||||
* @fault_count: RGMU fault count
|
||||
*/
|
||||
struct rgmu_device {
|
||||
u32 ver;
|
||||
struct platform_device *pdev;
|
||||
unsigned int rgmu_interrupt_num;
|
||||
unsigned int oob_interrupt_num;
|
||||
unsigned int *fw_hostptr;
|
||||
uint32_t fw_size;
|
||||
struct regulator *cx_gdsc;
|
||||
struct regulator *gx_gdsc;
|
||||
struct clk_bulk_data *clks;
|
||||
/** @num_clks: Number of clocks in @clks */
|
||||
int num_clks;
|
||||
struct clk *gpu_clk;
|
||||
struct clk *rgmu_clk;
|
||||
unsigned int idle_level;
|
||||
unsigned int fault_count;
|
||||
};
|
||||
|
||||
extern struct gmu_dev_ops adreno_a6xx_rgmudev;
|
||||
#define KGSL_RGMU_DEVICE(_a) ((struct rgmu_device *)((_a)->gmu_core.ptr))
|
||||
|
||||
irqreturn_t rgmu_irq_handler(int irq, void *data);
|
||||
irqreturn_t oob_irq_handler(int irq, void *data);
|
||||
#endif /* __KGSL_RGMU_H */
|
||||
|
|
@ -728,7 +728,6 @@ void kgsl_device_snapshot(struct kgsl_device *device,
|
|||
snapshot->start = device->snapshot_memory.ptr;
|
||||
snapshot->ptr = device->snapshot_memory.ptr;
|
||||
snapshot->remain = device->snapshot_memory.size;
|
||||
snapshot->gmu_fault = gmu_fault;
|
||||
snapshot->recovered = false;
|
||||
snapshot->first_read = true;
|
||||
snapshot->sysfs_read = 0;
|
||||
|
|
@ -1269,7 +1268,7 @@ static void kgsl_snapshot_save_frozen_objs(struct work_struct *work)
|
|||
size_t size = 0;
|
||||
void *ptr;
|
||||
|
||||
if (snapshot->gmu_fault)
|
||||
if (snapshot->device->gmu_fault)
|
||||
goto gmu_only;
|
||||
|
||||
kgsl_snapshot_process_ib_obj_list(snapshot);
|
||||
|
|
|
|||
Loading…
Reference in a new issue