diff --git a/board/synopsys/hsdk/genimage.cfg b/board/synopsys/hsdk/genimage.cfg index 8928f704a2b..9aefd7ae649 100644 --- a/board/synopsys/hsdk/genimage.cfg +++ b/board/synopsys/hsdk/genimage.cfg @@ -2,7 +2,10 @@ image boot.vfat { vfat { files = { "uboot.env", - "uImage" + "uImage", + "u-boot", + "u-boot.head", + "hsdk.dtb" } } size = 100M diff --git a/board/synopsys/hsdk/headerise.py b/board/synopsys/hsdk/headerise.py new file mode 100755 index 00000000000..a71797505ea --- /dev/null +++ b/board/synopsys/hsdk/headerise.py @@ -0,0 +1,125 @@ +import os, getopt, sys, zlib +#we can use binascii instead of zlib + +def usage(exit_code): + print("usage:") + print(sys.argv[0] + " --arc-id 0x52 --image u-boot.bin --elf u-boot") + sys.exit(exit_code) + +def main(): + try: + opts, args = getopt.getopt(sys.argv[1:], + "ha:i:l:e:", ["help", "arc-id=", "image=", "elf=", "env="]) + except getopt.GetoptError as err: + print(err) + usage(2) + + # default filenames + uboot_bin_filename = "u-boot.bin" + uboot_elf_filename = "u-boot" + headerised_filename = "u-boot.head" + uboot_default_env = "u-boot-env.txt" + uboot_patched_env = "u-boot-p-env.txt" + + # initial header values + arc_id = 0x52 + uboot_img_size = 0x0497fc + check_sum = 0x61 + image_copy_adr = 0x81000000 + magic1 = 0xdeadbeafaf # big endian byte order + jump_address = 0x81000000 + flash_address = 0x0 + flash_type = 0x0 # 0 - SPI flash, 1 - NOR flash + magic2 = [ # big endian byte order + 0x20202a2020202020202020202a20202020207c5c2e20202020202e2f7c20202020207c2d, + 0x2e5c2020202f2e2d7c20202020205c2020602d2d2d6020202f20202020202f205f202020, + 0x205f20205c20202020207c205f60712070205f207c2020202020272e5f3d2f205c3d5f2e, + 0x272020202020202020605c202f60202020202020202020202020206f2020202020202020] + + for opt, arg in opts: + if opt in ('-h', "--help"): usage(0) + if opt in ('-a', "--arc-id"): arc_id = int(arg, 16) + if opt in ('-i', "--image"): uboot_bin_filename = arg + if opt in ('-l', "--elf"): uboot_elf_filename = arg + if opt in ('-e', "--env"): uboot_default_env = arg + + # verify args: + if arc_id not in [0x52, 0x53]: + print("unknown ARC ID: " + hex(arc_id)) + sys.exit(2) + + if not os.path.isfile(uboot_bin_filename): + print("uboot bin file not exists: " + uboot_bin_filename) + sys.exit(2) + + if not os.path.isfile(uboot_default_env): + print("uboot defaul environment file not exists: " + uboot_default_env) + sys.exit(2) + + uboot_img_size = os.path.getsize(uboot_bin_filename) + + # Calculate u-boot image check_sum: it is sum of all u-boot binary bytes + with open(uboot_bin_filename, "rb") as file: + ba = bytearray(file.read()) + check_sum = sum(ba) & 0xFF + + # write header to file + with open(headerised_filename, "wb") as file: + file.write(arc_id.to_bytes(2, byteorder='little')) + file.write(uboot_img_size.to_bytes(4, byteorder='little')) + file.write(check_sum.to_bytes(1, byteorder='little')) + file.write(image_copy_adr.to_bytes(4, byteorder='little')) + file.write(magic1.to_bytes(5, byteorder='big')) + file.write(jump_address.to_bytes(4, byteorder='little')) + for i in range(12): file.write(0xFF.to_bytes(1, byteorder='little')) + for byte in magic2: file.write(byte.to_bytes(36, byteorder='big')) + for i in range(208 - len(magic2) * 36): + file.write(0xFF.to_bytes(1, byteorder='little')) + file.write(flash_address.to_bytes(4, byteorder='little')) + for i in range(11): file.write(0xFF.to_bytes(1, byteorder='little')) + file.write(flash_type.to_bytes(1, byteorder='little')) + + # append u-boot image to header + with open(headerised_filename, "ab") as fo: + with open(uboot_bin_filename,'rb') as fi: + fo.write(fi.read()) + + # calc u-boot headerised image CRC32 (will be used by uboot update + # command for check) + headerised_image_crc = "" + with open(headerised_filename, "rb") as fi: + headerised_image_crc = hex(zlib.crc32(fi.read()) & 0xffffffff) + print("image CRC32 = " + headerised_image_crc) + + load_addr = 0x81000000 + load_size = os.path.getsize(headerised_filename) + +# print("crc32 " + hex(load_addr) + " " + hex (load_size)) + + # make errase size to be allighned by 64K + if load_size & 0xFFFF == 0: + errase_size = load_size + else: + errase_size = load_size - (load_size & 0xFFFF) + 0x10000 + + # u-bood CMD to load u-bood with header to SPI flash + sf_load_image_cmd = \ + "fatload mmc 0:1 " + hex(load_addr) + " " + headerised_filename + " && " + \ + "sf probe 0:0 && " + \ + "sf protect unlock 0x0 " + hex(errase_size) + " && " + \ + "sf erase 0x0 " + hex(errase_size) + " && " + \ + "sf write " + hex(load_addr) + " 0x0 " + hex(errase_size) + " && " + \ + "sf protect lock 0x0 " + hex(errase_size) + + update_uboot_cmd = "update_uboot=" + \ + sf_load_image_cmd + " && echo \"u-boot update: OK\"" + + # append default environment with update commands + with open(uboot_default_env, "rb") as fi: + with open(uboot_patched_env, 'wb') as fo: + fo.write(fi.read()) + fo.write(update_uboot_cmd.encode('ascii')) + + +if __name__ == "__main__": + main() diff --git a/board/synopsys/hsdk/linux-patches/0001-ARC-setup-cpu-possible-mask-according-to-status-fiel.patch b/board/synopsys/hsdk/linux-patches/0001-ARC-setup-cpu-possible-mask-according-to-status-fiel.patch new file mode 100644 index 00000000000..35fe45b6ae3 --- /dev/null +++ b/board/synopsys/hsdk/linux-patches/0001-ARC-setup-cpu-possible-mask-according-to-status-fiel.patch @@ -0,0 +1,115 @@ +From 69175409cd952276c93653891da77fdb34aebc5e Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Fri, 22 Dec 2017 20:17:20 +0300 +Subject: [RFC] ARC: setup cpu possible mask according to status field in dts + +As we have option in u-boot to set CPU mask for running linux, +we want to pass information to kernel about CPU cores should +be brought up. + +So we patch kernel dtb in u-boot to set CPUs status. + +On linux boot we setup cpu possible mask according to status +field in each cpu node. It is generic method according to ePAPR: + status - a standard property describing the state of a CPU. + This property shall be present for nodes representing CPUs in a + symmetric multiprocessing (SMP) configuration. For a CPU node + the meaning of the "okay" and "disabled" values are as follows: + "okay" - The CPU is running; "disabled" - The CPU is in a + quiescent state." + +Also we setup MCIP debug mask according cpu possible mask. + +Signed-off-by: Eugeniy Paltsev +--- + arch/arc/kernel/mcip.c | 10 ++++++++-- + arch/arc/kernel/smp.c | 30 ++++++++++++++++++++++++++---- + 2 files changed, 34 insertions(+), 6 deletions(-) + +diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c +index f61a52b..246481d 100644 +--- a/arch/arc/kernel/mcip.c ++++ b/arch/arc/kernel/mcip.c +@@ -89,6 +89,8 @@ static void mcip_ipi_clear(int irq) + static void mcip_probe_n_setup(void) + { + struct mcip_bcr mp; ++ u32 mcip_mask = 0; ++ int i; + + READ_BCR(ARC_REG_MCIP_BCR, mp); + +@@ -102,9 +104,13 @@ static void mcip_probe_n_setup(void) + + cpuinfo_arc700[0].extn.gfrc = mp.gfrc; + ++ for (i = 0; i < NR_CPUS; i++) ++ if (cpu_possible(i)) ++ mcip_mask |= BIT(i); ++ + if (mp.dbg) { +- __mcip_cmd_data(CMD_DEBUG_SET_SELECT, 0, 0xf); +- __mcip_cmd_data(CMD_DEBUG_SET_MASK, 0xf, 0xf); ++ __mcip_cmd_data(CMD_DEBUG_SET_SELECT, 0, mcip_mask); ++ __mcip_cmd_data(CMD_DEBUG_SET_MASK, 0xf, mcip_mask); + } + } + +diff --git a/arch/arc/kernel/smp.c b/arch/arc/kernel/smp.c +index efe8b42..ee8b20a 100644 +--- a/arch/arc/kernel/smp.c ++++ b/arch/arc/kernel/smp.c +@@ -24,6 +24,8 @@ + #include + #include + #include ++#include ++#include + + #include + #include +@@ -47,6 +49,29 @@ void __init smp_prepare_boot_cpu(void) + { + } + ++/* Mark cpu as possible if cpu status is "okay" or status absents */ ++void __init smp_init_cpumask(void) ++{ ++ const struct fdt_property *prop; ++ char fdt_cpu_path[25]; ++ unsigned int i, oft; ++ ++ for (i = 0; i < NR_CPUS; i++) { ++ sprintf(fdt_cpu_path, "/cpus/cpu@%u", i); ++ oft = fdt_path_offset(initial_boot_params, fdt_cpu_path); ++ prop = fdt_get_property(initial_boot_params, oft, "status", NULL); ++ ++ /* No status property == status OK */ ++ if (!prop) { ++ set_cpu_possible(i, true); ++ continue; ++ } ++ ++ if (!strcmp("okay", prop->data)) ++ set_cpu_possible(i, true); ++ } ++} ++ + /* + * Called from setup_arch() before calling setup_processor() + * +@@ -58,10 +83,7 @@ void __init smp_prepare_boot_cpu(void) + */ + void __init smp_init_cpus(void) + { +- unsigned int i; +- +- for (i = 0; i < NR_CPUS; i++) +- set_cpu_possible(i, true); ++ smp_init_cpumask(); + + if (plat_smp_ops.init_early_smp) + plat_smp_ops.init_early_smp(); +-- +2.9.3 + diff --git a/board/synopsys/hsdk/post-image.sh b/board/synopsys/hsdk/post-image.sh old mode 100644 new mode 100755 index e99a4a0b96f..3662579f384 --- a/board/synopsys/hsdk/post-image.sh +++ b/board/synopsys/hsdk/post-image.sh @@ -6,7 +6,10 @@ GENIMAGE_CFG="${BOARD_DIR}/genimage.cfg" GENIMAGE_TMP="${BUILD_DIR}/genimage.tmp" rm -rf "${GENIMAGE_TMP}" -mv ${BINARIES_DIR}/uboot-env.bin ${BINARIES_DIR}/uboot.env +python3 ${BOARD_DIR}/headerise.py --arc-id 0x52 --image output/images/u-boot.bin --elf output/images/u-boot --env ${BOARD_DIR}/uboot.env.txt +mkenvimage -s 0x4000 -o output/images/uboot.env ./u-boot-p-env.txt +cp ./u-boot.head output/images +rm u-boot.head u-boot-p-env.txt genimage \ --rootpath "${TARGET_DIR}" \ diff --git a/board/synopsys/hsdk/uboot-patches/0001-ARC-HSDK-Fixup-DW-SDIO-CIU-frequency-to-50000000Hz.patch b/board/synopsys/hsdk/uboot-patches/0001-ARC-HSDK-Fixup-DW-SDIO-CIU-frequency-to-50000000Hz.patch new file mode 100644 index 00000000000..31b88c16ad7 --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0001-ARC-HSDK-Fixup-DW-SDIO-CIU-frequency-to-50000000Hz.patch @@ -0,0 +1,59 @@ +From 0aa461be83200a1211d365c1c924bd94e1b5a0d6 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Sat, 21 Oct 2017 15:02:44 +0300 +Subject: [PATCH 01/46] ARC: HSDK: Fixup DW SDIO CIU frequency to 50000000Hz + +DW sdio controller has external ciu clock devider controlled via +register in SDIO IP. Due to its unexpected default value +(it should devide by 1 but it devides by 8) +SDIO IP uses wrong CIU clock (it should be 100000000Hz but actual +is 12500000Hz) and works unstable (see STAR 9001204800) + +So increase SDIO CIU frequency from actual 12500000Hz to 50000000Hz +by switching from the default divisor value (div-by-8) to the +minimum possible value of the divisor (div-by-2) in HSDK platform +code. + +Signed-off-by: Eugeniy Paltsev +--- + board/synopsys/hsdk/hsdk.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/board/synopsys/hsdk/hsdk.c b/board/synopsys/hsdk/hsdk.c +index 7b562556e6..7641978a7b 100644 +--- a/board/synopsys/hsdk/hsdk.c ++++ b/board/synopsys/hsdk/hsdk.c +@@ -26,6 +26,10 @@ int board_early_init_f(void) + 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; +@@ -36,12 +40,18 @@ int board_mmc_init(bd_t *bis) + 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 = 100000000; ++ host->bus_hz = 50000000; + + add_dwmci(host, host->bus_hz / 2, 400000); + +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0002-PATCH-ARC-clk-introduce-HSDK-pll-driver.patch b/board/synopsys/hsdk/uboot-patches/0002-PATCH-ARC-clk-introduce-HSDK-pll-driver.patch new file mode 100644 index 00000000000..57f5cbe388c --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0002-PATCH-ARC-clk-introduce-HSDK-pll-driver.patch @@ -0,0 +1,408 @@ +From 01a6b199d86c20ceb10ce42519fd0a6c5cdc3d17 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Wed, 25 Oct 2017 18:36:05 +0300 +Subject: [PATCH 02/46] [PATCH] ARC: clk: introduce HSDK pll driver + +HSDK soc manages it's clocks using various PLLs. These PLL has same +dividers and corresponding control registers mapped to different addresses. +So we add one common driver for such PLLs. + +Each PLL on HSDK board consist of three dividers: IDIV, FBDIV and +ODIV. Output clock value is managed using these dividers. + +We add pre-defined tables with supported rate values and appropriate +configurations of IDIV, FBDIV and ODIV for each value. + +As of today we add support for PLLs that generate clock for the +HSDK arc cpus, system, ddr, AXI tunnel and hdmi. + +Signed-off-by: Eugeniy Paltsev +--- + MAINTAINERS | 6 + + drivers/clk/Kconfig | 6 + + drivers/clk/Makefile | 1 + + drivers/clk/hsdk-clk.c | 326 +++++++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 339 insertions(+) + create mode 100644 drivers/clk/hsdk-clk.c + +diff --git a/MAINTAINERS b/MAINTAINERS +index b167b028ec..a3f9694d24 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -59,6 +59,12 @@ S: Maintained + T: git git://git.denx.de/u-boot-arc.git + F: arch/arc/ + ++ARC HSDK PLL CLK ++M: Eugeniy Paltsev ++S: Maintained ++L: uboot-snps-arc@synopsys.com ++F: drivers/clk/hsdk-clk.c ++ + ARM + M: Albert Aribaud + S: Maintained +diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig +index baa60a52e6..20641a9a51 100644 +--- a/drivers/clk/Kconfig ++++ b/drivers/clk/Kconfig +@@ -46,6 +46,12 @@ config CLK_BOSTON + help + Enable this to support the clocks + ++config CLK_HSDK ++ bool "Enable pll clock driver for HSDK" ++ depends on CLK ++ help ++ Enable this to support the pll clocks on HSDK ++ + config CLK_ZYNQ + bool "Enable clock driver support for Zynq" + depends on CLK && ARCH_ZYNQ +diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile +index 83fe88ce9f..4b6cc1935d 100644 +--- a/drivers/clk/Makefile ++++ b/drivers/clk/Makefile +@@ -20,6 +20,7 @@ obj-$(CONFIG_CLK_EXYNOS) += exynos/ + obj-$(CONFIG_CLK_AT91) += at91/ + obj-$(CONFIG_CLK_BCM6345) += clk_bcm6345.o + obj-$(CONFIG_CLK_BOSTON) += clk_boston.o ++obj-$(CONFIG_CLK_HSDK) += hsdk-clk.o + obj-$(CONFIG_ARCH_ASPEED) += aspeed/ + obj-$(CONFIG_STM32F7) += clk_stm32f7.o + obj-$(CONFIG_STM32H7) += clk_stm32h7.o +diff --git a/drivers/clk/hsdk-clk.c b/drivers/clk/hsdk-clk.c +new file mode 100644 +index 0000000000..2323c6317b +--- /dev/null ++++ b/drivers/clk/hsdk-clk.c +@@ -0,0 +1,326 @@ ++/* ++ * Synopsys HSDK SDP Generic PLL clock driver ++ * ++ * Copyright (C) 2017 Synopsys ++ * Author: Eugeniy Paltsev ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define CGU_PLL_CTRL 0x000 /* ARC PLL control register */ ++#define CGU_PLL_STATUS 0x004 /* ARC PLL status register */ ++#define CGU_PLL_FMEAS 0x008 /* ARC PLL frequency measurement register */ ++#define CGU_PLL_MON 0x00C /* ARC PLL monitor register */ ++ ++#define CGU_PLL_CTRL_ODIV_SHIFT 2 ++#define CGU_PLL_CTRL_IDIV_SHIFT 4 ++#define CGU_PLL_CTRL_FBDIV_SHIFT 9 ++#define CGU_PLL_CTRL_BAND_SHIFT 20 ++ ++#define CGU_PLL_CTRL_ODIV_MASK GENMASK(3, CGU_PLL_CTRL_ODIV_SHIFT) ++#define CGU_PLL_CTRL_IDIV_MASK GENMASK(8, CGU_PLL_CTRL_IDIV_SHIFT) ++#define CGU_PLL_CTRL_FBDIV_MASK GENMASK(15, CGU_PLL_CTRL_FBDIV_SHIFT) ++ ++#define CGU_PLL_CTRL_PD BIT(0) ++#define CGU_PLL_CTRL_BYPASS BIT(1) ++ ++#define CGU_PLL_STATUS_LOCK BIT(0) ++#define CGU_PLL_STATUS_ERR BIT(1) ++ ++#define HSDK_PLL_MAX_LOCK_TIME 100 /* 100 us */ ++ ++#define CREG_CORE_IF_DIV 0x000 /* ARC CORE interface divider */ ++#define CORE_IF_CLK_THRESHOLD_HZ 500000000 ++#define CREG_CORE_IF_CLK_DIV_1 0x0 ++#define CREG_CORE_IF_CLK_DIV_2 0x1 ++ ++#define PARENT_RATE 33333333 /* fixed clock - xtal */ ++ ++struct hsdk_pll_cfg { ++ u32 rate; ++ u32 idiv; ++ u32 fbdiv; ++ u32 odiv; ++ u32 band; ++}; ++ ++static const struct hsdk_pll_cfg asdt_pll_cfg[] = { ++ { 100000000, 0, 11, 3, 0 }, ++ { 133000000, 0, 15, 3, 0 }, ++ { 200000000, 1, 47, 3, 0 }, ++ { 233000000, 1, 27, 2, 0 }, ++ { 300000000, 1, 35, 2, 0 }, ++ { 333000000, 1, 39, 2, 0 }, ++ { 400000000, 1, 47, 2, 0 }, ++ { 500000000, 0, 14, 1, 0 }, ++ { 600000000, 0, 17, 1, 0 }, ++ { 700000000, 0, 20, 1, 0 }, ++ { 800000000, 0, 23, 1, 0 }, ++ { 900000000, 1, 26, 0, 0 }, ++ { 1000000000, 1, 29, 0, 0 }, ++ { 1100000000, 1, 32, 0, 0 }, ++ { 1200000000, 1, 35, 0, 0 }, ++ { 1300000000, 1, 38, 0, 0 }, ++ { 1400000000, 1, 41, 0, 0 }, ++ { 1500000000, 1, 44, 0, 0 }, ++ { 1600000000, 1, 47, 0, 0 }, ++ {} ++}; ++ ++static const struct hsdk_pll_cfg hdmi_pll_cfg[] = { ++ { 297000000, 0, 21, 2, 0 }, ++ { 540000000, 0, 19, 1, 0 }, ++ { 594000000, 0, 21, 1, 0 }, ++ {} ++}; ++ ++struct hsdk_pll_clk { ++ void __iomem *regs; ++ void __iomem *spec_regs; ++ const struct hsdk_pll_devdata *pll_devdata; ++}; ++ ++struct hsdk_pll_devdata { ++ const struct hsdk_pll_cfg *pll_cfg; ++ int (*update_rate)(struct hsdk_pll_clk *clk, unsigned long rate, ++ const struct hsdk_pll_cfg *cfg); ++}; ++ ++static int hsdk_pll_core_update_rate(struct hsdk_pll_clk *, unsigned long, ++ const struct hsdk_pll_cfg *); ++static int hsdk_pll_comm_update_rate(struct hsdk_pll_clk *, unsigned long, ++ const struct hsdk_pll_cfg *); ++ ++static const struct hsdk_pll_devdata core_pll_devdata = { ++ .pll_cfg = asdt_pll_cfg, ++ .update_rate = hsdk_pll_core_update_rate, ++}; ++ ++static const struct hsdk_pll_devdata sdt_pll_devdata = { ++ .pll_cfg = asdt_pll_cfg, ++ .update_rate = hsdk_pll_comm_update_rate, ++}; ++ ++static const struct hsdk_pll_devdata hdmi_pll_devdata = { ++ .pll_cfg = hdmi_pll_cfg, ++ .update_rate = hsdk_pll_comm_update_rate, ++}; ++ ++static inline void hsdk_pll_write(struct hsdk_pll_clk *clk, u32 reg, u32 val) ++{ ++ iowrite32(val, clk->regs + reg); ++} ++ ++static inline u32 hsdk_pll_read(struct hsdk_pll_clk *clk, u32 reg) ++{ ++ return ioread32(clk->regs + reg); ++} ++ ++static inline void hsdk_pll_spcwrite(struct hsdk_pll_clk *clk, u32 reg, u32 val) ++{ ++ iowrite32(val, clk->spec_regs + reg); ++} ++ ++static inline u32 hsdk_pll_spcread(struct hsdk_pll_clk *clk, u32 reg) ++{ ++ return ioread32(clk->spec_regs + reg); ++} ++ ++static inline void hsdk_pll_set_cfg(struct hsdk_pll_clk *clk, ++ const struct hsdk_pll_cfg *cfg) ++{ ++ u32 val = 0; ++ ++ /* Powerdown and Bypass bits should be cleared */ ++ val |= cfg->idiv << CGU_PLL_CTRL_IDIV_SHIFT; ++ val |= cfg->fbdiv << CGU_PLL_CTRL_FBDIV_SHIFT; ++ val |= cfg->odiv << CGU_PLL_CTRL_ODIV_SHIFT; ++ val |= cfg->band << CGU_PLL_CTRL_BAND_SHIFT; ++ ++ pr_debug("write configurarion: %#x\n", val); ++ ++ hsdk_pll_write(clk, CGU_PLL_CTRL, val); ++} ++ ++static inline bool hsdk_pll_is_locked(struct hsdk_pll_clk *clk) ++{ ++ return !!(hsdk_pll_read(clk, CGU_PLL_STATUS) & CGU_PLL_STATUS_LOCK); ++} ++ ++static inline bool hsdk_pll_is_err(struct hsdk_pll_clk *clk) ++{ ++ return !!(hsdk_pll_read(clk, CGU_PLL_STATUS) & CGU_PLL_STATUS_ERR); ++} ++ ++static ulong hsdk_pll_get_rate(struct clk *sclk) ++{ ++ u32 val; ++ u64 rate; ++ u32 idiv, fbdiv, odiv; ++ struct hsdk_pll_clk *clk = dev_get_priv(sclk->dev); ++ ++ val = hsdk_pll_read(clk, CGU_PLL_CTRL); ++ ++ pr_debug("current configurarion: %#x\n", val); ++ ++ /* Check if PLL is disabled */ ++ if (val & CGU_PLL_CTRL_PD) ++ return 0; ++ ++ /* Check if PLL is bypassed */ ++ if (val & CGU_PLL_CTRL_BYPASS) ++ return PARENT_RATE; ++ ++ /* input divider = reg.idiv + 1 */ ++ idiv = 1 + ((val & CGU_PLL_CTRL_IDIV_MASK) >> CGU_PLL_CTRL_IDIV_SHIFT); ++ /* fb divider = 2*(reg.fbdiv + 1) */ ++ fbdiv = 2 * (1 + ((val & CGU_PLL_CTRL_FBDIV_MASK) >> CGU_PLL_CTRL_FBDIV_SHIFT)); ++ /* output divider = 2^(reg.odiv) */ ++ odiv = 1 << ((val & CGU_PLL_CTRL_ODIV_MASK) >> CGU_PLL_CTRL_ODIV_SHIFT); ++ ++ rate = (u64)PARENT_RATE * fbdiv; ++ do_div(rate, idiv * odiv); ++ ++ return rate; ++} ++ ++static unsigned long hsdk_pll_round_rate(struct clk *sclk, unsigned long rate) ++{ ++ int i; ++ unsigned long best_rate; ++ struct hsdk_pll_clk *clk = dev_get_priv(sclk->dev); ++ const struct hsdk_pll_cfg *pll_cfg = clk->pll_devdata->pll_cfg; ++ ++ if (pll_cfg[0].rate == 0) ++ return -EINVAL; ++ ++ best_rate = pll_cfg[0].rate; ++ ++ for (i = 1; pll_cfg[i].rate != 0; i++) { ++ if (abs(rate - pll_cfg[i].rate) < abs(rate - best_rate)) ++ best_rate = pll_cfg[i].rate; ++ } ++ ++ pr_debug("chosen best rate: %lu\n", best_rate); ++ ++ return best_rate; ++} ++ ++static int hsdk_pll_comm_update_rate(struct hsdk_pll_clk *clk, ++ unsigned long rate, ++ const struct hsdk_pll_cfg *cfg) ++{ ++ hsdk_pll_set_cfg(clk, cfg); ++ ++ /* ++ * Wait until CGU relocks and check error status. ++ * If after timeout CGU is unlocked yet return error. ++ */ ++ udelay(HSDK_PLL_MAX_LOCK_TIME); ++ if (!hsdk_pll_is_locked(clk)) ++ return -ETIMEDOUT; ++ ++ if (hsdk_pll_is_err(clk)) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int hsdk_pll_core_update_rate(struct hsdk_pll_clk *clk, ++ unsigned long rate, ++ const struct hsdk_pll_cfg *cfg) ++{ ++ /* ++ * When core clock exceeds 500MHz, the divider for the interface ++ * clock must be programmed to div-by-2. ++ */ ++ if (rate > CORE_IF_CLK_THRESHOLD_HZ) ++ hsdk_pll_spcwrite(clk, CREG_CORE_IF_DIV, CREG_CORE_IF_CLK_DIV_2); ++ ++ hsdk_pll_set_cfg(clk, cfg); ++ ++ /* ++ * Wait until CGU relocks and check error status. ++ * If after timeout CGU is unlocked yet return error. ++ */ ++ udelay(HSDK_PLL_MAX_LOCK_TIME); ++ if (!hsdk_pll_is_locked(clk)) ++ return -ETIMEDOUT; ++ ++ if (hsdk_pll_is_err(clk)) ++ return -EINVAL; ++ ++ /* ++ * Program divider to div-by-1 if we succesfuly set core clock below ++ * 500MHz threshold. ++ */ ++ if (rate <= CORE_IF_CLK_THRESHOLD_HZ) ++ hsdk_pll_spcwrite(clk, CREG_CORE_IF_DIV, CREG_CORE_IF_CLK_DIV_1); ++ ++ return 0; ++} ++ ++static ulong hsdk_pll_set_rate(struct clk *sclk, ulong rate) ++{ ++ int i; ++ unsigned long best_rate; ++ struct hsdk_pll_clk *clk = dev_get_priv(sclk->dev); ++ const struct hsdk_pll_cfg *pll_cfg = clk->pll_devdata->pll_cfg; ++ ++ best_rate = hsdk_pll_round_rate(sclk, rate); ++ ++ for (i = 0; pll_cfg[i].rate != 0; i++) { ++ if (pll_cfg[i].rate == best_rate) { ++ return clk->pll_devdata->update_rate(clk, best_rate, ++ &pll_cfg[i]); ++ } ++ } ++ ++ pr_err("invalid rate=%ld, parent_rate=%d\n", best_rate, PARENT_RATE); ++ ++ return -EINVAL; ++} ++ ++static const struct clk_ops hsdk_pll_ops = { ++ .set_rate = hsdk_pll_set_rate, ++ .get_rate = hsdk_pll_get_rate, ++}; ++ ++static int hsdk_pll_clk_probe(struct udevice *dev) ++{ ++ struct hsdk_pll_clk *pll_clk = dev_get_priv(dev); ++ ++ pll_clk->pll_devdata = (const struct hsdk_pll_devdata *) ++ dev_get_driver_data(dev); ++ ++ pll_clk->regs = (void __iomem *)devfdt_get_addr_index(dev, 0); ++ pll_clk->spec_regs = (void __iomem *)devfdt_get_addr_index(dev, 1); ++ if ((pll_clk->pll_devdata == &core_pll_devdata) && !pll_clk->spec_regs) ++ return -ENOENT; ++ ++ return 0; ++} ++ ++static const struct udevice_id hsdk_pll_clk_id[] = { ++ { .compatible = "snps,hsdk-gp-pll-clock", .data = (ulong)&sdt_pll_devdata}, ++ { .compatible = "snps,hsdk-hdmi-pll-clock", .data = (ulong)&hdmi_pll_devdata}, ++ { .compatible = "snps,hsdk-core-pll-clock", .data = (ulong)&core_pll_devdata}, ++ { } ++}; ++ ++U_BOOT_DRIVER(hsdk_pll_clk) = { ++ .name = "hsdk-pll-clk", ++ .id = UCLASS_CLK, ++ .of_match = hsdk_pll_clk_id, ++ .probe = hsdk_pll_clk_probe, ++ .platdata_auto_alloc_size = sizeof(struct hsdk_pll_clk), ++ .ops = &hsdk_pll_ops, ++}; +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0003-HSDK-DTS-add-pll-nodes-and-fmeas-dummy-node.patch b/board/synopsys/hsdk/uboot-patches/0003-HSDK-DTS-add-pll-nodes-and-fmeas-dummy-node.patch new file mode 100644 index 00000000000..a707ed8abd3 --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0003-HSDK-DTS-add-pll-nodes-and-fmeas-dummy-node.patch @@ -0,0 +1,53 @@ +From 8ae4784638590243ab26323328e83779d12b697b Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Thu, 9 Nov 2017 17:58:51 +0300 +Subject: [PATCH 03/46] HSDK: DTS: add pll nodes and fmeas dummy node + +Signed-off-by: Eugeniy Paltsev +--- + arch/arc/dts/hsdk.dts | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/arch/arc/dts/hsdk.dts b/arch/arc/dts/hsdk.dts +index a7b276c01e..9a2090f3ea 100644 +--- a/arch/arc/dts/hsdk.dts ++++ b/arch/arc/dts/hsdk.dts +@@ -24,6 +24,35 @@ + }; + }; + ++ clk-fmeas { ++ clocks = <&cpu_clk>, <&sys_clk>, <&tun_clk>, <&ddr_clk>; ++ clock-names = "cpu-clk", "sys-clk", "tun-clk", "ddr-clk"; ++ }; ++ ++ cpu_clk: cpu-clk@f0000000 { ++ compatible = "snps,hsdk-core-pll-clock"; ++ reg = <0xf0000000 0x10>, <0xf00014B8 0x4>; ++ #clock-cells = <0>; ++ }; ++ ++ sys_clk: sys-clk@f0000010 { ++ compatible = "snps,hsdk-gp-pll-clock"; ++ reg = <0xf0000010 0x10>; ++ #clock-cells = <0>; ++ }; ++ ++ ddr_clk: ddr-clk@f0000020 { ++ compatible = "snps,hsdk-gp-pll-clock"; ++ reg = <0xf0000020 0x10>; ++ #clock-cells = <0>; ++ }; ++ ++ tun_clk: tun-clk@f0000030 { ++ compatible = "snps,hsdk-gp-pll-clock"; ++ reg = <0xf0000030 0x10>; ++ #clock-cells = <0>; ++ }; ++ + uart0: serial0@f0005000 { + compatible = "snps,dw-apb-uart"; + reg = <0xf0005000 0x1000>; +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0004-ARC-ARCv2-invalidate-i-and-d-at-startup-code.patch b/board/synopsys/hsdk/uboot-patches/0004-ARC-ARCv2-invalidate-i-and-d-at-startup-code.patch new file mode 100644 index 00000000000..57bf1804767 --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0004-ARC-ARCv2-invalidate-i-and-d-at-startup-code.patch @@ -0,0 +1,38 @@ +From 2f497a47506e79b066a32325e349c12715535b05 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Thu, 9 Nov 2017 17:59:39 +0300 +Subject: [PATCH 04/46] ARC: ARCv2: invalidate i$ and d$ at startup code + +Signed-off-by: Eugeniy Paltsev +--- + arch/arc/lib/start.S | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/arch/arc/lib/start.S b/arch/arc/lib/start.S +index 95d64f9d43..3b247fd031 100644 +--- a/arch/arc/lib/start.S ++++ b/arch/arc/lib/start.S +@@ -44,6 +44,9 @@ ENTRY(_start) + #endif + sr r5, [ARC_AUX_IC_CTRL] + ++ mov r5, 1 ++ sr r5, [ARC_AUX_IC_IVIC] ++ + 1: + ; Disable/enable D-cache according to configuration + lr r5, [ARC_BCR_DC_BUILD] +@@ -57,6 +60,10 @@ ENTRY(_start) + #endif + sr r5, [ARC_AUX_DC_CTRL] + ++ mov r5, 1 ++ sr r5, [ARC_AUX_DC_IVDC] ++ ++ + 1: + #ifdef CONFIG_ISA_ARCV2 + ; Disable System-Level Cache (SLC) +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0005-ARC-HSDK-add-hsdk_go-comand.patch b/board/synopsys/hsdk/uboot-patches/0005-ARC-HSDK-add-hsdk_go-comand.patch new file mode 100644 index 00000000000..6b7269f4562 --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0005-ARC-HSDK-add-hsdk_go-comand.patch @@ -0,0 +1,681 @@ +From c9d1c6994a9b713ecefda32b4ce385769b9eb148 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Thu, 9 Nov 2017 18:01:35 +0300 +Subject: [PATCH 05/46] ARC: HSDK: add hsdk_go comand + +hsdk_go - Boot stand-alone application on HSDK (Synopsys +HSDK-specific command) + +Signed-off-by: Eugeniy Paltsev +--- + board/synopsys/hsdk/Makefile | 1 + + board/synopsys/hsdk/hsdk-cmd.c | 648 +++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 649 insertions(+) + create mode 100644 board/synopsys/hsdk/hsdk-cmd.c + +diff --git a/board/synopsys/hsdk/Makefile b/board/synopsys/hsdk/Makefile +index d84dd03265..49fca891e1 100644 +--- a/board/synopsys/hsdk/Makefile ++++ b/board/synopsys/hsdk/Makefile +@@ -5,3 +5,4 @@ + # + + obj-y += hsdk.o ++obj-y += hsdk-cmd.o +diff --git a/board/synopsys/hsdk/hsdk-cmd.c b/board/synopsys/hsdk/hsdk-cmd.c +new file mode 100644 +index 0000000000..f3b8a1d43d +--- /dev/null ++++ b/board/synopsys/hsdk/hsdk-cmd.c +@@ -0,0 +1,648 @@ ++#define DEBUG ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define HSDKGO_VERSION "0.4" ++ ++#define MAX_CPUS 4 ++#define MASTER_CPU 0 ++#define MAX_CMD_LEN 40 ++ ++#define VAL_NO_XCCM 0x10 ++ ++void smp_set_core_boot_addr(unsigned long addr, int corenr); ++ ++struct hsdk_per_cpu_ctl { ++ bool used; ++ u32 entry; ++ u32 icache; ++ u32 dcache; ++ u32 iccm; ++ u32 dccm; ++}; ++ ++struct hsdk_common_ctl { ++ bool halt_on_boot; ++ u32 core_mask; ++ u32 cpu_freq; ++ u32 axi_freq; ++ u32 tun_freq; ++ u32 nvlim; ++}; ++ ++struct hsdk_env_map { ++ const char * const env_name; ++ bool core_specific; ++ bool mandatory; ++ u32 min; ++ u32 max; ++ int (* func)(u32, u32); ++}; ++ ++/* Temporary place for slave cpu stack */ ++static u32 slave_stack[1024] __attribute__((aligned(4))); ++ ++static struct hsdk_per_cpu_ctl hsdk_env_per_cpu_ctl[MAX_CPUS] = {}; ++static struct hsdk_common_ctl hsdk_env_common_ctl = {}; ++ ++int soc_clk_ctl(const char *name, ulong *rate, bool set) ++{ ++ int ret; ++ struct clk clk; ++ ++ /* Dummy fmeas device, just to 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) ++ return ret; ++ ++ ret = clk_enable(&clk); ++ if (ret && ret != -ENOSYS) ++ return ret; ++ ++ if (set) { ++ ret = clk_set_rate(&clk, *rate); ++ if (ret) ++ return ret; ++ } ++ ++ *rate = clk_get_rate(&clk); ++ ++ clk_free(&clk); ++ ++ printf("HSDK: clock %s rate %lu\n", name, *rate); ++ ++ return 0; ++} ++ ++static int core_ccm_check(u32 core, u32 val) ++{ ++ /* Cores 0 and 2 don't have ICCM and DCCM */ ++ if ((core == 0 || core == 2) && val != VAL_NO_XCCM) { ++ pr_err("Cores 0 and 2 don't have ICCM and DCCM"); ++ return -EINVAL; ++ } ++ ++ /* Cores 1 and 3 have ICCM and DCCM */ ++ if ((core == 1 || core == 3) && val == VAL_NO_XCCM) { ++ pr_err("Cores 1 and 3 have ICCM and DCCM, we can't disable it"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++int do_core_mask(u32 core, u32 val) ++{ ++ hsdk_env_common_ctl.core_mask = val; ++ ++ if (val & 0x1) ++ hsdk_env_per_cpu_ctl[0].used = true; ++ ++ if (val & 0x2) ++ hsdk_env_per_cpu_ctl[1].used = true; ++ ++ if (val & 0x4) ++ hsdk_env_per_cpu_ctl[2].used = true; ++ ++ if (val & 0x8) ++ hsdk_env_per_cpu_ctl[3].used = true; ++ ++ return 0; ++} ++ ++int do_cpu_freq(u32 core, u32 val) ++{ ++ hsdk_env_common_ctl.cpu_freq = val; ++ return 0; ++} ++ ++int do_axi_freq(u32 core, u32 val) ++{ ++ hsdk_env_common_ctl.axi_freq = val; ++ return 0; ++} ++ ++int do_tun_freq(u32 core, u32 val) ++{ ++ hsdk_env_common_ctl.tun_freq = val; ++ return 0; ++} ++ ++int do_core_entry(u32 core, u32 val) ++{ ++ hsdk_env_per_cpu_ctl[core].entry = val; ++ return 0; ++} ++ ++int do_icache_ena(u32 core, u32 val) ++{ ++ hsdk_env_per_cpu_ctl[core].icache = val; ++ return 0; ++} ++ ++int do_dcache_ena(u32 core, u32 val) ++{ ++ hsdk_env_per_cpu_ctl[core].dcache = val; ++ return 0; ++} ++ ++int do_aux_iccm(u32 core, u32 val) ++{ ++ if (core_ccm_check(core, val)) ++ return -EINVAL; ++ ++ hsdk_env_per_cpu_ctl[core].iccm = val; ++ return 0; ++} ++ ++int do_aux_dccm(u32 core, u32 val) ++{ ++ if (core_ccm_check(core, val)) ++ return -EINVAL; ++ ++ hsdk_env_per_cpu_ctl[core].dccm = val; ++ return 0; ++} ++ ++int do_aux_nvlimn(u32 core, u32 val) ++{ ++ hsdk_env_common_ctl.nvlim = val; ++ return 0; ++} ++ ++/* TODO: add default values */ ++static const struct hsdk_env_map env_map[] = { ++ { "core_mask", false, true, 0x1, 0xF, do_core_mask }, ++ /* core_mask must be first table entry */ ++ { "cpu_freq", false, false, 100, 1000, do_cpu_freq }, ++ { "axi_freq", false, false, 200, 800, do_axi_freq }, ++ { "tun_freq", false, false, 0, 150, do_tun_freq }, ++ { "non_volatile_limit", false, true, 0x1, 0xF, do_aux_nvlimn }, ++ ++ { "core_entry", true, true, 0, U32_MAX, do_core_entry }, ++ { "core_icache_ena", true, true, 0, 1, do_icache_ena }, ++ { "core_dcache_ena", true, true, 0, 1, do_dcache_ena }, ++ { "core_aux_iccm", true, true, 0x1, VAL_NO_XCCM, do_aux_iccm }, ++ { "core_aux_dccm", true, true, 0x1, VAL_NO_XCCM, do_aux_dccm }, ++ {} ++}; ++ ++static int check_env_bound(u32 index, u32 val) ++{ ++ if (val < env_map[index].min || val > env_map[index].max) { ++ pr_err("\'%s\' must be between %#x and %#x\n", env_map[index].env_name, ++ env_map[index].min, env_map[index].max); ++ ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int check_env_core_specific(u32 env_index, u32 cpu_index) ++{ ++ /* We assume if slave CPU[x] is enabled all of mandatory x CPU ++ * environment variables must be set */ ++ if (hsdk_env_per_cpu_ctl[cpu_index].used && env_map[env_index].mandatory) { ++ pr_err("CPU %u is used, but \'%s_%u\' is not defined\n", ++ cpu_index, env_map[env_index].env_name, cpu_index); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int check_env_common(u32 env_index) ++{ ++ if (env_map[env_index].mandatory) { ++ pr_err("Variable \'%s\' is mandatory, but it is not defined\n", ++ env_map[env_index].env_name); ++ ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++/* TODO: refactor: split variable get and check */ ++static int env_process(u32 index) ++{ ++ u32 i, val; ++ char comand[MAX_CMD_LEN]; ++ ++ if (!env_map[index].core_specific) { ++ if (!env_get_yesno(env_map[index].env_name)) { ++ val = (u32)env_get_hex(env_map[index].env_name, 0); ++ if (check_env_bound(index, val)) ++ return -EINVAL; ++ ++ debug("ENV: %s = %#x\n", env_map[index].env_name, val); ++ if (env_map[index].func(0, val)) ++ return -EINVAL; ++ } else { ++ /* Check if it is OK, that this variable isn't defined */ ++ if (check_env_common(index)) ++ return -EINVAL; ++ } ++ ++ return 0; ++ } ++ ++ /* process core specific variables */ ++ for (i = 0; i < MAX_CPUS; i++) { ++ sprintf(comand, "%s_%u", env_map[index].env_name, i); ++ if (!env_get_yesno(comand)) { ++ val = (u32)env_get_hex(comand, 0); ++ if (check_env_bound(index, val)) ++ return -EINVAL; ++ ++ debug("ENV: %s: = %#x\n", comand, val); ++ if (env_map[index].func(i, val)) ++ return -EINVAL; ++ } else { ++ /* Check if it is OK, that this variable isn't defined */ ++ if (check_env_core_specific(index, i)) ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++ ++#define APT_SHIFT 28 ++ ++/* Bit values in IC_CTRL */ ++#define IC_CTRL_CACHE_DISABLE (1 << 0) ++ ++/* Bit values in DC_CTRL */ ++#define DC_CTRL_CACHE_DISABLE (1 << 0) ++#define DC_CTRL_INV_MODE_FLUSH (1 << 6) ++ ++/* TODO: move this to "arch/arc/include/asm/arcregs.h" */ ++#define AUX_NON_VOLATILE_LIMIT 0x5E ++#define ARC_REG_AUX_DCCM 0x18 /* DCCM Base Addr ARCv2 */ ++#define ARC_REG_AUX_ICCM 0x208 /* ICCM Base Addr (ARCv2) */ ++#define AUX_VOL 0x5E ++#define AUX_CACHE_LIMIT 0x5D ++ ++#define AUX_IDENTITY 4 ++ ++static inline void nop_instr(void) ++{ ++ __asm__ __volatile__("nop"); ++} ++ ++// TODO: add xCCM runtime check ++static void smp_init_slave_cpu_func(u32 core) ++{ ++ unsigned int r; ++ ++ /* ICCM move if exists */ ++ if (hsdk_env_per_cpu_ctl[core].iccm != VAL_NO_XCCM) { ++ r = ARC_REG_AUX_ICCM; ++ write_aux_reg(r, hsdk_env_per_cpu_ctl[core].iccm << APT_SHIFT); ++ } ++ ++ /* DCCM move if exists */ ++ if (hsdk_env_per_cpu_ctl[core].dccm != VAL_NO_XCCM) { ++ r = ARC_REG_AUX_DCCM; ++ write_aux_reg(r, hsdk_env_per_cpu_ctl[core].dccm << APT_SHIFT); ++ } ++ ++ /* i$ enable if required (it is disabled by default) */ ++ if (hsdk_env_per_cpu_ctl[core].icache) { ++ r = ARC_AUX_IC_CTRL; ++ write_aux_reg(r, read_aux_reg(r) & ~IC_CTRL_CACHE_DISABLE); ++ } ++ ++ /* d$ enable if required (it is disabled by default) */ ++ if (hsdk_env_per_cpu_ctl[core].dcache) { ++ r = ARC_AUX_DC_CTRL; ++ write_aux_reg(r, read_aux_reg(r) & ~(DC_CTRL_CACHE_DISABLE | DC_CTRL_INV_MODE_FLUSH)); ++ } ++} ++ ++static void init_master_nvlim(void) ++{ ++ u32 val = hsdk_env_common_ctl.nvlim << APT_SHIFT; ++ ++ flush_dcache_all(); ++ write_aux_reg(AUX_NON_VOLATILE_LIMIT, val); ++ write_aux_reg(AUX_CACHE_LIMIT, val); ++} ++ ++// TODO: !! add my own implementation of flush_dcache_all, invalidate_icache_all ++// as current implementations depends on CONFIG_SYS_DCACHE_OFF and ++// CONFIG_SYS_ICACHE_OFF ++ ++static void init_master_icache(void) ++{ ++ unsigned int r; ++ ++#ifndef CONFIG_SYS_ICACHE_OFF ++ /* enable if required, else - nothing to do */ ++ if (hsdk_env_per_cpu_ctl[MASTER_CPU].icache) { ++ r = ARC_AUX_IC_CTRL; ++ write_aux_reg(r, read_aux_reg(r) & ~IC_CTRL_CACHE_DISABLE); ++ } ++#else ++ /* disable if required, else - nothing to do (we will invalidate i$ ++ * just before app launch) */ ++ if (!hsdk_env_per_cpu_ctl[MASTER_CPU].icache) { ++ /* next code copied from board_hsdk.c */ ++ /* instruction cache invalidate */ ++ write_aux_reg(ARC_AUX_IC_IVIC, 0x00000001U); ++ /* HS Databook, 5.3.3.2: three NOP's must be inserted inbetween ++ * invalidate and disable */ ++ nop_instr(); ++ nop_instr(); ++ nop_instr(); ++ /* instruction cache disable */ ++ write_aux_reg(ARC_AUX_IC_CTRL, 0x00000001U); ++ } ++#endif ++} ++ ++static void init_master_dcache(void) ++{ ++ unsigned int r; ++ ++#ifndef CONFIG_SYS_ICACHE_OFF ++ /* enable if required, else - nothing to do */ ++ if (hsdk_env_per_cpu_ctl[MASTER_CPU].dcache) { ++ r = ARC_AUX_DC_CTRL; ++ write_aux_reg(r, read_aux_reg(r) & ~(DC_CTRL_CACHE_DISABLE | DC_CTRL_INV_MODE_FLUSH)); ++ } ++#else ++ /* disable if required, else - nothing to do (we will flush d$ and sl$ ++ * just before app launch) */ ++ if (!hsdk_env_per_cpu_ctl[MASTER_CPU].dcache) { ++ /* next code copied from board_hsdk.c */ ++ flush_dcache_all(); /* TODO: it is OK if we flush SL$ too? */ ++ /* data cache ctrl: invalidate mode to: invalidate dc and flush ++ * dirty entries */ ++ write_aux_reg(ARC_AUX_DC_CTRL, 0x00000060U); ++ /* data cache invalidate */ ++ write_aux_reg(ARC_AUX_DC_IVDC, 0x00000001U); ++ /* data cache disable */ ++ write_aux_reg(ARC_AUX_DC_CTRL, 0x00000001U); ++ } ++#endif ++} ++ ++static int cleanup_cache_before_go(void) ++{ ++ flush_dcache_all(); ++ invalidate_dcache_all(); ++ invalidate_icache_all(); ++ ++ return 0; ++} ++ ++/* ********************* SMP: START ********************* */ ++ ++#define ARCNUM_SHIFT 8 ++ ++static inline u32 get_this_cpu_id(void) ++{ ++ u32 val = read_aux_reg(AUX_IDENTITY); ++ ++// val &= GENMASK(15, ARCNUM_SHIFT); ++ ++ val &= 0xFF00; ++ val >>= ARCNUM_SHIFT; ++ ++ return val; ++} ++ ++#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) ++#define CPU_START_MASK 0xF ++ ++static int cleanup_before_go(void) ++{ ++ disable_interrupts(); ++ cleanup_cache_before_go(); ++ ++ return 0; ++} ++ ++static inline void this_cpu_halt(void) ++{ ++ __asm__ __volatile__("flag 1\n"); ++} ++ ++static void smp_kick_cpu_x(u32 cpu_id) ++{ ++ int cmd = readl((void __iomem *)CREG_CPU_START); ++ ++ if (cpu_id > MAX_CPUS) ++ return; ++ ++ cmd &= ~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 &= ~CPU_START_MASK; ++ ++ return cmd | hsdk_env_common_ctl.core_mask; ++} ++ ++volatile u32 data_flag; ++volatile u32 stack_ptr; ++ ++static inline void set_data_flag(void) ++{ ++ __asm__ __volatile__( "mov r8, %%sp\n" ++ "st r8, %0\n" ++ : "=m" (data_flag) ++ : /* no input */ ++ : "memory"); ++} ++ ++/* flatten */ ++__attribute__((naked, noreturn, flatten)) noinline void hsdk_core_init_f(void) ++{ ++ __asm__ __volatile__( "ld r8, %0\n" ++ "mov %%sp, r8\n" ++ "mov %%fp, %%sp\n" ++ : /* no output */ ++ : "m" (stack_ptr) ++ : "memory"); ++ ++ smp_init_slave_cpu_func(get_this_cpu_id()); ++ ++ set_data_flag(); ++ /* Make sure other cores see written value in memory */ ++ flush_dcache_all(); ++ ++ /* Halt the processor untill the master kick us again */ ++ this_cpu_halt(); ++ ++ nop_instr(); ++ nop_instr(); ++ nop_instr(); ++ ++ /* Run our program */ ++ ((void (*)(void))(hsdk_env_per_cpu_ctl[get_this_cpu_id()].entry))(); ++ ++ /* Something went terribly wrong */ ++ while (true) ++ this_cpu_halt(); ++} ++ ++static void do_init_slave_cpu(u32 cpu_id) ++{ ++ u32 timeout = 50000; ++ ++ data_flag = 0; ++ ++ /* Use global unic place for slave cpu stack */ ++ /* TODO: optimize memory usage, now we have one unused aperture */ ++ stack_ptr = (u32)(slave_stack + (64 * cpu_id)); ++ ++ /* TODO: remove useless debug's in do_init_slave_cpu */ ++ debug("CPU %u: STACK: %x\n", cpu_id, stack_ptr); ++ debug("CPU %u: comm STACK: %p\n", cpu_id, slave_stack); ++ smp_set_core_boot_addr((unsigned long)hsdk_core_init_f, -1); ++ ++ /* Make sure other cores see written value in memory */ ++ flush_dcache_all(); ++ ++ smp_kick_cpu_x(cpu_id); ++ ++ debug("CPU %u: FLAG0: %x\n", cpu_id, data_flag); ++ while (!data_flag && timeout) ++ timeout--; ++ ++ /* 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); ++ ++ debug("CPU %u: FLAG1: %x\n", cpu_id, data_flag); ++} ++ ++static void do_init_slave_cpus(void) ++{ ++ u32 i; ++ ++ for (i = 1; i < MAX_CPUS; i++) ++ if (hsdk_env_per_cpu_ctl[i].used) ++ do_init_slave_cpu(i); ++} ++ ++static void do_init_master_cpu(void) ++{ ++ if (hsdk_env_per_cpu_ctl[MASTER_CPU].used) { ++ init_master_icache(); ++ init_master_dcache(); ++ } ++} ++ ++/* ********************* SMP: END ********************* */ ++ ++static int check_master_cpu_id(void) ++{ ++ if (get_this_cpu_id() == MASTER_CPU) ++ return 0; ++ ++ pr_err("u-boot runs on non-master cpu with id: %u\n", get_this_cpu_id()); ++ ++ return -ENOENT; ++} ++ ++static int do_hsdk_go(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) ++{ ++ u32 i, reg; ++ ulong rate; ++ int ret; ++ ++ printf("HSDK: hsdk_go version: %s\n", HSDKGO_VERSION); ++ ++ /* Check for 'halt' parameter. 'halt' = enter halt-mode just before ++ * starting the application; can be used for debug */ ++ if (argc > 1) { ++ hsdk_env_common_ctl.halt_on_boot = !strcmp(argv[1], "halt"); ++ if (!hsdk_env_common_ctl.halt_on_boot) { ++ pr_err("Unrecognised parameter: \'%s\'\n", argv[1]); ++ return -EINVAL; ++ } ++ } ++ ++ ret = check_master_cpu_id(); ++ if (ret) ++ return ret; ++ ++ for (i = 0; env_map[i].env_name; i++) { ++ ret = env_process(i); ++ if (ret) ++ return ret; ++ } ++ ++ do_init_slave_cpus(); ++ ++ /* TODO: set frequency, not only read */ ++ soc_clk_ctl("cpu-clk", &rate, false); ++ soc_clk_ctl("sys-clk", &rate, false); ++ soc_clk_ctl("ddr-clk", &rate, false); ++ soc_clk_ctl("tun-clk", &rate, false); ++ ++ /* A multi-core ARC HS configuration always includes only one ++ * AUX_NON_VOLATILE_LIMIT register, which is shared by all the cores. */ ++ init_master_nvlim(); ++ ++ /* Prepare CREG_CPU_START for kicking chosen CPUs */ ++ reg = prepare_cpu_ctart_reg(); ++ ++ do_init_master_cpu(); ++ ++ /* Cleanup caches, disable interrupts */ ++ cleanup_before_go(); ++ ++ if (hsdk_env_common_ctl.halt_on_boot) ++ this_cpu_halt(); ++ ++ /* Kick chosen CPUs */ ++ writel(reg, (void __iomem *)CREG_CPU_START); ++ ++ if (hsdk_env_per_cpu_ctl[MASTER_CPU].used) ++ ((void (*)(void))(hsdk_env_per_cpu_ctl[MASTER_CPU].entry))(); ++ else ++ this_cpu_halt(); ++ ++ pr_err("u-boot still runs on cpu [%d]\n", get_this_cpu_id()); ++ ++ /* We will never return after executing our program if master cpu used ++ * otherwise halt master cpu manually */ ++ while (true) ++ this_cpu_halt(); ++ ++ return 0; ++} ++ ++U_BOOT_CMD( ++ hsdk_go, 3, 0, do_hsdk_go, ++ "Synopsys HSDK specific command", ++ "hsdk_go - Boot stand-alone application on HSDK\n" ++); +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0006-ARC-HSDK-hsdk-go-v0.5.patch b/board/synopsys/hsdk/uboot-patches/0006-ARC-HSDK-hsdk-go-v0.5.patch new file mode 100644 index 00000000000..48718a91476 --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0006-ARC-HSDK-hsdk-go-v0.5.patch @@ -0,0 +1,819 @@ +From 36027229e369687442dd25e96442979ba7544bf9 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Mon, 20 Nov 2017 14:03:20 +0300 +Subject: [PATCH 06/46] ARC: HSDK: hsdk-go v0.5 + +The new hsdk u-boot v0.5 with significant changes: + * Now we use environment when launching linux. + * All aliases like 'hsdk_hs38x3' were added. + * We are able to set CPU frequency. + * Default environment was added. + * A lot of small limitations were fixed + +Signed-off-by: Eugeniy Paltsev +--- + arch/arc/lib/bootm.c | 11 +- + board/synopsys/hsdk/hsdk-cmd.c | 521 ++++++++++++++++++++++++----------------- + include/configs/hsdk.h | 3 + + 3 files changed, 317 insertions(+), 218 deletions(-) + +diff --git a/arch/arc/lib/bootm.c b/arch/arc/lib/bootm.c +index a498ce5b29..d4fddc38b3 100644 +--- a/arch/arc/lib/bootm.c ++++ b/arch/arc/lib/bootm.c +@@ -58,8 +58,7 @@ static void boot_prep_linux(bootm_headers_t *images) + hang(); + } + +-__weak void smp_set_core_boot_addr(unsigned long addr, int corenr) {} +-__weak void smp_kick_all_cpus(void) {} ++__weak int bootm_prepare_and_run(u32 entry) { return 0; } + + /* Subcommand: GO */ + static void boot_jump_linux(bootm_headers_t *images, int flag) +@@ -88,11 +87,13 @@ static void boot_jump_linux(bootm_headers_t *images, int flag) + r2 = (unsigned int)env_get("bootargs"); + } + +- smp_set_core_boot_addr((unsigned long)kernel_entry, -1); +- smp_kick_all_cpus(); ++ if (!fake) { ++ //TODO: split for prepare and run ++ if (bootm_prepare_and_run((u32)kernel_entry)) ++ return; + +- if (!fake) + kernel_entry(r0, 0, r2); ++ } + } + + int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images) +diff --git a/board/synopsys/hsdk/hsdk-cmd.c b/board/synopsys/hsdk/hsdk-cmd.c +index f3b8a1d43d..776865fecd 100644 +--- a/board/synopsys/hsdk/hsdk-cmd.c ++++ b/board/synopsys/hsdk/hsdk-cmd.c +@@ -1,4 +1,4 @@ +-#define DEBUG ++//#define DEBUG + + #include + #include +@@ -9,55 +9,73 @@ + #include + #include + +-#define HSDKGO_VERSION "0.4" ++#ifdef CONFIG_CPU_BIG_ENDIAN ++ #error "hsdk_go will not work with BIG endian CPU" ++#endif ++ ++#define HSDKGO_VERSION "0.5" ++ ++#define ceil(x, y) ({ ulong __x = (x), __y = (y); (__x + __y - 1) / __y; }) + +-#define MAX_CPUS 4 ++#define NR_CPUS 4 + #define MASTER_CPU 0 +-#define MAX_CMD_LEN 40 ++#define MAX_CMD_LEN 25 + +-#define VAL_NO_XCCM 0x10 ++#define NO_CCM 0x10 + + void smp_set_core_boot_addr(unsigned long addr, int corenr); + +-struct hsdk_per_cpu_ctl { +- bool used; +- u32 entry; +- u32 icache; +- u32 dcache; +- u32 iccm; +- u32 dccm; ++typedef struct { ++ u32 val; ++ bool set; ++} u32_env; ++ ++struct hsdk_env_core_ctl { ++ bool used[NR_CPUS]; ++ u32_env entry[NR_CPUS]; ++ u32_env iccm[NR_CPUS]; ++ u32_env dccm[NR_CPUS]; + }; + +-struct hsdk_common_ctl { ++struct hsdk_env_common_ctl { + bool halt_on_boot; +- u32 core_mask; +- u32 cpu_freq; +- u32 axi_freq; +- u32 tun_freq; +- u32 nvlim; ++ 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; + }; + +-struct hsdk_env_map { ++struct hsdk_env_map_common { + const char * const env_name; +- bool core_specific; + bool mandatory; + u32 min; + u32 max; +- int (* func)(u32, u32); ++ u32_env *val; + }; + +-/* Temporary place for slave cpu stack */ ++struct hsdk_env_map_core { ++ const char * const env_name; ++ bool mandatory; ++ u32 min[NR_CPUS]; ++ u32 max[NR_CPUS]; ++ u32_env (*val)[NR_CPUS]; ++}; ++ ++/* Place for slave cpu temporary stack */ + static u32 slave_stack[1024] __attribute__((aligned(4))); + +-static struct hsdk_per_cpu_ctl hsdk_env_per_cpu_ctl[MAX_CPUS] = {}; +-static struct hsdk_common_ctl hsdk_env_common_ctl = {}; ++static struct hsdk_env_common_ctl env_common = {}; ++static struct hsdk_env_core_ctl env_core = {}; + + int soc_clk_ctl(const char *name, ulong *rate, bool set) + { + int ret; + struct clk clk; + +- /* Dummy fmeas device, just to able to use standard clk_* api funcs */ ++ /* Dummy fmeas device, just to be able to use standard clk_* api funcs */ + struct udevice fmeas = { + .name = "clk-fmeas", + .node = ofnode_path("/clk-fmeas"), +@@ -81,207 +99,165 @@ int soc_clk_ctl(const char *name, ulong *rate, bool set) + + clk_free(&clk); + +- printf("HSDK: clock %s rate %lu\n", name, *rate); ++ printf("HSDK: clock '%s' rate %lu MHz\n", name, ceil(*rate, 1000000)); + + return 0; + } + +-static int core_ccm_check(u32 core, u32 val) ++static bool is_cpu_used(u32 cpu_id) + { +- /* Cores 0 and 2 don't have ICCM and DCCM */ +- if ((core == 0 || core == 2) && val != VAL_NO_XCCM) { +- pr_err("Cores 0 and 2 don't have ICCM and DCCM"); +- return -EINVAL; +- } +- +- /* Cores 1 and 3 have ICCM and DCCM */ +- if ((core == 1 || core == 3) && val == VAL_NO_XCCM) { +- pr_err("Cores 1 and 3 have ICCM and DCCM, we can't disable it"); +- return -EINVAL; +- } +- +- return 0; ++ return !!(env_common.core_mask.val & BIT(cpu_id)); + } + +-int do_core_mask(u32 core, u32 val) +-{ +- hsdk_env_common_ctl.core_mask = val; ++static const struct hsdk_env_map_common env_map_common[] = { ++ { "core_mask", true, 0x1, 0xF, &env_common.core_mask }, ++ { "cpu_freq", false, 100, 1000, &env_common.cpu_freq }, ++ { "axi_freq", false, 200, 800, &env_common.axi_freq }, ++ { "tun_freq", false, 0, 150, &env_common.tun_freq }, ++ { "non_volatile_limit", true, 0x1, 0xF, &env_common.nvlim }, ++ { "icache_ena", true, 0, 1, &env_common.icache }, ++ { "dcache_ena", true, 0, 1, &env_common.dcache }, ++ {} ++}; + +- if (val & 0x1) +- hsdk_env_per_cpu_ctl[0].used = true; ++static const struct hsdk_env_map_core env_map_core[] = { ++ { "core_entry", true, {0, 0, 0, 0}, {U32_MAX, U32_MAX, U32_MAX, U32_MAX}, &env_core.entry }, ++ { "core_iccm", true, {NO_CCM, 0, NO_CCM, 0}, {NO_CCM, 0xF, NO_CCM, 0xF}, &env_core.iccm }, ++ { "core_dccm", true, {NO_CCM, 0, NO_CCM, 0}, {NO_CCM, 0xF, NO_CCM, 0xF}, &env_core.dccm }, ++ {} ++}; + +- if (val & 0x2) +- hsdk_env_per_cpu_ctl[1].used = true; ++static int env_read_common(u32 index) ++{ ++ u32 val; + +- if (val & 0x4) +- hsdk_env_per_cpu_ctl[2].used = true; ++ if (!env_get_yesno(env_map_common[index].env_name)) { ++ val = (u32)env_get_hex(env_map_common[index].env_name, 0); ++ debug("ENV: %s = %#x\n", env_map_common[index].env_name, val); + +- if (val & 0x8) +- hsdk_env_per_cpu_ctl[3].used = true; ++ env_map_common[index].val->val = val; ++ env_map_common[index].val->set = true; ++ } + + return 0; + } + +-int do_cpu_freq(u32 core, u32 val) ++/* process core specific variables */ ++static int env_read_core(u32 index) + { +- hsdk_env_common_ctl.cpu_freq = val; +- return 0; +-} ++ u32 i, val; ++ char comand[MAX_CMD_LEN]; + +-int do_axi_freq(u32 core, u32 val) +-{ +- hsdk_env_common_ctl.axi_freq = val; +- return 0; +-} ++ for (i = 0; i < NR_CPUS; i++) { ++ sprintf(comand, "%s_%u", env_map_core[index].env_name, i); ++ if (!env_get_yesno(comand)) { ++ val = (u32)env_get_hex(comand, 0); ++ debug("ENV: %s: = %#x\n", comand, val); + +-int do_tun_freq(u32 core, u32 val) +-{ +- hsdk_env_common_ctl.tun_freq = val; +- return 0; +-} ++ (*env_map_core[index].val)[i].val = val; ++ (*env_map_core[index].val)[i].set = true; ++ } ++ } + +-int do_core_entry(u32 core, u32 val) +-{ +- hsdk_env_per_cpu_ctl[core].entry = val; + return 0; + } + +-int do_icache_ena(u32 core, u32 val) ++/* environment common verification */ ++static int env_validate_common(u32 index) + { +- hsdk_env_per_cpu_ctl[core].icache = val; +- return 0; +-} ++ u32 value = env_map_common[index].val->val; ++ bool set = env_map_common[index].val->set; ++ u32 min = env_map_common[index].min; ++ u32 max = env_map_common[index].max; + +-int do_dcache_ena(u32 core, u32 val) +-{ +- hsdk_env_per_cpu_ctl[core].dcache = val; +- return 0; +-} ++ /* Check if environment is mandatory */ ++ if (env_map_common[index].mandatory && !set) { ++ pr_err("Variable \'%s\' is mandatory, but it is not defined\n", ++ env_map_common[index].env_name); + +-int do_aux_iccm(u32 core, u32 val) +-{ +- if (core_ccm_check(core, val)) + return -EINVAL; ++ } + +- hsdk_env_per_cpu_ctl[core].iccm = val; +- return 0; +-} ++ /* Check environment boundary */ ++ if (set && (value < min || value > max)) { ++ pr_err("Variable \'%s\' must be between %#x and %#x\n", ++ env_map_common[index].env_name, min, max); + +-int do_aux_dccm(u32 core, u32 val) +-{ +- if (core_ccm_check(core, val)) + return -EINVAL; ++ } + +- hsdk_env_per_cpu_ctl[core].dccm = val; +- return 0; +-} +- +-int do_aux_nvlimn(u32 core, u32 val) +-{ +- hsdk_env_common_ctl.nvlim = val; + return 0; + } + +-/* TODO: add default values */ +-static const struct hsdk_env_map env_map[] = { +- { "core_mask", false, true, 0x1, 0xF, do_core_mask }, +- /* core_mask must be first table entry */ +- { "cpu_freq", false, false, 100, 1000, do_cpu_freq }, +- { "axi_freq", false, false, 200, 800, do_axi_freq }, +- { "tun_freq", false, false, 0, 150, do_tun_freq }, +- { "non_volatile_limit", false, true, 0x1, 0xF, do_aux_nvlimn }, +- +- { "core_entry", true, true, 0, U32_MAX, do_core_entry }, +- { "core_icache_ena", true, true, 0, 1, do_icache_ena }, +- { "core_dcache_ena", true, true, 0, 1, do_dcache_ena }, +- { "core_aux_iccm", true, true, 0x1, VAL_NO_XCCM, do_aux_iccm }, +- { "core_aux_dccm", true, true, 0x1, VAL_NO_XCCM, do_aux_dccm }, +- {} +-}; +- +-static int check_env_bound(u32 index, u32 val) ++static int env_validate_core(u32 index) + { +- if (val < env_map[index].min || val > env_map[index].max) { +- pr_err("\'%s\' must be between %#x and %#x\n", env_map[index].env_name, +- env_map[index].min, env_map[index].max); ++ u32 i; ++ u32 value; ++ bool set; ++ bool mandatory = env_map_core[index].mandatory; ++ u32 min, max; + +- return -EINVAL; +- } ++ for (i = 0; i < NR_CPUS; i++) { ++ set = (*env_map_core[index].val)[i].set; ++ value = (*env_map_core[index].val)[i].val; + +- return 0; +-} ++ /* Check if environment is mandatory */ ++ if (is_cpu_used(i) && !(mandatory && set)) { ++ pr_err("CPU %u is used, but \'%s_%u\' is not defined\n", ++ i, env_map_core[index].env_name, i); + +-static int check_env_core_specific(u32 env_index, u32 cpu_index) +-{ +- /* We assume if slave CPU[x] is enabled all of mandatory x CPU +- * environment variables must be set */ +- if (hsdk_env_per_cpu_ctl[cpu_index].used && env_map[env_index].mandatory) { +- pr_err("CPU %u is used, but \'%s_%u\' is not defined\n", +- cpu_index, env_map[env_index].env_name, cpu_index); +- return -EINVAL; +- } ++ return -EINVAL; ++ } + +- return 0; +-} ++ min = env_map_core[index].min[i]; ++ max = env_map_core[index].max[i]; + +-static int check_env_common(u32 env_index) +-{ +- if (env_map[env_index].mandatory) { +- pr_err("Variable \'%s\' is mandatory, but it is not defined\n", +- env_map[env_index].env_name); ++ /* Check environment boundary */ ++ if (set && (value < min || value > max)) { ++ pr_err("Variable \'%s_%u\' must be between %#x and %#x\n", ++ env_map_core[index].env_name, i, min, max); + +- return -EINVAL; ++ return -EINVAL; ++ } + } + + return 0; + } + +-/* TODO: refactor: split variable get and check */ +-static int env_process(u32 index) ++static int env_process_and_validate(void) + { +- u32 i, val; +- char comand[MAX_CMD_LEN]; ++ u32 i; ++ int ret; + +- if (!env_map[index].core_specific) { +- if (!env_get_yesno(env_map[index].env_name)) { +- val = (u32)env_get_hex(env_map[index].env_name, 0); +- if (check_env_bound(index, val)) +- return -EINVAL; +- +- debug("ENV: %s = %#x\n", env_map[index].env_name, val); +- if (env_map[index].func(0, val)) +- return -EINVAL; +- } else { +- /* Check if it is OK, that this variable isn't defined */ +- if (check_env_common(index)) +- return -EINVAL; +- } ++ /* Generic read */ ++ for (i = 0; env_map_common[i].env_name; i++) { ++ ret = env_read_common(i); ++ if (ret) ++ return ret; ++ } + +- return 0; ++ for (i = 0; env_map_core[i].env_name; i++) { ++ ret = env_read_core(i); ++ if (ret) ++ return ret; + } + +- /* process core specific variables */ +- for (i = 0; i < MAX_CPUS; i++) { +- sprintf(comand, "%s_%u", env_map[index].env_name, i); +- if (!env_get_yesno(comand)) { +- val = (u32)env_get_hex(comand, 0); +- if (check_env_bound(index, val)) +- return -EINVAL; ++ /* Generic validate */ ++ for (i = 0; env_map_common[i].env_name; i++) { ++ ret = env_validate_common(i); ++ if (ret) ++ return ret; ++ } + +- debug("ENV: %s: = %#x\n", comand, val); +- if (env_map[index].func(i, val)) +- return -EINVAL; +- } else { +- /* Check if it is OK, that this variable isn't defined */ +- if (check_env_core_specific(index, i)) +- return -EINVAL; +- } ++ for (i = 0; env_map_core[i].env_name; i++) { ++ ret = env_validate_core(i); ++ if (ret) ++ return ret; + } + + return 0; + } + +- + #define APT_SHIFT 28 + + /* Bit values in IC_CTRL */ +@@ -311,25 +287,25 @@ static void smp_init_slave_cpu_func(u32 core) + unsigned int r; + + /* ICCM move if exists */ +- if (hsdk_env_per_cpu_ctl[core].iccm != VAL_NO_XCCM) { ++ if (env_core.iccm[core].val != NO_CCM) { + r = ARC_REG_AUX_ICCM; +- write_aux_reg(r, hsdk_env_per_cpu_ctl[core].iccm << APT_SHIFT); ++ write_aux_reg(r, env_core.iccm[core].val << APT_SHIFT); + } + + /* DCCM move if exists */ +- if (hsdk_env_per_cpu_ctl[core].dccm != VAL_NO_XCCM) { ++ if (env_core.dccm[core].val != NO_CCM) { + r = ARC_REG_AUX_DCCM; +- write_aux_reg(r, hsdk_env_per_cpu_ctl[core].dccm << APT_SHIFT); ++ write_aux_reg(r, env_core.dccm[core].val << APT_SHIFT); + } + + /* i$ enable if required (it is disabled by default) */ +- if (hsdk_env_per_cpu_ctl[core].icache) { ++ if (env_common.icache.val) { + r = ARC_AUX_IC_CTRL; + write_aux_reg(r, read_aux_reg(r) & ~IC_CTRL_CACHE_DISABLE); + } + + /* d$ enable if required (it is disabled by default) */ +- if (hsdk_env_per_cpu_ctl[core].dcache) { ++ if (env_common.dcache.val) { + r = ARC_AUX_DC_CTRL; + write_aux_reg(r, read_aux_reg(r) & ~(DC_CTRL_CACHE_DISABLE | DC_CTRL_INV_MODE_FLUSH)); + } +@@ -337,7 +313,7 @@ static void smp_init_slave_cpu_func(u32 core) + + static void init_master_nvlim(void) + { +- u32 val = hsdk_env_common_ctl.nvlim << APT_SHIFT; ++ u32 val = env_common.nvlim.val << APT_SHIFT; + + flush_dcache_all(); + write_aux_reg(AUX_NON_VOLATILE_LIMIT, val); +@@ -354,14 +330,14 @@ static void init_master_icache(void) + + #ifndef CONFIG_SYS_ICACHE_OFF + /* enable if required, else - nothing to do */ +- if (hsdk_env_per_cpu_ctl[MASTER_CPU].icache) { ++ if (env_common.icache.val) { + r = ARC_AUX_IC_CTRL; + write_aux_reg(r, read_aux_reg(r) & ~IC_CTRL_CACHE_DISABLE); + } + #else + /* disable if required, else - nothing to do (we will invalidate i$ + * just before app launch) */ +- if (!hsdk_env_per_cpu_ctl[MASTER_CPU].icache) { ++ if (!env_common.icache.val) { + /* next code copied from board_hsdk.c */ + /* instruction cache invalidate */ + write_aux_reg(ARC_AUX_IC_IVIC, 0x00000001U); +@@ -382,14 +358,14 @@ static void init_master_dcache(void) + + #ifndef CONFIG_SYS_ICACHE_OFF + /* enable if required, else - nothing to do */ +- if (hsdk_env_per_cpu_ctl[MASTER_CPU].dcache) { ++ if (env_common.dcache.val) { + r = ARC_AUX_DC_CTRL; + write_aux_reg(r, read_aux_reg(r) & ~(DC_CTRL_CACHE_DISABLE | DC_CTRL_INV_MODE_FLUSH)); + } + #else + /* disable if required, else - nothing to do (we will flush d$ and sl$ + * just before app launch) */ +- if (!hsdk_env_per_cpu_ctl[MASTER_CPU].dcache) { ++ if (!env_common.dcache.val) { + /* next code copied from board_hsdk.c */ + flush_dcache_all(); /* TODO: it is OK if we flush SL$ too? */ + /* data cache ctrl: invalidate mode to: invalidate dc and flush +@@ -451,7 +427,7 @@ static void smp_kick_cpu_x(u32 cpu_id) + { + int cmd = readl((void __iomem *)CREG_CPU_START); + +- if (cpu_id > MAX_CPUS) ++ if (cpu_id > NR_CPUS) + return; + + cmd &= ~CPU_START_MASK; +@@ -465,7 +441,7 @@ static u32 prepare_cpu_ctart_reg(void) + + cmd &= ~CPU_START_MASK; + +- return cmd | hsdk_env_common_ctl.core_mask; ++ return cmd | env_common.core_mask.val; + } + + volatile u32 data_flag; +@@ -504,7 +480,7 @@ __attribute__((naked, noreturn, flatten)) noinline void hsdk_core_init_f(void) + nop_instr(); + + /* Run our program */ +- ((void (*)(void))(hsdk_env_per_cpu_ctl[get_this_cpu_id()].entry))(); ++ ((void (*)(void))(env_core.entry[get_this_cpu_id()].val))(); + + /* Something went terribly wrong */ + while (true) +@@ -547,14 +523,14 @@ static void do_init_slave_cpus(void) + { + u32 i; + +- for (i = 1; i < MAX_CPUS; i++) +- if (hsdk_env_per_cpu_ctl[i].used) ++ for (i = 1; i < NR_CPUS; i++) ++ if (env_core.used[i]) + do_init_slave_cpu(i); + } + + static void do_init_master_cpu(void) + { +- if (hsdk_env_per_cpu_ctl[MASTER_CPU].used) { ++ if (env_core.used[MASTER_CPU]) { + init_master_icache(); + init_master_dcache(); + } +@@ -572,62 +548,60 @@ static int check_master_cpu_id(void) + return -ENOENT; + } + +-static int do_hsdk_go(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) ++static int prepare_cpus(u32 *cpu_start_reg) + { +- u32 i, reg; ++ u32 i; + ulong rate; ++ bool set; + int ret; + +- printf("HSDK: hsdk_go version: %s\n", HSDKGO_VERSION); +- +- /* Check for 'halt' parameter. 'halt' = enter halt-mode just before +- * starting the application; can be used for debug */ +- if (argc > 1) { +- hsdk_env_common_ctl.halt_on_boot = !strcmp(argv[1], "halt"); +- if (!hsdk_env_common_ctl.halt_on_boot) { +- pr_err("Unrecognised parameter: \'%s\'\n", argv[1]); +- return -EINVAL; +- } +- } +- + ret = check_master_cpu_id(); + if (ret) + return ret; + +- for (i = 0; env_map[i].env_name; i++) { +- ret = env_process(i); +- if (ret) +- return ret; ++ ret = env_process_and_validate(); ++ if (ret) ++ return ret; ++ ++ for (i = 0; i < NR_CPUS; i++) { ++ env_core.used[i] = is_cpu_used(i); + } + + do_init_slave_cpus(); + +- /* TODO: set frequency, not only read */ +- soc_clk_ctl("cpu-clk", &rate, false); ++ rate = env_common.cpu_freq.val * 1000000; ++ set = env_common.cpu_freq.set; ++ soc_clk_ctl("cpu-clk", &rate, set); ++ /* TODO: set AXI and TUN frequency, not only read */ + soc_clk_ctl("sys-clk", &rate, false); +- soc_clk_ctl("ddr-clk", &rate, false); + soc_clk_ctl("tun-clk", &rate, false); ++ soc_clk_ctl("ddr-clk", &rate, false); + + /* A multi-core ARC HS configuration always includes only one + * AUX_NON_VOLATILE_LIMIT register, which is shared by all the cores. */ + init_master_nvlim(); + + /* Prepare CREG_CPU_START for kicking chosen CPUs */ +- reg = prepare_cpu_ctart_reg(); ++ *cpu_start_reg = prepare_cpu_ctart_reg(); + + do_init_master_cpu(); + ++ return 0; ++} ++ ++static int hsdk_go_run(u32 cpu_start_reg) ++{ + /* Cleanup caches, disable interrupts */ + cleanup_before_go(); + +- if (hsdk_env_common_ctl.halt_on_boot) ++ if (env_common.halt_on_boot) + this_cpu_halt(); + + /* Kick chosen CPUs */ +- writel(reg, (void __iomem *)CREG_CPU_START); ++ writel(cpu_start_reg, (void __iomem *)CREG_CPU_START); + +- if (hsdk_env_per_cpu_ctl[MASTER_CPU].used) +- ((void (*)(void))(hsdk_env_per_cpu_ctl[MASTER_CPU].entry))(); ++ if (env_core.used[MASTER_CPU]) ++ ((void (*)(void))(env_core.entry[MASTER_CPU].val))(); + else + this_cpu_halt(); + +@@ -641,6 +615,127 @@ static int do_hsdk_go(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) + return 0; + } + ++static int bootm_run(u32 cpu_start_reg) ++{ ++ debug("bootm cpumask: %#x\n", cpu_start_reg); ++ ++ /* Cleanup caches, disable interrupts */ ++ cleanup_before_go(); ++ ++ /* Kick chosen CPUs */ ++ writel(cpu_start_reg, (void __iomem *)CREG_CPU_START); ++ ++ return 0; ++} ++ ++static int hsdk_go_prepare_and_run(void) ++{ ++ int ret; ++ u32 reg; ++ ++ ret = prepare_cpus(®); ++ if (ret) ++ return ret; ++ ++ return hsdk_go_run(reg); ++} ++ ++int bootm_prepare_and_run(u32 entry) ++{ ++ int ret; ++ u32 i, reg; ++ char comand[MAX_CMD_LEN]; ++ ++ /* override core entry env by value from image*/ ++ for (i = 0; i < NR_CPUS; i++) { ++ sprintf(comand, "%s_%u", "core_entry", i); ++ env_set_hex(comand, entry); ++ } ++ ++ ret = prepare_cpus(®); ++ if (ret) ++ return ret; ++ ++ return bootm_run(reg); ++} ++ ++//static int prepare_and_run(void) ++//{ ++// u32 i, reg; ++// ulong rate; ++// int ret; ++// ++// ret = check_master_cpu_id(); ++// if (ret) ++// return ret; ++// ++// ret = env_process_and_validate(); ++// if (ret) ++// return ret; ++// ++// for (i = 0; i < NR_CPUS; i++) { ++// env_core.used[i] = is_cpu_used(i); ++// } ++// ++// do_init_slave_cpus(); ++// ++// /* TODO: set frequency, not only read */ ++// soc_clk_ctl("cpu-clk", &rate, false); ++// soc_clk_ctl("sys-clk", &rate, false); ++// soc_clk_ctl("ddr-clk", &rate, false); ++// soc_clk_ctl("tun-clk", &rate, false); ++// ++// /* A multi-core ARC HS configuration always includes only one ++// * AUX_NON_VOLATILE_LIMIT register, which is shared by all the cores. */ ++// init_master_nvlim(); ++// ++// /* Prepare CREG_CPU_START for kicking chosen CPUs */ ++// reg = prepare_cpu_ctart_reg(); ++// ++// do_init_master_cpu(); ++// ++// /* Cleanup caches, disable interrupts */ ++// cleanup_before_go(); ++// ++// if (env_common.halt_on_boot) ++// this_cpu_halt(); ++// ++// /* Kick chosen CPUs */ ++// writel(reg, (void __iomem *)CREG_CPU_START); ++// ++// if (env_core.used[MASTER_CPU]) ++// ((void (*)(void))(env_core.entry[MASTER_CPU].val))(); ++// else ++// this_cpu_halt(); ++// ++// pr_err("u-boot still runs on cpu [%d]\n", get_this_cpu_id()); ++// ++// /* We will never return after executing our program if master cpu used ++// * otherwise halt master cpu manually */ ++// while (true) ++// this_cpu_halt(); ++// ++// return 0; ++//} ++ ++static int do_hsdk_go(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) ++{ ++ /* TODO: delete after release */ ++ printf("HSDK: hsdk_go version: %s\n", HSDKGO_VERSION); ++ ++ /* 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 -EINVAL; ++ } ++ } ++ ++ return hsdk_go_prepare_and_run(); ++} ++ + U_BOOT_CMD( + hsdk_go, 3, 0, do_hsdk_go, + "Synopsys HSDK specific command", +diff --git a/include/configs/hsdk.h b/include/configs/hsdk.h +index 0ac8022275..157ae413b3 100644 +--- a/include/configs/hsdk.h ++++ b/include/configs/hsdk.h +@@ -79,4 +79,7 @@ + */ + #define CONFIG_BOUNCE_BUFFER + ++/* Cli configuration */ ++#define CONFIG_SYS_CBSIZE 2048 ++ + #endif /* _CONFIG_HSDK_H_ */ +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0007-ARC-HSDK-add-default-environment.patch b/board/synopsys/hsdk/uboot-patches/0007-ARC-HSDK-add-default-environment.patch new file mode 100644 index 00000000000..f20943894ef --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0007-ARC-HSDK-add-default-environment.patch @@ -0,0 +1,46 @@ +From 611887da40d3ea121cddbcb4f2125abe4b5a5702 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Mon, 20 Nov 2017 22:52:41 +0300 +Subject: [PATCH 07/46] ARC: HSDK: add default environment + +Signed-off-by: Eugeniy Paltsev +--- + include/configs/hsdk.h | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/include/configs/hsdk.h b/include/configs/hsdk.h +index 157ae413b3..9eacafb25f 100644 +--- a/include/configs/hsdk.h ++++ b/include/configs/hsdk.h +@@ -61,6 +61,28 @@ + */ + #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 + */ +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0008-ARC-HSDK-Add-composite-clock-driver.patch b/board/synopsys/hsdk/uboot-patches/0008-ARC-HSDK-Add-composite-clock-driver.patch new file mode 100644 index 00000000000..5961c3afb36 --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0008-ARC-HSDK-Add-composite-clock-driver.patch @@ -0,0 +1,651 @@ +From 3e27d0c4a3b1ded1591a3bc40011a1a96f8ede45 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Mon, 27 Nov 2017 20:37:16 +0300 +Subject: [PATCH 08/46] ARC: HSDK: Add composite clock driver + +Add composite clock driver which supports CPU, SYSTEM, TUNNEL, +HDMI, DDR PPLs and all their clock childs. + +Signed-off-by: Eugeniy Paltsev +--- + drivers/clk/Makefile | 1 + + drivers/clk/clk-hsdk-cgu-mappings.h | 24 ++ + drivers/clk/clk-hsdk-cgu.c | 583 ++++++++++++++++++++++++++++++++++++ + 3 files changed, 608 insertions(+) + create mode 100644 drivers/clk/clk-hsdk-cgu-mappings.h + create mode 100644 drivers/clk/clk-hsdk-cgu.c + +diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile +index 4b6cc1935d..6425efa3b6 100644 +--- a/drivers/clk/Makefile ++++ b/drivers/clk/Makefile +@@ -21,6 +21,7 @@ obj-$(CONFIG_CLK_AT91) += at91/ + obj-$(CONFIG_CLK_BCM6345) += clk_bcm6345.o + obj-$(CONFIG_CLK_BOSTON) += clk_boston.o + obj-$(CONFIG_CLK_HSDK) += hsdk-clk.o ++obj-$(CONFIG_CLK_HSDK) += clk-hsdk-cgu.o + obj-$(CONFIG_ARCH_ASPEED) += aspeed/ + obj-$(CONFIG_STM32F7) += clk_stm32f7.o + obj-$(CONFIG_STM32H7) += clk_stm32h7.o +diff --git a/drivers/clk/clk-hsdk-cgu-mappings.h b/drivers/clk/clk-hsdk-cgu-mappings.h +new file mode 100644 +index 0000000000..f76a3b91a9 +--- /dev/null ++++ b/drivers/clk/clk-hsdk-cgu-mappings.h +@@ -0,0 +1,24 @@ ++#define CLK_ARC_PLL 0 ++#define CLK_ARC 1 ++#define CLK_DDR_PLL 2 ++#define CLK_SYS_PLL 3 ++#define CLK_SYS_APB 4 ++#define CLK_SYS_AXI 5 ++#define CLK_SYS_ETH 6 ++#define CLK_SYS_USB 7 ++#define CLK_SYS_SDIO 8 ++#define CLK_SYS_HDMI 9 ++#define CLK_SYS_GFX_CORE 10 ++#define CLK_SYS_GFX_DMA 11 ++#define CLK_SYS_GFX_CFG 12 ++#define CLK_SYS_DMAC_CORE 13 ++#define CLK_SYS_DMAC_CFG 14 ++#define CLK_SYS_SDIO_REF 15 ++#define CLK_SYS_SPI_REF 16 ++#define CLK_SYS_I2C_REF 17 ++#define CLK_SYS_UART_REF 18 ++#define CLK_SYS_EBI_REF 19 ++#define CLK_TUN_PLL 20 ++#define CLK_TUN 21 ++#define CLK_HDMI_PLL 22 ++#define CLK_HDMI 23 +diff --git a/drivers/clk/clk-hsdk-cgu.c b/drivers/clk/clk-hsdk-cgu.c +new file mode 100644 +index 0000000000..048b172bad +--- /dev/null ++++ b/drivers/clk/clk-hsdk-cgu.c +@@ -0,0 +1,583 @@ ++/* ++ * Synopsys HSDK SDP CGU clock driver ++ * ++ * Copyright (C) 2017 Synopsys ++ * Author: Eugeniy Paltsev ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++#include "clk-hsdk-cgu-mappings.h" ++ ++#define CGU_ARC_PLL_CTRL 0x000 //RW ARC PLL control register ++#define CGU_ARC_PLL_STATUS 0x004 //R ARC PLL status register ++ ++#define CGU_SYS_PLL_CTRL 0x010 //RW SYS PLL control register ++#define CGU_SYS_PLL_STATUS 0x014 //R SYS PLL status register ++ ++#define CGU_DDR_PLL_CTRL 0x020 //RW DDR PLL control register ++#define CGU_DDR_PLL_STATUS 0x024 //R DDR PLL status register ++ ++#define CGU_TUN_PLL_CTRL 0x030 //RW Tunnel PLL control register ++#define CGU_TUN_PLL_STATUS 0x034 //R Tunnel PLL status register ++ ++#define CGU_HDMI_PLL_CTRL 0x040 //RW HDMI PLL control register ++#define CGU_HDMI_PLL_STATUS 0x044 //R HDMI PLL status register ++ ++#define CGU_ARC_IDIV 0x080 //RW Integer divider register for ARC HS38x4 clock ++ ++#define CGU_SYS_IDIV_APB 0x180 //RW Integer divider register for APB clock ++#define CGU_SYS_IDIV_AXI 0x190 //RW Integer divider register for AXI clock ++#define CGU_SYS_IDIV_ETH 0x1A0 //RW Integer divider register for ETH clock ++#define CGU_SYS_IDIV_USB 0x1B0 //RW Integer divider register for USB clock ++#define CGU_SYS_IDIV_SDIO 0x1C0 //RW Integer divider register for SDIO clock ++#define CGU_SYS_IDIV_HDMI 0x1D0 //RW Integer divider register for HDMI clock ++#define CGU_SYS_IDIV_GFX_CORE 0x1E0 //RW Integer divider register for GFX core clock ++#define CGU_SYS_IDIV_GFX_DMA 0x1F0 //RW Integer divider register for GFX dma clock ++#define CGU_SYS_IDIV_GFX_CFG 0x200 //RW Integer divider register for GFX config clock ++#define CGU_SYS_IDIV_DMAC_CORE 0x210 //RW Integer divider register for DMAC clock ++#define CGU_SYS_IDIV_DMAC_CFG 0x220 //RW Integer divider register for DMAC config clock ++#define CGU_SYS_IDIV_SDIO_REF 0x230 //RW Integer divider register for SDIO reference clock ++#define CGU_SYS_IDIV_SPI_REF 0x240 //RW Integer divider register for SPI reference clock ++#define CGU_SYS_IDIV_I2C_REF 0x250 //RW Integer divider register for I2C reference clock ++#define CGU_SYS_IDIV_UART_REF 0x260 //RW Integer divider register for UART reference clock ++#define CGU_SYS_IDIV_EBI_REF 0x270 //RW Integer divider register for EBI reference clock ++ ++#define CGU_TUN_IDIV 0x380 //RW Integer divider register for Tunnel clock ++ ++#define CGU_HDMI_IDIV_APB 0x480 //RW Integer divider register for HDMI clock ++ ++#define CGU_I2S_IDIV_TX 0x580 //RW Integer divider register for I2S TX clock ++#define CGU_I2S_IDIV_RX 0x590 //RW Integer divider register for I2S RX clock ++ ++//////////////////////// ++#define CGU_PLL_CTRL 0x000 /* ARC PLL control register */ ++#define CGU_PLL_STATUS 0x004 /* ARC PLL status register */ ++#define CGU_PLL_FMEAS 0x008 /* ARC PLL frequency measurement register */ ++#define CGU_PLL_MON 0x00C /* ARC PLL monitor register */ ++ ++#define CGU_PLL_CTRL_ODIV_SHIFT 2 ++#define CGU_PLL_CTRL_IDIV_SHIFT 4 ++#define CGU_PLL_CTRL_FBDIV_SHIFT 9 ++#define CGU_PLL_CTRL_BAND_SHIFT 20 ++ ++#define CGU_PLL_CTRL_ODIV_MASK GENMASK(3, CGU_PLL_CTRL_ODIV_SHIFT) ++#define CGU_PLL_CTRL_IDIV_MASK GENMASK(8, CGU_PLL_CTRL_IDIV_SHIFT) ++#define CGU_PLL_CTRL_FBDIV_MASK GENMASK(15, CGU_PLL_CTRL_FBDIV_SHIFT) ++ ++#define CGU_PLL_CTRL_PD BIT(0) ++#define CGU_PLL_CTRL_BYPASS BIT(1) ++ ++#define CGU_PLL_STATUS_LOCK BIT(0) ++#define CGU_PLL_STATUS_ERR BIT(1) ++ ++#define HSDK_PLL_MAX_LOCK_TIME 100 /* 100 us */ ++ ++#define CREG_CORE_IF_DIV 0x000 /* ARC CORE interface divider */ ++#define CORE_IF_CLK_THRESHOLD_HZ 500000000 ++#define CREG_CORE_IF_CLK_DIV_1 0x0 ++#define CREG_CORE_IF_CLK_DIV_2 0x1 ++ ++#define PARENT_RATE 33333333 /* fixed clock - xtal */ ++//////////////////////// ++ ++#define CGU_ARC_PLL_OFFT 0x0 ++#define CGU_SYS_PLL_OFFT 0x10 ++#define CGU_DDR_PLL_OFFT 0x20 ++#define CGU_TUN_PLL_OFFT 0x30 ++#define CGU_HDMI_PLL_OFFT 0x40 ++ ++#define CGU_MAX_CLOCKS 24 ++ ++#define CGU_IDIV_MASK 0xFF ++ ++struct hsdk_pll_cfg { ++ u32 rate; ++ u32 idiv; ++ u32 fbdiv; ++ u32 odiv; ++ u32 band; ++}; ++ ++static const struct hsdk_pll_cfg asdt_pll_cfg[] = { ++ { 100000000, 0, 11, 3, 0 }, ++ { 125000000, 0, 14, 3, 0 }, ++ { 133000000, 0, 15, 3, 0 }, ++ { 150000000, 0, 17, 3, 0 }, ++ { 200000000, 1, 47, 3, 0 }, ++ { 233000000, 1, 27, 2, 0 }, ++ { 300000000, 1, 35, 2, 0 }, ++ { 333000000, 1, 39, 2, 0 }, ++ { 400000000, 1, 47, 2, 0 }, ++ { 500000000, 0, 14, 1, 0 }, ++ { 600000000, 0, 17, 1, 0 }, ++ { 700000000, 0, 20, 1, 0 }, ++ { 800000000, 0, 23, 1, 0 }, ++ { 900000000, 1, 26, 0, 0 }, ++ { 1000000000, 1, 29, 0, 0 }, ++ { 1100000000, 1, 32, 0, 0 }, ++ { 1200000000, 1, 35, 0, 0 }, ++ { 1300000000, 1, 38, 0, 0 }, ++ { 1400000000, 1, 41, 0, 0 }, ++ { 1500000000, 1, 44, 0, 0 }, ++ { 1600000000, 1, 47, 0, 0 }, ++ {} ++}; ++ ++static const struct hsdk_pll_cfg hdmi_pll_cfg[] = { ++ { 297000000, 0, 21, 2, 0 }, ++ { 540000000, 0, 19, 1, 0 }, ++ { 594000000, 0, 21, 1, 0 }, ++ {} ++}; ++ ++struct hsdk_pll_clk { ++ /* CGU block register */ ++ void __iomem *cgu_regs; ++ /* CREG block register */ ++ void __iomem *creg_regs; ++ ++ /* PLLs registers */ ++ void __iomem *regs; ++ /* PLLs special registers */ ++ void __iomem *spec_regs; ++ /* PLLs devdata */ ++ const struct hsdk_pll_devdata *pll_devdata; ++ ++ /* Dividers registers */ ++ void __iomem *idiv_regs; ++}; ++ ++struct hsdk_pll_devdata { ++ const struct hsdk_pll_cfg *pll_cfg; ++ int (*update_rate)(struct hsdk_pll_clk *clk, unsigned long rate, ++ const struct hsdk_pll_cfg *cfg); ++}; ++ ++static int hsdk_pll_core_update_rate(struct hsdk_pll_clk *, unsigned long, ++ const struct hsdk_pll_cfg *); ++static int hsdk_pll_comm_update_rate(struct hsdk_pll_clk *, unsigned long, ++ const struct hsdk_pll_cfg *); ++ ++static const struct hsdk_pll_devdata core_pll_devdata = { ++ .pll_cfg = asdt_pll_cfg, ++ .update_rate = hsdk_pll_core_update_rate, ++}; ++ ++static const struct hsdk_pll_devdata sdt_pll_devdata = { ++ .pll_cfg = asdt_pll_cfg, ++ .update_rate = hsdk_pll_comm_update_rate, ++}; ++ ++static const struct hsdk_pll_devdata hdmi_pll_devdata = { ++ .pll_cfg = hdmi_pll_cfg, ++ .update_rate = hsdk_pll_comm_update_rate, ++}; ++ ++struct hsdk_cgu_clock_map { ++ u32 cgu_pll_oft; ++ u32 creg_div_oft; ++ u32 cgu_div_oft; ++ const struct hsdk_pll_devdata *pll_devdata; ++}; ++ ++static const struct hsdk_cgu_clock_map clock_map[] = { ++ { CGU_ARC_PLL_OFFT, 0, 0, &core_pll_devdata }, // CLK_ARC_PLL ++ { CGU_ARC_PLL_OFFT, 0, CGU_ARC_IDIV, &core_pll_devdata }, // CLK_ARC ++ { CGU_DDR_PLL_OFFT, 0, 0, &sdt_pll_devdata }, // CLK_DDR_PLL ++ { CGU_SYS_PLL_OFFT, 0, 0, &sdt_pll_devdata }, // CLK_SYS_PLL ++ { CGU_SYS_PLL_OFFT, 0, CGU_SYS_IDIV_APB, &sdt_pll_devdata }, // CLK_SYS_APB ++ { CGU_SYS_PLL_OFFT, 0, CGU_SYS_IDIV_AXI, &sdt_pll_devdata }, // CLK_SYS_AXI ++ { CGU_SYS_PLL_OFFT, 0, CGU_SYS_IDIV_ETH, &sdt_pll_devdata }, // CLK_SYS_ETH ++ { CGU_SYS_PLL_OFFT, 0, CGU_SYS_IDIV_USB, &sdt_pll_devdata }, // CLK_SYS_USB ++ { CGU_SYS_PLL_OFFT, 0, CGU_SYS_IDIV_SDIO, &sdt_pll_devdata }, // CLK_SYS_SDIO ++ { CGU_SYS_PLL_OFFT, 0, CGU_SYS_IDIV_HDMI, &sdt_pll_devdata }, // CLK_SYS_HDMI ++ { CGU_SYS_PLL_OFFT, 0, CGU_SYS_IDIV_GFX_CORE, &sdt_pll_devdata }, // CLK_SYS_GFX_CORE ++ { CGU_SYS_PLL_OFFT, 0, CGU_SYS_IDIV_GFX_DMA, &sdt_pll_devdata }, // CLK_SYS_GFX_DMA ++ { CGU_SYS_PLL_OFFT, 0, CGU_SYS_IDIV_GFX_CFG, &sdt_pll_devdata }, // CLK_SYS_GFX_CFG ++ { CGU_SYS_PLL_OFFT, 0, CGU_SYS_IDIV_DMAC_CORE, &sdt_pll_devdata }, // CLK_SYS_DMAC_CORE ++ { CGU_SYS_PLL_OFFT, 0, CGU_SYS_IDIV_DMAC_CFG, &sdt_pll_devdata }, // CLK_SYS_DMAC_CFG ++ { CGU_SYS_PLL_OFFT, 0, CGU_SYS_IDIV_SDIO_REF, &sdt_pll_devdata }, // CLK_SYS_SDIO_REF ++ { CGU_SYS_PLL_OFFT, 0, CGU_SYS_IDIV_SPI_REF, &sdt_pll_devdata }, // CLK_SYS_SPI_REF ++ { CGU_SYS_PLL_OFFT, 0, CGU_SYS_IDIV_I2C_REF, &sdt_pll_devdata }, // CLK_SYS_I2C_REF ++ { CGU_SYS_PLL_OFFT, 0, CGU_SYS_IDIV_UART_REF, &sdt_pll_devdata }, // CLK_SYS_UART_REF ++ { CGU_SYS_PLL_OFFT, 0, CGU_SYS_IDIV_EBI_REF, &sdt_pll_devdata }, // CLK_SYS_EBI_REF ++ { CGU_TUN_PLL_OFFT, 0, 0, &sdt_pll_devdata }, // CLK_TUN_PLL ++ { CGU_TUN_PLL_OFFT, 0, CGU_TUN_IDIV, &sdt_pll_devdata }, // CLK_TUN ++ { CGU_HDMI_PLL_OFFT, 0, 0, &hdmi_pll_devdata }, // CLK_HDMI_PLL ++ { CGU_HDMI_PLL_OFFT, 0, CGU_HDMI_IDIV_APB, &hdmi_pll_devdata } // CLK_HDMI ++}; ++ ++static inline void hsdk_idiv_write(struct hsdk_pll_clk *clk, u32 val) ++{ ++ iowrite32(val, clk->idiv_regs); ++} ++ ++static inline u32 hsdk_idiv_read(struct hsdk_pll_clk *clk) ++{ ++ return ioread32(clk->idiv_regs); ++} ++ ++static inline void hsdk_pll_write(struct hsdk_pll_clk *clk, u32 reg, u32 val) ++{ ++ iowrite32(val, clk->regs + reg); ++} ++ ++static inline u32 hsdk_pll_read(struct hsdk_pll_clk *clk, u32 reg) ++{ ++ return ioread32(clk->regs + reg); ++} ++ ++static inline void hsdk_pll_spcwrite(struct hsdk_pll_clk *clk, u32 reg, u32 val) ++{ ++ iowrite32(val, clk->spec_regs + reg); ++} ++ ++static inline u32 hsdk_pll_spcread(struct hsdk_pll_clk *clk, u32 reg) ++{ ++ return ioread32(clk->spec_regs + reg); ++} ++ ++static inline void hsdk_pll_set_cfg(struct hsdk_pll_clk *clk, ++ const struct hsdk_pll_cfg *cfg) ++{ ++ u32 val = 0; ++ ++ /* Powerdown and Bypass bits should be cleared */ ++ val |= cfg->idiv << CGU_PLL_CTRL_IDIV_SHIFT; ++ val |= cfg->fbdiv << CGU_PLL_CTRL_FBDIV_SHIFT; ++ val |= cfg->odiv << CGU_PLL_CTRL_ODIV_SHIFT; ++ val |= cfg->band << CGU_PLL_CTRL_BAND_SHIFT; ++ ++ pr_debug("write configurarion: %#x\n", val); ++ ++ hsdk_pll_write(clk, CGU_PLL_CTRL, val); ++} ++ ++static inline bool hsdk_pll_is_locked(struct hsdk_pll_clk *clk) ++{ ++ return !!(hsdk_pll_read(clk, CGU_PLL_STATUS) & CGU_PLL_STATUS_LOCK); ++} ++ ++static inline bool hsdk_pll_is_err(struct hsdk_pll_clk *clk) ++{ ++ return !!(hsdk_pll_read(clk, CGU_PLL_STATUS) & CGU_PLL_STATUS_ERR); ++} ++ ++static ulong hsdk_pll_get_rate(struct clk *sclk) ++{ ++ u32 val; ++ u64 rate; ++ u32 idiv, fbdiv, odiv; ++ struct hsdk_pll_clk *clk = dev_get_priv(sclk->dev); ++ ++ val = hsdk_pll_read(clk, CGU_PLL_CTRL); ++ ++ pr_debug("current configurarion: %#x\n", val); ++ ++ /* Check if PLL is disabled */ ++ if (val & CGU_PLL_CTRL_PD) ++ return 0; ++ ++ /* Check if PLL is bypassed */ ++ if (val & CGU_PLL_CTRL_BYPASS) ++ return PARENT_RATE; ++ ++ /* input divider = reg.idiv + 1 */ ++ idiv = 1 + ((val & CGU_PLL_CTRL_IDIV_MASK) >> CGU_PLL_CTRL_IDIV_SHIFT); ++ /* fb divider = 2*(reg.fbdiv + 1) */ ++ fbdiv = 2 * (1 + ((val & CGU_PLL_CTRL_FBDIV_MASK) >> CGU_PLL_CTRL_FBDIV_SHIFT)); ++ /* output divider = 2^(reg.odiv) */ ++ odiv = 1 << ((val & CGU_PLL_CTRL_ODIV_MASK) >> CGU_PLL_CTRL_ODIV_SHIFT); ++ ++ rate = (u64)PARENT_RATE * fbdiv; ++ do_div(rate, idiv * odiv); ++ ++ return rate; ++} ++ ++static unsigned long hsdk_pll_round_rate(struct clk *sclk, unsigned long rate) ++{ ++ int i; ++ unsigned long best_rate; ++ struct hsdk_pll_clk *clk = dev_get_priv(sclk->dev); ++ const struct hsdk_pll_cfg *pll_cfg = clk->pll_devdata->pll_cfg; ++ ++ if (pll_cfg[0].rate == 0) ++ return -EINVAL; ++ ++ best_rate = pll_cfg[0].rate; ++ ++ for (i = 1; pll_cfg[i].rate != 0; i++) { ++ if (abs(rate - pll_cfg[i].rate) < abs(rate - best_rate)) ++ best_rate = pll_cfg[i].rate; ++ } ++ ++ pr_debug("chosen best rate: %lu\n", best_rate); ++ ++ return best_rate; ++} ++ ++static int hsdk_pll_comm_update_rate(struct hsdk_pll_clk *clk, ++ unsigned long rate, ++ const struct hsdk_pll_cfg *cfg) ++{ ++ hsdk_pll_set_cfg(clk, cfg); ++ ++ /* ++ * Wait until CGU relocks and check error status. ++ * If after timeout CGU is unlocked yet return error. ++ */ ++ udelay(HSDK_PLL_MAX_LOCK_TIME); ++ if (!hsdk_pll_is_locked(clk)) ++ return -ETIMEDOUT; ++ ++ if (hsdk_pll_is_err(clk)) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int hsdk_pll_core_update_rate(struct hsdk_pll_clk *clk, ++ unsigned long rate, ++ const struct hsdk_pll_cfg *cfg) ++{ ++ /* ++ * When core clock exceeds 500MHz, the divider for the interface ++ * clock must be programmed to div-by-2. ++ */ ++ if (rate > CORE_IF_CLK_THRESHOLD_HZ) ++ hsdk_pll_spcwrite(clk, CREG_CORE_IF_DIV, CREG_CORE_IF_CLK_DIV_2); ++ ++ hsdk_pll_set_cfg(clk, cfg); ++ ++ /* ++ * Wait until CGU relocks and check error status. ++ * If after timeout CGU is unlocked yet return error. ++ */ ++ udelay(HSDK_PLL_MAX_LOCK_TIME); ++ if (!hsdk_pll_is_locked(clk)) ++ return -ETIMEDOUT; ++ ++ if (hsdk_pll_is_err(clk)) ++ return -EINVAL; ++ ++ /* ++ * Program divider to div-by-1 if we succesfuly set core clock below ++ * 500MHz threshold. ++ */ ++ if (rate <= CORE_IF_CLK_THRESHOLD_HZ) ++ hsdk_pll_spcwrite(clk, CREG_CORE_IF_DIV, CREG_CORE_IF_CLK_DIV_1); ++ ++ return 0; ++} ++ ++static ulong hsdk_pll_set_rate(struct clk *sclk, ulong rate) ++{ ++ int i; ++ unsigned long best_rate; ++ struct hsdk_pll_clk *clk = dev_get_priv(sclk->dev); ++ const struct hsdk_pll_cfg *pll_cfg = clk->pll_devdata->pll_cfg; ++ ++ best_rate = hsdk_pll_round_rate(sclk, rate); ++ ++ for (i = 0; pll_cfg[i].rate != 0; i++) { ++ if (pll_cfg[i].rate == best_rate) { ++ return clk->pll_devdata->update_rate(clk, best_rate, ++ &pll_cfg[i]); ++ } ++ } ++ ++ pr_err("invalid rate=%ld, parent_rate=%d\n", best_rate, PARENT_RATE); ++ ++ return -EINVAL; ++} ++ ++static ulong hsdk_idiv_get_rate(struct clk *sclk) ++{ ++ struct hsdk_pll_clk *clk = dev_get_priv(sclk->dev); ++ ulong parent_rate = hsdk_pll_get_rate(sclk); ++ u32 div_factor = hsdk_idiv_read(clk); ++ ++ div_factor &= CGU_IDIV_MASK; ++ ++ debug("current configurarion: %#x (%d)\n", div_factor, div_factor); ++ ++ if (div_factor == 0) ++ return 0; ++ ++ return parent_rate / div_factor; ++} ++ ++static ulong hsdk_idiv_set_rate(struct clk *sclk, ulong rate) ++{ ++ struct hsdk_pll_clk *clk = dev_get_priv(sclk->dev); ++ ulong parent_rate = hsdk_pll_get_rate(sclk); ++ u32 div_factor; ++ ++ div_factor = parent_rate / rate; ++ if (abs(rate - parent_rate / (div_factor + 1)) <= abs(rate - parent_rate / div_factor)) ++ div_factor += 1; ++ ++ if (div_factor & ~CGU_IDIV_MASK) { ++ pr_err("invalid rate=%ld, parent_rate=%ld, div=%d: max divider valie is%d\n", ++ rate, parent_rate, div_factor, CGU_IDIV_MASK); ++ ++ div_factor = CGU_IDIV_MASK; ++ } ++ ++ if (div_factor == 0) { ++ pr_err("invalid rate=%ld, parent_rate=%ld, div=%d: min divider valie is 1\n", ++ rate, parent_rate, div_factor); ++ ++ div_factor = 1; ++ } ++ ++ hsdk_idiv_write(clk, div_factor); ++ ++ return 0; ++} ++ ++static void hsdk_prepare_clock_tree_branch(struct clk *sclk) ++{ ++ struct hsdk_pll_clk *clk = dev_get_priv(sclk->dev); ++ ++ clk->pll_devdata = clock_map[sclk->id].pll_devdata; ++ clk->regs = clk->cgu_regs + clock_map[sclk->id].cgu_pll_oft; ++ clk->spec_regs = clk->creg_regs + clock_map[sclk->id].creg_div_oft; ++ clk->idiv_regs = clk->cgu_regs + clock_map[sclk->id].cgu_div_oft; ++} ++ ++static ulong hsdk_cgu_get_rate(struct clk *sclk) ++{ ++// printf("PAL: %s: id: %ld\n", __func__, sclk->id); ++ ++ if (sclk->id >= CGU_MAX_CLOCKS) ++ return -EINVAL; ++ ++ hsdk_prepare_clock_tree_branch(sclk); ++ ++ switch (sclk->id) { ++ case CLK_ARC_PLL: ++ case CLK_DDR_PLL: ++ case CLK_SYS_PLL: ++ case CLK_TUN_PLL: ++ case CLK_HDMI_PLL: ++ return hsdk_pll_get_rate(sclk); ++ break; ++ ++ case CLK_ARC: ++ case CLK_SYS_APB: ++ case CLK_SYS_AXI: ++ case CLK_SYS_ETH: ++ case CLK_SYS_USB: ++ case CLK_SYS_SDIO: ++ case CLK_SYS_HDMI: ++ case CLK_SYS_GFX_CORE: ++ case CLK_SYS_GFX_DMA: ++ case CLK_SYS_GFX_CFG: ++ case CLK_SYS_DMAC_CORE: ++ case CLK_SYS_DMAC_CFG: ++ case CLK_SYS_SDIO_REF: ++ case CLK_SYS_SPI_REF: ++ case CLK_SYS_I2C_REF: ++ case CLK_SYS_UART_REF: ++ case CLK_SYS_EBI_REF: ++ case CLK_TUN: ++ case CLK_HDMI: ++ return hsdk_idiv_get_rate(sclk); ++ break; ++ ++ default: ++ pr_err("CLK-ERR: %s: id: %ld: unsupported\n", __func__, sclk->id); ++ break; ++ } ++ ++ return 0; ++} ++ ++static ulong hsdk_cgu_set_rate(struct clk *sclk, ulong rate) ++{ ++// debug("PAL: %s: id: %ld\n", __func__, sclk->id); ++ ++ if (sclk->id >= CGU_MAX_CLOCKS) ++ return -EINVAL; ++ ++ hsdk_prepare_clock_tree_branch(sclk); ++ ++ switch (sclk->id) { ++ case CLK_ARC_PLL: ++ case CLK_DDR_PLL: ++ case CLK_SYS_PLL: ++ case CLK_TUN_PLL: ++ case CLK_HDMI_PLL: ++ return hsdk_pll_set_rate(sclk, rate); ++ break; ++ ++ case CLK_ARC: ++ case CLK_SYS_APB: ++ case CLK_SYS_AXI: ++ case CLK_SYS_ETH: ++ case CLK_SYS_USB: ++ case CLK_SYS_SDIO: ++ case CLK_SYS_HDMI: ++ case CLK_SYS_GFX_CORE: ++ case CLK_SYS_GFX_DMA: ++ case CLK_SYS_GFX_CFG: ++ case CLK_SYS_DMAC_CORE: ++ case CLK_SYS_DMAC_CFG: ++ case CLK_SYS_SDIO_REF: ++ case CLK_SYS_SPI_REF: ++ case CLK_SYS_I2C_REF: ++ case CLK_SYS_UART_REF: ++ case CLK_SYS_EBI_REF: ++ case CLK_TUN: ++ case CLK_HDMI: ++ return hsdk_idiv_set_rate(sclk, rate); ++ break; ++ ++ default: ++ pr_err("CLK-ERR: %s: id: %ld: unsupported\n", __func__, sclk->id); ++ break; ++ } ++ ++ return 0; ++} ++ ++static const struct clk_ops hsdk_cgu_ops = { ++ .set_rate = hsdk_cgu_set_rate, ++ .get_rate = hsdk_cgu_get_rate, ++}; ++ ++static int hsdk_cgu_clk_probe(struct udevice *dev) ++{ ++ struct hsdk_pll_clk *pll_clk = dev_get_priv(dev); ++ ++ BUILD_BUG_ON(ARRAY_SIZE(clock_map) != CGU_MAX_CLOCKS); ++ ++ pll_clk->cgu_regs = (void __iomem *)devfdt_get_addr_index(dev, 0); ++ pll_clk->creg_regs = (void __iomem *)devfdt_get_addr_index(dev, 1); ++ ++ return 0; ++} ++ ++static const struct udevice_id hsdk_cgu_clk_id[] = { ++ { .compatible = "snps,hsdk-cgu-clock" }, ++ { } ++}; ++ ++U_BOOT_DRIVER(hsdk_cgu_clk) = { ++ .name = "hsdk-cgu-clk", ++ .id = UCLASS_CLK, ++ .of_match = hsdk_cgu_clk_id, ++ .probe = hsdk_cgu_clk_probe, ++ .platdata_auto_alloc_size = sizeof(struct hsdk_pll_clk), ++ .ops = &hsdk_cgu_ops, ++}; +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0009-ARC-HSDK-DTS-switch-to-cgu-clock.patch b/board/synopsys/hsdk/uboot-patches/0009-ARC-HSDK-DTS-switch-to-cgu-clock.patch new file mode 100644 index 00000000000..d210e2acc6f --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0009-ARC-HSDK-DTS-switch-to-cgu-clock.patch @@ -0,0 +1,44 @@ +From 825f820acf405f6af4bc890b2e24155e16aa0271 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Tue, 28 Nov 2017 15:36:35 +0300 +Subject: [PATCH 09/46] ARC: HSDK: DTS: switch to cgu clock + +Signed-off-by: Eugeniy Paltsev +--- + arch/arc/dts/hsdk.dts | 20 ++++++++++++++++++-- + 1 file changed, 18 insertions(+), 2 deletions(-) + +diff --git a/arch/arc/dts/hsdk.dts b/arch/arc/dts/hsdk.dts +index 9a2090f3ea..0527e1341b 100644 +--- a/arch/arc/dts/hsdk.dts ++++ b/arch/arc/dts/hsdk.dts +@@ -25,8 +25,24 @@ + }; + + clk-fmeas { +- clocks = <&cpu_clk>, <&sys_clk>, <&tun_clk>, <&ddr_clk>; +- clock-names = "cpu-clk", "sys-clk", "tun-clk", "ddr-clk"; ++ clocks = <&cgu_clk 0>, <&cgu_clk 3>, <&cgu_clk 20>, <&cgu_clk 2>, ++ <&cgu_clk 1>, <&cgu_clk 22>, <&cgu_clk 21>, <&cgu_clk 23>, ++ <&cgu_clk 4>, <&cgu_clk 5>, <&cgu_clk 6>, <&cgu_clk 7>, ++ <&cgu_clk 8>, <&cgu_clk 9>, <&cgu_clk 10>, <&cgu_clk 11>, ++ <&cgu_clk 12>, <&cgu_clk 13>, <&cgu_clk 14>, <&cgu_clk 15>, ++ <&cgu_clk 16>, <&cgu_clk 17>, <&cgu_clk 18>, <&cgu_clk 19>; ++ clock-names = "cpu-pll", "sys-pll", "tun-pll", "ddr-clk", ++ "cpu-clk", "hdmi-pll", "tun-clk", "hdmi-clk", ++ "sys-apb", "sys-axi", "sys-eth", "sys-usb", ++ "sys-sdio", "sys-hdmi", "sys-gfx-core", "sys-gfx-dma", ++ "sys-gfx-cfg", "sys-dmac-core", "sys-dmac-cfg", "sys-sdio-ref", ++ "sys-spi", "sys-i2c", "sys-uart", "sys-ebi"; ++ }; ++ ++ cgu_clk: cgu-clk@f0000000 { ++ compatible = "snps,hsdk-cgu-clock"; ++ reg = <0xf0000000 0x10>, <0xf00014B8 0x4>; ++ #clock-cells = <1>; + }; + + cpu_clk: cpu-clk@f0000000 { +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0010-ARC-hsdk-go-0.6-version.patch b/board/synopsys/hsdk/uboot-patches/0010-ARC-hsdk-go-0.6-version.patch new file mode 100644 index 00000000000..59d4840adc9 --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0010-ARC-hsdk-go-0.6-version.patch @@ -0,0 +1,379 @@ +From 8a351af70a00186a7533158fc954d431be83d6ba Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Mon, 27 Nov 2017 20:40:00 +0300 +Subject: [PATCH 10/46] ARC: hsdk-go: 0.6 version + +The new u-boot with significant changes is ready. + * All aliases like 'hsdk_hs38x3' and default variables now are available even without + uboot.env (for example when there is no SD card connected) + * We are able to set all required frequencies (CPU, AXI, TUNNEL). + * Memory map programming was added. + * A lot of small limitations were fixed. + +Signed-off-by: Eugeniy Paltsev +--- + board/synopsys/hsdk/hsdk-cmd.c | 277 +++++++++++++++++++++++++++++++++++++---- + 1 file changed, 255 insertions(+), 22 deletions(-) + +diff --git a/board/synopsys/hsdk/hsdk-cmd.c b/board/synopsys/hsdk/hsdk-cmd.c +index 776865fecd..523af6ec69 100644 +--- a/board/synopsys/hsdk/hsdk-cmd.c ++++ b/board/synopsys/hsdk/hsdk-cmd.c +@@ -13,7 +13,9 @@ + #error "hsdk_go will not work with BIG endian CPU" + #endif + +-#define HSDKGO_VERSION "0.5" ++#define HSDKGO_VERSION "0.6" ++ ++#define HZ_IN_MHZ 1000000 + + #define ceil(x, y) ({ ulong __x = (x), __y = (y); (__x + __y - 1) / __y; }) + +@@ -65,7 +67,7 @@ struct hsdk_env_map_core { + }; + + /* Place for slave cpu temporary stack */ +-static u32 slave_stack[1024] __attribute__((aligned(4))); ++static u32 slave_stack[256 * NR_CPUS] __attribute__((aligned(4))); + + static struct hsdk_env_common_ctl env_common = {}; + static struct hsdk_env_core_ctl env_core = {}; +@@ -82,8 +84,10 @@ int soc_clk_ctl(const char *name, ulong *rate, bool set) + }; + + ret = clk_get_by_name(&fmeas, name, &clk); +- if (ret) ++ if (ret) { ++ pr_err("clock '%s' not found, err=%d\n", name, ret); + return ret; ++ } + + ret = clk_enable(&clk); + if (ret && ret != -ENOSYS) +@@ -99,7 +103,7 @@ int soc_clk_ctl(const char *name, ulong *rate, bool set) + + clk_free(&clk); + +- printf("HSDK: clock '%s' rate %lu MHz\n", name, ceil(*rate, 1000000)); ++ debug("HSDK: clock '%s' rate %lu MHz\n", name, ceil(*rate, HZ_IN_MHZ)); + + return 0; + } +@@ -114,14 +118,14 @@ static const struct hsdk_env_map_common env_map_common[] = { + { "cpu_freq", false, 100, 1000, &env_common.cpu_freq }, + { "axi_freq", false, 200, 800, &env_common.axi_freq }, + { "tun_freq", false, 0, 150, &env_common.tun_freq }, +- { "non_volatile_limit", true, 0x1, 0xF, &env_common.nvlim }, ++ { "non_volatile_limit", true, 0, 0xF, &env_common.nvlim }, + { "icache_ena", true, 0, 1, &env_common.icache }, + { "dcache_ena", true, 0, 1, &env_common.dcache }, + {} + }; + + static const struct hsdk_env_map_core env_map_core[] = { +- { "core_entry", true, {0, 0, 0, 0}, {U32_MAX, U32_MAX, U32_MAX, U32_MAX}, &env_core.entry }, ++ { "core_entry", true, {0, 0, 0, 0}, {U32_MAX, U32_MAX, U32_MAX, U32_MAX}, &env_core.entry }, + { "core_iccm", true, {NO_CCM, 0, NO_CCM, 0}, {NO_CCM, 0xF, NO_CCM, 0xF}, &env_core.iccm }, + { "core_dccm", true, {NO_CCM, 0, NO_CCM, 0}, {NO_CCM, 0xF, NO_CCM, 0xF}, &env_core.dccm }, + {} +@@ -405,8 +409,6 @@ static inline u32 get_this_cpu_id(void) + } + + #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) + #define CPU_START_MASK 0xF + +@@ -498,8 +500,8 @@ static void do_init_slave_cpu(u32 cpu_id) + stack_ptr = (u32)(slave_stack + (64 * cpu_id)); + + /* TODO: remove useless debug's in do_init_slave_cpu */ +- debug("CPU %u: STACK: %x\n", cpu_id, stack_ptr); +- debug("CPU %u: comm STACK: %p\n", cpu_id, slave_stack); ++ debug("CPU %u: stack base: %x\n", cpu_id, stack_ptr); ++ debug("CPU %u: stack pool base: %p\n", cpu_id, slave_stack); + smp_set_core_boot_addr((unsigned long)hsdk_core_init_f, -1); + + /* Make sure other cores see written value in memory */ +@@ -536,6 +538,247 @@ static void do_init_master_cpu(void) + } + } + ++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_PAE ((void __iomem *)(CREG_BASE + 0x180)) ++#define CREG_PAE_UPDT ((void __iomem *)(CREG_BASE + 0x194)) ++ ++static void init_memory_bridge(void) ++{ ++ 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, tmp_rate; ++ ++ /* Setup CPU clock */ ++ if (env_common.cpu_freq.set) { ++ rate = env_common.cpu_freq.val * HZ_IN_MHZ; ++ soc_clk_ctl("cpu-pll", &rate, true); /* 100MHz - 1GHz is OK for PLL */ ++ soc_clk_ctl("cpu-clk", &rate, true); /* div factor = 1 */ ++ } else { ++ soc_clk_ctl("cpu-clk", &rate, false); ++ } ++ printf("HSDK: clock '%s' rate %lu MHz\n", "cpu-clk", ceil(rate, HZ_IN_MHZ)); ++ ++ /* Setup TUN clock */ ++ if (env_common.tun_freq.set) { ++ rate = env_common.tun_freq.val * HZ_IN_MHZ; ++ if (rate >= 100 * HZ_IN_MHZ) { ++ /* 150 MHz : PLL - 150MHz; DIV = 1 */ ++ /* 125 MHz : PLL - 125MHz; DIV = 1 */ ++ /* 100 MHz : PLL - 100MHz; DIV = 1 */ ++ soc_clk_ctl("tun-pll", &rate, true); /* 100MHz - 150MHz is OK for PLL */ ++ soc_clk_ctl("tun-clk", &rate, true); /* div factor = 1 */ ++ } else if (rate > 0) { ++ /* 75 MHz : PLL - 150MHz; DIV = 2 */ ++ /* 50 MHz : PLL - 150MHz; DIV = 3 */ ++ /* 25 MHz : PLL - 150MHz; DIV = 6 */ ++ tmp_rate = 150 * HZ_IN_MHZ; ++ soc_clk_ctl("tun-pll", &tmp_rate, true); ++ soc_clk_ctl("tun-clk", &rate, true); /* div factor - autocalc */ ++ } else { ++ /* 25 MHz : PLL - DNC; DIV = OFF */ ++ // TODO: add ++ } ++ } else { ++ soc_clk_ctl("tun-clk", &rate, false); ++ } ++ printf("HSDK: clock '%s' rate %lu MHz\n", "tun-clk", ceil(rate, HZ_IN_MHZ)); ++ ++ if (env_common.axi_freq.set) { ++ rate = env_common.axi_freq.val * HZ_IN_MHZ; ++ /* firstly we need to increase SYS dividers factors to set ++ * 'safe' freq values */ ++ tmp_rate = 33333333; ++ soc_clk_ctl("sys-apb", &tmp_rate, true); ++ soc_clk_ctl("sys-axi", &tmp_rate, true); ++ soc_clk_ctl("sys-eth", &tmp_rate, true); ++ soc_clk_ctl("sys-usb", &tmp_rate, true); ++ soc_clk_ctl("sys-sdio", &tmp_rate, true); ++ soc_clk_ctl("sys-hdmi", &tmp_rate, true); ++ soc_clk_ctl("sys-gfx-core", &tmp_rate, true); ++ soc_clk_ctl("sys-gfx-dma", &tmp_rate, true); ++ soc_clk_ctl("sys-gfx-cfg", &tmp_rate, true); ++ soc_clk_ctl("sys-dmac-core", &tmp_rate, true); ++ soc_clk_ctl("sys-dmac-cfg", &tmp_rate, true); ++ soc_clk_ctl("sys-sdio-ref", &tmp_rate, true); ++ soc_clk_ctl("sys-spi", &tmp_rate, true); ++ soc_clk_ctl("sys-i2c", &tmp_rate, true); ++ soc_clk_ctl("sys-uart", &tmp_rate, true); ++ soc_clk_ctl("sys-ebi", &tmp_rate, true); ++ ++ /* update (increase) PLL clock */ ++ if (rate == 800 * HZ_IN_MHZ) { ++ tmp_rate = 800 * HZ_IN_MHZ; ++ soc_clk_ctl("sys-pll", &tmp_rate, true); ++ soc_clk_ctl("sys-axi", &tmp_rate, true); ++ } else if (rate == 600 * HZ_IN_MHZ) { ++ tmp_rate = 600 * HZ_IN_MHZ; ++ soc_clk_ctl("sys-pll", &tmp_rate, true); ++ soc_clk_ctl("sys-axi", &tmp_rate, true); ++ } else if (rate <= 400 * HZ_IN_MHZ) { ++ tmp_rate = 400 * HZ_IN_MHZ; ++ soc_clk_ctl("sys-pll", &tmp_rate, true); ++ soc_clk_ctl("sys-axi", &rate, true); /* div factor - autocalc */ ++ } ++ ++ /* return SYS dividers factors to 'fast' freq values */ ++ tmp_rate = 200 * HZ_IN_MHZ; ++ soc_clk_ctl("sys-apb", &tmp_rate, true); ++ tmp_rate = 400 * HZ_IN_MHZ; ++ soc_clk_ctl("sys-eth", &tmp_rate, true); ++ soc_clk_ctl("sys-usb", &tmp_rate, true); ++ soc_clk_ctl("sys-sdio", &tmp_rate, true); ++ soc_clk_ctl("sys-hdmi", &tmp_rate, true); ++ tmp_rate = 800 * HZ_IN_MHZ; ++ soc_clk_ctl("sys-gfx-core", &tmp_rate, true); ++ tmp_rate = 400 * HZ_IN_MHZ; ++ soc_clk_ctl("sys-gfx-dma", &tmp_rate, true); ++ tmp_rate = 200 * HZ_IN_MHZ; ++ soc_clk_ctl("sys-gfx-cfg", &tmp_rate, true); ++ tmp_rate = 400 * HZ_IN_MHZ; ++ soc_clk_ctl("sys-dmac-core", &tmp_rate, true); ++ tmp_rate = 200 * HZ_IN_MHZ; ++ soc_clk_ctl("sys-dmac-cfg", &tmp_rate, true); ++ tmp_rate = 100 * HZ_IN_MHZ; ++ soc_clk_ctl("sys-sdio-ref", &tmp_rate, true); ++ tmp_rate = 33333333; ++ soc_clk_ctl("sys-spi", &tmp_rate, true); ++ tmp_rate = 200 * HZ_IN_MHZ; ++ soc_clk_ctl("sys-i2c", &tmp_rate, true); ++ tmp_rate = 33333333; ++ soc_clk_ctl("sys-uart", &tmp_rate, true); ++ tmp_rate = 50 * HZ_IN_MHZ; ++ soc_clk_ctl("sys-ebi", &tmp_rate, true); ++ } ++ soc_clk_ctl("sys-axi", &rate, false); ++ printf("HSDK: clock '%s' rate %lu MHz\n", "axi-clk", ceil(rate, HZ_IN_MHZ)); ++ ++ soc_clk_ctl("ddr-clk", &rate, false); ++ printf("HSDK: clock '%s' rate %lu MHz\n", "ddr-clk", ceil(rate, HZ_IN_MHZ)); ++} ++ ++static void do_init_claster(void) ++{ ++ /* A multi-core ARC HS configuration always includes only one ++ * AUX_NON_VOLATILE_LIMIT register, which is shared by all the cores. */ ++ init_master_nvlim(); ++ ++ init_memory_bridge(); ++} ++ + /* ********************* SMP: END ********************* */ + + static int check_master_cpu_id(void) +@@ -551,8 +794,6 @@ static int check_master_cpu_id(void) + static int prepare_cpus(u32 *cpu_start_reg) + { + u32 i; +- ulong rate; +- bool set; + int ret; + + ret = check_master_cpu_id(); +@@ -569,17 +810,9 @@ static int prepare_cpus(u32 *cpu_start_reg) + + do_init_slave_cpus(); + +- rate = env_common.cpu_freq.val * 1000000; +- set = env_common.cpu_freq.set; +- soc_clk_ctl("cpu-clk", &rate, set); +- /* TODO: set AXI and TUN frequency, not only read */ +- soc_clk_ctl("sys-clk", &rate, false); +- soc_clk_ctl("tun-clk", &rate, false); +- soc_clk_ctl("ddr-clk", &rate, false); ++ setup_clocks(); + +- /* A multi-core ARC HS configuration always includes only one +- * AUX_NON_VOLATILE_LIMIT register, which is shared by all the cores. */ +- init_master_nvlim(); ++ do_init_claster(); + + /* Prepare CREG_CPU_START for kicking chosen CPUs */ + *cpu_start_reg = prepare_cpu_ctart_reg(); +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0011-ARC-add-defines-of-some-cache-and-xCCM-AUX-registers.patch b/board/synopsys/hsdk/uboot-patches/0011-ARC-add-defines-of-some-cache-and-xCCM-AUX-registers.patch new file mode 100644 index 00000000000..9e748736cf3 --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0011-ARC-add-defines-of-some-cache-and-xCCM-AUX-registers.patch @@ -0,0 +1,30 @@ +From abd1219f94dee34cbb1209e951c0e81bbb282154 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Tue, 28 Nov 2017 16:49:05 +0300 +Subject: [PATCH 11/46] ARC: add defines of some cache and xCCM AUX registers + +Signed-off-by: Eugeniy Paltsev +--- + arch/arc/include/asm/arcregs.h | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arc/include/asm/arcregs.h b/arch/arc/include/asm/arcregs.h +index 54a9b00d4c..09ac62a885 100644 +--- a/arch/arc/include/asm/arcregs.h ++++ b/arch/arc/include/asm/arcregs.h +@@ -27,6 +27,12 @@ + #define ARC_AUX_IC_PTAG 0x1E + #endif + #define ARC_BCR_IC_BUILD 0x77 ++#define AUX_AUX_CACHE_LIMIT 0x5D ++#define ARC_AUX_NON_VOLATILE_LIMIT 0x5E ++ ++/* ICCM and DCCM auxiliary registers */ ++#define ARC_AUX_DCCM_BASE 0x18 /* DCCM Base Addr ARCv2 */ ++#define ARC_AUX_ICCM_BASE 0x208 /* ICCM Base Addr ARCv2 */ + + /* Timer related auxiliary registers */ + #define ARC_AUX_TIMER0_CNT 0x21 /* Timer 0 count */ +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0012-ARC-add-macro-to-get-CPU-id.patch b/board/synopsys/hsdk/uboot-patches/0012-ARC-add-macro-to-get-CPU-id.patch new file mode 100644 index 00000000000..636a04854d1 --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0012-ARC-add-macro-to-get-CPU-id.patch @@ -0,0 +1,30 @@ +From f4206d24ce8461c36ce0fa5ac6304436b10c6ef6 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Tue, 28 Nov 2017 16:21:18 +0300 +Subject: [PATCH 12/46] ARC: add macro to get CPU id + +ARCNUM [15:8] field in ARC_AUX_IDENTITY register allows you to +uniquely identify each core in a multi-core system. + +Signed-off-by: Eugeniy Paltsev +--- + arch/arc/include/asm/arcregs.h | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/arc/include/asm/arcregs.h b/arch/arc/include/asm/arcregs.h +index 09ac62a885..ba1f7bac77 100644 +--- a/arch/arc/include/asm/arcregs.h ++++ b/arch/arc/include/asm/arcregs.h +@@ -78,6 +78,9 @@ + /* gcc builtin sr needs reg param to be long immediate */ + #define write_aux_reg(reg_immed, val) \ + __builtin_arc_sr((unsigned int)val, reg_immed) ++ ++/* ARCNUM [15:8] - field to identify each core in a multi-core system */ ++#define CPU_ID_GET() ((read_aux_reg(ARC_AUX_IDENTITY) & 0xFF00) >> 8) + #endif /* __ASSEMBLY__ */ + + #endif /* _ASM_ARC_ARCREGS_H */ +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0013-ARC-hsdk-go-cleanup.patch b/board/synopsys/hsdk/uboot-patches/0013-ARC-hsdk-go-cleanup.patch new file mode 100644 index 00000000000..d7b85a3bc8e --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0013-ARC-hsdk-go-cleanup.patch @@ -0,0 +1,232 @@ +From 8313d759e1b5a5b27875832dc55acd155bb627ba Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Tue, 28 Nov 2017 17:45:44 +0300 +Subject: [PATCH 13/46] ARC: hsdk-go cleanup + +Signed-off-by: Eugeniy Paltsev +--- + board/synopsys/hsdk/hsdk-cmd.c | 122 ++++++----------------------------------- + 1 file changed, 17 insertions(+), 105 deletions(-) + +diff --git a/board/synopsys/hsdk/hsdk-cmd.c b/board/synopsys/hsdk/hsdk-cmd.c +index 523af6ec69..c13942bd69 100644 +--- a/board/synopsys/hsdk/hsdk-cmd.c ++++ b/board/synopsys/hsdk/hsdk-cmd.c +@@ -271,20 +271,6 @@ static int env_process_and_validate(void) + #define DC_CTRL_CACHE_DISABLE (1 << 0) + #define DC_CTRL_INV_MODE_FLUSH (1 << 6) + +-/* TODO: move this to "arch/arc/include/asm/arcregs.h" */ +-#define AUX_NON_VOLATILE_LIMIT 0x5E +-#define ARC_REG_AUX_DCCM 0x18 /* DCCM Base Addr ARCv2 */ +-#define ARC_REG_AUX_ICCM 0x208 /* ICCM Base Addr (ARCv2) */ +-#define AUX_VOL 0x5E +-#define AUX_CACHE_LIMIT 0x5D +- +-#define AUX_IDENTITY 4 +- +-static inline void nop_instr(void) +-{ +- __asm__ __volatile__("nop"); +-} +- + // TODO: add xCCM runtime check + static void smp_init_slave_cpu_func(u32 core) + { +@@ -292,13 +278,13 @@ static void smp_init_slave_cpu_func(u32 core) + + /* ICCM move if exists */ + if (env_core.iccm[core].val != NO_CCM) { +- r = ARC_REG_AUX_ICCM; ++ r = ARC_AUX_ICCM_BASE; + write_aux_reg(r, env_core.iccm[core].val << APT_SHIFT); + } + + /* DCCM move if exists */ + if (env_core.dccm[core].val != NO_CCM) { +- r = ARC_REG_AUX_DCCM; ++ r = ARC_AUX_DCCM_BASE; + write_aux_reg(r, env_core.dccm[core].val << APT_SHIFT); + } + +@@ -320,8 +306,8 @@ static void init_master_nvlim(void) + u32 val = env_common.nvlim.val << APT_SHIFT; + + flush_dcache_all(); +- write_aux_reg(AUX_NON_VOLATILE_LIMIT, val); +- write_aux_reg(AUX_CACHE_LIMIT, val); ++ write_aux_reg(ARC_AUX_NON_VOLATILE_LIMIT, val); ++ write_aux_reg(AUX_AUX_CACHE_LIMIT, val); + } + + // TODO: !! add my own implementation of flush_dcache_all, invalidate_icache_all +@@ -347,9 +333,9 @@ static void init_master_icache(void) + write_aux_reg(ARC_AUX_IC_IVIC, 0x00000001U); + /* HS Databook, 5.3.3.2: three NOP's must be inserted inbetween + * invalidate and disable */ +- nop_instr(); +- nop_instr(); +- nop_instr(); ++ __builtin_arc_nop(); ++ __builtin_arc_nop(); ++ __builtin_arc_nop(); + /* instruction cache disable */ + write_aux_reg(ARC_AUX_IC_CTRL, 0x00000001U); + } +@@ -393,21 +379,6 @@ static int cleanup_cache_before_go(void) + } + + /* ********************* SMP: START ********************* */ +- +-#define ARCNUM_SHIFT 8 +- +-static inline u32 get_this_cpu_id(void) +-{ +- u32 val = read_aux_reg(AUX_IDENTITY); +- +-// val &= GENMASK(15, ARCNUM_SHIFT); +- +- val &= 0xFF00; +- val >>= ARCNUM_SHIFT; +- +- return val; +-} +- + #define CREG_BASE (ARC_PERIPHERAL_BASE + 0x1000) + #define CREG_CPU_START (CREG_BASE + 0x400) + #define CPU_START_MASK 0xF +@@ -422,7 +393,7 @@ static int cleanup_before_go(void) + + static inline void this_cpu_halt(void) + { +- __asm__ __volatile__("flag 1\n"); ++ __builtin_arc_flag(1); + } + + static void smp_kick_cpu_x(u32 cpu_id) +@@ -468,7 +439,7 @@ __attribute__((naked, noreturn, flatten)) noinline void hsdk_core_init_f(void) + : "m" (stack_ptr) + : "memory"); + +- smp_init_slave_cpu_func(get_this_cpu_id()); ++ smp_init_slave_cpu_func(CPU_ID_GET()); + + set_data_flag(); + /* Make sure other cores see written value in memory */ +@@ -477,12 +448,12 @@ __attribute__((naked, noreturn, flatten)) noinline void hsdk_core_init_f(void) + /* Halt the processor untill the master kick us again */ + this_cpu_halt(); + +- nop_instr(); +- nop_instr(); +- nop_instr(); ++ __builtin_arc_nop(); ++ __builtin_arc_nop(); ++ __builtin_arc_nop(); + + /* Run our program */ +- ((void (*)(void))(env_core.entry[get_this_cpu_id()].val))(); ++ ((void (*)(void))(env_core.entry[CPU_ID_GET()].val))(); + + /* Something went terribly wrong */ + while (true) +@@ -773,7 +744,7 @@ static void setup_clocks(void) + static void do_init_claster(void) + { + /* A multi-core ARC HS configuration always includes only one +- * AUX_NON_VOLATILE_LIMIT register, which is shared by all the cores. */ ++ * ARC_AUX_NON_VOLATILE_LIMIT register, which is shared by all the cores. */ + init_master_nvlim(); + + init_memory_bridge(); +@@ -783,10 +754,10 @@ static void do_init_claster(void) + + static int check_master_cpu_id(void) + { +- if (get_this_cpu_id() == MASTER_CPU) ++ if (CPU_ID_GET() == MASTER_CPU) + return 0; + +- pr_err("u-boot runs on non-master cpu with id: %u\n", get_this_cpu_id()); ++ pr_err("u-boot runs on non-master cpu with id: %u\n", CPU_ID_GET()); + + return -ENOENT; + } +@@ -838,7 +809,7 @@ static int hsdk_go_run(u32 cpu_start_reg) + else + this_cpu_halt(); + +- pr_err("u-boot still runs on cpu [%d]\n", get_this_cpu_id()); ++ pr_err("u-boot still runs on cpu [%d]\n", CPU_ID_GET()); + + /* We will never return after executing our program if master cpu used + * otherwise halt master cpu manually */ +@@ -892,65 +863,6 @@ int bootm_prepare_and_run(u32 entry) + return bootm_run(reg); + } + +-//static int prepare_and_run(void) +-//{ +-// u32 i, reg; +-// ulong rate; +-// int ret; +-// +-// ret = check_master_cpu_id(); +-// if (ret) +-// return ret; +-// +-// ret = env_process_and_validate(); +-// if (ret) +-// return ret; +-// +-// for (i = 0; i < NR_CPUS; i++) { +-// env_core.used[i] = is_cpu_used(i); +-// } +-// +-// do_init_slave_cpus(); +-// +-// /* TODO: set frequency, not only read */ +-// soc_clk_ctl("cpu-clk", &rate, false); +-// soc_clk_ctl("sys-clk", &rate, false); +-// soc_clk_ctl("ddr-clk", &rate, false); +-// soc_clk_ctl("tun-clk", &rate, false); +-// +-// /* A multi-core ARC HS configuration always includes only one +-// * AUX_NON_VOLATILE_LIMIT register, which is shared by all the cores. */ +-// init_master_nvlim(); +-// +-// /* Prepare CREG_CPU_START for kicking chosen CPUs */ +-// reg = prepare_cpu_ctart_reg(); +-// +-// do_init_master_cpu(); +-// +-// /* Cleanup caches, disable interrupts */ +-// cleanup_before_go(); +-// +-// if (env_common.halt_on_boot) +-// this_cpu_halt(); +-// +-// /* Kick chosen CPUs */ +-// writel(reg, (void __iomem *)CREG_CPU_START); +-// +-// if (env_core.used[MASTER_CPU]) +-// ((void (*)(void))(env_core.entry[MASTER_CPU].val))(); +-// else +-// this_cpu_halt(); +-// +-// pr_err("u-boot still runs on cpu [%d]\n", get_this_cpu_id()); +-// +-// /* We will never return after executing our program if master cpu used +-// * otherwise halt master cpu manually */ +-// while (true) +-// this_cpu_halt(); +-// +-// return 0; +-//} +- + static int do_hsdk_go(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) + { + /* TODO: delete after release */ +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0014-ARC-hsdk_go-clock-ang-cmd-decription-changes.patch b/board/synopsys/hsdk/uboot-patches/0014-ARC-hsdk_go-clock-ang-cmd-decription-changes.patch new file mode 100644 index 00000000000..b2fdd5818db --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0014-ARC-hsdk_go-clock-ang-cmd-decription-changes.patch @@ -0,0 +1,96 @@ +From 952610299c5a513a51115622501f6055825da273 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Fri, 1 Dec 2017 16:31:36 +0300 +Subject: [PATCH 14/46] ARC: hsdk_go: clock ang cmd decription changes + +Signed-off-by: Eugeniy Paltsev +--- + board/synopsys/hsdk/hsdk-cmd.c | 23 +++++++++++++---------- + 1 file changed, 13 insertions(+), 10 deletions(-) + +diff --git a/board/synopsys/hsdk/hsdk-cmd.c b/board/synopsys/hsdk/hsdk-cmd.c +index c13942bd69..32c622fd6b 100644 +--- a/board/synopsys/hsdk/hsdk-cmd.c ++++ b/board/synopsys/hsdk/hsdk-cmd.c +@@ -9,6 +9,7 @@ + #include + #include + ++ + #ifdef CONFIG_CPU_BIG_ENDIAN + #error "hsdk_go will not work with BIG endian CPU" + #endif +@@ -90,7 +91,7 @@ int soc_clk_ctl(const char *name, ulong *rate, bool set) + } + + ret = clk_enable(&clk); +- if (ret && ret != -ENOSYS) ++ if (ret && ret != -ENOSYS && ret != -ENOTSUPP) + return ret; + + if (set) { +@@ -638,10 +639,7 @@ static void setup_clocks(void) + rate = env_common.cpu_freq.val * HZ_IN_MHZ; + soc_clk_ctl("cpu-pll", &rate, true); /* 100MHz - 1GHz is OK for PLL */ + soc_clk_ctl("cpu-clk", &rate, true); /* div factor = 1 */ +- } else { +- soc_clk_ctl("cpu-clk", &rate, false); + } +- printf("HSDK: clock '%s' rate %lu MHz\n", "cpu-clk", ceil(rate, HZ_IN_MHZ)); + + /* Setup TUN clock */ + if (env_common.tun_freq.set) { +@@ -663,10 +661,7 @@ static void setup_clocks(void) + /* 25 MHz : PLL - DNC; DIV = OFF */ + // TODO: add + } +- } else { +- soc_clk_ctl("tun-clk", &rate, false); + } +- printf("HSDK: clock '%s' rate %lu MHz\n", "tun-clk", ceil(rate, HZ_IN_MHZ)); + + if (env_common.axi_freq.set) { + rate = env_common.axi_freq.val * HZ_IN_MHZ; +@@ -734,6 +729,13 @@ static void setup_clocks(void) + tmp_rate = 50 * HZ_IN_MHZ; + soc_clk_ctl("sys-ebi", &tmp_rate, true); + } ++ ++ soc_clk_ctl("cpu-clk", &rate, false); ++ printf("HSDK: clock '%s' rate %lu MHz\n", "cpu-clk", ceil(rate, HZ_IN_MHZ)); ++ ++ soc_clk_ctl("tun-clk", &rate, false); ++ printf("HSDK: clock '%s' rate %lu MHz\n", "tun-clk", ceil(rate, HZ_IN_MHZ)); ++ + soc_clk_ctl("sys-axi", &rate, false); + printf("HSDK: clock '%s' rate %lu MHz\n", "axi-clk", ceil(rate, HZ_IN_MHZ)); + +@@ -757,7 +759,7 @@ static int check_master_cpu_id(void) + if (CPU_ID_GET() == MASTER_CPU) + return 0; + +- pr_err("u-boot runs on non-master cpu with id: %u\n", CPU_ID_GET()); ++ pr_err("u-boot runs on non-master cpu with id: %lu\n", CPU_ID_GET()); + + return -ENOENT; + } +@@ -809,7 +811,7 @@ static int hsdk_go_run(u32 cpu_start_reg) + else + this_cpu_halt(); + +- pr_err("u-boot still runs on cpu [%d]\n", CPU_ID_GET()); ++ 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 */ +@@ -884,5 +886,6 @@ static int do_hsdk_go(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) + U_BOOT_CMD( + hsdk_go, 3, 0, do_hsdk_go, + "Synopsys HSDK specific command", +- "hsdk_go - Boot stand-alone application on HSDK\n" ++ " - Boot stand-alone application on HSDK\n" ++ "hsdk_go halt - Boot stand-alone application on HSDK, halt CPU just before application run\n" + ); +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0015-ARC-HSDK-implement-callbacks-to-init-usb-and-set-clo.patch b/board/synopsys/hsdk/uboot-patches/0015-ARC-HSDK-implement-callbacks-to-init-usb-and-set-clo.patch new file mode 100644 index 00000000000..7c7c1287d0b --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0015-ARC-HSDK-implement-callbacks-to-init-usb-and-set-clo.patch @@ -0,0 +1,57 @@ +From c1b704249ef2d58e4d20dc38adb006e802d9cc71 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Sat, 9 Dec 2017 20:19:49 +0300 +Subject: [PATCH 15/46] ARC: HSDK: implement callbacks to init usb and set + clock env + +Signed-off-by: Eugeniy Paltsev +--- + board/synopsys/hsdk/hsdk.c | 16 ++++++++++++++++ + include/configs/hsdk.h | 6 ++++++ + 2 files changed, 22 insertions(+) + +diff --git a/board/synopsys/hsdk/hsdk.c b/board/synopsys/hsdk/hsdk.c +index 7641978a7b..237a13316d 100644 +--- a/board/synopsys/hsdk/hsdk.c ++++ b/board/synopsys/hsdk/hsdk.c +@@ -58,6 +58,22 @@ int board_mmc_init(bd_t *bis) + return 0; + } + ++int board_early_init_r(void) ++{ ++ /* Init USB to be able read environment from USB MSD */ ++ usb_init(); ++ ++ return 0; ++} ++ ++int board_late_init(void) ++{ ++ /* Populate environment with clock frequency values */ ++ run_command("hsdk_clock get", 0); ++ ++ return 0; ++} ++ + #define RESET_VECTOR_ADDR 0x0 + + void smp_set_core_boot_addr(unsigned long addr, int corenr) +diff --git a/include/configs/hsdk.h b/include/configs/hsdk.h +index 9eacafb25f..b0323e0919 100644 +--- a/include/configs/hsdk.h ++++ b/include/configs/hsdk.h +@@ -104,4 +104,10 @@ + /* Cli configuration */ + #define CONFIG_SYS_CBSIZE 2048 + ++/* ++ * Callback configuration ++ */ ++#define CONFIG_BOARD_EARLY_INIT_R ++#define CONFIG_BOARD_LATE_INIT ++ + #endif /* _CONFIG_HSDK_H_ */ +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0016-ARc-HSDK-hsdk_go-V0.7-clock-command-clock-improvemen.patch b/board/synopsys/hsdk/uboot-patches/0016-ARc-HSDK-hsdk_go-V0.7-clock-command-clock-improvemen.patch new file mode 100644 index 00000000000..731f0c4e857 --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0016-ARc-HSDK-hsdk_go-V0.7-clock-command-clock-improvemen.patch @@ -0,0 +1,875 @@ +From 7bb75b85e0b31f62bdcfb351d2e7ee357dd95daa Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Sat, 9 Dec 2017 20:25:59 +0300 +Subject: [PATCH 16/46] ARc: HSDK: hsdk_go V0.7, clock command, clock + improvements + +Signed-off-by: Eugeniy Paltsev +--- + board/synopsys/hsdk/hsdk-cmd.c | 616 +++++++++++++++++++++++++++++------------ + 1 file changed, 437 insertions(+), 179 deletions(-) + +diff --git a/board/synopsys/hsdk/hsdk-cmd.c b/board/synopsys/hsdk/hsdk-cmd.c +index 32c622fd6b..1fad17adf9 100644 +--- a/board/synopsys/hsdk/hsdk-cmd.c ++++ b/board/synopsys/hsdk/hsdk-cmd.c +@@ -14,20 +14,33 @@ + #error "hsdk_go will not work with BIG endian CPU" + #endif + +-#define HSDKGO_VERSION "0.6" +- +-#define HZ_IN_MHZ 1000000 ++#define HSDKGO_VERSION "0.7" + + #define ceil(x, y) ({ ulong __x = (x), __y = (y); (__x + __y - 1) / __y; }) + ++/* TODO: move to common config */ + #define NR_CPUS 4 + #define MASTER_CPU 0 + #define MAX_CMD_LEN 25 ++#define HZ_IN_MHZ 1000000 + + #define NO_CCM 0x10 + ++enum clk_ctl { ++ 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 */ ++}; ++ + void smp_set_core_boot_addr(unsigned long addr, int corenr); + ++enum env_type { ++ ENV_DEC, ++ ENV_HEX ++}; ++ + typedef struct { + u32 val; + bool set; +@@ -52,7 +65,8 @@ struct hsdk_env_common_ctl { + }; + + struct hsdk_env_map_common { +- const char * const env_name; ++ const char *const env_name; ++ enum env_type type; + bool mandatory; + u32 min; + u32 max; +@@ -60,7 +74,8 @@ struct hsdk_env_map_common { + }; + + struct hsdk_env_map_core { +- const char * const env_name; ++ const char *const env_name; ++ enum env_type type; + bool mandatory; + u32 min[NR_CPUS]; + u32 max[NR_CPUS]; +@@ -73,9 +88,10 @@ static u32 slave_stack[256 * NR_CPUS] __attribute__((aligned(4))); + static struct hsdk_env_common_ctl env_common = {}; + static struct hsdk_env_core_ctl env_core = {}; + +-int soc_clk_ctl(const char *name, ulong *rate, bool set) ++int soc_clk_ctl(const char *name, ulong *rate, enum clk_ctl ctl) + { + int ret; ++ ulong priv_rate; + struct clk clk; + + /* Dummy fmeas device, just to be able to use standard clk_* api funcs */ +@@ -90,21 +106,39 @@ int soc_clk_ctl(const char *name, ulong *rate, bool set) + return ret; + } + +- ret = clk_enable(&clk); +- if (ret && ret != -ENOSYS && ret != -ENOTSUPP) +- return ret; ++ if (ctl & CLK_ON) { ++ ret = clk_enable(&clk); ++ if (ret && ret != -ENOSYS && ret != -ENOTSUPP) ++ return ret; ++ } + +- if (set) { ++ if ((ctl & CLK_SET) && rate != NULL) { + ret = clk_set_rate(&clk, *rate); + if (ret) + return ret; + } + +- *rate = clk_get_rate(&clk); ++ 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); ++ ++ if ((ctl & CLK_GET) && rate != NULL) { ++ *rate = priv_rate; ++ } + + clk_free(&clk); + +- debug("HSDK: clock '%s' rate %lu MHz\n", name, ceil(*rate, HZ_IN_MHZ)); ++ if (ctl & CLK_PRINT) { ++ printf("HSDK: clock '%s' rate %lu MHz\n", name, ceil(priv_rate, HZ_IN_MHZ)); ++ } else { ++ debug("HSDK: clock '%s' rate %lu MHz\n", name, ceil(priv_rate, HZ_IN_MHZ)); ++ } + + return 0; + } +@@ -115,33 +149,53 @@ static bool is_cpu_used(u32 cpu_id) + } + + static const struct hsdk_env_map_common env_map_common[] = { +- { "core_mask", true, 0x1, 0xF, &env_common.core_mask }, +- { "cpu_freq", false, 100, 1000, &env_common.cpu_freq }, +- { "axi_freq", false, 200, 800, &env_common.axi_freq }, +- { "tun_freq", false, 0, 150, &env_common.tun_freq }, +- { "non_volatile_limit", true, 0, 0xF, &env_common.nvlim }, +- { "icache_ena", true, 0, 1, &env_common.icache }, +- { "dcache_ena", true, 0, 1, &env_common.dcache }, ++ { "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 hsdk_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 hsdk_env_map_core env_map_core[] = { +- { "core_entry", true, {0, 0, 0, 0}, {U32_MAX, U32_MAX, U32_MAX, U32_MAX}, &env_core.entry }, +- { "core_iccm", true, {NO_CCM, 0, NO_CCM, 0}, {NO_CCM, 0xF, NO_CCM, 0xF}, &env_core.iccm }, +- { "core_dccm", true, {NO_CCM, 0, NO_CCM, 0}, {NO_CCM, 0xF, NO_CCM, 0xF}, &env_core.dccm }, ++ { "core_entry", ENV_HEX, true, {0, 0, 0, 0}, {U32_MAX, U32_MAX, U32_MAX, U32_MAX}, &env_core.entry }, ++ { "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 hsdk_env_map_common env_map_bootm[] = { ++ { "core_mask", ENV_HEX, false, 0x1, 0xF, &env_common.core_mask }, + {} + }; + +-static int env_read_common(u32 index) ++static void env_clear_common(u32 index, const struct hsdk_env_map_common *map) ++{ ++ map[index].val->val = 0; ++ map[index].val->set = false; ++} ++ ++static int env_read_common(u32 index, const struct hsdk_env_map_common *map) + { + u32 val; + +- if (!env_get_yesno(env_map_common[index].env_name)) { +- val = (u32)env_get_hex(env_map_common[index].env_name, 0); +- debug("ENV: %s = %#x\n", env_map_common[index].env_name, 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); ++ } + +- env_map_common[index].val->val = val; +- env_map_common[index].val->set = true; ++ map[index].val->val = val; ++ map[index].val->set = true; + } + + return 0; +@@ -156,8 +210,13 @@ static int env_read_core(u32 index) + for (i = 0; i < NR_CPUS; i++) { + sprintf(comand, "%s_%u", env_map_core[index].env_name, i); + if (!env_get_yesno(comand)) { +- val = (u32)env_get_hex(comand, 0); +- debug("ENV: %s: = %#x\n", comand, val); ++ if (env_map_core[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); ++ } + + (*env_map_core[index].val)[i].val = val; + (*env_map_core[index].val)[i].set = true; +@@ -168,17 +227,17 @@ static int env_read_core(u32 index) + } + + /* environment common verification */ +-static int env_validate_common(u32 index) ++static int env_validate_common(u32 index, const struct hsdk_env_map_common *map) + { +- u32 value = env_map_common[index].val->val; +- bool set = env_map_common[index].val->set; +- u32 min = env_map_common[index].min; +- u32 max = env_map_common[index].max; ++ 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 (env_map_common[index].mandatory && !set) { ++ if (map[index].mandatory && !set) { + pr_err("Variable \'%s\' is mandatory, but it is not defined\n", +- env_map_common[index].env_name); ++ map[index].env_name); + + return -EINVAL; + } +@@ -186,7 +245,7 @@ static int env_validate_common(u32 index) + /* Check environment boundary */ + if (set && (value < min || value > max)) { + pr_err("Variable \'%s\' must be between %#x and %#x\n", +- env_map_common[index].env_name, min, max); ++ map[index].env_name, min, max); + + return -EINVAL; + } +@@ -229,27 +288,76 @@ static int env_validate_core(u32 index) + return 0; + } + +-static int env_process_and_validate(void) ++static void envs_cleanup_common(const struct hsdk_env_map_common *map) ++{ ++ u32 i; ++ ++ /* Cleanup env struct first */ ++ for (i = 0; map[i].env_name; i++) { ++ env_clear_common(i, map); ++ } ++} ++ ++static int envs_read_common(const struct hsdk_env_map_common *map) + { + u32 i; + int ret; + +- /* Generic read */ +- for (i = 0; env_map_common[i].env_name; i++) { +- ret = env_read_common(i); ++ for (i = 0; map[i].env_name; i++) { ++ ret = env_read_common(i, map); + if (ret) + return ret; + } + +- for (i = 0; env_map_core[i].env_name; i++) { +- ret = env_read_core(i); ++ return 0; ++} ++ ++static int envs_validate_common(const struct hsdk_env_map_common *map) ++{ ++ u32 i; ++ int ret; ++ ++ for (i = 0; map[i].env_name; i++) { ++ ret = env_validate_common(i, map); + if (ret) + return ret; + } + +- /* Generic validate */ +- for (i = 0; env_map_common[i].env_name; i++) { +- ret = env_validate_common(i); ++ return 0; ++} ++ ++static int env_read_validate_common(const struct hsdk_env_map_common *map) ++{ ++ u32 i; ++ int ret; ++ ++ /* Cleanup env struct first */ ++ for (i = 0; map[i].env_name; i++) { ++ env_clear_common(i, map); ++ } ++ ++ for (i = 0; map[i].env_name; i++) { ++ ret = env_read_common(i, map); ++ if (ret) ++ return ret; ++ } ++ ++ for (i = 0; map[i].env_name; i++) { ++ ret = env_validate_common(i, map); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int env_read_validate_core(void) ++{ ++ u32 i; ++ int ret; ++ ++ for (i = 0; env_map_core[i].env_name; i++) { ++ ret = env_read_core(i); + if (ret) + return ret; + } +@@ -263,14 +371,29 @@ static int env_process_and_validate(void) + return 0; + } + +-#define APT_SHIFT 28 ++static int env_process_and_validate(void) ++{ ++ int ret; ++ ++ ret = env_read_validate_common(env_map_common); ++ if (ret) ++ return ret; ++ ++ ret = env_read_validate_core(); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++/* TODO: move to explicit external cache header */ + + /* Bit values in IC_CTRL */ + #define IC_CTRL_CACHE_DISABLE (1 << 0) +- + /* Bit values in DC_CTRL */ + #define DC_CTRL_CACHE_DISABLE (1 << 0) + #define DC_CTRL_INV_MODE_FLUSH (1 << 6) ++#define APT_SHIFT 28 + + // TODO: add xCCM runtime check + static void smp_init_slave_cpu_func(u32 core) +@@ -392,7 +515,7 @@ static int cleanup_before_go(void) + return 0; + } + +-static inline void this_cpu_halt(void) ++static inline void halt_this_cpu(void) + { + __builtin_arc_flag(1); + } +@@ -447,7 +570,7 @@ __attribute__((naked, noreturn, flatten)) noinline void hsdk_core_init_f(void) + flush_dcache_all(); + + /* Halt the processor untill the master kick us again */ +- this_cpu_halt(); ++ halt_this_cpu(); + + __builtin_arc_nop(); + __builtin_arc_nop(); +@@ -458,7 +581,7 @@ __attribute__((naked, noreturn, flatten)) noinline void hsdk_core_init_f(void) + + /* Something went terribly wrong */ + while (true) +- this_cpu_halt(); ++ halt_this_cpu(); + } + + static void do_init_slave_cpu(u32 cpu_id) +@@ -632,115 +755,27 @@ static void init_memory_bridge(void) + + static void setup_clocks(void) + { +- ulong rate, tmp_rate; ++ ulong rate; + + /* Setup CPU clock */ + if (env_common.cpu_freq.set) { + rate = env_common.cpu_freq.val * HZ_IN_MHZ; +- soc_clk_ctl("cpu-pll", &rate, true); /* 100MHz - 1GHz is OK for PLL */ +- soc_clk_ctl("cpu-clk", &rate, true); /* div factor = 1 */ ++ soc_clk_ctl("cpu-clk", &rate, CLK_ON | CLK_SET); + } + + /* Setup TUN clock */ + if (env_common.tun_freq.set) { + rate = env_common.tun_freq.val * HZ_IN_MHZ; +- if (rate >= 100 * HZ_IN_MHZ) { +- /* 150 MHz : PLL - 150MHz; DIV = 1 */ +- /* 125 MHz : PLL - 125MHz; DIV = 1 */ +- /* 100 MHz : PLL - 100MHz; DIV = 1 */ +- soc_clk_ctl("tun-pll", &rate, true); /* 100MHz - 150MHz is OK for PLL */ +- soc_clk_ctl("tun-clk", &rate, true); /* div factor = 1 */ +- } else if (rate > 0) { +- /* 75 MHz : PLL - 150MHz; DIV = 2 */ +- /* 50 MHz : PLL - 150MHz; DIV = 3 */ +- /* 25 MHz : PLL - 150MHz; DIV = 6 */ +- tmp_rate = 150 * HZ_IN_MHZ; +- soc_clk_ctl("tun-pll", &tmp_rate, true); +- soc_clk_ctl("tun-clk", &rate, true); /* div factor - autocalc */ +- } else { +- /* 25 MHz : PLL - DNC; DIV = OFF */ +- // TODO: add +- } ++ if (rate) ++ soc_clk_ctl("tun-clk", &rate, CLK_ON | CLK_SET); ++ else ++ soc_clk_ctl("tun-clk", NULL, CLK_OFF); + } + + if (env_common.axi_freq.set) { + rate = env_common.axi_freq.val * HZ_IN_MHZ; +- /* firstly we need to increase SYS dividers factors to set +- * 'safe' freq values */ +- tmp_rate = 33333333; +- soc_clk_ctl("sys-apb", &tmp_rate, true); +- soc_clk_ctl("sys-axi", &tmp_rate, true); +- soc_clk_ctl("sys-eth", &tmp_rate, true); +- soc_clk_ctl("sys-usb", &tmp_rate, true); +- soc_clk_ctl("sys-sdio", &tmp_rate, true); +- soc_clk_ctl("sys-hdmi", &tmp_rate, true); +- soc_clk_ctl("sys-gfx-core", &tmp_rate, true); +- soc_clk_ctl("sys-gfx-dma", &tmp_rate, true); +- soc_clk_ctl("sys-gfx-cfg", &tmp_rate, true); +- soc_clk_ctl("sys-dmac-core", &tmp_rate, true); +- soc_clk_ctl("sys-dmac-cfg", &tmp_rate, true); +- soc_clk_ctl("sys-sdio-ref", &tmp_rate, true); +- soc_clk_ctl("sys-spi", &tmp_rate, true); +- soc_clk_ctl("sys-i2c", &tmp_rate, true); +- soc_clk_ctl("sys-uart", &tmp_rate, true); +- soc_clk_ctl("sys-ebi", &tmp_rate, true); +- +- /* update (increase) PLL clock */ +- if (rate == 800 * HZ_IN_MHZ) { +- tmp_rate = 800 * HZ_IN_MHZ; +- soc_clk_ctl("sys-pll", &tmp_rate, true); +- soc_clk_ctl("sys-axi", &tmp_rate, true); +- } else if (rate == 600 * HZ_IN_MHZ) { +- tmp_rate = 600 * HZ_IN_MHZ; +- soc_clk_ctl("sys-pll", &tmp_rate, true); +- soc_clk_ctl("sys-axi", &tmp_rate, true); +- } else if (rate <= 400 * HZ_IN_MHZ) { +- tmp_rate = 400 * HZ_IN_MHZ; +- soc_clk_ctl("sys-pll", &tmp_rate, true); +- soc_clk_ctl("sys-axi", &rate, true); /* div factor - autocalc */ +- } +- +- /* return SYS dividers factors to 'fast' freq values */ +- tmp_rate = 200 * HZ_IN_MHZ; +- soc_clk_ctl("sys-apb", &tmp_rate, true); +- tmp_rate = 400 * HZ_IN_MHZ; +- soc_clk_ctl("sys-eth", &tmp_rate, true); +- soc_clk_ctl("sys-usb", &tmp_rate, true); +- soc_clk_ctl("sys-sdio", &tmp_rate, true); +- soc_clk_ctl("sys-hdmi", &tmp_rate, true); +- tmp_rate = 800 * HZ_IN_MHZ; +- soc_clk_ctl("sys-gfx-core", &tmp_rate, true); +- tmp_rate = 400 * HZ_IN_MHZ; +- soc_clk_ctl("sys-gfx-dma", &tmp_rate, true); +- tmp_rate = 200 * HZ_IN_MHZ; +- soc_clk_ctl("sys-gfx-cfg", &tmp_rate, true); +- tmp_rate = 400 * HZ_IN_MHZ; +- soc_clk_ctl("sys-dmac-core", &tmp_rate, true); +- tmp_rate = 200 * HZ_IN_MHZ; +- soc_clk_ctl("sys-dmac-cfg", &tmp_rate, true); +- tmp_rate = 100 * HZ_IN_MHZ; +- soc_clk_ctl("sys-sdio-ref", &tmp_rate, true); +- tmp_rate = 33333333; +- soc_clk_ctl("sys-spi", &tmp_rate, true); +- tmp_rate = 200 * HZ_IN_MHZ; +- soc_clk_ctl("sys-i2c", &tmp_rate, true); +- tmp_rate = 33333333; +- soc_clk_ctl("sys-uart", &tmp_rate, true); +- tmp_rate = 50 * HZ_IN_MHZ; +- soc_clk_ctl("sys-ebi", &tmp_rate, true); +- } +- +- soc_clk_ctl("cpu-clk", &rate, false); +- printf("HSDK: clock '%s' rate %lu MHz\n", "cpu-clk", ceil(rate, HZ_IN_MHZ)); +- +- soc_clk_ctl("tun-clk", &rate, false); +- printf("HSDK: clock '%s' rate %lu MHz\n", "tun-clk", ceil(rate, HZ_IN_MHZ)); +- +- soc_clk_ctl("sys-axi", &rate, false); +- printf("HSDK: clock '%s' rate %lu MHz\n", "axi-clk", ceil(rate, HZ_IN_MHZ)); +- +- soc_clk_ctl("ddr-clk", &rate, false); +- printf("HSDK: clock '%s' rate %lu MHz\n", "ddr-clk", ceil(rate, HZ_IN_MHZ)); ++ soc_clk_ctl("sys-axi", &rate, CLK_SET | CLK_ON); ++ } + } + + static void do_init_claster(void) +@@ -781,9 +816,9 @@ static int prepare_cpus(u32 *cpu_start_reg) + env_core.used[i] = is_cpu_used(i); + } + +- do_init_slave_cpus(); ++ printf("CPU start mask is %#x\n", env_common.core_mask.val); + +- setup_clocks(); ++ do_init_slave_cpus(); + + do_init_claster(); + +@@ -801,72 +836,87 @@ static int hsdk_go_run(u32 cpu_start_reg) + cleanup_before_go(); + + if (env_common.halt_on_boot) +- this_cpu_halt(); ++ halt_this_cpu(); + +- /* Kick chosen CPUs */ ++ __builtin_arc_nop(); ++ __builtin_arc_nop(); ++ __builtin_arc_nop(); ++ ++ /* Kick chosen slave CPUs */ + writel(cpu_start_reg, (void __iomem *)CREG_CPU_START); + + if (env_core.used[MASTER_CPU]) + ((void (*)(void))(env_core.entry[MASTER_CPU].val))(); + else +- this_cpu_halt(); ++ 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) +- this_cpu_halt(); ++ halt_this_cpu(); + + return 0; + } + +-static int bootm_run(u32 cpu_start_reg) ++int board_prep_linux(bootm_headers_t *images) + { +- debug("bootm cpumask: %#x\n", cpu_start_reg); ++ int ret; + +- /* Cleanup caches, disable interrupts */ +- cleanup_before_go(); ++ ret = env_read_validate_common(env_map_bootm); ++ if (ret) ++ return ret; + +- /* Kick chosen CPUs */ +- writel(cpu_start_reg, (void __iomem *)CREG_CPU_START); ++ /* Rollback to default values */ ++ if (!env_common.core_mask.set) { ++ env_common.core_mask.val = 0xF; ++ env_common.core_mask.set = true; ++ } ++ ++ printf("CPU start mask is %#x\n", env_common.core_mask.val); + + return 0; + } + +-static int hsdk_go_prepare_and_run(void) ++void board_jump_and_run(ulong entry, int zero, int arch, uint params) + { +- int ret; +- u32 reg; ++ void (*kernel_entry)(int zero, int arch, uint params); ++ u32 cpu_start_reg; + +- ret = prepare_cpus(®); +- if (ret) +- return ret; ++ kernel_entry = (void (*)(int, int, uint))entry; + +- return hsdk_go_run(reg); ++ /* Prepare CREG_CPU_START for kicking chosen CPUs */ ++ cpu_start_reg = prepare_cpu_ctart_reg(); ++ ++ smp_set_core_boot_addr(entry, -1); ++ ++ /* Kick chosen slave CPUs */ ++ writel(cpu_start_reg, (void __iomem *)CREG_CPU_START); ++ ++ if (env_common.core_mask.val & BIT(0)) ++ kernel_entry(zero, arch, params); + } + +-int bootm_prepare_and_run(u32 entry) ++static int hsdk_go_prepare_and_run(void) + { + int ret; +- u32 i, reg; +- char comand[MAX_CMD_LEN]; +- +- /* override core entry env by value from image*/ +- for (i = 0; i < NR_CPUS; i++) { +- sprintf(comand, "%s_%u", "core_entry", i); +- env_set_hex(comand, entry); +- } ++ u32 reg; + + ret = prepare_cpus(®); + if (ret) + return ret; + +- return bootm_run(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; ++ + /* TODO: delete after release */ + printf("HSDK: hsdk_go version: %s\n", HSDKGO_VERSION); + +@@ -876,11 +926,13 @@ static int do_hsdk_go(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) + env_common.halt_on_boot = !strcmp(argv[1], "halt"); + if (!env_common.halt_on_boot) { + pr_err("Unrecognised parameter: \'%s\'\n", argv[1]); +- return -EINVAL; ++ return CMD_RET_FAILURE; + } + } + +- return hsdk_go_prepare_and_run(); ++ ret = hsdk_go_prepare_and_run(); ++ ++ return ret ? CMD_RET_FAILURE : CMD_RET_SUCCESS; + } + + U_BOOT_CMD( +@@ -889,3 +941,209 @@ U_BOOT_CMD( + " - 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 hsdk_read_args_search(const struct hsdk_env_map_common *map, int argc, char * const argv[]) ++{ ++ int i; ++ ++ for (i = 0; map[i].env_name; i++) { ++ if (!strcmp(argv[0], map[i].env_name)) ++ return i; ++ } ++ ++ return -ENOENT; ++} ++ ++static int arg_read_set(const struct hsdk_env_map_common *map, u32 i, int argc, char *const argv[]) ++{ ++ char *endp = argv[1]; ++ ++ map[i].val->set = true; ++ ++ 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); ++ ++ if (*endp == '\0') ++ return 0; ++ ++ pr_err("Unexpected argument '%s', can't parse\n", argv[1]); ++ ++ map[i].val->set = false; ++ ++ return -EINVAL; ++} ++ ++static int hsdk_args_enumerate(const struct hsdk_env_map_common *map, int enum_by, int (*act)(const struct hsdk_env_map_common *, u32, int, char *const []), 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 = hsdk_read_args_search(map, argc, argv); ++ ++// printf("PAL: %s: found '%s' with index %d\n", __func__, map[i].env_name, i); ++ ++ if (i < 0) { ++ pr_err("unknown arg: %s\n", argv[0]); ++ return -EINVAL; ++ } ++ ++ if (act(map, i, argc, argv)) ++ return -EINVAL; ++ ++// printf("PAL: %s: value.s '%s' == %#x\n", __func__, argv[1], map[i].val->val); ++ ++ argc -= enum_by; ++ argv += enum_by; ++ } ++ ++ return 0; ++} ++ ++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 = hsdk_args_enumerate(env_map_clock, 2, arg_read_set, 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; ++} ++ ++int env_set_hexi(const char *varname, ulong value) ++{ ++ char str[17]; ++ ++ sprintf(str, "%#lx", value); ++ return env_set(varname, str); ++} ++ ++static int do_hsdk_clock_get(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) ++{ ++ int ret = 0; ++ ulong rate; ++ ++ ret = soc_clk_ctl("cpu-clk", &rate, CLK_GET); ++ if (ret) ++ return CMD_RET_FAILURE; ++ ++ ret = env_set_ulong("cpu_freq", ceil(rate, HZ_IN_MHZ)); ++ if (ret) ++ return CMD_RET_FAILURE; ++ ++ ret = soc_clk_ctl("tun-clk", &rate, CLK_GET); ++ if (ret) ++ return CMD_RET_FAILURE; ++ ++ ret = env_set_ulong("tun_freq", ceil(rate, HZ_IN_MHZ)); ++ if (ret) ++ return CMD_RET_FAILURE; ++ ++ ret = soc_clk_ctl("sys-axi", &rate, CLK_GET); ++ if (ret) ++ return CMD_RET_FAILURE; ++ ++ ret = env_set_ulong("axi_freq", ceil(rate, HZ_IN_MHZ)); ++ if (ret) ++ 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); ++ soc_clk_ctl("tun-clk", NULL, CLK_PRINT); ++ soc_clk_ctl("sys-axi", NULL, CLK_PRINT); ++ soc_clk_ctl("ddr-clk", NULL, CLK_PRINT); ++ ++ /* Other sys clocks */ ++ soc_clk_ctl("sys-apb", NULL, CLK_PRINT); ++// soc_clk_ctl("sys-axi", NULL, CLK_PRINT); ++ soc_clk_ctl("sys-eth", NULL, CLK_PRINT); ++ soc_clk_ctl("sys-usb", NULL, CLK_PRINT); ++ soc_clk_ctl("sys-sdio", NULL, CLK_PRINT); ++ soc_clk_ctl("sys-hdmi", NULL, CLK_PRINT); ++ soc_clk_ctl("sys-gfx-core", NULL, CLK_PRINT); ++ soc_clk_ctl("sys-gfx-dma", NULL, CLK_PRINT); ++ soc_clk_ctl("sys-gfx-cfg", NULL, CLK_PRINT); ++ soc_clk_ctl("sys-dmac-core", NULL, CLK_PRINT); ++ soc_clk_ctl("sys-dmac-cfg", NULL, CLK_PRINT); ++ soc_clk_ctl("sys-sdio-ref", NULL, CLK_PRINT); ++ soc_clk_ctl("sys-spi", NULL, CLK_PRINT); ++ soc_clk_ctl("sys-i2c", NULL, CLK_PRINT); ++ soc_clk_ctl("sys-ebi", NULL, CLK_PRINT); ++ soc_clk_ctl("sys-uart", NULL, CLK_PRINT); ++ ++ /* Other hdmi clocks */ ++ soc_clk_ctl("hdmi-clk", NULL, CLK_PRINT); ++ ++ /* Other pll clocks */ ++ soc_clk_ctl("hdmi-pll", NULL, CLK_PRINT); ++ soc_clk_ctl("tun-pll", NULL, CLK_PRINT); ++ soc_clk_ctl("sys-pll", NULL, CLK_PRINT); ++ ++ 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, "", ""), ++}; ++ ++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 clock values to console\n" ++); +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0017-ARC-HSDK-don-t-configure-HW-during-bootm.patch b/board/synopsys/hsdk/uboot-patches/0017-ARC-HSDK-don-t-configure-HW-during-bootm.patch new file mode 100644 index 00000000000..6231d6bedb9 --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0017-ARC-HSDK-don-t-configure-HW-during-bootm.patch @@ -0,0 +1,75 @@ +From 9fdebe8e91fd26ca3ec79fbb45c3cd2c976dcbe8 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Sat, 9 Dec 2017 20:30:10 +0300 +Subject: [PATCH 17/46] ARC: HSDK: don't configure HW during bootm + +Signed-off-by: Eugeniy Paltsev +--- + arch/arc/lib/bootm.c | 28 +++++++++++++++++----------- + 1 file changed, 17 insertions(+), 11 deletions(-) + +diff --git a/arch/arc/lib/bootm.c b/arch/arc/lib/bootm.c +index d4fddc38b3..4fdf3e045e 100644 +--- a/arch/arc/lib/bootm.c ++++ b/arch/arc/lib/bootm.c +@@ -51,26 +51,37 @@ static int cleanup_before_linux(void) + return 0; + } + ++__weak int board_prep_linux(bootm_headers_t *images) { return 0; } ++ + /* Subcommand: PREP */ + static void boot_prep_linux(bootm_headers_t *images) + { + if (image_setup_linux(images)) + hang(); ++ ++ board_prep_linux(images); + } + +-__weak int bootm_prepare_and_run(u32 entry) { return 0; } ++__weak 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; ++ ++ kernel_entry(zero, arch, params); ++} + + /* Subcommand: GO */ + static void boot_jump_linux(bootm_headers_t *images, int flag) + { +- void (*kernel_entry)(int zero, int arch, uint params); ++ ulong kernel_entry; + unsigned int r0, r2; + int fake = (flag & BOOTM_STATE_OS_FAKE_GO); + +- kernel_entry = (void (*)(int, int, uint))images->ep; ++ kernel_entry = images->ep; + + debug("## Transferring control to Linux (at address %08lx)...\n", +- (ulong) kernel_entry); ++ kernel_entry); + bootstage_mark(BOOTSTAGE_ID_RUN_OS); + + printf("\nStarting kernel ...%s\n\n", fake ? +@@ -87,13 +98,8 @@ static void boot_jump_linux(bootm_headers_t *images, int flag) + r2 = (unsigned int)env_get("bootargs"); + } + +- if (!fake) { +- //TODO: split for prepare and run +- if (bootm_prepare_and_run((u32)kernel_entry)) +- return; +- +- kernel_entry(r0, 0, r2); +- } ++ if (!fake) ++ board_jump_and_run(kernel_entry, r0, 0, r2); + } + + int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images) +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0018-ARC-HSDK-CLK-remove-unused-mappings.patch b/board/synopsys/hsdk/uboot-patches/0018-ARC-HSDK-CLK-remove-unused-mappings.patch new file mode 100644 index 00000000000..27e19c898a8 --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0018-ARC-HSDK-CLK-remove-unused-mappings.patch @@ -0,0 +1,44 @@ +From 0355cc41cdd09d9a96561aeb42420f569ad6e0bc Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Mon, 11 Dec 2017 11:53:39 +0300 +Subject: [PATCH 18/46] ARC: HSDK: CLK: remove unused mappings + +Signed-off-by: Eugeniy Paltsev +--- + drivers/clk/clk-hsdk-cgu-mappings.h | 24 ------------------------ + 1 file changed, 24 deletions(-) + delete mode 100644 drivers/clk/clk-hsdk-cgu-mappings.h + +diff --git a/drivers/clk/clk-hsdk-cgu-mappings.h b/drivers/clk/clk-hsdk-cgu-mappings.h +deleted file mode 100644 +index f76a3b91a9..0000000000 +--- a/drivers/clk/clk-hsdk-cgu-mappings.h ++++ /dev/null +@@ -1,24 +0,0 @@ +-#define CLK_ARC_PLL 0 +-#define CLK_ARC 1 +-#define CLK_DDR_PLL 2 +-#define CLK_SYS_PLL 3 +-#define CLK_SYS_APB 4 +-#define CLK_SYS_AXI 5 +-#define CLK_SYS_ETH 6 +-#define CLK_SYS_USB 7 +-#define CLK_SYS_SDIO 8 +-#define CLK_SYS_HDMI 9 +-#define CLK_SYS_GFX_CORE 10 +-#define CLK_SYS_GFX_DMA 11 +-#define CLK_SYS_GFX_CFG 12 +-#define CLK_SYS_DMAC_CORE 13 +-#define CLK_SYS_DMAC_CFG 14 +-#define CLK_SYS_SDIO_REF 15 +-#define CLK_SYS_SPI_REF 16 +-#define CLK_SYS_I2C_REF 17 +-#define CLK_SYS_UART_REF 18 +-#define CLK_SYS_EBI_REF 19 +-#define CLK_TUN_PLL 20 +-#define CLK_TUN 21 +-#define CLK_HDMI_PLL 22 +-#define CLK_HDMI 23 +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0019-ARC-HSDK-ADD-usb-header.patch b/board/synopsys/hsdk/uboot-patches/0019-ARC-HSDK-ADD-usb-header.patch new file mode 100644 index 00000000000..0aaf6d0aa4c --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0019-ARC-HSDK-ADD-usb-header.patch @@ -0,0 +1,25 @@ +From 8ac3684df6bc4828ccf7d31fd6df1af1bd54673e Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Mon, 11 Dec 2017 12:04:48 +0300 +Subject: [PATCH 19/46] ARC: HSDK: ADD usb header + +Signed-off-by: Eugeniy Paltsev +--- + board/synopsys/hsdk/hsdk.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/board/synopsys/hsdk/hsdk.c b/board/synopsys/hsdk/hsdk.c +index 237a13316d..c20f00c2bf 100644 +--- a/board/synopsys/hsdk/hsdk.c ++++ b/board/synopsys/hsdk/hsdk.c +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + + DECLARE_GLOBAL_DATA_PTR; + +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0020-ARC-cache-fix-using-uninitialized-_exists-variables.patch b/board/synopsys/hsdk/uboot-patches/0020-ARC-cache-fix-using-uninitialized-_exists-variables.patch new file mode 100644 index 00000000000..3a50a3cb48f --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0020-ARC-cache-fix-using-uninitialized-_exists-variables.patch @@ -0,0 +1,89 @@ +From bb0f513315fe3c80092837a233f7da7bd7c0e14b Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Thu, 30 Nov 2017 15:03:36 +0300 +Subject: [PATCH 20/46] ARC: cache: fix using uninitialized "*_exists" + variables + +dcache_exists, icache_exists, slc_exists, ioc_exists global +variables in "arch/arc/lib/cache.c" remain uninitialized if +SOC doesn't have corresponding HW. +This happens because we use next construction for their +definition/initialization: + +-------------------------->>--------------------- +int ioc_exists __section(".data"); + +if (/* condition */) + ioc_exists = 1; +-------------------------->>--------------------- + +Also fix ther type to "bool" as more appropriate. + +Signed-off-by: Eugeniy Paltsev +--- + arch/arc/lib/cache.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/arch/arc/lib/cache.c b/arch/arc/lib/cache.c +index cbae27e9fc..9f560d227c 100644 +--- a/arch/arc/lib/cache.c ++++ b/arch/arc/lib/cache.c +@@ -32,15 +32,15 @@ + * relocation but will be used after being zeroed. + */ + int l1_line_sz __section(".data"); +-int dcache_exists __section(".data"); +-int icache_exists __section(".data"); ++bool dcache_exists __section(".data") = false; ++bool icache_exists __section(".data") = false; + + #define CACHE_LINE_MASK (~(l1_line_sz - 1)) + + #ifdef CONFIG_ISA_ARCV2 + int slc_line_sz __section(".data"); +-int slc_exists __section(".data"); +-int ioc_exists __section(".data"); ++bool slc_exists __section(".data") = false; ++bool ioc_exists __section(".data") = false; + + static unsigned int __before_slc_op(const int op) + { +@@ -152,7 +152,7 @@ static void read_decode_cache_bcr_arcv2(void) + sbcr.word = read_aux_reg(ARC_BCR_SLC); + if (sbcr.fields.ver) { + slc_cfg.word = read_aux_reg(ARC_AUX_SLC_CONFIG); +- slc_exists = 1; ++ slc_exists = true; + slc_line_sz = (slc_cfg.fields.lsz == 0) ? 128 : 64; + } + +@@ -169,7 +169,7 @@ static void read_decode_cache_bcr_arcv2(void) + + cbcr.word = read_aux_reg(ARC_BCR_CLUSTER); + if (cbcr.fields.c) +- ioc_exists = 1; ++ ioc_exists = true; + } + #endif + +@@ -190,7 +190,7 @@ void read_decode_cache_bcr(void) + + ibcr.word = read_aux_reg(ARC_BCR_IC_BUILD); + if (ibcr.fields.ver) { +- icache_exists = 1; ++ icache_exists = true; + l1_line_sz = ic_line_sz = 8 << ibcr.fields.line_len; + if (!ic_line_sz) + panic("Instruction exists but line length is 0\n"); +@@ -198,7 +198,7 @@ void read_decode_cache_bcr(void) + + dbcr.word = read_aux_reg(ARC_BCR_DC_BUILD); + if (dbcr.fields.ver){ +- dcache_exists = 1; ++ dcache_exists = true; + l1_line_sz = dc_line_sz = 16 << dbcr.fields.line_len; + if (!dc_line_sz) + panic("Data cache exists but line length is 0\n"); +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0021-ARC-HSDK-CLK-update-CGU-driver.patch b/board/synopsys/hsdk/uboot-patches/0021-ARC-HSDK-CLK-update-CGU-driver.patch new file mode 100644 index 00000000000..14c9eee8174 --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0021-ARC-HSDK-CLK-update-CGU-driver.patch @@ -0,0 +1,725 @@ +From 26f274628016d0bcfba54e5fcdc73f29937e1d65 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Fri, 15 Dec 2017 16:52:34 +0300 +Subject: [PATCH 21/46] ARC: HSDK: CLK: update CGU driver + +Signed-off-by: Eugeniy Paltsev +--- + drivers/clk/clk-hsdk-cgu.c | 483 ++++++++++++++++++++++++++------------------- + 1 file changed, 285 insertions(+), 198 deletions(-) + +diff --git a/drivers/clk/clk-hsdk-cgu.c b/drivers/clk/clk-hsdk-cgu.c +index 048b172bad..047bc14681 100644 +--- a/drivers/clk/clk-hsdk-cgu.c ++++ b/drivers/clk/clk-hsdk-cgu.c +@@ -8,60 +8,91 @@ + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ ++ ++#define DEBUG ++ + #include + #include + #include + #include + #include + +-#include "clk-hsdk-cgu-mappings.h" +- +-#define CGU_ARC_PLL_CTRL 0x000 //RW ARC PLL control register +-#define CGU_ARC_PLL_STATUS 0x004 //R ARC PLL status register +- +-#define CGU_SYS_PLL_CTRL 0x010 //RW SYS PLL control register +-#define CGU_SYS_PLL_STATUS 0x014 //R SYS PLL status register +- +-#define CGU_DDR_PLL_CTRL 0x020 //RW DDR PLL control register +-#define CGU_DDR_PLL_STATUS 0x024 //R DDR PLL status register +- +-#define CGU_TUN_PLL_CTRL 0x030 //RW Tunnel PLL control register +-#define CGU_TUN_PLL_STATUS 0x034 //R Tunnel PLL status register +- +-#define CGU_HDMI_PLL_CTRL 0x040 //RW HDMI PLL control register +-#define CGU_HDMI_PLL_STATUS 0x044 //R HDMI PLL status register +- +-#define CGU_ARC_IDIV 0x080 //RW Integer divider register for ARC HS38x4 clock +- +-#define CGU_SYS_IDIV_APB 0x180 //RW Integer divider register for APB clock +-#define CGU_SYS_IDIV_AXI 0x190 //RW Integer divider register for AXI clock +-#define CGU_SYS_IDIV_ETH 0x1A0 //RW Integer divider register for ETH clock +-#define CGU_SYS_IDIV_USB 0x1B0 //RW Integer divider register for USB clock +-#define CGU_SYS_IDIV_SDIO 0x1C0 //RW Integer divider register for SDIO clock +-#define CGU_SYS_IDIV_HDMI 0x1D0 //RW Integer divider register for HDMI clock +-#define CGU_SYS_IDIV_GFX_CORE 0x1E0 //RW Integer divider register for GFX core clock +-#define CGU_SYS_IDIV_GFX_DMA 0x1F0 //RW Integer divider register for GFX dma clock +-#define CGU_SYS_IDIV_GFX_CFG 0x200 //RW Integer divider register for GFX config clock +-#define CGU_SYS_IDIV_DMAC_CORE 0x210 //RW Integer divider register for DMAC clock +-#define CGU_SYS_IDIV_DMAC_CFG 0x220 //RW Integer divider register for DMAC config clock +-#define CGU_SYS_IDIV_SDIO_REF 0x230 //RW Integer divider register for SDIO reference clock +-#define CGU_SYS_IDIV_SPI_REF 0x240 //RW Integer divider register for SPI reference clock +-#define CGU_SYS_IDIV_I2C_REF 0x250 //RW Integer divider register for I2C reference clock +-#define CGU_SYS_IDIV_UART_REF 0x260 //RW Integer divider register for UART reference clock +-#define CGU_SYS_IDIV_EBI_REF 0x270 //RW Integer divider register for EBI reference clock +- +-#define CGU_TUN_IDIV 0x380 //RW Integer divider register for Tunnel clock +- +-#define CGU_HDMI_IDIV_APB 0x480 //RW Integer divider register for HDMI clock +- +-#define CGU_I2S_IDIV_TX 0x580 //RW Integer divider register for I2S TX clock +-#define CGU_I2S_IDIV_RX 0x590 //RW Integer divider register for I2S RX clock ++/* ++ * Synopsys ARC HSDK clock tree. ++ * ++ * ------------------ ++ * | 33.33 MHz xtal | ++ * ------------------ ++ * | ++ * | ----------- ++ * |-->| ARC PLL | ++ * | ----------- ++ * | | ++ * | |-->|CGU_ARC_IDIV|-----------> ++ * | |-->|CREG_CORE_IF_DIV|-------> ++ * | ++ * | -------------- ++ * |-->| SYSTEM PLL | ++ * | -------------- ++ * | | ++ * | |-->|CGU_SYS_IDIV_APB|-------> ++ * | |-->|CGU_SYS_IDIV_AXI|-------> ++ * | |-->|CGU_SYS_IDIV_*|---------> ++ * | |-->|CGU_SYS_IDIV_EBI_REF|---> ++ * | ++ * | -------------- ++ * |-->| TUNNEL PLL | ++ * | -------------- ++ * | | ++ * | |-->|CGU_TUN_IDIV|-----------> ++ * | ++ * | ------------ ++ * |-->| HDMI PLL | ++ * | ------------ ++ * | | ++ * | |-->|CGU_HDMI_IDIV_APB|------> ++ * | ++ * | ----------- ++ * |-->| DDR PLL | ++ * ----------- ++ * | ++ * |----------------------------> ++ */ + +-//////////////////////// +-#define CGU_PLL_CTRL 0x000 /* ARC PLL control register */ +-#define CGU_PLL_STATUS 0x004 /* ARC PLL status register */ +-#define CGU_PLL_FMEAS 0x008 /* ARC PLL frequency measurement register */ +-#define CGU_PLL_MON 0x00C /* ARC PLL monitor register */ ++DECLARE_GLOBAL_DATA_PTR; ++ ++#define CGU_ARC_IDIV 0x080 ++#define CGU_TUN_IDIV 0x380 ++#define CGU_HDMI_IDIV_APB 0x480 ++#define CGU_SYS_IDIV_APB 0x180 ++#define CGU_SYS_IDIV_AXI 0x190 ++#define CGU_SYS_IDIV_ETH 0x1A0 ++#define CGU_SYS_IDIV_USB 0x1B0 ++#define CGU_SYS_IDIV_SDIO 0x1C0 ++#define CGU_SYS_IDIV_HDMI 0x1D0 ++#define CGU_SYS_IDIV_GFX_CORE 0x1E0 ++#define CGU_SYS_IDIV_GFX_DMA 0x1F0 ++#define CGU_SYS_IDIV_GFX_CFG 0x200 ++#define CGU_SYS_IDIV_DMAC_CORE 0x210 ++#define CGU_SYS_IDIV_DMAC_CFG 0x220 ++#define CGU_SYS_IDIV_SDIO_REF 0x230 ++#define CGU_SYS_IDIV_SPI_REF 0x240 ++#define CGU_SYS_IDIV_I2C_REF 0x250 ++#define CGU_SYS_IDIV_UART_REF 0x260 ++#define CGU_SYS_IDIV_EBI_REF 0x270 ++ ++#define CGU_IDIV_MASK 0xFF /* All idiv have 8 significant bits */ ++ ++#define CGU_ARC_PLL 0x0 ++#define CGU_SYS_PLL 0x10 ++#define CGU_DDR_PLL 0x20 ++#define CGU_TUN_PLL 0x30 ++#define CGU_HDMI_PLL 0x40 ++ ++#define CGU_PLL_CTRL 0x000 /* ARC PLL control register */ ++#define CGU_PLL_STATUS 0x004 /* ARC PLL status register */ ++#define CGU_PLL_FMEAS 0x008 /* ARC PLL frequency measurement register */ ++#define CGU_PLL_MON 0x00C /* ARC PLL monitor register */ + + #define CGU_PLL_CTRL_ODIV_SHIFT 2 + #define CGU_PLL_CTRL_IDIV_SHIFT 4 +@@ -85,18 +116,45 @@ + #define CREG_CORE_IF_CLK_DIV_1 0x0 + #define CREG_CORE_IF_CLK_DIV_2 0x1 + ++#define MIN_PLL_RATE 100000000 /* 100 MHz */ + #define PARENT_RATE 33333333 /* fixed clock - xtal */ +-//////////////////////// ++#define CGU_MAX_CLOCKS 24 + +-#define CGU_ARC_PLL_OFFT 0x0 +-#define CGU_SYS_PLL_OFFT 0x10 +-#define CGU_DDR_PLL_OFFT 0x20 +-#define CGU_TUN_PLL_OFFT 0x30 +-#define CGU_HDMI_PLL_OFFT 0x40 ++#define CGU_SYS_CLOCKS 16 ++#define MAX_AXI_CLOCKS 4 + +-#define CGU_MAX_CLOCKS 24 ++struct hsdk_idiv_cfg { ++ u32 oft; ++ u8 val[MAX_AXI_CLOCKS]; ++}; + +-#define CGU_IDIV_MASK 0xFF ++struct hsdk_clk_cfg { ++ const u32 clk_rate[MAX_AXI_CLOCKS]; ++ const u32 pll_rate[MAX_AXI_CLOCKS]; ++ const struct hsdk_idiv_cfg idiv[CGU_SYS_CLOCKS]; ++}; ++ ++static const struct hsdk_clk_cfg axi_clk_cfg = { ++ { 200000000, 400000000, 600000000, 800000000 }, ++ { 400000000, 400000000, 600000000, 800000000 }, { ++ { CGU_SYS_IDIV_APB, { 2, 2, 3, 4 } }, /* APB */ ++ { CGU_SYS_IDIV_AXI, { 2, 1, 1, 1 } }, /* AXI */ ++ { CGU_SYS_IDIV_ETH, { 1, 1, 2, 2 } }, /* ETH */ ++ { CGU_SYS_IDIV_USB, { 1, 1, 2, 2 } }, /* USB */ ++ { CGU_SYS_IDIV_SDIO, { 1, 1, 2, 2 } }, /* SDIO */ ++ { CGU_SYS_IDIV_HDMI, { 1, 1, 2, 2 } }, /* HDMI */ ++ { CGU_SYS_IDIV_GFX_CORE, { 1, 1, 2, 2 } }, /* GPU-CORE */ ++ { CGU_SYS_IDIV_GFX_DMA, { 1, 1, 2, 2 } }, /* GPU-DMA */ ++ { CGU_SYS_IDIV_GFX_CFG, { 2, 2, 3, 4 } }, /* GPU-CFG */ ++ { CGU_SYS_IDIV_DMAC_CORE,{ 1, 1, 2, 2 } }, /* DMAC-CORE */ ++ { CGU_SYS_IDIV_DMAC_CFG, { 2, 2, 3, 4 } }, /* DMAC-CFG */ ++ { CGU_SYS_IDIV_SDIO_REF, { 4, 4, 6, 8 } }, /* SDIO-REF */ ++ { CGU_SYS_IDIV_SPI_REF, { 12, 12, 18, 24 } }, /* SPI-REF */ ++ { CGU_SYS_IDIV_I2C_REF, { 2, 2, 3, 4 } }, /* I2C-REF */ ++ { CGU_SYS_IDIV_UART_REF, { 12, 12, 18, 24 } }, /* UART-REF */ ++ { CGU_SYS_IDIV_EBI_REF, { 8, 8, 12, 16 } } /* EBI-REF */ ++ } ++}; + + struct hsdk_pll_cfg { + u32 rate; +@@ -138,7 +196,7 @@ static const struct hsdk_pll_cfg hdmi_pll_cfg[] = { + {} + }; + +-struct hsdk_pll_clk { ++struct hsdk_cgu_clk { + /* CGU block register */ + void __iomem *cgu_regs; + /* CREG block register */ +@@ -157,95 +215,107 @@ struct hsdk_pll_clk { + + struct hsdk_pll_devdata { + const struct hsdk_pll_cfg *pll_cfg; +- int (*update_rate)(struct hsdk_pll_clk *clk, unsigned long rate, ++ int (*update_rate)(struct hsdk_cgu_clk *clk, unsigned long rate, + const struct hsdk_pll_cfg *cfg); + }; + +-static int hsdk_pll_core_update_rate(struct hsdk_pll_clk *, unsigned long, ++static int hsdk_pll_core_update_rate(struct hsdk_cgu_clk *, unsigned long, + const struct hsdk_pll_cfg *); +-static int hsdk_pll_comm_update_rate(struct hsdk_pll_clk *, unsigned long, ++static int hsdk_pll_comm_update_rate(struct hsdk_cgu_clk *, unsigned long, + const struct hsdk_pll_cfg *); + +-static const struct hsdk_pll_devdata core_pll_devdata = { ++static const struct hsdk_pll_devdata core_pll_dat = { + .pll_cfg = asdt_pll_cfg, + .update_rate = hsdk_pll_core_update_rate, + }; + +-static const struct hsdk_pll_devdata sdt_pll_devdata = { ++static const struct hsdk_pll_devdata sdt_pll_dat = { + .pll_cfg = asdt_pll_cfg, + .update_rate = hsdk_pll_comm_update_rate, + }; + +-static const struct hsdk_pll_devdata hdmi_pll_devdata = { ++static const struct hsdk_pll_devdata hdmi_pll_dat = { + .pll_cfg = hdmi_pll_cfg, + .update_rate = hsdk_pll_comm_update_rate, + }; + ++static ulong idiv_set(struct clk *, ulong); ++static ulong cpu_clk_set(struct clk *, ulong); ++static ulong axi_clk_set(struct clk *, ulong); ++static ulong tun_clk_set(struct clk *, ulong); ++static ulong idiv_get(struct clk *); ++static int idiv_off(struct clk *); ++static ulong pll_set(struct clk *, ulong); ++static ulong pll_get(struct clk *); ++ + struct hsdk_cgu_clock_map { + u32 cgu_pll_oft; + u32 creg_div_oft; + u32 cgu_div_oft; + const struct hsdk_pll_devdata *pll_devdata; ++ ulong (*get_rate)(struct clk *clk); ++ ulong (*set_rate)(struct clk *clk, ulong rate); ++ int (*disable)(struct clk *clk); + }; + + static const struct hsdk_cgu_clock_map clock_map[] = { +- { CGU_ARC_PLL_OFFT, 0, 0, &core_pll_devdata }, // CLK_ARC_PLL +- { CGU_ARC_PLL_OFFT, 0, CGU_ARC_IDIV, &core_pll_devdata }, // CLK_ARC +- { CGU_DDR_PLL_OFFT, 0, 0, &sdt_pll_devdata }, // CLK_DDR_PLL +- { CGU_SYS_PLL_OFFT, 0, 0, &sdt_pll_devdata }, // CLK_SYS_PLL +- { CGU_SYS_PLL_OFFT, 0, CGU_SYS_IDIV_APB, &sdt_pll_devdata }, // CLK_SYS_APB +- { CGU_SYS_PLL_OFFT, 0, CGU_SYS_IDIV_AXI, &sdt_pll_devdata }, // CLK_SYS_AXI +- { CGU_SYS_PLL_OFFT, 0, CGU_SYS_IDIV_ETH, &sdt_pll_devdata }, // CLK_SYS_ETH +- { CGU_SYS_PLL_OFFT, 0, CGU_SYS_IDIV_USB, &sdt_pll_devdata }, // CLK_SYS_USB +- { CGU_SYS_PLL_OFFT, 0, CGU_SYS_IDIV_SDIO, &sdt_pll_devdata }, // CLK_SYS_SDIO +- { CGU_SYS_PLL_OFFT, 0, CGU_SYS_IDIV_HDMI, &sdt_pll_devdata }, // CLK_SYS_HDMI +- { CGU_SYS_PLL_OFFT, 0, CGU_SYS_IDIV_GFX_CORE, &sdt_pll_devdata }, // CLK_SYS_GFX_CORE +- { CGU_SYS_PLL_OFFT, 0, CGU_SYS_IDIV_GFX_DMA, &sdt_pll_devdata }, // CLK_SYS_GFX_DMA +- { CGU_SYS_PLL_OFFT, 0, CGU_SYS_IDIV_GFX_CFG, &sdt_pll_devdata }, // CLK_SYS_GFX_CFG +- { CGU_SYS_PLL_OFFT, 0, CGU_SYS_IDIV_DMAC_CORE, &sdt_pll_devdata }, // CLK_SYS_DMAC_CORE +- { CGU_SYS_PLL_OFFT, 0, CGU_SYS_IDIV_DMAC_CFG, &sdt_pll_devdata }, // CLK_SYS_DMAC_CFG +- { CGU_SYS_PLL_OFFT, 0, CGU_SYS_IDIV_SDIO_REF, &sdt_pll_devdata }, // CLK_SYS_SDIO_REF +- { CGU_SYS_PLL_OFFT, 0, CGU_SYS_IDIV_SPI_REF, &sdt_pll_devdata }, // CLK_SYS_SPI_REF +- { CGU_SYS_PLL_OFFT, 0, CGU_SYS_IDIV_I2C_REF, &sdt_pll_devdata }, // CLK_SYS_I2C_REF +- { CGU_SYS_PLL_OFFT, 0, CGU_SYS_IDIV_UART_REF, &sdt_pll_devdata }, // CLK_SYS_UART_REF +- { CGU_SYS_PLL_OFFT, 0, CGU_SYS_IDIV_EBI_REF, &sdt_pll_devdata }, // CLK_SYS_EBI_REF +- { CGU_TUN_PLL_OFFT, 0, 0, &sdt_pll_devdata }, // CLK_TUN_PLL +- { CGU_TUN_PLL_OFFT, 0, CGU_TUN_IDIV, &sdt_pll_devdata }, // CLK_TUN +- { CGU_HDMI_PLL_OFFT, 0, 0, &hdmi_pll_devdata }, // CLK_HDMI_PLL +- { CGU_HDMI_PLL_OFFT, 0, CGU_HDMI_IDIV_APB, &hdmi_pll_devdata } // CLK_HDMI ++ { CGU_ARC_PLL, 0, 0, &core_pll_dat, pll_get, pll_set, NULL }, ++ { CGU_ARC_PLL, 0, CGU_ARC_IDIV, &core_pll_dat, idiv_get, cpu_clk_set, idiv_off }, /* special behavior */ ++ { CGU_DDR_PLL, 0, 0, &sdt_pll_dat, pll_get, pll_set, NULL }, ++ { CGU_SYS_PLL, 0, 0, &sdt_pll_dat, pll_get, pll_set, NULL }, ++ { CGU_SYS_PLL, 0, CGU_SYS_IDIV_APB, &sdt_pll_dat, idiv_get, idiv_set, idiv_off }, ++ { CGU_SYS_PLL, 0, CGU_SYS_IDIV_AXI, &sdt_pll_dat, idiv_get, axi_clk_set, idiv_off }, /* special behavior */ ++ { CGU_SYS_PLL, 0, CGU_SYS_IDIV_ETH, &sdt_pll_dat, idiv_get, idiv_set, idiv_off }, ++ { CGU_SYS_PLL, 0, CGU_SYS_IDIV_USB, &sdt_pll_dat, idiv_get, idiv_set, idiv_off }, ++ { CGU_SYS_PLL, 0, CGU_SYS_IDIV_SDIO, &sdt_pll_dat, idiv_get, idiv_set, idiv_off }, ++ { CGU_SYS_PLL, 0, CGU_SYS_IDIV_HDMI, &sdt_pll_dat, idiv_get, idiv_set, idiv_off }, ++ { CGU_SYS_PLL, 0, CGU_SYS_IDIV_GFX_CORE, &sdt_pll_dat, idiv_get, idiv_set, idiv_off }, ++ { CGU_SYS_PLL, 0, CGU_SYS_IDIV_GFX_DMA, &sdt_pll_dat, idiv_get, idiv_set, idiv_off }, ++ { CGU_SYS_PLL, 0, CGU_SYS_IDIV_GFX_CFG, &sdt_pll_dat, idiv_get, idiv_set, idiv_off }, ++ { CGU_SYS_PLL, 0, CGU_SYS_IDIV_DMAC_CORE, &sdt_pll_dat, idiv_get, idiv_set, idiv_off }, ++ { CGU_SYS_PLL, 0, CGU_SYS_IDIV_DMAC_CFG, &sdt_pll_dat, idiv_get, idiv_set, idiv_off }, ++ { CGU_SYS_PLL, 0, CGU_SYS_IDIV_SDIO_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off }, ++ { CGU_SYS_PLL, 0, CGU_SYS_IDIV_SPI_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off }, ++ { CGU_SYS_PLL, 0, CGU_SYS_IDIV_I2C_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off }, ++ { CGU_SYS_PLL, 0, CGU_SYS_IDIV_UART_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off }, ++ { CGU_SYS_PLL, 0, CGU_SYS_IDIV_EBI_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off }, ++ { CGU_TUN_PLL, 0, 0, &sdt_pll_dat, pll_get, pll_set, NULL }, ++ { CGU_TUN_PLL, 0, CGU_TUN_IDIV, &sdt_pll_dat, idiv_get, tun_clk_set, idiv_off }, /* special behavior */ ++ { CGU_HDMI_PLL, 0, 0, &hdmi_pll_dat, pll_get, pll_set, NULL }, ++ { CGU_HDMI_PLL, 0, CGU_HDMI_IDIV_APB, &hdmi_pll_dat, idiv_get, idiv_set, idiv_off } + }; + +-static inline void hsdk_idiv_write(struct hsdk_pll_clk *clk, u32 val) ++static inline void hsdk_idiv_write(struct hsdk_cgu_clk *clk, u32 val) + { + iowrite32(val, clk->idiv_regs); + } + +-static inline u32 hsdk_idiv_read(struct hsdk_pll_clk *clk) ++static inline u32 hsdk_idiv_read(struct hsdk_cgu_clk *clk) + { + return ioread32(clk->idiv_regs); + } + +-static inline void hsdk_pll_write(struct hsdk_pll_clk *clk, u32 reg, u32 val) ++static inline void hsdk_pll_write(struct hsdk_cgu_clk *clk, u32 reg, u32 val) + { + iowrite32(val, clk->regs + reg); + } + +-static inline u32 hsdk_pll_read(struct hsdk_pll_clk *clk, u32 reg) ++static inline u32 hsdk_pll_read(struct hsdk_cgu_clk *clk, u32 reg) + { + return ioread32(clk->regs + reg); + } + +-static inline void hsdk_pll_spcwrite(struct hsdk_pll_clk *clk, u32 reg, u32 val) ++static inline void hsdk_pll_spcwrite(struct hsdk_cgu_clk *clk, u32 reg, u32 val) + { + iowrite32(val, clk->spec_regs + reg); + } + +-static inline u32 hsdk_pll_spcread(struct hsdk_pll_clk *clk, u32 reg) ++static inline u32 hsdk_pll_spcread(struct hsdk_cgu_clk *clk, u32 reg) + { + return ioread32(clk->spec_regs + reg); + } + +-static inline void hsdk_pll_set_cfg(struct hsdk_pll_clk *clk, ++static inline void hsdk_pll_set_cfg(struct hsdk_cgu_clk *clk, + const struct hsdk_pll_cfg *cfg) + { + u32 val = 0; +@@ -261,22 +331,22 @@ static inline void hsdk_pll_set_cfg(struct hsdk_pll_clk *clk, + hsdk_pll_write(clk, CGU_PLL_CTRL, val); + } + +-static inline bool hsdk_pll_is_locked(struct hsdk_pll_clk *clk) ++static inline bool hsdk_pll_is_locked(struct hsdk_cgu_clk *clk) + { + return !!(hsdk_pll_read(clk, CGU_PLL_STATUS) & CGU_PLL_STATUS_LOCK); + } + +-static inline bool hsdk_pll_is_err(struct hsdk_pll_clk *clk) ++static inline bool hsdk_pll_is_err(struct hsdk_cgu_clk *clk) + { + return !!(hsdk_pll_read(clk, CGU_PLL_STATUS) & CGU_PLL_STATUS_ERR); + } + +-static ulong hsdk_pll_get_rate(struct clk *sclk) ++static ulong pll_get(struct clk *sclk) + { + u32 val; + u64 rate; + u32 idiv, fbdiv, odiv; +- struct hsdk_pll_clk *clk = dev_get_priv(sclk->dev); ++ struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev); + + val = hsdk_pll_read(clk, CGU_PLL_CTRL); + +@@ -307,7 +377,7 @@ static unsigned long hsdk_pll_round_rate(struct clk *sclk, unsigned long rate) + { + int i; + unsigned long best_rate; +- struct hsdk_pll_clk *clk = dev_get_priv(sclk->dev); ++ struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev); + const struct hsdk_pll_cfg *pll_cfg = clk->pll_devdata->pll_cfg; + + if (pll_cfg[0].rate == 0) +@@ -325,7 +395,7 @@ static unsigned long hsdk_pll_round_rate(struct clk *sclk, unsigned long rate) + return best_rate; + } + +-static int hsdk_pll_comm_update_rate(struct hsdk_pll_clk *clk, ++static int hsdk_pll_comm_update_rate(struct hsdk_cgu_clk *clk, + unsigned long rate, + const struct hsdk_pll_cfg *cfg) + { +@@ -345,7 +415,7 @@ static int hsdk_pll_comm_update_rate(struct hsdk_pll_clk *clk, + return 0; + } + +-static int hsdk_pll_core_update_rate(struct hsdk_pll_clk *clk, ++static int hsdk_pll_core_update_rate(struct hsdk_cgu_clk *clk, + unsigned long rate, + const struct hsdk_pll_cfg *cfg) + { +@@ -379,11 +449,11 @@ static int hsdk_pll_core_update_rate(struct hsdk_pll_clk *clk, + return 0; + } + +-static ulong hsdk_pll_set_rate(struct clk *sclk, ulong rate) ++static ulong pll_set(struct clk *sclk, ulong rate) + { + int i; + unsigned long best_rate; +- struct hsdk_pll_clk *clk = dev_get_priv(sclk->dev); ++ struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev); + const struct hsdk_pll_cfg *pll_cfg = clk->pll_devdata->pll_cfg; + + best_rate = hsdk_pll_round_rate(sclk, rate); +@@ -395,20 +465,29 @@ static ulong hsdk_pll_set_rate(struct clk *sclk, ulong rate) + } + } + +- pr_err("invalid rate=%ld, parent_rate=%d\n", best_rate, PARENT_RATE); ++ pr_err("invalid rate=%ld Hz, parent_rate=%d Hz\n", best_rate, PARENT_RATE); + + return -EINVAL; + } + +-static ulong hsdk_idiv_get_rate(struct clk *sclk) ++static int idiv_off(struct clk *sclk) + { +- struct hsdk_pll_clk *clk = dev_get_priv(sclk->dev); +- ulong parent_rate = hsdk_pll_get_rate(sclk); ++ struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev); ++ ++ hsdk_idiv_write(clk, 0); ++ ++ return 0; ++} ++ ++static ulong idiv_get(struct clk *sclk) ++{ ++ struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev); ++ ulong parent_rate = pll_get(sclk); + u32 div_factor = hsdk_idiv_read(clk); + + div_factor &= CGU_IDIV_MASK; + +- debug("current configurarion: %#x (%d)\n", div_factor, div_factor); ++ pr_debug("current configurarion: %#x (%d)\n", div_factor, div_factor); + + if (div_factor == 0) + return 0; +@@ -416,25 +495,91 @@ static ulong hsdk_idiv_get_rate(struct clk *sclk) + return parent_rate / div_factor; + } + +-static ulong hsdk_idiv_set_rate(struct clk *sclk, ulong rate) ++/* Special behavior: wen we set this clock we set both idiv and pll */ ++static ulong cpu_clk_set(struct clk *sclk, ulong rate) + { +- struct hsdk_pll_clk *clk = dev_get_priv(sclk->dev); +- ulong parent_rate = hsdk_pll_get_rate(sclk); ++ ulong ret; ++ ++ ret = pll_set(sclk, rate); ++ idiv_set(sclk, rate); ++ ++ return ret; ++} ++ ++/* Special behavior: wen we set this clock we set both idiv and pll and all pll dividers */ ++static ulong axi_clk_set(struct clk *sclk, ulong rate) ++{ ++ struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev); ++ ulong pll_rate; ++ int i, freq_idx = -1; ++ ulong ret = 0; ++ ++ pll_rate = pll_get(sclk); ++ ++ for (i = 0; i < MAX_AXI_CLOCKS; i++) { ++ if (axi_clk_cfg.clk_rate[i] == rate) { ++ freq_idx = i; ++ break; ++ } ++ } ++ ++ if (freq_idx < 0) { ++ pr_err("axi clk: invalid rate=%ld Hz\n", rate); ++ return -EINVAL; ++ } ++ ++ /* configure PLL before dividers */ ++ if (axi_clk_cfg.pll_rate[freq_idx] < pll_rate) ++ ret = pll_set(sclk, axi_clk_cfg.pll_rate[freq_idx]); ++ ++ /* configure SYS dividers */ ++ for (i = 0; i < CGU_SYS_CLOCKS; i++) { ++ clk->idiv_regs = clk->cgu_regs + axi_clk_cfg.idiv[i].oft; ++ hsdk_idiv_write(clk, axi_clk_cfg.idiv[i].val[freq_idx]); ++ } ++ ++ /* configure PLL after dividers */ ++ if (axi_clk_cfg.pll_rate[freq_idx] >= pll_rate) ++ ret = pll_set(sclk, axi_clk_cfg.pll_rate[freq_idx]); ++ ++ return ret; ++} ++ ++static ulong tun_clk_set(struct clk *sclk, ulong rate) ++{ ++ ulong ret; ++ ++ if (rate >= MIN_PLL_RATE) ++ ret = pll_set(sclk, rate); ++ else ++ ret = pll_set(sclk, 150000000); ++ ++ idiv_set(sclk, rate); ++ ++ return ret; ++} ++ ++static ulong idiv_set(struct clk *sclk, ulong rate) ++{ ++ struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev); ++ ulong parent_rate = pll_get(sclk); + u32 div_factor; + + div_factor = parent_rate / rate; +- if (abs(rate - parent_rate / (div_factor + 1)) <= abs(rate - parent_rate / div_factor)) ++ if (abs(rate - parent_rate / (div_factor + 1)) <= ++ abs(rate - parent_rate / div_factor)) { + div_factor += 1; ++ } + + if (div_factor & ~CGU_IDIV_MASK) { +- pr_err("invalid rate=%ld, parent_rate=%ld, div=%d: max divider valie is%d\n", ++ pr_err("invalid rate=%ld Hz, parent_rate=%ld Hz, div=%d: max divider valie is%d\n", + rate, parent_rate, div_factor, CGU_IDIV_MASK); + + div_factor = CGU_IDIV_MASK; + } + + if (div_factor == 0) { +- pr_err("invalid rate=%ld, parent_rate=%ld, div=%d: min divider valie is 1\n", ++ pr_err("invalid rate=%ld Hz, parent_rate=%ld Hz, div=%d: min divider valie is 1\n", + rate, parent_rate, div_factor); + + div_factor = 1; +@@ -445,125 +590,67 @@ static ulong hsdk_idiv_set_rate(struct clk *sclk, ulong rate) + return 0; + } + +-static void hsdk_prepare_clock_tree_branch(struct clk *sclk) ++static int hsdk_prepare_clock_tree_branch(struct clk *sclk) + { +- struct hsdk_pll_clk *clk = dev_get_priv(sclk->dev); ++ struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev); ++ ++ if (sclk->id >= CGU_MAX_CLOCKS) ++ return -EINVAL; + + clk->pll_devdata = clock_map[sclk->id].pll_devdata; + clk->regs = clk->cgu_regs + clock_map[sclk->id].cgu_pll_oft; + clk->spec_regs = clk->creg_regs + clock_map[sclk->id].creg_div_oft; + clk->idiv_regs = clk->cgu_regs + clock_map[sclk->id].cgu_div_oft; ++ ++ return 0; + } + + static ulong hsdk_cgu_get_rate(struct clk *sclk) + { +-// printf("PAL: %s: id: %ld\n", __func__, sclk->id); +- +- if (sclk->id >= CGU_MAX_CLOCKS) ++ if (hsdk_prepare_clock_tree_branch(sclk)) + return -EINVAL; + +- hsdk_prepare_clock_tree_branch(sclk); +- +- switch (sclk->id) { +- case CLK_ARC_PLL: +- case CLK_DDR_PLL: +- case CLK_SYS_PLL: +- case CLK_TUN_PLL: +- case CLK_HDMI_PLL: +- return hsdk_pll_get_rate(sclk); +- break; +- +- case CLK_ARC: +- case CLK_SYS_APB: +- case CLK_SYS_AXI: +- case CLK_SYS_ETH: +- case CLK_SYS_USB: +- case CLK_SYS_SDIO: +- case CLK_SYS_HDMI: +- case CLK_SYS_GFX_CORE: +- case CLK_SYS_GFX_DMA: +- case CLK_SYS_GFX_CFG: +- case CLK_SYS_DMAC_CORE: +- case CLK_SYS_DMAC_CFG: +- case CLK_SYS_SDIO_REF: +- case CLK_SYS_SPI_REF: +- case CLK_SYS_I2C_REF: +- case CLK_SYS_UART_REF: +- case CLK_SYS_EBI_REF: +- case CLK_TUN: +- case CLK_HDMI: +- return hsdk_idiv_get_rate(sclk); +- break; +- +- default: +- pr_err("CLK-ERR: %s: id: %ld: unsupported\n", __func__, sclk->id); +- break; +- } +- +- return 0; ++ return clock_map[sclk->id].get_rate(sclk); + } + + static ulong hsdk_cgu_set_rate(struct clk *sclk, ulong rate) + { +-// debug("PAL: %s: id: %ld\n", __func__, sclk->id); +- +- if (sclk->id >= CGU_MAX_CLOCKS) ++ if (hsdk_prepare_clock_tree_branch(sclk)) + return -EINVAL; + +- hsdk_prepare_clock_tree_branch(sclk); +- +- switch (sclk->id) { +- case CLK_ARC_PLL: +- case CLK_DDR_PLL: +- case CLK_SYS_PLL: +- case CLK_TUN_PLL: +- case CLK_HDMI_PLL: +- return hsdk_pll_set_rate(sclk, rate); +- break; ++ return clock_map[sclk->id].set_rate(sclk, rate); ++} + +- case CLK_ARC: +- case CLK_SYS_APB: +- case CLK_SYS_AXI: +- case CLK_SYS_ETH: +- case CLK_SYS_USB: +- case CLK_SYS_SDIO: +- case CLK_SYS_HDMI: +- case CLK_SYS_GFX_CORE: +- case CLK_SYS_GFX_DMA: +- case CLK_SYS_GFX_CFG: +- case CLK_SYS_DMAC_CORE: +- case CLK_SYS_DMAC_CFG: +- case CLK_SYS_SDIO_REF: +- case CLK_SYS_SPI_REF: +- case CLK_SYS_I2C_REF: +- case CLK_SYS_UART_REF: +- case CLK_SYS_EBI_REF: +- case CLK_TUN: +- case CLK_HDMI: +- return hsdk_idiv_set_rate(sclk, rate); +- break; ++static int hsdk_cgu_disable(struct clk *sclk) ++{ ++ if (hsdk_prepare_clock_tree_branch(sclk)) ++ return -EINVAL; + +- default: +- pr_err("CLK-ERR: %s: id: %ld: unsupported\n", __func__, sclk->id); +- break; +- } ++ if (clock_map[sclk->id].disable) ++ return clock_map[sclk->id].disable(sclk); + +- return 0; ++ return -ENOTSUPP; + } + + static const struct clk_ops hsdk_cgu_ops = { + .set_rate = hsdk_cgu_set_rate, + .get_rate = hsdk_cgu_get_rate, ++ .disable = hsdk_cgu_disable, + }; + + static int hsdk_cgu_clk_probe(struct udevice *dev) + { +- struct hsdk_pll_clk *pll_clk = dev_get_priv(dev); ++ struct hsdk_cgu_clk *pll_clk = dev_get_priv(dev); + + BUILD_BUG_ON(ARRAY_SIZE(clock_map) != CGU_MAX_CLOCKS); + + pll_clk->cgu_regs = (void __iomem *)devfdt_get_addr_index(dev, 0); ++ if (!pll_clk->cgu_regs) ++ return -EINVAL; ++ + pll_clk->creg_regs = (void __iomem *)devfdt_get_addr_index(dev, 1); ++ if (!pll_clk->creg_regs) ++ return -EINVAL; + + return 0; + } +@@ -578,6 +665,6 @@ U_BOOT_DRIVER(hsdk_cgu_clk) = { + .id = UCLASS_CLK, + .of_match = hsdk_cgu_clk_id, + .probe = hsdk_cgu_clk_probe, +- .platdata_auto_alloc_size = sizeof(struct hsdk_pll_clk), ++ .platdata_auto_alloc_size = sizeof(struct hsdk_cgu_clk), + .ops = &hsdk_cgu_ops, + }; +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0022-ARC-CACHE-add-option-to-disable-IOC.patch b/board/synopsys/hsdk/uboot-patches/0022-ARC-CACHE-add-option-to-disable-IOC.patch new file mode 100644 index 00000000000..85c71cb3faa --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0022-ARC-CACHE-add-option-to-disable-IOC.patch @@ -0,0 +1,36 @@ +From e814dd7a2d43666a237e26bfeabd4e836f2e1f8e Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Fri, 15 Dec 2017 17:30:51 +0300 +Subject: [PATCH 22/46] ARC: CACHE: add option to disable IOC + +Signed-off-by: Eugeniy Paltsev +--- + arch/arc/lib/cache.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/arch/arc/lib/cache.c b/arch/arc/lib/cache.c +index 9f560d227c..a3f9fc23ad 100644 +--- a/arch/arc/lib/cache.c ++++ b/arch/arc/lib/cache.c +@@ -42,6 +42,9 @@ int slc_line_sz __section(".data"); + bool slc_exists __section(".data") = false; + bool ioc_exists __section(".data") = false; + ++/* To force enable IOC set ioc_enable to 'true' */ ++bool ioc_enable __section(".data") = false; ++ + static unsigned int __before_slc_op(const int op) + { + unsigned int reg = reg; +@@ -168,7 +171,7 @@ static void read_decode_cache_bcr_arcv2(void) + } cbcr; + + cbcr.word = read_aux_reg(ARC_BCR_CLUSTER); +- if (cbcr.fields.c) ++ if (cbcr.fields.c && ioc_enable) + ioc_exists = true; + } + #endif +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0023-ARC-ARCv2-CACHE-fix-work-without-IOC.patch b/board/synopsys/hsdk/uboot-patches/0023-ARC-ARCv2-CACHE-fix-work-without-IOC.patch new file mode 100644 index 00000000000..31199020df0 --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0023-ARC-ARCv2-CACHE-fix-work-without-IOC.patch @@ -0,0 +1,273 @@ +From fe2280cca76aed9fb1c76c4cec721865a503aa2d Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Mon, 18 Dec 2017 21:32:08 +0300 +Subject: [PATCH 23/46] ARC: ARCv2: CACHE: fix work without IOC + +Previous slc_line_op implementation is broken. Fix it by replacing +with region operations. + +Signed-off-by: Eugeniy Paltsev +--- + arch/arc/include/asm/arcregs.h | 4 ++ + arch/arc/lib/cache.c | 158 ++++++++++++++++++++++------------------- + 2 files changed, 89 insertions(+), 73 deletions(-) + +diff --git a/arch/arc/include/asm/arcregs.h b/arch/arc/include/asm/arcregs.h +index ba1f7bac77..9e546ccf21 100644 +--- a/arch/arc/include/asm/arcregs.h ++++ b/arch/arc/include/asm/arcregs.h +@@ -63,6 +63,10 @@ + #define ARC_AUX_SLC_INVALIDATE 0x905 + #define ARC_AUX_SLC_IVDL 0x910 + #define ARC_AUX_SLC_FLDL 0x912 ++#define ARC_AUX_SLC_RGN_START 0x914 ++#define ARC_AUX_SLC_RGN_START1 0x915 ++#define ARC_AUX_SLC_RGN_END 0x916 ++#define ARC_AUX_SLC_RGN_END1 0x917 + #define ARC_BCR_CLUSTER 0xcf + + /* IO coherency related auxiliary registers */ +diff --git a/arch/arc/lib/cache.c b/arch/arc/lib/cache.c +index a3f9fc23ad..2764ef3f54 100644 +--- a/arch/arc/lib/cache.c ++++ b/arch/arc/lib/cache.c +@@ -26,6 +26,12 @@ + #define OP_FLUSH 0x2 + #define OP_INV_IC 0x3 + ++/* Bit val in SLC_CONTROL */ ++#define SLC_CTRL_DIS 0x001 ++#define SLC_CTRL_IM 0x040 ++#define SLC_CTRL_BUSY 0x100 ++#define SLC_CTRL_RGN_OP_INV 0x200 ++ + /* + * By default that variable will fall into .bss section. + * But .bss section is not relocated and so it will be initilized before +@@ -45,87 +51,85 @@ bool ioc_exists __section(".data") = false; + /* To force enable IOC set ioc_enable to 'true' */ + bool ioc_enable __section(".data") = false; + +-static unsigned int __before_slc_op(const int op) ++noinline static void __slc_entire_op(const int op) + { +- unsigned int reg = reg; ++ unsigned int ctrl, r = ARC_AUX_SLC_CTRL; + +- if (op == OP_INV) { +- /* +- * IM is set by default and implies Flush-n-inv +- * Clear it here for vanilla inv +- */ +- reg = read_aux_reg(ARC_AUX_SLC_CTRL); +- write_aux_reg(ARC_AUX_SLC_CTRL, reg & ~DC_CTRL_INV_MODE_FLUSH); +- } ++ ctrl = read_aux_reg(r); + +- return reg; +-} +- +-static void __after_slc_op(const int op, unsigned int reg) +-{ +- if (op & OP_FLUSH) { /* flush / flush-n-inv both wait */ +- /* +- * Make sure "busy" bit reports correct status, +- * see STAR 9001165532 +- */ +- read_aux_reg(ARC_AUX_SLC_CTRL); +- while (read_aux_reg(ARC_AUX_SLC_CTRL) & +- DC_CTRL_FLUSH_STATUS) +- ; +- } +- +- /* Switch back to default Invalidate mode */ +- if (op == OP_INV) +- write_aux_reg(ARC_AUX_SLC_CTRL, reg | DC_CTRL_INV_MODE_FLUSH); +-} +- +-static inline void __slc_line_loop(unsigned long paddr, unsigned long sz, +- const int op) +-{ +- unsigned int aux_cmd; +- int num_lines; ++ if (!(op & OP_FLUSH)) /* i.e. OP_INV */ ++ ctrl &= ~SLC_CTRL_IM; /* clear IM: Disable flush before Inv */ ++ else ++ ctrl |= SLC_CTRL_IM; + +-#define SLC_LINE_MASK (~(slc_line_sz - 1)) ++ write_aux_reg(r, ctrl); + +- aux_cmd = op & OP_INV ? ARC_AUX_SLC_IVDL : ARC_AUX_SLC_FLDL; ++ write_aux_reg(ARC_AUX_SLC_INVALIDATE, 1); + +- sz += paddr & ~SLC_LINE_MASK; +- paddr &= SLC_LINE_MASK; ++ /* Make sure "busy" bit reports correct stataus, see STAR 9001165532 */ ++ read_aux_reg(r); + +- num_lines = DIV_ROUND_UP(sz, slc_line_sz); ++ /* Important to wait for flush to complete */ ++ while (read_aux_reg(r) & SLC_CTRL_BUSY); ++} + +- while (num_lines-- > 0) { +- write_aux_reg(aux_cmd, paddr); +- paddr += slc_line_sz; +- } ++static void slc_upper_region_init(void) ++{ ++ /* ++ * ARC_AUX_SLC_RGN_END1 and ARC_AUX_SLC_RGN_START1 are always == 0 ++ * as we don't use PAE40. ++ */ ++ write_aux_reg(ARC_AUX_SLC_RGN_END1, 0); ++ write_aux_reg(ARC_AUX_SLC_RGN_START1, 0); + } + +-static inline void __slc_entire_op(const int cacheop) ++noinline void __slc_rgn_op(unsigned long paddr, unsigned long sz, const int op) + { +- int aux; +- unsigned int ctrl_reg = __before_slc_op(cacheop); ++ unsigned int ctrl; ++ unsigned long end; ++ ++ /* ++ * The Region Flush operation is specified by CTRL.RGN_OP[11..9] ++ * - b'000 (default) is Flush, ++ * - b'001 is Invalidate if CTRL.IM == 0 ++ * - b'001 is Flush-n-Invalidate if CTRL.IM == 1 ++ */ ++ ctrl = read_aux_reg(ARC_AUX_SLC_CTRL); ++ ++ /* Don't rely on default value of IM bit */ ++ if (!(op & OP_FLUSH)) /* i.e. OP_INV */ ++ ctrl &= ~SLC_CTRL_IM; /* clear IM: Disable flush before Inv */ ++ else ++ ctrl |= SLC_CTRL_IM; + +- if (cacheop & OP_INV) /* Inv or flush-n-inv use same cmd reg */ +- aux = ARC_AUX_SLC_INVALIDATE; ++ if (op & OP_INV) ++ ctrl |= SLC_CTRL_RGN_OP_INV; /* Inv or flush-n-inv */ + else +- aux = ARC_AUX_SLC_FLUSH; ++ ctrl &= ~SLC_CTRL_RGN_OP_INV; + +- write_aux_reg(aux, 0x1); ++ write_aux_reg(ARC_AUX_SLC_CTRL, ctrl); + +- __after_slc_op(cacheop, ctrl_reg); +-} ++ /* ++ * Lower bits are ignored, no need to clip ++ * END needs to be setup before START (latter triggers the operation) ++ * END can't be same as START, so add (l2_line_sz - 1) to sz ++ */ ++ end = paddr + sz + slc_line_sz - 1; + +-static inline void __slc_line_op(unsigned long paddr, unsigned long sz, +- const int cacheop) +-{ +- unsigned int ctrl_reg = __before_slc_op(cacheop); +- __slc_line_loop(paddr, sz, cacheop); +- __after_slc_op(cacheop, ctrl_reg); ++ /* ++ * Upper addresses (ARC_AUX_SLC_RGN_END1 and ARC_AUX_SLC_RGN_START1) ++ * are always == 0 as we don't use PAE40, so we only setup lower ones ++ * (ARC_AUX_SLC_RGN_END and ARC_AUX_SLC_RGN_START) ++ */ ++ write_aux_reg(ARC_AUX_SLC_RGN_END, end); ++ write_aux_reg(ARC_AUX_SLC_RGN_START, paddr); ++ ++ /* Make sure "busy" bit reports correct stataus, see STAR 9001165532 */ ++ read_aux_reg(ARC_AUX_SLC_CTRL); ++ ++ while (read_aux_reg(ARC_AUX_SLC_CTRL) & SLC_CTRL_BUSY); + } +-#else +-#define __slc_entire_op(cacheop) +-#define __slc_line_op(paddr, sz, cacheop) +-#endif ++#endif /* CONFIG_ISA_ARCV2 */ + + #ifdef CONFIG_ISA_ARCV2 + static void read_decode_cache_bcr_arcv2(void) +@@ -247,7 +251,10 @@ void cache_init(void) + write_aux_reg(ARC_AUX_IO_COH_ENABLE, 1); + + } +-#endif ++ ++ if (slc_exists) ++ slc_upper_region_init(); ++#endif /* CONFIG_ISA_ARCV2 */ + } + + int icache_status(void) +@@ -275,7 +282,6 @@ void icache_disable(void) + IC_CTRL_CACHE_DISABLE); + } + +-#ifndef CONFIG_SYS_DCACHE_OFF + void invalidate_icache_all(void) + { + /* Any write to IC_IVIC register triggers invalidation of entire I$ */ +@@ -283,12 +289,12 @@ void invalidate_icache_all(void) + write_aux_reg(ARC_AUX_IC_IVIC, 1); + read_aux_reg(ARC_AUX_IC_CTRL); /* blocks */ + } +-} +-#else +-void invalidate_icache_all(void) +-{ +-} ++ ++#ifdef CONFIG_ISA_ARCV2 ++ if (slc_exists) ++ __slc_entire_op(OP_INV); + #endif ++} + + int dcache_status(void) + { +@@ -415,6 +421,9 @@ static inline void __dc_line_op(unsigned long paddr, unsigned long sz, + + void invalidate_dcache_range(unsigned long start, unsigned long end) + { ++ if (start >= end) ++ return; ++ + #ifdef CONFIG_ISA_ARCV2 + if (!ioc_exists) + #endif +@@ -422,12 +431,15 @@ void invalidate_dcache_range(unsigned long start, unsigned long end) + + #ifdef CONFIG_ISA_ARCV2 + if (slc_exists && !ioc_exists) +- __slc_line_op(start, end - start, OP_INV); ++ __slc_rgn_op(start, end - start, OP_INV); + #endif + } + + void flush_dcache_range(unsigned long start, unsigned long end) + { ++ if (start >= end) ++ return; ++ + #ifdef CONFIG_ISA_ARCV2 + if (!ioc_exists) + #endif +@@ -435,7 +447,7 @@ void flush_dcache_range(unsigned long start, unsigned long end) + + #ifdef CONFIG_ISA_ARCV2 + if (slc_exists && !ioc_exists) +- __slc_line_op(start, end - start, OP_FLUSH); ++ __slc_rgn_op(start, end - start, OP_FLUSH); + #endif + } + +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0024-ARC-add-invalidation-of-I-and-D-to-relocation-helper.patch b/board/synopsys/hsdk/uboot-patches/0024-ARC-add-invalidation-of-I-and-D-to-relocation-helper.patch new file mode 100644 index 00000000000..323824b32e2 --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0024-ARC-add-invalidation-of-I-and-D-to-relocation-helper.patch @@ -0,0 +1,30 @@ +From 2b53220b292ef5b494996836dccf7cbcb3986909 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Tue, 19 Dec 2017 14:02:40 +0300 +Subject: [PATCH 24/46] ARC: add invalidation of I$ and D$ to relocation helper + +--- + arch/arc/lib/init_helpers.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/arch/arc/lib/init_helpers.c b/arch/arc/lib/init_helpers.c +index dbc8d68ffb..67cfeb1db9 100644 +--- a/arch/arc/lib/init_helpers.c ++++ b/arch/arc/lib/init_helpers.c +@@ -10,8 +10,11 @@ DECLARE_GLOBAL_DATA_PTR; + + int init_cache_f_r(void) + { +-#ifndef CONFIG_SYS_DCACHE_OFF + flush_dcache_all(); +-#endif ++ invalidate_dcache_all(); ++ ++ /* Actually needed only in case of disabled dcache */ ++ invalidate_icache_all(); ++ + return 0; + } +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0025-ARC-HSDK-hang-on-panic.patch b/board/synopsys/hsdk/uboot-patches/0025-ARC-HSDK-hang-on-panic.patch new file mode 100644 index 00000000000..77ea3de1dc0 --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0025-ARC-HSDK-hang-on-panic.patch @@ -0,0 +1,25 @@ +From 139f2a5d0a98aedf4ea9a5d50bd2bf08ba5dcac8 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Tue, 19 Dec 2017 14:05:32 +0300 +Subject: [PATCH 25/46] ARC: HSDK: hang on panic + +Hang instead of reset on panic as reset is not implemented +--- + include/configs/hsdk.h | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/include/configs/hsdk.h b/include/configs/hsdk.h +index b0323e0919..687610896c 100644 +--- a/include/configs/hsdk.h ++++ b/include/configs/hsdk.h +@@ -110,4 +110,7 @@ + #define CONFIG_BOARD_EARLY_INIT_R + #define CONFIG_BOARD_LATE_INIT + ++ ++#define CONFIG_PANIC_HANG ++ + #endif /* _CONFIG_HSDK_H_ */ +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0026-ARC-CACHE-fix-slc_entire_op-flush-only-instead-of-fl.patch b/board/synopsys/hsdk/uboot-patches/0026-ARC-CACHE-fix-slc_entire_op-flush-only-instead-of-fl.patch new file mode 100644 index 00000000000..0d7336ab0ce --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0026-ARC-CACHE-fix-slc_entire_op-flush-only-instead-of-fl.patch @@ -0,0 +1,52 @@ +From 3c31cb3bed5557beb4db1762cfff021320729568 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Wed, 20 Dec 2017 20:11:07 +0300 +Subject: [PATCH 26/46] ARC: CACHE: fix slc_entire_op: flush only instead of + flush-n-inv + +Signed-off-by: Eugeniy Paltsev +--- + arch/arc/lib/cache.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +diff --git a/arch/arc/lib/cache.c b/arch/arc/lib/cache.c +index 2764ef3f54..05275e2bd8 100644 +--- a/arch/arc/lib/cache.c ++++ b/arch/arc/lib/cache.c +@@ -53,24 +53,27 @@ bool ioc_enable __section(".data") = false; + + noinline static void __slc_entire_op(const int op) + { +- unsigned int ctrl, r = ARC_AUX_SLC_CTRL; ++ unsigned int ctrl; + +- ctrl = read_aux_reg(r); ++ ctrl = read_aux_reg(ARC_AUX_SLC_CTRL); + + if (!(op & OP_FLUSH)) /* i.e. OP_INV */ + ctrl &= ~SLC_CTRL_IM; /* clear IM: Disable flush before Inv */ + else + ctrl |= SLC_CTRL_IM; + +- write_aux_reg(r, ctrl); ++ write_aux_reg(ARC_AUX_SLC_CTRL, ctrl); + +- write_aux_reg(ARC_AUX_SLC_INVALIDATE, 1); ++ if (op & OP_INV) /* Inv or flush-n-inv use same cmd reg */ ++ write_aux_reg(ARC_AUX_SLC_INVALIDATE, 0x1); ++ else ++ write_aux_reg(ARC_AUX_SLC_FLUSH, 0x1); + + /* Make sure "busy" bit reports correct stataus, see STAR 9001165532 */ +- read_aux_reg(r); ++ read_aux_reg(ARC_AUX_SLC_CTRL); + + /* Important to wait for flush to complete */ +- while (read_aux_reg(r) & SLC_CTRL_BUSY); ++ while (read_aux_reg(ARC_AUX_SLC_CTRL) & SLC_CTRL_BUSY); + } + + static void slc_upper_region_init(void) +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0027-ARC-HSDK-CLK-use-special-set-algo-for-TUN-CPU-AXI-cl.patch b/board/synopsys/hsdk/uboot-patches/0027-ARC-HSDK-CLK-use-special-set-algo-for-TUN-CPU-AXI-cl.patch new file mode 100644 index 00000000000..a3b55eca091 --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0027-ARC-HSDK-CLK-use-special-set-algo-for-TUN-CPU-AXI-cl.patch @@ -0,0 +1,191 @@ +From 8b613fc71f273e61ece1a752aaad01878749720f Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Fri, 22 Dec 2017 13:39:54 +0300 +Subject: [PATCH 27/46] ARC: HSDK: CLK: use special set algo for TUN, CPU, AXI + clocks + +use special set algo for TUN, CPU, AXI clocks +add support for ROM and PWM clocks + +Signed-off-by: Eugeniy Paltsev +--- + drivers/clk/clk-hsdk-cgu.c | 119 +++++++++++++++++++++++++++++++++------------ + 1 file changed, 87 insertions(+), 32 deletions(-) + +diff --git a/drivers/clk/clk-hsdk-cgu.c b/drivers/clk/clk-hsdk-cgu.c +index 047bc14681..61926656d9 100644 +--- a/drivers/clk/clk-hsdk-cgu.c ++++ b/drivers/clk/clk-hsdk-cgu.c +@@ -44,7 +44,9 @@ + * |-->| TUNNEL PLL | + * | -------------- + * | | +- * | |-->|CGU_TUN_IDIV|-----------> ++ * | |-->|CGU_TUN_IDIV_TUN|-----------> ++ * | |-->|CGU_TUN_IDIV_ROM|-----------> ++ * | |-->|CGU_TUN_IDIV_PWM|-----------> + * | + * | ------------ + * |-->| HDMI PLL | +@@ -62,7 +64,9 @@ + DECLARE_GLOBAL_DATA_PTR; + + #define CGU_ARC_IDIV 0x080 +-#define CGU_TUN_IDIV 0x380 ++#define CGU_TUN_IDIV_TUN 0x380 ++#define CGU_TUN_IDIV_ROM 0x390 ++#define CGU_TUN_IDIV_PWM 0x3A0 + #define CGU_HDMI_IDIV_APB 0x480 + #define CGU_SYS_IDIV_APB 0x180 + #define CGU_SYS_IDIV_AXI 0x190 +@@ -118,41 +122,64 @@ DECLARE_GLOBAL_DATA_PTR; + + #define MIN_PLL_RATE 100000000 /* 100 MHz */ + #define PARENT_RATE 33333333 /* fixed clock - xtal */ +-#define CGU_MAX_CLOCKS 24 ++#define CGU_MAX_CLOCKS 26 + + #define CGU_SYS_CLOCKS 16 + #define MAX_AXI_CLOCKS 4 + +-struct hsdk_idiv_cfg { ++#define CGU_TUN_CLOCKS 3 ++#define MAX_TUN_CLOCKS 6 ++ ++struct hsdk_tun_idiv_cfg { ++ u32 oft; ++ u8 val[MAX_TUN_CLOCKS]; ++}; ++ ++struct hsdk_tun_clk_cfg { ++ const u32 clk_rate[MAX_TUN_CLOCKS]; ++ const u32 pll_rate[MAX_TUN_CLOCKS]; ++ const struct hsdk_tun_idiv_cfg idiv[CGU_TUN_CLOCKS]; ++}; ++ ++static const struct hsdk_tun_clk_cfg tun_clk_cfg = { ++ { 25000000, 50000000, 75000000, 100000000, 125000000, 150000000 }, ++ { 600000000, 600000000, 600000000, 600000000, 700000000, 600000000 }, { ++ { CGU_TUN_IDIV_TUN, { 24, 12, 8, 6, 6, 4 } }, ++ { CGU_TUN_IDIV_ROM, { 4, 4, 4, 4, 5, 4 } }, ++ { CGU_TUN_IDIV_PWM, { 8, 8, 8, 8, 10, 8 } } ++ } ++}; ++ ++struct hsdk_sys_idiv_cfg { + u32 oft; + u8 val[MAX_AXI_CLOCKS]; + }; + +-struct hsdk_clk_cfg { ++struct hsdk_axi_clk_cfg { + const u32 clk_rate[MAX_AXI_CLOCKS]; + const u32 pll_rate[MAX_AXI_CLOCKS]; +- const struct hsdk_idiv_cfg idiv[CGU_SYS_CLOCKS]; ++ const struct hsdk_sys_idiv_cfg idiv[CGU_SYS_CLOCKS]; + }; + +-static const struct hsdk_clk_cfg axi_clk_cfg = { ++static const struct hsdk_axi_clk_cfg axi_clk_cfg = { + { 200000000, 400000000, 600000000, 800000000 }, +- { 400000000, 400000000, 600000000, 800000000 }, { +- { CGU_SYS_IDIV_APB, { 2, 2, 3, 4 } }, /* APB */ +- { CGU_SYS_IDIV_AXI, { 2, 1, 1, 1 } }, /* AXI */ +- { CGU_SYS_IDIV_ETH, { 1, 1, 2, 2 } }, /* ETH */ +- { CGU_SYS_IDIV_USB, { 1, 1, 2, 2 } }, /* USB */ +- { CGU_SYS_IDIV_SDIO, { 1, 1, 2, 2 } }, /* SDIO */ +- { CGU_SYS_IDIV_HDMI, { 1, 1, 2, 2 } }, /* HDMI */ +- { CGU_SYS_IDIV_GFX_CORE, { 1, 1, 2, 2 } }, /* GPU-CORE */ +- { CGU_SYS_IDIV_GFX_DMA, { 1, 1, 2, 2 } }, /* GPU-DMA */ +- { CGU_SYS_IDIV_GFX_CFG, { 2, 2, 3, 4 } }, /* GPU-CFG */ +- { CGU_SYS_IDIV_DMAC_CORE,{ 1, 1, 2, 2 } }, /* DMAC-CORE */ +- { CGU_SYS_IDIV_DMAC_CFG, { 2, 2, 3, 4 } }, /* DMAC-CFG */ +- { CGU_SYS_IDIV_SDIO_REF, { 4, 4, 6, 8 } }, /* SDIO-REF */ +- { CGU_SYS_IDIV_SPI_REF, { 12, 12, 18, 24 } }, /* SPI-REF */ +- { CGU_SYS_IDIV_I2C_REF, { 2, 2, 3, 4 } }, /* I2C-REF */ +- { CGU_SYS_IDIV_UART_REF, { 12, 12, 18, 24 } }, /* UART-REF */ +- { CGU_SYS_IDIV_EBI_REF, { 8, 8, 12, 16 } } /* EBI-REF */ ++ { 800000000, 800000000, 600000000, 800000000 }, { ++ { CGU_SYS_IDIV_APB, { 4, 4, 3, 4 } }, /* APB */ ++ { CGU_SYS_IDIV_AXI, { 4, 2, 1, 1 } }, /* AXI */ ++ { CGU_SYS_IDIV_ETH, { 2, 2, 2, 2 } }, /* ETH */ ++ { CGU_SYS_IDIV_USB, { 2, 2, 2, 2 } }, /* USB */ ++ { CGU_SYS_IDIV_SDIO, { 2, 2, 2, 2 } }, /* SDIO */ ++ { CGU_SYS_IDIV_HDMI, { 2, 2, 2, 2 } }, /* HDMI */ ++ { CGU_SYS_IDIV_GFX_CORE, { 1, 1, 1, 1 } }, /* GPU-CORE */ ++ { CGU_SYS_IDIV_GFX_DMA, { 2, 2, 2, 2 } }, /* GPU-DMA */ ++ { CGU_SYS_IDIV_GFX_CFG, { 4, 4, 3, 4 } }, /* GPU-CFG */ ++ { CGU_SYS_IDIV_DMAC_CORE,{ 2, 2, 2, 2 } }, /* DMAC-CORE */ ++ { CGU_SYS_IDIV_DMAC_CFG, { 4, 4, 3, 4 } }, /* DMAC-CFG */ ++ { CGU_SYS_IDIV_SDIO_REF, { 8, 8, 6, 8 } }, /* SDIO-REF */ ++ { CGU_SYS_IDIV_SPI_REF, { 24, 24, 18, 24 } }, /* SPI-REF */ ++ { CGU_SYS_IDIV_I2C_REF, { 4, 4, 3, 4 } }, /* I2C-REF */ ++ { CGU_SYS_IDIV_UART_REF, { 24, 24, 18, 24 } }, /* UART-REF */ ++ { CGU_SYS_IDIV_EBI_REF, { 16, 16, 12, 16 } } /* EBI-REF */ + } + }; + +@@ -280,9 +307,13 @@ static const struct hsdk_cgu_clock_map clock_map[] = { + { CGU_SYS_PLL, 0, CGU_SYS_IDIV_UART_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off }, + { CGU_SYS_PLL, 0, CGU_SYS_IDIV_EBI_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off }, + { CGU_TUN_PLL, 0, 0, &sdt_pll_dat, pll_get, pll_set, NULL }, +- { CGU_TUN_PLL, 0, CGU_TUN_IDIV, &sdt_pll_dat, idiv_get, tun_clk_set, idiv_off }, /* special behavior */ ++ { CGU_TUN_PLL, 0, CGU_TUN_IDIV_TUN, &sdt_pll_dat, idiv_get, tun_clk_set, idiv_off }, /* special behavior */ + { CGU_HDMI_PLL, 0, 0, &hdmi_pll_dat, pll_get, pll_set, NULL }, +- { CGU_HDMI_PLL, 0, CGU_HDMI_IDIV_APB, &hdmi_pll_dat, idiv_get, idiv_set, idiv_off } ++ { CGU_HDMI_PLL, 0, CGU_HDMI_IDIV_APB, &hdmi_pll_dat, idiv_get, idiv_set, idiv_off }, ++ ++ /* TODO: move in right place */ ++ { CGU_TUN_PLL, 0, CGU_TUN_IDIV_ROM, &sdt_pll_dat, idiv_get, idiv_set, idiv_off }, ++ { CGU_TUN_PLL, 0, CGU_TUN_IDIV_PWM, &sdt_pll_dat, idiv_get, idiv_set, idiv_off } + }; + + static inline void hsdk_idiv_write(struct hsdk_cgu_clk *clk, u32 val) +@@ -547,14 +578,38 @@ static ulong axi_clk_set(struct clk *sclk, ulong rate) + + static ulong tun_clk_set(struct clk *sclk, ulong rate) + { +- ulong ret; ++ struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev); ++ ulong pll_rate; ++ int i, freq_idx = -1; ++ ulong ret = 0; ++ ++ pll_rate = pll_get(sclk); + +- if (rate >= MIN_PLL_RATE) +- ret = pll_set(sclk, rate); +- else +- ret = pll_set(sclk, 150000000); ++ for (i = 0; i < MAX_TUN_CLOCKS; i++) { ++ if (tun_clk_cfg.clk_rate[i] == rate) { ++ freq_idx = i; ++ break; ++ } ++ } + +- idiv_set(sclk, rate); ++ if (freq_idx < 0) { ++ pr_err("tun clk: invalid rate=%ld Hz\n", rate); ++ return -EINVAL; ++ } ++ ++ /* configure PLL before dividers */ ++ if (tun_clk_cfg.pll_rate[freq_idx] < pll_rate) ++ ret = pll_set(sclk, tun_clk_cfg.pll_rate[freq_idx]); ++ ++ /* configure SYS dividers */ ++ for (i = 0; i < CGU_TUN_CLOCKS; i++) { ++ clk->idiv_regs = clk->cgu_regs + tun_clk_cfg.idiv[i].oft; ++ hsdk_idiv_write(clk, tun_clk_cfg.idiv[i].val[freq_idx]); ++ } ++ ++ /* configure PLL after dividers */ ++ if (tun_clk_cfg.pll_rate[freq_idx] >= pll_rate) ++ ret = pll_set(sclk, tun_clk_cfg.pll_rate[freq_idx]); + + return ret; + } +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0028-ARC-HSDK-DTS-add-ROM-and-PWM-clocks.patch b/board/synopsys/hsdk/uboot-patches/0028-ARC-HSDK-DTS-add-ROM-and-PWM-clocks.patch new file mode 100644 index 00000000000..501087f0e2a --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0028-ARC-HSDK-DTS-add-ROM-and-PWM-clocks.patch @@ -0,0 +1,35 @@ +From 38a1234b3718837ec63cce8a4f2d057779407dd3 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Fri, 22 Dec 2017 13:43:41 +0300 +Subject: [PATCH 28/46] ARC: HSDK: DTS: add ROM and PWM clocks + +Signed-off-by: Eugeniy Paltsev +--- + arch/arc/dts/hsdk.dts | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/arch/arc/dts/hsdk.dts b/arch/arc/dts/hsdk.dts +index 0527e1341b..aaaf2a2a3d 100644 +--- a/arch/arc/dts/hsdk.dts ++++ b/arch/arc/dts/hsdk.dts +@@ -30,13 +30,15 @@ + <&cgu_clk 4>, <&cgu_clk 5>, <&cgu_clk 6>, <&cgu_clk 7>, + <&cgu_clk 8>, <&cgu_clk 9>, <&cgu_clk 10>, <&cgu_clk 11>, + <&cgu_clk 12>, <&cgu_clk 13>, <&cgu_clk 14>, <&cgu_clk 15>, +- <&cgu_clk 16>, <&cgu_clk 17>, <&cgu_clk 18>, <&cgu_clk 19>; ++ <&cgu_clk 16>, <&cgu_clk 17>, <&cgu_clk 18>, <&cgu_clk 19>, ++ <&cgu_clk 24>, <&cgu_clk 25>; + clock-names = "cpu-pll", "sys-pll", "tun-pll", "ddr-clk", + "cpu-clk", "hdmi-pll", "tun-clk", "hdmi-clk", + "sys-apb", "sys-axi", "sys-eth", "sys-usb", + "sys-sdio", "sys-hdmi", "sys-gfx-core", "sys-gfx-dma", + "sys-gfx-cfg", "sys-dmac-core", "sys-dmac-cfg", "sys-sdio-ref", +- "sys-spi", "sys-i2c", "sys-uart", "sys-ebi"; ++ "sys-spi", "sys-i2c", "sys-uart", "sys-ebi", ++ "rom-clk", "pwm-clk"; + }; + + cgu_clk: cgu-clk@f0000000 { +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0029-ARC-HSDK-DTS-get-rid-of-old-clock-driver-nodes.patch b/board/synopsys/hsdk/uboot-patches/0029-ARC-HSDK-DTS-get-rid-of-old-clock-driver-nodes.patch new file mode 100644 index 00000000000..560be8754e4 --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0029-ARC-HSDK-DTS-get-rid-of-old-clock-driver-nodes.patch @@ -0,0 +1,48 @@ +From 5ffca48a885be16fa72020fd08e01c97187d8aa0 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Fri, 22 Dec 2017 13:45:37 +0300 +Subject: [PATCH 29/46] ARC: HSDK: DTS: get rid of old clock driver nodes + +Signed-off-by: Eugeniy Paltsev +--- + arch/arc/dts/hsdk.dts | 24 ------------------------ + 1 file changed, 24 deletions(-) + +diff --git a/arch/arc/dts/hsdk.dts b/arch/arc/dts/hsdk.dts +index aaaf2a2a3d..678a238071 100644 +--- a/arch/arc/dts/hsdk.dts ++++ b/arch/arc/dts/hsdk.dts +@@ -47,30 +47,6 @@ + #clock-cells = <1>; + }; + +- cpu_clk: cpu-clk@f0000000 { +- compatible = "snps,hsdk-core-pll-clock"; +- reg = <0xf0000000 0x10>, <0xf00014B8 0x4>; +- #clock-cells = <0>; +- }; +- +- sys_clk: sys-clk@f0000010 { +- compatible = "snps,hsdk-gp-pll-clock"; +- reg = <0xf0000010 0x10>; +- #clock-cells = <0>; +- }; +- +- ddr_clk: ddr-clk@f0000020 { +- compatible = "snps,hsdk-gp-pll-clock"; +- reg = <0xf0000020 0x10>; +- #clock-cells = <0>; +- }; +- +- tun_clk: tun-clk@f0000030 { +- compatible = "snps,hsdk-gp-pll-clock"; +- reg = <0xf0000030 0x10>; +- #clock-cells = <0>; +- }; +- + uart0: serial0@f0005000 { + compatible = "snps,dw-apb-uart"; + reg = <0xf0005000 0x1000>; +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0030-ARC-HSDK-CONFIG-add-options-to-store-environment-in-.patch b/board/synopsys/hsdk/uboot-patches/0030-ARC-HSDK-CONFIG-add-options-to-store-environment-in-.patch new file mode 100644 index 00000000000..59c63be9cdb --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0030-ARC-HSDK-CONFIG-add-options-to-store-environment-in-.patch @@ -0,0 +1,31 @@ +From 04972fb4ebc98f2b287a246e7a30d3f96ac0b646 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Fri, 22 Dec 2017 13:46:58 +0300 +Subject: [PATCH 30/46] ARC: HSDK: CONFIG: add options to store environment in + SPI flash + +NOTE: It is optional and is disabled by default. + +Signed-off-by: Eugeniy Paltsev +--- + include/configs/hsdk.h | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/include/configs/hsdk.h b/include/configs/hsdk.h +index 687610896c..cdc1b2e365 100644 +--- a/include/configs/hsdk.h ++++ b/include/configs/hsdk.h +@@ -60,6 +60,10 @@ + * 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" \ +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0031-ARC-CACHE-export-L1-entry-operations.patch b/board/synopsys/hsdk/uboot-patches/0031-ARC-CACHE-export-L1-entry-operations.patch new file mode 100644 index 00000000000..51e71583298 --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0031-ARC-CACHE-export-L1-entry-operations.patch @@ -0,0 +1,61 @@ +From 8c6fae617f8ca6523618e1eb557aac1f21f69787 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Fri, 22 Dec 2017 13:50:01 +0300 +Subject: [PATCH 31/46] ARC: CACHE: export L1 entry operations + +NOTE: it should be rewrited + +Signed-off-by: Eugeniy Paltsev +--- + arch/arc/lib/cache.c | 28 ++++++++++++++++++++++++---- + 1 file changed, 24 insertions(+), 4 deletions(-) + +diff --git a/arch/arc/lib/cache.c b/arch/arc/lib/cache.c +index 05275e2bd8..83ffec728a 100644 +--- a/arch/arc/lib/cache.c ++++ b/arch/arc/lib/cache.c +@@ -285,13 +285,18 @@ void icache_disable(void) + IC_CTRL_CACHE_DISABLE); + } + ++/* IC supports only invalidation */ ++static inline void __ic_entire_op(void) ++{ ++ write_aux_reg(ARC_AUX_IC_IVIC, 1); ++ read_aux_reg(ARC_AUX_IC_CTRL); /* blocks */ ++} ++ + void invalidate_icache_all(void) + { + /* Any write to IC_IVIC register triggers invalidation of entire I$ */ +- if (icache_status()) { +- write_aux_reg(ARC_AUX_IC_IVIC, 1); +- read_aux_reg(ARC_AUX_IC_CTRL); /* blocks */ +- } ++ if (icache_status()) ++ __ic_entire_op(); + + #ifdef CONFIG_ISA_ARCV2 + if (slc_exists) +@@ -478,3 +483,18 @@ void flush_dcache_all(void) + __slc_entire_op(OP_FLUSH); + #endif + } ++ ++void __l1_dc_flush_all(void) ++{ ++ __dc_entire_op(OP_FLUSH); ++} ++ ++void __l1_dc_invalidate_all(void) ++{ ++ __dc_entire_op(OP_INV); ++} ++ ++void __l1_ic_invalidate_all(void) ++{ ++ __ic_entire_op(); ++} +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0032-ARC-HSDK-hsdk_go-v0.8-version.patch b/board/synopsys/hsdk/uboot-patches/0032-ARC-HSDK-hsdk_go-v0.8-version.patch new file mode 100644 index 00000000000..ccd3f98815a --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0032-ARC-HSDK-hsdk_go-v0.8-version.patch @@ -0,0 +1,568 @@ +From 600f74e0a9f3978ee85b47b72edd810c6df980bb Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Fri, 22 Dec 2017 13:53:31 +0300 +Subject: [PATCH 32/46] ARC: HSDK: hsdk_go: v0.8 version + +The new u-boot with significant changes is ready. + * Fix u-boot work with IOC disabled. There were several problems like + broken implementation SLC region/line operations. Now we use u-boot + without IOC by default. + * 'hsdk_go' is now split to 'hsdk_go' and 'hsdk_init', so now there are several + boot flows: + 1) hsdk_init -> hsdk_go + 2) hsdk_init -> bootm + 3) bootm + * 'hsdk_clock print_all' subcommand is implemented. + * hsdk_clock print' output re-arranged. + * Sys-hdmi, Sys-ebi, Hdmi-clk, Hdmi-pll clocks are removed from + 'hsdk_clock print' output. + * Fix SYS clock domain settings to set GFX_CORE clock to 800MHz (instead of 400MHz) + * ROM and PWM clocks were added to 'hsdk_clock print' output. + * Now we setup both TUN, ROM and PWM dividers when we change TUN frequency. + +Signed-off-by: Eugeniy Paltsev +--- + board/synopsys/hsdk/hsdk-cmd.c | 249 ++++++++++++++++++++++++++++++++--------- + 1 file changed, 195 insertions(+), 54 deletions(-) + +diff --git a/board/synopsys/hsdk/hsdk-cmd.c b/board/synopsys/hsdk/hsdk-cmd.c +index 1fad17adf9..b706901d6c 100644 +--- a/board/synopsys/hsdk/hsdk-cmd.c ++++ b/board/synopsys/hsdk/hsdk-cmd.c +@@ -14,7 +14,7 @@ + #error "hsdk_go will not work with BIG endian CPU" + #endif + +-#define HSDKGO_VERSION "0.7" ++#define HSDKGO_VERSION "0.8" + + #define ceil(x, y) ({ ulong __x = (x), __y = (y); (__x + __y - 1) / __y; }) + +@@ -34,6 +34,7 @@ enum clk_ctl { + CLK_PRINT = BIT(4) /* print frequency */ + }; + ++/* TODO: use local */ + void smp_set_core_boot_addr(unsigned long addr, int corenr); + + enum env_type { +@@ -164,17 +165,21 @@ static const struct hsdk_env_map_common env_map_clock[] = { + }; + + static const struct hsdk_env_map_core env_map_core[] = { +- { "core_entry", ENV_HEX, true, {0, 0, 0, 0}, {U32_MAX, U32_MAX, U32_MAX, U32_MAX}, &env_core.entry }, + { "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 hsdk_env_map_common env_map_bootm[] = { ++static const struct hsdk_env_map_common env_map_mask[] = { + { "core_mask", ENV_HEX, false, 0x1, 0xF, &env_common.core_mask }, + {} + }; + ++static const struct hsdk_env_map_core 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 env_clear_common(u32 index, const struct hsdk_env_map_common *map) + { + map[index].val->val = 0; +@@ -201,16 +206,26 @@ static int env_read_common(u32 index, const struct hsdk_env_map_common *map) + return 0; + } + ++static int env_clear_core(u32 index, const struct hsdk_env_map_core *map) ++{ ++ u32 i; ++ ++ for (i = 0; i < NR_CPUS; i++) { ++ (*map[index].val)[i].val = 0; ++ (*map[index].val)[i].set = false; ++ } ++} ++ + /* process core specific variables */ +-static int env_read_core(u32 index) ++static int env_read_core(u32 index, const struct hsdk_env_map_core *map) + { + u32 i, val; + char comand[MAX_CMD_LEN]; + + for (i = 0; i < NR_CPUS; i++) { +- sprintf(comand, "%s_%u", env_map_core[index].env_name, i); ++ sprintf(comand, "%s_%u", map[index].env_name, i); + if (!env_get_yesno(comand)) { +- if (env_map_core[index].type == ENV_HEX) { ++ if (map[index].type == ENV_HEX) { + val = (u32)env_get_hex(comand, 0); + debug("ENV: %s: = %#x\n", comand, val); + } else { +@@ -218,8 +233,8 @@ static int env_read_core(u32 index) + debug("ENV: %s: = %d\n", comand, val); + } + +- (*env_map_core[index].val)[i].val = val; +- (*env_map_core[index].val)[i].set = true; ++ (*map[index].val)[i].val = val; ++ (*map[index].val)[i].set = true; + } + } + +@@ -253,33 +268,33 @@ static int env_validate_common(u32 index, const struct hsdk_env_map_common *map) + return 0; + } + +-static int env_validate_core(u32 index) ++static int env_validate_core(u32 index, const struct hsdk_env_map_core *map) + { + u32 i; + u32 value; + bool set; +- bool mandatory = env_map_core[index].mandatory; ++ bool mandatory = map[index].mandatory; + u32 min, max; + + for (i = 0; i < NR_CPUS; i++) { +- set = (*env_map_core[index].val)[i].set; +- value = (*env_map_core[index].val)[i].val; ++ set = (*map[index].val)[i].set; ++ value = (*map[index].val)[i].val; + + /* Check if environment is mandatory */ +- if (is_cpu_used(i) && !(mandatory && set)) { ++ if (is_cpu_used(i) && mandatory && !set) { + pr_err("CPU %u is used, but \'%s_%u\' is not defined\n", +- i, env_map_core[index].env_name, i); ++ i, map[index].env_name, i); + + return -EINVAL; + } + +- min = env_map_core[index].min[i]; +- max = env_map_core[index].max[i]; ++ min = map[index].min[i]; ++ max = map[index].max[i]; + + /* Check environment boundary */ + if (set && (value < min || value > max)) { + pr_err("Variable \'%s_%u\' must be between %#x and %#x\n", +- env_map_core[index].env_name, i, min, max); ++ map[index].env_name, i, min, max); + + return -EINVAL; + } +@@ -351,19 +366,24 @@ static int env_read_validate_common(const struct hsdk_env_map_common *map) + return 0; + } + +-static int env_read_validate_core(void) ++static int env_read_validate_core(const struct hsdk_env_map_core *map) + { + u32 i; + int ret; + ++ /* Cleanup env struct first */ ++ for (i = 0; env_map_core[i].env_name; i++) { ++ env_clear_core(i, map); ++ } ++ + for (i = 0; env_map_core[i].env_name; i++) { +- ret = env_read_core(i); ++ ret = env_read_core(i, map); + if (ret) + return ret; + } + + for (i = 0; env_map_core[i].env_name; i++) { +- ret = env_validate_core(i); ++ ret = env_validate_core(i, map); + if (ret) + return ret; + } +@@ -371,15 +391,16 @@ static int env_read_validate_core(void) + return 0; + } + +-static int env_process_and_validate(void) ++static int env_process_and_validate(const struct hsdk_env_map_common *common, ++ const struct hsdk_env_map_core *core) + { + int ret; + +- ret = env_read_validate_common(env_map_common); ++ ret = env_read_validate_common(common); + if (ret) + return ret; + +- ret = env_read_validate_core(); ++ ret = env_read_validate_core(core); + if (ret) + return ret; + +@@ -393,8 +414,43 @@ static int env_process_and_validate(void) + /* Bit values in DC_CTRL */ + #define DC_CTRL_CACHE_DISABLE (1 << 0) + #define DC_CTRL_INV_MODE_FLUSH (1 << 6) ++#define DC_CTRL_FLUSH_STATUS (1 << 8) + #define APT_SHIFT 28 + ++/* ********************* LOCAL CACHE: START ********************* */ ++static void smp_local_invalidate_icache_l1_all(void) ++{ ++ write_aux_reg(ARC_AUX_IC_IVIC, 1); ++ read_aux_reg(ARC_AUX_IC_CTRL); /* blocks */ ++} ++ ++static void smp_local_invalidate_dcache_l1_all(void) ++{ ++ unsigned int reg; ++ ++ /* ++ * IM is set by default and implies Flush-n-inv ++ * Clear it here for vanilla inv ++ */ ++ reg = read_aux_reg(ARC_AUX_DC_CTRL); ++ write_aux_reg(ARC_AUX_DC_CTRL, reg & ~DC_CTRL_INV_MODE_FLUSH); ++ ++ write_aux_reg(ARC_AUX_DC_IVDC, 0x1); ++ ++ /* Switch back to default Invalidate mode */ ++ write_aux_reg(ARC_AUX_DC_CTRL, reg | DC_CTRL_INV_MODE_FLUSH); ++} ++ ++static void smp_local_flush_dcache_l1_all(void) ++{ ++ write_aux_reg(ARC_AUX_DC_FLSH, 0x1); ++ ++ /* flush / flush-n-inv both wait */ ++ while (read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_FLUSH_STATUS); ++} ++ ++/* ********************* LOCAL CACHE: END ********************* */ ++ + // TODO: add xCCM runtime check + static void smp_init_slave_cpu_func(u32 core) + { +@@ -425,19 +481,22 @@ static void smp_init_slave_cpu_func(u32 core) + } + } + +-static void init_master_nvlim(void) ++static void init_claster_nvlim(void) + { + u32 val = env_common.nvlim.val << APT_SHIFT; + + flush_dcache_all(); + write_aux_reg(ARC_AUX_NON_VOLATILE_LIMIT, val); + write_aux_reg(AUX_AUX_CACHE_LIMIT, val); ++ invalidate_dcache_all(); + } + + // TODO: !! add my own implementation of flush_dcache_all, invalidate_icache_all + // as current implementations depends on CONFIG_SYS_DCACHE_OFF and + // CONFIG_SYS_ICACHE_OFF + ++/* TODO: use generic status functions */ ++ + static void init_master_icache(void) + { + unsigned int r; +@@ -576,6 +635,13 @@ __attribute__((naked, noreturn, flatten)) noinline void hsdk_core_init_f(void) + __builtin_arc_nop(); + __builtin_arc_nop(); + ++ /* get the updated entry - invalidate L1i$ */ ++ __l1_ic_invalidate_all(); ++ __l1_dc_invalidate_all(); ++ ++// smp_local_invalidate_icache_l1_all(); ++// smp_local_invalidate_dcache_l1_all(); ++ + /* Run our program */ + ((void (*)(void))(env_core.entry[CPU_ID_GET()].val))(); + +@@ -584,9 +650,9 @@ __attribute__((naked, noreturn, flatten)) noinline void hsdk_core_init_f(void) + halt_this_cpu(); + } + +-static void do_init_slave_cpu(u32 cpu_id) ++noinline static void do_init_slave_cpu(u32 cpu_id) + { +- u32 timeout = 50000; ++ u32 timeout = 5000; + + data_flag = 0; + +@@ -599,21 +665,32 @@ static void do_init_slave_cpu(u32 cpu_id) + debug("CPU %u: stack pool base: %p\n", cpu_id, slave_stack); + smp_set_core_boot_addr((unsigned long)hsdk_core_init_f, -1); + +- /* Make sure other cores see written value in memory */ ++ /* ++ * Slave CPUs may start with disabled caches, so ++ * make sure other cores see written value in memory - flush L1, L2 ++ */ + flush_dcache_all(); + + smp_kick_cpu_x(cpu_id); + +- debug("CPU %u: FLAG0: %x\n", cpu_id, data_flag); +- while (!data_flag && timeout) ++ debug("CPU %u: FLAG0: %x [before timeout]\n", cpu_id, data_flag); ++ ++ /* TODO: add dcache invalidation here */ ++ while (!data_flag && timeout) { + timeout--; ++ mdelay(10); ++ /* we need L1d$ invalidation here, if we use slave CPUs with ++ * disabled L1d$, as we configure master CPU caches later. ++ * (master CPU L1d$ is possibly enabled here) */ ++ __l1_dc_invalidate_all(0x1); ++ } + + /* 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); + +- debug("CPU %u: FLAG1: %x\n", cpu_id, data_flag); ++ debug("CPU %u: FLAG1: %x [after timeout]\n", cpu_id, data_flag); + } + + static void do_init_slave_cpus(void) +@@ -782,7 +859,7 @@ 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_master_nvlim(); ++ init_claster_nvlim(); + + init_memory_bridge(); + } +@@ -799,7 +876,7 @@ static int check_master_cpu_id(void) + return -ENOENT; + } + +-static int prepare_cpus(u32 *cpu_start_reg) ++static int prepare_cpus(void) + { + u32 i; + int ret; +@@ -808,7 +885,7 @@ static int prepare_cpus(u32 *cpu_start_reg) + if (ret) + return ret; + +- ret = env_process_and_validate(); ++ ret = env_process_and_validate(env_map_common, env_map_core); + if (ret) + return ret; + +@@ -820,13 +897,10 @@ static int prepare_cpus(u32 *cpu_start_reg) + + do_init_slave_cpus(); + +- do_init_claster(); +- +- /* Prepare CREG_CPU_START for kicking chosen CPUs */ +- *cpu_start_reg = prepare_cpu_ctart_reg(); +- + do_init_master_cpu(); + ++ do_init_claster(); ++ + return 0; + } + +@@ -864,7 +938,7 @@ int board_prep_linux(bootm_headers_t *images) + { + int ret; + +- ret = env_read_validate_common(env_map_bootm); ++ ret = env_read_validate_common(env_map_mask); + if (ret) + return ret; + +@@ -882,30 +956,39 @@ int board_prep_linux(bootm_headers_t *images) + 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; ++ u32 cpu_start_reg, i; + + 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 */ + smp_set_core_boot_addr(entry, -1); + ++ /* In case of run with hsdk_init */ ++ for (i = 0; i < NR_CPUS; i++) { ++ env_core.entry[i].val = entry; ++ env_core.entry[i].set = true; ++ } ++ ++ /* Entry goes to slave cpu icache so we need to flush master cpu dcache ++ * as there is no coherency between icache and dcache */ ++ flush_dcache_all(); ++ + /* Kick chosen slave CPUs */ + writel(cpu_start_reg, (void __iomem *)CREG_CPU_START); + +- if (env_common.core_mask.val & BIT(0)) ++ if (is_cpu_used(0)) + kernel_entry(zero, arch, params); + } + + static int hsdk_go_prepare_and_run(void) + { +- int ret; + u32 reg; + +- ret = prepare_cpus(®); +- if (ret) +- return ret; ++ /* Prepare CREG_CPU_START for kicking chosen CPUs */ ++ reg = prepare_cpu_ctart_reg(); + + if (env_common.halt_on_boot) + printf("CPU will halt before application start, start application with debugger.\n"); +@@ -930,6 +1013,14 @@ static int do_hsdk_go(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) + } + } + ++ ret = check_master_cpu_id(); ++ if (ret) ++ return ret; ++ ++ ret = env_process_and_validate(env_map_mask, env_map_go); ++ if (ret) ++ return ret; ++ + ret = hsdk_go_prepare_and_run(); + + return ret ? CMD_RET_FAILURE : CMD_RET_SUCCESS; +@@ -942,6 +1033,33 @@ U_BOOT_CMD( + "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; ++ ++ /* TODO: delete after release */ ++ printf("HSDK: hsdk_init version: %s\n", HSDKGO_VERSION); ++ ++ /* hsdk_init can be run only once */ ++ if (done) { ++ printf("HSDK HW is already initialized!\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 hsdk_read_args_search(const struct hsdk_env_map_common *map, int argc, char * const argv[]) + { + int i; +@@ -1050,6 +1168,7 @@ static int do_hsdk_clock_get(cmd_tbl_t *cmdtp, int flag, int argc, char * const + int ret = 0; + ulong rate; + ++ /* TODO: get rid of ret */ + ret = soc_clk_ctl("cpu-clk", &rate, CLK_GET); + if (ret) + return CMD_RET_FAILURE; +@@ -1087,13 +1206,24 @@ static int do_hsdk_clock_print(cmd_tbl_t *cmdtp, int flag, int argc, char * cons + soc_clk_ctl("sys-axi", NULL, CLK_PRINT); + soc_clk_ctl("ddr-clk", NULL, CLK_PRINT); + +- /* Other sys clocks */ ++ 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); ++ soc_clk_ctl("cpu-clk", NULL, CLK_PRINT); ++ printf("\n"); ++ ++ /* SYS clock domain */ ++ soc_clk_ctl("sys-pll", NULL, CLK_PRINT); + soc_clk_ctl("sys-apb", NULL, CLK_PRINT); +-// soc_clk_ctl("sys-axi", NULL, CLK_PRINT); ++ soc_clk_ctl("sys-axi", NULL, CLK_PRINT); + soc_clk_ctl("sys-eth", NULL, CLK_PRINT); + soc_clk_ctl("sys-usb", NULL, CLK_PRINT); + soc_clk_ctl("sys-sdio", NULL, CLK_PRINT); +- soc_clk_ctl("sys-hdmi", NULL, CLK_PRINT); ++/* soc_clk_ctl("sys-hdmi", NULL, CLK_PRINT); */ + soc_clk_ctl("sys-gfx-core", NULL, CLK_PRINT); + soc_clk_ctl("sys-gfx-dma", NULL, CLK_PRINT); + soc_clk_ctl("sys-gfx-cfg", NULL, CLK_PRINT); +@@ -1102,16 +1232,25 @@ static int do_hsdk_clock_print(cmd_tbl_t *cmdtp, int flag, int argc, char * cons + soc_clk_ctl("sys-sdio-ref", NULL, CLK_PRINT); + soc_clk_ctl("sys-spi", NULL, CLK_PRINT); + soc_clk_ctl("sys-i2c", NULL, CLK_PRINT); +- soc_clk_ctl("sys-ebi", NULL, CLK_PRINT); ++/* soc_clk_ctl("sys-ebi", NULL, CLK_PRINT); */ + soc_clk_ctl("sys-uart", NULL, CLK_PRINT); ++ printf("\n"); ++ ++ /* DDR clock domain */ ++ soc_clk_ctl("ddr-clk", NULL, CLK_PRINT); ++ printf("\n"); + +- /* Other hdmi clocks */ ++ /* HDMI clock domain */ ++/* soc_clk_ctl("hdmi-pll", NULL, CLK_PRINT); + soc_clk_ctl("hdmi-clk", NULL, CLK_PRINT); ++ printf("\n"); */ + +- /* Other pll clocks */ +- soc_clk_ctl("hdmi-pll", NULL, CLK_PRINT); ++ /* TUN clock domain */ + soc_clk_ctl("tun-pll", NULL, CLK_PRINT); +- soc_clk_ctl("sys-pll", NULL, CLK_PRINT); ++ soc_clk_ctl("tun-clk", NULL, CLK_PRINT); ++ soc_clk_ctl("rom-clk", NULL, CLK_PRINT); ++ soc_clk_ctl("pwm-clk", NULL, CLK_PRINT); ++ printf("\n"); + + return CMD_RET_SUCCESS; + } +@@ -1120,6 +1259,7 @@ 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[]) +@@ -1145,5 +1285,6 @@ U_BOOT_CMD( + "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 clock values to console\n" ++ "hsdk_clock print - Print main clock values to console\n" ++ "hsdk_clock print_all - Print all clock values to console\n" + ); +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0033-ARC-HSDK-CLOCK-finaly-switch-to-composite-CGU-driver.patch b/board/synopsys/hsdk/uboot-patches/0033-ARC-HSDK-CLOCK-finaly-switch-to-composite-CGU-driver.patch new file mode 100644 index 00000000000..0f6f5ba84f7 --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0033-ARC-HSDK-CLOCK-finaly-switch-to-composite-CGU-driver.patch @@ -0,0 +1,373 @@ +From ae92f689c8a9738657afb6ea4a6e42d876fbc528 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Fri, 22 Dec 2017 14:09:37 +0300 +Subject: [PATCH 33/46] ARC: HSDK: CLOCK: finaly switch to composite CGU driver + +Signed-off-by: Eugeniy Paltsev +--- + MAINTAINERS | 2 +- + drivers/clk/Makefile | 1 - + drivers/clk/hsdk-clk.c | 326 ------------------------------------------------- + 3 files changed, 1 insertion(+), 328 deletions(-) + delete mode 100644 drivers/clk/hsdk-clk.c + +diff --git a/MAINTAINERS b/MAINTAINERS +index a3f9694d24..077a40b447 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -63,7 +63,7 @@ ARC HSDK PLL CLK + M: Eugeniy Paltsev + S: Maintained + L: uboot-snps-arc@synopsys.com +-F: drivers/clk/hsdk-clk.c ++F: drivers/clk/clk-hsdk-cgu.c + + ARM + M: Albert Aribaud +diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile +index 6425efa3b6..84f34d0e3d 100644 +--- a/drivers/clk/Makefile ++++ b/drivers/clk/Makefile +@@ -20,7 +20,6 @@ obj-$(CONFIG_CLK_EXYNOS) += exynos/ + obj-$(CONFIG_CLK_AT91) += at91/ + obj-$(CONFIG_CLK_BCM6345) += clk_bcm6345.o + obj-$(CONFIG_CLK_BOSTON) += clk_boston.o +-obj-$(CONFIG_CLK_HSDK) += hsdk-clk.o + obj-$(CONFIG_CLK_HSDK) += clk-hsdk-cgu.o + obj-$(CONFIG_ARCH_ASPEED) += aspeed/ + obj-$(CONFIG_STM32F7) += clk_stm32f7.o +diff --git a/drivers/clk/hsdk-clk.c b/drivers/clk/hsdk-clk.c +deleted file mode 100644 +index 2323c6317b..0000000000 +--- a/drivers/clk/hsdk-clk.c ++++ /dev/null +@@ -1,326 +0,0 @@ +-/* +- * Synopsys HSDK SDP Generic PLL clock driver +- * +- * Copyright (C) 2017 Synopsys +- * Author: Eugeniy Paltsev +- * +- * This file is licensed under the terms of the GNU General Public +- * License version 2. This program is licensed "as is" without any +- * warranty of any kind, whether express or implied. +- */ +- +-#include +-#include +-#include +-#include +-#include +- +-#define CGU_PLL_CTRL 0x000 /* ARC PLL control register */ +-#define CGU_PLL_STATUS 0x004 /* ARC PLL status register */ +-#define CGU_PLL_FMEAS 0x008 /* ARC PLL frequency measurement register */ +-#define CGU_PLL_MON 0x00C /* ARC PLL monitor register */ +- +-#define CGU_PLL_CTRL_ODIV_SHIFT 2 +-#define CGU_PLL_CTRL_IDIV_SHIFT 4 +-#define CGU_PLL_CTRL_FBDIV_SHIFT 9 +-#define CGU_PLL_CTRL_BAND_SHIFT 20 +- +-#define CGU_PLL_CTRL_ODIV_MASK GENMASK(3, CGU_PLL_CTRL_ODIV_SHIFT) +-#define CGU_PLL_CTRL_IDIV_MASK GENMASK(8, CGU_PLL_CTRL_IDIV_SHIFT) +-#define CGU_PLL_CTRL_FBDIV_MASK GENMASK(15, CGU_PLL_CTRL_FBDIV_SHIFT) +- +-#define CGU_PLL_CTRL_PD BIT(0) +-#define CGU_PLL_CTRL_BYPASS BIT(1) +- +-#define CGU_PLL_STATUS_LOCK BIT(0) +-#define CGU_PLL_STATUS_ERR BIT(1) +- +-#define HSDK_PLL_MAX_LOCK_TIME 100 /* 100 us */ +- +-#define CREG_CORE_IF_DIV 0x000 /* ARC CORE interface divider */ +-#define CORE_IF_CLK_THRESHOLD_HZ 500000000 +-#define CREG_CORE_IF_CLK_DIV_1 0x0 +-#define CREG_CORE_IF_CLK_DIV_2 0x1 +- +-#define PARENT_RATE 33333333 /* fixed clock - xtal */ +- +-struct hsdk_pll_cfg { +- u32 rate; +- u32 idiv; +- u32 fbdiv; +- u32 odiv; +- u32 band; +-}; +- +-static const struct hsdk_pll_cfg asdt_pll_cfg[] = { +- { 100000000, 0, 11, 3, 0 }, +- { 133000000, 0, 15, 3, 0 }, +- { 200000000, 1, 47, 3, 0 }, +- { 233000000, 1, 27, 2, 0 }, +- { 300000000, 1, 35, 2, 0 }, +- { 333000000, 1, 39, 2, 0 }, +- { 400000000, 1, 47, 2, 0 }, +- { 500000000, 0, 14, 1, 0 }, +- { 600000000, 0, 17, 1, 0 }, +- { 700000000, 0, 20, 1, 0 }, +- { 800000000, 0, 23, 1, 0 }, +- { 900000000, 1, 26, 0, 0 }, +- { 1000000000, 1, 29, 0, 0 }, +- { 1100000000, 1, 32, 0, 0 }, +- { 1200000000, 1, 35, 0, 0 }, +- { 1300000000, 1, 38, 0, 0 }, +- { 1400000000, 1, 41, 0, 0 }, +- { 1500000000, 1, 44, 0, 0 }, +- { 1600000000, 1, 47, 0, 0 }, +- {} +-}; +- +-static const struct hsdk_pll_cfg hdmi_pll_cfg[] = { +- { 297000000, 0, 21, 2, 0 }, +- { 540000000, 0, 19, 1, 0 }, +- { 594000000, 0, 21, 1, 0 }, +- {} +-}; +- +-struct hsdk_pll_clk { +- void __iomem *regs; +- void __iomem *spec_regs; +- const struct hsdk_pll_devdata *pll_devdata; +-}; +- +-struct hsdk_pll_devdata { +- const struct hsdk_pll_cfg *pll_cfg; +- int (*update_rate)(struct hsdk_pll_clk *clk, unsigned long rate, +- const struct hsdk_pll_cfg *cfg); +-}; +- +-static int hsdk_pll_core_update_rate(struct hsdk_pll_clk *, unsigned long, +- const struct hsdk_pll_cfg *); +-static int hsdk_pll_comm_update_rate(struct hsdk_pll_clk *, unsigned long, +- const struct hsdk_pll_cfg *); +- +-static const struct hsdk_pll_devdata core_pll_devdata = { +- .pll_cfg = asdt_pll_cfg, +- .update_rate = hsdk_pll_core_update_rate, +-}; +- +-static const struct hsdk_pll_devdata sdt_pll_devdata = { +- .pll_cfg = asdt_pll_cfg, +- .update_rate = hsdk_pll_comm_update_rate, +-}; +- +-static const struct hsdk_pll_devdata hdmi_pll_devdata = { +- .pll_cfg = hdmi_pll_cfg, +- .update_rate = hsdk_pll_comm_update_rate, +-}; +- +-static inline void hsdk_pll_write(struct hsdk_pll_clk *clk, u32 reg, u32 val) +-{ +- iowrite32(val, clk->regs + reg); +-} +- +-static inline u32 hsdk_pll_read(struct hsdk_pll_clk *clk, u32 reg) +-{ +- return ioread32(clk->regs + reg); +-} +- +-static inline void hsdk_pll_spcwrite(struct hsdk_pll_clk *clk, u32 reg, u32 val) +-{ +- iowrite32(val, clk->spec_regs + reg); +-} +- +-static inline u32 hsdk_pll_spcread(struct hsdk_pll_clk *clk, u32 reg) +-{ +- return ioread32(clk->spec_regs + reg); +-} +- +-static inline void hsdk_pll_set_cfg(struct hsdk_pll_clk *clk, +- const struct hsdk_pll_cfg *cfg) +-{ +- u32 val = 0; +- +- /* Powerdown and Bypass bits should be cleared */ +- val |= cfg->idiv << CGU_PLL_CTRL_IDIV_SHIFT; +- val |= cfg->fbdiv << CGU_PLL_CTRL_FBDIV_SHIFT; +- val |= cfg->odiv << CGU_PLL_CTRL_ODIV_SHIFT; +- val |= cfg->band << CGU_PLL_CTRL_BAND_SHIFT; +- +- pr_debug("write configurarion: %#x\n", val); +- +- hsdk_pll_write(clk, CGU_PLL_CTRL, val); +-} +- +-static inline bool hsdk_pll_is_locked(struct hsdk_pll_clk *clk) +-{ +- return !!(hsdk_pll_read(clk, CGU_PLL_STATUS) & CGU_PLL_STATUS_LOCK); +-} +- +-static inline bool hsdk_pll_is_err(struct hsdk_pll_clk *clk) +-{ +- return !!(hsdk_pll_read(clk, CGU_PLL_STATUS) & CGU_PLL_STATUS_ERR); +-} +- +-static ulong hsdk_pll_get_rate(struct clk *sclk) +-{ +- u32 val; +- u64 rate; +- u32 idiv, fbdiv, odiv; +- struct hsdk_pll_clk *clk = dev_get_priv(sclk->dev); +- +- val = hsdk_pll_read(clk, CGU_PLL_CTRL); +- +- pr_debug("current configurarion: %#x\n", val); +- +- /* Check if PLL is disabled */ +- if (val & CGU_PLL_CTRL_PD) +- return 0; +- +- /* Check if PLL is bypassed */ +- if (val & CGU_PLL_CTRL_BYPASS) +- return PARENT_RATE; +- +- /* input divider = reg.idiv + 1 */ +- idiv = 1 + ((val & CGU_PLL_CTRL_IDIV_MASK) >> CGU_PLL_CTRL_IDIV_SHIFT); +- /* fb divider = 2*(reg.fbdiv + 1) */ +- fbdiv = 2 * (1 + ((val & CGU_PLL_CTRL_FBDIV_MASK) >> CGU_PLL_CTRL_FBDIV_SHIFT)); +- /* output divider = 2^(reg.odiv) */ +- odiv = 1 << ((val & CGU_PLL_CTRL_ODIV_MASK) >> CGU_PLL_CTRL_ODIV_SHIFT); +- +- rate = (u64)PARENT_RATE * fbdiv; +- do_div(rate, idiv * odiv); +- +- return rate; +-} +- +-static unsigned long hsdk_pll_round_rate(struct clk *sclk, unsigned long rate) +-{ +- int i; +- unsigned long best_rate; +- struct hsdk_pll_clk *clk = dev_get_priv(sclk->dev); +- const struct hsdk_pll_cfg *pll_cfg = clk->pll_devdata->pll_cfg; +- +- if (pll_cfg[0].rate == 0) +- return -EINVAL; +- +- best_rate = pll_cfg[0].rate; +- +- for (i = 1; pll_cfg[i].rate != 0; i++) { +- if (abs(rate - pll_cfg[i].rate) < abs(rate - best_rate)) +- best_rate = pll_cfg[i].rate; +- } +- +- pr_debug("chosen best rate: %lu\n", best_rate); +- +- return best_rate; +-} +- +-static int hsdk_pll_comm_update_rate(struct hsdk_pll_clk *clk, +- unsigned long rate, +- const struct hsdk_pll_cfg *cfg) +-{ +- hsdk_pll_set_cfg(clk, cfg); +- +- /* +- * Wait until CGU relocks and check error status. +- * If after timeout CGU is unlocked yet return error. +- */ +- udelay(HSDK_PLL_MAX_LOCK_TIME); +- if (!hsdk_pll_is_locked(clk)) +- return -ETIMEDOUT; +- +- if (hsdk_pll_is_err(clk)) +- return -EINVAL; +- +- return 0; +-} +- +-static int hsdk_pll_core_update_rate(struct hsdk_pll_clk *clk, +- unsigned long rate, +- const struct hsdk_pll_cfg *cfg) +-{ +- /* +- * When core clock exceeds 500MHz, the divider for the interface +- * clock must be programmed to div-by-2. +- */ +- if (rate > CORE_IF_CLK_THRESHOLD_HZ) +- hsdk_pll_spcwrite(clk, CREG_CORE_IF_DIV, CREG_CORE_IF_CLK_DIV_2); +- +- hsdk_pll_set_cfg(clk, cfg); +- +- /* +- * Wait until CGU relocks and check error status. +- * If after timeout CGU is unlocked yet return error. +- */ +- udelay(HSDK_PLL_MAX_LOCK_TIME); +- if (!hsdk_pll_is_locked(clk)) +- return -ETIMEDOUT; +- +- if (hsdk_pll_is_err(clk)) +- return -EINVAL; +- +- /* +- * Program divider to div-by-1 if we succesfuly set core clock below +- * 500MHz threshold. +- */ +- if (rate <= CORE_IF_CLK_THRESHOLD_HZ) +- hsdk_pll_spcwrite(clk, CREG_CORE_IF_DIV, CREG_CORE_IF_CLK_DIV_1); +- +- return 0; +-} +- +-static ulong hsdk_pll_set_rate(struct clk *sclk, ulong rate) +-{ +- int i; +- unsigned long best_rate; +- struct hsdk_pll_clk *clk = dev_get_priv(sclk->dev); +- const struct hsdk_pll_cfg *pll_cfg = clk->pll_devdata->pll_cfg; +- +- best_rate = hsdk_pll_round_rate(sclk, rate); +- +- for (i = 0; pll_cfg[i].rate != 0; i++) { +- if (pll_cfg[i].rate == best_rate) { +- return clk->pll_devdata->update_rate(clk, best_rate, +- &pll_cfg[i]); +- } +- } +- +- pr_err("invalid rate=%ld, parent_rate=%d\n", best_rate, PARENT_RATE); +- +- return -EINVAL; +-} +- +-static const struct clk_ops hsdk_pll_ops = { +- .set_rate = hsdk_pll_set_rate, +- .get_rate = hsdk_pll_get_rate, +-}; +- +-static int hsdk_pll_clk_probe(struct udevice *dev) +-{ +- struct hsdk_pll_clk *pll_clk = dev_get_priv(dev); +- +- pll_clk->pll_devdata = (const struct hsdk_pll_devdata *) +- dev_get_driver_data(dev); +- +- pll_clk->regs = (void __iomem *)devfdt_get_addr_index(dev, 0); +- pll_clk->spec_regs = (void __iomem *)devfdt_get_addr_index(dev, 1); +- if ((pll_clk->pll_devdata == &core_pll_devdata) && !pll_clk->spec_regs) +- return -ENOENT; +- +- return 0; +-} +- +-static const struct udevice_id hsdk_pll_clk_id[] = { +- { .compatible = "snps,hsdk-gp-pll-clock", .data = (ulong)&sdt_pll_devdata}, +- { .compatible = "snps,hsdk-hdmi-pll-clock", .data = (ulong)&hdmi_pll_devdata}, +- { .compatible = "snps,hsdk-core-pll-clock", .data = (ulong)&core_pll_devdata}, +- { } +-}; +- +-U_BOOT_DRIVER(hsdk_pll_clk) = { +- .name = "hsdk-pll-clk", +- .id = UCLASS_CLK, +- .of_match = hsdk_pll_clk_id, +- .probe = hsdk_pll_clk_probe, +- .platdata_auto_alloc_size = sizeof(struct hsdk_pll_clk), +- .ops = &hsdk_pll_ops, +-}; +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0034-ARC-HSDK-introduce-CREG-GPIO-driver.patch b/board/synopsys/hsdk/uboot-patches/0034-ARC-HSDK-introduce-CREG-GPIO-driver.patch new file mode 100644 index 00000000000..098ef30fda1 --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0034-ARC-HSDK-introduce-CREG-GPIO-driver.patch @@ -0,0 +1,182 @@ +From c8584119d03e82c575b360f6c7dc7a94b56f7c49 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Fri, 13 Oct 2017 15:38:31 +0300 +Subject: [PATCH 34/46] ARC: HSDK: introduce CREG GPIO driver + +The HSDK can manage some pins via CREG registers block. + +Signed-off-by: Eugeniy Paltsev +--- + MAINTAINERS | 6 +++ + drivers/gpio/Kconfig | 7 +++ + drivers/gpio/Makefile | 1 + + drivers/gpio/hsdk-creg-gpio.c | 110 ++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 124 insertions(+) + create mode 100644 drivers/gpio/hsdk-creg-gpio.c + +diff --git a/MAINTAINERS b/MAINTAINERS +index 077a40b447..41d9116c3d 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -65,6 +65,12 @@ S: Maintained + L: uboot-snps-arc@synopsys.com + F: drivers/clk/clk-hsdk-cgu.c + ++ARC HSDK CREG GPIO ++M: Eugeniy Paltsev ++S: Maintained ++L: uboot-snps-arc@synopsys.com ++F: drivers/gpio/hsdk-creg-gpio.c ++ + ARM + M: Albert Aribaud + S: Maintained +diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig +index 6240c39539..2acb33bb51 100644 +--- a/drivers/gpio/Kconfig ++++ b/drivers/gpio/Kconfig +@@ -80,6 +80,13 @@ config IMX_RGPIO2P + help + This driver supports i.MX7ULP Rapid GPIO2P controller. + ++config HSDK_CREG_GPIO ++ bool "HSDK CREG GPIO griver" ++ depends on DM ++ default n ++ help ++ This driver supports CREG GPIOs on Synopsys HSDK SOC. ++ + config LPC32XX_GPIO + bool "LPC32XX GPIO driver" + depends on DM +diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile +index 81f55a576b..201d7bfff9 100644 +--- a/drivers/gpio/Makefile ++++ b/drivers/gpio/Makefile +@@ -54,6 +54,7 @@ obj-$(CONFIG_GPIO_UNIPHIER) += gpio-uniphier.o + obj-$(CONFIG_ZYNQ_GPIO) += zynq_gpio.o + obj-$(CONFIG_VYBRID_GPIO) += vybrid_gpio.o + obj-$(CONFIG_HIKEY_GPIO) += hi6220_gpio.o ++obj-$(CONFIG_HSDK_CREG_GPIO) += hsdk-creg-gpio.o + obj-$(CONFIG_IMX_RGPIO2P) += imx_rgpio2p.o + obj-$(CONFIG_PIC32_GPIO) += pic32_gpio.o + obj-$(CONFIG_MVEBU_GPIO) += mvebu_gpio.o +diff --git a/drivers/gpio/hsdk-creg-gpio.c b/drivers/gpio/hsdk-creg-gpio.c +new file mode 100644 +index 0000000000..8ca807a18f +--- /dev/null ++++ b/drivers/gpio/hsdk-creg-gpio.c +@@ -0,0 +1,110 @@ ++/* ++ * Synopsys HSDK SDP Generic PLL clock driver ++ * ++ * Copyright (C) 2017 Synopsys ++ * Author: Eugeniy Paltsev ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++DECLARE_GLOBAL_DATA_PTR; ++ ++#define HSDK_CREG_MAX_GPIO 8 ++ ++#define GPIO_ACTIVATE 0x2 ++#define GPIO_DEACTIVATE 0x3 ++#define GPIO_PIN_MASK 0x3 ++#define BIT_PER_GPIO 2 ++ ++struct hsdk_creg_gpio { ++ uint32_t *regs; ++}; ++ ++static int hsdk_creg_gpio_set_value(struct udevice *dev, unsigned oft, int val) ++{ ++ struct hsdk_creg_gpio *hcg = dev_get_priv(dev); ++ uint32_t reg = readl(hcg->regs); ++ uint32_t cmd = val ? GPIO_DEACTIVATE : GPIO_ACTIVATE; ++ ++ reg &= ~(GPIO_PIN_MASK << (oft * BIT_PER_GPIO)); ++ reg |= (cmd << (oft * BIT_PER_GPIO)); ++ ++ writel(reg, hcg->regs); ++ ++ return 0; ++} ++ ++static int hsdk_creg_gpio_direction_output(struct udevice *dev, unsigned oft, ++ int val) ++{ ++ hsdk_creg_gpio_set_value(dev, oft, val); ++ ++ return 0; ++} ++ ++static int hsdk_creg_gpio_direction_input(struct udevice *dev, unsigned oft) ++{ ++ pr_err("hsdk-creg-gpio can't be used as input!\n"); ++ ++ return -ENOTSUPP; ++} ++ ++static int hsdk_creg_gpio_get_value(struct udevice *dev, unsigned int oft) ++{ ++ struct hsdk_creg_gpio *hcg = dev_get_priv(dev); ++ uint32_t val = readl(hcg->regs); ++ ++ val = (val >> (oft * BIT_PER_GPIO)) & GPIO_PIN_MASK; ++ return (val == GPIO_DEACTIVATE) ? 1 : 0; ++} ++ ++static const struct dm_gpio_ops hsdk_creg_gpio_ops = { ++ .direction_output = hsdk_creg_gpio_direction_output, ++ .direction_input = hsdk_creg_gpio_direction_input, ++ .set_value = hsdk_creg_gpio_set_value, ++ .get_value = hsdk_creg_gpio_get_value, ++}; ++ ++static int hsdk_creg_gpio_probe(struct udevice *dev) ++{ ++ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); ++ struct hsdk_creg_gpio *hcg = dev_get_priv(dev); ++ ++ hcg->regs = (uint32_t *)devfdt_get_addr_ptr(dev); ++ ++ uc_priv->gpio_count = dev_read_u32_default(dev, "gpio-count", 1); ++ if (uc_priv->gpio_count > HSDK_CREG_MAX_GPIO) ++ uc_priv->gpio_count = HSDK_CREG_MAX_GPIO; ++ ++ uc_priv->bank_name = dev_read_string(dev, "gpio-bank-name"); ++ if (!uc_priv->bank_name) ++ uc_priv->bank_name = dev_read_name(dev); ++ ++ pr_debug("%s GPIO [0x%p] controller with %d gpios probed\n", ++ uc_priv->bank_name, hcg->regs, uc_priv->gpio_count); ++ ++ return 0; ++} ++ ++static const struct udevice_id hsdk_creg_gpio_ids[] = { ++ { .compatible = "snps,hsdk-creg-gpio" }, ++ { } ++}; ++ ++U_BOOT_DRIVER(gpio_hsdk_creg) = { ++ .name = "gpio_hsdk_creg", ++ .id = UCLASS_GPIO, ++ .ops = &hsdk_creg_gpio_ops, ++ .probe = hsdk_creg_gpio_probe, ++ .of_match = hsdk_creg_gpio_ids, ++ .platdata_auto_alloc_size = sizeof(struct hsdk_creg_gpio), ++}; +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0035-DW-SPI-fix-tx-data-loss-on-FIFO-flush.patch b/board/synopsys/hsdk/uboot-patches/0035-DW-SPI-fix-tx-data-loss-on-FIFO-flush.patch new file mode 100644 index 00000000000..4b00202366d --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0035-DW-SPI-fix-tx-data-loss-on-FIFO-flush.patch @@ -0,0 +1,56 @@ +From 05ddd46833a89a8ee95c60394784cdf1ffd88358 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Thu, 5 Oct 2017 18:28:50 +0300 +Subject: [PATCH 35/46] DW SPI: fix tx data loss on FIFO flush + +In current implementation if some data still exists in Tx FIFO it +can be silently flushed, i.e. dropped on disabling of the controller, +which happens when writing 0 to DW_SPI_SSIENR (it happens in the +begining of new transfer) + +So add wait for current transmit operation to complete to be sure +that current transmit operation is finished before new one. + +Signed-off-by: Eugeniy Paltsev +--- + drivers/spi/designware_spi.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c +index 5aa507b2d8..391f77b21b 100644 +--- a/drivers/spi/designware_spi.c ++++ b/drivers/spi/designware_spi.c +@@ -297,6 +297,7 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen, + { + struct udevice *bus = dev->parent; + struct dw_spi_priv *priv = dev_get_priv(bus); ++ unsigned start; + const u8 *tx = dout; + u8 *rx = din; + int ret = 0; +@@ -353,6 +354,22 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen, + /* Start transfer in a polling loop */ + ret = poll_transfer(priv); + ++ /* ++ * Wait for current transmit operation to complete. ++ * Otherwise if some data still exists in Tx FIFO it can be ++ * silently flushed, i.e. dropped on disabling of the controller, ++ * which happens when writing 0 to DW_SPI_SSIENR which happens ++ * in the begining of new transfer. ++ */ ++ start = get_timer(0); ++ while (!(dw_readl(priv, DW_SPI_SR) & SR_TF_EMPT) || ++ (dw_readl(priv, DW_SPI_SR) & SR_BUSY)) { ++ if (get_timer(start) > RX_TIMEOUT) { ++ ret = -ETIMEDOUT; ++ break; ++ } ++ } ++ + return ret; + } + +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0036-DW-SPI-fix-transmit-only-mode.patch b/board/synopsys/hsdk/uboot-patches/0036-DW-SPI-fix-transmit-only-mode.patch new file mode 100644 index 00000000000..05dc496f3f5 --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0036-DW-SPI-fix-transmit-only-mode.patch @@ -0,0 +1,39 @@ +From 22d4b8ed3b33991659b498303fa60dac0aadf19e Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Mon, 9 Oct 2017 20:37:35 +0300 +Subject: [PATCH 36/46] DW SPI: fix transmit only mode + +In current implementation we get -ETIMEDOUT error when we try to use +transmit only mode (SPI_TMOD_TO) +This happens because in transmit only mode input FIFO never gets any data +which breaks our logic in dw_reader(): we are waiting until RX data will be +ready in dw_reader, but this newer happens, so we return with error. + +Fix that by using SPI_TMOD_TR instead of SPI_TMOD_TO which allows to use +RX FIFO. + +Signed-off-by: Eugeniy Paltsev +--- + drivers/spi/designware_spi.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c +index 391f77b21b..76dc3ba328 100644 +--- a/drivers/spi/designware_spi.c ++++ b/drivers/spi/designware_spi.c +@@ -319,7 +319,11 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen, + else if (rx) + priv->tmode = SPI_TMOD_RO; + else +- priv->tmode = SPI_TMOD_TO; ++ /* ++ * In transmit only mode (SPI_TMOD_TO) input FIFO never gets ++ * any data which breaks our logic in poll_transfer() above. ++ */ ++ priv->tmode = SPI_TMOD_TR; + + cr0 &= ~SPI_TMOD_MASK; + cr0 |= (priv->tmode << SPI_TMOD_OFFSET); +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0037-DW-SPI-refactor-poll_transfer-functions.patch b/board/synopsys/hsdk/uboot-patches/0037-DW-SPI-refactor-poll_transfer-functions.patch new file mode 100644 index 00000000000..98e2908c92b --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0037-DW-SPI-refactor-poll_transfer-functions.patch @@ -0,0 +1,79 @@ +From 03e6a7f3a8a0d7abe940f3e9973d9c0a2a2b8b85 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Mon, 9 Oct 2017 20:56:50 +0300 +Subject: [PATCH 37/46] DW SPI: refactor poll_transfer functions + +There is no sense in waiting for RX data in dw_reader function: +there is no chance that RX data will appear in RX FIFO if +RX FIFO is empty after previous TX write in dw_writer function. +So get rid of this waiting. After that we can get rid of dw_reader +return value and make it returning void. After that we can get rid +of dw_reader return value check in poll_transfer function. + +With these changes we're getting closer to Linux DW SPI driver. + +Signed-off-by: Eugeniy Paltsev +--- + drivers/spi/designware_spi.c | 26 ++++---------------------- + 1 file changed, 4 insertions(+), 22 deletions(-) + +diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c +index 76dc3ba328..3a63dfdcd5 100644 +--- a/drivers/spi/designware_spi.c ++++ b/drivers/spi/designware_spi.c +@@ -244,28 +244,16 @@ static void dw_writer(struct dw_spi_priv *priv) + } + } + +-static int dw_reader(struct dw_spi_priv *priv) ++static void dw_reader(struct dw_spi_priv *priv) + { +- unsigned start = get_timer(0); +- u32 max; ++ u32 max = rx_max(priv); + u16 rxw; + +- /* Wait for rx data to be ready */ +- while (rx_max(priv) == 0) { +- if (get_timer(start) > RX_TIMEOUT) +- return -ETIMEDOUT; +- } +- +- max = rx_max(priv); +- + while (max--) { + rxw = dw_readw(priv, DW_SPI_DR); + debug("%s: rx=0x%02x\n", __func__, rxw); + +- /* +- * Care about rx only if the transfer's original "rx" is +- * not null +- */ ++ /* Care about rx if the transfer's original "rx" is not null */ + if (priv->rx_end - priv->len) { + if (priv->bits_per_word == 8) + *(u8 *)(priv->rx) = rxw; +@@ -274,19 +262,13 @@ static int dw_reader(struct dw_spi_priv *priv) + } + priv->rx += priv->bits_per_word >> 3; + } +- +- return 0; + } + + static int poll_transfer(struct dw_spi_priv *priv) + { +- int ret; +- + do { + dw_writer(priv); +- ret = dw_reader(priv); +- if (ret < 0) +- return ret; ++ dw_reader(priv); + } while (priv->rx_end > priv->rx); + + return 0; +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0038-DW-SPI-add-option-to-use-external-gpio-for-chip-sele.patch b/board/synopsys/hsdk/uboot-patches/0038-DW-SPI-add-option-to-use-external-gpio-for-chip-sele.patch new file mode 100644 index 00000000000..65a53cca272 --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0038-DW-SPI-add-option-to-use-external-gpio-for-chip-sele.patch @@ -0,0 +1,120 @@ +From e71cbc4c64d85f5bff81b6c6d58956624164601e Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Thu, 5 Oct 2017 16:08:09 +0300 +Subject: [PATCH 38/46] DW SPI: add option to use external gpio for chip select + +Add option to use external gpio for chip select. Gpio can be added +via device tree using standard gpio bindings. + +Signed-off-by: Eugeniy Paltsev +--- + drivers/spi/designware_spi.c | 51 +++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 50 insertions(+), 1 deletion(-) + +diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c +index 3a63dfdcd5..0f3d0e75ee 100644 +--- a/drivers/spi/designware_spi.c ++++ b/drivers/spi/designware_spi.c +@@ -10,6 +10,7 @@ + * SPDX-License-Identifier: GPL-2.0 + */ + ++#include + #include + #include + #include +@@ -95,6 +96,8 @@ struct dw_spi_priv { + unsigned int freq; /* Default frequency */ + unsigned int mode; + ++ struct gpio_desc cs_gpio; /* External chip-select gpio */ ++ + int bits_per_word; + u8 cs; /* chip select pin */ + u8 tmode; /* TR/TO/RO/EEPROM */ +@@ -128,6 +131,32 @@ static inline void dw_writew(struct dw_spi_priv *priv, u32 offset, u16 val) + __raw_writew(val, priv->regs + offset); + } + ++static int request_gpio_cs(struct udevice *bus) ++{ ++#if defined(CONFIG_DM_GPIO) ++ struct dw_spi_priv *priv = dev_get_priv(bus); ++ int ret; ++ ++ /* External chip select gpio line is optional */ ++ ret = gpio_request_by_name(bus, "cs-gpio", 0, &priv->cs_gpio, 0); ++ if (ret == -ENOENT) ++ return 0; ++ ++ if (ret < 0) { ++ printf("Can't get %s gpio! Error: %d\n", bus->name, ret); ++ return ret; ++ } ++ ++ if (dm_gpio_is_valid(&priv->cs_gpio)) { ++ dm_gpio_set_dir_flags(&priv->cs_gpio, ++ GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); ++ } ++ ++ debug("%s: used external gpio for CS managment\n", __func__); ++#endif ++ return 0; ++} ++ + static int dw_spi_ofdata_to_platdata(struct udevice *bus) + { + struct dw_spi_platdata *plat = bus->platdata; +@@ -142,7 +171,7 @@ static int dw_spi_ofdata_to_platdata(struct udevice *bus) + debug("%s: regs=%p max-frequency=%d\n", __func__, plat->regs, + plat->frequency); + +- return 0; ++ return request_gpio_cs(bus); + } + + static inline void spi_enable_chip(struct dw_spi_priv *priv, int enable) +@@ -274,6 +303,18 @@ static int poll_transfer(struct dw_spi_priv *priv) + return 0; + } + ++static void external_cs_manage(struct udevice *dev, bool on) ++{ ++#if defined(CONFIG_DM_GPIO) ++ struct dw_spi_priv *priv = dev_get_priv(dev->parent); ++ ++ if (!dm_gpio_is_valid(&priv->cs_gpio)) ++ return; ++ ++ dm_gpio_set_value(&priv->cs_gpio, on ? 1 : 0); ++#endif ++} ++ + static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) + { +@@ -292,6 +333,10 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen, + return -1; + } + ++ /* Start the transaction if necessary. */ ++ if (flags & SPI_XFER_BEGIN) ++ external_cs_manage(dev, false); ++ + cr0 = (priv->bits_per_word - 1) | (priv->type << SPI_FRF_OFFSET) | + (priv->mode << SPI_MODE_OFFSET) | + (priv->tmode << SPI_TMOD_OFFSET); +@@ -356,6 +401,10 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen, + } + } + ++ /* Stop the transaction if necessary */ ++ if (flags & SPI_XFER_END) ++ external_cs_manage(dev, true); ++ + return ret; + } + +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0039-DW-SPI-use-32-bit-access-instead-of-16-and-32-bit-mi.patch b/board/synopsys/hsdk/uboot-patches/0039-DW-SPI-use-32-bit-access-instead-of-16-and-32-bit-mi.patch new file mode 100644 index 00000000000..a916604be3c --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0039-DW-SPI-use-32-bit-access-instead-of-16-and-32-bit-mi.patch @@ -0,0 +1,172 @@ +From 2ff5b469b47e3a74ee6a01b33493746c890634d3 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Mon, 25 Sep 2017 21:48:40 +0300 +Subject: [PATCH 39/46] DW SPI: use 32 bit access instead of 16 and 32 bit mix + +Current DW SPI driver uses 32 bit access for some registers and +16 bit access for others. So if DW SPI IP is connected via bus +which doesn't support 16 bit access we will get bus error. + +Fix that by switching to 32 bit access only instead of 16 and 32 bit mix + +Additional Documentation to Support this Change: +The DW_apb_ssi databook states: +"All registers in the DW_apb_ssi are addressed at 32-bit boundaries +to remain consistent with the AHB bus. Where the physical size of +any register is less than 32-bits wide, the upper unused bits of +the 32-bit boundary are reserved. Writing to these bits has no +effect; reading from these bits returns 0." [1] + +[1] Section 6.1 of dw_apb_ssi.pdf (version 3.22a) + +Signed-off-by: Eugeniy Paltsev +--- + drivers/spi/designware_spi.c | 44 +++++++++++++++++--------------------------- + 1 file changed, 17 insertions(+), 27 deletions(-) + +diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c +index 0f3d0e75ee..6cc4f51a1f 100644 +--- a/drivers/spi/designware_spi.c ++++ b/drivers/spi/designware_spi.c +@@ -111,26 +111,16 @@ struct dw_spi_priv { + void *rx_end; + }; + +-static inline u32 dw_readl(struct dw_spi_priv *priv, u32 offset) ++static inline u32 dw_read(struct dw_spi_priv *priv, u32 offset) + { + return __raw_readl(priv->regs + offset); + } + +-static inline void dw_writel(struct dw_spi_priv *priv, u32 offset, u32 val) ++static inline void dw_write(struct dw_spi_priv *priv, u32 offset, u32 val) + { + __raw_writel(val, priv->regs + offset); + } + +-static inline u16 dw_readw(struct dw_spi_priv *priv, u32 offset) +-{ +- return __raw_readw(priv->regs + offset); +-} +- +-static inline void dw_writew(struct dw_spi_priv *priv, u32 offset, u16 val) +-{ +- __raw_writew(val, priv->regs + offset); +-} +- + static int request_gpio_cs(struct udevice *bus) + { + #if defined(CONFIG_DM_GPIO) +@@ -176,14 +166,14 @@ static int dw_spi_ofdata_to_platdata(struct udevice *bus) + + static inline void spi_enable_chip(struct dw_spi_priv *priv, int enable) + { +- dw_writel(priv, DW_SPI_SSIENR, (enable ? 1 : 0)); ++ dw_write(priv, DW_SPI_SSIENR, (enable ? 1 : 0)); + } + + /* Restart the controller, disable all interrupts, clean rx fifo */ + static void spi_hw_init(struct dw_spi_priv *priv) + { + spi_enable_chip(priv, 0); +- dw_writel(priv, DW_SPI_IMR, 0xff); ++ dw_write(priv, DW_SPI_IMR, 0xff); + spi_enable_chip(priv, 1); + + /* +@@ -194,13 +184,13 @@ static void spi_hw_init(struct dw_spi_priv *priv) + u32 fifo; + + for (fifo = 1; fifo < 256; fifo++) { +- dw_writew(priv, DW_SPI_TXFLTR, fifo); +- if (fifo != dw_readw(priv, DW_SPI_TXFLTR)) ++ dw_write(priv, DW_SPI_TXFLTR, fifo); ++ if (fifo != dw_read(priv, DW_SPI_TXFLTR)) + break; + } + + priv->fifo_len = (fifo == 1) ? 0 : fifo; +- dw_writew(priv, DW_SPI_TXFLTR, 0); ++ dw_write(priv, DW_SPI_TXFLTR, 0); + } + debug("%s: fifo_len=%d\n", __func__, priv->fifo_len); + } +@@ -230,7 +220,7 @@ static inline u32 tx_max(struct dw_spi_priv *priv) + u32 tx_left, tx_room, rxtx_gap; + + tx_left = (priv->tx_end - priv->tx) / (priv->bits_per_word >> 3); +- tx_room = priv->fifo_len - dw_readw(priv, DW_SPI_TXFLR); ++ tx_room = priv->fifo_len - dw_read(priv, DW_SPI_TXFLR); + + /* + * Another concern is about the tx/rx mismatch, we +@@ -251,7 +241,7 @@ static inline u32 rx_max(struct dw_spi_priv *priv) + { + u32 rx_left = (priv->rx_end - priv->rx) / (priv->bits_per_word >> 3); + +- return min_t(u32, rx_left, dw_readw(priv, DW_SPI_RXFLR)); ++ return min_t(u32, rx_left, dw_read(priv, DW_SPI_RXFLR)); + } + + static void dw_writer(struct dw_spi_priv *priv) +@@ -267,7 +257,7 @@ static void dw_writer(struct dw_spi_priv *priv) + else + txw = *(u16 *)(priv->tx); + } +- dw_writew(priv, DW_SPI_DR, txw); ++ dw_write(priv, DW_SPI_DR, txw); + debug("%s: tx=0x%02x\n", __func__, txw); + priv->tx += priv->bits_per_word >> 3; + } +@@ -279,7 +269,7 @@ static void dw_reader(struct dw_spi_priv *priv) + u16 rxw; + + while (max--) { +- rxw = dw_readw(priv, DW_SPI_DR); ++ rxw = dw_read(priv, DW_SPI_DR); + debug("%s: rx=0x%02x\n", __func__, rxw); + + /* Care about rx if the transfer's original "rx" is not null */ +@@ -368,8 +358,8 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen, + + debug("%s: cr0=%08x\n", __func__, cr0); + /* Reprogram cr0 only if changed */ +- if (dw_readw(priv, DW_SPI_CTRL0) != cr0) +- dw_writew(priv, DW_SPI_CTRL0, cr0); ++ if (dw_read(priv, DW_SPI_CTRL0) != cr0) ++ dw_write(priv, DW_SPI_CTRL0, cr0); + + /* + * Configure the desired SS (slave select 0...3) in the controller +@@ -377,7 +367,7 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen, + * automatically. So no cs_activate() etc is needed in this driver. + */ + cs = spi_chip_select(dev); +- dw_writel(priv, DW_SPI_SER, 1 << cs); ++ dw_write(priv, DW_SPI_SER, 1 << cs); + + /* Enable controller after writing control registers */ + spi_enable_chip(priv, 1); +@@ -393,8 +383,8 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen, + * in the begining of new transfer. + */ + start = get_timer(0); +- while (!(dw_readl(priv, DW_SPI_SR) & SR_TF_EMPT) || +- (dw_readl(priv, DW_SPI_SR) & SR_BUSY)) { ++ while (!(dw_read(priv, DW_SPI_SR) & SR_TF_EMPT) || ++ (dw_read(priv, DW_SPI_SR) & SR_BUSY)) { + if (get_timer(start) > RX_TIMEOUT) { + ret = -ETIMEDOUT; + break; +@@ -423,7 +413,7 @@ static int dw_spi_set_speed(struct udevice *bus, uint speed) + /* clk_div doesn't support odd number */ + clk_div = cm_get_spi_controller_clk_hz() / speed; + clk_div = (clk_div + 1) & 0xfffe; +- dw_writel(priv, DW_SPI_BAUDR, clk_div); ++ dw_write(priv, DW_SPI_BAUDR, clk_div); + + /* Enable controller after writing control registers */ + spi_enable_chip(priv, 1); +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0040-SPI-Flash-add-support-of-sst26wf-flash-series.patch b/board/synopsys/hsdk/uboot-patches/0040-SPI-Flash-add-support-of-sst26wf-flash-series.patch new file mode 100644 index 00000000000..9cf2d26a878 --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0040-SPI-Flash-add-support-of-sst26wf-flash-series.patch @@ -0,0 +1,223 @@ +From d2c42047dabd6b9eeb9de2ae5a6f056e54bbbe01 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Mon, 9 Oct 2017 19:25:51 +0300 +Subject: [PATCH 40/46] SPI Flash: add support of sst26wf* flash series + +sst26wf flash series block protection implementation differs +from other SST series, so add implementation for sst26wf +lock/unlock/is_locked functions. + +Signed-off-by: Eugeniy Paltsev +--- + drivers/mtd/spi/spi_flash.c | 188 ++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 188 insertions(+) + +diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c +index 51e28bf07b..163471d143 100644 +--- a/drivers/mtd/spi/spi_flash.c ++++ b/drivers/mtd/spi/spi_flash.c +@@ -839,6 +839,184 @@ int stm_unlock(struct spi_flash *flash, u32 ofs, size_t len) + } + #endif + ++#if defined(CONFIG_SPI_FLASH_SST) ++#define SST26_CMD_READ_BPR 0x72 ++#define SST26_CMD_WRITE_BPR 0x42 ++ ++#define BLOCK_64K_SZ 0x10000 ++#define MAX_BPR_REG_LEN (18 + 1) ++#define SST26WF_BOUND_REG_SIZE ((32 + 4 * 8) * 1024) ++ ++bool sst26_check_bpr(u32 bpr_size, u8 *cmd, u32 bit) ++{ ++ return !!(cmd[bpr_size - (bit / 8) - 1] & BIT(bit % 8)); ++} ++ ++bool sst26_clear_bpr(u32 bpr_size, u8 *cmd, u32 bit) ++{ ++ cmd[bpr_size - (bit / 8) - 1] &= ~BIT(bit % 8); ++ return false; ++} ++ ++bool sst26_set_bpr(u32 bpr_size, u8 *cmd, u32 bit) ++{ ++ cmd[bpr_size - (bit / 8) - 1] |= BIT(bit % 8); ++ return false; ++} ++ ++enum lock_ctl { ++ CTL_LOCK, ++ CTL_UNLOCK, ++ CTL_CHECK ++}; ++ ++/* ++ * sst26wf016/sst26wf032/sst26wf064 have next block protection: ++ * 4x - 8 KByte blocks - read & write protection bits - upper addresses ++ * 1x - 32 KByte blocks - write protection bits ++ * rest - 64 KByte blocks - write protection bits ++ * 1x - 32 KByte blocks - write protection bits ++ * 4x - 8 KByte blocks - read & write protection bits - lower addresses ++ * ++ * We'll support only per 64k lock/unlock so lower and upper 64 KByte region ++ * will be treated as single block. ++ */ ++ ++/* ++ * Lock, unlock or check lock status of the flash region of the flash (depending ++ * on the lock_ctl value) ++ */ ++int sst26_lock_ctl(struct spi_flash *flash, u32 ofs, size_t len, enum lock_ctl ctl) ++{ ++ u32 i, bpr_ptr, rptr_64k, lptr_64k, bpr_size; ++ bool lower_64k = false, upper_64k = false; ++ u8 cmd, bpr_buff[MAX_BPR_REG_LEN] = {}; ++ int ret; ++ ++ bool (* bpr_bit_process) (u32 bpr_size, u8 *, u32); ++ ++ /* Check length and offset for 64k alignment */ ++ if ((ofs & 0xFFFF) || (len & 0xFFFF)) ++ return -EINVAL; ++ ++ if (ofs + len > flash->size) ++ return -EINVAL; ++ ++ /* SST26 family has only 16 Mbit, 32 Mbit and 64 Mbit IC */ ++ if (flash->size != 0x200000 && ++ flash->size != 0x400000 && ++ flash->size != 0x800000) ++ return -EINVAL; ++ ++ bpr_size = 2 + (flash->size / BLOCK_64K_SZ / 8); ++ ++ cmd = SST26_CMD_READ_BPR; ++ ret = spi_flash_read_common(flash, &cmd, 1, bpr_buff, bpr_size); ++ if (ret < 0) { ++ printf("SF: fail to read block-protection register\n"); ++ return ret; ++ } ++ ++ if (ctl == CTL_LOCK) ++ bpr_bit_process = sst26_set_bpr; ++ else if (ctl == CTL_UNLOCK) ++ bpr_bit_process = sst26_clear_bpr; ++ else ++ bpr_bit_process = sst26_check_bpr; ++ ++ rptr_64k = min_t(u32, ofs + len , flash->size - SST26WF_BOUND_REG_SIZE); ++ lptr_64k = max_t(u32, ofs, SST26WF_BOUND_REG_SIZE); ++ ++ upper_64k = ((ofs + len) > (flash->size - SST26WF_BOUND_REG_SIZE)); ++ lower_64k = (ofs < SST26WF_BOUND_REG_SIZE); ++ ++ /* Lower bits in block-protection register are about 64k region */ ++ bpr_ptr = lptr_64k / BLOCK_64K_SZ - 1; ++ ++ /* Process 64K blocks region */ ++ while (lptr_64k < rptr_64k) { ++ if (bpr_bit_process(bpr_size, bpr_buff, bpr_ptr)) ++ return 1; ++ ++ bpr_ptr++; ++ lptr_64k += BLOCK_64K_SZ; ++ } ++ ++ /* 32K and 8K region bits in BPR are after 64k region bits */ ++ bpr_ptr = (flash->size - 2 * SST26WF_BOUND_REG_SIZE) / BLOCK_64K_SZ; ++ ++ /* Process lower 32K block region */ ++ if (lower_64k) ++ if (bpr_bit_process(bpr_size, bpr_buff, bpr_ptr)) ++ return 1; ++ ++ bpr_ptr++; ++ ++ /* Process upper 32K block region */ ++ if (upper_64k) ++ if (bpr_bit_process(bpr_size, bpr_buff, bpr_ptr)) ++ return 1; ++ ++ bpr_ptr++; ++ ++ /* Process lower 8K block region */ ++ for (i = 0; i < 4; i++) { ++ if (lower_64k) ++ if (bpr_bit_process(bpr_size, bpr_buff, bpr_ptr)) ++ return 1; ++ ++ /* In 8K area BPR has both read and write protection bits */ ++ bpr_ptr += 2; ++ } ++ ++ /* Process upper 8K block region */ ++ for (i = 0; i < 4; i++) { ++ if (upper_64k) ++ if (bpr_bit_process(bpr_size, bpr_buff, bpr_ptr)) ++ return 1; ++ ++ /* In 8K area BPR has both read and write protection bits */ ++ bpr_ptr += 2; ++ } ++ ++ /* If we check region status we don't need to write BPR back */ ++ if (ctl == CTL_CHECK) ++ return 0; ++ ++ cmd = SST26_CMD_WRITE_BPR; ++ ret = spi_flash_write_common(flash, &cmd, 1, bpr_buff, bpr_size); ++ if (ret < 0) { ++ printf("SF: fail to write block-protection register\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int sst26_unlock(struct spi_flash *flash, u32 ofs, size_t len) ++{ ++ return sst26_lock_ctl(flash, ofs, len, CTL_UNLOCK); ++} ++ ++int sst26_lock(struct spi_flash *flash, u32 ofs, size_t len) ++{ ++ return sst26_lock_ctl(flash, ofs, len, CTL_LOCK); ++} ++ ++int sst26_is_locked(struct spi_flash *flash, u32 ofs, size_t len) ++{ ++ /* ++ * is_locked function is used for check before reading or erasing flash ++ * region, so offset and length might be not 64k allighned, so adjust ++ * them to be 64k allighned as sst26_lock_ctl works only with 64k ++ * allighned regions. ++ */ ++ ofs -= ofs & 0xFFFF; ++ len = len & 0xFFFF ? (len & ~0xFFFF) + BLOCK_64K_SZ : len; ++ ++ return sst26_lock_ctl(flash, ofs, len, CTL_CHECK); ++} ++#endif + + #ifdef CONFIG_SPI_FLASH_MACRONIX + static int macronix_quad_enable(struct spi_flash *flash) +@@ -1030,6 +1208,16 @@ int spi_flash_scan(struct spi_flash *flash) + } + #endif + ++/* sst26wf series block protection implementation differs from other series */ ++#if defined(CONFIG_SPI_FLASH_SST) ++ if (JEDEC_MFR(info) == SPI_FLASH_CFI_MFR_SST && ++ (JEDEC_ID(info) >> 8) == 0x26) { ++ flash->flash_lock = sst26_lock; ++ flash->flash_unlock = sst26_unlock; ++ flash->flash_is_locked = sst26_is_locked; ++ } ++#endif ++ + /* Compute the flash size */ + flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 : 0; + flash->page_size = info->page_size; +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0041-SF-add-add-support-for-sst26wf016-sst26wf032-sst26wf.patch b/board/synopsys/hsdk/uboot-patches/0041-SF-add-add-support-for-sst26wf016-sst26wf032-sst26wf.patch new file mode 100644 index 00000000000..09c55007a9a --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0041-SF-add-add-support-for-sst26wf016-sst26wf032-sst26wf.patch @@ -0,0 +1,31 @@ +From 1bfc5dc22320b6f1e9d1a57a7c1d6a01b7dc4b87 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Mon, 9 Oct 2017 20:05:18 +0300 +Subject: [PATCH 41/46] SF: add add support for sst26wf016, sst26wf032, + sst26wf064 + +This commit adds support for the SST sst26wf016, sst26wf032 +and sst26wf064 flash IC. + +Signed-off-by: Eugeniy Paltsev +--- + drivers/mtd/spi/spi_flash_ids.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/mtd/spi/spi_flash_ids.c b/drivers/mtd/spi/spi_flash_ids.c +index 13f64e773f..e18bc50dcf 100644 +--- a/drivers/mtd/spi/spi_flash_ids.c ++++ b/drivers/mtd/spi/spi_flash_ids.c +@@ -149,6 +149,9 @@ const struct spi_flash_info spi_flash_ids[] = { + {"sst25wf040", INFO(0xbf2504, 0x0, 64 * 1024, 8, SECT_4K | SST_WR) }, + {"sst25wf040b", INFO(0x621613, 0x0, 64 * 1024, 8, SECT_4K) }, + {"sst25wf080", INFO(0xbf2505, 0x0, 64 * 1024, 16, SECT_4K | SST_WR) }, ++ {"sst26wf016", INFO(0xbf2651, 0x0, 64 * 1024, 32, SECT_4K) }, ++ {"sst26wf032", INFO(0xbf2622, 0x0, 64 * 1024, 64, SECT_4K) }, ++ {"sst26wf064", INFO(0xbf2643, 0x0, 64 * 1024, 128, SECT_4K) }, + #endif + #ifdef CONFIG_SPI_FLASH_WINBOND /* WINBOND */ + {"w25p80", INFO(0xef2014, 0x0, 64 * 1024, 16, 0) }, +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0042-ARC-add-asm-gpio.h-to-fix-compilation-error-with-CON.patch b/board/synopsys/hsdk/uboot-patches/0042-ARC-add-asm-gpio.h-to-fix-compilation-error-with-CON.patch new file mode 100644 index 00000000000..c17530ba3c4 --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0042-ARC-add-asm-gpio.h-to-fix-compilation-error-with-CON.patch @@ -0,0 +1,27 @@ +From edcc97e71bab4b8e5423059712091ce14c916086 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Mon, 16 Oct 2017 15:07:46 +0300 +Subject: [PATCH 42/46] ARC: add asm/gpio.h to fix compilation error with + CONFIG_CMD_GPIO + +With CONFIG_CMD_GPIO compilation reports error. +common/cmd_gpio.c:13:22: fatal error: asm/gpio.h: No such file or directory + #include + ^ + +Signed-off-by: Eugeniy Paltsev +--- + arch/arc/include/asm/gpio.h | 1 + + 1 file changed, 1 insertion(+) + create mode 100644 arch/arc/include/asm/gpio.h + +diff --git a/arch/arc/include/asm/gpio.h b/arch/arc/include/asm/gpio.h +new file mode 100644 +index 0000000000..306ab4c9f2 +--- /dev/null ++++ b/arch/arc/include/asm/gpio.h +@@ -0,0 +1 @@ ++#include +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0043-ARC-HSDK-update-dts-and-defconfig-for-SPI-flash-usag.patch b/board/synopsys/hsdk/uboot-patches/0043-ARC-HSDK-update-dts-and-defconfig-for-SPI-flash-usag.patch new file mode 100644 index 00000000000..443b69050b1 --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0043-ARC-HSDK-update-dts-and-defconfig-for-SPI-flash-usag.patch @@ -0,0 +1,107 @@ +From 3e2d11bb28ff6180bd1996e204f7ac1fdc64bf82 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Wed, 1 Nov 2017 21:11:00 +0300 +Subject: [PATCH 43/46] ARC: HSDK: update dts and defconfig for SPI flash usage + +Add nodes of DW SPI controller, SPI flash IC and SPI CS GPIO. +Enable SPI subsystem in defconfig. + +Signed-off-by: Eugeniy Paltsev +--- + arch/arc/dts/hsdk.dts | 34 ++++++++++++++++++++++++++++++++++ + configs/hsdk_defconfig | 9 +++++++++ + 2 files changed, 43 insertions(+) + +diff --git a/arch/arc/dts/hsdk.dts b/arch/arc/dts/hsdk.dts +index 678a238071..3c7f36da94 100644 +--- a/arch/arc/dts/hsdk.dts ++++ b/arch/arc/dts/hsdk.dts +@@ -13,6 +13,7 @@ + + aliases { + console = &uart0; ++ spi0 = "/spi@f0020000"; + }; + + cpu_card { +@@ -47,6 +48,13 @@ + #clock-cells = <1>; + }; + ++ periph_clk: periph_clk { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <33330000>; ++ u-boot,dm-pre-reloc; ++ }; ++ + uart0: serial0@f0005000 { + compatible = "snps,dw-apb-uart"; + reg = <0xf0005000 0x1000>; +@@ -70,4 +78,30 @@ + 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 = <&periph_clk>; ++ 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 { ++ u-boot,dm-pre-reloc; ++ 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/configs/hsdk_defconfig b/configs/hsdk_defconfig +index a04cfee5f0..c2cea0a2c3 100644 +--- a/configs/hsdk_defconfig ++++ b/configs/hsdk_defconfig +@@ -10,6 +10,8 @@ CONFIG_BOARD_EARLY_INIT_F=y + CONFIG_SYS_PROMPT="hsdk# " + # CONFIG_CMD_FLASH is not set + 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 +@@ -25,12 +27,19 @@ CONFIG_ENV_FAT_INTERFACE="mmc" + CONFIG_ENV_FAT_DEVICE_AND_PART="0:1" + CONFIG_NET_RANDOM_ETHADDR=y + CONFIG_DM=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 +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0044-SOCFPGA-clock-manager-implement-dw_spi_get_clk-funct.patch b/board/synopsys/hsdk/uboot-patches/0044-SOCFPGA-clock-manager-implement-dw_spi_get_clk-funct.patch new file mode 100644 index 00000000000..475bf3af014 --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0044-SOCFPGA-clock-manager-implement-dw_spi_get_clk-funct.patch @@ -0,0 +1,75 @@ +From 0b721c697e6a4866530e9440a79c028b35cdcf1b Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Fri, 10 Nov 2017 17:21:25 +0300 +Subject: [PATCH 44/46] SOCFPGA: clock manager: implement dw_spi_get_clk + function + +Implement dw_spi_get_clk function to override its weak +implementation in designware_spi.c driver. + +We need this change to get rid of cm_get_spi_controller_clk_hz +function and clock_manager.h include in designware_spi.c driver. + +Signed-off-by: Eugeniy Paltsev +--- + arch/arm/mach-socfpga/clock_manager_arria10.c | 9 +++++++++ + arch/arm/mach-socfpga/clock_manager_gen5.c | 9 +++++++++ + 2 files changed, 18 insertions(+) + +diff --git a/arch/arm/mach-socfpga/clock_manager_arria10.c b/arch/arm/mach-socfpga/clock_manager_arria10.c +index 482b8543f4..623a266f80 100644 +--- a/arch/arm/mach-socfpga/clock_manager_arria10.c ++++ b/arch/arm/mach-socfpga/clock_manager_arria10.c +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + #include + + DECLARE_GLOBAL_DATA_PTR; +@@ -1076,6 +1077,14 @@ unsigned int cm_get_qspi_controller_clk_hz(void) + return cm_get_l4_noc_hz(CLKMGR_MAINPLL_NOCDIV_L4MAINCLK_LSB); + } + ++/* Override weak dw_spi_get_clk implementation in designware_spi.c driver */ ++int dw_spi_get_clk(struct udevice *bus, ulong *rate) ++{ ++ *rate = cm_get_spi_controller_clk_hz(); ++ ++ return 0; ++} ++ + void cm_print_clock_quick_summary(void) + { + printf("MPU %10ld kHz\n", cm_get_mpu_clk_hz() / 1000); +diff --git a/arch/arm/mach-socfpga/clock_manager_gen5.c b/arch/arm/mach-socfpga/clock_manager_gen5.c +index 31fd51097a..a371d83620 100644 +--- a/arch/arm/mach-socfpga/clock_manager_gen5.c ++++ b/arch/arm/mach-socfpga/clock_manager_gen5.c +@@ -6,6 +6,7 @@ + + #include + #include ++#include + #include + #include + +@@ -509,6 +510,14 @@ unsigned int cm_get_spi_controller_clk_hz(void) + return clock; + } + ++/* Override weak dw_spi_get_clk implementation in designware_spi.c driver */ ++int dw_spi_get_clk(struct udevice *bus, ulong *rate) ++{ ++ *rate = cm_get_spi_controller_clk_hz(); ++ ++ return 0; ++} ++ + void cm_print_clock_quick_summary(void) + { + printf("MPU %10ld kHz\n", cm_get_mpu_clk_hz() / 1000); +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0045-DW-SPI-Get-clock-value-from-Device-Tree.patch b/board/synopsys/hsdk/uboot-patches/0045-DW-SPI-Get-clock-value-from-Device-Tree.patch new file mode 100644 index 00000000000..121252b9f55 --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0045-DW-SPI-Get-clock-value-from-Device-Tree.patch @@ -0,0 +1,114 @@ +From 90f119b4dbbcd10fe890a6fbad3e0cf361c57182 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Mon, 25 Sep 2017 19:04:54 +0300 +Subject: [PATCH 45/46] DW SPI: Get clock value from Device Tree + +Add option to set spi controller clock frequency via device tree +using standard clock bindings. + +Define dw_spi_get_clk function as 'weak' as some targets +(like SOCFPGA_GEN5 and SOCFPGA_ARRIA10) fon't use standard clock API +and implement dw_spi_get_clk their own way in their clock manager. + +Get rid of clock_manager.h include as we don't use +cm_get_spi_controller_clk_hz function anymore. (we use redefined +dw_spi_get_clk in SOCFPGA clock managers instead) + +Signed-off-by: Eugeniy Paltsev +--- + drivers/spi/designware_spi.c | 43 +++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 41 insertions(+), 2 deletions(-) + +diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c +index 6cc4f51a1f..4830af883c 100644 +--- a/drivers/spi/designware_spi.c ++++ b/drivers/spi/designware_spi.c +@@ -12,6 +12,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -19,7 +20,6 @@ + #include + #include + #include +-#include + + DECLARE_GLOBAL_DATA_PTR; + +@@ -95,6 +95,8 @@ struct dw_spi_priv { + void __iomem *regs; + unsigned int freq; /* Default frequency */ + unsigned int mode; ++ struct clk clk; ++ unsigned long bus_clk_rate; + + struct gpio_desc cs_gpio; /* External chip-select gpio */ + +@@ -195,14 +197,51 @@ static void spi_hw_init(struct dw_spi_priv *priv) + debug("%s: fifo_len=%d\n", __func__, priv->fifo_len); + } + ++/* ++ * We define dw_spi_get_clk function as 'weak' as some targets ++ * (like SOCFPGA_GEN5 and SOCFPGA_ARRIA10) fon't use standard clock API ++ * and implement dw_spi_get_clk their own way in their clock manager. ++ */ ++__weak int dw_spi_get_clk(struct udevice *bus, ulong *rate) ++{ ++ struct dw_spi_priv *priv = dev_get_priv(bus); ++ int ret; ++ ++ ret = clk_get_by_index(bus, 0, &priv->clk); ++ if (ret) ++ return -EINVAL; ++ ++ ret = clk_enable(&priv->clk); ++ if (ret && ret != -ENOSYS && ret != -ENOSYS && ret != -ENOTSUPP) ++ return ret; ++ ++ *rate = clk_get_rate(&priv->clk); ++ if (!*rate) { ++ clk_disable(&priv->clk); ++ return -EINVAL; ++ } ++ ++ debug("%s: get spi controller clk via device tree: %lu Hz\n", ++ __func__, *rate); ++ ++ clk_free(&priv->clk); ++ ++ return 0; ++} ++ + static int dw_spi_probe(struct udevice *bus) + { + struct dw_spi_platdata *plat = dev_get_platdata(bus); + struct dw_spi_priv *priv = dev_get_priv(bus); ++ int ret; + + priv->regs = plat->regs; + priv->freq = plat->frequency; + ++ ret = dw_spi_get_clk(bus, &priv->bus_clk_rate); ++ if (ret) ++ return ret; ++ + /* Currently only bits_per_word == 8 supported */ + priv->bits_per_word = 8; + +@@ -411,7 +450,7 @@ static int dw_spi_set_speed(struct udevice *bus, uint speed) + spi_enable_chip(priv, 0); + + /* clk_div doesn't support odd number */ +- clk_div = cm_get_spi_controller_clk_hz() / speed; ++ clk_div = priv->bus_clk_rate / speed; + clk_div = (clk_div + 1) & 0xfffe; + dw_write(priv, DW_SPI_BAUDR, clk_div); + +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0046-ARc-HSDK-update-defconfig.patch b/board/synopsys/hsdk/uboot-patches/0046-ARc-HSDK-update-defconfig.patch new file mode 100644 index 00000000000..34868aac8a1 --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0046-ARc-HSDK-update-defconfig.patch @@ -0,0 +1,47 @@ +From 5f989f7efb78f63b6d31d6f5a6fa98da866a1f75 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Fri, 22 Dec 2017 15:46:28 +0300 +Subject: [PATCH 46/46] ARc: HSDK: update defconfig + +Signed-off-by: Eugeniy Paltsev +--- + configs/hsdk_defconfig | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/configs/hsdk_defconfig b/configs/hsdk_defconfig +index c2cea0a2c3..b8978e25f2 100644 +--- a/configs/hsdk_defconfig ++++ b/configs/hsdk_defconfig +@@ -6,9 +6,13 @@ 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 +@@ -16,6 +20,7 @@ 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 +@@ -27,6 +32,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_DM_GPIO=y + CONFIG_HSDK_CREG_GPIO=y + CONFIG_MMC=y +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0047-ARC-HSDK-patch-linux-dtb-according-to-core_mask.patch b/board/synopsys/hsdk/uboot-patches/0047-ARC-HSDK-patch-linux-dtb-according-to-core_mask.patch new file mode 100644 index 00000000000..80a4332074b --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0047-ARC-HSDK-patch-linux-dtb-according-to-core_mask.patch @@ -0,0 +1,79 @@ +From effcd70a980b8c4d6f4d82d04b79972832863267 Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Fri, 22 Dec 2017 19:37:14 +0300 +Subject: [PATCH 1/2] ARC: HSDK: patch linux dtb according to core_mask + +Patch cpus 'status' property in linux dtb according to core_mask + +Signed-off-by: Eugeniy Paltsev +--- + board/synopsys/hsdk/hsdk-cmd.c | 26 +++++++++++++++++++++++++- + 1 file changed, 25 insertions(+), 1 deletion(-) + +diff --git a/board/synopsys/hsdk/hsdk-cmd.c b/board/synopsys/hsdk/hsdk-cmd.c +index b706901d6c..c2d5ab0afa 100644 +--- a/board/synopsys/hsdk/hsdk-cmd.c ++++ b/board/synopsys/hsdk/hsdk-cmd.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + + + #ifdef CONFIG_CPU_BIG_ENDIAN +@@ -20,6 +21,7 @@ + + /* TODO: move to common config */ + #define NR_CPUS 4 ++#define ALL_CPU_MASK 0xF /* GENMASK(NR_CPUS, 0) */ + #define MASTER_CPU 0 + #define MAX_CMD_LEN 25 + #define HZ_IN_MHZ 1000000 +@@ -936,7 +938,9 @@ static int hsdk_go_run(u32 cpu_start_reg) + + int board_prep_linux(bootm_headers_t *images) + { ++ u32 i; + int ret; ++ char dt_cpu_path[30]; + + ret = env_read_validate_common(env_map_mask); + if (ret) +@@ -944,12 +948,32 @@ int board_prep_linux(bootm_headers_t *images) + + /* Rollback to default values */ + if (!env_common.core_mask.set) { +- env_common.core_mask.val = 0xF; ++ 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)) ++ pr_err("ERR: try to launch linux with CPU[0] disabled! It doesn't work for ARC.\n"); ++ ++ if (!IMAGE_ENABLE_OF_LIBFDT || !images->ft_len) { ++ if (env_common.core_mask.val != ALL_CPU_MASK) { ++ pr_err("WARN: core_mask setup will work properly only with external DTB!\n"); ++ ++ return 0; ++ } ++ } ++ ++ for (i = 0; i < NR_CPUS; i++) { ++ if (!is_cpu_used(i)) { ++ sprintf(dt_cpu_path, "/cpus/cpu@%u", i); ++ ret = fdt_status_disabled_by_alias(images->ft_addr, dt_cpu_path); ++ debug("patched '%s' node status: ret=%d%s\n", dt_cpu_path, ++ ret, ret == 0 ? "(OK)" : ""); ++ } ++ } ++ + return 0; + } + +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0048-ARC-HSDK-fixies-in-CL-arg-parser.patch b/board/synopsys/hsdk/uboot-patches/0048-ARC-HSDK-fixies-in-CL-arg-parser.patch new file mode 100644 index 00000000000..cdf0ab9bcb8 --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0048-ARC-HSDK-fixies-in-CL-arg-parser.patch @@ -0,0 +1,44 @@ +From 52dadcf3f623975a8de5a00ab9404102550872bd Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Fri, 22 Dec 2017 19:38:51 +0300 +Subject: [PATCH 2/2] ARC: HSDK: fixies in CL arg parser + +Signed-off-by: Eugeniy Paltsev +--- + board/synopsys/hsdk/hsdk-cmd.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/board/synopsys/hsdk/hsdk-cmd.c b/board/synopsys/hsdk/hsdk-cmd.c +index c2d5ab0afa..5d8f456a80 100644 +--- a/board/synopsys/hsdk/hsdk-cmd.c ++++ b/board/synopsys/hsdk/hsdk-cmd.c +@@ -208,7 +208,7 @@ static int env_read_common(u32 index, const struct hsdk_env_map_common *map) + return 0; + } + +-static int env_clear_core(u32 index, const struct hsdk_env_map_core *map) ++static void env_clear_core(u32 index, const struct hsdk_env_map_core *map) + { + u32 i; + +@@ -1093,6 +1093,8 @@ static int hsdk_read_args_search(const struct hsdk_env_map_common *map, int argc + return i; + } + ++ pr_err("Unexpected argument '%s', can't parse\n", argv[0]); ++ + return -ENOENT; + } + +@@ -1128,6 +1130,8 @@ static int hsdk_args_enumerate(const struct hsdk_env_map_common *map, int enum_b + + while (argc > 0) { + i = hsdk_read_args_search(map, argc, argv); ++ if (i < 0) ++ return i; + + // printf("PAL: %s: found '%s' with index %d\n", __func__, map[i].env_name, i); + +-- +2.11.0 + diff --git a/board/synopsys/hsdk/uboot-patches/0049-ARC-HSDK-USB-disable-USB-init.patch b/board/synopsys/hsdk/uboot-patches/0049-ARC-HSDK-USB-disable-USB-init.patch new file mode 100644 index 00000000000..77f3d6016ce --- /dev/null +++ b/board/synopsys/hsdk/uboot-patches/0049-ARC-HSDK-USB-disable-USB-init.patch @@ -0,0 +1,25 @@ +From afc2a95abd55053d224a97806b3417ada22f3ebe Mon Sep 17 00:00:00 2001 +From: Eugeniy Paltsev +Date: Fri, 22 Dec 2017 21:19:36 +0300 +Subject: [PATCH] ARC: HSDK: USB: disable USB init + +Disable default USB init as it break USB work in linux + +Signed-off-by: Eugeniy Paltsev +--- + board/synopsys/hsdk/hsdk.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/board/synopsys/hsdk/hsdk.c b/board/synopsys/hsdk/hsdk.c +index c20f00c2bf..b2f9ef3cae 100644 +--- a/board/synopsys/hsdk/hsdk.c ++++ b/board/synopsys/hsdk/hsdk.c +@@ -62,7 +62,7 @@ int board_mmc_init(bd_t *bis) + int board_early_init_r(void) + { + /* Init USB to be able read environment from USB MSD */ +- usb_init(); ++ /* usb_init(); */ /* Temporary disable init as it break usb in linux */ + + return 0; + } diff --git a/board/synopsys/hsdk/uboot.env.txt b/board/synopsys/hsdk/uboot.env.txt index 6bcfb56a77f..7f7d8f5703f 100644 --- a/board/synopsys/hsdk/uboot.env.txt +++ b/board/synopsys/hsdk/uboot.env.txt @@ -1,9 +1,31 @@ baudrate=115200 -bootargs=console=ttyS3,115200n8 root=/dev/mmcblk0p2 rootwait -bootcmd=fatload mmc 0:1; bootm +bootargs=console=ttyS0,115200n8 root=/dev/mmcblk0p2 rootwait +bootcmd=fatload mmc 0:1 0x82000000 uImage && fatload mmc 0:1 0x81000000 hsdk.dtb && bootm 0x82000000 - 0x81000000 bootdelay=2 bootfile=uImage loadaddr=0x82000000 stderr=serial0@f0005000 stdin=serial0@f0005000 stdout=serial0@f0005000 + +core_dccm_0=0x10 +core_dccm_1=0x6 +core_dccm_2=0x10 +core_dccm_3=0x6 +core_iccm_0=0x10 +core_iccm_1=0x6 +core_iccm_2=0x10 +core_iccm_3=0x6 +core_mask=0xF +dcache_ena=0x1 +icache_ena=0x1 +non_volatile_limit=0xE + +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; +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; +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; +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; +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; +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; +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; +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; diff --git a/boot/uboot/uboot.mk b/boot/uboot/uboot.mk index a1fac7dcaea..ca03c4971c4 100644 --- a/boot/uboot/uboot.mk +++ b/boot/uboot/uboot.mk @@ -40,6 +40,14 @@ ifeq ($(BR2_TARGET_UBOOT_FORMAT_BIN),y) UBOOT_BINS += u-boot.bin endif +#Building u-boot files for hsdk requires host-python3 +ifeq ($(BR2_arc),y) +ifeq ($(BR2_TARGET_UBOOT_BOARD_DEFCONFIG),"hsdk") +UBOOT_DEPENDENCIES += host-python3 +endif +endif + + ifeq ($(BR2_TARGET_UBOOT_FORMAT_ELF),y) UBOOT_BINS += u-boot # To make elf usable for debuging on ARC use special target diff --git a/configs/snps_hsdk_defconfig b/configs/snps_hsdk_defconfig index 1f699f5e8c3..add7c94e489 100644 --- a/configs/snps_hsdk_defconfig +++ b/configs/snps_hsdk_defconfig @@ -3,7 +3,12 @@ BR2_arcle=y BR2_archs38=y #Linux headers -BR2_KERNEL_HEADERS_4_14=y +BR2_KERNEL_HEADERS_4_13=y + +#Toolchain +BR2_TOOLCHAIN_BUILDROOT_WCHAR=y +BR2_PTHREAD_DEBUG=y +BR2_TOOLCHAIN_BUILDROOT_CXX=y #System BR2_TARGET_GENERIC_HOSTNAME="hsdk" @@ -13,9 +18,12 @@ BR2_SYSTEM_DHCP="eth0" #Kernel BR2_LINUX_KERNEL=y BR2_LINUX_KERNEL_CUSTOM_VERSION=y -BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="4.14.4" +BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="4.14.7" +BR2_LINUX_KERNEL_PATCH="board/synopsys/hsdk/linux-patches" BR2_LINUX_KERNEL_DEFCONFIG="hsdk" BR2_LINUX_KERNEL_CONFIG_FRAGMENT_FILES="board/synopsys/hsdk/linux.fragment" +BR2_LINUX_KERNEL_DTS_SUPPORT=y +BR2_LINUX_KERNEL_INTREE_DTS_NAME="hsdk" #Filesystem / image BR2_TARGET_ROOTFS_EXT2=y @@ -31,9 +39,24 @@ BR2_TARGET_UBOOT=y BR2_TARGET_UBOOT_BUILD_SYSTEM_KCONFIG=y BR2_TARGET_UBOOT_CUSTOM_VERSION=y BR2_TARGET_UBOOT_CUSTOM_VERSION_VALUE="2017.11" +BR2_TARGET_UBOOT_PATCH="board/synopsys/hsdk/uboot-patches" BR2_TARGET_UBOOT_BOARD_DEFCONFIG="hsdk" BR2_TARGET_UBOOT_NEEDS_DTC=y BR2_TARGET_UBOOT_FORMAT_ELF=y -BR2_TARGET_UBOOT_ENVIMAGE=y -BR2_TARGET_UBOOT_ENVIMAGE_SOURCE="board/synopsys/hsdk/uboot.env.txt" -BR2_TARGET_UBOOT_ENVIMAGE_SIZE="0x4000" + +#Packages +BR2_PACKAGE_LINUX_TOOLS_PERF=y +BR2_PACKAGE_MPLAYER=y +BR2_PACKAGE_BONNIE=y +BR2_PACKAGE_GDB=y +BR2_PACKAGE_GDB_SERVER=y +BR2_PACKAGE_GDB_DEBUGGER=y +BR3_PACKAGE_RT_TESTS=y +BR2_PACKAGE_CHOCOLATE_DOOM=y +BR2_PACKAGE_DOOM_WAD=y +BR2_PACKAGE_FB_TEST_APP=y +BR2_PACKAGE_IFTOP=y +BR2_PACKAGE_IPERF3=y +BR2_PACKAGE_OPENSSH=y +BR2_PACKAGE_HTOP=y +