162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci// dump_psb. (c) 2004, Dave Jones, Red Hat Inc. 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <fcntl.h> 562306a36Sopenharmony_ci#include <stdio.h> 662306a36Sopenharmony_ci#include <stdlib.h> 762306a36Sopenharmony_ci#include <string.h> 862306a36Sopenharmony_ci#include <unistd.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#define _GNU_SOURCE 1162306a36Sopenharmony_ci#include <getopt.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <sys/mman.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define LEN (0x100000 - 0xc0000) 1662306a36Sopenharmony_ci#define OFFSET (0xc0000) 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#ifndef __packed 1962306a36Sopenharmony_ci#define __packed __attribute((packed)) 2062306a36Sopenharmony_ci#endif 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic long relevant; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic const int fid_to_mult[32] = { 2562306a36Sopenharmony_ci 110, 115, 120, 125, 50, 55, 60, 65, 2662306a36Sopenharmony_ci 70, 75, 80, 85, 90, 95, 100, 105, 2762306a36Sopenharmony_ci 30, 190, 40, 200, 130, 135, 140, 210, 2862306a36Sopenharmony_ci 150, 225, 160, 165, 170, 180, -1, -1, 2962306a36Sopenharmony_ci}; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic const int vid_to_voltage[32] = { 3262306a36Sopenharmony_ci 2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650, 3362306a36Sopenharmony_ci 1600, 1550, 1500, 1450, 1400, 1350, 1300, 0, 3462306a36Sopenharmony_ci 1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100, 3562306a36Sopenharmony_ci 1075, 1050, 1024, 1000, 975, 950, 925, 0, 3662306a36Sopenharmony_ci}; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistruct psb_header { 3962306a36Sopenharmony_ci char signature[10]; 4062306a36Sopenharmony_ci u_char version; 4162306a36Sopenharmony_ci u_char flags; 4262306a36Sopenharmony_ci u_short settlingtime; 4362306a36Sopenharmony_ci u_char res1; 4462306a36Sopenharmony_ci u_char numpst; 4562306a36Sopenharmony_ci} __packed; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistruct pst_header { 4862306a36Sopenharmony_ci u_int32_t cpuid; 4962306a36Sopenharmony_ci u_char fsb; 5062306a36Sopenharmony_ci u_char maxfid; 5162306a36Sopenharmony_ci u_char startvid; 5262306a36Sopenharmony_ci u_char numpstates; 5362306a36Sopenharmony_ci} __packed; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic u_int fsb; 5662306a36Sopenharmony_cistatic u_int sgtc; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic int 5962306a36Sopenharmony_cidecode_pst(char *p, int npstates) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci int i; 6262306a36Sopenharmony_ci int freq, fid, vid; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci for (i = 0; i < npstates; ++i) { 6562306a36Sopenharmony_ci fid = *p++; 6662306a36Sopenharmony_ci vid = *p++; 6762306a36Sopenharmony_ci freq = 100 * fid_to_mult[fid] * fsb; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci printf(" %2d %8dkHz FID %02x (%2d.%01d) VID %02x (%4dmV)\n", 7062306a36Sopenharmony_ci i, 7162306a36Sopenharmony_ci freq, 7262306a36Sopenharmony_ci fid, fid_to_mult[fid]/10, fid_to_mult[fid]%10, 7362306a36Sopenharmony_ci vid, vid_to_voltage[vid]); 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci return 0; 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic 8062306a36Sopenharmony_civoid decode_psb(char *p, int numpst) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci int i; 8362306a36Sopenharmony_ci struct psb_header *psb; 8462306a36Sopenharmony_ci struct pst_header *pst; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci psb = (struct psb_header*) p; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci if (psb->version != 0x12) 8962306a36Sopenharmony_ci return; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci printf("PSB version: %hhx flags: %hhx settling time %hhuus res1 %hhx num pst %hhu\n", 9262306a36Sopenharmony_ci psb->version, 9362306a36Sopenharmony_ci psb->flags, 9462306a36Sopenharmony_ci psb->settlingtime, 9562306a36Sopenharmony_ci psb->res1, 9662306a36Sopenharmony_ci psb->numpst); 9762306a36Sopenharmony_ci sgtc = psb->settlingtime * 100; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci if (sgtc < 10000) 10062306a36Sopenharmony_ci sgtc = 10000; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci p = ((char *) psb) + sizeof(struct psb_header); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci if (numpst < 0) 10562306a36Sopenharmony_ci numpst = psb->numpst; 10662306a36Sopenharmony_ci else 10762306a36Sopenharmony_ci printf("Overriding number of pst :%d\n", numpst); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci for (i = 0; i < numpst; i++) { 11062306a36Sopenharmony_ci pst = (struct pst_header*) p; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci if (relevant != 0) { 11362306a36Sopenharmony_ci if (relevant!= pst->cpuid) 11462306a36Sopenharmony_ci goto next_one; 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci printf(" PST %d cpuid %.3x fsb %hhu mfid %hhx svid %hhx numberstates %hhu\n", 11862306a36Sopenharmony_ci i+1, 11962306a36Sopenharmony_ci pst->cpuid, 12062306a36Sopenharmony_ci pst->fsb, 12162306a36Sopenharmony_ci pst->maxfid, 12262306a36Sopenharmony_ci pst->startvid, 12362306a36Sopenharmony_ci pst->numpstates); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci fsb = pst->fsb; 12662306a36Sopenharmony_ci decode_pst(p + sizeof(struct pst_header), pst->numpstates); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cinext_one: 12962306a36Sopenharmony_ci p += sizeof(struct pst_header) + 2*pst->numpstates; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic struct option info_opts[] = { 13562306a36Sopenharmony_ci {"numpst", no_argument, NULL, 'n'}, 13662306a36Sopenharmony_ci}; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_civoid print_help(void) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci printf ("Usage: dump_psb [options]\n"); 14162306a36Sopenharmony_ci printf ("Options:\n"); 14262306a36Sopenharmony_ci printf (" -n, --numpst Set number of PST tables to scan\n"); 14362306a36Sopenharmony_ci printf (" -r, --relevant Only display PSTs relevant to cpuid N\n"); 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ciint 14762306a36Sopenharmony_cimain(int argc, char *argv[]) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci int fd; 15062306a36Sopenharmony_ci int numpst=-1; 15162306a36Sopenharmony_ci int ret=0, cont=1; 15262306a36Sopenharmony_ci char *mem = NULL; 15362306a36Sopenharmony_ci char *p; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci do { 15662306a36Sopenharmony_ci ret = getopt_long(argc, argv, "hr:n:", info_opts, NULL); 15762306a36Sopenharmony_ci switch (ret){ 15862306a36Sopenharmony_ci case '?': 15962306a36Sopenharmony_ci case 'h': 16062306a36Sopenharmony_ci print_help(); 16162306a36Sopenharmony_ci cont = 0; 16262306a36Sopenharmony_ci break; 16362306a36Sopenharmony_ci case 'r': 16462306a36Sopenharmony_ci relevant = strtol(optarg, NULL, 16); 16562306a36Sopenharmony_ci break; 16662306a36Sopenharmony_ci case 'n': 16762306a36Sopenharmony_ci numpst = strtol(optarg, NULL, 10); 16862306a36Sopenharmony_ci break; 16962306a36Sopenharmony_ci case -1: 17062306a36Sopenharmony_ci cont = 0; 17162306a36Sopenharmony_ci break; 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci } while(cont); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci fd = open("/dev/mem", O_RDONLY); 17762306a36Sopenharmony_ci if (fd < 0) { 17862306a36Sopenharmony_ci printf ("Couldn't open /dev/mem. Are you root?\n"); 17962306a36Sopenharmony_ci exit(1); 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci mem = mmap(mem, 0x100000 - 0xc0000, PROT_READ, MAP_SHARED, fd, 0xc0000); 18362306a36Sopenharmony_ci close(fd); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci for (p = mem; p - mem < LEN; p+=16) { 18662306a36Sopenharmony_ci if (memcmp(p, "AMDK7PNOW!", 10) == 0) { 18762306a36Sopenharmony_ci decode_psb(p, numpst); 18862306a36Sopenharmony_ci break; 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci munmap(mem, LEN); 19362306a36Sopenharmony_ci return 0; 19462306a36Sopenharmony_ci} 195