first commit

This commit is contained in:
Ole Algoritme
2022-09-05 21:52:22 +02:00
commit 698a8f7487
198 changed files with 951446 additions and 0 deletions

2
include/nva/README.md Normal file
View File

@@ -0,0 +1,2 @@
Copyright (C) envytools
https://github.com/envytools/envytools

17
include/nva/bus.h Normal file
View File

@@ -0,0 +1,17 @@
/* This file is auto-generated -- do not edit. */
#ifndef CGEN_BUS_H
#define CGEN_BUS_H
enum bus_interface_index {
BUS_PCI,
BUS_PCIE,
BUS_IGP,
BUS_FLEX_IO,
BUS_TEGRA,
NUM_BUS_INTERFACE,
BUS_INTERFACE_UNKNOWN = NUM_BUS_INTERFACE,
};
#endif

185
include/nva/chipset.c Normal file
View File

@@ -0,0 +1,185 @@
#include "chipset.h"
#include "gpu.h"
#include <stdlib.h>
#include <string.h>
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();
}
}

70
include/nva/chipset.h Normal file
View File

@@ -0,0 +1,70 @@
/*
* Copyright (C) 2012 Marcelina Kościelnicka <mwk@0x04.net>
* All Rights Reserved.
*
* 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.
*/
#ifndef NVHW_H
#define NVHW_H
#include "gpu.h"
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
enum pfb_type {
PFB_NONE,
PFB_NV01,
PFB_NV03,
PFB_NV10,
PFB_NV20,
PFB_NV40,
PFB_NV41,
PFB_NV44,
PFB_NV50,
PFB_NVC0,
};
struct chipset_info {
uint32_t pmc_id;
int chipset;
int card_type;
int endian;
enum gpu_index gpu;
const struct gpu *gpu_desc;
};
int parse_pmc_id(uint32_t pmc_id, struct chipset_info *info);
int is_igp(int chipset);
int is_g7x(int chipset);
int pfb_type(int chipset);
int get_maxparts(int chipset);
#ifdef __cplusplus
}
#endif
#endif

41
include/nva/fb.h Normal file
View File

@@ -0,0 +1,41 @@
/* This file is auto-generated -- do not edit. */
#ifndef CGEN_FB_H
#define CGEN_FB_H
enum fb_gen_index {
FB_NV1,
FB_NV3,
FB_NV3T,
FB_NV4,
FB_NV5,
FB_NVA,
FB_NV10,
FB_NV1A,
FB_NV1F,
FB_NV20,
FB_NV2A,
FB_NV25,
FB_NV30,
FB_NV31,
FB_NV35,
FB_NV36,
FB_NV40,
FB_NV41,
FB_NV43,
FB_G70,
FB_G73,
FB_NV44,
FB_G72,
FB_C51,
FB_MCP61,
FB_G80,
FB_MCP77,
FB_GF100,
FB_GK20A,
NUM_FB_GEN,
FB_GEN_UNKNOWN = NUM_FB_GEN,
};
#endif

143
include/nva/gen.h Normal file
View File

@@ -0,0 +1,143 @@
#ifndef CGEN_GPU_H
#define CGEN_GPU_H
#include <stdbool.h>
#include <stdint.h>
#include "bus.h"
#include "fb.h"
enum gpu_gen_index {
GEN_NV1,
GEN_NV3,
GEN_NV4,
GEN_CELSIUS,
GEN_KELVIN,
GEN_RANKINE,
GEN_CURIE,
GEN_TESLA,
GEN_FERMI,
GEN_KEPLER,
GEN_MAXWELL,
GEN_PASCAL,
GEN_VOLTA,
GEN_TURING,
NUM_GPU_GEN,
GPU_GEN_UNKNOWN = NUM_GPU_GEN,
};
enum gpu_index {
GPU_NV1,
GPU_NV3,
GPU_NV3T,
GPU_NV4,
GPU_NV5,
GPU_NV6,
GPU_NVA,
GPU_NV10,
GPU_NV15,
GPU_NV1A,
GPU_NV11,
GPU_NV17,
GPU_NV1F,
GPU_NV18,
GPU_NV20,
GPU_NV2A,
GPU_NV25,
GPU_NV28,
GPU_NV30,
GPU_NV35,
GPU_NV31,
GPU_NV36,
GPU_NV34,
GPU_NV40,
GPU_NV45,
GPU_NV41,
GPU_NV42,
GPU_NV43,
GPU_NV44,
GPU_NV44A,
GPU_G70,
GPU_G72,
GPU_G71,
GPU_G73,
GPU_C51,
GPU_MCP61,
GPU_MCP67,
GPU_MCP68,
GPU_MCP73,
GPU_RSX,
GPU_G80,
GPU_G84,
GPU_G86,
GPU_G92,
GPU_G94,
GPU_G96,
GPU_G98,
GPU_G200,
GPU_MCP77,
GPU_MCP79,
GPU_GT215,
GPU_GT216,
GPU_GT218,
GPU_MCP89,
GPU_GF100,
GPU_GF104,
GPU_GF114,
GPU_GF106,
GPU_GF116,
GPU_GF108,
GPU_GF110,
GPU_GF119,
GPU_GF117,
GPU_GK104,
GPU_GK107,
GPU_GK106,
GPU_GK110,
GPU_GK110B,
GPU_GK210,
GPU_GK208,
GPU_GK208B,
GPU_GK20A,
GPU_GM107,
GPU_GM108,
GPU_GM204,
GPU_GM200,
GPU_GM206,
GPU_GM20B,
GPU_GP100,
GPU_GP102,
GPU_GP104,
GPU_GP106,
GPU_GP107,
GPU_GP108,
GPU_GP10B,
GPU_GV100,
GPU_GV11B,
GPU_TU102,
GPU_TU104,
GPU_TU106,
GPU_TU116,
GPU_TU117,
NUM_GPU,
GPU_UNKNOWN = NUM_GPU,
};
extern const struct gpu {
const char *name;
uint32_t id;
bool id_valid;
uint32_t pciid;
bool pciid_valid;
int pciid_varbits;
bool pciid_varbits_valid;
uint32_t bios_major;
bool bios_major_valid;
uint32_t bios_chip;
bool bios_chip_valid;
enum bus_interface_index bus;
enum fb_gen_index fb;
enum gpu_gen_index gen;
} gpu_list[];
#endif

97
include/nva/gpu.c Normal file
View File

