From c96f0216161ebe779d75803926652bc4f076575c Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Wed, 1 Apr 2020 11:32:12 -0600 Subject: [PATCH 01/30] msm: kgsl: Add target specific probe functions Add support for target specific probe functions to give individual targets the flexibility to define their own device structs and do other target specific setup that doesn't belong in the generic init. To start all targets use a common helper probe function but that is expected to change soon. Change-Id: Ic0dedbad9e159be724368c7d2a496af151226cc0 Signed-off-by: Jordan Crouse --- drivers/gpu/msm/adreno.c | 235 +++++++++++++++++++--------------- drivers/gpu/msm/adreno.h | 31 +++++ drivers/gpu/msm/adreno_a3xx.c | 1 + drivers/gpu/msm/adreno_a5xx.c | 1 + drivers/gpu/msm/adreno_a6xx.c | 1 + 5 files changed, 163 insertions(+), 106 deletions(-) diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 96863da68b5b..33d82b7dcbb9 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -691,26 +691,64 @@ adreno_get_soc_hw_revision_node(struct platform_device *pdev, u32 hwrev) return NULL; } +static u32 adreno_efuse_read_soc_hw_rev(struct platform_device *pdev) +{ + unsigned int val; + unsigned int soc_hw_rev[3]; + int ret; + + if (of_property_read_u32_array(pdev->dev.of_node, + "qcom,soc-hw-rev-efuse", soc_hw_rev, 3)) + return 0; + + ret = adreno_efuse_map(pdev); + if (ret) { + dev_err(&pdev->dev, + "Unable to map hardware revision fuse: ret=%d\n", ret); + return 0; + } + + ret = adreno_efuse_read_u32(soc_hw_rev[0], &val); + adreno_efuse_unmap(); + + if (ret) { + dev_err(&pdev->dev, + "Unable to read hardware revision fuse: ret=%d\n", ret); + return 0; + } + + return (val >> soc_hw_rev[1]) & soc_hw_rev[2]; +} + +static int adreno_get_chipid(struct platform_device *pdev, u32 *chipid) +{ + u32 hwrev = adreno_efuse_read_soc_hw_rev(pdev); + struct device_node *node; + int ret; + + node = adreno_get_soc_hw_revision_node(pdev, hwrev); + if (!node) + node = of_node_get(pdev->dev.of_node); + + ret = of_property_read_u32(node, "qcom,chipid", chipid); + + of_node_put(node); + return ret; +} + static void adreno_update_soc_hw_revision_quirks(struct adreno_device *adreno_dev, - struct platform_device *pdev, u32 hwrev) + struct platform_device *pdev) { struct device_node *node; int i; + u32 hwrev; + + hwrev = adreno_efuse_read_soc_hw_rev(pdev); node = adreno_get_soc_hw_revision_node(pdev, hwrev); if (node == NULL) - node = pdev->dev.of_node; - - /* get chip id, fall back to parent if revision node does not have it */ - if (of_property_read_u32(node, "qcom,chipid", &adreno_dev->chipid)) { - if (of_property_read_u32(pdev->dev.of_node, - "qcom,chipid", &adreno_dev->chipid)) { - dev_crit(&pdev->dev, "No GPU chip ID was specified\n"); - BUG(); - return; - } - } + node = of_node_get(pdev->dev.of_node); /* update quirk */ for (i = 0; i < ARRAY_SIZE(adreno_quirks); i++) { @@ -723,55 +761,40 @@ adreno_update_soc_hw_revision_quirks(struct adreno_device *adreno_dev, kgsl_mmu_set_feature(KGSL_DEVICE(adreno_dev), KGSL_MMU_SECURE_CB_ALT); - - if (node != pdev->dev.of_node) - of_node_put(node); + of_node_put(node); } -static int adreno_identify_gpu(struct platform_device *pdev, - struct adreno_device *adreno_dev) +static const struct adreno_gpu_core * +adreno_identify_gpu(struct platform_device *pdev, u32 *chipid) { - struct adreno_gpudev *gpudev; - int i; + const struct adreno_gpu_core *gpucore; - adreno_dev->gpucore = _get_gpu_core(pdev, adreno_dev->chipid); + if (adreno_get_chipid(pdev, chipid)) { + dev_crit(&pdev->dev, "Unable to get the GPU chip ID\n"); + return ERR_PTR(-ENODEV); + } - if (adreno_dev->gpucore == NULL) { - dev_crit(&pdev->dev, - "Unknown GPU chip ID %8.8X\n", adreno_dev->chipid); - return -ENODEV; + gpucore = _get_gpu_core(pdev, *chipid); + if (!gpucore) { + dev_crit(&pdev->dev, "Unknown GPU chip ID %8.8x\n", *chipid); + return ERR_PTR(-ENODEV); } /* * Identify non-longer supported targets and spins and print a helpful * message */ - if (adreno_dev->gpucore->features & ADRENO_DEPRECATED) { + if (gpucore->features & ADRENO_DEPRECATED) { dev_err(&pdev->dev, "Support for GPU %d.%d.%d.%d has been deprecated\n", - adreno_dev->gpucore->core, - adreno_dev->gpucore->major, - adreno_dev->gpucore->minor, - adreno_dev->gpucore->patchid); - return -ENODEV; + gpucore->core, + gpucore->major, + gpucore->minor, + gpucore->patchid); + return ERR_PTR(-ENODEV); } - gpudev = ADRENO_GPU_DEVICE(adreno_dev); - - /* - * 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 (!gpudev->reg_offsets[i]) - gpudev->reg_offsets[i] = ADRENO_REG_UNUSED; - } - - /* Do target specific identification */ - if (gpudev->platform_setup != NULL) - gpudev->platform_setup(adreno_dev); - - return 0; + return gpucore; } static const struct of_device_id adreno_match_table[] = { @@ -1132,50 +1155,20 @@ static void adreno_isense_probe(struct kgsl_device *device) dev_warn(device->dev, "isense ioremap failed\n"); } -static u32 adreno_efuse_read_soc_hw_rev(struct platform_device *pdev) -{ - unsigned int val; - unsigned int soc_hw_rev[3]; - int ret; - - if (of_property_read_u32_array(pdev->dev.of_node, - "qcom,soc-hw-rev-efuse", soc_hw_rev, 3)) - return 0; - - ret = adreno_efuse_map(pdev); - if (ret) { - dev_err(&pdev->dev, - "Unable to map hardware revision fuse: ret=%d\n", ret); - return 0; - } - - ret = adreno_efuse_read_u32(soc_hw_rev[0], &val); - adreno_efuse_unmap(); - - if (ret) { - dev_err(&pdev->dev, - "Unable to read hardware revision fuse: ret=%d\n", ret); - return 0; - } - - return (val >> soc_hw_rev[1]) & soc_hw_rev[2]; -} - -static bool adreno_is_gpu_disabled(struct adreno_device *adreno_dev) +static bool adreno_is_gpu_disabled(struct platform_device *pdev) { unsigned int row0; unsigned int pte_row0_msb[3]; int ret; - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - if (of_property_read_u32_array(device->pdev->dev.of_node, + if (of_property_read_u32_array(pdev->dev.of_node, "qcom,gpu-disable-fuse", pte_row0_msb, 3)) return false; /* * Read the fuse value to disable GPU driver if fuse * is blown. By default(fuse value is 0) GPU is enabled. */ - if (adreno_efuse_map(device->pdev)) + if (adreno_efuse_map(pdev)) return false; ret = adreno_efuse_read_u32(pte_row0_msb[0], &row0); @@ -1278,8 +1271,6 @@ static void adreno_setup_device(struct adreno_device *adreno_dev) { u32 i; - memset(adreno_dev, 0, sizeof(*adreno_dev)); - adreno_dev->dev.name = "kgsl-3d0"; adreno_dev->dev.ftbl = &adreno_functable; @@ -1310,35 +1301,23 @@ static void adreno_setup_device(struct adreno_device *adreno_dev) } } -static int adreno_bind(struct device *dev) +int adreno_device_probe(struct platform_device *pdev, + struct adreno_device *adreno_dev) { - struct platform_device *pdev = to_platform_device(dev); - struct adreno_device *adreno_dev; - struct kgsl_device *device; - int status; + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct device *dev = &pdev->dev; unsigned int priv = 0; - u32 size, hwrev; - - adreno_dev = (struct adreno_device *) of_device_get_match_data(dev); + int status; + u32 size; /* Initialize the adreno device structure */ adreno_setup_device(adreno_dev); - device = KGSL_DEVICE(adreno_dev); - dev_set_drvdata(dev, device); device->pdev = pdev; - if (adreno_is_gpu_disabled(adreno_dev)) { - dev_err(&pdev->dev, "adreno: GPU is disabled on this device\n"); - return -ENODEV; - } - - /* Identify SOC hardware revision to be used */ - hwrev = adreno_efuse_read_soc_hw_rev(pdev); - - adreno_update_soc_hw_revision_quirks(adreno_dev, pdev, hwrev); + adreno_update_soc_hw_revision_quirks(adreno_dev, pdev); status = adreno_read_speed_bin(pdev); if (status < 0) @@ -1346,10 +1325,6 @@ static int adreno_bind(struct device *dev) device->speed_bin = status; - /* Get the chip ID from the DT and set up target specific parameters */ - if (adreno_identify_gpu(pdev, adreno_dev)) - return -ENODEV; - status = adreno_of_get_power(adreno_dev, pdev); if (status) return status; @@ -1478,6 +1453,52 @@ err: return status; } +int adreno_target_probe(struct platform_device *pdev, + u32 chipid, const struct adreno_gpu_core *gpucore) +{ + struct adreno_device *adreno_dev = &device_3d0; + struct adreno_gpudev *gpudev = gpucore->gpudev; + int i; + + memset(adreno_dev, 0, sizeof(*adreno_dev)); + + adreno_dev->gpucore = gpucore; + adreno_dev->chipid = chipid; + + /* + * 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 (!gpudev->reg_offsets[i]) + gpudev->reg_offsets[i] = ADRENO_REG_UNUSED; + } + + /* Do target specific identification */ + if (gpudev->platform_setup) + gpudev->platform_setup(adreno_dev); + + return adreno_device_probe(pdev, adreno_dev); +} + +static int adreno_bind(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + const struct adreno_gpu_core *gpucore; + u32 chipid; + + if (adreno_is_gpu_disabled(pdev)) { + dev_err(&pdev->dev, "adreno: GPU is disabled on this device\n"); + return -ENODEV; + } + + gpucore = adreno_identify_gpu(pdev, &chipid); + if (IS_ERR(gpucore)) + return PTR_ERR(gpucore); + + return gpucore->gpudev->probe(pdev, chipid, gpucore); +} + static void _adreno_free_memories(struct adreno_device *adreno_dev) { struct adreno_firmware *pfp_fw = ADRENO_FW(adreno_dev, ADRENO_FW_PFP); @@ -1500,9 +1521,11 @@ static void adreno_unbind(struct device *dev) struct kgsl_device *device; struct adreno_gpudev *gpudev; - adreno_dev = (struct adreno_device *) of_device_get_match_data(dev); + device = dev_get_drvdata(dev); + if (!device) + return; - device = KGSL_DEVICE(adreno_dev); + adreno_dev = ADRENO_DEVICE(device); gpudev = ADRENO_GPU_DEVICE(adreno_dev); if (gpudev->remove != NULL) diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 912224ca6057..212adbe1609d 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -746,6 +746,8 @@ 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); @@ -1706,4 +1708,33 @@ 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_target_probe - Helper function for target specific probe + * @pdev: Pointer to the platform device + * @chipid: Chipid for the target + * @gpucore: Pointer to the GPU core definition for this target + * + * This is a generic probe function for targets that don't need any special + * setup. This function sets up the reg_offsets and platform setup and then + * calls the generic device probe. + * + * Return: 0 on success or negative on failure + */ +int adreno_target_probe(struct platform_device *pdev, + u32 chipid, const struct adreno_gpu_core *gpucore); + #endif /*__ADRENO_H */ diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c index 898bf3091515..85fb7f7a3899 100644 --- a/drivers/gpu/msm/adreno_a3xx.c +++ b/drivers/gpu/msm/adreno_a3xx.c @@ -1406,6 +1406,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, + .probe = adreno_target_probe, .platform_setup = a3xx_platform_setup, .rb_start = a3xx_rb_start, .init = a3xx_init, diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c index 36f5e2ff21f3..91f541ac45b0 100644 --- a/drivers/gpu/msm/adreno_a5xx.c +++ b/drivers/gpu/msm/adreno_a5xx.c @@ -2970,6 +2970,7 @@ struct adreno_gpudev adreno_a5xx_gpudev = { #ifdef CONFIG_QCOM_KGSL_CORESIGHT .coresight = {&a5xx_coresight}, #endif + .probe = adreno_target_probe, .start = a5xx_start, .snapshot = a5xx_snapshot, .platform_setup = a5xx_platform_setup, diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index 786a89f68879..dc07e117f06d 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -2635,6 +2635,7 @@ u64 a6xx_read_alwayson(struct adreno_device *adreno_dev) struct adreno_gpudev adreno_a6xx_gpudev = { .reg_offsets = a6xx_register_offsets, + .probe = adreno_target_probe, .start = a6xx_start, .snapshot = a6xx_snapshot, .platform_setup = a6xx_platform_setup, From 2561b2928e5a3abd663a18a7b77c62283fdf757d Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Wed, 1 Apr 2020 12:52:23 -0600 Subject: [PATCH 02/30] msm: kgsl: Add a3xx probe function Add a target specific function for a3xx probe and create a helper function to set up the register offset array. Change-Id: Ic0dedbad2f8f54ee2635da3cb8256fce531ab8dd Signed-off-by: Jordan Crouse --- drivers/gpu/msm/adreno.c | 10 +--------- drivers/gpu/msm/adreno.h | 22 ++++++++++++++++++++++ drivers/gpu/msm/adreno_a3xx.c | 21 ++++++++++++++++++--- 3 files changed, 41 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 33d82b7dcbb9..144f00cccbef 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -1458,21 +1458,13 @@ int adreno_target_probe(struct platform_device *pdev, { struct adreno_device *adreno_dev = &device_3d0; struct adreno_gpudev *gpudev = gpucore->gpudev; - int i; memset(adreno_dev, 0, sizeof(*adreno_dev)); adreno_dev->gpucore = gpucore; adreno_dev->chipid = chipid; - /* - * 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 (!gpudev->reg_offsets[i]) - gpudev->reg_offsets[i] = ADRENO_REG_UNUSED; - } + adreno_reg_offset_init(gpudev->reg_offsets); /* Do target specific identification */ if (gpudev->platform_setup) diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 212adbe1609d..2d76c90debcc 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -1662,6 +1662,28 @@ static inline bool adreno_move_preempt_state(struct adreno_device *adreno_dev, return (atomic_cmpxchg(&adreno_dev->preempt.state, old, new) == old); } +/** + * 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; + } +} + + void adreno_gmu_clear_and_unmask_irqs(struct adreno_device *adreno_dev); void adreno_gmu_mask_and_clear_irqs(struct adreno_device *adreno_dev); int adreno_gmu_fenced_write(struct adreno_device *adreno_dev, diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c index 85fb7f7a3899..65f030557ca6 100644 --- a/drivers/gpu/msm/adreno_a3xx.c +++ b/drivers/gpu/msm/adreno_a3xx.c @@ -5,6 +5,7 @@ #include #include +#include #include #include "adreno.h" @@ -567,10 +568,25 @@ 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; + + 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; + + return adreno_device_probe(pdev, adreno_dev); } static int a3xx_send_me_init(struct adreno_device *adreno_dev, @@ -1406,8 +1422,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, - .probe = adreno_target_probe, - .platform_setup = a3xx_platform_setup, + .probe = a3xx_probe, .rb_start = a3xx_rb_start, .init = a3xx_init, .microcode_read = a3xx_microcode_read, From f86d4770a87698fb3fb754cb43cd19ee8bee57fd Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Wed, 1 Apr 2020 13:32:44 -0600 Subject: [PATCH 03/30] msm: kgsl: Add a5xx probe function Add the a5xx specific probe function. Change-Id: Ic0dedbad38737fdea9e6f34dd791200e9e477ca7 Signed-off-by: Jordan Crouse --- drivers/gpu/msm/adreno_a5xx.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c index 91f541ac45b0..2b9f43daeb96 100644 --- a/drivers/gpu/msm/adreno_a5xx.c +++ b/drivers/gpu/msm/adreno_a5xx.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -87,8 +88,21 @@ 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; + + 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 +121,8 @@ static void a5xx_platform_setup(struct adreno_device *adreno_dev) if (adreno_is_a530(adreno_dev)) a530_efuse_leakage(adreno_dev); + + return adreno_device_probe(pdev, adreno_dev); } static void _do_fixup(const struct adreno_critical_fixup *fixups, int count, @@ -2970,10 +2986,9 @@ struct adreno_gpudev adreno_a5xx_gpudev = { #ifdef CONFIG_QCOM_KGSL_CORESIGHT .coresight = {&a5xx_coresight}, #endif - .probe = adreno_target_probe, + .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, From 4d0eb9d995c106d4a213178fb7c96ad5a885f1f0 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Wed, 1 Apr 2020 13:35:51 -0600 Subject: [PATCH 04/30] msm: kgsl: Add a6xx probe function Add the a6xx specific probe function. With this we no longer need the generic helper nor the platform_setup function so they can be removed. Change-Id: Ic0dedbadd317f8489f8451541dbb77a76c925719 Signed-off-by: Jordan Crouse --- drivers/gpu/msm/adreno.c | 20 -------------------- drivers/gpu/msm/adreno.h | 16 ---------------- drivers/gpu/msm/adreno_a6xx.c | 22 ++++++++++++++++++---- 3 files changed, 18 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 144f00cccbef..2fc4c0563fed 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -1453,26 +1453,6 @@ err: return status; } -int adreno_target_probe(struct platform_device *pdev, - u32 chipid, const struct adreno_gpu_core *gpucore) -{ - struct adreno_device *adreno_dev = &device_3d0; - struct adreno_gpudev *gpudev = gpucore->gpudev; - - memset(adreno_dev, 0, sizeof(*adreno_dev)); - - adreno_dev->gpucore = gpucore; - adreno_dev->chipid = chipid; - - adreno_reg_offset_init(gpudev->reg_offsets); - - /* Do target specific identification */ - if (gpudev->platform_setup) - gpudev->platform_setup(adreno_dev); - - return adreno_device_probe(pdev, adreno_dev); -} - static int adreno_bind(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 2d76c90debcc..1ddec025e572 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -750,7 +750,6 @@ struct adreno_gpudev { 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); @@ -1744,19 +1743,4 @@ irqreturn_t adreno_irq_callbacks(struct adreno_device *adreno_dev, int adreno_device_probe(struct platform_device *pdev, struct adreno_device *adreno_dev); -/** - * adreno_target_probe - Helper function for target specific probe - * @pdev: Pointer to the platform device - * @chipid: Chipid for the target - * @gpucore: Pointer to the GPU core definition for this target - * - * This is a generic probe function for targets that don't need any special - * setup. This function sets up the reg_offsets and platform setup and then - * calls the generic device probe. - * - * Return: 0 on success or negative on failure - */ -int adreno_target_probe(struct platform_device *pdev, - u32 chipid, const struct adreno_gpu_core *gpucore); - #endif /*__ADRENO_H */ diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index dc07e117f06d..ebcd7d4e9425 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -5,6 +5,7 @@ #include #include +#include #include #include "adreno.h" @@ -2333,9 +2334,21 @@ static struct adreno_perfcounters a6xx_perfcounters = { ARRAY_SIZE(a6xx_perfcounter_groups), }; -static void a6xx_platform_setup(struct adreno_device *adreno_dev) +static int a6xx_probe(struct platform_device *pdev, + u32 chipid, const struct adreno_gpu_core *gpucore) { - struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); + struct adreno_device *adreno_dev; + struct adreno_gpudev *gpudev = gpucore->gpudev; + + 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(gpudev->reg_offsets); adreno_dev->hwcg_enabled = true; @@ -2372,6 +2385,8 @@ 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); } @@ -2635,10 +2650,9 @@ u64 a6xx_read_alwayson(struct adreno_device *adreno_dev) struct adreno_gpudev adreno_a6xx_gpudev = { .reg_offsets = a6xx_register_offsets, - .probe = adreno_target_probe, + .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, From 3c09b03d0cf7e6c0780002b1c6581c704c10c16b Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Wed, 1 Apr 2020 14:56:26 -0600 Subject: [PATCH 05/30] msm: kgsl: Remove gmu_core_regulator_isenabled() Commit 0d44684cabc0 ("msm: kgsl: Take GMU snapshot on GMU failures") removed the only usage of gmu_core_regulator_isenabled(). Change-Id: Ic0dedbadb40e1faed4a9e0629e9d0babb718f6b3 Signed-off-by: Jordan Crouse --- drivers/gpu/msm/kgsl_gmu.c | 8 -------- drivers/gpu/msm/kgsl_gmu_core.c | 10 ---------- drivers/gpu/msm/kgsl_gmu_core.h | 2 -- drivers/gpu/msm/kgsl_rgmu.c | 8 -------- 4 files changed, 28 deletions(-) diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c index 9a833f301da9..d6316cf3b9fd 100644 --- a/drivers/gpu/msm/kgsl_gmu.c +++ b/drivers/gpu/msm/kgsl_gmu.c @@ -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, }; diff --git a/drivers/gpu/msm/kgsl_gmu_core.c b/drivers/gpu/msm/kgsl_gmu_core.c index 87df810bd63a..0ebb4f09ed13 100644 --- a/drivers/gpu/msm/kgsl_gmu_core.c +++ b/drivers/gpu/msm/kgsl_gmu_core.c @@ -131,16 +131,6 @@ int gmu_core_acd_set(struct kgsl_device *device, bool 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) { diff --git a/drivers/gpu/msm/kgsl_gmu_core.h b/drivers/gpu/msm/kgsl_gmu_core.h index b35e573c9be2..a2c86409eae8 100644 --- a/drivers/gpu/msm/kgsl_gmu_core.h +++ b/drivers/gpu/msm/kgsl_gmu_core.h @@ -107,7 +107,6 @@ struct gmu_core_ops { 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); }; @@ -181,7 +180,6 @@ 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); bool gmu_core_is_register_offset(struct kgsl_device *device, unsigned int offsetwords); void gmu_core_regread(struct kgsl_device *device, unsigned int offsetwords, diff --git a/drivers/gpu/msm/kgsl_rgmu.c b/drivers/gpu/msm/kgsl_rgmu.c index dcd4f679769c..f8610129aef9 100644 --- a/drivers/gpu/msm/kgsl_rgmu.c +++ b/drivers/gpu/msm/kgsl_rgmu.c @@ -399,13 +399,6 @@ static int rgmu_dcvs_set(struct kgsl_device *device, 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); @@ -419,7 +412,6 @@ static struct gmu_core_ops rgmu_ops = { .stop = rgmu_stop, .dcvs_set = rgmu_dcvs_set, .snapshot = rgmu_snapshot, - .regulator_isenabled = rgmu_regulator_isenabled, .suspend = rgmu_suspend, }; From c359b1dd27719aad182c36a35d6e411af6ddb026 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Wed, 27 May 2020 10:38:28 -0600 Subject: [PATCH 06/30] msm: kgsl: Make all GMU code target specific Move all the GMU code to a6xx target specific code. This is the first in several steps to make the GMU code more modular and flexibile for various usecases. Change-Id: Ic0dedbad0e70771c301705a0eb4ed422efb4c80a Signed-off-by: Jordan Crouse --- drivers/gpu/msm/Makefile | 1 - drivers/gpu/msm/adreno.h | 1 - drivers/gpu/msm/adreno_a6xx.c | 2 - drivers/gpu/msm/adreno_a6xx_gmu.c | 1769 ++++++++++++++++++++++++++++- drivers/gpu/msm/kgsl_bus.c | 5 +- drivers/gpu/msm/kgsl_gmu.h | 11 +- drivers/gpu/msm/kgsl_gmu_core.c | 2 +- drivers/gpu/msm/kgsl_gmu_core.h | 2 +- 8 files changed, 1756 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile index 4c3f64d41c97..6c9de9394c2c 100644 --- a/drivers/gpu/msm/Makefile +++ b/drivers/gpu/msm/Makefile @@ -9,7 +9,6 @@ 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 \ diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 1ddec025e572..1d5bacb851c5 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -667,7 +667,6 @@ enum adreno_regs { 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, diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index ebcd7d4e9425..b3be11b8d414 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -2486,8 +2486,6 @@ static unsigned int a6xx_register_offsets[ADRENO_REG_REGISTER_MAX] = { 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, diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index 84398b5a4618..ae5640f30caa 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -3,18 +3,64 @@ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ -/* soc/qcom/cmd-db.h needs types.h */ +#include +#include +#include +#include #include +#include #include -#include +#include +#include #include +#include #include +#include #include "adreno.h" #include "adreno_a6xx.h" #include "adreno_snapshot.h" +#include "kgsl_bus.h" +#include "kgsl_device.h" #include "kgsl_gmu.h" #include "kgsl_trace.h" +#include "kgsl_util.h" + +struct gmu_iommu_context { + const char *name; + struct platform_device *pdev; + struct iommu_domain *domain; +}; + +struct gmu_vma_entry { + unsigned int start; + unsigned int size; +}; + +static const struct gmu_vma_entry a6xx_gmu_vma_legacy[] = { + [GMU_ITCM] = { .start = 0x00000, .size = SZ_16K }, + [GMU_ICACHE] = { .start = 0x04000, .size = (SZ_256K - SZ_16K) }, + [GMU_DTCM] = { .start = 0x40000, .size = SZ_16K }, + [GMU_DCACHE] = { .start = 0x44000, .size = (SZ_256K - SZ_16K) }, + [GMU_NONCACHED_KERNEL] = { .start = 0x60000000, .size = SZ_512M }, + [GMU_NONCACHED_USER] = { .start = 0x80000000, .size = SZ_1G }, + [GMU_MEM_TYPE_MAX] = { .start = 0x0, .size = 0x0 }, +}; + +static const struct gmu_vma_entry a6xx_gmu_vma[] = { + [GMU_ITCM] = { .start = 0x00000000, .size = SZ_16K }, + [GMU_CACHE] = { .start = SZ_16K, .size = (SZ_16M - SZ_16K) }, + [GMU_DTCM] = { .start = SZ_256M + SZ_16K, .size = SZ_16K }, + [GMU_DCACHE] = { .start = 0x0, .size = 0x0 }, + [GMU_NONCACHED_KERNEL] = { .start = 0x60000000, .size = SZ_512M }, + [GMU_NONCACHED_USER] = { .start = 0x80000000, .size = SZ_1G }, + [GMU_MEM_TYPE_MAX] = { .start = 0x0, .size = 0x0 }, +}; + +static struct gmu_iommu_context a6xx_gmu_ctx[] = { + [GMU_CONTEXT_USER] = { .name = "gmu_user" }, + [GMU_CONTEXT_KERNEL] = { .name = "gmu_kernel" } +}; static const unsigned int a6xx_gmu_gx_registers[] = { /* GMU GX */ @@ -365,11 +411,7 @@ static void a6xx_gmu_power_config(struct kgsl_device *device) RPMH_ENABLE_MASK); } -/* - * a6xx_gmu_start() - Start GMU and wait until FW boot up. - * @device: Pointer to KGSL device - */ -static int a6xx_gmu_start(struct kgsl_device *device) +static int a6xx_gmu_device_start(struct kgsl_device *device) { struct gmu_device *gmu = KGSL_GMU_DEVICE(device); u32 val = 0x00000100; @@ -540,6 +582,26 @@ static int _load_legacy_gmu_fw(struct kgsl_device *device, return 0; } +static struct gmu_memdesc *a6xx_gmu_get_memdesc(struct gmu_device *gmu, + unsigned int addr, unsigned int size) +{ + int i; + struct gmu_memdesc *mem; + + for (i = 0; i < GMU_KERNEL_ENTRIES; i++) { + if (!test_bit(i, &gmu->kmem_bitmap)) + continue; + + mem = &gmu->kmem_entries[i]; + + if (addr >= mem->gmuaddr && + (addr + size <= mem->gmuaddr + mem->size)) + return mem; + } + + return NULL; +} + static int load_gmu_fw(struct kgsl_device *device) { struct gmu_device *gmu = KGSL_GMU_DEVICE(device); @@ -560,7 +622,7 @@ static int load_gmu_fw(struct kgsl_device *device) if (blk->size == 0) continue; - md = gmu_get_memdesc(gmu, blk->addr, blk->size); + md = a6xx_gmu_get_memdesc(gmu, blk->addr, blk->size); if (md == NULL) { dev_err(&gmu->pdev->dev, "No backing memory for 0x%8.8X\n", @@ -1045,6 +1107,16 @@ static void load_gmu_version_info(struct kgsl_device *device) &gmu->ver.hfi); } +static void a6xx_gmu_mem_free(struct gmu_device *gmu, + struct gmu_memdesc *md) +{ + /* Free GMU image memory */ + if (md->hostptr) + dma_free_attrs(&gmu->pdev->dev, (size_t) md->size, + (void *)md->hostptr, md->physaddr, 0); + memset(md, 0, sizeof(*md)); +} + /* * a6xx_gmu_fw_start() - set up GMU and start FW * @device: Pointer to KGSL device @@ -1157,7 +1229,7 @@ static int a6xx_gmu_fw_start(struct kgsl_device *device, /* Clear any previously set cm3 fault */ atomic_set(&gmu->cm3_fault, 0); - ret = a6xx_gmu_start(device); + ret = a6xx_gmu_device_start(device); if (ret) return ret; @@ -1184,6 +1256,221 @@ static int a6xx_gmu_fw_start(struct kgsl_device *device, return ret; } +static int a6xx_gmu_alloc_and_map(struct gmu_device *gmu, + struct gmu_memdesc *md, unsigned int attrs) +{ + struct iommu_domain *domain = a6xx_gmu_ctx[md->ctx_idx].domain; + int ret; + + md->hostptr = dma_alloc_attrs(&gmu->pdev->dev, (size_t) md->size, + &md->physaddr, GFP_KERNEL, 0); + + if (md->hostptr == NULL) + return -ENOMEM; + + ret = iommu_map(domain, md->gmuaddr, md->physaddr, md->size, + attrs); + + if (ret) { + dev_err(&gmu->pdev->dev, + "gmu map err: gaddr=0x%016llX, paddr=0x%pa\n", + md->gmuaddr, &(md->physaddr)); + a6xx_gmu_mem_free(gmu, md); + } + + return ret; +} + +/* + * There are a few static memory buffers that are allocated and mapped at boot + * time for GMU to function. The buffers are permanent (not freed) after + * GPU boot. The size of the buffers are constant and not expected to change. + * + * We define an array and a simple allocator to keep track of the currently + * active SMMU entries of GMU kernel mode context. Each entry is assigned + * a unique address inside GMU kernel mode address range. + */ +static struct gmu_memdesc *a6xx_gmu_kmem_allocate(struct gmu_device *gmu, + enum gmu_mem_type mem_type, unsigned int addr, + unsigned int size, unsigned int attrs) +{ + static unsigned int next_uncached_kernel_alloc; + static unsigned int next_uncached_user_alloc; + + struct gmu_memdesc *md; + int ret; + int entry_idx = find_first_zero_bit( + &gmu->kmem_bitmap, GMU_KERNEL_ENTRIES); + + if (entry_idx >= GMU_KERNEL_ENTRIES) { + dev_err(&gmu->pdev->dev, + "Ran out of GMU kernel mempool slots\n"); + return ERR_PTR(-EINVAL); + } + + /* Non-TCM requests have page alignment requirement */ + if ((mem_type != GMU_ITCM) && (mem_type != GMU_DTCM) && + addr & (PAGE_SIZE - 1)) { + dev_err(&gmu->pdev->dev, + "Invalid alignment request 0x%X\n", + addr); + return ERR_PTR(-EINVAL); + } + + md = &gmu->kmem_entries[entry_idx]; + set_bit(entry_idx, &gmu->kmem_bitmap); + + memset(md, 0, sizeof(*md)); + + switch (mem_type) { + case GMU_ITCM: + case GMU_DTCM: + /* Assign values and return without mapping */ + md->size = size; + md->mem_type = mem_type; + md->gmuaddr = addr; + return md; + + case GMU_DCACHE: + case GMU_ICACHE: + md->ctx_idx = GMU_CONTEXT_KERNEL; + size = PAGE_ALIGN(size); + break; + + case GMU_NONCACHED_KERNEL: + /* Set start address for first uncached kernel alloc */ + if (next_uncached_kernel_alloc == 0) + next_uncached_kernel_alloc = gmu->vma[mem_type].start; + + if (addr == 0) + addr = next_uncached_kernel_alloc; + + md->ctx_idx = GMU_CONTEXT_KERNEL; + size = PAGE_ALIGN(size); + break; + case GMU_NONCACHED_USER: + /* Set start address for first uncached kernel alloc */ + if (next_uncached_user_alloc == 0) + next_uncached_user_alloc = gmu->vma[mem_type].start; + + if (addr == 0) + addr = next_uncached_user_alloc; + + md->ctx_idx = GMU_CONTEXT_USER; + size = PAGE_ALIGN(size); + break; + + default: + dev_err(&gmu->pdev->dev, + "Invalid memory type (%d) requested\n", + mem_type); + clear_bit(entry_idx, &gmu->kmem_bitmap); + return ERR_PTR(-EINVAL); + } + + md->size = size; + md->mem_type = mem_type; + md->gmuaddr = addr; + + ret = a6xx_gmu_alloc_and_map(gmu, md, attrs); + if (ret) { + clear_bit(entry_idx, &gmu->kmem_bitmap); + return ERR_PTR(ret); + } + + if (mem_type == GMU_NONCACHED_KERNEL) + next_uncached_kernel_alloc = PAGE_ALIGN(md->gmuaddr + md->size); + if (mem_type == GMU_NONCACHED_USER) + next_uncached_user_alloc = PAGE_ALIGN(md->gmuaddr + md->size); + + return md; +} + + +static int a6xx_gmu_cache_finalize(struct adreno_device *adreno_dev, + struct gmu_device *gmu) +{ + struct gmu_memdesc *md; + + /* Preallocations were made so no need to request all this memory */ + if (gmu->preallocations) + return 0; + + md = a6xx_gmu_kmem_allocate(gmu, GMU_ICACHE, + gmu->vma[GMU_ICACHE].start, gmu->vma[GMU_ICACHE].size, + (IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV)); + if (IS_ERR(md)) + return PTR_ERR(md); + + if (!adreno_is_a650_family(adreno_dev)) { + md = a6xx_gmu_kmem_allocate(gmu, GMU_DCACHE, + gmu->vma[GMU_DCACHE].start, + gmu->vma[GMU_DCACHE].size, + (IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV)); + if (IS_ERR(md)) + return PTR_ERR(md); + } + + md = a6xx_gmu_kmem_allocate(gmu, GMU_NONCACHED_KERNEL, + 0, SZ_4K, (IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV)); + if (IS_ERR(md)) + return PTR_ERR(md); + + if (ADRENO_FEATURE(adreno_dev, ADRENO_ECP)) { + /* Allocation to account for future MEM_ALLOC buffers */ + md = a6xx_gmu_kmem_allocate(gmu, GMU_NONCACHED_KERNEL, + 0, SZ_32K, + (IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV)); + if (IS_ERR(md)) + return PTR_ERR(md); + } + + gmu->preallocations = true; + + return 0; +} + +static enum gmu_mem_type a6xx_gmu_get_blk_memtype(struct gmu_device *gmu, + struct gmu_block_header *blk) +{ + int i; + + for (i = 0; i < GMU_MEM_TYPE_MAX; i++) { + if (blk->addr >= gmu->vma[i].start && + blk->addr + blk->value <= + gmu->vma[i].start + gmu->vma[i].size) + return (enum gmu_mem_type)i; + } + + return GMU_MEM_TYPE_MAX; +} + +static int a6xx_gmu_prealloc_req(struct gmu_device *gmu, + struct gmu_block_header *blk) +{ + enum gmu_mem_type type; + struct gmu_memdesc *md; + + /* Check to see if this memdesc is already around */ + md = a6xx_gmu_get_memdesc(gmu, blk->addr, blk->value); + if (md) + return 0; + + type = a6xx_gmu_get_blk_memtype(gmu, blk); + if (type >= GMU_MEM_TYPE_MAX) + return -EINVAL; + + md = a6xx_gmu_kmem_allocate(gmu, type, blk->addr, blk->value, + (IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV)); + if (IS_ERR(md)) + return PTR_ERR(md); + + gmu->preallocations = true; + + return 0; +} + + /* * a6xx_gmu_load_firmware() - Load the ucode into the GPMU RAM & PDC/RSC * @device: Pointer to KGSL device @@ -1232,14 +1519,61 @@ static int a6xx_gmu_load_firmware(struct kgsl_device *device) if (blk->type == GMU_BLK_TYPE_PREALLOC_REQ || blk->type == GMU_BLK_TYPE_PREALLOC_PERSIST_REQ) - ret = gmu_prealloc_req(device, blk); + ret = a6xx_gmu_prealloc_req(gmu, blk); if (ret) return ret; } /* Request any other cache ranges that might be required */ - return gmu_cache_finalize(device); + return a6xx_gmu_cache_finalize(adreno_dev, gmu); +} + +static int a6xx_gmu_memory_probe(struct adreno_device *adreno_dev, + struct gmu_device *gmu) +{ + /* Allocates & maps memory for HFI */ + if (IS_ERR_OR_NULL(gmu->hfi_mem)) + gmu->hfi_mem = a6xx_gmu_kmem_allocate(gmu, + GMU_NONCACHED_KERNEL, 0, + HFIMEM_SIZE, (IOMMU_READ | IOMMU_WRITE)); + if (IS_ERR(gmu->hfi_mem)) + return PTR_ERR(gmu->hfi_mem); + + /* Allocates & maps GMU crash dump memory */ + if (adreno_is_a630(adreno_dev) || adreno_is_a615_family(adreno_dev)) { + if (IS_ERR_OR_NULL(gmu->dump_mem)) + gmu->dump_mem = a6xx_gmu_kmem_allocate(gmu, + GMU_NONCACHED_KERNEL, 0, SZ_16K, + (IOMMU_READ | IOMMU_WRITE)); + if (IS_ERR(gmu->dump_mem)) + return PTR_ERR(gmu->dump_mem); + } + + /* GMU master log */ + if (IS_ERR_OR_NULL(gmu->gmu_log)) + gmu->gmu_log = a6xx_gmu_kmem_allocate(gmu, + GMU_NONCACHED_KERNEL, 0, + SZ_4K, (IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV)); + return PTR_ERR_OR_ZERO(gmu->gmu_log); +} + +static int a6xx_gmu_init(struct kgsl_device *device) +{ + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + int ret; + + ret = a6xx_gmu_load_firmware(device); + if (ret) + return ret; + + ret = a6xx_gmu_memory_probe(ADRENO_DEVICE(device), gmu); + if (ret) + return ret; + + hfi_init(gmu); + + return 0; } #define A6XX_VBIF_XIN_HALT_CTRL1_ACKS (BIT(0) | BIT(1) | BIT(2) | BIT(3)) @@ -1278,7 +1612,7 @@ static void do_gbif_halt(struct kgsl_device *device, u32 reg, u32 ack_reg, dev_err(device->dev, "%s GBIF halt timed out\n", client); } -static int a6xx_gmu_suspend(struct kgsl_device *device) +static int a6xx_gmu_pwrctrl_suspend(struct kgsl_device *device) { int ret = 0; struct gmu_device *gmu = KGSL_GMU_DEVICE(device); @@ -1410,7 +1744,7 @@ out: } /* - * a6xx_rpmh_gpu_pwrctrl() - GPU power control via RPMh/GMU interface + * a6xx_gmu_rpmh_gpu_pwrctrl() - GPU power control via RPMh/GMU interface * @adreno_dev: Pointer to adreno device * @mode: requested power mode * @arg1: first argument for mode control @@ -1428,7 +1762,7 @@ static int a6xx_gmu_rpmh_gpu_pwrctrl(struct kgsl_device *device, ret = a6xx_gmu_fw_start(device, arg1); break; case GMU_SUSPEND: - ret = a6xx_gmu_suspend(device); + ret = a6xx_gmu_pwrctrl_suspend(device); break; case GMU_FW_STOP: if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) @@ -1451,6 +1785,113 @@ static int a6xx_gmu_rpmh_gpu_pwrctrl(struct kgsl_device *device, return ret; } +static int a6xx_gmu_suspend(struct kgsl_device *device) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + + if (!test_bit(GMU_CLK_ON, &device->gmu_core.flags)) + return 0; + + /* Pending message in all queues are abandoned */ + a6xx_gmu_irq_disable(device); + hfi_stop(gmu); + + if (a6xx_gmu_rpmh_gpu_pwrctrl(device, GMU_SUSPEND, 0, 0)) + return -EINVAL; + + clk_bulk_disable_unprepare(gmu->num_clks, gmu->clks); + clear_bit(GMU_CLK_ON, &device->gmu_core.flags); + + if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_CX_GDSC)) + regulator_set_mode(gmu->cx_gdsc, REGULATOR_MODE_IDLE); + + if (!kgsl_regulator_disable_wait(gmu->cx_gdsc, 5000)) + dev_err(&gmu->pdev->dev, "GMU CX gdsc off timeout\n"); + + if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_CX_GDSC)) + regulator_set_mode(gmu->cx_gdsc, REGULATOR_MODE_NORMAL); + + dev_err(&gmu->pdev->dev, "Suspended GMU\n"); + + clear_bit(GMU_FAULT, &device->gmu_core.flags); + + return 0; +} + +static void a6xx_gmu_snapshot(struct kgsl_device *device); + +static int a6xx_gmu_dcvs_set(struct kgsl_device *device, + int gpu_pwrlevel, int bus_level) +{ + int ret = 0; + struct kgsl_pwrctrl *pwr = &device->pwrctrl; + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct hfi_gx_bw_perf_vote_cmd req = { + .ack_type = DCVS_ACK_BLOCK, + .freq = INVALID_DCVS_IDX, + .bw = INVALID_DCVS_IDX, + }; + + /* If GMU has not been started, save it */ + if (!test_bit(GMU_HFI_ON, &device->gmu_core.flags)) { + /* store clock change request */ + set_bit(GMU_DCVS_REPLAY, &device->gmu_core.flags); + return 0; + } + + /* Do not set to XO and lower GPU clock vote from GMU */ + if ((gpu_pwrlevel != INVALID_DCVS_IDX) && + (gpu_pwrlevel >= gmu->num_gpupwrlevels - 1)) + return -EINVAL; + + if (gpu_pwrlevel < gmu->num_gpupwrlevels - 1) + req.freq = gmu->num_gpupwrlevels - gpu_pwrlevel - 1; + + if (bus_level < pwr->ddr_table_count && bus_level > 0) + req.bw = bus_level; + + /* GMU will vote for slumber levels through the sleep sequence */ + if ((req.freq == INVALID_DCVS_IDX) && + (req.bw == INVALID_DCVS_IDX)) { + clear_bit(GMU_DCVS_REPLAY, &device->gmu_core.flags); + return 0; + } + + if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) + ret = a6xx_gmu_rpmh_gpu_pwrctrl(device, + GMU_DCVS_NOHFI, req.freq, req.bw); + else if (test_bit(GMU_HFI_ON, &device->gmu_core.flags)) + ret = hfi_send_req(gmu, H2F_MSG_GX_BW_PERF_VOTE, &req); + + if (ret) { + dev_err_ratelimited(&gmu->pdev->dev, + "Failed to set GPU perf idx %d, bw idx %d\n", + req.freq, req.bw); + + /* + * We can be here in two situations. First, we send a dcvs + * hfi so gmu knows at what level it must bring up the gpu. + * If that fails, it is already being handled as part of + * gmu boot failures. The other reason why we are here is + * because we are trying to scale an active gpu. For this, + * we need to do inline snapshot and dispatcher based + * recovery. + */ + if (test_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv)) { + a6xx_gmu_snapshot(device); + adreno_set_gpu_fault(adreno_dev, ADRENO_GMU_FAULT | + ADRENO_GMU_FAULT_SKIP_SNAPSHOT); + adreno_dispatcher_schedule(device); + } + } + + /* indicate actual clock change */ + clear_bit(GMU_DCVS_REPLAY, &device->gmu_core.flags); + return ret; +} + static void a6xx_gmu_enable_lm(struct kgsl_device *device) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); @@ -1572,6 +2013,7 @@ struct a6xx_tcm_data { static size_t a6xx_snapshot_gmu_tcm(struct kgsl_device *device, u8 *buf, size_t remain, void *priv) { + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); struct kgsl_snapshot_gmu_mem *mem_hdr = (struct kgsl_snapshot_gmu_mem *)buf; unsigned int *data = (unsigned int *)(buf + sizeof(*mem_hdr)); @@ -1587,8 +2029,7 @@ static size_t a6xx_snapshot_gmu_tcm(struct kgsl_device *device, mem_hdr->type = SNAPSHOT_GMU_MEM_BIN_BLOCK; mem_hdr->hostaddr = 0; - mem_hdr->gmuaddr = gmu_get_memtype_base(KGSL_GMU_DEVICE(device), - tcm->type); + mem_hdr->gmuaddr = gmu->vma[tcm->type].start; mem_hdr->gpuaddr = 0; for (i = tcm->start; i <= tcm->last; i++) @@ -1701,14 +2142,14 @@ static void a6xx_gmu_snapshot_versions(struct kgsl_device *device, } /* - * a6xx_gmu_snapshot() - A6XX GMU snapshot function + * 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 */ -static void a6xx_gmu_snapshot(struct kgsl_device *device, +static void a6xx_gmu_device_snapshot(struct kgsl_device *device, struct kgsl_snapshot *snapshot) { unsigned int val; @@ -1817,7 +2258,370 @@ static u64 a6xx_gmu_read_alwayson(struct kgsl_device *device) return a6xx_read_alwayson(ADRENO_DEVICE(device)); } -struct gmu_dev_ops adreno_a6xx_gmudev = { +static irqreturn_t a6xx_gmu_irq_handler(int irq, void *data) +{ + struct kgsl_device *device = data; + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + unsigned int mask, status = 0; + + gmu_core_regread(device, A6XX_GMU_AO_HOST_INTERRUPT_STATUS, &status); + gmu_core_regwrite(device, A6XX_GMU_AO_HOST_INTERRUPT_CLR, status); + + /* Ignore GMU_INT_RSCC_COMP and GMU_INT_DBD WAKEUP interrupts */ + if (status & GMU_INT_WDOG_BITE) { + /* Temporarily mask the watchdog interrupt to prevent a storm */ + gmu_core_regread(device, A6XX_GMU_AO_HOST_INTERRUPT_MASK, + &mask); + gmu_core_regwrite(device, A6XX_GMU_AO_HOST_INTERRUPT_MASK, + (mask | GMU_INT_WDOG_BITE)); + + /* make sure we're reading the latest cm3_fault */ + smp_rmb(); + + /* + * We should not send NMI if there was a CM3 fault reported + * because we don't want to overwrite the critical CM3 state + * captured by gmu before it sent the CM3 fault interrupt. + */ + if (!atomic_read(&gmu->cm3_fault)) + adreno_gmu_send_nmi(adreno_dev); + + /* + * There is sufficient delay for the GMU to have finished + * handling the NMI before snapshot is taken, as the fault + * worker is scheduled below. + */ + + dev_err_ratelimited(&gmu->pdev->dev, + "GMU watchdog expired interrupt received\n"); + } + if (status & GMU_INT_HOST_AHB_BUS_ERR) + dev_err_ratelimited(&gmu->pdev->dev, + "AHB bus error interrupt received\n"); + if (status & GMU_INT_FENCE_ERR) { + unsigned int fence_status; + + gmu_core_regread(device, A6XX_GMU_AHB_FENCE_STATUS, + &fence_status); + dev_err_ratelimited(&gmu->pdev->dev, + "FENCE error interrupt received %x\n", fence_status); + } + + if (status & ~GMU_AO_INT_MASK) + dev_err_ratelimited(&gmu->pdev->dev, + "Unhandled GMU interrupts 0x%lx\n", + status & ~GMU_AO_INT_MASK); + + return IRQ_HANDLED; +} + + +static void a6xx_gmu_snapshot(struct kgsl_device *device) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + + /* Abstain from sending another nmi or over-writing snapshot */ + if (test_and_set_bit(GMU_FAULT, &device->gmu_core.flags)) + return; + + /* make sure we're reading the latest cm3_fault */ + smp_rmb(); + + /* + * We should not send NMI if there was a CM3 fault reported because we + * don't want to overwrite the critical CM3 state captured by gmu before + * it sent the CM3 fault interrupt. + */ + if (!atomic_read(&gmu->cm3_fault)) { + adreno_gmu_send_nmi(adreno_dev); + + /* Wait for the NMI to be handled */ + udelay(100); + } + + kgsl_device_snapshot(device, NULL, true); + + gmu_core_regwrite(device, A6XX_GMU_GMU2HOST_INTR_CLR, + 0xffffffff); + gmu_core_regwrite(device, A6XX_GMU_GMU2HOST_INTR_MASK, + HFI_IRQ_MASK); + + gmu->fault_count++; +} + +/* Caller shall ensure GPU is ready for SLUMBER */ +static void a6xx_gmu_stop(struct kgsl_device *device) +{ + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct kgsl_pwrctrl *pwr = &device->pwrctrl; + int ret = 0; + + if (!test_bit(GMU_CLK_ON, &device->gmu_core.flags)) + return; + + /* Force suspend if gmu is already in fault */ + if (test_bit(GMU_FAULT, &device->gmu_core.flags)) { + a6xx_gmu_suspend(device); + return; + } + + /* Wait for the lowest idle level we requested */ + if (a6xx_gmu_wait_for_lowest_idle(device)) + goto error; + + ret = a6xx_gmu_rpmh_gpu_pwrctrl(device, + GMU_NOTIFY_SLUMBER, 0, 0); + if (ret) + goto error; + + if (a6xx_gmu_wait_for_idle(device)) + goto error; + + /* Pending message in all queues are abandoned */ + a6xx_gmu_irq_disable(device); + hfi_stop(gmu); + + a6xx_gmu_rpmh_gpu_pwrctrl(device, GMU_FW_STOP, 0, 0); + + clk_bulk_disable_unprepare(gmu->num_clks, gmu->clks); + clear_bit(GMU_CLK_ON, &device->gmu_core.flags); + + /* Pool to make sure that the CX is off */ + if (!kgsl_regulator_disable_wait(gmu->cx_gdsc, 5000)) + dev_err(&gmu->pdev->dev, "GMU CX gdsc off timeout\n"); + + icc_set_bw(pwr->icc_path, 0, 0); + return; + +error: + dev_err(&gmu->pdev->dev, "Failed to stop GMU\n"); + a6xx_gmu_snapshot(device); + /* + * We failed to stop the gmu successfully. Force a suspend + * to set things up for a fresh start. + */ + a6xx_gmu_suspend(device); +} + +static int a6xx_gmu_aop_send_acd_state(struct mbox_chan *channel, bool flag) +{ + char msg_buf[33]; + struct { + u32 len; + void *msg; + } msg; + + if (IS_ERR_OR_NULL(channel)) + return 0; + + msg.len = scnprintf(msg_buf, sizeof(msg_buf), + "{class: gpu, res: acd, value: %d}", flag); + msg.msg = msg_buf; + + return mbox_send_message(channel, &msg); +} + +static int a6xx_gmu_enable_gdsc(struct kgsl_device *device) +{ + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + int ret; + + ret = regulator_enable(gmu->cx_gdsc); + if (ret) + dev_err(&gmu->pdev->dev, + "Failed to enable GMU CX gdsc, error %d\n", ret); + + return ret; +} + +static int a6xx_gmu_clk_set_rate(struct gmu_device *gmu, const char *id, + unsigned long rate) +{ + struct clk *clk; + + clk = kgsl_of_clk_by_name(gmu->clks, gmu->num_clks, id); + if (!clk) + return -ENODEV; + + return clk_set_rate(clk, rate); +} + +static int a6xx_gmu_enable_clks(struct kgsl_device *device) +{ + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + int ret; + + ret = a6xx_gmu_clk_set_rate(gmu, "gmu_clk", GMU_FREQUENCY); + if (ret) { + dev_err(&gmu->pdev->dev, "Unable to set the GMU clock\n"); + return ret; + } + + ret = a6xx_gmu_clk_set_rate(gmu, "hub_clk", 150000000); + if (ret && ret != ENODEV) { + dev_err(&gmu->pdev->dev, "Unable to set the HUB clock\n"); + return ret; + } + + ret = clk_bulk_prepare_enable(gmu->num_clks, gmu->clks); + if (ret) { + dev_err(&gmu->pdev->dev, "Cannot enable GMU clocks\n"); + return ret; + } + + set_bit(GMU_CLK_ON, &device->gmu_core.flags); + return 0; +} + + + +static int a6xx_gmu_start_from_init(struct kgsl_device *device) +{ + struct kgsl_pwrctrl *pwr = &device->pwrctrl; + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + int level, ret; + + if (device->state == KGSL_STATE_INIT) { + int ret = a6xx_gmu_aop_send_acd_state(gmu->mailbox.channel, + adreno_dev->acd_enabled); + if (ret) + dev_err(&gmu->pdev->dev, + "AOP mbox send message failed: %d\n", ret); + } + + WARN_ON(test_bit(GMU_CLK_ON, &device->gmu_core.flags)); + + a6xx_gmu_enable_gdsc(device); + a6xx_gmu_enable_clks(device); + a6xx_gmu_irq_enable(device); + + /* Vote for minimal DDR BW for GMU to init */ + level = pwr->pwrlevels[pwr->default_pwrlevel].bus_min; + icc_set_bw(pwr->icc_path, 0, kBps_to_icc(pwr->ddr_table[level])); + + ret = a6xx_gmu_rpmh_gpu_pwrctrl(device, GMU_FW_START, + GMU_COLD_BOOT, 0); + if (ret) + return ret; + + ret = hfi_start(device, gmu, GMU_COLD_BOOT); + if (ret) + return ret; + + /* Request default DCVS level */ + return kgsl_pwrctrl_set_default_gpu_pwrlevel(device); +} + +static int a6xx_gmu_start_from_slumber(struct kgsl_device *device) +{ + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + int ret; + + WARN_ON(test_bit(GMU_CLK_ON, &device->gmu_core.flags)); + + a6xx_gmu_enable_gdsc(device); + a6xx_gmu_enable_clks(device); + a6xx_gmu_irq_enable(device); + + ret = a6xx_gmu_rpmh_gpu_pwrctrl(device, GMU_FW_START, + GMU_COLD_BOOT, 0); + if (ret) + return ret; + + ret = hfi_start(device, gmu, GMU_COLD_BOOT); + if (ret) + return ret; + + return kgsl_pwrctrl_set_default_gpu_pwrlevel(device); +} + +static int a6xx_gmu_start_from_reset(struct kgsl_device *device) +{ + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + int ret; + + a6xx_gmu_suspend(device); + + a6xx_gmu_enable_gdsc(device); + a6xx_gmu_enable_clks(device); + a6xx_gmu_irq_enable(device); + + ret = a6xx_gmu_rpmh_gpu_pwrctrl(device, GMU_FW_START, GMU_COLD_BOOT, 0); + if (ret) + return ret; + + ret = hfi_start(device, gmu, GMU_COLD_BOOT); + if (ret) + return ret; + + /* Send DCVS level prior to reset*/ + return kgsl_pwrctrl_set_default_gpu_pwrlevel(device); +} + +/* To be called to power on both GPU and GMU */ +static int a6xx_gmu_start(struct kgsl_device *device) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + int ret = 0; + + switch (device->state) { + case KGSL_STATE_INIT: + case KGSL_STATE_SUSPEND: + ret = a6xx_gmu_start_from_init(device); + break; + + case KGSL_STATE_SLUMBER: + ret = a6xx_gmu_start_from_slumber(device); + break; + case KGSL_STATE_RESET: + ret = a6xx_gmu_start_from_reset(device); + break; + } + + if (ret) { + if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) + a6xx_gmu_oob_clear(device, oob_boot_slumber); + + a6xx_gmu_snapshot(device); + } + + return ret; +} + +static int a6xx_gmu_acd_set(struct kgsl_device *device, bool val) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + int ret; + + if (IS_ERR_OR_NULL(gmu->mailbox.channel)) + return -EINVAL; + + /* Don't do any unneeded work if ACD is already in the correct state */ + if (adreno_dev->acd_enabled == val) + return 0; + + mutex_lock(&device->mutex); + + /* Power down the GPU before enabling or disabling ACD */ + kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND); + + adreno_dev->acd_enabled = val; + ret = a6xx_gmu_aop_send_acd_state(gmu->mailbox.channel, val); + if (ret) + dev_err(&gmu->pdev->dev, + "AOP mbox send message failed: %d\n", ret); + + kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER); + + mutex_unlock(&device->mutex); + return 0; +} + +static struct gmu_dev_ops a6xx_gmudev = { .load_firmware = a6xx_gmu_load_firmware, .oob_set = a6xx_gmu_oob_set, .oob_clear = a6xx_gmu_oob_clear, @@ -1831,7 +2635,7 @@ struct gmu_dev_ops adreno_a6xx_gmudev = { .wait_for_gmu_idle = a6xx_gmu_wait_for_idle, .ifpc_store = a6xx_gmu_ifpc_store, .ifpc_show = a6xx_gmu_ifpc_show, - .snapshot = a6xx_gmu_snapshot, + .snapshot = a6xx_gmu_device_snapshot, .cooperative_reset = a6xx_gmu_cooperative_reset, .wait_for_active_transition = a6xx_gmu_wait_for_active_transition, .read_alwayson = a6xx_gmu_read_alwayson, @@ -1839,3 +2643,928 @@ struct gmu_dev_ops adreno_a6xx_gmudev = { .gmu_ao_intr_mask = GMU_AO_INT_MASK, .scales_bandwidth = a6xx_gmu_scales_bandwidth, }; + +static struct gmu_core_ops a6xx_gmu_ops = { + .init = a6xx_gmu_init, + .start = a6xx_gmu_start, + .stop = a6xx_gmu_stop, + .dcvs_set = a6xx_gmu_dcvs_set, + .snapshot = a6xx_gmu_snapshot, + .suspend = a6xx_gmu_suspend, + .acd_set = a6xx_gmu_acd_set, +}; + +static int a6xx_gmu_bus_set(struct kgsl_device *device, int buslevel, + u32 ab) +{ + struct kgsl_pwrctrl *pwr = &device->pwrctrl; + int ret = 0; + + if (buslevel != pwr->cur_buslevel) { + ret = a6xx_gmu_dcvs_set(device, INVALID_DCVS_IDX, buslevel); + if (ret) + return ret; + + pwr->cur_buslevel = buslevel; + + trace_kgsl_buslevel(device, pwr->active_pwrlevel, buslevel); + } + + if (ab != pwr->cur_ab) { + icc_set_bw(pwr->icc_path, MBps_to_icc(ab), 0); + pwr->cur_ab = ab; + } + + return ret; +} + +static void a6xx_gmu_iommu_cb_close(struct gmu_iommu_context *ctx); + +static void a6xx_gmu_memory_close(struct gmu_device *gmu) +{ + int i; + struct gmu_memdesc *md; + struct gmu_iommu_context *ctx; + + gmu->hfi_mem = NULL; + gmu->dump_mem = NULL; + gmu->gmu_log = NULL; + gmu->preallocations = false; + + /* Unmap and free all memories in GMU kernel memory pool */ + for (i = 0; i < GMU_KERNEL_ENTRIES; i++) { + if (!test_bit(i, &gmu->kmem_bitmap)) + continue; + + md = &gmu->kmem_entries[i]; + ctx = &a6xx_gmu_ctx[md->ctx_idx]; + + if (md->gmuaddr && md->mem_type != GMU_ITCM && + md->mem_type != GMU_DTCM) + iommu_unmap(ctx->domain, md->gmuaddr, md->size); + + a6xx_gmu_mem_free(gmu, md); + + clear_bit(i, &gmu->kmem_bitmap); + } + + a6xx_gmu_iommu_cb_close(&a6xx_gmu_ctx[GMU_CONTEXT_KERNEL]); + a6xx_gmu_iommu_cb_close(&a6xx_gmu_ctx[GMU_CONTEXT_USER]); +} + +static int a6xx_gmu_aop_mailbox_init(struct adreno_device *adreno_dev, + struct gmu_device *gmu) +{ + struct kgsl_mailbox *mailbox = &gmu->mailbox; + + mailbox->client.dev = &gmu->pdev->dev; + mailbox->client.tx_block = true; + mailbox->client.tx_tout = 1000; + mailbox->client.knows_txdone = false; + + mailbox->channel = mbox_request_channel(&mailbox->client, 0); + if (IS_ERR(mailbox->channel)) + return PTR_ERR(mailbox->channel); + + adreno_dev->acd_enabled = true; + return 0; +} + +static void a6xx_gmu_acd_probe(struct kgsl_device *device, + struct gmu_device *gmu, struct device_node *node) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct kgsl_pwrctrl *pwr = &device->pwrctrl; + struct hfi_acd_table_cmd *cmd = &gmu->hfi.acd_tbl_cmd; + u32 acd_level, cmd_idx, numlvl = pwr->num_pwrlevels; + int ret, i; + + if (!ADRENO_FEATURE(adreno_dev, ADRENO_ACD)) + return; + + cmd->hdr = 0xFFFFFFFF; + cmd->version = HFI_ACD_INIT_VERSION; + cmd->stride = 1; + cmd->enable_by_level = 0; + + for (i = 0, cmd_idx = 0; i < numlvl; i++) { + acd_level = pwr->pwrlevels[numlvl - i].acd_level; + if (acd_level) { + cmd->enable_by_level |= (1 << i); + cmd->data[cmd_idx++] = acd_level; + } + } + + if (!cmd->enable_by_level) + return; + + cmd->num_levels = cmd_idx; + + ret = a6xx_gmu_aop_mailbox_init(adreno_dev, gmu); + if (ret) + dev_err(&gmu->pdev->dev, + "AOP mailbox init failed: %d\n", ret); +} + +struct rpmh_arc_vals { + unsigned int num; + const u16 *val; +}; + +enum rpmh_vote_type { + GPU_ARC_VOTE = 0, + GMU_ARC_VOTE, + INVALID_ARC_VOTE, +}; + +/* + * rpmh_arc_cmds() - query RPMh command database for GX/CX/MX rail + * VLVL tables. The index of table will be used by GMU to vote rail + * voltage. + * + * @gmu: Pointer to GMU device + * @arc: Pointer to RPMh rail controller (ARC) voltage table + * @res_id: Pointer to 8 char array that contains rail name + */ +static int rpmh_arc_cmds(struct gmu_device *gmu, + 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; +} + +/* + * setup_volt_dependency_tbl() - set up GX->MX or CX->MX rail voltage + * dependencies. Second rail voltage shall be equal to or higher than + * primary rail voltage. VLVL table index was used by RPMh for PMIC + * voltage setting. + * @votes: Pointer to a ARC vote descriptor + * @pri_rail: Pointer to primary power rail VLVL table + * @sec_rail: Pointer to second/dependent power rail VLVL table + * @vlvl: Pointer to VLVL table being used by GPU or GMU driver, a subset + * of pri_rail VLVL table + * @num_entries: Valid number of entries in table pointed by "vlvl" parameter + */ +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; +} + +static int rpmh_gmu_arc_votes_init(struct gmu_device *gmu, + 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 }; + + return setup_volt_dependency_tbl(gmu->rpmh_votes.cx_votes, pri_rail, + sec_rail, gmu_cx_vlvl, 2); +} + +/* + * rpmh_arc_votes_init() - initialized GX RPMh votes needed for rails + * voltage scaling by GMU. + * @device: Pointer to KGSL device + * @gmu: Pointer to GMU device + * @pri_rail: Pointer to primary power rail VLVL table + * @sec_rail: Pointer to second/dependent power rail VLVL table + * of pri_rail VLVL table + * @type: the type of the primary rail, GPU or GMU + */ +static int rpmh_arc_votes_init(struct kgsl_device *device, + struct gmu_device *gmu, struct rpmh_arc_vals *pri_rail, + struct rpmh_arc_vals *sec_rail, unsigned int type) +{ + unsigned int num_freqs; + u16 vlvl_tbl[MAX_GX_LEVELS]; + int i; + + if (type == GMU_ARC_VOTE) + return rpmh_gmu_arc_votes_init(gmu, pri_rail, sec_rail); + + num_freqs = gmu->num_gpupwrlevels; + + if (num_freqs > pri_rail->num || num_freqs > ARRAY_SIZE(vlvl_tbl)) { + dev_err(&gmu->pdev->dev, + "Defined more GPU DCVS levels than RPMh can support\n"); + return -EINVAL; + } + + memset(vlvl_tbl, 0, sizeof(vlvl_tbl)); + for (i = 0; i < num_freqs; i++) + vlvl_tbl[i] = gmu->pwrlevels[i].level; + + return setup_volt_dependency_tbl(gmu->rpmh_votes.gx_votes, pri_rail, + sec_rail, vlvl_tbl, num_freqs); +} + +struct bcm { + const char *name; + u32 buswidth; + u32 channels; + u32 unit; + u16 width; + u8 vcd; + bool fixed; +}; + +/* + * 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 }, +}; + +/* 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); + } +} + +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; +}; + +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; +} + +static void build_bwtable_cmd_cache(struct hfi_bwtable_cmd *cmd, + struct rpmh_bw_votes *ddr, struct rpmh_bw_votes *cnoc) +{ + unsigned int i, j; + + cmd->hdr = 0xFFFFFFFF; + 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 a6xx_gmu_bus_vote_init(struct kgsl_device *device) +{ + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct kgsl_pwrctrl *pwr = &device->pwrctrl; + struct rpmh_bw_votes *ddr, *cnoc = NULL; + u32 *cnoc_table; + u32 count; + + /* Build the DDR votes */ + 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); + + /* Get the CNOC table */ + cnoc_table = kgsl_bus_get_table(device->pdev, "qcom,bus-table-cnoc", + &count); + + /* And build the votes for that, if it exists */ + 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 the HFI command once */ + build_bwtable_cmd_cache(&gmu->hfi.bwtbl_cmd, ddr, cnoc); + + free_rpmh_bw_votes(ddr); + free_rpmh_bw_votes(cnoc); + + return 0; +} + +static int a6xx_gmu_rpmh_init(struct kgsl_device *device, + struct gmu_device *gmu) +{ + struct rpmh_arc_vals gfx_arc, cx_arc, mx_arc; + int ret; + + /* Initialize BW tables */ + ret = a6xx_gmu_bus_vote_init(device); + if (ret) + return ret; + + /* Populate GPU and GMU frequency vote table */ + ret = rpmh_arc_cmds(gmu, &gfx_arc, "gfx.lvl"); + if (ret) + return ret; + + ret = rpmh_arc_cmds(gmu, &cx_arc, "cx.lvl"); + if (ret) + return ret; + + ret = rpmh_arc_cmds(gmu, &mx_arc, "mx.lvl"); + if (ret) + return ret; + + ret = rpmh_arc_votes_init(device, gmu, &gfx_arc, &mx_arc, GPU_ARC_VOTE); + if (ret) + return ret; + + return rpmh_arc_votes_init(device, gmu, &cx_arc, &mx_arc, GMU_ARC_VOTE); +} + + +static int a6xx_gmu_reg_probe(struct kgsl_device *device) +{ + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct resource *res; + + res = platform_get_resource_byname(gmu->pdev, IORESOURCE_MEM, + "kgsl_gmu_reg"); + if (!res) { + dev_err(&gmu->pdev->dev, "The GMU 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); + + /* + * We can't use devm_ioremap_resource here because we purposely double + * map the gpu_cc registers for debugging purposes + */ + device->gmu_core.reg_virt = devm_ioremap(&gmu->pdev->dev, res->start, + resource_size(res)); + + if (!device->gmu_core.reg_virt) { + dev_err(&gmu->pdev->dev, "Unable to map the GMU registers\n"); + return -ENOMEM; + } + + return 0; +} + +static int a6xx_gmu_tcm_init(struct gmu_device *gmu) +{ + struct gmu_memdesc *md; + + /* Reserve a memdesc for ITCM. No actually memory allocated */ + md = a6xx_gmu_kmem_allocate(gmu, GMU_ITCM, gmu->vma[GMU_ITCM].start, + gmu->vma[GMU_ITCM].size, 0); + if (IS_ERR(md)) + return PTR_ERR(md); + + /* Reserve a memdesc for DTCM. No actually memory allocated */ + md = a6xx_gmu_kmem_allocate(gmu, GMU_DTCM, gmu->vma[GMU_DTCM].start, + gmu->vma[GMU_DTCM].size, 0); + + return PTR_ERR_OR_ZERO(md); +} + + +static int a6xx_gmu_iommu_fault_handler(struct iommu_domain *domain, + struct device *dev, unsigned long addr, int flags, void *token, + const char *name) +{ + char *fault_type = "unknown"; + + if (flags & IOMMU_FAULT_TRANSLATION) + fault_type = "translation"; + else if (flags & IOMMU_FAULT_PERMISSION) + fault_type = "permission"; + else if (flags & IOMMU_FAULT_EXTERNAL) + fault_type = "external"; + else if (flags & IOMMU_FAULT_TRANSACTION_STALLED) + fault_type = "transaction stalled"; + + dev_err(dev, "GMU fault addr = %lX, context=%s (%s %s fault)\n", + addr, name, + (flags & IOMMU_FAULT_WRITE) ? "write" : "read", + fault_type); + + return 0; +} + +static int a6xx_gmu_kernel_fault_handler(struct iommu_domain *domain, + struct device *dev, unsigned long addr, int flags, void *token) +{ + return a6xx_gmu_iommu_fault_handler(domain, dev, addr, flags, token, + "gmu_kernel"); +} + +static int a6xx_gmu_user_fault_handler(struct iommu_domain *domain, + struct device *dev, unsigned long addr, int flags, void *token) +{ + return a6xx_gmu_iommu_fault_handler(domain, dev, addr, flags, token, + "gmu_user"); +} + +static int a6xx_gmu_iommu_cb_probe(struct gmu_device *gmu, + const char *name, struct gmu_iommu_context *ctx, + struct device_node *parent, iommu_fault_handler_t handler) +{ + struct device_node *node = of_get_child_by_name(parent, name); + struct platform_device *pdev; + int ret; + + if (!node) + return -ENODEV; + + pdev = of_find_device_by_node(node); + ret = of_dma_configure(&pdev->dev, node, true); + of_node_put(node); + + if (ret) { + platform_device_put(pdev); + return ret; + } + + ctx->pdev = pdev; + ctx->domain = iommu_domain_alloc(&platform_bus_type); + if (ctx->domain == NULL) { + dev_err(&gmu->pdev->dev, "gmu iommu fail to alloc %s domain\n", + ctx->name); + platform_device_put(pdev); + return -ENODEV; + } + + ret = iommu_attach_device(ctx->domain, &pdev->dev); + if (!ret) { + iommu_set_fault_handler(ctx->domain, handler, ctx); + return 0; + } + + dev_err(&gmu->pdev->dev, + "gmu iommu fail to attach %s device\n", ctx->name); + iommu_domain_free(ctx->domain); + ctx->domain = NULL; + platform_device_put(pdev); + + return ret; +} + +static void a6xx_gmu_iommu_cb_close(struct gmu_iommu_context *ctx) +{ + if (!ctx->domain) + return; + + iommu_detach_device(ctx->domain, &ctx->pdev->dev); + iommu_domain_free(ctx->domain); + + platform_device_put(ctx->pdev); + ctx->domain = NULL; +} + +static int a6xx_gmu_iommu_init(struct gmu_device *gmu, struct device_node *node) +{ + int ret; + + devm_of_platform_populate(&gmu->pdev->dev); + + ret = a6xx_gmu_iommu_cb_probe(gmu, "gmu_user", + &a6xx_gmu_ctx[GMU_CONTEXT_USER], node, + a6xx_gmu_user_fault_handler); + if (ret) + return ret; + + return a6xx_gmu_iommu_cb_probe(gmu, "gmu_kernel", + &a6xx_gmu_ctx[GMU_CONTEXT_KERNEL], node, + a6xx_gmu_kernel_fault_handler); +} + +static int a6xx_gmu_regulators_probe(struct gmu_device *gmu, + struct platform_device *pdev) +{ + gmu->cx_gdsc = devm_regulator_get(&pdev->dev, "vddcx"); + if (IS_ERR(gmu->cx_gdsc)) { + if (PTR_ERR(gmu->cx_gdsc) != -EPROBE_DEFER) + dev_err(&pdev->dev, "Couldn't get the vddcx gdsc\n"); + return PTR_ERR(gmu->cx_gdsc); + } + + gmu->gx_gdsc = devm_regulator_get(&pdev->dev, "vdd"); + if (IS_ERR(gmu->gx_gdsc)) { + if (PTR_ERR(gmu->gx_gdsc) != -EPROBE_DEFER) + dev_err(&pdev->dev, "Couldn't get the vdd gdsc\n"); + return PTR_ERR(gmu->gx_gdsc); + } + + return 0; +} + +static void a6xx_gmu_remove(struct kgsl_device *device) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + + tasklet_kill(&gmu->hfi.tasklet); + + a6xx_gmu_stop(device); + + if (!IS_ERR_OR_NULL(gmu->mailbox.channel)) + mbox_free_channel(gmu->mailbox.channel); + + adreno_dev->acd_enabled = false; + + if (gmu->fw_image) + release_firmware(gmu->fw_image); + + a6xx_gmu_memory_close(gmu); + + memset(&device->gmu_core, 0, sizeof(device->gmu_core)); +} + +static int a6xx_gmu_probe(struct kgsl_device *device, + struct platform_device *pdev) +{ + struct gmu_device *gmu; + struct kgsl_hfi *hfi; + struct kgsl_pwrctrl *pwr = &device->pwrctrl; + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + int i = 0, ret = -ENXIO, index; + + gmu = devm_kzalloc(&pdev->dev, sizeof(*gmu), GFP_KERNEL); + if (!gmu) + return -ENOMEM; + + gmu->pdev = pdev; + + device->gmu_core.ptr = gmu; + hfi = &gmu->hfi; + gmu->load_mode = TCM_BOOT; + + dma_set_coherent_mask(&gmu->pdev->dev, DMA_BIT_MASK(64)); + gmu->pdev->dev.dma_mask = &gmu->pdev->dev.coherent_dma_mask; + set_dma_ops(&gmu->pdev->dev, NULL); + + /* Set up GMU regulators */ + ret = a6xx_gmu_regulators_probe(gmu, pdev); + if (ret) + return ret; + + ret = devm_clk_bulk_get_all(&pdev->dev, &gmu->clks); + if (ret < 0) + return ret; + + gmu->num_clks = ret; + + /* Set up GMU IOMMU and shared memory with GMU */ + ret = a6xx_gmu_iommu_init(gmu, pdev->dev.of_node); + if (ret) + goto error; + + if (adreno_is_a650_family(adreno_dev)) + gmu->vma = a6xx_gmu_vma; + else + gmu->vma = a6xx_gmu_vma_legacy; + + ret = a6xx_gmu_tcm_init(gmu); + if (ret) + goto error; + + /* Map and reserve GMU CSRs registers */ + ret = a6xx_gmu_reg_probe(device); + if (ret) + goto error; + + /* Initialize HFI and GMU interrupts */ + ret = kgsl_request_irq(gmu->pdev, "kgsl_hfi_irq", hfi_irq_handler, + device); + if (ret < 0) + goto error; + + hfi->hfi_interrupt_num = ret; + + ret = kgsl_request_irq(gmu->pdev, "kgsl_gmu_irq", a6xx_gmu_irq_handler, + device); + if (ret < 0) + goto error; + + gmu->gmu_interrupt_num = ret; + + /* Don't enable GMU interrupts until GMU started */ + /* We cannot use irq_disable because it writes registers */ + disable_irq(gmu->gmu_interrupt_num); + disable_irq(hfi->hfi_interrupt_num); + + tasklet_init(&hfi->tasklet, hfi_receiver, (unsigned long) gmu); + hfi->kgsldev = device; + + if (WARN(pwr->num_pwrlevels + 1 > ARRAY_SIZE(gmu->pwrlevels), + "Too many GPU powerlevels for the GMU HFI\n")) { + ret = -EINVAL; + goto error; + } + + /* Add a dummy level for "off" because the GMU expects it */ + gmu->pwrlevels[0].freq = 0; + gmu->pwrlevels[0].level = 0; + + /* GMU power levels are in ascending order */ + for (index = 1, i = pwr->num_pwrlevels - 1; i >= 0; i--, index++) { + gmu->pwrlevels[index].freq = pwr->pwrlevels[i].gpu_freq; + gmu->pwrlevels[index].level = pwr->pwrlevels[i].voltage_level; + } + + gmu->num_gpupwrlevels = pwr->num_pwrlevels + 1; + + /* Populates RPMh configurations */ + ret = a6xx_gmu_rpmh_init(device, gmu); + if (ret) + goto error; + + /* Set up GMU idle states */ + if (ADRENO_FEATURE(adreno_dev, ADRENO_MIN_VOLT)) + gmu->idle_level = GPU_HW_MIN_VOLT; + else if (ADRENO_FEATURE(adreno_dev, ADRENO_HW_NAP)) + gmu->idle_level = GPU_HW_NAP; + else if (ADRENO_FEATURE(adreno_dev, ADRENO_IFPC)) + gmu->idle_level = GPU_HW_IFPC; + else if (ADRENO_FEATURE(adreno_dev, ADRENO_SPTP_PC)) + gmu->idle_level = GPU_HW_SPTP_PC; + else + gmu->idle_level = GPU_HW_ACTIVE; + + a6xx_gmu_acd_probe(device, gmu, pdev->dev.of_node); + + + if (a6xx_gmu_scales_bandwidth(device)) + pwr->bus_set = a6xx_gmu_bus_set; + + set_bit(GMU_ENABLED, &device->gmu_core.flags); + + device->gmu_core.core_ops = &a6xx_gmu_ops; + device->gmu_core.dev_ops = &a6xx_gmudev; + + return 0; + +error: + a6xx_gmu_remove(device); + return ret; +} + + + +static int a6xx_gmu_bind(struct device *dev, struct device *master, void *data) +{ + struct kgsl_device *device = dev_get_drvdata(master); + + return a6xx_gmu_probe(device, to_platform_device(dev)); +} + +static void a6xx_gmu_unbind(struct device *dev, struct device *master, + void *data) +{ + struct kgsl_device *device = dev_get_drvdata(master); + + a6xx_gmu_remove(device); +} + +static const struct component_ops a6xx_gmu_component_ops = { + .bind = a6xx_gmu_bind, + .unbind = a6xx_gmu_unbind, +}; + +static int a6xx_gmu_probe_dev(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &a6xx_gmu_component_ops); +} + +static int a6xx_gmu_remove_dev(struct platform_device *pdev) +{ + component_del(&pdev->dev, &a6xx_gmu_component_ops); + return 0; +} + +static const struct of_device_id a6xx_gmu_match_table[] = { + { .compatible = "qcom,gpu-gmu" }, + { }, +}; + +struct platform_driver a6xx_gmu_driver = { + .probe = a6xx_gmu_probe_dev, + .remove = a6xx_gmu_remove_dev, + .driver = { + .name = "adreno-a6xx-gmu", + .of_match_table = a6xx_gmu_match_table, + }, +}; diff --git a/drivers/gpu/msm/kgsl_bus.c b/drivers/gpu/msm/kgsl_bus.c index 84d71dfa30ad..94dd5d68011f 100644 --- a/drivers/gpu/msm/kgsl_bus.c +++ b/drivers/gpu/msm/kgsl_bus.c @@ -127,7 +127,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,6 +171,8 @@ 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); } @@ -181,5 +183,6 @@ done: void kgsl_bus_close(struct kgsl_device *device) { + kfree(device->pwrctrl.ddr_table); icc_put(device->pwrctrl.icc_path); } diff --git a/drivers/gpu/msm/kgsl_gmu.h b/drivers/gpu/msm/kgsl_gmu.h index 062cb362bfaa..c385c5e456ca 100644 --- a/drivers/gpu/msm/kgsl_gmu.h +++ b/drivers/gpu/msm/kgsl_gmu.h @@ -81,7 +81,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 { @@ -96,7 +95,7 @@ enum gmu_mem_type { }; enum gmu_context_index { - GMU_CONTEXT_USER = 0, + GMU_CONTEXT_USER, GMU_CONTEXT_KERNEL, }; @@ -208,12 +207,4 @@ struct gmu_device { atomic_t cm3_fault; }; -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); - -int gmu_prealloc_req(struct kgsl_device *device, struct gmu_block_header *blk); -int gmu_cache_finalize(struct kgsl_device *device); - #endif /* __KGSL_GMU_H */ diff --git a/drivers/gpu/msm/kgsl_gmu_core.c b/drivers/gpu/msm/kgsl_gmu_core.c index 0ebb4f09ed13..aded346fa01e 100644 --- a/drivers/gpu/msm/kgsl_gmu_core.c +++ b/drivers/gpu/msm/kgsl_gmu_core.c @@ -11,7 +11,7 @@ #include "kgsl_trace.h" static const struct of_device_id gmu_match_table[] = { - { .compatible = "qcom,gpu-gmu", .data = &kgsl_gmu_driver }, + { .compatible = "qcom,gpu-gmu", .data = &a6xx_gmu_driver }, { .compatible = "qcom,gpu-rgmu", .data = &kgsl_rgmu_driver }, {}, }; diff --git a/drivers/gpu/msm/kgsl_gmu_core.h b/drivers/gpu/msm/kgsl_gmu_core.h index a2c86409eae8..ff82d5619469 100644 --- a/drivers/gpu/msm/kgsl_gmu_core.h +++ b/drivers/gpu/msm/kgsl_gmu_core.h @@ -161,7 +161,7 @@ struct gmu_core_device { unsigned long flags; }; -extern struct platform_driver kgsl_gmu_driver; +extern struct platform_driver a6xx_gmu_driver; extern struct platform_driver kgsl_rgmu_driver; /* GMU core functions */ From 78ad23520948d5681a301d7d7d6cf4d264f2eb0c Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Wed, 1 Apr 2020 16:28:46 -0600 Subject: [PATCH 07/30] msm: kgsl: Move HFI to the a6xx space The next step in the GMU transition is to move HFI to a6xx target specific code. Rename the file, functions and kgsl_hfi struct. Change-Id: Ic0dedbad7efcda12f03fbd37bb2267296ee7a5ac Signed-off-by: Jordan Crouse --- drivers/gpu/msm/Makefile | 2 +- drivers/gpu/msm/adreno_a6xx_gmu.c | 30 ++-- .../gpu/msm/{kgsl_hfi.c => adreno_a6xx_hfi.c} | 148 +++++++++--------- .../gpu/msm/{kgsl_hfi.h => adreno_a6xx_hfi.h} | 24 +-- drivers/gpu/msm/kgsl_gmu.h | 4 +- 5 files changed, 105 insertions(+), 103 deletions(-) rename drivers/gpu/msm/{kgsl_hfi.c => adreno_a6xx_hfi.c} (82%) rename drivers/gpu/msm/{kgsl_hfi.h => adreno_a6xx_hfi.h} (96%) diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile index 6c9de9394c2c..b59779d910c7 100644 --- a/drivers/gpu/msm/Makefile +++ b/drivers/gpu/msm/Makefile @@ -10,7 +10,6 @@ msm_kgsl-y = \ kgsl_events.o \ kgsl_ioctl.o \ kgsl_gmu_core.o \ - kgsl_hfi.o \ kgsl_mmu.o \ kgsl_pool.o \ kgsl_pwrctrl.o \ @@ -35,6 +34,7 @@ msm_kgsl-y += \ adreno_a5xx_snapshot.o \ adreno_a6xx.o \ adreno_a6xx_gmu.o \ + adreno_a6xx_hfi.o \ adreno_a6xx_preempt.o \ adreno_a6xx_rgmu.o \ adreno_a6xx_snapshot.o \ diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index ae5640f30caa..b2c335ba8006 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -744,7 +744,7 @@ static void a6xx_gmu_oob_clear(struct kgsl_device *device, static void a6xx_gmu_irq_enable(struct kgsl_device *device) { struct gmu_device *gmu = KGSL_GMU_DEVICE(device); - struct kgsl_hfi *hfi = &gmu->hfi; + struct a6xx_hfi *hfi = &gmu->hfi; /* Clear pending IRQs and Unmask needed IRQs */ adreno_gmu_clear_and_unmask_irqs(ADRENO_DEVICE(device)); @@ -757,7 +757,7 @@ static void a6xx_gmu_irq_enable(struct kgsl_device *device) static void a6xx_gmu_irq_disable(struct kgsl_device *device) { struct gmu_device *gmu = KGSL_GMU_DEVICE(device); - struct kgsl_hfi *hfi = &gmu->hfi; + struct a6xx_hfi *hfi = &gmu->hfi; /* Disable all IRQs on host */ disable_irq(gmu->gmu_interrupt_num); @@ -778,7 +778,7 @@ static int a6xx_gmu_hfi_start_msg(struct kgsl_device *device) * legacy firmware. */ if (!ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) - return hfi_send_req(KGSL_GMU_DEVICE(device), + return a6xx_hfi_send_req(KGSL_GMU_DEVICE(device), H2F_MSG_START, &req); return 0; @@ -1571,7 +1571,7 @@ static int a6xx_gmu_init(struct kgsl_device *device) if (ret) return ret; - hfi_init(gmu); + a6xx_hfi_init(gmu); return 0; } @@ -1714,7 +1714,7 @@ static int a6xx_gmu_notify_slumber(struct kgsl_device *device) .bw = bus_level, }; - ret = hfi_send_req(gmu, H2F_MSG_PREPARE_SLUMBER, &req); + ret = a6xx_hfi_send_req(gmu, H2F_MSG_PREPARE_SLUMBER, &req); goto out; } @@ -1795,7 +1795,7 @@ static int a6xx_gmu_suspend(struct kgsl_device *device) /* Pending message in all queues are abandoned */ a6xx_gmu_irq_disable(device); - hfi_stop(gmu); + a6xx_hfi_stop(gmu); if (a6xx_gmu_rpmh_gpu_pwrctrl(device, GMU_SUSPEND, 0, 0)) return -EINVAL; @@ -1863,7 +1863,7 @@ static int a6xx_gmu_dcvs_set(struct kgsl_device *device, ret = a6xx_gmu_rpmh_gpu_pwrctrl(device, GMU_DCVS_NOHFI, req.freq, req.bw); else if (test_bit(GMU_HFI_ON, &device->gmu_core.flags)) - ret = hfi_send_req(gmu, H2F_MSG_GX_BW_PERF_VOTE, &req); + ret = a6xx_hfi_send_req(gmu, H2F_MSG_GX_BW_PERF_VOTE, &req); if (ret) { dev_err_ratelimited(&gmu->pdev->dev, @@ -2381,7 +2381,7 @@ static void a6xx_gmu_stop(struct kgsl_device *device) /* Pending message in all queues are abandoned */ a6xx_gmu_irq_disable(device); - hfi_stop(gmu); + a6xx_hfi_stop(gmu); a6xx_gmu_rpmh_gpu_pwrctrl(device, GMU_FW_STOP, 0, 0); @@ -2507,7 +2507,7 @@ static int a6xx_gmu_start_from_init(struct kgsl_device *device) if (ret) return ret; - ret = hfi_start(device, gmu, GMU_COLD_BOOT); + ret = a6xx_hfi_start(device, gmu, GMU_COLD_BOOT); if (ret) return ret; @@ -2531,7 +2531,7 @@ static int a6xx_gmu_start_from_slumber(struct kgsl_device *device) if (ret) return ret; - ret = hfi_start(device, gmu, GMU_COLD_BOOT); + ret = a6xx_hfi_start(device, gmu, GMU_COLD_BOOT); if (ret) return ret; @@ -2553,7 +2553,7 @@ static int a6xx_gmu_start_from_reset(struct kgsl_device *device) if (ret) return ret; - ret = hfi_start(device, gmu, GMU_COLD_BOOT); + ret = a6xx_hfi_start(device, gmu, GMU_COLD_BOOT); if (ret) return ret; @@ -3397,7 +3397,7 @@ static int a6xx_gmu_probe(struct kgsl_device *device, struct platform_device *pdev) { struct gmu_device *gmu; - struct kgsl_hfi *hfi; + struct a6xx_hfi *hfi; struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct adreno_device *adreno_dev = ADRENO_DEVICE(device); int i = 0, ret = -ENXIO, index; @@ -3447,8 +3447,8 @@ static int a6xx_gmu_probe(struct kgsl_device *device, goto error; /* Initialize HFI and GMU interrupts */ - ret = kgsl_request_irq(gmu->pdev, "kgsl_hfi_irq", hfi_irq_handler, - device); + ret = kgsl_request_irq(gmu->pdev, "kgsl_hfi_irq", + a6xx_hfi_irq_handler, device); if (ret < 0) goto error; @@ -3466,7 +3466,7 @@ static int a6xx_gmu_probe(struct kgsl_device *device, disable_irq(gmu->gmu_interrupt_num); disable_irq(hfi->hfi_interrupt_num); - tasklet_init(&hfi->tasklet, hfi_receiver, (unsigned long) gmu); + tasklet_init(&hfi->tasklet, a6xx_hfi_receiver, (unsigned long) gmu); hfi->kgsldev = device; if (WARN(pwr->num_pwrlevels + 1 > ARRAY_SIZE(gmu->pwrlevels), diff --git a/drivers/gpu/msm/kgsl_hfi.c b/drivers/gpu/msm/adreno_a6xx_hfi.c similarity index 82% rename from drivers/gpu/msm/kgsl_hfi.c rename to drivers/gpu/msm/adreno_a6xx_hfi.c index ff67032061eb..45c8014ed626 100644 --- a/drivers/gpu/msm/kgsl_hfi.c +++ b/drivers/gpu/msm/adreno_a6xx_hfi.c @@ -8,9 +8,9 @@ #include "adreno.h" #include "adreno_a6xx.h" +#include "adreno_a6xx_hfi.h" #include "kgsl_device.h" #include "kgsl_gmu.h" -#include "kgsl_hfi.h" #include "kgsl_trace.h" #define HFI_QUEUE_OFFSET(i) \ @@ -34,11 +34,11 @@ #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, +static void a6xx_hfi_process_queue(struct 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 gmu_device *gmu, uint32_t queue_idx, unsigned int *output, unsigned int max_size) { struct gmu_memdesc *mem_addr = gmu->hfi_mem; @@ -97,13 +97,13 @@ done: } /* Size in below functions are in unit of dwords */ -static int hfi_queue_write(struct gmu_device *gmu, uint32_t queue_idx, +static int a6xx_hfi_queue_write(struct gmu_device *gmu, uint32_t queue_idx, uint32_t *msg) { struct hfi_queue_table *tbl = gmu->hfi_mem->hostptr; struct hfi_queue_header *hdr = &tbl->qhdr[queue_idx]; uint32_t *queue; - struct kgsl_hfi *hfi = &gmu->hfi; + struct a6xx_hfi *hfi = &gmu->hfi; uint32_t i, write, empty_space; uint32_t size = MSG_HDR_GET_SIZE(*msg); uint32_t id = MSG_HDR_GET_ID(*msg); @@ -173,9 +173,9 @@ 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) +void a6xx_hfi_init(struct gmu_device *gmu) { - struct kgsl_hfi *hfi = &gmu->hfi; + struct a6xx_hfi *hfi = &gmu->hfi; struct adreno_device *adreno_dev = ADRENO_DEVICE(hfi->kgsldev); struct gmu_memdesc *mem_addr = gmu->hfi_mem; int i; @@ -235,7 +235,7 @@ static void receive_ack_cmd(struct gmu_device *gmu, void *rcvd, uint32_t *ack = rcvd; uint32_t hdr = ack[0]; uint32_t req_hdr = ack[1]; - struct kgsl_hfi *hfi = &gmu->hfi; + struct a6xx_hfi *hfi = &gmu->hfi; if (ret_cmd == NULL) return; @@ -293,22 +293,22 @@ 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, +static int a6xx_hfi_send_cmd(struct gmu_device *gmu, uint32_t queue_idx, void *data, struct pending_cmd *ret_cmd) { 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(gmu, queue_idx, cmd); ret_cmd->sent_hdr = cmd[0]; - rc = hfi_queue_write(gmu, queue_idx, cmd); + rc = a6xx_hfi_queue_write(gmu, queue_idx, cmd); if (rc) return rc; @@ -326,14 +326,14 @@ static int hfi_send_cmd(struct gmu_device *gmu, uint32_t queue_idx, adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_GMU2HOST_INTR_CLR, HFI_IRQ_MSGQ_MASK); - hfi_process_queue(gmu, HFI_MSG_ID, ret_cmd); + 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, +static int a6xx_hfi_send_generic_req(struct gmu_device *gmu, uint32_t queue, void *cmd) { struct pending_cmd ret_cmd; @@ -341,7 +341,7 @@ static int hfi_send_generic_req(struct gmu_device *gmu, uint32_t queue, memset(&ret_cmd, 0, sizeof(ret_cmd)); - rc = hfi_send_cmd(gmu, queue, cmd, &ret_cmd); + rc = a6xx_hfi_send_cmd(gmu, queue, cmd, &ret_cmd); if (!rc && ret_cmd.results[2] == HFI_ACK_ERROR) { dev_err(&gmu->pdev->dev, "HFI ACK failure: Req 0x%8.8X\n", @@ -352,7 +352,7 @@ 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 gmu_device *gmu, uint32_t boot_state) { struct hfi_gmu_init_cmd cmd = { .hdr = CMD_MSG_HDR(H2F_MSG_INIT, sizeof(cmd)), @@ -362,10 +362,10 @@ static int hfi_send_gmu_init(struct gmu_device *gmu, uint32_t boot_state) .boot_state = boot_state, }; - return hfi_send_generic_req(gmu, HFI_CMD_ID, &cmd); + return a6xx_hfi_send_generic_req(gmu, HFI_CMD_ID, &cmd); } -static int hfi_get_fw_version(struct gmu_device *gmu, +static int a6xx_hfi_get_fw_version(struct gmu_device *gmu, uint32_t expected_ver, uint32_t *ver) { struct hfi_fw_version_cmd cmd = { @@ -377,7 +377,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(gmu, HFI_CMD_ID, &cmd, &ret_cmd); if (rc) return rc; @@ -391,17 +391,17 @@ 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 gmu_device *gmu) { 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(gmu, HFI_CMD_ID, &cmd); } -static const char * const hfi_features[] = { +static const char * const a6xx_hfi_features[] = { [HFI_FEATURE_ECP] = "ECP", [HFI_FEATURE_ACD] = "ACD", [HFI_FEATURE_LM] = "LM", @@ -409,13 +409,14 @@ static const char * const hfi_features[] = { 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, +static int a6xx_hfi_send_feature_ctrl(struct gmu_device *gmu, uint32_t feature, uint32_t enable, uint32_t data) { struct hfi_feature_ctrl_cmd cmd = { @@ -426,7 +427,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(gmu, HFI_CMD_ID, &cmd); if (ret) dev_err(&gmu->pdev->dev, "Unable to %s feature %s (%d)\n", @@ -436,7 +437,7 @@ 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 gmu_device *gmu) { struct hfi_dcvstable_v1_cmd cmd = { .hdr = CMD_MSG_HDR(H2F_MSG_PERF_TBL, sizeof(cmd)), @@ -456,10 +457,10 @@ static int hfi_send_dcvstbl_v1(struct gmu_device *gmu) 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); + return a6xx_hfi_send_generic_req(gmu, HFI_CMD_ID, &cmd); } -static int hfi_send_get_value(struct gmu_device *gmu, +static int a6xx_hfi_send_get_value(struct gmu_device *gmu, struct hfi_get_value_req *req) { struct hfi_get_value_cmd *cmd = &req->cmd; @@ -470,7 +471,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(gmu, HFI_CMD_ID, cmd, &ret_cmd); if (rc) return rc; @@ -480,7 +481,7 @@ static int hfi_send_get_value(struct gmu_device *gmu, return 0; } -static int hfi_send_dcvstbl(struct gmu_device *gmu) +static int a6xx_hfi_send_dcvstbl(struct gmu_device *gmu) { struct hfi_dcvstable_cmd cmd = { .hdr = CMD_MSG_HDR(H2F_MSG_PERF_TBL, sizeof(cmd)), @@ -502,34 +503,34 @@ static int hfi_send_dcvstbl(struct gmu_device *gmu) 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); + return a6xx_hfi_send_generic_req(gmu, HFI_CMD_ID, &cmd); } -static int hfi_send_bwtbl(struct gmu_device *gmu) +static int a6xx_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); + return a6xx_hfi_send_generic_req(gmu, HFI_CMD_ID, cmd); } -static int hfi_send_acd_tbl(struct gmu_device *gmu) +static int a6xx_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); + return a6xx_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 gmu_device *gmu) { 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(gmu, HFI_CMD_ID, &cmd); } static void receive_err_req(struct gmu_device *gmu, void *rcvd) @@ -550,7 +551,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 gmu_device *gmu, uint32_t *rcvd, struct pending_cmd *ret_cmd) { /* V1 ACK Handler */ @@ -575,15 +576,15 @@ 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, +static void a6xx_hfi_process_queue(struct 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; } @@ -610,13 +611,13 @@ static void hfi_process_queue(struct gmu_device *gmu, uint32_t queue_idx, } } -void hfi_receiver(unsigned long data) +void a6xx_hfi_receiver(unsigned long data) { /* Process all asynchronous read (firmware to host) queues */ - hfi_process_queue((struct gmu_device *) data, HFI_DBG_ID, NULL); + a6xx_hfi_process_queue((struct gmu_device *) data, HFI_DBG_ID, NULL); } -static int hfi_verify_fw_version(struct kgsl_device *device, +static int a6xx_hfi_verify_fw_version(struct kgsl_device *device, struct gmu_device *gmu) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); @@ -631,7 +632,7 @@ 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(gmu, GMU_VERSION(major, minor), &ver); if (result) { dev_err_once(&gmu->pdev->dev, "Failed to get FW version via HFI\n"); @@ -655,7 +656,7 @@ static int hfi_verify_fw_version(struct kgsl_device *device, return 0; } -static int hfi_send_lm_feature_ctrl(struct gmu_device *gmu, +static int a6xx_hfi_send_lm_feature_ctrl(struct gmu_device *gmu, struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); @@ -674,30 +675,31 @@ 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(gmu, 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(gmu, H2F_MSG_SET_VALUE, &req); return ret; } -static int hfi_send_acd_feature_ctrl(struct gmu_device *gmu, +static int a6xx_hfi_send_acd_feature_ctrl(struct gmu_device *gmu, struct adreno_device *adreno_dev) { int ret = 0; if (adreno_dev->acd_enabled) { - ret = hfi_send_acd_tbl(gmu); + ret = a6xx_hfi_send_acd_tbl(gmu); if (!ret) - ret = hfi_send_feature_ctrl(gmu, HFI_FEATURE_ACD, 1, 0); + ret = a6xx_hfi_send_feature_ctrl(gmu, HFI_FEATURE_ACD, + 1, 0); } return ret; } -int hfi_start(struct kgsl_device *device, +int a6xx_hfi_start(struct kgsl_device *device, struct gmu_device *gmu, uint32_t boot_state) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); @@ -725,23 +727,23 @@ 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(gmu, boot_state); if (result) return result; } - result = hfi_verify_fw_version(device, gmu); + result = a6xx_hfi_verify_fw_version(device, gmu); if (result) return result; if (GMU_VER_MAJOR(gmu->ver.hfi) < 2) - result = hfi_send_dcvstbl_v1(gmu); + result = a6xx_hfi_send_dcvstbl_v1(gmu); else - result = hfi_send_dcvstbl(gmu); + result = a6xx_hfi_send_dcvstbl(gmu); if (result) return result; - result = hfi_send_bwtbl(gmu); + result = a6xx_hfi_send_bwtbl(gmu); if (result) return result; @@ -752,26 +754,26 @@ int hfi_start(struct kgsl_device *device, */ if (GMU_VER_MAJOR(gmu->ver.hfi) >= 2) { if (ADRENO_FEATURE(adreno_dev, ADRENO_ECP)) { - result = hfi_send_feature_ctrl(gmu, + result = a6xx_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(gmu, adreno_dev); if (result) return result; - result = hfi_send_lm_feature_ctrl(gmu, adreno_dev); + result = a6xx_hfi_send_lm_feature_ctrl(gmu, adreno_dev); if (result) return result; - result = hfi_send_core_fw_start(gmu); + result = a6xx_hfi_send_core_fw_start(gmu); if (result) return result; } else { if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) { - result = hfi_send_test(gmu); + result = a6xx_hfi_send_test(gmu); if (result) return result; } @@ -780,12 +782,12 @@ int hfi_start(struct kgsl_device *device, return 0; } -void hfi_stop(struct gmu_device *gmu) +void a6xx_hfi_stop(struct gmu_device *gmu) { struct gmu_memdesc *mem_addr = gmu->hfi_mem; struct hfi_queue_table *tbl = mem_addr->hostptr; struct hfi_queue_header *hdr; - struct kgsl_hfi *hfi = &gmu->hfi; + struct a6xx_hfi *hfi = &gmu->hfi; struct kgsl_device *device = hfi->kgsldev; unsigned int i; @@ -809,7 +811,7 @@ void hfi_stop(struct gmu_device *gmu) } /* 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 gmu_device *gmu, unsigned int id, void *data) { switch (id) { case H2F_MSG_GX_BW_PERF_VOTE: { @@ -817,7 +819,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(gmu, HFI_CMD_ID, cmd); } case H2F_MSG_PREPARE_SLUMBER: { struct hfi_prep_slumber_cmd *cmd = data; @@ -827,24 +829,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(gmu, 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(gmu, HFI_CMD_ID, cmd); } case H2F_MSG_GET_VALUE: { - return hfi_send_get_value(gmu, data); + return a6xx_hfi_send_get_value(gmu, 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(gmu, HFI_CMD_ID, cmd); } default: break; @@ -854,11 +856,11 @@ 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_hfi *hfi = &gmu->hfi; unsigned int status = 0; adreno_read_gmureg(ADRENO_DEVICE(device), diff --git a/drivers/gpu/msm/kgsl_hfi.h b/drivers/gpu/msm/adreno_a6xx_hfi.h similarity index 96% rename from drivers/gpu/msm/kgsl_hfi.h rename to drivers/gpu/msm/adreno_a6xx_hfi.h index a6d054be7e4c..60f770f99c51 100644 --- a/drivers/gpu/msm/kgsl_hfi.h +++ b/drivers/gpu/msm/adreno_a6xx_hfi.h @@ -1,9 +1,9 @@ /* 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 */ @@ -588,7 +588,7 @@ struct pending_cmd { }; /** - * struct kgsl_hfi - HFI control structure + * struct a6xx_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 @@ -598,7 +598,7 @@ struct pending_cmd { * @bwtbl_cmd: HFI BW table buffer * @acd_tbl_cmd: HFI table for ACD data */ -struct kgsl_hfi { +struct a6xx_hfi { struct kgsl_device *kgsldev; int hfi_interrupt_num; struct mutex cmdq_mutex; @@ -611,13 +611,13 @@ struct kgsl_hfi { struct gmu_device; struct gmu_memdesc; -irqreturn_t hfi_irq_handler(int irq, void *data); -int hfi_start(struct kgsl_device *device, struct gmu_device *gmu, +irqreturn_t a6xx_hfi_irq_handler(int irq, void *data); +int a6xx_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); +void a6xx_hfi_stop(struct gmu_device *gmu); +void a6xx_hfi_receiver(unsigned long data); +void a6xx_hfi_init(struct gmu_device *gmu); /* 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 */ +int a6xx_hfi_send_req(struct gmu_device *gmu, unsigned int id, void *data); +#endif /* __ADRENO_A6XX_HFI_H */ diff --git a/drivers/gpu/msm/kgsl_gmu.h b/drivers/gpu/msm/kgsl_gmu.h index c385c5e456ca..9c5416015268 100644 --- a/drivers/gpu/msm/kgsl_gmu.h +++ b/drivers/gpu/msm/kgsl_gmu.h @@ -7,8 +7,8 @@ #include +#include "adreno_a6xx_hfi.h" #include "kgsl_gmu_core.h" -#include "kgsl_hfi.h" #define GMU_PWR_LEVELS 2 #define GMU_FREQUENCY 200000000 @@ -176,7 +176,7 @@ struct gmu_device { 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 */ From 4c11fb7793a965d2e84858490e6f212f1760c6b2 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Wed, 1 Apr 2020 16:40:40 -0600 Subject: [PATCH 08/30] msm: kgsl: Finish the GMU transition to a6xx Finish the transition of the GMU code to a6xx. Rename the gmu_device to a6xx_gmu_device and move the header files. All GMU code should now exist entirely in the a6xx domain. Change-Id: Ic0dedbad3640906599421373bef38217fafbf6dc Signed-off-by: Jordan Crouse --- drivers/gpu/msm/adreno_a6xx_gmu.c | 139 +++++++++--------- .../gpu/msm/{kgsl_gmu.h => adreno_a6xx_gmu.h} | 12 +- drivers/gpu/msm/adreno_a6xx_hfi.c | 70 ++++----- drivers/gpu/msm/adreno_a6xx_hfi.h | 10 +- 4 files changed, 116 insertions(+), 115 deletions(-) rename drivers/gpu/msm/{kgsl_gmu.h => adreno_a6xx_gmu.h} (96%) diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index b2c335ba8006..b4fd51a0a5b1 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -19,10 +19,10 @@ #include "adreno.h" #include "adreno_a6xx.h" +#include "adreno_a6xx_gmu.h" #include "adreno_snapshot.h" #include "kgsl_bus.h" #include "kgsl_device.h" -#include "kgsl_gmu.h" #include "kgsl_trace.h" #include "kgsl_util.h" @@ -168,7 +168,7 @@ static void a6xx_load_rsc_ucode(struct kgsl_device *device) static int a6xx_load_pdc_ucode(struct kgsl_device *device) { - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct resource *res_pdc, *res_cfg, *res_seq; unsigned int cfg_offset, seq_offset; @@ -366,7 +366,7 @@ static int _load_gmu_rpmh_ucode(struct kgsl_device *device) static void a6xx_gmu_power_config(struct kgsl_device *device) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); /* Configure registers for idle setting. The setting is cumulative */ @@ -413,7 +413,7 @@ static void a6xx_gmu_power_config(struct kgsl_device *device) static int a6xx_gmu_device_start(struct kgsl_device *device) { - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); u32 val = 0x00000100; u32 mask = 0x000001FF; @@ -454,7 +454,7 @@ static int a6xx_gmu_device_start(struct kgsl_device *device) */ static int a6xx_gmu_hfi_start(struct kgsl_device *device) { - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); gmu_core_regwrite(device, A6XX_GMU_HFI_CTRL_INIT, 1); @@ -472,7 +472,7 @@ static int a6xx_gmu_hfi_start(struct kgsl_device *device) static int a6xx_rpmh_power_on_gpu(struct kgsl_device *device) { - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); struct device *dev = &gmu->pdev->dev; int val; @@ -528,7 +528,7 @@ error_rsc: static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device) { - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); struct adreno_device *adreno_dev = ADRENO_DEVICE(device); int ret; @@ -567,7 +567,7 @@ static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device) } static int _load_legacy_gmu_fw(struct kgsl_device *device, - struct gmu_device *gmu) + struct a6xx_gmu_device *gmu) { const struct firmware *fw = gmu->fw_image; @@ -582,7 +582,7 @@ static int _load_legacy_gmu_fw(struct kgsl_device *device, return 0; } -static struct gmu_memdesc *a6xx_gmu_get_memdesc(struct gmu_device *gmu, +static struct gmu_memdesc *a6xx_gmu_get_memdesc(struct a6xx_gmu_device *gmu, unsigned int addr, unsigned int size) { int i; @@ -604,7 +604,7 @@ static struct gmu_memdesc *a6xx_gmu_get_memdesc(struct gmu_device *gmu, static int load_gmu_fw(struct kgsl_device *device) { - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); uint8_t *fw = (uint8_t *)gmu->fw_image->data; int tcm_addr; struct gmu_block_header *blk; @@ -677,7 +677,7 @@ static int a6xx_gmu_oob_set(struct kgsl_device *device, enum oob_request req) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); int ret = 0; int set, check; @@ -723,7 +723,7 @@ static void a6xx_gmu_oob_clear(struct kgsl_device *device, enum oob_request req) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); int clear; if (adreno_is_a630(adreno_dev) || adreno_is_a615_family(adreno_dev)) { @@ -743,7 +743,7 @@ static void a6xx_gmu_oob_clear(struct kgsl_device *device, static void a6xx_gmu_irq_enable(struct kgsl_device *device) { - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); struct a6xx_hfi *hfi = &gmu->hfi; /* Clear pending IRQs and Unmask needed IRQs */ @@ -756,7 +756,7 @@ static void a6xx_gmu_irq_enable(struct kgsl_device *device) static void a6xx_gmu_irq_disable(struct kgsl_device *device) { - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); struct a6xx_hfi *hfi = &gmu->hfi; /* Disable all IRQs on host */ @@ -778,7 +778,7 @@ static int a6xx_gmu_hfi_start_msg(struct kgsl_device *device) * legacy firmware. */ if (!ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) - return a6xx_hfi_send_req(KGSL_GMU_DEVICE(device), + return a6xx_hfi_send_req(A6XX_GMU_DEVICE(device), H2F_MSG_START, &req); return 0; @@ -846,7 +846,7 @@ static int a6xx_complete_rpmh_votes(struct kgsl_device *device) int a6xx_gmu_sptprac_enable(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); if (!gmu_core_gpmu_isenabled(device) || !adreno_has_sptprac_gdsc(adreno_dev)) @@ -874,7 +874,7 @@ int a6xx_gmu_sptprac_enable(struct adreno_device *adreno_dev) void a6xx_gmu_sptprac_disable(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); if (!gmu_core_gpmu_isenabled(device) || !adreno_has_sptprac_gdsc(adreno_dev)) @@ -940,7 +940,7 @@ bool a6xx_gmu_sptprac_is_on(struct adreno_device *adreno_dev) static int a6xx_gmu_gfx_rail_on(struct kgsl_device *device) { struct kgsl_pwrctrl *pwr = &device->pwrctrl; - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); unsigned int perf_idx = gmu->num_gpupwrlevels - pwr->default_pwrlevel - 1; uint32_t default_opp = gmu->rpmh_votes.gx_votes[perf_idx]; @@ -993,7 +993,7 @@ static const char *idle_level_name(int level) static int a6xx_gmu_wait_for_lowest_idle(struct kgsl_device *device) { - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); unsigned int reg, reg1, reg2, reg3, reg4, reg5, reg6, reg7, reg8; unsigned long t; uint64_t ts1, ts2, ts3; @@ -1068,7 +1068,7 @@ static int a6xx_gmu_wait_for_lowest_idle(struct kgsl_device *device) #define CXGXCPUBUSYIGNAHB BIT(30) static int a6xx_gmu_wait_for_idle(struct kgsl_device *device) { - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); unsigned int status2; uint64_t ts1; @@ -1092,7 +1092,7 @@ static int a6xx_gmu_wait_for_idle(struct kgsl_device *device) static void load_gmu_version_info(struct kgsl_device *device) { - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); /* GMU version info is at a fixed offset in the DTCM */ gmu_core_regread(device, A6XX_GMU_CM3_DTCM_START + 0xFF8, @@ -1107,7 +1107,7 @@ static void load_gmu_version_info(struct kgsl_device *device) &gmu->ver.hfi); } -static void a6xx_gmu_mem_free(struct gmu_device *gmu, +static void a6xx_gmu_mem_free(struct a6xx_gmu_device *gmu, struct gmu_memdesc *md) { /* Free GMU image memory */ @@ -1126,7 +1126,7 @@ static int a6xx_gmu_fw_start(struct kgsl_device *device, unsigned int boot_state) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); const struct adreno_a6xx_core *a6xx_core = to_a6xx_core(adreno_dev); uint32_t gmu_log_info; int ret; @@ -1256,7 +1256,7 @@ static int a6xx_gmu_fw_start(struct kgsl_device *device, return ret; } -static int a6xx_gmu_alloc_and_map(struct gmu_device *gmu, +static int a6xx_gmu_alloc_and_map(struct a6xx_gmu_device *gmu, struct gmu_memdesc *md, unsigned int attrs) { struct iommu_domain *domain = a6xx_gmu_ctx[md->ctx_idx].domain; @@ -1290,7 +1290,7 @@ static int a6xx_gmu_alloc_and_map(struct gmu_device *gmu, * active SMMU entries of GMU kernel mode context. Each entry is assigned * a unique address inside GMU kernel mode address range. */ -static struct gmu_memdesc *a6xx_gmu_kmem_allocate(struct gmu_device *gmu, +static struct gmu_memdesc *a6xx_gmu_kmem_allocate(struct a6xx_gmu_device *gmu, enum gmu_mem_type mem_type, unsigned int addr, unsigned int size, unsigned int attrs) { @@ -1388,7 +1388,7 @@ static struct gmu_memdesc *a6xx_gmu_kmem_allocate(struct gmu_device *gmu, static int a6xx_gmu_cache_finalize(struct adreno_device *adreno_dev, - struct gmu_device *gmu) + struct a6xx_gmu_device *gmu) { struct gmu_memdesc *md; @@ -1430,7 +1430,7 @@ static int a6xx_gmu_cache_finalize(struct adreno_device *adreno_dev, return 0; } -static enum gmu_mem_type a6xx_gmu_get_blk_memtype(struct gmu_device *gmu, +static enum gmu_mem_type a6xx_gmu_get_blk_memtype(struct a6xx_gmu_device *gmu, struct gmu_block_header *blk) { int i; @@ -1445,7 +1445,7 @@ static enum gmu_mem_type a6xx_gmu_get_blk_memtype(struct gmu_device *gmu, return GMU_MEM_TYPE_MAX; } -static int a6xx_gmu_prealloc_req(struct gmu_device *gmu, +static int a6xx_gmu_prealloc_req(struct a6xx_gmu_device *gmu, struct gmu_block_header *blk) { enum gmu_mem_type type; @@ -1470,7 +1470,6 @@ static int a6xx_gmu_prealloc_req(struct gmu_device *gmu, return 0; } - /* * a6xx_gmu_load_firmware() - Load the ucode into the GPMU RAM & PDC/RSC * @device: Pointer to KGSL device @@ -1478,7 +1477,7 @@ static int a6xx_gmu_prealloc_req(struct gmu_device *gmu, static int a6xx_gmu_load_firmware(struct kgsl_device *device) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); const struct adreno_a6xx_core *a6xx_core = to_a6xx_core(adreno_dev); struct gmu_block_header *blk; int ret, offset = 0; @@ -1530,7 +1529,7 @@ static int a6xx_gmu_load_firmware(struct kgsl_device *device) } static int a6xx_gmu_memory_probe(struct adreno_device *adreno_dev, - struct gmu_device *gmu) + struct a6xx_gmu_device *gmu) { /* Allocates & maps memory for HFI */ if (IS_ERR_OR_NULL(gmu->hfi_mem)) @@ -1560,7 +1559,7 @@ static int a6xx_gmu_memory_probe(struct adreno_device *adreno_dev, static int a6xx_gmu_init(struct kgsl_device *device) { - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); int ret; ret = a6xx_gmu_load_firmware(device); @@ -1615,7 +1614,7 @@ static void do_gbif_halt(struct kgsl_device *device, u32 reg, u32 ack_reg, static int a6xx_gmu_pwrctrl_suspend(struct kgsl_device *device) { int ret = 0; - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); struct adreno_device *adreno_dev = ADRENO_DEVICE(device); /* If SPTP_RAC is on, turn off SPTP_RAC HS */ @@ -1696,7 +1695,7 @@ static int a6xx_gmu_notify_slumber(struct kgsl_device *device) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct kgsl_pwrctrl *pwr = &device->pwrctrl; - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); int bus_level = pwr->pwrlevels[pwr->default_pwrlevel].bus_freq; int perf_idx = gmu->num_gpupwrlevels - pwr->default_pwrlevel - 1; int ret, state; @@ -1754,7 +1753,7 @@ static int a6xx_gmu_rpmh_gpu_pwrctrl(struct kgsl_device *device, unsigned int mode, unsigned int arg1, unsigned int arg2) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); int ret; switch (mode) { @@ -1788,7 +1787,7 @@ static int a6xx_gmu_rpmh_gpu_pwrctrl(struct kgsl_device *device, static int a6xx_gmu_suspend(struct kgsl_device *device) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); if (!test_bit(GMU_CLK_ON, &device->gmu_core.flags)) return 0; @@ -1826,7 +1825,7 @@ static int a6xx_gmu_dcvs_set(struct kgsl_device *device, { int ret = 0; struct kgsl_pwrctrl *pwr = &device->pwrctrl; - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct hfi_gx_bw_perf_vote_cmd req = { .ack_type = DCVS_ACK_BLOCK, @@ -1930,7 +1929,7 @@ static int a6xx_gmu_ifpc_store(struct kgsl_device *device, unsigned int val) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); unsigned int requested_idle_level; if (!ADRENO_FEATURE(adreno_dev, ADRENO_IFPC)) @@ -1963,7 +1962,7 @@ static int a6xx_gmu_ifpc_store(struct kgsl_device *device, static unsigned int a6xx_gmu_ifpc_show(struct kgsl_device *device) { - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); return gmu->idle_level >= GPU_HW_IFPC; } @@ -2013,7 +2012,7 @@ struct a6xx_tcm_data { static size_t a6xx_snapshot_gmu_tcm(struct kgsl_device *device, u8 *buf, size_t remain, void *priv) { - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); struct kgsl_snapshot_gmu_mem *mem_hdr = (struct kgsl_snapshot_gmu_mem *)buf; unsigned int *data = (unsigned int *)(buf + sizeof(*mem_hdr)); @@ -2041,7 +2040,7 @@ static size_t a6xx_snapshot_gmu_tcm(struct kgsl_device *device, static void a6xx_gmu_snapshot_memories(struct kgsl_device *device, struct kgsl_snapshot *snapshot) { - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); struct gmu_mem_type_desc desc; struct gmu_memdesc *md; int i; @@ -2121,7 +2120,7 @@ static void a6xx_gmu_snapshot_versions(struct kgsl_device *device, struct kgsl_snapshot *snapshot) { int i; - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); struct kgsl_snapshot_gmu_version gmu_vers[] = { { .type = SNAPSHOT_DEBUG_GMU_CORE_VERSION, .value = gmu->ver.core, }, @@ -2190,7 +2189,7 @@ static void a6xx_gmu_device_snapshot(struct kgsl_device *device, static void a6xx_gmu_cooperative_reset(struct kgsl_device *device) { - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); unsigned int result; gmu_core_regwrite(device, A6XX_GMU_CX_GMU_WDOG_CTRL, 0); @@ -2223,7 +2222,7 @@ static int a6xx_gmu_wait_for_active_transition( struct kgsl_device *device) { unsigned int reg, num_retries; - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); gmu_core_regread(device, A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE, ®); @@ -2261,7 +2260,7 @@ static u64 a6xx_gmu_read_alwayson(struct kgsl_device *device) static irqreturn_t a6xx_gmu_irq_handler(int irq, void *data) { struct kgsl_device *device = data; - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); struct adreno_device *adreno_dev = ADRENO_DEVICE(device); unsigned int mask, status = 0; @@ -2320,7 +2319,7 @@ static irqreturn_t a6xx_gmu_irq_handler(int irq, void *data) static void a6xx_gmu_snapshot(struct kgsl_device *device) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); /* Abstain from sending another nmi or over-writing snapshot */ if (test_and_set_bit(GMU_FAULT, &device->gmu_core.flags)) @@ -2354,7 +2353,7 @@ static void a6xx_gmu_snapshot(struct kgsl_device *device) /* Caller shall ensure GPU is ready for SLUMBER */ static void a6xx_gmu_stop(struct kgsl_device *device) { - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); struct kgsl_pwrctrl *pwr = &device->pwrctrl; int ret = 0; @@ -2425,7 +2424,7 @@ static int a6xx_gmu_aop_send_acd_state(struct mbox_chan *channel, bool flag) static int a6xx_gmu_enable_gdsc(struct kgsl_device *device) { - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); int ret; ret = regulator_enable(gmu->cx_gdsc); @@ -2436,7 +2435,7 @@ static int a6xx_gmu_enable_gdsc(struct kgsl_device *device) return ret; } -static int a6xx_gmu_clk_set_rate(struct gmu_device *gmu, const char *id, +static int a6xx_gmu_clk_set_rate(struct a6xx_gmu_device *gmu, const char *id, unsigned long rate) { struct clk *clk; @@ -2450,7 +2449,7 @@ static int a6xx_gmu_clk_set_rate(struct gmu_device *gmu, const char *id, static int a6xx_gmu_enable_clks(struct kgsl_device *device) { - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); int ret; ret = a6xx_gmu_clk_set_rate(gmu, "gmu_clk", GMU_FREQUENCY); @@ -2481,7 +2480,7 @@ static int a6xx_gmu_start_from_init(struct kgsl_device *device) { struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); int level, ret; if (device->state == KGSL_STATE_INIT) { @@ -2517,7 +2516,7 @@ static int a6xx_gmu_start_from_init(struct kgsl_device *device) static int a6xx_gmu_start_from_slumber(struct kgsl_device *device) { - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); int ret; WARN_ON(test_bit(GMU_CLK_ON, &device->gmu_core.flags)); @@ -2540,7 +2539,7 @@ static int a6xx_gmu_start_from_slumber(struct kgsl_device *device) static int a6xx_gmu_start_from_reset(struct kgsl_device *device) { - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); int ret; a6xx_gmu_suspend(device); @@ -2594,7 +2593,7 @@ static int a6xx_gmu_start(struct kgsl_device *device) static int a6xx_gmu_acd_set(struct kgsl_device *device, bool val) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); int ret; if (IS_ERR_OR_NULL(gmu->mailbox.channel)) @@ -2680,7 +2679,7 @@ static int a6xx_gmu_bus_set(struct kgsl_device *device, int buslevel, static void a6xx_gmu_iommu_cb_close(struct gmu_iommu_context *ctx); -static void a6xx_gmu_memory_close(struct gmu_device *gmu) +static void a6xx_gmu_memory_close(struct a6xx_gmu_device *gmu) { int i; struct gmu_memdesc *md; @@ -2713,7 +2712,7 @@ static void a6xx_gmu_memory_close(struct gmu_device *gmu) } static int a6xx_gmu_aop_mailbox_init(struct adreno_device *adreno_dev, - struct gmu_device *gmu) + struct a6xx_gmu_device *gmu) { struct kgsl_mailbox *mailbox = &gmu->mailbox; @@ -2731,7 +2730,7 @@ static int a6xx_gmu_aop_mailbox_init(struct adreno_device *adreno_dev, } static void a6xx_gmu_acd_probe(struct kgsl_device *device, - struct gmu_device *gmu, struct device_node *node) + struct a6xx_gmu_device *gmu, struct device_node *node) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct kgsl_pwrctrl *pwr = &device->pwrctrl; @@ -2786,7 +2785,7 @@ enum rpmh_vote_type { * @arc: Pointer to RPMh rail controller (ARC) voltage table * @res_id: Pointer to 8 char array that contains rail name */ -static int rpmh_arc_cmds(struct gmu_device *gmu, +static int rpmh_arc_cmds(struct a6xx_gmu_device *gmu, struct rpmh_arc_vals *arc, const char *res_id) { size_t len = 0; @@ -2868,7 +2867,7 @@ static int setup_volt_dependency_tbl(uint32_t *votes, return 0; } -static int rpmh_gmu_arc_votes_init(struct gmu_device *gmu, +static int rpmh_gmu_arc_votes_init(struct a6xx_gmu_device *gmu, struct rpmh_arc_vals *pri_rail, struct rpmh_arc_vals *sec_rail) { /* Hardcoded values of GMU CX voltage levels */ @@ -2889,7 +2888,7 @@ static int rpmh_gmu_arc_votes_init(struct gmu_device *gmu, * @type: the type of the primary rail, GPU or GMU */ static int rpmh_arc_votes_init(struct kgsl_device *device, - struct gmu_device *gmu, struct rpmh_arc_vals *pri_rail, + struct a6xx_gmu_device *gmu, struct rpmh_arc_vals *pri_rail, struct rpmh_arc_vals *sec_rail, unsigned int type) { unsigned int num_freqs; @@ -3125,7 +3124,7 @@ static void build_bwtable_cmd_cache(struct hfi_bwtable_cmd *cmd, static int a6xx_gmu_bus_vote_init(struct kgsl_device *device) { - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct rpmh_bw_votes *ddr, *cnoc = NULL; u32 *cnoc_table; @@ -3162,7 +3161,7 @@ static int a6xx_gmu_bus_vote_init(struct kgsl_device *device) } static int a6xx_gmu_rpmh_init(struct kgsl_device *device, - struct gmu_device *gmu) + struct a6xx_gmu_device *gmu) { struct rpmh_arc_vals gfx_arc, cx_arc, mx_arc; int ret; @@ -3195,7 +3194,7 @@ static int a6xx_gmu_rpmh_init(struct kgsl_device *device, static int a6xx_gmu_reg_probe(struct kgsl_device *device) { - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); struct resource *res; res = platform_get_resource_byname(gmu->pdev, IORESOURCE_MEM, @@ -3223,7 +3222,7 @@ static int a6xx_gmu_reg_probe(struct kgsl_device *device) return 0; } -static int a6xx_gmu_tcm_init(struct gmu_device *gmu) +static int a6xx_gmu_tcm_init(struct a6xx_gmu_device *gmu) { struct gmu_memdesc *md; @@ -3277,8 +3276,7 @@ static int a6xx_gmu_user_fault_handler(struct iommu_domain *domain, return a6xx_gmu_iommu_fault_handler(domain, dev, addr, flags, token, "gmu_user"); } - -static int a6xx_gmu_iommu_cb_probe(struct gmu_device *gmu, +static int a6xx_gmu_iommu_cb_probe(struct a6xx_gmu_device *gmu, const char *name, struct gmu_iommu_context *ctx, struct device_node *parent, iommu_fault_handler_t handler) { @@ -3334,7 +3332,8 @@ static void a6xx_gmu_iommu_cb_close(struct gmu_iommu_context *ctx) ctx->domain = NULL; } -static int a6xx_gmu_iommu_init(struct gmu_device *gmu, struct device_node *node) +static int a6xx_gmu_iommu_init(struct a6xx_gmu_device *gmu, + struct device_node *node) { int ret; @@ -3351,7 +3350,7 @@ static int a6xx_gmu_iommu_init(struct gmu_device *gmu, struct device_node *node) a6xx_gmu_kernel_fault_handler); } -static int a6xx_gmu_regulators_probe(struct gmu_device *gmu, +static int a6xx_gmu_regulators_probe(struct a6xx_gmu_device *gmu, struct platform_device *pdev) { gmu->cx_gdsc = devm_regulator_get(&pdev->dev, "vddcx"); @@ -3374,7 +3373,7 @@ static int a6xx_gmu_regulators_probe(struct gmu_device *gmu, static void a6xx_gmu_remove(struct kgsl_device *device) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); tasklet_kill(&gmu->hfi.tasklet); @@ -3396,7 +3395,7 @@ static void a6xx_gmu_remove(struct kgsl_device *device) static int a6xx_gmu_probe(struct kgsl_device *device, struct platform_device *pdev) { - struct gmu_device *gmu; + struct a6xx_gmu_device *gmu; struct a6xx_hfi *hfi; struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct adreno_device *adreno_dev = ADRENO_DEVICE(device); diff --git a/drivers/gpu/msm/kgsl_gmu.h b/drivers/gpu/msm/adreno_a6xx_gmu.h similarity index 96% rename from drivers/gpu/msm/kgsl_gmu.h rename to drivers/gpu/msm/adreno_a6xx_gmu.h index 9c5416015268..d1de4e6ce916 100644 --- a/drivers/gpu/msm/kgsl_gmu.h +++ b/drivers/gpu/msm/adreno_a6xx_gmu.h @@ -2,8 +2,8 @@ /* * 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 @@ -81,7 +81,7 @@ struct gmu_block_header { /* GMU memdesc entries */ #define GMU_KERNEL_ENTRIES 16 -#define KGSL_GMU_DEVICE(_a) ((struct gmu_device *)((_a)->gmu_core.ptr)) +#define A6XX_GMU_DEVICE(_a) ((struct a6xx_gmu_device *)((_a)->gmu_core.ptr)) enum gmu_mem_type { GMU_ITCM = 0, @@ -138,7 +138,7 @@ struct kgsl_mailbox { struct icc_path; /** - * struct gmu_device - GMU device structure + * struct a6xx_gmu_device - GMU device structure * @ver: GMU Version information * @gmu_interrupt_num: GMU interrupt number * @fw_image: GMU FW image @@ -162,7 +162,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; @@ -207,4 +207,4 @@ struct gmu_device { atomic_t cm3_fault; }; -#endif /* __KGSL_GMU_H */ +#endif diff --git a/drivers/gpu/msm/adreno_a6xx_hfi.c b/drivers/gpu/msm/adreno_a6xx_hfi.c index 45c8014ed626..68752897ddb9 100644 --- a/drivers/gpu/msm/adreno_a6xx_hfi.c +++ b/drivers/gpu/msm/adreno_a6xx_hfi.c @@ -8,9 +8,9 @@ #include "adreno.h" #include "adreno_a6xx.h" +#include "adreno_a6xx_gmu.h" #include "adreno_a6xx_hfi.h" #include "kgsl_device.h" -#include "kgsl_gmu.h" #include "kgsl_trace.h" #define HFI_QUEUE_OFFSET(i) \ @@ -34,11 +34,11 @@ #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 a6xx_hfi_process_queue(struct gmu_device *gmu, uint32_t queue_idx, - struct pending_cmd *ret_cmd); +static void 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 a6xx_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; @@ -97,7 +97,7 @@ done: } /* Size in below functions are in unit of dwords */ -static int a6xx_hfi_queue_write(struct gmu_device *gmu, uint32_t queue_idx, +static int a6xx_hfi_queue_write(struct a6xx_gmu_device *gmu, uint32_t queue_idx, uint32_t *msg) { struct hfi_queue_table *tbl = gmu->hfi_mem->hostptr; @@ -173,7 +173,7 @@ static int a6xx_hfi_queue_write(struct gmu_device *gmu, uint32_t queue_idx, /* Sizes of the queue and message are in unit of dwords */ -void a6xx_hfi_init(struct gmu_device *gmu) +void a6xx_hfi_init(struct a6xx_gmu_device *gmu) { struct a6xx_hfi *hfi = &gmu->hfi; struct adreno_device *adreno_dev = ADRENO_DEVICE(hfi->kgsldev); @@ -229,7 +229,7 @@ void a6xx_hfi_init(struct gmu_device *gmu) #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 void receive_ack_cmd(struct a6xx_gmu_device *gmu, void *rcvd, struct pending_cmd *ret_cmd) { uint32_t *ack = rcvd; @@ -267,7 +267,7 @@ static int poll_adreno_gmu_reg(struct adreno_device *adreno_dev, { unsigned int val; struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); u64 ao_pre_poll, ao_post_poll; @@ -293,7 +293,7 @@ static int poll_adreno_gmu_reg(struct adreno_device *adreno_dev, return -ETIMEDOUT; } -static int a6xx_hfi_send_cmd(struct gmu_device *gmu, uint32_t queue_idx, +static int a6xx_hfi_send_cmd(struct a6xx_gmu_device *gmu, uint32_t queue_idx, void *data, struct pending_cmd *ret_cmd) { int rc; @@ -333,8 +333,8 @@ static int a6xx_hfi_send_cmd(struct gmu_device *gmu, uint32_t queue_idx, #define HFI_ACK_ERROR 0xffffffff -static int a6xx_hfi_send_generic_req(struct gmu_device *gmu, uint32_t queue, - void *cmd) +static int a6xx_hfi_send_generic_req(struct a6xx_gmu_device *gmu, + uint32_t queue, void *cmd) { struct pending_cmd ret_cmd; int rc; @@ -352,7 +352,8 @@ static int a6xx_hfi_send_generic_req(struct gmu_device *gmu, uint32_t queue, return rc; } -static int a6xx_hfi_send_gmu_init(struct gmu_device *gmu, uint32_t boot_state) +static int a6xx_hfi_send_gmu_init(struct a6xx_gmu_device *gmu, + uint32_t boot_state) { struct hfi_gmu_init_cmd cmd = { .hdr = CMD_MSG_HDR(H2F_MSG_INIT, sizeof(cmd)), @@ -365,7 +366,7 @@ static int a6xx_hfi_send_gmu_init(struct gmu_device *gmu, uint32_t boot_state) return a6xx_hfi_send_generic_req(gmu, HFI_CMD_ID, &cmd); } -static int a6xx_hfi_get_fw_version(struct gmu_device *gmu, +static int a6xx_hfi_get_fw_version(struct a6xx_gmu_device *gmu, uint32_t expected_ver, uint32_t *ver) { struct hfi_fw_version_cmd cmd = { @@ -391,7 +392,7 @@ static int a6xx_hfi_get_fw_version(struct gmu_device *gmu, return rc; } -static int a6xx_hfi_send_core_fw_start(struct gmu_device *gmu) +static int a6xx_hfi_send_core_fw_start(struct a6xx_gmu_device *gmu) { struct hfi_core_fw_start_cmd cmd = { .hdr = CMD_MSG_HDR(H2F_MSG_CORE_FW_START, sizeof(cmd)), @@ -416,7 +417,7 @@ static const char *feature_to_string(uint32_t feature) return "unknown"; } -static int a6xx_hfi_send_feature_ctrl(struct gmu_device *gmu, +static int a6xx_hfi_send_feature_ctrl(struct a6xx_gmu_device *gmu, uint32_t feature, uint32_t enable, uint32_t data) { struct hfi_feature_ctrl_cmd cmd = { @@ -437,7 +438,7 @@ static int a6xx_hfi_send_feature_ctrl(struct gmu_device *gmu, return ret; } -static int a6xx_hfi_send_dcvstbl_v1(struct gmu_device *gmu) +static int a6xx_hfi_send_dcvstbl_v1(struct a6xx_gmu_device *gmu) { struct hfi_dcvstable_v1_cmd cmd = { .hdr = CMD_MSG_HDR(H2F_MSG_PERF_TBL, sizeof(cmd)), @@ -460,7 +461,7 @@ static int a6xx_hfi_send_dcvstbl_v1(struct gmu_device *gmu) return a6xx_hfi_send_generic_req(gmu, HFI_CMD_ID, &cmd); } -static int a6xx_hfi_send_get_value(struct gmu_device *gmu, +static int a6xx_hfi_send_get_value(struct a6xx_gmu_device *gmu, struct hfi_get_value_req *req) { struct hfi_get_value_cmd *cmd = &req->cmd; @@ -481,7 +482,7 @@ static int a6xx_hfi_send_get_value(struct gmu_device *gmu, return 0; } -static int a6xx_hfi_send_dcvstbl(struct gmu_device *gmu) +static int a6xx_hfi_send_dcvstbl(struct a6xx_gmu_device *gmu) { struct hfi_dcvstable_cmd cmd = { .hdr = CMD_MSG_HDR(H2F_MSG_PERF_TBL, sizeof(cmd)), @@ -506,7 +507,7 @@ static int a6xx_hfi_send_dcvstbl(struct gmu_device *gmu) return a6xx_hfi_send_generic_req(gmu, HFI_CMD_ID, &cmd); } -static int a6xx_hfi_send_bwtbl(struct gmu_device *gmu) +static int a6xx_hfi_send_bwtbl(struct a6xx_gmu_device *gmu) { struct hfi_bwtable_cmd *cmd = &gmu->hfi.bwtbl_cmd; @@ -515,7 +516,7 @@ static int a6xx_hfi_send_bwtbl(struct gmu_device *gmu) return a6xx_hfi_send_generic_req(gmu, HFI_CMD_ID, cmd); } -static int a6xx_hfi_send_acd_tbl(struct gmu_device *gmu) +static int a6xx_hfi_send_acd_tbl(struct a6xx_gmu_device *gmu) { struct hfi_acd_table_cmd *cmd = &gmu->hfi.acd_tbl_cmd; @@ -524,7 +525,7 @@ static int a6xx_hfi_send_acd_tbl(struct gmu_device *gmu) return a6xx_hfi_send_generic_req(gmu, HFI_CMD_IDX, cmd); } -static int a6xx_hfi_send_test(struct gmu_device *gmu) +static int a6xx_hfi_send_test(struct a6xx_gmu_device *gmu) { struct hfi_test_cmd cmd = { .hdr = CMD_MSG_HDR(H2F_MSG_TEST, sizeof(cmd)), @@ -533,7 +534,7 @@ static int a6xx_hfi_send_test(struct gmu_device *gmu) return a6xx_hfi_send_generic_req(gmu, 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; @@ -543,7 +544,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; @@ -551,7 +552,7 @@ static void receive_debug_req(struct gmu_device *gmu, void *rcvd) cmd->type, cmd->timestamp, cmd->data); } -static void a6xx_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 */ @@ -576,8 +577,8 @@ static void a6xx_hfi_v1_receiver(struct gmu_device *gmu, uint32_t *rcvd, } } -static void a6xx_hfi_process_queue(struct gmu_device *gmu, uint32_t queue_idx, - struct pending_cmd *ret_cmd) +static void a6xx_hfi_process_queue(struct a6xx_gmu_device *gmu, + uint32_t queue_idx, struct pending_cmd *ret_cmd) { uint32_t rcvd[MAX_RCVD_SIZE]; @@ -614,11 +615,12 @@ static void a6xx_hfi_process_queue(struct gmu_device *gmu, uint32_t queue_idx, void a6xx_hfi_receiver(unsigned long data) { /* Process all asynchronous read (firmware to host) queues */ - a6xx_hfi_process_queue((struct gmu_device *) data, HFI_DBG_ID, NULL); + a6xx_hfi_process_queue((struct a6xx_gmu_device *) data, HFI_DBG_ID, + NULL); } static int a6xx_hfi_verify_fw_version(struct kgsl_device *device, - struct gmu_device *gmu) + struct a6xx_gmu_device *gmu) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); const struct adreno_a6xx_core *a6xx_core = to_a6xx_core(adreno_dev); @@ -656,7 +658,7 @@ static int a6xx_hfi_verify_fw_version(struct kgsl_device *device, return 0; } -static int a6xx_hfi_send_lm_feature_ctrl(struct gmu_device *gmu, +static int a6xx_hfi_send_lm_feature_ctrl(struct a6xx_gmu_device *gmu, struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); @@ -684,7 +686,7 @@ static int a6xx_hfi_send_lm_feature_ctrl(struct gmu_device *gmu, return ret; } -static int a6xx_hfi_send_acd_feature_ctrl(struct gmu_device *gmu, +static int a6xx_hfi_send_acd_feature_ctrl(struct a6xx_gmu_device *gmu, struct adreno_device *adreno_dev) { int ret = 0; @@ -700,7 +702,7 @@ static int a6xx_hfi_send_acd_feature_ctrl(struct gmu_device *gmu, } int a6xx_hfi_start(struct kgsl_device *device, - struct gmu_device *gmu, uint32_t boot_state) + struct a6xx_gmu_device *gmu, uint32_t boot_state) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct gmu_memdesc *mem_addr = gmu->hfi_mem; @@ -782,7 +784,7 @@ int a6xx_hfi_start(struct kgsl_device *device, return 0; } -void a6xx_hfi_stop(struct gmu_device *gmu) +void a6xx_hfi_stop(struct a6xx_gmu_device *gmu) { struct gmu_memdesc *mem_addr = gmu->hfi_mem; struct hfi_queue_table *tbl = mem_addr->hostptr; @@ -811,7 +813,7 @@ void a6xx_hfi_stop(struct gmu_device *gmu) } /* Entry point for external HFI requests */ -int a6xx_hfi_send_req(struct gmu_device *gmu, unsigned int id, void *data) +int a6xx_hfi_send_req(struct a6xx_gmu_device *gmu, unsigned int id, void *data) { switch (id) { case H2F_MSG_GX_BW_PERF_VOTE: { @@ -859,7 +861,7 @@ int a6xx_hfi_send_req(struct gmu_device *gmu, unsigned int id, 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 a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); struct a6xx_hfi *hfi = &gmu->hfi; unsigned int status = 0; diff --git a/drivers/gpu/msm/adreno_a6xx_hfi.h b/drivers/gpu/msm/adreno_a6xx_hfi.h index 60f770f99c51..ee1a25c15769 100644 --- a/drivers/gpu/msm/adreno_a6xx_hfi.h +++ b/drivers/gpu/msm/adreno_a6xx_hfi.h @@ -608,16 +608,16 @@ struct a6xx_hfi { struct hfi_acd_table_cmd acd_tbl_cmd; }; -struct gmu_device; +struct a6xx_gmu_device; struct gmu_memdesc; irqreturn_t a6xx_hfi_irq_handler(int irq, void *data); -int a6xx_hfi_start(struct kgsl_device *device, struct gmu_device *gmu, +int a6xx_hfi_start(struct kgsl_device *device, struct a6xx_gmu_device *gmu, uint32_t boot_state); -void a6xx_hfi_stop(struct gmu_device *gmu); +void a6xx_hfi_stop(struct a6xx_gmu_device *gmu); void a6xx_hfi_receiver(unsigned long data); -void a6xx_hfi_init(struct gmu_device *gmu); +void a6xx_hfi_init(struct a6xx_gmu_device *gmu); /* hfi_send_req is only for external (to HFI) requests */ -int a6xx_hfi_send_req(struct gmu_device *gmu, unsigned int id, void *data); +int a6xx_hfi_send_req(struct a6xx_gmu_device *gmu, unsigned int id, void *data); #endif /* __ADRENO_A6XX_HFI_H */ From 455046da215bf856c9e4d0062772e4067c58e242 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Mon, 6 Apr 2020 10:18:12 -0600 Subject: [PATCH 09/30] msm: kgsl: Move RGMU to the a6xx target specific space Much like the GMU code, the GMU code belongs in the a6xx target specific space. Luckily, it is a lot easier to move. Move everything to adreno_a6xx_rgmu.[ch] and rename the functions and structs. Change-Id: Ic0dedbadf9f16f458f1cb1e540960a074464b348 Signed-off-by: Jordan Crouse --- drivers/gpu/msm/Makefile | 1 - drivers/gpu/msm/adreno_a6xx_rgmu.c | 483 +++++++++++++++++- .../msm/{kgsl_rgmu.h => adreno_a6xx_rgmu.h} | 15 +- drivers/gpu/msm/kgsl.h | 2 +- drivers/gpu/msm/kgsl_gmu_core.c | 2 +- drivers/gpu/msm/kgsl_gmu_core.h | 2 +- drivers/gpu/msm/kgsl_rgmu.c | 461 ----------------- 7 files changed, 471 insertions(+), 495 deletions(-) rename drivers/gpu/msm/{kgsl_rgmu.h => adreno_a6xx_rgmu.h} (79%) delete mode 100644 drivers/gpu/msm/kgsl_rgmu.c diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile index b59779d910c7..2f1cc3f757a6 100644 --- a/drivers/gpu/msm/Makefile +++ b/drivers/gpu/msm/Makefile @@ -14,7 +14,6 @@ msm_kgsl-y = \ kgsl_pool.o \ kgsl_pwrctrl.o \ kgsl_pwrscale.o \ - kgsl_rgmu.o \ kgsl_sharedmem.o \ kgsl_snapshot.o \ kgsl_trace.o \ diff --git a/drivers/gpu/msm/adreno_a6xx_rgmu.c b/drivers/gpu/msm/adreno_a6xx_rgmu.c index af229d91f81d..74cd52cbb126 100644 --- a/drivers/gpu/msm/adreno_a6xx_rgmu.c +++ b/drivers/gpu/msm/adreno_a6xx_rgmu.c @@ -3,14 +3,23 @@ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ +#include +#include +#include #include +#include +#include +#include #include #include "adreno.h" #include "adreno_a6xx.h" +#include "adreno_a6xx_rgmu.h" #include "adreno_snapshot.h" -#include "kgsl_rgmu.h" #include "kgsl_trace.h" +#include "kgsl_util.h" + +#define RGMU_CLK_FREQ 200000000 /* RGMU timeouts */ #define RGMU_IDLE_TIMEOUT 100 /* ms */ @@ -31,10 +40,10 @@ static const unsigned int a6xx_rgmu_registers[] = { 0x26000, 0x26002, }; -irqreturn_t rgmu_irq_handler(int irq, void *data) +static irqreturn_t a6xx_rgmu_irq_handler(int irq, void *data) { struct kgsl_device *device = data; - struct rgmu_device *rgmu = KGSL_RGMU_DEVICE(device); + struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); unsigned int status = 0; gmu_core_regread(device, A6XX_GMU_AO_HOST_INTERRUPT_STATUS, &status); @@ -59,10 +68,10 @@ irqreturn_t rgmu_irq_handler(int irq, void *data) return IRQ_HANDLED; } -irqreturn_t oob_irq_handler(int irq, void *data) +static irqreturn_t a6xx_oob_irq_handler(int irq, void *data) { struct kgsl_device *device = data; - struct rgmu_device *rgmu = KGSL_RGMU_DEVICE(device); + struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); struct adreno_device *adreno_dev = ADRENO_DEVICE(device); unsigned int status = 0; @@ -101,7 +110,7 @@ static const char *oob_to_str(enum oob_request req) static int a6xx_rgmu_oob_set(struct kgsl_device *device, enum oob_request req) { - struct rgmu_device *rgmu = KGSL_RGMU_DEVICE(device); + struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); int ret, set, check; set = BIT(req + 16); @@ -144,7 +153,7 @@ static void a6xx_rgmu_oob_clear(struct kgsl_device *device, static void a6xx_rgmu_bcl_config(struct kgsl_device *device, bool on) { - struct rgmu_device *rgmu = KGSL_RGMU_DEVICE(device); + struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); if (on) { /* Enable BCL CRC HW i/f */ @@ -171,7 +180,7 @@ static void a6xx_rgmu_bcl_config(struct kgsl_device *device, bool on) static void a6xx_rgmu_irq_enable(struct kgsl_device *device) { - struct rgmu_device *rgmu = KGSL_RGMU_DEVICE(device); + struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); /* Clear pending IRQs and Unmask needed IRQs */ adreno_gmu_clear_and_unmask_irqs(ADRENO_DEVICE(device)); @@ -183,7 +192,7 @@ static void a6xx_rgmu_irq_enable(struct kgsl_device *device) static void a6xx_rgmu_irq_disable(struct kgsl_device *device) { - struct rgmu_device *rgmu = KGSL_RGMU_DEVICE(device); + struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); /* Disable all IRQs on host */ disable_irq(rgmu->rgmu_interrupt_num); @@ -197,7 +206,7 @@ static int a6xx_rgmu_ifpc_store(struct kgsl_device *device, unsigned int val) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct rgmu_device *rgmu = KGSL_RGMU_DEVICE(device); + struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); unsigned int requested_idle_level; if (!ADRENO_FEATURE(adreno_dev, ADRENO_IFPC)) @@ -225,7 +234,7 @@ static int a6xx_rgmu_ifpc_store(struct kgsl_device *device, static unsigned int a6xx_rgmu_ifpc_show(struct kgsl_device *device) { - struct rgmu_device *rgmu = KGSL_RGMU_DEVICE(device); + struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); return rgmu->idle_level == GPU_HW_IFPC; } @@ -256,7 +265,7 @@ static bool a6xx_rgmu_gx_is_on(struct kgsl_device *device) static int a6xx_rgmu_wait_for_lowest_idle(struct kgsl_device *device) { - struct rgmu_device *rgmu = KGSL_RGMU_DEVICE(device); + struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); unsigned int reg[10] = {0}; unsigned long t; uint64_t ts1, ts2, ts3; @@ -344,7 +353,7 @@ static int a6xx_rgmu_wait_for_lowest_idle(struct kgsl_device *device) static int a6xx_rgmu_fw_start(struct kgsl_device *device, unsigned int boot_state) { - struct rgmu_device *rgmu = KGSL_RGMU_DEVICE(device); + struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); unsigned int status; int i; @@ -420,9 +429,9 @@ static int a6xx_rgmu_fw_start(struct kgsl_device *device, return 0; } -static int a6xx_rgmu_suspend(struct kgsl_device *device) +static int a6xx_rgmu_suspend_device(struct kgsl_device *device) { - struct rgmu_device *rgmu = KGSL_RGMU_DEVICE(device); + struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); int ret = 0; /* Check GX GDSC is status */ @@ -467,7 +476,7 @@ static int a6xx_rgmu_gpu_pwrctrl(struct kgsl_device *device, ret = a6xx_rgmu_fw_start(device, arg1); break; case GMU_SUSPEND: - ret = a6xx_rgmu_suspend(device); + ret = a6xx_rgmu_suspend_device(device); break; case GMU_NOTIFY_SLUMBER: @@ -487,6 +496,178 @@ static int a6xx_rgmu_gpu_pwrctrl(struct kgsl_device *device, return ret; } +static void a6xx_rgmu_disable_clks(struct kgsl_device *device) +{ + struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); + int ret; + + /* Check GX GDSC is status */ + if (a6xx_rgmu_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 (a6xx_rgmu_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 a6xx_rgmu_disable_gdsc(struct kgsl_device *device) +{ + struct a6xx_rgmu_device *rgmu = A6XX_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 void a6xx_rgmu_halt_execution(struct kgsl_device *device); + +static void a6xx_rgmu_snapshot(struct kgsl_device *device) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct a6xx_rgmu_device *rgmu = A6XX_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. + */ + a6xx_rgmu_halt_execution(device); + + kgsl_device_snapshot(device, NULL, true); + + gmu_core_regwrite(device, A6XX_GMU_GMU2HOST_INTR_CLR, 0xffffffff); + gmu_core_regwrite(device, A6XX_GMU_GMU2HOST_INTR_MASK, + RGMU_OOB_IRQ_MASK); + + rgmu->fault_count++; +} + +static int a6xx_rgmu_suspend(struct kgsl_device *device) +{ + if (!test_bit(GMU_CLK_ON, &device->gmu_core.flags)) + return 0; + + a6xx_rgmu_irq_disable(device); + + if (a6xx_rgmu_gpu_pwrctrl(device, GMU_SUSPEND, 0, 0)) + return -EINVAL; + + a6xx_rgmu_disable_clks(device); + a6xx_rgmu_disable_gdsc(device); + return 0; +} + +static int a6xx_rgmu_enable_clks(struct kgsl_device *device) +{ + int ret; + struct a6xx_rgmu_device *rgmu = A6XX_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 a6xx_rgmu_enable_gdsc(struct a6xx_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; +} + +/* To be called to power on both GPU and RGMU */ +static int a6xx_rgmu_start(struct kgsl_device *device) +{ + int ret = 0; + struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); + + switch (device->state) { + case KGSL_STATE_RESET: + ret = a6xx_rgmu_suspend(device); + if (ret) + goto error_rgmu; + /* Fall-through */ + case KGSL_STATE_INIT: + case KGSL_STATE_SUSPEND: + case KGSL_STATE_SLUMBER: + a6xx_rgmu_enable_gdsc(rgmu); + a6xx_rgmu_enable_clks(device); + a6xx_rgmu_irq_enable(device); + ret = a6xx_rgmu_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); + a6xx_rgmu_snapshot(device); + return ret; +} + + + /* * a6xx_rgmu_load_firmware() - Load the ucode into the RGMU TCM * @device: Pointer to KGSL device @@ -495,7 +676,7 @@ static int a6xx_rgmu_load_firmware(struct kgsl_device *device) { const struct firmware *fw = NULL; struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct rgmu_device *rgmu = KGSL_RGMU_DEVICE(device); + struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); const struct adreno_a6xx_core *a6xx_core = to_a6xx_core(adreno_dev); int ret; @@ -520,10 +701,15 @@ static int a6xx_rgmu_load_firmware(struct kgsl_device *device) return rgmu->fw_hostptr ? 0 : -ENOMEM; } +static int a6xx_rgmu_init(struct kgsl_device *device) +{ + return a6xx_rgmu_load_firmware(device); +} + /* Halt RGMU execution */ static void a6xx_rgmu_halt_execution(struct kgsl_device *device) { - struct rgmu_device *rgmu = KGSL_RGMU_DEVICE(device); + struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); unsigned int index, status, fence; gmu_core_regread(device, A6XX_RGMU_CX_PCC_DEBUG, &index); @@ -556,7 +742,7 @@ static void a6xx_rgmu_halt_execution(struct kgsl_device *device) * This is where all of the A6XX GMU specific bits and pieces are grabbed * into the snapshot memory */ -static void a6xx_rgmu_snapshot(struct kgsl_device *device, +static void a6xx_rgmu_device_snapshot(struct kgsl_device *device, struct kgsl_snapshot *snapshot) { @@ -569,7 +755,64 @@ static u64 a6xx_rgmu_read_alwayson(struct kgsl_device *device) return a6xx_read_alwayson(ADRENO_DEVICE(device)); } -struct gmu_dev_ops adreno_a6xx_rgmudev = { +/* Caller shall ensure GPU is ready for SLUMBER */ +static void a6xx_rgmu_stop(struct kgsl_device *device) +{ + if (!test_bit(GMU_CLK_ON, &device->gmu_core.flags)) + return; + + /* Wait for the lowest idle level we requested */ + if (a6xx_rgmu_wait_for_lowest_idle(device)) + goto error; + + a6xx_rgmu_gpu_pwrctrl(device, + GMU_NOTIFY_SLUMBER, 0, 0); + + a6xx_rgmu_irq_disable(device); + a6xx_rgmu_disable_clks(device); + a6xx_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); + a6xx_rgmu_snapshot(device); +} + +/* + * a6xx_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 a6xx_rgmu_dcvs_set(struct kgsl_device *device, + int pwrlevel, int bus_level) +{ + struct a6xx_rgmu_device *rgmu = A6XX_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 struct gmu_dev_ops a6xx_rgmudev = { .load_firmware = a6xx_rgmu_load_firmware, .oob_set = a6xx_rgmu_oob_set, .oob_clear = a6xx_rgmu_oob_clear, @@ -581,9 +824,207 @@ struct gmu_dev_ops adreno_a6xx_rgmudev = { .wait_for_lowest_idle = a6xx_rgmu_wait_for_lowest_idle, .ifpc_store = a6xx_rgmu_ifpc_store, .ifpc_show = a6xx_rgmu_ifpc_show, - .snapshot = a6xx_rgmu_snapshot, + .snapshot = a6xx_rgmu_device_snapshot, .halt_execution = a6xx_rgmu_halt_execution, .read_alwayson = a6xx_rgmu_read_alwayson, .gmu2host_intr_mask = RGMU_OOB_IRQ_MASK, .gmu_ao_intr_mask = RGMU_AO_IRQ_MASK, }; + +static struct gmu_core_ops a6xx_rgmu_ops = { + .init = a6xx_rgmu_init, + .start = a6xx_rgmu_start, + .stop = a6xx_rgmu_stop, + .dcvs_set = a6xx_rgmu_dcvs_set, + .snapshot = a6xx_rgmu_snapshot, + .suspend = a6xx_rgmu_suspend, +}; + +static int a6xx_rgmu_irq_probe(struct kgsl_device *device) +{ + struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); + int ret; + + ret = kgsl_request_irq(rgmu->pdev, "kgsl_oob", + a6xx_oob_irq_handler, device); + if (ret < 0) + return ret; + + rgmu->oob_interrupt_num = ret; + + ret = kgsl_request_irq(rgmu->pdev, + "kgsl_rgmu", a6xx_rgmu_irq_handler, device); + if (ret < 0) + return ret; + + rgmu->rgmu_interrupt_num = ret; + return 0; +} + +static int a6xx_rgmu_regulators_probe(struct a6xx_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 a6xx_rgmu_clocks_probe(struct a6xx_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; +} + +/* Do not access any RGMU registers in RGMU probe function */ +static int a6xx_rgmu_probe(struct kgsl_device *device, + struct platform_device *pdev) +{ + struct a6xx_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 = a6xx_rgmu_regulators_probe(rgmu); + if (ret) + return ret; + + /* Set up RGMU clocks */ + ret = a6xx_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 = a6xx_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 = &a6xx_rgmu_ops; + device->gmu_core.dev_ops = &a6xx_rgmudev; + + return 0; +} + +static void a6xx_rgmu_remove(struct kgsl_device *device) +{ + a6xx_rgmu_stop(device); + + memset(&device->gmu_core, 0, sizeof(device->gmu_core)); +} + +static int a6xx_rgmu_bind(struct device *dev, struct device *master, void *data) +{ + struct kgsl_device *device = dev_get_drvdata(master); + + return a6xx_rgmu_probe(device, to_platform_device(dev)); +} + +static void a6xx_rgmu_unbind(struct device *dev, struct device *master, + void *data) +{ + struct kgsl_device *device = dev_get_drvdata(master); + + a6xx_rgmu_remove(device); +} + +static const struct component_ops a6xx_rgmu_component_ops = { + .bind = a6xx_rgmu_bind, + .unbind = a6xx_rgmu_unbind, +}; + +static int a6xx_rgmu_probe_dev(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &a6xx_rgmu_component_ops); +} + +static int a6xx_rgmu_remove_dev(struct platform_device *pdev) +{ + component_del(&pdev->dev, &a6xx_rgmu_component_ops); + return 0; +} + +static const struct of_device_id a6xx_rgmu_match_table[] = { + { .compatible = "qcom,gpu-rgmu" }, + { }, +}; + +struct platform_driver a6xx_rgmu_driver = { + .probe = a6xx_rgmu_probe_dev, + .remove = a6xx_rgmu_remove_dev, + .driver = { + .name = "kgsl-rgmu", + .of_match_table = a6xx_rgmu_match_table, + }, +}; diff --git a/drivers/gpu/msm/kgsl_rgmu.h b/drivers/gpu/msm/adreno_a6xx_rgmu.h similarity index 79% rename from drivers/gpu/msm/kgsl_rgmu.h rename to drivers/gpu/msm/adreno_a6xx_rgmu.h index 112f6e52c6ef..02839b16001e 100644 --- a/drivers/gpu/msm/kgsl_rgmu.h +++ b/drivers/gpu/msm/adreno_a6xx_rgmu.h @@ -2,8 +2,8 @@ /* * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ -#ifndef __KGSL_RGMU_H -#define __KGSL_RGMU_H +#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 @@ -16,7 +16,7 @@ #define MAX_RGMU_CLKS 8 /** - * struct rgmu_device - rGMU device structure + * 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 @@ -31,7 +31,7 @@ * @idle_level: Minimal GPU idle power level * @fault_count: RGMU fault count */ -struct rgmu_device { +struct a6xx_rgmu_device { u32 ver; struct platform_device *pdev; unsigned int rgmu_interrupt_num; @@ -49,9 +49,6 @@ struct rgmu_device { unsigned int fault_count; }; -extern struct gmu_dev_ops adreno_a6xx_rgmudev; -#define KGSL_RGMU_DEVICE(_a) ((struct rgmu_device *)((_a)->gmu_core.ptr)) +#define A6XX_RGMU_DEVICE(_a) ((struct a6xx_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 */ +#endif /* __ADRENO_A6XX_RGMU_H */ diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h index 43b5a4c5c54a..8ffbf0b07b8b 100644 --- a/drivers/gpu/msm/kgsl.h +++ b/drivers/gpu/msm/kgsl.h @@ -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 diff --git a/drivers/gpu/msm/kgsl_gmu_core.c b/drivers/gpu/msm/kgsl_gmu_core.c index aded346fa01e..be1f81cd91d9 100644 --- a/drivers/gpu/msm/kgsl_gmu_core.c +++ b/drivers/gpu/msm/kgsl_gmu_core.c @@ -12,7 +12,7 @@ static const struct of_device_id gmu_match_table[] = { { .compatible = "qcom,gpu-gmu", .data = &a6xx_gmu_driver }, - { .compatible = "qcom,gpu-rgmu", .data = &kgsl_rgmu_driver }, + { .compatible = "qcom,gpu-rgmu", .data = &a6xx_rgmu_driver }, {}, }; diff --git a/drivers/gpu/msm/kgsl_gmu_core.h b/drivers/gpu/msm/kgsl_gmu_core.h index ff82d5619469..43c180f5033c 100644 --- a/drivers/gpu/msm/kgsl_gmu_core.h +++ b/drivers/gpu/msm/kgsl_gmu_core.h @@ -162,7 +162,7 @@ struct gmu_core_device { }; extern struct platform_driver a6xx_gmu_driver; -extern struct platform_driver kgsl_rgmu_driver; +extern struct platform_driver a6xx_rgmu_driver; /* GMU core functions */ diff --git a/drivers/gpu/msm/kgsl_rgmu.c b/drivers/gpu/msm/kgsl_rgmu.c deleted file mode 100644 index f8610129aef9..000000000000 --- a/drivers/gpu/msm/kgsl_rgmu.c +++ /dev/null @@ -1,461 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include - -#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 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, - .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, - }, -}; From 317169acd3996010d0bbffcc8a80d357581b4ab2 Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Fri, 27 Mar 2020 03:17:29 -0600 Subject: [PATCH 10/30] msm: kgsl: Remove any eCP references As this is not enabled for any a6xx. Change-Id: I9f44301885dfcd24c79d18c857267a4225cdb26b Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/adreno.h | 8 +++----- drivers/gpu/msm/adreno_a6xx_gmu.c | 9 --------- drivers/gpu/msm/adreno_a6xx_hfi.c | 7 ------- drivers/gpu/msm/adreno_a6xx_hfi.h | 2 +- 4 files changed, 4 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 1d5bacb851c5..f95a7dcdfd26 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -97,14 +97,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 */ diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index b4fd51a0a5b1..feaffb64675a 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -1416,15 +1416,6 @@ static int a6xx_gmu_cache_finalize(struct adreno_device *adreno_dev, if (IS_ERR(md)) return PTR_ERR(md); - if (ADRENO_FEATURE(adreno_dev, ADRENO_ECP)) { - /* Allocation to account for future MEM_ALLOC buffers */ - md = a6xx_gmu_kmem_allocate(gmu, GMU_NONCACHED_KERNEL, - 0, SZ_32K, - (IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV)); - if (IS_ERR(md)) - return PTR_ERR(md); - } - gmu->preallocations = true; return 0; diff --git a/drivers/gpu/msm/adreno_a6xx_hfi.c b/drivers/gpu/msm/adreno_a6xx_hfi.c index 68752897ddb9..1b1141093715 100644 --- a/drivers/gpu/msm/adreno_a6xx_hfi.c +++ b/drivers/gpu/msm/adreno_a6xx_hfi.c @@ -403,7 +403,6 @@ static int a6xx_hfi_send_core_fw_start(struct a6xx_gmu_device *gmu) } static const char * const a6xx_hfi_features[] = { - [HFI_FEATURE_ECP] = "ECP", [HFI_FEATURE_ACD] = "ACD", [HFI_FEATURE_LM] = "LM", }; @@ -755,12 +754,6 @@ int a6xx_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 = a6xx_hfi_send_feature_ctrl(gmu, - HFI_FEATURE_ECP, 1, 0); - if (result) - return result; - } result = a6xx_hfi_send_acd_feature_ctrl(gmu, adreno_dev); if (result) diff --git a/drivers/gpu/msm/adreno_a6xx_hfi.h b/drivers/gpu/msm/adreno_a6xx_hfi.h index ee1a25c15769..08b00020322a 100644 --- a/drivers/gpu/msm/adreno_a6xx_hfi.h +++ b/drivers/gpu/msm/adreno_a6xx_hfi.h @@ -67,7 +67,7 @@ struct hfi_queue_table; #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 From 80150b77561846367589f2fbdf107d23c953f55e Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Mon, 30 Mar 2020 14:23:38 -0600 Subject: [PATCH 11/30] msm: kgsl: Remove gmu_core_dev_enable_lm function This function writes to GMU CX/AO registers which can be configured much earlier in gmu code itself instead. Change-Id: I403ad8d2e0fa4f199663f0fb6234de3e59bd05f9 Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/adreno_a6xx.c | 1 - drivers/gpu/msm/adreno_a6xx_gmu.c | 71 ++++++++++++++++--------------- drivers/gpu/msm/kgsl_gmu_core.c | 8 ---- drivers/gpu/msm/kgsl_gmu_core.h | 2 - 4 files changed, 36 insertions(+), 46 deletions(-) diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index b3be11b8d414..ecc8d0a6e9e9 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -617,7 +617,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); diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index feaffb64675a..15cb9d5e8c3d 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -1117,6 +1117,40 @@ static void a6xx_gmu_mem_free(struct a6xx_gmu_device *gmu, memset(md, 0, sizeof(*md)); } +static void a6xx_gmu_enable_lm(struct kgsl_device *device) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + u32 val; + + memset(adreno_dev->busy_data.throttle_cycles, 0, + sizeof(adreno_dev->busy_data.throttle_cycles)); + + if (!adreno_dev->lm_enabled) + return; + + /* + * For throttling, use the following counters for throttled cycles: + * XOCLK1: countable: 0x10 + * XOCLK2: countable: 0x16 for newer hardware / 0x15 for others + * XOCLK3: countable: 0xf for newer hardware / 0x19 for others + * + * POWER_CONTROL_SELECT_0 controls counters 0 - 3, each selector + * is 8 bits wide. + */ + + if (adreno_is_a620(adreno_dev) || adreno_is_a650(adreno_dev)) + val = (0x10 << 8) | (0x16 << 16) | (0x0f << 24); + else + val = (0x10 << 8) | (0x15 << 16) | (0x19 << 24); + + + /* Make sure not to write over XOCLK0 */ + gmu_core_regrmw(device, A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0, + 0xffffff00, val); + + gmu_core_regwrite(device, A6XX_GMU_AO_SPARE_CNTL, 1); +} + /* * a6xx_gmu_fw_start() - set up GMU and start FW * @device: Pointer to KGSL device @@ -1226,6 +1260,8 @@ static int a6xx_gmu_fw_start(struct kgsl_device *device, /* Populate the GMU version info before GMU boots */ load_gmu_version_info(device); + a6xx_gmu_enable_lm(device); + /* Clear any previously set cm3 fault */ atomic_set(&gmu->cm3_fault, 0); @@ -1882,40 +1918,6 @@ static int a6xx_gmu_dcvs_set(struct kgsl_device *device, return ret; } -static void a6xx_gmu_enable_lm(struct kgsl_device *device) -{ - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - u32 val; - - memset(adreno_dev->busy_data.throttle_cycles, 0, - sizeof(adreno_dev->busy_data.throttle_cycles)); - - if (!adreno_dev->lm_enabled) - return; - - /* - * For throttling, use the following counters for throttled cycles: - * XOCLK1: countable: 0x10 - * XOCLK2: countable: 0x16 for newer hardware / 0x15 for others - * XOCLK3: countable: 0xf for newer hardware / 0x19 for others - * - * POWER_CONTROL_SELECT_0 controls counters 0 - 3, each selector - * is 8 bits wide. - */ - - if (adreno_is_a620(adreno_dev) || adreno_is_a650(adreno_dev)) - val = (0x10 << 8) | (0x16 << 16) | (0x0f << 24); - else - val = (0x10 << 8) | (0x15 << 16) | (0x19 << 24); - - - /* Make sure not to write over XOCLK0 */ - gmu_core_regrmw(device, A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0, - 0xffffff00, val); - - gmu_core_regwrite(device, A6XX_GMU_AO_SPARE_CNTL, 1); -} - static int a6xx_gmu_ifpc_store(struct kgsl_device *device, unsigned int val) { @@ -2618,7 +2620,6 @@ static struct gmu_dev_ops a6xx_gmudev = { .irq_enable = a6xx_gmu_irq_enable, .irq_disable = a6xx_gmu_irq_disable, .hfi_start_msg = a6xx_gmu_hfi_start_msg, - .enable_lm = a6xx_gmu_enable_lm, .rpmh_gpu_pwrctrl = a6xx_gmu_rpmh_gpu_pwrctrl, .gx_is_on = a6xx_gmu_gx_is_on, .wait_for_lowest_idle = a6xx_gmu_wait_for_lowest_idle, diff --git a/drivers/gpu/msm/kgsl_gmu_core.c b/drivers/gpu/msm/kgsl_gmu_core.c index be1f81cd91d9..2e2f0e152d4a 100644 --- a/drivers/gpu/msm/kgsl_gmu_core.c +++ b/drivers/gpu/msm/kgsl_gmu_core.c @@ -251,14 +251,6 @@ int gmu_core_dev_wait_for_lowest_idle(struct kgsl_device *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) { diff --git a/drivers/gpu/msm/kgsl_gmu_core.h b/drivers/gpu/msm/kgsl_gmu_core.h index 43c180f5033c..eed413a082b8 100644 --- a/drivers/gpu/msm/kgsl_gmu_core.h +++ b/drivers/gpu/msm/kgsl_gmu_core.h @@ -119,7 +119,6 @@ struct gmu_dev_ops { 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); @@ -207,7 +206,6 @@ 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); From 3a9f35a7872a0ea2671ec1f6673cb188065cdaaf Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Mon, 30 Mar 2020 14:32:04 -0600 Subject: [PATCH 12/30] msm: kgsl: Remove duplicated register write This register is already being programmed in a6xx_start. Also, remove duplicated register macros. Change-Id: I3f59e23446b376e39df6abd5eee817317bfb2d67 Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/a6xx_reg.h | 2 -- drivers/gpu/msm/adreno_a6xx_gmu.c | 3 --- drivers/gpu/msm/adreno_a6xx_rgmu.c | 6 ------ 3 files changed, 11 deletions(-) diff --git a/drivers/gpu/msm/a6xx_reg.h b/drivers/gpu/msm/a6xx_reg.h index 47b5faaa316f..a2b83f15809f 100644 --- a/drivers/gpu/msm/a6xx_reg.h +++ b/drivers/gpu/msm/a6xx_reg.h @@ -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 diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index 15cb9d5e8c3d..f1cbd4931a5c 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -517,9 +517,6 @@ static int a6xx_rpmh_power_on_gpu(struct kgsl_device *device) /* Clear sleep sequence flag as wakeup sequence is successful */ clear_bit(GMU_RSCC_SLEEP_SEQ_DONE, &device->gmu_core.flags); - /* Enable the power counter because it was disabled before slumber */ - gmu_core_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 1); - return 0; error_rsc: dev_err(dev, "GPU RSC sequence stuck in waking up GPU\n"); diff --git a/drivers/gpu/msm/adreno_a6xx_rgmu.c b/drivers/gpu/msm/adreno_a6xx_rgmu.c index 74cd52cbb126..5a3f7c106602 100644 --- a/drivers/gpu/msm/adreno_a6xx_rgmu.c +++ b/drivers/gpu/msm/adreno_a6xx_rgmu.c @@ -367,12 +367,6 @@ static int a6xx_rgmu_fw_start(struct kgsl_device *device, for (i = 0; i < rgmu->fw_size; i++) gmu_core_regwrite(device, A6XX_GMU_CM3_ITCM_START + i, rgmu->fw_hostptr[i]); - /* - * Enable power counter because it was disabled before - * slumber. - */ - gmu_core_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, - 1); break; } From f707fc737dc1cce9679c1d8478daf641813bad31 Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Mon, 30 Mar 2020 14:13:21 -0600 Subject: [PATCH 13/30] msm: kgsl: Consolidate gmu register programming Make a single function to configure gmu registers before gmu boot. This will be used by hardware dispatcher as well. Also, get rid of gmu->load_mode since it's always been TCM BOOT. Change-Id: I832b450e25cb1e76f0294a053eb9880759e65229 Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/adreno_a6xx_gmu.c | 86 +++++++++++++------------------ drivers/gpu/msm/adreno_a6xx_gmu.h | 10 ---- 2 files changed, 37 insertions(+), 59 deletions(-) diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index f1cbd4931a5c..48408e45025c 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -1148,61 +1148,23 @@ static void a6xx_gmu_enable_lm(struct kgsl_device *device) gmu_core_regwrite(device, A6XX_GMU_AO_SPARE_CNTL, 1); } -/* - * a6xx_gmu_fw_start() - set up GMU and start FW - * @device: Pointer to KGSL device - * @boot_state: State of the GMU being started - */ -static int a6xx_gmu_fw_start(struct kgsl_device *device, - unsigned int boot_state) +static void a6xx_gmu_register_config(struct kgsl_device *device) { - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); const struct adreno_a6xx_core *a6xx_core = to_a6xx_core(adreno_dev); - uint32_t gmu_log_info; - int ret; - unsigned int chipid = 0; + u32 gmu_log_info, chipid = 0; /* Vote veto for FAL10 feature if supported*/ if (a6xx_core->veto_fal10) gmu_core_regwrite(device, A6XX_GPU_GMU_CX_GMU_CX_FAL_INTF, 0x1); - switch (boot_state) { - case GMU_COLD_BOOT: - /* Turn on TCM retention */ - gmu_core_regwrite(device, A6XX_GMU_GENERAL_7, 1); - - if (!test_and_set_bit(GMU_BOOT_INIT_DONE, - &device->gmu_core.flags)) - ret = _load_gmu_rpmh_ucode(device); - else - ret = a6xx_rpmh_power_on_gpu(device); - if (ret) - return ret; - - if (gmu->load_mode == TCM_BOOT) { - /* Load GMU image via AHB bus */ - ret = load_gmu_fw(device); - if (ret) - return ret; - } else { - dev_err(&gmu->pdev->dev, "Unsupported GMU load mode %d\n", - gmu->load_mode); - return -EINVAL; - } - break; - case GMU_WARM_BOOT: - ret = a6xx_rpmh_power_on_gpu(device); - if (ret) - return ret; - break; - default: - break; - } + /* Turn on TCM retention */ + gmu_core_regwrite(device, A6XX_GMU_GENERAL_7, 1); /* Clear init result to make sure we are getting fresh value */ gmu_core_regwrite(device, A6XX_GMU_CM3_FW_INIT_RESULT, 0); - gmu_core_regwrite(device, A6XX_GMU_CM3_BOOT_CONFIG, gmu->load_mode); + gmu_core_regwrite(device, A6XX_GMU_CM3_BOOT_CONFIG, 0x2); gmu_core_regwrite(device, A6XX_GMU_HFI_QTBL_ADDR, gmu->hfi_mem->gmuaddr); @@ -1223,7 +1185,7 @@ static int a6xx_gmu_fw_start(struct kgsl_device *device, * not get cleared if the gdsc was not reset. So clear it before * attempting GMU boot. */ - if (!adreno_is_a630(ADRENO_DEVICE(device))) + if (!adreno_is_a630(adreno_dev)) kgsl_regwrite(device, A6XX_GBIF_HALT, 0x0); /* Set the log wptr index */ @@ -1254,11 +1216,38 @@ static int a6xx_gmu_fw_start(struct kgsl_device *device, /* Configure power control and bring the GMU out of reset */ a6xx_gmu_power_config(device); + a6xx_gmu_enable_lm(device); +} + +/* + * a6xx_gmu_fw_start() - set up GMU and start FW + * @device: Pointer to KGSL device + */ +static int a6xx_gmu_fw_start(struct kgsl_device *device) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); + int ret; + + /* Do the necessary register programming */ + a6xx_gmu_register_config(device); + + if (!test_and_set_bit(GMU_BOOT_INIT_DONE, + &device->gmu_core.flags)) + ret = _load_gmu_rpmh_ucode(device); + else + ret = a6xx_rpmh_power_on_gpu(device); + if (ret) + return ret; + + /* Load GMU image via AHB bus */ + ret = load_gmu_fw(device); + if (ret) + return ret; + /* Populate the GMU version info before GMU boots */ load_gmu_version_info(device); - a6xx_gmu_enable_lm(device); - /* Clear any previously set cm3 fault */ atomic_set(&gmu->cm3_fault, 0); @@ -1782,7 +1771,7 @@ static int a6xx_gmu_rpmh_gpu_pwrctrl(struct kgsl_device *device, switch (mode) { case GMU_FW_START: - ret = a6xx_gmu_fw_start(device, arg1); + ret = a6xx_gmu_fw_start(device); break; case GMU_SUSPEND: ret = a6xx_gmu_pwrctrl_suspend(device); @@ -3398,7 +3387,6 @@ static int a6xx_gmu_probe(struct kgsl_device *device, device->gmu_core.ptr = gmu; hfi = &gmu->hfi; - gmu->load_mode = TCM_BOOT; dma_set_coherent_mask(&gmu->pdev->dev, DMA_BIT_MASK(64)); gmu->pdev->dev.dma_mask = &gmu->pdev->dev.coherent_dma_mask; diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.h b/drivers/gpu/msm/adreno_a6xx_gmu.h index d1de4e6ce916..d72690bd9f46 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.h +++ b/drivers/gpu/msm/adreno_a6xx_gmu.h @@ -122,14 +122,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; @@ -154,7 +146,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 @@ -193,7 +184,6 @@ struct a6xx_gmu_device { 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; From e7c78f113fe026024c9b04eba22c91cb1eae3e95 Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Thu, 23 Apr 2020 07:01:24 -0600 Subject: [PATCH 14/30] msm: kgsl: Create adreno power operations This enables us to define target specific device power up/down sequences. Also create adreno_power_cycle for certain settings to take effect by powering down, change the settings and then resume the device. Change-Id: Ie6a0feb224f0b0babcd0249c812674c31dc6c4ab Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/adreno.c | 204 +++++++++++++++++++++++++-- drivers/gpu/msm/adreno.h | 129 ++++++++++++++++- drivers/gpu/msm/adreno_a3xx.c | 1 + drivers/gpu/msm/adreno_a5xx.c | 3 +- drivers/gpu/msm/adreno_a6xx.c | 1 + drivers/gpu/msm/adreno_a6xx_gmu.c | 43 +++--- drivers/gpu/msm/adreno_a6xx_rgmu.c | 13 +- drivers/gpu/msm/adreno_coresight.c | 18 +-- drivers/gpu/msm/adreno_debugfs.c | 26 ++-- drivers/gpu/msm/adreno_dispatch.c | 6 +- drivers/gpu/msm/adreno_ioctl.c | 6 +- drivers/gpu/msm/adreno_perfcounter.c | 6 +- drivers/gpu/msm/adreno_profile.c | 6 +- drivers/gpu/msm/adreno_sysfs.c | 68 ++++----- drivers/gpu/msm/kgsl_pwrctrl.c | 80 +---------- drivers/gpu/msm/kgsl_pwrctrl.h | 9 +- 16 files changed, 404 insertions(+), 215 deletions(-) diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 2fc4c0563fed..407f8deb2d66 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -1546,11 +1546,10 @@ static void adreno_unbind(struct device *dev) clear_bit(ADRENO_DEVICE_INITIALIZED, &adreno_dev->priv); } -static int adreno_pm_resume(struct device *dev) +static void adreno_resume(struct adreno_device *adreno_dev) { - struct kgsl_device *device = dev_get_drvdata(dev); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - mutex_lock(&device->mutex); if (device->state == KGSL_STATE_SUSPEND) { adreno_dispatcher_unhalt(device); kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER); @@ -1565,19 +1564,41 @@ static int adreno_pm_resume(struct device *dev) kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER); dev_err(device->dev, "resume invoked without a suspend\n"); } +} + +static int adreno_pm_resume(struct device *dev) +{ + struct kgsl_device *device = dev_get_drvdata(dev); + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + const struct adreno_power_ops *ops = ADRENO_POWER_OPS(adreno_dev); + + mutex_lock(&device->mutex); + ops->pm_resume(adreno_dev); mutex_unlock(&device->mutex); + return 0; } +static int adreno_suspend(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + int status = kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND); + + if (!status && device->state == KGSL_STATE_SUSPEND) + adreno_dispatcher_halt(device); + + return status; +} + static int adreno_pm_suspend(struct device *dev) { struct kgsl_device *device = dev_get_drvdata(dev); + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + const struct adreno_power_ops *ops = ADRENO_POWER_OPS(adreno_dev); int status; mutex_lock(&device->mutex); - status = kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND); - if (!status && device->state == KGSL_STATE_SUSPEND) - adreno_dispatcher_halt(device); + status = ops->pm_suspend(adreno_dev); mutex_unlock(&device->mutex); return status; @@ -1825,14 +1846,15 @@ static void adreno_set_active_ctxs_null(struct adreno_device *adreno_dev) } } -static int adreno_first_open(struct kgsl_device *device) +static int adreno_open(struct adreno_device *adreno_dev) { + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); int ret; /* * active_cnt special case: we are starting up for the first * time, so use this sequence instead of the kgsl_pwrctrl_wake() - * which will be called by kgsl_active_count_get(). + * which will be called by adreno_active_count_get(). */ atomic_inc(&device->active_cnt); @@ -1850,7 +1872,7 @@ static int adreno_first_open(struct kgsl_device *device) complete_all(&device->hwaccess_gate); kgsl_pwrctrl_change_state(device, KGSL_STATE_ACTIVE); - kgsl_active_count_put(device); + adreno_active_count_put(adreno_dev); return 0; err: @@ -1860,8 +1882,18 @@ err: return ret; } -static int adreno_last_close(struct kgsl_device *device) +static int adreno_first_open(struct kgsl_device *device) { + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + const struct adreno_power_ops *ops = ADRENO_POWER_OPS(adreno_dev); + + return ops->first_open(adreno_dev); +} + +static int adreno_close(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + /* * Wait up to 1 second for the active count to go low * and then start complaining about it @@ -1878,6 +1910,84 @@ static int adreno_last_close(struct kgsl_device *device) return kgsl_pwrctrl_change_state(device, KGSL_STATE_INIT); } +static int adreno_last_close(struct kgsl_device *device) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + const struct adreno_power_ops *ops = ADRENO_POWER_OPS(adreno_dev); + + return ops->last_close(adreno_dev); +} + +static int adreno_pwrctrl_active_count_get(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + 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; +} + +static void adreno_pwrctrl_active_count_put(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + + 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); +} + +int adreno_active_count_get(struct adreno_device *adreno_dev) +{ + const struct adreno_power_ops *ops = ADRENO_POWER_OPS(adreno_dev); + + return ops->active_count_get(adreno_dev); +} + +void adreno_active_count_put(struct adreno_device *adreno_dev) +{ + const struct adreno_power_ops *ops = ADRENO_POWER_OPS(adreno_dev); + + ops->active_count_put(adreno_dev); +} + /** * _adreno_start - Power up the GPU and prepare to accept commands * @adreno_dev: Pointer to an adreno_device structure @@ -2597,9 +2707,9 @@ static int adreno_setproperty(struct kgsl_device_private *dev_priv, if (enable) { device->pwrctrl.ctrl_flags = 0; - if (!kgsl_active_count_get(device)) { + if (!adreno_active_count_get(adreno_dev)) { adreno_fault_detect_start(adreno_dev); - kgsl_active_count_put(device); + adreno_active_count_put(adreno_dev); } kgsl_pwrscale_enable(device); @@ -3662,6 +3772,67 @@ static void adreno_drawctxt_sched(struct kgsl_device *device, adreno_dispatcher_queue_context(device, ADRENO_CONTEXT(context)); } +int adreno_power_cycle(struct adreno_device *adreno_dev, + void (*callback)(struct adreno_device *adreno_dev, void *priv), + void *priv) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + const struct adreno_power_ops *ops = ADRENO_POWER_OPS(adreno_dev); + int ret; + + mutex_lock(&device->mutex); + ret = ops->pm_suspend(adreno_dev); + + if (!ret) { + callback(adreno_dev, priv); + ops->pm_resume(adreno_dev); + } + + mutex_unlock(&device->mutex); + + return ret; +} + +int adreno_power_cycle_bool(struct adreno_device *adreno_dev, + bool *flag, bool val) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + const struct adreno_power_ops *ops = ADRENO_POWER_OPS(adreno_dev); + int ret; + + mutex_lock(&device->mutex); + ret = ops->pm_suspend(adreno_dev); + + if (!ret) { + *flag = val; + ops->pm_resume(adreno_dev); + } + + mutex_unlock(&device->mutex); + + return ret; +} + +int adreno_power_cycle_u32(struct adreno_device *adreno_dev, + u32 *flag, u32 val) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + const struct adreno_power_ops *ops = ADRENO_POWER_OPS(adreno_dev); + int ret; + + mutex_lock(&device->mutex); + ret = ops->pm_suspend(adreno_dev); + + if (!ret) { + *flag = val; + ops->pm_resume(adreno_dev); + } + + mutex_unlock(&device->mutex); + + return ret; +} + static const struct kgsl_functable adreno_functable = { /* Mandatory functions */ .regread = adreno_regread, @@ -3712,6 +3883,15 @@ static const struct component_master_ops adreno_ops = { .unbind = adreno_unbind, }; +const struct adreno_power_ops adreno_power_operations = { + .first_open = adreno_open, + .last_close = adreno_close, + .active_count_get = adreno_pwrctrl_active_count_get, + .active_count_put = adreno_pwrctrl_active_count_put, + .pm_suspend = adreno_suspend, + .pm_resume = adreno_resume, +}; + static const struct of_device_id adreno_gmu_match[] = { { .compatible = "qcom,gpu-gmu" }, { .compatible = "qcom,gpu-rgmu" }, diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index f95a7dcdfd26..54d811fcfac6 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -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) @@ -322,6 +328,37 @@ 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); +}; + /** * struct adreno_gpu_core - A specific GPU core definition * @gpurev: Unique GPU revision identifier @@ -794,6 +831,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; }; /** @@ -855,6 +897,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; @@ -950,6 +993,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) \ { \ @@ -1556,28 +1623,33 @@ 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) @@ -1740,4 +1812,49 @@ irqreturn_t adreno_irq_callbacks(struct adreno_device *adreno_dev, 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); #endif /*__ADRENO_H */ diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c index 65f030557ca6..2bc99359652f 100644 --- a/drivers/gpu/msm/adreno_a3xx.c +++ b/drivers/gpu/msm/adreno_a3xx.c @@ -1434,4 +1434,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, }; diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c index 2b9f43daeb96..ec67437a709a 100644 --- a/drivers/gpu/msm/adreno_a5xx.c +++ b/drivers/gpu/msm/adreno_a5xx.c @@ -1449,7 +1449,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 @@ -3011,4 +3011,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, }; diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index ecc8d0a6e9e9..03ce1743769b 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -2677,4 +2677,5 @@ struct adreno_gpudev adreno_a6xx_gpudev = { #endif .clk_set_options = a6xx_clk_set_options, .read_alwayson = a6xx_read_alwayson, + .power_ops = &adreno_power_operations, }; diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index 48408e45025c..38bd5c171381 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -1927,16 +1927,9 @@ static int a6xx_gmu_ifpc_store(struct kgsl_device *device, requested_idle_level = GPU_HW_ACTIVE; } - mutex_lock(&device->mutex); - /* Power down the GPU before changing the idle level */ - kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND); - gmu->idle_level = requested_idle_level; - kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER); - - mutex_unlock(&device->mutex); - - return 0; + return adreno_power_cycle_u32(adreno_dev, &gmu->idle_level, + requested_idle_level); } static unsigned int a6xx_gmu_ifpc_show(struct kgsl_device *device) @@ -2569,11 +2562,24 @@ static int a6xx_gmu_start(struct kgsl_device *device) return ret; } +static void set_acd(struct adreno_device *adreno_dev, void *priv) +{ + struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(KGSL_DEVICE(adreno_dev)); + int ret; + + adreno_dev->acd_enabled = *((bool *)priv); + + ret = a6xx_gmu_aop_send_acd_state(gmu->mailbox.channel, + adreno_dev->acd_enabled); + if (ret) + dev_err(&gmu->pdev->dev, + "AOP mbox send message failed: %d\n", ret); +} + static int a6xx_gmu_acd_set(struct kgsl_device *device, bool val) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); - int ret; if (IS_ERR_OR_NULL(gmu->mailbox.channel)) return -EINVAL; @@ -2582,21 +2588,8 @@ static int a6xx_gmu_acd_set(struct kgsl_device *device, bool val) if (adreno_dev->acd_enabled == val) return 0; - mutex_lock(&device->mutex); - - /* Power down the GPU before enabling or disabling ACD */ - kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND); - - adreno_dev->acd_enabled = val; - ret = a6xx_gmu_aop_send_acd_state(gmu->mailbox.channel, val); - if (ret) - dev_err(&gmu->pdev->dev, - "AOP mbox send message failed: %d\n", ret); - - kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER); - - mutex_unlock(&device->mutex); - return 0; + /* Power cycle the GPU for changes to take effect */ + return adreno_power_cycle(adreno_dev, set_acd, &val); } static struct gmu_dev_ops a6xx_gmudev = { diff --git a/drivers/gpu/msm/adreno_a6xx_rgmu.c b/drivers/gpu/msm/adreno_a6xx_rgmu.c index 5a3f7c106602..124e6eaf6291 100644 --- a/drivers/gpu/msm/adreno_a6xx_rgmu.c +++ b/drivers/gpu/msm/adreno_a6xx_rgmu.c @@ -220,16 +220,9 @@ static int a6xx_rgmu_ifpc_store(struct kgsl_device *device, if (requested_idle_level == rgmu->idle_level) return 0; - mutex_lock(&device->mutex); - - /* Power down the GPU before changing the idle level */ - kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND); - rgmu->idle_level = requested_idle_level; - kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER); - - mutex_unlock(&device->mutex); - - return 0; + /* Power cycle the GPU for changes to take effect */ + return adreno_power_cycle_u32(adreno_dev, &rgmu->idle_level, + requested_idle_level); } static unsigned int a6xx_rgmu_ifpc_show(struct kgsl_device *device) diff --git a/drivers/gpu/msm/adreno_coresight.c b/drivers/gpu/msm/adreno_coresight.c index 67b35b4660cf..faa4006c2a93 100644 --- a/drivers/gpu/msm/adreno_coresight.c +++ b/drivers/gpu/msm/adreno_coresight.c @@ -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 @@ -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); } } } diff --git a/drivers/gpu/msm/adreno_debugfs.c b/drivers/gpu/msm/adreno_debugfs.c index 2d2a6473089d..11a1df147bd8 100644 --- a/drivers/gpu/msm/adreno_debugfs.c +++ b/drivers/gpu/msm/adreno_debugfs.c @@ -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; } diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c index e42fc4a6bb03..ac52cde6f5d3 100644 --- a/drivers/gpu/msm/adreno_dispatch.c +++ b/drivers/gpu/msm/adreno_dispatch.c @@ -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); } } @@ -2500,7 +2500,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); } diff --git a/drivers/gpu/msm/adreno_ioctl.c b/drivers/gpu/msm/adreno_ioctl.c index 11f3827801e4..4e2b5254d46c 100644 --- a/drivers/gpu/msm/adreno_ioctl.c +++ b/drivers/gpu/msm/adreno_ioctl.c @@ -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 @@ -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); diff --git a/drivers/gpu/msm/adreno_perfcounter.c b/drivers/gpu/msm/adreno_perfcounter.c index 19c961e97cb2..7b2966896400 100644 --- a/drivers/gpu/msm/adreno_perfcounter.c +++ b/drivers/gpu/msm/adreno_perfcounter.c @@ -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 @@ -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); diff --git a/drivers/gpu/msm/adreno_profile.c b/drivers/gpu/msm/adreno_profile.c index 6c52f75a1b12..fcd7b0b3d4e9 100644 --- a/drivers/gpu/msm/adreno_profile.c +++ b/drivers/gpu/msm/adreno_profile.c @@ -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 @@ -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: diff --git a/drivers/gpu/msm/adreno_sysfs.c b/drivers/gpu/msm/adreno_sysfs.c index f5fb8641fd5c..5aacc1e51ffd 100644 --- a/drivers/gpu/msm/adreno_sysfs.c +++ b/drivers/gpu/msm/adreno_sysfs.c @@ -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) diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index 692451e863b3..f8ec88fc6f4d 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -46,8 +46,6 @@ 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); @@ -2116,7 +2114,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) @@ -2149,82 +2147,6 @@ const char *kgsl_pwrstate_to_str(unsigned int state) 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 */ diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h index ebc3d208472f..daddadb00099 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.h +++ b/drivers/gpu/msm/kgsl_pwrctrl.h @@ -197,12 +197,17 @@ 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); + #endif /* __KGSL_PWRCTRL_H */ From 9f28807f7f58b8ecc3c4a4002caba811e041f936 Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Fri, 24 Apr 2020 13:36:38 -0600 Subject: [PATCH 15/30] msm: kgsl: Move kgsl_idle_check to target specific probe We will be re-purposing the idle check structures to run different idle check functions for gmu and rgmu based targets. So move the relevant bits to target specific probe. Change-Id: I27b936eb46568f3e5511257d67dd93c23407fd18 Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/adreno.c | 2 -- drivers/gpu/msm/adreno_a3xx.c | 7 +++++++ drivers/gpu/msm/adreno_a5xx.c | 7 +++++++ drivers/gpu/msm/adreno_a6xx.c | 7 +++++++ drivers/gpu/msm/kgsl_pwrctrl.c | 10 +--------- drivers/gpu/msm/kgsl_pwrctrl.h | 9 +++++++++ 6 files changed, 31 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 407f8deb2d66..133245ce4ad7 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -1868,8 +1868,6 @@ static int adreno_open(struct adreno_device *adreno_dev) if (ret) goto err; - timer_setup(&device->idle_timer, kgsl_timer, 0); - complete_all(&device->hwaccess_gate); kgsl_pwrctrl_change_state(device, KGSL_STATE_ACTIVE); adreno_active_count_put(adreno_dev); diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c index 2bc99359652f..a1e12f094686 100644 --- a/drivers/gpu/msm/adreno_a3xx.c +++ b/drivers/gpu/msm/adreno_a3xx.c @@ -572,6 +572,7 @@ 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); @@ -586,6 +587,12 @@ static int a3xx_probe(struct platform_device *pdev, /* 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); } diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c index ec67437a709a..cf23b5215fd6 100644 --- a/drivers/gpu/msm/adreno_a5xx.c +++ b/drivers/gpu/msm/adreno_a5xx.c @@ -92,6 +92,7 @@ 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); @@ -122,6 +123,12 @@ static int a5xx_probe(struct platform_device *pdev, 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); } diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index 03ce1743769b..4d1f4d30e86c 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -2338,6 +2338,7 @@ static int a6xx_probe(struct platform_device *pdev, { struct adreno_device *adreno_dev; struct adreno_gpudev *gpudev = gpucore->gpudev; + struct kgsl_device *device; adreno_dev = (struct adreno_device *) of_device_get_match_data(&pdev->dev); @@ -2385,6 +2386,12 @@ static int a6xx_probe(struct platform_device *pdev, adreno_dev->perfctr_ifpc_lo = A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_4_L; + 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); } diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index f8ec88fc6f4d..3d36724cf725 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -1483,8 +1483,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; @@ -1514,7 +1512,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 */ @@ -1573,12 +1570,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); diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h index daddadb00099..a7b879b2fa30 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.h +++ b/drivers/gpu/msm/kgsl_pwrctrl.h @@ -210,4 +210,13 @@ int kgsl_pwrctrl_set_default_gpu_pwrlevel(struct kgsl_device *device); */ void kgsl_pwrctrl_request_state(struct kgsl_device *device, u32 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 */ From 8c7ac65bb8fd2b280bad1d2bce2f049063cc0c30 Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Mon, 27 Apr 2020 09:57:30 -0600 Subject: [PATCH 16/30] msm: kgsl: Move bus counter allocation to its own function This code will be called from gmu and rgmu target specific boot sequences. Change-Id: If34641f0ad74d01b78c2638e674306248d082168 Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/adreno.c | 205 +++++++++++++++++---------------------- drivers/gpu/msm/adreno.h | 18 ++++ 2 files changed, 109 insertions(+), 114 deletions(-) diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 133245ce4ad7..0700bea88c37 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -1986,6 +1986,94 @@ void adreno_active_count_put(struct adreno_device *adreno_dev) ops->active_count_put(adreno_dev); } +void adreno_get_bus_counters(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + + if (!device->pwrctrl.bus_control) + return; + + /* VBIF waiting for RAM */ + if (adreno_dev->starved_ram_lo == 0) + if (adreno_perfcounter_get(adreno_dev, + KGSL_PERFCOUNTER_GROUP_VBIF_PWR, 0, + &adreno_dev->starved_ram_lo, NULL, + PERFCOUNTER_FLAG_KERNEL)) + goto err; + + /* VBIF DDR cycles */ + if (!adreno_has_gbif(adreno_dev) && (adreno_dev->ram_cycles_lo == 0)) { + if (adreno_perfcounter_get(adreno_dev, + KGSL_PERFCOUNTER_GROUP_VBIF, + VBIF_AXI_TOTAL_BEATS, + &adreno_dev->ram_cycles_lo, NULL, + PERFCOUNTER_FLAG_KERNEL)) + goto err; + return; + } + + if (adreno_dev->starved_ram_lo_ch1 == 0) + if (adreno_perfcounter_get(adreno_dev, + KGSL_PERFCOUNTER_GROUP_VBIF_PWR, 1, + &adreno_dev->starved_ram_lo_ch1, NULL, + PERFCOUNTER_FLAG_KERNEL)) + goto err; + + if (adreno_dev->ram_cycles_lo == 0) + if (adreno_perfcounter_get(adreno_dev, + KGSL_PERFCOUNTER_GROUP_VBIF, + GBIF_AXI0_READ_DATA_TOTAL_BEATS, + &adreno_dev->ram_cycles_lo, NULL, + PERFCOUNTER_FLAG_KERNEL)) + goto err; + + if (adreno_dev->ram_cycles_lo_ch1_read == 0) + if (adreno_perfcounter_get(adreno_dev, + KGSL_PERFCOUNTER_GROUP_VBIF, + GBIF_AXI1_READ_DATA_TOTAL_BEATS, + &adreno_dev->ram_cycles_lo_ch1_read, + NULL, + PERFCOUNTER_FLAG_KERNEL)) + goto err; + + if (adreno_dev->ram_cycles_lo_ch0_write == 0) + if (adreno_perfcounter_get(adreno_dev, + KGSL_PERFCOUNTER_GROUP_VBIF, + GBIF_AXI0_WRITE_DATA_TOTAL_BEATS, + &adreno_dev->ram_cycles_lo_ch0_write, + NULL, + PERFCOUNTER_FLAG_KERNEL)) + goto err; + + if (adreno_dev->ram_cycles_lo_ch1_write == 0) + if (adreno_perfcounter_get(adreno_dev, + KGSL_PERFCOUNTER_GROUP_VBIF, + GBIF_AXI1_WRITE_DATA_TOTAL_BEATS, + &adreno_dev->ram_cycles_lo_ch1_write, + NULL, + PERFCOUNTER_FLAG_KERNEL)) + goto err; + + return; +err: + dev_err(KGSL_DEVICE(adreno_dev)->dev, + "Unable to get perf counters for bus DCVS\n"); + +} + +void adreno_clear_dcvs_counters(struct adreno_device *adreno_dev) +{ + /* Clear the busy_data stats - we're starting over from scratch */ + adreno_dev->busy_data.gpu_busy = 0; + adreno_dev->busy_data.bif_ram_cycles = 0; + adreno_dev->busy_data.bif_ram_cycles_read_ch1 = 0; + adreno_dev->busy_data.bif_ram_cycles_write_ch0 = 0; + adreno_dev->busy_data.bif_ram_cycles_write_ch1 = 0; + adreno_dev->busy_data.bif_starved_ram = 0; + adreno_dev->busy_data.bif_starved_ram_ch1 = 0; + adreno_dev->busy_data.num_ifpc = 0; +} + /** * _adreno_start - Power up the GPU and prepare to accept commands * @adreno_dev: Pointer to an adreno_device structure @@ -1997,7 +2085,7 @@ static int _adreno_start(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); - int status = -EINVAL, ret; + int status; unsigned int state = device->state; bool regulator_left_on; @@ -2055,120 +2143,9 @@ static int _adreno_start(struct adreno_device *adreno_dev) goto error_oob_clear; } - if (device->pwrctrl.bus_control) { - /* VBIF waiting for RAM */ - if (adreno_dev->starved_ram_lo == 0) { - ret = adreno_perfcounter_get(adreno_dev, - KGSL_PERFCOUNTER_GROUP_VBIF_PWR, 0, - &adreno_dev->starved_ram_lo, NULL, - PERFCOUNTER_FLAG_KERNEL); + adreno_get_bus_counters(adreno_dev); - if (ret) { - dev_err(device->dev, - "Unable to get perf counters for bus DCVS\n"); - adreno_dev->starved_ram_lo = 0; - } - } - - if (adreno_has_gbif(adreno_dev)) { - if (adreno_dev->starved_ram_lo_ch1 == 0) { - ret = adreno_perfcounter_get(adreno_dev, - KGSL_PERFCOUNTER_GROUP_VBIF_PWR, 1, - &adreno_dev->starved_ram_lo_ch1, NULL, - PERFCOUNTER_FLAG_KERNEL); - - if (ret) { - dev_err(device->dev, - "Unable to get perf counters for bus DCVS\n"); - adreno_dev->starved_ram_lo_ch1 = 0; - } - } - - if (adreno_dev->ram_cycles_lo == 0) { - ret = adreno_perfcounter_get(adreno_dev, - KGSL_PERFCOUNTER_GROUP_VBIF, - GBIF_AXI0_READ_DATA_TOTAL_BEATS, - &adreno_dev->ram_cycles_lo, NULL, - PERFCOUNTER_FLAG_KERNEL); - - if (ret) { - dev_err(device->dev, - "Unable to get perf counters for bus DCVS\n"); - adreno_dev->ram_cycles_lo = 0; - } - } - - if (adreno_dev->ram_cycles_lo_ch1_read == 0) { - ret = adreno_perfcounter_get(adreno_dev, - KGSL_PERFCOUNTER_GROUP_VBIF, - GBIF_AXI1_READ_DATA_TOTAL_BEATS, - &adreno_dev->ram_cycles_lo_ch1_read, - NULL, - PERFCOUNTER_FLAG_KERNEL); - - if (ret) { - dev_err(device->dev, - "Unable to get perf counters for bus DCVS\n"); - adreno_dev->ram_cycles_lo_ch1_read = 0; - } - } - - if (adreno_dev->ram_cycles_lo_ch0_write == 0) { - ret = adreno_perfcounter_get(adreno_dev, - KGSL_PERFCOUNTER_GROUP_VBIF, - GBIF_AXI0_WRITE_DATA_TOTAL_BEATS, - &adreno_dev->ram_cycles_lo_ch0_write, - NULL, - PERFCOUNTER_FLAG_KERNEL); - - if (ret) { - dev_err(device->dev, - "Unable to get perf counters for bus DCVS\n"); - adreno_dev->ram_cycles_lo_ch0_write = 0; - } - } - - if (adreno_dev->ram_cycles_lo_ch1_write == 0) { - ret = adreno_perfcounter_get(adreno_dev, - KGSL_PERFCOUNTER_GROUP_VBIF, - GBIF_AXI1_WRITE_DATA_TOTAL_BEATS, - &adreno_dev->ram_cycles_lo_ch1_write, - NULL, - PERFCOUNTER_FLAG_KERNEL); - - if (ret) { - dev_err(device->dev, - "Unable to get perf counters for bus DCVS\n"); - adreno_dev->ram_cycles_lo_ch1_write = 0; - } - } - } else { - /* VBIF DDR cycles */ - if (adreno_dev->ram_cycles_lo == 0) { - ret = adreno_perfcounter_get(adreno_dev, - KGSL_PERFCOUNTER_GROUP_VBIF, - VBIF_AXI_TOTAL_BEATS, - &adreno_dev->ram_cycles_lo, NULL, - PERFCOUNTER_FLAG_KERNEL); - - if (ret) { - dev_err(device->dev, - "Unable to get perf counters for bus DCVS\n"); - adreno_dev->ram_cycles_lo = 0; - } - } - } - } - - /* Clear the busy_data stats - we're starting over from scratch */ - adreno_dev->busy_data.gpu_busy = 0; - adreno_dev->busy_data.bif_ram_cycles = 0; - adreno_dev->busy_data.bif_ram_cycles_read_ch1 = 0; - adreno_dev->busy_data.bif_ram_cycles_write_ch0 = 0; - adreno_dev->busy_data.bif_ram_cycles_write_ch1 = 0; - adreno_dev->busy_data.bif_starved_ram = 0; - adreno_dev->busy_data.bif_starved_ram_ch1 = 0; - adreno_dev->busy_data.num_ifpc = 0; + adreno_clear_dcvs_counters(adreno_dev); /* Restore performance counter registers with saved values */ adreno_perfcounter_restore(adreno_dev); diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 54d811fcfac6..5e07029e0799 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -1857,4 +1857,22 @@ int adreno_power_cycle_bool(struct adreno_device *adreno_dev, */ int adreno_power_cycle_u32(struct adreno_device *adreno_dev, u32 *flag, u32 val); + +/** + * 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); #endif /*__ADRENO_H */ From 251880f82b7e85c05dac16886e674f437af509ad Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Tue, 28 Apr 2020 17:40:13 -0600 Subject: [PATCH 17/30] msm: kgsl: Remove fault argument from target specific reset It is unused in the target specific reset sequences. Change-Id: I1af60c19c03c7cf116ef3178f1cf501c18b92e74 Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/adreno.c | 2 +- drivers/gpu/msm/adreno.h | 2 +- drivers/gpu/msm/adreno_a6xx.c | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 0700bea88c37..d5ce6c4802db 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -2319,7 +2319,7 @@ int adreno_reset(struct kgsl_device *device, int fault) int i; if (gpudev->reset) - return gpudev->reset(device, fault); + return gpudev->reset(device); /* * Try soft reset first Do not do soft reset for a IOMMU fault (because diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 5e07029e0799..7afe78e0cb78 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -822,7 +822,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); diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index 4d1f4d30e86c..a582ad008554 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -1093,13 +1093,12 @@ static int64_t a6xx_read_throttling_counters(struct adreno_device *adreno_dev) /** * 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. */ -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; From 90da593e71d2a4076df1bf4db8117d3333b58653 Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Sat, 4 Apr 2020 15:32:59 -0600 Subject: [PATCH 18/30] msm: kgsl: Create a6xx gmu power ops Instead of overwhelming the legacy power up/down sequences, create a6xx gmu specific power up/down sequences. The gpudev power ops will be set during a6xx gmu probe so that we don't have to do gmu checks in legacy probe. Change-Id: I897d775bdc3c9f97d38d20bc39b56f2551703bce Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/Makefile | 2 + drivers/gpu/msm/adreno-gpulist.h | 22 +- drivers/gpu/msm/adreno.c | 26 +- drivers/gpu/msm/adreno.h | 11 +- drivers/gpu/msm/adreno_a6xx.c | 91 +- drivers/gpu/msm/adreno_a6xx.h | 121 +- drivers/gpu/msm/adreno_a6xx_gmu.c | 2658 +++++++++----------- drivers/gpu/msm/adreno_a6xx_gmu.h | 126 +- drivers/gpu/msm/adreno_a6xx_gmu_snapshot.c | 279 ++ drivers/gpu/msm/adreno_a6xx_hfi.c | 341 ++- drivers/gpu/msm/adreno_a6xx_hfi.h | 270 +- drivers/gpu/msm/adreno_a6xx_rpmh.c | 462 ++++ drivers/gpu/msm/kgsl_pwrctrl.c | 3 +- drivers/gpu/msm/kgsl_pwrctrl.h | 10 + 14 files changed, 2416 insertions(+), 2006 deletions(-) create mode 100644 drivers/gpu/msm/adreno_a6xx_gmu_snapshot.c create mode 100644 drivers/gpu/msm/adreno_a6xx_rpmh.c diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile index 2f1cc3f757a6..8d893855b8a5 100644 --- a/drivers/gpu/msm/Makefile +++ b/drivers/gpu/msm/Makefile @@ -33,9 +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 \ diff --git a/drivers/gpu/msm/adreno-gpulist.h b/drivers/gpu/msm/adreno-gpulist.h index fb7845d12134..e7760b2ab6dd 100644 --- a/drivers/gpu/msm/adreno-gpulist.h +++ b/drivers/gpu/msm/adreno-gpulist.h @@ -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_a6xx_gmu_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_a6xx_gmu_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_a6xx_gmu_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_a6xx_gmu_gpudev, .gmem_size = SZ_512K, .bus_width = 32, }, @@ -1080,7 +1080,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_a6xx_gmu_gpudev, .gmem_base = 0, .gmem_size = SZ_512K, .bus_width = 32, @@ -1170,7 +1170,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, @@ -1250,7 +1250,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, @@ -1279,7 +1279,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, @@ -1305,7 +1305,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, @@ -1407,7 +1407,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_a6xx_gmu_gpudev, .gmem_base = 0x100000, .gmem_size = SZ_512K, .bus_width = 32, @@ -1548,7 +1548,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, diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index d5ce6c4802db..dea6efcdafa7 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -321,30 +321,6 @@ void adreno_fault_detect_stop(struct adreno_device *adreno_dev) adreno_dev->fast_hang_detect = 0; } -#define GMU_CM3_CFG_NONMASKINTR_SHIFT 9 - -/* Send an NMI to the GMU */ -void adreno_gmu_send_nmi(struct adreno_device *adreno_dev) -{ - u32 val; - /* 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 before causing it */ - wmb(); - if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) - adreno_write_gmureg(adreno_dev, - ADRENO_REG_GMU_NMI_CONTROL_STATUS, 0); - - adreno_read_gmureg(adreno_dev, ADRENO_REG_GMU_CM3_CFG, &val); - val |= 1 << GMU_CM3_CFG_NONMASKINTR_SHIFT; - adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_CM3_CFG, val); - - /* Make sure the NMI is invoked before we proceed*/ - wmb(); -} - /* * A workqueue callback responsible for actually turning on the GPU after a * touch event. kgsl_pwrctrl_change_state(ACTIVE) is used without any @@ -1831,7 +1807,7 @@ int adreno_switch_to_unsecure_mode(struct adreno_device *adreno_dev, return ret; } -static void adreno_set_active_ctxs_null(struct adreno_device *adreno_dev) +void adreno_set_active_ctxs_null(struct adreno_device *adreno_dev) { int i; struct adreno_ringbuffer *rb; diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 7afe78e0cb78..994efb868905 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -905,6 +905,7 @@ 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 int adreno_wake_nice; extern unsigned int adreno_wake_timeout; @@ -1758,7 +1759,6 @@ 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); /** @@ -1858,6 +1858,15 @@ int adreno_power_cycle_bool(struct adreno_device *adreno_dev, 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 diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index a582ad008554..5eb7e8eee1f0 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -119,7 +119,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 +400,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); @@ -860,11 +854,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; @@ -1030,11 +1020,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); @@ -2332,17 +2318,11 @@ static struct adreno_perfcounters a6xx_perfcounters = { ARRAY_SIZE(a6xx_perfcounter_groups), }; -static int a6xx_probe(struct platform_device *pdev, - u32 chipid, const struct adreno_gpu_core *gpucore) +int a6xx_probe_common(struct platform_device *pdev, + struct adreno_device *adreno_dev, u32 chipid, + const struct adreno_gpu_core *gpucore) { - struct adreno_device *adreno_dev; struct adreno_gpudev *gpudev = gpucore->gpudev; - 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; @@ -2385,13 +2365,33 @@ static int a6xx_probe(struct platform_device *pdev, 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 adreno_device_probe(pdev, adreno_dev); + return 0; } @@ -2685,3 +2685,38 @@ struct adreno_gpudev adreno_a6xx_gpudev = { .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_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_reset, + .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, +}; diff --git a/drivers/gpu/msm/adreno_a6xx.h b/drivers/gpu/msm/adreno_a6xx.h index 09b55fa184e3..301a3320a537 100644 --- a/drivers/gpu/msm/adreno_a6xx.h +++ b/drivers/gpu/msm/adreno_a6xx.h @@ -7,8 +7,22 @@ #define _ADRENO_A6XX_H_ #include +#include #include "a6xx_reg.h" +#include "adreno_a6xx_gmu.h" + +extern const struct adreno_power_ops a6xx_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; + /** @adreno_dev: Container for the generic adreno device */ + struct adreno_device adreno_dev; +}; /** * struct a6xx_protected_regs - container for a protect register span @@ -174,41 +188,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; + return 0; } static inline int timed_poll_check_rscc(struct kgsl_device *device, @@ -219,14 +227,15 @@ static inline int timed_poll_check_rscc(struct kgsl_device *device, unsigned long t; unsigned int value; + if (!adreno_is_a650_family(adreno_dev)) + return timed_poll_check(device, offset + RSCC_OFFSET_LEGACY, + expected_ret, timeout, mask); + 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); + adreno_rscc_regread(adreno_dev, offset, &value); + if ((value & mask) == expected_ret) return 0; /* Wait 100us to reduce unnecessary AHB bus traffic */ @@ -236,8 +245,7 @@ static inline int timed_poll_check_rscc(struct kgsl_device *device, /* 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; @@ -273,10 +281,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 diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index 38bd5c171381..036b20c0473e 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -3,7 +3,6 @@ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ -#include #include #include #include @@ -14,14 +13,11 @@ #include #include #include +#include #include -#include #include "adreno.h" #include "adreno_a6xx.h" -#include "adreno_a6xx_gmu.h" -#include "adreno_snapshot.h" -#include "kgsl_bus.h" #include "kgsl_device.h" #include "kgsl_trace.h" #include "kgsl_util.h" @@ -32,29 +28,72 @@ struct gmu_iommu_context { struct iommu_domain *domain; }; -struct gmu_vma_entry { - unsigned int start; - unsigned int size; +#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)) + +static struct gmu_vma_entry a6xx_gmu_vma_legacy[] = { + [GMU_ITCM] = { + .start = 0x00000, + .size = SZ_16K + }, + [GMU_ICACHE] = { + .start = 0x04000, + .size = (SZ_256K - SZ_16K), + .next_va = 0x4000 + }, + [GMU_DTCM] = { + .start = 0x40000, + .size = SZ_16K + }, + [GMU_DCACHE] = { + .start = 0x44000, + .size = (SZ_256K - SZ_16K), + .next_va = 0x44000 + }, + [GMU_NONCACHED_KERNEL] = { + .start = 0x60000000, + .size = SZ_512M, + .next_va = 0x60000000 + }, + [GMU_NONCACHED_USER] = { + .start = 0x80000000, + .size = SZ_1G, + .next_va = 0x80000000 + }, }; -static const struct gmu_vma_entry a6xx_gmu_vma_legacy[] = { - [GMU_ITCM] = { .start = 0x00000, .size = SZ_16K }, - [GMU_ICACHE] = { .start = 0x04000, .size = (SZ_256K - SZ_16K) }, - [GMU_DTCM] = { .start = 0x40000, .size = SZ_16K }, - [GMU_DCACHE] = { .start = 0x44000, .size = (SZ_256K - SZ_16K) }, - [GMU_NONCACHED_KERNEL] = { .start = 0x60000000, .size = SZ_512M }, - [GMU_NONCACHED_USER] = { .start = 0x80000000, .size = SZ_1G }, - [GMU_MEM_TYPE_MAX] = { .start = 0x0, .size = 0x0 }, -}; - -static const struct gmu_vma_entry a6xx_gmu_vma[] = { - [GMU_ITCM] = { .start = 0x00000000, .size = SZ_16K }, - [GMU_CACHE] = { .start = SZ_16K, .size = (SZ_16M - SZ_16K) }, - [GMU_DTCM] = { .start = SZ_256M + SZ_16K, .size = SZ_16K }, - [GMU_DCACHE] = { .start = 0x0, .size = 0x0 }, - [GMU_NONCACHED_KERNEL] = { .start = 0x60000000, .size = SZ_512M }, - [GMU_NONCACHED_USER] = { .start = 0x80000000, .size = SZ_1G }, - [GMU_MEM_TYPE_MAX] = { .start = 0x0, .size = 0x0 }, +static struct gmu_vma_entry a6xx_gmu_vma[] = { + [GMU_ITCM] = { + .start = 0x00000000, + .size = SZ_16K + }, + [GMU_CACHE] = { + .start = SZ_16K, + .size = (SZ_16M - SZ_16K), + .next_va = SZ_16K + }, + [GMU_DTCM] = { + .start = SZ_256M + SZ_16K, + .size = SZ_16K + }, + [GMU_DCACHE] = { + .start = 0x0, + .size = 0x0 + }, + [GMU_NONCACHED_KERNEL] = { + .start = 0x60000000, + .size = SZ_512M, + .next_va = 0x60000000 + }, + [GMU_NONCACHED_USER] = { + .start = 0x80000000, + .size = SZ_1G, + .next_va = 0x80000000 + }, }; static struct gmu_iommu_context a6xx_gmu_ctx[] = { @@ -62,53 +101,21 @@ static struct gmu_iommu_context a6xx_gmu_ctx[] = { [GMU_CONTEXT_KERNEL] = { .name = "gmu_kernel" } }; -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, -}; +struct a6xx_gmu_device *to_a6xx_gmu(struct adreno_device *adreno_dev) +{ + struct a6xx_device *a6xx_dev = container_of(adreno_dev, + struct a6xx_device, adreno_dev); -static const unsigned int a6xx_gmu_tcm_registers[] = { - /* ITCM */ - 0x1B400, 0x1C3FF, - /* DTCM */ - 0x1C400, 0x1D3FF, -}; + return &a6xx_dev->gmu; +} -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, -}; +struct adreno_device *a6xx_gmu_to_adreno(struct a6xx_gmu_device *gmu) +{ + struct a6xx_device *a6xx_dev = + container_of(gmu, struct a6xx_device, gmu); -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, -}; + return &a6xx_dev->adreno_dev; +} #define RSC_CMD_OFFSET 2 #define PDC_CMD_OFFSET 4 @@ -122,9 +129,9 @@ static void _regwrite(void __iomem *regbase, __raw_writel(value, reg); } -static void a6xx_load_rsc_ucode(struct kgsl_device *device) +static void a6xx_load_rsc_ucode(struct adreno_device *adreno_dev) { - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); void __iomem *rscc; if (adreno_is_a650_family(adreno_dev)) @@ -166,10 +173,9 @@ static void a6xx_load_rsc_ucode(struct kgsl_device *device) } } -static int a6xx_load_pdc_ucode(struct kgsl_device *device) +static int a6xx_load_pdc_ucode(struct adreno_device *adreno_dev) { - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); struct resource *res_pdc, *res_cfg, *res_seq; unsigned int cfg_offset, seq_offset; void __iomem *cfg = NULL, *seq = NULL; @@ -336,12 +342,6 @@ done: return 0; } -static int _load_gmu_rpmh_ucode(struct kgsl_device *device) -{ - a6xx_load_rsc_ucode(device); - return a6xx_load_pdc_ucode(device); -} - /* GMU timeouts */ #define GMU_IDLE_TIMEOUT 100 /* ms */ #define GMU_START_TIMEOUT 100 /* ms */ @@ -361,12 +361,12 @@ static int _load_gmu_rpmh_ucode(struct kgsl_device *device) /* * a6xx_gmu_power_config() - Configure and enable GMU's low power mode * setting based on ADRENO feature flags. - * @device: Pointer to KGSL device + * @adreno_dev: Pointer to adreno device */ -static void a6xx_gmu_power_config(struct kgsl_device *device) +static void a6xx_gmu_power_config(struct adreno_device *adreno_dev) { - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); /* Configure registers for idle setting. The setting is cumulative */ @@ -411,9 +411,10 @@ static void a6xx_gmu_power_config(struct kgsl_device *device) RPMH_ENABLE_MASK); } -static int a6xx_gmu_device_start(struct kgsl_device *device) +static int a6xx_gmu_device_start(struct adreno_device *adreno_dev) { - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); u32 val = 0x00000100; u32 mask = 0x000001FF; @@ -452,9 +453,10 @@ static int a6xx_gmu_device_start(struct kgsl_device *device) * a6xx_gmu_hfi_start() - Write registers and start HFI. * @device: Pointer to KGSL device */ -static int a6xx_gmu_hfi_start(struct kgsl_device *device) +static int a6xx_gmu_hfi_start(struct adreno_device *adreno_dev) { - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); gmu_core_regwrite(device, A6XX_GMU_HFI_CTRL_INIT, 1); @@ -470,16 +472,16 @@ static int a6xx_gmu_hfi_start(struct kgsl_device *device) return 0; } -static int a6xx_rpmh_power_on_gpu(struct kgsl_device *device) +static int a6xx_rscc_wakeup_sequence(struct adreno_device *adreno_dev) { - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); struct device *dev = &gmu->pdev->dev; int val; - /* Only trigger wakeup sequence if sleep sequence was done earlier */ - if (!test_bit(GMU_RSCC_SLEEP_SEQ_DONE, &device->gmu_core.flags)) + /* Skip wakeup sequence if we didn't do the sleep sequence */ + if (!test_bit(GMU_PRIV_RSCC_SLEEP_DONE, &gmu->flags)) return 0; - /* A660 has a replacement register */ if (adreno_is_a660(ADRENO_DEVICE(device))) gmu_core_regread(device, A6XX_GPU_CC_GX_DOMAIN_MISC3, &val); @@ -502,7 +504,7 @@ static int a6xx_rpmh_power_on_gpu(struct kgsl_device *device) GPU_START_TIMEOUT, BIT(1))) { dev_err(dev, "Failed to do GPU RSC power on\n"); - return -EINVAL; + return -ETIMEDOUT; } if (timed_poll_check_rscc(device, @@ -514,22 +516,25 @@ static int a6xx_rpmh_power_on_gpu(struct kgsl_device *device) gmu_core_regwrite(device, A6XX_GMU_RSCC_CONTROL_REQ, 0); - /* Clear sleep sequence flag as wakeup sequence is successful */ - clear_bit(GMU_RSCC_SLEEP_SEQ_DONE, &device->gmu_core.flags); + clear_bit(GMU_PRIV_RSCC_SLEEP_DONE, &gmu->flags); return 0; + error_rsc: dev_err(dev, "GPU RSC sequence stuck in waking up GPU\n"); - return -EINVAL; + return -ETIMEDOUT; } -static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device) +static int a6xx_rscc_sleep_sequence(struct adreno_device *adreno_dev) { - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); int ret; - if (test_bit(GMU_RSCC_SLEEP_SEQ_DONE, &device->gmu_core.flags)) + if (!test_bit(GMU_PRIV_FIRST_BOOT_DONE, &gmu->flags)) + return 0; + + if (test_bit(GMU_PRIV_RSCC_SLEEP_DONE, &gmu->flags)) return 0; gmu_core_regwrite(device, A6XX_GMU_CM3_SYSRESET, 1); @@ -559,10 +564,53 @@ static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device) if (adreno_dev->lm_enabled) gmu_core_regwrite(device, A6XX_GMU_AO_SPARE_CNTL, 0); - set_bit(GMU_RSCC_SLEEP_SEQ_DONE, &device->gmu_core.flags); + set_bit(GMU_PRIV_RSCC_SLEEP_DONE, &gmu->flags); + return 0; } +static struct gmu_memdesc *find_gmu_memdesc(struct a6xx_gmu_device *gmu, + u32 addr, u32 size) +{ + int i; + + for (i = 0; i < gmu->global_entries; i++) { + struct gmu_memdesc *md = &gmu->gmu_globals[i]; + + if ((addr >= md->gmuaddr) && + (((addr + size) <= (md->gmuaddr + md->size)))) + return md; + } + + return NULL; +} + +static int find_vma_block(struct a6xx_gmu_device *gmu, u32 addr, u32 size) +{ + int i; + + for (i = 0; i < GMU_MEM_TYPE_MAX; i++) { + struct gmu_vma_entry *vma = &gmu->vma[i]; + + if ((addr >= vma->start) && + ((addr + size) <= (vma->start + vma->size))) + return i; + } + + return -ENOENT; +} + +static struct iommu_domain *get_gmu_domain(struct a6xx_gmu_device *gmu, + struct gmu_memdesc *md) +{ + u32 vma_id = find_vma_block(gmu, md->gmuaddr, md->size); + + if (vma_id == GMU_NONCACHED_USER) + return a6xx_gmu_ctx[GMU_CONTEXT_USER].domain; + + return a6xx_gmu_ctx[GMU_CONTEXT_KERNEL].domain; +} + static int _load_legacy_gmu_fw(struct kgsl_device *device, struct a6xx_gmu_device *gmu) { @@ -579,69 +627,66 @@ static int _load_legacy_gmu_fw(struct kgsl_device *device, return 0; } -static struct gmu_memdesc *a6xx_gmu_get_memdesc(struct a6xx_gmu_device *gmu, - unsigned int addr, unsigned int size) +static void load_tcm(struct adreno_device *adreno_dev, const u8 *src, + u32 tcm_start, u32 base, const struct gmu_block_header *blk) { - int i; - struct gmu_memdesc *mem; + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + u32 tcm_offset = tcm_start + ((blk->addr - base)/sizeof(u32)); + void __iomem *addr = device->gmu_core.reg_virt + + ((tcm_offset - device->gmu_core.gmu2gpu_offset) << 2); - for (i = 0; i < GMU_KERNEL_ENTRIES; i++) { - if (!test_bit(i, &gmu->kmem_bitmap)) - continue; - - mem = &gmu->kmem_entries[i]; - - if (addr >= mem->gmuaddr && - (addr + size <= mem->gmuaddr + mem->size)) - return mem; - } - - return NULL; + memcpy_toio(addr, src, blk->size); } -static int load_gmu_fw(struct kgsl_device *device) +static int a6xx_gmu_load_fw(struct adreno_device *adreno_dev) { - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); - uint8_t *fw = (uint8_t *)gmu->fw_image->data; - int tcm_addr; - struct gmu_block_header *blk; - struct gmu_memdesc *md; + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + const u8 *fw = (const u8 *)gmu->fw_image->data; - if (adreno_is_a630(ADRENO_DEVICE(device)) || - adreno_is_a615_family(ADRENO_DEVICE(device))) - return _load_legacy_gmu_fw(device, gmu); + if (adreno_is_a630(adreno_dev) || adreno_is_a615_family(adreno_dev)) + return _load_legacy_gmu_fw(KGSL_DEVICE(adreno_dev), gmu); + + while (fw < gmu->fw_image->data + gmu->fw_image->size) { + const struct gmu_block_header *blk = + (const struct gmu_block_header *)fw; + int id; - while (fw < (uint8_t *)gmu->fw_image->data + gmu->fw_image->size) { - blk = (struct gmu_block_header *)fw; fw += sizeof(*blk); /* Don't deal with zero size blocks */ if (blk->size == 0) continue; - md = a6xx_gmu_get_memdesc(gmu, blk->addr, blk->size); - if (md == NULL) { + id = find_vma_block(gmu, blk->addr, blk->size); + + if (id < 0) { dev_err(&gmu->pdev->dev, - "No backing memory for 0x%8.8X\n", - blk->addr); + "Unknown block in GMU FW addr:0x%x size:0x%x\n", + blk->addr, blk->size); return -EINVAL; } - if (md->mem_type == GMU_ITCM || md->mem_type == GMU_DTCM) { - tcm_addr = (blk->addr - (uint32_t)md->gmuaddr) / - sizeof(uint32_t); - - if (md->mem_type == GMU_ITCM) - tcm_addr += A6XX_GMU_CM3_ITCM_START; - else - tcm_addr += A6XX_GMU_CM3_DTCM_START; - - gmu_core_blkwrite(device, tcm_addr, fw, blk->size); + if (id == GMU_ITCM) { + load_tcm(adreno_dev, fw, + A6XX_GMU_CM3_ITCM_START, + gmu->vma[GMU_ITCM].start, blk); + } else if (id == GMU_DTCM) { + load_tcm(adreno_dev, fw, + A6XX_GMU_CM3_DTCM_START, + gmu->vma[GMU_DTCM].start, blk); } else { - uint32_t offset = blk->addr - (uint32_t)md->gmuaddr; + struct gmu_memdesc *md = + find_gmu_memdesc(gmu, blk->addr, blk->size); - /* Copy the memory directly */ - memcpy(md->hostptr + offset, fw, blk->size); + if (!md) { + dev_err(&gmu->pdev->dev, + "No backing memory for GMU FW block addr:0x%x size:0x%x\n", + blk->addr, blk->size); + return -EINVAL; + } + + memcpy(md->hostptr + (blk->addr - md->gmuaddr), fw, + blk->size); } fw += blk->size; @@ -665,16 +710,11 @@ static const char *oob_to_str(enum oob_request req) return "unknown"; } -/* - * a6xx_gmu_oob_set() - Set OOB interrupt to GMU. - * @device: Pointer to kgsl device - * @req: Which of the OOB bits to request - */ static int a6xx_gmu_oob_set(struct kgsl_device *device, enum oob_request req) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); int ret = 0; int set, check; @@ -711,16 +751,11 @@ static int a6xx_gmu_oob_set(struct kgsl_device *device, return ret; } -/* - * a6xx_gmu_oob_clear() - Clear a previously set OOB request. - * @device: Pointer to the kgsl device that has the GMU - * @req: Which of the OOB bits to clear - */ static void a6xx_gmu_oob_clear(struct kgsl_device *device, enum oob_request req) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); int clear; if (adreno_is_a630(adreno_dev) || adreno_is_a615_family(adreno_dev)) { @@ -738,35 +773,34 @@ static void a6xx_gmu_oob_clear(struct kgsl_device *device, trace_kgsl_gmu_oob_clear(clear); } -static void a6xx_gmu_irq_enable(struct kgsl_device *device) +static void a6xx_gmu_irq_enable(struct adreno_device *adreno_dev) { - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); struct a6xx_hfi *hfi = &gmu->hfi; /* Clear pending IRQs and Unmask needed IRQs */ - adreno_gmu_clear_and_unmask_irqs(ADRENO_DEVICE(device)); + adreno_gmu_clear_and_unmask_irqs(adreno_dev); /* Enable all IRQs on host */ - enable_irq(hfi->hfi_interrupt_num); - enable_irq(gmu->gmu_interrupt_num); + enable_irq(hfi->irq); + enable_irq(gmu->irq); } -static void a6xx_gmu_irq_disable(struct kgsl_device *device) +static void a6xx_gmu_irq_disable(struct adreno_device *adreno_dev) { - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); struct a6xx_hfi *hfi = &gmu->hfi; /* Disable all IRQs on host */ - disable_irq(gmu->gmu_interrupt_num); - disable_irq(hfi->hfi_interrupt_num); + disable_irq(gmu->irq); + disable_irq(hfi->irq); /* Mask all IRQs and clear pending IRQs */ - adreno_gmu_mask_and_clear_irqs(ADRENO_DEVICE(device)); + adreno_gmu_mask_and_clear_irqs(adreno_dev); } -static int a6xx_gmu_hfi_start_msg(struct kgsl_device *device) +static int a6xx_gmu_hfi_start_msg(struct adreno_device *adreno_dev) { - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct hfi_start_cmd req; /* @@ -775,7 +809,7 @@ static int a6xx_gmu_hfi_start_msg(struct kgsl_device *device) * legacy firmware. */ if (!ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) - return a6xx_hfi_send_req(A6XX_GMU_DEVICE(device), + return a6xx_hfi_send_req(adreno_dev, H2F_MSG_START, &req); return 0; @@ -785,6 +819,8 @@ static int a6xx_gmu_hfi_start_msg(struct kgsl_device *device) #define FREQ_VOTE(idx, ack) (((idx) & 0xFF) | (((ack) & 0xF) << 28)) #define BW_VOTE(idx) ((((idx) & 0xFFF) << 12) | ((idx) & 0xFFF)) +#define CLKSET_OPTION_ATLEAST 3 + /* * a6xx_gmu_dcvs_nohfi() - request GMU to do DCVS without using HFI * @device: Pointer to KGSL device @@ -813,8 +849,10 @@ static int a6xx_gmu_dcvs_nohfi(struct kgsl_device *device, return ret; } -static int a6xx_complete_rpmh_votes(struct kgsl_device *device) + +static int a6xx_complete_rpmh_votes(struct adreno_device *adreno_dev) { + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); int ret = 0; ret |= timed_poll_check_rscc(device, A6XX_RSCC_TCS0_DRV0_STATUS, @@ -843,7 +881,7 @@ static int a6xx_complete_rpmh_votes(struct kgsl_device *device) int a6xx_gmu_sptprac_enable(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); if (!gmu_core_gpmu_isenabled(device) || !adreno_has_sptprac_gdsc(adreno_dev)) @@ -858,7 +896,7 @@ int a6xx_gmu_sptprac_enable(struct adreno_device *adreno_dev) SPTPRAC_CTRL_TIMEOUT, SPTPRAC_POWERON_STATUS_MASK)) { dev_err(&gmu->pdev->dev, "power on SPTPRAC fail\n"); - return -EINVAL; + return -ETIMEDOUT; } return 0; @@ -871,7 +909,7 @@ int a6xx_gmu_sptprac_enable(struct adreno_device *adreno_dev) void a6xx_gmu_sptprac_disable(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); if (!gmu_core_gpmu_isenabled(device) || !adreno_has_sptprac_gdsc(adreno_dev)) @@ -897,13 +935,8 @@ void a6xx_gmu_sptprac_disable(struct adreno_device *adreno_dev) #define GX_GDSC_POWER_OFF BIT(6) #define GX_CLK_OFF BIT(7) #define is_on(val) (!(val & (GX_GDSC_POWER_OFF | GX_CLK_OFF))) -/* - * a6xx_gmu_gx_is_on() - Check if GX is on using pwr status register - * @device - Pointer to KGSLxi _device - * This check should only be performed if the keepalive bit is set or it - * can be guaranteed that the power state of the GPU will remain unchanged - */ -static bool a6xx_gmu_gx_is_on(struct kgsl_device *device) + +bool a6xx_gmu_gx_is_on(struct kgsl_device *device) { unsigned int val; @@ -934,13 +967,14 @@ bool a6xx_gmu_sptprac_is_on(struct adreno_device *adreno_dev) * @device: Pointer to KGSL device * */ -static int a6xx_gmu_gfx_rail_on(struct kgsl_device *device) +static int a6xx_gmu_gfx_rail_on(struct adreno_device *adreno_dev) { + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct kgsl_pwrctrl *pwr = &device->pwrctrl; - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); - unsigned int perf_idx = gmu->num_gpupwrlevels - + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + u32 perf_idx = gmu->hfi.dcvs_table.gpu_level_num - pwr->default_pwrlevel - 1; - uint32_t default_opp = gmu->rpmh_votes.gx_votes[perf_idx]; + u32 default_opp = gmu->hfi.dcvs_table.gx_votes[perf_idx].vote; gmu_core_regwrite(device, A6XX_GMU_BOOT_SLUMBER_OPTION, OOB_BOOT_OPTION); @@ -988,14 +1022,15 @@ static const char *idle_level_name(int level) return ""; } -static int a6xx_gmu_wait_for_lowest_idle(struct kgsl_device *device) +static int a6xx_gmu_wait_for_lowest_idle(struct adreno_device *adreno_dev) { - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); unsigned int reg, reg1, reg2, reg3, reg4, reg5, reg6, reg7, reg8; unsigned long t; uint64_t ts1, ts2, ts3; - ts1 = a6xx_read_alwayson(ADRENO_DEVICE(device)); + ts1 = a6xx_read_alwayson(adreno_dev); t = jiffies + msecs_to_jiffies(GMU_IDLE_TIMEOUT); do { @@ -1010,7 +1045,7 @@ static int a6xx_gmu_wait_for_lowest_idle(struct kgsl_device *device) usleep_range(10, 100); } while (!time_after(jiffies, t)); - ts2 = a6xx_read_alwayson(ADRENO_DEVICE(device)); + ts2 = a6xx_read_alwayson(adreno_dev); /* Check one last time */ gmu_core_regread(device, A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE, ®); @@ -1019,7 +1054,7 @@ static int a6xx_gmu_wait_for_lowest_idle(struct kgsl_device *device) if (idle_trandition_complete(gmu->idle_level, reg, reg1)) return 0; - ts3 = a6xx_read_alwayson(ADRENO_DEVICE(device)); + ts3 = a6xx_read_alwayson(adreno_dev); /* Collect abort data to help with debugging */ gmu_core_regread(device, A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS, ®2); @@ -1063,13 +1098,14 @@ static int a6xx_gmu_wait_for_lowest_idle(struct kgsl_device *device) /* Bitmask for GPU idle status check */ #define CXGXCPUBUSYIGNAHB BIT(30) -static int a6xx_gmu_wait_for_idle(struct kgsl_device *device) +static int a6xx_gmu_wait_for_idle(struct adreno_device *adreno_dev) { - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); unsigned int status2; uint64_t ts1; - ts1 = a6xx_read_alwayson(ADRENO_DEVICE(device)); + ts1 = a6xx_read_alwayson(adreno_dev); if (timed_poll_check(device, A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS, 0, GMU_START_TIMEOUT, CXGXCPUBUSYIGNAHB)) { gmu_core_regread(device, @@ -1087,9 +1123,10 @@ static int a6xx_gmu_wait_for_idle(struct kgsl_device *device) /* A6xx GMU FENCE RANGE MASK */ #define GMU_FENCE_RANGE_MASK ((0x1 << 31) | ((0xA << 2) << 18) | (0x8A0)) -static void load_gmu_version_info(struct kgsl_device *device) +static void a6xx_gmu_version_info(struct adreno_device *adreno_dev) { - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); /* GMU version info is at a fixed offset in the DTCM */ gmu_core_regread(device, A6XX_GMU_CM3_DTCM_START + 0xFF8, @@ -1104,19 +1141,30 @@ static void load_gmu_version_info(struct kgsl_device *device) &gmu->ver.hfi); } -static void a6xx_gmu_mem_free(struct a6xx_gmu_device *gmu, - struct gmu_memdesc *md) +static int a6xx_gmu_itcm_shadow(struct adreno_device *adreno_dev) { - /* Free GMU image memory */ - if (md->hostptr) - dma_free_attrs(&gmu->pdev->dev, (size_t) md->size, - (void *)md->hostptr, md->physaddr, 0); - memset(md, 0, sizeof(*md)); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + u32 i, *dest; + + if (gmu->itcm_shadow) + return 0; + + gmu->itcm_shadow = vzalloc(gmu->vma[GMU_ITCM].size); + if (!gmu->itcm_shadow) + return -ENOMEM; + + dest = (u32 *)gmu->itcm_shadow; + + for (i = 0; i < (gmu->vma[GMU_ITCM].size >> 2); i++) + gmu_core_regread(KGSL_DEVICE(adreno_dev), + A6XX_GMU_CM3_ITCM_START + i, dest++); + + return 0; } -static void a6xx_gmu_enable_lm(struct kgsl_device *device) +static void a6xx_gmu_enable_lm(struct adreno_device *adreno_dev) { - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); u32 val; memset(adreno_dev->busy_data.throttle_cycles, 0, @@ -1148,11 +1196,11 @@ static void a6xx_gmu_enable_lm(struct kgsl_device *device) gmu_core_regwrite(device, A6XX_GMU_AO_SPARE_CNTL, 1); } -static void a6xx_gmu_register_config(struct kgsl_device *device) +static void a6xx_gmu_register_config(struct adreno_device *adreno_dev) { - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); const struct adreno_a6xx_core *a6xx_core = to_a6xx_core(adreno_dev); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); u32 gmu_log_info, chipid = 0; /* Vote veto for FAL10 feature if supported*/ @@ -1167,7 +1215,7 @@ static void a6xx_gmu_register_config(struct kgsl_device *device) gmu_core_regwrite(device, A6XX_GMU_CM3_BOOT_CONFIG, 0x2); gmu_core_regwrite(device, A6XX_GMU_HFI_QTBL_ADDR, - gmu->hfi_mem->gmuaddr); + gmu->hfi.hfi_mem->gmuaddr); gmu_core_regwrite(device, A6XX_GMU_HFI_QTBL_INFO, 1); gmu_core_regwrite(device, A6XX_GMU_AHB_FENCE_RANGE_0, @@ -1214,227 +1262,92 @@ static void a6xx_gmu_register_config(struct kgsl_device *device) gmu_log_info); /* Configure power control and bring the GMU out of reset */ - a6xx_gmu_power_config(device); + a6xx_gmu_power_config(adreno_dev); - a6xx_gmu_enable_lm(device); + a6xx_gmu_enable_lm(adreno_dev); } -/* - * a6xx_gmu_fw_start() - set up GMU and start FW - * @device: Pointer to KGSL device - */ -static int a6xx_gmu_fw_start(struct kgsl_device *device) +struct gmu_memdesc *reserve_gmu_kernel_block(struct a6xx_gmu_device *gmu, + u32 addr, u32 size, u32 vma_id) { - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); int ret; + struct gmu_memdesc *md; + struct gmu_vma_entry *vma = &gmu->vma[vma_id]; - /* Do the necessary register programming */ - a6xx_gmu_register_config(device); + if (gmu->global_entries == ARRAY_SIZE(gmu->gmu_globals)) + return ERR_PTR(-ENOMEM); - if (!test_and_set_bit(GMU_BOOT_INIT_DONE, - &device->gmu_core.flags)) - ret = _load_gmu_rpmh_ucode(device); - else - ret = a6xx_rpmh_power_on_gpu(device); - if (ret) - return ret; + md = &gmu->gmu_globals[gmu->global_entries]; - /* Load GMU image via AHB bus */ - ret = load_gmu_fw(device); - if (ret) - return ret; + md->size = PAGE_ALIGN(size); - /* Populate the GMU version info before GMU boots */ - load_gmu_version_info(device); - - /* Clear any previously set cm3 fault */ - atomic_set(&gmu->cm3_fault, 0); - - ret = a6xx_gmu_device_start(device); - if (ret) - return ret; - - if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) { - ret = a6xx_gmu_gfx_rail_on(device); - if (ret) { - a6xx_gmu_oob_clear(device, oob_boot_slumber); - return ret; - } - } - - if (gmu->idle_level < GPU_HW_SPTP_PC) { - ret = a6xx_gmu_sptprac_enable(adreno_dev); - if (ret) - return ret; - } - - ret = a6xx_gmu_hfi_start(device); - if (ret) - return ret; - - /* Make sure the write to start HFI happens before sending a message */ - wmb(); - return ret; -} - -static int a6xx_gmu_alloc_and_map(struct a6xx_gmu_device *gmu, - struct gmu_memdesc *md, unsigned int attrs) -{ - struct iommu_domain *domain = a6xx_gmu_ctx[md->ctx_idx].domain; - int ret; - - md->hostptr = dma_alloc_attrs(&gmu->pdev->dev, (size_t) md->size, + md->hostptr = dma_alloc_attrs(&gmu->pdev->dev, (size_t)md->size, &md->physaddr, GFP_KERNEL, 0); if (md->hostptr == NULL) - return -ENOMEM; + return ERR_PTR(-ENOMEM); - ret = iommu_map(domain, md->gmuaddr, md->physaddr, md->size, - attrs); + memset(md->hostptr, 0x0, size); - if (ret) { - dev_err(&gmu->pdev->dev, - "gmu map err: gaddr=0x%016llX, paddr=0x%pa\n", - md->gmuaddr, &(md->physaddr)); - a6xx_gmu_mem_free(gmu, md); - } + if (!addr) + addr = vma->next_va; - return ret; -} - -/* - * There are a few static memory buffers that are allocated and mapped at boot - * time for GMU to function. The buffers are permanent (not freed) after - * GPU boot. The size of the buffers are constant and not expected to change. - * - * We define an array and a simple allocator to keep track of the currently - * active SMMU entries of GMU kernel mode context. Each entry is assigned - * a unique address inside GMU kernel mode address range. - */ -static struct gmu_memdesc *a6xx_gmu_kmem_allocate(struct a6xx_gmu_device *gmu, - enum gmu_mem_type mem_type, unsigned int addr, - unsigned int size, unsigned int attrs) -{ - static unsigned int next_uncached_kernel_alloc; - static unsigned int next_uncached_user_alloc; - - struct gmu_memdesc *md; - int ret; - int entry_idx = find_first_zero_bit( - &gmu->kmem_bitmap, GMU_KERNEL_ENTRIES); - - if (entry_idx >= GMU_KERNEL_ENTRIES) { - dev_err(&gmu->pdev->dev, - "Ran out of GMU kernel mempool slots\n"); - return ERR_PTR(-EINVAL); - } - - /* Non-TCM requests have page alignment requirement */ - if ((mem_type != GMU_ITCM) && (mem_type != GMU_DTCM) && - addr & (PAGE_SIZE - 1)) { - dev_err(&gmu->pdev->dev, - "Invalid alignment request 0x%X\n", - addr); - return ERR_PTR(-EINVAL); - } - - md = &gmu->kmem_entries[entry_idx]; - set_bit(entry_idx, &gmu->kmem_bitmap); - - memset(md, 0, sizeof(*md)); - - switch (mem_type) { - case GMU_ITCM: - case GMU_DTCM: - /* Assign values and return without mapping */ - md->size = size; - md->mem_type = mem_type; - md->gmuaddr = addr; - return md; - - case GMU_DCACHE: - case GMU_ICACHE: - md->ctx_idx = GMU_CONTEXT_KERNEL; - size = PAGE_ALIGN(size); - break; - - case GMU_NONCACHED_KERNEL: - /* Set start address for first uncached kernel alloc */ - if (next_uncached_kernel_alloc == 0) - next_uncached_kernel_alloc = gmu->vma[mem_type].start; - - if (addr == 0) - addr = next_uncached_kernel_alloc; - - md->ctx_idx = GMU_CONTEXT_KERNEL; - size = PAGE_ALIGN(size); - break; - case GMU_NONCACHED_USER: - /* Set start address for first uncached kernel alloc */ - if (next_uncached_user_alloc == 0) - next_uncached_user_alloc = gmu->vma[mem_type].start; - - if (addr == 0) - addr = next_uncached_user_alloc; - - md->ctx_idx = GMU_CONTEXT_USER; - size = PAGE_ALIGN(size); - break; - - default: - dev_err(&gmu->pdev->dev, - "Invalid memory type (%d) requested\n", - mem_type); - clear_bit(entry_idx, &gmu->kmem_bitmap); - return ERR_PTR(-EINVAL); - } - - md->size = size; - md->mem_type = mem_type; md->gmuaddr = addr; - ret = a6xx_gmu_alloc_and_map(gmu, md, attrs); + ret = iommu_map(get_gmu_domain(gmu, md), addr, md->physaddr, md->size, + IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV); if (ret) { - clear_bit(entry_idx, &gmu->kmem_bitmap); + dev_err(&gmu->pdev->dev, + "Unable to map GMU kernel block: addr:0x%08x size:0x%x :%d\n", + md->gmuaddr, md->size, ret); + dma_free_attrs(&gmu->pdev->dev, (size_t)size, + (void *)md->hostptr, md->physaddr, 0); + memset(md, 0, sizeof(*md)); return ERR_PTR(ret); } - if (mem_type == GMU_NONCACHED_KERNEL) - next_uncached_kernel_alloc = PAGE_ALIGN(md->gmuaddr + md->size); - if (mem_type == GMU_NONCACHED_USER) - next_uncached_user_alloc = PAGE_ALIGN(md->gmuaddr + md->size); + vma->next_va = md->gmuaddr + md->size; + + gmu->global_entries++; return md; } - -static int a6xx_gmu_cache_finalize(struct adreno_device *adreno_dev, - struct a6xx_gmu_device *gmu) +static int reserve_entire_vma(struct a6xx_gmu_device *gmu, u32 vma_id) { struct gmu_memdesc *md; + u32 start = gmu->vma[vma_id].start, size = gmu->vma[vma_id].size; + + md = find_gmu_memdesc(gmu, start, size); + if (md) + return 0; + + md = reserve_gmu_kernel_block(gmu, start, size, vma_id); + + return PTR_ERR_OR_ZERO(md); +} + +static int a6xx_gmu_cache_finalize(struct adreno_device *adreno_dev) +{ + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + struct gmu_memdesc *md; + int ret; /* Preallocations were made so no need to request all this memory */ if (gmu->preallocations) return 0; - md = a6xx_gmu_kmem_allocate(gmu, GMU_ICACHE, - gmu->vma[GMU_ICACHE].start, gmu->vma[GMU_ICACHE].size, - (IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV)); - if (IS_ERR(md)) - return PTR_ERR(md); + ret = reserve_entire_vma(gmu, GMU_ICACHE); + if (ret) + return ret; if (!adreno_is_a650_family(adreno_dev)) { - md = a6xx_gmu_kmem_allocate(gmu, GMU_DCACHE, - gmu->vma[GMU_DCACHE].start, - gmu->vma[GMU_DCACHE].size, - (IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV)); - if (IS_ERR(md)) - return PTR_ERR(md); + ret = reserve_entire_vma(gmu, GMU_DCACHE); + if (ret) + return ret; } - md = a6xx_gmu_kmem_allocate(gmu, GMU_NONCACHED_KERNEL, - 0, SZ_4K, (IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV)); + md = reserve_gmu_kernel_block(gmu, 0, SZ_4K, GMU_NONCACHED_KERNEL); if (IS_ERR(md)) return PTR_ERR(md); @@ -1443,38 +1356,30 @@ static int a6xx_gmu_cache_finalize(struct adreno_device *adreno_dev, return 0; } -static enum gmu_mem_type a6xx_gmu_get_blk_memtype(struct a6xx_gmu_device *gmu, - struct gmu_block_header *blk) +static int a6xx_gmu_process_prealloc(struct a6xx_gmu_device *gmu, + struct gmu_block_header *blk) { - int i; - - for (i = 0; i < GMU_MEM_TYPE_MAX; i++) { - if (blk->addr >= gmu->vma[i].start && - blk->addr + blk->value <= - gmu->vma[i].start + gmu->vma[i].size) - return (enum gmu_mem_type)i; - } - - return GMU_MEM_TYPE_MAX; -} - -static int a6xx_gmu_prealloc_req(struct a6xx_gmu_device *gmu, - struct gmu_block_header *blk) -{ - enum gmu_mem_type type; struct gmu_memdesc *md; - /* Check to see if this memdesc is already around */ - md = a6xx_gmu_get_memdesc(gmu, blk->addr, blk->value); - if (md) + int id = find_vma_block(gmu, blk->addr, blk->value); + + if (id < 0) { + dev_err(&gmu->pdev->dev, + "Invalid prealloc block addr: 0x%x value:%d\n", + blk->addr, blk->value); + return id; + } + + /* Nothing to do for TCM blocks or user uncached */ + if (id == GMU_ITCM || id == GMU_DTCM || id == GMU_NONCACHED_USER) return 0; - type = a6xx_gmu_get_blk_memtype(gmu, blk); - if (type >= GMU_MEM_TYPE_MAX) - return -EINVAL; + /* Check if the block is already allocated */ + md = find_gmu_memdesc(gmu, blk->addr, blk->value); + if (md != NULL) + return 0; - md = a6xx_gmu_kmem_allocate(gmu, type, blk->addr, blk->value, - (IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV)); + md = reserve_gmu_kernel_block(gmu, blk->addr, blk->value, id); if (IS_ERR(md)) return PTR_ERR(md); @@ -1483,14 +1388,9 @@ static int a6xx_gmu_prealloc_req(struct a6xx_gmu_device *gmu, return 0; } -/* - * a6xx_gmu_load_firmware() - Load the ucode into the GPMU RAM & PDC/RSC - * @device: Pointer to KGSL device - */ -static int a6xx_gmu_load_firmware(struct kgsl_device *device) +static int a6xx_gmu_parse_fw(struct adreno_device *adreno_dev) { - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); const struct adreno_a6xx_core *a6xx_core = to_a6xx_core(adreno_dev); struct gmu_block_header *blk; int ret, offset = 0; @@ -1531,61 +1431,54 @@ static int a6xx_gmu_load_firmware(struct kgsl_device *device) if (blk->type == GMU_BLK_TYPE_PREALLOC_REQ || blk->type == GMU_BLK_TYPE_PREALLOC_PERSIST_REQ) - ret = a6xx_gmu_prealloc_req(gmu, blk); + ret = a6xx_gmu_process_prealloc(gmu, blk); if (ret) return ret; } - /* Request any other cache ranges that might be required */ - return a6xx_gmu_cache_finalize(adreno_dev, gmu); + return 0; } -static int a6xx_gmu_memory_probe(struct adreno_device *adreno_dev, - struct a6xx_gmu_device *gmu) +static int a6xx_gmu_memory_init(struct adreno_device *adreno_dev) { - /* Allocates & maps memory for HFI */ - if (IS_ERR_OR_NULL(gmu->hfi_mem)) - gmu->hfi_mem = a6xx_gmu_kmem_allocate(gmu, - GMU_NONCACHED_KERNEL, 0, - HFIMEM_SIZE, (IOMMU_READ | IOMMU_WRITE)); - if (IS_ERR(gmu->hfi_mem)) - return PTR_ERR(gmu->hfi_mem); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); /* Allocates & maps GMU crash dump memory */ if (adreno_is_a630(adreno_dev) || adreno_is_a615_family(adreno_dev)) { if (IS_ERR_OR_NULL(gmu->dump_mem)) - gmu->dump_mem = a6xx_gmu_kmem_allocate(gmu, - GMU_NONCACHED_KERNEL, 0, SZ_16K, - (IOMMU_READ | IOMMU_WRITE)); + gmu->dump_mem = reserve_gmu_kernel_block(gmu, 0, SZ_16K, + GMU_NONCACHED_KERNEL); if (IS_ERR(gmu->dump_mem)) return PTR_ERR(gmu->dump_mem); } /* GMU master log */ if (IS_ERR_OR_NULL(gmu->gmu_log)) - gmu->gmu_log = a6xx_gmu_kmem_allocate(gmu, - GMU_NONCACHED_KERNEL, 0, - SZ_4K, (IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV)); + gmu->gmu_log = reserve_gmu_kernel_block(gmu, 0, SZ_4K, + GMU_NONCACHED_KERNEL); + return PTR_ERR_OR_ZERO(gmu->gmu_log); } -static int a6xx_gmu_init(struct kgsl_device *device) +static int a6xx_gmu_init(struct adreno_device *adreno_dev) { - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); int ret; - ret = a6xx_gmu_load_firmware(device); + ret = a6xx_gmu_parse_fw(adreno_dev); if (ret) return ret; - ret = a6xx_gmu_memory_probe(ADRENO_DEVICE(device), gmu); + /* Request any other cache ranges that might be required */ + ret = a6xx_gmu_cache_finalize(adreno_dev); if (ret) return ret; - a6xx_hfi_init(gmu); + ret = a6xx_gmu_memory_init(adreno_dev); + if (ret) + return ret; - return 0; + return a6xx_hfi_init(adreno_dev); } #define A6XX_VBIF_XIN_HALT_CTRL1_ACKS (BIT(0) | BIT(1) | BIT(2) | BIT(3)) @@ -1624,11 +1517,11 @@ static void do_gbif_halt(struct kgsl_device *device, u32 reg, u32 ack_reg, dev_err(device->dev, "%s GBIF halt timed out\n", client); } -static int a6xx_gmu_pwrctrl_suspend(struct kgsl_device *device) +static void a6xx_gmu_pwrctrl_suspend(struct adreno_device *adreno_dev) { int ret = 0; - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); /* If SPTP_RAC is on, turn off SPTP_RAC HS */ a6xx_gmu_sptprac_disable(adreno_dev); @@ -1636,7 +1529,7 @@ static int a6xx_gmu_pwrctrl_suspend(struct kgsl_device *device) /* Disconnect GPU from BUS is not needed if CX GDSC goes off later */ /* Check no outstanding RPMh voting */ - a6xx_complete_rpmh_votes(device); + a6xx_complete_rpmh_votes(adreno_dev); /* Clear the WRITEDROPPED fields and set fence to allow mode */ gmu_core_regwrite(device, A6XX_GMU_AHB_FENCE_STATUS_CLR, 0x7); @@ -1648,19 +1541,16 @@ static int a6xx_gmu_pwrctrl_suspend(struct kgsl_device *device) gmu_core_regwrite(device, A6XX_GMU_CM3_SYSRESET, 1); if (adreno_has_gbif(adreno_dev)) { - struct adreno_gpudev *gpudev = - ADRENO_GPU_DEVICE(adreno_dev); - /* Halt GX traffic */ if (a6xx_gmu_gx_is_on(device)) do_gbif_halt(device, A6XX_RBBM_GBIF_HALT, A6XX_RBBM_GBIF_HALT_ACK, - gpudev->gbif_gx_halt_mask, + A6XX_GBIF_GX_HALT_MASK, "GX"); /* Halt CX traffic */ do_gbif_halt(device, A6XX_GBIF_HALT, A6XX_GBIF_HALT_ACK, - gpudev->gbif_arb_halt_mask, "CX"); + A6XX_GBIF_ARB_HALT_MASK, "CX"); } if (a6xx_gmu_gx_is_on(device)) @@ -1696,21 +1586,20 @@ static int a6xx_gmu_pwrctrl_suspend(struct kgsl_device *device) "gx is stuck on\n"); } } - - return ret; } /* * a6xx_gmu_notify_slumber() - initiate request to GMU to prepare to slumber * @device: Pointer to KGSL device */ -static int a6xx_gmu_notify_slumber(struct kgsl_device *device) +static int a6xx_gmu_notify_slumber(struct adreno_device *adreno_dev) { - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct kgsl_pwrctrl *pwr = &device->pwrctrl; - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); int bus_level = pwr->pwrlevels[pwr->default_pwrlevel].bus_freq; - int perf_idx = gmu->num_gpupwrlevels - pwr->default_pwrlevel - 1; + int perf_idx = gmu->hfi.dcvs_table.gpu_level_num - + pwr->default_pwrlevel - 1; int ret, state; /* Disable the power counter so that the GMU is not busy */ @@ -1726,7 +1615,8 @@ static int a6xx_gmu_notify_slumber(struct kgsl_device *device) .bw = bus_level, }; - ret = a6xx_hfi_send_req(gmu, H2F_MSG_PREPARE_SLUMBER, &req); + ret = a6xx_hfi_send_req(adreno_dev, + H2F_MSG_PREPARE_SLUMBER, &req); goto out; } @@ -1745,7 +1635,7 @@ static int a6xx_gmu_notify_slumber(struct kgsl_device *device) dev_err(&gmu->pdev->dev, "Failed to prepare for slumber: 0x%x\n", state); - ret = -EINVAL; + ret = -ETIMEDOUT; } } @@ -1755,65 +1645,15 @@ out: return ret; } -/* - * a6xx_gmu_rpmh_gpu_pwrctrl() - GPU power control via RPMh/GMU interface - * @adreno_dev: Pointer to adreno device - * @mode: requested power mode - * @arg1: first argument for mode control - * @arg2: second argument for mode control - */ -static int a6xx_gmu_rpmh_gpu_pwrctrl(struct kgsl_device *device, - unsigned int mode, unsigned int arg1, unsigned int arg2) +static void a6xx_gmu_suspend(struct adreno_device *adreno_dev) { - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); - int ret; + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); - switch (mode) { - case GMU_FW_START: - ret = a6xx_gmu_fw_start(device); - break; - case GMU_SUSPEND: - ret = a6xx_gmu_pwrctrl_suspend(device); - break; - case GMU_FW_STOP: - if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) - a6xx_gmu_oob_clear(device, oob_boot_slumber); - ret = a6xx_rpmh_power_off_gpu(device); - break; - case GMU_DCVS_NOHFI: - ret = a6xx_gmu_dcvs_nohfi(device, arg1, arg2); - break; - case GMU_NOTIFY_SLUMBER: - ret = a6xx_gmu_notify_slumber(device); - break; - default: - dev_err(&gmu->pdev->dev, - "unsupported GMU power ctrl mode:%d\n", mode); - ret = -EINVAL; - break; - } + a6xx_gmu_irq_disable(adreno_dev); - return ret; -} - -static int a6xx_gmu_suspend(struct kgsl_device *device) -{ - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); - - if (!test_bit(GMU_CLK_ON, &device->gmu_core.flags)) - return 0; - - /* Pending message in all queues are abandoned */ - a6xx_gmu_irq_disable(device); - a6xx_hfi_stop(gmu); - - if (a6xx_gmu_rpmh_gpu_pwrctrl(device, GMU_SUSPEND, 0, 0)) - return -EINVAL; + a6xx_gmu_pwrctrl_suspend(adreno_dev); clk_bulk_disable_unprepare(gmu->num_clks, gmu->clks); - clear_bit(GMU_CLK_ON, &device->gmu_core.flags); if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_CX_GDSC)) regulator_set_mode(gmu->cx_gdsc, REGULATOR_MODE_IDLE); @@ -1826,40 +1666,33 @@ static int a6xx_gmu_suspend(struct kgsl_device *device) dev_err(&gmu->pdev->dev, "Suspended GMU\n"); - clear_bit(GMU_FAULT, &device->gmu_core.flags); - - return 0; + gmu->fault = false; } -static void a6xx_gmu_snapshot(struct kgsl_device *device); - static int a6xx_gmu_dcvs_set(struct kgsl_device *device, int gpu_pwrlevel, int bus_level) { - int ret = 0; - struct kgsl_pwrctrl *pwr = &device->pwrctrl; - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct kgsl_pwrctrl *pwr = &device->pwrctrl; + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + struct hfi_dcvstable_cmd *table = &gmu->hfi.dcvs_table; struct hfi_gx_bw_perf_vote_cmd req = { .ack_type = DCVS_ACK_BLOCK, .freq = INVALID_DCVS_IDX, .bw = INVALID_DCVS_IDX, }; + int ret = 0; - /* If GMU has not been started, save it */ - if (!test_bit(GMU_HFI_ON, &device->gmu_core.flags)) { - /* store clock change request */ - set_bit(GMU_DCVS_REPLAY, &device->gmu_core.flags); + if (!test_bit(GMU_PRIV_HFI_STARTED, &gmu->flags)) return 0; - } /* Do not set to XO and lower GPU clock vote from GMU */ if ((gpu_pwrlevel != INVALID_DCVS_IDX) && - (gpu_pwrlevel >= gmu->num_gpupwrlevels - 1)) + (gpu_pwrlevel >= table->gpu_level_num - 1)) return -EINVAL; - if (gpu_pwrlevel < gmu->num_gpupwrlevels - 1) - req.freq = gmu->num_gpupwrlevels - gpu_pwrlevel - 1; + if (gpu_pwrlevel < table->gpu_level_num - 1) + req.freq = table->gpu_level_num - gpu_pwrlevel - 1; if (bus_level < pwr->ddr_table_count && bus_level > 0) req.bw = bus_level; @@ -1867,15 +1700,14 @@ static int a6xx_gmu_dcvs_set(struct kgsl_device *device, /* GMU will vote for slumber levels through the sleep sequence */ if ((req.freq == INVALID_DCVS_IDX) && (req.bw == INVALID_DCVS_IDX)) { - clear_bit(GMU_DCVS_REPLAY, &device->gmu_core.flags); return 0; } if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) - ret = a6xx_gmu_rpmh_gpu_pwrctrl(device, - GMU_DCVS_NOHFI, req.freq, req.bw); - else if (test_bit(GMU_HFI_ON, &device->gmu_core.flags)) - ret = a6xx_hfi_send_req(gmu, H2F_MSG_GX_BW_PERF_VOTE, &req); + ret = a6xx_gmu_dcvs_nohfi(device, req.freq, req.bw); + else + ret = a6xx_hfi_send_req(adreno_dev, H2F_MSG_GX_BW_PERF_VOTE, + &req); if (ret) { dev_err_ratelimited(&gmu->pdev->dev, @@ -1883,24 +1715,16 @@ static int a6xx_gmu_dcvs_set(struct kgsl_device *device, req.freq, req.bw); /* - * We can be here in two situations. First, we send a dcvs - * hfi so gmu knows at what level it must bring up the gpu. - * If that fails, it is already being handled as part of - * gmu boot failures. The other reason why we are here is - * because we are trying to scale an active gpu. For this, - * we need to do inline snapshot and dispatcher based - * recovery. + * If this was a dcvs request along side an active gpu, request + * dispatcher based reset and recovery. */ - if (test_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv)) { - a6xx_gmu_snapshot(device); + if (test_bit(GMU_PRIV_GPU_STARTED, &gmu->flags)) { adreno_set_gpu_fault(adreno_dev, ADRENO_GMU_FAULT | ADRENO_GMU_FAULT_SKIP_SNAPSHOT); adreno_dispatcher_schedule(device); } } - /* indicate actual clock change */ - clear_bit(GMU_DCVS_REPLAY, &device->gmu_core.flags); return ret; } @@ -1908,7 +1732,7 @@ static int a6xx_gmu_ifpc_store(struct kgsl_device *device, unsigned int val) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); unsigned int requested_idle_level; if (!ADRENO_FEATURE(adreno_dev, ADRENO_IFPC)) @@ -1934,234 +1758,39 @@ static int a6xx_gmu_ifpc_store(struct kgsl_device *device, static unsigned int a6xx_gmu_ifpc_show(struct kgsl_device *device) { - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(ADRENO_DEVICE(device)); return gmu->idle_level >= GPU_HW_IFPC; } -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) +/* Send an NMI to the GMU */ +static void a6xx_gmu_send_nmi(struct adreno_device *adreno_dev) { - 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; + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + u32 val; - if (priv == NULL) - return 0; + /* Mask so there's no interrupt caused by NMI */ + gmu_core_regwrite(device, A6XX_GMU_GMU2HOST_INTR_MASK, 0xFFFFFFFF); - 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; - } + /* Make sure the interrupt is masked before causing it */ + wmb(); + if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) + gmu_core_regwrite(device, + A6XX_GMU_NMI_CONTROL_STATUS, 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; + /* This will cause the GMU to save it's internal state to ddr */ + gmu_core_regread(device, A6XX_GMU_CM3_CFG, &val); + val |= BIT(9); + gmu_core_regwrite(device, A6XX_GMU_CM3_CFG, val); - /* Just copy the ringbuffer, there are no active IBs */ - memcpy(data, desc->memdesc->hostptr, desc->memdesc->size); - - return desc->memdesc->size + sizeof(*mem_hdr); -} - -struct a6xx_tcm_data { - enum gmu_mem_type type; - u32 start; - u32 last; -}; - -static size_t a6xx_snapshot_gmu_tcm(struct kgsl_device *device, - u8 *buf, size_t remain, void *priv) -{ - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); - struct kgsl_snapshot_gmu_mem *mem_hdr = - (struct kgsl_snapshot_gmu_mem *)buf; - unsigned int *data = (unsigned int *)(buf + sizeof(*mem_hdr)); - unsigned int i, bytes; - struct a6xx_tcm_data *tcm = priv; - - bytes = (tcm->last - tcm->start + 1) << 2; - - if (remain < bytes + sizeof(*mem_hdr)) { - SNAPSHOT_ERR_NOMEM(device, "GMU Memory"); - return 0; - } - - mem_hdr->type = SNAPSHOT_GMU_MEM_BIN_BLOCK; - mem_hdr->hostaddr = 0; - mem_hdr->gmuaddr = gmu->vma[tcm->type].start; - mem_hdr->gpuaddr = 0; - - for (i = tcm->start; i <= tcm->last; i++) - kgsl_regread(device, i, data++); - - return bytes + sizeof(*mem_hdr); -} - -static void a6xx_gmu_snapshot_memories(struct kgsl_device *device, - struct kgsl_snapshot *snapshot) -{ - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); - struct gmu_mem_type_desc desc; - struct gmu_memdesc *md; - int i; - - for (i = 0; i < ARRAY_SIZE(gmu->kmem_entries); i++) { - if (!test_bit(i, &gmu->kmem_bitmap)) - continue; - - md = &gmu->kmem_entries[i]; - if (!md->size) - continue; - - desc.memdesc = md; - if (md == gmu->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; - - if (md->mem_type == GMU_ITCM) { - struct a6xx_tcm_data tcm = { - .type = md->mem_type, - .start = a6xx_gmu_tcm_registers[0], - .last = a6xx_gmu_tcm_registers[1], - }; - - kgsl_snapshot_add_section(device, - KGSL_SNAPSHOT_SECTION_GMU_MEMORY, - snapshot, a6xx_snapshot_gmu_tcm, &tcm); - } else if (md->mem_type == GMU_DTCM) { - struct a6xx_tcm_data tcm = { - .type = md->mem_type, - .start = a6xx_gmu_tcm_registers[2], - .last = a6xx_gmu_tcm_registers[3], - }; - - kgsl_snapshot_add_section(device, - KGSL_SNAPSHOT_SECTION_GMU_MEMORY, - snapshot, a6xx_snapshot_gmu_tcm, &tcm); - } else { - 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 kgsl_snapshot *snapshot) -{ - int i; - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); - 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]); -} - -/* - * 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 - */ -static void a6xx_gmu_device_snapshot(struct kgsl_device *device, - struct kgsl_snapshot *snapshot) -{ - unsigned int val; - - a6xx_gmu_snapshot_versions(device, snapshot); - - a6xx_gmu_snapshot_memories(device, snapshot); - - /* Snapshot tcms as registers for legacy targets */ - if (adreno_is_a630(ADRENO_DEVICE(device)) || - adreno_is_a615_family(ADRENO_DEVICE(device))) - 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_DEVICE(device))) - adreno_snapshot_registers(device, snapshot, a660_gmu_registers, - ARRAY_SIZE(a660_gmu_registers) / 2); - - if (a6xx_gmu_gx_is_on(device)) { - /* 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); - - dev_err(device->dev, "set FENCE to ALLOW mode:%x\n", val); - adreno_snapshot_registers(device, snapshot, - a6xx_gmu_gx_registers, - ARRAY_SIZE(a6xx_gmu_gx_registers) / 2); - } + /* Make sure the NMI is invoked before we proceed*/ + wmb(); } static void a6xx_gmu_cooperative_reset(struct kgsl_device *device) { - - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); unsigned int result; gmu_core_regwrite(device, A6XX_GMU_CX_GMU_WDOG_CTRL, 0); @@ -2182,7 +1811,7 @@ static void a6xx_gmu_cooperative_reset(struct kgsl_device *device) * If we dont get a snapshot ready from GMU, trigger NMI * and if we still timeout then we just continue with reset. */ - adreno_gmu_send_nmi(ADRENO_DEVICE(device)); + a6xx_gmu_send_nmi(adreno_dev); udelay(200); gmu_core_regread(device, A6XX_GMU_CM3_FW_INIT_RESULT, &result); if ((result & 0x800) != 0x800) @@ -2194,7 +1823,10 @@ static int a6xx_gmu_wait_for_active_transition( struct kgsl_device *device) { unsigned int reg, num_retries; - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(ADRENO_DEVICE(device)); + + if (!gmu_core_isenabled(device)) + return 0; gmu_core_regread(device, A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE, ®); @@ -2232,8 +1864,8 @@ static u64 a6xx_gmu_read_alwayson(struct kgsl_device *device) static irqreturn_t a6xx_gmu_irq_handler(int irq, void *data) { struct kgsl_device *device = data; - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); unsigned int mask, status = 0; gmu_core_regread(device, A6XX_GMU_AO_HOST_INTERRUPT_STATUS, &status); @@ -2256,7 +1888,7 @@ static irqreturn_t a6xx_gmu_irq_handler(int irq, void *data) * captured by gmu before it sent the CM3 fault interrupt. */ if (!atomic_read(&gmu->cm3_fault)) - adreno_gmu_send_nmi(adreno_dev); + a6xx_gmu_send_nmi(adreno_dev); /* * There is sufficient delay for the GMU to have finished @@ -2291,10 +1923,10 @@ static irqreturn_t a6xx_gmu_irq_handler(int irq, void *data) static void a6xx_gmu_snapshot(struct kgsl_device *device) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); /* Abstain from sending another nmi or over-writing snapshot */ - if (test_and_set_bit(GMU_FAULT, &device->gmu_core.flags)) + if (gmu->fault) return; /* make sure we're reading the latest cm3_fault */ @@ -2306,7 +1938,7 @@ static void a6xx_gmu_snapshot(struct kgsl_device *device) * it sent the CM3 fault interrupt. */ if (!atomic_read(&gmu->cm3_fault)) { - adreno_gmu_send_nmi(adreno_dev); + a6xx_gmu_send_nmi(adreno_dev); /* Wait for the NMI to be handled */ udelay(100); @@ -2319,61 +1951,8 @@ static void a6xx_gmu_snapshot(struct kgsl_device *device) gmu_core_regwrite(device, A6XX_GMU_GMU2HOST_INTR_MASK, HFI_IRQ_MASK); - gmu->fault_count++; -} + gmu->fault = true; -/* Caller shall ensure GPU is ready for SLUMBER */ -static void a6xx_gmu_stop(struct kgsl_device *device) -{ - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); - struct kgsl_pwrctrl *pwr = &device->pwrctrl; - int ret = 0; - - if (!test_bit(GMU_CLK_ON, &device->gmu_core.flags)) - return; - - /* Force suspend if gmu is already in fault */ - if (test_bit(GMU_FAULT, &device->gmu_core.flags)) { - a6xx_gmu_suspend(device); - return; - } - - /* Wait for the lowest idle level we requested */ - if (a6xx_gmu_wait_for_lowest_idle(device)) - goto error; - - ret = a6xx_gmu_rpmh_gpu_pwrctrl(device, - GMU_NOTIFY_SLUMBER, 0, 0); - if (ret) - goto error; - - if (a6xx_gmu_wait_for_idle(device)) - goto error; - - /* Pending message in all queues are abandoned */ - a6xx_gmu_irq_disable(device); - a6xx_hfi_stop(gmu); - - a6xx_gmu_rpmh_gpu_pwrctrl(device, GMU_FW_STOP, 0, 0); - - clk_bulk_disable_unprepare(gmu->num_clks, gmu->clks); - clear_bit(GMU_CLK_ON, &device->gmu_core.flags); - - /* Pool to make sure that the CX is off */ - if (!kgsl_regulator_disable_wait(gmu->cx_gdsc, 5000)) - dev_err(&gmu->pdev->dev, "GMU CX gdsc off timeout\n"); - - icc_set_bw(pwr->icc_path, 0, 0); - return; - -error: - dev_err(&gmu->pdev->dev, "Failed to stop GMU\n"); - a6xx_gmu_snapshot(device); - /* - * We failed to stop the gmu successfully. Force a suspend - * to set things up for a fresh start. - */ - a6xx_gmu_suspend(device); } static int a6xx_gmu_aop_send_acd_state(struct mbox_chan *channel, bool flag) @@ -2394,9 +1973,9 @@ static int a6xx_gmu_aop_send_acd_state(struct mbox_chan *channel, bool flag) return mbox_send_message(channel, &msg); } -static int a6xx_gmu_enable_gdsc(struct kgsl_device *device) +static int a6xx_gmu_enable_gdsc(struct adreno_device *adreno_dev) { - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); int ret; ret = regulator_enable(gmu->cx_gdsc); @@ -2419,9 +1998,9 @@ static int a6xx_gmu_clk_set_rate(struct a6xx_gmu_device *gmu, const char *id, return clk_set_rate(clk, rate); } -static int a6xx_gmu_enable_clks(struct kgsl_device *device) +static int a6xx_gmu_enable_clks(struct adreno_device *adreno_dev) { - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); int ret; ret = a6xx_gmu_clk_set_rate(gmu, "gmu_clk", GMU_FREQUENCY); @@ -2442,129 +2021,174 @@ static int a6xx_gmu_enable_clks(struct kgsl_device *device) return ret; } - set_bit(GMU_CLK_ON, &device->gmu_core.flags); return 0; } - - -static int a6xx_gmu_start_from_init(struct kgsl_device *device) +static int a6xx_gmu_first_boot(struct adreno_device *adreno_dev) { + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct kgsl_pwrctrl *pwr = &device->pwrctrl; - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); int level, ret; - if (device->state == KGSL_STATE_INIT) { - int ret = a6xx_gmu_aop_send_acd_state(gmu->mailbox.channel, - adreno_dev->acd_enabled); - if (ret) - dev_err(&gmu->pdev->dev, - "AOP mbox send message failed: %d\n", ret); + if (adreno_is_a650_family(adreno_dev) && !adreno_dev->rscc_virt) { + dev_err(&gmu->pdev->dev, "RSCC registers not mapped\n"); + return -EINVAL; } - WARN_ON(test_bit(GMU_CLK_ON, &device->gmu_core.flags)); + ret = a6xx_gmu_aop_send_acd_state(gmu->mailbox.channel, + adreno_dev->acd_enabled); + if (ret) { + dev_err(&gmu->pdev->dev, + "AOP mbox send message failed: %d\n", ret); + return ret; + } - a6xx_gmu_enable_gdsc(device); - a6xx_gmu_enable_clks(device); - a6xx_gmu_irq_enable(device); + ret = a6xx_gmu_enable_gdsc(adreno_dev); + if (ret) + return ret; + + ret = a6xx_gmu_enable_clks(adreno_dev); + if (ret) + goto gdsc_off; + + ret = a6xx_gmu_load_fw(adreno_dev); + if (ret) + goto clks_gdsc_off; + + ret = a6xx_gmu_itcm_shadow(adreno_dev); + if (ret) + goto clks_gdsc_off; + + a6xx_gmu_register_config(adreno_dev); + + a6xx_gmu_version_info(adreno_dev); + + a6xx_gmu_irq_enable(adreno_dev); /* Vote for minimal DDR BW for GMU to init */ level = pwr->pwrlevels[pwr->default_pwrlevel].bus_min; icc_set_bw(pwr->icc_path, 0, kBps_to_icc(pwr->ddr_table[level])); - ret = a6xx_gmu_rpmh_gpu_pwrctrl(device, GMU_FW_START, - GMU_COLD_BOOT, 0); + ret = a6xx_gmu_device_start(adreno_dev); if (ret) - return ret; + goto err; - ret = a6xx_hfi_start(device, gmu, GMU_COLD_BOOT); + if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) { + ret = a6xx_gmu_gfx_rail_on(adreno_dev); + if (ret) { + a6xx_gmu_oob_clear(device, oob_boot_slumber); + goto err; + } + } + + if (gmu->idle_level < GPU_HW_SPTP_PC) { + ret = a6xx_gmu_sptprac_enable(adreno_dev); + if (ret) + goto err; + } + + ret = a6xx_gmu_hfi_start(adreno_dev); if (ret) - return ret; + goto err; - /* Request default DCVS level */ - return kgsl_pwrctrl_set_default_gpu_pwrlevel(device); + ret = a6xx_hfi_start(adreno_dev); + if (ret) + goto err; + + icc_set_bw(pwr->icc_path, 0, 0); + + return 0; + +err: + a6xx_gmu_suspend(adreno_dev); + + return ret; + +clks_gdsc_off: + clk_bulk_disable_unprepare(gmu->num_clks, gmu->clks); + +gdsc_off: + /* Pool to make sure that the CX is off */ + if (!kgsl_regulator_disable_wait(gmu->cx_gdsc, 5000)) + dev_err(&gmu->pdev->dev, "GMU CX gdsc off timeout\n"); + + return ret; } -static int a6xx_gmu_start_from_slumber(struct kgsl_device *device) +static int a6xx_gmu_boot(struct adreno_device *adreno_dev) { - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); - int ret; - - WARN_ON(test_bit(GMU_CLK_ON, &device->gmu_core.flags)); - - a6xx_gmu_enable_gdsc(device); - a6xx_gmu_enable_clks(device); - a6xx_gmu_irq_enable(device); - - ret = a6xx_gmu_rpmh_gpu_pwrctrl(device, GMU_FW_START, - GMU_COLD_BOOT, 0); - if (ret) - return ret; - - ret = a6xx_hfi_start(device, gmu, GMU_COLD_BOOT); - if (ret) - return ret; - - return kgsl_pwrctrl_set_default_gpu_pwrlevel(device); -} - -static int a6xx_gmu_start_from_reset(struct kgsl_device *device) -{ - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); - int ret; - - a6xx_gmu_suspend(device); - - a6xx_gmu_enable_gdsc(device); - a6xx_gmu_enable_clks(device); - a6xx_gmu_irq_enable(device); - - ret = a6xx_gmu_rpmh_gpu_pwrctrl(device, GMU_FW_START, GMU_COLD_BOOT, 0); - if (ret) - return ret; - - ret = a6xx_hfi_start(device, gmu, GMU_COLD_BOOT); - if (ret) - return ret; - - /* Send DCVS level prior to reset*/ - return kgsl_pwrctrl_set_default_gpu_pwrlevel(device); -} - -/* To be called to power on both GPU and GMU */ -static int a6xx_gmu_start(struct kgsl_device *device) -{ - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); int ret = 0; - switch (device->state) { - case KGSL_STATE_INIT: - case KGSL_STATE_SUSPEND: - ret = a6xx_gmu_start_from_init(device); - break; + ret = a6xx_gmu_enable_gdsc(adreno_dev); + if (ret) + return ret; - case KGSL_STATE_SLUMBER: - ret = a6xx_gmu_start_from_slumber(device); - break; - case KGSL_STATE_RESET: - ret = a6xx_gmu_start_from_reset(device); - break; - } + ret = a6xx_gmu_enable_clks(adreno_dev); + if (ret) + goto gdsc_off; - if (ret) { - if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) + ret = a6xx_rscc_wakeup_sequence(adreno_dev); + if (ret) + goto clks_gdsc_off; + + ret = a6xx_gmu_load_fw(adreno_dev); + if (ret) + goto clks_gdsc_off; + + a6xx_gmu_register_config(adreno_dev); + + a6xx_gmu_irq_enable(adreno_dev); + + ret = a6xx_gmu_device_start(adreno_dev); + if (ret) + goto err; + + if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) { + ret = a6xx_gmu_gfx_rail_on(adreno_dev); + if (ret) { a6xx_gmu_oob_clear(device, oob_boot_slumber); - - a6xx_gmu_snapshot(device); + goto err; + } } + if (gmu->idle_level < GPU_HW_SPTP_PC) { + ret = a6xx_gmu_sptprac_enable(adreno_dev); + if (ret) + goto err; + } + + ret = a6xx_gmu_hfi_start(adreno_dev); + if (ret) + goto err; + + ret = a6xx_hfi_start(adreno_dev); + if (ret) + goto err; + + return 0; + +err: + a6xx_gmu_suspend(adreno_dev); + + return ret; + +clks_gdsc_off: + clk_bulk_disable_unprepare(gmu->num_clks, gmu->clks); + +gdsc_off: + /* Pool to make sure that the CX is off */ + if (!kgsl_regulator_disable_wait(gmu->cx_gdsc, 5000)) + dev_err(&gmu->pdev->dev, "GMU CX gdsc off timeout\n"); + return ret; } static void set_acd(struct adreno_device *adreno_dev, void *priv) { - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(KGSL_DEVICE(adreno_dev)); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); int ret; adreno_dev->acd_enabled = *((bool *)priv); @@ -2579,7 +2203,7 @@ static void set_acd(struct adreno_device *adreno_dev, void *priv) static int a6xx_gmu_acd_set(struct kgsl_device *device, bool val) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); if (IS_ERR_OR_NULL(gmu->mailbox.channel)) return -EINVAL; @@ -2593,16 +2217,9 @@ static int a6xx_gmu_acd_set(struct kgsl_device *device, bool val) } static struct gmu_dev_ops a6xx_gmudev = { - .load_firmware = a6xx_gmu_load_firmware, .oob_set = a6xx_gmu_oob_set, .oob_clear = a6xx_gmu_oob_clear, - .irq_enable = a6xx_gmu_irq_enable, - .irq_disable = a6xx_gmu_irq_disable, - .hfi_start_msg = a6xx_gmu_hfi_start_msg, - .rpmh_gpu_pwrctrl = a6xx_gmu_rpmh_gpu_pwrctrl, .gx_is_on = a6xx_gmu_gx_is_on, - .wait_for_lowest_idle = a6xx_gmu_wait_for_lowest_idle, - .wait_for_gmu_idle = a6xx_gmu_wait_for_idle, .ifpc_store = a6xx_gmu_ifpc_store, .ifpc_show = a6xx_gmu_ifpc_show, .snapshot = a6xx_gmu_device_snapshot, @@ -2615,12 +2232,8 @@ static struct gmu_dev_ops a6xx_gmudev = { }; static struct gmu_core_ops a6xx_gmu_ops = { - .init = a6xx_gmu_init, - .start = a6xx_gmu_start, - .stop = a6xx_gmu_stop, .dcvs_set = a6xx_gmu_dcvs_set, .snapshot = a6xx_gmu_snapshot, - .suspend = a6xx_gmu_suspend, .acd_set = a6xx_gmu_acd_set, }; @@ -2648,38 +2261,40 @@ static int a6xx_gmu_bus_set(struct kgsl_device *device, int buslevel, return ret; } -static void a6xx_gmu_iommu_cb_close(struct gmu_iommu_context *ctx); +static void a6xx_gmu_iommu_cb_close(struct gmu_iommu_context *ctx) +{ + if (!ctx->domain) + return; -static void a6xx_gmu_memory_close(struct a6xx_gmu_device *gmu) + iommu_detach_device(ctx->domain, &ctx->pdev->dev); + iommu_domain_free(ctx->domain); + + platform_device_put(ctx->pdev); + ctx->domain = NULL; +} + +static void a6xx_free_gmu_globals(struct a6xx_gmu_device *gmu) { int i; - struct gmu_memdesc *md; - struct gmu_iommu_context *ctx; - gmu->hfi_mem = NULL; - gmu->dump_mem = NULL; - gmu->gmu_log = NULL; - gmu->preallocations = false; + for (i = 0; i < gmu->global_entries; i++) { + struct gmu_memdesc *md = &gmu->gmu_globals[i]; - /* Unmap and free all memories in GMU kernel memory pool */ - for (i = 0; i < GMU_KERNEL_ENTRIES; i++) { - if (!test_bit(i, &gmu->kmem_bitmap)) + if (!md->gmuaddr) continue; - md = &gmu->kmem_entries[i]; - ctx = &a6xx_gmu_ctx[md->ctx_idx]; + iommu_unmap(get_gmu_domain(gmu, md), md->gmuaddr, md->size); - if (md->gmuaddr && md->mem_type != GMU_ITCM && - md->mem_type != GMU_DTCM) - iommu_unmap(ctx->domain, md->gmuaddr, md->size); + dma_free_attrs(&gmu->pdev->dev, (size_t) md->size, + (void *)md->hostptr, md->physaddr, 0); - a6xx_gmu_mem_free(gmu, md); - - clear_bit(i, &gmu->kmem_bitmap); + memset(md, 0, sizeof(*md)); } a6xx_gmu_iommu_cb_close(&a6xx_gmu_ctx[GMU_CONTEXT_KERNEL]); a6xx_gmu_iommu_cb_close(&a6xx_gmu_ctx[GMU_CONTEXT_USER]); + + gmu->global_entries = 0; } static int a6xx_gmu_aop_mailbox_init(struct adreno_device *adreno_dev, @@ -2705,15 +2320,15 @@ static void a6xx_gmu_acd_probe(struct kgsl_device *device, { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct kgsl_pwrctrl *pwr = &device->pwrctrl; - struct hfi_acd_table_cmd *cmd = &gmu->hfi.acd_tbl_cmd; + struct hfi_acd_table_cmd *cmd = &gmu->hfi.acd_table; u32 acd_level, cmd_idx, numlvl = pwr->num_pwrlevels; int ret, i; if (!ADRENO_FEATURE(adreno_dev, ADRENO_ACD)) return; - cmd->hdr = 0xFFFFFFFF; - cmd->version = HFI_ACD_INIT_VERSION; + cmd->hdr = CMD_MSG_HDR(H2F_MSG_ACD_TBL, sizeof(*cmd)); + cmd->version = 1; cmd->stride = 1; cmd->enable_by_level = 0; @@ -2736,436 +2351,10 @@ static void a6xx_gmu_acd_probe(struct kgsl_device *device, "AOP mailbox init failed: %d\n", ret); } -struct rpmh_arc_vals { - unsigned int num; - const u16 *val; -}; - -enum rpmh_vote_type { - GPU_ARC_VOTE = 0, - GMU_ARC_VOTE, - INVALID_ARC_VOTE, -}; - -/* - * rpmh_arc_cmds() - query RPMh command database for GX/CX/MX rail - * VLVL tables. The index of table will be used by GMU to vote rail - * voltage. - * - * @gmu: Pointer to GMU device - * @arc: Pointer to RPMh rail controller (ARC) voltage table - * @res_id: Pointer to 8 char array that contains rail name - */ -static int rpmh_arc_cmds(struct a6xx_gmu_device *gmu, - struct rpmh_arc_vals *arc, const char *res_id) +static int a6xx_gmu_reg_probe(struct adreno_device *adreno_dev) { - 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; -} - -/* - * setup_volt_dependency_tbl() - set up GX->MX or CX->MX rail voltage - * dependencies. Second rail voltage shall be equal to or higher than - * primary rail voltage. VLVL table index was used by RPMh for PMIC - * voltage setting. - * @votes: Pointer to a ARC vote descriptor - * @pri_rail: Pointer to primary power rail VLVL table - * @sec_rail: Pointer to second/dependent power rail VLVL table - * @vlvl: Pointer to VLVL table being used by GPU or GMU driver, a subset - * of pri_rail VLVL table - * @num_entries: Valid number of entries in table pointed by "vlvl" parameter - */ -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; -} - -static int rpmh_gmu_arc_votes_init(struct a6xx_gmu_device *gmu, - 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 }; - - return setup_volt_dependency_tbl(gmu->rpmh_votes.cx_votes, pri_rail, - sec_rail, gmu_cx_vlvl, 2); -} - -/* - * rpmh_arc_votes_init() - initialized GX RPMh votes needed for rails - * voltage scaling by GMU. - * @device: Pointer to KGSL device - * @gmu: Pointer to GMU device - * @pri_rail: Pointer to primary power rail VLVL table - * @sec_rail: Pointer to second/dependent power rail VLVL table - * of pri_rail VLVL table - * @type: the type of the primary rail, GPU or GMU - */ -static int rpmh_arc_votes_init(struct kgsl_device *device, - struct a6xx_gmu_device *gmu, struct rpmh_arc_vals *pri_rail, - struct rpmh_arc_vals *sec_rail, unsigned int type) -{ - unsigned int num_freqs; - u16 vlvl_tbl[MAX_GX_LEVELS]; - int i; - - if (type == GMU_ARC_VOTE) - return rpmh_gmu_arc_votes_init(gmu, pri_rail, sec_rail); - - num_freqs = gmu->num_gpupwrlevels; - - if (num_freqs > pri_rail->num || num_freqs > ARRAY_SIZE(vlvl_tbl)) { - dev_err(&gmu->pdev->dev, - "Defined more GPU DCVS levels than RPMh can support\n"); - return -EINVAL; - } - - memset(vlvl_tbl, 0, sizeof(vlvl_tbl)); - for (i = 0; i < num_freqs; i++) - vlvl_tbl[i] = gmu->pwrlevels[i].level; - - return setup_volt_dependency_tbl(gmu->rpmh_votes.gx_votes, pri_rail, - sec_rail, vlvl_tbl, num_freqs); -} - -struct bcm { - const char *name; - u32 buswidth; - u32 channels; - u32 unit; - u16 width; - u8 vcd; - bool fixed; -}; - -/* - * 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 }, -}; - -/* 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); - } -} - -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; -}; - -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; -} - -static void build_bwtable_cmd_cache(struct hfi_bwtable_cmd *cmd, - struct rpmh_bw_votes *ddr, struct rpmh_bw_votes *cnoc) -{ - unsigned int i, j; - - cmd->hdr = 0xFFFFFFFF; - 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 a6xx_gmu_bus_vote_init(struct kgsl_device *device) -{ - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); - struct kgsl_pwrctrl *pwr = &device->pwrctrl; - struct rpmh_bw_votes *ddr, *cnoc = NULL; - u32 *cnoc_table; - u32 count; - - /* Build the DDR votes */ - 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); - - /* Get the CNOC table */ - cnoc_table = kgsl_bus_get_table(device->pdev, "qcom,bus-table-cnoc", - &count); - - /* And build the votes for that, if it exists */ - 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 the HFI command once */ - build_bwtable_cmd_cache(&gmu->hfi.bwtbl_cmd, ddr, cnoc); - - free_rpmh_bw_votes(ddr); - free_rpmh_bw_votes(cnoc); - - return 0; -} - -static int a6xx_gmu_rpmh_init(struct kgsl_device *device, - struct a6xx_gmu_device *gmu) -{ - struct rpmh_arc_vals gfx_arc, cx_arc, mx_arc; - int ret; - - /* Initialize BW tables */ - ret = a6xx_gmu_bus_vote_init(device); - if (ret) - return ret; - - /* Populate GPU and GMU frequency vote table */ - ret = rpmh_arc_cmds(gmu, &gfx_arc, "gfx.lvl"); - if (ret) - return ret; - - ret = rpmh_arc_cmds(gmu, &cx_arc, "cx.lvl"); - if (ret) - return ret; - - ret = rpmh_arc_cmds(gmu, &mx_arc, "mx.lvl"); - if (ret) - return ret; - - ret = rpmh_arc_votes_init(device, gmu, &gfx_arc, &mx_arc, GPU_ARC_VOTE); - if (ret) - return ret; - - return rpmh_arc_votes_init(device, gmu, &cx_arc, &mx_arc, GMU_ARC_VOTE); -} - - -static int a6xx_gmu_reg_probe(struct kgsl_device *device) -{ - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); struct resource *res; res = platform_get_resource_byname(gmu->pdev, IORESOURCE_MEM, @@ -3193,23 +2382,43 @@ static int a6xx_gmu_reg_probe(struct kgsl_device *device) return 0; } -static int a6xx_gmu_tcm_init(struct a6xx_gmu_device *gmu) +static int a6xx_gmu_regulators_probe(struct a6xx_gmu_device *gmu, + struct platform_device *pdev) { - struct gmu_memdesc *md; + gmu->cx_gdsc = devm_regulator_get(&pdev->dev, "vddcx"); + if (IS_ERR(gmu->cx_gdsc)) { + if (PTR_ERR(gmu->cx_gdsc) != -EPROBE_DEFER) + dev_err(&pdev->dev, "Couldn't get the vddcx gdsc\n"); + return PTR_ERR(gmu->cx_gdsc); + } - /* Reserve a memdesc for ITCM. No actually memory allocated */ - md = a6xx_gmu_kmem_allocate(gmu, GMU_ITCM, gmu->vma[GMU_ITCM].start, - gmu->vma[GMU_ITCM].size, 0); - if (IS_ERR(md)) - return PTR_ERR(md); + gmu->gx_gdsc = devm_regulator_get(&pdev->dev, "vdd"); + if (IS_ERR(gmu->gx_gdsc)) { + if (PTR_ERR(gmu->gx_gdsc) != -EPROBE_DEFER) + dev_err(&pdev->dev, "Couldn't get the vdd gdsc\n"); + return PTR_ERR(gmu->gx_gdsc); + } - /* Reserve a memdesc for DTCM. No actually memory allocated */ - md = a6xx_gmu_kmem_allocate(gmu, GMU_DTCM, gmu->vma[GMU_DTCM].start, - gmu->vma[GMU_DTCM].size, 0); - - return PTR_ERR_OR_ZERO(md); + return 0; } +static void a6xx_gmu_remove(struct kgsl_device *device) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + + if (!IS_ERR_OR_NULL(gmu->mailbox.channel)) + mbox_free_channel(gmu->mailbox.channel); + + adreno_dev->acd_enabled = false; + + if (gmu->fw_image) + release_firmware(gmu->fw_image); + + a6xx_free_gmu_globals(gmu); + + vfree(gmu->itcm_shadow); +} static int a6xx_gmu_iommu_fault_handler(struct iommu_domain *domain, struct device *dev, unsigned long addr, int flags, void *token, @@ -3247,11 +2456,12 @@ static int a6xx_gmu_user_fault_handler(struct iommu_domain *domain, return a6xx_gmu_iommu_fault_handler(domain, dev, addr, flags, token, "gmu_user"); } + static int a6xx_gmu_iommu_cb_probe(struct a6xx_gmu_device *gmu, - const char *name, struct gmu_iommu_context *ctx, - struct device_node *parent, iommu_fault_handler_t handler) + struct gmu_iommu_context *ctx, struct device_node *parent, + iommu_fault_handler_t handler) { - struct device_node *node = of_get_child_by_name(parent, name); + struct device_node *node = of_get_child_by_name(parent, ctx->name); struct platform_device *pdev; int ret; @@ -3291,18 +2501,6 @@ static int a6xx_gmu_iommu_cb_probe(struct a6xx_gmu_device *gmu, return ret; } -static void a6xx_gmu_iommu_cb_close(struct gmu_iommu_context *ctx) -{ - if (!ctx->domain) - return; - - iommu_detach_device(ctx->domain, &ctx->pdev->dev); - iommu_domain_free(ctx->domain); - - platform_device_put(ctx->pdev); - ctx->domain = NULL; -} - static int a6xx_gmu_iommu_init(struct a6xx_gmu_device *gmu, struct device_node *node) { @@ -3310,77 +2508,26 @@ static int a6xx_gmu_iommu_init(struct a6xx_gmu_device *gmu, devm_of_platform_populate(&gmu->pdev->dev); - ret = a6xx_gmu_iommu_cb_probe(gmu, "gmu_user", - &a6xx_gmu_ctx[GMU_CONTEXT_USER], node, - a6xx_gmu_user_fault_handler); + ret = a6xx_gmu_iommu_cb_probe(gmu, &a6xx_gmu_ctx[GMU_CONTEXT_USER], + node, a6xx_gmu_user_fault_handler); if (ret) return ret; - return a6xx_gmu_iommu_cb_probe(gmu, "gmu_kernel", - &a6xx_gmu_ctx[GMU_CONTEXT_KERNEL], node, - a6xx_gmu_kernel_fault_handler); -} - -static int a6xx_gmu_regulators_probe(struct a6xx_gmu_device *gmu, - struct platform_device *pdev) -{ - gmu->cx_gdsc = devm_regulator_get(&pdev->dev, "vddcx"); - if (IS_ERR(gmu->cx_gdsc)) { - if (PTR_ERR(gmu->cx_gdsc) != -EPROBE_DEFER) - dev_err(&pdev->dev, "Couldn't get the vddcx gdsc\n"); - return PTR_ERR(gmu->cx_gdsc); - } - - gmu->gx_gdsc = devm_regulator_get(&pdev->dev, "vdd"); - if (IS_ERR(gmu->gx_gdsc)) { - if (PTR_ERR(gmu->gx_gdsc) != -EPROBE_DEFER) - dev_err(&pdev->dev, "Couldn't get the vdd gdsc\n"); - return PTR_ERR(gmu->gx_gdsc); - } - - return 0; -} - -static void a6xx_gmu_remove(struct kgsl_device *device) -{ - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); - - tasklet_kill(&gmu->hfi.tasklet); - - a6xx_gmu_stop(device); - - if (!IS_ERR_OR_NULL(gmu->mailbox.channel)) - mbox_free_channel(gmu->mailbox.channel); - - adreno_dev->acd_enabled = false; - - if (gmu->fw_image) - release_firmware(gmu->fw_image); - - a6xx_gmu_memory_close(gmu); - - memset(&device->gmu_core, 0, sizeof(device->gmu_core)); + return a6xx_gmu_iommu_cb_probe(gmu, &a6xx_gmu_ctx[GMU_CONTEXT_KERNEL], + node, a6xx_gmu_kernel_fault_handler); } static int a6xx_gmu_probe(struct kgsl_device *device, struct platform_device *pdev) { - struct a6xx_gmu_device *gmu; - struct a6xx_hfi *hfi; - struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - int i = 0, ret = -ENXIO, index; - - gmu = devm_kzalloc(&pdev->dev, sizeof(*gmu), GFP_KERNEL); - if (!gmu) - return -ENOMEM; + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + struct kgsl_pwrctrl *pwr = &device->pwrctrl; + struct a6xx_hfi *hfi = &gmu->hfi; + int ret; gmu->pdev = pdev; - device->gmu_core.ptr = gmu; - hfi = &gmu->hfi; - dma_set_coherent_mask(&gmu->pdev->dev, DMA_BIT_MASK(64)); gmu->pdev->dev.dma_mask = &gmu->pdev->dev.coherent_dma_mask; set_dma_ops(&gmu->pdev->dev, NULL); @@ -3406,84 +2553,53 @@ static int a6xx_gmu_probe(struct kgsl_device *device, else gmu->vma = a6xx_gmu_vma_legacy; - ret = a6xx_gmu_tcm_init(gmu); - if (ret) - goto error; - /* Map and reserve GMU CSRs registers */ - ret = a6xx_gmu_reg_probe(device); + ret = a6xx_gmu_reg_probe(adreno_dev); if (ret) goto error; - /* Initialize HFI and GMU interrupts */ - ret = kgsl_request_irq(gmu->pdev, "kgsl_hfi_irq", - a6xx_hfi_irq_handler, device); - if (ret < 0) - goto error; - - hfi->hfi_interrupt_num = ret; - - ret = kgsl_request_irq(gmu->pdev, "kgsl_gmu_irq", a6xx_gmu_irq_handler, - device); - if (ret < 0) - goto error; - - gmu->gmu_interrupt_num = ret; - - /* Don't enable GMU interrupts until GMU started */ - /* We cannot use irq_disable because it writes registers */ - disable_irq(gmu->gmu_interrupt_num); - disable_irq(hfi->hfi_interrupt_num); - - tasklet_init(&hfi->tasklet, a6xx_hfi_receiver, (unsigned long) gmu); - hfi->kgsldev = device; - - if (WARN(pwr->num_pwrlevels + 1 > ARRAY_SIZE(gmu->pwrlevels), - "Too many GPU powerlevels for the GMU HFI\n")) { - ret = -EINVAL; - goto error; - } - - /* Add a dummy level for "off" because the GMU expects it */ - gmu->pwrlevels[0].freq = 0; - gmu->pwrlevels[0].level = 0; - - /* GMU power levels are in ascending order */ - for (index = 1, i = pwr->num_pwrlevels - 1; i >= 0; i--, index++) { - gmu->pwrlevels[index].freq = pwr->pwrlevels[i].gpu_freq; - gmu->pwrlevels[index].level = pwr->pwrlevels[i].voltage_level; - } - - gmu->num_gpupwrlevels = pwr->num_pwrlevels + 1; - /* Populates RPMh configurations */ - ret = a6xx_gmu_rpmh_init(device, gmu); + ret = a6xx_build_rpmh_tables(adreno_dev); if (ret) goto error; - /* Set up GMU idle states */ - if (ADRENO_FEATURE(adreno_dev, ADRENO_MIN_VOLT)) - gmu->idle_level = GPU_HW_MIN_VOLT; - else if (ADRENO_FEATURE(adreno_dev, ADRENO_HW_NAP)) - gmu->idle_level = GPU_HW_NAP; - else if (ADRENO_FEATURE(adreno_dev, ADRENO_IFPC)) + /* Set up GMU idle state */ + if (ADRENO_FEATURE(adreno_dev, ADRENO_IFPC)) gmu->idle_level = GPU_HW_IFPC; - else if (ADRENO_FEATURE(adreno_dev, ADRENO_SPTP_PC)) - gmu->idle_level = GPU_HW_SPTP_PC; else gmu->idle_level = GPU_HW_ACTIVE; a6xx_gmu_acd_probe(device, gmu, pdev->dev.of_node); - - if (a6xx_gmu_scales_bandwidth(device)) - pwr->bus_set = a6xx_gmu_bus_set; - set_bit(GMU_ENABLED, &device->gmu_core.flags); device->gmu_core.core_ops = &a6xx_gmu_ops; device->gmu_core.dev_ops = &a6xx_gmudev; + /* Initialize HFI and GMU interrupts */ + hfi->irq = kgsl_request_irq(gmu->pdev, "kgsl_hfi_irq", + a6xx_hfi_irq_handler, device); + if (hfi->irq < 0) { + ret = hfi->irq; + goto error; + } + + gmu->irq = kgsl_request_irq(gmu->pdev, "kgsl_gmu_irq", + a6xx_gmu_irq_handler, device); + + if (gmu->irq < 0) { + ret = gmu->irq; + goto error; + } + + /* Don't enable GMU interrupts until GMU started */ + /* We cannot use irq_disable because it writes registers */ + disable_irq(gmu->irq); + disable_irq(gmu->hfi.irq); + + if (a6xx_gmu_scales_bandwidth(device)) + pwr->bus_set = a6xx_gmu_bus_set; + return 0; error: @@ -3491,7 +2607,483 @@ error: return ret; } +static void a6xx_gmu_active_count_put(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + 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)) { + 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 halt_gbif(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + int ret; + + /* Halt new client requests */ + kgsl_regwrite(device, A6XX_GBIF_HALT, A6XX_GBIF_CLIENT_HALT_MASK); + ret = adreno_wait_for_halt_ack(device, + ADRENO_REG_GBIF_HALT_ACK, + A6XX_GBIF_CLIENT_HALT_MASK); + + /* Halt all AXI requests */ + kgsl_regwrite(device, A6XX_GBIF_HALT, A6XX_GBIF_ARB_HALT_MASK); + ret = adreno_wait_for_halt_ack(device, + ADRENO_REG_GBIF_HALT_ACK, + A6XX_GBIF_ARB_HALT_MASK); + + /* De-assert the halts */ + kgsl_regwrite(device, A6XX_GBIF_HALT, 0x0); + + return ret; +} + +static int a6xx_gmu_power_off(struct adreno_device *adreno_dev) +{ + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + int ret = 0; + + if (gmu->fault) + goto error; + + /* Wait for the lowest idle level we requested */ + ret = a6xx_gmu_wait_for_lowest_idle(adreno_dev); + if (ret) + goto error; + + ret = a6xx_gmu_notify_slumber(adreno_dev); + if (ret) + goto error; + + ret = a6xx_gmu_wait_for_idle(adreno_dev); + if (ret) + goto error; + + ret = a6xx_rscc_sleep_sequence(adreno_dev); + + /* Now that we are done with GMU and GPU, Clear the GBIF */ + if (!adreno_is_a630(adreno_dev)) + ret = halt_gbif(adreno_dev); + + a6xx_gmu_irq_disable(adreno_dev); + + a6xx_hfi_stop(adreno_dev); + + clk_bulk_disable_unprepare(gmu->num_clks, gmu->clks); + + /* Pool to make sure that the CX is off */ + if (!kgsl_regulator_disable_wait(gmu->cx_gdsc, 5000)) + dev_err(&gmu->pdev->dev, "GMU CX gdsc off timeout\n"); + + return ret; + +error: + a6xx_hfi_stop(adreno_dev); + a6xx_gmu_suspend(adreno_dev); + + return ret; +} + +static void enable_gpu_irq(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct kgsl_pwrctrl *pwr = &device->pwrctrl; + + adreno_irqctrl(adreno_dev, 1); + enable_irq(pwr->interrupt_num); + + trace_kgsl_irq(device, 1); +} + +static void disable_gpu_irq(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct kgsl_pwrctrl *pwr = &device->pwrctrl; + + disable_irq(pwr->interrupt_num); + + if (a6xx_gmu_gx_is_on(device)) + adreno_irqctrl(adreno_dev, 0); + + trace_kgsl_irq(device, 0); +} + +static int a6xx_gpu_boot(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + int ret; + + /* Clear any GPU faults that might have been left over */ + adreno_clear_gpu_fault(adreno_dev); + + adreno_set_active_ctxs_null(adreno_dev); + + adreno_ringbuffer_set_global(adreno_dev, 0); + + ret = kgsl_mmu_start(device); + if (ret) + goto err; + + ret = a6xx_gmu_oob_set(device, oob_gpu); + if (ret) + goto oob_clear; + + ret = a6xx_gmu_hfi_start_msg(adreno_dev); + if (ret) + goto oob_clear; + + adreno_clear_dcvs_counters(adreno_dev); + + /* Restore performance counter registers with saved values */ + adreno_perfcounter_restore(adreno_dev); + + a6xx_start(adreno_dev); + + /* Re-initialize the coresight registers if applicable */ + adreno_coresight_start(adreno_dev); + + adreno_perfcounter_start(adreno_dev); + + /* Clear FSR here in case it is set from a previous pagefault */ + kgsl_mmu_clear_fsr(&device->mmu); + + enable_gpu_irq(adreno_dev); + + ret = a6xx_rb_start(adreno_dev); + if (ret) { + disable_gpu_irq(adreno_dev); + goto oob_clear; + } + + /* Start the dispatcher */ + adreno_dispatcher_start(device); + + device->reset_counter++; + + a6xx_gmu_oob_clear(device, oob_gpu); + + if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) + gmu_core_dev_oob_clear(device, oob_boot_slumber); + + return 0; + +oob_clear: + a6xx_gmu_oob_clear(device, oob_gpu); + + if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) + gmu_core_dev_oob_clear(device, oob_boot_slumber); + +err: + a6xx_gmu_power_off(adreno_dev); + + return ret; +} + +static void gmu_idle_timer(struct timer_list *t) +{ + struct kgsl_device *device = container_of(t, struct kgsl_device, + idle_timer); + + kgsl_schedule_work(&device->idle_check_ws); +} + +static int a6xx_boot(struct adreno_device *adreno_dev) +{ + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + int ret; + + WARN_ON(test_bit(GMU_PRIV_GPU_STARTED, &gmu->flags)); + + ret = a6xx_gmu_boot(adreno_dev); + if (ret) + return ret; + + ret = a6xx_gpu_boot(adreno_dev); + if (ret) + return ret; + + mod_timer(&device->idle_timer, jiffies + + device->pwrctrl.interval_timeout); + + kgsl_pwrscale_wake(device); + + set_bit(GMU_PRIV_GPU_STARTED, &gmu->flags); + device->state = KGSL_STATE_ACTIVE; + + return ret; +} + +static int a6xx_first_boot(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + int ret; + unsigned long priv = 0; + + if (test_bit(GMU_PRIV_FIRST_BOOT_DONE, &gmu->flags)) + return a6xx_boot(adreno_dev); + + ret = adreno_dispatcher_init(adreno_dev); + if (ret) + return ret; + + ret = adreno_ringbuffer_init(adreno_dev); + if (ret) + return ret; + + ret = a6xx_microcode_read(adreno_dev); + if (ret) + return ret; + + ret = a6xx_init(adreno_dev); + if (ret) + return ret; + + ret = a6xx_gmu_init(adreno_dev); + if (ret) + return ret; + + ret = a6xx_gmu_first_boot(adreno_dev); + if (ret) + return ret; + + ret = a6xx_gpu_boot(adreno_dev); + if (ret) + return ret; + + ret = a6xx_load_pdc_ucode(adreno_dev); + if (ret) { + a6xx_gmu_power_off(adreno_dev); + return ret; + } + + a6xx_load_rsc_ucode(adreno_dev); + + adreno_get_bus_counters(adreno_dev); + + adreno_dev->cooperative_reset = ADRENO_FEATURE(adreno_dev, + ADRENO_COOP_RESET); + + if (ADRENO_FEATURE(adreno_dev, ADRENO_APRIV)) + priv |= KGSL_MEMDESC_PRIVILEGED; + + adreno_dev->profile_buffer = kgsl_allocate_global(device, PAGE_SIZE, 0, + priv, "alwayson"); + + adreno_dev->profile_index = 0; + + if (!IS_ERR(adreno_dev->profile_buffer)) + set_bit(ADRENO_DEVICE_DRAWOBJ_PROFILE, &adreno_dev->priv); + + set_bit(GMU_PRIV_FIRST_BOOT_DONE, &gmu->flags); + set_bit(GMU_PRIV_GPU_STARTED, &gmu->flags); + + device->state = KGSL_STATE_ACTIVE; + + return 0; +} + +static int a630_vbif_halt(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + int ret; + + kgsl_regwrite(device, A6XX_VBIF_XIN_HALT_CTRL0, + A6XX_VBIF_XIN_HALT_CTRL0_MASK); + ret = adreno_wait_for_halt_ack(device, + ADRENO_REG_VBIF_XIN_HALT_CTRL1, + A6XX_VBIF_XIN_HALT_CTRL0_MASK); + kgsl_regwrite(device, A6XX_VBIF_XIN_HALT_CTRL0, 0); + + return ret; +} + +static int a6xx_power_off(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + int ret; + + WARN_ON(!test_bit(GMU_PRIV_GPU_STARTED, &gmu->flags)); + + ret = a6xx_gmu_oob_set(device, oob_gpu); + if (ret) { + a6xx_gmu_oob_clear(device, oob_gpu); + goto no_gx_power; + } + + kgsl_pwrscale_update_stats(device); + + /* Save active coresight registers if applicable */ + adreno_coresight_stop(adreno_dev); + + /* Save physical performance counter values before GPU power down*/ + adreno_perfcounter_save(adreno_dev); + + /* + * Clear GX halt on non-gbif targets. For targets with GBIF, + * GX halt is handled by the GMU FW. + */ + if (adreno_is_a630(adreno_dev)) + a630_vbif_halt(adreno_dev); + + a6xx_gmu_oob_clear(device, oob_gpu); + +no_gx_power: + disable_gpu_irq(adreno_dev); + + a6xx_gmu_power_off(adreno_dev); + + adreno_set_active_ctxs_null(adreno_dev); + + adreno_dispatcher_stop(adreno_dev); + + adreno_ringbuffer_stop(adreno_dev); + + if (!IS_ERR_OR_NULL(adreno_dev->gpu_llc_slice)) + llcc_slice_deactivate(adreno_dev->gpu_llc_slice); + + if (!IS_ERR_OR_NULL(adreno_dev->gpuhtw_llc_slice)) + llcc_slice_deactivate(adreno_dev->gpuhtw_llc_slice); + + clear_bit(GMU_PRIV_GPU_STARTED, &gmu->flags); + + device->state = KGSL_STATE_NONE; + + del_timer_sync(&device->idle_timer); + + kgsl_pwrscale_sleep(device); + + return ret; +} + +static void gmu_idle_check(struct work_struct *work) +{ + struct kgsl_device *device = container_of(work, + struct kgsl_device, idle_check_ws); + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + + mutex_lock(&device->mutex); + + if (!atomic_read(&device->active_cnt)) { + if (test_bit(GMU_PRIV_GPU_STARTED, &gmu->flags)) + a6xx_power_off(adreno_dev); + } else { + mod_timer(&device->idle_timer, + jiffies + device->pwrctrl.interval_timeout); + } + + mutex_unlock(&device->mutex); +} + +static int a6xx_gmu_first_open(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + int ret; + + /* + * Do the one time settings that need to happen when we + * attempt to boot the gpu the very first time + */ + ret = a6xx_first_boot(adreno_dev); + if (ret) + return ret; + + /* + * A client that does a first_open but never closes the device + * may prevent us from going back to SLUMBER. So trigger the idle + * check by incrementing the active count and immediately releasing it. + */ + atomic_inc(&device->active_cnt); + a6xx_gmu_active_count_put(adreno_dev); + + return 0; +} + +static int a6xx_gmu_last_close(struct adreno_device *adreno_dev) +{ + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + + if (test_bit(GMU_PRIV_GPU_STARTED, &gmu->flags)) + return a6xx_power_off(adreno_dev); + + return 0; +} + +static int a6xx_gmu_active_count_get(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + int ret = 0; + + if (WARN_ON(!mutex_is_locked(&device->mutex))) + return -EINVAL; + + if ((atomic_read(&device->active_cnt) == 0) && + !test_bit(GMU_PRIV_GPU_STARTED, &gmu->flags)) + ret = a6xx_boot(adreno_dev); + + if (ret == 0) + atomic_inc(&device->active_cnt); + + trace_kgsl_active_count(device, + (unsigned long) __builtin_return_address(0)); + + return ret; +} + +const struct adreno_power_ops a6xx_gmu_power_ops = { + .first_open = a6xx_gmu_first_open, + .last_close = a6xx_gmu_last_close, + .active_count_get = a6xx_gmu_active_count_get, + .active_count_put = a6xx_gmu_active_count_put, +}; + +int a6xx_gmu_device_probe(struct platform_device *pdev, + u32 chipid, const struct adreno_gpu_core *gpucore) +{ + struct adreno_device *adreno_dev; + struct kgsl_device *device; + struct a6xx_device *a6xx_dev; + int ret; + + a6xx_dev = devm_kzalloc(&pdev->dev, sizeof(*a6xx_dev), + GFP_KERNEL); + if (!a6xx_dev) + return -ENOMEM; + + adreno_dev = &a6xx_dev->adreno_dev; + + ret = a6xx_probe_common(pdev, adreno_dev, chipid, gpucore); + if (ret) + return ret; + + device = KGSL_DEVICE(adreno_dev); + + INIT_WORK(&device->idle_check_ws, gmu_idle_check); + + timer_setup(&device->idle_timer, gmu_idle_timer, 0); + + return 0; +} static int a6xx_gmu_bind(struct device *dev, struct device *master, void *data) { diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.h b/drivers/gpu/msm/adreno_a6xx_gmu.h index d72690bd9f46..bce5b7350b6d 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.h +++ b/drivers/gpu/msm/adreno_a6xx_gmu.h @@ -10,11 +10,10 @@ #include "adreno_a6xx_hfi.h" #include "kgsl_gmu_core.h" -#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_PWR_LEVELS 2 +#define MAX_GMUFW_SIZE 0x8000 /* in bytes */ #define GMU_VER_MAJOR(ver) (((ver) >> 28) & 0xF) #define GMU_VER_MINOR(ver) (((ver) >> 16) & 0xFFF) @@ -81,8 +80,6 @@ struct gmu_block_header { /* GMU memdesc entries */ #define GMU_KERNEL_ENTRIES 16 -#define A6XX_GMU_DEVICE(_a) ((struct a6xx_gmu_device *)((_a)->gmu_core.ptr)) - enum gmu_mem_type { GMU_ITCM = 0, GMU_ICACHE, @@ -105,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 { @@ -129,10 +122,26 @@ 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, +}; + /** * 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 @@ -162,39 +171,98 @@ struct a6xx_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 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; - 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; + /** @fault: To track if we hit a gmu fault */ + bool fault; }; +/* Helper function to get to a6xx gmu device from adreno device */ +struct a6xx_gmu_device *to_a6xx_gmu(struct adreno_device *adreno_dev); + +/* Helper function to get to adreno device from a6xx gmu device */ +struct adreno_device *a6xx_gmu_to_adreno(struct a6xx_gmu_device *gmu); + +/** + * 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); #endif diff --git a/drivers/gpu/msm/adreno_a6xx_gmu_snapshot.c b/drivers/gpu/msm/adreno_a6xx_gmu_snapshot.c new file mode 100644 index 000000000000..bdecffdec328 --- /dev/null +++ b/drivers/gpu/msm/adreno_a6xx_gmu_snapshot.c @@ -0,0 +1,279 @@ +// 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, +}; + +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]); +} + +/* + * 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 a6xx_gmu_device *gmu = to_a6xx_gmu(ADRENO_DEVICE(device)); + 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_DEVICE(device)) || + adreno_is_a615_family(ADRENO_DEVICE(device))) + 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_DEVICE(device))) + adreno_snapshot_registers(device, snapshot, a660_gmu_registers, + ARRAY_SIZE(a660_gmu_registers) / 2); + + 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); +} diff --git a/drivers/gpu/msm/adreno_a6xx_hfi.c b/drivers/gpu/msm/adreno_a6xx_hfi.c index 1b1141093715..5e92cdcfcee9 100644 --- a/drivers/gpu/msm/adreno_a6xx_hfi.c +++ b/drivers/gpu/msm/adreno_a6xx_hfi.c @@ -8,11 +8,23 @@ #include "adreno.h" #include "adreno_a6xx.h" -#include "adreno_a6xx_gmu.h" -#include "adreno_a6xx_hfi.h" #include "kgsl_device.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,12 +40,6 @@ #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 a6xx_hfi_process_queue(struct a6xx_gmu_device *gmu, uint32_t queue_idx, struct pending_cmd *ret_cmd); @@ -41,7 +47,7 @@ static void a6xx_hfi_process_queue(struct a6xx_gmu_device *gmu, 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 a6xx_hfi_queue_write(struct a6xx_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 a6xx_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 a6xx_hfi_queue_write(struct a6xx_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 a6xx_hfi_queue_write(struct a6xx_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,7 +160,7 @@ static int a6xx_hfi_queue_write(struct a6xx_gmu_device *gmu, uint32_t queue_idx, wmb(); /* Send interrupt to GMU to receive the message */ - adreno_write_gmureg(ADRENO_DEVICE(hfi->kgsldev), + adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_HOST2GMU_INTR_SET, 0x1); return 0; @@ -173,11 +172,10 @@ static int a6xx_hfi_queue_write(struct a6xx_gmu_device *gmu, uint32_t queue_idx, /* Sizes of the queue and message are in unit of dwords */ -void a6xx_hfi_init(struct a6xx_gmu_device *gmu) +static void init_queues(struct adreno_device *adreno_dev) { - struct a6xx_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,8 +220,22 @@ void a6xx_hfi_init(struct a6xx_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) \ @@ -232,10 +244,10 @@ void a6xx_hfi_init(struct a6xx_gmu_device *gmu) static void 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); uint32_t *ack = rcvd; uint32_t hdr = ack[0]; uint32_t req_hdr = ack[1]; - struct a6xx_hfi *hfi = &gmu->hfi; if (ret_cmd == NULL) return; @@ -254,8 +266,8 @@ static void receive_ack_cmd(struct a6xx_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); + adreno_set_gpu_fault(adreno_dev, ADRENO_GMU_FAULT); + adreno_dispatcher_schedule(KGSL_DEVICE(adreno_dev)); } #define MSG_HDR_SET_SEQNUM(hdr, num) \ @@ -267,7 +279,7 @@ static int poll_adreno_gmu_reg(struct adreno_device *adreno_dev, { unsigned int val; struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); u64 ao_pre_poll, ao_post_poll; @@ -293,22 +305,22 @@ static int poll_adreno_gmu_reg(struct adreno_device *adreno_dev, return -ETIMEDOUT; } -static int a6xx_hfi_send_cmd(struct a6xx_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); int rc; uint32_t *cmd = data; 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 a6xx_hfi_queue_write(gmu, queue_idx, cmd); + return a6xx_hfi_queue_write(adreno_dev, queue_idx, cmd); ret_cmd->sent_hdr = cmd[0]; - rc = a6xx_hfi_queue_write(gmu, queue_idx, cmd); + rc = a6xx_hfi_queue_write(adreno_dev, queue_idx, cmd); if (rc) return rc; @@ -333,7 +345,7 @@ static int a6xx_hfi_send_cmd(struct a6xx_gmu_device *gmu, uint32_t queue_idx, #define HFI_ACK_ERROR 0xffffffff -static int a6xx_hfi_send_generic_req(struct a6xx_gmu_device *gmu, +static int a6xx_hfi_send_generic_req(struct adreno_device *adreno_dev, uint32_t queue, void *cmd) { struct pending_cmd ret_cmd; @@ -341,9 +353,11 @@ static int a6xx_hfi_send_generic_req(struct a6xx_gmu_device *gmu, memset(&ret_cmd, 0, sizeof(ret_cmd)); - rc = a6xx_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); + dev_err(&gmu->pdev->dev, "HFI ACK failure: Req 0x%8.8X\n", ret_cmd.results[1]); return -EINVAL; @@ -352,23 +366,24 @@ static int a6xx_hfi_send_generic_req(struct a6xx_gmu_device *gmu, return rc; } -static int a6xx_hfi_send_gmu_init(struct a6xx_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 a6xx_hfi_send_generic_req(gmu, HFI_CMD_ID, &cmd); + return a6xx_hfi_send_generic_req(adreno_dev, HFI_CMD_ID, &cmd); } -static int a6xx_hfi_get_fw_version(struct a6xx_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, @@ -378,7 +393,7 @@ static int a6xx_hfi_get_fw_version(struct a6xx_gmu_device *gmu, memset(&ret_cmd, 0, sizeof(ret_cmd)); - rc = a6xx_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; @@ -392,14 +407,14 @@ static int a6xx_hfi_get_fw_version(struct a6xx_gmu_device *gmu, return rc; } -static int a6xx_hfi_send_core_fw_start(struct a6xx_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 a6xx_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 a6xx_hfi_features[] = { @@ -416,9 +431,10 @@ static const char *feature_to_string(uint32_t feature) return "unknown"; } -static int a6xx_hfi_send_feature_ctrl(struct a6xx_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, @@ -427,7 +443,7 @@ static int a6xx_hfi_send_feature_ctrl(struct a6xx_gmu_device *gmu, }; int ret; - ret = a6xx_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", @@ -437,30 +453,31 @@ static int a6xx_hfi_send_feature_ctrl(struct a6xx_gmu_device *gmu, return ret; } -static int a6xx_hfi_send_dcvstbl_v1(struct a6xx_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 a6xx_hfi_send_generic_req(gmu, HFI_CMD_ID, &cmd); + return a6xx_hfi_send_generic_req(adreno_dev, HFI_CMD_ID, &cmd); } -static int a6xx_hfi_send_get_value(struct a6xx_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; @@ -471,7 +488,7 @@ static int a6xx_hfi_send_get_value(struct a6xx_gmu_device *gmu, cmd->hdr = CMD_MSG_HDR(H2F_MSG_GET_VALUE, sizeof(*cmd)); - rc = a6xx_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; @@ -481,56 +498,13 @@ static int a6xx_hfi_send_get_value(struct a6xx_gmu_device *gmu, return 0; } -static int a6xx_hfi_send_dcvstbl(struct a6xx_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 a6xx_hfi_send_generic_req(gmu, HFI_CMD_ID, &cmd); -} - -static int a6xx_hfi_send_bwtbl(struct a6xx_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 a6xx_hfi_send_generic_req(gmu, HFI_CMD_ID, cmd); -} - -static int a6xx_hfi_send_acd_tbl(struct a6xx_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 a6xx_hfi_send_generic_req(gmu, HFI_CMD_IDX, cmd); -} - -static int a6xx_hfi_send_test(struct a6xx_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 a6xx_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 a6xx_gmu_device *gmu, void *rcvd) @@ -611,17 +585,9 @@ static void a6xx_hfi_process_queue(struct a6xx_gmu_device *gmu, } } -void a6xx_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 */ - a6xx_hfi_process_queue((struct a6xx_gmu_device *) data, HFI_DBG_ID, - NULL); -} - -static int a6xx_hfi_verify_fw_version(struct kgsl_device *device, - struct a6xx_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; @@ -633,7 +599,8 @@ static int a6xx_hfi_verify_fw_version(struct kgsl_device *device, major = a6xx_core->gmu_major; minor = a6xx_core->gmu_minor; - result = a6xx_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"); @@ -657,8 +624,7 @@ static int a6xx_hfi_verify_fw_version(struct kgsl_device *device, return 0; } -static int a6xx_hfi_send_lm_feature_ctrl(struct a6xx_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; @@ -676,42 +642,40 @@ static int a6xx_hfi_send_lm_feature_ctrl(struct a6xx_gmu_device *gmu, req.subtype = 0; req.data = slope; - ret = a6xx_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 = a6xx_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 a6xx_hfi_send_acd_feature_ctrl(struct a6xx_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 = a6xx_hfi_send_acd_tbl(gmu); + ret = a6xx_hfi_send_generic_req(adreno_dev, HFI_CMD_ID, + &gmu->hfi.acd_table); if (!ret) - ret = a6xx_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 a6xx_hfi_start(struct kgsl_device *device, - struct a6xx_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]; @@ -728,25 +692,27 @@ int a6xx_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 = a6xx_hfi_send_gmu_init(gmu, boot_state); + result = a6xx_hfi_send_gmu_init(adreno_dev); if (result) - return result; + goto err; } - result = a6xx_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 = a6xx_hfi_send_dcvstbl_v1(gmu); + result = a6xx_hfi_send_dcvstbl_v1(adreno_dev); else - result = a6xx_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 = a6xx_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 @@ -754,42 +720,52 @@ int a6xx_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) { - - result = a6xx_hfi_send_acd_feature_ctrl(gmu, adreno_dev); + result = a6xx_hfi_send_acd_feature_ctrl(adreno_dev); if (result) - return result; + goto err; - result = a6xx_hfi_send_lm_feature_ctrl(gmu, adreno_dev); + result = a6xx_hfi_send_lm_feature_ctrl(adreno_dev); if (result) - return result; + goto err; - result = a6xx_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 = a6xx_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 */ + kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON); + +err: + if (result) + a6xx_hfi_stop(adreno_dev); + + return result; + } -void a6xx_hfi_stop(struct a6xx_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 a6xx_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]; @@ -802,11 +778,14 @@ void a6xx_hfi_stop(struct a6xx_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 a6xx_hfi_send_req(struct a6xx_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: { @@ -814,7 +793,7 @@ int a6xx_hfi_send_req(struct a6xx_gmu_device *gmu, unsigned int id, void *data) cmd->hdr = CMD_MSG_HDR(id, sizeof(*cmd)); - return a6xx_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; @@ -824,24 +803,24 @@ int a6xx_hfi_send_req(struct a6xx_gmu_device *gmu, unsigned int id, void *data) cmd->hdr = CMD_MSG_HDR(id, sizeof(*cmd)); - return a6xx_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 a6xx_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 a6xx_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 a6xx_hfi_send_generic_req(gmu, HFI_CMD_ID, cmd); + return a6xx_hfi_send_generic_req(adreno_dev, HFI_CMD_ID, cmd); } default: break; @@ -854,17 +833,17 @@ int a6xx_hfi_send_req(struct a6xx_gmu_device *gmu, unsigned int id, void *data) irqreturn_t a6xx_hfi_irq_handler(int irq, void *data) { struct kgsl_device *device = data; - struct a6xx_gmu_device *gmu = A6XX_GMU_DEVICE(device); - struct a6xx_hfi *hfi = &gmu->hfi; + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); unsigned int status = 0; - adreno_read_gmureg(ADRENO_DEVICE(device), + adreno_read_gmureg(adreno_dev, ADRENO_REG_GMU_GMU2HOST_INTR_INFO, &status); - adreno_write_gmureg(ADRENO_DEVICE(device), + adreno_write_gmureg(adreno_dev, ADRENO_REG_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"); diff --git a/drivers/gpu/msm/adreno_a6xx_hfi.h b/drivers/gpu/msm/adreno_a6xx_hfi.h index 08b00020322a..b56efb70a9dc 100644 --- a/drivers/gpu/msm/adreno_a6xx_hfi.h +++ b/drivers/gpu/msm/adreno_a6xx_hfi.h @@ -10,17 +10,6 @@ #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,11 +46,6 @@ 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 @@ -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 @@ -589,35 +495,63 @@ struct pending_cmd { /** * struct a6xx_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 * @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 a6xx_hfi { - struct kgsl_device *kgsldev; - int hfi_interrupt_num; - struct mutex cmdq_mutex; - struct tasklet_struct tasklet; + /** @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 a6xx_gmu_device; -struct gmu_memdesc; +/* a6xx_hfi_irq_handler - IRQ handler for HFI interripts */ irqreturn_t a6xx_hfi_irq_handler(int irq, void *data); -int a6xx_hfi_start(struct kgsl_device *device, struct a6xx_gmu_device *gmu, - uint32_t boot_state); -void a6xx_hfi_stop(struct a6xx_gmu_device *gmu); -void a6xx_hfi_receiver(unsigned long data); -void a6xx_hfi_init(struct a6xx_gmu_device *gmu); -/* hfi_send_req is only for external (to HFI) requests */ -int a6xx_hfi_send_req(struct a6xx_gmu_device *gmu, unsigned int id, void *data); -#endif /* __ADRENO_A6XX_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 diff --git a/drivers/gpu/msm/adreno_a6xx_rpmh.c b/drivers/gpu/msm/adreno_a6xx_rpmh.c new file mode 100644 index 000000000000..fe03df7239f6 --- /dev/null +++ b/drivers/gpu/msm/adreno_a6xx_rpmh.c @@ -0,0 +1,462 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include + +#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); +} diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index 3d36724cf725..ed7e68a6f8a1 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -42,7 +42,6 @@ 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); @@ -1276,7 +1275,7 @@ static void kgsl_pwrctrl_clk(struct kgsl_device *device, int state, } } -static void kgsl_pwrctrl_axi(struct kgsl_device *device, int state) +void kgsl_pwrctrl_axi(struct kgsl_device *device, int state) { struct kgsl_pwrctrl *pwr = &device->pwrctrl; diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h index a7b879b2fa30..2238cfc5b3d8 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.h +++ b/drivers/gpu/msm/kgsl_pwrctrl.h @@ -210,6 +210,16 @@ int kgsl_pwrctrl_set_default_gpu_pwrlevel(struct kgsl_device *device); */ 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 + */ +void kgsl_pwrctrl_axi(struct kgsl_device *device, int state); + /** * kgsl_idle_check - kgsl idle function * @work: work item being run by the function From 8508ab429286a813bfdc91f1d48723e1b0e43c2f Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Wed, 22 Apr 2020 11:18:55 -0600 Subject: [PATCH 19/30] msm: kgsl: Add a6xx gmu suspend and resume This adds the target specific sequence which is void of any kgsl power control interactions for suspending and resuming a gmu based target. Change-Id: I43b5bc14d7f757c4cc3105f892f0c19dcefe7a6e Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/adreno_a6xx_gmu.c | 59 +++++++++++++++++++++++++++++++ drivers/gpu/msm/adreno_a6xx_gmu.h | 1 + drivers/gpu/msm/adreno_dispatch.c | 2 +- 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index 036b20c0473e..c54bc19c9441 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -3037,6 +3037,9 @@ static int a6xx_gmu_active_count_get(struct adreno_device *adreno_dev) if (WARN_ON(!mutex_is_locked(&device->mutex))) return -EINVAL; + if (test_bit(GMU_PRIV_PM_SUSPEND, &gmu->flags)) + return -EINVAL; + if ((atomic_read(&device->active_cnt) == 0) && !test_bit(GMU_PRIV_GPU_STARTED, &gmu->flags)) ret = a6xx_boot(adreno_dev); @@ -3050,11 +3053,67 @@ static int a6xx_gmu_active_count_get(struct adreno_device *adreno_dev) return ret; } +static int a6xx_gmu_pm_suspend(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + int ret; + + if (test_bit(GMU_PRIV_PM_SUSPEND, &gmu->flags)) + return 0; + + /* Halt any new submissions */ + reinit_completion(&device->halt_gate); + + /* wait for active count so device can be put in slumber */ + ret = kgsl_active_count_wait(device, 0); + if (ret) { + dev_err(device->dev, + "Timed out waiting for the active count\n"); + goto err; + } + + ret = adreno_idle(device); + if (ret) + goto err; + + if (test_bit(GMU_PRIV_GPU_STARTED, &gmu->flags)) + a6xx_power_off(adreno_dev); + + set_bit(GMU_PRIV_PM_SUSPEND, &gmu->flags); + + adreno_dispatcher_halt(device); + + return 0; +err: + adreno_dispatcher_start(device); + return ret; +} + +static void a6xx_gmu_pm_resume(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + + if (!test_bit(GMU_PRIV_PM_SUSPEND, &gmu->flags)) { + dev_err(device->dev, "resume invoked without a suspend\n"); + return; + } + + adreno_dispatcher_unhalt(device); + + adreno_dispatcher_start(device); + + clear_bit(GMU_PRIV_PM_SUSPEND, &gmu->flags); +} + const struct adreno_power_ops a6xx_gmu_power_ops = { .first_open = a6xx_gmu_first_open, .last_close = a6xx_gmu_last_close, .active_count_get = a6xx_gmu_active_count_get, .active_count_put = a6xx_gmu_active_count_put, + .pm_suspend = a6xx_gmu_pm_suspend, + .pm_resume = a6xx_gmu_pm_resume, }; int a6xx_gmu_device_probe(struct platform_device *pdev, diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.h b/drivers/gpu/msm/adreno_a6xx_gmu.h index bce5b7350b6d..dd0c37eb7f9e 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.h +++ b/drivers/gpu/msm/adreno_a6xx_gmu.h @@ -136,6 +136,7 @@ enum { GMU_PRIV_GPU_STARTED, GMU_PRIV_HFI_STARTED, GMU_PRIV_RSCC_SLEEP_DONE, + GMU_PRIV_PM_SUSPEND, }; /** diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c index ac52cde6f5d3..da6dbb42ef0b 100644 --- a/drivers/gpu/msm/adreno_dispatch.c +++ b/drivers/gpu/msm/adreno_dispatch.c @@ -2908,7 +2908,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; /* From cbb2300459a8b8bee350eb24e48a17f558b4f334 Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Tue, 21 Apr 2020 23:26:55 -0600 Subject: [PATCH 20/30] msm: kgsl: Separate out reset sequence for a6xx gmu targets Now that we have a6xx gmu specific gpudev, we can dissociate the gmu reset sequence from the generic a6xx_reset function. Change-Id: Ib56456d5390fc059fc34407941f805c06cdfe42a Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/adreno_a6xx.c | 16 ++++---------- drivers/gpu/msm/adreno_a6xx_gmu.c | 36 +++++++++++++++++++++++++------ drivers/gpu/msm/adreno_a6xx_gmu.h | 8 +++++++ 3 files changed, 42 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index 5eb7e8eee1f0..91087ae772b6 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -1080,23 +1080,15 @@ static int64_t a6xx_read_throttling_counters(struct adreno_device *adreno_dev) * a6xx_reset() - Helper function to reset the GPU * @device: Pointer to the KGSL device structure for the GPU * - * 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) { 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); @@ -2702,7 +2694,7 @@ struct adreno_gpudev adreno_a6xx_gmu_gpudev = { .gpu_keepalive = a6xx_gpu_keepalive, .hw_isidle = a6xx_hw_isidle, .iommu_fault_block = a6xx_iommu_fault_block, - .reset = a6xx_reset, + .reset = a6xx_gmu_restart, .preemption_pre_ibsubmit = a6xx_preemption_pre_ibsubmit, .preemption_post_ibsubmit = a6xx_preemption_post_ibsubmit, .preemption_init = a6xx_preemption_init, diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index c54bc19c9441..6e71a5287e5b 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -2098,12 +2098,15 @@ static int a6xx_gmu_first_boot(struct adreno_device *adreno_dev) icc_set_bw(pwr->icc_path, 0, 0); + gmu->fault = false; + return 0; err: - a6xx_gmu_suspend(adreno_dev); - - return ret; + if (gmu->fault) { + a6xx_gmu_suspend(adreno_dev); + return ret; + } clks_gdsc_off: clk_bulk_disable_unprepare(gmu->num_clks, gmu->clks); @@ -2168,12 +2171,15 @@ static int a6xx_gmu_boot(struct adreno_device *adreno_dev) if (ret) goto err; + gmu->fault = false; + return 0; err: - a6xx_gmu_suspend(adreno_dev); - - return ret; + if (gmu->fault) { + a6xx_gmu_suspend(adreno_dev); + return ret; + } clks_gdsc_off: clk_bulk_disable_unprepare(gmu->num_clks, gmu->clks); @@ -3144,6 +3150,24 @@ int a6xx_gmu_device_probe(struct platform_device *pdev, return 0; } +int a6xx_gmu_restart(struct kgsl_device *device) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + + a6xx_hfi_stop(adreno_dev); + + disable_gpu_irq(adreno_dev); + + /* Hard reset the gmu and gpu */ + a6xx_gmu_suspend(adreno_dev); + + clear_bit(GMU_PRIV_GPU_STARTED, &gmu->flags); + + /* Attempt to reboot the gmu and gpu */ + return a6xx_boot(adreno_dev); +} + static int a6xx_gmu_bind(struct device *dev, struct device *master, void *data) { struct kgsl_device *device = dev_get_drvdata(master); diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.h b/drivers/gpu/msm/adreno_a6xx_gmu.h index dd0c37eb7f9e..a0caf28c25fe 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.h +++ b/drivers/gpu/msm/adreno_a6xx_gmu.h @@ -266,4 +266,12 @@ void a6xx_gmu_device_snapshot(struct kgsl_device *device, */ 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); #endif From 51f932b1e39e59dbf3fd3fa4e9148c2ec53f2830 Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Wed, 22 Apr 2020 19:55:40 -0600 Subject: [PATCH 21/30] msm: kgsl: Create a6xx rgmu power ops This completely dissociates the power sequences from the kgsl power controller for rgmu based targets and makes them target specific. Change-Id: I7f848ab507762ee6cdcfa6f64d07c84967a35bfa Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/adreno-gpulist.h | 2 +- drivers/gpu/msm/adreno.h | 1 + drivers/gpu/msm/adreno_a6xx.c | 35 ++ drivers/gpu/msm/adreno_a6xx.h | 4 + drivers/gpu/msm/adreno_a6xx_gmu.c | 12 +- drivers/gpu/msm/adreno_a6xx_gmu.h | 14 + drivers/gpu/msm/adreno_a6xx_rgmu.c | 755 +++++++++++++++++++++-------- drivers/gpu/msm/adreno_a6xx_rgmu.h | 33 +- 8 files changed, 634 insertions(+), 222 deletions(-) diff --git a/drivers/gpu/msm/adreno-gpulist.h b/drivers/gpu/msm/adreno-gpulist.h index e7760b2ab6dd..9a0c401a8934 100644 --- a/drivers/gpu/msm/adreno-gpulist.h +++ b/drivers/gpu/msm/adreno-gpulist.h @@ -1382,7 +1382,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, diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 994efb868905..7b1bf2781dde 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -906,6 +906,7 @@ 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 int adreno_wake_nice; extern unsigned int adreno_wake_timeout; diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index 91087ae772b6..58ed94ab6eef 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -2712,3 +2712,38 @@ struct adreno_gpudev adreno_a6xx_gmu_gpudev = { .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_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, +}; diff --git a/drivers/gpu/msm/adreno_a6xx.h b/drivers/gpu/msm/adreno_a6xx.h index 301a3320a537..3de5b699ce9c 100644 --- a/drivers/gpu/msm/adreno_a6xx.h +++ b/drivers/gpu/msm/adreno_a6xx.h @@ -11,8 +11,10 @@ #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; /** * struct a6xx_device - Container for the a6xx_device @@ -20,6 +22,8 @@ extern const struct adreno_power_ops a6xx_gmu_power_ops; 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; }; diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index 6e71a5287e5b..1754a8580881 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -2706,7 +2706,7 @@ error: return ret; } -static void enable_gpu_irq(struct adreno_device *adreno_dev) +void a6xx_enable_gpu_irq(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct kgsl_pwrctrl *pwr = &device->pwrctrl; @@ -2717,7 +2717,7 @@ static void enable_gpu_irq(struct adreno_device *adreno_dev) trace_kgsl_irq(device, 1); } -static void disable_gpu_irq(struct adreno_device *adreno_dev) +void a6xx_disable_gpu_irq(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct kgsl_pwrctrl *pwr = &device->pwrctrl; @@ -2769,11 +2769,11 @@ static int a6xx_gpu_boot(struct adreno_device *adreno_dev) /* Clear FSR here in case it is set from a previous pagefault */ kgsl_mmu_clear_fsr(&device->mmu); - enable_gpu_irq(adreno_dev); + a6xx_enable_gpu_irq(adreno_dev); ret = a6xx_rb_start(adreno_dev); if (ret) { - disable_gpu_irq(adreno_dev); + a6xx_disable_gpu_irq(adreno_dev); goto oob_clear; } @@ -2953,7 +2953,7 @@ static int a6xx_power_off(struct adreno_device *adreno_dev) a6xx_gmu_oob_clear(device, oob_gpu); no_gx_power: - disable_gpu_irq(adreno_dev); + a6xx_disable_gpu_irq(adreno_dev); a6xx_gmu_power_off(adreno_dev); @@ -3157,7 +3157,7 @@ int a6xx_gmu_restart(struct kgsl_device *device) a6xx_hfi_stop(adreno_dev); - disable_gpu_irq(adreno_dev); + a6xx_disable_gpu_irq(adreno_dev); /* Hard reset the gmu and gpu */ a6xx_gmu_suspend(adreno_dev); diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.h b/drivers/gpu/msm/adreno_a6xx_gmu.h index a0caf28c25fe..2e7ca929b1d2 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.h +++ b/drivers/gpu/msm/adreno_a6xx_gmu.h @@ -274,4 +274,18 @@ int a6xx_gmu_device_probe(struct platform_device *pdev, * 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); + + #endif diff --git a/drivers/gpu/msm/adreno_a6xx_rgmu.c b/drivers/gpu/msm/adreno_a6xx_rgmu.c index 124e6eaf6291..2b6b3add062c 100644 --- a/drivers/gpu/msm/adreno_a6xx_rgmu.c +++ b/drivers/gpu/msm/adreno_a6xx_rgmu.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "adreno.h" #include "adreno_a6xx.h" @@ -40,10 +41,42 @@ static const unsigned int a6xx_rgmu_registers[] = { 0x26000, 0x26002, }; +static struct a6xx_rgmu_device *to_a6xx_rgmu(struct adreno_device *adreno_dev) +{ + struct a6xx_device *a6xx_dev = container_of(adreno_dev, + struct a6xx_device, adreno_dev); + + return &a6xx_dev->rgmu; +} + +static void a6xx_rgmu_active_count_put(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + + 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)) { + 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 irqreturn_t a6xx_rgmu_irq_handler(int irq, void *data) { struct kgsl_device *device = data; - struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); + struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(ADRENO_DEVICE(device)); unsigned int status = 0; gmu_core_regread(device, A6XX_GMU_AO_HOST_INTERRUPT_STATUS, &status); @@ -71,8 +104,8 @@ static irqreturn_t a6xx_rgmu_irq_handler(int irq, void *data) static irqreturn_t a6xx_oob_irq_handler(int irq, void *data) { struct kgsl_device *device = data; - struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev); unsigned int status = 0; gmu_core_regread(device, A6XX_GMU_GMU2HOST_INTR_INFO, &status); @@ -110,7 +143,7 @@ static const char *oob_to_str(enum oob_request req) static int a6xx_rgmu_oob_set(struct kgsl_device *device, enum oob_request req) { - struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); + struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(ADRENO_DEVICE(device)); int ret, set, check; set = BIT(req + 16); @@ -153,7 +186,7 @@ static void a6xx_rgmu_oob_clear(struct kgsl_device *device, static void a6xx_rgmu_bcl_config(struct kgsl_device *device, bool on) { - struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); + struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(ADRENO_DEVICE(device)); if (on) { /* Enable BCL CRC HW i/f */ @@ -178,35 +211,35 @@ static void a6xx_rgmu_bcl_config(struct kgsl_device *device, bool on) } } -static void a6xx_rgmu_irq_enable(struct kgsl_device *device) +static void a6xx_rgmu_irq_enable(struct adreno_device *adreno_dev) { - struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); + struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev); /* Clear pending IRQs and Unmask needed IRQs */ - adreno_gmu_clear_and_unmask_irqs(ADRENO_DEVICE(device)); + adreno_gmu_clear_and_unmask_irqs(adreno_dev); /* Enable all IRQs on host */ enable_irq(rgmu->oob_interrupt_num); enable_irq(rgmu->rgmu_interrupt_num); } -static void a6xx_rgmu_irq_disable(struct kgsl_device *device) +static void a6xx_rgmu_irq_disable(struct adreno_device *adreno_dev) { - struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); + struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev); /* Disable all IRQs on host */ disable_irq(rgmu->rgmu_interrupt_num); disable_irq(rgmu->oob_interrupt_num); /* Mask all IRQs and clear pending IRQs */ - adreno_gmu_mask_and_clear_irqs(ADRENO_DEVICE(device)); + adreno_gmu_mask_and_clear_irqs(adreno_dev); } static int a6xx_rgmu_ifpc_store(struct kgsl_device *device, unsigned int val) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); + struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev); unsigned int requested_idle_level; if (!ADRENO_FEATURE(adreno_dev, ADRENO_IFPC)) @@ -227,7 +260,7 @@ static int a6xx_rgmu_ifpc_store(struct kgsl_device *device, static unsigned int a6xx_rgmu_ifpc_show(struct kgsl_device *device) { - struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); + struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(ADRENO_DEVICE(device)); return rgmu->idle_level == GPU_HW_IFPC; } @@ -235,10 +268,8 @@ static unsigned int a6xx_rgmu_ifpc_show(struct kgsl_device *device) static void a6xx_rgmu_prepare_stop(struct kgsl_device *device) { - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); /* Turn off GX_MEM retention */ - kgsl_regwrite(KGSL_DEVICE(adreno_dev), - A6XX_RBBM_BLOCK_GX_RETENTION_CNTL, 0); + kgsl_regwrite(device, A6XX_RBBM_BLOCK_GX_RETENTION_CNTL, 0); } #define GX_GDSC_POWER_OFF BIT(6) @@ -256,9 +287,10 @@ static bool a6xx_rgmu_gx_is_on(struct kgsl_device *device) return !(val & GX_GDSC_POWER_OFF); } -static int a6xx_rgmu_wait_for_lowest_idle(struct kgsl_device *device) +static int a6xx_rgmu_wait_for_lowest_idle(struct adreno_device *adreno_dev) { - struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev); unsigned int reg[10] = {0}; unsigned long t; uint64_t ts1, ts2, ts3; @@ -266,7 +298,7 @@ static int a6xx_rgmu_wait_for_lowest_idle(struct kgsl_device *device) if (rgmu->idle_level != GPU_HW_IFPC) return 0; - ts1 = a6xx_read_alwayson(ADRENO_DEVICE(device)); + ts1 = a6xx_read_alwayson(adreno_dev); t = jiffies + msecs_to_jiffies(RGMU_IDLE_TIMEOUT); do { @@ -280,7 +312,7 @@ static int a6xx_rgmu_wait_for_lowest_idle(struct kgsl_device *device) usleep_range(10, 100); } while (!time_after(jiffies, t)); - ts2 = a6xx_read_alwayson(ADRENO_DEVICE(device)); + ts2 = a6xx_read_alwayson(adreno_dev); /* Do one last read incase it succeeds */ gmu_core_regread(device, @@ -289,7 +321,7 @@ static int a6xx_rgmu_wait_for_lowest_idle(struct kgsl_device *device) if (reg[0] & GX_GDSC_POWER_OFF) return 0; - ts3 = a6xx_read_alwayson(ADRENO_DEVICE(device)); + ts3 = a6xx_read_alwayson(adreno_dev); /* Collect abort data to help with debugging */ gmu_core_regread(device, A6XX_RGMU_CX_PCC_DEBUG, ®[1]); @@ -338,15 +370,11 @@ static int a6xx_rgmu_wait_for_lowest_idle(struct kgsl_device *device) /* RGMU FENCE RANGE MASK */ #define RGMU_FENCE_RANGE_MASK ((0x1 << 31) | ((0xA << 2) << 18) | (0x8A0)) -/* - * a6xx_rgmu_fw_start() - set up GMU and start FW - * @device: Pointer to KGSL device - * @boot_state: State of the rgmu being started - */ -static int a6xx_rgmu_fw_start(struct kgsl_device *device, +static int a6xx_rgmu_fw_start(struct adreno_device *adreno_dev, unsigned int boot_state) { - struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev); unsigned int status; int i; @@ -416,76 +444,21 @@ static int a6xx_rgmu_fw_start(struct kgsl_device *device, return 0; } -static int a6xx_rgmu_suspend_device(struct kgsl_device *device) +static void a6xx_rgmu_notify_slumber(struct adreno_device *adreno_dev) { - struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); - int ret = 0; + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - /* Check GX GDSC is status */ - if (a6xx_rgmu_gx_is_on(device)) { + /* Disable the power counter so that the RGMU is not busy */ + gmu_core_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 0); - /* 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, error:%d\n", ret); - - ret = regulator_disable(rgmu->gx_gdsc); - if (ret) - dev_err(&rgmu->pdev->dev, - "Fail to disable gx gdsc, error:%d\n", ret); - - if (a6xx_rgmu_gx_is_on(device)) - dev_err(&rgmu->pdev->dev, "gx is stuck on\n"); - } - - return ret; + /* BCL OFF Sequence */ + a6xx_rgmu_bcl_config(device, false); } -/* - * a6xx_rgmu_gpu_pwrctrl() - GPU power control via rgmu interface - * @adreno_dev: Pointer to adreno device - * @mode: requested power mode - * @arg1: first argument for mode control - * @arg2: second argument for mode control - */ -static int a6xx_rgmu_gpu_pwrctrl(struct kgsl_device *device, - unsigned int mode, unsigned int arg1, unsigned int arg2) +static void a6xx_rgmu_disable_clks(struct adreno_device *adreno_dev) { - int ret = 0; - - switch (mode) { - case GMU_FW_START: - ret = a6xx_rgmu_fw_start(device, arg1); - break; - case GMU_SUSPEND: - ret = a6xx_rgmu_suspend_device(device); - break; - case GMU_NOTIFY_SLUMBER: - - /* Disable the power counter so that the RGMU is not busy */ - gmu_core_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, - 0); - - /* BCL OFF Sequence */ - a6xx_rgmu_bcl_config(device, false); - - break; - default: - ret = -EINVAL; - break; - } - - return ret; -} - -static void a6xx_rgmu_disable_clks(struct kgsl_device *device) -{ - struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev); int ret; /* Check GX GDSC is status */ @@ -514,13 +487,11 @@ static void a6xx_rgmu_disable_clks(struct kgsl_device *device) } clk_bulk_disable_unprepare(rgmu->num_clks, rgmu->clks); - - clear_bit(GMU_CLK_ON, &device->gmu_core.flags); } -static int a6xx_rgmu_disable_gdsc(struct kgsl_device *device) +static int a6xx_rgmu_disable_gdsc(struct adreno_device *adreno_dev) { - struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); + struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev); /* Wait up to 5 seconds for the regulator to go off */ if (kgsl_regulator_disable_wait(rgmu->cx_gdsc, 5000)) @@ -536,11 +507,13 @@ static void a6xx_rgmu_halt_execution(struct kgsl_device *device); static void a6xx_rgmu_snapshot(struct kgsl_device *device) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); + struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev); + + if (rgmu->fault) + return; /* Mask so there's no interrupt caused by NMI */ - adreno_write_gmureg(adreno_dev, - ADRENO_REG_GMU_GMU2HOST_INTR_MASK, 0xFFFFFFFF); + gmu_core_regwrite(device, A6XX_GMU_GMU2HOST_INTR_MASK, 0xFFFFFFFF); /* Make sure the interrupt is masked */ wmb(); @@ -558,27 +531,23 @@ static void a6xx_rgmu_snapshot(struct kgsl_device *device) RGMU_OOB_IRQ_MASK); rgmu->fault_count++; + + rgmu->fault = true; } -static int a6xx_rgmu_suspend(struct kgsl_device *device) +static void a6xx_rgmu_suspend(struct adreno_device *adreno_dev) { - if (!test_bit(GMU_CLK_ON, &device->gmu_core.flags)) - return 0; + a6xx_rgmu_irq_disable(adreno_dev); - a6xx_rgmu_irq_disable(device); - - if (a6xx_rgmu_gpu_pwrctrl(device, GMU_SUSPEND, 0, 0)) - return -EINVAL; - - a6xx_rgmu_disable_clks(device); - a6xx_rgmu_disable_gdsc(device); - return 0; + a6xx_rgmu_disable_clks(adreno_dev); + a6xx_rgmu_disable_gdsc(adreno_dev); } -static int a6xx_rgmu_enable_clks(struct kgsl_device *device) +static int a6xx_rgmu_enable_clks(struct adreno_device *adreno_dev) { int ret; - struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev); struct kgsl_pwrctrl *pwr = &device->pwrctrl; ret = clk_set_rate(rgmu->rgmu_clk, RGMU_CLK_FREQ); @@ -600,12 +569,12 @@ static int a6xx_rgmu_enable_clks(struct kgsl_device *device) return ret; } - set_bit(GMU_CLK_ON, &device->gmu_core.flags); return 0; } -static int a6xx_rgmu_enable_gdsc(struct a6xx_rgmu_device *rgmu) +static int a6xx_rgmu_enable_gdsc(struct adreno_device *adreno_dev) { + struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev); int ret; if (IS_ERR_OR_NULL(rgmu->cx_gdsc)) @@ -619,51 +588,14 @@ static int a6xx_rgmu_enable_gdsc(struct a6xx_rgmu_device *rgmu) return ret; } -/* To be called to power on both GPU and RGMU */ -static int a6xx_rgmu_start(struct kgsl_device *device) -{ - int ret = 0; - struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); - - switch (device->state) { - case KGSL_STATE_RESET: - ret = a6xx_rgmu_suspend(device); - if (ret) - goto error_rgmu; - /* Fall-through */ - case KGSL_STATE_INIT: - case KGSL_STATE_SUSPEND: - case KGSL_STATE_SLUMBER: - a6xx_rgmu_enable_gdsc(rgmu); - a6xx_rgmu_enable_clks(device); - a6xx_rgmu_irq_enable(device); - ret = a6xx_rgmu_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); - a6xx_rgmu_snapshot(device); - return ret; -} - - - /* * a6xx_rgmu_load_firmware() - Load the ucode into the RGMU TCM - * @device: Pointer to KGSL device + * @adreno_dev: Pointer to adreno device */ -static int a6xx_rgmu_load_firmware(struct kgsl_device *device) +static int a6xx_rgmu_load_firmware(struct adreno_device *adreno_dev) { const struct firmware *fw = NULL; - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); + struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev); const struct adreno_a6xx_core *a6xx_core = to_a6xx_core(adreno_dev); int ret; @@ -688,15 +620,10 @@ static int a6xx_rgmu_load_firmware(struct kgsl_device *device) return rgmu->fw_hostptr ? 0 : -ENOMEM; } -static int a6xx_rgmu_init(struct kgsl_device *device) -{ - return a6xx_rgmu_load_firmware(device); -} - /* Halt RGMU execution */ static void a6xx_rgmu_halt_execution(struct kgsl_device *device) { - struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); + struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(ADRENO_DEVICE(device)); unsigned int index, status, fence; gmu_core_regread(device, A6XX_RGMU_CX_PCC_DEBUG, &index); @@ -737,53 +664,52 @@ static void a6xx_rgmu_device_snapshot(struct kgsl_device *device, ARRAY_SIZE(a6xx_rgmu_registers) / 2); } -static u64 a6xx_rgmu_read_alwayson(struct kgsl_device *device) +static void halt_gbif_arb(struct adreno_device *adreno_dev) { - return a6xx_read_alwayson(ADRENO_DEVICE(device)); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + + /* Halt all AXI requests */ + kgsl_regwrite(device, A6XX_GBIF_HALT, A6XX_GBIF_ARB_HALT_MASK); + adreno_wait_for_halt_ack(device, ADRENO_REG_GBIF_HALT_ACK, + A6XX_GBIF_ARB_HALT_MASK); + + /* De-assert the halts */ + kgsl_regwrite(device, A6XX_GBIF_HALT, 0x0); } + /* Caller shall ensure GPU is ready for SLUMBER */ -static void a6xx_rgmu_stop(struct kgsl_device *device) +static void a6xx_rgmu_power_off(struct adreno_device *adreno_dev) { - if (!test_bit(GMU_CLK_ON, &device->gmu_core.flags)) - return; + struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + int ret; + + kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_OFF); + + if (rgmu->fault) + return a6xx_rgmu_suspend(adreno_dev); /* Wait for the lowest idle level we requested */ - if (a6xx_rgmu_wait_for_lowest_idle(device)) - goto error; + ret = a6xx_rgmu_wait_for_lowest_idle(adreno_dev); + if (ret) + return a6xx_rgmu_suspend(adreno_dev); - a6xx_rgmu_gpu_pwrctrl(device, - GMU_NOTIFY_SLUMBER, 0, 0); + a6xx_rgmu_notify_slumber(adreno_dev); - a6xx_rgmu_irq_disable(device); - a6xx_rgmu_disable_clks(device); - a6xx_rgmu_disable_gdsc(device); - return; + /* Halt CX traffic and de-assert halt */ + halt_gbif_arb(adreno_dev); -error: + a6xx_rgmu_irq_disable(adreno_dev); + a6xx_rgmu_disable_clks(adreno_dev); + a6xx_rgmu_disable_gdsc(adreno_dev); - /* - * 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); - a6xx_rgmu_snapshot(device); } -/* - * a6xx_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 a6xx_rgmu_dcvs_set(struct kgsl_device *device, int pwrlevel, int bus_level) { - struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); + struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(ADRENO_DEVICE(device)); int ret; unsigned long rate; @@ -799,37 +725,410 @@ static int a6xx_rgmu_dcvs_set(struct kgsl_device *device, return ret; } +static int a6xx_gpu_boot(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + int ret; + + /* Clear any GPU faults that might have been left over */ + adreno_clear_gpu_fault(adreno_dev); + + adreno_set_active_ctxs_null(adreno_dev); + + adreno_ringbuffer_set_global(adreno_dev, 0); + + ret = kgsl_mmu_start(device); + if (ret) + goto err; + + ret = a6xx_rgmu_oob_set(device, oob_gpu); + if (ret) + goto err_oob_clear; + + adreno_clear_dcvs_counters(adreno_dev); + + /* Restore performance counter registers with saved values */ + adreno_perfcounter_restore(adreno_dev); + + a6xx_start(adreno_dev); + + /* Re-initialize the coresight registers if applicable */ + adreno_coresight_start(adreno_dev); + + adreno_perfcounter_start(adreno_dev); + + /* Clear FSR here in case it is set from a previous pagefault */ + kgsl_mmu_clear_fsr(&device->mmu); + + a6xx_enable_gpu_irq(adreno_dev); + + ret = a6xx_rb_start(adreno_dev); + if (ret) { + a6xx_disable_gpu_irq(adreno_dev); + goto err_oob_clear; + } + + /* Start the dispatcher */ + adreno_dispatcher_start(device); + + device->reset_counter++; + + a6xx_rgmu_oob_clear(device, oob_gpu); + + return 0; + +err_oob_clear: + a6xx_rgmu_oob_clear(device, oob_gpu); + +err: + a6xx_rgmu_power_off(adreno_dev); + + return ret; +} + +static int a6xx_rgmu_boot(struct adreno_device *adreno_dev) +{ + struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + int ret; + + ret = a6xx_rgmu_enable_gdsc(adreno_dev); + if (ret) + return ret; + + ret = a6xx_rgmu_enable_clks(adreno_dev); + if (ret) { + a6xx_rgmu_disable_gdsc(adreno_dev); + return ret; + } + + a6xx_rgmu_irq_enable(adreno_dev); + + ret = a6xx_rgmu_fw_start(adreno_dev, GMU_COLD_BOOT); + if (ret) + goto err; + + /* Request default DCVS level */ + ret = kgsl_pwrctrl_set_default_gpu_pwrlevel(device); + if (ret) + goto err; + + kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON); + + rgmu->fault = false; + + return 0; + +err: + a6xx_rgmu_power_off(adreno_dev); + + return ret; +} + +static int a6xx_power_off(struct adreno_device *adreno_dev); + +static void rgmu_idle_check(struct work_struct *work) +{ + struct kgsl_device *device = container_of(work, + struct kgsl_device, idle_check_ws); + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + + mutex_lock(&device->mutex); + + if (!atomic_read(&device->active_cnt)) + a6xx_power_off(adreno_dev); + else + mod_timer(&device->idle_timer, + jiffies + device->pwrctrl.interval_timeout); + + mutex_unlock(&device->mutex); +} + +static void rgmu_idle_timer(struct timer_list *t) +{ + struct kgsl_device *device = container_of(t, struct kgsl_device, + idle_timer); + + kgsl_schedule_work(&device->idle_check_ws); +} + +static int a6xx_boot(struct adreno_device *adreno_dev) +{ + struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + int ret; + + if (test_bit(RGMU_PRIV_GPU_STARTED, &rgmu->flags)) + return 0; + + ret = a6xx_rgmu_boot(adreno_dev); + if (ret) + return ret; + + ret = a6xx_gpu_boot(adreno_dev); + if (ret) + return ret; + + mod_timer(&device->idle_timer, jiffies + + device->pwrctrl.interval_timeout); + + kgsl_pwrscale_wake(device); + + set_bit(RGMU_PRIV_GPU_STARTED, &rgmu->flags); + + device->state = KGSL_STATE_ACTIVE; + + return 0; +} + +static int a6xx_first_boot(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev); + int ret; + + if (test_bit(RGMU_PRIV_FIRST_BOOT_DONE, &rgmu->flags)) + return a6xx_boot(adreno_dev); + + ret = adreno_dispatcher_init(adreno_dev); + if (ret) + return ret; + + ret = adreno_ringbuffer_init(adreno_dev); + if (ret) + return ret; + + ret = a6xx_microcode_read(adreno_dev); + if (ret) + return ret; + + ret = a6xx_init(adreno_dev); + if (ret) + return ret; + + ret = a6xx_rgmu_load_firmware(adreno_dev); + if (ret) + return ret; + + ret = a6xx_rgmu_boot(adreno_dev); + if (ret) + return ret; + + ret = a6xx_gpu_boot(adreno_dev); + if (ret) + return ret; + + adreno_get_bus_counters(adreno_dev); + + adreno_dev->profile_buffer = kgsl_allocate_global(device, PAGE_SIZE, 0, + 0, "alwayson"); + + adreno_dev->profile_index = 0; + + if (!IS_ERR(adreno_dev->profile_buffer)) + set_bit(ADRENO_DEVICE_DRAWOBJ_PROFILE, &adreno_dev->priv); + + set_bit(RGMU_PRIV_FIRST_BOOT_DONE, &rgmu->flags); + set_bit(RGMU_PRIV_GPU_STARTED, &rgmu->flags); + + device->state = KGSL_STATE_ACTIVE; + + return 0; +} + +static int a6xx_rgmu_first_open(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + int ret; + + ret = a6xx_first_boot(adreno_dev); + if (ret) + return ret; + + /* + * A client that does a first_open but never closes the device + * may prevent us from going back to SLUMBER. So trigger the idle + * check by incrementing the active count and immediately releasing it. + */ + atomic_inc(&device->active_cnt); + a6xx_rgmu_active_count_put(adreno_dev); + + return 0; +} + +static int a6xx_power_off(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev); + int ret; + + if (!test_bit(RGMU_PRIV_GPU_STARTED, &rgmu->flags)) + return 0; + + ret = a6xx_rgmu_oob_set(device, oob_gpu); + if (ret) { + a6xx_rgmu_oob_clear(device, oob_gpu); + goto no_gx_power; + } + + kgsl_pwrscale_update_stats(device); + + /* Save active coresight registers if applicable */ + adreno_coresight_stop(adreno_dev); + + /* Save physical performance counter values before GPU power down*/ + adreno_perfcounter_save(adreno_dev); + + a6xx_rgmu_prepare_stop(device); + + a6xx_rgmu_oob_clear(device, oob_gpu); + +no_gx_power: + /* Halt all gx traffic */ + kgsl_regwrite(device, A6XX_GBIF_HALT, A6XX_GBIF_CLIENT_HALT_MASK); + + adreno_wait_for_halt_ack(device, ADRENO_REG_GBIF_HALT_ACK, + A6XX_GBIF_CLIENT_HALT_MASK); + + a6xx_disable_gpu_irq(adreno_dev); + + a6xx_rgmu_power_off(adreno_dev); + + adreno_set_active_ctxs_null(adreno_dev); + + adreno_dispatcher_stop(adreno_dev); + + adreno_ringbuffer_stop(adreno_dev); + + if (!IS_ERR_OR_NULL(adreno_dev->gpu_llc_slice)) + llcc_slice_deactivate(adreno_dev->gpu_llc_slice); + + if (!IS_ERR_OR_NULL(adreno_dev->gpuhtw_llc_slice)) + llcc_slice_deactivate(adreno_dev->gpuhtw_llc_slice); + + clear_bit(RGMU_PRIV_GPU_STARTED, &rgmu->flags); + + device->state = KGSL_STATE_NONE; + + del_timer_sync(&device->idle_timer); + + kgsl_pwrscale_sleep(device); + + return ret; +} + +int a6xx_rgmu_restart(struct kgsl_device *device) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev); + + a6xx_disable_gpu_irq(adreno_dev); + + /* Hard reset the rgmu and gpu */ + a6xx_rgmu_suspend(adreno_dev); + + clear_bit(RGMU_PRIV_GPU_STARTED, &rgmu->flags); + + /* Attempt rebooting the rgmu and gpu */ + return a6xx_boot(adreno_dev); +} + +static int a6xx_rgmu_active_count_get(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev); + int ret = 0; + + if (WARN_ON(!mutex_is_locked(&device->mutex))) + return -EINVAL; + + if (test_bit(RGMU_PRIV_PM_SUSPEND, &rgmu->flags)) + return -EINVAL; + + if (atomic_read(&device->active_cnt) == 0) + ret = a6xx_boot(adreno_dev); + + if (ret == 0) { + atomic_inc(&device->active_cnt); + trace_kgsl_active_count(device, + (unsigned long) __builtin_return_address(0)); + } + + return ret; +} + +static int a6xx_rgmu_pm_suspend(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev); + int ret; + + if (test_bit(RGMU_PRIV_PM_SUSPEND, &rgmu->flags)) + return 0; + + /* Halt any new submissions */ + reinit_completion(&device->halt_gate); + + /* wait for active count so device can be put in slumber */ + ret = kgsl_active_count_wait(device, 0); + if (ret) { + dev_err(device->dev, + "Timed out waiting for the active count\n"); + goto err; + } + + ret = adreno_idle(device); + if (ret) + goto err; + + a6xx_power_off(adreno_dev); + + set_bit(RGMU_PRIV_PM_SUSPEND, &rgmu->flags); + + adreno_dispatcher_halt(device); + + return 0; +err: + adreno_dispatcher_start(device); + return ret; +} + +static void a6xx_rgmu_pm_resume(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev); + + if (!test_bit(RGMU_PRIV_PM_SUSPEND, &rgmu->flags)) { + dev_err(device->dev, "resume invoked without a suspend\n"); + return; + } + + adreno_dispatcher_unhalt(device); + + clear_bit(RGMU_PRIV_PM_SUSPEND, &rgmu->flags); + + adreno_dispatcher_start(device); +} + static struct gmu_dev_ops a6xx_rgmudev = { - .load_firmware = a6xx_rgmu_load_firmware, .oob_set = a6xx_rgmu_oob_set, .oob_clear = a6xx_rgmu_oob_clear, - .irq_enable = a6xx_rgmu_irq_enable, - .irq_disable = a6xx_rgmu_irq_disable, - .rpmh_gpu_pwrctrl = a6xx_rgmu_gpu_pwrctrl, .gx_is_on = a6xx_rgmu_gx_is_on, - .prepare_stop = a6xx_rgmu_prepare_stop, - .wait_for_lowest_idle = a6xx_rgmu_wait_for_lowest_idle, .ifpc_store = a6xx_rgmu_ifpc_store, .ifpc_show = a6xx_rgmu_ifpc_show, .snapshot = a6xx_rgmu_device_snapshot, - .halt_execution = a6xx_rgmu_halt_execution, - .read_alwayson = a6xx_rgmu_read_alwayson, .gmu2host_intr_mask = RGMU_OOB_IRQ_MASK, .gmu_ao_intr_mask = RGMU_AO_IRQ_MASK, }; static struct gmu_core_ops a6xx_rgmu_ops = { - .init = a6xx_rgmu_init, - .start = a6xx_rgmu_start, - .stop = a6xx_rgmu_stop, .dcvs_set = a6xx_rgmu_dcvs_set, .snapshot = a6xx_rgmu_snapshot, - .suspend = a6xx_rgmu_suspend, }; static int a6xx_rgmu_irq_probe(struct kgsl_device *device) { - struct a6xx_rgmu_device *rgmu = A6XX_RGMU_DEVICE(device); + struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(ADRENO_DEVICE(device)); int ret; ret = kgsl_request_irq(rgmu->pdev, "kgsl_oob", @@ -898,18 +1197,51 @@ static int a6xx_rgmu_clocks_probe(struct a6xx_rgmu_device *rgmu, return 0; } +const struct adreno_power_ops a6xx_rgmu_power_ops = { + .first_open = a6xx_rgmu_first_open, + .last_close = a6xx_power_off, + .active_count_get = a6xx_rgmu_active_count_get, + .active_count_put = a6xx_rgmu_active_count_put, + .pm_suspend = a6xx_rgmu_pm_suspend, + .pm_resume = a6xx_rgmu_pm_resume, +}; + +int a6xx_rgmu_device_probe(struct platform_device *pdev, + u32 chipid, const struct adreno_gpu_core *gpucore) +{ + struct adreno_device *adreno_dev; + struct kgsl_device *device; + struct a6xx_device *a6xx_dev; + int ret; + + a6xx_dev = devm_kzalloc(&pdev->dev, sizeof(*a6xx_dev), + GFP_KERNEL); + if (!a6xx_dev) + return -ENOMEM; + + adreno_dev = &a6xx_dev->adreno_dev; + + ret = a6xx_probe_common(pdev, adreno_dev, chipid, gpucore); + if (ret) + return ret; + + device = KGSL_DEVICE(adreno_dev); + + INIT_WORK(&device->idle_check_ws, rgmu_idle_check); + + timer_setup(&device->idle_timer, rgmu_idle_timer, 0); + + return 0; +} + /* Do not access any RGMU registers in RGMU probe function */ static int a6xx_rgmu_probe(struct kgsl_device *device, struct platform_device *pdev) { - struct a6xx_rgmu_device *rgmu; + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev); struct resource *res; - int ret = -ENXIO; - - rgmu = devm_kzalloc(&pdev->dev, sizeof(*rgmu), GFP_KERNEL); - - if (rgmu == NULL) - return -ENOMEM; + int ret; rgmu->pdev = pdev; @@ -939,8 +1271,6 @@ static int a6xx_rgmu_probe(struct kgsl_device *device, return PTR_ERR(device->gmu_core.reg_virt); } - device->gmu_core.ptr = (void *)rgmu; - /* Initialize OOB and RGMU interrupts */ ret = a6xx_rgmu_irq_probe(device); if (ret) @@ -966,7 +1296,6 @@ static int a6xx_rgmu_probe(struct kgsl_device *device, static void a6xx_rgmu_remove(struct kgsl_device *device) { - a6xx_rgmu_stop(device); memset(&device->gmu_core, 0, sizeof(device->gmu_core)); } diff --git a/drivers/gpu/msm/adreno_a6xx_rgmu.h b/drivers/gpu/msm/adreno_a6xx_rgmu.h index 02839b16001e..f59c4de09dfd 100644 --- a/drivers/gpu/msm/adreno_a6xx_rgmu.h +++ b/drivers/gpu/msm/adreno_a6xx_rgmu.h @@ -15,6 +15,15 @@ #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 @@ -47,8 +56,28 @@ struct a6xx_rgmu_device { struct clk *rgmu_clk; unsigned int idle_level; unsigned int fault_count; + /** @fault: to track whether we encountered a rgmu fault */ + bool fault; + /** @flags: rgmu internal flags */ + unsigned long flags; }; -#define A6XX_RGMU_DEVICE(_a) ((struct a6xx_rgmu_device *)((_a)->gmu_core.ptr)) +/** + * 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); -#endif /* __ADRENO_A6XX_RGMU_H */ +/** + * 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); +#endif From f7954ed2e543fc2294a4685da9ad34e7f6d68cdb Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Wed, 20 May 2020 22:07:40 -0600 Subject: [PATCH 22/30] msm: kgsl: Add target specific touch wakeup function This is needed because gmu and rgmu targets have their own different power up sequences. Change-Id: I98f6d24938bfd5968e041c5b680b42750f87dd2e Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/adreno.c | 44 ++++++++++++++++++++---------- drivers/gpu/msm/adreno.h | 4 +++ drivers/gpu/msm/adreno_a6xx_gmu.c | 39 ++++++++++++++++++++++++++ drivers/gpu/msm/adreno_a6xx_rgmu.c | 40 +++++++++++++++++++++++++++ 4 files changed, 113 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index dea6efcdafa7..e290c41dcf9f 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -321,23 +321,10 @@ void adreno_fault_detect_stop(struct adreno_device *adreno_dev) adreno_dev->fast_hang_detect = 0; } -/* - * A workqueue callback responsible for actually turning on the GPU after a - * touch event. kgsl_pwrctrl_change_state(ACTIVE) is used without any - * active_count protection to avoid the need to maintain state. Either - * somebody will start using the GPU or the idle timer will fire and put the - * GPU back into slumber. - */ -static void adreno_input_work(struct work_struct *work) +static void adreno_touch_wakeup(struct adreno_device *adreno_dev) { - struct adreno_device *adreno_dev = container_of(work, - struct adreno_device, input_work); struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - mutex_lock(&device->mutex); - - device->flags |= KGSL_FLAG_WAKE_ON_TOUCH; - /* * Don't schedule adreno_start in a high priority workqueue, we are * already in a workqueue which should be sufficient @@ -352,6 +339,29 @@ static void adreno_input_work(struct work_struct *work) */ mod_timer(&device->idle_timer, jiffies + msecs_to_jiffies(adreno_wake_timeout)); + +} + +/* + * A workqueue callback responsible for actually turning on the GPU after a + * touch event. kgsl_pwrctrl_change_state(ACTIVE) is used without any + * active_count protection to avoid the need to maintain state. Either + * somebody will start using the GPU or the idle timer will fire and put the + * GPU back into slumber. + */ +static void adreno_input_work(struct work_struct *work) +{ + struct adreno_device *adreno_dev = container_of(work, + struct adreno_device, input_work); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + const struct adreno_power_ops *ops = ADRENO_POWER_OPS(adreno_dev); + + mutex_lock(&device->mutex); + + device->flags |= KGSL_FLAG_WAKE_ON_TOUCH; + + ops->touch_wakeup(adreno_dev); + mutex_unlock(&device->mutex); } @@ -377,6 +387,11 @@ static void adreno_input_event(struct input_handle *handle, unsigned int type, if (device->flags & KGSL_FLAG_WAKE_ON_TOUCH) return; + if (gmu_core_isenabled(device)) { + schedule_work(&adreno_dev->input_work); + return; + } + /* * If the device is in nap, kick the idle timer to make sure that we * don't go into slumber before the first render. If the device is @@ -3841,6 +3856,7 @@ const struct adreno_power_ops adreno_power_operations = { .active_count_put = adreno_pwrctrl_active_count_put, .pm_suspend = adreno_suspend, .pm_resume = adreno_resume, + .touch_wakeup = adreno_touch_wakeup, }; static const struct of_device_id adreno_gmu_match[] = { diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 7b1bf2781dde..090a6ca7c26c 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -357,6 +357,10 @@ struct adreno_power_ops { 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); }; /** diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index 1754a8580881..7a2e94d75dbd 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -3113,6 +3113,44 @@ static void a6xx_gmu_pm_resume(struct adreno_device *adreno_dev) clear_bit(GMU_PRIV_PM_SUSPEND, &gmu->flags); } +static void a6xx_gmu_touch_wakeup(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + int ret; + + /* Do not wake up a suspended device through touch event */ + if (test_bit(GMU_PRIV_PM_SUSPEND, &gmu->flags)) + return; + + if (test_bit(GMU_PRIV_GPU_STARTED, &gmu->flags)) + goto done; + + ret = a6xx_gmu_boot(adreno_dev); + if (ret) + return; + + ret = a6xx_gpu_boot(adreno_dev); + if (ret) + return; + + kgsl_pwrscale_wake(device); + + set_bit(GMU_PRIV_GPU_STARTED, &gmu->flags); + device->state = KGSL_STATE_ACTIVE; + +done: + /* + * When waking up from a touch event we want to stay active long enough + * for the user to send a draw command. The default idle timer timeout + * is shorter than we want so go ahead and push the idle timer out + * further for this special case + */ + mod_timer(&device->idle_timer, jiffies + + msecs_to_jiffies(adreno_wake_timeout)); + +} + const struct adreno_power_ops a6xx_gmu_power_ops = { .first_open = a6xx_gmu_first_open, .last_close = a6xx_gmu_last_close, @@ -3120,6 +3158,7 @@ const struct adreno_power_ops a6xx_gmu_power_ops = { .active_count_put = a6xx_gmu_active_count_put, .pm_suspend = a6xx_gmu_pm_suspend, .pm_resume = a6xx_gmu_pm_resume, + .touch_wakeup = a6xx_gmu_touch_wakeup, }; int a6xx_gmu_device_probe(struct platform_device *pdev, diff --git a/drivers/gpu/msm/adreno_a6xx_rgmu.c b/drivers/gpu/msm/adreno_a6xx_rgmu.c index 2b6b3add062c..8969c6dda4a6 100644 --- a/drivers/gpu/msm/adreno_a6xx_rgmu.c +++ b/drivers/gpu/msm/adreno_a6xx_rgmu.c @@ -881,6 +881,45 @@ static int a6xx_boot(struct adreno_device *adreno_dev) return 0; } +static void a6xx_rgmu_touch_wakeup(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev); + int ret; + + /* Do not wake up a suspended device through touch event */ + if (test_bit(RGMU_PRIV_PM_SUSPEND, &rgmu->flags)) + return; + + if (test_bit(RGMU_PRIV_GPU_STARTED, &rgmu->flags)) + goto done; + + ret = a6xx_rgmu_boot(adreno_dev); + if (ret) + return; + + ret = a6xx_gpu_boot(adreno_dev); + if (ret) + return; + + kgsl_pwrscale_wake(device); + + set_bit(RGMU_PRIV_GPU_STARTED, &rgmu->flags); + + device->state = KGSL_STATE_ACTIVE; + +done: + /* + * When waking up from a touch event we want to stay active long enough + * for the user to send a draw command. The default idle timer timeout + * is shorter than we want so go ahead and push the idle timer out + * further for this special case + */ + mod_timer(&device->idle_timer, jiffies + + msecs_to_jiffies(adreno_wake_timeout)); + +} + static int a6xx_first_boot(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); @@ -1204,6 +1243,7 @@ const struct adreno_power_ops a6xx_rgmu_power_ops = { .active_count_put = a6xx_rgmu_active_count_put, .pm_suspend = a6xx_rgmu_pm_suspend, .pm_resume = a6xx_rgmu_pm_resume, + .touch_wakeup = a6xx_rgmu_touch_wakeup, }; int a6xx_rgmu_device_probe(struct platform_device *pdev, From d7784ea62c6a54e70d9355f9ee8ae219cc11a563 Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Fri, 24 Apr 2020 14:25:03 -0600 Subject: [PATCH 23/30] msm: kgsl: Add target specific clock and bus scaling This allows us to define target specific clock and bus scaling functions. Also, get rid of the dcvs_set function pointer from gmu core ops. Change-Id: I137ea0071958bfdd73a266d734e278703f0dc722 Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/adreno-gpulist.h | 12 +++---- drivers/gpu/msm/adreno.c | 52 ++++++++++++++++++++++++++++++ drivers/gpu/msm/adreno.h | 6 ++++ drivers/gpu/msm/adreno_a6xx.c | 35 ++++++++++++++++++++ drivers/gpu/msm/adreno_a6xx.h | 1 + drivers/gpu/msm/adreno_a6xx_gmu.c | 33 +++++++++++++------ drivers/gpu/msm/adreno_a6xx_rgmu.c | 10 +++--- drivers/gpu/msm/kgsl_bus.c | 22 +------------ drivers/gpu/msm/kgsl_device.h | 4 +++ drivers/gpu/msm/kgsl_gmu_core.c | 11 ------- drivers/gpu/msm/kgsl_gmu_core.h | 4 --- drivers/gpu/msm/kgsl_pwrctrl.c | 40 ++++------------------- drivers/gpu/msm/kgsl_pwrctrl.h | 5 +-- 13 files changed, 143 insertions(+), 92 deletions(-) diff --git a/drivers/gpu/msm/adreno-gpulist.h b/drivers/gpu/msm/adreno-gpulist.h index 9a0c401a8934..fac59f07fd03 100644 --- a/drivers/gpu/msm/adreno-gpulist.h +++ b/drivers/gpu/msm/adreno-gpulist.h @@ -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_gmu_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_gmu_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_gmu_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_gmu_gpudev, + .gpudev = &adreno_a630_gpudev, .gmem_size = SZ_512K, .bus_width = 32, }, @@ -1080,7 +1080,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_gmu_gpudev, + .gpudev = &adreno_a630_gpudev, .gmem_base = 0, .gmem_size = SZ_512K, .bus_width = 32, @@ -1407,7 +1407,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_gmu_gpudev, + .gpudev = &adreno_a630_gpudev, .gmem_base = 0x100000, .gmem_size = SZ_512K, .bus_width = 32, diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index e290c41dcf9f..c06c799503de 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -3799,6 +3800,55 @@ int adreno_power_cycle_u32(struct adreno_device *adreno_dev, return ret; } +static int adreno_gpu_clock_set(struct kgsl_device *device, u32 pwrlevel) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + const struct adreno_power_ops *ops = ADRENO_POWER_OPS(adreno_dev); + struct kgsl_pwrctrl *pwr = &device->pwrctrl; + struct kgsl_pwrlevel *pl = &pwr->pwrlevels[pwrlevel]; + int ret; + + if (ops->gpu_clock_set) + return ops->gpu_clock_set(adreno_dev, pwrlevel); + + ret = clk_set_rate(pwr->grp_clks[0], pl->gpu_freq); + if (ret) + dev_err(device->dev, "GPU clk freq set failure: %d\n", ret); + + return ret; +} + +static int adreno_interconnect_bus_set(struct adreno_device *adreno_dev, + int level, u32 ab) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + 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 int adreno_gpu_bus_set(struct kgsl_device *device, int level, u32 ab) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + const struct adreno_power_ops *ops = ADRENO_POWER_OPS(adreno_dev); + + if (ops->gpu_bus_set) + return ops->gpu_bus_set(adreno_dev, level, ab); + + return adreno_interconnect_bus_set(adreno_dev, level, ab); +} + static const struct kgsl_functable adreno_functable = { /* Mandatory functions */ .regread = adreno_regread, @@ -3842,6 +3892,8 @@ static const struct kgsl_functable adreno_functable = { .stop_fault_timer = adreno_dispatcher_stop_fault_timer, .query_property_list = adreno_query_property_list, .is_hwcg_on = adreno_is_hwcg_on, + .gpu_clock_set = adreno_gpu_clock_set, + .gpu_bus_set = adreno_gpu_bus_set, }; static const struct component_master_ops adreno_ops = { diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 090a6ca7c26c..7815a947d4d9 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -361,6 +361,11 @@ struct adreno_power_ops { * @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); }; /** @@ -911,6 +916,7 @@ 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; diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index 58ed94ab6eef..3b7d0300a79f 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -2747,3 +2747,38 @@ struct adreno_gpudev adreno_a6xx_rgmu_gpudev = { .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_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, +}; diff --git a/drivers/gpu/msm/adreno_a6xx.h b/drivers/gpu/msm/adreno_a6xx.h index 3de5b699ce9c..40e0b222cdd6 100644 --- a/drivers/gpu/msm/adreno_a6xx.h +++ b/drivers/gpu/msm/adreno_a6xx.h @@ -15,6 +15,7 @@ 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 diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index 7a2e94d75dbd..7a633cdc478c 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -18,6 +18,7 @@ #include "adreno.h" #include "adreno_a6xx.h" +#include "kgsl_bus.h" #include "kgsl_device.h" #include "kgsl_trace.h" #include "kgsl_util.h" @@ -1669,10 +1670,10 @@ static void a6xx_gmu_suspend(struct adreno_device *adreno_dev) gmu->fault = false; } -static int a6xx_gmu_dcvs_set(struct kgsl_device *device, +static int a6xx_gmu_dcvs_set(struct adreno_device *adreno_dev, int gpu_pwrlevel, int bus_level) { - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); struct hfi_dcvstable_cmd *table = &gmu->hfi.dcvs_table; @@ -1728,6 +1729,11 @@ static int a6xx_gmu_dcvs_set(struct kgsl_device *device, return ret; } +static int a6xx_gmu_clock_set(struct adreno_device *adreno_dev, u32 pwrlevel) +{ + return a6xx_gmu_dcvs_set(adreno_dev, pwrlevel, INVALID_DCVS_IDX); +} + static int a6xx_gmu_ifpc_store(struct kgsl_device *device, unsigned int val) { @@ -2238,19 +2244,19 @@ static struct gmu_dev_ops a6xx_gmudev = { }; static struct gmu_core_ops a6xx_gmu_ops = { - .dcvs_set = a6xx_gmu_dcvs_set, .snapshot = a6xx_gmu_snapshot, .acd_set = a6xx_gmu_acd_set, }; -static int a6xx_gmu_bus_set(struct kgsl_device *device, int buslevel, +static int a6xx_gmu_bus_set(struct adreno_device *adreno_dev, int buslevel, u32 ab) { + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct kgsl_pwrctrl *pwr = &device->pwrctrl; int ret = 0; if (buslevel != pwr->cur_buslevel) { - ret = a6xx_gmu_dcvs_set(device, INVALID_DCVS_IDX, buslevel); + ret = a6xx_gmu_dcvs_set(adreno_dev, INVALID_DCVS_IDX, buslevel); if (ret) return ret; @@ -2528,7 +2534,6 @@ static int a6xx_gmu_probe(struct kgsl_device *device, { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); - struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct a6xx_hfi *hfi = &gmu->hfi; int ret; @@ -2603,9 +2608,6 @@ static int a6xx_gmu_probe(struct kgsl_device *device, disable_irq(gmu->irq); disable_irq(gmu->hfi.irq); - if (a6xx_gmu_scales_bandwidth(device)) - pwr->bus_set = a6xx_gmu_bus_set; - return 0; error: @@ -3159,6 +3161,19 @@ const struct adreno_power_ops a6xx_gmu_power_ops = { .pm_suspend = a6xx_gmu_pm_suspend, .pm_resume = a6xx_gmu_pm_resume, .touch_wakeup = a6xx_gmu_touch_wakeup, + .gpu_clock_set = a6xx_gmu_clock_set, + .gpu_bus_set = a6xx_gmu_bus_set, +}; + +const struct adreno_power_ops a630_gmu_power_ops = { + .first_open = a6xx_gmu_first_open, + .last_close = a6xx_gmu_last_close, + .active_count_get = a6xx_gmu_active_count_get, + .active_count_put = a6xx_gmu_active_count_put, + .pm_suspend = a6xx_gmu_pm_suspend, + .pm_resume = a6xx_gmu_pm_resume, + .touch_wakeup = a6xx_gmu_touch_wakeup, + .gpu_clock_set = a6xx_gmu_clock_set, }; int a6xx_gmu_device_probe(struct platform_device *pdev, diff --git a/drivers/gpu/msm/adreno_a6xx_rgmu.c b/drivers/gpu/msm/adreno_a6xx_rgmu.c index 8969c6dda4a6..57ff909fca28 100644 --- a/drivers/gpu/msm/adreno_a6xx_rgmu.c +++ b/drivers/gpu/msm/adreno_a6xx_rgmu.c @@ -17,6 +17,7 @@ #include "adreno_a6xx.h" #include "adreno_a6xx_rgmu.h" #include "adreno_snapshot.h" +#include "kgsl_bus.h" #include "kgsl_trace.h" #include "kgsl_util.h" @@ -706,10 +707,11 @@ static void a6xx_rgmu_power_off(struct adreno_device *adreno_dev) } -static int a6xx_rgmu_dcvs_set(struct kgsl_device *device, - int pwrlevel, int bus_level) +static int a6xx_rgmu_clock_set(struct adreno_device *adreno_dev, + u32 pwrlevel) { - struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(ADRENO_DEVICE(device)); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev); int ret; unsigned long rate; @@ -1161,7 +1163,6 @@ static struct gmu_dev_ops a6xx_rgmudev = { }; static struct gmu_core_ops a6xx_rgmu_ops = { - .dcvs_set = a6xx_rgmu_dcvs_set, .snapshot = a6xx_rgmu_snapshot, }; @@ -1244,6 +1245,7 @@ const struct adreno_power_ops a6xx_rgmu_power_ops = { .pm_suspend = a6xx_rgmu_pm_suspend, .pm_resume = a6xx_rgmu_pm_resume, .touch_wakeup = a6xx_rgmu_touch_wakeup, + .gpu_clock_set = a6xx_rgmu_clock_set, }; int a6xx_rgmu_device_probe(struct platform_device *pdev, diff --git a/drivers/gpu/msm/kgsl_bus.c b/drivers/gpu/msm/kgsl_bus.c index 94dd5d68011f..d0638e924ff5 100644 --- a/drivers/gpu/msm/kgsl_bus.c +++ b/drivers/gpu/msm/kgsl_bus.c @@ -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) @@ -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); + device->ftbl->gpu_bus_set(device, buslevel, ab); } static void validate_pwrlevels(struct kgsl_device *device, u32 *ibs, @@ -176,8 +158,6 @@ done: return PTR_ERR(pwr->icc_path); } - pwr->bus_set = interconnect_bus_set; - return 0; } diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index 861c7ca59989..fcd04b53b3a1 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -168,6 +168,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 { diff --git a/drivers/gpu/msm/kgsl_gmu_core.c b/drivers/gpu/msm/kgsl_gmu_core.c index 2e2f0e152d4a..17336ba630a6 100644 --- a/drivers/gpu/msm/kgsl_gmu_core.c +++ b/drivers/gpu/msm/kgsl_gmu_core.c @@ -110,17 +110,6 @@ void gmu_core_snapshot(struct kgsl_device *device) 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); diff --git a/drivers/gpu/msm/kgsl_gmu_core.h b/drivers/gpu/msm/kgsl_gmu_core.h index eed413a082b8..092d8e7d1e13 100644 --- a/drivers/gpu/msm/kgsl_gmu_core.h +++ b/drivers/gpu/msm/kgsl_gmu_core.h @@ -101,8 +101,6 @@ 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); @@ -176,8 +174,6 @@ 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_is_register_offset(struct kgsl_device *device, unsigned int offsetwords); diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index ed7e68a6f8a1..176fdcbcac6e 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -100,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 @@ -232,7 +205,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, @@ -1215,7 +1188,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); @@ -1228,7 +1201,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); @@ -1242,7 +1215,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); @@ -1532,7 +1505,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) @@ -2196,5 +2170,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); } diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h index 2238cfc5b3d8..a51e790240b5 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.h +++ b/drivers/gpu/msm/kgsl_pwrctrl.h @@ -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); From 1b6b3732fc61f851f96aa530bbb841d5d4183371 Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Sat, 25 Apr 2020 17:11:09 -0600 Subject: [PATCH 24/30] msm: kgsl: Make kgsl_pwrctrl_axi return a value On gmu targets, we may fail the boot bandwidth hfi, so return the error all the way up. Change-Id: I059fb18090ae6cb33af3c0b53f2a8fd5875b7e52 Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/adreno_a6xx_hfi.c | 2 +- drivers/gpu/msm/adreno_a6xx_rgmu.c | 4 +++- drivers/gpu/msm/kgsl_bus.c | 6 +++--- drivers/gpu/msm/kgsl_bus.h | 4 ++-- drivers/gpu/msm/kgsl_pwrctrl.c | 10 ++++++---- drivers/gpu/msm/kgsl_pwrctrl.h | 4 +++- 6 files changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/msm/adreno_a6xx_hfi.c b/drivers/gpu/msm/adreno_a6xx_hfi.c index 5e92cdcfcee9..0ee0b08d0b89 100644 --- a/drivers/gpu/msm/adreno_a6xx_hfi.c +++ b/drivers/gpu/msm/adreno_a6xx_hfi.c @@ -747,7 +747,7 @@ int a6xx_hfi_start(struct adreno_device *adreno_dev) goto err; /* Request default BW vote */ - kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON); + result = kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON); err: if (result) diff --git a/drivers/gpu/msm/adreno_a6xx_rgmu.c b/drivers/gpu/msm/adreno_a6xx_rgmu.c index 57ff909fca28..5e6adc6fbdf2 100644 --- a/drivers/gpu/msm/adreno_a6xx_rgmu.c +++ b/drivers/gpu/msm/adreno_a6xx_rgmu.c @@ -815,7 +815,9 @@ static int a6xx_rgmu_boot(struct adreno_device *adreno_dev) if (ret) goto err; - kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON); + ret = kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON); + if (ret) + goto err; rgmu->fault = false; diff --git a/drivers/gpu/msm/kgsl_bus.c b/drivers/gpu/msm/kgsl_bus.c index d0638e924ff5..648c81152d0b 100644 --- a/drivers/gpu/msm/kgsl_bus.c +++ b/drivers/gpu/msm/kgsl_bus.c @@ -31,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? */ @@ -41,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. @@ -60,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]); - device->ftbl->gpu_bus_set(device, buslevel, ab); + return device->ftbl->gpu_bus_set(device, buslevel, ab); } static void validate_pwrlevels(struct kgsl_device *device, u32 *ibs, diff --git a/drivers/gpu/msm/kgsl_bus.h b/drivers/gpu/msm/kgsl_bus.h index 2329cce8000b..8fd6d6d8ef08 100644 --- a/drivers/gpu/msm/kgsl_bus.h +++ b/drivers/gpu/msm/kgsl_bus.h @@ -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); diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index 176fdcbcac6e..fd03cecdabe4 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -1248,26 +1248,28 @@ static void kgsl_pwrctrl_clk(struct kgsl_device *device, int state, } } -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, diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h index a51e790240b5..483ab3464576 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.h +++ b/drivers/gpu/msm/kgsl_pwrctrl.h @@ -214,8 +214,10 @@ void kgsl_pwrctrl_request_state(struct kgsl_device *device, u32 state); * * 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 */ -void kgsl_pwrctrl_axi(struct kgsl_device *device, int state); +int kgsl_pwrctrl_axi(struct kgsl_device *device, int state); /** * kgsl_idle_check - kgsl idle function From 97a10b913383c8f2d3bb588d6d5b959fa807bcbf Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Sat, 25 Apr 2020 17:26:28 -0600 Subject: [PATCH 25/30] msm: kgsl: Do inline gmu and rgmu snapshot This helps in ultimately getting rid of gmu_core_snapshot. Change-Id: Ie72f851ddec6ddb70d3dfa763b6c638c2f0f8775 Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/adreno.h | 1 - drivers/gpu/msm/adreno_a6xx_gmu.c | 6 +++++- drivers/gpu/msm/adreno_a6xx_gmu.h | 7 ++++++- drivers/gpu/msm/adreno_a6xx_hfi.c | 26 +++++++++++++++++--------- drivers/gpu/msm/adreno_a6xx_rgmu.c | 5 +++++ 5 files changed, 33 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 7815a947d4d9..85b4aa908688 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -1644,7 +1644,6 @@ static inline int adreno_perfcntr_active_oob_get( if (!ret) { ret = gmu_core_dev_oob_set(device, oob_perfcntr); if (ret) { - gmu_core_snapshot(device); adreno_set_gpu_fault(adreno_dev, ADRENO_GMU_FAULT_SKIP_SNAPSHOT); adreno_dispatcher_schedule(device); diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index 7a633cdc478c..a8b4d63302d7 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -444,6 +444,7 @@ static int a6xx_gmu_device_start(struct adreno_device *adreno_dev) A6XX_GMU_CM3_DTCM_START + (0x3fdc >> 2), &val); dev_err(&gmu->pdev->dev, "GMU doesn't boot: 0x%x\n", val); + a6xx_gmu_snapshot(device); return -ETIMEDOUT; } @@ -467,6 +468,7 @@ static int a6xx_gmu_hfi_start(struct adreno_device *adreno_dev) GMU_START_TIMEOUT, BIT(0))) { dev_err(&gmu->pdev->dev, "GMU HFI init failed\n"); + a6xx_gmu_snapshot(device); return -ETIMEDOUT; } @@ -743,6 +745,7 @@ static int a6xx_gmu_oob_set(struct kgsl_device *device, if (timed_poll_check(device, A6XX_GMU_GMU2HOST_INTR_INFO, check, GPU_START_TIMEOUT, check)) { ret = -ETIMEDOUT; + a6xx_gmu_snapshot(device); WARN(1, "OOB request %s timed out\n", oob_to_str(req)); } @@ -897,6 +900,7 @@ int a6xx_gmu_sptprac_enable(struct adreno_device *adreno_dev) SPTPRAC_CTRL_TIMEOUT, SPTPRAC_POWERON_STATUS_MASK)) { dev_err(&gmu->pdev->dev, "power on SPTPRAC fail\n"); + a6xx_gmu_snapshot(device); return -ETIMEDOUT; } @@ -1926,7 +1930,7 @@ static irqreturn_t a6xx_gmu_irq_handler(int irq, void *data) } -static void a6xx_gmu_snapshot(struct kgsl_device *device) +void a6xx_gmu_snapshot(struct kgsl_device *device) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.h b/drivers/gpu/msm/adreno_a6xx_gmu.h index 2e7ca929b1d2..9a0db32a19f8 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.h +++ b/drivers/gpu/msm/adreno_a6xx_gmu.h @@ -287,5 +287,10 @@ void a6xx_enable_gpu_irq(struct adreno_device *adreno_dev); */ void a6xx_disable_gpu_irq(struct adreno_device *adreno_dev); - +/** + * a6xx_gmu_snapshot - Send nmi to gmu and take snapshot + * @device: Pointer to the kgsl device + * + */ +void a6xx_gmu_snapshot(struct kgsl_device *device); #endif diff --git a/drivers/gpu/msm/adreno_a6xx_hfi.c b/drivers/gpu/msm/adreno_a6xx_hfi.c index 0ee0b08d0b89..de5fa2630801 100644 --- a/drivers/gpu/msm/adreno_a6xx_hfi.c +++ b/drivers/gpu/msm/adreno_a6xx_hfi.c @@ -40,7 +40,7 @@ struct hfi_queue_table { #define MSG_HDR_GET_TYPE(hdr) (((hdr) >> 16) & 0xF) #define MSG_HDR_GET_SEQNUM(hdr) (((hdr) >> 20) & 0xFFF) -static void a6xx_hfi_process_queue(struct a6xx_gmu_device *gmu, +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 */ @@ -241,7 +241,7 @@ int a6xx_hfi_init(struct adreno_device *adreno_dev) #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 a6xx_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); @@ -250,7 +250,7 @@ static void receive_ack_cmd(struct a6xx_gmu_device *gmu, void *rcvd, uint32_t req_hdr = ack[1]; if (ret_cmd == NULL) - return; + return -EINVAL; trace_kgsl_hfi_receive(MSG_HDR_GET_ID(req_hdr), MSG_HDR_GET_SIZE(req_hdr), @@ -258,7 +258,7 @@ static void receive_ack_cmd(struct a6xx_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 */ @@ -266,8 +266,9 @@ static void receive_ack_cmd(struct a6xx_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_dev, ADRENO_GMU_FAULT); - adreno_dispatcher_schedule(KGSL_DEVICE(adreno_dev)); + a6xx_gmu_snapshot(KGSL_DEVICE(adreno_dev)); + + return -ENODEV; } #define MSG_HDR_SET_SEQNUM(hdr, num) \ @@ -328,6 +329,7 @@ static int a6xx_hfi_send_cmd(struct adreno_device *adreno_dev, HFI_IRQ_MSGQ_MASK, HFI_IRQ_MSGQ_MASK, HFI_RSP_TIMEOUT); if (rc) { + a6xx_gmu_snapshot(KGSL_DEVICE(adreno_dev)); 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)); @@ -338,7 +340,7 @@ static int a6xx_hfi_send_cmd(struct adreno_device *adreno_dev, adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_GMU2HOST_INTR_CLR, HFI_IRQ_MSGQ_MASK); - a6xx_hfi_process_queue(gmu, HFI_MSG_ID, ret_cmd); + rc = a6xx_hfi_process_queue(gmu, HFI_MSG_ID, ret_cmd); return rc; } @@ -358,6 +360,7 @@ static int a6xx_hfi_send_generic_req(struct adreno_device *adreno_dev, if (!rc && ret_cmd.results[2] == HFI_ACK_ERROR) { struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + a6xx_gmu_snapshot(KGSL_DEVICE(adreno_dev)); dev_err(&gmu->pdev->dev, "HFI ACK failure: Req 0x%8.8X\n", ret_cmd.results[1]); return -EINVAL; @@ -550,7 +553,7 @@ static void a6xx_hfi_v1_receiver(struct a6xx_gmu_device *gmu, uint32_t *rcvd, } } -static void a6xx_hfi_process_queue(struct a6xx_gmu_device *gmu, +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]; @@ -564,7 +567,10 @@ static void a6xx_hfi_process_queue(struct a6xx_gmu_device *gmu, /* 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; } @@ -583,6 +589,8 @@ static void a6xx_hfi_process_queue(struct a6xx_gmu_device *gmu, break; } } + + return 0; } static int a6xx_hfi_verify_fw_version(struct adreno_device *adreno_dev) diff --git a/drivers/gpu/msm/adreno_a6xx_rgmu.c b/drivers/gpu/msm/adreno_a6xx_rgmu.c index 5e6adc6fbdf2..6c1488da3507 100644 --- a/drivers/gpu/msm/adreno_a6xx_rgmu.c +++ b/drivers/gpu/msm/adreno_a6xx_rgmu.c @@ -42,6 +42,8 @@ static const unsigned int a6xx_rgmu_registers[] = { 0x26000, 0x26002, }; +static void a6xx_rgmu_snapshot(struct kgsl_device *device); + static struct a6xx_rgmu_device *to_a6xx_rgmu(struct adreno_device *adreno_dev) { struct a6xx_device *a6xx_dev = container_of(adreno_dev, @@ -165,6 +167,7 @@ static int a6xx_rgmu_oob_set(struct kgsl_device *device, dev_err(&rgmu->pdev->dev, "Timed out while setting OOB req:%s status:0x%x\n", oob_to_str(req), status); + a6xx_rgmu_snapshot(device); return ret; } @@ -353,6 +356,7 @@ static int a6xx_rgmu_wait_for_lowest_idle(struct adreno_device *adreno_dev) reg[7], reg[8], reg[9]); WARN_ON(1); + a6xx_rgmu_snapshot(device); return -ETIMEDOUT; } @@ -436,6 +440,7 @@ static int a6xx_rgmu_fw_start(struct adreno_device *adreno_dev, gmu_core_regread(device, A6XX_RGMU_CX_PCC_DEBUG, &status); dev_err(&rgmu->pdev->dev, "rgmu boot Failed. status:%08x\n", status); + a6xx_rgmu_snapshot(device); return -ETIMEDOUT; } From d2645d62058044522481bf226962d020752223dd Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Sat, 25 Apr 2020 14:40:34 -0600 Subject: [PATCH 26/30] msm: kgsl: Move gmu_fault from snapshot structure Add gmu_fault member to kgsl device structure and remove it from snapshot, a6xx gmu and rgmu structures. This helps in removing snapshot function from the gmu core ops in the next patch. Change-Id: I5f2aba879ebf0330ef2c73d1d2fa4a2032bb6c9b Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/adreno_a6xx_gmu.c | 17 ++++++++--------- drivers/gpu/msm/adreno_a6xx_gmu.h | 2 -- drivers/gpu/msm/adreno_a6xx_rgmu.c | 10 ++++------ drivers/gpu/msm/adreno_a6xx_rgmu.h | 2 -- drivers/gpu/msm/kgsl_device.h | 4 ++-- drivers/gpu/msm/kgsl_snapshot.c | 3 +-- 6 files changed, 15 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index a8b4d63302d7..d0e6b03fa22a 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -1670,8 +1670,6 @@ static void a6xx_gmu_suspend(struct adreno_device *adreno_dev) regulator_set_mode(gmu->cx_gdsc, REGULATOR_MODE_NORMAL); dev_err(&gmu->pdev->dev, "Suspended GMU\n"); - - gmu->fault = false; } static int a6xx_gmu_dcvs_set(struct adreno_device *adreno_dev, @@ -1936,7 +1934,7 @@ void a6xx_gmu_snapshot(struct kgsl_device *device) struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); /* Abstain from sending another nmi or over-writing snapshot */ - if (gmu->fault) + if (device->gmu_fault) return; /* make sure we're reading the latest cm3_fault */ @@ -1961,7 +1959,7 @@ void a6xx_gmu_snapshot(struct kgsl_device *device) gmu_core_regwrite(device, A6XX_GMU_GMU2HOST_INTR_MASK, HFI_IRQ_MASK); - gmu->fault = true; + device->gmu_fault = true; } @@ -2108,12 +2106,12 @@ static int a6xx_gmu_first_boot(struct adreno_device *adreno_dev) icc_set_bw(pwr->icc_path, 0, 0); - gmu->fault = false; + device->gmu_fault = false; return 0; err: - if (gmu->fault) { + if (device->gmu_fault) { a6xx_gmu_suspend(adreno_dev); return ret; } @@ -2181,12 +2179,12 @@ static int a6xx_gmu_boot(struct adreno_device *adreno_dev) if (ret) goto err; - gmu->fault = false; + device->gmu_fault = false; return 0; err: - if (gmu->fault) { + if (device->gmu_fault) { a6xx_gmu_suspend(adreno_dev); return ret; } @@ -2669,9 +2667,10 @@ static int halt_gbif(struct adreno_device *adreno_dev) static int a6xx_gmu_power_off(struct adreno_device *adreno_dev) { struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); int ret = 0; - if (gmu->fault) + if (device->gmu_fault) goto error; /* Wait for the lowest idle level we requested */ diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.h b/drivers/gpu/msm/adreno_a6xx_gmu.h index 9a0db32a19f8..2ec6cc30ff08 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.h +++ b/drivers/gpu/msm/adreno_a6xx_gmu.h @@ -201,8 +201,6 @@ struct a6xx_gmu_device { void *itcm_shadow; /** @flags: Internal gmu flags */ unsigned long flags; - /** @fault: To track if we hit a gmu fault */ - bool fault; }; /* Helper function to get to a6xx gmu device from adreno device */ diff --git a/drivers/gpu/msm/adreno_a6xx_rgmu.c b/drivers/gpu/msm/adreno_a6xx_rgmu.c index 6c1488da3507..3d082cca5382 100644 --- a/drivers/gpu/msm/adreno_a6xx_rgmu.c +++ b/drivers/gpu/msm/adreno_a6xx_rgmu.c @@ -515,7 +515,7 @@ static void a6xx_rgmu_snapshot(struct kgsl_device *device) struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev); - if (rgmu->fault) + if (device->gmu_fault) return; /* Mask so there's no interrupt caused by NMI */ @@ -538,7 +538,7 @@ static void a6xx_rgmu_snapshot(struct kgsl_device *device) rgmu->fault_count++; - rgmu->fault = true; + device->gmu_fault = true; } static void a6xx_rgmu_suspend(struct adreno_device *adreno_dev) @@ -687,13 +687,12 @@ static void halt_gbif_arb(struct adreno_device *adreno_dev) /* Caller shall ensure GPU is ready for SLUMBER */ static void a6xx_rgmu_power_off(struct adreno_device *adreno_dev) { - struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev); struct kgsl_device *device = KGSL_DEVICE(adreno_dev); int ret; kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_OFF); - if (rgmu->fault) + if (device->gmu_fault) return a6xx_rgmu_suspend(adreno_dev); /* Wait for the lowest idle level we requested */ @@ -795,7 +794,6 @@ err: static int a6xx_rgmu_boot(struct adreno_device *adreno_dev) { - struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev); struct kgsl_device *device = KGSL_DEVICE(adreno_dev); int ret; @@ -824,7 +822,7 @@ static int a6xx_rgmu_boot(struct adreno_device *adreno_dev) if (ret) goto err; - rgmu->fault = false; + device->gmu_fault = false; return 0; diff --git a/drivers/gpu/msm/adreno_a6xx_rgmu.h b/drivers/gpu/msm/adreno_a6xx_rgmu.h index f59c4de09dfd..017e487cd9b3 100644 --- a/drivers/gpu/msm/adreno_a6xx_rgmu.h +++ b/drivers/gpu/msm/adreno_a6xx_rgmu.h @@ -56,8 +56,6 @@ struct a6xx_rgmu_device { struct clk *rgmu_clk; unsigned int idle_level; unsigned int fault_count; - /** @fault: to track whether we encountered a rgmu fault */ - bool fault; /** @flags: rgmu internal flags */ unsigned long flags; }; diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index fcd04b53b3a1..c401aa047cbb 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -320,6 +320,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) \ @@ -485,7 +487,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 { @@ -509,7 +510,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; }; diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c index d12564a9ec76..06f63a85561e 100644 --- a/drivers/gpu/msm/kgsl_snapshot.c +++ b/drivers/gpu/msm/kgsl_snapshot.c @@ -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); From efa44eb2e60c5640bb0f7831e2b2d49f83af9739 Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Thu, 23 Apr 2020 12:18:35 -0600 Subject: [PATCH 27/30] msm: kgsl: Pare down the gmu core and dev ops Remove the ones that we don't need anymore. Also, remove KGSL_STATE_RESET as it was only needed with gmu recovery, which now is completely target specific. Also, remove unused adreno gmu register defines. Change-Id: I20b8bc04714e30cd7418d81e8634e4c5079fa175 Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/adreno.c | 158 ++++------------------------- drivers/gpu/msm/adreno.h | 17 ---- drivers/gpu/msm/adreno_a6xx.c | 28 ----- drivers/gpu/msm/adreno_a6xx_gmu.c | 26 +++-- drivers/gpu/msm/adreno_a6xx_hfi.c | 31 +++--- drivers/gpu/msm/adreno_a6xx_rgmu.c | 18 +++- drivers/gpu/msm/kgsl_device.h | 1 - drivers/gpu/msm/kgsl_gmu_core.c | 76 -------------- drivers/gpu/msm/kgsl_gmu_core.h | 25 ----- drivers/gpu/msm/kgsl_pwrctrl.c | 62 +---------- 10 files changed, 66 insertions(+), 376 deletions(-) diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index c06c799503de..8e01c1c20224 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -1646,28 +1646,26 @@ int adreno_clear_pending_transactions(struct kgsl_device *device) if (adreno_has_gbif(adreno_dev)) { - /* This is taken care by GMU firmware if GMU is enabled */ - if (!gmu_core_gpmu_isenabled(device)) { - /* Halt GBIF GX traffic and poll for halt ack */ - if (adreno_is_a615_family(adreno_dev)) { - adreno_writereg(adreno_dev, - ADRENO_REG_RBBM_GPR0_CNTL, - GBIF_HALT_REQUEST); - ret = adreno_wait_for_halt_ack(device, - A6XX_RBBM_VBIF_GX_RESET_STATUS, - VBIF_RESET_ACK_MASK); - } else { - adreno_writereg(adreno_dev, - ADRENO_REG_RBBM_GBIF_HALT, - gpudev->gbif_gx_halt_mask); - ret = adreno_wait_for_halt_ack(device, - ADRENO_REG_RBBM_GBIF_HALT_ACK, - gpudev->gbif_gx_halt_mask); - } - if (ret) - return ret; + /* Halt GBIF GX traffic and poll for halt ack */ + if (adreno_is_a615_family(adreno_dev)) { + adreno_writereg(adreno_dev, + ADRENO_REG_RBBM_GPR0_CNTL, + GBIF_HALT_REQUEST); + ret = adreno_wait_for_halt_ack(device, + A6XX_RBBM_VBIF_GX_RESET_STATUS, + VBIF_RESET_ACK_MASK); + } else { + adreno_writereg(adreno_dev, + ADRENO_REG_RBBM_GBIF_HALT, + gpudev->gbif_gx_halt_mask); + ret = adreno_wait_for_halt_ack(device, + ADRENO_REG_RBBM_GBIF_HALT_ACK, + gpudev->gbif_gx_halt_mask); } + if (ret) + return ret; + /* Halt new client requests */ adreno_writereg(adreno_dev, ADRENO_REG_GBIF_HALT, gpudev->gbif_client_halt_mask); @@ -1734,10 +1732,6 @@ static int adreno_init(struct kgsl_device *device) return ret; } - ret = gmu_core_init(device); - if (ret) - return ret; - /* Put the GPU in a responsive state */ if (ADRENO_GPUREV(adreno_dev) < 600) { /* No need for newer generation architectures */ @@ -2120,20 +2114,7 @@ static int _adreno_start(struct adreno_device *adreno_dev) status = kgsl_mmu_start(device); if (status) - goto error_boot_oob_clear; - - /* Send OOB request to turn on the GX */ - status = gmu_core_dev_oob_set(device, oob_gpu); - if (status) { - gmu_core_snapshot(device); - goto error_oob_clear; - } - - status = gmu_core_dev_hfi_start_msg(device); - if (status) { - gmu_core_snapshot(device); - goto error_oob_clear; - } + goto error_pwr_off; adreno_get_bus_counters(adreno_dev); @@ -2157,7 +2138,7 @@ static int _adreno_start(struct adreno_device *adreno_dev) status = gpudev->rb_start(adreno_dev); if (status) - goto error_oob_clear; + goto error_pwr_off; /* * At this point it is safe to assume that we recovered. Setting @@ -2174,22 +2155,8 @@ static int _adreno_start(struct adreno_device *adreno_dev) set_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv); - /* Send OOB request to allow IFPC */ - gmu_core_dev_oob_clear(device, oob_gpu); - - /* If we made it this far, the BOOT OOB was sent to the GMU */ - if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) - gmu_core_dev_oob_clear(device, oob_boot_slumber); - return 0; -error_oob_clear: - gmu_core_dev_oob_clear(device, oob_gpu); - -error_boot_oob_clear: - if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) - gmu_core_dev_oob_clear(device, oob_boot_slumber); - error_pwr_off: /* set the state back to original state */ kgsl_pwrctrl_change_state(device, state); @@ -2231,14 +2198,6 @@ static int adreno_stop(struct kgsl_device *device) if (!test_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv)) return 0; - error = gmu_core_dev_oob_set(device, oob_gpu); - if (error) { - gmu_core_dev_oob_clear(device, oob_gpu); - gmu_core_snapshot(device); - error = -EINVAL; - goto no_gx_power; - } - kgsl_pwrscale_update_stats(device); adreno_irqctrl(adreno_dev, 0); @@ -2249,24 +2208,8 @@ static int adreno_stop(struct kgsl_device *device) /* Save physical performance counter values before GPU power down*/ adreno_perfcounter_save(adreno_dev); - gmu_core_dev_prepare_stop(device); - gmu_core_dev_oob_clear(device, oob_gpu); - - /* - * Saving perfcounters will use an OOB to put the GMU into - * active state. Before continuing, we should wait for the - * GMU to return to the lowest idle level. This is - * because some idle level transitions require VBIF and MMU. - */ - - if (!error && gmu_core_dev_wait_for_lowest_idle(device)) { - gmu_core_snapshot(device); - error = -EINVAL; - } - adreno_clear_pending_transactions(device); -no_gx_power: adreno_dispatcher_stop(adreno_dev); adreno_ringbuffer_stop(adreno_dev); @@ -2277,16 +2220,6 @@ no_gx_power: if (!IS_ERR_OR_NULL(adreno_dev->gpuhtw_llc_slice)) llcc_slice_deactivate(adreno_dev->gpuhtw_llc_slice); - /* - * The halt is not cleared in the above function if we have GBIF. - * Clear it here if GMU is enabled as GMU stop needs access to - * system memory to stop. For non-GMU targets, we don't need to - * clear it as it will get cleared automatically once headswitch - * goes OFF immediately after adreno_stop. - */ - if (gmu_core_gpmu_isenabled(device)) - adreno_deassert_gbif_halt(adreno_dev); - adreno_set_active_ctxs_null(adreno_dev); clear_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv); @@ -2887,15 +2820,7 @@ void adreno_spin_idle_debug(struct adreno_device *adreno_dev, dev_err(device->dev, " hwfault=%8.8X\n", hwfault); - /* - * If CP is stuck, gmu may not perform as expected. So force a gmu - * snapshot which captures entire state as well as sets the gmu fault - * because things need to be reset anyway. - */ - if (gmu_core_isenabled(device)) - gmu_core_snapshot(device); - else - kgsl_device_snapshot(device, NULL, false); + kgsl_device_snapshot(device, NULL, false); } /** @@ -3090,47 +3015,6 @@ static void adreno_regwrite(struct kgsl_device *device, __raw_writel(value, reg); } -/** - * adreno_gmu_clear_and_unmask_irqs() - Clear pending IRQs and Unmask IRQs - * @adreno_dev: Pointer to the Adreno device that owns the GMU - */ -void adreno_gmu_clear_and_unmask_irqs(struct adreno_device *adreno_dev) -{ - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct gmu_dev_ops *gmu_dev_ops = GMU_DEVICE_OPS(device); - - /* Clear any pending IRQs before unmasking on GMU */ - adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_GMU2HOST_INTR_CLR, - 0xFFFFFFFF); - adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_AO_HOST_INTERRUPT_CLR, - 0xFFFFFFFF); - - /* Unmask needed IRQs on GMU */ - adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_GMU2HOST_INTR_MASK, - (unsigned int) ~(gmu_dev_ops->gmu2host_intr_mask)); - adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_AO_HOST_INTERRUPT_MASK, - (unsigned int) ~(gmu_dev_ops->gmu_ao_intr_mask)); -} - -/** - * adreno_gmu_mask_and_clear_irqs() - Mask all IRQs and clear pending IRQs - * @adreno_dev: Pointer to the Adreno device that owns the GMU - */ -void adreno_gmu_mask_and_clear_irqs(struct adreno_device *adreno_dev) -{ - /* Mask all IRQs on GMU */ - adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_AO_HOST_INTERRUPT_MASK, - 0xFFFFFFFF); - adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_GMU2HOST_INTR_MASK, - 0xFFFFFFFF); - - /* Clear any pending IRQs before disabling */ - adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_AO_HOST_INTERRUPT_CLR, - 0xFFFFFFFF); - adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_GMU2HOST_INTR_CLR, - 0xFFFFFFFF); -} - /* * adreno_gmu_fenced_write() - Check if there is a GMU and it is enabled * @adreno_dev: Pointer to the Adreno device that owns the GMU diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 85b4aa908688..602164ef74e9 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -709,23 +709,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_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, }; @@ -1762,9 +1748,6 @@ static inline void adreno_reg_offset_init(u32 *reg_offsets) } } - -void adreno_gmu_clear_and_unmask_irqs(struct adreno_device *adreno_dev); -void adreno_gmu_mask_and_clear_irqs(struct adreno_device *adreno_dev); int adreno_gmu_fenced_write(struct adreno_device *adreno_dev, enum adreno_regs offset, unsigned int val, unsigned int fence_mask); diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index 3b7d0300a79f..18a245d5ea62 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -2479,40 +2479,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_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) diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index d0e6b03fa22a..1c75f673af23 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -779,11 +779,19 @@ static void a6xx_gmu_oob_clear(struct kgsl_device *device, static void a6xx_gmu_irq_enable(struct adreno_device *adreno_dev) { + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); struct a6xx_hfi *hfi = &gmu->hfi; /* Clear pending IRQs and Unmask needed IRQs */ - adreno_gmu_clear_and_unmask_irqs(adreno_dev); + gmu_core_regwrite(device, A6XX_GMU_GMU2HOST_INTR_CLR, 0xffffffff); + gmu_core_regwrite(device, A6XX_GMU_AO_HOST_INTERRUPT_CLR, 0xffffffff); + + gmu_core_regwrite(device, A6XX_GMU_GMU2HOST_INTR_MASK, + (unsigned int)~HFI_IRQ_MASK); + gmu_core_regwrite(device, A6XX_GMU_AO_HOST_INTERRUPT_MASK, + (unsigned int)~GMU_AO_INT_MASK); + /* Enable all IRQs on host */ enable_irq(hfi->irq); @@ -792,6 +800,7 @@ static void a6xx_gmu_irq_enable(struct adreno_device *adreno_dev) static void a6xx_gmu_irq_disable(struct adreno_device *adreno_dev) { + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); struct a6xx_hfi *hfi = &gmu->hfi; @@ -800,7 +809,12 @@ static void a6xx_gmu_irq_disable(struct adreno_device *adreno_dev) disable_irq(hfi->irq); /* Mask all IRQs and clear pending IRQs */ - adreno_gmu_mask_and_clear_irqs(adreno_dev); + gmu_core_regwrite(device, A6XX_GMU_GMU2HOST_INTR_MASK, 0xffffffff); + gmu_core_regwrite(device, A6XX_GMU_AO_HOST_INTERRUPT_MASK, 0xffffffff); + + gmu_core_regwrite(device, A6XX_GMU_GMU2HOST_INTR_CLR, 0xffffffff); + gmu_core_regwrite(device, A6XX_GMU_AO_HOST_INTERRUPT_CLR, 0xffffffff); + } static int a6xx_gmu_hfi_start_msg(struct adreno_device *adreno_dev) @@ -1864,11 +1878,6 @@ static bool a6xx_gmu_scales_bandwidth(struct kgsl_device *device) return (ADRENO_GPUREV(adreno_dev) >= ADRENO_REV_A640); } -static u64 a6xx_gmu_read_alwayson(struct kgsl_device *device) -{ - return a6xx_read_alwayson(ADRENO_DEVICE(device)); -} - static irqreturn_t a6xx_gmu_irq_handler(int irq, void *data) { struct kgsl_device *device = data; @@ -2239,9 +2248,6 @@ static struct gmu_dev_ops a6xx_gmudev = { .snapshot = a6xx_gmu_device_snapshot, .cooperative_reset = a6xx_gmu_cooperative_reset, .wait_for_active_transition = a6xx_gmu_wait_for_active_transition, - .read_alwayson = a6xx_gmu_read_alwayson, - .gmu2host_intr_mask = HFI_IRQ_MASK, - .gmu_ao_intr_mask = GMU_AO_INT_MASK, .scales_bandwidth = a6xx_gmu_scales_bandwidth, }; diff --git a/drivers/gpu/msm/adreno_a6xx_hfi.c b/drivers/gpu/msm/adreno_a6xx_hfi.c index de5fa2630801..4c18c7004516 100644 --- a/drivers/gpu/msm/adreno_a6xx_hfi.c +++ b/drivers/gpu/msm/adreno_a6xx_hfi.c @@ -160,8 +160,8 @@ static int a6xx_hfi_queue_write(struct adreno_device *adreno_dev, wmb(); /* Send interrupt to GMU to receive the message */ - adreno_write_gmureg(adreno_dev, - ADRENO_REG_GMU_HOST2GMU_INTR_SET, 0x1); + gmu_core_regwrite(KGSL_DEVICE(adreno_dev), A6XX_GMU_HOST2GMU_INTR_SET, + 0x1); return 0; } @@ -274,29 +274,29 @@ static int receive_ack_cmd(struct a6xx_gmu_device *gmu, void *rcvd, #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 kgsl_device *device = KGSL_DEVICE(adreno_dev); struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); 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; @@ -325,7 +325,7 @@ static int a6xx_hfi_send_cmd(struct adreno_device *adreno_dev, 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) { @@ -337,7 +337,7 @@ static int a6xx_hfi_send_cmd(struct adreno_device *adreno_dev, } /* Clear the interrupt */ - adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_GMU2HOST_INTR_CLR, + gmu_core_regwrite(KGSL_DEVICE(adreno_dev), A6XX_GMU_GMU2HOST_INTR_CLR, HFI_IRQ_MSGQ_MASK); rc = a6xx_hfi_process_queue(gmu, HFI_MSG_ID, ret_cmd); @@ -841,14 +841,11 @@ int a6xx_hfi_send_req(struct adreno_device *adreno_dev, unsigned int id, irqreturn_t a6xx_hfi_irq_handler(int irq, void *data) { struct kgsl_device *device = data; - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(ADRENO_DEVICE(device)); unsigned int status = 0; - adreno_read_gmureg(adreno_dev, - ADRENO_REG_GMU_GMU2HOST_INTR_INFO, &status); - adreno_write_gmureg(adreno_dev, - 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) a6xx_hfi_process_queue(gmu, HFI_DBG_ID, NULL); diff --git a/drivers/gpu/msm/adreno_a6xx_rgmu.c b/drivers/gpu/msm/adreno_a6xx_rgmu.c index 3d082cca5382..6ba17af3df98 100644 --- a/drivers/gpu/msm/adreno_a6xx_rgmu.c +++ b/drivers/gpu/msm/adreno_a6xx_rgmu.c @@ -218,9 +218,16 @@ static void a6xx_rgmu_bcl_config(struct kgsl_device *device, bool on) static void a6xx_rgmu_irq_enable(struct adreno_device *adreno_dev) { struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); /* Clear pending IRQs and Unmask needed IRQs */ - adreno_gmu_clear_and_unmask_irqs(adreno_dev); + gmu_core_regwrite(device, A6XX_GMU_GMU2HOST_INTR_CLR, 0xffffffff); + gmu_core_regwrite(device, A6XX_GMU_AO_HOST_INTERRUPT_CLR, 0xffffffff); + + gmu_core_regwrite(device, A6XX_GMU_GMU2HOST_INTR_MASK, + ~((unsigned int)RGMU_OOB_IRQ_MASK)); + gmu_core_regwrite(device, A6XX_GMU_AO_HOST_INTERRUPT_MASK, + (unsigned int)~RGMU_AO_IRQ_MASK); /* Enable all IRQs on host */ enable_irq(rgmu->oob_interrupt_num); @@ -230,13 +237,18 @@ static void a6xx_rgmu_irq_enable(struct adreno_device *adreno_dev) static void a6xx_rgmu_irq_disable(struct adreno_device *adreno_dev) { struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); /* Disable all IRQs on host */ disable_irq(rgmu->rgmu_interrupt_num); disable_irq(rgmu->oob_interrupt_num); /* Mask all IRQs and clear pending IRQs */ - adreno_gmu_mask_and_clear_irqs(adreno_dev); + gmu_core_regwrite(device, A6XX_GMU_GMU2HOST_INTR_MASK, 0xffffffff); + gmu_core_regwrite(device, A6XX_GMU_AO_HOST_INTERRUPT_MASK, 0xffffffff); + + gmu_core_regwrite(device, A6XX_GMU_GMU2HOST_INTR_CLR, 0xffffffff); + gmu_core_regwrite(device, A6XX_GMU_AO_HOST_INTERRUPT_CLR, 0xffffffff); } static int a6xx_rgmu_ifpc_store(struct kgsl_device *device, @@ -1163,8 +1175,6 @@ static struct gmu_dev_ops a6xx_rgmudev = { .ifpc_store = a6xx_rgmu_ifpc_store, .ifpc_show = a6xx_rgmu_ifpc_show, .snapshot = a6xx_rgmu_device_snapshot, - .gmu2host_intr_mask = RGMU_OOB_IRQ_MASK, - .gmu_ao_intr_mask = RGMU_AO_IRQ_MASK, }; static struct gmu_core_ops a6xx_rgmu_ops = { diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index c401aa047cbb..256255dae52d 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -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 diff --git a/drivers/gpu/msm/kgsl_gmu_core.c b/drivers/gpu/msm/kgsl_gmu_core.c index 17336ba630a6..62b9a311f8a3 100644 --- a/drivers/gpu/msm/kgsl_gmu_core.c +++ b/drivers/gpu/msm/kgsl_gmu_core.c @@ -64,44 +64,6 @@ bool gmu_core_scales_bandwidth(struct kgsl_device *device) return false; } -int gmu_core_init(struct kgsl_device *device) -{ - struct gmu_core_ops *gmu_core_ops = GMU_CORE_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); - - 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); @@ -220,26 +182,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_snapshot(struct kgsl_device *device, struct kgsl_snapshot *snapshot) { @@ -288,14 +230,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); @@ -305,13 +239,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; -} diff --git a/drivers/gpu/msm/kgsl_gmu_core.h b/drivers/gpu/msm/kgsl_gmu_core.h index 092d8e7d1e13..943b7a59909d 100644 --- a/drivers/gpu/msm/kgsl_gmu_core.h +++ b/drivers/gpu/msm/kgsl_gmu_core.h @@ -101,28 +101,14 @@ struct kgsl_device; struct kgsl_snapshot; struct gmu_core_ops { - int (*init)(struct kgsl_device *device); - int (*start)(struct kgsl_device *device); - void (*stop)(struct kgsl_device *device); void (*snapshot)(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); - 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, @@ -131,9 +117,6 @@ struct gmu_dev_ops { 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; }; /** @@ -166,10 +149,6 @@ extern struct platform_driver a6xx_rgmu_driver; 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); @@ -200,16 +179,12 @@ 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_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 */ diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index fd03cecdabe4..2a7dec418778 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -174,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); /* @@ -1657,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) @@ -1685,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); @@ -1722,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); @@ -1843,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; @@ -1868,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; @@ -1911,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"); @@ -1958,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; @@ -2053,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); @@ -2106,8 +2048,6 @@ 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; } From 2960707394c252fee6cf982229d28a6eb4eeb25d Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Sat, 25 Apr 2020 16:05:32 -0600 Subject: [PATCH 28/30] msm: kgsl: Get rid of gmu_core_snapshot and gmu_core_dev_snapshot Assign the gmu specific snapshot function to gpudev->snapshot instead of creating a gmu_core_snapshot. This function will send an nmi if we hit a gmu fault. Then, it will capture gmu snapshot followed by the generic a6xx_snapshot as against a6xx snapshot calling the gmu snapshot. Do the same for rgmu. This helps get rid of gmu_core_snapshot and gmu_core_dev_snapshot() functions. Change-Id: I0f72a930633557260b59a76f0161bcde8c5a6da2 Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/adreno.h | 8 ++++ drivers/gpu/msm/adreno_a6xx.c | 6 +-- drivers/gpu/msm/adreno_a6xx_gmu.c | 46 +++++++++++-------- drivers/gpu/msm/adreno_a6xx_gmu.h | 10 ++-- drivers/gpu/msm/adreno_a6xx_hfi.c | 11 +++-- drivers/gpu/msm/adreno_a6xx_preempt.c | 2 +- drivers/gpu/msm/adreno_a6xx_rgmu.c | 63 +++++++++----------------- drivers/gpu/msm/adreno_a6xx_rgmu.h | 11 +++++ drivers/gpu/msm/adreno_a6xx_snapshot.c | 3 -- drivers/gpu/msm/adreno_ringbuffer.c | 2 +- drivers/gpu/msm/adreno_sysfs.c | 2 +- drivers/gpu/msm/kgsl_gmu_core.c | 27 ++--------- drivers/gpu/msm/kgsl_gmu_core.h | 16 +------ 13 files changed, 94 insertions(+), 113 deletions(-) diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 602164ef74e9..0decb1041d54 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -1877,4 +1877,12 @@ void adreno_get_bus_counters(struct adreno_device *adreno_dev); * 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 */ diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index 18a245d5ea62..ec0220e6ecd2 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -2654,7 +2654,7 @@ struct adreno_gpudev adreno_a6xx_gmu_gpudev = { .reg_offsets = a6xx_register_offsets, .probe = a6xx_gmu_device_probe, .start = a6xx_start, - .snapshot = a6xx_snapshot, + .snapshot = a6xx_gmu_snapshot, .init = a6xx_init, .irq_handler = a6xx_irq_handler, .rb_start = a6xx_rb_start, @@ -2689,7 +2689,7 @@ struct adreno_gpudev adreno_a6xx_rgmu_gpudev = { .reg_offsets = a6xx_register_offsets, .probe = a6xx_rgmu_device_probe, .start = a6xx_start, - .snapshot = a6xx_snapshot, + .snapshot = a6xx_rgmu_snapshot, .init = a6xx_init, .irq_handler = a6xx_irq_handler, .rb_start = a6xx_rb_start, @@ -2724,7 +2724,7 @@ struct adreno_gpudev adreno_a630_gpudev = { .reg_offsets = a6xx_register_offsets, .probe = a6xx_gmu_device_probe, .start = a6xx_start, - .snapshot = a6xx_snapshot, + .snapshot = a6xx_gmu_snapshot, .init = a6xx_init, .irq_handler = a6xx_irq_handler, .rb_start = a6xx_rb_start, diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index 1c75f673af23..5b770f8a9422 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -102,6 +102,12 @@ static struct gmu_iommu_context a6xx_gmu_ctx[] = { [GMU_CONTEXT_KERNEL] = { .name = "gmu_kernel" } }; +void gmu_fault_snapshot(struct kgsl_device *device) +{ + device->gmu_fault = true; + kgsl_device_snapshot(device, NULL, true); +} + struct a6xx_gmu_device *to_a6xx_gmu(struct adreno_device *adreno_dev) { struct a6xx_device *a6xx_dev = container_of(adreno_dev, @@ -443,8 +449,7 @@ static int a6xx_gmu_device_start(struct adreno_device *adreno_dev) gmu_core_regread(device, A6XX_GMU_CM3_DTCM_START + (0x3fdc >> 2), &val); dev_err(&gmu->pdev->dev, "GMU doesn't boot: 0x%x\n", val); - - a6xx_gmu_snapshot(device); + gmu_fault_snapshot(device); return -ETIMEDOUT; } @@ -468,7 +473,7 @@ static int a6xx_gmu_hfi_start(struct adreno_device *adreno_dev) GMU_START_TIMEOUT, BIT(0))) { dev_err(&gmu->pdev->dev, "GMU HFI init failed\n"); - a6xx_gmu_snapshot(device); + gmu_fault_snapshot(device); return -ETIMEDOUT; } @@ -744,8 +749,8 @@ static int a6xx_gmu_oob_set(struct kgsl_device *device, if (timed_poll_check(device, A6XX_GMU_GMU2HOST_INTR_INFO, check, GPU_START_TIMEOUT, check)) { + gmu_fault_snapshot(device); ret = -ETIMEDOUT; - a6xx_gmu_snapshot(device); WARN(1, "OOB request %s timed out\n", oob_to_str(req)); } @@ -914,7 +919,7 @@ int a6xx_gmu_sptprac_enable(struct adreno_device *adreno_dev) SPTPRAC_CTRL_TIMEOUT, SPTPRAC_POWERON_STATUS_MASK)) { dev_err(&gmu->pdev->dev, "power on SPTPRAC fail\n"); - a6xx_gmu_snapshot(device); + gmu_fault_snapshot(device); return -ETIMEDOUT; } @@ -1112,6 +1117,7 @@ static int a6xx_gmu_wait_for_lowest_idle(struct adreno_device *adreno_dev) } WARN_ON(1); + gmu_fault_snapshot(device); return -ETIMEDOUT; } @@ -1133,6 +1139,7 @@ static int a6xx_gmu_wait_for_idle(struct adreno_device *adreno_dev) "GMU not idling: status2=0x%x %llx %llx\n", status2, ts1, a6xx_read_alwayson(ADRENO_DEVICE(device))); + gmu_fault_snapshot(device); return -ETIMEDOUT; } @@ -1936,14 +1943,13 @@ static irqreturn_t a6xx_gmu_irq_handler(int irq, void *data) return IRQ_HANDLED; } - -void a6xx_gmu_snapshot(struct kgsl_device *device) +static void a6xx_gmu_nmi(struct adreno_device *adreno_dev) { - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); - /* Abstain from sending another nmi or over-writing snapshot */ - if (device->gmu_fault) + /* No need to nmi if it was a gpu fault */ + if (!device->gmu_fault) return; /* make sure we're reading the latest cm3_fault */ @@ -1960,16 +1966,24 @@ void a6xx_gmu_snapshot(struct kgsl_device *device) /* Wait for the NMI to be handled */ udelay(100); } +} - kgsl_device_snapshot(device, NULL, true); +void a6xx_gmu_snapshot(struct adreno_device *adreno_dev, + struct kgsl_snapshot *snapshot) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + + a6xx_gmu_nmi(adreno_dev); + + a6xx_gmu_device_snapshot(device, snapshot); + + a6xx_snapshot(adreno_dev, snapshot); gmu_core_regwrite(device, A6XX_GMU_GMU2HOST_INTR_CLR, 0xffffffff); gmu_core_regwrite(device, A6XX_GMU_GMU2HOST_INTR_MASK, HFI_IRQ_MASK); - device->gmu_fault = true; - } static int a6xx_gmu_aop_send_acd_state(struct mbox_chan *channel, bool flag) @@ -2245,14 +2259,9 @@ static struct gmu_dev_ops a6xx_gmudev = { .gx_is_on = a6xx_gmu_gx_is_on, .ifpc_store = a6xx_gmu_ifpc_store, .ifpc_show = a6xx_gmu_ifpc_show, - .snapshot = a6xx_gmu_device_snapshot, .cooperative_reset = a6xx_gmu_cooperative_reset, .wait_for_active_transition = a6xx_gmu_wait_for_active_transition, .scales_bandwidth = a6xx_gmu_scales_bandwidth, -}; - -static struct gmu_core_ops a6xx_gmu_ops = { - .snapshot = a6xx_gmu_snapshot, .acd_set = a6xx_gmu_acd_set, }; @@ -2592,7 +2601,6 @@ static int a6xx_gmu_probe(struct kgsl_device *device, set_bit(GMU_ENABLED, &device->gmu_core.flags); - device->gmu_core.core_ops = &a6xx_gmu_ops; device->gmu_core.dev_ops = &a6xx_gmudev; /* Initialize HFI and GMU interrupts */ diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.h b/drivers/gpu/msm/adreno_a6xx_gmu.h index 2ec6cc30ff08..9a3341c06b75 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.h +++ b/drivers/gpu/msm/adreno_a6xx_gmu.h @@ -286,9 +286,13 @@ void a6xx_enable_gpu_irq(struct adreno_device *adreno_dev); void a6xx_disable_gpu_irq(struct adreno_device *adreno_dev); /** - * a6xx_gmu_snapshot - Send nmi to gmu and take snapshot - * @device: Pointer to the kgsl device + * 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 kgsl_device *device); +void a6xx_gmu_snapshot(struct adreno_device *adreno_dev, + struct kgsl_snapshot *snapshot); #endif diff --git a/drivers/gpu/msm/adreno_a6xx_hfi.c b/drivers/gpu/msm/adreno_a6xx_hfi.c index 4c18c7004516..06bbe3561e04 100644 --- a/drivers/gpu/msm/adreno_a6xx_hfi.c +++ b/drivers/gpu/msm/adreno_a6xx_hfi.c @@ -245,6 +245,7 @@ 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]; @@ -266,7 +267,7 @@ static int receive_ack_cmd(struct a6xx_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); - a6xx_gmu_snapshot(KGSL_DEVICE(adreno_dev)); + gmu_fault_snapshot(device); return -ENODEV; } @@ -310,6 +311,7 @@ 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 a6xx_hfi *hfi = &gmu->hfi; @@ -329,7 +331,7 @@ static int a6xx_hfi_send_cmd(struct adreno_device *adreno_dev, HFI_IRQ_MSGQ_MASK, HFI_IRQ_MSGQ_MASK, HFI_RSP_TIMEOUT); if (rc) { - a6xx_gmu_snapshot(KGSL_DEVICE(adreno_dev)); + 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)); @@ -337,7 +339,7 @@ static int a6xx_hfi_send_cmd(struct adreno_device *adreno_dev, } /* Clear the interrupt */ - gmu_core_regwrite(KGSL_DEVICE(adreno_dev), A6XX_GMU_GMU2HOST_INTR_CLR, + gmu_core_regwrite(device, A6XX_GMU_GMU2HOST_INTR_CLR, HFI_IRQ_MSGQ_MASK); rc = a6xx_hfi_process_queue(gmu, HFI_MSG_ID, ret_cmd); @@ -359,8 +361,9 @@ static int a6xx_hfi_send_generic_req(struct adreno_device *adreno_dev, 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); - a6xx_gmu_snapshot(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; diff --git a/drivers/gpu/msm/adreno_a6xx_preempt.c b/drivers/gpu/msm/adreno_a6xx_preempt.c index d83c095ab1c9..da8851edb4a2 100644 --- a/drivers/gpu/msm/adreno_a6xx_preempt.c +++ b/drivers/gpu/msm/adreno_a6xx_preempt.c @@ -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 { diff --git a/drivers/gpu/msm/adreno_a6xx_rgmu.c b/drivers/gpu/msm/adreno_a6xx_rgmu.c index 6ba17af3df98..7623de43be59 100644 --- a/drivers/gpu/msm/adreno_a6xx_rgmu.c +++ b/drivers/gpu/msm/adreno_a6xx_rgmu.c @@ -42,8 +42,6 @@ static const unsigned int a6xx_rgmu_registers[] = { 0x26000, 0x26002, }; -static void a6xx_rgmu_snapshot(struct kgsl_device *device); - static struct a6xx_rgmu_device *to_a6xx_rgmu(struct adreno_device *adreno_dev) { struct a6xx_device *a6xx_dev = container_of(adreno_dev, @@ -167,7 +165,7 @@ static int a6xx_rgmu_oob_set(struct kgsl_device *device, dev_err(&rgmu->pdev->dev, "Timed out while setting OOB req:%s status:0x%x\n", oob_to_str(req), status); - a6xx_rgmu_snapshot(device); + gmu_fault_snapshot(device); return ret; } @@ -368,7 +366,7 @@ static int a6xx_rgmu_wait_for_lowest_idle(struct adreno_device *adreno_dev) reg[7], reg[8], reg[9]); WARN_ON(1); - a6xx_rgmu_snapshot(device); + gmu_fault_snapshot(device); return -ETIMEDOUT; } @@ -452,7 +450,7 @@ static int a6xx_rgmu_fw_start(struct adreno_device *adreno_dev, gmu_core_regread(device, A6XX_RGMU_CX_PCC_DEBUG, &status); dev_err(&rgmu->pdev->dev, "rgmu boot Failed. status:%08x\n", status); - a6xx_rgmu_snapshot(device); + gmu_fault_snapshot(device); return -ETIMEDOUT; } @@ -522,35 +520,29 @@ static int a6xx_rgmu_disable_gdsc(struct adreno_device *adreno_dev) static void a6xx_rgmu_halt_execution(struct kgsl_device *device); -static void a6xx_rgmu_snapshot(struct kgsl_device *device) +void a6xx_rgmu_snapshot(struct adreno_device *adreno_dev, + struct kgsl_snapshot *snapshot) { - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev); - if (device->gmu_fault) - return; - - /* Mask so there's no interrupt caused by NMI */ - gmu_core_regwrite(device, A6XX_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. */ a6xx_rgmu_halt_execution(device); - kgsl_device_snapshot(device, NULL, true); + adreno_snapshot_registers(device, snapshot, a6xx_rgmu_registers, + ARRAY_SIZE(a6xx_rgmu_registers) / 2); + + a6xx_snapshot(adreno_dev, snapshot); gmu_core_regwrite(device, A6XX_GMU_GMU2HOST_INTR_CLR, 0xffffffff); gmu_core_regwrite(device, A6XX_GMU_GMU2HOST_INTR_MASK, RGMU_OOB_IRQ_MASK); - rgmu->fault_count++; - - device->gmu_fault = true; + if (device->gmu_fault) + rgmu->fault_count++; } static void a6xx_rgmu_suspend(struct adreno_device *adreno_dev) @@ -644,6 +636,15 @@ static void a6xx_rgmu_halt_execution(struct kgsl_device *device) struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(ADRENO_DEVICE(device)); unsigned int index, status, fence; + if (!device->gmu_fault) + return; + + /* Mask so there's no interrupt caused by NMI */ + gmu_core_regwrite(device, A6XX_GMU_GMU2HOST_INTR_MASK, 0xFFFFFFFF); + + /* Make sure the interrupt is masked */ + wmb(); + gmu_core_regread(device, A6XX_RGMU_CX_PCC_DEBUG, &index); gmu_core_regread(device, A6XX_RGMU_CX_PCC_STATUS, &status); gmu_core_regread(device, A6XX_GMU_AO_AHB_FENCE_CTRL, &fence); @@ -666,22 +667,6 @@ static void a6xx_rgmu_halt_execution(struct kgsl_device *device) } -/* - * a6xx_rgmu_snapshot() - A6XX GMU snapshot function - * @adreno_dev: 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 - */ -static void a6xx_rgmu_device_snapshot(struct kgsl_device *device, - struct kgsl_snapshot *snapshot) -{ - - adreno_snapshot_registers(device, snapshot, a6xx_rgmu_registers, - ARRAY_SIZE(a6xx_rgmu_registers) / 2); -} - static void halt_gbif_arb(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); @@ -1174,11 +1159,6 @@ static struct gmu_dev_ops a6xx_rgmudev = { .gx_is_on = a6xx_rgmu_gx_is_on, .ifpc_store = a6xx_rgmu_ifpc_store, .ifpc_show = a6xx_rgmu_ifpc_show, - .snapshot = a6xx_rgmu_device_snapshot, -}; - -static struct gmu_core_ops a6xx_rgmu_ops = { - .snapshot = a6xx_rgmu_snapshot, }; static int a6xx_rgmu_irq_probe(struct kgsl_device *device) @@ -1345,7 +1325,6 @@ static int a6xx_rgmu_probe(struct kgsl_device *device, rgmu->idle_level = GPU_HW_ACTIVE; set_bit(GMU_ENABLED, &device->gmu_core.flags); - device->gmu_core.core_ops = &a6xx_rgmu_ops; device->gmu_core.dev_ops = &a6xx_rgmudev; return 0; diff --git a/drivers/gpu/msm/adreno_a6xx_rgmu.h b/drivers/gpu/msm/adreno_a6xx_rgmu.h index 017e487cd9b3..6defcbc5ac46 100644 --- a/drivers/gpu/msm/adreno_a6xx_rgmu.h +++ b/drivers/gpu/msm/adreno_a6xx_rgmu.h @@ -78,4 +78,15 @@ int a6xx_rgmu_device_probe(struct platform_device *pdev, * 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 diff --git a/drivers/gpu/msm/adreno_a6xx_snapshot.c b/drivers/gpu/msm/adreno_a6xx_snapshot.c index 8d7c9cdb8540..7181c6ca574a 100644 --- a/drivers/gpu/msm/adreno_a6xx_snapshot.c +++ b/drivers/gpu/msm/adreno_a6xx_snapshot.c @@ -1784,9 +1784,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 diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c index 00857d97adeb..b7d134929625 100644 --- a/drivers/gpu/msm/adreno_ringbuffer.c +++ b/drivers/gpu/msm/adreno_ringbuffer.c @@ -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); diff --git a/drivers/gpu/msm/adreno_sysfs.c b/drivers/gpu/msm/adreno_sysfs.c index 5aacc1e51ffd..72f314257605 100644 --- a/drivers/gpu/msm/adreno_sysfs.c +++ b/drivers/gpu/msm/adreno_sysfs.c @@ -261,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, diff --git a/drivers/gpu/msm/kgsl_gmu_core.c b/drivers/gpu/msm/kgsl_gmu_core.c index 62b9a311f8a3..4654507ee743 100644 --- a/drivers/gpu/msm/kgsl_gmu_core.c +++ b/drivers/gpu/msm/kgsl_gmu_core.c @@ -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,20 +64,12 @@ bool gmu_core_scales_bandwidth(struct kgsl_device *device) return false; } -void gmu_core_snapshot(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->snapshot) - gmu_core_ops->snapshot(device); -} - -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); + if (ops && ops->acd_set) + return ops->acd_set(device, val); return -EINVAL; } @@ -182,15 +174,6 @@ void gmu_core_dev_oob_clear(struct kgsl_device *device, enum oob_request req) ops->oob_clear(device, req); } -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) { diff --git a/drivers/gpu/msm/kgsl_gmu_core.h b/drivers/gpu/msm/kgsl_gmu_core.h index 943b7a59909d..07f3c7b79139 100644 --- a/drivers/gpu/msm/kgsl_gmu_core.h +++ b/drivers/gpu/msm/kgsl_gmu_core.h @@ -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 @@ -100,23 +99,17 @@ struct device_node; struct kgsl_device; struct kgsl_snapshot; -struct gmu_core_ops { - void (*snapshot)(struct kgsl_device *device); - int (*acd_set)(struct kgsl_device *device, bool val); -}; - struct gmu_dev_ops { int (*oob_set)(struct kgsl_device *device, enum oob_request req); void (*oob_clear)(struct kgsl_device *device, enum oob_request req); bool (*gx_is_on)(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); + int (*acd_set)(struct kgsl_device *device, bool val); }; /** @@ -127,7 +120,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 */ @@ -136,7 +128,6 @@ 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; }; @@ -149,11 +140,10 @@ extern struct platform_driver a6xx_rgmu_driver; void __init gmu_core_register(void); void __exit gmu_core_unregister(void); -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_acd_set(struct kgsl_device *device, bool val); +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, @@ -179,8 +169,6 @@ 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); -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); From c832a7c9748215c28c68fe517c147ef094852be0 Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Wed, 20 May 2020 16:08:06 -0600 Subject: [PATCH 29/30] msm: kgsl: Move rscc to a6xx gmu space Rscc registers are only needed for gmu based targets. So move the probe and snapshot to a6xx gmu probe and snapshot respectively. Also, fix the rscc offset for targets which have rscc registers part of the gmu register space. Change-Id: I3f73e3c99838d01676f81df6bc7bd7ab3334a0fe Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/a6xx_reg.h | 2 +- drivers/gpu/msm/adreno.c | 39 ------ drivers/gpu/msm/adreno.h | 8 -- drivers/gpu/msm/adreno_a6xx.h | 33 ----- drivers/gpu/msm/adreno_a6xx_gmu.c | 36 ++++- drivers/gpu/msm/adreno_a6xx_gmu.h | 2 + drivers/gpu/msm/adreno_a6xx_gmu_snapshot.c | 150 ++++++++++++++++++++- drivers/gpu/msm/adreno_a6xx_snapshot.c | 125 ----------------- 8 files changed, 179 insertions(+), 216 deletions(-) diff --git a/drivers/gpu/msm/a6xx_reg.h b/drivers/gpu/msm/a6xx_reg.h index a2b83f15809f..b3b7f2e5ce1b 100644 --- a/drivers/gpu/msm/a6xx_reg.h +++ b/drivers/gpu/msm/a6xx_reg.h @@ -1122,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 diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 8e01c1c20224..46fb0735c173 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -1110,25 +1110,6 @@ static void adreno_cx_misc_probe(struct kgsl_device *device) res->start, adreno_dev->cx_misc_len); } -static void adreno_rscc_probe(struct kgsl_device *device) -{ - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct resource *res; - - res = platform_get_resource_byname(device->pdev, IORESOURCE_MEM, - "rscc"); - - if (res == NULL) - return; - - adreno_dev->rscc_base = res->start - device->reg_phys; - adreno_dev->rscc_len = resource_size(res); - adreno_dev->rscc_virt = devm_ioremap(&device->pdev->dev, res->start, - adreno_dev->rscc_len); - if (adreno_dev->rscc_virt == NULL) - dev_warn(device->dev, "rscc ioremap failed\n"); -} - static void adreno_isense_probe(struct kgsl_device *device) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); @@ -1379,8 +1360,6 @@ int adreno_device_probe(struct platform_device *pdev, /* Probe for the optional CX_MISC block */ adreno_cx_misc_probe(device); - adreno_rscc_probe(device); - adreno_isense_probe(device); /* Allocate the memstore for storing timestamps and other useful info */ @@ -3144,24 +3123,6 @@ void adreno_cx_misc_regread(struct adreno_device *adreno_dev, */ rmb(); } -void adreno_rscc_regread(struct adreno_device *adreno_dev, - unsigned int offsetwords, unsigned int *value) -{ - unsigned int rscc_offset; - - rscc_offset = (offsetwords << 2); - if (!adreno_dev->rscc_virt || - (rscc_offset >= adreno_dev->rscc_len)) - return; - - *value = __raw_readl(adreno_dev->rscc_virt + rscc_offset); - - /* - * ensure this read finishes before the next one. - * i.e. act like normal readl() - */ - rmb(); -} void adreno_isense_regread(struct adreno_device *adreno_dev, unsigned int offsetwords, unsigned int *value) diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 0decb1041d54..8e5229d7df51 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -405,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 @@ -487,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; @@ -978,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); diff --git a/drivers/gpu/msm/adreno_a6xx.h b/drivers/gpu/msm/adreno_a6xx.h index 40e0b222cdd6..3af126c6be78 100644 --- a/drivers/gpu/msm/adreno_a6xx.h +++ b/drivers/gpu/msm/adreno_a6xx.h @@ -224,39 +224,6 @@ static inline int timed_poll_check(struct kgsl_device *device, return 0; } -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; - - if (!adreno_is_a650_family(adreno_dev)) - return timed_poll_check(device, offset + RSCC_OFFSET_LEGACY, - expected_ret, timeout, mask); - - t = jiffies + msecs_to_jiffies(timeout); - - do { - adreno_rscc_regread(adreno_dev, 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)); - - /* Double check one last time */ - if (adreno_is_a650_family(adreno_dev)) - adreno_rscc_regread(adreno_dev, offset, &value); - - if ((value & mask) == expected_ret) - return 0; - - return -ETIMEDOUT; -} - /* Preemption functions */ void a6xx_preemption_trigger(struct adreno_device *adreno_dev); void a6xx_preemption_schedule(struct adreno_device *adreno_dev); diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index 5b770f8a9422..3ce035f7a85a 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -102,6 +102,22 @@ static struct gmu_iommu_context a6xx_gmu_ctx[] = { [GMU_CONTEXT_KERNEL] = { .name = "gmu_kernel" } }; +static 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); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + u32 value; + + if (!adreno_is_a650_family(adreno_dev)) + return timed_poll_check(device, offset + RSCC_OFFSET_LEGACY, + expected_ret, timeout, mask); + + return readl_poll_timeout(gmu->rscc_virt + (offset << 2), value, + (value & mask) == expected_ret, 100, timeout * 1000); +} + void gmu_fault_snapshot(struct kgsl_device *device) { device->gmu_fault = true; @@ -139,10 +155,11 @@ static void _regwrite(void __iomem *regbase, static void a6xx_load_rsc_ucode(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); void __iomem *rscc; if (adreno_is_a650_family(adreno_dev)) - rscc = adreno_dev->rscc_virt; + rscc = gmu->rscc_virt; else rscc = device->gmu_core.reg_virt + 0x23000; @@ -2062,11 +2079,6 @@ static int a6xx_gmu_first_boot(struct adreno_device *adreno_dev) struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); int level, ret; - if (adreno_is_a650_family(adreno_dev) && !adreno_dev->rscc_virt) { - dev_err(&gmu->pdev->dev, "RSCC registers not mapped\n"); - return -EINVAL; - } - ret = a6xx_gmu_aop_send_acd_state(gmu->mailbox.channel, adreno_dev->acd_enabled); if (ret) { @@ -2552,6 +2564,7 @@ static int a6xx_gmu_probe(struct kgsl_device *device, struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); struct a6xx_hfi *hfi = &gmu->hfi; + struct resource *res; int ret; gmu->pdev = pdev; @@ -2560,6 +2573,17 @@ static int a6xx_gmu_probe(struct kgsl_device *device, gmu->pdev->dev.dma_mask = &gmu->pdev->dev.coherent_dma_mask; set_dma_ops(&gmu->pdev->dev, NULL); + res = platform_get_resource_byname(device->pdev, IORESOURCE_MEM, + "rscc"); + if (res) { + gmu->rscc_virt = devm_ioremap(&device->pdev->dev, res->start, + resource_size(res)); + if (gmu->rscc_virt == NULL) { + dev_err(&gmu->pdev->dev, "rscc ioremap failed\n"); + return -ENOMEM; + } + } + /* Set up GMU regulators */ ret = a6xx_gmu_regulators_probe(gmu, pdev); if (ret) diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.h b/drivers/gpu/msm/adreno_a6xx_gmu.h index 9a3341c06b75..e6bdc5f49d60 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.h +++ b/drivers/gpu/msm/adreno_a6xx_gmu.h @@ -201,6 +201,8 @@ struct a6xx_gmu_device { void *itcm_shadow; /** @flags: Internal gmu flags */ unsigned long flags; + /** @rscc_virt: Pointer where RSCC block is mapped */ + void __iomem *rscc_virt; }; /* Helper function to get to a6xx gmu device from adreno device */ diff --git a/drivers/gpu/msm/adreno_a6xx_gmu_snapshot.c b/drivers/gpu/msm/adreno_a6xx_gmu_snapshot.c index bdecffdec328..8ec0951108f3 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu_snapshot.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu_snapshot.c @@ -57,6 +57,74 @@ static const unsigned int a660_gmu_registers[] = { 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; @@ -225,6 +293,77 @@ static void a6xx_gmu_snapshot_versions(struct kgsl_device *device, &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 @@ -236,7 +375,8 @@ static void a6xx_gmu_snapshot_versions(struct kgsl_device *device, void a6xx_gmu_device_snapshot(struct kgsl_device *device, struct kgsl_snapshot *snapshot) { - struct a6xx_gmu_device *gmu = to_a6xx_gmu(ADRENO_DEVICE(device)); + 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, @@ -250,8 +390,8 @@ void a6xx_gmu_device_snapshot(struct kgsl_device *device, a6xx_gmu_snapshot_memories(device, gmu, snapshot); /* Snapshot tcms as registers for legacy targets */ - if (adreno_is_a630(ADRENO_DEVICE(device)) || - adreno_is_a615_family(ADRENO_DEVICE(device))) + 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); @@ -260,10 +400,12 @@ void a6xx_gmu_device_snapshot(struct kgsl_device *device, ARRAY_SIZE(a6xx_gmu_registers) / 2); /* Snapshot A660 specific GMU registers */ - if (adreno_is_a660(ADRENO_DEVICE(device))) + 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; diff --git a/drivers/gpu/msm/adreno_a6xx_snapshot.c b/drivers/gpu/msm/adreno_a6xx_snapshot.c index 7181c6ca574a..23f20f2802a2 100644 --- a/drivers/gpu/msm/adreno_a6xx_snapshot.c +++ b/drivers/gpu/msm/adreno_a6xx_snapshot.c @@ -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) { @@ -1797,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, From 3d5ebabeb4bbd2291f1e35893b530f50507ae2eb Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Thu, 7 May 2020 16:03:18 -0600 Subject: [PATCH 30/30] msm: kgsl: Fix kgsl_state_is_awake for gmu targets KGSL_STATE_AWARE has worked for non gmu targets to indicate that power and clocks are on. Set the KGSL_STATE_AWARE once gmu clocks and power is turned on and clear it when clocks and power is turned off. Change-Id: I6be046ca2a076b24bc6708c88bf9637276df2244 Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/adreno_a6xx_gmu.c | 10 ++++++++-- drivers/gpu/msm/adreno_a6xx_rgmu.c | 8 ++++++-- drivers/gpu/msm/kgsl_device.h | 3 --- drivers/gpu/msm/kgsl_gmu_core.h | 1 - 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index 3ce035f7a85a..edd48127fe52 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -1691,6 +1691,7 @@ out: static void a6xx_gmu_suspend(struct adreno_device *adreno_dev) { struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); a6xx_gmu_irq_disable(adreno_dev); @@ -1708,6 +1709,8 @@ static void a6xx_gmu_suspend(struct adreno_device *adreno_dev) regulator_set_mode(gmu->cx_gdsc, REGULATOR_MODE_NORMAL); dev_err(&gmu->pdev->dev, "Suspended GMU\n"); + + device->state = KGSL_STATE_NONE; } static int a6xx_gmu_dcvs_set(struct adreno_device *adreno_dev, @@ -2049,6 +2052,7 @@ static int a6xx_gmu_clk_set_rate(struct a6xx_gmu_device *gmu, const char *id, static int a6xx_gmu_enable_clks(struct adreno_device *adreno_dev) { struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); int ret; ret = a6xx_gmu_clk_set_rate(gmu, "gmu_clk", GMU_FREQUENCY); @@ -2069,6 +2073,8 @@ static int a6xx_gmu_enable_clks(struct adreno_device *adreno_dev) return ret; } + device->state = KGSL_STATE_AWARE; + return 0; } @@ -2740,6 +2746,8 @@ static int a6xx_gmu_power_off(struct adreno_device *adreno_dev) if (!kgsl_regulator_disable_wait(gmu->cx_gdsc, 5000)) dev_err(&gmu->pdev->dev, "GMU CX gdsc off timeout\n"); + device->state = KGSL_STATE_NONE; + return ret; error: @@ -3014,8 +3022,6 @@ no_gx_power: clear_bit(GMU_PRIV_GPU_STARTED, &gmu->flags); - device->state = KGSL_STATE_NONE; - del_timer_sync(&device->idle_timer); kgsl_pwrscale_sleep(device); diff --git a/drivers/gpu/msm/adreno_a6xx_rgmu.c b/drivers/gpu/msm/adreno_a6xx_rgmu.c index 7623de43be59..e1f0dde2f9d8 100644 --- a/drivers/gpu/msm/adreno_a6xx_rgmu.c +++ b/drivers/gpu/msm/adreno_a6xx_rgmu.c @@ -508,12 +508,16 @@ static void a6xx_rgmu_disable_clks(struct adreno_device *adreno_dev) static int a6xx_rgmu_disable_gdsc(struct adreno_device *adreno_dev) { struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); /* 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"); + + device->state = KGSL_STATE_NONE; + return -ETIMEDOUT; } @@ -579,6 +583,8 @@ static int a6xx_rgmu_enable_clks(struct adreno_device *adreno_dev) return ret; } + device->state = KGSL_STATE_AWARE; + return 0; } @@ -1051,8 +1057,6 @@ no_gx_power: clear_bit(RGMU_PRIV_GPU_STARTED, &rgmu->flags); - device->state = KGSL_STATE_NONE; - del_timer_sync(&device->idle_timer); kgsl_pwrscale_sleep(device); diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index 256255dae52d..eafb9b342a5d 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -592,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; } diff --git a/drivers/gpu/msm/kgsl_gmu_core.h b/drivers/gpu/msm/kgsl_gmu_core.h index 07f3c7b79139..dd2685c6f1a5 100644 --- a/drivers/gpu/msm/kgsl_gmu_core.h +++ b/drivers/gpu/msm/kgsl_gmu_core.h @@ -34,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,