ARC: HSDK: Add platform-specific commands

This patch add support of hsdk platform-specific commands:

hsdk_clock set - set clock from axi_freq, cpu_freq and tun_freq
environment variables/command line arguments

hsdk_clock get - save clock frequencies to axi_freq, cpu_freq
and tun_freq environment variables

hsdk_clock print - show CPU, AXI, DDR and TUNNEL current
clock frequencies.

hsdk_clock print_all - show all currently used clock frequencies.

hsdk_init - setup board HW in one of pre-defined configuration
(hsdk_hs34 / hsdk_hs36 / hsdk_hs36_ccm / hsdk_hs38 /
hsdk_hs38_ccm / hsdk_hs38x2 / hsdk_hs38x3 / hsdk_hs38x4)

hsdk_go - run baremetal application on hsdk configured
by hsdk_init command.

This patch changes default behaviour of 'bootm' command:
now we are able to set number of CPUs to be kicked by setting
'core_mask' environment variable before 'bootm' command run.

Signed-off-by: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
This commit is contained in:
Eugeniy Paltsev 2018-03-26 15:57:37 +03:00 committed by Alexey Brodkin
parent 1e43118560
commit ada8affdfe
10 changed files with 1569 additions and 56 deletions

View file

@ -6,6 +6,7 @@
/dts-v1/;
#include "skeleton.dtsi"
#include "dt-bindings/clock/snps,hsdk-cgu.h"
/ {
#address-cells = <1>;
@ -24,6 +25,35 @@
};
};
clk-fmeas {
clocks = <&cgu_clk CLK_ARC_PLL>, <&cgu_clk CLK_SYS_PLL>,
<&cgu_clk CLK_TUN_PLL>, <&cgu_clk CLK_DDR_PLL>,
<&cgu_clk CLK_ARC>, <&cgu_clk CLK_HDMI_PLL>,
<&cgu_clk CLK_TUN_TUN>, <&cgu_clk CLK_HDMI>,
<&cgu_clk CLK_SYS_APB>, <&cgu_clk CLK_SYS_AXI>,
<&cgu_clk CLK_SYS_ETH>, <&cgu_clk CLK_SYS_USB>,
<&cgu_clk CLK_SYS_SDIO>, <&cgu_clk CLK_SYS_HDMI>,
<&cgu_clk CLK_SYS_GFX_CORE>, <&cgu_clk CLK_SYS_GFX_DMA>,
<&cgu_clk CLK_SYS_GFX_CFG>, <&cgu_clk CLK_SYS_DMAC_CORE>,
<&cgu_clk CLK_SYS_DMAC_CFG>, <&cgu_clk CLK_SYS_SDIO_REF>,
<&cgu_clk CLK_SYS_SPI_REF>, <&cgu_clk CLK_SYS_I2C_REF>,
<&cgu_clk CLK_SYS_UART_REF>, <&cgu_clk CLK_SYS_EBI_REF>,
<&cgu_clk CLK_TUN_ROM>, <&cgu_clk CLK_TUN_PWM>;
clock-names = "cpu-pll", "sys-pll",
"tun-pll", "ddr-clk",
"cpu-clk", "hdmi-pll",
"tun-clk", "hdmi-clk",
"apb-clk", "axi-clk",
"eth-clk", "usb-clk",
"sdio-clk", "hdmi-sys-clk",
"gfx-core-clk", "gfx-dma-clk",
"gfx-cfg-clk", "dmac-core-clk",
"dmac-cfg-clk", "sdio-ref-clk",
"spi-clk", "i2c-clk",
"uart-clk", "ebi-clk",
"rom-clk", "pwm-clk";
};
cgu_clk: cgu-clk@f0000000 {
compatible = "snps,hsdk-cgu-clock";
reg = <0xf0000000 0x10>, <0xf00014B8 0x4>;

View file

@ -1,5 +1,5 @@
AXS10X BOARD
M: Alexey Brodkin <abrodkin@synopsys.com>
HSDK BOARD
M: Eugeniy Paltsev <paltsev@synopsys.com>
S: Maintained
F: board/synopsys/hsdk/
F: configs/hsdk_defconfig

View file

@ -5,3 +5,5 @@
#
obj-y += hsdk.o
obj-y += env-lib.o
obj-y += clk-lib.o

View file

@ -0,0 +1,75 @@
/*
* Copyright (C) 2018 Synopsys, Inc. All rights reserved.
* Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <clk.h>
#include <dm/device.h>
#include "clk-lib.h"
#define HZ_IN_MHZ 1000000
#define ceil(x, y) ({ ulong __x = (x), __y = (y); (__x + __y - 1) / __y; })
int soc_clk_ctl(const char *name, ulong *rate, enum clk_ctl_ops ctl)
{
int ret;
ulong mhz_rate, priv_rate;
struct clk clk;
/* Dummy fmeas device, just to be able to use standard clk_* api */
struct udevice fmeas = {
.name = "clk-fmeas",
.node = ofnode_path("/clk-fmeas"),
};
ret = clk_get_by_name(&fmeas, name, &clk);
if (ret) {
pr_err("clock '%s' not found, err=%d\n", name, ret);
return ret;
}
if (ctl & CLK_ON) {
ret = clk_enable(&clk);
if (ret && ret != -ENOSYS && ret != -ENOTSUPP)
return ret;
}
if ((ctl & CLK_SET) && rate) {
priv_rate = ctl & CLK_MHZ ? (*rate) * HZ_IN_MHZ : *rate;
ret = clk_set_rate(&clk, priv_rate);
if (ret)
return ret;
}
if (ctl & CLK_OFF) {
ret = clk_disable(&clk);
if (ret) {
pr_err("clock '%s' can't be disabled, err=%d\n", name, ret);
return ret;
}
}
priv_rate = clk_get_rate(&clk);
clk_free(&clk);
mhz_rate = ceil(priv_rate, HZ_IN_MHZ);
if (ctl & CLK_MHZ)
priv_rate = mhz_rate;
if ((ctl & CLK_GET) && rate)
*rate = priv_rate;
if ((ctl & CLK_PRINT) && (ctl & CLK_MHZ))
printf("HSDK: clock '%s' rate %lu MHz\n", name, priv_rate);
else if (ctl & CLK_PRINT)
printf("HSDK: clock '%s' rate %lu Hz\n", name, priv_rate);
else
debug("HSDK: clock '%s' rate %lu MHz\n", name, mhz_rate);
return 0;
}

