rbcfg: Implement CPU frequency control
This patch implements CPU frequency control as found on several routerboard devices. Supported SoCs: - QCA953X - AR9344 Tested on hAP lite and mAP lite (QCA953x): steps of 50MHz Tested on LHG 5 (AR9344): steps of 50MHz On unsupported hardware, this patch is a NOP: it will not alter the new field. "rbcfg help" will display an empty "cpu_freq" help listing. "rbcfg show" will not show the cpu_freq field. "rbcfg set/get cpu_freq" will return an error code. Signed-off-by: Thibaut VARENE <hacks@slashdirt.org> [adjusted subject] Signed-off-by: Jo-Philipp Wich <jo@mein.io>
This commit is contained in:
parent
b9c31c44d7
commit
2be307c998
3 changed files with 139 additions and 4 deletions
|
@ -8,7 +8,7 @@
|
|||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=rbcfg
|
||||
PKG_RELEASE:=1
|
||||
PKG_RELEASE:=2
|
||||
|
||||
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* RouterBOOT configuration utility
|
||||
*
|
||||
* Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
|
||||
* Copyright (C) 2017 Thibaut VARENE <varenet@parisc-linux.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published
|
||||
|
@ -29,6 +30,7 @@
|
|||
#define RB_ERR_INVALID 2
|
||||
#define RB_ERR_NOMEM 3
|
||||
#define RB_ERR_IO 4
|
||||
#define RB_ERR_NOTWANTED 5
|
||||
|
||||
#define ARRAY_SIZE(_a) (sizeof((_a)) / sizeof((_a)[0]))
|
||||
|
||||
|
@ -67,6 +69,11 @@ struct rbcfg_command {
|
|||
int (*exec)(int argc, const char *argv[]);
|
||||
};
|
||||
|
||||
struct rbcfg_soc {
|
||||
const char *needle;
|
||||
const int type;
|
||||
};
|
||||
|
||||
static void usage(void);
|
||||
|
||||
/* Globals */
|
||||
|
@ -135,12 +142,32 @@ static const struct rbcfg_value rbcfg_cpu_mode[] = {
|
|||
RB_CPU_MODE_REGULAR),
|
||||
};
|
||||
|
||||
static const struct rbcfg_value rbcfg_cpu_freq_dummy[] = {
|
||||
};
|
||||
|
||||
static const struct rbcfg_value rbcfg_cpu_freq_qca953x[] = {
|
||||
CFG_U32("-2", "-100MHz", RB_CPU_FREQ_L2),
|
||||
CFG_U32("-1", "- 50MHz", RB_CPU_FREQ_L1),
|
||||
CFG_U32("0", "Factory", RB_CPU_FREQ_N0),
|
||||
CFG_U32("+1", "+ 50MHz", RB_CPU_FREQ_H1),
|
||||
CFG_U32("+2", "+100MHz", RB_CPU_FREQ_H2),
|
||||
};
|
||||
|
||||
static const struct rbcfg_value rbcfg_cpu_freq_ar9344[] = {
|
||||
CFG_U32("-2", "-100MHz", RB_CPU_FREQ_L2),
|
||||
CFG_U32("-1", "- 50MHz", RB_CPU_FREQ_L1),
|
||||
CFG_U32("0", "Factory", RB_CPU_FREQ_N0),
|
||||
CFG_U32("+1", "+ 50MHz", RB_CPU_FREQ_H1),
|
||||
CFG_U32("+2", "+100MHz", RB_CPU_FREQ_H2),
|
||||
CFG_U32("+3", "+150MHz", RB_CPU_FREQ_H3),
|
||||
};
|
||||
|
||||
static const struct rbcfg_value rbcfg_booter[] = {
|
||||
CFG_U32("regular", "load regular booter", RB_BOOTER_REGULAR),
|
||||
CFG_U32("backup", "force backup-booter loading", RB_BOOTER_BACKUP),
|
||||
};
|
||||
|
||||
static const struct rbcfg_env rbcfg_envs[] = {
|
||||
static struct rbcfg_env rbcfg_envs[] = {
|
||||
{
|
||||
.name = "boot_delay",
|
||||
.id = RB_ID_BOOT_DELAY,
|
||||
|
@ -177,6 +204,12 @@ static const struct rbcfg_env rbcfg_envs[] = {
|
|||
.type = RBCFG_ENV_TYPE_U32,
|
||||
.values = rbcfg_cpu_mode,
|
||||
.num_values = ARRAY_SIZE(rbcfg_cpu_mode),
|
||||
}, {
|
||||
.name = "cpu_freq",
|
||||
.id = RB_ID_CPU_FREQ,
|
||||
.type = RBCFG_ENV_TYPE_U32,
|
||||
.values = rbcfg_cpu_freq_dummy,
|
||||
.num_values = ARRAY_SIZE(rbcfg_cpu_freq_dummy),
|
||||
}, {
|
||||
.name = "uart_speed",
|
||||
.id = RB_ID_UART_SPEED,
|
||||
|
@ -240,8 +273,10 @@ rbcfg_find_tag(struct rbcfg_ctx *ctx, uint16_t tag_id, uint16_t *tag_len,
|
|||
buf += 2;
|
||||
buflen -= 2;
|
||||
|
||||
if (id == RB_ID_TERMINATOR)
|
||||
if (id == RB_ID_TERMINATOR) {
|
||||
ret = RB_ERR_NOTWANTED;
|
||||
break;
|
||||
}
|
||||
|
||||
if (buflen < len)
|
||||
break;
|
||||
|
@ -257,7 +292,7 @@ rbcfg_find_tag(struct rbcfg_ctx *ctx, uint16_t tag_id, uint16_t *tag_len,
|
|||
buflen -= len;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
if (RB_ERR_NOTFOUND == ret)
|
||||
fprintf(stderr, "no tag found with id=%u\n", tag_id);
|
||||
|
||||
return ret;
|
||||
|
@ -748,6 +783,96 @@ usage(void)
|
|||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
#define RBCFG_SOC_UNKNOWN 0
|
||||
#define RBCFG_SOC_QCA953X 1
|
||||
#define RBCFG_SOC_AR9344 2
|
||||
|
||||
static const struct rbcfg_soc rbcfg_socs[] = {
|
||||
{
|
||||
.needle = "QCA953",
|
||||
.type = RBCFG_SOC_QCA953X,
|
||||
}, {
|
||||
.needle = "AR9344",
|
||||
.type = RBCFG_SOC_AR9344,
|
||||
},
|
||||
};
|
||||
|
||||
#define CPUINFO_BUFSIZE 128 /* lines of interest are < 80 chars */
|
||||
|
||||
static int cpuinfo_find_soc(void)
|
||||
{
|
||||
FILE *fp;
|
||||
char temp[CPUINFO_BUFSIZE];
|
||||
char *haystack, *needle;
|
||||
int i, found = 0, soc_type = RBCFG_SOC_UNKNOWN;
|
||||
|
||||
fp = fopen("/proc/cpuinfo", "r");
|
||||
if (!fp)
|
||||
goto end;
|
||||
|
||||
/* first, extract the system type line */
|
||||
needle = "system type";
|
||||
while(fgets(temp, CPUINFO_BUFSIZE, fp)) {
|
||||
if (!strncmp(temp, needle, strlen(needle))) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
/* failsafe in case cpuinfo format changes */
|
||||
if (!found)
|
||||
goto end;
|
||||
|
||||
/* skip the field header */
|
||||
haystack = strchr(temp, ':');
|
||||
|
||||
/* then, try to identify known SoC, stop at first match */
|
||||
for (i = 0; i < ARRAY_SIZE(rbcfg_socs); i++) {
|
||||
if ((strstr(haystack, rbcfg_socs[i].needle))) {
|
||||
soc_type = rbcfg_socs[i].type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
return soc_type;
|
||||
}
|
||||
|
||||
static void fixup_rbcfg_envs(void)
|
||||
{
|
||||
int i, num_val, soc_type;
|
||||
const struct rbcfg_value * env_value;
|
||||
|
||||
/* detect SoC */
|
||||
soc_type = cpuinfo_find_soc();
|
||||
|
||||
/* update rbcfg_envs */
|
||||
switch (soc_type) {
|
||||
case RBCFG_SOC_QCA953X:
|
||||
env_value = rbcfg_cpu_freq_qca953x;
|
||||
num_val = ARRAY_SIZE(rbcfg_cpu_freq_qca953x);
|
||||
break;
|
||||
case RBCFG_SOC_AR9344:
|
||||
env_value = rbcfg_cpu_freq_ar9344;
|
||||
num_val = ARRAY_SIZE(rbcfg_cpu_freq_ar9344);
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(rbcfg_envs); i++) {
|
||||
if (RB_ID_CPU_FREQ == rbcfg_envs[i].id) {
|
||||
if (RBCFG_SOC_UNKNOWN == soc_type)
|
||||
rbcfg_envs[i].id = RB_ID_TERMINATOR;
|
||||
else {
|
||||
rbcfg_envs[i].values = env_value;
|
||||
rbcfg_envs[i].num_values = num_val;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
const struct rbcfg_command *cmd = NULL;
|
||||
|
@ -756,6 +881,8 @@ int main(int argc, const char *argv[])
|
|||
|
||||
rbcfg_name = (char *) argv[0];
|
||||
|
||||
fixup_rbcfg_envs();
|
||||
|
||||
if (argc < 2) {
|
||||
usage();
|
||||
return EXIT_FAILURE;
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#define RB_ID_BOOT_PROTOCOL 9
|
||||
#define RB_ID_SOFT_10 10
|
||||
#define RB_ID_SOFT_11 11
|
||||
#define RB_ID_CPU_FREQ 12
|
||||
#define RB_ID_BOOTER 13
|
||||
|
||||
#define RB_UART_SPEED_115200 0
|
||||
|
@ -71,6 +72,13 @@
|
|||
#define RB_BOOT_PROTOCOL_BOOTP 0
|
||||
#define RB_BOOT_PROTOCOL_DHCP 1
|
||||
|
||||
#define RB_CPU_FREQ_L2 (0 << 3)
|
||||
#define RB_CPU_FREQ_L1 (1 << 3)
|
||||
#define RB_CPU_FREQ_N0 (2 << 3)
|
||||
#define RB_CPU_FREQ_H1 (3 << 3)
|
||||
#define RB_CPU_FREQ_H2 (4 << 3)
|
||||
#define RB_CPU_FREQ_H3 (5 << 3)
|
||||
|
||||
#define RB_BOOTER_REGULAR 0
|
||||
#define RB_BOOTER_BACKUP 1
|
||||
|
||||
|
|
Loading…
Reference in a new issue