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 irqreturn_t a4xx_irq(struct msm_gpu *gpu) { uint32_t status; status = gpu_read(gpu, REG_A4XX_RBBM_INT_0_STATUS); DBG("%s: Int status %08x", gpu->name, status); if (status & A4XX_INT0_CP_REG_PROTECT_FAULT) { uint32_t reg = gpu_read(gpu, REG_A4XX_CP_PROTECT_STATUS); printk("CP | Protected mode error| %s | addr=%x\n", reg & (1 << 24) ? "WRITE" : "READ", (reg & 0xFFFFF) >> 2); }
static void hangcheck_handler(unsigned long data) { struct etnaviv_gpu *gpu = (struct etnaviv_gpu *)data; u32 fence = gpu->completed_fence; bool progress = false; if (fence != gpu->hangcheck_fence) { gpu->hangcheck_fence = fence; progress = true; } if (!progress) { u32 dma_addr = gpu_read(gpu, VIVS_FE_DMA_ADDRESS); int change = dma_addr - gpu->hangcheck_dma_addr; if (change < 0 || change > 16) { gpu->hangcheck_dma_addr = dma_addr; progress = true; } } if (!progress && fence_after(gpu->active_fence, fence)) { dev_err(gpu->dev, "hangcheck detected gpu lockup!\n"); dev_err(gpu->dev, " completed fence: %u\n", fence); dev_err(gpu->dev, " active fence: %u\n", gpu->active_fence); etnaviv_queue_work(gpu->drm, &gpu->recover_work); } /* if still more pending work, reset the hangcheck timer: */ if (fence_after(gpu->active_fence, gpu->hangcheck_fence)) hangcheck_timer_reset(gpu); }
void adreno_show(struct msm_gpu *gpu, struct seq_file *m) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); int i; seq_printf(m, "revision: %d (%d.%d.%d.%d)\n", adreno_gpu->info->revn, adreno_gpu->rev.core, adreno_gpu->rev.major, adreno_gpu->rev.minor, adreno_gpu->rev.patchid); seq_printf(m, "fence: %d/%d\n", adreno_gpu->memptrs->fence, gpu->fctx->last_fence); seq_printf(m, "rptr: %d\n", get_rptr(adreno_gpu)); seq_printf(m, "wptr: %d\n", adreno_gpu->memptrs->wptr); seq_printf(m, "rb wptr: %d\n", get_wptr(gpu->rb)); /* dump these out in a form that can be parsed by demsm: */ seq_printf(m, "IO:region %s 00000000 00020000\n", gpu->name); for (i = 0; adreno_gpu->registers[i] != ~0; i += 2) { uint32_t start = adreno_gpu->registers[i]; uint32_t end = adreno_gpu->registers[i+1]; uint32_t addr; for (addr = start; addr <= end; addr++) { uint32_t val = gpu_read(gpu, addr); seq_printf(m, "IO:R %08x %08x\n", addr<<2, val); } } }
/* 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 verify_dma(struct etnaviv_gpu *gpu, struct dma_debug *debug) { u32 i; debug->address[0] = gpu_read(gpu, VIVS_FE_DMA_ADDRESS); debug->state[0] = gpu_read(gpu, VIVS_FE_DMA_DEBUG_STATE); for (i = 0; i < 500; i++) { debug->address[1] = gpu_read(gpu, VIVS_FE_DMA_ADDRESS); debug->state[1] = gpu_read(gpu, VIVS_FE_DMA_DEBUG_STATE); if (debug->address[0] != debug->address[1]) break; if (debug->state[0] != debug->state[1]) 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); }
static void a4xx_idle(struct msm_gpu *gpu) { /* wait for ringbuffer to drain: */ adreno_idle(gpu); /* then wait for GPU to finish: */ if (spin_until(!(gpu_read(gpu, REG_A4XX_RBBM_STATUS) & A4XX_RBBM_STATUS_GPU_BUSY))) DRM_ERROR("%s: timeout waiting for GPU to idle!\n", gpu->name); /* TODO maybe we need to reset GPU here to recover from hang? */ }
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); }
uint8 memorymap_registers_read(uint32 Addr) { switch (Addr&0x1fff) { case 0x00: case 0x01: case 0x02: case 0x03: return(gpu_read(Addr)); case 0x20: return(controls_read(Addr)); case 0x21: return(io_read(Addr)); case 0x23: case 0x24: return(timer_read(Addr)); } uint8 data = memorymap_regs[Addr&0x1fff]; // iprintf("regs: reading 0x%.2x from 0x%.4x\n", data, Addr); return(data); }
/* would be nice to not have to duplicate the _show() stuff with printk(): */ void adreno_dump(struct msm_gpu *gpu) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); int i; /* dump these out in a form that can be parsed by demsm: */ printk("IO:region %s 00000000 00020000\n", gpu->name); for (i = 0; adreno_gpu->registers[i] != ~0; i += 2) { uint32_t start = adreno_gpu->registers[i]; uint32_t end = adreno_gpu->registers[i+1]; uint32_t addr; for (addr = start; addr <= end; addr++) { uint32_t val = gpu_read(gpu, addr); printk("IO:R %08x %08x\n", addr<<2, val); } } }
static void etnaviv_sched_timedout_job(struct drm_sched_job *sched_job) { struct etnaviv_gem_submit *submit = to_etnaviv_submit(sched_job); struct etnaviv_gpu *gpu = submit->gpu; u32 dma_addr; int change; /* * If the GPU managed to complete this jobs fence, the timout is * spurious. Bail out. */ if (dma_fence_is_signaled(submit->out_fence)) return; /* * If the GPU is still making forward progress on the front-end (which * should never loop) we shift out the timeout to give it a chance to * finish the job. */ dma_addr = gpu_read(gpu, VIVS_FE_DMA_ADDRESS); change = dma_addr - gpu->hangcheck_dma_addr; if (change < 0 || change > 16) { gpu->hangcheck_dma_addr = dma_addr; return; } /* block scheduler */ drm_sched_stop(&gpu->sched); if(sched_job) drm_sched_increase_karma(sched_job); /* get the GPU back into the init state */ etnaviv_core_dump(gpu); etnaviv_gpu_recover_hang(gpu); drm_sched_resubmit_jobs(&gpu->sched); /* restart scheduler after GPU is usable again */ drm_sched_start(&gpu->sched, true); }
static void etnaviv_hw_specs(struct etnaviv_gpu *gpu) { if (gpu->identity.minor_features0 & chipMinorFeatures0_MORE_MINOR_FEATURES) { u32 specs[4]; unsigned int streams; specs[0] = gpu_read(gpu, VIVS_HI_CHIP_SPECS); specs[1] = gpu_read(gpu, VIVS_HI_CHIP_SPECS_2); specs[2] = gpu_read(gpu, VIVS_HI_CHIP_SPECS_3); specs[3] = gpu_read(gpu, VIVS_HI_CHIP_SPECS_4); gpu->identity.stream_count = etnaviv_field(specs[0], VIVS_HI_CHIP_SPECS_STREAM_COUNT); gpu->identity.register_max = etnaviv_field(specs[0], VIVS_HI_CHIP_SPECS_REGISTER_MAX); gpu->identity.thread_count = etnaviv_field(specs[0], VIVS_HI_CHIP_SPECS_THREAD_COUNT); gpu->identity.vertex_cache_size = etnaviv_field(specs[0], VIVS_HI_CHIP_SPECS_VERTEX_CACHE_SIZE); gpu->identity.shader_core_count = etnaviv_field(specs[0], VIVS_HI_CHIP_SPECS_SHADER_CORE_COUNT); gpu->identity.pixel_pipes = etnaviv_field(specs[0], VIVS_HI_CHIP_SPECS_PIXEL_PIPES); gpu->identity.vertex_output_buffer_size = etnaviv_field(specs[0], VIVS_HI_CHIP_SPECS_VERTEX_OUTPUT_BUFFER_SIZE); gpu->identity.buffer_size = etnaviv_field(specs[1], VIVS_HI_CHIP_SPECS_2_BUFFER_SIZE); gpu->identity.instruction_count = etnaviv_field(specs[1], VIVS_HI_CHIP_SPECS_2_INSTRUCTION_COUNT); gpu->identity.num_constants = etnaviv_field(specs[1], VIVS_HI_CHIP_SPECS_2_NUM_CONSTANTS); gpu->identity.varyings_count = etnaviv_field(specs[2], VIVS_HI_CHIP_SPECS_3_VARYINGS_COUNT); /* This overrides the value from older register if non-zero */ streams = etnaviv_field(specs[3], VIVS_HI_CHIP_SPECS_4_STREAM_COUNT); if (streams) gpu->identity.stream_count = streams; } /* Fill in the stream count if not specified */ if (gpu->identity.stream_count == 0) { if (gpu->identity.model >= 0x1000) gpu->identity.stream_count = 4; else gpu->identity.stream_count = 1; } /* Convert the register max value */ if (gpu->identity.register_max) gpu->identity.register_max = 1 << gpu->identity.register_max; else if (gpu->identity.model == chipModel_GC400) gpu->identity.register_max = 32; else gpu->identity.register_max = 64; /* Convert thread count */ if (gpu->identity.thread_count) gpu->identity.thread_count = 1 << gpu->identity.thread_count; else if (gpu->identity.model == chipModel_GC400) gpu->identity.thread_count = 64; else if (gpu->identity.model == chipModel_GC500 || gpu->identity.model == chipModel_GC530) gpu->identity.thread_count = 128; else gpu->identity.thread_count = 256; if (gpu->identity.vertex_cache_size == 0) gpu->identity.vertex_cache_size = 8; if (gpu->identity.shader_core_count == 0) { if (gpu->identity.model >= 0x1000) gpu->identity.shader_core_count = 2; else gpu->identity.shader_core_count = 1; } if (gpu->identity.pixel_pipes == 0) gpu->identity.pixel_pipes = 1; /* Convert virtex buffer size */ if (gpu->identity.vertex_output_buffer_size) { gpu->identity.vertex_output_buffer_size = 1 << gpu->identity.vertex_output_buffer_size; } else if (gpu->identity.model == chipModel_GC400) { if (gpu->identity.revision < 0x4000) gpu->identity.vertex_output_buffer_size = 512; else if (gpu->identity.revision < 0x4200) gpu->identity.vertex_output_buffer_size = 256; else gpu->identity.vertex_output_buffer_size = 128; } else { gpu->identity.vertex_output_buffer_size = 512; } switch (gpu->identity.instruction_count) { case 0: if (etnaviv_is_model_rev(gpu, GC2000, 0x5108) || gpu->identity.model == chipModel_GC880) gpu->identity.instruction_count = 512; else gpu->identity.instruction_count = 256; break; case 1: gpu->identity.instruction_count = 1024; break; case 2: gpu->identity.instruction_count = 2048; break; default: gpu->identity.instruction_count = 256; break; } if (gpu->identity.num_constants == 0) gpu->identity.num_constants = 168; if (gpu->identity.varyings_count == 0) { if (gpu->identity.minor_features1 & chipMinorFeatures1_HALTI0) gpu->identity.varyings_count = 12; else gpu->identity.varyings_count = 8; } /* * For some cores, two varyings are consumed for position, so the * maximum varying count needs to be reduced by one. */ if (etnaviv_is_model_rev(gpu, GC5000, 0x5434) || etnaviv_is_model_rev(gpu, GC4000, 0x5222) || etnaviv_is_model_rev(gpu, GC4000, 0x5245) || etnaviv_is_model_rev(gpu, GC4000, 0x5208) || etnaviv_is_model_rev(gpu, GC3000, 0x5435) || etnaviv_is_model_rev(gpu, GC2200, 0x5244) || etnaviv_is_model_rev(gpu, GC2100, 0x5108) || etnaviv_is_model_rev(gpu, GC2000, 0x5108) || etnaviv_is_model_rev(gpu, GC1500, 0x5246) || etnaviv_is_model_rev(gpu, GC880, 0x5107) || etnaviv_is_model_rev(gpu, GC880, 0x5106)) gpu->identity.varyings_count -= 1; }
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 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; }
int etnaviv_gpu_debugfs(struct etnaviv_gpu *gpu, struct seq_file *m) { struct dma_debug debug; u32 dma_lo, dma_hi, axi, idle; int ret; seq_printf(m, "%s Status:\n", dev_name(gpu->dev)); ret = pm_runtime_get_sync(gpu->dev); if (ret < 0) return ret; dma_lo = gpu_read(gpu, VIVS_FE_DMA_LOW); dma_hi = gpu_read(gpu, VIVS_FE_DMA_HIGH); axi = gpu_read(gpu, VIVS_HI_AXI_STATUS); idle = gpu_read(gpu, VIVS_HI_IDLE_STATE); verify_dma(gpu, &debug); seq_puts(m, "\tfeatures\n"); seq_printf(m, "\t minor_features0: 0x%08x\n", gpu->identity.minor_features0); seq_printf(m, "\t minor_features1: 0x%08x\n", gpu->identity.minor_features1); seq_printf(m, "\t minor_features2: 0x%08x\n", gpu->identity.minor_features2); seq_printf(m, "\t minor_features3: 0x%08x\n", gpu->identity.minor_features3); seq_printf(m, "\t minor_features4: 0x%08x\n", gpu->identity.minor_features4); seq_printf(m, "\t minor_features5: 0x%08x\n", gpu->identity.minor_features5); seq_puts(m, "\tspecs\n"); seq_printf(m, "\t stream_count: %d\n", gpu->identity.stream_count); seq_printf(m, "\t register_max: %d\n", gpu->identity.register_max); seq_printf(m, "\t thread_count: %d\n", gpu->identity.thread_count); seq_printf(m, "\t vertex_cache_size: %d\n", gpu->identity.vertex_cache_size); seq_printf(m, "\t shader_core_count: %d\n", gpu->identity.shader_core_count); seq_printf(m, "\t pixel_pipes: %d\n", gpu->identity.pixel_pipes); seq_printf(m, "\t vertex_output_buffer_size: %d\n", gpu->identity.vertex_output_buffer_size); seq_printf(m, "\t buffer_size: %d\n", gpu->identity.buffer_size); seq_printf(m, "\t instruction_count: %d\n", gpu->identity.instruction_count); seq_printf(m, "\t num_constants: %d\n", gpu->identity.num_constants); seq_printf(m, "\t varyings_count: %d\n", gpu->identity.varyings_count); seq_printf(m, "\taxi: 0x%08x\n", axi); seq_printf(m, "\tidle: 0x%08x\n", idle); idle |= ~gpu->idle_mask & ~VIVS_HI_IDLE_STATE_AXI_LP; if ((idle & VIVS_HI_IDLE_STATE_FE) == 0) seq_puts(m, "\t FE is not idle\n"); if ((idle & VIVS_HI_IDLE_STATE_DE) == 0) seq_puts(m, "\t DE is not idle\n"); if ((idle & VIVS_HI_IDLE_STATE_PE) == 0) seq_puts(m, "\t PE is not idle\n"); if ((idle & VIVS_HI_IDLE_STATE_SH) == 0) seq_puts(m, "\t SH is not idle\n"); if ((idle & VIVS_HI_IDLE_STATE_PA) == 0) seq_puts(m, "\t PA is not idle\n"); if ((idle & VIVS_HI_IDLE_STATE_SE) == 0) seq_puts(m, "\t SE is not idle\n"); if ((idle & VIVS_HI_IDLE_STATE_RA) == 0) seq_puts(m, "\t RA is not idle\n"); if ((idle & VIVS_HI_IDLE_STATE_TX) == 0) seq_puts(m, "\t TX is not idle\n"); if ((idle & VIVS_HI_IDLE_STATE_VG) == 0) seq_puts(m, "\t VG is not idle\n"); if ((idle & VIVS_HI_IDLE_STATE_IM) == 0) seq_puts(m, "\t IM is not idle\n"); if ((idle & VIVS_HI_IDLE_STATE_FP) == 0) seq_puts(m, "\t FP is not idle\n"); if ((idle & VIVS_HI_IDLE_STATE_TS) == 0) seq_puts(m, "\t TS is not idle\n"); if (idle & VIVS_HI_IDLE_STATE_AXI_LP) seq_puts(m, "\t AXI low power mode\n"); if (gpu->identity.features & chipFeatures_DEBUG_MODE) { u32 read0 = gpu_read(gpu, VIVS_MC_DEBUG_READ0); u32 read1 = gpu_read(gpu, VIVS_MC_DEBUG_READ1); u32 write = gpu_read(gpu, VIVS_MC_DEBUG_WRITE); seq_puts(m, "\tMC\n"); seq_printf(m, "\t read0: 0x%08x\n", read0); seq_printf(m, "\t read1: 0x%08x\n", read1); seq_printf(m, "\t write: 0x%08x\n", write); } seq_puts(m, "\tDMA "); if (debug.address[0] == debug.address[1] && debug.state[0] == debug.state[1]) { seq_puts(m, "seems to be stuck\n"); } else if (debug.address[0] == debug.address[1]) { seq_puts(m, "address is constant\n"); } else { seq_puts(m, "is running\n"); } seq_printf(m, "\t address 0: 0x%08x\n", debug.address[0]); seq_printf(m, "\t address 1: 0x%08x\n", debug.address[1]); seq_printf(m, "\t state 0: 0x%08x\n", debug.state[0]); seq_printf(m, "\t state 1: 0x%08x\n", debug.state[1]); seq_printf(m, "\t last fetch 64 bit word: 0x%08x 0x%08x\n", dma_lo, dma_hi); ret = 0; pm_runtime_mark_last_busy(gpu->dev); pm_runtime_put_autosuspend(gpu->dev); return ret; }
static void etnaviv_hw_identify(struct etnaviv_gpu *gpu) { u32 chipIdentity; chipIdentity = gpu_read(gpu, VIVS_HI_CHIP_IDENTITY); /* Special case for older graphic cores. */ if (etnaviv_field(chipIdentity, VIVS_HI_CHIP_IDENTITY_FAMILY) == 0x01) { gpu->identity.model = chipModel_GC500; gpu->identity.revision = etnaviv_field(chipIdentity, VIVS_HI_CHIP_IDENTITY_REVISION); } else { gpu->identity.model = gpu_read(gpu, VIVS_HI_CHIP_MODEL); gpu->identity.revision = gpu_read(gpu, VIVS_HI_CHIP_REV); /* * !!!! HACK ALERT !!!! * Because people change device IDs without letting software * know about it - here is the hack to make it all look the * same. Only for GC400 family. */ if ((gpu->identity.model & 0xff00) == 0x0400 && gpu->identity.model != chipModel_GC420) { gpu->identity.model = gpu->identity.model & 0x0400; } /* Another special case */ if (etnaviv_is_model_rev(gpu, GC300, 0x2201)) { u32 chipDate = gpu_read(gpu, VIVS_HI_CHIP_DATE); u32 chipTime = gpu_read(gpu, VIVS_HI_CHIP_TIME); if (chipDate == 0x20080814 && chipTime == 0x12051100) { /* * This IP has an ECO; put the correct * revision in it. */ gpu->identity.revision = 0x1051; } } } dev_info(gpu->dev, "model: GC%x, revision: %x\n", gpu->identity.model, gpu->identity.revision); gpu->identity.features = gpu_read(gpu, VIVS_HI_CHIP_FEATURE); /* Disable fast clear on GC700. */ if (gpu->identity.model == chipModel_GC700) gpu->identity.features &= ~chipFeatures_FAST_CLEAR; if ((gpu->identity.model == chipModel_GC500 && gpu->identity.revision < 2) || (gpu->identity.model == chipModel_GC300 && gpu->identity.revision < 0x2000)) { /* * GC500 rev 1.x and GC300 rev < 2.0 doesn't have these * registers. */ gpu->identity.minor_features0 = 0; gpu->identity.minor_features1 = 0; gpu->identity.minor_features2 = 0; gpu->identity.minor_features3 = 0; gpu->identity.minor_features4 = 0; gpu->identity.minor_features5 = 0; } else gpu->identity.minor_features0 = gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_0); if (gpu->identity.minor_features0 & chipMinorFeatures0_MORE_MINOR_FEATURES) { gpu->identity.minor_features1 = gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_1); gpu->identity.minor_features2 = gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_2); gpu->identity.minor_features3 = gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_3); gpu->identity.minor_features4 = gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_4); gpu->identity.minor_features5 = gpu_read(gpu, VIVS_HI_CHIP_MINOR_FEATURE_5); } /* GC600 idle register reports zero bits where modules aren't present */ if (gpu->identity.model == chipModel_GC600) { gpu->idle_mask = VIVS_HI_IDLE_STATE_TX | VIVS_HI_IDLE_STATE_RA | VIVS_HI_IDLE_STATE_SE | VIVS_HI_IDLE_STATE_PA | VIVS_HI_IDLE_STATE_SH | VIVS_HI_IDLE_STATE_PE | VIVS_HI_IDLE_STATE_DE | VIVS_HI_IDLE_STATE_FE; } else { gpu->idle_mask = ~VIVS_HI_IDLE_STATE_AXI_LP; } etnaviv_hw_specs(gpu); }