View file

@ -0,0 +1,38 @@
/*
* Copyright (C) 2018 Synopsys, Inc. All rights reserved.
* Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef __BOARD_CLK_LIB_H
#define __BOARD_CLK_LIB_H
#include <common.h>
enum clk_ctl_ops {
CLK_SET = BIT(0), /* set frequency */
CLK_GET = BIT(1), /* get frequency */
CLK_ON = BIT(2), /* enable clock */
CLK_OFF = BIT(3), /* disable clock */
CLK_PRINT = BIT(4), /* print frequency */
CLK_MHZ = BIT(5) /* all values in MHZ instead of HZ */
};
/*
* Depending on the clk_ctl_ops enable / disable /
* set clock rate from 'rate' argument / read clock to 'rate' argument /
* print clock rate. If CLK_MHZ flag set in clk_ctl_ops 'rate' is in MHz,
* otherwise - in Hz.
*
* This function expects "clk-fmeas" node in device tree:
* / {
* clk-fmeas {
* clocks = <&cpu_pll>, <&sys_pll>;
* clock-names = "cpu-pll", "sys-pll";
* };
* };
*/
int soc_clk_ctl(const char *name, ulong *rate, enum clk_ctl_ops ctl);
#endif /* __BOARD_CLK_LIB_H */

View file

