summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/msm/Kconfig1
-rw-r--r--drivers/gpu/drm/msm/adreno/a5xx_gpu.c180
-rw-r--r--drivers/gpu/drm/msm/adreno/a5xx_gpu.h2
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_device.c1
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_gpu.h1
5 files changed, 183 insertions, 2 deletions
diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
index 0a31cd6d01ce..b638d192ce5e 100644
--- a/drivers/gpu/drm/msm/Kconfig
+++ b/drivers/gpu/drm/msm/Kconfig
@@ -5,6 +5,7 @@ config DRM_MSM
depends on ARCH_QCOM || (ARM && COMPILE_TEST)
depends on OF && COMMON_CLK
depends on MMU
+ select QCOM_MDT_LOADER
select REGULATOR
select DRM_KMS_HELPER
select DRM_PANEL
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
index 31a9bceed32c..67fd6bf2a25f 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
@@ -11,6 +11,12 @@
*
*/
+#include <linux/types.h>
+#include <linux/cpumask.h>
+#include <linux/qcom_scm.h>
+#include <linux/dma-mapping.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/soc/qcom/mdt_loader.h>
#include "msm_gem.h"
#include "msm_mmu.h"
#include "a5xx_gpu.h"
@@ -18,6 +24,62 @@
extern bool hang_debug;
static void a5xx_dump(struct msm_gpu *gpu);
+#define GPU_PAS_ID 13
+
+#if IS_ENABLED(CONFIG_QCOM_MDT_LOADER)
+
+static int zap_shader_load_mdt(struct device *dev, const char *fwname)
+{
+ const struct firmware *fw;
+ phys_addr_t mem_phys;
+ ssize_t mem_size;
+ void *mem_region = NULL;
+ int ret;
+
+ /* Request the MDT file for the firmware */
+ ret = request_firmware(&fw, fwname, dev);
+ if (ret) {
+ DRM_DEV_ERROR(dev, "Unable to load %s\n", fwname);
+ return ret;
+ }
+
+ /* Figure out how much memory we need */
+ mem_size = qcom_mdt_get_size(fw);
+ if (mem_size < 0) {
+ ret = mem_size;
+ goto out;
+ }
+
+ /* Allocate memory for the firmware image */
+ mem_region = dmam_alloc_coherent(dev, mem_size, &mem_phys, GFP_KERNEL);
+ if (!mem_region) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* Load the rest of the MDT */
+ ret = qcom_mdt_load(dev, fw, fwname, GPU_PAS_ID, mem_region, mem_phys,
+ mem_size);
+ if (ret)
+ goto out;
+
+ /* Send the image to the secure world */
+ ret = qcom_scm_pas_auth_and_reset(GPU_PAS_ID);
+ if (ret)
+ DRM_DEV_ERROR(dev, "Unable to authorize the image\n");
+
+out:
+ release_firmware(fw);
+
+ return ret;
+}
+#else
+static int zap_shader_load_mdt(struct device *dev, const char *fwname)
+{
+ return -ENODEV;
+}
+#endif
+
static void a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
struct msm_file_private *ctx)
{
@@ -304,6 +366,98 @@ static int a5xx_ucode_init(struct msm_gpu *gpu)
return 0;
}
+#define SCM_GPU_ZAP_SHADER_RESUME 0
+
+static int a5xx_zap_shader_resume(struct msm_gpu *gpu)
+{
+ int ret;
+
+ ret = qcom_scm_set_remote_state(SCM_GPU_ZAP_SHADER_RESUME, GPU_PAS_ID);
+ if (ret)
+ DRM_ERROR("%s: zap-shader resume failed: %d\n",
+ gpu->name, ret);
+
+ return ret;
+}
+
+/* Set up a child device to "own" the zap shader */
+static int a5xx_zap_shader_dev_init(struct device *parent, struct device *dev)
+{
+ struct device_node *node;
+ int ret;
+
+ if (dev->parent)
+ return 0;
+
+ /* Find the sub-node for the zap shader */
+ node = of_get_child_by_name(parent->of_node, "zap-shader");
+ if (!node) {
+ DRM_DEV_ERROR(parent, "zap-shader not found in device tree\n");
+ return -ENODEV;
+ }
+
+ dev->parent = parent;
+ dev->of_node = node;
+ dev_set_name(dev, "adreno_zap_shader");
+
+ ret = device_register(dev);
+ if (ret) {
+ DRM_DEV_ERROR(parent, "Couldn't register zap shader device\n");
+ goto out;
+ }
+
+ ret = of_reserved_mem_device_init(dev);
+ if (ret) {
+ DRM_DEV_ERROR(parent, "Unable to set up the reserved memory\n");
+ device_unregister(dev);
+ }
+
+out:
+ if (ret)
+ dev->parent = NULL;
+
+ return ret;
+}
+
+static int a5xx_zap_shader_init(struct msm_gpu *gpu)
+{
+ static bool loaded;
+ struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+ struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu);
+ struct platform_device *pdev = a5xx_gpu->pdev;
+ int ret;
+
+ /*
+ * If the zap shader is already loaded into memory we just need to kick
+ * the remote processor to reinitialize it
+ */
+ if (loaded)
+ return a5xx_zap_shader_resume(gpu);
+
+ /* We need SCM to be able to load the firmware */
+ if (!qcom_scm_is_available()) {
+ DRM_DEV_ERROR(&pdev->dev, "SCM is not available\n");
+ return -EPROBE_DEFER;
+ }
+
+ /* Each GPU has a target specific zap shader firmware name to use */
+ if (!adreno_gpu->info->zapfw) {
+ DRM_DEV_ERROR(&pdev->dev,
+ "Zap shader firmware file not specified for this target\n");
+ return -ENODEV;
+ }
+
+ ret = a5xx_zap_shader_dev_init(&pdev->dev, &a5xx_gpu->zap_dev);
+
+ if (!ret)
+ ret = zap_shader_load_mdt(&a5xx_gpu->zap_dev,
+ adreno_gpu->info->zapfw);
+
+ loaded = !ret;
+
+ return ret;
+}
+
#define A5XX_INT_MASK (A5XX_RBBM_INT_0_MASK_RBBM_AHB_ERROR | \
A5XX_RBBM_INT_0_MASK_RBBM_TRANSFER_TIMEOUT | \
A5XX_RBBM_INT_0_MASK_RBBM_ME_MS_TIMEOUT | \
@@ -488,8 +642,27 @@ static int a5xx_hw_init(struct msm_gpu *gpu)
return -EINVAL;
}
- /* Put the GPU into unsecure mode */
- gpu_write(gpu, REG_A5XX_RBBM_SECVID_TRUST_CNTL, 0x0);
+ /*
+ * Try to load a zap shader into the secure world. If successful
+ * we can use the CP to switch out of secure mode. If not then we
+ * have no resource but to try to switch ourselves out manually. If we
+ * guessed wrong then access to the RBBM_SECVID_TRUST_CNTL register will
+ * be blocked and a permissions violation will soon follow.
+ */
+ ret = a5xx_zap_shader_init(gpu);
+ if (!ret) {
+ OUT_PKT7(gpu->rb, CP_SET_SECURE_MODE, 1);
+ OUT_RING(gpu->rb, 0x00000000);
+
+ gpu->funcs->flush(gpu);
+ if (!gpu->funcs->idle(gpu))
+ return -EINVAL;
+ } else {
+ /* Print a warning so if we die, we know why */
+ dev_warn_once(gpu->dev->dev,
+ "Zap shader not enabled - using SECVID_TRUST_CNTL instead\n");
+ gpu_write(gpu, REG_A5XX_RBBM_SECVID_TRUST_CNTL, 0x0);
+ }
return 0;
}
@@ -521,6 +694,9 @@ static void a5xx_destroy(struct msm_gpu *gpu)
DBG("%s", gpu->name);
+ if (a5xx_gpu->zap_dev.parent)
+ device_unregister(&a5xx_gpu->zap_dev);
+
if (a5xx_gpu->pm4_bo) {
if (a5xx_gpu->pm4_iova)
msm_gem_put_iova(a5xx_gpu->pm4_bo, gpu->id);
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.h b/drivers/gpu/drm/msm/adreno/a5xx_gpu.h
index 1590f845d554..78408f56660e 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.h
@@ -36,6 +36,8 @@ struct a5xx_gpu {
uint32_t gpmu_dwords;
uint32_t lm_leakage;
+
+ struct device zap_dev;
};
#define to_a5xx_gpu(x) container_of(x, struct a5xx_gpu, base)
diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c
index c0fa5d1c75ff..b7bd6d393215 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_device.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_device.c
@@ -86,6 +86,7 @@ static const struct adreno_info gpulist[] = {
ADRENO_QUIRK_FAULT_DETECT_MASK,
.init = a5xx_gpu_init,
.gpmufw = "a530v3_gpmu.fw2",
+ .zapfw = "a530_zap.mdt",
},
};
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
index fb4831f9f80b..12b1483625f8 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
@@ -77,6 +77,7 @@ struct adreno_info {
uint32_t gmem;
enum adreno_quirks quirks;
struct msm_gpu *(*init)(struct drm_device *dev);
+ const char *zapfw;
};
const struct adreno_info *adreno_info(struct adreno_rev rev);