diff --git a/include/nvhw.h b/include/nvhw.h index f81972f3..5ff07da1 100644 --- a/include/nvhw.h +++ b/include/nvhw.h @@ -27,6 +27,15 @@ #include +struct chipset_info { + uint32_t pmc_id; + int chipset; + int card_type; + int is_nv03t; + int endian; + const char *name; +}; + enum pfb_type { PFB_NONE, PFB_NV01, @@ -55,6 +64,7 @@ struct mc_config { int partshift; }; +int parse_pmc_id(uint32_t pmc_id, struct chipset_info *info); int pfb_type(int chipset); int tile_pitch_valid(int chipset, uint32_t pitch, int *pshift, int *pfactor); diff --git a/nvhw/chipset.c b/nvhw/chipset.c index dbbc3c9b..9419ec2e 100644 --- a/nvhw/chipset.c +++ b/nvhw/chipset.c @@ -24,6 +24,160 @@ #include "nvhw.h" #include +#include + +int parse_pmc_id(uint32_t pmc_id, struct chipset_info *info) { + /* First, detect PMC_ID format and endian. There are four cases: + * + * - pre-NV10 card: always little endian, bits 7 and 31 are guaranteed + * to be 0 (they're high bits of fields that never got big values) + * - NV10+ little-endian card: bit 7 is guaranteed to be 1 (MSB of + * stepping, which is always 0xaX or 0xbX), bit 31 is guaranteed + * to be 0 + * - NV10+ big-endian card: like above, but with byteswapping - bit 7 + * is 0, bit 31 is 1 + * - something is broken with BAR0 access and ID returns 0xffffffff + * - both bit 7 and bit 31 are set + */ + memset(info, 0, sizeof *info); + info->endian = 0; + if (pmc_id & 0x80000000) { + /* bit 31 set - set endian flag and byteswap */ + info->endian = 1; + pmc_id = (pmc_id & 0x0000ffff) << 16 | (pmc_id & 0xffff0000) >> 16; + pmc_id = (pmc_id & 0x00ff00ff) << 8 | (pmc_id & 0xff00ff00) >> 8; + } + if (pmc_id & 0x80000000) { + /* bit 31 still set - ie. old bit 7 was set - BAR0 is broken */ + info->chipset = -1; + info->name = "(disabled)"; + return -1; + } + info->pmc_id = pmc_id; + if (pmc_id & 0x80) { + /* NV10+ */ + info->chipset = pmc_id >> 20 & 0x1ff; + info->card_type = info->chipset & 0x1f0; + if (info->card_type == 0x60) { + info->card_type = 0x40; + } else if (info->card_type >= 0x80 && info->card_type <= 0xa0) { + info->card_type = 0x50; + } else if (info->card_type >= 0xc0 && info->card_type <= 0x100) { + info->card_type = 0xc0; + } + switch (info->chipset) { + /* celsius */ + case 0x10: info->name = "NV10"; break; + case 0x15: info->name = "NV15"; break; + case 0x1a: info->name = "NV1A"; break; + case 0x11: info->name = "NV11"; break; + case 0x17: info->name = "NV17"; break; + case 0x18: info->name = "NV18"; break; + case 0x1f: info->name = "NV1F"; break; + + /* kelvin */ + case 0x20: info->name = "NV20"; break; + case 0x2a: info->name = "NV2A"; break; + case 0x25: info->name = "NV25"; break; + case 0x28: info->name = "NV28"; break; + + /* rankine */ + case 0x30: info->name = "NV30"; break; + case 0x35: info->name = "NV35"; break; + case 0x31: info->name = "NV31"; break; + case 0x36: info->name = "NV36"; break; + case 0x34: info->name = "NV34"; break; + + /* curie */ + case 0x40: info->name = "NV40"; break; + case 0x45: info->name = "NV45"; break; + case 0x41: info->name = "NV41"; break; + case 0x42: info->name = "NV42"; break; + case 0x43: info->name = "NV43"; break; + case 0x44: info->name = "NV44"; break; + case 0x4a: info->name = "NV44A"; break; + case 0x4e: info->name = "C51"; break; + + /* curie2 */ + case 0x47: info->name = "G70"; break; + case 0x49: info->name = "G71"; break; + case 0x4b: info->name = "G73"; break; + case 0x46: info->name = "G72"; break; + case 0x4c: info->name = "C61"; break; + case 0x67: info->name = "C67"; break; + case 0x68: info->name = "C68"; break; + case 0x63: info->name = "C73"; break; + + /* tesla */ + case 0x50: info->name = "G80"; break; + case 0x84: info->name = "G84"; break; + case 0x86: info->name = "G86"; break; + case 0x92: info->name = "G92"; break; + case 0x94: info->name = "G94"; break; + case 0x96: info->name = "G96"; break; + case 0x98: info->name = "G98"; break; + case 0xa0: info->name = "GT200"; break; + case 0xaa: info->name = "MCP77"; break; + case 0xac: info->name = "MCP79"; break; + + /* tesla2 */ + case 0xa3: info->name = "GT215"; break; + case 0xa5: info->name = "GT216"; break; + case 0xa8: info->name = "GT218"; break; + case 0xaf: info->name = "MCP89"; break; + + /* fermi */ + case 0xc0: info->name = "GF100"; break; + case 0xc4: info->name = "GF104"; break; + case 0xc3: info->name = "GF106"; break; + case 0xce: info->name = "GF114"; break; + case 0xcf: info->name = "GF116"; break; + case 0xc1: info->name = "GF108"; break; + case 0xc8: info->name = "GF110"; break; + case 0xd9: info->name = "GF119"; break; + case 0xd7: info->name = "GF117"; break; + + /* kepler */ + case 0xe4: info->name = "GK104"; break; + case 0xe6: info->name = "GK106"; break; + case 0xe7: info->name = "GK107"; break; + case 0xf0: info->name = "GK110"; break; + case 0xf1: info->name = "GK110B"; break; + case 0x108: info->name = "GK208"; break; + + /* wtf */ + default: info->name = "???"; + } + } else { + /* pre-NV10 */ + if (pmc_id & 0xf000) { + if (pmc_id & 0xf00000) { + info->chipset = 5; + info->name = "NV05"; + } else { + info->chipset = 4; + info->name = "NV04"; + } + info->card_type = 4; + } else { + info->chipset = pmc_id >> 16 & 0xf; + info->card_type = info->chipset; + if (info->chipset == 1) { + info->name = "NV01"; + } else if (info->chipset == 3) { + if ((pmc_id & 0xff) >= 0x20) { + info->name = "NV03T"; + info->is_nv03t = 1; + } else { + info->name = "NV03"; + } + } else { + info->name = "???"; + } + } + } + return 0; +} int is_igp(int chipset) { switch (chipset) {