]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
arm: add mach-nexell (all files except header files)
authorStefan Bosch <stefan_b@posteo.net>
Fri, 10 Jul 2020 17:07:26 +0000 (19:07 +0200)
committerTom Rini <trini@konsulko.com>
Wed, 29 Jul 2020 12:43:40 +0000 (08:43 -0400)
Changes in relation to FriendlyARM's U-Boot nanopi2-v2016.01:
- SPL not supported yet --> no spl-directory in arch/arm/mach-nexell.
  Appropriate line in Makefile removed.
- clock.c: 'section(".data")' added to declaration of clk_periphs[] and
  core_hz.
- Kconfig: Changes to have a structure like in mach-bcm283x/Kconfig,
  e.g. "config ..." entries moved from other Kconfig.
- timer.c: 'section(".data")' added to declaration of timestamp and
  lastdec.
- arch/arm/mach-nexell/serial.c removed because this is for the UARTs
  of the S5P6818 SoC which is not supported yet. S5P4418 UARTs are
  different, here the (existing) PL011-code is used.
- '#ifdef CONFIG...' changed to 'if (IS_ENABLED(CONFIG...))' where
  possible (and similar).

Signed-off-by: Stefan Bosch <stefan_b@posteo.net>
13 files changed:
arch/arm/Kconfig
arch/arm/Makefile
arch/arm/mach-nexell/Kconfig [new file with mode: 0644]
arch/arm/mach-nexell/Makefile [new file with mode: 0644]
arch/arm/mach-nexell/clock.c [new file with mode: 0644]
arch/arm/mach-nexell/cmd_boot_linux.c [new file with mode: 0644]
arch/arm/mach-nexell/config.mk [new file with mode: 0644]
arch/arm/mach-nexell/nx_gpio.c [new file with mode: 0644]
arch/arm/mach-nexell/nx_sec_reg.c [new file with mode: 0644]
arch/arm/mach-nexell/reg-call.S [new file with mode: 0644]
arch/arm/mach-nexell/reset.c [new file with mode: 0644]
arch/arm/mach-nexell/tieoff.c [new file with mode: 0644]
arch/arm/mach-nexell/timer.c [new file with mode: 0644]

index f951dca0071c513c09a6817d61af86abc6a4f3ae..ded8cfee094bed52e4af6a4db16f63f6c843926e 100644 (file)
@@ -916,6 +916,11 @@ config ARCH_MX5
        select CPU_V7A
        imply MXC_GPIO
 
+config ARCH_NEXELL
+       bool "Nexell S5P4418/S5P6818 SoC"
+       select ENABLE_ARM_SOC_BOOT0_HOOK
+       select DM
+
 config ARCH_OWL
        bool "Actions Semi OWL SoCs"
        select DM
@@ -1892,6 +1897,8 @@ source "arch/arm/cpu/armv8/Kconfig"
 
 source "arch/arm/mach-imx/Kconfig"
 
+source "arch/arm/mach-nexell/Kconfig"
+
 source "board/bosch/shc/Kconfig"
 source "board/bosch/guardian/Kconfig"
 source "board/CarMediaLab/flea3/Kconfig"
index a20b82bc8d5c5c0896c834a93411cc30f805aba2..bf3890e99bf8ff98f5fb59c27ab5054a62a129d2 100644 (file)
@@ -66,6 +66,7 @@ machine-$(CONFIG_ARCH_LPC32XX)                += lpc32xx
 machine-$(CONFIG_ARCH_MEDIATEK)                += mediatek
 machine-$(CONFIG_ARCH_MESON)           += meson
 machine-$(CONFIG_ARCH_MVEBU)           += mvebu
+machine-$(CONFIG_ARCH_NEXELL)          += nexell
 machine-$(CONFIG_ARCH_OMAP2PLUS)       += omap2
 machine-$(CONFIG_ARCH_ORION5X)         += orion5x
 machine-$(CONFIG_ARCH_OWL)             += owl
