1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2014-2017 Broadcom 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21bf215546Sopenharmony_ci * IN THE SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci/** 25bf215546Sopenharmony_ci * @file v3dx_simulator.c 26bf215546Sopenharmony_ci * 27bf215546Sopenharmony_ci * Implements the actual HW interaction betweeh the GL driver's V3D simulator and the simulator. 28bf215546Sopenharmony_ci * 29bf215546Sopenharmony_ci * The register headers between V3D versions will have conflicting defines, so 30bf215546Sopenharmony_ci * all register interactions appear in this file and are compiled per V3D version 31bf215546Sopenharmony_ci * we support. 32bf215546Sopenharmony_ci */ 33bf215546Sopenharmony_ci 34bf215546Sopenharmony_ci#ifdef USE_V3D_SIMULATOR 35bf215546Sopenharmony_ci 36bf215546Sopenharmony_ci#include <assert.h> 37bf215546Sopenharmony_ci#include <stdbool.h> 38bf215546Sopenharmony_ci#include <stdio.h> 39bf215546Sopenharmony_ci 40bf215546Sopenharmony_ci#include "v3d_simulator.h" 41bf215546Sopenharmony_ci#include "v3d_simulator_wrapper.h" 42bf215546Sopenharmony_ci 43bf215546Sopenharmony_ci#include "util/macros.h" 44bf215546Sopenharmony_ci#include "util/bitscan.h" 45bf215546Sopenharmony_ci#include "drm-uapi/v3d_drm.h" 46bf215546Sopenharmony_ci 47bf215546Sopenharmony_ci#define HW_REGISTER_RO(x) (x) 48bf215546Sopenharmony_ci#define HW_REGISTER_RW(x) (x) 49bf215546Sopenharmony_ci#if V3D_VERSION >= 41 50bf215546Sopenharmony_ci#include "libs/core/v3d/registers/4.1.35.0/v3d.h" 51bf215546Sopenharmony_ci#else 52bf215546Sopenharmony_ci#include "libs/core/v3d/registers/3.3.0.0/v3d.h" 53bf215546Sopenharmony_ci#endif 54bf215546Sopenharmony_ci 55bf215546Sopenharmony_ci#define V3D_WRITE(reg, val) v3d_hw_write_reg(v3d, reg, val) 56bf215546Sopenharmony_ci#define V3D_READ(reg) v3d_hw_read_reg(v3d, reg) 57bf215546Sopenharmony_ci 58bf215546Sopenharmony_cistatic void 59bf215546Sopenharmony_civ3d_invalidate_l3(struct v3d_hw *v3d) 60bf215546Sopenharmony_ci{ 61bf215546Sopenharmony_ci#if V3D_VERSION < 40 62bf215546Sopenharmony_ci uint32_t gca_ctrl = V3D_READ(V3D_GCA_CACHE_CTRL); 63bf215546Sopenharmony_ci 64bf215546Sopenharmony_ci V3D_WRITE(V3D_GCA_CACHE_CTRL, gca_ctrl | V3D_GCA_CACHE_CTRL_FLUSH_SET); 65bf215546Sopenharmony_ci V3D_WRITE(V3D_GCA_CACHE_CTRL, gca_ctrl & ~V3D_GCA_CACHE_CTRL_FLUSH_SET); 66bf215546Sopenharmony_ci#endif 67bf215546Sopenharmony_ci} 68bf215546Sopenharmony_ci 69bf215546Sopenharmony_ci/* Invalidates the L2C cache. This is a read-only cache for uniforms and instructions. */ 70bf215546Sopenharmony_cistatic void 71bf215546Sopenharmony_civ3d_invalidate_l2c(struct v3d_hw *v3d) 72bf215546Sopenharmony_ci{ 73bf215546Sopenharmony_ci if (V3D_VERSION >= 33) 74bf215546Sopenharmony_ci return; 75bf215546Sopenharmony_ci 76bf215546Sopenharmony_ci V3D_WRITE(V3D_CTL_0_L2CACTL, 77bf215546Sopenharmony_ci V3D_CTL_0_L2CACTL_L2CCLR_SET | 78bf215546Sopenharmony_ci V3D_CTL_0_L2CACTL_L2CENA_SET); 79bf215546Sopenharmony_ci} 80bf215546Sopenharmony_ci 81bf215546Sopenharmony_cienum v3d_l2t_cache_flush_mode { 82bf215546Sopenharmony_ci V3D_CACHE_FLUSH_MODE_FLUSH, 83bf215546Sopenharmony_ci V3D_CACHE_FLUSH_MODE_CLEAR, 84bf215546Sopenharmony_ci V3D_CACHE_FLUSH_MODE_CLEAN, 85bf215546Sopenharmony_ci}; 86bf215546Sopenharmony_ci 87bf215546Sopenharmony_ci/* Invalidates texture L2 cachelines */ 88bf215546Sopenharmony_cistatic void 89bf215546Sopenharmony_civ3d_invalidate_l2t(struct v3d_hw *v3d) 90bf215546Sopenharmony_ci{ 91bf215546Sopenharmony_ci V3D_WRITE(V3D_CTL_0_L2TFLSTA, 0); 92bf215546Sopenharmony_ci V3D_WRITE(V3D_CTL_0_L2TFLEND, ~0); 93bf215546Sopenharmony_ci V3D_WRITE(V3D_CTL_0_L2TCACTL, 94bf215546Sopenharmony_ci V3D_CTL_0_L2TCACTL_L2TFLS_SET | 95bf215546Sopenharmony_ci (V3D_CACHE_FLUSH_MODE_FLUSH << V3D_CTL_0_L2TCACTL_L2TFLM_LSB)); 96bf215546Sopenharmony_ci} 97bf215546Sopenharmony_ci 98bf215546Sopenharmony_ci/* 99bf215546Sopenharmony_ci * Wait for l2tcactl, used for flushes. 100bf215546Sopenharmony_ci * 101bf215546Sopenharmony_ci * FIXME: for a multicore scenario we should pass here the core. All wrapper 102bf215546Sopenharmony_ci * assumes just one core, so would be better to handle that on that case. 103bf215546Sopenharmony_ci */ 104bf215546Sopenharmony_cistatic UNUSED void v3d_core_wait_l2tcactl(struct v3d_hw *v3d, 105bf215546Sopenharmony_ci uint32_t ctrl) 106bf215546Sopenharmony_ci{ 107bf215546Sopenharmony_ci assert(!(ctrl & ~(V3D_CTL_0_L2TCACTL_TMUWCF_SET | V3D_CTL_0_L2TCACTL_L2TFLS_SET))); 108bf215546Sopenharmony_ci 109bf215546Sopenharmony_ci while (V3D_READ(V3D_CTL_0_L2TCACTL) & ctrl) { 110bf215546Sopenharmony_ci v3d_hw_tick(v3d); 111bf215546Sopenharmony_ci } 112bf215546Sopenharmony_ci} 113bf215546Sopenharmony_ci 114bf215546Sopenharmony_ci/* Flushes dirty texture cachelines from the L1 write combiner */ 115bf215546Sopenharmony_cistatic void 116bf215546Sopenharmony_civ3d_flush_l1td(struct v3d_hw *v3d) 117bf215546Sopenharmony_ci{ 118bf215546Sopenharmony_ci V3D_WRITE(V3D_CTL_0_L2TCACTL, 119bf215546Sopenharmony_ci V3D_CTL_0_L2TCACTL_TMUWCF_SET); 120bf215546Sopenharmony_ci 121bf215546Sopenharmony_ci /* Note: here the kernel (and previous versions of the simulator 122bf215546Sopenharmony_ci * wrapper) is using V3D_CTL_0_L2TCACTL_L2TFLS_SET, as with l2t. We 123bf215546Sopenharmony_ci * understand that it makes more sense to do like this. We need to 124bf215546Sopenharmony_ci * confirm which one is doing it correctly. So far things work fine on 125bf215546Sopenharmony_ci * the simulator this way. 126bf215546Sopenharmony_ci */ 127bf215546Sopenharmony_ci v3d_core_wait_l2tcactl(v3d, V3D_CTL_0_L2TCACTL_TMUWCF_SET); 128bf215546Sopenharmony_ci} 129bf215546Sopenharmony_ci 130bf215546Sopenharmony_ci/* Flushes dirty texture L2 cachelines */ 131bf215546Sopenharmony_cistatic void 132bf215546Sopenharmony_civ3d_flush_l2t(struct v3d_hw *v3d) 133bf215546Sopenharmony_ci{ 134bf215546Sopenharmony_ci V3D_WRITE(V3D_CTL_0_L2TFLSTA, 0); 135bf215546Sopenharmony_ci V3D_WRITE(V3D_CTL_0_L2TFLEND, ~0); 136bf215546Sopenharmony_ci V3D_WRITE(V3D_CTL_0_L2TCACTL, 137bf215546Sopenharmony_ci V3D_CTL_0_L2TCACTL_L2TFLS_SET | 138bf215546Sopenharmony_ci (V3D_CACHE_FLUSH_MODE_CLEAN << V3D_CTL_0_L2TCACTL_L2TFLM_LSB)); 139bf215546Sopenharmony_ci 140bf215546Sopenharmony_ci v3d_core_wait_l2tcactl(v3d, V3D_CTL_0_L2TCACTL_L2TFLS_SET); 141bf215546Sopenharmony_ci} 142bf215546Sopenharmony_ci 143bf215546Sopenharmony_ci/* Invalidates the slice caches. These are read-only caches. */ 144bf215546Sopenharmony_cistatic void 145bf215546Sopenharmony_civ3d_invalidate_slices(struct v3d_hw *v3d) 146bf215546Sopenharmony_ci{ 147bf215546Sopenharmony_ci V3D_WRITE(V3D_CTL_0_SLCACTL, ~0); 148bf215546Sopenharmony_ci} 149bf215546Sopenharmony_ci 150bf215546Sopenharmony_cistatic void 151bf215546Sopenharmony_civ3d_invalidate_caches(struct v3d_hw *v3d) 152bf215546Sopenharmony_ci{ 153bf215546Sopenharmony_ci v3d_invalidate_l3(v3d); 154bf215546Sopenharmony_ci v3d_invalidate_l2c(v3d); 155bf215546Sopenharmony_ci v3d_invalidate_l2t(v3d); 156bf215546Sopenharmony_ci v3d_invalidate_slices(v3d); 157bf215546Sopenharmony_ci} 158bf215546Sopenharmony_ci 159bf215546Sopenharmony_cistatic uint32_t g_gmp_ofs; 160bf215546Sopenharmony_cistatic void 161bf215546Sopenharmony_civ3d_reload_gmp(struct v3d_hw *v3d) 162bf215546Sopenharmony_ci{ 163bf215546Sopenharmony_ci /* Completely reset the GMP. */ 164bf215546Sopenharmony_ci V3D_WRITE(V3D_GMP_CFG, 165bf215546Sopenharmony_ci V3D_GMP_CFG_PROTENABLE_SET); 166bf215546Sopenharmony_ci V3D_WRITE(V3D_GMP_TABLE_ADDR, g_gmp_ofs); 167bf215546Sopenharmony_ci V3D_WRITE(V3D_GMP_CLEAR_LOAD, ~0); 168bf215546Sopenharmony_ci while (V3D_READ(V3D_GMP_STATUS) & 169bf215546Sopenharmony_ci V3D_GMP_STATUS_CFG_BUSY_SET) { 170bf215546Sopenharmony_ci ; 171bf215546Sopenharmony_ci } 172bf215546Sopenharmony_ci} 173bf215546Sopenharmony_ci 174bf215546Sopenharmony_cistatic UNUSED void 175bf215546Sopenharmony_civ3d_flush_caches(struct v3d_hw *v3d) 176bf215546Sopenharmony_ci{ 177bf215546Sopenharmony_ci v3d_flush_l1td(v3d); 178bf215546Sopenharmony_ci v3d_flush_l2t(v3d); 179bf215546Sopenharmony_ci} 180bf215546Sopenharmony_ci 181bf215546Sopenharmony_ciint 182bf215546Sopenharmony_civ3dX(simulator_submit_tfu_ioctl)(struct v3d_hw *v3d, 183bf215546Sopenharmony_ci struct drm_v3d_submit_tfu *args) 184bf215546Sopenharmony_ci{ 185bf215546Sopenharmony_ci int last_vtct = V3D_READ(V3D_TFU_CS) & V3D_TFU_CS_CVTCT_SET; 186bf215546Sopenharmony_ci 187bf215546Sopenharmony_ci V3D_WRITE(V3D_TFU_IIA, args->iia); 188bf215546Sopenharmony_ci V3D_WRITE(V3D_TFU_IIS, args->iis); 189bf215546Sopenharmony_ci V3D_WRITE(V3D_TFU_ICA, args->ica); 190bf215546Sopenharmony_ci V3D_WRITE(V3D_TFU_IUA, args->iua); 191bf215546Sopenharmony_ci V3D_WRITE(V3D_TFU_IOA, args->ioa); 192bf215546Sopenharmony_ci V3D_WRITE(V3D_TFU_IOS, args->ios); 193bf215546Sopenharmony_ci V3D_WRITE(V3D_TFU_COEF0, args->coef[0]); 194bf215546Sopenharmony_ci V3D_WRITE(V3D_TFU_COEF1, args->coef[1]); 195bf215546Sopenharmony_ci V3D_WRITE(V3D_TFU_COEF2, args->coef[2]); 196bf215546Sopenharmony_ci V3D_WRITE(V3D_TFU_COEF3, args->coef[3]); 197bf215546Sopenharmony_ci 198bf215546Sopenharmony_ci V3D_WRITE(V3D_TFU_ICFG, args->icfg); 199bf215546Sopenharmony_ci 200bf215546Sopenharmony_ci while ((V3D_READ(V3D_TFU_CS) & V3D_TFU_CS_CVTCT_SET) == last_vtct) { 201bf215546Sopenharmony_ci v3d_hw_tick(v3d); 202bf215546Sopenharmony_ci } 203bf215546Sopenharmony_ci 204bf215546Sopenharmony_ci return 0; 205bf215546Sopenharmony_ci} 206bf215546Sopenharmony_ci 207bf215546Sopenharmony_ci#if V3D_VERSION >= 41 208bf215546Sopenharmony_ciint 209bf215546Sopenharmony_civ3dX(simulator_submit_csd_ioctl)(struct v3d_hw *v3d, 210bf215546Sopenharmony_ci struct drm_v3d_submit_csd *args, 211bf215546Sopenharmony_ci uint32_t gmp_ofs) 212bf215546Sopenharmony_ci{ 213bf215546Sopenharmony_ci int last_completed_jobs = (V3D_READ(V3D_CSD_0_STATUS) & 214bf215546Sopenharmony_ci V3D_CSD_0_STATUS_NUM_COMPLETED_JOBS_SET); 215bf215546Sopenharmony_ci g_gmp_ofs = gmp_ofs; 216bf215546Sopenharmony_ci v3d_reload_gmp(v3d); 217bf215546Sopenharmony_ci 218bf215546Sopenharmony_ci v3d_invalidate_caches(v3d); 219bf215546Sopenharmony_ci 220bf215546Sopenharmony_ci V3D_WRITE(V3D_CSD_0_QUEUED_CFG1, args->cfg[1]); 221bf215546Sopenharmony_ci V3D_WRITE(V3D_CSD_0_QUEUED_CFG2, args->cfg[2]); 222bf215546Sopenharmony_ci V3D_WRITE(V3D_CSD_0_QUEUED_CFG3, args->cfg[3]); 223bf215546Sopenharmony_ci V3D_WRITE(V3D_CSD_0_QUEUED_CFG4, args->cfg[4]); 224bf215546Sopenharmony_ci V3D_WRITE(V3D_CSD_0_QUEUED_CFG5, args->cfg[5]); 225bf215546Sopenharmony_ci V3D_WRITE(V3D_CSD_0_QUEUED_CFG6, args->cfg[6]); 226bf215546Sopenharmony_ci /* CFG0 kicks off the job */ 227bf215546Sopenharmony_ci V3D_WRITE(V3D_CSD_0_QUEUED_CFG0, args->cfg[0]); 228bf215546Sopenharmony_ci 229bf215546Sopenharmony_ci /* Now we wait for the dispatch to finish. The safest way is to check 230bf215546Sopenharmony_ci * if NUM_COMPLETED_JOBS has increased. Note that in spite of that 231bf215546Sopenharmony_ci * name that register field is about the number of completed 232bf215546Sopenharmony_ci * dispatches. 233bf215546Sopenharmony_ci */ 234bf215546Sopenharmony_ci while ((V3D_READ(V3D_CSD_0_STATUS) & 235bf215546Sopenharmony_ci V3D_CSD_0_STATUS_NUM_COMPLETED_JOBS_SET) == last_completed_jobs) { 236bf215546Sopenharmony_ci v3d_hw_tick(v3d); 237bf215546Sopenharmony_ci } 238bf215546Sopenharmony_ci 239bf215546Sopenharmony_ci v3d_flush_caches(v3d); 240bf215546Sopenharmony_ci 241bf215546Sopenharmony_ci return 0; 242bf215546Sopenharmony_ci} 243bf215546Sopenharmony_ci#endif 244bf215546Sopenharmony_ci 245bf215546Sopenharmony_ciint 246bf215546Sopenharmony_civ3dX(simulator_get_param_ioctl)(struct v3d_hw *v3d, 247bf215546Sopenharmony_ci struct drm_v3d_get_param *args) 248bf215546Sopenharmony_ci{ 249bf215546Sopenharmony_ci static const uint32_t reg_map[] = { 250bf215546Sopenharmony_ci [DRM_V3D_PARAM_V3D_UIFCFG] = V3D_HUB_CTL_UIFCFG, 251bf215546Sopenharmony_ci [DRM_V3D_PARAM_V3D_HUB_IDENT1] = V3D_HUB_CTL_IDENT1, 252bf215546Sopenharmony_ci [DRM_V3D_PARAM_V3D_HUB_IDENT2] = V3D_HUB_CTL_IDENT2, 253bf215546Sopenharmony_ci [DRM_V3D_PARAM_V3D_HUB_IDENT3] = V3D_HUB_CTL_IDENT3, 254bf215546Sopenharmony_ci [DRM_V3D_PARAM_V3D_CORE0_IDENT0] = V3D_CTL_0_IDENT0, 255bf215546Sopenharmony_ci [DRM_V3D_PARAM_V3D_CORE0_IDENT1] = V3D_CTL_0_IDENT1, 256bf215546Sopenharmony_ci [DRM_V3D_PARAM_V3D_CORE0_IDENT2] = V3D_CTL_0_IDENT2, 257bf215546Sopenharmony_ci }; 258bf215546Sopenharmony_ci 259bf215546Sopenharmony_ci switch (args->param) { 260bf215546Sopenharmony_ci case DRM_V3D_PARAM_SUPPORTS_TFU: 261bf215546Sopenharmony_ci args->value = 1; 262bf215546Sopenharmony_ci return 0; 263bf215546Sopenharmony_ci case DRM_V3D_PARAM_SUPPORTS_CSD: 264bf215546Sopenharmony_ci args->value = V3D_VERSION >= 41; 265bf215546Sopenharmony_ci return 0; 266bf215546Sopenharmony_ci case DRM_V3D_PARAM_SUPPORTS_CACHE_FLUSH: 267bf215546Sopenharmony_ci args->value = 1; 268bf215546Sopenharmony_ci return 0; 269bf215546Sopenharmony_ci case DRM_V3D_PARAM_SUPPORTS_PERFMON: 270bf215546Sopenharmony_ci args->value = V3D_VERSION >= 41; 271bf215546Sopenharmony_ci return 0; 272bf215546Sopenharmony_ci case DRM_V3D_PARAM_SUPPORTS_MULTISYNC_EXT: 273bf215546Sopenharmony_ci args->value = 1; 274bf215546Sopenharmony_ci return 0; 275bf215546Sopenharmony_ci } 276bf215546Sopenharmony_ci 277bf215546Sopenharmony_ci if (args->param < ARRAY_SIZE(reg_map) && reg_map[args->param]) { 278bf215546Sopenharmony_ci args->value = V3D_READ(reg_map[args->param]); 279bf215546Sopenharmony_ci return 0; 280bf215546Sopenharmony_ci } 281bf215546Sopenharmony_ci 282bf215546Sopenharmony_ci fprintf(stderr, "Unknown DRM_IOCTL_V3D_GET_PARAM(%lld)\n", 283bf215546Sopenharmony_ci (long long)args->value); 284bf215546Sopenharmony_ci abort(); 285bf215546Sopenharmony_ci} 286bf215546Sopenharmony_ci 287bf215546Sopenharmony_cistatic struct v3d_hw *v3d_isr_hw; 288bf215546Sopenharmony_ci 289bf215546Sopenharmony_ci 290bf215546Sopenharmony_cistatic void 291bf215546Sopenharmony_civ3d_isr_core(struct v3d_hw *v3d, 292bf215546Sopenharmony_ci unsigned core) 293bf215546Sopenharmony_ci{ 294bf215546Sopenharmony_ci /* FIXME: so far we are assuming just one core, and using only the _0_ 295bf215546Sopenharmony_ci * registers. If we add multiple-core on the simulator, we would need 296bf215546Sopenharmony_ci * to pass core as a parameter, and chose the proper registers. 297bf215546Sopenharmony_ci */ 298bf215546Sopenharmony_ci assert(core == 0); 299bf215546Sopenharmony_ci uint32_t core_status = V3D_READ(V3D_CTL_0_INT_STS); 300bf215546Sopenharmony_ci V3D_WRITE(V3D_CTL_0_INT_CLR, core_status); 301bf215546Sopenharmony_ci 302bf215546Sopenharmony_ci if (core_status & V3D_CTL_0_INT_STS_INT_OUTOMEM_SET) { 303bf215546Sopenharmony_ci uint32_t size = 256 * 1024; 304bf215546Sopenharmony_ci uint32_t offset = v3d_simulator_get_spill(size); 305bf215546Sopenharmony_ci 306bf215546Sopenharmony_ci v3d_reload_gmp(v3d); 307bf215546Sopenharmony_ci 308bf215546Sopenharmony_ci V3D_WRITE(V3D_PTB_0_BPOA, offset); 309bf215546Sopenharmony_ci V3D_WRITE(V3D_PTB_0_BPOS, size); 310bf215546Sopenharmony_ci return; 311bf215546Sopenharmony_ci } 312bf215546Sopenharmony_ci 313bf215546Sopenharmony_ci if (core_status & V3D_CTL_0_INT_STS_INT_GMPV_SET) { 314bf215546Sopenharmony_ci fprintf(stderr, "GMP violation at 0x%08x\n", 315bf215546Sopenharmony_ci V3D_READ(V3D_GMP_VIO_ADDR)); 316bf215546Sopenharmony_ci abort(); 317bf215546Sopenharmony_ci } else { 318bf215546Sopenharmony_ci fprintf(stderr, 319bf215546Sopenharmony_ci "Unexpected ISR with core status 0x%08x\n", 320bf215546Sopenharmony_ci core_status); 321bf215546Sopenharmony_ci } 322bf215546Sopenharmony_ci abort(); 323bf215546Sopenharmony_ci} 324bf215546Sopenharmony_ci 325bf215546Sopenharmony_cistatic void 326bf215546Sopenharmony_cihandle_mmu_interruptions(struct v3d_hw *v3d, 327bf215546Sopenharmony_ci uint32_t hub_status) 328bf215546Sopenharmony_ci{ 329bf215546Sopenharmony_ci bool wrv = hub_status & V3D_HUB_CTL_INT_STS_INT_MMU_WRV_SET; 330bf215546Sopenharmony_ci bool pti = hub_status & V3D_HUB_CTL_INT_STS_INT_MMU_PTI_SET; 331bf215546Sopenharmony_ci bool cap = hub_status & V3D_HUB_CTL_INT_STS_INT_MMU_CAP_SET; 332bf215546Sopenharmony_ci 333bf215546Sopenharmony_ci if (!(pti || cap || wrv)) 334bf215546Sopenharmony_ci return; 335bf215546Sopenharmony_ci 336bf215546Sopenharmony_ci const char *client = "?"; 337bf215546Sopenharmony_ci uint32_t axi_id = V3D_READ(V3D_MMU_VIO_ID); 338bf215546Sopenharmony_ci uint32_t va_width = 30; 339bf215546Sopenharmony_ci 340bf215546Sopenharmony_ci#if V3D_VERSION >= 41 341bf215546Sopenharmony_ci static const char *const v3d41_axi_ids[] = { 342bf215546Sopenharmony_ci "L2T", 343bf215546Sopenharmony_ci "PTB", 344bf215546Sopenharmony_ci "PSE", 345bf215546Sopenharmony_ci "TLB", 346bf215546Sopenharmony_ci "CLE", 347bf215546Sopenharmony_ci "TFU", 348bf215546Sopenharmony_ci "MMU", 349bf215546Sopenharmony_ci "GMP", 350bf215546Sopenharmony_ci }; 351bf215546Sopenharmony_ci 352bf215546Sopenharmony_ci axi_id = axi_id >> 5; 353bf215546Sopenharmony_ci if (axi_id < ARRAY_SIZE(v3d41_axi_ids)) 354bf215546Sopenharmony_ci client = v3d41_axi_ids[axi_id]; 355bf215546Sopenharmony_ci 356bf215546Sopenharmony_ci uint32_t mmu_debug = V3D_READ(V3D_MMU_DEBUG_INFO); 357bf215546Sopenharmony_ci 358bf215546Sopenharmony_ci va_width += ((mmu_debug & V3D_MMU_DEBUG_INFO_VA_WIDTH_SET) 359bf215546Sopenharmony_ci >> V3D_MMU_DEBUG_INFO_VA_WIDTH_LSB); 360bf215546Sopenharmony_ci#endif 361bf215546Sopenharmony_ci /* Only the top bits (final number depends on the gen) of the virtual 362bf215546Sopenharmony_ci * address are reported in the MMU VIO_ADDR register. 363bf215546Sopenharmony_ci */ 364bf215546Sopenharmony_ci uint64_t vio_addr = ((uint64_t)V3D_READ(V3D_MMU_VIO_ADDR) << 365bf215546Sopenharmony_ci (va_width - 32)); 366bf215546Sopenharmony_ci 367bf215546Sopenharmony_ci /* Difference with the kernal: here were are going to abort after 368bf215546Sopenharmony_ci * logging, so we don't bother with some stuff that the kernel does, 369bf215546Sopenharmony_ci * like restoring the MMU ctrl bits 370bf215546Sopenharmony_ci */ 371bf215546Sopenharmony_ci 372bf215546Sopenharmony_ci fprintf(stderr, "MMU error from client %s (%d) at 0x%llx%s%s%s\n", 373bf215546Sopenharmony_ci client, axi_id, (long long) vio_addr, 374bf215546Sopenharmony_ci wrv ? ", write violation" : "", 375bf215546Sopenharmony_ci pti ? ", pte invalid" : "", 376bf215546Sopenharmony_ci cap ? ", cap exceeded" : ""); 377bf215546Sopenharmony_ci 378bf215546Sopenharmony_ci abort(); 379bf215546Sopenharmony_ci} 380bf215546Sopenharmony_ci 381bf215546Sopenharmony_cistatic void 382bf215546Sopenharmony_civ3d_isr_hub(struct v3d_hw *v3d) 383bf215546Sopenharmony_ci{ 384bf215546Sopenharmony_ci uint32_t hub_status = V3D_READ(V3D_HUB_CTL_INT_STS); 385bf215546Sopenharmony_ci 386bf215546Sopenharmony_ci /* Acknowledge the interrupts we're handling here */ 387bf215546Sopenharmony_ci V3D_WRITE(V3D_HUB_CTL_INT_CLR, hub_status); 388bf215546Sopenharmony_ci 389bf215546Sopenharmony_ci if (hub_status & V3D_HUB_CTL_INT_STS_INT_TFUC_SET) { 390bf215546Sopenharmony_ci /* FIXME: we were not able to raise this exception. We let the 391bf215546Sopenharmony_ci * unreachable here, so we could get one if it is raised on 392bf215546Sopenharmony_ci * the future. In any case, note that for this case we would 393bf215546Sopenharmony_ci * only be doing debugging log. 394bf215546Sopenharmony_ci */ 395bf215546Sopenharmony_ci unreachable("TFU Conversion Complete interrupt not handled"); 396bf215546Sopenharmony_ci } 397bf215546Sopenharmony_ci 398bf215546Sopenharmony_ci handle_mmu_interruptions(v3d, hub_status); 399bf215546Sopenharmony_ci} 400bf215546Sopenharmony_ci 401bf215546Sopenharmony_cistatic void 402bf215546Sopenharmony_civ3d_isr(uint32_t hub_status) 403bf215546Sopenharmony_ci{ 404bf215546Sopenharmony_ci struct v3d_hw *v3d = v3d_isr_hw; 405bf215546Sopenharmony_ci uint32_t mask = hub_status; 406bf215546Sopenharmony_ci 407bf215546Sopenharmony_ci /* Check the hub_status bits */ 408bf215546Sopenharmony_ci while (mask) { 409bf215546Sopenharmony_ci unsigned core = u_bit_scan(&mask); 410bf215546Sopenharmony_ci 411bf215546Sopenharmony_ci if (core == v3d_hw_get_hub_core()) 412bf215546Sopenharmony_ci v3d_isr_hub(v3d); 413bf215546Sopenharmony_ci else 414bf215546Sopenharmony_ci v3d_isr_core(v3d, core); 415bf215546Sopenharmony_ci } 416bf215546Sopenharmony_ci 417bf215546Sopenharmony_ci return; 418bf215546Sopenharmony_ci} 419bf215546Sopenharmony_ci 420bf215546Sopenharmony_civoid 421bf215546Sopenharmony_civ3dX(simulator_init_regs)(struct v3d_hw *v3d) 422bf215546Sopenharmony_ci{ 423bf215546Sopenharmony_ci#if V3D_VERSION == 33 424bf215546Sopenharmony_ci /* Set OVRTMUOUT to match kernel behavior. 425bf215546Sopenharmony_ci * 426bf215546Sopenharmony_ci * This means that the texture sampler uniform configuration's tmu 427bf215546Sopenharmony_ci * output type field is used, instead of using the hardware default 428bf215546Sopenharmony_ci * behavior based on the texture type. If you want the default 429bf215546Sopenharmony_ci * behavior, you can still put "2" in the indirect texture state's 430bf215546Sopenharmony_ci * output_type field. 431bf215546Sopenharmony_ci */ 432bf215546Sopenharmony_ci V3D_WRITE(V3D_CTL_0_MISCCFG, V3D_CTL_1_MISCCFG_OVRTMUOUT_SET); 433bf215546Sopenharmony_ci#endif 434bf215546Sopenharmony_ci 435bf215546Sopenharmony_ci /* FIXME: the kernel captures some additional core interrupts here, 436bf215546Sopenharmony_ci * for tracing. Perhaps we should evaluate to do the same here and add 437bf215546Sopenharmony_ci * some debug options. 438bf215546Sopenharmony_ci */ 439bf215546Sopenharmony_ci uint32_t core_interrupts = (V3D_CTL_0_INT_STS_INT_GMPV_SET | 440bf215546Sopenharmony_ci V3D_CTL_0_INT_STS_INT_OUTOMEM_SET); 441bf215546Sopenharmony_ci V3D_WRITE(V3D_CTL_0_INT_MSK_SET, ~core_interrupts); 442bf215546Sopenharmony_ci V3D_WRITE(V3D_CTL_0_INT_MSK_CLR, core_interrupts); 443bf215546Sopenharmony_ci 444bf215546Sopenharmony_ci uint32_t hub_interrupts = 445bf215546Sopenharmony_ci (V3D_HUB_CTL_INT_STS_INT_MMU_WRV_SET | /* write violation */ 446bf215546Sopenharmony_ci V3D_HUB_CTL_INT_STS_INT_MMU_PTI_SET | /* page table invalid */ 447bf215546Sopenharmony_ci V3D_HUB_CTL_INT_STS_INT_MMU_CAP_SET | /* CAP exceeded */ 448bf215546Sopenharmony_ci V3D_HUB_CTL_INT_STS_INT_TFUC_SET); /* TFU conversion */ 449bf215546Sopenharmony_ci 450bf215546Sopenharmony_ci V3D_WRITE(V3D_HUB_CTL_INT_MSK_SET, ~hub_interrupts); 451bf215546Sopenharmony_ci V3D_WRITE(V3D_HUB_CTL_INT_MSK_CLR, hub_interrupts); 452bf215546Sopenharmony_ci 453bf215546Sopenharmony_ci v3d_isr_hw = v3d; 454bf215546Sopenharmony_ci v3d_hw_set_isr(v3d, v3d_isr); 455bf215546Sopenharmony_ci} 456bf215546Sopenharmony_ci 457bf215546Sopenharmony_civoid 458bf215546Sopenharmony_civ3dX(simulator_submit_cl_ioctl)(struct v3d_hw *v3d, 459bf215546Sopenharmony_ci struct drm_v3d_submit_cl *submit, 460bf215546Sopenharmony_ci uint32_t gmp_ofs) 461bf215546Sopenharmony_ci{ 462bf215546Sopenharmony_ci int last_bfc = (V3D_READ(V3D_CLE_0_BFC) & 463bf215546Sopenharmony_ci V3D_CLE_0_BFC_BMFCT_SET); 464bf215546Sopenharmony_ci 465bf215546Sopenharmony_ci int last_rfc = (V3D_READ(V3D_CLE_0_RFC) & 466bf215546Sopenharmony_ci V3D_CLE_0_RFC_RMFCT_SET); 467bf215546Sopenharmony_ci 468bf215546Sopenharmony_ci g_gmp_ofs = gmp_ofs; 469bf215546Sopenharmony_ci v3d_reload_gmp(v3d); 470bf215546Sopenharmony_ci 471bf215546Sopenharmony_ci v3d_invalidate_caches(v3d); 472bf215546Sopenharmony_ci 473bf215546Sopenharmony_ci if (submit->qma) { 474bf215546Sopenharmony_ci V3D_WRITE(V3D_CLE_0_CT0QMA, submit->qma); 475bf215546Sopenharmony_ci V3D_WRITE(V3D_CLE_0_CT0QMS, submit->qms); 476bf215546Sopenharmony_ci } 477bf215546Sopenharmony_ci#if V3D_VERSION >= 41 478bf215546Sopenharmony_ci if (submit->qts) { 479bf215546Sopenharmony_ci V3D_WRITE(V3D_CLE_0_CT0QTS, 480bf215546Sopenharmony_ci V3D_CLE_0_CT0QTS_CTQTSEN_SET | 481bf215546Sopenharmony_ci submit->qts); 482bf215546Sopenharmony_ci } 483bf215546Sopenharmony_ci#endif 484bf215546Sopenharmony_ci V3D_WRITE(V3D_CLE_0_CT0QBA, submit->bcl_start); 485bf215546Sopenharmony_ci V3D_WRITE(V3D_CLE_0_CT0QEA, submit->bcl_end); 486bf215546Sopenharmony_ci 487bf215546Sopenharmony_ci /* Wait for bin to complete before firing render. The kernel's 488bf215546Sopenharmony_ci * scheduler implements this using the GPU scheduler blocking on the 489bf215546Sopenharmony_ci * bin fence completing. (We don't use HW semaphores). 490bf215546Sopenharmony_ci */ 491bf215546Sopenharmony_ci while ((V3D_READ(V3D_CLE_0_BFC) & 492bf215546Sopenharmony_ci V3D_CLE_0_BFC_BMFCT_SET) == last_bfc) { 493bf215546Sopenharmony_ci v3d_hw_tick(v3d); 494bf215546Sopenharmony_ci } 495bf215546Sopenharmony_ci 496bf215546Sopenharmony_ci v3d_invalidate_caches(v3d); 497bf215546Sopenharmony_ci 498bf215546Sopenharmony_ci V3D_WRITE(V3D_CLE_0_CT1QBA, submit->rcl_start); 499bf215546Sopenharmony_ci V3D_WRITE(V3D_CLE_0_CT1QEA, submit->rcl_end); 500bf215546Sopenharmony_ci 501bf215546Sopenharmony_ci while ((V3D_READ(V3D_CLE_0_RFC) & 502bf215546Sopenharmony_ci V3D_CLE_0_RFC_RMFCT_SET) == last_rfc) { 503bf215546Sopenharmony_ci v3d_hw_tick(v3d); 504bf215546Sopenharmony_ci } 505bf215546Sopenharmony_ci} 506bf215546Sopenharmony_ci 507bf215546Sopenharmony_ci#if V3D_VERSION >= 41 508bf215546Sopenharmony_ci#define V3D_PCTR_0_PCTR_N(x) (V3D_PCTR_0_PCTR0 + 4 * (x)) 509bf215546Sopenharmony_ci#define V3D_PCTR_0_SRC_N(x) (V3D_PCTR_0_SRC_0_3 + 4 * (x)) 510bf215546Sopenharmony_ci#define V3D_PCTR_0_SRC_N_SHIFT(x) ((x) * 8) 511bf215546Sopenharmony_ci#define V3D_PCTR_0_SRC_N_MASK(x) (BITFIELD_RANGE(V3D_PCTR_0_SRC_N_SHIFT(x), \ 512bf215546Sopenharmony_ci V3D_PCTR_0_SRC_N_SHIFT(x) + 6)) 513bf215546Sopenharmony_ci#endif 514bf215546Sopenharmony_ci 515bf215546Sopenharmony_civoid 516bf215546Sopenharmony_civ3dX(simulator_perfmon_start)(struct v3d_hw *v3d, 517bf215546Sopenharmony_ci uint32_t ncounters, 518bf215546Sopenharmony_ci uint8_t *events) 519bf215546Sopenharmony_ci{ 520bf215546Sopenharmony_ci#if V3D_VERSION >= 41 521bf215546Sopenharmony_ci int i, j; 522bf215546Sopenharmony_ci uint32_t source; 523bf215546Sopenharmony_ci uint32_t mask = BITFIELD_RANGE(0, ncounters); 524bf215546Sopenharmony_ci 525bf215546Sopenharmony_ci for (i = 0; i < ncounters; i+=4) { 526bf215546Sopenharmony_ci source = i / 4; 527bf215546Sopenharmony_ci uint32_t channels = 0; 528bf215546Sopenharmony_ci for (j = 0; j < 4 && (i + j) < ncounters; j++) 529bf215546Sopenharmony_ci channels |= events[i + j] << V3D_PCTR_0_SRC_N_SHIFT(j); 530bf215546Sopenharmony_ci V3D_WRITE(V3D_PCTR_0_SRC_N(source), channels); 531bf215546Sopenharmony_ci } 532bf215546Sopenharmony_ci V3D_WRITE(V3D_PCTR_0_CLR, mask); 533bf215546Sopenharmony_ci V3D_WRITE(V3D_PCTR_0_OVERFLOW, mask); 534bf215546Sopenharmony_ci V3D_WRITE(V3D_PCTR_0_EN, mask); 535bf215546Sopenharmony_ci#endif 536bf215546Sopenharmony_ci} 537bf215546Sopenharmony_ci 538bf215546Sopenharmony_civoid v3dX(simulator_perfmon_stop)(struct v3d_hw *v3d, 539bf215546Sopenharmony_ci uint32_t ncounters, 540bf215546Sopenharmony_ci uint64_t *values) 541bf215546Sopenharmony_ci{ 542bf215546Sopenharmony_ci#if V3D_VERSION >= 41 543bf215546Sopenharmony_ci int i; 544bf215546Sopenharmony_ci 545bf215546Sopenharmony_ci for (i = 0; i < ncounters; i++) 546bf215546Sopenharmony_ci values[i] += V3D_READ(V3D_PCTR_0_PCTR_N(i)); 547bf215546Sopenharmony_ci 548bf215546Sopenharmony_ci V3D_WRITE(V3D_PCTR_0_EN, 0); 549bf215546Sopenharmony_ci#endif 550bf215546Sopenharmony_ci} 551bf215546Sopenharmony_ci 552bf215546Sopenharmony_ci#endif /* USE_V3D_SIMULATOR */ 553