diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c | 118 |
1 files changed, 79 insertions, 39 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index f05d9d4c6e5c..519b109f40d2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -1652,6 +1652,82 @@ gf100_gr_init_ctxctl(struct gf100_gr *gr) return ret; } +void +gf100_gr_oneinit_tiles(struct gf100_gr *gr) +{ + static const u8 primes[] = { + 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61 + }; + int init_frac[GPC_MAX], init_err[GPC_MAX], run_err[GPC_MAX], i, j; + u32 mul_factor, comm_denom; + u8 gpc_map[GPC_MAX]; + bool sorted; + + switch (gr->tpc_total) { + case 15: gr->screen_tile_row_offset = 0x06; break; + case 14: gr->screen_tile_row_offset = 0x05; break; + case 13: gr->screen_tile_row_offset = 0x02; break; + case 11: gr->screen_tile_row_offset = 0x07; break; + case 10: gr->screen_tile_row_offset = 0x06; break; + case 7: + case 5: gr->screen_tile_row_offset = 0x01; break; + case 3: gr->screen_tile_row_offset = 0x02; break; + case 2: + case 1: gr->screen_tile_row_offset = 0x01; break; + default: gr->screen_tile_row_offset = 0x03; + for (i = 0; i < ARRAY_SIZE(primes); i++) { + if (gr->tpc_total % primes[i]) { + gr->screen_tile_row_offset = primes[i]; + break; + } + } + break; + } + + /* Sort GPCs by TPC count, highest-to-lowest. */ + for (i = 0; i < gr->gpc_nr; i++) + gpc_map[i] = i; + sorted = false; + + while (!sorted) { + for (sorted = true, i = 0; i < gr->gpc_nr - 1; i++) { + if (gr->tpc_nr[gpc_map[i + 1]] > + gr->tpc_nr[gpc_map[i + 0]]) { + u8 swap = gpc_map[i]; + gpc_map[i + 0] = gpc_map[i + 1]; + gpc_map[i + 1] = swap; + sorted = false; + } + } + } + + /* Determine tile->GPC mapping */ + mul_factor = gr->gpc_nr * gr->tpc_max; + if (mul_factor & 1) + mul_factor = 2; + else + mul_factor = 1; + + comm_denom = gr->gpc_nr * gr->tpc_max * mul_factor; + + for (i = 0; i < gr->gpc_nr; i++) { + init_frac[i] = gr->tpc_nr[gpc_map[i]] * gr->gpc_nr * mul_factor; + init_err[i] = i * gr->tpc_max * mul_factor - comm_denom/2; + run_err[i] = init_frac[i] + init_err[i]; + } + + for (i = 0; i < gr->tpc_total;) { + for (j = 0; j < gr->gpc_nr; j++) { + if ((run_err[j] * 2) >= comm_denom) { + gr->tile[i++] = gpc_map[j]; + run_err[j] += init_frac[j] - comm_denom; + } else { + run_err[j] += init_frac[j]; + } + } + } +} + static int gf100_gr_oneinit(struct nvkm_gr *base) { @@ -1691,45 +1767,8 @@ gf100_gr_oneinit(struct nvkm_gr *base) } } - /*XXX: these need figuring out... though it might not even matter */ - switch (device->chipset) { - case 0xc0: - if (gr->tpc_total == 11) { /* 465, 3/4/4/0, 4 */ - gr->screen_tile_row_offset = 0x07; - } else - if (gr->tpc_total == 14) { /* 470, 3/3/4/4, 5 */ - gr->screen_tile_row_offset = 0x05; - } else - if (gr->tpc_total == 15) { /* 480, 3/4/4/4, 6 */ - gr->screen_tile_row_offset = 0x06; - } - break; - case 0xc3: /* 450, 4/0/0/0, 2 */ - gr->screen_tile_row_offset = 0x03; - break; - case 0xc4: /* 460, 3/4/0/0, 4 */ - gr->screen_tile_row_offset = 0x01; - break; - case 0xc1: /* 2/0/0/0, 1 */ - gr->screen_tile_row_offset = 0x01; - break; - case 0xc8: /* 4/4/3/4, 5 */ - gr->screen_tile_row_offset = 0x06; - break; - case 0xce: /* 4/4/0/0, 4 */ - gr->screen_tile_row_offset = 0x03; - break; - case 0xcf: /* 4/0/0/0, 3 */ - gr->screen_tile_row_offset = 0x03; - break; - case 0xd7: - case 0xd9: /* 1/0/0/0, 1 */ - case 0xea: /* gk20a */ - case 0x12b: /* gm20b */ - gr->screen_tile_row_offset = 0x01; - break; - } - + memset(gr->tile, 0xff, sizeof(gr->tile)); + gr->func->oneinit_tiles(gr); return 0; } @@ -2164,6 +2203,7 @@ gf100_gr_gpccs_ucode = { static const struct gf100_gr_func gf100_gr = { + .oneinit_tiles = gf100_gr_oneinit_tiles, .init = gf100_gr_init, .init_gpc_mmu = gf100_gr_init_gpc_mmu, .init_vsc_stream_master = gf100_gr_init_vsc_stream_master, |