@ -0,0 +1,302 @@
/*
* Copyright (C) 2018 Synopsys, Inc. All rights reserved.
* Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include "env-lib.h"
#define MAX_CMD_LEN 25
static void env_clear_common(u32 index, const struct env_map_common *map)
{
map[index].val->val = 0;
map[index].val->set = false;
}
static int env_read_common(u32 index, const struct env_map_common *map)
{
u32 val;
if (!env_get_yesno(map[index].env_name)) {
if (map[index].type == ENV_HEX) {
val = (u32)env_get_hex(map[index].env_name, 0);
debug("ENV: %s: = %#x\n", map[index].env_name, val);
} else {
val = (u32)env_get_ulong(map[index].env_name, 10, 0);
debug("ENV: %s: = %d\n", map[index].env_name, val);
}
map[index].val->val = val;
map[index].val->set = true;
}
return 0;
}
static void env_clear_core(u32 index, const struct env_map_percpu *map)
{
for (u32 i = 0; i < NR_CPUS; i++) {
(*map[index].val)[i].val = 0;
(*map[index].val)[i].set = false;
}
}
static int env_read_core(u32 index, const struct env_map_percpu *map)
{
u32 val;
char command[MAX_CMD_LEN];
for (u32 i = 0; i < NR_CPUS; i++) {
sprintf(command, "%s_%u", map[index].env_name, i);
if (!env_get_yesno(command)) {
if (map[index].type == ENV_HEX) {
val = (u32)env_get_hex(command, 0);
debug("ENV: %s: = %#x\n", command, val);
} else {
val = (u32)env_get_ulong(command, 10, 0);
debug("ENV: %s: = %d\n", command, val);
}
(*map[index].val)[i].val = val;
(*map[index].val)[i].set = true;
}
}
return 0;
}
static int env_validate_common(u32 index, const struct env_map_common *map)
{
u32 value = map[index].val->val;
bool set = map[index].val->set;
u32 min = map[index].min;
u32 max = map[index].max;
/* Check if environment is mandatory */
if (map[index].mandatory && !set) {
pr_err("Variable \'%s\' is mandatory, but it is not defined\n",
map[index].env_name);
return -EINVAL;
}
/* Check environment boundary */
if (set && (value < min || value > max)) {
if (map[index].type == ENV_HEX)
pr_err("Variable \'%s\' must be between %#x and %#x\n",
map[index].env_name, min, max);
else
pr_err("Variable \'%s\' must be between %u and %u\n",
map[index].env_name, min, max);
return -EINVAL;
}
return 0;
}
static int env_validate_core(u32 index, const struct env_map_percpu *map,
bool (*cpu_used)(u32))
{
u32 value;
bool set;
bool mandatory = map[index].mandatory;
u32 min, max;
for (u32 i = 0; i < NR_CPUS; i++) {
set = (*map[index].val)[i].set;
value = (*map[index].val)[i].val;
/* Check if environment is mandatory */
if (cpu_used(i) && mandatory && !set) {
pr_err("CPU %u is used, but \'%s_%u\' is not defined\n",
i, map[index].env_name, i);
return -EINVAL;
}
min = map[index].min[i];
max = map[index].max[i];
/* Check environment boundary */
if (set && (value < min || value > max)) {
if (map[index].type == ENV_HEX)
pr_err("Variable \'%s_%u\' must be between %#x and %#x\n",
map[index].env_name, i, min, max);
else
pr_err("Variable \'%s_%u\' must be between %d and %d\n",
map[index].env_name, i, min, max);
return -EINVAL;
}
}
return 0;
}
void envs_cleanup_core(const struct env_map_percpu *map)
{
/* Cleanup env struct first */
for (u32 i = 0; map[i].env_name; i++)
env_clear_core(i, map);
}
void envs_cleanup_common(const struct env_map_common *map)
{
/* Cleanup env struct first */
for (u32 i = 0; map[i].env_name; i++)
env_clear_common(i, map);
}
int envs_read_common(const struct env_map_common *map)
{
int ret;
for (u32 i = 0; map[i].env_name; i++) {
ret = env_read_common(i, map);
if (ret)
return ret;
}
return 0;
}
int envs_validate_common(const struct env_map_common *map)
{
int ret;
for (u32 i = 0; map[i].env_name; i++) {
ret = env_validate_common(i, map);
if (ret)
return ret;
}
return 0;
}
int envs_read_validate_common(const struct env_map_common *map)
{
int ret;
envs_cleanup_common(map);
ret = envs_read_common(map);
if (ret)
return ret;
ret = envs_validate_common(map);
if (ret)
return ret;
return 0;
}
int envs_read_validate_core(const struct env_map_percpu *map,
bool (*cpu_used)(u32))
{
int ret;
envs_cleanup_core(map);
for (u32 i = 0; map[i].env_name; i++) {
ret = env_read_core(i, map);
if (ret)
return ret;
}
for (u32 i = 0; map[i].env_name; i++) {
ret = env_validate_core(i, map, cpu_used);
if (ret)
return ret;
}
return 0;
}
int envs_process_and_validate(const struct env_map_common *common,
const struct env_map_percpu *core,
bool (*cpu_used)(u32))
{
int ret;
ret = envs_read_validate_common(common);
if (ret)
return ret;
ret = envs_read_validate_core(core, cpu_used);
if (ret)
return ret;
return 0;
}
static int args_envs_read_search(const struct env_map_common *map,
int argc, char *const argv[])
{
for (int i = 0; map[i].env_name; i++) {
if (!strcmp(argv[0], map[i].env_name))
return i;
}
pr_err("Unexpected argument '%s', can't parse\n", argv[0]);
return -ENOENT;
}
static int arg_read_set(const struct env_map_common *map, u32 i, int argc,
char *const argv[])
{
char *endp = argv[1];
if (map[i].type == ENV_HEX)
map[i].val->val = simple_strtoul(argv[1], &endp, 16);
else
map[i].val->val = simple_strtoul(argv[1], &endp, 10);
map[i].val->set = true;
if (*endp == '\0')
return 0;
pr_err("Unexpected argument '%s', can't parse\n", argv[1]);
map[i].val->set = false;
return -EINVAL;
}
int args_envs_enumerate(const struct env_map_common *map, int enum_by,
int argc, char *const argv[])
{
u32 i;
if (argc % enum_by) {
pr_err("unexpected argument number: %d\n", argc);
return -EINVAL;
}
while (argc > 0) {
i = args_envs_read_search(map, argc, argv);
if (i < 0)
return i;
debug("ARG: found '%s' with index %d\n", map[i].env_name, i);
if (i < 0) {
pr_err("unknown arg: %s\n", argv[0]);
return -EINVAL;
}
if (arg_read_set(map, i, argc, argv))
return -EINVAL;
debug("ARG: value.s '%s' == %#x\n", argv[1], map[i].val->val);
argc -= enum_by;
argv += enum_by;
}
return 0;
}

