18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * dump_psb. (c) 2004, Dave Jones, Red Hat Inc. 38c2ecf20Sopenharmony_ci * Licensed under the GPL v2. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <fcntl.h> 78c2ecf20Sopenharmony_ci#include <stdio.h> 88c2ecf20Sopenharmony_ci#include <stdlib.h> 98c2ecf20Sopenharmony_ci#include <string.h> 108c2ecf20Sopenharmony_ci#include <unistd.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#define _GNU_SOURCE 138c2ecf20Sopenharmony_ci#include <getopt.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <sys/mman.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define LEN (0x100000 - 0xc0000) 188c2ecf20Sopenharmony_ci#define OFFSET (0xc0000) 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#ifndef __packed 218c2ecf20Sopenharmony_ci#define __packed __attribute((packed)) 228c2ecf20Sopenharmony_ci#endif 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic long relevant; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic const int fid_to_mult[32] = { 278c2ecf20Sopenharmony_ci 110, 115, 120, 125, 50, 55, 60, 65, 288c2ecf20Sopenharmony_ci 70, 75, 80, 85, 90, 95, 100, 105, 298c2ecf20Sopenharmony_ci 30, 190, 40, 200, 130, 135, 140, 210, 308c2ecf20Sopenharmony_ci 150, 225, 160, 165, 170, 180, -1, -1, 318c2ecf20Sopenharmony_ci}; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic const int vid_to_voltage[32] = { 348c2ecf20Sopenharmony_ci 2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650, 358c2ecf20Sopenharmony_ci 1600, 1550, 1500, 1450, 1400, 1350, 1300, 0, 368c2ecf20Sopenharmony_ci 1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100, 378c2ecf20Sopenharmony_ci 1075, 1050, 1024, 1000, 975, 950, 925, 0, 388c2ecf20Sopenharmony_ci}; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistruct psb_header { 418c2ecf20Sopenharmony_ci char signature[10]; 428c2ecf20Sopenharmony_ci u_char version; 438c2ecf20Sopenharmony_ci u_char flags; 448c2ecf20Sopenharmony_ci u_short settlingtime; 458c2ecf20Sopenharmony_ci u_char res1; 468c2ecf20Sopenharmony_ci u_char numpst; 478c2ecf20Sopenharmony_ci} __packed; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistruct pst_header { 508c2ecf20Sopenharmony_ci u_int32_t cpuid; 518c2ecf20Sopenharmony_ci u_char fsb; 528c2ecf20Sopenharmony_ci u_char maxfid; 538c2ecf20Sopenharmony_ci u_char startvid; 548c2ecf20Sopenharmony_ci u_char numpstates; 558c2ecf20Sopenharmony_ci} __packed; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic u_int fsb; 588c2ecf20Sopenharmony_cistatic u_int sgtc; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic int 618c2ecf20Sopenharmony_cidecode_pst(char *p, int npstates) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci int i; 648c2ecf20Sopenharmony_ci int freq, fid, vid; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci for (i = 0; i < npstates; ++i) { 678c2ecf20Sopenharmony_ci fid = *p++; 688c2ecf20Sopenharmony_ci vid = *p++; 698c2ecf20Sopenharmony_ci freq = 100 * fid_to_mult[fid] * fsb; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci printf(" %2d %8dkHz FID %02x (%2d.%01d) VID %02x (%4dmV)\n", 728c2ecf20Sopenharmony_ci i, 738c2ecf20Sopenharmony_ci freq, 748c2ecf20Sopenharmony_ci fid, fid_to_mult[fid]/10, fid_to_mult[fid]%10, 758c2ecf20Sopenharmony_ci vid, vid_to_voltage[vid]); 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci return 0; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic 828c2ecf20Sopenharmony_civoid decode_psb(char *p, int numpst) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci int i; 858c2ecf20Sopenharmony_ci struct psb_header *psb; 868c2ecf20Sopenharmony_ci struct pst_header *pst; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci psb = (struct psb_header*) p; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci if (psb->version != 0x12) 918c2ecf20Sopenharmony_ci return; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci printf("PSB version: %hhx flags: %hhx settling time %hhuus res1 %hhx num pst %hhu\n", 948c2ecf20Sopenharmony_ci psb->version, 958c2ecf20Sopenharmony_ci psb->flags, 968c2ecf20Sopenharmony_ci psb->settlingtime, 978c2ecf20Sopenharmony_ci psb->res1, 988c2ecf20Sopenharmony_ci psb->numpst); 998c2ecf20Sopenharmony_ci sgtc = psb->settlingtime * 100; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci if (sgtc < 10000) 1028c2ecf20Sopenharmony_ci sgtc = 10000; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci p = ((char *) psb) + sizeof(struct psb_header); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (numpst < 0) 1078c2ecf20Sopenharmony_ci numpst = psb->numpst; 1088c2ecf20Sopenharmony_ci else 1098c2ecf20Sopenharmony_ci printf("Overriding number of pst :%d\n", numpst); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci for (i = 0; i < numpst; i++) { 1128c2ecf20Sopenharmony_ci pst = (struct pst_header*) p; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci if (relevant != 0) { 1158c2ecf20Sopenharmony_ci if (relevant!= pst->cpuid) 1168c2ecf20Sopenharmony_ci goto next_one; 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci printf(" PST %d cpuid %.3x fsb %hhu mfid %hhx svid %hhx numberstates %hhu\n", 1208c2ecf20Sopenharmony_ci i+1, 1218c2ecf20Sopenharmony_ci pst->cpuid, 1228c2ecf20Sopenharmony_ci pst->fsb, 1238c2ecf20Sopenharmony_ci pst->maxfid, 1248c2ecf20Sopenharmony_ci pst->startvid, 1258c2ecf20Sopenharmony_ci pst->numpstates); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci fsb = pst->fsb; 1288c2ecf20Sopenharmony_ci decode_pst(p + sizeof(struct pst_header), pst->numpstates); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cinext_one: 1318c2ecf20Sopenharmony_ci p += sizeof(struct pst_header) + 2*pst->numpstates; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic struct option info_opts[] = { 1378c2ecf20Sopenharmony_ci {"numpst", no_argument, NULL, 'n'}, 1388c2ecf20Sopenharmony_ci}; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_civoid print_help(void) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci printf ("Usage: dump_psb [options]\n"); 1438c2ecf20Sopenharmony_ci printf ("Options:\n"); 1448c2ecf20Sopenharmony_ci printf (" -n, --numpst Set number of PST tables to scan\n"); 1458c2ecf20Sopenharmony_ci printf (" -r, --relevant Only display PSTs relevant to cpuid N\n"); 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ciint 1498c2ecf20Sopenharmony_cimain(int argc, char *argv[]) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci int fd; 1528c2ecf20Sopenharmony_ci int numpst=-1; 1538c2ecf20Sopenharmony_ci int ret=0, cont=1; 1548c2ecf20Sopenharmony_ci char *mem = NULL; 1558c2ecf20Sopenharmony_ci char *p; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci do { 1588c2ecf20Sopenharmony_ci ret = getopt_long(argc, argv, "hr:n:", info_opts, NULL); 1598c2ecf20Sopenharmony_ci switch (ret){ 1608c2ecf20Sopenharmony_ci case '?': 1618c2ecf20Sopenharmony_ci case 'h': 1628c2ecf20Sopenharmony_ci print_help(); 1638c2ecf20Sopenharmony_ci cont = 0; 1648c2ecf20Sopenharmony_ci break; 1658c2ecf20Sopenharmony_ci case 'r': 1668c2ecf20Sopenharmony_ci relevant = strtol(optarg, NULL, 16); 1678c2ecf20Sopenharmony_ci break; 1688c2ecf20Sopenharmony_ci case 'n': 1698c2ecf20Sopenharmony_ci numpst = strtol(optarg, NULL, 10); 1708c2ecf20Sopenharmony_ci break; 1718c2ecf20Sopenharmony_ci case -1: 1728c2ecf20Sopenharmony_ci cont = 0; 1738c2ecf20Sopenharmony_ci break; 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci } while(cont); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci fd = open("/dev/mem", O_RDONLY); 1798c2ecf20Sopenharmony_ci if (fd < 0) { 1808c2ecf20Sopenharmony_ci printf ("Couldn't open /dev/mem. Are you root?\n"); 1818c2ecf20Sopenharmony_ci exit(1); 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci mem = mmap(mem, 0x100000 - 0xc0000, PROT_READ, MAP_SHARED, fd, 0xc0000); 1858c2ecf20Sopenharmony_ci close(fd); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci for (p = mem; p - mem < LEN; p+=16) { 1888c2ecf20Sopenharmony_ci if (memcmp(p, "AMDK7PNOW!", 10) == 0) { 1898c2ecf20Sopenharmony_ci decode_psb(p, numpst); 1908c2ecf20Sopenharmony_ci break; 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci munmap(mem, LEN); 1958c2ecf20Sopenharmony_ci return 0; 1968c2ecf20Sopenharmony_ci} 197