diff --git a/arch/arm/mach-nexell/Kconfig b/arch/arm/mach-nexell/Kconfig
new file mode 100644 (file)
index 0000000..ffa4d48
--- /dev/null
@@ -0,0 +1,58 @@
+if ARCH_NEXELL
+
+config ARCH_S5P4418
+       bool "Nexell S5P4418 SoC"
+       select CPU_V7A
+       select OF_CONTROL
+       select OF_SEPARATE
+       select NX_GPIO
+       select PL011_SERIAL
+       select PL011_SERIAL_FLUSH_ON_INIT
+       help
+         Enable support for Nexell S5P4418 SoC.
+
+config ARCH_S5P6818
+       bool "Nexell S5P6818 SoC"
+       select ARM64
+       select ARMV8_MULTIENTRY
+       help
+         Enable support for Nexell S5P6818 SoC.
+
+menu "Nexell S5P4418/S5P6818"
+       depends on ARCH_NEXELL
+
+choice
+       prompt "Nexell S5P4418/S5P6818 board select"
+       optional
+
+config TARGET_NANOPI2
+       bool "FriendlyARM NanoPi2 / NanoPC-T2 Board"
+       select ARCH_S5P4418
+       help
+         Enable support for FriendlyARM NanoPi2 and NanoPC-T2 Boards.
+
+endchoice
+
+config SYS_BOARD
+       default "nanopi2"
+
+config SYS_VENDOR
+       default "friendlyarm"
+
+config SYS_SOC
+       default "nexell"
+
+config SYS_CONFIG_NAME
+       default "s5p4418_nanopi2"
+
+endmenu
+
+config SYS_PLLFIN
+       int
+
+config TIMER_SYS_TICK_CH
+       int
+
+source "board/friendlyarm/Kconfig"
+
+endif
diff --git a/arch/arm/mach-nexell/Makefile b/arch/arm/mach-nexell/Makefile
new file mode 100644 (file)
index 0000000..10b3963
--- /dev/null
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2016 Nexell
+# Hyunseok, Jung <hsjung@nexell.co.kr>
+
+obj-y                          += clock.o
+obj-y                          += timer.o
+obj-y                          += reset.o
+obj-y                          += nx_gpio.o
+obj-y                          += tieoff.o
+obj-$(CONFIG_ARCH_S5P4418)     += reg-call.o
+obj-$(CONFIG_ARCH_S5P4418)     += nx_sec_reg.o
+obj-$(CONFIG_CMD_BOOTL)                += cmd_boot_linux.o
diff --git a/arch/arm/mach-nexell/clock.c b/arch/arm/mach-nexell/clock.c
new file mode 100644 (file)
index 0000000..a0ba2d8
--- /dev/null
@@ -0,0 +1,869 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016 Nexell
+ * Hyunseok, Jung <hsjung@nexell.co.kr>
+ */
+
+#include <common.h>
+#include <command.h>
+#include <linux/err.h>
+#include <asm/io.h>
+#include <asm/arch/nexell.h>
+#include <asm/arch/clk.h>
+
+/*
+ * clock generator macros
+ */
+#define        I_PLL0_BIT              (0)
+#define        I_PLL1_BIT              (1)
+#define        I_PLL2_BIT              (2)
+#define        I_PLL3_BIT              (3)
+#define        I_EXT1_BIT              (4)
+#define        I_EXT2_BIT              (5)
+#define        I_CLKn_BIT              (7)
+#define        I_EXT1_BIT_FORCE        (8)
+#define        I_EXT2_BIT_FORCE        (9)
+
+#define        I_CLOCK_NUM             6 /* PLL0, PLL1, PLL2, PLL3, EXT1, EXT2 */
+
+#define I_EXECEPT_CLK          (0)
+#define        I_CLOCK_MASK            (((1 << I_CLOCK_NUM) - 1) & ~I_EXECEPT_CLK)
+
+#define        I_PLL0                  (1 << I_PLL0_BIT)
+#define        I_PLL1                  (1 << I_PLL1_BIT)
+#define        I_PLL2                  (1 << I_PLL2_BIT)
+#define        I_PLL3                  (1 << I_PLL3_BIT)
+#define        I_EXTCLK1               (1 << I_EXT1_BIT)
+#define        I_EXTCLK2               (1 << I_EXT2_BIT)
+#define        I_EXTCLK1_FORCE         (1 << I_EXT1_BIT_FORCE)
+#define        I_EXTCLK2_FORCE         (1 << I_EXT2_BIT_FORCE)
+
+#define        I_PLL_0_1               (I_PLL0    | I_PLL1)
+#define        I_PLL_0_2               (I_PLL_0_1 | I_PLL2)
+#define        I_PLL_0_3               (I_PLL_0_2 | I_PLL3)
+#define        I_CLKnOUT               (0)
+
+#define        I_PCLK                  (1 << 16)
+#define        I_BCLK                  (1 << 17)
+#define        I_GATE_PCLK             (1 << 20)
+#define        I_GATE_BCLK             (1 << 21)
+#define        I_PCLK_MASK             (I_GATE_PCLK | I_PCLK)
+#define        I_BCLK_MASK             (I_GATE_BCLK | I_BCLK)
+
+struct clk_dev_peri {
+       const char *dev_name;
+       void __iomem *base;
+       int dev_id;
+       int periph_id;
+       int clk_step;
+       u32 in_mask;
+       u32 in_mask1;
+       int div_src_0;
+       int div_val_0;
+       int invert_0;
+       int div_src_1;
+       int div_val_1;
+       int invert_1;
+       int in_extclk_1;
+       int in_extclk_2;
+};
+
+struct clk_dev {
+       struct clk  clk;
+       struct clk *link;
+       const char *name;
+       struct clk_dev_peri *peri;
+};
+
+struct clk_dev_map {
+       unsigned int con_enb;
+       unsigned int con_gen[4];
+};
+
+#define CLK_PERI_1S(name, devid, id, addr, mk)[id] = \
+       { .dev_name = name, .dev_id = devid, .periph_id = id, .clk_step = 1, \
+       .base = (void *)addr, .in_mask = mk, }
+
+#define CLK_PERI_2S(name, devid, id, addr, mk, mk2)[id] = \
+       { .dev_name = name, .dev_id = devid, .periph_id = id, .clk_step = 2, \
+       .base = (void *)addr, .in_mask = mk, .in_mask1 = mk2, }
+
+static const char * const clk_core[] = {
+       CORECLK_NAME_PLL0, CORECLK_NAME_PLL1, CORECLK_NAME_PLL2,
+       CORECLK_NAME_PLL3, CORECLK_NAME_FCLK, CORECLK_NAME_MCLK,
+       CORECLK_NAME_BCLK, CORECLK_NAME_PCLK, CORECLK_NAME_HCLK,
+};
+
+/*
+ * Section ".data" must be used because BSS is not available before relocation,
+ * in board_init_f(), respectively! I.e. global variables can not be used!
+ */
+static struct clk_dev_peri clk_periphs[]
+       __attribute__((section(".data"))) = {
+       CLK_PERI_1S(DEV_NAME_TIMER,     0,      CLK_ID_TIMER_0,
+                   PHY_BASEADDR_CLKGEN14, (I_PLL_0_2)),
+       CLK_PERI_1S(DEV_NAME_TIMER,     1,      CLK_ID_TIMER_1,
+                   PHY_BASEADDR_CLKGEN0, (I_PLL_0_2)),
+       CLK_PERI_1S(DEV_NAME_TIMER,     2,      CLK_ID_TIMER_2,
+                   PHY_BASEADDR_CLKGEN1, (I_PLL_0_2)),
+       CLK_PERI_1S(DEV_NAME_TIMER,     3,      CLK_ID_TIMER_3,
+                   PHY_BASEADDR_CLKGEN2, (I_PLL_0_2)),
+       CLK_PERI_1S(DEV_NAME_UART,      0,      CLK_ID_UART_0,
+                   PHY_BASEADDR_CLKGEN22, (I_PLL_0_2)),
+       CLK_PERI_1S(DEV_NAME_UART,      1,      CLK_ID_UART_1,
+                   PHY_BASEADDR_CLKGEN24, (I_PLL_0_2)),
+       CLK_PERI_1S(DEV_NAME_UART,      2,      CLK_ID_UART_2,
+                   PHY_BASEADDR_CLKGEN23, (I_PLL_0_2)),
+       CLK_PERI_1S(DEV_NAME_UART,      3,      CLK_ID_UART_3,
+                   PHY_BASEADDR_CLKGEN25, (I_PLL_0_2)),
+       CLK_PERI_1S(DEV_NAME_UART,      4,      CLK_ID_UART_4,
+                   PHY_BASEADDR_CLKGEN26, (I_PLL_0_2)),
+       CLK_PERI_1S(DEV_NAME_UART,      5,      CLK_ID_UART_5,
+                   PHY_BASEADDR_CLKGEN27, (I_PLL_0_2)),
+       CLK_PERI_1S(DEV_NAME_PWM,       0,      CLK_ID_PWM_0,
+                   PHY_BASEADDR_CLKGEN13, (I_PLL_0_2)),
+       CLK_PERI_1S(DEV_NAME_PWM,       1,      CLK_ID_PWM_1,
+                   PHY_BASEADDR_CLKGEN3, (I_PLL_0_2)),
+       CLK_PERI_1S(DEV_NAME_PWM,       2,      CLK_ID_PWM_2,
+                   PHY_BASEADDR_CLKGEN4, (I_PLL_0_2)),
+       CLK_PERI_1S(DEV_NAME_PWM,       3,      CLK_ID_PWM_3,
+                   PHY_BASEADDR_CLKGEN5, (I_PLL_0_2)),
+       CLK_PERI_1S(DEV_NAME_I2C,       0,      CLK_ID_I2C_0,
+                   PHY_BASEADDR_CLKGEN6, (I_GATE_PCLK)),
+       CLK_PERI_1S(DEV_NAME_I2C,       1,      CLK_ID_I2C_1,
+                   PHY_BASEADDR_CLKGEN7, (I_GATE_PCLK)),
+       CLK_PERI_1S(DEV_NAME_I2C,       2,      CLK_ID_I2C_2,
+                   PHY_BASEADDR_CLKGEN8, (I_GATE_PCLK)),
+       CLK_PERI_2S(DEV_NAME_GMAC,      0,      CLK_ID_GMAC,
+                   PHY_BASEADDR_CLKGEN10,
+                   (I_PLL_0_3 | I_EXTCLK1 | I_EXTCLK1_FORCE),
+                   (I_CLKnOUT)),
+       CLK_PERI_2S(DEV_NAME_I2S,       0,      CLK_ID_I2S_0,
+                   PHY_BASEADDR_CLKGEN15, (I_PLL_0_3 | I_EXTCLK1),
+                   (I_CLKnOUT)),
+       CLK_PERI_2S(DEV_NAME_I2S,       1,      CLK_ID_I2S_1,
+                   PHY_BASEADDR_CLKGEN16, (I_PLL_0_3 | I_EXTCLK1),
+                   (I_CLKnOUT)),
+       CLK_PERI_2S(DEV_NAME_I2S,       2,      CLK_ID_I2S_2,
+                   PHY_BASEADDR_CLKGEN17, (I_PLL_0_3 | I_EXTCLK1),
+                   (I_CLKnOUT)),
+       CLK_PERI_1S(DEV_NAME_SDHC,      0,      CLK_ID_SDHC_0,
+                   PHY_BASEADDR_CLKGEN18, (I_PLL_0_2 | I_GATE_PCLK)),
+       CLK_PERI_1S(DEV_NAME_SDHC,      1,      CLK_ID_SDHC_1,
+                   PHY_BASEADDR_CLKGEN19, (I_PLL_0_2 | I_GATE_PCLK)),
+       CLK_PERI_1S(DEV_NAME_SDHC,      2,      CLK_ID_SDHC_2,
+                   PHY_BASEADDR_CLKGEN20, (I_PLL_0_2 | I_GATE_PCLK)),
+       CLK_PERI_1S(DEV_NAME_SPI,       0,      CLK_ID_SPI_0,
+                   PHY_BASEADDR_CLKGEN37, (I_PLL_0_2)),
+       CLK_PERI_1S(DEV_NAME_SPI,       1,      CLK_ID_SPI_1,
+                   PHY_BASEADDR_CLKGEN38, (I_PLL_0_2)),
+       CLK_PERI_1S(DEV_NAME_SPI,       2,      CLK_ID_SPI_2,
+                   PHY_BASEADDR_CLKGEN39, (I_PLL_0_2)),
+};
+
+#define        CLK_PERI_NUM            ((int)ARRAY_SIZE(clk_periphs))
+#define        CLK_CORE_NUM            ((int)ARRAY_SIZE(clk_core))
+#define        CLK_DEVS_NUM            (CLK_CORE_NUM + CLK_PERI_NUM)
+#define        MAX_DIVIDER             ((1 << 8) - 1)  /* 256, align 2 */
+
+static struct clk_dev          st_clk_devs[CLK_DEVS_NUM]
+                               __attribute__((section(".data")));
+#define        clk_dev_get(n)          ((struct clk_dev *)&st_clk_devs[n])
+#define        clk_container(p)        (container_of(p, struct clk_dev, clk))
+
+/*
+ * Core frequencys
+ */
+struct _core_hz_ {
+       unsigned long pll[4];                                   /* PLL */
+       unsigned long cpu_fclk, cpu_bclk;                       /* cpu */
+       unsigned long mem_fclk, mem_dclk, mem_bclk, mem_pclk;   /* ddr */
+       unsigned long bus_bclk, bus_pclk;                       /* bus */
+#if defined(CONFIG_ARCH_S5P6818)
+       unsigned long cci4_bclk, cci4_pclk;                     /* cci */
+#endif
+       /* ip */
+       unsigned long g3d_bclk;
+       unsigned long coda_bclk, coda_pclk;
+#if defined(CONFIG_ARCH_S5P6818)
+       unsigned long disp_bclk, disp_pclk;
+       unsigned long hdmi_pclk;
+#endif
+};
+
+/*
+ * Section ".data" must be used because BSS is not available before relocation,
+ * in board_init_f(), respectively! I.e. global variables can not be used!
+ */
+/* core clock */
+static struct _core_hz_ core_hz __attribute__((section(".data")));
+
+#define        CORE_HZ_SIZE    (sizeof(core_hz) / 4)
+
+/*
+ * CLKGEN HW
+ */
+static inline void clk_dev_bclk(void *base, int on)
+{
+       struct clk_dev_map *reg = base;
+       unsigned int val = readl(&reg->con_enb) & ~(0x3);
+
+       val |= (on ? 3 : 0) & 0x3;      /* always BCLK */
+       writel(val, &reg->con_enb);
+}
+
+static inline void clk_dev_pclk(void *base, int on)
+{
+       struct clk_dev_map *reg = base;
+       unsigned int val = 0;
+
+       if (!on)
+               return;
+
+       val      = readl(&reg->con_enb) & ~(1 << 3);
+       val |= (1 << 3);
+       writel(val, &reg->con_enb);
+}
+
+static inline void clk_dev_rate(void *base, int step, int src, int div)
+{
+       struct clk_dev_map *reg = base;
+       unsigned int val = 0;
+
+       val  = readl(&reg->con_gen[step << 1]);
+       val &= ~(0x07   << 2);
+       val |=  (src    << 2);  /* source */
+       val     &= ~(0xFF   << 5);
+       val     |=  (div - 1) << 5;     /* divider */
+       writel(val, &reg->con_gen[step << 1]);
+}
+
+static inline void clk_dev_inv(void *base, int step, int inv)
+{
+       struct clk_dev_map *reg = base;
+       unsigned int val = readl(&reg->con_gen[step << 1]) & ~(1 << 1);
+
+       val     |= (inv << 1);
+       writel(val, &reg->con_gen[step << 1]);
+}
+
+static inline void clk_dev_enb(void *base, int on)
+{
+       struct clk_dev_map *reg = base;
+       unsigned int val = readl(&reg->con_enb) & ~(1 << 2);
+
+       val     |= ((on ? 1 : 0) << 2);
+       writel(val, &reg->con_enb);
+}
+
+/*
+ * CORE FREQUENCY
+ *
+ * PLL0 [P,M,S]        ------- | | ----- [DIV0] --- CPU-G0
+ *                     |M| ----- [DIV1] --- BCLK/PCLK
+ * PLL1 [P,M,S]        ------- | | ----- [DIV2] --- DDR
+ *                     |U| ----- [DIV3] --- 3D
+ * PLL2 [P,M,S,K]-------| | ----- [DIV4] --- CODA
+ *                     |X| ----- [DIV5] --- DISPLAY
+ * PLL3 [P,M,S,K]-------| | ----- [DIV6] --- HDMI
+ *                     | | ----- [DIV7] --- CPU-G1
+ *                     | | ----- [DIV8] --- CCI-400(FASTBUS)
+ *
+ */
+
+struct nx_clkpwr_registerset {
+       u32 clkmodereg0;        /* 0x000 : Clock Mode Register0 */
+       u32 __reserved0;        /* 0x004 */
+       u32 pllsetreg[4];       /* 0x008 ~ 0x014 : PLL Setting Register */
+       u32 __reserved1[2];     /* 0x018 ~ 0x01C */
+       u32 dvoreg[9];          /* 0x020 ~ 0x040 : Divider Setting Register */
+       u32 __Reserved2;        /* 0x044 */
+       u32 pllsetreg_sscg[6];  /* 0x048 ~ 0x05C */
+       u32 __reserved3[8];             /* 0x060 ~ 0x07C */
+       u8 __reserved4[0x200 - 0x80];   /* padding (0x80 ~ 0x1FF) */
+       u32 gpiowakeupriseenb;  /* 0x200 : GPIO Rising Edge Detect En. Reg. */
+       u32 gpiowakeupfallenb;  /* 0x204 : GPIO Falling Edge Detect En. Reg. */
+       u32 gpiorstenb;         /* 0x208 : GPIO Reset Enable Register */
+       u32 gpiowakeupenb;      /* 0x20C : GPIO Wakeup Source Enable */
+       u32 gpiointenb;         /* 0x210 : Interrupt Enable Register */
+       u32 gpiointpend;        /* 0x214 : Interrupt Pend Register */
+       u32 resetstatus;        /* 0x218 : Reset Status Register */
+       u32 intenable;          /* 0x21C : Interrupt Enable Register */
+       u32 intpend;            /* 0x220 : Interrupt Pend Register */
+       u32 pwrcont;            /* 0x224 : Power Control Register */
+       u32 pwrmode;            /* 0x228 : Power Mode Register */
+       u32 __reserved5;        /* 0x22C : Reserved Region */
+       u32 scratch[3];         /* 0x230 ~ 0x238 : Scratch Register */
+       u32 sysrstconfig;       /* 0x23C : System Reset Configuration Reg. */
+       u8  __reserved6[0x2A0 - 0x240]; /* padding (0x240 ~ 0x29F) */
+       u32 cpupowerdownreq;    /* 0x2A0 : CPU Power Down Request Register */
+       u32 cpupoweronreq;      /* 0x2A4 : CPU Power On Request Register */
+       u32 cpuresetmode;       /* 0x2A8 : CPU Reset Mode Register */
+       u32 cpuwarmresetreq;    /* 0x2AC : CPU Warm Reset Request Register */
+       u32 __reserved7;        /* 0x2B0 */
+       u32 cpustatus;          /* 0x2B4 : CPU Status Register */
+       u8  __reserved8[0x400 - 0x2B8]; /* padding (0x2B8 ~ 0x33F) */
+};
+
+static struct nx_clkpwr_registerset * const clkpwr =
+       (struct nx_clkpwr_registerset *)PHY_BASEADDR_CLKPWR;
+
+#define        getquotient(v, d)       ((v) / (d))
+
+#define        DIV_CPUG0       0
+#define        DIV_BUS         1
+#define        DIV_MEM         2
+#define        DIV_G3D         3
+#define        DIV_CODA        4
+#if defined(CONFIG_ARCH_S5P6818)
+#define        DIV_DISP        5
+#define        DIV_HDMI        6
+#define        DIV_CPUG1       7
+#define        DIV_CCI4        8
+#endif
+
+#define        DVO0            3
+#define        DVO1            9
+#define        DVO2            15
+#define        DVO3            21
+
+static unsigned int pll_rate(unsigned int plln, unsigned int xtal)
+{
+       unsigned int val, val1, nP, nM, nS, nK;
+       unsigned int temp = 0;
+
+       val   = clkpwr->pllsetreg[plln];
+       val1  = clkpwr->pllsetreg_sscg[plln];
+       xtal /= 1000;   /* Unit Khz */
+
+       nP = (val >> 18) & 0x03F;
+       nM = (val >>  8) & 0x3FF;
+       nS = (val >>  0) & 0x0FF;
+       nK = (val1 >> 16) & 0xFFFF;
+
+       if (plln > 1 && nK) {
+               temp = (unsigned int)(getquotient((getquotient((nK * 1000),
+                       65536) * xtal), nP) >> nS);
+       }
+
+       temp = (unsigned int)((getquotient((nM * xtal), nP) >> nS) * 1000)
+              + temp;
+       return temp;
+}
+
+static unsigned int pll_dvo(int dvo)
+{
+       unsigned int val;
+
+       val = (clkpwr->dvoreg[dvo] & 0x7);
+       return val;
+}
+
+static unsigned int pll_div(int dvo)
+{
+       unsigned int val = clkpwr->dvoreg[dvo];
+
+       return  ((((val >> DVO3) & 0x3F) + 1) << 24)  |
+                       ((((val >> DVO2) & 0x3F) + 1) << 16) |
+                       ((((val >> DVO1) & 0x3F) + 1) << 8)  |
+                       ((((val >> DVO0) & 0x3F) + 1) << 0);
+}
+
+#define        PLLN_RATE(n)     (pll_rate(n, CONFIG_SYS_PLLFIN))       /* 0~ 3 */
+#define        CPU_FCLK_RATE(n) (pll_rate(pll_dvo(n), CONFIG_SYS_PLLFIN) / \
+                        ((pll_div(n) >> 0) & 0x3F))
+#define        CPU_BCLK_RATE(n) (pll_rate(pll_dvo(n), CONFIG_SYS_PLLFIN) / \
+                        ((pll_div(n) >> 0) & 0x3F) /               \
+                        ((pll_div(n) >> 8) & 0x3F))
+
+#define        MEM_FCLK_RATE()  (pll_rate(pll_dvo(DIV_MEM), CONFIG_SYS_PLLFIN) / \
+                        ((pll_div(DIV_MEM) >> 0) & 0x3F) / \
+                        ((pll_div(DIV_MEM) >> 8) & 0x3F))
+
+#define        MEM_DCLK_RATE()  (pll_rate(pll_dvo(DIV_MEM), CONFIG_SYS_PLLFIN) / \
+                        ((pll_div(DIV_MEM) >> 0) & 0x3F))
+
+#define        MEM_BCLK_RATE()  (pll_rate(pll_dvo(DIV_MEM), CONFIG_SYS_PLLFIN) / \
+                        ((pll_div(DIV_MEM) >> 0) & 0x3F) / \
+                        ((pll_div(DIV_MEM) >> 8) & 0x3F) / \
+                        ((pll_div(DIV_MEM) >> 16) & 0x3F))
+#define        MEM_PCLK_RATE()  (pll_rate(pll_dvo(DIV_MEM), CONFIG_SYS_PLLFIN) / \
+                        ((pll_div(DIV_MEM) >> 0) & 0x3F) / \
+                        ((pll_div(DIV_MEM) >> 8) & 0x3F) / \
+                        ((pll_div(DIV_MEM) >> 16) & 0x3F) / \
+                        ((pll_div(DIV_MEM) >> 24) & 0x3F))
+
+#define        BUS_BCLK_RATE()  (pll_rate(pll_dvo(DIV_BUS), CONFIG_SYS_PLLFIN) / \
+                        ((pll_div(DIV_BUS) >> 0) & 0x3F))
+#define        BUS_PCLK_RATE()  (pll_rate(pll_dvo(DIV_BUS), CONFIG_SYS_PLLFIN) / \
+                        ((pll_div(DIV_BUS) >> 0) & 0x3F) / \
+                        ((pll_div(DIV_BUS) >> 8) & 0x3F))
+
+#define        G3D_BCLK_RATE()  (pll_rate(pll_dvo(DIV_G3D), CONFIG_SYS_PLLFIN) / \
+                        ((pll_div(DIV_G3D) >> 0) & 0x3F))
+
+#define        MPG_BCLK_RATE()  (pll_rate(pll_dvo(DIV_CODA), CONFIG_SYS_PLLFIN) / \
+                        ((pll_div(DIV_CODA) >> 0) & 0x3F))
+#define        MPG_PCLK_RATE()  (pll_rate(pll_dvo(DIV_CODA), CONFIG_SYS_PLLFIN) / \
+                        ((pll_div(DIV_CODA) >> 0) & 0x3F)      / \
+                        ((pll_div(DIV_CODA) >> 8) & 0x3F))
+
+#if defined(CONFIG_ARCH_S5P6818)
+#define        DISP_BCLK_RATE() (pll_rate(pll_dvo(DIV_DISP), CONFIG_SYS_PLLFIN) / \
+                        ((pll_div(DIV_DISP) >> 0) & 0x3F))
+#define        DISP_PCLK_RATE() (pll_rate(pll_dvo(DIV_DISP), CONFIG_SYS_PLLFIN) / \
+                        ((pll_div(DIV_DISP) >> 0) & 0x3F)      / \
+                        ((pll_div(DIV_DISP) >> 8) & 0x3F))
+
+#define        HDMI_PCLK_RATE() (pll_rate(pll_dvo(DIV_HDMI), CONFIG_SYS_PLLFIN) / \
+                        ((pll_div(DIV_HDMI) >> 0) & 0x3F))
+
+#define        CCI4_BCLK_RATE() (pll_rate(pll_dvo(DIV_CCI4), CONFIG_SYS_PLLFIN) / \
+                        ((pll_div(DIV_CCI4) >> 0) & 0x3F))
+#define        CCI4_PCLK_RATE() (pll_rate(pll_dvo(DIV_CCI4), CONFIG_SYS_PLLFIN) / \
+                        ((pll_div(DIV_CCI4) >> 0) & 0x3F)      / \
+                        ((pll_div(DIV_CCI4) >> 8) & 0x3F))
+#endif
+
+static void core_update_rate(int type)
+{
+       switch (type) {
+       case  0:
+               core_hz.pll[0] = PLLN_RATE(0); break;
+       case  1:
+               core_hz.pll[1] = PLLN_RATE(1); break;
+       case  2:
+               core_hz.pll[2] = PLLN_RATE(2); break;
+       case  3:
+               core_hz.pll[3] = PLLN_RATE(3); break;
+       case  4:
+               core_hz.cpu_fclk = CPU_FCLK_RATE(DIV_CPUG0); break;
+       case  5:
+               core_hz.mem_fclk = MEM_FCLK_RATE(); break;
+       case  6:
+               core_hz.bus_bclk = BUS_BCLK_RATE(); break;
+       case  7:
+               core_hz.bus_pclk = BUS_PCLK_RATE(); break;
+       case  8:
+               core_hz.cpu_bclk = CPU_BCLK_RATE(DIV_CPUG0); break;
+       case  9:
+               core_hz.mem_dclk = MEM_DCLK_RATE(); break;
+       case 10:
+               core_hz.mem_bclk = MEM_BCLK_RATE(); break;
+       case 11:
+               core_hz.mem_pclk = MEM_PCLK_RATE(); break;
+       case 12:
+               core_hz.g3d_bclk = G3D_BCLK_RATE(); break;
+       case 13:
+               core_hz.coda_bclk = MPG_BCLK_RATE(); break;
+       case 14:
+               core_hz.coda_pclk = MPG_PCLK_RATE(); break;
+#if defined(CONFIG_ARCH_S5P6818)
+       case 15:
+               core_hz.disp_bclk = DISP_BCLK_RATE(); break;
+       case 16:
+               core_hz.disp_pclk = DISP_PCLK_RATE(); break;
+       case 17:
+               core_hz.hdmi_pclk = HDMI_PCLK_RATE(); break;
+       case 18:
+               core_hz.cci4_bclk = CCI4_BCLK_RATE(); break;
+       case 19:
+               core_hz.cci4_pclk = CCI4_PCLK_RATE(); break;
+#endif
+       };
+}
+
+static unsigned long core_get_rate(int type)
+{
+       unsigned long rate = 0;
+
+       switch (type) {
+       case  0:
+               rate = core_hz.pll[0];          break;
+       case  1:
+               rate = core_hz.pll[1];          break;
+       case  2:
+               rate = core_hz.pll[2];          break;
+       case  3:
+               rate = core_hz.pll[3];          break;
+       case  4:
+               rate = core_hz.cpu_fclk;        break;
+       case  5:
+               rate = core_hz.mem_fclk;        break;
+       case  6:
+               rate = core_hz.bus_bclk;        break;
+       case  7:
+               rate = core_hz.bus_pclk;        break;
+       case  8:
+               rate = core_hz.cpu_bclk;        break;
+       case  9:
+               rate = core_hz.mem_dclk;        break;
+       case 10:
+               rate = core_hz.mem_bclk;        break;
+       case 11:
+               rate = core_hz.mem_pclk;        break;
+       case 12:
+               rate = core_hz.g3d_bclk;        break;
+       case 13:
+               rate = core_hz.coda_bclk;       break;
+       case 14:
+               rate = core_hz.coda_pclk;       break;
+#if defined(CONFIG_ARCH_S5P6818)
+       case 15:
+               rate = core_hz.disp_bclk;       break;
+       case 16:
+               rate = core_hz.disp_pclk;       break;
+       case 17:
+               rate = core_hz.hdmi_pclk;       break;
+       case 18:
+               rate = core_hz.cci4_bclk;       break;
+       case 19:
+               rate = core_hz.cci4_pclk;       break;
+#endif
+       default:
+               printf("unknown core clock type %d ...\n", type);
+               break;
+       };
+       return rate;
+}
+
+static long core_set_rate(struct clk *clk, long rate)
+{
+       return clk->rate;
+}
+
+static void core_rate_init(void)
+{
+       int i;
+
+       for (i = 0; i < CORE_HZ_SIZE; i++)
+               core_update_rate(i);
+}
+
+/*
+ * Clock Interfaces
+ */
+static inline long clk_divide(long rate, long request,
+                             int align, int *divide)
+{
+       int div = (rate / request);
+       int max = MAX_DIVIDER & ~(align - 1);
+       int adv = (div & ~(align - 1)) + align;
+       long ret;
+
+       if (!div) {
+               if (divide)
+                       *divide = 1;
+               return rate;
+       }
+
+       if (div != 1)
+               div &= ~(align - 1);
+
+       if (div != adv && abs(request - rate / div) > abs(request - rate / adv))
+               div = adv;
+
+       div = (div > max ? max : div);
+       if (divide)
+               *divide = div;
+
+       ret = rate / div;
+       return ret;
+}
+
+void clk_put(struct clk *clk)
+{
+}
+
+struct clk *clk_get(const char *id)
+{
+       struct clk_dev *cdev = clk_dev_get(0);
+       struct clk *clk = NULL;
+       const char *str = NULL, *c = NULL;
+       int i, devid;
+
+       if (id)
+               str = id;
+
+       for (i = 0; i < CLK_DEVS_NUM; i++, cdev++) {
+               if (!cdev->name)
+                       continue;
+               if (!strncmp(cdev->name, str, strlen(cdev->name))) {
+                       c = strrchr((const char *)str, (int)'.');
+                       if (!c || !cdev->peri)
+                               break;
+               devid = simple_strtoul(++c, NULL, 10);
+               if (cdev->peri->dev_id == devid)
+                       break;
+               }
+       }
+       if (i < CLK_DEVS_NUM)
+               clk = &cdev->clk;
+       else
+               clk = &(clk_dev_get(7))->clk;   /* pclk */
+
+       return clk ? clk : ERR_PTR(-ENOENT);
+}
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+       struct clk_dev *pll = NULL, *cdev = clk_container(clk);
+       struct clk_dev_peri *peri = cdev->peri;
+       unsigned long request = rate, rate_hz = 0;
+       unsigned int mask;
+       int step, div[2] = { 0, };
+       int i, n, clk2 = 0;
+       int start_src = 0, max_src = I_CLOCK_NUM;
+       short s1 = 0, s2 = 0, d1 = 0, d2 = 0;
+
+       if (!peri)
+               return core_set_rate(clk, rate);
+
+       step = peri->clk_step;
+       mask = peri->in_mask;
+       debug("clk: %s.%d request = %ld [input=0x%x]\n", peri->dev_name,
+             peri->dev_id, rate, mask);
+
+       if (!(I_CLOCK_MASK & mask)) {
+               if (I_PCLK_MASK & mask)
+                       return core_get_rate(CORECLK_ID_PCLK);
+               else if (I_BCLK_MASK & mask)
+                       return core_get_rate(CORECLK_ID_BCLK);
+               else
+                       return clk->rate;
+       }
+
+next:
+       if (peri->in_mask &  I_EXTCLK1_FORCE) {
+               start_src = 4; max_src = 5;
+       }
+       for (n = start_src ; max_src > n; n++) {
+               if (!(((mask & I_CLOCK_MASK) >> n) & 0x1))
+                       continue;
+
+               if (n == I_EXT1_BIT) {
+                       rate = peri->in_extclk_1;
+               } else if (n == I_EXT2_BIT) {
+                       rate = peri->in_extclk_2;
+               } else {
+                       pll  = clk_dev_get(n);
+                       rate = pll->clk.rate;
+               }
+
+               if (!rate)
+                       continue;
+
+               for (i = 0; step > i ; i++)
+                       rate = clk_divide(rate, request, 2, &div[i]);
+
+               if (rate_hz && (abs(rate - request) > abs(rate_hz - request)))
+                       continue;
+
+               debug("clk: %s.%d, pll.%d[%lu] request[%ld] calc[%ld]\n",
+                     peri->dev_name, peri->dev_id, n, pll->clk.rate,
+                     request, rate);
+
+               if (clk2) {
+                       s1 = -1, d1 = -1;       /* not use */
+                       s2 =  n, d2 = div[0];
+               } else {
+                       s1 = n, d1 = div[0];
+                       s2 = I_CLKn_BIT, d2 = div[1];
+               }
+               rate_hz = rate;
+       }
+
+       /* search 2th clock from input */
+       if (!clk2 && abs(rate_hz - request) &&
+           peri->in_mask1 & ((1 << I_CLOCK_NUM) - 1)) {
+               clk2 = 1;
+               mask = peri->in_mask1;
+               step = 1;
+               goto next;
+       }
+       if (peri->in_mask &  I_EXTCLK1_FORCE) {
+               if (s1 == 0) {
+                       s1 = 4; s2 = 7;
+                       d1 = 1; d2 = 1;
+               }
+       }
+
+       peri->div_src_0 = s1, peri->div_val_0 = d1;
+       peri->div_src_1 = s2, peri->div_val_1 = d2;
+       clk->rate = rate_hz;
+
+       debug("clk: %s.%d, step[%d] src[%d,%d] %ld", peri->dev_name,
+             peri->dev_id, peri->clk_step, peri->div_src_0, peri->div_src_1,
+             rate);
+       debug("/(div0: %d * div1: %d) = %ld, %ld diff (%ld)\n",
+             peri->div_val_0, peri->div_val_1, rate_hz, request,
+             abs(rate_hz - request));
+
+       return clk->rate;
+}
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+       struct clk_dev *cdev = clk_container(clk);
+
+       if (cdev->link)
+               clk = cdev->link;
+       return clk->rate;
+}
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+       struct clk_dev *cdev = clk_container(clk);
+       struct clk_dev_peri *peri = cdev->peri;
+       int i;
+
+       if (!peri)
+               return core_set_rate(clk, rate);
+
+       clk_round_rate(clk, rate);
+
+       for (i = 0; peri->clk_step > i ; i++)   {
+               int s = (i == 0 ? peri->div_src_0 : peri->div_src_1);
+               int d = (i == 0 ? peri->div_val_0 : peri->div_val_1);
+
+               if (-1 == s)
+                       continue;
+
+               clk_dev_rate(peri->base, i, s, d);
+
+               debug("clk: %s.%d (%p) set_rate [%d] src[%d] div[%d]\n",
+                     peri->dev_name, peri->dev_id, peri->base, i, s, d);
+       }
+
+       return clk->rate;
+}
+
+int clk_enable(struct clk *clk)
+{
+       struct clk_dev *cdev = clk_container(clk);
+       struct clk_dev_peri *peri = cdev->peri;
+       int i = 0, inv = 0;
+
+       if (!peri)
+               return 0;
+
+       debug("clk: %s.%d enable (BCLK=%s, PCLK=%s)\n", peri->dev_name,
+             peri->dev_id, I_GATE_BCLK & peri->in_mask ? "ON" : "PASS",
+             I_GATE_PCLK & peri->in_mask ? "ON" : "PASS");
+
+       if (!(I_CLOCK_MASK & peri->in_mask)) {
+               /* Gated BCLK/PCLK enable */
+               if (I_GATE_BCLK & peri->in_mask)
+                       clk_dev_bclk(peri->base, 1);
+
+               if (I_GATE_PCLK & peri->in_mask)
+                       clk_dev_pclk(peri->base, 1);
+
+               return 0;
+       }
+
+       /* invert */
+       inv = peri->invert_0;
+       for (; peri->clk_step > i; i++, inv = peri->invert_1)
+               clk_dev_inv(peri->base, i, inv);
+
+       /* Gated BCLK/PCLK enable */
+       if (I_GATE_BCLK & peri->in_mask)
+               clk_dev_bclk(peri->base, 1);
+
+       if (I_GATE_PCLK & peri->in_mask)
+               clk_dev_pclk(peri->base, 1);
+
+       /* restore clock rate */
+       for (i = 0; peri->clk_step > i ; i++)   {
+               int s = (i == 0 ? peri->div_src_0 : peri->div_src_1);
+               int d = (i == 0 ? peri->div_val_0 : peri->div_val_1);
+
+               if (s == -1)
+                       continue;
+               clk_dev_rate(peri->base, i, s, d);
+       }
+
+       clk_dev_enb(peri->base, 1);
+
+       return 0;
+}
+
+void clk_disable(struct clk *clk)
+{
+       struct clk_dev *cdev = clk_container(clk);
+       struct clk_dev_peri *peri = cdev->peri;
+
+       if (!peri)
+               return;
+
+       debug("clk: %s.%d disable\n", peri->dev_name, peri->dev_id);
+
+       if (!(I_CLOCK_MASK & peri->in_mask)) {
+               /* Gated BCLK/PCLK disable */
+               if (I_GATE_BCLK & peri->in_mask)
+                       clk_dev_bclk(peri->base, 0);
+
+               if (I_GATE_PCLK & peri->in_mask)
+                       clk_dev_pclk(peri->base, 0);
+
+               return;
+       }
+
+       clk_dev_rate(peri->base, 0, 7, 256);    /* for power save */
+       clk_dev_enb(peri->base, 0);
+
+       /* Gated BCLK/PCLK disable */
+       if (I_GATE_BCLK & peri->in_mask)
+               clk_dev_bclk(peri->base, 0);
+
+       if (I_GATE_PCLK & peri->in_mask)
+               clk_dev_pclk(peri->base, 0);
+}
+
+/*
+ * Core clocks APIs
+ */
+void __init clk_init(void)
+{
+       struct clk_dev *cdev = st_clk_devs;
+       struct clk_dev_peri *peri = clk_periphs;
+       struct clk *clk = NULL;
+       int i = 0;
+
+       memset(cdev, 0, sizeof(st_clk_devs));
+       core_rate_init();
+
+       for (i = 0; (CLK_CORE_NUM + CLK_PERI_NUM) > i; i++, cdev++) {
+               if (i < CLK_CORE_NUM) {
+                       cdev->name = clk_core[i];
+                       clk = &cdev->clk;
+                       clk->rate = core_get_rate(i);
+                       continue;
+               }
+
+               peri = &clk_periphs[i - CLK_CORE_NUM];
+               peri->base = (void *)peri->base;
+
+               cdev->peri = peri;
+               cdev->name = peri->dev_name;
+
+               if (!(I_CLOCK_MASK & peri->in_mask)) {
+                       if (I_BCLK_MASK & peri->in_mask)
+                               cdev->clk.rate = core_get_rate(CORECLK_ID_BCLK);
+                       if (I_PCLK_MASK & peri->in_mask)
+                               cdev->clk.rate = core_get_rate(CORECLK_ID_PCLK);
+               }
+
+               /* prevent uart clock disable for low step debug message */
+               #ifndef CONFIG_DEBUG_NX_UART
+               if (peri->dev_name) {
+                       #ifdef CONFIG_BACKLIGHT_PWM
+                       if (!strcmp(peri->dev_name, DEV_NAME_PWM))
+                               continue;
+                       #endif
+               }
+               #endif
+       }
+       debug("CPU : Clock Generator= %d EA, ", CLK_DEVS_NUM);
+}
diff --git a/arch/arm/mach-nexell/cmd_boot_linux.c b/arch/arm/mach-nexell/cmd_boot_linux.c
new file mode 100644 (file)
index 0000000..f2dedfe
--- /dev/null
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016 nexell
+ * jhkim <jhkim@nexell.co.kr>
+ */
+
+#include <common.h>
+#include <bootm.h>
+#include <command.h>
+#include <environment.h>
+#include <errno.h>
+#include <image.h>
+#include <fdt_support.h>
+
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_CLI_FRAMEWORK)
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static bootm_headers_t linux_images;
+
+static void boot_go_set_os(cmd_tbl_t *cmdtp, int flag, int argc,
+                          char * const argv[],
+                          bootm_headers_t *images)
+{
+       char * const img_addr = argv[0];
+
+       images->os.type = IH_TYPE_KERNEL;
+       images->os.comp = IH_COMP_NONE;
+       images->os.os = IH_OS_LINUX;
+       images->os.load = simple_strtoul(img_addr, NULL, 16);
+       images->ep = images->os.load;
+#if defined(CONFIG_ARM)
+       images->os.arch = IH_ARCH_ARM;
+#elif defined(CONFIG_ARM64)
+       images->os.arch = IH_ARCH_ARM64;
+#else
+       #error "Not support architecture ..."
+#endif
+       if (!IS_ENABLED(CONFIG_OF_LIBFDT) && !IS_ENABLED(CONFIG_SPL_BUILD)) {
+               /* set DTB address for linux kernel */
+               if (argc > 2) {
+                       unsigned long ft_addr;
+
+                       ft_addr = simple_strtol(argv[2], NULL, 16);
+                       images->ft_addr = (char *)ft_addr;
+
+                       /*
+                        * if not defined IMAGE_ENABLE_OF_LIBFDT,
+                        * must be set to fdt address
+                        */
+                       if (!IMAGE_ENABLE_OF_LIBFDT)
+                               gd->bd->bi_boot_params = ft_addr;
+
+                       debug("## set ft:%08lx and boot params:%08lx [control of:%s]"
+                             "...\n", ft_addr, gd->bd->bi_boot_params,
+                             IMAGE_ENABLE_OF_LIBFDT ? "on" : "off");
+               }
+       }
+}
+
+#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_LMB)
+static void boot_start_lmb(bootm_headers_t *images)
+{
+       ulong           mem_start;
+       phys_size_t     mem_size;
+
+       lmb_init(&images->lmb);
+
+       mem_start = getenv_bootm_low();
+       mem_size = getenv_bootm_size();
+
+       lmb_add(&images->lmb, (phys_addr_t)mem_start, mem_size);
+
+       arch_lmb_reserve(&images->lmb);
+       board_lmb_reserve(&images->lmb);
+}
+#else
+#define lmb_reserve(lmb, base, size)
+static inline void boot_start_lmb(bootm_headers_t *images) { }
+#endif
+
+int do_boot_linux(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       boot_os_fn *boot_fn;
+       bootm_headers_t *images = &linux_images;
+       int flags;
+       int ret;
+
+       boot_start_lmb(images);
+
+       flags  = BOOTM_STATE_START;
+
+       argc--; argv++;
+       boot_go_set_os(cmdtp, flag, argc, argv, images);
+
+       if (IS_ENABLED(CONFIG_OF_LIBFDT)) {
+               /* find flattened device tree */
+               ret = boot_get_fdt(flag, argc, argv, IH_ARCH_DEFAULT, images,
+                                  &images->ft_addr, &images->ft_len);
+               if (ret) {
+                       puts("Could not find a valid device tree\n");
+                       return 1;
+               }
+               set_working_fdt_addr((ulong)images->ft_addr);
+       }
+
+       if (!IS_ENABLED(CONFIG_OF_LIBFDT))
+               flags |= BOOTM_STATE_OS_GO;
+
+       boot_fn = do_bootm_linux;
+       ret = boot_fn(flags, argc, argv, images);
+
+       if (ret == BOOTM_ERR_UNIMPLEMENTED)
+               show_boot_progress(BOOTSTAGE_ID_DECOMP_UNIMPL);
+       else if (ret == BOOTM_ERR_RESET)
+               do_reset(cmdtp, flag, argc, argv);
+
+       return ret;
+}
+
+U_BOOT_CMD(bootl, CONFIG_SYS_MAXARGS, 1, do_boot_linux,
+          "boot linux image from memory",
+          "[addr [arg ...]]\n    - boot linux image stored in memory\n"
+          "\tuse a '-' for the DTB address\n"
+);
+#endif
+
+#if defined(CONFIG_CMD_BOOTD) && !defined(CONFIG_CMD_BOOTM)
+int do_bootd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       return run_command(env_get("bootcmd"), flag);
+}
+
+U_BOOT_CMD(boot, 1, 1, do_bootd,
+          "boot default, i.e., run 'bootcmd'",
+          ""
+);
+
+/* keep old command name "bootd" for backward compatibility */
+U_BOOT_CMD(bootd, 1,   1,      do_bootd,
+          "boot default, i.e., run 'bootcmd'",
+          ""
+);
+#endif
diff --git a/arch/arm/mach-nexell/config.mk b/arch/arm/mach-nexell/config.mk
new file mode 100644 (file)
index 0000000..7b06626
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# (C) Copyright 2016 Nexell
+# junghyun kim<jhkim@nexell.co.kr>
+#
+# SPDX-License-Identifier:      GPL-2.0+
+#
+
+SOCDIR=CPUDIR/$(VENDOR)
+MACHDIR=$(patsubst %,arch/arm/mach-%,$(machine-y))
+
+LDPPFLAGS += -DMACHDIR=$(MACHDIR) -DSOCDIR=$(SOCDIR)
diff --git a/arch/arm/mach-nexell/nx_gpio.c b/arch/arm/mach-nexell/nx_gpio.c
new file mode 100644 (file)
index 0000000..dfba3a2
--- /dev/null
@@ -0,0 +1,352 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016 Nexell
+ * Youngbok, Park <ybpark@nexell.co.kr>
+ */
+
+/*
+ * FIXME : will be remove after support pinctrl
+ */
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/arch/nexell.h>
+#include "asm/arch/nx_gpio.h"
+#define NUMBER_OF_GPIO_MODULE 5
+u32 __g_nx_gpio_valid_bit[NUMBER_OF_GPIO_MODULE] = {
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF};
+
+static struct {
+       struct nx_gpio_register_set *pregister;
+} __g_module_variables[NUMBER_OF_GPIO_MODULE] = {
+       { (struct nx_gpio_register_set *)PHY_BASEADDR_GPIOA },
+       { (struct nx_gpio_register_set *)PHY_BASEADDR_GPIOB },
+       { (struct nx_gpio_register_set *)PHY_BASEADDR_GPIOC },
+       { (struct nx_gpio_register_set *)PHY_BASEADDR_GPIOD },
+       { (struct nx_gpio_register_set *)PHY_BASEADDR_GPIOE },
+};
+
+enum { nx_gpio_max_bit = 32 };
+
+void nx_gpio_set_bit(u32 *value, u32 bit, int enable)
+{
+       register u32 newvalue;
+
+       newvalue = *value;
+       newvalue &= ~(1ul << bit);
+       newvalue |= (u32)enable << bit;
+       writel(newvalue, value);
+}
+
+int nx_gpio_get_bit(u32 value, u32 bit)
+{
+       return (int)((value >> bit) & (1ul));
+}
+
+void nx_gpio_set_bit2(u32 *value, u32 bit, u32 bit_value)
+{
+       register u32 newvalue = *value;
+
+       newvalue = (u32)(newvalue & ~(3ul << (bit * 2)));
+       newvalue = (u32)(newvalue | (bit_value << (bit * 2)));
+
+       writel(newvalue, value);
+}
+
+u32 nx_gpio_get_bit2(u32 value, u32 bit)
+{
+       return (u32)((u32)(value >> (bit * 2)) & 3ul);
+}
+
+int nx_gpio_initialize(void)
+{
+       static int binit;
+       u32 i;
+
+       binit = 0;
+
+       if (binit == 0) {
+               for (i = 0; i < NUMBER_OF_GPIO_MODULE; i++)
+                       __g_module_variables[i].pregister = NULL;
+               binit = true;
+       }
+       for (i = 0; i < NUMBER_OF_GPIO_MODULE; i++) {
+               __g_nx_gpio_valid_bit[i] = 0xFFFFFFFF;
+       };
+       return true;
+}
+
+u32 nx_gpio_get_number_of_module(void)
+{
+       return NUMBER_OF_GPIO_MODULE;
+}
+
+u32 nx_gpio_get_size_of_register_set(void)
+{
+       return sizeof(struct nx_gpio_register_set);
+}
+
+void nx_gpio_set_base_address(u32 module_index, void *base_address)
+{
+       __g_module_variables[module_index].pregister =
+               (struct nx_gpio_register_set *)base_address;
+}
+
+void *nx_gpio_get_base_address(u32 module_index)
+{
+       return (void *)__g_module_variables[module_index].pregister;
+}
+
+int nx_gpio_open_module(u32 module_index)
+{
+       register struct nx_gpio_register_set *pregister;
+
+       pregister = __g_module_variables[module_index].pregister;
+       writel(0xFFFFFFFF, &pregister->gpiox_slew_disable_default);
+       writel(0xFFFFFFFF, &pregister->gpiox_drv1_disable_default);
+       writel(0xFFFFFFFF, &pregister->gpiox_drv0_disable_default);
+       writel(0xFFFFFFFF, &pregister->gpiox_pullsel_disable_default);
+       writel(0xFFFFFFFF, &pregister->gpiox_pullenb_disable_default);
+       return true;
+}
+
+int nx_gpio_close_module(u32 module_index) { return true; }
+
+int nx_gpio_check_busy(u32 module_index) { return false; }
+
+void nx_gpio_set_pad_function(u32 module_index, u32 bit_number,
+                             u32 padfunc)
+{
+       register struct nx_gpio_register_set *pregister;
+
+       pregister = __g_module_variables[module_index].pregister;
+       nx_gpio_set_bit2(&pregister->gpioxaltfn[bit_number / 16],
+                        bit_number % 16, padfunc);
+}
+
+void nx_gpio_set_pad_function32(u32 module_index, u32 msbvalue, u32 lsbvalue)
+{
+       register struct nx_gpio_register_set *pregister;
+
+       pregister = __g_module_variables[module_index].pregister;
+       writel(lsbvalue, &pregister->gpioxaltfn[0]);
+       writel(msbvalue, &pregister->gpioxaltfn[1]);
+}
+
+int nx_gpio_get_pad_function(u32 module_index, u32 bit_number)
+{
+       register struct nx_gpio_register_set *pregister;
+
+       pregister = __g_module_variables[module_index].pregister;
+       return (int)nx_gpio_get_bit2
+               (readl(&pregister->gpioxaltfn[bit_number / 16]),
+                bit_number % 16);
+}
+
+void nx_gpio_set_output_enable(u32 module_index, u32 bit_number,
+                              int output_enb)
+{
+       register struct nx_gpio_register_set *pregister;
+
+       pregister = __g_module_variables[module_index].pregister;
+       nx_gpio_set_bit(&pregister->gpioxoutenb, bit_number, output_enb);
+}
+
+int nx_gpio_get_detect_enable(u32 module_index, u32 bit_number)
+{
+       register struct nx_gpio_register_set *pregister;
+
+       pregister = __g_module_variables[module_index].pregister;
+       return nx_gpio_get_bit(readl(&pregister->gpioxdetenb), bit_number);
+}
+
+u32 nx_gpio_get_detect_enable32(u32 module_index)
+{
+       register struct nx_gpio_register_set *pregister;
+
+       pregister = __g_module_variables[module_index].pregister;
+       return readl(&pregister->gpioxdetenb);
+}
+
+void nx_gpio_set_detect_enable(u32 module_index, u32 bit_number,
+                              int detect_enb)
+{
+       register struct nx_gpio_register_set *pregister;
+
+       pregister = __g_module_variables[module_index].pregister;
+       nx_gpio_set_bit(&pregister->gpioxdetenb, bit_number, detect_enb);
+}
+
+void nx_gpio_set_detect_enable32(u32 module_index, u32 enable_flag)
+{
+       register struct nx_gpio_register_set *pregister;
+
+       pregister = __g_module_variables[module_index].pregister;
+       writel(enable_flag, &pregister->gpioxdetenb);
+}
+
+int nx_gpio_get_output_enable(u32 module_index, u32 bit_number)
+{
+       register struct nx_gpio_register_set *pregister;
+
+       pregister = __g_module_variables[module_index].pregister;
+       return nx_gpio_get_bit(readl(&pregister->gpioxoutenb), bit_number);
+}
+
+void nx_gpio_set_output_enable32(u32 module_index, int output_enb)
+{
+       register struct nx_gpio_register_set *pregister;
+
+       pregister = __g_module_variables[module_index].pregister;
+       if (output_enb)
+               writel(0xFFFFFFFF, &pregister->gpioxoutenb);
+       else
+               writel(0x0, &pregister->gpioxoutenb);
+}
+
+u32 nx_gpio_get_output_enable32(u32 module_index)
+{
+       register struct nx_gpio_register_set *pregister;
+
+       pregister = __g_module_variables[module_index].pregister;
+       return readl(&pregister->gpioxoutenb);
+}
+
+void nx_gpio_set_output_value(u32 module_index, u32 bit_number, int value)
+{
+       register struct nx_gpio_register_set *pregister;
+
+       pregister = __g_module_variables[module_index].pregister;
+       nx_gpio_set_bit(&pregister->gpioxout, bit_number, value);
+}
+
+int nx_gpio_get_output_value(u32 module_index, u32 bit_number)
+{
+       register struct nx_gpio_register_set *pregister;
+
+       pregister = __g_module_variables[module_index].pregister;
+       return nx_gpio_get_bit(readl(&pregister->gpioxout), bit_number);
+}
+
+void nx_gpio_set_output_value32(u32 module_index, u32 value)
+{
+       register struct nx_gpio_register_set *pregister;
+
+       pregister = __g_module_variables[module_index].pregister;
+       writel(value, &pregister->gpioxout);
+}
+
+u32 nx_gpio_get_output_value32(u32 module_index)
+{
+       register struct nx_gpio_register_set *pregister;
+
+       pregister = __g_module_variables[module_index].pregister;
+       return readl(&pregister->gpioxout);
+}
+
+int nx_gpio_get_input_value(u32 module_index, u32 bit_number)
+{
+       register struct nx_gpio_register_set *pregister;
+
+       pregister = __g_module_variables[module_index].pregister;
+       return nx_gpio_get_bit(readl(&pregister->gpioxpad), bit_number);
+}
+
+void nx_gpio_set_pull_select(u32 module_index, u32 bit_number, int enable)
+{
+       nx_gpio_set_bit(&__g_module_variables[module_index]
+                       .pregister->gpiox_pullsel_disable_default,
+                       bit_number, true);
+       nx_gpio_set_bit
+               (&__g_module_variables[module_index].pregister->gpiox_pullsel,
+                bit_number, enable);
+}
+
+void nx_gpio_set_pull_select32(u32 module_index, u32 value)
+{
+       writel(value,
+              &__g_module_variables[module_index].pregister->gpiox_pullsel);
+}
+
+int nx_gpio_get_pull_select(u32 module_index, u32 bit_number)
+{
+       return nx_gpio_get_bit
+               (__g_module_variables[module_index].pregister->gpiox_pullsel,
+                bit_number);
+}
+
+u32 nx_gpio_get_pull_select32(u32 module_index)
+{
+       return __g_module_variables[module_index].pregister->gpiox_pullsel;
+}
+
+void nx_gpio_set_pull_mode(u32 module_index, u32 bit_number, u32 mode)
+{
+       nx_gpio_set_bit(&__g_module_variables[module_index]
+                       .pregister->gpiox_pullsel_disable_default,
+                       bit_number, true);
+       nx_gpio_set_bit(&__g_module_variables[module_index]
+                       .pregister->gpiox_pullenb_disable_default,
+                       bit_number, true);
+       if (mode == nx_gpio_pull_off) {
+               nx_gpio_set_bit
+                (&__g_module_variables[module_index].pregister->gpiox_pullenb,
+                bit_number, false);
+               nx_gpio_set_bit
+                (&__g_module_variables[module_index].pregister->gpiox_pullsel,
+                bit_number, false);
+       } else {
+               nx_gpio_set_bit
+                (&__g_module_variables[module_index].pregister->gpiox_pullsel,
+                bit_number, (mode & 1 ? true : false));
+               nx_gpio_set_bit
+                (&__g_module_variables[module_index].pregister->gpiox_pullenb,
+                bit_number, true);
+       }
+}
+
+void nx_gpio_set_fast_slew(u32 module_index, u32 bit_number,
+                          int enable)
+{
+       register struct nx_gpio_register_set *pregister;
+
+       pregister = __g_module_variables[module_index].pregister;
+       nx_gpio_set_bit(&pregister->gpiox_slew, bit_number,
+                       (int)(!enable));
+}
+
+void nx_gpio_set_drive_strength(u32 module_index, u32 bit_number,
+                               u32 drvstrength)
+{
+       register struct nx_gpio_register_set *pregister;
+
+       pregister = __g_module_variables[module_index].pregister;
+       nx_gpio_set_bit(&pregister->gpiox_drv1, bit_number,
+                       (int)(((u32)drvstrength >> 0) & 0x1));
+       nx_gpio_set_bit(&pregister->gpiox_drv0, bit_number,
+                       (int)(((u32)drvstrength >> 1) & 0x1));
+}
+
+void nx_gpio_set_drive_strength_disable_default(u32 module_index,
+                                               u32 bit_number, int enable)
+{
+       register struct nx_gpio_register_set *pregister;
+
+       pregister = __g_module_variables[module_index].pregister;
+       nx_gpio_set_bit(&pregister->gpiox_drv1_disable_default, bit_number,
+                       (int)(enable));
+       nx_gpio_set_bit(&pregister->gpiox_drv0_disable_default, bit_number,
+                       (int)(enable));
+}
+
+u32 nx_gpio_get_drive_strength(u32 module_index, u32 bit_number)
+{
+       register struct nx_gpio_register_set *pregister;
+       register u32 retvalue;
+
+       pregister = __g_module_variables[module_index].pregister;
+       retvalue =
+               nx_gpio_get_bit(readl(&pregister->gpiox_drv0), bit_number) << 1;
+       retvalue |=
+               nx_gpio_get_bit(readl(&pregister->gpiox_drv1), bit_number) << 0;
+       return retvalue;
+}
diff --git a/arch/arm/mach-nexell/nx_sec_reg.c b/arch/arm/mach-nexell/nx_sec_reg.c
new file mode 100644 (file)
index 0000000..3d3dd9f
--- /dev/null
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016 Nexell
+ * Youngbok, Park <park@nexell.co.kr>
+ */
+
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/arch/nexell.h>
+#include <asm/arch/sec_reg.h>
+#include <linux/linkage.h>
+
+#define NEXELL_SMC_BASE                        0x82000000
+
+#define NEXELL_SMC_FN(n)               (NEXELL_SMC_BASE +  (n))
+
+#define NEXELL_SMC_SEC_REG_WRITE       NEXELL_SMC_FN(0x0)
+#define NEXELL_SMC_SEC_REG_READ                NEXELL_SMC_FN(0x1)
+
+#define SECURE_ID_SHIFT                        8
+
+#define SEC_4K_OFFSET                  ((4 * 1024) - 1)
+#define SEC_64K_OFFSET                 ((64 * 1024) - 1)
+
+asmlinkage int __invoke_nexell_fn_smc(u32, u32, u32, u32);
+
+int write_sec_reg_by_id(void __iomem *reg, int val, int id)
+{
+       int ret = 0;
+       u32 off = 0;
+
+       switch (id) {
+       case NEXELL_L2C_SEC_ID:
+       case NEXELL_MIPI_SEC_ID:
+       case NEXELL_TOFF_SEC_ID:
+               off = (u32)reg & SEC_4K_OFFSET;
+               break;
+       case NEXELL_MALI_SEC_ID:
+               off = (u32)reg & SEC_64K_OFFSET;
+               break;
+       }
+       ret = __invoke_nexell_fn_smc(NEXELL_SMC_SEC_REG_WRITE |
+                       ((1 << SECURE_ID_SHIFT) + id), off, val, 0);
+       return ret;
+}
+
+int read_sec_reg_by_id(void __iomem *reg, int id)
+{
+       int ret = 0;
+       u32 off = 0;
+
+       switch (id) {
+       case NEXELL_L2C_SEC_ID:
+       case NEXELL_MIPI_SEC_ID:
+       case NEXELL_TOFF_SEC_ID:
+               off = (u32)reg & SEC_4K_OFFSET;
+               break;
+       case NEXELL_MALI_SEC_ID:
+               off = (u32)reg & SEC_64K_OFFSET;
+               break;
+       }
+       ret = __invoke_nexell_fn_smc(NEXELL_SMC_SEC_REG_READ |
+                       ((1 << SECURE_ID_SHIFT) + id), off, 0, 0);
+       return ret;
+}
+
+int write_sec_reg(void __iomem *reg, int val)
+{
+       int ret = 0;
+
+       ret = __invoke_nexell_fn_smc(NEXELL_SMC_SEC_REG_WRITE,
+                                    (u32)reg, val, 0);
+       return ret;
+}
+
+int read_sec_reg(void __iomem *reg)
+{
+       int ret = 0;
+
+       ret = __invoke_nexell_fn_smc(NEXELL_SMC_SEC_REG_READ, (u32)reg, 0, 0);
+       return ret;
+}
diff --git a/arch/arm/mach-nexell/reg-call.S b/arch/arm/mach-nexell/reg-call.S
new file mode 100644 (file)
index 0000000..5fdf515
--- /dev/null
@@ -0,0 +1,23 @@
+#include <asm-offsets.h>
+#include <config.h>
+#include <linux/linkage.h>
+
+#define ___asm_opcode_identity32(x) ((x) & 0xFFFFFFFF)
+#define __opcode_to_mem_arm(x) ___opcode_identity32(x)
+#define ___asm_opcode_to_mem_arm(x) ___asm_opcode_identity32(x)
+
+#define ___opcode_identity32(x) ((u32)(x))
+#define ___inst_arm(x) .long x
+#define __inst_arm(x) ___inst_arm(___asm_opcode_to_mem_arm(x))
+
+#define __inst_arm_thumb32(arm_opcode, thumb_opcode) __inst_arm(arm_opcode)
+
+#define __SMC(imm4) __inst_arm_thumb32(                                 \
+        0xE1600070 | (((imm4) & 0xF) << 0),                             \
+        0xF7F08000 | (((imm4) & 0xF) << 16)                             \
+)
+
+ENTRY(__invoke_nexell_fn_smc)
+       __SMC(0)
+       bx      lr
+ENDPROC(__invoke_nexell_fn_smc)
diff --git a/arch/arm/mach-nexell/reset.c b/arch/arm/mach-nexell/reset.c
new file mode 100644 (file)
index 0000000..1f732a3
--- /dev/null
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016 Nexell
+ * Youngbok, Park <park@nexell.co.kr>
+ */
+
+/*
+ *FIXME : Not support device tree & reset control driver.
+ *        will remove after support device tree & reset control driver.
+ */
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/nexell.h>
+#include <asm/arch/reset.h>
+
+struct nx_rstcon_registerset {
+       u32     regrst[(NUMBER_OF_RESET_MODULE_PIN + 31) >> 5];
+};
+
+static struct nx_rstcon_registerset *nx_rstcon =
+                       (struct nx_rstcon_registerset *)PHY_BASEADDR_RSTCON;
+
+void nx_rstcon_setrst(u32 rstindex, enum rstcon status)
+{
+       u32 regnum, bitpos, curstat;
+
+       regnum          = rstindex >> 5;
+       curstat         = (u32)readl(&nx_rstcon->regrst[regnum]);
+       bitpos          = rstindex & 0x1f;
+       curstat         &= ~(1UL << bitpos);
+       curstat         |= (status & 0x01) << bitpos;
+       writel(curstat, &nx_rstcon->regrst[regnum]);
+}
diff --git a/arch/arm/mach-nexell/tieoff.c b/arch/arm/mach-nexell/tieoff.c
new file mode 100644 (file)
index 0000000..5a4744c
--- /dev/null
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016 Nexell
+ * Youngbok, Park <park@nexell.co.kr>
+ */
+
+#include <common.h>
+#include <asm/arch/nexell.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/reset.h>
+#include <asm/arch/nx_gpio.h>
+#include <asm/arch/tieoff.h>
+#include <asm/arch/sec_reg.h>
+
+#define        NX_PIN_FN_SIZE  4
+#define TIEOFF_REG_NUM 33
+
+struct nx_tieoff_registerset {
+       u32     tieoffreg[TIEOFF_REG_NUM];
+};
+
+static struct nx_tieoff_registerset *nx_tieoff = (void *)PHY_BASEADDR_TIEOFF;
+
+static int tieoff_readl(void __iomem *reg)
+{
+       if (IS_ENABLED(CONFIG_ARCH_S5P4418))
+               return read_sec_reg_by_id(reg, NEXELL_TOFF_SEC_ID);
+       else
+               return readl(reg);
+}
+
+static int  tieoff_writetl(void __iomem *reg, int val)
+{
+       if (IS_ENABLED(CONFIG_ARCH_S5P4418))
+               return write_sec_reg_by_id(reg, val, NEXELL_TOFF_SEC_ID);
+       else
+               return writel(val, reg);
+}
+
+void nx_tieoff_set(u32 tieoff_index, u32 tieoff_value)
+{
+       u32 regindex, mask;
+       u32 lsb, msb;
+       u32 regval;
+
+       u32 position;
+       u32 bitwidth;
+
+       position = tieoff_index & 0xffff;
+       bitwidth = (tieoff_index >> 16) & 0xffff;
+
+       regindex        = position >> 5;
+
+       lsb = position & 0x1F;
+       msb = lsb + bitwidth;
+
+       if (msb > 32) {
+               msb &= 0x1F;
+               mask   = ~(0xffffffff << lsb);
+               regval = tieoff_readl(&nx_tieoff->tieoffreg[regindex]) & mask;
+               regval |= ((tieoff_value & ((1UL << bitwidth) - 1)) << lsb);
+               tieoff_writetl(&nx_tieoff->tieoffreg[regindex], regval);
+
+               mask   = (0xffffffff << msb);
+               regval = tieoff_readl(&nx_tieoff->tieoffreg[regindex]) & mask;
+               regval |= ((tieoff_value & ((1UL << bitwidth) - 1)) >> msb);
+               tieoff_writetl(&nx_tieoff->tieoffreg[regindex + 1], regval);
+       } else  {
+               mask    = (0xffffffff << msb) | (~(0xffffffff << lsb));
+               regval = tieoff_readl(&nx_tieoff->tieoffreg[regindex]) & mask;
+               regval  |= ((tieoff_value & ((1UL << bitwidth) - 1)) << lsb);
+               tieoff_writetl(&nx_tieoff->tieoffreg[regindex], regval);
+       }
+}
+
+u32 nx_tieoff_get(u32 tieoff_index)
+{
+       u32 regindex, mask;
+       u32 lsb, msb;
+       u32 regval;
+
+       u32 position;
+       u32 bitwidth;
+
+       position = tieoff_index & 0xffff;
+       bitwidth = (tieoff_index >> 16) & 0xffff;
+
+       regindex = position / 32;
+       lsb = position % 32;
+       msb = lsb + bitwidth;
+
+       if (msb > 32) {
+               msb &= 0x1F;
+               mask   = 0xffffffff << lsb;
+               regval = tieoff_readl(&nx_tieoff->tieoffreg[regindex]) & mask;
+               regval >>= lsb;
+
+               mask   = ~(0xffffffff << msb);
+               regval |= ((tieoff_readl(&nx_tieoff->tieoffreg[regindex + 1])
+                                       & mask) << (32 - lsb));
+       } else  {
+               mask   = ~(0xffffffff << msb) & (0xffffffff << lsb);
+               regval = tieoff_readl(&nx_tieoff->tieoffreg[regindex]) & mask;
+               regval >>= lsb;
+       }
+       return regval;
+}
diff --git a/arch/arm/mach-nexell/timer.c b/arch/arm/mach-nexell/timer.c
new file mode 100644 (file)
index 0000000..fecee67
--- /dev/null
@@ -0,0 +1,299 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016 Nexell
+ * Hyunseok, Jung <hsjung@nexell.co.kr>
+ */
+
+#include <common.h>
+#include <log.h>
+
+#include <asm/io.h>
+#include <asm/arch/nexell.h>
+#include <asm/arch/clk.h>
+#if defined(CONFIG_ARCH_S5P4418)
+#include <asm/arch/reset.h>
+#endif
+
+#if (CONFIG_TIMER_SYS_TICK_CH > 3)
+#error Not support timer channel. Please use "0~3" channels.
+#endif
+
+/* global variables to save timer count
+ *
+ * Section ".data" must be used because BSS is not available before relocation,
+ * in board_init_f(), respectively! I.e. global variables can not be used!
+ */
+static unsigned long timestamp __attribute__ ((section(".data")));
+static unsigned long lastdec __attribute__ ((section(".data")));
+static int     timerinit __attribute__ ((section(".data")));
+
+/* macro to hw timer tick config */
+static long    TIMER_FREQ  = 1000000;
+static long    TIMER_HZ    = 1000000 / CONFIG_SYS_HZ;
+static long    TIMER_COUNT = 0xFFFFFFFF;
+
+#define        REG_TCFG0                       (0x00)
+#define        REG_TCFG1                       (0x04)
+#define        REG_TCON                        (0x08)
+#define        REG_TCNTB0                      (0x0C)
+#define        REG_TCMPB0                      (0x10)
+#define        REG_TCNT0                       (0x14)
+#define        REG_CSTAT                       (0x44)
+
+#define        TCON_BIT_AUTO                   (1 << 3)
+#define        TCON_BIT_INVT                   (1 << 2)
+#define        TCON_BIT_UP                     (1 << 1)
+#define        TCON_BIT_RUN                    (1 << 0)
+#define TCFG0_BIT_CH(ch)               ((ch) == 0 || (ch) == 1 ? 0 : 8)
+#define TCFG1_BIT_CH(ch)               ((ch) * 4)
+#define TCON_BIT_CH(ch)                        ((ch) ? (ch) * 4  + 4 : 0)
+#define TINT_CH(ch)                    (ch)
+#define TINT_CSTAT_BIT_CH(ch)          ((ch) + 5)
+#define        TINT_CSTAT_MASK                 (0x1F)
+#define TIMER_TCNT_OFFS                        (0xC)
+
+void reset_timer_masked(void);
+unsigned long get_timer_masked(void);
+
+/*
+ * Timer HW
+ */
+static inline void timer_clock(void __iomem *base, int ch, int mux, int scl)
+{
+       u32 val = readl(base + REG_TCFG0) & ~(0xFF << TCFG0_BIT_CH(ch));
+
+       writel(val | ((scl - 1) << TCFG0_BIT_CH(ch)), base + REG_TCFG0);
+       val = readl(base + REG_TCFG1) & ~(0xF << TCFG1_BIT_CH(ch));
+       writel(val | (mux << TCFG1_BIT_CH(ch)), base + REG_TCFG1);
+}
+
+static inline void timer_count(void __iomem *base, int ch, unsigned int cnt)
+{
+       writel((cnt - 1), base + REG_TCNTB0 + (TIMER_TCNT_OFFS * ch));
+       writel((cnt - 1), base + REG_TCMPB0 + (TIMER_TCNT_OFFS * ch));
+}
+
+static inline void timer_start(void __iomem *base, int ch)
+{
+       int on = 0;
+       u32 val = readl(base + REG_CSTAT) & ~(TINT_CSTAT_MASK << 5 | 0x1 << ch);
+
+       writel(val | (0x1 << TINT_CSTAT_BIT_CH(ch) | on << ch),
+              base + REG_CSTAT);
+       val = readl(base + REG_TCON) & ~(0xE << TCON_BIT_CH(ch));
+       writel(val | (TCON_BIT_UP << TCON_BIT_CH(ch)), base + REG_TCON);
+
+       val &= ~(TCON_BIT_UP << TCON_BIT_CH(ch));
+       val |= ((TCON_BIT_AUTO | TCON_BIT_RUN) << TCON_BIT_CH(ch));
+       writel(val, base + REG_TCON);
+       dmb();
+}
+
+static inline void timer_stop(void __iomem *base, int ch)
+{
+       int on = 0;
+       u32 val = readl(base + REG_CSTAT) & ~(TINT_CSTAT_MASK << 5 | 0x1 << ch);
+
+       writel(val | (0x1 << TINT_CSTAT_BIT_CH(ch) | on << ch),
+              base + REG_CSTAT);
+       val = readl(base + REG_TCON) & ~(TCON_BIT_RUN << TCON_BIT_CH(ch));
+       writel(val, base + REG_TCON);
+}
+
+static inline unsigned long timer_read(void __iomem *base, int ch)
+{
+       unsigned long ret;
+
+       ret = TIMER_COUNT - readl(base + REG_TCNT0 + (TIMER_TCNT_OFFS * ch));
+       return ret;
+}
+
+int timer_init(void)
+{
+       struct clk *clk = NULL;
+       char name[16] = "pclk";
+       int ch = CONFIG_TIMER_SYS_TICK_CH;
+       unsigned long rate, tclk = 0;
+       unsigned long mout, thz, cmp = -1UL;
+       int tcnt, tscl = 0, tmux = 0;
+       int mux = 0, scl = 0;
+       void __iomem *base = (void __iomem *)PHY_BASEADDR_TIMER;
+
+       if (timerinit)
+               return 0;
+
+       /* get with PCLK */
+       clk  = clk_get(name);
+       rate = clk_get_rate(clk);
+       for (mux = 0; mux < 5; mux++) {
+               mout = rate / (1 << mux), scl = mout / TIMER_FREQ,
+               thz = mout / scl;
+               if (!(mout % TIMER_FREQ) && 256 > scl) {
+                       tclk = thz, tmux = mux, tscl = scl;
+                       break;
+               }
+               if (scl > 256)
+                       continue;
+               if (abs(thz - TIMER_FREQ) >= cmp)
+                       continue;
+               tclk = thz, tmux = mux, tscl = scl;
+               cmp = abs(thz - TIMER_FREQ);
+       }
+       tcnt = tclk;    /* Timer Count := 1 Mhz counting */
+
+       TIMER_FREQ = tcnt;      /* Timer Count := 1 Mhz counting */
+       TIMER_HZ = TIMER_FREQ / CONFIG_SYS_HZ;
+       tcnt = TIMER_COUNT == 0xFFFFFFFF ? TIMER_COUNT + 1 : tcnt;
+
+       timer_stop(base, ch);
+       timer_clock(base, ch, tmux, tscl);
+       timer_count(base, ch, tcnt);
+       timer_start(base, ch);
+
+       reset_timer_masked();
+       timerinit = 1;
+
+       return 0;
+}
+
+void reset_timer(void)
+{
+       reset_timer_masked();
+}
+
+unsigned long get_timer(unsigned long base)
+{
+       long ret;
+       unsigned long time = get_timer_masked();
+       unsigned long hz = TIMER_HZ;
+
+       ret = time / hz - base;
+       return ret;
+}
+
+void set_timer(unsigned long t)
+{
+       timestamp = (unsigned long)t;
+}
+
+void reset_timer_masked(void)
+{
+       void __iomem *base = (void __iomem *)PHY_BASEADDR_TIMER;
+       int ch = CONFIG_TIMER_SYS_TICK_CH;
+
+       /* reset time */
+       /* capure current decrementer value time */
+       lastdec = timer_read(base, ch);
+       /* start "advancing" time stamp from 0 */
+       timestamp = 0;
+}
+
+unsigned long get_timer_masked(void)
+{
+       void __iomem *base = (void __iomem *)PHY_BASEADDR_TIMER;
+       int ch = CONFIG_TIMER_SYS_TICK_CH;
+
+       unsigned long now = timer_read(base, ch); /* current tick value */
+
+       if (now >= lastdec) {                     /* normal mode (non roll) */
+               /* move stamp fordward with absolute diff ticks */
+               timestamp += now - lastdec;
+       } else {
+               /* we have overflow of the count down timer */
+               /* nts = ts + ld + (TLV - now)
+                * ts=old stamp, ld=time that passed before passing through -1
+                * (TLV-now) amount of time after passing though -1
+                * nts = new "advancing time stamp"...
+                * it could also roll and cause problems.
+                */
+               timestamp += now + TIMER_COUNT - lastdec;
+       }
+       /* save last */
+       lastdec = now;
+
+       debug("now=%lu, last=%lu, timestamp=%lu\n", now, lastdec, timestamp);
+       return (unsigned long)timestamp;
+}
+
+void __udelay(unsigned long usec)
+{
+       unsigned long tmo, tmp;
+
+       debug("+udelay=%ld\n", usec);
+
+       if (!timerinit)
+               timer_init();
+
+       /* if "big" number, spread normalization to seconds */
+       if (usec >= 1000) {
+               /* start to normalize for usec to ticks per sec */
+               tmo  = usec / 1000;
+               /* find number of "ticks" to wait to achieve target */
+               tmo *= TIMER_FREQ;
+               /* finish normalize. */
+               tmo /= 1000;
+       /* else small number, don't kill it prior to HZ multiply */
+       } else {
+               tmo = usec * TIMER_FREQ;
+               tmo /= (1000 * 1000);
+       }
+
+       tmp = get_timer_masked();       /* get current timestamp */
+       debug("A. tmo=%ld, tmp=%ld\n", tmo, tmp);
+
+       /* if setting this fordward will roll time stamp */
+       if (tmp > (tmo + tmp + 1))
+               /* reset "advancing" timestamp to 0, set lastdec value */
+               reset_timer_masked();
+       else
+               /* set advancing stamp wake up time */
+               tmo += tmp;
+
+       debug("B. tmo=%ld, tmp=%ld\n", tmo, tmp);
+
+       /* loop till event */
+       do {
+               tmp = get_timer_masked();
+       } while (tmo > tmp);
+       debug("-udelay=%ld\n", usec);
+}
+
+void udelay_masked(unsigned long usec)
+{
+       unsigned long tmo, endtime;
+       signed long diff;
+
+       /* if "big" number, spread normalization to seconds */
+       if (usec >= 1000) {
+               /* start to normalize for usec to ticks per sec */
+               tmo = usec / 1000;
+               /* find number of "ticks" to wait to achieve target */
+               tmo *= TIMER_FREQ;
+               /* finish normalize. */
+               tmo /= 1000;
+       } else { /* else small number, don't kill it prior to HZ multiply */
+               tmo = usec * TIMER_FREQ;
+               tmo /= (1000 * 1000);
+       }
+
+       endtime = get_timer_masked() + tmo;
+
+       do {
+               unsigned long now = get_timer_masked();
+
+               diff = endtime - now;
+       } while (diff >= 0);
+}
+
+unsigned long long get_ticks(void)
+{
+       return get_timer_masked();
+}
+
+#if defined(CONFIG_ARCH_S5P4418)
+ulong get_tbclk(void)
+{
+       ulong  tbclk = TIMER_FREQ;
+       return tbclk;
+}
+#endif