/* Gracefully try to shut down the GMU and by extension the GPU */ static void a6xx_gmu_shutdown(struct a6xx_gmu *gmu) { struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu); struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; struct msm_gpu *gpu = &adreno_gpu->base; u32 val; /* * The GMU may still be in slumber unless the GPU started so check and * skip putting it back into slumber if so */ val = gmu_read(gmu, REG_A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE); if (val != 0xf) { int ret = a6xx_gmu_wait_for_idle(gmu); /* If the GMU isn't responding assume it is hung */ if (ret) { a6xx_gmu_force_off(gmu); return; } /* Clear the VBIF pipe before shutting down */ gpu_write(gpu, REG_A6XX_VBIF_XIN_HALT_CTRL0, 0xf); spin_until((gpu_read(gpu, REG_A6XX_VBIF_XIN_HALT_CTRL1) & 0xf) == 0xf); gpu_write(gpu, REG_A6XX_VBIF_XIN_HALT_CTRL0, 0); /* tell the GMU we want to slumber */ a6xx_gmu_notify_slumber(gmu); ret = gmu_poll_timeout(gmu, REG_A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS, val, !(val & A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS_GPUBUSYIGNAHB), 100, 10000); /* * Let the user know we failed to slumber but don't worry too * much because we are powering down anyway */ if (ret) DRM_DEV_ERROR(gmu->dev, "Unable to slumber GMU: status = 0%x/0%x\n", gmu_read(gmu, REG_A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS), gmu_read(gmu, REG_A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS2)); } /* Turn off HFI */ a6xx_hfi_stop(gmu); /* Stop the interrupts and mask the hardware */ a6xx_gmu_irq_disable(gmu); /* Tell RPMh to power off the GPU */ a6xx_rpmh_stop(gmu); }
static void a4xx_recover(struct msm_gpu *gpu) { adreno_dump_info(gpu); /* dump registers before resetting gpu, if enabled: */ if (hang_debug) a4xx_dump(gpu); gpu_write(gpu, REG_A4XX_RBBM_SW_RESET_CMD, 1); gpu_read(gpu, REG_A4XX_RBBM_SW_RESET_CMD); gpu_write(gpu, REG_A4XX_RBBM_SW_RESET_CMD, 0); adreno_recover(gpu); }
void memorymap_registers_write(uint32 Addr, uint8 Value) { #ifdef DEBUG printf("Addr 0x%.2x, Value 0x%.2x\n", Addr, Value); #endif memorymap_regs[Addr&0x1fff] = Value; switch (Addr&0x1fff) { case 0x00: case 0x01: case 0x02: case 0x03: gpu_write(Addr, Value); break; case 0x22: io_write(Addr, Value); break; case 0x23: case 0x24: timer_write(Addr, Value); break; case 0x26: //fprintf(log_get(), "memorymap: writing 0x%.2x to rom bank register\n", Value); memorymap_lowerRomBank = memorymap_programRom + ((((uint32)Value) & 0x60) << 9); memorymap_upperRomBank = memorymap_programRom + (memorymap_programRomSize==0x10000?0xc000:0x4000); return; case 0x27: //fprintf(log_get(), "regs: writing 0x%.2x from 0x%.4x\n", Value, Addr); break; case 0x10: case 0x11: case 0x12: case 0x13: // ALEK case 0x14: case 0x15: case 0x16: case 0x17: // ALEK #ifndef NOAUDIO soundport_w(((Addr&0x4)>>2), Addr&3, Value); break; #endif //sound_write(Addr&7, Value); break; case 0x28: case 0x29: case 0x2a: #ifndef NOAUDIO svision_noise_w(Addr&0x07, Value); break; #endif //sound_noise_write(Addr&0x07, Value); break; case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: #ifdef GP2X if(currentConfig.enable_sound) sound_audio_dma(Addr&0x07, Value); break; #else svision_sounddma_w(Addr&0x07, Value); break; #endif break; } }
static void a4xx_recover(struct msm_gpu *gpu) { int i; adreno_dump_info(gpu); for (i = 0; i < 8; i++) { printk("CP_SCRATCH_REG%d: %u\n", i, gpu_read(gpu, REG_AXXX_CP_SCRATCH_REG0 + i)); } /* dump registers before resetting gpu, if enabled: */ if (hang_debug) a4xx_dump(gpu); gpu_write(gpu, REG_A4XX_RBBM_SW_RESET_CMD, 1); gpu_read(gpu, REG_A4XX_RBBM_SW_RESET_CMD); gpu_write(gpu, REG_A4XX_RBBM_SW_RESET_CMD, 0); adreno_recover(gpu); }
/* * a4xx_enable_hwcg() - Program the clock control registers * @device: The adreno device pointer */ static void a4xx_enable_hwcg(struct msm_gpu *gpu) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); unsigned int i; for (i = 0; i < 4; i++) gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL_TP(i), 0x02222202); for (i = 0; i < 4; i++) gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL2_TP(i), 0x00002222); for (i = 0; i < 4; i++) gpu_write(gpu, REG_A4XX_RBBM_CLOCK_HYST_TP(i), 0x0E739CE7); for (i = 0; i < 4; i++) gpu_write(gpu, REG_A4XX_RBBM_CLOCK_DELAY_TP(i), 0x00111111); for (i = 0; i < 4; i++) gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL_SP(i), 0x22222222); for (i = 0; i < 4; i++) gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL2_SP(i), 0x00222222); for (i = 0; i < 4; i++) gpu_write(gpu, REG_A4XX_RBBM_CLOCK_HYST_SP(i), 0x00000104); for (i = 0; i < 4; i++) gpu_write(gpu, REG_A4XX_RBBM_CLOCK_DELAY_SP(i), 0x00000081); gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL_UCHE, 0x22222222); gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL2_UCHE, 0x02222222); gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL3_UCHE, 0x00000000); gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL4_UCHE, 0x00000000); gpu_write(gpu, REG_A4XX_RBBM_CLOCK_HYST_UCHE, 0x00004444); gpu_write(gpu, REG_A4XX_RBBM_CLOCK_DELAY_UCHE, 0x00001112); for (i = 0; i < 4; i++) gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL_RB(i), 0x22222222); /* Disable L1 clocking in A420 due to CCU issues with it */ for (i = 0; i < 4; i++) { if (adreno_is_a420(adreno_gpu)) { gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL2_RB(i), 0x00002020); } else { gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL2_RB(i), 0x00022020); } } for (i = 0; i < 4; i++) { gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL_MARB_CCU(i), 0x00000922); } for (i = 0; i < 4; i++) { gpu_write(gpu, REG_A4XX_RBBM_CLOCK_HYST_RB_MARB_CCU(i), 0x00000000); } for (i = 0; i < 4; i++) { gpu_write(gpu, REG_A4XX_RBBM_CLOCK_DELAY_RB_MARB_CCU_L1(i), 0x00000001); } gpu_write(gpu, REG_A4XX_RBBM_CLOCK_MODE_GPC, 0x02222222); gpu_write(gpu, REG_A4XX_RBBM_CLOCK_HYST_GPC, 0x04100104); gpu_write(gpu, REG_A4XX_RBBM_CLOCK_DELAY_GPC, 0x00022222); gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL_COM_DCOM, 0x00000022); gpu_write(gpu, REG_A4XX_RBBM_CLOCK_HYST_COM_DCOM, 0x0000010F); gpu_write(gpu, REG_A4XX_RBBM_CLOCK_DELAY_COM_DCOM, 0x00000022); gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL_TSE_RAS_RBBM, 0x00222222); gpu_write(gpu, REG_A4XX_RBBM_CLOCK_HYST_TSE_RAS_RBBM, 0x00004104); gpu_write(gpu, REG_A4XX_RBBM_CLOCK_DELAY_TSE_RAS_RBBM, 0x00000222); gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL_HLSQ , 0x00000000); gpu_write(gpu, REG_A4XX_RBBM_CLOCK_HYST_HLSQ, 0x00000000); gpu_write(gpu, REG_A4XX_RBBM_CLOCK_DELAY_HLSQ, 0x00220000); /* Early A430's have a timing issue with SP/TP power collapse; disabling HW clock gating prevents it. */ if (adreno_is_a430(adreno_gpu) && adreno_gpu->rev.patchid < 2) gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL, 0); else gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL, 0xAAAAAAAA); gpu_write(gpu, REG_A4XX_RBBM_CLOCK_CTL2, 0); }
static int a4xx_hw_init(struct msm_gpu *gpu) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); struct a4xx_gpu *a4xx_gpu = to_a4xx_gpu(adreno_gpu); uint32_t *ptr, len; int i, ret; if (adreno_is_a420(adreno_gpu)) { gpu_write(gpu, REG_A4XX_VBIF_ABIT_SORT, 0x0001001F); gpu_write(gpu, REG_A4XX_VBIF_ABIT_SORT_CONF, 0x000000A4); gpu_write(gpu, REG_A4XX_VBIF_GATE_OFF_WRREQ_EN, 0x00000001); gpu_write(gpu, REG_A4XX_VBIF_IN_RD_LIM_CONF0, 0x18181818); gpu_write(gpu, REG_A4XX_VBIF_IN_RD_LIM_CONF1, 0x00000018); gpu_write(gpu, REG_A4XX_VBIF_IN_WR_LIM_CONF0, 0x18181818); gpu_write(gpu, REG_A4XX_VBIF_IN_WR_LIM_CONF1, 0x00000018); gpu_write(gpu, REG_A4XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x00000003); } else if (adreno_is_a430(adreno_gpu)) { gpu_write(gpu, REG_A4XX_VBIF_GATE_OFF_WRREQ_EN, 0x00000001); gpu_write(gpu, REG_A4XX_VBIF_IN_RD_LIM_CONF0, 0x18181818); gpu_write(gpu, REG_A4XX_VBIF_IN_RD_LIM_CONF1, 0x00000018); gpu_write(gpu, REG_A4XX_VBIF_IN_WR_LIM_CONF0, 0x18181818); gpu_write(gpu, REG_A4XX_VBIF_IN_WR_LIM_CONF1, 0x00000018); gpu_write(gpu, REG_A4XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x00000003); } else { BUG(); } /* Make all blocks contribute to the GPU BUSY perf counter */ gpu_write(gpu, REG_A4XX_RBBM_GPU_BUSY_MASKED, 0xffffffff); /* Tune the hystersis counters for SP and CP idle detection */ gpu_write(gpu, REG_A4XX_RBBM_SP_HYST_CNT, 0x10); gpu_write(gpu, REG_A4XX_RBBM_WAIT_IDLE_CLOCKS_CTL, 0x10); if (adreno_is_a430(adreno_gpu)) { gpu_write(gpu, REG_A4XX_RBBM_WAIT_IDLE_CLOCKS_CTL2, 0x30); } /* Enable the RBBM error reporting bits */ gpu_write(gpu, REG_A4XX_RBBM_AHB_CTL0, 0x00000001); /* Enable AHB error reporting*/ gpu_write(gpu, REG_A4XX_RBBM_AHB_CTL1, 0xa6ffffff); /* Enable power counters*/ gpu_write(gpu, REG_A4XX_RBBM_RBBM_CTL, 0x00000030); /* * Turn on hang detection - this spews a lot of useful information * into the RBBM registers on a hang: */ gpu_write(gpu, REG_A4XX_RBBM_INTERFACE_HANG_INT_CTL, (1 << 30) | 0xFFFF); gpu_write(gpu, REG_A4XX_RB_GMEM_BASE_ADDR, (unsigned int)(a4xx_gpu->ocmem_base >> 14)); /* Turn on performance counters: */ gpu_write(gpu, REG_A4XX_RBBM_PERFCTR_CTL, 0x01); /* use the first CP counter for timestamp queries.. userspace may set * this as well but it selects the same counter/countable: */ gpu_write(gpu, REG_A4XX_CP_PERFCTR_CP_SEL_0, CP_ALWAYS_COUNT); if (adreno_is_a430(adreno_gpu)) gpu_write(gpu, REG_A4XX_UCHE_CACHE_WAYS_VFD, 0x07); /* Disable L2 bypass to avoid UCHE out of bounds errors */ gpu_write(gpu, REG_A4XX_UCHE_TRAP_BASE_LO, 0xffff0000); gpu_write(gpu, REG_A4XX_UCHE_TRAP_BASE_HI, 0xffff0000); gpu_write(gpu, REG_A4XX_CP_DEBUG, (1 << 25) | (adreno_is_a420(adreno_gpu) ? (1 << 29) : 0)); /* On A430 enable SP regfile sleep for power savings */ /* TODO downstream does this for !420, so maybe applies for 405 too? */ if (!adreno_is_a420(adreno_gpu)) { gpu_write(gpu, REG_A4XX_RBBM_SP_REGFILE_SLEEP_CNTL_0, 0x00000441); gpu_write(gpu, REG_A4XX_RBBM_SP_REGFILE_SLEEP_CNTL_1, 0x00000441); } a4xx_enable_hwcg(gpu); /* * For A420 set RBBM_CLOCK_DELAY_HLSQ.CGC_HLSQ_TP_EARLY_CYC >= 2 * due to timing issue with HLSQ_TP_CLK_EN */ if (adreno_is_a420(adreno_gpu)) { unsigned int val; val = gpu_read(gpu, REG_A4XX_RBBM_CLOCK_DELAY_HLSQ); val &= ~A4XX_CGC_HLSQ_EARLY_CYC__MASK; val |= 2 << A4XX_CGC_HLSQ_EARLY_CYC__SHIFT; gpu_write(gpu, REG_A4XX_RBBM_CLOCK_DELAY_HLSQ, val); } /* setup access protection: */ gpu_write(gpu, REG_A4XX_CP_PROTECT_CTRL, 0x00000007); /* RBBM registers */ gpu_write(gpu, REG_A4XX_CP_PROTECT(0), 0x62000010); gpu_write(gpu, REG_A4XX_CP_PROTECT(1), 0x63000020); gpu_write(gpu, REG_A4XX_CP_PROTECT(2), 0x64000040); gpu_write(gpu, REG_A4XX_CP_PROTECT(3), 0x65000080); gpu_write(gpu, REG_A4XX_CP_PROTECT(4), 0x66000100); gpu_write(gpu, REG_A4XX_CP_PROTECT(5), 0x64000200); /* CP registers */ gpu_write(gpu, REG_A4XX_CP_PROTECT(6), 0x67000800); gpu_write(gpu, REG_A4XX_CP_PROTECT(7), 0x64001600); /* RB registers */ gpu_write(gpu, REG_A4XX_CP_PROTECT(8), 0x60003300); /* HLSQ registers */ gpu_write(gpu, REG_A4XX_CP_PROTECT(9), 0x60003800); /* VPC registers */ gpu_write(gpu, REG_A4XX_CP_PROTECT(10), 0x61003980); /* SMMU registers */ gpu_write(gpu, REG_A4XX_CP_PROTECT(11), 0x6e010000); gpu_write(gpu, REG_A4XX_RBBM_INT_0_MASK, A4XX_INT0_MASK); ret = adreno_hw_init(gpu); if (ret) return ret; /* Load PM4: */ ptr = (uint32_t *)(adreno_gpu->pm4->data); len = adreno_gpu->pm4->size / 4; DBG("loading PM4 ucode version: %u", ptr[0]); gpu_write(gpu, REG_A4XX_CP_ME_RAM_WADDR, 0); for (i = 1; i < len; i++) gpu_write(gpu, REG_A4XX_CP_ME_RAM_DATA, ptr[i]); /* Load PFP: */ ptr = (uint32_t *)(adreno_gpu->pfp->data); len = adreno_gpu->pfp->size / 4; DBG("loading PFP ucode version: %u", ptr[0]); gpu_write(gpu, REG_A4XX_CP_PFP_UCODE_ADDR, 0); for (i = 1; i < len; i++) gpu_write(gpu, REG_A4XX_CP_PFP_UCODE_DATA, ptr[i]); /* clear ME_HALT to start micro engine */ gpu_write(gpu, REG_A4XX_CP_ME_CNTL, 0); return a4xx_me_init(gpu) ? 0 : -EINVAL; }
static int a3xx_hw_init(struct msm_gpu *gpu) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); struct a3xx_gpu *a3xx_gpu = to_a3xx_gpu(adreno_gpu); uint32_t *ptr, len; int i, ret; DBG("%s", gpu->name); if (adreno_is_a305(adreno_gpu)) { /* Set up 16 deep read/write request queues: */ gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010); gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010); gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010); gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010); gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303); gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010); gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010); /* Enable WR-REQ: */ gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000ff); /* Set up round robin arbitration between both AXI ports: */ gpu_write(gpu, REG_A3XX_VBIF_ARB_CTL, 0x00000030); /* Set up AOOO: */ gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003c); gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0x003c003c); } else if (adreno_is_a320(adreno_gpu)) { /* Set up 16 deep read/write request queues: */ gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010); gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010); gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x10101010); gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x10101010); gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303); gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF0, 0x10101010); gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF1, 0x10101010); /* Enable WR-REQ: */ gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000ff); /* Set up round robin arbitration between both AXI ports: */ gpu_write(gpu, REG_A3XX_VBIF_ARB_CTL, 0x00000030); /* Set up AOOO: */ gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003c); gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0x003c003c); /* Enable 1K sort: */ gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x000000ff); gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4); } else if (adreno_is_a330v2(adreno_gpu)) { /* * Most of the VBIF registers on 8974v2 have the correct * values at power on, so we won't modify those if we don't * need to */ /* Enable 1k sort: */ gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x0001003f); gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4); /* Enable WR-REQ: */ gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003f); gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303); /* Set up VBIF_ROUND_ROBIN_QOS_ARB: */ gpu_write(gpu, REG_A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0003); } else if (adreno_is_a330(adreno_gpu)) { /* Set up 16 deep read/write request queues: */ gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x18181818); gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF1, 0x18181818); gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x18181818); gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x18181818); gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303); gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF0, 0x18181818); gpu_write(gpu, REG_A3XX_VBIF_IN_WR_LIM_CONF1, 0x18181818); /* Enable WR-REQ: */ gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003f); /* Set up round robin arbitration between both AXI ports: */ gpu_write(gpu, REG_A3XX_VBIF_ARB_CTL, 0x00000030); /* Set up VBIF_ROUND_ROBIN_QOS_ARB: */ gpu_write(gpu, REG_A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0001); /* Set up AOOO: */ gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003f); gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0x003f003f); /* Enable 1K sort: */ gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x0001003f); gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4); /* Disable VBIF clock gating. This is to enable AXI running * higher frequency than GPU: */ gpu_write(gpu, REG_A3XX_VBIF_CLKON, 0x00000001); } else { BUG(); } /* Make all blocks contribute to the GPU BUSY perf counter: */ gpu_write(gpu, REG_A3XX_RBBM_GPU_BUSY_MASKED, 0xffffffff); /* Tune the hystersis counters for SP and CP idle detection: */ gpu_write(gpu, REG_A3XX_RBBM_SP_HYST_CNT, 0x10); gpu_write(gpu, REG_A3XX_RBBM_WAIT_IDLE_CLOCKS_CTL, 0x10); /* Enable the RBBM error reporting bits. This lets us get * useful information on failure: */ gpu_write(gpu, REG_A3XX_RBBM_AHB_CTL0, 0x00000001); /* Enable AHB error reporting: */ gpu_write(gpu, REG_A3XX_RBBM_AHB_CTL1, 0xa6ffffff); /* Turn on the power counters: */ gpu_write(gpu, REG_A3XX_RBBM_RBBM_CTL, 0x00030000); /* Turn on hang detection - this spews a lot of useful information * into the RBBM registers on a hang: */ gpu_write(gpu, REG_A3XX_RBBM_INTERFACE_HANG_INT_CTL, 0x00010fff); /* Enable 64-byte cacheline size. HW Default is 32-byte (0x000000E0): */ gpu_write(gpu, REG_A3XX_UCHE_CACHE_MODE_CONTROL_REG, 0x00000001); /* Enable Clock gating: */ if (adreno_is_a320(adreno_gpu)) gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xbfffffff); else if (adreno_is_a330v2(adreno_gpu)) gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xaaaaaaaa); else if (adreno_is_a330(adreno_gpu)) gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xbffcffff); if (adreno_is_a330v2(adreno_gpu)) gpu_write(gpu, REG_A3XX_RBBM_GPR0_CTL, 0x05515455); else if (adreno_is_a330(adreno_gpu)) gpu_write(gpu, REG_A3XX_RBBM_GPR0_CTL, 0x00000000); /* Set the OCMEM base address for A330, etc */ if (a3xx_gpu->ocmem_hdl) { gpu_write(gpu, REG_A3XX_RB_GMEM_BASE_ADDR, (unsigned int)(a3xx_gpu->ocmem_base >> 14)); }
static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu) { u16 prefetch; if ((etnaviv_is_model_rev(gpu, GC320, 0x5007) || etnaviv_is_model_rev(gpu, GC320, 0x5220)) && gpu_read(gpu, VIVS_HI_CHIP_TIME) != 0x2062400) { u32 mc_memory_debug; mc_memory_debug = gpu_read(gpu, VIVS_MC_DEBUG_MEMORY) & ~0xff; if (gpu->identity.revision == 0x5007) mc_memory_debug |= 0x0c; else mc_memory_debug |= 0x08; gpu_write(gpu, VIVS_MC_DEBUG_MEMORY, mc_memory_debug); } /* * Update GPU AXI cache atttribute to "cacheable, no allocate". * This is necessary to prevent the iMX6 SoC locking up. */ gpu_write(gpu, VIVS_HI_AXI_CONFIG, VIVS_HI_AXI_CONFIG_AWCACHE(2) | VIVS_HI_AXI_CONFIG_ARCACHE(2)); /* GC2000 rev 5108 needs a special bus config */ if (etnaviv_is_model_rev(gpu, GC2000, 0x5108)) { u32 bus_config = gpu_read(gpu, VIVS_MC_BUS_CONFIG); bus_config &= ~(VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG__MASK | VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG__MASK); bus_config |= VIVS_MC_BUS_CONFIG_FE_BUS_CONFIG(1) | VIVS_MC_BUS_CONFIG_TX_BUS_CONFIG(0); gpu_write(gpu, VIVS_MC_BUS_CONFIG, bus_config); } /* set base addresses */ gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_RA, gpu->memory_base); gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_FE, gpu->memory_base); gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_TX, gpu->memory_base); gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_PEZ, gpu->memory_base); gpu_write(gpu, VIVS_MC_MEMORY_BASE_ADDR_PE, gpu->memory_base); /* setup the MMU page table pointers */ etnaviv_iommu_domain_restore(gpu, gpu->mmu->domain); /* Start command processor */ prefetch = etnaviv_buffer_init(gpu); gpu_write(gpu, VIVS_HI_INTR_ENBL, ~0U); gpu_write(gpu, VIVS_FE_COMMAND_ADDRESS, gpu->buffer->paddr - gpu->memory_base); gpu_write(gpu, VIVS_FE_COMMAND_CONTROL, VIVS_FE_COMMAND_CONTROL_ENABLE | VIVS_FE_COMMAND_CONTROL_PREFETCH(prefetch)); }
static int etnaviv_hw_reset(struct etnaviv_gpu *gpu) { u32 control, idle; unsigned long timeout; bool failed = true; /* TODO * * - clock gating * - puls eater * - what about VG? */ /* We hope that the GPU resets in under one second */ timeout = jiffies + msecs_to_jiffies(1000); while (time_is_after_jiffies(timeout)) { control = VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS | VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(0x40); /* enable clock */ etnaviv_gpu_load_clock(gpu, control); /* Wait for stable clock. Vivante's code waited for 1ms */ usleep_range(1000, 10000); /* isolate the GPU. */ control |= VIVS_HI_CLOCK_CONTROL_ISOLATE_GPU; gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control); /* set soft reset. */ control |= VIVS_HI_CLOCK_CONTROL_SOFT_RESET; gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control); /* wait for reset. */ msleep(1); /* reset soft reset bit. */ control &= ~VIVS_HI_CLOCK_CONTROL_SOFT_RESET; gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control); /* reset GPU isolation. */ control &= ~VIVS_HI_CLOCK_CONTROL_ISOLATE_GPU; gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control); /* read idle register. */ idle = gpu_read(gpu, VIVS_HI_IDLE_STATE); /* try reseting again if FE it not idle */ if ((idle & VIVS_HI_IDLE_STATE_FE) == 0) { dev_dbg(gpu->dev, "FE is not idle\n"); continue; } /* read reset register. */ control = gpu_read(gpu, VIVS_HI_CLOCK_CONTROL); /* is the GPU idle? */ if (((control & VIVS_HI_CLOCK_CONTROL_IDLE_3D) == 0) || ((control & VIVS_HI_CLOCK_CONTROL_IDLE_2D) == 0)) { dev_dbg(gpu->dev, "GPU is not idle\n"); continue; } failed = false; break; } if (failed) { idle = gpu_read(gpu, VIVS_HI_IDLE_STATE); control = gpu_read(gpu, VIVS_HI_CLOCK_CONTROL); dev_err(gpu->dev, "GPU failed to reset: FE %sidle, 3D %sidle, 2D %sidle\n", idle & VIVS_HI_IDLE_STATE_FE ? "" : "not ", control & VIVS_HI_CLOCK_CONTROL_IDLE_3D ? "" : "not ", control & VIVS_HI_CLOCK_CONTROL_IDLE_2D ? "" : "not "); return -EBUSY; } /* We rely on the GPU running, so program the clock */ control = VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS | VIVS_HI_CLOCK_CONTROL_FSCALE_VAL(0x40); /* enable clock */ etnaviv_gpu_load_clock(gpu, control); return 0; }
static void etnaviv_gpu_load_clock(struct etnaviv_gpu *gpu, u32 clock) { gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, clock | VIVS_HI_CLOCK_CONTROL_FSCALE_CMD_LOAD); gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, clock); }