
Signed-off-by: Eugeniy Paltsev Eugeniy.Paltsev@synopsys.com --- arch/arc/dts/hsdk.dts | 56 +++ board/synopsys/hsdk/MAINTAINERS | 6 +- board/synopsys/hsdk/Makefile | 4 +- board/synopsys/hsdk/clk-lib.c | 68 +++ board/synopsys/hsdk/clk-lib.h | 17 + board/synopsys/hsdk/env-lib.c | 295 ++++++++++++ board/synopsys/hsdk/env-lib.h | 51 ++ board/synopsys/hsdk/hsdk-cmd.c | 995 ++++++++++++++++++++++++++++++++++++++++ board/synopsys/hsdk/hsdk.c | 95 ---- configs/hsdk_defconfig | 15 + include/configs/hsdk.h | 38 +- 11 files changed, 1538 insertions(+), 102 deletions(-) create mode 100644 board/synopsys/hsdk/clk-lib.c create mode 100644 board/synopsys/hsdk/clk-lib.h create mode 100644 board/synopsys/hsdk/env-lib.c create mode 100644 board/synopsys/hsdk/env-lib.h create mode 100644 board/synopsys/hsdk/hsdk-cmd.c delete mode 100644 board/synopsys/hsdk/hsdk.c
diff --git a/arch/arc/dts/hsdk.dts b/arch/arc/dts/hsdk.dts index 67dfb93ca8..d9151ed646 100644 --- a/arch/arc/dts/hsdk.dts +++ b/arch/arc/dts/hsdk.dts @@ -6,6 +6,7 @@ /dts-v1/;
#include "skeleton.dtsi" +#include "dt-bindings/clock/snps,hsdk-cgu.h"
/ { #address-cells = <1>; @@ -13,6 +14,7 @@
aliases { console = &uart0; + spi0 = "/spi@f0020000"; };
cpu_card { @@ -24,6 +26,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>; @@ -53,4 +84,29 @@ compatible = "generic-ohci"; reg = <0xf0060000 0x100>; }; + + spi@f0020000 { + compatible = "snps,dw-apb-ssi"; + reg = <0xf0020000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + spi-max-frequency = <4000000>; + clocks = <&cgu_clk CLK_SYS_SPI_REF>; + clock-names = "spi_clk"; + cs-gpio = <&cs_gpio 0>; + spi_flash@0 { + compatible = "spi-flash"; + reg = <0>; + spi-max-frequency = <4000000>; + }; + }; + + cs_gpio: gpio@f00114B0 { + compatible = "snps,hsdk-creg-gpio"; + reg = <0xf00014B0 0x4>; + gpio-controller; + #gpio-cells = <1>; + gpio-bank-name = "hsdk-spi-cs"; + gpio-count = <1>; + }; }; diff --git a/board/synopsys/hsdk/MAINTAINERS b/board/synopsys/hsdk/MAINTAINERS index d034bc479d..8c02f52976 100644 --- a/board/synopsys/hsdk/MAINTAINERS +++ b/board/synopsys/hsdk/MAINTAINERS @@ -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: board/synopsys/hsdk-cmd/ F: configs/hsdk_defconfig diff --git a/board/synopsys/hsdk/Makefile b/board/synopsys/hsdk/Makefile index d84dd03265..390e429557 100644 --- a/board/synopsys/hsdk/Makefile +++ b/board/synopsys/hsdk/Makefile @@ -4,4 +4,6 @@ # SPDX-License-Identifier: GPL-2.0+ #
-obj-y += hsdk.o +obj-y += hsdk-cmd.o +obj-y += env-lib.o +obj-y += clk-lib.o diff --git a/board/synopsys/hsdk/clk-lib.c b/board/synopsys/hsdk/clk-lib.c new file mode 100644 index 0000000000..a2a9cb17f3 --- /dev/null +++ b/board/synopsys/hsdk/clk-lib.c @@ -0,0 +1,68 @@ +#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 funcs */ + 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 != NULL)) { + 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 disable, 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 != NULL)) + *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; +} diff --git a/board/synopsys/hsdk/clk-lib.h b/board/synopsys/hsdk/clk-lib.h new file mode 100644 index 0000000000..6fc4c2a21e --- /dev/null +++ b/board/synopsys/hsdk/clk-lib.h @@ -0,0 +1,17 @@ +#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 */ +}; + +int soc_clk_ctl(const char *name, ulong *rate, enum clk_ctl_ops ctl); + +#endif /* __BOARD_CLK_LIB_H */ diff --git a/board/synopsys/hsdk/env-lib.c b/board/synopsys/hsdk/env-lib.c new file mode 100644 index 0000000000..00aab0fccf --- /dev/null +++ b/board/synopsys/hsdk/env-lib.c @@ -0,0 +1,295 @@ +#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 comand[MAX_CMD_LEN]; + + for (u32 i = 0; i < NR_CPUS; i++) { + sprintf(comand, "%s_%u", map[index].env_name, i); + if (!env_get_yesno(comand)) { + if (map[index].type == ENV_HEX) { + val = (u32)env_get_hex(comand, 0); + debug("ENV: %s: = %#x\n", comand, val); + } else { + val = (u32)env_get_ulong(comand, 10, 0); + debug("ENV: %s: = %d\n", comand, 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; +} diff --git a/board/synopsys/hsdk/env-lib.h b/board/synopsys/hsdk/env-lib.h new file mode 100644 index 0000000000..cf07a4419f --- /dev/null +++ b/board/synopsys/hsdk/env-lib.h @@ -0,0 +1,51 @@ +#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 */ diff --git a/board/synopsys/hsdk/hsdk-cmd.c b/board/synopsys/hsdk/hsdk-cmd.c new file mode 100644 index 0000000000..f329a53b97 --- /dev/null +++ b/board/synopsys/hsdk/hsdk-cmd.c @@ -0,0 +1,995 @@ +#include <common.h> +#include <config.h> +#include <linux/printk.h> +#include <linux/kernel.h> +#include <linux/io.h> +#include <asm/arcregs.h> +#include <fdt_support.h> +#include <dwmmc.h> +#include <malloc.h> +#include <usb.h> + +#include "clk-lib.h" +#include "env-lib.h" + +DECLARE_GLOBAL_DATA_PTR; + +#define ALL_CPU_MASK GENMASK(NR_CPUS - 1, 0) +#define MASTER_CPU_ID 0 +#define APERTURE_SHIFT 28 +#define NO_CCM 0x10 + +#define RESET_VECTOR_ADDR 0x0 + +#define CREG_BASE (ARC_PERIPHERAL_BASE + 0x1000) +#define CREG_CPU_START (CREG_BASE + 0x400) +#define CREG_CPU_START_MASK 0xF + +#define SDIO_BASE (ARC_PERIPHERAL_BASE + 0xA000) +#define SDIO_UHS_REG_EXT (SDIO_BASE + 0x108) +#define SDIO_UHS_REG_EXT_DIV_2 (2 << 30) + +/* Uncached access macros */ +#define arc_read_uncached_32(ptr) \ +({ \ + unsigned int __ret; \ + __asm__ __volatile__( \ + " ld.di %0, [%1] \n" \ + : "=r"(__ret) \ + : "r"(ptr)); \ + __ret; \ +}) + +#define arc_write_uncached_32(ptr, data)\ +({ \ + __asm__ __volatile__( \ + " st.di %0, [%1] \n" \ + : \ + : "r"(data), "r"(ptr)); \ +}) + +struct hsdk_env_core_ctl { + u32_env entry[NR_CPUS]; + u32_env iccm[NR_CPUS]; + u32_env dccm[NR_CPUS]; +}; + +struct hsdk_env_common_ctl { + bool halt_on_boot; + u32_env core_mask; + u32_env cpu_freq; + u32_env axi_freq; + u32_env tun_freq; + u32_env nvlim; + u32_env icache; + u32_env dcache; +}; + +/* Uncached cross-cpu structure */ +struct hsdk_cross_cpu { + /* cross_cpu flags */ + u32 data_flag; + u32 stack_ptr; + s32 status[NR_CPUS]; + + /* cross_cpu data */ + u32 entry[NR_CPUS]; + u32 iccm[NR_CPUS]; + u32 dccm[NR_CPUS]; + + u32 core_mask; + u32 icache; + u32 dcache; + + u8 cache_padding[ARCH_DMA_MINALIGN]; +} __aligned(ARCH_DMA_MINALIGN); + +/* Place for slave cpu temporary stack */ +static u32 slave_stack[256 * NR_CPUS] __aligned(4); + +static struct hsdk_env_common_ctl env_common = {}; +static struct hsdk_env_core_ctl env_core = {}; +static struct hsdk_cross_cpu cross_cpu_data; + +static const struct env_map_common env_map_common[] = { + { "core_mask", ENV_HEX, true, 0x1, 0xF, &env_common.core_mask }, + { "non_volatile_limit", ENV_HEX, true, 0, 0xF, &env_common.nvlim }, + { "icache_ena", ENV_HEX, true, 0, 1, &env_common.icache }, + { "dcache_ena", ENV_HEX, true, 0, 1, &env_common.dcache }, + {} +}; + +static const struct env_map_common env_map_clock[] = { + { "cpu_freq", ENV_DEC, false, 100, 1000, &env_common.cpu_freq }, + { "axi_freq", ENV_DEC, false, 200, 800, &env_common.axi_freq }, + { "tun_freq", ENV_DEC, false, 0, 150, &env_common.tun_freq }, + {} +}; + +static const struct env_map_percpu env_map_core[] = { + { "core_iccm", ENV_HEX, true, {NO_CCM, 0, NO_CCM, 0}, {NO_CCM, 0xF, NO_CCM, 0xF}, &env_core.iccm }, + { "core_dccm", ENV_HEX, true, {NO_CCM, 0, NO_CCM, 0}, {NO_CCM, 0xF, NO_CCM, 0xF}, &env_core.dccm }, + {} +}; + +static const struct env_map_common env_map_mask[] = { + { "core_mask", ENV_HEX, false, 0x1, 0xF, &env_common.core_mask }, + {} +}; + +static const struct env_map_percpu env_map_go[] = { + { "core_entry", ENV_HEX, true, {0, 0, 0, 0}, {U32_MAX, U32_MAX, U32_MAX, U32_MAX}, &env_core.entry }, + {} +}; + +static void sync_cross_cpu_data(void) +{ + u32 value; + + for (u32 i = 0; i < NR_CPUS; i++) { + value = env_core.entry[i].val; + arc_write_uncached_32(&cross_cpu_data.entry[i], value); + } + + for (u32 i = 0; i < NR_CPUS; i++) { + value = env_core.iccm[i].val; + arc_write_uncached_32(&cross_cpu_data.iccm[i], value); + } + + for (u32 i = 0; i < NR_CPUS; i++) { + value = env_core.dccm[i].val; + arc_write_uncached_32(&cross_cpu_data.dccm[i], value); + } + + value = env_common.core_mask.val; + arc_write_uncached_32(&cross_cpu_data.core_mask, value); + + value = env_common.icache.val; + arc_write_uncached_32(&cross_cpu_data.icache, value); + + value = env_common.dcache.val; + arc_write_uncached_32(&cross_cpu_data.dcache, value); +} + +static bool is_cpu_used(u32 cpu_id) +{ + return !!(env_common.core_mask.val & BIT(cpu_id)); +} + +/* TODO: add ICCM and DCCM runtime check */ +static void smp_init_slave_cpu_func(u32 core) +{ + u32 val; + + /* ICCM move if exists */ + val = arc_read_uncached_32(&cross_cpu_data.iccm[core]); + if (val != NO_CCM) + write_aux_reg(ARC_AUX_ICCM_BASE, val << APERTURE_SHIFT); + + /* DCCM move if exists */ + val = arc_read_uncached_32(&cross_cpu_data.dccm[core]); + if (val != NO_CCM) + write_aux_reg(ARC_AUX_DCCM_BASE, val << APERTURE_SHIFT); + + if (arc_read_uncached_32(&cross_cpu_data.icache)) + icache_enable(); + else + icache_disable(); + + if (arc_read_uncached_32(&cross_cpu_data.dcache)) + dcache_enable(); + else + dcache_disable(); +} + +static void init_claster_nvlim(void) +{ + u32 val = env_common.nvlim.val << APERTURE_SHIFT; + + flush_dcache_all(); + write_aux_reg(ARC_AUX_NON_VOLATILE_LIMIT, val); + write_aux_reg(AUX_AUX_CACHE_LIMIT, val); + flush_n_invalidate_dcache_all(); +} + +static void init_master_icache(void) +{ + if (icache_status()) { + /* I$ is enabled - we need to disable it */ + if (!env_common.icache.val) + icache_disable(); + } else { + /* I$ is disabled - we need to enable it */ + if (env_common.icache.val) { + icache_enable(); + + /* invalidate I$ right after enable */ + invalidate_icache_all(); + } + } +} + +static void init_master_dcache(void) +{ + if (dcache_status()) { + /* D$ is enabled - we need to disable it */ + if (!env_common.dcache.val) + dcache_disable(); + } else { + /* D$ is disabled - we need to enable it */ + if (env_common.dcache.val) + dcache_enable(); + + /* TODO: probably we need ti invalidate D$ right after enable */ + } +} + +static int cleanup_before_go(void) +{ + disable_interrupts(); + sync_n_cleanup_cache_all(); + + return 0; +} + +void slave_cpu_set_boot_addr(u32 addr) +{ + /* All cores have reset vector pointing to 0 */ + writel(addr, (void __iomem *)RESET_VECTOR_ADDR); + + /* Make sure other cores see written value in memory */ + sync_n_cleanup_cache_all(); +} + +static inline void halt_this_cpu(void) +{ + __builtin_arc_flag(1); +} + +static void smp_kick_cpu_x(u32 cpu_id) +{ + int cmd = readl((void __iomem *)CREG_CPU_START); + + if (cpu_id > NR_CPUS) + return; + + cmd &= ~CREG_CPU_START_MASK; + cmd |= (1 << cpu_id); + writel(cmd, (void __iomem *)CREG_CPU_START); +} + +static u32 prepare_cpu_ctart_reg(void) +{ + int cmd = readl((void __iomem *)CREG_CPU_START); + + cmd &= ~CREG_CPU_START_MASK; + + return cmd | env_common.core_mask.val; +} + +/* slave CPU entry for configuration */ +__attribute__((naked, noreturn, flatten)) noinline void hsdk_core_init_f(void) +{ + __asm__ __volatile__( "ld.di r8, [%0]\n" + "mov %%sp, r8\n" + "mov %%fp, %%sp\n" + : /* no output */ + : "r" (&cross_cpu_data.stack_ptr)); + + invalidate_icache_all(); + + arc_write_uncached_32(&cross_cpu_data.status[CPU_ID_GET()], 1); + smp_init_slave_cpu_func(CPU_ID_GET()); + + arc_write_uncached_32(&cross_cpu_data.data_flag, 0x12345678); + arc_write_uncached_32(&cross_cpu_data.status[CPU_ID_GET()], 2); + + /* Halt the processor untill the master kick us again */ + halt_this_cpu(); + + __builtin_arc_nop(); + __builtin_arc_nop(); + __builtin_arc_nop(); + + arc_write_uncached_32(&cross_cpu_data.status[CPU_ID_GET()], 3); + + /* get the updated entry - invalidate i$ */ + invalidate_icache_all(); + + arc_write_uncached_32(&cross_cpu_data.status[CPU_ID_GET()], 4); + + /* Run our program */ + ((void (*)(void))(arc_read_uncached_32(&cross_cpu_data.entry[CPU_ID_GET()])))(); + + arc_write_uncached_32(&cross_cpu_data.status[CPU_ID_GET()], 5); + + /* Something went terribly wrong */ + while (true) + halt_this_cpu(); +} + +static void clear_cross_cpu_data(void) +{ + arc_write_uncached_32(&cross_cpu_data.data_flag, 0); + arc_write_uncached_32(&cross_cpu_data.stack_ptr, 0); + + for (u32 i = 0; i < NR_CPUS; i++) + arc_write_uncached_32(&cross_cpu_data.status[i], 0); +} + +noinline static void do_init_slave_cpu(u32 cpu_id) +{ + u32 timeout = 100; + /* TODO: optimize memory usage, now we have one unused aperture */ + u32 stack_ptr = (u32)(slave_stack + (64 * cpu_id)); + + if (cpu_id >= NR_CPUS) + return; + + arc_write_uncached_32(&cross_cpu_data.data_flag, 0); + + /* Use global unic place for slave cpu stack */ + arc_write_uncached_32(&cross_cpu_data.stack_ptr, stack_ptr); + + debug("CPU %u: stack pool base: %p\n", cpu_id, slave_stack); + debug("CPU %u: current slave stack base: %x\n", cpu_id, stack_ptr); + slave_cpu_set_boot_addr((u32)hsdk_core_init_f); + + smp_kick_cpu_x(cpu_id); + + debug("CPU %u: cross-cpu flag: %x [before timeout]\n", cpu_id, + arc_read_uncached_32(&cross_cpu_data.data_flag)); + + while (!arc_read_uncached_32(&cross_cpu_data.data_flag) && timeout--) + mdelay(10); + + /* Just to be sure that slave cpu is halted after it set data_flag */ + mdelay(20); + + /* + * We need to panic here as there is no option to halt slave cpu + * (or check that slave cpu is halted) + */ + if (!timeout) + pr_err("CPU %u is not responding after init!\n", cpu_id); + + /* Check current stage of slave cpu */ + if (arc_read_uncached_32(&cross_cpu_data.status[cpu_id]) != 2) + pr_err("CPU %u status is unexpected: %d\n", cpu_id, + arc_read_uncached_32(&cross_cpu_data.status[cpu_id])); + + debug("CPU %u: cross-cpu flag: %x [after timeout]\n", cpu_id, + arc_read_uncached_32(&cross_cpu_data.data_flag)); + debug("CPU %u: status: %d [after timeout]\n", cpu_id, + arc_read_uncached_32(&cross_cpu_data.status[cpu_id])); +} + +static void do_init_slave_cpus(void) +{ + clear_cross_cpu_data(); + sync_cross_cpu_data(); + + debug("cross_cpu_data location: %#x\n", (u32)&cross_cpu_data); + + for (u32 i = MASTER_CPU_ID + 1; i < NR_CPUS; i++) + if (is_cpu_used(i)) + do_init_slave_cpu(i); +} + +static void do_init_master_cpu(void) +{ + /* + * Setup master caches even if master isn't used as we want to use + * same cache configuration on all running CPUs + */ + init_master_icache(); + init_master_dcache(); +} + +enum hsdk_axi_masters { + M_HS_CORE = 0, + M_HS_RTT, + M_AXI_TUN, + M_HDMI_VIDEO, + M_HDMI_AUDIO, + M_USB_HOST, + M_ETHERNET, + M_SDIO, + M_GPU, + M_DMAC_0, + M_DMAC_1, + M_DVFS +}; + +#define UPDATE_VAL 1 + +/* + * m master AXI_M_m_SLV0 AXI_M_m_SLV1 AXI_M_m_OFFSET0 AXI_M_m_OFFSET1 + * 0 HS (CBU) 0x11111111 0x63111111 0xFEDCBA98 0x0E543210 + * 1 HS (RTT) 0x77777777 0x77777777 0xFEDCBA98 0x76543210 + * 2 AXI Tunnel 0x88888888 0x88888888 0xFEDCBA98 0x76543210 + * 3 HDMI-VIDEO 0x77777777 0x77777777 0xFEDCBA98 0x76543210 + * 4 HDMI-ADUIO 0x77777777 0x77777777 0xFEDCBA98 0x76543210 + * 5 USB-HOST 0x77777777 0x77999999 0xFEDCBA98 0x76DCBA98 + * 6 ETHERNET 0x77777777 0x77999999 0xFEDCBA98 0x76DCBA98 + * 7 SDIO 0x77777777 0x77999999 0xFEDCBA98 0x76DCBA98 + * 8 GPU 0x77777777 0x77777777 0xFEDCBA98 0x76543210 + * 9 DMAC (port #1) 0x77777777 0x77777777 0xFEDCBA98 0x76543210 + * 10 DMAC (port #2) 0x77777777 0x77777777 0xFEDCBA98 0x76543210 + * 11 DVFS 0x00000000 0x60000000 0x00000000 0x00000000 + */ + +#define CREG_AXI_M_SLV0(m) ((void __iomem *)(CREG_BASE + 0x020 * (m))) +#define CREG_AXI_M_SLV1(m) ((void __iomem *)(CREG_BASE + 0x020 * (m) + 0x004)) +#define CREG_AXI_M_OFT0(m) ((void __iomem *)(CREG_BASE + 0x020 * (m) + 0x008)) +#define CREG_AXI_M_OFT1(m) ((void __iomem *)(CREG_BASE + 0x020 * (m) + 0x00C)) +#define CREG_AXI_M_UPDT(m) ((void __iomem *)(CREG_BASE + 0x020 * (m) + 0x014)) + +#define CREG_AXI_M_HS_CORE_BOOT ((void __iomem *)(CREG_BASE + 0x010)) + +#define CREG_PAE ((void __iomem *)(CREG_BASE + 0x180)) +#define CREG_PAE_UPDT ((void __iomem *)(CREG_BASE + 0x194)) + +void init_memory_bridge(void) +{ + u32 reg; + + /* + * M_HS_CORE has one unic register - BOOT. + * We need to clean boot mirror (BOOT[1:0]) bits in them. + */ + reg = readl(CREG_AXI_M_HS_CORE_BOOT) & (~0x3); + writel(reg, CREG_AXI_M_HS_CORE_BOOT); + writel(0x11111111, CREG_AXI_M_SLV0(M_HS_CORE)); + writel(0x63111111, CREG_AXI_M_SLV1(M_HS_CORE)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HS_CORE)); + writel(0x0E543210, CREG_AXI_M_OFT1(M_HS_CORE)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HS_CORE)); + + writel(0x77777777, CREG_AXI_M_SLV0(M_HS_RTT)); + writel(0x77777777, CREG_AXI_M_SLV1(M_HS_RTT)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HS_RTT)); + writel(0x76543210, CREG_AXI_M_OFT1(M_HS_RTT)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HS_RTT)); + + writel(0x88888888, CREG_AXI_M_SLV0(M_AXI_TUN)); + writel(0x88888888, CREG_AXI_M_SLV1(M_AXI_TUN)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_AXI_TUN)); + writel(0x76543210, CREG_AXI_M_OFT1(M_AXI_TUN)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_AXI_TUN)); + + writel(0x77777777, CREG_AXI_M_SLV0(M_HDMI_VIDEO)); + writel(0x77777777, CREG_AXI_M_SLV1(M_HDMI_VIDEO)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HDMI_VIDEO)); + writel(0x76543210, CREG_AXI_M_OFT1(M_HDMI_VIDEO)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HDMI_VIDEO)); + + writel(0x77777777, CREG_AXI_M_SLV0(M_HDMI_AUDIO)); + writel(0x77777777, CREG_AXI_M_SLV1(M_HDMI_AUDIO)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HDMI_AUDIO)); + writel(0x76543210, CREG_AXI_M_OFT1(M_HDMI_AUDIO)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HDMI_AUDIO)); + + writel(0x77777777, CREG_AXI_M_SLV0(M_USB_HOST)); + writel(0x77999999, CREG_AXI_M_SLV1(M_USB_HOST)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_USB_HOST)); + writel(0x76DCBA98, CREG_AXI_M_OFT1(M_USB_HOST)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_USB_HOST)); + + writel(0x77777777, CREG_AXI_M_SLV0(M_ETHERNET)); + writel(0x77999999, CREG_AXI_M_SLV1(M_ETHERNET)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_ETHERNET)); + writel(0x76DCBA98, CREG_AXI_M_OFT1(M_ETHERNET)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_ETHERNET)); + + writel(0x77777777, CREG_AXI_M_SLV0(M_SDIO)); + writel(0x77999999, CREG_AXI_M_SLV1(M_SDIO)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_SDIO)); + writel(0x76DCBA98, CREG_AXI_M_OFT1(M_SDIO)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_SDIO)); + + writel(0x77777777, CREG_AXI_M_SLV0(M_GPU)); + writel(0x77777777, CREG_AXI_M_SLV1(M_GPU)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_GPU)); + writel(0x76543210, CREG_AXI_M_OFT1(M_GPU)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_GPU)); + + writel(0x77777777, CREG_AXI_M_SLV0(M_DMAC_0)); + writel(0x77777777, CREG_AXI_M_SLV1(M_DMAC_0)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_DMAC_0)); + writel(0x76543210, CREG_AXI_M_OFT1(M_DMAC_0)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DMAC_0)); + + writel(0x77777777, CREG_AXI_M_SLV0(M_DMAC_1)); + writel(0x77777777, CREG_AXI_M_SLV1(M_DMAC_1)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_DMAC_1)); + writel(0x76543210, CREG_AXI_M_OFT1(M_DMAC_1)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DMAC_1)); + + writel(0x00000000, CREG_AXI_M_SLV0(M_DVFS)); + writel(0x60000000, CREG_AXI_M_SLV1(M_DVFS)); + writel(0x00000000, CREG_AXI_M_OFT0(M_DVFS)); + writel(0x00000000, CREG_AXI_M_OFT1(M_DVFS)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DVFS)); + + writel(0x00000000, CREG_PAE); + writel(UPDATE_VAL, CREG_PAE_UPDT); +} + +static void setup_clocks(void) +{ + ulong rate; + + /* Setup CPU clock */ + if (env_common.cpu_freq.set) { + rate = env_common.cpu_freq.val; + soc_clk_ctl("cpu-clk", &rate, CLK_ON | CLK_SET | CLK_MHZ); + } + + /* Setup TUN clock */ + if (env_common.tun_freq.set) { + rate = env_common.tun_freq.val; + if (rate) + soc_clk_ctl("tun-clk", &rate, CLK_ON | CLK_SET | CLK_MHZ); + else + soc_clk_ctl("tun-clk", NULL, CLK_OFF); + } + + if (env_common.axi_freq.set) { + rate = env_common.axi_freq.val; + soc_clk_ctl("axi-clk", &rate, CLK_SET | CLK_ON | CLK_MHZ); + } +} + +static void do_init_claster(void) +{ + /* + * A multi-core ARC HS configuration always includes only one + * ARC_AUX_NON_VOLATILE_LIMIT register, which is shared by all the + * cores. + */ + init_claster_nvlim(); +} + +static int check_master_cpu_id(void) +{ + if (CPU_ID_GET() == MASTER_CPU_ID) + return 0; + + pr_err("u-boot runs on non-master cpu with id: %lu\n", CPU_ID_GET()); + + return -ENOENT; +} + +noinline static int prepare_cpus(void) +{ + int ret; + + ret = check_master_cpu_id(); + if (ret) + return ret; + + ret = envs_process_and_validate(env_map_common, env_map_core, is_cpu_used); + if (ret) + return ret; + + printf("CPU start mask is %#x\n", env_common.core_mask.val); + + __builtin_arc_nop(); + __builtin_arc_nop(); + + do_init_slave_cpus(); + + do_init_master_cpu(); + + do_init_claster(); + + return 0; +} + +static int hsdk_go_run(u32 cpu_start_reg) +{ + /* Cleanup caches, disable interrupts */ + cleanup_before_go(); + + if (env_common.halt_on_boot) + halt_this_cpu(); + + __builtin_arc_nop(); + __builtin_arc_nop(); + __builtin_arc_nop(); + + /* Kick chosen slave CPUs */ + writel(cpu_start_reg, (void __iomem *)CREG_CPU_START); + + if (is_cpu_used(MASTER_CPU_ID)) + ((void (*)(void))(env_core.entry[MASTER_CPU_ID].val))(); + else + halt_this_cpu(); + + pr_err("u-boot still runs on cpu [%ld]\n", CPU_ID_GET()); + + /* We will never return after executing our program if master cpu used + * otherwise halt master cpu manually */ + while (true) + halt_this_cpu(); + + return 0; +} + +int board_prep_linux(bootm_headers_t *images) +{ + int ret, ofst; + char mask[15]; + + ret = envs_read_validate_common(env_map_mask); + if (ret) + return ret; + + /* Rollback to default values */ + if (!env_common.core_mask.set) { + env_common.core_mask.val = ALL_CPU_MASK; + env_common.core_mask.set = true; + } + + printf("CPU start mask is %#x\n", env_common.core_mask.val); + + if (!is_cpu_used(MASTER_CPU_ID)) + pr_err("ERR: try to launch linux with CPU[0] disabled! It doesn't work for ARC.\n"); + + /* If we want to launch linux on all CPUs we don't need to patch + * linux DTB as it is default configuration */ + if (env_common.core_mask.val == ALL_CPU_MASK) + return 0; + + if (!IMAGE_ENABLE_OF_LIBFDT || !images->ft_len) { + pr_err("WARN: core_mask setup will work properly only with external DTB!\n"); + return 0; + } + + /* patch '/possible-cpus' property according to cpu mask */ + ofst = fdt_path_offset(images->ft_addr, "/"); + sprintf(mask, "%s%s%s%s", + is_cpu_used(0) ? "0," : "", + is_cpu_used(1) ? "1," : "", + is_cpu_used(2) ? "2," : "", + is_cpu_used(3) ? "3," : ""); + ret = fdt_setprop_string(images->ft_addr, ofst, "possible-cpus", mask); + /* + * If we failed to patch '/possible-cpus' property we don't need break + * linux loading process: kernel will handle it but linux will print + * warning like "Timeout: CPU1 FAILED to comeup !!!". + * So warn here about error, but return 0 like no error had occurred. + */ + if (ret) + pr_err("WARN: failed to patch '/possible-cpus' property, ret=%d\n", + ret); + + return 0; +} + +void board_jump_and_run(ulong entry, int zero, int arch, uint params) +{ + void (*kernel_entry)(int zero, int arch, uint params); + u32 cpu_start_reg; + + kernel_entry = (void (*)(int, int, uint))entry; + + /* Prepare CREG_CPU_START for kicking chosen CPUs */ + cpu_start_reg = prepare_cpu_ctart_reg(); + + /* In case of run without hsdk_init */ + slave_cpu_set_boot_addr(entry); + + /* In case of run with hsdk_init */ + for (u32 i = 0; i < NR_CPUS; i++) { + env_core.entry[i].val = entry; + env_core.entry[i].set = true; + } + /* sync cross_cpu struct as we updated core-entry variables */ + sync_cross_cpu_data(); + + /* Kick chosen slave CPUs */ + writel(cpu_start_reg, (void __iomem *)CREG_CPU_START); + + if (is_cpu_used(0)) + kernel_entry(zero, arch, params); +} + +static int hsdk_go_prepare_and_run(void) +{ + /* Prepare CREG_CPU_START for kicking chosen CPUs */ + u32 reg = prepare_cpu_ctart_reg(); + + if (env_common.halt_on_boot) + printf("CPU will halt before application start, start application with debugger.\n"); + + return hsdk_go_run(reg); +} + +static int do_hsdk_go(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + int ret; + + /* Check for 'halt' parameter. 'halt' = enter halt-mode just before + * starting the application; can be used for debug */ + if (argc > 1) { + env_common.halt_on_boot = !strcmp(argv[1], "halt"); + if (!env_common.halt_on_boot) { + pr_err("Unrecognised parameter: '%s'\n", argv[1]); + return CMD_RET_FAILURE; + } + } + + ret = check_master_cpu_id(); + if (ret) + return ret; + + ret = envs_process_and_validate(env_map_mask, env_map_go, is_cpu_used); + if (ret) + return ret; + + /* sync cross_cpu struct as we updated core-entry variables */ + sync_cross_cpu_data(); + + ret = hsdk_go_prepare_and_run(); + + return ret ? CMD_RET_FAILURE : CMD_RET_SUCCESS; +} + +U_BOOT_CMD( + hsdk_go, 3, 0, do_hsdk_go, + "Synopsys HSDK specific command", + " - Boot stand-alone application on HSDK\n" + "hsdk_go halt - Boot stand-alone application on HSDK, halt CPU just before application run\n" +); + +static int do_hsdk_init(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + static bool done = false; + int ret; + + /* hsdk_init can be run only once */ + if (done) { + printf("HSDK HW is already initialized! Please reset the board if you want to change the configuration.\n"); + return CMD_RET_FAILURE; + } + + ret = prepare_cpus(); + if (!ret) + done = true; + + return ret ? CMD_RET_FAILURE : CMD_RET_SUCCESS; +} + +U_BOOT_CMD( + hsdk_init, 1, 0, do_hsdk_init, + "Synopsys HSDK specific command", + "- Init HSDK HW\n" +); + +static int do_hsdk_clock_set(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + int ret = 0; + + /* Strip off leading subcommand argument */ + argc--; + argv++; + + envs_cleanup_common(env_map_clock); + + if (!argc) { + printf("Set clocks to values specified in environment\n"); + ret = envs_read_common(env_map_clock); + } else { + printf("Set clocks to values specified in args\n"); + ret = args_envs_enumerate(env_map_clock, 2, argc, argv); + } + + if (ret) + return CMD_RET_FAILURE; + + ret = envs_validate_common(env_map_clock); + if (ret) + return CMD_RET_FAILURE; + + /* Setup clock tree HW */ + setup_clocks(); + + return CMD_RET_SUCCESS; +} + +static int do_hsdk_clock_get(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + ulong rate; + + if (soc_clk_ctl("cpu-clk", &rate, CLK_GET | CLK_MHZ)) + return CMD_RET_FAILURE; + + if (env_set_ulong("cpu_freq", rate)) + return CMD_RET_FAILURE; + + if (soc_clk_ctl("tun-clk", &rate, CLK_GET | CLK_MHZ)) + return CMD_RET_FAILURE; + + if (env_set_ulong("tun_freq", rate)) + return CMD_RET_FAILURE; + + if (soc_clk_ctl("axi-clk", &rate, CLK_GET | CLK_MHZ)) + return CMD_RET_FAILURE; + + if (env_set_ulong("axi_freq", rate)) + return CMD_RET_FAILURE; + + printf("Clock values are saved to environment\n"); + + return CMD_RET_SUCCESS; +} + +static int do_hsdk_clock_print(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + /* Main clocks */ + soc_clk_ctl("cpu-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("tun-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("axi-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("ddr-clk", NULL, CLK_PRINT | CLK_MHZ); + + return CMD_RET_SUCCESS; +} + +static int do_hsdk_clock_print_all(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + /* CPU clock domain */ + soc_clk_ctl("cpu-pll", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("cpu-clk", NULL, CLK_PRINT | CLK_MHZ); + printf("\n"); + + /* SYS clock domain */ + soc_clk_ctl("sys-pll", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("apb-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("axi-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("eth-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("usb-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("sdio-clk", NULL, CLK_PRINT | CLK_MHZ); +/* soc_clk_ctl("hdmi-sys-clk", NULL, CLK_PRINT | CLK_MHZ); */ + soc_clk_ctl("gfx-core-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("gfx-dma-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("gfx-cfg-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("dmac-core-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("dmac-cfg-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("sdio-ref-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("spi-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("i2c-clk", NULL, CLK_PRINT | CLK_MHZ); +/* soc_clk_ctl("ebi-clk", NULL, CLK_PRINT | CLK_MHZ); */ + soc_clk_ctl("uart-clk", NULL, CLK_PRINT | CLK_MHZ); + printf("\n"); + + /* DDR clock domain */ + soc_clk_ctl("ddr-clk", NULL, CLK_PRINT | CLK_MHZ); + printf("\n"); + + /* HDMI clock domain */ +/* soc_clk_ctl("hdmi-pll", NULL, CLK_PRINT | CLK_MHZ); */ +/* soc_clk_ctl("hdmi-clk", NULL, CLK_PRINT | CLK_MHZ); */ +/* printf("\n"); */ + + /* TUN clock domain */ + soc_clk_ctl("tun-pll", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("tun-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("rom-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("pwm-clk", NULL, CLK_PRINT | CLK_MHZ); + printf("\n"); + + return CMD_RET_SUCCESS; +} + +cmd_tbl_t cmd_hsdk_clock[] = { + U_BOOT_CMD_MKENT(set, 3, 0, do_hsdk_clock_set, "", ""), + U_BOOT_CMD_MKENT(get, 3, 0, do_hsdk_clock_get, "", ""), + U_BOOT_CMD_MKENT(print, 4, 0, do_hsdk_clock_print, "", ""), + U_BOOT_CMD_MKENT(print_all, 4, 0, do_hsdk_clock_print_all, "", ""), +}; + +static int do_hsdk_clock(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + cmd_tbl_t *c; + + if (argc < 2) + return CMD_RET_USAGE; + + /* Strip off leading 'hsdk_clock' command argument */ + argc--; + argv++; + + c = find_cmd_tbl(argv[0], cmd_hsdk_clock, ARRAY_SIZE(cmd_hsdk_clock)); + if (!c) + return CMD_RET_USAGE; + + return c->cmd(cmdtp, flag, argc, argv); +} + +U_BOOT_CMD( + hsdk_clock, CONFIG_SYS_MAXARGS, 0, do_hsdk_clock, + "Synopsys HSDK specific clock command", + "set - Set clock to values specified in environment / command line arguments\n" + "hsdk_clock get - Save clock values to environment\n" + "hsdk_clock print - Print main clock values to console\n" + "hsdk_clock print_all - Print all clock values to console\n" +); + + +/* init calls */ +int board_early_init_f(void) +{ + /* Setup AXI apertures unconditionally as we want to have DDR + * in 0x00000000 region when we are kicking slave cpus */ + init_memory_bridge(); + + return 0; +} + +int board_early_init_r(void) +{ + /* + * TODO: Init USB here to be able read environment from USB MSD. + * It can be done with usb_init() call. We can't do it right now + * due to brocken USB IP SW reset and lack of USB IP HW reset in + * linux kernel (if we init USB here we will break USB in linux) + */ + + /* + * Flush all d$ as we want to use uncached area with st.di / ld.di + * instructions and we don't want to have any dirty line in L1d$ or SL$ + * in this area. It is enough to flush all d$ once here as we access to + * uncached area with regular st (non .di) instruction only when we copy + * data during u-boot relocation. + */ + flush_dcache_all(); + + printf("Relocation Offset is: %08lx\n", gd->reloc_off); + + return 0; +} + +int board_late_init(void) +{ + /* + * Populate environment with clock frequency values - + * run hsdk_clock get callback without uboot command run. + */ + do_hsdk_clock_get(NULL, 0, 0, NULL); + + return 0; +} + +int board_mmc_init(bd_t *bis) +{ + struct dwmci_host *host = NULL; + + host = malloc(sizeof(struct dwmci_host)); + if (!host) { + printf("dwmci_host malloc fail!\n"); + return 1; + } + + /* + * Switch SDIO external ciu clock divider from default div-by-8 to + * minimum possible div-by-2. + */ + writel(SDIO_UHS_REG_EXT_DIV_2, (void __iomem *) SDIO_UHS_REG_EXT); + + memset(host, 0, sizeof(struct dwmci_host)); + host->name = "Synopsys Mobile storage"; + host->ioaddr = (void *)ARC_DWMMC_BASE; + host->buswidth = 4; + host->dev_index = 0; + host->bus_hz = 50000000; + + add_dwmci(host, host->bus_hz / 2, 400000); + + return 0; +} diff --git a/board/synopsys/hsdk/hsdk.c b/board/synopsys/hsdk/hsdk.c deleted file mode 100644 index 5b3a063b69..0000000000 --- a/board/synopsys/hsdk/hsdk.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2017 Synopsys, Inc. All rights reserved. - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <dwmmc.h> -#include <malloc.h> - -DECLARE_GLOBAL_DATA_PTR; - -#define CREG_BASE (ARC_PERIPHERAL_BASE + 0x1000) -#define CREG_PAE (CREG_BASE + 0x180) -#define CREG_PAE_UPDATE (CREG_BASE + 0x194) -#define CREG_CPU_START (CREG_BASE + 0x400) - -int board_early_init_f(void) -{ - /* In current chip PAE support for DMA is broken, disabling it. */ - writel(0, (void __iomem *) CREG_PAE); - - /* Really apply settings made above */ - writel(1, (void __iomem *) CREG_PAE_UPDATE); - - return 0; -} - -#define SDIO_BASE (ARC_PERIPHERAL_BASE + 0xA000) -#define SDIO_UHS_REG_EXT (SDIO_BASE + 0x108) -#define SDIO_UHS_REG_EXT_DIV_2 (2 << 30) - -int board_mmc_init(bd_t *bis) -{ - struct dwmci_host *host = NULL; - - host = malloc(sizeof(struct dwmci_host)); - if (!host) { - printf("dwmci_host malloc fail!\n"); - return 1; - } - - /* - * Switch SDIO external ciu clock divider from default div-by-8 to - * minimum possible div-by-2. - */ - writel(SDIO_UHS_REG_EXT_DIV_2, (void __iomem *) SDIO_UHS_REG_EXT); - - memset(host, 0, sizeof(struct dwmci_host)); - host->name = "Synopsys Mobile storage"; - host->ioaddr = (void *)ARC_DWMMC_BASE; - host->buswidth = 4; - host->dev_index = 0; - host->bus_hz = 50000000; - - add_dwmci(host, host->bus_hz / 2, 400000); - - return 0; -} - -void board_jump_and_run(ulong entry, int zero, int arch, uint params) -{ - void (*kernel_entry)(int zero, int arch, uint params); - - kernel_entry = (void (*)(int, int, uint))entry; - - smp_set_core_boot_addr(entry, -1); - smp_kick_all_cpus(); - kernel_entry(zero, arch, params); -} - -#define RESET_VECTOR_ADDR 0x0 - -void smp_set_core_boot_addr(unsigned long addr, int corenr) -{ - /* All cores have reset vector pointing to 0 */ - writel(addr, (void __iomem *)RESET_VECTOR_ADDR); - - /* Make sure other cores see written value in memory */ - flush_dcache_all(); -} - -void smp_kick_all_cpus(void) -{ -#define BITS_START_CORE1 1 -#define BITS_START_CORE2 2 -#define BITS_START_CORE3 3 - - int cmd = readl((void __iomem *)CREG_CPU_START); - - cmd |= (1 << BITS_START_CORE1) | - (1 << BITS_START_CORE2) | - (1 << BITS_START_CORE3); - writel(cmd, (void __iomem *)CREG_CPU_START); -} diff --git a/configs/hsdk_defconfig b/configs/hsdk_defconfig index 11cb7e03a6..a70bf9d8a1 100644 --- a/configs/hsdk_defconfig +++ b/configs/hsdk_defconfig @@ -6,14 +6,21 @@ CONFIG_SYS_CLK_FREQ=1000000000 CONFIG_DEFAULT_DEVICE_TREE="hsdk" CONFIG_USE_BOOTARGS=y CONFIG_BOOTARGS="console=ttyS0,115200n8" +CONFIG_DISPLAY_BOARDINFO=y 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_GPIO=y CONFIG_CMD_MMC=y +CONFIG_CMD_SF=y +CONFIG_CMD_SPI=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,12 +32,20 @@ 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_DM_GPIO=y +CONFIG_HSDK_CREG_GPIO=y CONFIG_MMC=y CONFIG_MMC_DW=y +CONFIG_DM_SPI_FLASH=y +CONFIG_SPI_FLASH=y +CONFIG_SPI_FLASH_SST=y CONFIG_DM_ETH=y CONFIG_ETH_DESIGNWARE=y CONFIG_DM_SERIAL=y CONFIG_SYS_NS16550=y +CONFIG_DM_SPI=y +CONFIG_DESIGNWARE_SPI=y CONFIG_USB=y CONFIG_DM_USB=y CONFIG_USB_EHCI_HCD=y diff --git a/include/configs/hsdk.h b/include/configs/hsdk.h index fb4829ab46..a280ce0057 100644 --- a/include/configs/hsdk.h +++ b/include/configs/hsdk.h @@ -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) @@ -60,6 +61,32 @@ * Environment settings */ #define CONFIG_ENV_SIZE SZ_16K +/* Last 64K block is for env */ +#define CONFIG_ENV_OFFSET (SZ_64K * 16) +/* 64K block */ +#define CONFIG_ENV_SECT_SIZE SZ_64K + +#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 @@ -68,12 +95,17 @@ #define CONFIG_LOADADDR CONFIG_SYS_LOAD_ADDR
/* - * Console configuration + * Misc utility configuration */ +#define CONFIG_BOUNCE_BUFFER + +/* Cli configuration */ +#define CONFIG_SYS_CBSIZE 2048
/* - * Misc utility configuration + * Callback configuration */ -#define CONFIG_BOUNCE_BUFFER +#define CONFIG_BOARD_EARLY_INIT_R +#define CONFIG_BOARD_LATE_INIT
#endif /* _CONFIG_HSDK_H_ */