More ARC changes and fixes for v2018.05 * Update of ARC tools to the most recent arc-2017.09 * Fix for compile-time warning for AXS10x * Add support of platform-specific commands for HSDK * Add support for on-board SPI flash on HSDK Note though that for write support another series [1] is required. I hope that Jagan will be able to review and act on SPI flash improvement series before we get beyond RC1. Also note that to get clean build for HSDK we need to disable stack-usage check [2] as our current GCC erroneously tries to calculate stack-usage on a naked function which leads to warning. [1] https://patchwork.ozlabs.org/project/uboot/list/?series=35796 [2] https://patchwork.ozlabs.org/patch/894139/master
commit
e63d142f6f
@ -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 |
||||
|
@ -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; |
||||
} |
@ -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 */ |
@ -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; |
||||
} |
@ -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
Loading…
Reference in new issue