@@ -0,0 +1,97 @@
#include "gpu.h"
const struct gpu gpu_list[] = {
{ "NV1", 0, false, 0x8, true, 1, true, 0, false, 0, false, BUS_PCI, FB_NV1, GEN_NV1, },
{ "NV3", 0, false, 0x18, true, 1, true, 0, false, 0, false, BUS_PCI, FB_NV3, GEN_NV3, },
{ "NV3T", 0, false, 0x18, true, 1, true, 0, false, 0, false, BUS_PCI, FB_NV3T, GEN_NV3, },
{ "NV4", 0, false, 0x20, true, 0, true, 0, false, 0, false, BUS_PCI, FB_NV4, GEN_NV4, },
{ "NV5", 0, false, 0x28, true, 2, true, 0x2, true, 0x5, true, BUS_PCI, FB_NV5, GEN_NV4, },
{ "NV6", 0, false, 0x2c, true, 2, true, 0x2, true, 0x5, true, BUS_PCI, FB_NV5, GEN_NV4, },
{ "NVA", 0, false, 0xa0, true, 0, true, 0x2, true, -1, false, BUS_PCI, FB_NVA, GEN_NV4, },
{ "NV10", 0x10, true, 0x100, true, 2, true, 0x2, true, 0x10, true, BUS_PCI, FB_NV10, GEN_CELSIUS, },
{ "NV15", 0x15, true, 0x150, true, 2, true, 0x3, true, 0x15, true, BUS_PCI, FB_NV10, GEN_CELSIUS, },
{ "NV1A", 0x1a, true, 0x1a0, true, 2, true, 0x3, true, 0x1a, true, BUS_PCI, FB_NV1A, GEN_CELSIUS, },
{ "NV11", 0x11, true, 0x110, true, 2, true, 0x3, true, 0x11, true, BUS_PCI, FB_NV10, GEN_CELSIUS, },
{ "NV17", 0x17, true, 0x170, true, 4, true, 0x4, true, 0x17, true, BUS_PCI, FB_NV10, GEN_CELSIUS, },
{ "NV1F", 0x1f, true, 0x1f0, true, 4, true, 0x4, true, 0x1f, true, BUS_PCI, FB_NV1F, GEN_CELSIUS, },
{ "NV18", 0x18, true, 0x180, true, 4, true, 0x4, true, 0x18, true, BUS_PCI, FB_NV10, GEN_CELSIUS, },
{ "NV20", 0x20, true, 0x200, true, 2, true, 0x3, true, 0x20, true, BUS_PCI, FB_NV20, GEN_KELVIN, },
{ "NV2A", 0x2a, true, 0x2a0, true, 2, true, 0, false, 0, false, BUS_PCI, FB_NV2A, GEN_KELVIN, },
{ "NV25", 0x25, true, 0x250, true, 4, true, 0x4, true, 0x25, true, BUS_PCI, FB_NV25, GEN_KELVIN, },
{ "NV28", 0x28, true, 0x280, true, 4, true, 0x4, true, 0x28, true, BUS_PCI, FB_NV25, GEN_KELVIN, },
{ "NV30", 0x30, true, 0x300, true, 4, true, 0x4, true, 0x30, true, BUS_PCI, FB_NV30, GEN_RANKINE, },
{ "NV35", 0x35, true, 0x330, true, 4, true, 0x4, true, 0x35, true, BUS_PCI, FB_NV35, GEN_RANKINE, },
{ "NV31", 0x31, true, 0x310, true, 4, true, 0x4, true, 0x31, true, BUS_PCI, FB_NV31, GEN_RANKINE, },
{ "NV36", 0x36, true, 0x340, true, 4, true, 0x4, true, 0x36, true, BUS_PCI, FB_NV36, GEN_RANKINE, },
{ "NV34", 0x34, true, 0x320, true, 4, true, 0x4, true, 0x34, true, BUS_PCI, FB_NV10, GEN_RANKINE, },
{ "NV40", 0x40, true, 0x40, true, 4, true, 0x5, true, 0x40, true, BUS_PCI, FB_NV40, GEN_CURIE, },
{ "NV45", 0x45, true, 0x40, true, 4, true, 0x5, true, 0x40, true, BUS_PCI, FB_NV40, GEN_CURIE, },
{ "NV41", 0x41, true, 0xc0, true, 4, true, 0x5, true, 0x41, true, BUS_PCIE, FB_NV41, GEN_CURIE, },
{ "NV42", 0x42, true, 0xc0, true, 4, true, 0x5, true, 0x41, true, BUS_PCIE, FB_NV41, GEN_CURIE, },
{ "NV43", 0x43, true, 0x140, true, 4, true, 0x5, true, 0x43, true, BUS_PCIE, FB_NV43, GEN_CURIE, },
{ "NV44", 0x44, true, 0x160, true, 4, true, 0x5, true, 0x44, true, BUS_PCIE, FB_NV44, GEN_CURIE, },
{ "NV44A", 0x4a, true, 0x220, true, 4, true, 0x5, true, 0x44, true, BUS_PCI, FB_NV44, GEN_CURIE, },
{ "G70", 0x47, true, 0x90, true, 4, true, 0x5, true, 0x70, true, BUS_PCIE, FB_G70, GEN_CURIE, },
{ "G72", 0x46, true, 0x1d0, true, 4, true, 0x5, true, 0x72, true, BUS_PCIE, FB_G72, GEN_CURIE, },
{ "G71", 0x49, true, 0x290, true, 4, true, 0x5, true, 0x71, true, BUS_PCIE, FB_G70, GEN_CURIE, },
{ "G73", 0x4b, true, 0x390, true, 4, true, 0x5, true, 0x73, true, BUS_PCIE, FB_G73, GEN_CURIE, },
{ "C51", 0x4e, true, 0x240, true, 4, true, 0x5, true, 0x51, true, BUS_IGP, FB_C51, GEN_CURIE, },
{ "MCP61", 0x4c, true, 0x3d0, true, 4, true, 0x5, true, 0x61, true, BUS_IGP, FB_MCP61, GEN_CURIE, },
{ "MCP67", 0x67, true, 0x530, true, 4, true, 0x5, true, 0x67, true, BUS_IGP, FB_MCP61, GEN_CURIE, },
{ "MCP68", 0x68, true, 0x530, true, 4, true, 0x5, true, 0x67, true, BUS_IGP, FB_MCP61, GEN_CURIE, },
{ "MCP73", 0x63, true, 0x7e0, true, 4, true, 0x5, true, 0x73, true, BUS_IGP, FB_MCP61, GEN_CURIE, },
{ "RSX", 0x4d, true, 0, false, 4, true, 0, false, 0, false, BUS_FLEX_IO, FB_G72, GEN_CURIE, },
{ "G80", 0x50, true, 0x190, true, 4, true, 0x60, true, 0x80, true, BUS_PCIE, FB_G80, GEN_TESLA, },
{ "G84", 0x84, true, 0x400, true, 4, true, 0x60, true, 0x84, true, BUS_PCIE, FB_G80, GEN_TESLA, },
{ "G86", 0x86, true, 0x420, true, 4, true, 0x60, true, 0x86, true, BUS_PCIE, FB_G80, GEN_TESLA, },
{ "G92", 0x92, true, 0x600, true, 5, true, 0x62, true, 0x92, true, BUS_PCIE, FB_G80, GEN_TESLA, },
{ "G94", 0x94, true, 0x620, true, 5, true, 0x62, true, 0x94, true, BUS_PCIE, FB_G80, GEN_TESLA, },
{ "G96", 0x96, true, 0x640, true, 5, true, 0x62, true, 0x94, true, BUS_PCIE, FB_G80, GEN_TESLA, },
{ "G98", 0x98, true, 0x6e0, true, 5, true, 0x62, true, 0x98, true, BUS_PCIE, FB_G80, GEN_TESLA, },
{ "G200", 0xa0, true, 0x5e0, true, 5, true, 0x62, true, 0x0, true, BUS_PCIE, FB_G80, GEN_TESLA, },
{ "MCP77", 0xaa, true, 0x840, true, 5, true, 0x62, true, 0x77, true, BUS_IGP, FB_MCP77, GEN_TESLA, },
{ "MCP79", 0xac, true, 0x860, true, 5, true, 0x62, true, 0x79, true, BUS_IGP, FB_MCP77, GEN_TESLA, },
{ "GT215", 0xa3, true, 0xca0, true, 5, true, 0x70, true, 0x15, true, BUS_PCIE, FB_G80, GEN_TESLA, },
{ "GT216", 0xa5, true, 0xa20, true, 5, true, 0x70, true, 0x16, true, BUS_PCIE, FB_G80, GEN_TESLA, },
{ "GT218", 0xa8, true, 0xa60, true, 5, true, 0x70, true, 0x18, true, BUS_PCIE, FB_G80, GEN_TESLA, },
{ "MCP89", 0xaf, true, 0x8a0, true, 5, true, 0x70, true, 0x89, true, BUS_IGP, FB_MCP77, GEN_TESLA, },
{ "GF100", 0xc0, true, 0x6c0, true, 5, true, 0x70, true, 0x0, true, BUS_PCIE, FB_GF100, GEN_FERMI, },
{ "GF104", 0xc4, true, 0xe20, true, 5, true, 0x70, true, 0x4, true, BUS_PCIE, FB_GF100, GEN_FERMI, },
{ "GF114", 0xce, true, 0x1200, true, 5, true, 0x70, true, 0x24, true, BUS_PCIE, FB_GF100, GEN_FERMI, },
{ "GF106", 0xc3, true, 0xdc0, true, 5, true, 0x70, true, 0x6, true, BUS_PCIE, FB_GF100, GEN_FERMI, },
{ "GF116", 0xcf, true, 0x1240, true, 5, true, 0x70, true, 0x26, true, BUS_PCIE, FB_GF100, GEN_FERMI, },
{ "GF108", 0xc1, true, 0xde0, true, 5, true, 0x70, true, 0x8, true, BUS_PCIE, FB_GF100, GEN_FERMI, },
{ "GF110", 0xc8, true, 0x1080, true, 5, true, 0x70, true, 0x10, true, BUS_PCIE, FB_GF100, GEN_FERMI, },
{ "GF119", 0xd9, true, 0x1040, true, 6, true, 0x75, true, 0x19, true, BUS_PCIE, FB_GF100, GEN_FERMI, },
{ "GF117", 0xd7, true, 0x1140, true, 6, true, 0x75, true, -1, false, BUS_PCIE, FB_GF100, GEN_FERMI, },
{ "GK104", 0xe4, true, 0x1180, true, 6, true, 0x80, true, 0x4, true, BUS_PCIE, FB_GF100, GEN_KEPLER, },
{ "GK107", 0xe7, true, 0xfc0, true, 6, true, 0x80, true, 0x7, true, BUS_PCIE, FB_GF100, GEN_KEPLER, },
{ "GK106", 0xe6, true, 0x11c0, true, 6, true, 0x80, true, 0x6, true, BUS_PCIE, FB_GF100, GEN_KEPLER, },
{ "GK110", 0xf0, true, 0x1000, true, 6, true, 0x80, true, 0x10, true, BUS_PCIE, FB_GF100, GEN_KEPLER, },
{ "GK110B", 0xf1, true, 0x1000, true, 6, true, 0x80, true, 0x80, true, BUS_PCIE, FB_GF100, GEN_KEPLER, },
{ "GK210", -1, false, -1, false, 6, true, 0x80, true, -1, false, BUS_PCIE, FB_GF100, GEN_KEPLER, },
{ "GK208", 0x108, true, 0x1280, true, 6, true, 0x80, true, 0x28, true, BUS_PCIE, FB_GF100, GEN_KEPLER, },
{ "GK208B", 0x106, true, 0x1280, true, 6, true, 0x80, true, 0x28, true, BUS_PCIE, FB_GF100, GEN_KEPLER, },
{ "GK20A", 0xea, true, 0, false, 6, true, 0, false, 0, false, BUS_TEGRA, FB_GK20A, GEN_KEPLER, },
{ "GM107", 0x117, true, 0x1380, true, 6, true, 0x82, true, 0x7, true, BUS_PCIE, FB_GF100, GEN_MAXWELL, },
{ "GM108", 0x118, true, 0x1340, true, 6, true, 0x82, true, 0x8, true, BUS_PCIE, FB_GF100, GEN_MAXWELL, },
{ "GM204", 0x124, true, 0x13c0, true, 6, true, 0x84, true, 0x4, true, BUS_PCIE, FB_GF100, GEN_MAXWELL, },
{ "GM200", 0x120, true, 0x17c0, true, 6, true, 0x84, true, 0x0, true, BUS_PCIE, FB_GF100, GEN_MAXWELL, },
{ "GM206", 0x126, true, 0x1400, true, 6, true, 0x84, true, 0x6, true, BUS_PCIE, FB_GF100, GEN_MAXWELL, },
{ "GM20B", 0x12b, true, 0, false, 6, true, 0, false, 0, false, BUS_TEGRA, FB_GK20A, GEN_MAXWELL, },
{ "GP100", 0x130, true, 0x1580, true, 7, true, 0x86, true, 0x0, true, BUS_PCIE, FB_GF100, GEN_PASCAL, },
{ "GP102", 0x132, true, 0x1b00, true, 7, true, 0x86, true, 0x2, true, BUS_PCIE, FB_GF100, GEN_PASCAL, },
{ "GP104", 0x134, true, 0x1b80, true, 7, true, 0x86, true, 0x4, true, BUS_PCIE, FB_GF100, GEN_PASCAL, },
{ "GP106", 0x136, true, 0x1c00, true, 7, true, 0x86, true, 0x6, true, BUS_PCIE, FB_GF100, GEN_PASCAL, },
{ "GP107", 0x137, true, 0x1c80, true, 7, true, 0x86, true, 0x7, true, BUS_PCIE, FB_GF100, GEN_PASCAL, },
{ "GP108", 0x138, true, 0x1d00, true, 7, true, 0x86, true, 0x8, true, BUS_PCIE, FB_GF100, GEN_PASCAL, },
{ "GP10B", 0x13b, true, 0x10e5, true, 7, true, 0, false, 0, false, BUS_TEGRA, FB_GF100, GEN_PASCAL, },
{ "GV100", 0x140, true, 0x1d80, true, 7, true, 0x88, true, 0x0, true, BUS_PCIE, FB_GF100, GEN_VOLTA, },
{ "GV11B", 0x15b, true, 0, false, 7, true, 0, false, 0, false, BUS_TEGRA, FB_GF100, GEN_VOLTA, },
{ "TU102", 0x162, true, 0x1e00, true, 7, true, 0x90, true, 0x2, true, BUS_PCIE, FB_GF100, GEN_TURING, },
{ "TU104", 0x164, true, 0x1e80, true, 7, true, 0x90, true, 0x4, true, BUS_PCIE, FB_GF100, GEN_TURING, },
{ "TU106", 0x166, true, 0x1f00, true, 7, true, 0x90, true, 0x6, true, BUS_PCIE, FB_GF100, GEN_TURING, },
{ "TU116", 0x168, true, 0x2180, true, 7, true, 0x90, true, 0x16, true, BUS_PCIE, FB_GF100, GEN_TURING, },
{ "TU117", 0x167, true, 0x1f80, true, 7, true, 0x90, true, 0x17, true, BUS_PCIE, FB_GF100, GEN_TURING, },
};