View file

@ -0,0 +1,58 @@
/*
* Copyright (C) 2018 Synopsys, Inc. All rights reserved.
* Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef __BOARD_ENV_LIB_H
#define __BOARD_ENV_LIB_H
#include <common.h>
#include <config.h>
#include <linux/kernel.h>
enum env_type {
ENV_DEC,
ENV_HEX
};
typedef struct {
u32 val;
bool set;
} u32_env;
struct env_map_common {
const char *const env_name;
enum env_type type;
bool mandatory;
u32 min;
u32 max;
u32_env *val;
};
struct env_map_percpu {
const char *const env_name;
enum env_type type;
bool mandatory;
u32 min[NR_CPUS];
u32 max[NR_CPUS];
u32_env (*val)[NR_CPUS];
};
void envs_cleanup_common(const struct env_map_common *map);
int envs_read_common(const struct env_map_common *map);
int envs_validate_common(const struct env_map_common *map);
int envs_read_validate_common(const struct env_map_common *map);
void envs_cleanup_core(const struct env_map_percpu *map);
int envs_read_validate_core(const struct env_map_percpu *map,
bool (*cpu_used)(u32));
int envs_process_and_validate(const struct env_map_common *common,
const struct env_map_percpu *core,
bool (*cpu_used)(u32));
int args_envs_enumerate(const struct env_map_common *map,
int enum_by, int argc, char *const argv[]);
#endif /* __BOARD_ENV_LIB_H */

File diff suppressed because it is too large Load diff

View file

@ -7,13 +7,16 @@ CONFIG_DEFAULT_DEVICE_TREE="hsdk"
CONFIG_USE_BOOTARGS=y
CONFIG_BOOTARGS="console=ttyS0,115200n8"
CONFIG_BOARD_EARLY_INIT_F=y
CONFIG_HUSH_PARSER=y
CONFIG_SYS_PROMPT="hsdk# "
CONFIG_CMD_ENV_FLAGS=y
# CONFIG_CMD_FLASH is not set
CONFIG_CMD_MMC=y
CONFIG_CMD_USB=y
# CONFIG_CMD_SETEXPR is not set
CONFIG_CMD_DHCP=y
CONFIG_CMD_PING=y
CONFIG_CMD_CACHE=y
CONFIG_CMD_EXT2=y
CONFIG_CMD_EXT4=y
CONFIG_CMD_EXT4_WRITE=y
@ -25,6 +28,7 @@ CONFIG_ENV_FAT_INTERFACE="mmc"
CONFIG_ENV_FAT_DEVICE_AND_PART="0:1"
CONFIG_NET_RANDOM_ETHADDR=y
CONFIG_DM=y
CONFIG_CLK_HSDK=y
CONFIG_MMC=y
CONFIG_MMC_DW=y
CONFIG_DM_ETH=y

