linux/drivers/gpu/drm/msm/adreno/a2xx_gpu.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* Copyright (c) 2018 The Linux Foundation. All rights reserved. */
   3
   4#include "a2xx_gpu.h"
   5#include "msm_gem.h"
   6#include "msm_mmu.h"
   7
   8extern bool hang_debug;
   9
  10static void a2xx_dump(struct msm_gpu *gpu);
  11static bool a2xx_idle(struct msm_gpu *gpu);
  12
  13static void a2xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
  14{
  15        struct msm_drm_private *priv = gpu->dev->dev_private;
  16        struct msm_ringbuffer *ring = submit->ring;
  17        unsigned int i;
  18
  19        for (i = 0; i < submit->nr_cmds; i++) {
  20                switch (submit->cmd[i].type) {
  21                case MSM_SUBMIT_CMD_IB_TARGET_BUF:
  22                        /* ignore IB-targets */
  23                        break;
  24                case MSM_SUBMIT_CMD_CTX_RESTORE_BUF:
  25                        /* ignore if there has not been a ctx switch: */
  26                        if (priv->lastctx == submit->queue->ctx)
  27                                break;
  28                        fallthrough;
  29                case MSM_SUBMIT_CMD_BUF:
  30                        OUT_PKT3(ring, CP_INDIRECT_BUFFER_PFD, 2);
  31                        OUT_RING(ring, lower_32_bits(submit->cmd[i].iova));
  32                        OUT_RING(ring, submit->cmd[i].size);
  33                        OUT_PKT2(ring);
  34                        break;
  35                }
  36        }
  37
  38        OUT_PKT0(ring, REG_AXXX_CP_SCRATCH_REG2, 1);
  39        OUT_RING(ring, submit->seqno);
  40
  41        /* wait for idle before cache flush/interrupt */
  42        OUT_PKT3(ring, CP_WAIT_FOR_IDLE, 1);
  43        OUT_RING(ring, 0x00000000);
  44
  45        OUT_PKT3(ring, CP_EVENT_WRITE, 3);
  46        OUT_RING(ring, CACHE_FLUSH_TS);
  47        OUT_RING(ring, rbmemptr(ring, fence));
  48        OUT_RING(ring, submit->seqno);
  49        OUT_PKT3(ring, CP_INTERRUPT, 1);
  50        OUT_RING(ring, 0x80000000);
  51
  52        adreno_flush(gpu, ring, REG_AXXX_CP_RB_WPTR);
  53}
  54
  55static bool a2xx_me_init(struct msm_gpu *gpu)
  56{
  57        struct msm_ringbuffer *ring = gpu->rb[0];
  58
  59        OUT_PKT3(ring, CP_ME_INIT, 18);
  60
  61        /* All fields present (bits 9:0) */
  62        OUT_RING(ring, 0x000003ff);
  63        /* Disable/Enable Real-Time Stream processing (present but ignored) */
  64        OUT_RING(ring, 0x00000000);
  65        /* Enable (2D <-> 3D) implicit synchronization (present but ignored) */
  66        OUT_RING(ring, 0x00000000);
  67
  68        OUT_RING(ring, REG_A2XX_RB_SURFACE_INFO - 0x2000);
  69        OUT_RING(ring, REG_A2XX_PA_SC_WINDOW_OFFSET - 0x2000);
  70        OUT_RING(ring, REG_A2XX_VGT_MAX_VTX_INDX - 0x2000);
  71        OUT_RING(ring, REG_A2XX_SQ_PROGRAM_CNTL - 0x2000);
  72        OUT_RING(ring, REG_A2XX_RB_DEPTHCONTROL - 0x2000);
  73        OUT_RING(ring, REG_A2XX_PA_SU_POINT_SIZE - 0x2000);
  74        OUT_RING(ring, REG_A2XX_PA_SC_LINE_CNTL - 0x2000);
  75        OUT_RING(ring, REG_A2XX_PA_SU_POLY_OFFSET_FRONT_SCALE - 0x2000);
  76
  77        /* Vertex and Pixel Shader Start Addresses in instructions
  78         * (3 DWORDS per instruction) */
  79        OUT_RING(ring, 0x80000180);
  80        /* Maximum Contexts */
  81        OUT_RING(ring, 0x00000001);
  82        /* Write Confirm Interval and The CP will wait the
  83         * wait_interval * 16 clocks between polling  */
  84        OUT_RING(ring, 0x00000000);
  85        /* NQ and External Memory Swap */
  86        OUT_RING(ring, 0x00000000);
  87        /* protected mode error checking (0x1f2 is REG_AXXX_CP_INT_CNTL) */
  88        OUT_RING(ring, 0x200001f2);
  89        /* Disable header dumping and Header dump address */
  90        OUT_RING(ring, 0x00000000);
  91        /* Header dump size */
  92        OUT_RING(ring, 0x00000000);
  93
  94        /* enable protected mode */
  95        OUT_PKT3(ring, CP_SET_PROTECTED_MODE, 1);
  96        OUT_RING(ring, 1);
  97
  98        adreno_flush(gpu, ring, REG_AXXX_CP_RB_WPTR);
  99        return a2xx_idle(gpu);
 100}
 101
 102static int a2xx_hw_init(struct msm_gpu *gpu)
 103{
 104        struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
 105        dma_addr_t pt_base, tran_error;
 106        uint32_t *ptr, len;
 107        int i, ret;
 108
 109        msm_gpummu_params(gpu->aspace->mmu, &pt_base, &tran_error);
 110
 111        DBG("%s", gpu->name);
 112
 113        /* halt ME to avoid ucode upload issues on a20x */
 114        gpu_write(gpu, REG_AXXX_CP_ME_CNTL, AXXX_CP_ME_CNTL_HALT);
 115
 116        gpu_write(gpu, REG_A2XX_RBBM_PM_OVERRIDE1, 0xfffffffe);
 117        gpu_write(gpu, REG_A2XX_RBBM_PM_OVERRIDE2, 0xffffffff);
 118
 119        /* note: kgsl uses 0x00000001 after first reset on a22x */
 120        gpu_write(gpu, REG_A2XX_RBBM_SOFT_RESET, 0xffffffff);
 121        msleep(30);
 122        gpu_write(gpu, REG_A2XX_RBBM_SOFT_RESET, 0x00000000);
 123
 124        if (adreno_is_a225(adreno_gpu))
 125                gpu_write(gpu, REG_A2XX_SQ_FLOW_CONTROL, 0x18000000);
 126
 127        /* note: kgsl uses 0x0000ffff for a20x */
 128        gpu_write(gpu, REG_A2XX_RBBM_CNTL, 0x00004442);
 129
 130        /* MPU: physical range */
 131        gpu_write(gpu, REG_A2XX_MH_MMU_MPU_BASE, 0x00000000);
 132        gpu_write(gpu, REG_A2XX_MH_MMU_MPU_END, 0xfffff000);
 133
 134        gpu_write(gpu, REG_A2XX_MH_MMU_CONFIG, A2XX_MH_MMU_CONFIG_MMU_ENABLE |
 135                A2XX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
 136                A2XX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
 137                A2XX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
 138                A2XX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
 139                A2XX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
 140                A2XX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
 141                A2XX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
 142                A2XX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
 143                A2XX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
 144                A2XX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR(BEH_TRAN_RNG) |
 145                A2XX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR(BEH_TRAN_RNG));
 146
 147        /* same as parameters in adreno_gpu */
 148        gpu_write(gpu, REG_A2XX_MH_MMU_VA_RANGE, SZ_16M |
 149                A2XX_MH_MMU_VA_RANGE_NUM_64KB_REGIONS(0xfff));
 150
 151        gpu_write(gpu, REG_A2XX_MH_MMU_PT_BASE, pt_base);
 152        gpu_write(gpu, REG_A2XX_MH_MMU_TRAN_ERROR, tran_error);
 153
 154        gpu_write(gpu, REG_A2XX_MH_MMU_INVALIDATE,
 155                A2XX_MH_MMU_INVALIDATE_INVALIDATE_ALL |
 156                A2XX_MH_MMU_INVALIDATE_INVALIDATE_TC);
 157
 158        gpu_write(gpu, REG_A2XX_MH_ARBITER_CONFIG,
 159                A2XX_MH_ARBITER_CONFIG_SAME_PAGE_LIMIT(16) |
 160                A2XX_MH_ARBITER_CONFIG_L1_ARB_ENABLE |
 161                A2XX_MH_ARBITER_CONFIG_L1_ARB_HOLD_ENABLE |
 162                A2XX_MH_ARBITER_CONFIG_PAGE_SIZE(1) |
 163                A2XX_MH_ARBITER_CONFIG_TC_REORDER_ENABLE |
 164                A2XX_MH_ARBITER_CONFIG_TC_ARB_HOLD_ENABLE |
 165                A2XX_MH_ARBITER_CONFIG_IN_FLIGHT_LIMIT_ENABLE |
 166                A2XX_MH_ARBITER_CONFIG_IN_FLIGHT_LIMIT(8) |
 167                A2XX_MH_ARBITER_CONFIG_CP_CLNT_ENABLE |
 168                A2XX_MH_ARBITER_CONFIG_VGT_CLNT_ENABLE |
 169                A2XX_MH_ARBITER_CONFIG_TC_CLNT_ENABLE |
 170                A2XX_MH_ARBITER_CONFIG_RB_CLNT_ENABLE |
 171                A2XX_MH_ARBITER_CONFIG_PA_CLNT_ENABLE);
 172        if (!adreno_is_a20x(adreno_gpu))
 173                gpu_write(gpu, REG_A2XX_MH_CLNT_INTF_CTRL_CONFIG1, 0x00032f07);
 174
 175        gpu_write(gpu, REG_A2XX_SQ_VS_PROGRAM, 0x00000000);
 176        gpu_write(gpu, REG_A2XX_SQ_PS_PROGRAM, 0x00000000);
 177
 178        gpu_write(gpu, REG_A2XX_RBBM_PM_OVERRIDE1, 0); /* 0x200 for msm8960? */
 179        gpu_write(gpu, REG_A2XX_RBBM_PM_OVERRIDE2, 0); /* 0x80/0x1a0 for a22x? */
 180
 181        /* note: gsl doesn't set this */
 182        gpu_write(gpu, REG_A2XX_RBBM_DEBUG, 0x00080000);
 183
 184        gpu_write(gpu, REG_A2XX_RBBM_INT_CNTL,
 185                A2XX_RBBM_INT_CNTL_RDERR_INT_MASK);
 186        gpu_write(gpu, REG_AXXX_CP_INT_CNTL,
 187                AXXX_CP_INT_CNTL_T0_PACKET_IN_IB_MASK |
 188                AXXX_CP_INT_CNTL_OPCODE_ERROR_MASK |
 189                AXXX_CP_INT_CNTL_PROTECTED_MODE_ERROR_MASK |
 190                AXXX_CP_INT_CNTL_RESERVED_BIT_ERROR_MASK |
 191                AXXX_CP_INT_CNTL_IB_ERROR_MASK |
 192                AXXX_CP_INT_CNTL_IB1_INT_MASK |
 193                AXXX_CP_INT_CNTL_RB_INT_MASK);
 194        gpu_write(gpu, REG_A2XX_SQ_INT_CNTL, 0);
 195        gpu_write(gpu, REG_A2XX_MH_INTERRUPT_MASK,
 196                A2XX_MH_INTERRUPT_MASK_AXI_READ_ERROR |
 197                A2XX_MH_INTERRUPT_MASK_AXI_WRITE_ERROR |
 198                A2XX_MH_INTERRUPT_MASK_MMU_PAGE_FAULT);
 199
 200        for (i = 3; i <= 5; i++)
 201                if ((SZ_16K << i) == adreno_gpu->gmem)
 202                        break;
 203        gpu_write(gpu, REG_A2XX_RB_EDRAM_INFO, i);
 204
 205        ret = adreno_hw_init(gpu);
 206        if (ret)
 207                return ret;
 208
 209        gpu_write(gpu, REG_AXXX_CP_RB_CNTL,
 210                MSM_GPU_RB_CNTL_DEFAULT | AXXX_CP_RB_CNTL_NO_UPDATE);
 211
 212        gpu_write(gpu, REG_AXXX_CP_RB_BASE, lower_32_bits(gpu->rb[0]->iova));
 213
 214        /* NOTE: PM4/micro-engine firmware registers look to be the same
 215         * for a2xx and a3xx.. we could possibly push that part down to
 216         * adreno_gpu base class.  Or push both PM4 and PFP but
 217         * parameterize the pfp ucode addr/data registers..
 218         */
 219
 220        /* Load PM4: */
 221        ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PM4]->data);
 222        len = adreno_gpu->fw[ADRENO_FW_PM4]->size / 4;
 223        DBG("loading PM4 ucode version: %x", ptr[1]);
 224
 225        gpu_write(gpu, REG_AXXX_CP_DEBUG,
 226                        AXXX_CP_DEBUG_MIU_128BIT_WRITE_ENABLE);
 227        gpu_write(gpu, REG_AXXX_CP_ME_RAM_WADDR, 0);
 228        for (i = 1; i < len; i++)
 229                gpu_write(gpu, REG_AXXX_CP_ME_RAM_DATA, ptr[i]);
 230
 231        /* Load PFP: */
 232        ptr = (uint32_t *)(adreno_gpu->fw[ADRENO_FW_PFP]->data);
 233        len = adreno_gpu->fw[ADRENO_FW_PFP]->size / 4;
 234        DBG("loading PFP ucode version: %x", ptr[5]);
 235
 236        gpu_write(gpu, REG_A2XX_CP_PFP_UCODE_ADDR, 0);
 237        for (i = 1; i < len; i++)
 238                gpu_write(gpu, REG_A2XX_CP_PFP_UCODE_DATA, ptr[i]);
 239
 240        gpu_write(gpu, REG_AXXX_CP_QUEUE_THRESHOLDS, 0x000C0804);
 241
 242        /* clear ME_HALT to start micro engine */
 243        gpu_write(gpu, REG_AXXX_CP_ME_CNTL, 0);
 244
 245        return a2xx_me_init(gpu) ? 0 : -EINVAL;
 246}
 247
 248static void a2xx_recover(struct msm_gpu *gpu)
 249{
 250        int i;
 251
 252        adreno_dump_info(gpu);
 253
 254        for (i = 0; i < 8; i++) {
 255                printk("CP_SCRATCH_REG%d: %u\n", i,
 256                        gpu_read(gpu, REG_AXXX_CP_SCRATCH_REG0 + i));
 257        }
 258
 259        /* dump registers before resetting gpu, if enabled: */
 260        if (hang_debug)
 261                a2xx_dump(gpu);
 262
 263        gpu_write(gpu, REG_A2XX_RBBM_SOFT_RESET, 1);
 264        gpu_read(gpu, REG_A2XX_RBBM_SOFT_RESET);
 265        gpu_write(gpu, REG_A2XX_RBBM_SOFT_RESET, 0);
 266        adreno_recover(gpu);
 267}
 268
 269static void a2xx_destroy(struct msm_gpu *gpu)
 270{
 271        struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
 272        struct a2xx_gpu *a2xx_gpu = to_a2xx_gpu(adreno_gpu);
 273
 274        DBG("%s", gpu->name);
 275
 276        adreno_gpu_cleanup(adreno_gpu);
 277
 278        kfree(a2xx_gpu);
 279}
 280
 281static bool a2xx_idle(struct msm_gpu *gpu)
 282{
 283        /* wait for ringbuffer to drain: */
 284        if (!adreno_idle(gpu, gpu->rb[0]))
 285                return false;
 286
 287        /* then wait for GPU to finish: */
 288        if (spin_until(!(gpu_read(gpu, REG_A2XX_RBBM_STATUS) &
 289                        A2XX_RBBM_STATUS_GUI_ACTIVE))) {
 290                DRM_ERROR("%s: timeout waiting for GPU to idle!\n", gpu->name);
 291
 292                /* TODO maybe we need to reset GPU here to recover from hang? */
 293                return false;
 294        }
 295
 296        return true;
 297}
 298
 299static irqreturn_t a2xx_irq(struct msm_gpu *gpu)
 300{
 301        uint32_t mstatus, status;
 302
 303        mstatus = gpu_read(gpu, REG_A2XX_MASTER_INT_SIGNAL);
 304
 305        if (mstatus & A2XX_MASTER_INT_SIGNAL_MH_INT_STAT) {
 306                status = gpu_read(gpu, REG_A2XX_MH_INTERRUPT_STATUS);
 307
 308                dev_warn(gpu->dev->dev, "MH_INT: %08X\n", status);
 309                dev_warn(gpu->dev->dev, "MMU_PAGE_FAULT: %08X\n",
 310                        gpu_read(gpu, REG_A2XX_MH_MMU_PAGE_FAULT));
 311
 312                gpu_write(gpu, REG_A2XX_MH_INTERRUPT_CLEAR, status);
 313        }
 314
 315        if (mstatus & A2XX_MASTER_INT_SIGNAL_CP_INT_STAT) {
 316                status = gpu_read(gpu, REG_AXXX_CP_INT_STATUS);
 317
 318                /* only RB_INT is expected */
 319                if (status & ~AXXX_CP_INT_CNTL_RB_INT_MASK)
 320                        dev_warn(gpu->dev->dev, "CP_INT: %08X\n", status);
 321
 322                gpu_write(gpu, REG_AXXX_CP_INT_ACK, status);
 323        }
 324
 325        if (mstatus & A2XX_MASTER_INT_SIGNAL_RBBM_INT_STAT) {
 326                status = gpu_read(gpu, REG_A2XX_RBBM_INT_STATUS);
 327
 328                dev_warn(gpu->dev->dev, "RBBM_INT: %08X\n", status);
 329
 330                gpu_write(gpu, REG_A2XX_RBBM_INT_ACK, status);
 331        }
 332
 333        msm_gpu_retire(gpu);
 334
 335        return IRQ_HANDLED;
 336}
 337
 338static const unsigned int a200_registers[] = {
 339        0x0000, 0x0002, 0x0004, 0x000B, 0x003B, 0x003D, 0x0040, 0x0044,
 340        0x0046, 0x0047, 0x01C0, 0x01C1, 0x01C3, 0x01C8, 0x01D5, 0x01D9,
 341        0x01DC, 0x01DD, 0x01EA, 0x01EA, 0x01EE, 0x01F3, 0x01F6, 0x01F7,
 342        0x01FC, 0x01FF, 0x0391, 0x0392, 0x039B, 0x039E, 0x03B2, 0x03B5,
 343        0x03B7, 0x03B7, 0x03F8, 0x03FB, 0x0440, 0x0440, 0x0443, 0x0444,
 344        0x044B, 0x044B, 0x044D, 0x044F, 0x0452, 0x0452, 0x0454, 0x045B,
 345        0x047F, 0x047F, 0x0578, 0x0587, 0x05C9, 0x05C9, 0x05D0, 0x05D0,
 346        0x0601, 0x0604, 0x0606, 0x0609, 0x060B, 0x060E, 0x0613, 0x0614,
 347        0x0A29, 0x0A2B, 0x0A2F, 0x0A31, 0x0A40, 0x0A43, 0x0A45, 0x0A45,
 348        0x0A4E, 0x0A4F, 0x0C2C, 0x0C2C, 0x0C30, 0x0C30, 0x0C38, 0x0C3C,
 349        0x0C40, 0x0C40, 0x0C44, 0x0C44, 0x0C80, 0x0C86, 0x0C88, 0x0C94,
 350        0x0C99, 0x0C9A, 0x0CA4, 0x0CA5, 0x0D00, 0x0D03, 0x0D06, 0x0D06,
 351        0x0D08, 0x0D0B, 0x0D34, 0x0D35, 0x0DAE, 0x0DC1, 0x0DC8, 0x0DD4,
 352        0x0DD8, 0x0DD9, 0x0E00, 0x0E00, 0x0E02, 0x0E04, 0x0E17, 0x0E1E,
 353        0x0EC0, 0x0EC9, 0x0ECB, 0x0ECC, 0x0ED0, 0x0ED0, 0x0ED4, 0x0ED7,
 354        0x0EE0, 0x0EE2, 0x0F01, 0x0F02, 0x0F0C, 0x0F0C, 0x0F0E, 0x0F12,
 355        0x0F26, 0x0F2A, 0x0F2C, 0x0F2C, 0x2000, 0x2002, 0x2006, 0x200F,
 356        0x2080, 0x2082, 0x2100, 0x2109, 0x210C, 0x2114, 0x2180, 0x2184,
 357        0x21F5, 0x21F7, 0x2200, 0x2208, 0x2280, 0x2283, 0x2293, 0x2294,
 358        0x2300, 0x2308, 0x2312, 0x2312, 0x2316, 0x231D, 0x2324, 0x2326,
 359        0x2380, 0x2383, 0x2400, 0x2402, 0x2406, 0x240F, 0x2480, 0x2482,
 360        0x2500, 0x2509, 0x250C, 0x2514, 0x2580, 0x2584, 0x25F5, 0x25F7,
 361        0x2600, 0x2608, 0x2680, 0x2683, 0x2693, 0x2694, 0x2700, 0x2708,
 362        0x2712, 0x2712, 0x2716, 0x271D, 0x2724, 0x2726, 0x2780, 0x2783,
 363        0x4000, 0x4003, 0x4800, 0x4805, 0x4900, 0x4900, 0x4908, 0x4908,
 364        ~0   /* sentinel */
 365};
 366
 367static const unsigned int a220_registers[] = {
 368        0x0000, 0x0002, 0x0004, 0x000B, 0x003B, 0x003D, 0x0040, 0x0044,
 369        0x0046, 0x0047, 0x01C0, 0x01C1, 0x01C3, 0x01C8, 0x01D5, 0x01D9,
 370        0x01DC, 0x01DD, 0x01EA, 0x01EA, 0x01EE, 0x01F3, 0x01F6, 0x01F7,
 371        0x01FC, 0x01FF, 0x0391, 0x0392, 0x039B, 0x039E, 0x03B2, 0x03B5,
 372        0x03B7, 0x03B7, 0x03F8, 0x03FB, 0x0440, 0x0440, 0x0443, 0x0444,
 373        0x044B, 0x044B, 0x044D, 0x044F, 0x0452, 0x0452, 0x0454, 0x045B,
 374        0x047F, 0x047F, 0x0578, 0x0587, 0x05C9, 0x05C9, 0x05D0, 0x05D0,
 375        0x0601, 0x0604, 0x0606, 0x0609, 0x060B, 0x060E, 0x0613, 0x0614,
 376        0x0A29, 0x0A2B, 0x0A2F, 0x0A31, 0x0A40, 0x0A40, 0x0A42, 0x0A43,
 377        0x0A45, 0x0A45, 0x0A4E, 0x0A4F, 0x0C30, 0x0C30, 0x0C38, 0x0C39,
 378        0x0C3C, 0x0C3C, 0x0C80, 0x0C81, 0x0C88, 0x0C93, 0x0D00, 0x0D03,
 379        0x0D05, 0x0D06, 0x0D08, 0x0D0B, 0x0D34, 0x0D35, 0x0DAE, 0x0DC1,
 380        0x0DC8, 0x0DD4, 0x0DD8, 0x0DD9, 0x0E00, 0x0E00, 0x0E02, 0x0E04,
 381        0x0E17, 0x0E1E, 0x0EC0, 0x0EC9, 0x0ECB, 0x0ECC, 0x0ED0, 0x0ED0,
 382        0x0ED4, 0x0ED7, 0x0EE0, 0x0EE2, 0x0F01, 0x0F02, 0x2000, 0x2002,
 383        0x2006, 0x200F, 0x2080, 0x2082, 0x2100, 0x2102, 0x2104, 0x2109,
 384        0x210C, 0x2114, 0x2180, 0x2184, 0x21F5, 0x21F7, 0x2200, 0x2202,
 385        0x2204, 0x2204, 0x2208, 0x2208, 0x2280, 0x2282, 0x2294, 0x2294,
 386        0x2300, 0x2308, 0x2309, 0x230A, 0x2312, 0x2312, 0x2316, 0x2316,
 387        0x2318, 0x231D, 0x2324, 0x2326, 0x2380, 0x2383, 0x2400, 0x2402,
 388        0x2406, 0x240F, 0x2480, 0x2482, 0x2500, 0x2502, 0x2504, 0x2509,
 389        0x250C, 0x2514, 0x2580, 0x2584, 0x25F5, 0x25F7, 0x2600, 0x2602,
 390        0x2604, 0x2606, 0x2608, 0x2608, 0x2680, 0x2682, 0x2694, 0x2694,
 391        0x2700, 0x2708, 0x2712, 0x2712, 0x2716, 0x2716, 0x2718, 0x271D,
 392        0x2724, 0x2726, 0x2780, 0x2783, 0x4000, 0x4003, 0x4800, 0x4805,
 393        0x4900, 0x4900, 0x4908, 0x4908,
 394        ~0   /* sentinel */
 395};
 396
 397static const unsigned int a225_registers[] = {
 398        0x0000, 0x0002, 0x0004, 0x000B, 0x003B, 0x003D, 0x0040, 0x0044,
 399        0x0046, 0x0047, 0x013C, 0x013C, 0x0140, 0x014F, 0x01C0, 0x01C1,
 400        0x01C3, 0x01C8, 0x01D5, 0x01D9, 0x01DC, 0x01DD, 0x01EA, 0x01EA,
 401        0x01EE, 0x01F3, 0x01F6, 0x01F7, 0x01FC, 0x01FF, 0x0391, 0x0392,
 402        0x039B, 0x039E, 0x03B2, 0x03B5, 0x03B7, 0x03B7, 0x03F8, 0x03FB,
 403        0x0440, 0x0440, 0x0443, 0x0444, 0x044B, 0x044B, 0x044D, 0x044F,
 404        0x0452, 0x0452, 0x0454, 0x045B, 0x047F, 0x047F, 0x0578, 0x0587,
 405        0x05C9, 0x05C9, 0x05D0, 0x05D0, 0x0601, 0x0604, 0x0606, 0x0609,
 406        0x060B, 0x060E, 0x0613, 0x0614, 0x0A29, 0x0A2B, 0x0A2F, 0x0A31,
 407        0x0A40, 0x0A40, 0x0A42, 0x0A43, 0x0A45, 0x0A45, 0x0A4E, 0x0A4F,
 408        0x0C01, 0x0C1D, 0x0C30, 0x0C30, 0x0C38, 0x0C39, 0x0C3C, 0x0C3C,
 409        0x0C80, 0x0C81, 0x0C88, 0x0C93, 0x0D00, 0x0D03, 0x0D05, 0x0D06,
 410        0x0D08, 0x0D0B, 0x0D34, 0x0D35, 0x0DAE, 0x0DC1, 0x0DC8, 0x0DD4,
 411        0x0DD8, 0x0DD9, 0x0E00, 0x0E00, 0x0E02, 0x0E04, 0x0E17, 0x0E1E,
 412        0x0EC0, 0x0EC9, 0x0ECB, 0x0ECC, 0x0ED0, 0x0ED0, 0x0ED4, 0x0ED7,
 413        0x0EE0, 0x0EE2, 0x0F01, 0x0F02, 0x2000, 0x200F, 0x2080, 0x2082,
 414        0x2100, 0x2109, 0x210C, 0x2114, 0x2180, 0x2184, 0x21F5, 0x21F7,
 415        0x2200, 0x2202, 0x2204, 0x2206, 0x2208, 0x2210, 0x2220, 0x2222,
 416        0x2280, 0x2282, 0x2294, 0x2294, 0x2297, 0x2297, 0x2300, 0x230A,
 417        0x2312, 0x2312, 0x2315, 0x2316, 0x2318, 0x231D, 0x2324, 0x2326,
 418        0x2340, 0x2357, 0x2360, 0x2360, 0x2380, 0x2383, 0x2400, 0x240F,
 419        0x2480, 0x2482, 0x2500, 0x2509, 0x250C, 0x2514, 0x2580, 0x2584,
 420        0x25F5, 0x25F7, 0x2600, 0x2602, 0x2604, 0x2606, 0x2608, 0x2610,
 421        0x2620, 0x2622, 0x2680, 0x2682, 0x2694, 0x2694, 0x2697, 0x2697,
 422        0x2700, 0x270A, 0x2712, 0x2712, 0x2715, 0x2716, 0x2718, 0x271D,
 423        0x2724, 0x2726, 0x2740, 0x2757, 0x2760, 0x2760, 0x2780, 0x2783,
 424        0x4000, 0x4003, 0x4800, 0x4806, 0x4808, 0x4808, 0x4900, 0x4900,
 425        0x4908, 0x4908,
 426        ~0   /* sentinel */
 427};
 428
 429/* would be nice to not have to duplicate the _show() stuff with printk(): */
 430static void a2xx_dump(struct msm_gpu *gpu)
 431{
 432        printk("status:   %08x\n",
 433                        gpu_read(gpu, REG_A2XX_RBBM_STATUS));
 434        adreno_dump(gpu);
 435}
 436
 437static struct msm_gpu_state *a2xx_gpu_state_get(struct msm_gpu *gpu)
 438{
 439        struct msm_gpu_state *state = kzalloc(sizeof(*state), GFP_KERNEL);
 440
 441        if (!state)
 442                return ERR_PTR(-ENOMEM);
 443
 444        adreno_gpu_state_get(gpu, state);
 445
 446        state->rbbm_status = gpu_read(gpu, REG_A2XX_RBBM_STATUS);
 447
 448        return state;
 449}
 450
 451static struct msm_gem_address_space *
 452a2xx_create_address_space(struct msm_gpu *gpu, struct platform_device *pdev)
 453{
 454        struct msm_mmu *mmu = msm_gpummu_new(&pdev->dev, gpu);
 455        struct msm_gem_address_space *aspace;
 456
 457        aspace = msm_gem_address_space_create(mmu, "gpu", SZ_16M,
 458                0xfff * SZ_64K);
 459
 460        if (IS_ERR(aspace) && !IS_ERR(mmu))
 461                mmu->funcs->destroy(mmu);
 462
 463        return aspace;
 464}
 465
 466static u32 a2xx_get_rptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
 467{
 468        ring->memptrs->rptr = gpu_read(gpu, REG_AXXX_CP_RB_RPTR);
 469        return ring->memptrs->rptr;
 470}
 471
 472static const struct adreno_gpu_funcs funcs = {
 473        .base = {
 474                .get_param = adreno_get_param,
 475                .hw_init = a2xx_hw_init,
 476                .pm_suspend = msm_gpu_pm_suspend,
 477                .pm_resume = msm_gpu_pm_resume,
 478                .recover = a2xx_recover,
 479                .submit = a2xx_submit,
 480                .active_ring = adreno_active_ring,
 481                .irq = a2xx_irq,
 482                .destroy = a2xx_destroy,
 483#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP)
 484                .show = adreno_show,
 485#endif
 486                .gpu_state_get = a2xx_gpu_state_get,
 487                .gpu_state_put = adreno_gpu_state_put,
 488                .create_address_space = a2xx_create_address_space,
 489                .get_rptr = a2xx_get_rptr,
 490        },
 491};
 492
 493static const struct msm_gpu_perfcntr perfcntrs[] = {
 494/* TODO */
 495};
 496
 497struct msm_gpu *a2xx_gpu_init(struct drm_device *dev)
 498{
 499        struct a2xx_gpu *a2xx_gpu = NULL;
 500        struct adreno_gpu *adreno_gpu;
 501        struct msm_gpu *gpu;
 502        struct msm_drm_private *priv = dev->dev_private;
 503        struct platform_device *pdev = priv->gpu_pdev;
 504        int ret;
 505
 506        if (!pdev) {
 507                dev_err(dev->dev, "no a2xx device\n");
 508                ret = -ENXIO;
 509                goto fail;
 510        }
 511
 512        a2xx_gpu = kzalloc(sizeof(*a2xx_gpu), GFP_KERNEL);
 513        if (!a2xx_gpu) {
 514                ret = -ENOMEM;
 515                goto fail;
 516        }
 517
 518        adreno_gpu = &a2xx_gpu->base;
 519        gpu = &adreno_gpu->base;
 520
 521        gpu->perfcntrs = perfcntrs;
 522        gpu->num_perfcntrs = ARRAY_SIZE(perfcntrs);
 523
 524        if (adreno_is_a20x(adreno_gpu))
 525                adreno_gpu->registers = a200_registers;
 526        else if (adreno_is_a225(adreno_gpu))
 527                adreno_gpu->registers = a225_registers;
 528        else
 529                adreno_gpu->registers = a220_registers;
 530
 531        ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 1);
 532        if (ret)
 533                goto fail;
 534
 535        if (!gpu->aspace) {
 536                dev_err(dev->dev, "No memory protection without MMU\n");
 537                if (!allow_vram_carveout) {
 538                        ret = -ENXIO;
 539                        goto fail;
 540                }
 541        }
 542
 543        return gpu;
 544
 545fail:
 546        if (a2xx_gpu)
 547                a2xx_destroy(&a2xx_gpu->base.base);
 548
 549        return ERR_PTR(ret);
 550}
 551