arm: add mach-nexell (all files except header files)
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>
This commit is contained in:
parent
a1ce9ed063
commit
95e9a8e2cb
@ -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"
|
||||
|
@ -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
|
||||
|
58
arch/arm/mach-nexell/Kconfig
Normal file
58
arch/arm/mach-nexell/Kconfig
Normal file
@ -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
|
13
arch/arm/mach-nexell/Makefile
Normal file
13
arch/arm/mach-nexell/Makefile
Normal file
@ -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
|
869
arch/arm/mach-nexell/clock.c
Normal file
869
arch/arm/mach-nexell/clock.c
Normal file
@ -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(®->con_enb) & ~(0x3);
|
||||
|
||||
val |= (on ? 3 : 0) & 0x3; /* always BCLK */
|
||||
writel(val, ®->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(®->con_enb) & ~(1 << 3);
|
||||
val |= (1 << 3);
|
||||
writel(val, ®->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(®->con_gen[step << 1]);
|
||||
val &= ~(0x07 << 2);
|
||||
val |= (src << 2); /* source */
|
||||
val &= ~(0xFF << 5);
|
||||
val |= (div - 1) << 5; /* divider */
|
||||
writel(val, ®->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(®->con_gen[step << 1]) & ~(1 << 1);
|
||||
|
||||
val |= (inv << 1);
|
||||
writel(val, ®->con_gen[step << 1]);
|
||||
}
|
||||
|
||||
static inline void clk_dev_enb(void *base, int on)
|
||||
{
|
||||
struct clk_dev_map *reg = base;
|
||||
unsigned int val = readl(®->con_enb) & ~(1 << 2);
|
||||
|
||||
val |= ((on ? 1 : 0) << 2);
|
||||
writel(val, ®->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);
|
||||
}
|
144
arch/arm/mach-nexell/cmd_boot_linux.c
Normal file
144
arch/arm/mach-nexell/cmd_boot_linux.c
Normal file
@ -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
|
11
arch/arm/mach-nexell/config.mk
Normal file
11
arch/arm/mach-nexell/config.mk
Normal file
@ -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)
|
352
arch/arm/mach-nexell/nx_gpio.c
Normal file
352
arch/arm/mach-nexell/nx_gpio.c
Normal file
@ -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;
|
||||
}
|
82
arch/arm/mach-nexell/nx_sec_reg.c
Normal file
82
arch/arm/mach-nexell/nx_sec_reg.c
Normal file
@ -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;
|
||||
}
|
23
arch/arm/mach-nexell/reg-call.S
Normal file
23
arch/arm/mach-nexell/reg-call.S
Normal file
@ -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)
|
33
arch/arm/mach-nexell/reset.c
Normal file
33
arch/arm/mach-nexell/reset.c
Normal file
@ -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]);
|
||||
}
|
107
arch/arm/mach-nexell/tieoff.c
Normal file
107
arch/arm/mach-nexell/tieoff.c
Normal file
@ -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;
|
||||
}
|
299
arch/arm/mach-nexell/timer.c
Normal file
299
arch/arm/mach-nexell/timer.c
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user