main.c
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#define BASE_REG_RIU_PA 0x1f000000
#define BASE_REG_MPLL_PA (BASE_REG_RIU_PA + 0x103000 * 2)
#define PLL_SIZE 0x1000
static void write_file(const char* fname, char* str)
{
int fd = open(fname, O_WRONLY);
if (fd >= 0) {
write(fd, str, strlen(str));
close(fd);
}
}
static int set_cpuclock(uint32_t newclock)
{
int fd_mem = -1;
void *pll_map = NULL;
uint32_t post_div = 0;
char clockstr[16] = {0};
const char fn_governor[] = "/sys/devices/system/cpu/cpufreq/policy0/scaling_governor";
const char fn_setspeed[] = "/sys/devices/system/cpu/cpufreq/policy0/scaling_setspeed";
fd_mem = open("/dev/mem", O_RDWR);
if (fd_mem < 0) {
return -1;
}
pll_map = mmap(0, PLL_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd_mem, BASE_REG_MPLL_PA);
if (pll_map) {
printf("Set cpuclock %dMHz\n", newclock);
newclock *= 1000;
sprintf(clockstr, "%d", newclock);
write_file(fn_governor, "userspace");
write_file(fn_setspeed, clockstr);
if (newclock >= 800000) {
post_div = 2;
}
else if (newclock >= 400000) {
post_div = 4;
}
else if (newclock >= 200000) {
post_div = 8;
}
else {
post_div = 16;
}
{
static const uint64_t divsrc = 432000000llu * 524288;
uint32_t rate = (newclock * 1000) / 16 * post_div / 2;
uint32_t lpf = (uint32_t)(divsrc / rate);
volatile uint16_t *p16 = (uint16_t *)pll_map;
uint32_t cur_post_div = (p16[0x232] & 0x0f) + 1;
uint32_t tmp_post_div = cur_post_div;
if (post_div > cur_post_div) {
while (tmp_post_div != post_div) {
tmp_post_div <<= 1;
p16[0x232] = (p16[0x232] & 0xf0) | ((tmp_post_div - 1) & 0x0f);
}
}
p16[0x2A8] = 0x0000; // reg_lpf_enable = 0
p16[0x2AE] = 0x000f; // reg_lpf_update_cnt = 32
p16[0x2A4] = lpf & 0xffff; // set target freq to LPF high
p16[0x2A6] = lpf >> 16; // set target freq to LPF high
p16[0x2B0] = 0x0001; // switch to LPF control
p16[0x2B2]|= 0x1000; // from low to high
p16[0x2A8] = 0x0001; // reg_lpf_enable = 1
while (!(p16[0x2ba] & 1)); // polling done
p16[0x2A0] = lpf & 0xffff; // store freq to LPF low
p16[0x2A2] = lpf >> 16; // store freq to LPF low
if (post_div < cur_post_div) {
while (tmp_post_div != post_div) {
tmp_post_div >>= 1;
p16[0x232] = (p16[0x232] & 0xf0) | ((tmp_post_div - 1) & 0x0f);
}
}
}
munmap(pll_map, PLL_SIZE);
}
close(fd_mem);
return 0;
}
int main(int argc, char **argv)
{
set_cpuclock(1500);
return 0;
}
P.S. newclock = 1500 = 1.5GHz