143
include/nva/gpu.h Normal file
View File

@@ -0,0 +1,143 @@
#ifndef CGEN_GPU_H
#define CGEN_GPU_H
#include <stdbool.h>
#include <stdint.h>
#include "bus.h"
#include "fb.h"
enum gpu_gen_index {
GEN_NV1,
GEN_NV3,
GEN_NV4,
GEN_CELSIUS,
GEN_KELVIN,
GEN_RANKINE,
GEN_CURIE,
GEN_TESLA,
GEN_FERMI,
GEN_KEPLER,
GEN_MAXWELL,
GEN_PASCAL,
GEN_VOLTA,
GEN_TURING,
NUM_GPU_GEN,
GPU_GEN_UNKNOWN = NUM_GPU_GEN,
};
enum gpu_index {
GPU_NV1,
GPU_NV3,
GPU_NV3T,
GPU_NV4,
GPU_NV5,
GPU_NV6,
GPU_NVA,
GPU_NV10,
GPU_NV15,
GPU_NV1A,
GPU_NV11,
GPU_NV17,
GPU_NV1F,
GPU_NV18,
GPU_NV20,
GPU_NV2A,
GPU_NV25,
GPU_NV28,
GPU_NV30,
GPU_NV35,
GPU_NV31,
GPU_NV36,
GPU_NV34,
GPU_NV40,
GPU_NV45,
GPU_NV41,
GPU_NV42,
GPU_NV43,
GPU_NV44,
GPU_NV44A,
GPU_G70,
GPU_G72,
GPU_G71,
GPU_G73,
GPU_C51,
GPU_MCP61,
GPU_MCP67,
GPU_MCP68,
GPU_MCP73,
GPU_RSX,
GPU_G80,
GPU_G84,
GPU_G86,
GPU_G92,
GPU_G94,
GPU_G96,
GPU_G98,
GPU_G200,
GPU_MCP77,
GPU_MCP79,
GPU_GT215,
GPU_GT216,
GPU_GT218,
GPU_MCP89,
GPU_GF100,
GPU_GF104,
GPU_GF114,
GPU_GF106,
GPU_GF116,
GPU_GF108,
GPU_GF110,
GPU_GF119,
GPU_GF117,
GPU_GK104,
GPU_GK107,
GPU_GK106,
GPU_GK110,
GPU_GK110B,
GPU_GK210,
GPU_GK208,
GPU_GK208B,
GPU_GK20A,
GPU_GM107,
GPU_GM108,
GPU_GM204,
GPU_GM200,
GPU_GM206,
GPU_GM20B,
GPU_GP100,
GPU_GP102,
GPU_GP104,
GPU_GP106,
GPU_GP107,
GPU_GP108,
GPU_GP10B,
GPU_GV100,
GPU_GV11B,
GPU_TU102,
GPU_TU104,
GPU_TU106,
GPU_TU116,
GPU_TU117,
NUM_GPU,
GPU_UNKNOWN = NUM_GPU,
};
extern const struct gpu {
const char *name;
uint32_t id;
bool id_valid;
uint32_t pciid;
bool pciid_valid;
int pciid_varbits;
bool pciid_varbits_valid;
uint32_t bios_major;
bool bios_major_valid;
uint32_t bios_chip;
bool bios_chip_valid;
enum bus_interface_index bus;
enum fb_gen_index fb;
enum gpu_gen_index gen;
} gpu_list[];
#endif

351
include/nva/nva.c Normal file
View File

