drm/etnaviv: add clock gating workaround for GC7000 r6202
[linux-2.6-microblaze.git] / drivers / gpu / drm / etnaviv / etnaviv_gpu.c
index c6404b8..c297fff 100644 (file)
 #include "state_hi.xml.h"
 #include "cmdstream.xml.h"
 
-#ifndef PHYS_OFFSET
-#define PHYS_OFFSET 0
-#endif
-
 static const struct platform_device_id gpu_ids[] = {
        { .name = "etnaviv-gpu,2d" },
        { },
@@ -156,6 +152,18 @@ int etnaviv_gpu_get_param(struct etnaviv_gpu *gpu, u32 param, u64 *value)
                        *value = ~0ULL;
                break;
 
+       case ETNAVIV_PARAM_GPU_PRODUCT_ID:
+               *value = gpu->identity.product_id;
+               break;
+
+       case ETNAVIV_PARAM_GPU_CUSTOMER_ID:
+               *value = gpu->identity.customer_id;
+               break;
+
+       case ETNAVIV_PARAM_GPU_ECO_ID:
+               *value = gpu->identity.eco_id;
+               break;
+
        default:
                DBG("%s: invalid param: %u", dev_name(gpu->dev), param);
                return -EINVAL;
@@ -605,6 +613,12 @@ static void etnaviv_gpu_enable_mlcg(struct etnaviv_gpu *gpu)
            etnaviv_is_model_rev(gpu, GC2000, 0x5108))
                pmc |= VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_TX;
 
+       /* Disable SE, RA and TX clock gating on affected core revisions. */
+       if (etnaviv_is_model_rev(gpu, GC7000, 0x6202))
+               pmc |= VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_SE |
+                      VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_RA |
+                      VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_TX;
+
        pmc |= VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_RA_HZ;
        pmc |= VIVS_PM_MODULE_CONTROLS_DISABLE_MODULE_CLOCK_GATING_RA_EZ;
 
@@ -724,6 +738,7 @@ static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu)
 int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
 {
        struct etnaviv_drm_private *priv = gpu->drm->dev_private;
+       dma_addr_t cmdbuf_paddr;
        int ret, i;
 
        ret = pm_runtime_get_sync(gpu->dev);
@@ -766,28 +781,6 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
        if (ret)
                goto fail;
 
-       /*
-        * Set the GPU linear window to be at the end of the DMA window, where
-        * the CMA area is likely to reside. This ensures that we are able to
-        * map the command buffers while having the linear window overlap as
-        * much RAM as possible, so we can optimize mappings for other buffers.
-        *
-        * For 3D cores only do this if MC2.0 is present, as with MC1.0 it leads
-        * to different views of the memory on the individual engines.
-        */
-       if (!(gpu->identity.features & chipFeatures_PIPE_3D) ||
-           (gpu->identity.minor_features0 & chipMinorFeatures0_MC20)) {
-               u32 dma_mask = (u32)dma_get_required_mask(gpu->dev);
-               if (dma_mask < PHYS_OFFSET + SZ_2G)
-                       priv->mmu_global->memory_base = PHYS_OFFSET;
-               else
-                       priv->mmu_global->memory_base = dma_mask - SZ_2G + 1;
-       } else if (PHYS_OFFSET >= SZ_2G) {
-               dev_info(gpu->dev, "Need to move linear window on MC1.0, disabling TS\n");
-               priv->mmu_global->memory_base = PHYS_OFFSET;
-               gpu->identity.features &= ~chipFeatures_FAST_CLEAR;
-       }
-
        /*
         * If the GPU is part of a system with DMA addressing limitations,
         * request pages for our SHM backend buffers from the DMA32 zone to
@@ -804,6 +797,31 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
                goto fail;
        }
 
+       /*
+        * Set the GPU linear window to cover the cmdbuf region, as the GPU
+        * won't be able to start execution otherwise. The alignment to 128M is
+        * chosen arbitrarily but helps in debugging, as the MMU offset
+        * calculations are much more straight forward this way.
+        *
+        * On MC1.0 cores the linear window offset is ignored by the TS engine,
+        * leading to inconsistent memory views. Avoid using the offset on those
+        * cores if possible, otherwise disable the TS feature.
+        */
+       cmdbuf_paddr = ALIGN_DOWN(etnaviv_cmdbuf_get_pa(&gpu->buffer), SZ_128M);
+
+       if (!(gpu->identity.features & chipFeatures_PIPE_3D) ||
+           (gpu->identity.minor_features0 & chipMinorFeatures0_MC20)) {
+               if (cmdbuf_paddr >= SZ_2G)
+                       priv->mmu_global->memory_base = SZ_2G;
+               else
+                       priv->mmu_global->memory_base = cmdbuf_paddr;
+       } else if (cmdbuf_paddr + SZ_128M >= SZ_2G) {
+               dev_info(gpu->dev,
+                        "Need to move linear window on MC1.0, disabling TS\n");
+               gpu->identity.features &= ~chipFeatures_FAST_CLEAR;
+               priv->mmu_global->memory_base = SZ_2G;
+       }
+
        /* Setup event management */
        spin_lock_init(&gpu->event_spinlock);
        init_completion(&gpu->event_free);
@@ -1771,10 +1789,8 @@ static int etnaviv_gpu_platform_probe(struct platform_device *pdev)
 
        /* Get Interrupt: */
        gpu->irq = platform_get_irq(pdev, 0);
-       if (gpu->irq < 0) {
-               dev_err(dev, "failed to get irq: %d\n", gpu->irq);
+       if (gpu->irq < 0)
                return gpu->irq;
-       }
 
        err = devm_request_irq(&pdev->dev, gpu->irq, irq_handler, 0,
                               dev_name(gpu->dev), gpu);