#include "chipset.h" #include "gpu.h" #include #include static bool pmc_id_flipped(uint32_t pmc_id) { /* * For determining endianness, 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. This can happen on later cards, so * in this case we can rely on bits 8-11 to be zero without * byteswapping */ if (pmc_id & 0x80000000) { if (!(pmc_id & 0x00000080)) /* bit 7 is 0, we're flipped */ return true; else /* bits 31 and 7 are both 1, rely on 8-11 instead */ return !!(pmc_id & 0x00000F00); } return false; } int parse_pmc_id(uint32_t pmc_id, struct chipset_info *info) { /* First, detect PMC_ID format and endianness */ memset(info, 0, sizeof *info); info->endian = 0; info->gpu = GPU_UNKNOWN; info->gpu_desc = 0; if (pmc_id_flipped(pmc_id)) { /* 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; } info->pmc_id = pmc_id; if (pmc_id & 0x80000000 && pmc_id & 0x00000F00) { /* bit 31 still set - ie. old bit 7 was set, and bits 8-11 are * still nonzero - BAR0 is broken */ return -1; } 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; } for (int i = 0; i < NUM_GPU; i++) { if (gpu_list[i].id_valid && gpu_list[i].id == info->chipset) { info->gpu = i; } } } else { /* pre-NV10 */ if (pmc_id & 0xf000) { if (pmc_id & 0xf00000) { info->chipset = 5; info->gpu = GPU_NV5; } else { info->chipset = 4; info->gpu = GPU_NV4; } info->card_type = 4; } else { info->chipset = pmc_id >> 16 & 0xf; info->card_type = info->chipset; if (info->chipset == 1) { info->gpu = GPU_NV1; } else if (info->chipset == 3) { if ((pmc_id & 0xff) >= 0x20) { info->gpu = GPU_NV3T; } else { info->gpu = GPU_NV3; } } } } if (info->gpu != GPU_UNKNOWN) { info->gpu_desc = &gpu_list[info->gpu]; return 0; } else { return -1; } } int is_igp(int chipset) { switch (chipset) { case 0x0a: case 0x1a: case 0x1f: case 0x2a: case 0x4e: case 0x4c: case 0x67: case 0x68: case 0x63: case 0xaa: case 0xac: case 0xaf: return 1; default: return 0; } } int is_g7x(int chipset) { if (chipset < 0x46 || chipset == 0x4a || chipset == 0x4e || chipset == 0x50 || chipset >= 0x70) return 0; return 1; } int pfb_type(int chipset) { if (chipset <3) return PFB_NV01; if (chipset < 0x10) return PFB_NV03; if (chipset < 0x1a || chipset == 0x34) return PFB_NV10; if (chipset < 0x20) return PFB_NONE; /* IGP */ if (chipset < 0x40) return PFB_NV20; if (chipset == 0x40 || chipset == 0x45) return PFB_NV40; if (chipset != 0x44 && chipset != 0x46 && chipset != 0x4a && chipset < 0x4c) return PFB_NV41; if (chipset != 0x50 && chipset < 0x80) return PFB_NV44; if (chipset < 0xc0) return PFB_NV50; return PFB_NVC0; } int get_maxparts(int chipset) { switch (chipset) { case 0x1a: case 0x1f: case 0x2a: case 0x4e: case 0x4c: case 0x67: case 0x68: case 0x63: return 0; case 0x10: case 0x15: case 0x11: case 0x17: case 0x18: case 0x20: case 0x25: case 0x28: case 0x30: case 0x35: case 0x40: case 0x41: case 0x42: case 0x47: case 0x49: return 4; case 0x31: case 0x36: case 0x43: case 0x4b: return 2; case 0x44: case 0x4a: case 0x46: return 1; default: abort(); } }