@@ -0,0 +1,351 @@
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include <pciaccess.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include "nva.h"
#include "util.h"
#include "chipset.h"
#define PLATFORM_DEVICES_DIR "/sys/bus/platform/devices"
struct nva_card **nva_cards = 0;
int nva_cardsnum = 0;
int nva_cardsmax = 0;
int nva_vgaarberr = 0;
struct pci_id_match nv_gpu_match[] = {
{0x104a, 0x0009, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0},
{0x12d2, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, 0x30000, 0xffff0000},
{0x10de, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, 0x30000, 0xffff0000},
{0x10de, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, 0x48000, 0xffffff00},
};
struct pci_id_match nv_apu_match[] = {
{0x10de, 0x01b0, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0},
{0x10de, 0x006b, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0},
};
struct pci_id_match nv_smu_match[] = {
{0x10de, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, 0xb4000, 0xffffff00},
};
struct pci_id_match nv_eth_match[] = {
{0x10de, 0x01c3, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP */
{0x10de, 0x0066, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP2 */
{0x10de, 0x0086, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP2A - network class */
{0x10de, 0x008c, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP2A - bridge class */
{0x10de, 0x00d6, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* CK8 */
{0x10de, 0x00e6, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* CK8S - network class */
{0x10de, 0x00df, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* CK8S - bridge class */
{0x10de, 0x0056, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* CK804 - network class */
{0x10de, 0x0057, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* CK804 - bridge class */
{0x10de, 0x0037, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP04 - network class */
{0x10de, 0x0038, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP04 - bridge class */
{0x10de, 0x0268, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP51 - network class */
{0x10de, 0x0269, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP51 - bridge class */
{0x10de, 0x0372, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP55 - network class */
{0x10de, 0x0373, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP55 - bridge class */
{0x10de, 0x03e5, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP61 ? */
{0x10de, 0x03e6, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP61 ? */
{0x10de, 0x03ee, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP61 ? */
{0x10de, 0x03ef, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP61 - bridge class */
{0x10de, 0x0450, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP65 - network class */
{0x10de, 0x0451, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP65 ? */
{0x10de, 0x0452, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP65 - bridge class */
{0x10de, 0x0453, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP65 ? */
{0x10de, 0x054c, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP67 - network class */
{0x10de, 0x054d, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP67 ? */
{0x10de, 0x054e, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP67 ? */
{0x10de, 0x054f, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP67 ? */
{0x10de, 0x07dc, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP73 - network class */
{0x10de, 0x07dd, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP73 ? */
{0x10de, 0x07de, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP73 ? */
{0x10de, 0x07df, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP73 ? */
{0x10de, 0x0760, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP77 - network class */
{0x10de, 0x0761, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP77 ? */
{0x10de, 0x0762, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP77 ? */
{0x10de, 0x0763, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP77 ? */
{0x10de, 0x0764, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP77 - bridge class */
{0x10de, 0x0765, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP77 ? */
{0x10de, 0x0766, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP77 ? */
{0x10de, 0x0767, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP77 ? */
{0x10de, 0x0ab0, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP79 - network class */
{0x10de, 0x0ab1, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP79 ? */
{0x10de, 0x0ab2, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP79 ? */
{0x10de, 0x0ab3, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP79 ? */
{0x10de, 0x0570, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP77/MCP79 alt 0 */
{0x10de, 0x0571, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP77/MCP79 alt 1 */
{0x10de, 0x0572, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP77/MCP79 alt 2 */
{0x10de, 0x0573, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP77/MCP79 alt 3 */
{0x10de, 0x0574, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP77/MCP79 alt 4 */
{0x10de, 0x0575, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP77/MCP79 alt 5 */
{0x10de, 0x0576, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP77/MCP79 alt 6 */
{0x10de, 0x0577, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP77/MCP79 alt 7 */
{0x10de, 0x0578, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP77/MCP79 alt 8 */
{0x10de, 0x0579, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP77/MCP79 alt 9 */
{0x10de, 0x057a, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP77/MCP79 alt 10 */
{0x10de, 0x057b, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP77/MCP79 alt 11 */
{0x10de, 0x057c, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP77/MCP79 alt 12 */
{0x10de, 0x057d, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP77/MCP79 alt 13 */
{0x10de, 0x057e, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP77/MCP79 alt 14 */
{0x10de, 0x057f, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP77/MCP79 alt 15 */
{0x10de, 0x0d7d, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0}, /* MCP89 */
};
struct nva_card *nva_init_gpu(struct pci_device *dev) {
struct nva_card *card = calloc(sizeof *card, 1);
if (!card)
return 0;
card->type = NVA_DEVICE_GPU;
card->bus_type = NVA_BUS_PCI;
card->bus.pci = dev;
int ret = pci_device_map_range(dev, dev->regions[0].base_addr, dev->regions[0].size, PCI_DEV_MAP_FLAG_WRITABLE, &card->bar0);
if (ret) {
fprintf (stderr, "WARN: Can't probe %04x:%02x:%02x.%x\n", dev->domain, dev->bus, dev->dev, dev->func);
free(card);
return 0;
}
card->bar0len = dev->regions[0].size;
if (dev->regions[1].size) {
card->hasbar1 = 1;
card->bar1len = dev->regions[1].size;
ret = pci_device_map_range(dev, dev->regions[1].base_addr, dev->regions[1].size, PCI_DEV_MAP_FLAG_WRITABLE, &card->bar1);
if (ret) {
card->bar1 = 0;
}
}
if (dev->regions[2].size && !dev->regions[2].is_IO) {
card->hasbar2 = 1;
card->bar2len = dev->regions[2].size;
ret = pci_device_map_range(dev, dev->regions[2].base_addr, dev->regions[2].size, PCI_DEV_MAP_FLAG_WRITABLE, &card->bar2);
if (ret) {
card->bar2 = 0;
}
} else if (dev->regions[3].size) {
card->hasbar2 = 1;
card->bar2len = dev->regions[3].size;
ret = pci_device_map_range(dev, dev->regions[3].base_addr, dev->regions[3].size, PCI_DEV_MAP_FLAG_WRITABLE, &card->bar2);
if (ret) {
card->bar2 = 0;
}
}
/* ignore errors */
pci_device_map_legacy(dev, 0, 0x100000, PCI_DEV_MAP_FLAG_WRITABLE, &card->rawmem);
card->rawio = pci_legacy_open_io(dev, 0, 0x10000);
int iobar = -1;
if (dev->regions[2].size && dev->regions[2].is_IO)
iobar = 2;
if (dev->regions[5].size && dev->regions[5].is_IO)
iobar = 5;
if (iobar != -1) {
card->iobar = pci_device_open_io(dev, dev->regions[iobar].base_addr, dev->regions[iobar].size);
card->iobarlen = dev->regions[iobar].size;
}
uint32_t pmc_id = nva_grd32(card->bar0, 0);
parse_pmc_id(pmc_id, &card->chipset);
return card;
}
struct nva_card *nva_init_smu(struct pci_device *dev) {
struct nva_card *card = calloc(sizeof *card, 1);
if (!card)
return 0;
card->type = NVA_DEVICE_SMU;
card->bus_type = NVA_BUS_PCI;
card->bus.pci = dev;
int ret = pci_device_map_range(dev, dev->regions[0].base_addr, dev->regions[0].size, PCI_DEV_MAP_FLAG_WRITABLE, &card->bar0);
if (ret) {
fprintf (stderr, "WARN: Can't probe %04x:%02x:%02x.%x\n", dev->domain, dev->bus, dev->dev, dev->func);
free(card);
return 0;
}
card->bar0len = dev->regions[0].size;
return card;
}
struct nva_card *nva_init_apu(struct pci_device *dev) {
struct nva_card *card = calloc(sizeof *card, 1);
if (!card)
return 0;
card->type = NVA_DEVICE_APU;
card->bus_type = NVA_BUS_PCI;
card->bus.pci = dev;
int ret = pci_device_map_range(dev, dev->regions[0].base_addr, dev->regions[0].size, PCI_DEV_MAP_FLAG_WRITABLE, &card->bar0);
if (ret) {
fprintf (stderr, "WARN: Can't probe %04x:%02x:%02x.%x\n", dev->domain, dev->bus, dev->dev, dev->func);
free(card);
return 0;
}
card->bar0len = dev->regions[0].size;
return card;
}
struct nva_card *nva_init_eth(struct pci_device *dev) {
struct nva_card *card = calloc(sizeof *card, 1);
if (!card)
return 0;
card->type = NVA_DEVICE_ETH;
card->bus_type = NVA_BUS_PCI;
card->bus.pci = dev;
int ret = pci_device_map_range(dev, dev->regions[0].base_addr, dev->regions[0].size, PCI_DEV_MAP_FLAG_WRITABLE, &card->bar0);
if (ret) {
fprintf (stderr, "WARN: Can't probe %04x:%02x:%02x.%x\n", dev->domain, dev->bus, dev->dev, dev->func);
free(card);
return 0;
}
card->bar0len = dev->regions[0].size;
return card;
}
static int check_modalias(const char *node_name) {
char path[PATH_MAX];
char buffer[255] = { 0 };
FILE *file;
/* Check if the GPU is indeed made by NVIDIA by checking the compatibility
* field of the device tree, exposed to the userspace via modalias. As
* we are lazy, let's not parse the modalias string but just check if
* it mentions nvidia at all. If it does, return 0.
*/
snprintf(path, PATH_MAX, "%s/%s/modalias", PLATFORM_DEVICES_DIR, node_name);
if (!(file = fopen(path, "r"))) {
return 2;
}
fread(buffer, 1, sizeof(buffer), file);
fclose(file);
return strstr(buffer, "nvidia") == NULL;
}
struct nva_card *nva_init_platform() {
uint32_t tmp, bar0 = 0xffffffff;
struct nva_card *card;
struct dirent *dent;
DIR *dir;
int fd;
/* Look for a gpu on the "platform" bus by looking at the platform bus,
* looking for an entry such as '/sys/bus/platform/devices/57000000.gpu'.
* We only expect up to one entry. This will not pick up the GPUs older
* than the tk1 because there was no "gpu" node before that, only gr2d
* and gr3d.
*/
if (!(dir = opendir(PLATFORM_DEVICES_DIR)))
return NULL;
while ((dent = readdir(dir))) {
/* FIXME: this may not work on downstream kernels */
const char *last_four = dent->d_name + strlen(dent->d_name) - 4;
if (strcmp(last_four, ".gpu") == 0) {
if (sscanf(dent->d_name, "%x.gpu", &tmp) == 1) {
/* Check if the modalias contains nvidia */
if (check_modalias(dent->d_name))
continue;
/* We have found the gpu, exit the loop */
bar0 = tmp;
break;
}
}
}
closedir(dir);
if (bar0 == 0xffffffff)
return NULL;
/* we have found a gpu */
card = calloc(sizeof *card, 1);
if (!card)
return 0;
card->type = NVA_DEVICE_GPU;
card->bus_type = NVA_BUS_PLATFORM;
card->bus.platform_address = bar0;
if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) {
fprintf (stderr, "WARN: Can't open /dev/mem. Are you root?\n");
free(card);
return 0;
}
fprintf (stdout, "bar0: 0x%x\n", bar0);
card->bar0 = mmap(0, 0x1000000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, bar0);
if (!card->bar0) {
fprintf (stderr, "WARN: Can't map the physical address 0x%x\n", bar0);
free(card);
return 0;
}
card->bar0len = 0x1000000;
uint32_t pmc_id = nva_grd32(card->bar0, 0);
parse_pmc_id(pmc_id, &card->chipset);
/* Enable bar1 for the devices we know because I cannot figure out how
* to read the relevant part of the DT via sysfs...
*/
if (card->chipset.chipset == 0xea) {
card->hasbar1 = 1;
card->bar1len = 0x1000000;
card->bar1 = mmap(0, 0x1000000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x58000000);
}
return card;
}
struct {
struct pci_id_match *match;
size_t len;
struct nva_card *(*func) (struct pci_device *dev);
} nva_types[] = {
{ nv_gpu_match, ARRAY_SIZE(nv_gpu_match), nva_init_gpu },
{ nv_smu_match, ARRAY_SIZE(nv_smu_match), nva_init_smu },
{ nv_apu_match, ARRAY_SIZE(nv_apu_match), nva_init_apu },
{ nv_eth_match, ARRAY_SIZE(nv_eth_match), nva_init_eth },
};
int nva_init() {
int ret;
ret = pci_system_init();
if (ret)
return -1;
nva_vgaarberr = pci_device_vgaarb_init();
int i, j;
for (i = 0; i < ARRAY_SIZE(nva_types); i++) {
for (j = 0; j < nva_types[i].len; j++) {
struct pci_device_iterator* it = pci_id_match_iterator_create(&nva_types[i].match[j]);
if (!it) {
pci_system_cleanup();
return -1;
}
struct pci_device *dev;
while ((dev = pci_device_next(it))) {
ret = pci_device_probe(dev);
if (ret) {
fprintf (stderr, "WARN: Can't probe %04x:%02x:%02x.%x\n", dev->domain, dev->bus, dev->dev, dev->func);
continue;
}
struct nva_card *card = nva_types[i].func(dev);
if (card)
ADDARRAY(nva_cards, card);
}
pci_iterator_destroy(it);
}
}
/* Finally, try reading the platform */
struct nva_card *card = nva_init_platform();
if (card)
ADDARRAY(nva_cards, card);
return (nva_cardsnum == 0);
}

168
include/nva/nva.h Normal file
View File

@@ -0,0 +1,168 @@
/*
* Copyright (C) 2010-2011 Marcelina Kościelnicka <mwk@0x04.net>
* All Rights Reserved.
*
* 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.
*/
#ifndef NVA_H
#define NVA_H
#include <stdint.h>
#include <stddef.h>
#include "chipset.h"
#ifdef __cplusplus
extern "C" {
#endif
enum nva_card_type {
NVA_DEVICE_GPU,
NVA_DEVICE_APU,
NVA_DEVICE_SMU,
NVA_DEVICE_ETH,
};
enum nva_bus_type {
NVA_BUS_PCI,
NVA_BUS_PLATFORM,
};
struct nva_card {
enum nva_card_type type;
enum nva_bus_type bus_type;
union {
struct pci_device *pci;
uint32_t platform_address;
} bus;
struct chipset_info chipset;
void *bar0;
size_t bar0len;
int hasbar1;
void *bar1;
size_t bar1len;
int hasbar2;
void *bar2;
size_t bar2len;
struct pci_io_handle *iobar;
size_t iobarlen;
void *rawmem;
struct pci_io_handle *rawio;
};
int nva_init();
extern struct nva_card **nva_cards;
extern int nva_cardsnum;
static inline uint32_t nva_grd32(void *base, uint32_t addr) {
return *((volatile uint32_t*)(((volatile uint8_t *)base) + addr));
}
static inline void nva_gwr32(void *base, uint32_t addr, uint32_t val) {
*((volatile uint32_t*)(((volatile uint8_t *)base) + addr)) = val;
}
static inline uint32_t nva_grd8(void *base, uint32_t addr) {
return *(((volatile uint8_t *)base) + addr);
}
static inline void nva_gwr8(void *base, uint32_t addr, uint32_t val) {
*(((volatile uint8_t *)base) + addr) = val;
}
static inline uint32_t nva_rd32(int card, uint32_t addr) {
return nva_grd32(nva_cards[card]->bar0, addr);
}
static inline void nva_wr32(int card, uint32_t addr, uint32_t val) {
nva_gwr32(nva_cards[card]->bar0, addr, val);
}
static inline uint32_t nva_rd8(int card, uint32_t addr) {
return nva_grd8(nva_cards[card]->bar0, addr);
}
static inline void nva_wr8(int card, uint32_t addr, uint32_t val) {
nva_gwr8(nva_cards[card]->bar0, addr, val);
}
static inline uint32_t nva_mask(int cnum, uint32_t reg, uint32_t mask, uint32_t val)
{
uint32_t tmp = nva_rd32(cnum, reg);
nva_wr32(cnum, reg, (tmp & ~mask) | val);
return tmp;
}
enum nva_regspace_type {
NVA_REGSPACE_BAR0,
NVA_REGSPACE_BAR1,
NVA_REGSPACE_BAR2,
NVA_REGSPACE_IOBAR,
NVA_REGSPACE_RAWMEM,
NVA_REGSPACE_RAWIO,
NVA_REGSPACE_PDAC,
NVA_REGSPACE_EEPROM,
NVA_REGSPACE_VGA_CR,
NVA_REGSPACE_VGA_SR,
NVA_REGSPACE_VGA_AR,
NVA_REGSPACE_VGA_GR,
NVA_REGSPACE_VGA_ST,
NVA_REGSPACE_DPRAM,
NVA_REGSPACE_PIPE,
NVA_REGSPACE_RDI,
NVA_REGSPACE_RDIB,
NVA_REGSPACE_VCOMP_CODE,
NVA_REGSPACE_VCOMP_REG,
NVA_REGSPACE_MACRO_CODE,
NVA_REGSPACE_XT,
NVA_REGSPACE_UNKNOWN,
};
struct nva_regspace {
struct nva_card *card;
int cnum;
enum nva_regspace_type type;
int regsz;
int idx;
};
int nva_wr(struct nva_regspace *regspace, uint32_t addr, uint64_t val);
int nva_rd(struct nva_regspace *regspace, uint32_t addr, uint64_t *val);
enum nva_err {
NVA_ERR_SUCCESS,
NVA_ERR_RANGE,
NVA_ERR_REGSZ,
NVA_ERR_NOSPC,
NVA_ERR_MAP,
};
int nva_rstype(const char *name);
int nva_rsdefsz(struct nva_regspace *regspace);
int nva_rsunitsz(struct nva_regspace *regspace);
char nva_rserrc(enum nva_err err);
void nva_rsprint(struct nva_regspace *regspace, enum nva_err err, uint64_t val);
#ifdef __cplusplus
}
#endif
#endif

698
include/nva/regspace.c Normal file
View File

@@ -0,0 +1,698 @@
#include "nva.h"
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <pciaccess.h>
int nva_wr(struct nva_regspace *regspace, uint32_t addr, uint64_t val) {
void *rawbase = 0;
size_t rawlen;
void *raw;
int i;
uint32_t vgaio;
uint32_t vgabase;
switch (regspace->type) {
case NVA_REGSPACE_BAR0:
rawbase = regspace->card->bar0;
rawlen = regspace->card->bar0len;
goto raw;
case NVA_REGSPACE_BAR1:
rawbase = regspace->card->bar1;
rawlen = regspace->card->bar1len;
if (!regspace->card->hasbar1)
return NVA_ERR_NOSPC;
goto raw;
case NVA_REGSPACE_BAR2:
rawbase = regspace->card->bar2;
rawlen = regspace->card->bar2len;
if (!regspace->card->hasbar2)
return NVA_ERR_NOSPC;
goto raw;
case NVA_REGSPACE_RAWMEM:
rawbase = regspace->card->rawmem;
rawlen = 0x100000;
raw:
if (!rawbase)
return NVA_ERR_MAP;
if (addr > rawlen - regspace->regsz)
return NVA_ERR_RANGE;
raw = (uint8_t *)rawbase + addr;
switch (regspace->regsz) {
case 1:
*(volatile uint8_t *)raw = val;
return 0;
case 2:
*(volatile uint16_t *)raw = val;
return 0;
case 4:
*(volatile uint32_t *)raw = val;
return 0;
case 8:
*(volatile uint64_t *)raw = val;
return 0;
default:
return NVA_ERR_REGSZ;
}
case NVA_REGSPACE_IOBAR:
if (!regspace->card->iobar)
return NVA_ERR_NOSPC;
if (addr > regspace->card->iobarlen - regspace->regsz)
return NVA_ERR_RANGE;
switch (regspace->regsz) {
case 1:
pci_io_write8(regspace->card->iobar, addr, val);
return 0;
case 2:
pci_io_write16(regspace->card->iobar, addr, val);
return 0;
case 4:
pci_io_write32(regspace->card->iobar, addr, val);
return 0;
default:
return NVA_ERR_REGSZ;
}
case NVA_REGSPACE_RAWIO:
if (!regspace->card->rawio)
return NVA_ERR_NOSPC;
if (addr > 0x10000 - regspace->regsz)
return NVA_ERR_RANGE;
switch (regspace->regsz) {
case 1:
pci_io_write8(regspace->card->rawio, addr, val);
return 0;
case 2:
pci_io_write16(regspace->card->rawio, addr, val);
return 0;
case 4:
pci_io_write32(regspace->card->rawio, addr, val);
return 0;
default:
return NVA_ERR_REGSZ;
}
case NVA_REGSPACE_PDAC:
if (regspace->card->chipset.chipset != 0x01)
return NVA_ERR_NOSPC;
if (addr > 0x10000 - regspace->regsz)
return NVA_ERR_RANGE;
if (regspace->regsz > 8)
return NVA_ERR_REGSZ;
nva_wr32(regspace->cnum, 0x609010, addr & 0xff);
nva_wr32(regspace->cnum, 0x609014, addr >> 8);
for (i = 0; i < regspace->regsz; i++)
nva_wr32(regspace->cnum, 0x609018, (val >> i * 8) & 0xff);
return 0;
case NVA_REGSPACE_EEPROM:
if (regspace->card->chipset.chipset != 0x01)
return NVA_ERR_NOSPC;
if (regspace->regsz != 1)
return NVA_ERR_REGSZ;
if (addr >= 0x80)
return NVA_ERR_RANGE;
while (nva_rd32(regspace->cnum, 0x60a400) & 0x10000000);
nva_wr32(regspace->cnum, 0x60a400, 0x1000000 | addr << 8 | (val & 0xff));
while (nva_rd32(regspace->cnum, 0x60a400) & 0x10000000);
return 0;
case NVA_REGSPACE_VGA_CR:
vgaio = 0x3d4;
if (addr >= 0x100)
return NVA_ERR_RANGE;
goto vga;
case NVA_REGSPACE_VGA_SR:
vgaio = 0x3c4;
if (addr >= 8)
return NVA_ERR_RANGE;
goto vga;
case NVA_REGSPACE_VGA_GR:
vgaio = 0x3ce;
if (addr >= 0x10)
return NVA_ERR_RANGE;
goto vga;
case NVA_REGSPACE_VGA_AR:
vgaio = 0x3c0;
if (addr >= 0x20)
return NVA_ERR_RANGE;
goto vga;
vga:
if (regspace->regsz != 1)
return NVA_ERR_REGSZ;
if (regspace->card->chipset.card_type == 0x01) {
vgabase = 0x6d0000;
if (regspace->idx != 0)
return NVA_ERR_NOSPC;
} else if (regspace->card->chipset.card_type < 0x50) {
if (vgaio == 0x3c4 || vgaio == 0x3ce)
vgabase = 0x0c0000;
else
vgabase = 0x601000;
if (regspace->idx > 2)
return NVA_ERR_NOSPC;
if ((regspace->card->chipset.chipset < 0x17 || regspace->card->chipset.chipset == 0x1a || regspace->card->chipset.chipset == 0x20) && regspace->idx == 1)
return NVA_ERR_NOSPC;
vgabase += regspace->idx * 0x2000;
} else {
vgabase = 0x601000;
if (regspace->idx != 0)
return NVA_ERR_NOSPC;
}
if (vgaio == 0x3c0) {
nva_rd8(regspace->cnum, vgabase + 0x3da);
uint8_t idx = nva_rd8(regspace->cnum, vgabase + 0x3c0);
nva_rd8(regspace->cnum, vgabase + 0x3da);
nva_wr8(regspace->cnum, vgabase + 0x3c0, addr);
nva_wr8(regspace->cnum, vgabase + 0x3c0, val);
nva_wr8(regspace->cnum, vgabase + 0x3c0, idx);
} else {
uint8_t idx = nva_rd8(regspace->cnum, vgabase + vgaio);
nva_wr8(regspace->cnum, vgabase + vgaio, addr);
nva_wr8(regspace->cnum, vgabase + vgaio + 1, val);
nva_wr8(regspace->cnum, vgabase + vgaio, idx);
}
return 0;
case NVA_REGSPACE_VGA_ST:
if (regspace->card->chipset.chipset < 0x41)
return NVA_ERR_NOSPC;
if (regspace->regsz != 1)
return NVA_ERR_REGSZ;
uint32_t vstbase = 0x1380;
if (regspace->card->chipset.card_type >= 0x50)
vstbase = 0x619e40;
uint32_t savepos = nva_rd32(regspace->cnum, vstbase+0xc);
uint32_t savecfg = nva_rd32(regspace->cnum, vstbase+0x8);
nva_wr32(regspace->cnum, vstbase+0xc, addr);
nva_wr32(regspace->cnum, vstbase+0x8, 7);
nva_wr32(regspace->cnum, vstbase+0x0, val);
nva_wr32(regspace->cnum, vstbase+0x8, savecfg);
nva_wr32(regspace->cnum, vstbase+0xc, savepos);
return 0;
case NVA_REGSPACE_DPRAM:
if (regspace->card->chipset.chipset == 0x34) {
if (regspace->regsz != 4)
return NVA_ERR_REGSZ;
nva_wr32(regspace->cnum, 0x400bb0, addr);
nva_wr32(regspace->cnum, 0x400bb4, val);
return 0;
}
if (regspace->card->chipset.card_type < 4 || regspace->card->chipset.card_type >= 0x20)
return NVA_ERR_NOSPC;
if (regspace->regsz != 4)
return NVA_ERR_REGSZ;
nva_wr32(regspace->cnum, 0x400828, addr);
nva_wr32(regspace->cnum, 0x40082c, val);
return 0;
case NVA_REGSPACE_PIPE:
if (regspace->card->chipset.card_type < 0x10 || regspace->card->chipset.card_type >= 0x50)
return NVA_ERR_NOSPC;
if (regspace->regsz != 4)
return NVA_ERR_REGSZ;
nva_wr32(regspace->cnum, 0x400f50, addr);
nva_wr32(regspace->cnum, 0x400f54, val);
return 0;
case NVA_REGSPACE_RDI:
if (regspace->card->chipset.chipset == 0x17 || regspace->card->chipset.chipset == 0x18 || regspace->card->chipset.chipset == 0x1f) {
if (regspace->regsz != 4)
return NVA_ERR_REGSZ;
nva_wr32(regspace->cnum, 0x400a08, addr);
nva_wr32(regspace->cnum, 0x400a0c, val);
return 0;
}
if (regspace->card->chipset.card_type < 0x20 || regspace->card->chipset.card_type >= 0x50)
return NVA_ERR_NOSPC;
nva_wr32(regspace->cnum, 0x400750, addr);
nva_wr32(regspace->cnum, 0x400754, val);
return 0;
case NVA_REGSPACE_RDIB:
if (regspace->card->chipset.card_type < 0x20 || regspace->card->chipset.card_type >= 0x50)
return NVA_ERR_NOSPC;
nva_wr32(regspace->cnum, 0x400750, addr);
nva_wr32(regspace->cnum, 0x400758, val);
return 0;
case NVA_REGSPACE_VCOMP_CODE:
if (regspace->card->chipset.chipset != 0xaf)
return NVA_ERR_NOSPC;
if (regspace->regsz != 4)
return NVA_ERR_REGSZ;
nva_wr32(regspace->cnum, 0x1c17c8, addr);
nva_wr32(regspace->cnum, 0x1c17cc, val);
return 0;
case NVA_REGSPACE_VCOMP_REG:
if (regspace->card->chipset.chipset != 0xaf)
return NVA_ERR_NOSPC;
if (regspace->regsz != 8)
return NVA_ERR_REGSZ;
nva_wr32(regspace->cnum, 0x1c17d0, addr/8);
nva_wr32(regspace->cnum, 0x1c17d4, val);
nva_wr32(regspace->cnum, 0x1c17d8, val >> 32);
return 0;
case NVA_REGSPACE_MACRO_CODE:
if (regspace->card->chipset.chipset < 0xc0)
return NVA_ERR_NOSPC;
if (regspace->regsz != 4)
return NVA_ERR_REGSZ;
nva_wr32(regspace->cnum, 0x40986c, 0x10);
nva_wr32(regspace->cnum, 0x409ffc, 2);
nva_wr32(regspace->cnum, 0x409928, 0xc);
while (nva_rd32(regspace->cnum, 0x409928));
nva_wr32(regspace->cnum, 0x40993c, 0xf);
nva_wr32(regspace->cnum, 0x409928, 0xa);
while (nva_rd32(regspace->cnum, 0x409928));
nva_wr32(regspace->cnum, 0x40991c, 0x1);
nva_wr32(regspace->cnum, 0x409928, 0x1);
while (nva_rd32(regspace->cnum, 0x409928));
for (i = 0; i < addr; i+=4) {
nva_wr32(regspace->cnum, 0x409928, 0x6);
while (nva_rd32(regspace->cnum, 0x409928));
}
nva_wr32(regspace->cnum, 0x409918, val);
nva_wr32(regspace->cnum, 0x409928, 0x7);
while (nva_rd32(regspace->cnum, 0x409928));
return 0;
case NVA_REGSPACE_XT:
if (regspace->regsz != 4)
return NVA_ERR_REGSZ;
nva_wr32(regspace->cnum, 0x1700, 0x30);
nva_wr32(regspace->cnum, 0x700004, addr);
nva_wr32(regspace->cnum, 0x700008, val);
nva_wr32(regspace->cnum, 0x70000, 1);
while (nva_rd32(regspace->cnum, 0x70000));
nva_wr32(regspace->cnum, 0x700000, 2);
while (nva_rd32(regspace->cnum, 0x700000));
return 0;
default:
return NVA_ERR_NOSPC;
}
}
int nva_rd(struct nva_regspace *regspace, uint32_t addr, uint64_t *val) {
void *rawbase = 0;
size_t rawlen;
void *raw;
int i;
uint32_t vgaio;
uint32_t vgabase;
switch (regspace->type) {
case NVA_REGSPACE_BAR0:
rawbase = regspace->card->bar0;
rawlen = regspace->card->bar0len;
goto raw;
case NVA_REGSPACE_BAR1:
rawbase = regspace->card->bar1;
rawlen = regspace->card->bar1len;
goto raw;
case NVA_REGSPACE_BAR2:
rawbase = regspace->card->bar2;
rawlen = regspace->card->bar2len;
goto raw;
case NVA_REGSPACE_RAWMEM:
rawbase = regspace->card->rawmem;
rawlen = 0x100000;
raw:
if (!rawbase)
return NVA_ERR_MAP;
if (addr > rawlen - regspace->regsz)
return NVA_ERR_RANGE;
raw = (uint8_t *)rawbase + addr;
switch (regspace->regsz) {
case 1:
*val = *(volatile uint8_t *)raw;
return 0;
case 2:
*val = *(volatile uint16_t *)raw;
return 0;
case 4:
*val = *(volatile uint32_t *)raw;
return 0;
case 8:
*val = *(volatile uint64_t *)raw;
return 0;
default:
return NVA_ERR_REGSZ;
}
case NVA_REGSPACE_IOBAR:
if (!regspace->card->iobar)
return NVA_ERR_NOSPC;
if (addr > regspace->card->iobarlen - regspace->regsz)
return NVA_ERR_RANGE;
switch (regspace->regsz) {
case 1:
*val = pci_io_read8(regspace->card->iobar, addr);
return 0;
case 2:
*val = pci_io_read16(regspace->card->iobar, addr);
return 0;
case 4:
*val = pci_io_read32(regspace->card->iobar, addr);
return 0;
default:
return NVA_ERR_REGSZ;
}
case NVA_REGSPACE_RAWIO:
if (!regspace->card->rawio)
return NVA_ERR_NOSPC;
if (addr > 0x10000 - regspace->regsz)
return NVA_ERR_RANGE;
switch (regspace->regsz) {
case 1:
*val = pci_io_read8(regspace->card->rawio, addr);
return 0;
case 2:
*val = pci_io_read16(regspace->card->rawio, addr);
return 0;
case 4:
*val = pci_io_read32(regspace->card->rawio, addr);
return 0;
default:
return NVA_ERR_REGSZ;
}
case NVA_REGSPACE_PDAC:
if (regspace->card->chipset.chipset != 0x01)
return NVA_ERR_NOSPC;
if (addr > 0x10000 - regspace->regsz)
return NVA_ERR_RANGE;
if (regspace->regsz > 8)
return NVA_ERR_REGSZ;
nva_wr32(regspace->cnum, 0x609010, addr & 0xff);
nva_wr32(regspace->cnum, 0x609014, addr >> 8);
*val = 0;
for (i = 0; i < regspace->regsz; i++)
*val |= (uint64_t)(nva_rd32(regspace->cnum, 0x609018) & 0xff) << i * 8;
return 0;
case NVA_REGSPACE_EEPROM:
if (regspace->card->chipset.chipset != 0x01)
return NVA_ERR_NOSPC;
if (regspace->regsz != 1)
return NVA_ERR_REGSZ;
if (addr >= 0x80)
return NVA_ERR_RANGE;
while (nva_rd32(regspace->cnum, 0x60a400) & 0x10000000);
nva_wr32(regspace->cnum, 0x60a400, 0x2000000 | addr << 8);
while (nva_rd32(regspace->cnum, 0x60a400) & 0x10000000);
*val = nva_rd32(regspace->cnum, 0x60a400) & 0xff;
return 0;
case NVA_REGSPACE_VGA_CR:
vgaio = 0x3d4;
if (addr >= 0x100)
return NVA_ERR_RANGE;
goto vga;
case NVA_REGSPACE_VGA_SR:
vgaio = 0x3c4;
if (addr >= 8)
return NVA_ERR_RANGE;
goto vga;
case NVA_REGSPACE_VGA_GR:
vgaio = 0x3ce;
if (addr >= 0x10)
return NVA_ERR_RANGE;
goto vga;
case NVA_REGSPACE_VGA_AR:
vgaio = 0x3c0;
if (addr >= 0x20)
return NVA_ERR_RANGE;
goto vga;
vga:
if (regspace->regsz != 1)
return NVA_ERR_REGSZ;
if (regspace->card->chipset.card_type == 0x01) {
vgabase = 0x6d0000;
if (regspace->idx != 0)
return NVA_ERR_NOSPC;
} else if (regspace->card->chipset.card_type < 0x50) {
if (vgaio == 0x3c4 || vgaio == 0x3ce)
vgabase = 0x0c0000;
else
vgabase = 0x601000;
if (regspace->idx > 2)
return NVA_ERR_NOSPC;
if ((regspace->card->chipset.chipset < 0x17 || regspace->card->chipset.chipset == 0x1a || regspace->card->chipset.chipset == 0x20) && regspace->idx == 1)
return NVA_ERR_NOSPC;
vgabase += regspace->idx * 0x2000;
} else {
vgabase = 0x601000;
if (regspace->idx != 0)
return NVA_ERR_NOSPC;
}
if (vgaio == 0x3c0) {
nva_rd8(regspace->cnum, vgabase + 0x3da);
uint8_t idx = nva_rd8(regspace->cnum, vgabase + 0x3c0);
nva_rd8(regspace->cnum, vgabase + 0x3da);
nva_wr8(regspace->cnum, vgabase + 0x3c0, addr);
*val = nva_rd8(regspace->cnum, vgabase + 0x3c1);
nva_rd8(regspace->cnum, vgabase + 0x3da);
nva_wr8(regspace->cnum, vgabase + 0x3c0, idx);
} else {
uint8_t idx = nva_rd8(regspace->cnum, vgabase + vgaio);
nva_wr8(regspace->cnum, vgabase + vgaio, addr);
*val = nva_rd8(regspace->cnum, vgabase + vgaio + 1);
nva_wr8(regspace->cnum, vgabase + vgaio, idx);
}
return 0;
case NVA_REGSPACE_VGA_ST:
if (regspace->card->chipset.chipset < 0x41)
return NVA_ERR_NOSPC;
if (regspace->regsz != 1)
return NVA_ERR_REGSZ;
uint32_t vstbase = 0x1380;
if (regspace->card->chipset.card_type >= 0x50)
vstbase = 0x619e40;
uint32_t savepos = nva_rd32(regspace->cnum, vstbase+0xc);
uint32_t savecfg = nva_rd32(regspace->cnum, vstbase+0x8);
nva_wr32(regspace->cnum, vstbase+0xc, addr+1);
nva_wr32(regspace->cnum, vstbase+0x8, 7);
*val = nva_rd32(regspace->cnum, vstbase+0x0);
nva_wr32(regspace->cnum, vstbase+0x8, savecfg);
nva_wr32(regspace->cnum, vstbase+0xc, savepos);
return 0;
case NVA_REGSPACE_DPRAM:
if (regspace->card->chipset.chipset == 0x34) {
if (regspace->regsz != 4)
return NVA_ERR_REGSZ;
nva_wr32(regspace->cnum, 0x400bb0, addr);
*val = nva_rd32(regspace->cnum, 0x400bb4);
return 0;
}
if (regspace->card->chipset.card_type < 4 || regspace->card->chipset.card_type >= 0x20)
return NVA_ERR_NOSPC;
if (regspace->regsz != 4)
return NVA_ERR_REGSZ;
nva_wr32(regspace->cnum, 0x400828, addr);
*val = nva_rd32(regspace->cnum, 0x40082c);
return 0;
case NVA_REGSPACE_PIPE:
if (regspace->card->chipset.card_type < 0x10 || regspace->card->chipset.card_type >= 0x50)
return NVA_ERR_NOSPC;
if (regspace->regsz != 4)
return NVA_ERR_REGSZ;
nva_wr32(regspace->cnum, 0x400f50, addr);
*val = nva_rd32(regspace->cnum, 0x400f54);
return 0;
case NVA_REGSPACE_RDI:
if (regspace->card->chipset.chipset == 0x17 || regspace->card->chipset.chipset == 0x18 || regspace->card->chipset.chipset == 0x1f) {
if (regspace->regsz != 4)
return NVA_ERR_REGSZ;
nva_wr32(regspace->cnum, 0x400a08, addr);
*val = nva_rd32(regspace->cnum, 0x400a0c);
return 0;
}
if (regspace->card->chipset.card_type < 0x20 || regspace->card->chipset.card_type >= 0x50)
return NVA_ERR_NOSPC;
if (regspace->regsz != 4)
return NVA_ERR_REGSZ;
nva_wr32(regspace->cnum, 0x400750, addr);
*val = nva_rd32(regspace->cnum, 0x400754);
return 0;
case NVA_REGSPACE_RDIB:
if (regspace->card->chipset.card_type < 0x20 || regspace->card->chipset.card_type >= 0x50)
return NVA_ERR_NOSPC;
if (regspace->regsz != 4)
return NVA_ERR_REGSZ;
nva_wr32(regspace->cnum, 0x400750, addr);
*val = nva_rd32(regspace->cnum, 0x400758);
return 0;
case NVA_REGSPACE_VCOMP_CODE:
if (regspace->card->chipset.chipset != 0xaf)
return NVA_ERR_NOSPC;
if (regspace->regsz != 4)
return NVA_ERR_REGSZ;
nva_wr32(regspace->cnum, 0x1c17c8, addr);
*val = nva_rd32(regspace->cnum, 0x1c17cc);
return 0;
case NVA_REGSPACE_VCOMP_REG:
if (regspace->card->chipset.chipset != 0xaf)
return NVA_ERR_NOSPC;
if (regspace->regsz != 8)
return NVA_ERR_REGSZ;
nva_wr32(regspace->cnum, 0x1c17d0, addr/8);
*val = nva_rd32(regspace->cnum, 0x1c17d4);
*val |= (uint64_t)nva_rd32(regspace->cnum, 0x1c17d8) << 32;
return 0;
case NVA_REGSPACE_MACRO_CODE:
if (regspace->card->chipset.chipset < 0xc0)
return NVA_ERR_NOSPC;
if (regspace->regsz != 4)
return NVA_ERR_REGSZ;
nva_wr32(regspace->cnum, 0x40986c, 0x10);
nva_wr32(regspace->cnum, 0x409ffc, 2);
nva_wr32(regspace->cnum, 0x409928, 0xc);
while (nva_rd32(regspace->cnum, 0x409928));
nva_wr32(regspace->cnum, 0x40993c, 0xf);
nva_wr32(regspace->cnum, 0x409928, 0xa);
while (nva_rd32(regspace->cnum, 0x409928));
nva_wr32(regspace->cnum, 0x40991c, 0x1);
nva_wr32(regspace->cnum, 0x409928, 0x1);
while (nva_rd32(regspace->cnum, 0x409928));
for (i = 0; i < addr; i+=4) {
nva_wr32(regspace->cnum, 0x409928, 0x6);
while (nva_rd32(regspace->cnum, 0x409928));
}
nva_wr32(regspace->cnum, 0x409928, 0x6);
while (nva_rd32(regspace->cnum, 0x409928));
*val = nva_rd32(regspace->cnum, 0x409918);
return 0;
case NVA_REGSPACE_XT:
if (regspace->regsz != 4)
return NVA_ERR_REGSZ;
nva_wr32(regspace->cnum, 0x1700, 0x30);
nva_wr32(regspace->cnum, 0x700004, addr);
nva_wr32(regspace->cnum, 0x70000, 1);
while (nva_rd32(regspace->cnum, 0x70000));
nva_wr32(regspace->cnum, 0x700000, 1);
while (nva_rd32(regspace->cnum, 0x700000));
*val = nva_rd32(regspace->cnum, 0x700004);
return 0;
default:
return NVA_ERR_NOSPC;
}
}
int nva_rstype(const char *name) {
if (!strcmp(name, "bar0"))
return NVA_REGSPACE_BAR0;
if (!strcmp(name, "mmio"))
return NVA_REGSPACE_BAR0;
if (!strcmp(name, "bar1"))
return NVA_REGSPACE_BAR1;
if (!strcmp(name, "fb"))
return NVA_REGSPACE_BAR1;
if (!strcmp(name, "bar2"))
return NVA_REGSPACE_BAR2;
if (!strcmp(name, "bar3"))
return NVA_REGSPACE_BAR2;
if (!strcmp(name, "ramin"))
return NVA_REGSPACE_BAR2;
if (!strcmp(name, "iobar"))
return NVA_REGSPACE_IOBAR;
if (!strcmp(name, "rawmem"))
return NVA_REGSPACE_RAWMEM;
if (!strcmp(name, "rawio"))
return NVA_REGSPACE_RAWIO;
if (!strcmp(name, "pdac"))
return NVA_REGSPACE_PDAC;
if (!strcmp(name, "eeprom"))
return NVA_REGSPACE_EEPROM;
if (!strcmp(name, "cr"))
return NVA_REGSPACE_VGA_CR;
if (!strcmp(name, "sr"))
return NVA_REGSPACE_VGA_SR;
if (!strcmp(name, "gr"))
return NVA_REGSPACE_VGA_GR;
if (!strcmp(name, "ar"))
return NVA_REGSPACE_VGA_AR;
if (!strcmp(name, "cr"))
return NVA_REGSPACE_VGA_CR;
if (!strcmp(name, "vst"))
return NVA_REGSPACE_VGA_ST;
if (!strcmp(name, "dpram"))
return NVA_REGSPACE_DPRAM;
if (!strcmp(name, "pipe"))
return NVA_REGSPACE_PIPE;
if (!strcmp(name, "rdi"))
return NVA_REGSPACE_RDI;
if (!strcmp(name, "rdib"))
return NVA_REGSPACE_RDIB;
if (!strcmp(name, "vcomp_code"))
return NVA_REGSPACE_VCOMP_CODE;
if (!strcmp(name, "vcomp_reg"))
return NVA_REGSPACE_VCOMP_REG;
if (!strcmp(name, "macro_code"))
return NVA_REGSPACE_MACRO_CODE;
if (!strcmp(name, "xt"))
return NVA_REGSPACE_XT;
return NVA_REGSPACE_UNKNOWN;
}
int nva_rsdefsz(struct nva_regspace *regspace) {
switch (regspace->type) {
case NVA_REGSPACE_BAR0:
case NVA_REGSPACE_BAR1:
case NVA_REGSPACE_BAR2:
case NVA_REGSPACE_IOBAR:
case NVA_REGSPACE_DPRAM:
case NVA_REGSPACE_PIPE:
case NVA_REGSPACE_RDI:
case NVA_REGSPACE_RDIB:
case NVA_REGSPACE_VCOMP_CODE:
case NVA_REGSPACE_MACRO_CODE:
case NVA_REGSPACE_XT:
return 4;
case NVA_REGSPACE_VCOMP_REG:
return 8;
default:
return 1;
}
}
int nva_rsunitsz(struct nva_regspace *regspace) {
switch (regspace->type) {
case NVA_REGSPACE_DPRAM:
return 4;
case NVA_REGSPACE_RDI:
case NVA_REGSPACE_RDIB:
if (regspace->card->chipset.chipset == 0x17 || regspace->card->chipset.chipset == 0x18 || regspace->card->chipset.chipset == 0x1f) {
return 4;
}
return 1;
default:
return 1;
}
}
char nva_rserrc(enum nva_err err) {
switch (err) {
case NVA_ERR_RANGE:
return 'R';
case NVA_ERR_REGSZ:
return 'B';
case NVA_ERR_NOSPC:
return 'S';
case NVA_ERR_MAP:
return 'M';
default:
abort();
}
}
void nva_rsprint(struct nva_regspace *regspace, enum nva_err err, uint64_t val) {
if (err) {
int k;
char ec = nva_rserrc(err);
printf(" ");
for (k = 0; k < regspace->regsz; k++)
printf("%c%c", ec, ec);
} else {
switch (regspace->regsz) {
case 1:
printf (" %02"PRIx64, val);
break;
case 2:
printf (" %04"PRIx64, val);
break;
case 4:
printf (" %08"PRIx64, val);
break;
case 8:
printf (" %016"PRIx64, val);
break;
}
}
}

19
include/nva/util.h Normal file
View File

@@ -0,0 +1,19 @@
#ifndef UTIL_H
#define UTIL_H
#define ARRAY_SIZE(a) (sizeof (a) / sizeof *(a))
#define ADDARRAY(a, e) \
do { \
if ((a ## num) >= (a ## max)) { \
if (!(a ## max)) \
(a ## max) = 16; \
else \
(a ## max) *= 2; \
(a) = realloc((a), (a ## max)*sizeof(*(a))); \
} \
(a)[(a ## num)++] = (e); \
} while(0)
#endif