View file

@ -12,6 +12,7 @@
/*
* CPU configuration
*/
#define NR_CPUS 4
#define ARC_PERIPHERAL_BASE 0xF0000000
#define ARC_DWMMC_BASE (ARC_PERIPHERAL_BASE + 0xA000)
#define ARC_DWGMAC_BASE (ARC_PERIPHERAL_BASE + 0x18000)
@ -61,19 +62,68 @@
*/
#define CONFIG_ENV_SIZE SZ_16K
#define CONFIG_EXTRA_ENV_SETTINGS \
"core_dccm_0=0x10\0" \
"core_dccm_1=0x6\0" \
"core_dccm_2=0x10\0" \
"core_dccm_3=0x6\0" \
"core_iccm_0=0x10\0" \
"core_iccm_1=0x6\0" \
"core_iccm_2=0x10\0" \
"core_iccm_3=0x6\0" \
"core_mask=0xF\0" \
"dcache_ena=0x1\0" \
"icache_ena=0x1\0" \
"non_volatile_limit=0xE\0" \
"hsdk_hs34=setenv core_mask 0x2; setenv icache_ena 0x0; \
setenv dcache_ena 0x0; setenv core_iccm_1 0x7; \
setenv core_dccm_1 0x8; setenv non_volatile_limit 0x0;\0" \
"hsdk_hs36=setenv core_mask 0x1; setenv icache_ena 0x1; \
setenv dcache_ena 0x1; setenv core_iccm_0 0x10; \
setenv core_dccm_0 0x10; setenv non_volatile_limit 0xE;\0" \
"hsdk_hs36_ccm=setenv core_mask 0x2; setenv icache_ena 0x1; \
setenv dcache_ena 0x1; setenv core_iccm_1 0x7; \
setenv core_dccm_1 0x8; setenv non_volatile_limit 0xE;\0" \
"hsdk_hs38=setenv core_mask 0x1; setenv icache_ena 0x1; \
setenv dcache_ena 0x1; setenv core_iccm_0 0x10; \
setenv core_dccm_0 0x10; setenv non_volatile_limit 0xE;\0" \
"hsdk_hs38_ccm=setenv core_mask 0x2; setenv icache_ena 0x1; \
setenv dcache_ena 0x1; setenv core_iccm_1 0x7; \
setenv core_dccm_1 0x8; setenv non_volatile_limit 0xE;\0" \
"hsdk_hs38x2=setenv core_mask 0x3; setenv icache_ena 0x1; \
setenv dcache_ena 0x1; setenv core_iccm_0 0x10; \
setenv core_dccm_0 0x10; setenv non_volatile_limit 0xE; \
setenv core_iccm_1 0x6; setenv core_dccm_1 0x6;\0" \
"hsdk_hs38x3=setenv core_mask 0x7; setenv icache_ena 0x1; \
setenv dcache_ena 0x1; setenv core_iccm_0 0x10; \
setenv core_dccm_0 0x10; setenv non_volatile_limit 0xE; \
setenv core_iccm_1 0x6; setenv core_dccm_1 0x6; \
setenv core_iccm_2 0x10; setenv core_dccm_2 0x10;\0" \
"hsdk_hs38x4=setenv core_mask 0xF; setenv icache_ena 0x1; \
setenv dcache_ena 0x1; setenv core_iccm_0 0x10; \
setenv core_dccm_0 0x10; setenv non_volatile_limit 0xE; \
setenv core_iccm_1 0x6; setenv core_dccm_1 0x6; \
setenv core_iccm_2 0x10; setenv core_dccm_2 0x10; \
setenv core_iccm_3 0x6; setenv core_dccm_3 0x6;\0"
/*
* Environment configuration
*/
#define CONFIG_BOOTFILE "uImage"
#define CONFIG_LOADADDR CONFIG_SYS_LOAD_ADDR
/*
* Console configuration
*/
/*
* Misc utility configuration
*/
#define CONFIG_BOUNCE_BUFFER
/* Cli configuration */
#define CONFIG_SYS_CBSIZE SZ_2K
/*
* Callback configuration
*/
#define CONFIG_BOARD_EARLY_INIT_R
#define CONFIG_BOARD_LATE_INIT
#endif /* _CONFIG_HSDK_H_ */