# # Copyright © 2021 Google, Inc. # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice (including the next # paragraph) shall be included in all copies or substantial portions of the # Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. from mako.template import Template import sys def max_bitfield_val(high, low, shift): return ((1 << (high - low)) - 1) << shift class State(object): def __init__(self): # List of unique device-info structs, multiple different GPU ids # can map to a single info struct in cases where the differences # are not sw visible, or the only differences are parameters # queried from the kernel (like GMEM size) self.gpu_infos = [] # Table mapping GPU id to device-info struct self.gpus = {} def info_index(self, gpu_info): i = 0 for info in self.gpu_infos: if gpu_info == info: return i i += 1 raise Error("invalid info") s = State() def add_gpus(ids, info): for id in ids: s.gpus[id] = info class GPUId(object): def __init__(self, gpu_id = None, chip_id = None, name=None): if chip_id == None: assert(gpu_id != None) val = gpu_id core = int(val / 100) val -= (core * 100); major = int(val / 10); val -= (major * 10) minor = val chip_id = (core << 24) | (major << 16) | (minor << 8) | 0xff self.chip_id = chip_id if gpu_id == None: gpu_id = 0 self.gpu_id = gpu_id if name == None: assert(gpu_id != 0) name = "FD%d" % gpu_id self.name = name class Struct(object): """A helper class that stringifies itself to a 'C' struct initializer """ def __str__(self): s = "{" for name, value in vars(self).items(): s += "." + name + "=" + str(value) + "," return s + "}" class GPUInfo(Struct): """Base class for any generation of adreno, consists of GMEM layout related parameters Note that tile_max_h is normally only constrained by corresponding bitfield size/shift (ie. VSC_BIN_SIZE, or similar), but tile_max_h tends to have lower limits, in which case a comment will describe the bitfield size/shift """ def __init__(self, gmem_align_w, gmem_align_h, tile_align_w, tile_align_h, tile_max_w, tile_max_h, num_vsc_pipes): self.gmem_align_w = gmem_align_w self.gmem_align_h = gmem_align_h self.tile_align_w = tile_align_w self.tile_align_h = tile_align_h self.tile_max_w = tile_max_w self.tile_max_h = tile_max_h self.num_vsc_pipes = num_vsc_pipes s.gpu_infos.append(self) class A6xxGPUInfo(GPUInfo): """The a6xx generation has a lot more parameters, and is broken down into distinct sub-generations. The template parameter avoids duplication of parameters that are unique to the sub-generation. """ def __init__(self, template, num_sp_cores, num_ccu, RB_UNKNOWN_8E04_blit, PC_POWER_CNTL): super().__init__(gmem_align_w = 16, gmem_align_h = 4, tile_align_w = 32, tile_align_h = 32, tile_max_w = 1024, # max_bitfield_val(5, 0, 5) tile_max_h = max_bitfield_val(14, 8, 4), num_vsc_pipes = 32) assert(num_sp_cores == num_ccu) self.num_sp_cores = num_sp_cores # 96 tile alignment seems correlated to 3 CCU if num_ccu == 3: self.tile_align_w = 96 self.a6xx = Struct() self.a6xx.magic = Struct() for name, val in template["magic"].items(): setattr(self.a6xx.magic, name, val) # Various "magic" register values: self.a6xx.magic.RB_UNKNOWN_8E04_blit = RB_UNKNOWN_8E04_blit self.a6xx.magic.PC_POWER_CNTL = PC_POWER_CNTL # Things that earlier gens have and later gens remove, provide # defaults here and let them be overridden by sub-gen template: self.a6xx.has_cp_reg_write = True self.a6xx.has_8bpp_ubwc = True for name, val in template.items(): if name == "magic": # handled above continue setattr(self.a6xx, name, val) # a2xx is really two sub-generations, a20x and a22x, but we don't currently # capture that in the device-info tables add_gpus([ GPUId(200), GPUId(201), GPUId(205), GPUId(220), ], GPUInfo( gmem_align_w = 32, gmem_align_h = 32, tile_align_w = 32, tile_align_h = 32, tile_max_w = 512, tile_max_h = ~0, # TODO num_vsc_pipes = 8, )) add_gpus([ GPUId(305), GPUId(307), GPUId(320), GPUId(330), ], GPUInfo( gmem_align_w = 32, gmem_align_h = 32, tile_align_w = 32, tile_align_h = 32, tile_max_w = 992, # max_bitfield_val(4, 0, 5) tile_max_h = max_bitfield_val(9, 5, 5), num_vsc_pipes = 8, )) add_gpus([ GPUId(405), GPUId(420), GPUId(430), ], GPUInfo( gmem_align_w = 32, gmem_align_h = 32, tile_align_w = 32, tile_align_h = 32, tile_max_w = 1024, # max_bitfield_val(4, 0, 5) tile_max_h = max_bitfield_val(9, 5, 5), num_vsc_pipes = 8, )) add_gpus([ GPUId(508), GPUId(509), GPUId(510), GPUId(512), GPUId(530), GPUId(540), ], GPUInfo( gmem_align_w = 64, gmem_align_h = 32, tile_align_w = 64, tile_align_h = 32, tile_max_w = 1024, # max_bitfield_val(7, 0, 5) tile_max_h = max_bitfield_val(16, 9, 5), num_vsc_pipes = 16, )) # a6xx can be divided into distinct sub-generations, where certain device- # info parameters are keyed to the sub-generation. These templates reduce # the copypaste # a615, a618, a630: a6xx_gen1 = dict( fibers_per_sp = 128 * 16, reg_size_vec4 = 96, ccu_cntl_gmem_unk2 = True, indirect_draw_wfm_quirk = True, depth_bounds_require_depth_test_quirk = True, magic = dict( TPL1_DBG_ECO_CNTL = 0x100000, ) ) # a640, a680: a6xx_gen2 = dict( fibers_per_sp = 128 * 4 * 16, reg_size_vec4 = 96, supports_multiview_mask = True, has_z24uint_s8uint = True, indirect_draw_wfm_quirk = True, depth_bounds_require_depth_test_quirk = True, # TODO: check if true magic = dict( TPL1_DBG_ECO_CNTL = 0, ), ) # a650: a6xx_gen3 = dict( fibers_per_sp = 128 * 2 * 16, reg_size_vec4 = 64, supports_multiview_mask = True, has_z24uint_s8uint = True, tess_use_shared = True, storage_16bit = True, has_tex_filter_cubic = True, has_sample_locations = True, has_ccu_flush_bug = True, has_8bpp_ubwc = False, magic = dict( # this seems to be a chicken bit that fixes cubic filtering: TPL1_DBG_ECO_CNTL = 0x1000000, ), ) # a635, a660: a6xx_gen4 = dict( fibers_per_sp = 128 * 2 * 16, reg_size_vec4 = 64, supports_multiview_mask = True, has_z24uint_s8uint = True, tess_use_shared = True, storage_16bit = True, has_tex_filter_cubic = True, has_sample_locations = True, has_cp_reg_write = False, has_8bpp_ubwc = False, has_lpac = True, has_shading_rate = True, magic = dict( TPL1_DBG_ECO_CNTL = 0x5008000, ), ) add_gpus([ GPUId(615), GPUId(618), ], A6xxGPUInfo( a6xx_gen1, num_sp_cores = 1, num_ccu = 1, RB_UNKNOWN_8E04_blit = 0x00100000, PC_POWER_CNTL = 0, )) add_gpus([ GPUId(630), ], A6xxGPUInfo( a6xx_gen1, num_sp_cores = 2, num_ccu = 2, RB_UNKNOWN_8E04_blit = 0x01000000, PC_POWER_CNTL = 1, )) add_gpus([ GPUId(640), ], A6xxGPUInfo( a6xx_gen2, num_sp_cores = 2, num_ccu = 2, RB_UNKNOWN_8E04_blit = 0x00100000, PC_POWER_CNTL = 1, )) add_gpus([ GPUId(680), ], A6xxGPUInfo( a6xx_gen2, num_sp_cores = 4, num_ccu = 4, RB_UNKNOWN_8E04_blit = 0x04100000, PC_POWER_CNTL = 3, )) add_gpus([ GPUId(650), ], A6xxGPUInfo( a6xx_gen3, num_sp_cores = 3, num_ccu = 3, RB_UNKNOWN_8E04_blit = 0x04100000, PC_POWER_CNTL = 2, )) add_gpus([ GPUId(chip_id=0x06030500, name="Adreno 7c Gen 3"), ], A6xxGPUInfo( a6xx_gen4, num_sp_cores = 2, num_ccu = 2, RB_UNKNOWN_8E04_blit = 0x00100000, PC_POWER_CNTL = 1, )) add_gpus([ GPUId(660), ], A6xxGPUInfo( a6xx_gen4, num_sp_cores = 3, num_ccu = 3, RB_UNKNOWN_8E04_blit = 0x04100000, PC_POWER_CNTL = 2, )) template = """\ /* Copyright (C) 2021 Google, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #include "freedreno_dev_info.h" /* Map python to C: */ #define True true #define False false %for info in s.gpu_infos: static const struct fd_dev_info __info${s.info_index(info)} = ${str(info)}; %endfor static const struct fd_dev_rec fd_dev_recs[] = { %for id, info in s.gpus.items(): { {${id.gpu_id}, ${hex(id.chip_id)}}, "${id.name}", &__info${s.info_index(info)} }, %endfor }; """ print(Template(template).render(s=s))