18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  (C) 2004 Bruno Ducrot <ducrot@poupinou.org>
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Based on code found in
68c2ecf20Sopenharmony_ci * linux/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
78c2ecf20Sopenharmony_ci * and originally developed by Paul Devriendt
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <stdio.h>
118c2ecf20Sopenharmony_ci#include <stdlib.h>
128c2ecf20Sopenharmony_ci#include <stdint.h>
138c2ecf20Sopenharmony_ci#include <unistd.h>
148c2ecf20Sopenharmony_ci#include <errno.h>
158c2ecf20Sopenharmony_ci#include <fcntl.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <sys/types.h>
188c2ecf20Sopenharmony_ci#include <sys/stat.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#define MCPU 32
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define MSR_FIDVID_STATUS	0xc0010042
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define MSR_S_HI_CURRENT_VID	0x0000001f
258c2ecf20Sopenharmony_ci#define MSR_S_LO_CURRENT_FID	0x0000003f
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cistatic int get_fidvid(uint32_t cpu, uint32_t *fid, uint32_t *vid)
288c2ecf20Sopenharmony_ci{
298c2ecf20Sopenharmony_ci	int err = 1;
308c2ecf20Sopenharmony_ci	uint64_t msr = 0;
318c2ecf20Sopenharmony_ci	int fd;
328c2ecf20Sopenharmony_ci	char file[20];
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	if (cpu > MCPU)
358c2ecf20Sopenharmony_ci		goto out;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	sprintf(file, "/dev/cpu/%d/msr", cpu);
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	fd = open(file, O_RDONLY);
408c2ecf20Sopenharmony_ci	if (fd < 0)
418c2ecf20Sopenharmony_ci		goto out;
428c2ecf20Sopenharmony_ci	lseek(fd, MSR_FIDVID_STATUS, SEEK_CUR);
438c2ecf20Sopenharmony_ci	if (read(fd, &msr, 8) != 8)
448c2ecf20Sopenharmony_ci		goto err1;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	*fid = ((uint32_t )(msr & 0xffffffffull)) & MSR_S_LO_CURRENT_FID;
478c2ecf20Sopenharmony_ci	*vid = ((uint32_t )(msr>>32 & 0xffffffffull)) & MSR_S_HI_CURRENT_VID;
488c2ecf20Sopenharmony_ci	err = 0;
498c2ecf20Sopenharmony_cierr1:
508c2ecf20Sopenharmony_ci	close(fd);
518c2ecf20Sopenharmony_ciout:
528c2ecf20Sopenharmony_ci	return err;
538c2ecf20Sopenharmony_ci}
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci/* Return a frequency in MHz, given an input fid */
578c2ecf20Sopenharmony_cistatic uint32_t find_freq_from_fid(uint32_t fid)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	return 800 + (fid * 100);
608c2ecf20Sopenharmony_ci}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci/* Return a voltage in miliVolts, given an input vid */
638c2ecf20Sopenharmony_cistatic uint32_t find_millivolts_from_vid(uint32_t vid)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	return 1550-vid*25;
668c2ecf20Sopenharmony_ci}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ciint main (int argc, char *argv[])
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	int err;
718c2ecf20Sopenharmony_ci	int cpu;
728c2ecf20Sopenharmony_ci	uint32_t fid, vid;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	if (argc < 2)
758c2ecf20Sopenharmony_ci		cpu = 0;
768c2ecf20Sopenharmony_ci	else
778c2ecf20Sopenharmony_ci		cpu = strtoul(argv[1], NULL, 0);
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	err = get_fidvid(cpu, &fid, &vid);
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	if (err) {
828c2ecf20Sopenharmony_ci		printf("can't get fid, vid from MSR\n");
838c2ecf20Sopenharmony_ci		printf("Possible trouble: you don't run a powernow-k8 capable cpu\n");
848c2ecf20Sopenharmony_ci		printf("or you are not root, or the msr driver is not present\n");
858c2ecf20Sopenharmony_ci		exit(1);
868c2ecf20Sopenharmony_ci	}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	printf("cpu %d currently at %d MHz and %d mV\n",
908c2ecf20Sopenharmony_ci			cpu,
918c2ecf20Sopenharmony_ci			find_freq_from_fid(fid),
928c2ecf20Sopenharmony_ci			find_millivolts_from_vid(vid));
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	return 0;
958c2ecf20Sopenharmony_ci}
96