Commit 5a903a44 authored by Konrad Dybcio's avatar Konrad Dybcio Committed by Rob Clark

drm/msm/a6xx: Introduce GMU wrapper support

Some (particularly SMD_RPM, a.k.a non-RPMh) SoCs implement A6XX GPUs
but don't implement the associated GMUs. This is due to the fact that
the GMU directly pokes at RPMh. Sadly, this means we have to take care
of enabling & scaling power rails, clocks and bandwidth ourselves.

Reuse existing Adreno-common code and modify the deeply-GMU-infused
A6XX code to facilitate these GPUs. This involves if-ing out lots
of GMU callbacks and introducing a new type of GMU - GMU wrapper (it's
the actual name that Qualcomm uses in their downstream kernels).

This is essentially a register region which is convenient to model
as a device. We'll use it for managing the GDSCs. The register
layout matches the actual GMU_CX/GX regions on the "real GMU" devices
and lets us reuse quite a bit of gmu_read/write/rmw calls.
Signed-off-by: default avatarKonrad Dybcio <konrad.dybcio@linaro.org>
Patchwork: https://patchwork.freedesktop.org/patch/542766/Signed-off-by: default avatarRob Clark <robdclark@chromium.org>
parent 30f55f3f
......@@ -1431,6 +1431,7 @@ static int a6xx_gmu_get_irq(struct a6xx_gmu *gmu, struct platform_device *pdev,
void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu)
{
struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
struct a6xx_gmu *gmu = &a6xx_gpu->gmu;
struct platform_device *pdev = to_platform_device(gmu->dev);
......@@ -1456,10 +1457,12 @@ void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu)
gmu->mmio = NULL;
gmu->rscc = NULL;
a6xx_gmu_memory_free(gmu);
if (!adreno_has_gmu_wrapper(adreno_gpu)) {
a6xx_gmu_memory_free(gmu);
free_irq(gmu->gmu_irq, gmu);
free_irq(gmu->hfi_irq, gmu);
free_irq(gmu->gmu_irq, gmu);
free_irq(gmu->hfi_irq, gmu);
}
/* Drop reference taken in of_find_device_by_node */
put_device(gmu->dev);
......@@ -1478,6 +1481,69 @@ static int cxpd_notifier_cb(struct notifier_block *nb,
return 0;
}
int a6xx_gmu_wrapper_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node)
{
struct platform_device *pdev = of_find_device_by_node(node);
struct a6xx_gmu *gmu = &a6xx_gpu->gmu;
int ret;
if (!pdev)
return -ENODEV;
gmu->dev = &pdev->dev;
of_dma_configure(gmu->dev, node, true);
pm_runtime_enable(gmu->dev);
/* Mark legacy for manual SPTPRAC control */
gmu->legacy = true;
/* Map the GMU registers */
gmu->mmio = a6xx_gmu_get_mmio(pdev, "gmu");
if (IS_ERR(gmu->mmio)) {
ret = PTR_ERR(gmu->mmio);
goto err_mmio;
}
gmu->cxpd = dev_pm_domain_attach_by_name(gmu->dev, "cx");
if (IS_ERR(gmu->cxpd)) {
ret = PTR_ERR(gmu->cxpd);
goto err_mmio;
}
if (!device_link_add(gmu->dev, gmu->cxpd, DL_FLAG_PM_RUNTIME)) {
ret = -ENODEV;
goto detach_cxpd;
}
init_completion(&gmu->pd_gate);
complete_all(&gmu->pd_gate);
gmu->pd_nb.notifier_call = cxpd_notifier_cb;
/* Get a link to the GX power domain to reset the GPU */
gmu->gxpd = dev_pm_domain_attach_by_name(gmu->dev, "gx");
if (IS_ERR(gmu->gxpd)) {
ret = PTR_ERR(gmu->gxpd);
goto err_mmio;
}
gmu->initialized = true;
return 0;
detach_cxpd:
dev_pm_domain_detach(gmu->cxpd, false);
err_mmio:
iounmap(gmu->mmio);
/* Drop reference taken in of_find_device_by_node */
put_device(gmu->dev);
return ret;
}
int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node)
{
struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
......
This diff is collapsed.
......@@ -76,6 +76,7 @@ int a6xx_gmu_set_oob(struct a6xx_gmu *gmu, enum a6xx_gmu_oob_state state);
void a6xx_gmu_clear_oob(struct a6xx_gmu *gmu, enum a6xx_gmu_oob_state state);
int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node);
int a6xx_gmu_wrapper_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node);
void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu);
void a6xx_gmu_set_freq(struct msm_gpu *gpu, struct dev_pm_opp *opp,
......
......@@ -1041,16 +1041,18 @@ struct msm_gpu_state *a6xx_gpu_state_get(struct msm_gpu *gpu)
/* Get the generic state from the adreno core */
adreno_gpu_state_get(gpu, &a6xx_state->base);
a6xx_get_gmu_registers(gpu, a6xx_state);
if (!adreno_has_gmu_wrapper(adreno_gpu)) {
a6xx_get_gmu_registers(gpu, a6xx_state);
a6xx_state->gmu_log = a6xx_snapshot_gmu_bo(a6xx_state, &a6xx_gpu->gmu.log);
a6xx_state->gmu_hfi = a6xx_snapshot_gmu_bo(a6xx_state, &a6xx_gpu->gmu.hfi);
a6xx_state->gmu_debug = a6xx_snapshot_gmu_bo(a6xx_state, &a6xx_gpu->gmu.debug);
a6xx_state->gmu_log = a6xx_snapshot_gmu_bo(a6xx_state, &a6xx_gpu->gmu.log);
a6xx_state->gmu_hfi = a6xx_snapshot_gmu_bo(a6xx_state, &a6xx_gpu->gmu.hfi);
a6xx_state->gmu_debug = a6xx_snapshot_gmu_bo(a6xx_state, &a6xx_gpu->gmu.debug);
a6xx_snapshot_gmu_hfi_history(gpu, a6xx_state);
a6xx_snapshot_gmu_hfi_history(gpu, a6xx_state);
}
/* If GX isn't on the rest of the data isn't going to be accessible */
if (!a6xx_gmu_gx_is_on(&a6xx_gpu->gmu))
if (!adreno_has_gmu_wrapper(adreno_gpu) && !a6xx_gmu_gx_is_on(&a6xx_gpu->gmu))
return &a6xx_state->base;
/* Get the banks of indexed registers */
......
......@@ -528,6 +528,10 @@ int adreno_load_fw(struct adreno_gpu *adreno_gpu)
if (!adreno_gpu->info->fw[i])
continue;
/* Skip loading GMU firwmare with GMU Wrapper */
if (adreno_has_gmu_wrapper(adreno_gpu) && i == ADRENO_FW_GMU)
continue;
/* Skip if the firmware has already been loaded */
if (adreno_gpu->fw[i])
continue;
......@@ -1074,8 +1078,8 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
u32 speedbin;
int ret;
/* Only handle the core clock when GMU is not in use */
if (config->rev.core < 6) {
/* Only handle the core clock when GMU is not in use (or is absent). */
if (adreno_has_gmu_wrapper(adreno_gpu) || config->rev.core < 6) {
/*
* This can only be done before devm_pm_opp_of_add_table(), or
* dev_pm_opp_set_config() will WARN_ON()
......
......@@ -115,6 +115,7 @@ struct adreno_gpu {
* code (a3xx_gpu.c) and stored in this common location.
*/
const unsigned int *reg_offsets;
bool gmu_is_wrapper;
};
#define to_adreno_gpu(x) container_of(x, struct adreno_gpu, base)
......@@ -152,6 +153,11 @@ static inline bool adreno_is_revn(const struct adreno_gpu *gpu, uint32_t revn)
return gpu->revn == revn;
}
static inline bool adreno_has_gmu_wrapper(const struct adreno_gpu *gpu)
{
return gpu->gmu_is_wrapper;
}
static inline bool adreno_is_a2xx(const struct adreno_gpu *gpu)
{
WARN_ON_ONCE(!gpu->revn);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment