avionic design with actual uboot and tooling
submodule of avionic design uboot bootloader and with included tools to get you started , read readme.md and readme-tk1-loader.md
This commit is contained in:
42
u-boot/arch/arm/cpu/armv7/Kconfig
Normal file
42
u-boot/arch/arm/cpu/armv7/Kconfig
Normal file
@@ -0,0 +1,42 @@
|
||||
if CPU_V7
|
||||
|
||||
config CPU_V7_HAS_NONSEC
|
||||
bool
|
||||
|
||||
config CPU_V7_HAS_VIRT
|
||||
bool
|
||||
|
||||
config ARMV7_NONSEC
|
||||
boolean "Enable support for booting in non-secure mode" if EXPERT
|
||||
depends on CPU_V7_HAS_NONSEC
|
||||
default y
|
||||
---help---
|
||||
Say Y here to enable support for booting in non-secure / SVC mode.
|
||||
|
||||
config ARMV7_BOOT_SEC_DEFAULT
|
||||
boolean "Boot in secure mode by default" if EXPERT
|
||||
depends on ARMV7_NONSEC
|
||||
default y if TEGRA
|
||||
---help---
|
||||
Say Y here to boot in secure mode by default even if non-secure mode
|
||||
is supported. This option is useful to boot kernels which do not
|
||||
suppport booting in non-secure mode. Only set this if you need it.
|
||||
This can be overriden at run-time by setting the bootm_boot_mode env.
|
||||
variable to "sec" or "nonsec".
|
||||
|
||||
config ARMV7_VIRT
|
||||
boolean "Enable support for hardware virtualization" if EXPERT
|
||||
depends on CPU_V7_HAS_VIRT && ARMV7_NONSEC
|
||||
default y
|
||||
---help---
|
||||
Say Y here to boot in hypervisor (HYP) mode when booting non-secure.
|
||||
|
||||
config ARMV7_LPAE
|
||||
boolean "Use LPAE page table format" if EXPERT
|
||||
depends on CPU_V7
|
||||
default n
|
||||
---help---
|
||||
Say Y here to use the long descriptor page table format. This is
|
||||
required if U-Boot runs in HYP mode.
|
||||
|
||||
endif
|
||||
48
u-boot/arch/arm/cpu/armv7/Makefile
Normal file
48
u-boot/arch/arm/cpu/armv7/Makefile
Normal file
@@ -0,0 +1,48 @@
|
||||
#
|
||||
# (C) Copyright 2000-2003
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
extra-y := start.o
|
||||
|
||||
obj-y += cache_v7.o cache_v7_asm.o
|
||||
|
||||
obj-y += cpu.o cp15.o
|
||||
obj-y += syslib.o
|
||||
|
||||
ifneq ($(CONFIG_AM43XX)$(CONFIG_AM33XX)$(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX)$(CONFIG_TEGRA)$(CONFIG_MX6)$(CONFIG_MX7)$(CONFIG_TI81XX)$(CONFIG_AT91FAMILY)$(CONFIG_SUNXI)$(CONFIG_ARCH_SOCFPGA),)
|
||||
ifneq ($(CONFIG_SKIP_LOWLEVEL_INIT),y)
|
||||
obj-y += lowlevel_init.o
|
||||
endif
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_ARMV7_NONSEC) += nonsec_virt.o virt-v7.o virt-dt.o
|
||||
obj-$(CONFIG_ARMV7_PSCI) += psci.o
|
||||
|
||||
obj-$(CONFIG_IPROC) += iproc-common/
|
||||
obj-$(CONFIG_KONA) += kona-common/
|
||||
obj-$(CONFIG_OMAP_COMMON) += omap-common/
|
||||
obj-$(CONFIG_SYS_ARCH_TIMER) += arch_timer.o
|
||||
|
||||
ifneq (,$(filter s5pc1xx exynos,$(SOC)))
|
||||
obj-y += s5p-common/
|
||||
endif
|
||||
|
||||
obj-$(if $(filter am33xx,$(SOC)),y) += am33xx/
|
||||
obj-$(if $(filter bcm235xx,$(SOC)),y) += bcm235xx/
|
||||
obj-$(if $(filter bcm281xx,$(SOC)),y) += bcm281xx/
|
||||
obj-$(if $(filter bcmcygnus,$(SOC)),y) += bcmcygnus/
|
||||
obj-$(if $(filter bcmnsp,$(SOC)),y) += bcmnsp/
|
||||
obj-$(if $(filter ls102xa,$(SOC)),y) += ls102xa/
|
||||
obj-$(if $(filter mx5,$(SOC)),y) += mx5/
|
||||
obj-$(CONFIG_MX6) += mx6/
|
||||
obj-$(CONFIG_MX7) += mx7/
|
||||
obj-$(CONFIG_OMAP34XX) += omap3/
|
||||
obj-$(CONFIG_OMAP44XX) += omap4/
|
||||
obj-$(CONFIG_OMAP54XX) += omap5/
|
||||
obj-$(CONFIG_RMOBILE) += rmobile/
|
||||
obj-$(if $(filter stv0991,$(SOC)),y) += stv0991/
|
||||
obj-$(CONFIG_ARCH_SUNXI) += sunxi/
|
||||
obj-$(CONFIG_VF610) += vf610/
|
||||
40
u-boot/arch/arm/cpu/armv7/am33xx/Kconfig
Normal file
40
u-boot/arch/arm/cpu/armv7/am33xx/Kconfig
Normal file
@@ -0,0 +1,40 @@
|
||||
if AM43XX
|
||||
config TARGET_AM43XX_EVM
|
||||
bool "Support am43xx_evm"
|
||||
select TI_I2C_BOARD_DETECT
|
||||
help
|
||||
This option specifies support for the AM43xx
|
||||
GP and HS EVM development platforms.The AM437x
|
||||
GP EVM is a standalone test, development, and
|
||||
evaluation module system that enables developers
|
||||
to write software and develop hardware around
|
||||
an AM43xx processor subsystem.
|
||||
|
||||
config ISW_ENTRY_ADDR
|
||||
hex "Address in memory or XIP flash of bootloader entry point"
|
||||
help
|
||||
After any reset, the boot ROM on the AM43XX SOC
|
||||
searches the boot media for a valid boot image.
|
||||
For non-XIP devices, the ROM then copies the
|
||||
image into internal memory.
|
||||
For all boot modes, after the ROM processes the
|
||||
boot image it eventually computes the entry
|
||||
point address depending on the device type
|
||||
(secure/non-secure), boot media (xip/non-xip) and
|
||||
image headers.
|
||||
default 0x402F4000
|
||||
|
||||
config PUB_ROM_DATA_SIZE
|
||||
hex "Size in bytes of the L3 SRAM reserved by ROM to store data"
|
||||
help
|
||||
During the device boot, the public ROM uses the top of
|
||||
the public L3 OCMC RAM to store r/w data like stack,
|
||||
heap, globals etc. When the ROM is copying the boot
|
||||
image from the boot media into memory, the image must
|
||||
not spill over into this area. This value can be used
|
||||
during compile time to determine the maximum size of a
|
||||
boot image. Once the ROM transfers control to the boot
|
||||
image, this area is no longer used, and can be reclaimed
|
||||
for run time use by the boot image.
|
||||
default 0x8400
|
||||
endif
|
||||
22
u-boot/arch/arm/cpu/armv7/am33xx/Makefile
Normal file
22
u-boot/arch/arm/cpu/armv7/am33xx/Makefile
Normal file
@@ -0,0 +1,22 @@
|
||||
#
|
||||
# Copyright (C) 2011, Texas Instruments, Incorporated - http://www.ti.com/
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-$(CONFIG_AM33XX) += clock_am33xx.o
|
||||
obj-$(CONFIG_TI814X) += clock_ti814x.o
|
||||
obj-$(CONFIG_AM43XX) += clock_am43xx.o
|
||||
|
||||
ifneq ($(CONFIG_AM43XX)$(CONFIG_AM33XX),)
|
||||
obj-y += clock.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_TI816X) += clock_ti816x.o
|
||||
obj-y += sys_info.o
|
||||
obj-y += ddr.o
|
||||
obj-y += emif4.o
|
||||
obj-y += board.o
|
||||
obj-y += mux.o
|
||||
|
||||
obj-$(CONFIG_CLOCK_SYNTHESIZER) += clk_synthesizer.o
|
||||
300
u-boot/arch/arm/cpu/armv7/am33xx/board.c
Normal file
300
u-boot/arch/arm/cpu/armv7/am33xx/board.c
Normal file
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
* board.c
|
||||
*
|
||||
* Common board functions for AM33XX based boards
|
||||
*
|
||||
* Copyright (C) 2011, Texas Instruments, Incorporated - http://www.ti.com/
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <ns16550.h>
|
||||
#include <spl.h>
|
||||
#include <asm/arch/cpu.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
#include <asm/arch/omap.h>
|
||||
#include <asm/arch/ddr_defs.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/gpio.h>
|
||||
#include <asm/arch/mem.h>
|
||||
#include <asm/arch/mmc_host_def.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/emif.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <i2c.h>
|
||||
#include <miiphy.h>
|
||||
#include <cpsw.h>
|
||||
#include <asm/errno.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
#include <linux/usb/musb.h>
|
||||
#include <asm/omap_musb.h>
|
||||
#include <asm/davinci_rtc.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#if !CONFIG_IS_ENABLED(OF_CONTROL)
|
||||
static const struct ns16550_platdata am33xx_serial[] = {
|
||||
{ .base = CONFIG_SYS_NS16550_COM1, .reg_shift = 2, .clock = CONFIG_SYS_NS16550_CLK },
|
||||
# ifdef CONFIG_SYS_NS16550_COM2
|
||||
{ .base = CONFIG_SYS_NS16550_COM2, .reg_shift = 2, .clock = CONFIG_SYS_NS16550_CLK },
|
||||
# ifdef CONFIG_SYS_NS16550_COM3
|
||||
{ .base = CONFIG_SYS_NS16550_COM3, .reg_shift = 2, .clock = CONFIG_SYS_NS16550_CLK },
|
||||
{ .base = CONFIG_SYS_NS16550_COM4, .reg_shift = 2, .clock = CONFIG_SYS_NS16550_CLK },
|
||||
{ .base = CONFIG_SYS_NS16550_COM5, .reg_shift = 2, .clock = CONFIG_SYS_NS16550_CLK },
|
||||
{ .base = CONFIG_SYS_NS16550_COM6, .reg_shift = 2, .clock = CONFIG_SYS_NS16550_CLK },
|
||||
# endif
|
||||
# endif
|
||||
};
|
||||
|
||||
U_BOOT_DEVICES(am33xx_uarts) = {
|
||||
{ "ns16550_serial", &am33xx_serial[0] },
|
||||
# ifdef CONFIG_SYS_NS16550_COM2
|
||||
{ "ns16550_serial", &am33xx_serial[1] },
|
||||
# ifdef CONFIG_SYS_NS16550_COM3
|
||||
{ "ns16550_serial", &am33xx_serial[2] },
|
||||
{ "ns16550_serial", &am33xx_serial[3] },
|
||||
{ "ns16550_serial", &am33xx_serial[4] },
|
||||
{ "ns16550_serial", &am33xx_serial[5] },
|
||||
# endif
|
||||
# endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DM_GPIO
|
||||
static const struct omap_gpio_platdata am33xx_gpio[] = {
|
||||
{ 0, AM33XX_GPIO0_BASE },
|
||||
{ 1, AM33XX_GPIO1_BASE },
|
||||
{ 2, AM33XX_GPIO2_BASE },
|
||||
{ 3, AM33XX_GPIO3_BASE },
|
||||
#ifdef CONFIG_AM43XX
|
||||
{ 4, AM33XX_GPIO4_BASE },
|
||||
{ 5, AM33XX_GPIO5_BASE },
|
||||
#endif
|
||||
};
|
||||
|
||||
U_BOOT_DEVICES(am33xx_gpios) = {
|
||||
{ "gpio_omap", &am33xx_gpio[0] },
|
||||
{ "gpio_omap", &am33xx_gpio[1] },
|
||||
{ "gpio_omap", &am33xx_gpio[2] },
|
||||
{ "gpio_omap", &am33xx_gpio[3] },
|
||||
#ifdef CONFIG_AM43XX
|
||||
{ "gpio_omap", &am33xx_gpio[4] },
|
||||
{ "gpio_omap", &am33xx_gpio[5] },
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_DM_GPIO
|
||||
static const struct gpio_bank gpio_bank_am33xx[] = {
|
||||
{ (void *)AM33XX_GPIO0_BASE },
|
||||
{ (void *)AM33XX_GPIO1_BASE },
|
||||
{ (void *)AM33XX_GPIO2_BASE },
|
||||
{ (void *)AM33XX_GPIO3_BASE },
|
||||
#ifdef CONFIG_AM43XX
|
||||
{ (void *)AM33XX_GPIO4_BASE },
|
||||
{ (void *)AM33XX_GPIO5_BASE },
|
||||
#endif
|
||||
};
|
||||
|
||||
const struct gpio_bank *const omap_gpio_bank = gpio_bank_am33xx;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_OMAP_HSMMC) && !defined(CONFIG_SPL_BUILD)
|
||||
int cpu_mmc_init(bd_t *bis)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = omap_mmc_init(0, 0, 0, -1, -1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return omap_mmc_init(1, 0, 0, -1, -1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* AM33XX has two MUSB controllers which can be host or gadget */
|
||||
#if (defined(CONFIG_USB_MUSB_GADGET) || defined(CONFIG_USB_MUSB_HOST)) && \
|
||||
(defined(CONFIG_AM335X_USB0) || defined(CONFIG_AM335X_USB1))
|
||||
static struct ctrl_dev *cdev = (struct ctrl_dev *)CTRL_DEVICE_BASE;
|
||||
|
||||
/* USB 2.0 PHY Control */
|
||||
#define CM_PHY_PWRDN (1 << 0)
|
||||
#define CM_PHY_OTG_PWRDN (1 << 1)
|
||||
#define OTGVDET_EN (1 << 19)
|
||||
#define OTGSESSENDEN (1 << 20)
|
||||
|
||||
static void am33xx_usb_set_phy_power(u8 on, u32 *reg_addr)
|
||||
{
|
||||
if (on) {
|
||||
clrsetbits_le32(reg_addr, CM_PHY_PWRDN | CM_PHY_OTG_PWRDN,
|
||||
OTGVDET_EN | OTGSESSENDEN);
|
||||
} else {
|
||||
clrsetbits_le32(reg_addr, 0, CM_PHY_PWRDN | CM_PHY_OTG_PWRDN);
|
||||
}
|
||||
}
|
||||
|
||||
static struct musb_hdrc_config musb_config = {
|
||||
.multipoint = 1,
|
||||
.dyn_fifo = 1,
|
||||
.num_eps = 16,
|
||||
.ram_bits = 12,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_AM335X_USB0
|
||||
static void am33xx_otg0_set_phy_power(u8 on)
|
||||
{
|
||||
am33xx_usb_set_phy_power(on, &cdev->usb_ctrl0);
|
||||
}
|
||||
|
||||
struct omap_musb_board_data otg0_board_data = {
|
||||
.set_phy_power = am33xx_otg0_set_phy_power,
|
||||
};
|
||||
|
||||
static struct musb_hdrc_platform_data otg0_plat = {
|
||||
.mode = CONFIG_AM335X_USB0_MODE,
|
||||
.config = &musb_config,
|
||||
.power = 50,
|
||||
.platform_ops = &musb_dsps_ops,
|
||||
.board_data = &otg0_board_data,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_AM335X_USB1
|
||||
static void am33xx_otg1_set_phy_power(u8 on)
|
||||
{
|
||||
am33xx_usb_set_phy_power(on, &cdev->usb_ctrl1);
|
||||
}
|
||||
|
||||
struct omap_musb_board_data otg1_board_data = {
|
||||
.set_phy_power = am33xx_otg1_set_phy_power,
|
||||
};
|
||||
|
||||
static struct musb_hdrc_platform_data otg1_plat = {
|
||||
.mode = CONFIG_AM335X_USB1_MODE,
|
||||
.config = &musb_config,
|
||||
.power = 50,
|
||||
.platform_ops = &musb_dsps_ops,
|
||||
.board_data = &otg1_board_data,
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int arch_misc_init(void)
|
||||
{
|
||||
#ifdef CONFIG_AM335X_USB0
|
||||
musb_register(&otg0_plat, &otg0_board_data,
|
||||
(void *)USB0_OTG_BASE);
|
||||
#endif
|
||||
#ifdef CONFIG_AM335X_USB1
|
||||
musb_register(&otg1_plat, &otg1_board_data,
|
||||
(void *)USB1_OTG_BASE);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
|
||||
/*
|
||||
* In the case of non-SPL based booting we'll want to call these
|
||||
* functions a tiny bit later as it will require gd to be set and cleared
|
||||
* and that's not true in s_init in this case so we cannot do it there.
|
||||
*/
|
||||
int board_early_init_f(void)
|
||||
{
|
||||
prcm_init();
|
||||
set_mux_conf_regs();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is the place to do per-board things such as ramp up the
|
||||
* MPU clock frequency.
|
||||
*/
|
||||
__weak void am33xx_spl_board_init(void)
|
||||
{
|
||||
do_setup_dpll(&dpll_core_regs, &dpll_core_opp100);
|
||||
do_setup_dpll(&dpll_mpu_regs, &dpll_mpu_opp100);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SPL_AM33XX_ENABLE_RTC32K_OSC)
|
||||
static void rtc32k_enable(void)
|
||||
{
|
||||
struct davinci_rtc *rtc = (struct davinci_rtc *)RTC_BASE;
|
||||
|
||||
/*
|
||||
* Unlock the RTC's registers. For more details please see the
|
||||
* RTC_SS section of the TRM. In order to unlock we need to
|
||||
* write these specific values (keys) in this order.
|
||||
*/
|
||||
writel(RTC_KICK0R_WE, &rtc->kick0r);
|
||||
writel(RTC_KICK1R_WE, &rtc->kick1r);
|
||||
|
||||
/* Enable the RTC 32K OSC by setting bits 3 and 6. */
|
||||
writel((1 << 3) | (1 << 6), &rtc->osc);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void uart_soft_reset(void)
|
||||
{
|
||||
struct uart_sys *uart_base = (struct uart_sys *)DEFAULT_UART_BASE;
|
||||
u32 regval;
|
||||
|
||||
regval = readl(&uart_base->uartsyscfg);
|
||||
regval |= UART_RESET;
|
||||
writel(regval, &uart_base->uartsyscfg);
|
||||
while ((readl(&uart_base->uartsyssts) &
|
||||
UART_CLK_RUNNING_MASK) != UART_CLK_RUNNING_MASK)
|
||||
;
|
||||
|
||||
/* Disable smart idle */
|
||||
regval = readl(&uart_base->uartsyscfg);
|
||||
regval |= UART_SMART_IDLE_EN;
|
||||
writel(regval, &uart_base->uartsyscfg);
|
||||
}
|
||||
|
||||
static void watchdog_disable(void)
|
||||
{
|
||||
struct wd_timer *wdtimer = (struct wd_timer *)WDT_BASE;
|
||||
|
||||
writel(0xAAAA, &wdtimer->wdtwspr);
|
||||
while (readl(&wdtimer->wdtwwps) != 0x0)
|
||||
;
|
||||
writel(0x5555, &wdtimer->wdtwspr);
|
||||
while (readl(&wdtimer->wdtwwps) != 0x0)
|
||||
;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPL_BUILD
|
||||
void board_init_f(ulong dummy)
|
||||
{
|
||||
board_early_init_f();
|
||||
sdram_init();
|
||||
}
|
||||
#endif
|
||||
|
||||
void s_init(void)
|
||||
{
|
||||
/*
|
||||
* The ROM will only have set up sufficient pinmux to allow for the
|
||||
* first 4KiB NOR to be read, we must finish doing what we know of
|
||||
* the NOR mux in this space in order to continue.
|
||||
*/
|
||||
#ifdef CONFIG_NOR_BOOT
|
||||
enable_norboot_pin_mux();
|
||||
#endif
|
||||
watchdog_disable();
|
||||
set_uart_mux_conf();
|
||||
setup_clocks_for_console();
|
||||
uart_soft_reset();
|
||||
#if defined(CONFIG_SPL_AM33XX_ENABLE_RTC32K_OSC)
|
||||
/* Enable RTC32K clock */
|
||||
rtc32k_enable();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
104
u-boot/arch/arm/cpu/armv7/am33xx/clk_synthesizer.c
Normal file
104
u-boot/arch/arm/cpu/armv7/am33xx/clk_synthesizer.c
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* clk-synthesizer.c
|
||||
*
|
||||
* Clock synthesizer apis
|
||||
*
|
||||
* Copyright (C) 2016, Texas Instruments, Incorporated - http://www.ti.com/
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch/clk_synthesizer.h>
|
||||
#include <i2c.h>
|
||||
|
||||
/**
|
||||
* clk_synthesizer_reg_read - Read register from synthesizer.
|
||||
* @addr: addr within the i2c device
|
||||
* buf: Buffer to which value is to be read.
|
||||
*
|
||||
* For reading the register from this clock synthesizer, a command needs to
|
||||
* be send along with enabling byte read more, and then read can happen.
|
||||
* Returns 0 on success
|
||||
*/
|
||||
static int clk_synthesizer_reg_read(int addr, uint8_t *buf)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Enable Bye read */
|
||||
addr = addr | CLK_SYNTHESIZER_BYTE_MODE;
|
||||
|
||||
/* Send the command byte */
|
||||
rc = i2c_write(CLK_SYNTHESIZER_I2C_ADDR, addr, 1, buf, 1);
|
||||
if (rc)
|
||||
printf("Failed to send command to clock synthesizer\n");
|
||||
|
||||
/* Read the Data */
|
||||
return i2c_read(CLK_SYNTHESIZER_I2C_ADDR, addr, 1, buf, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* clk_synthesizer_reg_write - Write a value to register in synthesizer.
|
||||
* @addr: addr within the i2c device
|
||||
* val: Value to be written in the addr.
|
||||
*
|
||||
* Enable the byte read mode in the address and start the i2c transfer.
|
||||
* Returns 0 on success
|
||||
*/
|
||||
static int clk_synthesizer_reg_write(int addr, uint8_t val)
|
||||
{
|
||||
uint8_t cmd[2];
|
||||
int rc = 0;
|
||||
|
||||
/* Enable byte write */
|
||||
cmd[0] = addr | CLK_SYNTHESIZER_BYTE_MODE;
|
||||
cmd[1] = val;
|
||||
|
||||
rc = i2c_write(CLK_SYNTHESIZER_I2C_ADDR, addr, 1, cmd, 2);
|
||||
if (rc)
|
||||
printf("Clock synthesizer reg write failed at addr = 0x%x\n",
|
||||
addr);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* setup_clock_syntherizer - Program the clock synthesizer to get the desired
|
||||
* frequency.
|
||||
* @data: Data containing the desired output
|
||||
*
|
||||
* This is a PLL-based high performance synthesizer which gives 3 outputs
|
||||
* as per the PLL_DIV and load capacitor programmed.
|
||||
*/
|
||||
int setup_clock_synthesizer(struct clk_synth *data)
|
||||
{
|
||||
int rc;
|
||||
uint8_t val;
|
||||
|
||||
rc = i2c_probe(CLK_SYNTHESIZER_I2C_ADDR);
|
||||
if (rc) {
|
||||
printf("i2c probe failed at address 0x%x\n",
|
||||
CLK_SYNTHESIZER_I2C_ADDR);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = clk_synthesizer_reg_read(CLK_SYNTHESIZER_ID_REG, &val);
|
||||
if (val != data->id)
|
||||
return rc;
|
||||
|
||||
/* Crystal Load capacitor selection */
|
||||
rc = clk_synthesizer_reg_write(CLK_SYNTHESIZER_XCSEL, data->capacitor);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = clk_synthesizer_reg_write(CLK_SYNTHESIZER_MUX_REG, data->mux);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = clk_synthesizer_reg_write(CLK_SYNTHESIZER_PDIV2_REG, data->pdiv2);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = clk_synthesizer_reg_write(CLK_SYNTHESIZER_PDIV3_REG, data->pdiv3);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
241
u-boot/arch/arm/cpu/armv7/am33xx/clock.c
Normal file
241
u-boot/arch/arm/cpu/armv7/am33xx/clock.c
Normal file
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* clock.c
|
||||
*
|
||||
* Clock initialization for AM33XX boards.
|
||||
* Derived from OMAP4 boards
|
||||
*
|
||||
* Copyright (C) 2013, Texas Instruments, Incorporated - http://www.ti.com/
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <asm/arch/cpu.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
static void setup_post_dividers(const struct dpll_regs *dpll_regs,
|
||||
const struct dpll_params *params)
|
||||
{
|
||||
/* Setup post-dividers */
|
||||
if (params->m2 >= 0)
|
||||
writel(params->m2, dpll_regs->cm_div_m2_dpll);
|
||||
if (params->m3 >= 0)
|
||||
writel(params->m3, dpll_regs->cm_div_m3_dpll);
|
||||
if (params->m4 >= 0)
|
||||
writel(params->m4, dpll_regs->cm_div_m4_dpll);
|
||||
if (params->m5 >= 0)
|
||||
writel(params->m5, dpll_regs->cm_div_m5_dpll);
|
||||
if (params->m6 >= 0)
|
||||
writel(params->m6, dpll_regs->cm_div_m6_dpll);
|
||||
}
|
||||
|
||||
static inline void do_lock_dpll(const struct dpll_regs *dpll_regs)
|
||||
{
|
||||
clrsetbits_le32(dpll_regs->cm_clkmode_dpll,
|
||||
CM_CLKMODE_DPLL_DPLL_EN_MASK,
|
||||
DPLL_EN_LOCK << CM_CLKMODE_DPLL_EN_SHIFT);
|
||||
}
|
||||
|
||||
static inline void wait_for_lock(const struct dpll_regs *dpll_regs)
|
||||
{
|
||||
if (!wait_on_value(ST_DPLL_CLK_MASK, ST_DPLL_CLK_MASK,
|
||||
(void *)dpll_regs->cm_idlest_dpll, LDELAY)) {
|
||||
printf("DPLL locking failed for 0x%x\n",
|
||||
dpll_regs->cm_clkmode_dpll);
|
||||
hang();
|
||||
}
|
||||
}
|
||||
|
||||
static inline void do_bypass_dpll(const struct dpll_regs *dpll_regs)
|
||||
{
|
||||
clrsetbits_le32(dpll_regs->cm_clkmode_dpll,
|
||||
CM_CLKMODE_DPLL_DPLL_EN_MASK,
|
||||
DPLL_EN_MN_BYPASS << CM_CLKMODE_DPLL_EN_SHIFT);
|
||||
}
|
||||
|
||||
static inline void wait_for_bypass(const struct dpll_regs *dpll_regs)
|
||||
{
|
||||
if (!wait_on_value(ST_DPLL_CLK_MASK, 0,
|
||||
(void *)dpll_regs->cm_idlest_dpll, LDELAY)) {
|
||||
printf("Bypassing DPLL failed 0x%x\n",
|
||||
dpll_regs->cm_clkmode_dpll);
|
||||
}
|
||||
}
|
||||
|
||||
static void bypass_dpll(const struct dpll_regs *dpll_regs)
|
||||
{
|
||||
do_bypass_dpll(dpll_regs);
|
||||
wait_for_bypass(dpll_regs);
|
||||
}
|
||||
|
||||
void do_setup_dpll(const struct dpll_regs *dpll_regs,
|
||||
const struct dpll_params *params)
|
||||
{
|
||||
u32 temp;
|
||||
|
||||
if (!params)
|
||||
return;
|
||||
|
||||
temp = readl(dpll_regs->cm_clksel_dpll);
|
||||
|
||||
bypass_dpll(dpll_regs);
|
||||
|
||||
/* Set M & N */
|
||||
temp &= ~CM_CLKSEL_DPLL_M_MASK;
|
||||
temp |= (params->m << CM_CLKSEL_DPLL_M_SHIFT) & CM_CLKSEL_DPLL_M_MASK;
|
||||
|
||||
temp &= ~CM_CLKSEL_DPLL_N_MASK;
|
||||
temp |= (params->n << CM_CLKSEL_DPLL_N_SHIFT) & CM_CLKSEL_DPLL_N_MASK;
|
||||
|
||||
writel(temp, dpll_regs->cm_clksel_dpll);
|
||||
|
||||
setup_post_dividers(dpll_regs, params);
|
||||
|
||||
/* Wait till the DPLL locks */
|
||||
do_lock_dpll(dpll_regs);
|
||||
wait_for_lock(dpll_regs);
|
||||
}
|
||||
|
||||
static void setup_dplls(void)
|
||||
{
|
||||
const struct dpll_params *params;
|
||||
|
||||
params = get_dpll_core_params();
|
||||
do_setup_dpll(&dpll_core_regs, params);
|
||||
|
||||
params = get_dpll_mpu_params();
|
||||
do_setup_dpll(&dpll_mpu_regs, params);
|
||||
|
||||
params = get_dpll_per_params();
|
||||
do_setup_dpll(&dpll_per_regs, params);
|
||||
writel(0x300, &cmwkup->clkdcoldodpllper);
|
||||
|
||||
params = get_dpll_ddr_params();
|
||||
do_setup_dpll(&dpll_ddr_regs, params);
|
||||
}
|
||||
|
||||
static inline void wait_for_clk_enable(u32 *clkctrl_addr)
|
||||
{
|
||||
u32 clkctrl, idlest = MODULE_CLKCTRL_IDLEST_DISABLED;
|
||||
u32 bound = LDELAY;
|
||||
|
||||
while ((idlest == MODULE_CLKCTRL_IDLEST_DISABLED) ||
|
||||
(idlest == MODULE_CLKCTRL_IDLEST_TRANSITIONING)) {
|
||||
clkctrl = readl(clkctrl_addr);
|
||||
idlest = (clkctrl & MODULE_CLKCTRL_IDLEST_MASK) >>
|
||||
MODULE_CLKCTRL_IDLEST_SHIFT;
|
||||
if (--bound == 0) {
|
||||
printf("Clock enable failed for 0x%p idlest 0x%x\n",
|
||||
clkctrl_addr, clkctrl);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void enable_clock_module(u32 *const clkctrl_addr, u32 enable_mode,
|
||||
u32 wait_for_enable)
|
||||
{
|
||||
clrsetbits_le32(clkctrl_addr, MODULE_CLKCTRL_MODULEMODE_MASK,
|
||||
enable_mode << MODULE_CLKCTRL_MODULEMODE_SHIFT);
|
||||
debug("Enable clock module - %p\n", clkctrl_addr);
|
||||
if (wait_for_enable)
|
||||
wait_for_clk_enable(clkctrl_addr);
|
||||
}
|
||||
|
||||
static inline void wait_for_clk_disable(u32 *clkctrl_addr)
|
||||
{
|
||||
u32 clkctrl, idlest = MODULE_CLKCTRL_IDLEST_FULLY_FUNCTIONAL;
|
||||
u32 bound = LDELAY;
|
||||
|
||||
while ((idlest != MODULE_CLKCTRL_IDLEST_DISABLED)) {
|
||||
clkctrl = readl(clkctrl_addr);
|
||||
idlest = (clkctrl & MODULE_CLKCTRL_IDLEST_MASK) >>
|
||||
MODULE_CLKCTRL_IDLEST_SHIFT;
|
||||
if (--bound == 0) {
|
||||
printf("Clock disable failed for 0x%p idlest 0x%x\n",
|
||||
clkctrl_addr, clkctrl);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
static inline void disable_clock_module(u32 *const clkctrl_addr,
|
||||
u32 wait_for_disable)
|
||||
{
|
||||
clrsetbits_le32(clkctrl_addr, MODULE_CLKCTRL_MODULEMODE_MASK,
|
||||
MODULE_CLKCTRL_MODULEMODE_SW_DISABLE <<
|
||||
MODULE_CLKCTRL_MODULEMODE_SHIFT);
|
||||
debug("Disable clock module - %p\n", clkctrl_addr);
|
||||
if (wait_for_disable)
|
||||
wait_for_clk_disable(clkctrl_addr);
|
||||
}
|
||||
|
||||
static inline void enable_clock_domain(u32 *const clkctrl_reg, u32 enable_mode)
|
||||
{
|
||||
clrsetbits_le32(clkctrl_reg, CD_CLKCTRL_CLKTRCTRL_MASK,
|
||||
enable_mode << CD_CLKCTRL_CLKTRCTRL_SHIFT);
|
||||
debug("Enable clock domain - %p\n", clkctrl_reg);
|
||||
}
|
||||
|
||||
static inline void disable_clock_domain(u32 *const clkctrl_reg)
|
||||
{
|
||||
clrsetbits_le32(clkctrl_reg, CD_CLKCTRL_CLKTRCTRL_MASK,
|
||||
CD_CLKCTRL_CLKTRCTRL_SW_SLEEP <<
|
||||
CD_CLKCTRL_CLKTRCTRL_SHIFT);
|
||||
debug("Disable clock domain - %p\n", clkctrl_reg);
|
||||
}
|
||||
|
||||
void do_enable_clocks(u32 *const *clk_domains,
|
||||
u32 *const *clk_modules_explicit_en, u8 wait_for_enable)
|
||||
{
|
||||
u32 i, max = 100;
|
||||
|
||||
/* Put the clock domains in SW_WKUP mode */
|
||||
for (i = 0; (i < max) && clk_domains[i]; i++) {
|
||||
enable_clock_domain(clk_domains[i],
|
||||
CD_CLKCTRL_CLKTRCTRL_SW_WKUP);
|
||||
}
|
||||
|
||||
/* Clock modules that need to be put in SW_EXPLICIT_EN mode */
|
||||
for (i = 0; (i < max) && clk_modules_explicit_en[i]; i++) {
|
||||
enable_clock_module(clk_modules_explicit_en[i],
|
||||
MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN,
|
||||
wait_for_enable);
|
||||
};
|
||||
}
|
||||
|
||||
void do_disable_clocks(u32 *const *clk_domains,
|
||||
u32 *const *clk_modules_disable,
|
||||
u8 wait_for_disable)
|
||||
{
|
||||
u32 i, max = 100;
|
||||
|
||||
|
||||
/* Clock modules that need to be put in SW_DISABLE */
|
||||
for (i = 0; (i < max) && clk_modules_disable[i]; i++)
|
||||
disable_clock_module(clk_modules_disable[i],
|
||||
wait_for_disable);
|
||||
|
||||
/* Put the clock domains in SW_SLEEP mode */
|
||||
for (i = 0; (i < max) && clk_domains[i]; i++)
|
||||
disable_clock_domain(clk_domains[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Before scaling up the clocks we need to have the PMIC scale up the
|
||||
* voltages first. This will be dependent on which PMIC is in use
|
||||
* and in some cases we may not be scaling things up at all and thus not
|
||||
* need to do anything here.
|
||||
*/
|
||||
__weak void scale_vcores(void)
|
||||
{
|
||||
}
|
||||
|
||||
void prcm_init()
|
||||
{
|
||||
enable_basic_clocks();
|
||||
scale_vcores();
|
||||
setup_dplls();
|
||||
timer_init();
|
||||
}
|
||||
234
u-boot/arch/arm/cpu/armv7/am33xx/clock_am33xx.c
Normal file
234
u-boot/arch/arm/cpu/armv7/am33xx/clock_am33xx.c
Normal file
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* clock_am33xx.c
|
||||
*
|
||||
* clocks for AM33XX based boards
|
||||
*
|
||||
* Copyright (C) 2013, Texas Instruments, Incorporated - http://www.ti.com/
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch/cpu.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#define OSC (V_OSCK/1000000)
|
||||
|
||||
struct cm_perpll *const cmper = (struct cm_perpll *)CM_PER;
|
||||
struct cm_wkuppll *const cmwkup = (struct cm_wkuppll *)CM_WKUP;
|
||||
struct cm_dpll *const cmdpll = (struct cm_dpll *)CM_DPLL;
|
||||
struct cm_rtc *const cmrtc = (struct cm_rtc *)CM_RTC;
|
||||
|
||||
const struct dpll_regs dpll_mpu_regs = {
|
||||
.cm_clkmode_dpll = CM_WKUP + 0x88,
|
||||
.cm_idlest_dpll = CM_WKUP + 0x20,
|
||||
.cm_clksel_dpll = CM_WKUP + 0x2C,
|
||||
.cm_div_m2_dpll = CM_WKUP + 0xA8,
|
||||
};
|
||||
|
||||
const struct dpll_regs dpll_core_regs = {
|
||||
.cm_clkmode_dpll = CM_WKUP + 0x90,
|
||||
.cm_idlest_dpll = CM_WKUP + 0x5C,
|
||||
.cm_clksel_dpll = CM_WKUP + 0x68,
|
||||
.cm_div_m4_dpll = CM_WKUP + 0x80,
|
||||
.cm_div_m5_dpll = CM_WKUP + 0x84,
|
||||
.cm_div_m6_dpll = CM_WKUP + 0xD8,
|
||||
};
|
||||
|
||||
const struct dpll_regs dpll_per_regs = {
|
||||
.cm_clkmode_dpll = CM_WKUP + 0x8C,
|
||||
.cm_idlest_dpll = CM_WKUP + 0x70,
|
||||
.cm_clksel_dpll = CM_WKUP + 0x9C,
|
||||
.cm_div_m2_dpll = CM_WKUP + 0xAC,
|
||||
};
|
||||
|
||||
const struct dpll_regs dpll_ddr_regs = {
|
||||
.cm_clkmode_dpll = CM_WKUP + 0x94,
|
||||
.cm_idlest_dpll = CM_WKUP + 0x34,
|
||||
.cm_clksel_dpll = CM_WKUP + 0x40,
|
||||
.cm_div_m2_dpll = CM_WKUP + 0xA0,
|
||||
};
|
||||
|
||||
struct dpll_params dpll_mpu_opp100 = {
|
||||
CONFIG_SYS_MPUCLK, OSC-1, 1, -1, -1, -1, -1};
|
||||
const struct dpll_params dpll_core_opp100 = {
|
||||
1000, OSC-1, -1, -1, 10, 8, 4};
|
||||
const struct dpll_params dpll_mpu = {
|
||||
MPUPLL_M_300, OSC-1, 1, -1, -1, -1, -1};
|
||||
const struct dpll_params dpll_core = {
|
||||
50, OSC-1, -1, -1, 1, 1, 1};
|
||||
const struct dpll_params dpll_per = {
|
||||
960, OSC-1, 5, -1, -1, -1, -1};
|
||||
|
||||
const struct dpll_params *get_dpll_mpu_params(void)
|
||||
{
|
||||
return &dpll_mpu;
|
||||
}
|
||||
|
||||
const struct dpll_params *get_dpll_core_params(void)
|
||||
{
|
||||
return &dpll_core;
|
||||
}
|
||||
|
||||
const struct dpll_params *get_dpll_per_params(void)
|
||||
{
|
||||
return &dpll_per;
|
||||
}
|
||||
|
||||
void setup_clocks_for_console(void)
|
||||
{
|
||||
clrsetbits_le32(&cmwkup->wkclkstctrl, CD_CLKCTRL_CLKTRCTRL_MASK,
|
||||
CD_CLKCTRL_CLKTRCTRL_SW_WKUP <<
|
||||
CD_CLKCTRL_CLKTRCTRL_SHIFT);
|
||||
|
||||
clrsetbits_le32(&cmper->l4hsclkstctrl, CD_CLKCTRL_CLKTRCTRL_MASK,
|
||||
CD_CLKCTRL_CLKTRCTRL_SW_WKUP <<
|
||||
CD_CLKCTRL_CLKTRCTRL_SHIFT);
|
||||
|
||||
clrsetbits_le32(&cmwkup->wkup_uart0ctrl,
|
||||
MODULE_CLKCTRL_MODULEMODE_MASK,
|
||||
MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN <<
|
||||
MODULE_CLKCTRL_MODULEMODE_SHIFT);
|
||||
clrsetbits_le32(&cmper->uart1clkctrl,
|
||||
MODULE_CLKCTRL_MODULEMODE_MASK,
|
||||
MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN <<
|
||||
MODULE_CLKCTRL_MODULEMODE_SHIFT);
|
||||
clrsetbits_le32(&cmper->uart2clkctrl,
|
||||
MODULE_CLKCTRL_MODULEMODE_MASK,
|
||||
MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN <<
|
||||
MODULE_CLKCTRL_MODULEMODE_SHIFT);
|
||||
clrsetbits_le32(&cmper->uart3clkctrl,
|
||||
MODULE_CLKCTRL_MODULEMODE_MASK,
|
||||
MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN <<
|
||||
MODULE_CLKCTRL_MODULEMODE_SHIFT);
|
||||
clrsetbits_le32(&cmper->uart4clkctrl,
|
||||
MODULE_CLKCTRL_MODULEMODE_MASK,
|
||||
MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN <<
|
||||
MODULE_CLKCTRL_MODULEMODE_SHIFT);
|
||||
clrsetbits_le32(&cmper->uart5clkctrl,
|
||||
MODULE_CLKCTRL_MODULEMODE_MASK,
|
||||
MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN <<
|
||||
MODULE_CLKCTRL_MODULEMODE_SHIFT);
|
||||
}
|
||||
|
||||
void enable_basic_clocks(void)
|
||||
{
|
||||
u32 *const clk_domains[] = {
|
||||
&cmper->l3clkstctrl,
|
||||
&cmper->l4fwclkstctrl,
|
||||
&cmper->l3sclkstctrl,
|
||||
&cmper->l4lsclkstctrl,
|
||||
&cmwkup->wkclkstctrl,
|
||||
&cmper->emiffwclkctrl,
|
||||
&cmrtc->clkstctrl,
|
||||
0
|
||||
};
|
||||
|
||||
u32 *const clk_modules_explicit_en[] = {
|
||||
&cmper->l3clkctrl,
|
||||
&cmper->l4lsclkctrl,
|
||||
&cmper->l4fwclkctrl,
|
||||
&cmwkup->wkl4wkclkctrl,
|
||||
&cmper->l3instrclkctrl,
|
||||
&cmper->l4hsclkctrl,
|
||||
&cmwkup->wkgpio0clkctrl,
|
||||
&cmwkup->wkctrlclkctrl,
|
||||
&cmper->timer2clkctrl,
|
||||
&cmper->gpmcclkctrl,
|
||||
&cmper->elmclkctrl,
|
||||
&cmper->mmc0clkctrl,
|
||||
&cmper->mmc1clkctrl,
|
||||
&cmwkup->wkup_i2c0ctrl,
|
||||
&cmper->gpio1clkctrl,
|
||||
&cmper->gpio2clkctrl,
|
||||
&cmper->gpio3clkctrl,
|
||||
&cmper->i2c1clkctrl,
|
||||
&cmper->cpgmac0clkctrl,
|
||||
&cmper->spi0clkctrl,
|
||||
&cmrtc->rtcclkctrl,
|
||||
&cmper->usb0clkctrl,
|
||||
&cmper->emiffwclkctrl,
|
||||
&cmper->emifclkctrl,
|
||||
0
|
||||
};
|
||||
|
||||
do_enable_clocks(clk_domains, clk_modules_explicit_en, 1);
|
||||
|
||||
/* Select the Master osc 24 MHZ as Timer2 clock source */
|
||||
writel(0x1, &cmdpll->clktimer2clk);
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable Spread Spectrum for the MPU by calculating the required
|
||||
* values and setting the registers accordingly.
|
||||
* @param permille The spreading in permille (10th of a percent)
|
||||
*/
|
||||
void set_mpu_spreadspectrum(int permille)
|
||||
{
|
||||
u32 multiplier_m;
|
||||
u32 predivider_n;
|
||||
u32 cm_clksel_dpll_mpu;
|
||||
u32 cm_clkmode_dpll_mpu;
|
||||
u32 ref_clock;
|
||||
u32 pll_bandwidth;
|
||||
u32 mod_freq_divider;
|
||||
u32 exponent;
|
||||
u32 mantissa;
|
||||
u32 delta_m_step;
|
||||
|
||||
printf("Enabling Spread Spectrum of %d permille for MPU\n",
|
||||
permille);
|
||||
|
||||
/* Read PLL parameter m and n */
|
||||
cm_clksel_dpll_mpu = readl(&cmwkup->clkseldpllmpu);
|
||||
multiplier_m = (cm_clksel_dpll_mpu >> 8) & 0x3FF;
|
||||
predivider_n = cm_clksel_dpll_mpu & 0x7F;
|
||||
|
||||
/*
|
||||
* Calculate reference clock (clock after pre-divider),
|
||||
* its max. PLL bandwidth,
|
||||
* and resulting mod_freq_divider
|
||||
*/
|
||||
ref_clock = V_OSCK / (predivider_n + 1);
|
||||
pll_bandwidth = ref_clock / 70;
|
||||
mod_freq_divider = ref_clock / (4 * pll_bandwidth);
|
||||
|
||||
/* Calculate Mantissa/Exponent */
|
||||
exponent = 0;
|
||||
mantissa = mod_freq_divider;
|
||||
while ((mantissa > 127) && (exponent < 7)) {
|
||||
exponent++;
|
||||
mantissa /= 2;
|
||||
}
|
||||
if (mantissa > 127)
|
||||
mantissa = 127;
|
||||
|
||||
mod_freq_divider = mantissa << exponent;
|
||||
|
||||
/*
|
||||
* Calculate Modulation steps
|
||||
* As we use Downspread only, the spread is twice the value of
|
||||
* permille, so Div2!
|
||||
* As it takes the value in percent, divide by ten!
|
||||
*/
|
||||
delta_m_step = ((u32)((multiplier_m * permille) / 10 / 2)) << 18;
|
||||
delta_m_step /= 100;
|
||||
delta_m_step /= mod_freq_divider;
|
||||
if (delta_m_step > 0xFFFFF)
|
||||
delta_m_step = 0xFFFFF;
|
||||
|
||||
/* Setup Spread Spectrum */
|
||||
writel(delta_m_step, &cmwkup->sscdeltamstepdllmpu);
|
||||
writel((exponent << 8) | mantissa, &cmwkup->sscmodfreqdivdpllmpu);
|
||||
cm_clkmode_dpll_mpu = readl(&cmwkup->clkmoddpllmpu);
|
||||
/* clear all SSC flags */
|
||||
cm_clkmode_dpll_mpu &= ~(0xF << CM_CLKMODE_DPLL_SSC_EN_SHIFT);
|
||||
/* enable SSC with Downspread only */
|
||||
cm_clkmode_dpll_mpu |= CM_CLKMODE_DPLL_SSC_EN_MASK |
|
||||
CM_CLKMODE_DPLL_SSC_DOWNSPREAD_MASK;
|
||||
writel(cm_clkmode_dpll_mpu, &cmwkup->clkmoddpllmpu);
|
||||
while (!(readl(&cmwkup->clkmoddpllmpu) & 0x2000))
|
||||
;
|
||||
}
|
||||
231
u-boot/arch/arm/cpu/armv7/am33xx/clock_am43xx.c
Normal file
231
u-boot/arch/arm/cpu/armv7/am33xx/clock_am43xx.c
Normal file
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* clock_am43xx.c
|
||||
*
|
||||
* clocks for AM43XX based boards
|
||||
* Derived from AM33XX based boards
|
||||
*
|
||||
* Copyright (C) 2013, Texas Instruments, Incorporated - http://www.ti.com/
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch/cpu.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
struct cm_perpll *const cmper = (struct cm_perpll *)CM_PER;
|
||||
struct cm_wkuppll *const cmwkup = (struct cm_wkuppll *)CM_WKUP;
|
||||
struct cm_dpll *const cmdpll = (struct cm_dpll *)CM_DPLL;
|
||||
|
||||
const struct dpll_regs dpll_mpu_regs = {
|
||||
.cm_clkmode_dpll = CM_WKUP + 0x560,
|
||||
.cm_idlest_dpll = CM_WKUP + 0x564,
|
||||
.cm_clksel_dpll = CM_WKUP + 0x56c,
|
||||
.cm_div_m2_dpll = CM_WKUP + 0x570,
|
||||
};
|
||||
|
||||
const struct dpll_regs dpll_core_regs = {
|
||||
.cm_clkmode_dpll = CM_WKUP + 0x520,
|
||||
.cm_idlest_dpll = CM_WKUP + 0x524,
|
||||
.cm_clksel_dpll = CM_WKUP + 0x52C,
|
||||
.cm_div_m4_dpll = CM_WKUP + 0x538,
|
||||
.cm_div_m5_dpll = CM_WKUP + 0x53C,
|
||||
.cm_div_m6_dpll = CM_WKUP + 0x540,
|
||||
};
|
||||
|
||||
const struct dpll_regs dpll_per_regs = {
|
||||
.cm_clkmode_dpll = CM_WKUP + 0x5E0,
|
||||
.cm_idlest_dpll = CM_WKUP + 0x5E4,
|
||||
.cm_clksel_dpll = CM_WKUP + 0x5EC,
|
||||
.cm_div_m2_dpll = CM_WKUP + 0x5F0,
|
||||
};
|
||||
|
||||
const struct dpll_regs dpll_ddr_regs = {
|
||||
.cm_clkmode_dpll = CM_WKUP + 0x5A0,
|
||||
.cm_idlest_dpll = CM_WKUP + 0x5A4,
|
||||
.cm_clksel_dpll = CM_WKUP + 0x5AC,
|
||||
.cm_div_m2_dpll = CM_WKUP + 0x5B0,
|
||||
.cm_div_m4_dpll = CM_WKUP + 0x5B8,
|
||||
};
|
||||
|
||||
void setup_clocks_for_console(void)
|
||||
{
|
||||
u32 clkctrl, idlest = MODULE_CLKCTRL_IDLEST_DISABLED;
|
||||
|
||||
/* Do not add any spl_debug prints in this function */
|
||||
clrsetbits_le32(&cmwkup->wkclkstctrl, CD_CLKCTRL_CLKTRCTRL_MASK,
|
||||
CD_CLKCTRL_CLKTRCTRL_SW_WKUP <<
|
||||
CD_CLKCTRL_CLKTRCTRL_SHIFT);
|
||||
|
||||
/* Enable UART0 */
|
||||
clrsetbits_le32(&cmwkup->wkup_uart0ctrl,
|
||||
MODULE_CLKCTRL_MODULEMODE_MASK,
|
||||
MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN <<
|
||||
MODULE_CLKCTRL_MODULEMODE_SHIFT);
|
||||
|
||||
while ((idlest == MODULE_CLKCTRL_IDLEST_DISABLED) ||
|
||||
(idlest == MODULE_CLKCTRL_IDLEST_TRANSITIONING)) {
|
||||
clkctrl = readl(&cmwkup->wkup_uart0ctrl);
|
||||
idlest = (clkctrl & MODULE_CLKCTRL_IDLEST_MASK) >>
|
||||
MODULE_CLKCTRL_IDLEST_SHIFT;
|
||||
}
|
||||
}
|
||||
|
||||
void enable_basic_clocks(void)
|
||||
{
|
||||
u32 *const clk_domains[] = {
|
||||
&cmper->l3clkstctrl,
|
||||
&cmper->l3sclkstctrl,
|
||||
&cmper->l4lsclkstctrl,
|
||||
&cmwkup->wkclkstctrl,
|
||||
&cmper->emifclkstctrl,
|
||||
0
|
||||
};
|
||||
|
||||
u32 *const clk_modules_explicit_en[] = {
|
||||
&cmper->l3clkctrl,
|
||||
&cmper->l4lsclkctrl,
|
||||
&cmper->l4fwclkctrl,
|
||||
&cmwkup->wkl4wkclkctrl,
|
||||
&cmper->l3instrclkctrl,
|
||||
&cmper->l4hsclkctrl,
|
||||
&cmwkup->wkgpio0clkctrl,
|
||||
&cmwkup->wkctrlclkctrl,
|
||||
&cmper->timer2clkctrl,
|
||||
&cmper->gpmcclkctrl,
|
||||
&cmper->elmclkctrl,
|
||||
&cmper->mmc0clkctrl,
|
||||
&cmper->mmc1clkctrl,
|
||||
&cmwkup->wkup_i2c0ctrl,
|
||||
&cmper->gpio1clkctrl,
|
||||
&cmper->gpio2clkctrl,
|
||||
&cmper->gpio3clkctrl,
|
||||
&cmper->gpio4clkctrl,
|
||||
&cmper->gpio5clkctrl,
|
||||
&cmper->i2c1clkctrl,
|
||||
&cmper->cpgmac0clkctrl,
|
||||
&cmper->emiffwclkctrl,
|
||||
&cmper->emifclkctrl,
|
||||
&cmper->otfaemifclkctrl,
|
||||
&cmper->qspiclkctrl,
|
||||
&cmper->spi0clkctrl,
|
||||
0
|
||||
};
|
||||
|
||||
do_enable_clocks(clk_domains, clk_modules_explicit_en, 1);
|
||||
|
||||
/* Select the Master osc clk as Timer2 clock source */
|
||||
writel(0x1, &cmdpll->clktimer2clk);
|
||||
|
||||
/* For OPP100 the mac clock should be /5. */
|
||||
writel(0x4, &cmdpll->clkselmacclk);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TI_EDMA3
|
||||
void enable_edma3_clocks(void)
|
||||
{
|
||||
u32 *const clk_domains_edma3[] = {
|
||||
0
|
||||
};
|
||||
|
||||
u32 *const clk_modules_explicit_en_edma3[] = {
|
||||
&cmper->tpccclkctrl,
|
||||
&cmper->tptc0clkctrl,
|
||||
0
|
||||
};
|
||||
|
||||
do_enable_clocks(clk_domains_edma3,
|
||||
clk_modules_explicit_en_edma3,
|
||||
1);
|
||||
}
|
||||
|
||||
void disable_edma3_clocks(void)
|
||||
{
|
||||
u32 *const clk_domains_edma3[] = {
|
||||
0
|
||||
};
|
||||
|
||||
u32 *const clk_modules_disable_edma3[] = {
|
||||
&cmper->tpccclkctrl,
|
||||
&cmper->tptc0clkctrl,
|
||||
0
|
||||
};
|
||||
|
||||
do_disable_clocks(clk_domains_edma3,
|
||||
clk_modules_disable_edma3,
|
||||
1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_DWC3) || defined(CONFIG_USB_XHCI_OMAP)
|
||||
void enable_usb_clocks(int index)
|
||||
{
|
||||
u32 *usbclkctrl = 0;
|
||||
u32 *usbphyocp2scpclkctrl = 0;
|
||||
|
||||
if (index == 0) {
|
||||
usbclkctrl = &cmper->usb0clkctrl;
|
||||
usbphyocp2scpclkctrl = &cmper->usbphyocp2scp0clkctrl;
|
||||
setbits_le32(&cmper->usb0clkctrl,
|
||||
USBOTGSSX_CLKCTRL_OPTFCLKEN_REFCLK960);
|
||||
setbits_le32(&cmwkup->usbphy0clkctrl,
|
||||
USBPHY0_CLKCTRL_OPTFCLKEN_CLK32K);
|
||||
} else if (index == 1) {
|
||||
usbclkctrl = &cmper->usb1clkctrl;
|
||||
usbphyocp2scpclkctrl = &cmper->usbphyocp2scp1clkctrl;
|
||||
setbits_le32(&cmper->usb1clkctrl,
|
||||
USBOTGSSX_CLKCTRL_OPTFCLKEN_REFCLK960);
|
||||
setbits_le32(&cmwkup->usbphy1clkctrl,
|
||||
USBPHY0_CLKCTRL_OPTFCLKEN_CLK32K);
|
||||
}
|
||||
|
||||
u32 *const clk_domains_usb[] = {
|
||||
0
|
||||
};
|
||||
|
||||
u32 *const clk_modules_explicit_en_usb[] = {
|
||||
usbclkctrl,
|
||||
usbphyocp2scpclkctrl,
|
||||
0
|
||||
};
|
||||
|
||||
do_enable_clocks(clk_domains_usb, clk_modules_explicit_en_usb, 1);
|
||||
}
|
||||
|
||||
void disable_usb_clocks(int index)
|
||||
{
|
||||
u32 *usbclkctrl = 0;
|
||||
u32 *usbphyocp2scpclkctrl = 0;
|
||||
|
||||
if (index == 0) {
|
||||
usbclkctrl = &cmper->usb0clkctrl;
|
||||
usbphyocp2scpclkctrl = &cmper->usbphyocp2scp0clkctrl;
|
||||
clrbits_le32(&cmper->usb0clkctrl,
|
||||
USBOTGSSX_CLKCTRL_OPTFCLKEN_REFCLK960);
|
||||
clrbits_le32(&cmwkup->usbphy0clkctrl,
|
||||
USBPHY0_CLKCTRL_OPTFCLKEN_CLK32K);
|
||||
} else if (index == 1) {
|
||||
usbclkctrl = &cmper->usb1clkctrl;
|
||||
usbphyocp2scpclkctrl = &cmper->usbphyocp2scp1clkctrl;
|
||||
clrbits_le32(&cmper->usb1clkctrl,
|
||||
USBOTGSSX_CLKCTRL_OPTFCLKEN_REFCLK960);
|
||||
clrbits_le32(&cmwkup->usbphy1clkctrl,
|
||||
USBPHY0_CLKCTRL_OPTFCLKEN_CLK32K);
|
||||
}
|
||||
|
||||
u32 *const clk_domains_usb[] = {
|
||||
0
|
||||
};
|
||||
|
||||
u32 *const clk_modules_disable_usb[] = {
|
||||
usbclkctrl,
|
||||
usbphyocp2scpclkctrl,
|
||||
0
|
||||
};
|
||||
|
||||
do_disable_clocks(clk_domains_usb, clk_modules_disable_usb, 1);
|
||||
}
|
||||
#endif
|
||||
404
u-boot/arch/arm/cpu/armv7/am33xx/clock_ti814x.c
Normal file
404
u-boot/arch/arm/cpu/armv7/am33xx/clock_ti814x.c
Normal file
@@ -0,0 +1,404 @@
|
||||
/*
|
||||
* clock_ti814x.c
|
||||
*
|
||||
* Clocks for TI814X based boards
|
||||
*
|
||||
* Copyright (C) 2013, Texas Instruments, Incorporated
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch/cpu.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/* PRCM */
|
||||
#define PRCM_MOD_EN 0x2
|
||||
|
||||
/* CLK_SRC */
|
||||
#define OSC_SRC0 0
|
||||
#define OSC_SRC1 1
|
||||
|
||||
#define L3_OSC_SRC OSC_SRC0
|
||||
|
||||
#define OSC_0_FREQ 20
|
||||
|
||||
#define DCO_HS2_MIN 500
|
||||
#define DCO_HS2_MAX 1000
|
||||
#define DCO_HS1_MIN 1000
|
||||
#define DCO_HS1_MAX 2000
|
||||
|
||||
#define SELFREQDCO_HS2 0x00000801
|
||||
#define SELFREQDCO_HS1 0x00001001
|
||||
|
||||
#define MPU_N 0x1
|
||||
#define MPU_M 0x3C
|
||||
#define MPU_M2 1
|
||||
#define MPU_CLKCTRL 0x1
|
||||
|
||||
#define L3_N 19
|
||||
#define L3_M 880
|
||||
#define L3_M2 4
|
||||
#define L3_CLKCTRL 0x801
|
||||
|
||||
#define DDR_N 19
|
||||
#define DDR_M 666
|
||||
#define DDR_M2 2
|
||||
#define DDR_CLKCTRL 0x801
|
||||
|
||||
/* ADPLLJ register values */
|
||||
#define ADPLLJ_CLKCTRL_HS2 0x00000801 /* HS2 mode, TINT2 = 1 */
|
||||
#define ADPLLJ_CLKCTRL_HS1 0x00001001 /* HS1 mode, TINT2 = 1 */
|
||||
#define ADPLLJ_CLKCTRL_CLKDCOLDOEN (1 << 29)
|
||||
#define ADPLLJ_CLKCTRL_IDLE (1 << 23)
|
||||
#define ADPLLJ_CLKCTRL_CLKOUTEN (1 << 20)
|
||||
#define ADPLLJ_CLKCTRL_CLKOUTLDOEN (1 << 19)
|
||||
#define ADPLLJ_CLKCTRL_CLKDCOLDOPWDNZ (1 << 17)
|
||||
#define ADPLLJ_CLKCTRL_LPMODE (1 << 12)
|
||||
#define ADPLLJ_CLKCTRL_DRIFTGUARDIAN (1 << 11)
|
||||
#define ADPLLJ_CLKCTRL_REGM4XEN (1 << 10)
|
||||
#define ADPLLJ_CLKCTRL_TINITZ (1 << 0)
|
||||
#define ADPLLJ_CLKCTRL_CLKDCO (ADPLLJ_CLKCTRL_CLKDCOLDOEN | \
|
||||
ADPLLJ_CLKCTRL_CLKOUTEN | \
|
||||
ADPLLJ_CLKCTRL_CLKOUTLDOEN | \
|
||||
ADPLLJ_CLKCTRL_CLKDCOLDOPWDNZ)
|
||||
|
||||
#define ADPLLJ_STATUS_PHASELOCK (1 << 10)
|
||||
#define ADPLLJ_STATUS_FREQLOCK (1 << 9)
|
||||
#define ADPLLJ_STATUS_PHSFRQLOCK (ADPLLJ_STATUS_PHASELOCK | \
|
||||
ADPLLJ_STATUS_FREQLOCK)
|
||||
#define ADPLLJ_STATUS_BYPASSACK (1 << 8)
|
||||
#define ADPLLJ_STATUS_BYPASS (1 << 0)
|
||||
#define ADPLLJ_STATUS_BYPASSANDACK (ADPLLJ_STATUS_BYPASSACK | \
|
||||
ADPLLJ_STATUS_BYPASS)
|
||||
|
||||
#define ADPLLJ_TENABLE_ENB (1 << 0)
|
||||
#define ADPLLJ_TENABLEDIV_ENB (1 << 0)
|
||||
|
||||
#define ADPLLJ_M2NDIV_M2SHIFT 16
|
||||
|
||||
#define MPU_PLL_BASE (PLL_SUBSYS_BASE + 0x048)
|
||||
#define L3_PLL_BASE (PLL_SUBSYS_BASE + 0x110)
|
||||
#define DDR_PLL_BASE (PLL_SUBSYS_BASE + 0x290)
|
||||
|
||||
struct ad_pll {
|
||||
unsigned int pwrctrl;
|
||||
unsigned int clkctrl;
|
||||
unsigned int tenable;
|
||||
unsigned int tenablediv;
|
||||
unsigned int m2ndiv;
|
||||
unsigned int mn2div;
|
||||
unsigned int fracdiv;
|
||||
unsigned int bwctrl;
|
||||
unsigned int fracctrl;
|
||||
unsigned int status;
|
||||
unsigned int m3div;
|
||||
unsigned int rampctrl;
|
||||
};
|
||||
|
||||
#define OSC_SRC_CTRL (PLL_SUBSYS_BASE + 0x2C0)
|
||||
|
||||
#define ENET_CLKCTRL_CMPL 0x30000
|
||||
|
||||
#define SATA_PLL_BASE (CTRL_BASE + 0x0720)
|
||||
|
||||
struct sata_pll {
|
||||
unsigned int pllcfg0;
|
||||
unsigned int pllcfg1;
|
||||
unsigned int pllcfg2;
|
||||
unsigned int pllcfg3;
|
||||
unsigned int pllcfg4;
|
||||
unsigned int pllstatus;
|
||||
unsigned int rxstatus;
|
||||
unsigned int txstatus;
|
||||
unsigned int testcfg;
|
||||
};
|
||||
|
||||
#define SEL_IN_FREQ (0x1 << 31)
|
||||
#define DIGCLRZ (0x1 << 30)
|
||||
#define ENDIGLDO (0x1 << 4)
|
||||
#define APLL_CP_CURR (0x1 << 3)
|
||||
#define ENBGSC_REF (0x1 << 2)
|
||||
#define ENPLLLDO (0x1 << 1)
|
||||
#define ENPLL (0x1 << 0)
|
||||
|
||||
#define SATA_PLLCFG0_1 (SEL_IN_FREQ | ENBGSC_REF)
|
||||
#define SATA_PLLCFG0_2 (SEL_IN_FREQ | ENDIGLDO | ENBGSC_REF)
|
||||
#define SATA_PLLCFG0_3 (SEL_IN_FREQ | ENDIGLDO | ENBGSC_REF | ENPLLLDO)
|
||||
#define SATA_PLLCFG0_4 (SEL_IN_FREQ | DIGCLRZ | ENDIGLDO | ENBGSC_REF | \
|
||||
ENPLLLDO | ENPLL)
|
||||
|
||||
#define PLL_LOCK (0x1 << 0)
|
||||
|
||||
#define ENSATAMODE (0x1 << 31)
|
||||
#define PLLREFSEL (0x1 << 30)
|
||||
#define MDIVINT (0x4b << 18)
|
||||
#define EN_CLKAUX (0x1 << 5)
|
||||
#define EN_CLK125M (0x1 << 4)
|
||||
#define EN_CLK100M (0x1 << 3)
|
||||
#define EN_CLK50M (0x1 << 2)
|
||||
|
||||
#define SATA_PLLCFG1 (ENSATAMODE | \
|
||||
PLLREFSEL | \
|
||||
MDIVINT | \
|
||||
EN_CLKAUX | \
|
||||
EN_CLK125M | \
|
||||
EN_CLK100M | \
|
||||
EN_CLK50M)
|
||||
|
||||
#define DIGLDO_EN_CAPLESSMODE (0x1 << 22)
|
||||
#define PLLDO_EN_LDO_STABLE (0x1 << 11)
|
||||
#define PLLDO_EN_BUF_CUR (0x1 << 7)
|
||||
#define PLLDO_EN_LP (0x1 << 6)
|
||||
#define PLLDO_CTRL_TRIM_1_4V (0x10 << 1)
|
||||
|
||||
#define SATA_PLLCFG3 (DIGLDO_EN_CAPLESSMODE | \
|
||||
PLLDO_EN_LDO_STABLE | \
|
||||
PLLDO_EN_BUF_CUR | \
|
||||
PLLDO_EN_LP | \
|
||||
PLLDO_CTRL_TRIM_1_4V)
|
||||
|
||||
const struct cm_alwon *cmalwon = (struct cm_alwon *)CM_ALWON_BASE;
|
||||
const struct cm_def *cmdef = (struct cm_def *)CM_DEFAULT_BASE;
|
||||
const struct sata_pll *spll = (struct sata_pll *)SATA_PLL_BASE;
|
||||
|
||||
/*
|
||||
* Enable the peripheral clock for required peripherals
|
||||
*/
|
||||
static void enable_per_clocks(void)
|
||||
{
|
||||
/* HSMMC1 */
|
||||
writel(PRCM_MOD_EN, &cmalwon->mmchs1clkctrl);
|
||||
while (readl(&cmalwon->mmchs1clkctrl) != PRCM_MOD_EN)
|
||||
;
|
||||
|
||||
/* Ethernet */
|
||||
writel(PRCM_MOD_EN, &cmalwon->ethclkstctrl);
|
||||
writel(PRCM_MOD_EN, &cmalwon->ethernet0clkctrl);
|
||||
while ((readl(&cmalwon->ethernet0clkctrl) & ENET_CLKCTRL_CMPL) != 0)
|
||||
;
|
||||
writel(PRCM_MOD_EN, &cmalwon->ethernet1clkctrl);
|
||||
while ((readl(&cmalwon->ethernet1clkctrl) & ENET_CLKCTRL_CMPL) != 0)
|
||||
;
|
||||
|
||||
/* RTC clocks */
|
||||
writel(PRCM_MOD_EN, &cmalwon->rtcclkstctrl);
|
||||
writel(PRCM_MOD_EN, &cmalwon->rtcclkctrl);
|
||||
while (readl(&cmalwon->rtcclkctrl) != PRCM_MOD_EN)
|
||||
;
|
||||
}
|
||||
|
||||
/*
|
||||
* select the HS1 or HS2 for DCO Freq
|
||||
* return : CLKCTRL
|
||||
*/
|
||||
static u32 pll_dco_freq_sel(u32 clkout_dco)
|
||||
{
|
||||
if (clkout_dco >= DCO_HS2_MIN && clkout_dco < DCO_HS2_MAX)
|
||||
return SELFREQDCO_HS2;
|
||||
else if (clkout_dco >= DCO_HS1_MIN && clkout_dco < DCO_HS1_MAX)
|
||||
return SELFREQDCO_HS1;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* select the sigma delta config
|
||||
* return: sigma delta val
|
||||
*/
|
||||
static u32 pll_sigma_delta_val(u32 clkout_dco)
|
||||
{
|
||||
u32 sig_val = 0;
|
||||
|
||||
sig_val = (clkout_dco + 225) / 250;
|
||||
sig_val = sig_val << 24;
|
||||
|
||||
return sig_val;
|
||||
}
|
||||
|
||||
/*
|
||||
* configure individual ADPLLJ
|
||||
*/
|
||||
static void pll_config(u32 base, u32 n, u32 m, u32 m2,
|
||||
u32 clkctrl_val, int adpllj)
|
||||
{
|
||||
const struct ad_pll *adpll = (struct ad_pll *)base;
|
||||
u32 m2nval, mn2val, read_clkctrl = 0, clkout_dco = 0;
|
||||
u32 sig_val = 0, hs_mod = 0;
|
||||
|
||||
m2nval = (m2 << ADPLLJ_M2NDIV_M2SHIFT) | n;
|
||||
mn2val = m;
|
||||
|
||||
/* calculate clkout_dco */
|
||||
clkout_dco = ((OSC_0_FREQ / (n+1)) * m);
|
||||
|
||||
/* sigma delta & Hs mode selection skip for ADPLLS*/
|
||||
if (adpllj) {
|
||||
sig_val = pll_sigma_delta_val(clkout_dco);
|
||||
hs_mod = pll_dco_freq_sel(clkout_dco);
|
||||
}
|
||||
|
||||
/* by-pass pll */
|
||||
read_clkctrl = readl(&adpll->clkctrl);
|
||||
writel((read_clkctrl | ADPLLJ_CLKCTRL_IDLE), &adpll->clkctrl);
|
||||
while ((readl(&adpll->status) & ADPLLJ_STATUS_BYPASSANDACK)
|
||||
!= ADPLLJ_STATUS_BYPASSANDACK)
|
||||
;
|
||||
|
||||
/* clear TINITZ */
|
||||
read_clkctrl = readl(&adpll->clkctrl);
|
||||
writel((read_clkctrl & ~ADPLLJ_CLKCTRL_TINITZ), &adpll->clkctrl);
|
||||
|
||||
/*
|
||||
* ref_clk = 20/(n + 1);
|
||||
* clkout_dco = ref_clk * m;
|
||||
* clk_out = clkout_dco/m2;
|
||||
*/
|
||||
read_clkctrl = readl(&adpll->clkctrl) &
|
||||
~(ADPLLJ_CLKCTRL_LPMODE |
|
||||
ADPLLJ_CLKCTRL_DRIFTGUARDIAN |
|
||||
ADPLLJ_CLKCTRL_REGM4XEN);
|
||||
writel(m2nval, &adpll->m2ndiv);
|
||||
writel(mn2val, &adpll->mn2div);
|
||||
|
||||
/* Skip for modena(ADPLLS) */
|
||||
if (adpllj) {
|
||||
writel(sig_val, &adpll->fracdiv);
|
||||
writel((read_clkctrl | hs_mod), &adpll->clkctrl);
|
||||
}
|
||||
|
||||
/* Load M2, N2 dividers of ADPLL */
|
||||
writel(ADPLLJ_TENABLEDIV_ENB, &adpll->tenablediv);
|
||||
writel(~ADPLLJ_TENABLEDIV_ENB, &adpll->tenablediv);
|
||||
|
||||
/* Load M, N dividers of ADPLL */
|
||||
writel(ADPLLJ_TENABLE_ENB, &adpll->tenable);
|
||||
writel(~ADPLLJ_TENABLE_ENB, &adpll->tenable);
|
||||
|
||||
/* Configure CLKDCOLDOEN,CLKOUTLDOEN,CLKOUT Enable BITS */
|
||||
read_clkctrl = readl(&adpll->clkctrl) & ~ADPLLJ_CLKCTRL_CLKDCO;
|
||||
if (adpllj)
|
||||
writel((read_clkctrl | ADPLLJ_CLKCTRL_CLKDCO),
|
||||
&adpll->clkctrl);
|
||||
|
||||
/* Enable TINTZ and disable IDLE(PLL in Active & Locked Mode */
|
||||
read_clkctrl = readl(&adpll->clkctrl) & ~ADPLLJ_CLKCTRL_IDLE;
|
||||
writel((read_clkctrl | ADPLLJ_CLKCTRL_TINITZ), &adpll->clkctrl);
|
||||
|
||||
/* Wait for phase and freq lock */
|
||||
while ((readl(&adpll->status) & ADPLLJ_STATUS_PHSFRQLOCK) !=
|
||||
ADPLLJ_STATUS_PHSFRQLOCK)
|
||||
;
|
||||
}
|
||||
|
||||
static void unlock_pll_control_mmr(void)
|
||||
{
|
||||
/* TRM 2.10.1.4 and 3.2.7-3.2.11 */
|
||||
writel(0x1EDA4C3D, 0x481C5040);
|
||||
writel(0x2FF1AC2B, 0x48140060);
|
||||
writel(0xF757FDC0, 0x48140064);
|
||||
writel(0xE2BC3A6D, 0x48140068);
|
||||
writel(0x1EBF131D, 0x4814006c);
|
||||
writel(0x6F361E05, 0x48140070);
|
||||
}
|
||||
|
||||
static void mpu_pll_config(void)
|
||||
{
|
||||
pll_config(MPU_PLL_BASE, MPU_N, MPU_M, MPU_M2, MPU_CLKCTRL, 0);
|
||||
}
|
||||
|
||||
static void l3_pll_config(void)
|
||||
{
|
||||
u32 l3_osc_src, rd_osc_src = 0;
|
||||
|
||||
l3_osc_src = L3_OSC_SRC;
|
||||
rd_osc_src = readl(OSC_SRC_CTRL);
|
||||
|
||||
if (OSC_SRC0 == l3_osc_src)
|
||||
writel((rd_osc_src & 0xfffffffe)|0x0, OSC_SRC_CTRL);
|
||||
else
|
||||
writel((rd_osc_src & 0xfffffffe)|0x1, OSC_SRC_CTRL);
|
||||
|
||||
pll_config(L3_PLL_BASE, L3_N, L3_M, L3_M2, L3_CLKCTRL, 1);
|
||||
}
|
||||
|
||||
void ddr_pll_config(unsigned int ddrpll_m)
|
||||
{
|
||||
pll_config(DDR_PLL_BASE, DDR_N, DDR_M, DDR_M2, DDR_CLKCTRL, 1);
|
||||
}
|
||||
|
||||
void sata_pll_config(void)
|
||||
{
|
||||
/*
|
||||
* This sequence for configuring the SATA PLL
|
||||
* resident in the control module is documented
|
||||
* in TI8148 TRM section 21.3.1
|
||||
*/
|
||||
writel(SATA_PLLCFG1, &spll->pllcfg1);
|
||||
udelay(50);
|
||||
|
||||
writel(SATA_PLLCFG3, &spll->pllcfg3);
|
||||
udelay(50);
|
||||
|
||||
writel(SATA_PLLCFG0_1, &spll->pllcfg0);
|
||||
udelay(50);
|
||||
|
||||
writel(SATA_PLLCFG0_2, &spll->pllcfg0);
|
||||
udelay(50);
|
||||
|
||||
writel(SATA_PLLCFG0_3, &spll->pllcfg0);
|
||||
udelay(50);
|
||||
|
||||
writel(SATA_PLLCFG0_4, &spll->pllcfg0);
|
||||
udelay(50);
|
||||
|
||||
while (((readl(&spll->pllstatus) & PLL_LOCK) == 0))
|
||||
;
|
||||
}
|
||||
|
||||
void enable_dmm_clocks(void)
|
||||
{
|
||||
writel(PRCM_MOD_EN, &cmdef->fwclkctrl);
|
||||
writel(PRCM_MOD_EN, &cmdef->l3fastclkstctrl);
|
||||
writel(PRCM_MOD_EN, &cmdef->emif0clkctrl);
|
||||
while ((readl(&cmdef->emif0clkctrl)) != PRCM_MOD_EN)
|
||||
;
|
||||
writel(PRCM_MOD_EN, &cmdef->emif1clkctrl);
|
||||
while ((readl(&cmdef->emif1clkctrl)) != PRCM_MOD_EN)
|
||||
;
|
||||
while ((readl(&cmdef->l3fastclkstctrl) & 0x300) != 0x300)
|
||||
;
|
||||
writel(PRCM_MOD_EN, &cmdef->dmmclkctrl);
|
||||
while ((readl(&cmdef->dmmclkctrl)) != PRCM_MOD_EN)
|
||||
;
|
||||
writel(PRCM_MOD_EN, &cmalwon->l3slowclkstctrl);
|
||||
while ((readl(&cmalwon->l3slowclkstctrl) & 0x2100) != 0x2100)
|
||||
;
|
||||
}
|
||||
|
||||
void setup_clocks_for_console(void)
|
||||
{
|
||||
unlock_pll_control_mmr();
|
||||
/* UART0 */
|
||||
writel(PRCM_MOD_EN, &cmalwon->uart0clkctrl);
|
||||
while (readl(&cmalwon->uart0clkctrl) != PRCM_MOD_EN)
|
||||
;
|
||||
}
|
||||
/*
|
||||
* Configure the PLL/PRCM for necessary peripherals
|
||||
*/
|
||||
void prcm_init(void)
|
||||
{
|
||||
/* Enable the control module */
|
||||
writel(PRCM_MOD_EN, &cmalwon->controlclkctrl);
|
||||
|
||||
/* Configure PLLs */
|
||||
mpu_pll_config();
|
||||
l3_pll_config();
|
||||
sata_pll_config();
|
||||
|
||||
/* Enable the required peripherals */
|
||||
enable_per_clocks();
|
||||
}
|
||||
445
u-boot/arch/arm/cpu/armv7/am33xx/clock_ti816x.c
Normal file
445
u-boot/arch/arm/cpu/armv7/am33xx/clock_ti816x.c
Normal file
@@ -0,0 +1,445 @@
|
||||
/*
|
||||
* clock_ti816x.c
|
||||
*
|
||||
* Clocks for TI816X based boards
|
||||
*
|
||||
* Copyright (C) 2013, Adeneo Embedded <www.adeneo-embedded.com>
|
||||
* Antoine Tenart, <atenart@adeneo-embedded.com>
|
||||
*
|
||||
* Based on TI-PSP-04.00.02.14 :
|
||||
*
|
||||
* Copyright (C) 2009, Texas Instruments, Incorporated
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch/ddr_defs.h>
|
||||
#include <asm/arch/cpu.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include <asm/emif.h>
|
||||
|
||||
#define CM_PLL_BASE (CTRL_BASE + 0x0400)
|
||||
|
||||
/* Main PLL */
|
||||
#define MAIN_N 64
|
||||
#define MAIN_P 0x1
|
||||
#define MAIN_INTFREQ1 0x8
|
||||
#define MAIN_FRACFREQ1 0x800000
|
||||
#define MAIN_MDIV1 0x2
|
||||
#define MAIN_INTFREQ2 0xE
|
||||
#define MAIN_FRACFREQ2 0x0
|
||||
#define MAIN_MDIV2 0x1
|
||||
#define MAIN_INTFREQ3 0x8
|
||||
#define MAIN_FRACFREQ3 0xAAAAB0
|
||||
#define MAIN_MDIV3 0x3
|
||||
#define MAIN_INTFREQ4 0x9
|
||||
#define MAIN_FRACFREQ4 0x55554F
|
||||
#define MAIN_MDIV4 0x3
|
||||
#define MAIN_INTFREQ5 0x9
|
||||
#define MAIN_FRACFREQ5 0x374BC6
|
||||
#define MAIN_MDIV5 0xC
|
||||
#define MAIN_MDIV6 0x48
|
||||
#define MAIN_MDIV7 0x4
|
||||
|
||||
/* DDR PLL */
|
||||
#if defined(CONFIG_TI816X_DDR_PLL_400) /* 400 MHz */
|
||||
#define DDR_N 59
|
||||
#define DDR_P 0x1
|
||||
#define DDR_MDIV1 0x4
|
||||
#define DDR_INTFREQ2 0x8
|
||||
#define DDR_FRACFREQ2 0xD99999
|
||||
#define DDR_MDIV2 0x1E
|
||||
#define DDR_INTFREQ3 0x8
|
||||
#define DDR_FRACFREQ3 0x0
|
||||
#define DDR_MDIV3 0x4
|
||||
#define DDR_INTFREQ4 0xE /* Expansion DDR clk */
|
||||
#define DDR_FRACFREQ4 0x0
|
||||
#define DDR_MDIV4 0x4
|
||||
#define DDR_INTFREQ5 0xE /* Expansion DDR clk */
|
||||
#define DDR_FRACFREQ5 0x0
|
||||
#define DDR_MDIV5 0x4
|
||||
#elif defined(CONFIG_TI816X_DDR_PLL_531) /* 531 MHz */
|
||||
#define DDR_N 59
|
||||
#define DDR_P 0x1
|
||||
#define DDR_MDIV1 0x3
|
||||
#define DDR_INTFREQ2 0x8
|
||||
#define DDR_FRACFREQ2 0xD99999
|
||||
#define DDR_MDIV2 0x1E
|
||||
#define DDR_INTFREQ3 0x8
|
||||
#define DDR_FRACFREQ3 0x0
|
||||
#define DDR_MDIV3 0x4
|
||||
#define DDR_INTFREQ4 0xE /* Expansion DDR clk */
|
||||
#define DDR_FRACFREQ4 0x0
|
||||
#define DDR_MDIV4 0x4
|
||||
#define DDR_INTFREQ5 0xE /* Expansion DDR clk */
|
||||
#define DDR_FRACFREQ5 0x0
|
||||
#define DDR_MDIV5 0x4
|
||||
#elif defined(CONFIG_TI816X_DDR_PLL_675) /* 675 MHz */
|
||||
#define DDR_N 50
|
||||
#define DDR_P 0x1
|
||||
#define DDR_MDIV1 0x2
|
||||
#define DDR_INTFREQ2 0x9
|
||||
#define DDR_FRACFREQ2 0x0
|
||||
#define DDR_MDIV2 0x19
|
||||
#define DDR_INTFREQ3 0x13
|
||||
#define DDR_FRACFREQ3 0x800000
|
||||
#define DDR_MDIV3 0x2
|
||||
#define DDR_INTFREQ4 0xE /* Expansion DDR clk */
|
||||
#define DDR_FRACFREQ4 0x0
|
||||
#define DDR_MDIV4 0x4
|
||||
#define DDR_INTFREQ5 0xE /* Expansion DDR clk */
|
||||
#define DDR_FRACFREQ5 0x0
|
||||
#define DDR_MDIV5 0x4
|
||||
#elif defined(CONFIG_TI816X_DDR_PLL_796) /* 796 MHz */
|
||||
#define DDR_N 59
|
||||
#define DDR_P 0x1
|
||||
#define DDR_MDIV1 0x2
|
||||
#define DDR_INTFREQ2 0x8
|
||||
#define DDR_FRACFREQ2 0xD99999
|
||||
#define DDR_MDIV2 0x1E
|
||||
#define DDR_INTFREQ3 0x8
|
||||
#define DDR_FRACFREQ3 0x0
|
||||
#define DDR_MDIV3 0x4
|
||||
#define DDR_INTFREQ4 0xE /* Expansion DDR clk */
|
||||
#define DDR_FRACFREQ4 0x0
|
||||
#define DDR_MDIV4 0x4
|
||||
#define DDR_INTFREQ5 0xE /* Expansion DDR clk */
|
||||
#define DDR_FRACFREQ5 0x0
|
||||
#define DDR_MDIV5 0x4
|
||||
#endif
|
||||
|
||||
#define CONTROL_STATUS (CTRL_BASE + 0x40)
|
||||
#define DDR_RCD (CTRL_BASE + 0x070C)
|
||||
#define CM_TIMER1_CLKSEL (PRCM_BASE + 0x390)
|
||||
#define DMM_PAT_BASE_ADDR (DMM_BASE + 0x420)
|
||||
#define CM_ALWON_CUST_EFUSE_CLKCTRL (PRCM_BASE + 0x1628)
|
||||
|
||||
#define INTCPS_SYSCONFIG 0x48200010
|
||||
#define CM_SYSCLK10_CLKSEL 0x48180324
|
||||
|
||||
struct cm_pll {
|
||||
unsigned int mainpll_ctrl; /* offset 0x400 */
|
||||
unsigned int mainpll_pwd;
|
||||
unsigned int mainpll_freq1;
|
||||
unsigned int mainpll_div1;
|
||||
unsigned int mainpll_freq2;
|
||||
unsigned int mainpll_div2;
|
||||
unsigned int mainpll_freq3;
|
||||
unsigned int mainpll_div3;
|
||||
unsigned int mainpll_freq4;
|
||||
unsigned int mainpll_div4;
|
||||
unsigned int mainpll_freq5;
|
||||
unsigned int mainpll_div5;
|
||||
unsigned int resv0[1];
|
||||
unsigned int mainpll_div6;
|
||||
unsigned int resv1[1];
|
||||
unsigned int mainpll_div7;
|
||||
unsigned int ddrpll_ctrl; /* offset 0x440 */
|
||||
unsigned int ddrpll_pwd;
|
||||
unsigned int resv2[1];
|
||||
unsigned int ddrpll_div1;
|
||||
unsigned int ddrpll_freq2;
|
||||
unsigned int ddrpll_div2;
|
||||
unsigned int ddrpll_freq3;
|
||||
unsigned int ddrpll_div3;
|
||||
unsigned int ddrpll_freq4;
|
||||
unsigned int ddrpll_div4;
|
||||
unsigned int ddrpll_freq5;
|
||||
unsigned int ddrpll_div5;
|
||||
unsigned int videopll_ctrl; /* offset 0x470 */
|
||||
unsigned int videopll_pwd;
|
||||
unsigned int videopll_freq1;
|
||||
unsigned int videopll_div1;
|
||||
unsigned int videopll_freq2;
|
||||
unsigned int videopll_div2;
|
||||
unsigned int videopll_freq3;
|
||||
unsigned int videopll_div3;
|
||||
unsigned int resv3[4];
|
||||
unsigned int audiopll_ctrl; /* offset 0x4A0 */
|
||||
unsigned int audiopll_pwd;
|
||||
unsigned int resv4[2];
|
||||
unsigned int audiopll_freq2;
|
||||
unsigned int audiopll_div2;
|
||||
unsigned int audiopll_freq3;
|
||||
unsigned int audiopll_div3;
|
||||
unsigned int audiopll_freq4;
|
||||
unsigned int audiopll_div4;
|
||||
unsigned int audiopll_freq5;
|
||||
unsigned int audiopll_div5;
|
||||
};
|
||||
|
||||
const struct cm_alwon *cmalwon = (struct cm_alwon *)CM_ALWON_BASE;
|
||||
const struct cm_def *cmdef = (struct cm_def *)CM_DEFAULT_BASE;
|
||||
const struct cm_pll *cmpll = (struct cm_pll *)CM_PLL_BASE;
|
||||
const struct wd_timer *wdtimer = (struct wd_timer *)WDT_BASE;
|
||||
|
||||
void enable_dmm_clocks(void)
|
||||
{
|
||||
writel(PRCM_MOD_EN, &cmdef->l3fastclkstctrl);
|
||||
writel(PRCM_MOD_EN, &cmdef->emif0clkctrl);
|
||||
writel(PRCM_MOD_EN, &cmdef->emif1clkctrl);
|
||||
|
||||
/* Wait for clocks to be active */
|
||||
while ((readl(&cmdef->l3fastclkstctrl) & 0x300) != 0x300)
|
||||
;
|
||||
/* Wait for emif0 to be fully functional, including OCP */
|
||||
while (((readl(&cmdef->emif0clkctrl) >> 17) & 0x3) != 0)
|
||||
;
|
||||
/* Wait for emif1 to be fully functional, including OCP */
|
||||
while (((readl(&cmdef->emif1clkctrl) >> 17) & 0x3) != 0)
|
||||
;
|
||||
|
||||
writel(PRCM_MOD_EN, &cmdef->dmmclkctrl);
|
||||
/* Wait for dmm to be fully functional, including OCP */
|
||||
while (((readl(&cmdef->dmmclkctrl) >> 17) & 0x3) != 0)
|
||||
;
|
||||
|
||||
/* Enable Tiled Access */
|
||||
writel(0x80000000, DMM_PAT_BASE_ADDR);
|
||||
}
|
||||
|
||||
/* assume delay is aprox at least 1us */
|
||||
static void ddr_delay(int d)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* read a control register.
|
||||
* this is a bit more delay and cannot be optimized by the compiler
|
||||
* assuming one read takes 200 cycles and A8 is runing 1 GHz
|
||||
* somewhat conservative setting
|
||||
*/
|
||||
for (i = 0; i < 50*d; i++)
|
||||
readl(CONTROL_STATUS);
|
||||
}
|
||||
|
||||
static void main_pll_init_ti816x(void)
|
||||
{
|
||||
u32 main_pll_ctrl = 0;
|
||||
|
||||
/* Put the PLL in bypass mode by setting BIT2 in its ctrl reg */
|
||||
main_pll_ctrl = readl(&cmpll->mainpll_ctrl);
|
||||
main_pll_ctrl &= 0xFFFFFFFB;
|
||||
main_pll_ctrl |= BIT(2);
|
||||
writel(main_pll_ctrl, &cmpll->mainpll_ctrl);
|
||||
|
||||
/* Enable PLL by setting BIT3 in its ctrl reg */
|
||||
main_pll_ctrl = readl(&cmpll->mainpll_ctrl);
|
||||
main_pll_ctrl &= 0xFFFFFFF7;
|
||||
main_pll_ctrl |= BIT(3);
|
||||
writel(main_pll_ctrl, &cmpll->mainpll_ctrl);
|
||||
|
||||
/* Write the values of N,P in the CTRL reg */
|
||||
main_pll_ctrl = readl(&cmpll->mainpll_ctrl);
|
||||
main_pll_ctrl &= 0xFF;
|
||||
main_pll_ctrl |= (MAIN_N<<16 | MAIN_P<<8);
|
||||
writel(main_pll_ctrl, &cmpll->mainpll_ctrl);
|
||||
|
||||
/* Power up clock1-7 */
|
||||
writel(0x0, &cmpll->mainpll_pwd);
|
||||
|
||||
/* Program the freq and divider values for clock1-7 */
|
||||
writel((1<<31 | 1<<28 | (MAIN_INTFREQ1<<24) | MAIN_FRACFREQ1),
|
||||
&cmpll->mainpll_freq1);
|
||||
writel(((1<<8) | MAIN_MDIV1), &cmpll->mainpll_div1);
|
||||
|
||||
writel((1<<31 | 1<<28 | (MAIN_INTFREQ2<<24) | MAIN_FRACFREQ2),
|
||||
&cmpll->mainpll_freq2);
|
||||
writel(((1<<8) | MAIN_MDIV2), &cmpll->mainpll_div2);
|
||||
|
||||
writel((1<<31 | 1<<28 | (MAIN_INTFREQ3<<24) | MAIN_FRACFREQ3),
|
||||
&cmpll->mainpll_freq3);
|
||||
writel(((1<<8) | MAIN_MDIV3), &cmpll->mainpll_div3);
|
||||
|
||||
writel((1<<31 | 1<<28 | (MAIN_INTFREQ4<<24) | MAIN_FRACFREQ4),
|
||||
&cmpll->mainpll_freq4);
|
||||
writel(((1<<8) | MAIN_MDIV4), &cmpll->mainpll_div4);
|
||||
|
||||
writel((1<<31 | 1<<28 | (MAIN_INTFREQ5<<24) | MAIN_FRACFREQ5),
|
||||
&cmpll->mainpll_freq5);
|
||||
writel(((1<<8) | MAIN_MDIV5), &cmpll->mainpll_div5);
|
||||
|
||||
writel((1<<8 | MAIN_MDIV6), &cmpll->mainpll_div6);
|
||||
|
||||
writel((1<<8 | MAIN_MDIV7), &cmpll->mainpll_div7);
|
||||
|
||||
/* Wait for PLL to lock */
|
||||
while ((readl(&cmpll->mainpll_ctrl) & BIT(7)) != BIT(7))
|
||||
;
|
||||
|
||||
/* Put the PLL in normal mode, disable bypass */
|
||||
main_pll_ctrl = readl(&cmpll->mainpll_ctrl);
|
||||
main_pll_ctrl &= 0xFFFFFFFB;
|
||||
writel(main_pll_ctrl, &cmpll->mainpll_ctrl);
|
||||
}
|
||||
|
||||
static void ddr_pll_bypass_ti816x(void)
|
||||
{
|
||||
u32 ddr_pll_ctrl = 0;
|
||||
|
||||
/* Put the PLL in bypass mode by setting BIT2 in its ctrl reg */
|
||||
ddr_pll_ctrl = readl(&cmpll->ddrpll_ctrl);
|
||||
ddr_pll_ctrl &= 0xFFFFFFFB;
|
||||
ddr_pll_ctrl |= BIT(2);
|
||||
writel(ddr_pll_ctrl, &cmpll->ddrpll_ctrl);
|
||||
}
|
||||
|
||||
static void ddr_pll_init_ti816x(void)
|
||||
{
|
||||
u32 ddr_pll_ctrl = 0;
|
||||
/* Enable PLL by setting BIT3 in its ctrl reg */
|
||||
ddr_pll_ctrl = readl(&cmpll->ddrpll_ctrl);
|
||||
ddr_pll_ctrl &= 0xFFFFFFF7;
|
||||
ddr_pll_ctrl |= BIT(3);
|
||||
writel(ddr_pll_ctrl, &cmpll->ddrpll_ctrl);
|
||||
|
||||
/* Write the values of N,P in the CTRL reg */
|
||||
ddr_pll_ctrl = readl(&cmpll->ddrpll_ctrl);
|
||||
ddr_pll_ctrl &= 0xFF;
|
||||
ddr_pll_ctrl |= (DDR_N<<16 | DDR_P<<8);
|
||||
writel(ddr_pll_ctrl, &cmpll->ddrpll_ctrl);
|
||||
|
||||
ddr_delay(10);
|
||||
|
||||
/* Power up clock1-5 */
|
||||
writel(0x0, &cmpll->ddrpll_pwd);
|
||||
|
||||
/* Program the freq and divider values for clock1-3 */
|
||||
writel(((0<<8) | DDR_MDIV1), &cmpll->ddrpll_div1);
|
||||
ddr_delay(1);
|
||||
writel(((1<<8) | DDR_MDIV1), &cmpll->ddrpll_div1);
|
||||
writel((1<<31 | 1<<28 | (DDR_INTFREQ2<<24) | DDR_FRACFREQ2),
|
||||
&cmpll->ddrpll_freq2);
|
||||
writel(((1<<8) | DDR_MDIV2), &cmpll->ddrpll_div2);
|
||||
writel(((0<<8) | DDR_MDIV3), &cmpll->ddrpll_div3);
|
||||
ddr_delay(1);
|
||||
writel(((1<<8) | DDR_MDIV3), &cmpll->ddrpll_div3);
|
||||
ddr_delay(1);
|
||||
writel((0<<31 | 1<<28 | (DDR_INTFREQ3<<24) | DDR_FRACFREQ3),
|
||||
&cmpll->ddrpll_freq3);
|
||||
ddr_delay(1);
|
||||
writel((1<<31 | 1<<28 | (DDR_INTFREQ3<<24) | DDR_FRACFREQ3),
|
||||
&cmpll->ddrpll_freq3);
|
||||
|
||||
ddr_delay(5);
|
||||
|
||||
/* Wait for PLL to lock */
|
||||
while ((readl(&cmpll->ddrpll_ctrl) & BIT(7)) != BIT(7))
|
||||
;
|
||||
|
||||
/* Power up RCD */
|
||||
writel(BIT(0), DDR_RCD);
|
||||
}
|
||||
|
||||
static void peripheral_enable(void)
|
||||
{
|
||||
/* Wake-up the l3_slow clock */
|
||||
writel(PRCM_MOD_EN, &cmalwon->l3slowclkstctrl);
|
||||
|
||||
/*
|
||||
* Note on Timers:
|
||||
* There are 8 timers(0-7) out of which timer 0 is a secure timer.
|
||||
* Timer 0 mux should not be changed
|
||||
*
|
||||
* To access the timer registers we need the to be
|
||||
* enabled which is what we do in the first step
|
||||
*/
|
||||
|
||||
/* Enable timer1 */
|
||||
writel(PRCM_MOD_EN, &cmalwon->timer1clkctrl);
|
||||
/* Select timer1 clock to be CLKIN (27MHz) */
|
||||
writel(BIT(1), CM_TIMER1_CLKSEL);
|
||||
|
||||
/* Wait for timer1 to be ON-ACTIVE */
|
||||
while (((readl(&cmalwon->l3slowclkstctrl)
|
||||
& (0x80000<<1))>>20) != 1)
|
||||
;
|
||||
/* Wait for timer1 to be enabled */
|
||||
while (((readl(&cmalwon->timer1clkctrl) & 0x30000)>>16) != 0)
|
||||
;
|
||||
/* Active posted mode */
|
||||
writel(PRCM_MOD_EN, (DM_TIMER1_BASE + 0x54));
|
||||
while (readl(DM_TIMER1_BASE + 0x10) & BIT(0))
|
||||
;
|
||||
/* Start timer1 */
|
||||
writel(BIT(0), (DM_TIMER1_BASE + 0x38));
|
||||
|
||||
/* eFuse */
|
||||
writel(PRCM_MOD_EN, CM_ALWON_CUST_EFUSE_CLKCTRL);
|
||||
while (readl(CM_ALWON_CUST_EFUSE_CLKCTRL) != PRCM_MOD_EN)
|
||||
;
|
||||
|
||||
/* Enable gpio0 */
|
||||
writel(PRCM_MOD_EN, &cmalwon->gpio0clkctrl);
|
||||
while (readl(&cmalwon->gpio0clkctrl) != PRCM_MOD_EN)
|
||||
;
|
||||
writel((BIT(8)), &cmalwon->gpio0clkctrl);
|
||||
|
||||
/* Enable spi */
|
||||
writel(PRCM_MOD_EN, &cmalwon->spiclkctrl);
|
||||
while (readl(&cmalwon->spiclkctrl) != PRCM_MOD_EN)
|
||||
;
|
||||
|
||||
/* Enable i2c0 */
|
||||
writel(PRCM_MOD_EN, &cmalwon->i2c0clkctrl);
|
||||
while (readl(&cmalwon->i2c0clkctrl) != PRCM_MOD_EN)
|
||||
;
|
||||
|
||||
/* Enable ethernet0 */
|
||||
writel(PRCM_MOD_EN, &cmalwon->ethclkstctrl);
|
||||
writel(PRCM_MOD_EN, &cmalwon->ethernet0clkctrl);
|
||||
writel(PRCM_MOD_EN, &cmalwon->ethernet1clkctrl);
|
||||
|
||||
/* Enable hsmmc */
|
||||
writel(PRCM_MOD_EN, &cmalwon->sdioclkctrl);
|
||||
while (readl(&cmalwon->sdioclkctrl) != PRCM_MOD_EN)
|
||||
;
|
||||
}
|
||||
|
||||
void setup_clocks_for_console(void)
|
||||
{
|
||||
/* Fix ROM code bug - from TI-PSP-04.00.02.14 */
|
||||
writel(0x0, CM_SYSCLK10_CLKSEL);
|
||||
|
||||
ddr_pll_bypass_ti816x();
|
||||
|
||||
/* Enable uart0-2 */
|
||||
writel(PRCM_MOD_EN, &cmalwon->uart0clkctrl);
|
||||
while (readl(&cmalwon->uart0clkctrl) != PRCM_MOD_EN)
|
||||
;
|
||||
writel(PRCM_MOD_EN, &cmalwon->uart1clkctrl);
|
||||
while (readl(&cmalwon->uart1clkctrl) != PRCM_MOD_EN)
|
||||
;
|
||||
writel(PRCM_MOD_EN, &cmalwon->uart2clkctrl);
|
||||
while (readl(&cmalwon->uart2clkctrl) != PRCM_MOD_EN)
|
||||
;
|
||||
while ((readl(&cmalwon->l3slowclkstctrl) & 0x2100) != 0x2100)
|
||||
;
|
||||
}
|
||||
|
||||
void prcm_init(void)
|
||||
{
|
||||
/* Enable the control */
|
||||
writel(PRCM_MOD_EN, &cmalwon->controlclkctrl);
|
||||
|
||||
main_pll_init_ti816x();
|
||||
ddr_pll_init_ti816x();
|
||||
|
||||
/*
|
||||
* With clk freqs setup to desired values,
|
||||
* enable the required peripherals
|
||||
*/
|
||||
peripheral_enable();
|
||||
}
|
||||
31
u-boot/arch/arm/cpu/armv7/am33xx/config.mk
Normal file
31
u-boot/arch/arm/cpu/armv7/am33xx/config.mk
Normal file
@@ -0,0 +1,31 @@
|
||||
#
|
||||
# Copyright (C) 2011, Texas Instruments, Incorporated - http://www.ti.com/
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
include $(srctree)/$(CPUDIR)/omap-common/config_secure.mk
|
||||
|
||||
ifdef CONFIG_SPL_BUILD
|
||||
ifeq ($(CONFIG_TI_SECURE_DEVICE),y)
|
||||
#
|
||||
# For booting from SPI use
|
||||
# u-boot-spl_HS_SPI_X-LOADER to program flash
|
||||
#
|
||||
# For booting spl from all other media
|
||||
# use u-boot-spl_HS_ISSW
|
||||
#
|
||||
# Refer to README.ti-secure for more info
|
||||
#
|
||||
ALL-y += u-boot-spl_HS_ISSW
|
||||
ALL-$(CONFIG_SPL_SPI_SUPPORT) += u-boot-spl_HS_SPI_X-LOADER
|
||||
else
|
||||
ALL-y += MLO
|
||||
ALL-$(CONFIG_SPL_SPI_SUPPORT) += MLO.byteswap
|
||||
endif
|
||||
else
|
||||
ifeq ($(CONFIG_TI_SECURE_DEVICE),y)
|
||||
ALL-$(CONFIG_QSPI_BOOT) += u-boot_HS_XIP_X-LOADER
|
||||
endif
|
||||
ALL-y += u-boot.img
|
||||
endif
|
||||
379
u-boot/arch/arm/cpu/armv7/am33xx/ddr.c
Normal file
379
u-boot/arch/arm/cpu/armv7/am33xx/ddr.c
Normal file
@@ -0,0 +1,379 @@
|
||||
/*
|
||||
* DDR Configuration for AM33xx devices.
|
||||
*
|
||||
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <asm/arch/cpu.h>
|
||||
#include <asm/arch/ddr_defs.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/emif.h>
|
||||
|
||||
/**
|
||||
* Base address for EMIF instances
|
||||
*/
|
||||
static struct emif_reg_struct *emif_reg[2] = {
|
||||
(struct emif_reg_struct *)EMIF4_0_CFG_BASE,
|
||||
(struct emif_reg_struct *)EMIF4_1_CFG_BASE};
|
||||
|
||||
/**
|
||||
* Base addresses for DDR PHY cmd/data regs
|
||||
*/
|
||||
static struct ddr_cmd_regs *ddr_cmd_reg[2] = {
|
||||
(struct ddr_cmd_regs *)DDR_PHY_CMD_ADDR,
|
||||
(struct ddr_cmd_regs *)DDR_PHY_CMD_ADDR2};
|
||||
|
||||
static struct ddr_data_regs *ddr_data_reg[2] = {
|
||||
(struct ddr_data_regs *)DDR_PHY_DATA_ADDR,
|
||||
(struct ddr_data_regs *)DDR_PHY_DATA_ADDR2};
|
||||
|
||||
/**
|
||||
* Base address for ddr io control instances
|
||||
*/
|
||||
static struct ddr_cmdtctrl *ioctrl_reg = {
|
||||
(struct ddr_cmdtctrl *)DDR_CONTROL_BASE_ADDR};
|
||||
|
||||
static inline u32 get_mr(int nr, u32 cs, u32 mr_addr)
|
||||
{
|
||||
u32 mr;
|
||||
|
||||
mr_addr |= cs << EMIF_REG_CS_SHIFT;
|
||||
writel(mr_addr, &emif_reg[nr]->emif_lpddr2_mode_reg_cfg);
|
||||
|
||||
mr = readl(&emif_reg[nr]->emif_lpddr2_mode_reg_data);
|
||||
debug("get_mr: EMIF1 cs %d mr %08x val 0x%x\n", cs, mr_addr, mr);
|
||||
if (((mr & 0x0000ff00) >> 8) == (mr & 0xff) &&
|
||||
((mr & 0x00ff0000) >> 16) == (mr & 0xff) &&
|
||||
((mr & 0xff000000) >> 24) == (mr & 0xff))
|
||||
return mr & 0xff;
|
||||
else
|
||||
return mr;
|
||||
}
|
||||
|
||||
static inline void set_mr(int nr, u32 cs, u32 mr_addr, u32 mr_val)
|
||||
{
|
||||
mr_addr |= cs << EMIF_REG_CS_SHIFT;
|
||||
writel(mr_addr, &emif_reg[nr]->emif_lpddr2_mode_reg_cfg);
|
||||
writel(mr_val, &emif_reg[nr]->emif_lpddr2_mode_reg_data);
|
||||
}
|
||||
|
||||
static void configure_mr(int nr, u32 cs)
|
||||
{
|
||||
u32 mr_addr;
|
||||
|
||||
while (get_mr(nr, cs, LPDDR2_MR0) & LPDDR2_MR0_DAI_MASK)
|
||||
;
|
||||
set_mr(nr, cs, LPDDR2_MR10, 0x56);
|
||||
|
||||
set_mr(nr, cs, LPDDR2_MR1, 0x43);
|
||||
set_mr(nr, cs, LPDDR2_MR2, 0x2);
|
||||
|
||||
mr_addr = LPDDR2_MR2 | EMIF_REG_REFRESH_EN_MASK;
|
||||
set_mr(nr, cs, mr_addr, 0x2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure EMIF4D5 registers and MR registers For details about these magic
|
||||
* values please see the EMIF registers section of the TRM.
|
||||
*/
|
||||
void config_sdram_emif4d5(const struct emif_regs *regs, int nr)
|
||||
{
|
||||
writel(0xA0, &emif_reg[nr]->emif_pwr_mgmt_ctrl);
|
||||
writel(0xA0, &emif_reg[nr]->emif_pwr_mgmt_ctrl_shdw);
|
||||
writel(regs->zq_config, &emif_reg[nr]->emif_zq_config);
|
||||
|
||||
writel(regs->temp_alert_config, &emif_reg[nr]->emif_temp_alert_config);
|
||||
writel(regs->emif_rd_wr_lvl_rmp_win,
|
||||
&emif_reg[nr]->emif_rd_wr_lvl_rmp_win);
|
||||
writel(regs->emif_rd_wr_lvl_rmp_ctl,
|
||||
&emif_reg[nr]->emif_rd_wr_lvl_rmp_ctl);
|
||||
writel(regs->emif_rd_wr_lvl_ctl, &emif_reg[nr]->emif_rd_wr_lvl_ctl);
|
||||
writel(regs->emif_rd_wr_exec_thresh,
|
||||
&emif_reg[nr]->emif_rd_wr_exec_thresh);
|
||||
|
||||
/*
|
||||
* for most SOCs these registers won't need to be changed so only
|
||||
* write to these registers if someone explicitly has set the
|
||||
* register's value.
|
||||
*/
|
||||
if(regs->emif_cos_config) {
|
||||
writel(regs->emif_prio_class_serv_map, &emif_reg[nr]->emif_prio_class_serv_map);
|
||||
writel(regs->emif_connect_id_serv_1_map, &emif_reg[nr]->emif_connect_id_serv_1_map);
|
||||
writel(regs->emif_connect_id_serv_2_map, &emif_reg[nr]->emif_connect_id_serv_2_map);
|
||||
writel(regs->emif_cos_config, &emif_reg[nr]->emif_cos_config);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sequence to ensure that the PHY is in a known state prior to
|
||||
* startting hardware leveling. Also acts as to latch some state from
|
||||
* the EMIF into the PHY.
|
||||
*/
|
||||
writel(0x2011, &emif_reg[nr]->emif_iodft_tlgc);
|
||||
writel(0x2411, &emif_reg[nr]->emif_iodft_tlgc);
|
||||
writel(0x2011, &emif_reg[nr]->emif_iodft_tlgc);
|
||||
|
||||
clrbits_le32(&emif_reg[nr]->emif_sdram_ref_ctrl,
|
||||
EMIF_REG_INITREF_DIS_MASK);
|
||||
|
||||
writel(regs->sdram_config, &emif_reg[nr]->emif_sdram_config);
|
||||
writel(regs->sdram_config, &cstat->secure_emif_sdram_config);
|
||||
writel(regs->ref_ctrl, &emif_reg[nr]->emif_sdram_ref_ctrl);
|
||||
writel(regs->ref_ctrl, &emif_reg[nr]->emif_sdram_ref_ctrl_shdw);
|
||||
|
||||
/* Perform hardware leveling for DDR3 */
|
||||
if (emif_sdram_type(regs->sdram_config) == EMIF_SDRAM_TYPE_DDR3) {
|
||||
udelay(1000);
|
||||
writel(readl(&emif_reg[nr]->emif_ddr_ext_phy_ctrl_36) |
|
||||
0x100, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_36);
|
||||
writel(readl(&emif_reg[nr]->emif_ddr_ext_phy_ctrl_36_shdw) |
|
||||
0x100, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_36_shdw);
|
||||
|
||||
writel(0x80000000, &emif_reg[nr]->emif_rd_wr_lvl_rmp_ctl);
|
||||
|
||||
/* Enable read leveling */
|
||||
writel(0x80000000, &emif_reg[nr]->emif_rd_wr_lvl_ctl);
|
||||
|
||||
/*
|
||||
* Enable full read and write leveling. Wait for read and write
|
||||
* leveling bit to clear RDWRLVLFULL_START bit 31
|
||||
*/
|
||||
while ((readl(&emif_reg[nr]->emif_rd_wr_lvl_ctl) & 0x80000000)
|
||||
!= 0)
|
||||
;
|
||||
|
||||
/* Check the timeout register to see if leveling is complete */
|
||||
if ((readl(&emif_reg[nr]->emif_status) & 0x70) != 0)
|
||||
puts("DDR3 H/W leveling incomplete with errors\n");
|
||||
|
||||
} else {
|
||||
/* DDR2 */
|
||||
configure_mr(nr, 0);
|
||||
configure_mr(nr, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure SDRAM
|
||||
*/
|
||||
void config_sdram(const struct emif_regs *regs, int nr)
|
||||
{
|
||||
if (regs->zq_config) {
|
||||
writel(regs->zq_config, &emif_reg[nr]->emif_zq_config);
|
||||
writel(regs->sdram_config, &cstat->secure_emif_sdram_config);
|
||||
writel(regs->sdram_config, &emif_reg[nr]->emif_sdram_config);
|
||||
|
||||
/* Trigger initialization */
|
||||
writel(0x00003100, &emif_reg[nr]->emif_sdram_ref_ctrl);
|
||||
/* Wait 1ms because of L3 timeout error */
|
||||
udelay(1000);
|
||||
|
||||
/* Write proper sdram_ref_cref_ctrl value */
|
||||
writel(regs->ref_ctrl, &emif_reg[nr]->emif_sdram_ref_ctrl);
|
||||
writel(regs->ref_ctrl, &emif_reg[nr]->emif_sdram_ref_ctrl_shdw);
|
||||
}
|
||||
writel(regs->ref_ctrl, &emif_reg[nr]->emif_sdram_ref_ctrl);
|
||||
writel(regs->ref_ctrl, &emif_reg[nr]->emif_sdram_ref_ctrl_shdw);
|
||||
writel(regs->sdram_config, &emif_reg[nr]->emif_sdram_config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set SDRAM timings
|
||||
*/
|
||||
void set_sdram_timings(const struct emif_regs *regs, int nr)
|
||||
{
|
||||
writel(regs->sdram_tim1, &emif_reg[nr]->emif_sdram_tim_1);
|
||||
writel(regs->sdram_tim1, &emif_reg[nr]->emif_sdram_tim_1_shdw);
|
||||
writel(regs->sdram_tim2, &emif_reg[nr]->emif_sdram_tim_2);
|
||||
writel(regs->sdram_tim2, &emif_reg[nr]->emif_sdram_tim_2_shdw);
|
||||
writel(regs->sdram_tim3, &emif_reg[nr]->emif_sdram_tim_3);
|
||||
writel(regs->sdram_tim3, &emif_reg[nr]->emif_sdram_tim_3_shdw);
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure EXT PHY registers for software leveling
|
||||
*/
|
||||
static void ext_phy_settings_swlvl(const struct emif_regs *regs, int nr)
|
||||
{
|
||||
u32 *ext_phy_ctrl_base = 0;
|
||||
u32 *emif_ext_phy_ctrl_base = 0;
|
||||
__maybe_unused const u32 *ext_phy_ctrl_const_regs;
|
||||
u32 i = 0;
|
||||
__maybe_unused u32 size;
|
||||
|
||||
ext_phy_ctrl_base = (u32 *)&(regs->emif_ddr_ext_phy_ctrl_1);
|
||||
emif_ext_phy_ctrl_base =
|
||||
(u32 *)&(emif_reg[nr]->emif_ddr_ext_phy_ctrl_1);
|
||||
|
||||
/* Configure external phy control timing registers */
|
||||
for (i = 0; i < EMIF_EXT_PHY_CTRL_TIMING_REG; i++) {
|
||||
writel(*ext_phy_ctrl_base, emif_ext_phy_ctrl_base++);
|
||||
/* Update shadow registers */
|
||||
writel(*ext_phy_ctrl_base++, emif_ext_phy_ctrl_base++);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_AM43XX
|
||||
/*
|
||||
* External phy 6-24 registers do not change with ddr frequency.
|
||||
* These only need to be set on DDR2 on AM43xx.
|
||||
*/
|
||||
emif_get_ext_phy_ctrl_const_regs(&ext_phy_ctrl_const_regs, &size);
|
||||
|
||||
if (!size)
|
||||
return;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
writel(ext_phy_ctrl_const_regs[i], emif_ext_phy_ctrl_base++);
|
||||
/* Update shadow registers */
|
||||
writel(ext_phy_ctrl_const_regs[i], emif_ext_phy_ctrl_base++);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure EXT PHY registers for hardware leveling
|
||||
*/
|
||||
static void ext_phy_settings_hwlvl(const struct emif_regs *regs, int nr)
|
||||
{
|
||||
/*
|
||||
* Enable hardware leveling on the EMIF. For details about these
|
||||
* magic values please see the EMIF registers section of the TRM.
|
||||
*/
|
||||
writel(0x08020080, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_1);
|
||||
writel(0x08020080, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_1_shdw);
|
||||
writel(0x00000000, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_22);
|
||||
writel(0x00000000, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_22_shdw);
|
||||
writel(0x00600020, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_23);
|
||||
writel(0x00600020, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_23_shdw);
|
||||
writel(0x40010080, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_24);
|
||||
writel(0x40010080, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_24_shdw);
|
||||
writel(0x08102040, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_25);
|
||||
writel(0x08102040, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_25_shdw);
|
||||
writel(0x00200020, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_26);
|
||||
writel(0x00200020, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_26_shdw);
|
||||
writel(0x00200020, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_27);
|
||||
writel(0x00200020, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_27_shdw);
|
||||
writel(0x00200020, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_28);
|
||||
writel(0x00200020, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_28_shdw);
|
||||
writel(0x00200020, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_29);
|
||||
writel(0x00200020, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_29_shdw);
|
||||
writel(0x00200020, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_30);
|
||||
writel(0x00200020, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_30_shdw);
|
||||
writel(0x00000000, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_31);
|
||||
writel(0x00000000, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_31_shdw);
|
||||
writel(0x00000000, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_32);
|
||||
writel(0x00000000, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_32_shdw);
|
||||
writel(0x00000000, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_33);
|
||||
writel(0x00000000, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_33_shdw);
|
||||
writel(0x00000000, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_34);
|
||||
writel(0x00000000, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_34_shdw);
|
||||
writel(0x00000000, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_35);
|
||||
writel(0x00000000, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_35_shdw);
|
||||
writel(0x000000FF, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_36);
|
||||
writel(0x000000FF, &emif_reg[nr]->emif_ddr_ext_phy_ctrl_36_shdw);
|
||||
|
||||
/*
|
||||
* Sequence to ensure that the PHY is again in a known state after
|
||||
* hardware leveling.
|
||||
*/
|
||||
writel(0x2011, &emif_reg[nr]->emif_iodft_tlgc);
|
||||
writel(0x2411, &emif_reg[nr]->emif_iodft_tlgc);
|
||||
writel(0x2011, &emif_reg[nr]->emif_iodft_tlgc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure DDR PHY
|
||||
*/
|
||||
void config_ddr_phy(const struct emif_regs *regs, int nr)
|
||||
{
|
||||
/*
|
||||
* Disable initialization and refreshes for now until we
|
||||
* finish programming EMIF regs.
|
||||
* Also set time between rising edge of DDR_RESET to rising
|
||||
* edge of DDR_CKE to > 500us per memory spec.
|
||||
*/
|
||||
#ifndef CONFIG_AM43XX
|
||||
setbits_le32(&emif_reg[nr]->emif_sdram_ref_ctrl,
|
||||
EMIF_REG_INITREF_DIS_MASK);
|
||||
#endif
|
||||
if (regs->zq_config)
|
||||
/* Set time between rising edge of DDR_RESET to rising
|
||||
* edge of DDR_CKE to > 500us per memory spec. */
|
||||
writel(0x00003100, &emif_reg[nr]->emif_sdram_ref_ctrl);
|
||||
|
||||
writel(regs->emif_ddr_phy_ctlr_1,
|
||||
&emif_reg[nr]->emif_ddr_phy_ctrl_1);
|
||||
writel(regs->emif_ddr_phy_ctlr_1,
|
||||
&emif_reg[nr]->emif_ddr_phy_ctrl_1_shdw);
|
||||
|
||||
if (get_emif_rev((u32)emif_reg[nr]) == EMIF_4D5) {
|
||||
if (emif_sdram_type(regs->sdram_config) == EMIF_SDRAM_TYPE_DDR3)
|
||||
ext_phy_settings_hwlvl(regs, nr);
|
||||
else
|
||||
ext_phy_settings_swlvl(regs, nr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure DDR CMD control registers
|
||||
*/
|
||||
void config_cmd_ctrl(const struct cmd_control *cmd, int nr)
|
||||
{
|
||||
if (!cmd)
|
||||
return;
|
||||
|
||||
writel(cmd->cmd0csratio, &ddr_cmd_reg[nr]->cm0csratio);
|
||||
writel(cmd->cmd0iclkout, &ddr_cmd_reg[nr]->cm0iclkout);
|
||||
|
||||
writel(cmd->cmd1csratio, &ddr_cmd_reg[nr]->cm1csratio);
|
||||
writel(cmd->cmd1iclkout, &ddr_cmd_reg[nr]->cm1iclkout);
|
||||
|
||||
writel(cmd->cmd2csratio, &ddr_cmd_reg[nr]->cm2csratio);
|
||||
writel(cmd->cmd2iclkout, &ddr_cmd_reg[nr]->cm2iclkout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure DDR DATA registers
|
||||
*/
|
||||
void config_ddr_data(const struct ddr_data *data, int nr)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
for (i = 0; i < DDR_DATA_REGS_NR; i++) {
|
||||
writel(data->datardsratio0,
|
||||
&(ddr_data_reg[nr]+i)->dt0rdsratio0);
|
||||
writel(data->datawdsratio0,
|
||||
&(ddr_data_reg[nr]+i)->dt0wdsratio0);
|
||||
writel(data->datawiratio0,
|
||||
&(ddr_data_reg[nr]+i)->dt0wiratio0);
|
||||
writel(data->datagiratio0,
|
||||
&(ddr_data_reg[nr]+i)->dt0giratio0);
|
||||
writel(data->datafwsratio0,
|
||||
&(ddr_data_reg[nr]+i)->dt0fwsratio0);
|
||||
writel(data->datawrsratio0,
|
||||
&(ddr_data_reg[nr]+i)->dt0wrsratio0);
|
||||
}
|
||||
}
|
||||
|
||||
void config_io_ctrl(const struct ctrl_ioregs *ioregs)
|
||||
{
|
||||
if (!ioregs)
|
||||
return;
|
||||
|
||||
writel(ioregs->cm0ioctl, &ioctrl_reg->cm0ioctl);
|
||||
writel(ioregs->cm1ioctl, &ioctrl_reg->cm1ioctl);
|
||||
writel(ioregs->cm2ioctl, &ioctrl_reg->cm2ioctl);
|
||||
writel(ioregs->dt0ioctl, &ioctrl_reg->dt0ioctl);
|
||||
writel(ioregs->dt1ioctl, &ioctrl_reg->dt1ioctl);
|
||||
#ifdef CONFIG_AM43XX
|
||||
writel(ioregs->dt2ioctrl, &ioctrl_reg->dt2ioctrl);
|
||||
writel(ioregs->dt3ioctrl, &ioctrl_reg->dt3ioctrl);
|
||||
writel(ioregs->emif_sdram_config_ext,
|
||||
&ioctrl_reg->emif_sdram_config_ext);
|
||||
#endif
|
||||
}
|
||||
140
u-boot/arch/arm/cpu/armv7/am33xx/emif4.c
Normal file
140
u-boot/arch/arm/cpu/armv7/am33xx/emif4.c
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* emif4.c
|
||||
*
|
||||
* AM33XX emif4 configuration file
|
||||
*
|
||||
* Copyright (C) 2011, Texas Instruments, Incorporated - http://www.ti.com/
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch/cpu.h>
|
||||
#include <asm/arch/ddr_defs.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/emif.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
int dram_init(void)
|
||||
{
|
||||
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
|
||||
sdram_init();
|
||||
#endif
|
||||
|
||||
/* dram_init must store complete ramsize in gd->ram_size */
|
||||
gd->ram_size = get_ram_size(
|
||||
(void *)CONFIG_SYS_SDRAM_BASE,
|
||||
CONFIG_MAX_RAM_BANK_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dram_init_banksize(void)
|
||||
{
|
||||
gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
|
||||
gd->bd->bi_dram[0].size = gd->ram_size;
|
||||
}
|
||||
|
||||
|
||||
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
|
||||
#ifdef CONFIG_TI81XX
|
||||
static struct dmm_lisa_map_regs *hw_lisa_map_regs =
|
||||
(struct dmm_lisa_map_regs *)DMM_BASE;
|
||||
#endif
|
||||
#ifndef CONFIG_TI816X
|
||||
static struct vtp_reg *vtpreg[2] = {
|
||||
(struct vtp_reg *)VTP0_CTRL_ADDR,
|
||||
(struct vtp_reg *)VTP1_CTRL_ADDR};
|
||||
#endif
|
||||
#ifdef CONFIG_AM33XX
|
||||
static struct ddr_ctrl *ddrctrl = (struct ddr_ctrl *)DDR_CTRL_ADDR;
|
||||
#endif
|
||||
#ifdef CONFIG_AM43XX
|
||||
static struct ddr_ctrl *ddrctrl = (struct ddr_ctrl *)DDR_CTRL_ADDR;
|
||||
static struct cm_device_inst *cm_device =
|
||||
(struct cm_device_inst *)CM_DEVICE_INST;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TI81XX
|
||||
void config_dmm(const struct dmm_lisa_map_regs *regs)
|
||||
{
|
||||
enable_dmm_clocks();
|
||||
|
||||
writel(0, &hw_lisa_map_regs->dmm_lisa_map_3);
|
||||
writel(0, &hw_lisa_map_regs->dmm_lisa_map_2);
|
||||
writel(0, &hw_lisa_map_regs->dmm_lisa_map_1);
|
||||
writel(0, &hw_lisa_map_regs->dmm_lisa_map_0);
|
||||
|
||||
writel(regs->dmm_lisa_map_3, &hw_lisa_map_regs->dmm_lisa_map_3);
|
||||
writel(regs->dmm_lisa_map_2, &hw_lisa_map_regs->dmm_lisa_map_2);
|
||||
writel(regs->dmm_lisa_map_1, &hw_lisa_map_regs->dmm_lisa_map_1);
|
||||
writel(regs->dmm_lisa_map_0, &hw_lisa_map_regs->dmm_lisa_map_0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TI816X
|
||||
static void config_vtp(int nr)
|
||||
{
|
||||
writel(readl(&vtpreg[nr]->vtp0ctrlreg) | VTP_CTRL_ENABLE,
|
||||
&vtpreg[nr]->vtp0ctrlreg);
|
||||
writel(readl(&vtpreg[nr]->vtp0ctrlreg) & (~VTP_CTRL_START_EN),
|
||||
&vtpreg[nr]->vtp0ctrlreg);
|
||||
writel(readl(&vtpreg[nr]->vtp0ctrlreg) | VTP_CTRL_START_EN,
|
||||
&vtpreg[nr]->vtp0ctrlreg);
|
||||
|
||||
/* Poll for READY */
|
||||
while ((readl(&vtpreg[nr]->vtp0ctrlreg) & VTP_CTRL_READY) !=
|
||||
VTP_CTRL_READY)
|
||||
;
|
||||
}
|
||||
#endif
|
||||
|
||||
void __weak ddr_pll_config(unsigned int ddrpll_m)
|
||||
{
|
||||
}
|
||||
|
||||
void config_ddr(unsigned int pll, const struct ctrl_ioregs *ioregs,
|
||||
const struct ddr_data *data, const struct cmd_control *ctrl,
|
||||
const struct emif_regs *regs, int nr)
|
||||
{
|
||||
ddr_pll_config(pll);
|
||||
#ifndef CONFIG_TI816X
|
||||
config_vtp(nr);
|
||||
#endif
|
||||
config_cmd_ctrl(ctrl, nr);
|
||||
|
||||
config_ddr_data(data, nr);
|
||||
#ifdef CONFIG_AM33XX
|
||||
config_io_ctrl(ioregs);
|
||||
|
||||
/* Set CKE to be controlled by EMIF/DDR PHY */
|
||||
writel(DDR_CKE_CTRL_NORMAL, &ddrctrl->ddrckectrl);
|
||||
|
||||
#endif
|
||||
#ifdef CONFIG_AM43XX
|
||||
writel(readl(&cm_device->cm_dll_ctrl) & ~0x1, &cm_device->cm_dll_ctrl);
|
||||
while ((readl(&cm_device->cm_dll_ctrl) & CM_DLL_READYST) == 0)
|
||||
;
|
||||
|
||||
config_io_ctrl(ioregs);
|
||||
|
||||
/* Set CKE to be controlled by EMIF/DDR PHY */
|
||||
writel(DDR_CKE_CTRL_NORMAL, &ddrctrl->ddrckectrl);
|
||||
|
||||
if (emif_sdram_type(regs->sdram_config) == EMIF_SDRAM_TYPE_DDR3)
|
||||
/* Allow EMIF to control DDR_RESET */
|
||||
writel(0x00000000, &ddrctrl->ddrioctrl);
|
||||
#endif
|
||||
|
||||
/* Program EMIF instance */
|
||||
config_ddr_phy(regs, nr);
|
||||
set_sdram_timings(regs, nr);
|
||||
if (get_emif_rev(EMIF1_BASE) == EMIF_4D5)
|
||||
config_sdram_emif4d5(regs, nr);
|
||||
else
|
||||
config_sdram(regs, nr);
|
||||
}
|
||||
#endif
|
||||
33
u-boot/arch/arm/cpu/armv7/am33xx/mux.c
Normal file
33
u-boot/arch/arm/cpu/armv7/am33xx/mux.c
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* mux.c
|
||||
*
|
||||
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation version 2.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch/mux.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/*
|
||||
* Configure the pin mux for the module
|
||||
*/
|
||||
void configure_module_pin_mux(struct module_pin_mux *mod_pin_mux)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!mod_pin_mux)
|
||||
return;
|
||||
|
||||
for (i = 0; mod_pin_mux[i].reg_offset != -1; i++)
|
||||
MUX_CFG(mod_pin_mux[i].val, mod_pin_mux[i].reg_offset);
|
||||
}
|
||||
175
u-boot/arch/arm/cpu/armv7/am33xx/sys_info.c
Normal file
175
u-boot/arch/arm/cpu/armv7/am33xx/sys_info.c
Normal file
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* sys_info.c
|
||||
*
|
||||
* System information functions
|
||||
*
|
||||
* Copyright (C) 2011, Texas Instruments, Incorporated - http://www.ti.com/
|
||||
*
|
||||
* Derived from Beagle Board and 3430 SDP code by
|
||||
* Richard Woodruff <r-woodruff2@ti.com>
|
||||
* Syed Mohammed Khasim <khasim@ti.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
#include <asm/arch/cpu.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <power/tps65910.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
struct ctrl_stat *cstat = (struct ctrl_stat *)CTRL_BASE;
|
||||
|
||||
/**
|
||||
* get_cpu_rev(void) - extract rev info
|
||||
*/
|
||||
u32 get_cpu_rev(void)
|
||||
{
|
||||
u32 id;
|
||||
u32 rev;
|
||||
|
||||
id = readl(DEVICE_ID);
|
||||
rev = (id >> 28) & 0xff;
|
||||
|
||||
return rev;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_cpu_type(void) - extract cpu info
|
||||
*/
|
||||
u32 get_cpu_type(void)
|
||||
{
|
||||
u32 id = 0;
|
||||
u32 partnum;
|
||||
|
||||
id = readl(DEVICE_ID);
|
||||
partnum = (id >> 12) & 0xffff;
|
||||
|
||||
return partnum;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_device_type(): tell if GP/HS/EMU/TST
|
||||
*/
|
||||
u32 get_device_type(void)
|
||||
{
|
||||
int mode;
|
||||
mode = readl(&cstat->statusreg) & (DEVICE_MASK);
|
||||
return mode >>= 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_sysboot_value(void) - return SYS_BOOT[4:0]
|
||||
*/
|
||||
u32 get_sysboot_value(void)
|
||||
{
|
||||
int mode;
|
||||
mode = readl(&cstat->statusreg) & (SYSBOOT_MASK);
|
||||
return mode;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DISPLAY_CPUINFO
|
||||
static char *cpu_revs[] = {
|
||||
"1.0",
|
||||
"2.0",
|
||||
"2.1"};
|
||||
|
||||
|
||||
static char *dev_types[] = {
|
||||
"TST",
|
||||
"EMU",
|
||||
"HS",
|
||||
"GP"};
|
||||
|
||||
/**
|
||||
* Print CPU information
|
||||
*/
|
||||
int print_cpuinfo(void)
|
||||
{
|
||||
char *cpu_s, *sec_s, *rev_s;
|
||||
|
||||
switch (get_cpu_type()) {
|
||||
case AM335X:
|
||||
cpu_s = "AM335X";
|
||||
break;
|
||||
case TI81XX:
|
||||
cpu_s = "TI81XX";
|
||||
break;
|
||||
default:
|
||||
cpu_s = "Unknown CPU type";
|
||||
break;
|
||||
}
|
||||
|
||||
if (get_cpu_rev() < ARRAY_SIZE(cpu_revs))
|
||||
rev_s = cpu_revs[get_cpu_rev()];
|
||||
else
|
||||
rev_s = "?";
|
||||
|
||||
if (get_device_type() < ARRAY_SIZE(dev_types))
|
||||
sec_s = dev_types[get_device_type()];
|
||||
else
|
||||
sec_s = "?";
|
||||
|
||||
printf("%s-%s rev %s\n", cpu_s, sec_s, rev_s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_DISPLAY_CPUINFO */
|
||||
|
||||
#ifdef CONFIG_AM33XX
|
||||
int am335x_get_efuse_mpu_max_freq(struct ctrl_dev *cdev)
|
||||
{
|
||||
int sil_rev;
|
||||
|
||||
sil_rev = readl(&cdev->deviceid) >> 28;
|
||||
|
||||
if (sil_rev == 1)
|
||||
/* PG 2.0, efuse may not be set. */
|
||||
return MPUPLL_M_800;
|
||||
else if (sil_rev >= 2) {
|
||||
/* Check what the efuse says our max speed is. */
|
||||
int efuse_arm_mpu_max_freq;
|
||||
efuse_arm_mpu_max_freq = readl(&cdev->efuse_sma);
|
||||
switch ((efuse_arm_mpu_max_freq & DEVICE_ID_MASK)) {
|
||||
case AM335X_ZCZ_1000:
|
||||
return MPUPLL_M_1000;
|
||||
case AM335X_ZCZ_800:
|
||||
return MPUPLL_M_800;
|
||||
case AM335X_ZCZ_720:
|
||||
return MPUPLL_M_720;
|
||||
case AM335X_ZCZ_600:
|
||||
case AM335X_ZCE_600:
|
||||
return MPUPLL_M_600;
|
||||
case AM335X_ZCZ_300:
|
||||
case AM335X_ZCE_300:
|
||||
return MPUPLL_M_300;
|
||||
}
|
||||
}
|
||||
|
||||
/* PG 1.0 or otherwise unknown, use the PG1.0 max */
|
||||
return MPUPLL_M_720;
|
||||
}
|
||||
|
||||
int am335x_get_tps65910_mpu_vdd(int sil_rev, int frequency)
|
||||
{
|
||||
/* For PG2.1 and later, we have one set of values. */
|
||||
if (sil_rev >= 2) {
|
||||
switch (frequency) {
|
||||
case MPUPLL_M_1000:
|
||||
return TPS65910_OP_REG_SEL_1_3_2_5;
|
||||
case MPUPLL_M_800:
|
||||
return TPS65910_OP_REG_SEL_1_2_6;
|
||||
case MPUPLL_M_720:
|
||||
return TPS65910_OP_REG_SEL_1_2_0;
|
||||
case MPUPLL_M_600:
|
||||
case MPUPLL_M_300:
|
||||
return TPS65910_OP_REG_SEL_1_1_3;
|
||||
}
|
||||
}
|
||||
|
||||
/* Default to PG1.0/PG2.0 values. */
|
||||
return TPS65910_OP_REG_SEL_1_1_3;
|
||||
}
|
||||
#endif
|
||||
56
u-boot/arch/arm/cpu/armv7/am33xx/u-boot-spl.lds
Normal file
56
u-boot/arch/arm/cpu/armv7/am33xx/u-boot-spl.lds
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* (C) Copyright 2002
|
||||
* Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
|
||||
*
|
||||
* (C) Copyright 2010
|
||||
* Texas Instruments, <www.ti.com>
|
||||
* Aneesh V <aneesh@ti.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
MEMORY { .sram : ORIGIN = CONFIG_SPL_TEXT_BASE,\
|
||||
LENGTH = CONFIG_SPL_MAX_SIZE }
|
||||
MEMORY { .sdram : ORIGIN = CONFIG_SPL_BSS_START_ADDR, \
|
||||
LENGTH = CONFIG_SPL_BSS_MAX_SIZE }
|
||||
|
||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
|
||||
OUTPUT_ARCH(arm)
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
.text :
|
||||
{
|
||||
__start = .;
|
||||
*(.vectors)
|
||||
arch/arm/cpu/armv7/start.o (.text)
|
||||
*(.text*)
|
||||
} >.sram
|
||||
|
||||
. = ALIGN(4);
|
||||
.rodata : { *(SORT_BY_ALIGNMENT(.rodata*)) } >.sram
|
||||
|
||||
. = ALIGN(4);
|
||||
.data : { *(SORT_BY_ALIGNMENT(.data*)) } >.sram
|
||||
|
||||
.u_boot_list : {
|
||||
KEEP(*(SORT(.u_boot_list*)));
|
||||
} >.sram
|
||||
|
||||
. = ALIGN(4);
|
||||
__image_copy_end = .;
|
||||
|
||||
.end :
|
||||
{
|
||||
*(.__end)
|
||||
} >.sram
|
||||
|
||||
.bss :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
__bss_start = .;
|
||||
*(.bss*)
|
||||
. = ALIGN(4);
|
||||
__bss_end = .;
|
||||
} >.sdram
|
||||
}
|
||||
58
u-boot/arch/arm/cpu/armv7/arch_timer.c
Normal file
58
u-boot/arch/arm/cpu/armv7/arch_timer.c
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* (C) Copyright 2012-2014
|
||||
* Texas Instruments Incorporated, <www.ti.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <div64.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
int timer_init(void)
|
||||
{
|
||||
gd->arch.tbl = 0;
|
||||
gd->arch.tbu = 0;
|
||||
|
||||
gd->arch.timer_rate_hz = CONFIG_SYS_HZ_CLOCK / CONFIG_SYS_HZ;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long long get_ticks(void)
|
||||
{
|
||||
ulong nowl, nowu;
|
||||
|
||||
asm volatile("mrrc p15, 0, %0, %1, c14" : "=r" (nowl), "=r" (nowu));
|
||||
|
||||
gd->arch.tbl = nowl;
|
||||
gd->arch.tbu = nowu;
|
||||
|
||||
return (((unsigned long long)gd->arch.tbu) << 32) | gd->arch.tbl;
|
||||
}
|
||||
|
||||
|
||||
ulong get_timer(ulong base)
|
||||
{
|
||||
return lldiv(get_ticks(), gd->arch.timer_rate_hz) - base;
|
||||
}
|
||||
|
||||
void __udelay(unsigned long usec)
|
||||
{
|
||||
unsigned long long endtime;
|
||||
|
||||
endtime = lldiv((unsigned long long)usec * gd->arch.timer_rate_hz,
|
||||
1000UL);
|
||||
|
||||
endtime += get_ticks();
|
||||
|
||||
while (get_ticks() < endtime)
|
||||
;
|
||||
}
|
||||
|
||||
ulong get_tbclk(void)
|
||||
{
|
||||
return gd->arch.timer_rate_hz;
|
||||
}
|
||||
12
u-boot/arch/arm/cpu/armv7/bcm235xx/Makefile
Normal file
12
u-boot/arch/arm/cpu/armv7/bcm235xx/Makefile
Normal file
@@ -0,0 +1,12 @@
|
||||
#
|
||||
# Copyright 2013 Broadcom Corporation.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y += clk-core.o
|
||||
obj-y += clk-bcm235xx.o
|
||||
obj-y += clk-sdio.o
|
||||
obj-y += clk-bsc.o
|
||||
obj-$(CONFIG_BCM_SF2_ETH) += clk-eth.o
|
||||
obj-y += clk-usb-otg.o
|
||||
569
u-boot/arch/arm/cpu/armv7/bcm235xx/clk-bcm235xx.c
Normal file
569
u-boot/arch/arm/cpu/armv7/bcm235xx/clk-bcm235xx.c
Normal file
@@ -0,0 +1,569 @@
|
||||
/*
|
||||
* Copyright 2013 Broadcom Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* bcm235xx-specific clock tables
|
||||
*
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/arch/sysmap.h>
|
||||
#include <asm/kona-common/clk.h>
|
||||
#include "clk-core.h"
|
||||
|
||||
#define CLOCK_1K 1000
|
||||
#define CLOCK_1M (CLOCK_1K * 1000)
|
||||
|
||||
/* declare a reference clock */
|
||||
#define DECLARE_REF_CLK(clk_name, clk_parent, clk_rate, clk_div) \
|
||||
static struct refclk clk_name = { \
|
||||
.clk = { \
|
||||
.name = #clk_name, \
|
||||
.parent = clk_parent, \
|
||||
.rate = clk_rate, \
|
||||
.div = clk_div, \
|
||||
.ops = &ref_clk_ops, \
|
||||
}, \
|
||||
}
|
||||
|
||||
/*
|
||||
* Reference clocks
|
||||
*/
|
||||
|
||||
/* Declare a list of reference clocks */
|
||||
DECLARE_REF_CLK(ref_crystal, 0, 26 * CLOCK_1M, 1);
|
||||
DECLARE_REF_CLK(var_96m, 0, 96 * CLOCK_1M, 1);
|
||||
DECLARE_REF_CLK(ref_96m, 0, 96 * CLOCK_1M, 1);
|
||||
DECLARE_REF_CLK(ref_312m, 0, 312 * CLOCK_1M, 0);
|
||||
DECLARE_REF_CLK(ref_104m, &ref_312m.clk, 104 * CLOCK_1M, 3);
|
||||
DECLARE_REF_CLK(ref_52m, &ref_104m.clk, 52 * CLOCK_1M, 2);
|
||||
DECLARE_REF_CLK(ref_13m, &ref_52m.clk, 13 * CLOCK_1M, 4);
|
||||
DECLARE_REF_CLK(var_312m, 0, 312 * CLOCK_1M, 0);
|
||||
DECLARE_REF_CLK(var_104m, &var_312m.clk, 104 * CLOCK_1M, 3);
|
||||
DECLARE_REF_CLK(var_52m, &var_104m.clk, 52 * CLOCK_1M, 2);
|
||||
DECLARE_REF_CLK(var_13m, &var_52m.clk, 13 * CLOCK_1M, 4);
|
||||
|
||||
struct refclk_lkup {
|
||||
struct refclk *procclk;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
/* Lookup table for string to clk tranlation */
|
||||
#define MKSTR(x) {&x, #x}
|
||||
static struct refclk_lkup refclk_str_tbl[] = {
|
||||
MKSTR(ref_crystal), MKSTR(var_96m), MKSTR(ref_96m),
|
||||
MKSTR(ref_312m), MKSTR(ref_104m), MKSTR(ref_52m),
|
||||
MKSTR(ref_13m), MKSTR(var_312m), MKSTR(var_104m),
|
||||
MKSTR(var_52m), MKSTR(var_13m),
|
||||
};
|
||||
|
||||
int refclk_entries = sizeof(refclk_str_tbl)/sizeof(refclk_str_tbl[0]);
|
||||
|
||||
/* convert ref clock string to clock structure pointer */
|
||||
struct refclk *refclk_str_to_clk(const char *name)
|
||||
{
|
||||
int i;
|
||||
struct refclk_lkup *tblp = refclk_str_tbl;
|
||||
for (i = 0; i < refclk_entries; i++, tblp++) {
|
||||
if (!(strcmp(name, tblp->name)))
|
||||
return tblp->procclk;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* frequency tables indexed by freq_id */
|
||||
unsigned long master_axi_freq_tbl[8] = {
|
||||
26 * CLOCK_1M,
|
||||
52 * CLOCK_1M,
|
||||
104 * CLOCK_1M,
|
||||
156 * CLOCK_1M,
|
||||
156 * CLOCK_1M,
|
||||
208 * CLOCK_1M,
|
||||
312 * CLOCK_1M,
|
||||
312 * CLOCK_1M
|
||||
};
|
||||
|
||||
unsigned long master_ahb_freq_tbl[8] = {
|
||||
26 * CLOCK_1M,
|
||||
52 * CLOCK_1M,
|
||||
52 * CLOCK_1M,
|
||||
52 * CLOCK_1M,
|
||||
78 * CLOCK_1M,
|
||||
104 * CLOCK_1M,
|
||||
104 * CLOCK_1M,
|
||||
156 * CLOCK_1M
|
||||
};
|
||||
|
||||
unsigned long slave_axi_freq_tbl[8] = {
|
||||
26 * CLOCK_1M,
|
||||
52 * CLOCK_1M,
|
||||
78 * CLOCK_1M,
|
||||
104 * CLOCK_1M,
|
||||
156 * CLOCK_1M,
|
||||
156 * CLOCK_1M
|
||||
};
|
||||
|
||||
unsigned long slave_apb_freq_tbl[8] = {
|
||||
26 * CLOCK_1M,
|
||||
26 * CLOCK_1M,
|
||||
39 * CLOCK_1M,
|
||||
52 * CLOCK_1M,
|
||||
52 * CLOCK_1M,
|
||||
78 * CLOCK_1M
|
||||
};
|
||||
|
||||
unsigned long esub_freq_tbl[8] = {
|
||||
78 * CLOCK_1M,
|
||||
156 * CLOCK_1M,
|
||||
156 * CLOCK_1M,
|
||||
156 * CLOCK_1M,
|
||||
208 * CLOCK_1M,
|
||||
208 * CLOCK_1M,
|
||||
208 * CLOCK_1M
|
||||
};
|
||||
|
||||
static struct bus_clk_data bsc1_apb_data = {
|
||||
.gate = HW_SW_GATE_AUTO(0x0458, 16, 0, 1),
|
||||
};
|
||||
|
||||
static struct bus_clk_data bsc2_apb_data = {
|
||||
.gate = HW_SW_GATE_AUTO(0x045c, 16, 0, 1),
|
||||
};
|
||||
|
||||
static struct bus_clk_data bsc3_apb_data = {
|
||||
.gate = HW_SW_GATE_AUTO(0x0484, 16, 0, 1),
|
||||
};
|
||||
|
||||
/* * Master CCU clocks */
|
||||
static struct peri_clk_data sdio1_data = {
|
||||
.gate = HW_SW_GATE(0x0358, 18, 2, 3),
|
||||
.clocks = CLOCKS("ref_crystal",
|
||||
"var_52m",
|
||||
"ref_52m",
|
||||
"var_96m",
|
||||
"ref_96m"),
|
||||
.sel = SELECTOR(0x0a28, 0, 3),
|
||||
.div = DIVIDER(0x0a28, 4, 14),
|
||||
.trig = TRIGGER(0x0afc, 9),
|
||||
};
|
||||
|
||||
static struct peri_clk_data sdio2_data = {
|
||||
.gate = HW_SW_GATE(0x035c, 18, 2, 3),
|
||||
.clocks = CLOCKS("ref_crystal",
|
||||
"var_52m",
|
||||
"ref_52m",
|
||||
"var_96m",
|
||||
"ref_96m"),
|
||||
.sel = SELECTOR(0x0a2c, 0, 3),
|
||||
.div = DIVIDER(0x0a2c, 4, 14),
|
||||
.trig = TRIGGER(0x0afc, 10),
|
||||
};
|
||||
|
||||
static struct peri_clk_data sdio3_data = {
|
||||
.gate = HW_SW_GATE(0x0364, 18, 2, 3),
|
||||
.clocks = CLOCKS("ref_crystal",
|
||||
"var_52m",
|
||||
"ref_52m",
|
||||
"var_96m",
|
||||
"ref_96m"),
|
||||
.sel = SELECTOR(0x0a34, 0, 3),
|
||||
.div = DIVIDER(0x0a34, 4, 14),
|
||||
.trig = TRIGGER(0x0afc, 12),
|
||||
};
|
||||
|
||||
static struct peri_clk_data sdio4_data = {
|
||||
.gate = HW_SW_GATE(0x0360, 18, 2, 3),
|
||||
.clocks = CLOCKS("ref_crystal",
|
||||
"var_52m",
|
||||
"ref_52m",
|
||||
"var_96m",
|
||||
"ref_96m"),
|
||||
.sel = SELECTOR(0x0a30, 0, 3),
|
||||
.div = DIVIDER(0x0a30, 4, 14),
|
||||
.trig = TRIGGER(0x0afc, 11),
|
||||
};
|
||||
|
||||
static struct peri_clk_data sdio1_sleep_data = {
|
||||
.clocks = CLOCKS("ref_32k"),
|
||||
.gate = SW_ONLY_GATE(0x0358, 20, 4),
|
||||
};
|
||||
|
||||
static struct peri_clk_data sdio2_sleep_data = {
|
||||
.clocks = CLOCKS("ref_32k"),
|
||||
.gate = SW_ONLY_GATE(0x035c, 20, 4),
|
||||
};
|
||||
|
||||
static struct peri_clk_data sdio3_sleep_data = {
|
||||
.clocks = CLOCKS("ref_32k"),
|
||||
.gate = SW_ONLY_GATE(0x0364, 20, 4),
|
||||
};
|
||||
|
||||
static struct peri_clk_data sdio4_sleep_data = {
|
||||
.clocks = CLOCKS("ref_32k"),
|
||||
.gate = SW_ONLY_GATE(0x0360, 20, 4),
|
||||
};
|
||||
|
||||
static struct bus_clk_data usb_otg_ahb_data = {
|
||||
.gate = HW_SW_GATE_AUTO(0x0348, 16, 0, 1),
|
||||
};
|
||||
|
||||
static struct bus_clk_data sdio1_ahb_data = {
|
||||
.gate = HW_SW_GATE_AUTO(0x0358, 16, 0, 1),
|
||||
};
|
||||
|
||||
static struct bus_clk_data sdio2_ahb_data = {
|
||||
.gate = HW_SW_GATE_AUTO(0x035c, 16, 0, 1),
|
||||
};
|
||||
|
||||
static struct bus_clk_data sdio3_ahb_data = {
|
||||
.gate = HW_SW_GATE_AUTO(0x0364, 16, 0, 1),
|
||||
};
|
||||
|
||||
static struct bus_clk_data sdio4_ahb_data = {
|
||||
.gate = HW_SW_GATE_AUTO(0x0360, 16, 0, 1),
|
||||
};
|
||||
|
||||
/* * Slave CCU clocks */
|
||||
static struct peri_clk_data bsc1_data = {
|
||||
.gate = HW_SW_GATE(0x0458, 18, 2, 3),
|
||||
.clocks = CLOCKS("ref_crystal",
|
||||
"var_104m",
|
||||
"ref_104m",
|
||||
"var_13m",
|
||||
"ref_13m"),
|
||||
.sel = SELECTOR(0x0a64, 0, 3),
|
||||
.trig = TRIGGER(0x0afc, 23),
|
||||
};
|
||||
|
||||
static struct peri_clk_data bsc2_data = {
|
||||
.gate = HW_SW_GATE(0x045c, 18, 2, 3),
|
||||
.clocks = CLOCKS("ref_crystal",
|
||||
"var_104m",
|
||||
"ref_104m",
|
||||
"var_13m",
|
||||
"ref_13m"),
|
||||
.sel = SELECTOR(0x0a68, 0, 3),
|
||||
.trig = TRIGGER(0x0afc, 24),
|
||||
};
|
||||
|
||||
static struct peri_clk_data bsc3_data = {
|
||||
.gate = HW_SW_GATE(0x0484, 18, 2, 3),
|
||||
.clocks = CLOCKS("ref_crystal",
|
||||
"var_104m",
|
||||
"ref_104m",
|
||||
"var_13m",
|
||||
"ref_13m"),
|
||||
.sel = SELECTOR(0x0a84, 0, 3),
|
||||
.trig = TRIGGER(0x0b00, 2),
|
||||
};
|
||||
|
||||
/*
|
||||
* CCU clocks
|
||||
*/
|
||||
|
||||
static struct ccu_clock kpm_ccu_clk = {
|
||||
.clk = {
|
||||
.name = "kpm_ccu_clk",
|
||||
.ops = &ccu_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
|
||||
},
|
||||
.num_policy_masks = 1,
|
||||
.policy_freq_offset = 0x00000008,
|
||||
.freq_bit_shift = 8,
|
||||
.policy_ctl_offset = 0x0000000c,
|
||||
.policy0_mask_offset = 0x00000010,
|
||||
.policy1_mask_offset = 0x00000014,
|
||||
.policy2_mask_offset = 0x00000018,
|
||||
.policy3_mask_offset = 0x0000001c,
|
||||
.lvm_en_offset = 0x00000034,
|
||||
.freq_id = 2,
|
||||
.freq_tbl = master_axi_freq_tbl,
|
||||
};
|
||||
|
||||
static struct ccu_clock kps_ccu_clk = {
|
||||
.clk = {
|
||||
.name = "kps_ccu_clk",
|
||||
.ops = &ccu_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR,
|
||||
},
|
||||
.num_policy_masks = 1,
|
||||
.policy_freq_offset = 0x00000008,
|
||||
.freq_bit_shift = 8,
|
||||
.policy_ctl_offset = 0x0000000c,
|
||||
.policy0_mask_offset = 0x00000010,
|
||||
.policy1_mask_offset = 0x00000014,
|
||||
.policy2_mask_offset = 0x00000018,
|
||||
.policy3_mask_offset = 0x0000001c,
|
||||
.lvm_en_offset = 0x00000034,
|
||||
.freq_id = 2,
|
||||
.freq_tbl = slave_axi_freq_tbl,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_BCM_SF2_ETH
|
||||
static struct ccu_clock esub_ccu_clk = {
|
||||
.clk = {
|
||||
.name = "esub_ccu_clk",
|
||||
.ops = &ccu_clk_ops,
|
||||
.ccu_clk_mgr_base = ESUB_CLK_BASE_ADDR,
|
||||
},
|
||||
.num_policy_masks = 1,
|
||||
.policy_freq_offset = 0x00000008,
|
||||
.freq_bit_shift = 8,
|
||||
.policy_ctl_offset = 0x0000000c,
|
||||
.policy0_mask_offset = 0x00000010,
|
||||
.policy1_mask_offset = 0x00000014,
|
||||
.policy2_mask_offset = 0x00000018,
|
||||
.policy3_mask_offset = 0x0000001c,
|
||||
.lvm_en_offset = 0x00000034,
|
||||
.freq_id = 2,
|
||||
.freq_tbl = esub_freq_tbl,
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Bus clocks
|
||||
*/
|
||||
|
||||
/* KPM bus clocks */
|
||||
static struct bus_clock usb_otg_ahb_clk = {
|
||||
.clk = {
|
||||
.name = "usb_otg_ahb_clk",
|
||||
.parent = &kpm_ccu_clk.clk,
|
||||
.ops = &bus_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
|
||||
},
|
||||
.freq_tbl = master_ahb_freq_tbl,
|
||||
.data = &usb_otg_ahb_data,
|
||||
};
|
||||
|
||||
static struct bus_clock sdio1_ahb_clk = {
|
||||
.clk = {
|
||||
.name = "sdio1_ahb_clk",
|
||||
.parent = &kpm_ccu_clk.clk,
|
||||
.ops = &bus_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
|
||||
},
|
||||
.freq_tbl = master_ahb_freq_tbl,
|
||||
.data = &sdio1_ahb_data,
|
||||
};
|
||||
|
||||
static struct bus_clock sdio2_ahb_clk = {
|
||||
.clk = {
|
||||
.name = "sdio2_ahb_clk",
|
||||
.parent = &kpm_ccu_clk.clk,
|
||||
.ops = &bus_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
|
||||
},
|
||||
.freq_tbl = master_ahb_freq_tbl,
|
||||
.data = &sdio2_ahb_data,
|
||||
};
|
||||
|
||||
static struct bus_clock sdio3_ahb_clk = {
|
||||
.clk = {
|
||||
.name = "sdio3_ahb_clk",
|
||||
.parent = &kpm_ccu_clk.clk,
|
||||
.ops = &bus_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
|
||||
},
|
||||
.freq_tbl = master_ahb_freq_tbl,
|
||||
.data = &sdio3_ahb_data,
|
||||
};
|
||||
|
||||
static struct bus_clock sdio4_ahb_clk = {
|
||||
.clk = {
|
||||
.name = "sdio4_ahb_clk",
|
||||
.parent = &kpm_ccu_clk.clk,
|
||||
.ops = &bus_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
|
||||
},
|
||||
.freq_tbl = master_ahb_freq_tbl,
|
||||
.data = &sdio4_ahb_data,
|
||||
};
|
||||
|
||||
static struct bus_clock bsc1_apb_clk = {
|
||||
.clk = {
|
||||
.name = "bsc1_apb_clk",
|
||||
.parent = &kps_ccu_clk.clk,
|
||||
.ops = &bus_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR,
|
||||
},
|
||||
.freq_tbl = slave_apb_freq_tbl,
|
||||
.data = &bsc1_apb_data,
|
||||
};
|
||||
|
||||
static struct bus_clock bsc2_apb_clk = {
|
||||
.clk = {
|
||||
.name = "bsc2_apb_clk",
|
||||
.parent = &kps_ccu_clk.clk,
|
||||
.ops = &bus_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR,
|
||||
},
|
||||
.freq_tbl = slave_apb_freq_tbl,
|
||||
.data = &bsc2_apb_data,
|
||||
};
|
||||
|
||||
static struct bus_clock bsc3_apb_clk = {
|
||||
.clk = {
|
||||
.name = "bsc3_apb_clk",
|
||||
.parent = &kps_ccu_clk.clk,
|
||||
.ops = &bus_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR,
|
||||
},
|
||||
.freq_tbl = slave_apb_freq_tbl,
|
||||
.data = &bsc3_apb_data,
|
||||
};
|
||||
|
||||
/* KPM peripheral */
|
||||
static struct peri_clock sdio1_clk = {
|
||||
.clk = {
|
||||
.name = "sdio1_clk",
|
||||
.parent = &ref_52m.clk,
|
||||
.ops = &peri_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
|
||||
},
|
||||
.data = &sdio1_data,
|
||||
};
|
||||
|
||||
static struct peri_clock sdio2_clk = {
|
||||
.clk = {
|
||||
.name = "sdio2_clk",
|
||||
.parent = &ref_52m.clk,
|
||||
.ops = &peri_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
|
||||
},
|
||||
.data = &sdio2_data,
|
||||
};
|
||||
|
||||
static struct peri_clock sdio3_clk = {
|
||||
.clk = {
|
||||
.name = "sdio3_clk",
|
||||
.parent = &ref_52m.clk,
|
||||
.ops = &peri_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
|
||||
},
|
||||
.data = &sdio3_data,
|
||||
};
|
||||
|
||||
static struct peri_clock sdio4_clk = {
|
||||
.clk = {
|
||||
.name = "sdio4_clk",
|
||||
.parent = &ref_52m.clk,
|
||||
.ops = &peri_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
|
||||
},
|
||||
.data = &sdio4_data,
|
||||
};
|
||||
|
||||
static struct peri_clock sdio1_sleep_clk = {
|
||||
.clk = {
|
||||
.name = "sdio1_sleep_clk",
|
||||
.parent = &kpm_ccu_clk.clk,
|
||||
.ops = &bus_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
|
||||
},
|
||||
.data = &sdio1_sleep_data,
|
||||
};
|
||||
|
||||
static struct peri_clock sdio2_sleep_clk = {
|
||||
.clk = {
|
||||
.name = "sdio2_sleep_clk",
|
||||
.parent = &kpm_ccu_clk.clk,
|
||||
.ops = &bus_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
|
||||
},
|
||||
.data = &sdio2_sleep_data,
|
||||
};
|
||||
|
||||
static struct peri_clock sdio3_sleep_clk = {
|
||||
.clk = {
|
||||
.name = "sdio3_sleep_clk",
|
||||
.parent = &kpm_ccu_clk.clk,
|
||||
.ops = &bus_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
|
||||
},
|
||||
.data = &sdio3_sleep_data,
|
||||
};
|
||||
|
||||
static struct peri_clock sdio4_sleep_clk = {
|
||||
.clk = {
|
||||
.name = "sdio4_sleep_clk",
|
||||
.parent = &kpm_ccu_clk.clk,
|
||||
.ops = &bus_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
|
||||
},
|
||||
.data = &sdio4_sleep_data,
|
||||
};
|
||||
|
||||
/* KPS peripheral clock */
|
||||
static struct peri_clock bsc1_clk = {
|
||||
.clk = {
|
||||
.name = "bsc1_clk",
|
||||
.parent = &ref_13m.clk,
|
||||
.rate = 13 * CLOCK_1M,
|
||||
.div = 1,
|
||||
.ops = &peri_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR,
|
||||
},
|
||||
.data = &bsc1_data,
|
||||
};
|
||||
|
||||
static struct peri_clock bsc2_clk = {
|
||||
.clk = {
|
||||
.name = "bsc2_clk",
|
||||
.parent = &ref_13m.clk,
|
||||
.rate = 13 * CLOCK_1M,
|
||||
.div = 1,
|
||||
.ops = &peri_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR,
|
||||
},
|
||||
.data = &bsc2_data,
|
||||
};
|
||||
|
||||
static struct peri_clock bsc3_clk = {
|
||||
.clk = {
|
||||
.name = "bsc3_clk",
|
||||
.parent = &ref_13m.clk,
|
||||
.rate = 13 * CLOCK_1M,
|
||||
.div = 1,
|
||||
.ops = &peri_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR,
|
||||
},
|
||||
.data = &bsc3_data,
|
||||
};
|
||||
|
||||
/* public table for registering clocks */
|
||||
struct clk_lookup arch_clk_tbl[] = {
|
||||
/* Peripheral clocks */
|
||||
CLK_LK(sdio1),
|
||||
CLK_LK(sdio2),
|
||||
CLK_LK(sdio3),
|
||||
CLK_LK(sdio4),
|
||||
CLK_LK(sdio1_sleep),
|
||||
CLK_LK(sdio2_sleep),
|
||||
CLK_LK(sdio3_sleep),
|
||||
CLK_LK(sdio4_sleep),
|
||||
CLK_LK(bsc1),
|
||||
CLK_LK(bsc2),
|
||||
CLK_LK(bsc3),
|
||||
/* Bus clocks */
|
||||
CLK_LK(usb_otg_ahb),
|
||||
CLK_LK(sdio1_ahb),
|
||||
CLK_LK(sdio2_ahb),
|
||||
CLK_LK(sdio3_ahb),
|
||||
CLK_LK(sdio4_ahb),
|
||||
CLK_LK(bsc1_apb),
|
||||
CLK_LK(bsc2_apb),
|
||||
CLK_LK(bsc3_apb),
|
||||
#ifdef CONFIG_BCM_SF2_ETH
|
||||
CLK_LK(esub_ccu),
|
||||
#endif
|
||||
};
|
||||
|
||||
/* public array size */
|
||||
unsigned int arch_clk_tbl_array_size = ARRAY_SIZE(arch_clk_tbl);
|
||||
52
u-boot/arch/arm/cpu/armv7/bcm235xx/clk-bsc.c
Normal file
52
u-boot/arch/arm/cpu/armv7/bcm235xx/clk-bsc.c
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2013 Broadcom Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/arch/sysmap.h>
|
||||
#include <asm/kona-common/clk.h>
|
||||
#include "clk-core.h"
|
||||
|
||||
/* Enable appropriate clocks for a BSC/I2C port */
|
||||
int clk_bsc_enable(void *base)
|
||||
{
|
||||
int ret;
|
||||
char *bscstr, *apbstr;
|
||||
|
||||
switch ((u32) base) {
|
||||
case PMU_BSC_BASE_ADDR:
|
||||
/* PMU clock is always enabled */
|
||||
return 0;
|
||||
case BSC1_BASE_ADDR:
|
||||
bscstr = "bsc1_clk";
|
||||
apbstr = "bsc1_apb_clk";
|
||||
break;
|
||||
case BSC2_BASE_ADDR:
|
||||
bscstr = "bsc2_clk";
|
||||
apbstr = "bsc2_apb_clk";
|
||||
break;
|
||||
case BSC3_BASE_ADDR:
|
||||
bscstr = "bsc3_clk";
|
||||
apbstr = "bsc3_apb_clk";
|
||||
break;
|
||||
default:
|
||||
printf("%s: base 0x%p not found\n", __func__, base);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Note that the bus clock must be enabled first */
|
||||
|
||||
ret = clk_get_and_enable(apbstr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_get_and_enable(bscstr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
513
u-boot/arch/arm/cpu/armv7/bcm235xx/clk-core.c
Normal file
513
u-boot/arch/arm/cpu/armv7/bcm235xx/clk-core.c
Normal file
@@ -0,0 +1,513 @@
|
||||
/*
|
||||
* Copyright 2013 Broadcom Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* bcm235xx architecture clock framework
|
||||
*
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/errno.h>
|
||||
#include <bitfield.h>
|
||||
#include <asm/arch/sysmap.h>
|
||||
#include <asm/kona-common/clk.h>
|
||||
#include "clk-core.h"
|
||||
|
||||
#define CLK_WR_ACCESS_PASSWORD 0x00a5a501
|
||||
#define WR_ACCESS_OFFSET 0 /* common to all clock blocks */
|
||||
#define POLICY_CTL_GO 1 /* Load and refresh policy masks */
|
||||
#define POLICY_CTL_GO_ATL 4 /* Active Load */
|
||||
|
||||
/* Helper function */
|
||||
int clk_get_and_enable(char *clkstr)
|
||||
{
|
||||
int ret = 0;
|
||||
struct clk *c;
|
||||
|
||||
debug("%s: %s\n", __func__, clkstr);
|
||||
|
||||
c = clk_get(clkstr);
|
||||
if (c) {
|
||||
ret = clk_enable(c);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
printf("%s: Couldn't find %s\n", __func__, clkstr);
|
||||
return -EINVAL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Poll a register in a CCU's address space, returning when the
|
||||
* specified bit in that register's value is set (or clear). Delay
|
||||
* a microsecond after each read of the register. Returns true if
|
||||
* successful, or false if we gave up trying.
|
||||
*
|
||||
* Caller must ensure the CCU lock is held.
|
||||
*/
|
||||
#define CLK_GATE_DELAY_USEC 2000
|
||||
static inline int wait_bit(void *base, u32 offset, u32 bit, bool want)
|
||||
{
|
||||
unsigned int tries;
|
||||
u32 bit_mask = 1 << bit;
|
||||
|
||||
for (tries = 0; tries < CLK_GATE_DELAY_USEC; tries++) {
|
||||
u32 val;
|
||||
bool bit_val;
|
||||
|
||||
val = readl(base + offset);
|
||||
bit_val = (val & bit_mask) ? 1 : 0;
|
||||
if (bit_val == want)
|
||||
return 0; /* success */
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
debug("%s: timeout on addr 0x%p, waiting for bit %d to go to %d\n",
|
||||
__func__, base + offset, bit, want);
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/* Enable a peripheral clock */
|
||||
static int peri_clk_enable(struct clk *c, int enable)
|
||||
{
|
||||
int ret = 0;
|
||||
u32 reg;
|
||||
struct peri_clock *peri_clk = to_peri_clk(c);
|
||||
struct peri_clk_data *cd = peri_clk->data;
|
||||
struct bcm_clk_gate *gate = &cd->gate;
|
||||
void *base = (void *)c->ccu_clk_mgr_base;
|
||||
|
||||
|
||||
debug("%s: %s\n", __func__, c->name);
|
||||
|
||||
clk_get_rate(c); /* Make sure rate and sel are filled in */
|
||||
|
||||
/* enable access */
|
||||
writel(CLK_WR_ACCESS_PASSWORD, base + WR_ACCESS_OFFSET);
|
||||
|
||||
if (enable) {
|
||||
debug("%s %s set rate %lu div %lu sel %d parent %lu\n",
|
||||
__func__, c->name, c->rate, c->div, c->sel,
|
||||
c->parent->rate);
|
||||
|
||||
/*
|
||||
* clkgate - only software controllable gates are
|
||||
* supported by u-boot which includes all clocks
|
||||
* that matter. This avoids bringing in a lot of extra
|
||||
* complexity as done in the kernel framework.
|
||||
*/
|
||||
if (gate_exists(gate)) {
|
||||
reg = readl(base + cd->gate.offset);
|
||||
reg |= (1 << cd->gate.en_bit);
|
||||
writel(reg, base + cd->gate.offset);
|
||||
}
|
||||
|
||||
/* div and pll select */
|
||||
if (divider_exists(&cd->div)) {
|
||||
reg = readl(base + cd->div.offset);
|
||||
bitfield_replace(reg, cd->div.shift, cd->div.width,
|
||||
c->div - 1);
|
||||
writel(reg, base + cd->div.offset);
|
||||
}
|
||||
|
||||
/* frequency selector */
|
||||
if (selector_exists(&cd->sel)) {
|
||||
reg = readl(base + cd->sel.offset);
|
||||
bitfield_replace(reg, cd->sel.shift, cd->sel.width,
|
||||
c->sel);
|
||||
writel(reg, base + cd->sel.offset);
|
||||
}
|
||||
|
||||
/* trigger */
|
||||
if (trigger_exists(&cd->trig)) {
|
||||
writel((1 << cd->trig.bit), base + cd->trig.offset);
|
||||
|
||||
/* wait for trigger status bit to go to 0 */
|
||||
ret = wait_bit(base, cd->trig.offset, cd->trig.bit, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* wait for running (status_bit = 1) */
|
||||
ret = wait_bit(base, cd->gate.offset, cd->gate.status_bit, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
debug("%s disable clock %s\n", __func__, c->name);
|
||||
|
||||
/* clkgate */
|
||||
reg = readl(base + cd->gate.offset);
|
||||
reg &= ~(1 << cd->gate.en_bit);
|
||||
writel(reg, base + cd->gate.offset);
|
||||
|
||||
/* wait for stop (status_bit = 0) */
|
||||
ret = wait_bit(base, cd->gate.offset, cd->gate.status_bit, 0);
|
||||
}
|
||||
|
||||
/* disable access */
|
||||
writel(0, base + WR_ACCESS_OFFSET);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Set the rate of a peripheral clock */
|
||||
static int peri_clk_set_rate(struct clk *c, unsigned long rate)
|
||||
{
|
||||
int ret = 0;
|
||||
int i;
|
||||
unsigned long diff;
|
||||
unsigned long new_rate = 0, div = 1;
|
||||
struct peri_clock *peri_clk = to_peri_clk(c);
|
||||
struct peri_clk_data *cd = peri_clk->data;
|
||||
const char **clock;
|
||||
|
||||
debug("%s: %s\n", __func__, c->name);
|
||||
diff = rate;
|
||||
|
||||
i = 0;
|
||||
for (clock = cd->clocks; *clock; clock++, i++) {
|
||||
struct refclk *ref = refclk_str_to_clk(*clock);
|
||||
if (!ref) {
|
||||
printf("%s: Lookup of %s failed\n", __func__, *clock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* round to the new rate */
|
||||
div = ref->clk.rate / rate;
|
||||
if (div == 0)
|
||||
div = 1;
|
||||
|
||||
new_rate = ref->clk.rate / div;
|
||||
|
||||
/* get the min diff */
|
||||
if (abs(new_rate - rate) < diff) {
|
||||
diff = abs(new_rate - rate);
|
||||
c->sel = i;
|
||||
c->parent = &ref->clk;
|
||||
c->rate = new_rate;
|
||||
c->div = div;
|
||||
}
|
||||
}
|
||||
|
||||
debug("%s %s set rate %lu div %lu sel %d parent %lu\n", __func__,
|
||||
c->name, c->rate, c->div, c->sel, c->parent->rate);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Get the rate of a peripheral clock */
|
||||
static unsigned long peri_clk_get_rate(struct clk *c)
|
||||
{
|
||||
struct peri_clock *peri_clk = to_peri_clk(c);
|
||||
struct peri_clk_data *cd = peri_clk->data;
|
||||
void *base = (void *)c->ccu_clk_mgr_base;
|
||||
int div = 1;
|
||||
const char **clock;
|
||||
struct refclk *ref;
|
||||
u32 reg;
|
||||
|
||||
debug("%s: %s\n", __func__, c->name);
|
||||
if (selector_exists(&cd->sel)) {
|
||||
reg = readl(base + cd->sel.offset);
|
||||
c->sel = bitfield_extract(reg, cd->sel.shift, cd->sel.width);
|
||||
} else {
|
||||
/*
|
||||
* For peri clocks that don't have a selector, the single
|
||||
* reference clock will always exist at index 0.
|
||||
*/
|
||||
c->sel = 0;
|
||||
}
|
||||
|
||||
if (divider_exists(&cd->div)) {
|
||||
reg = readl(base + cd->div.offset);
|
||||
div = bitfield_extract(reg, cd->div.shift, cd->div.width);
|
||||
div += 1;
|
||||
}
|
||||
|
||||
clock = cd->clocks;
|
||||
ref = refclk_str_to_clk(clock[c->sel]);
|
||||
if (!ref) {
|
||||
printf("%s: Can't lookup %s\n", __func__, clock[c->sel]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
c->parent = &ref->clk;
|
||||
c->div = div;
|
||||
c->rate = c->parent->rate / c->div;
|
||||
debug("%s parent rate %lu div %d sel %d rate %lu\n", __func__,
|
||||
c->parent->rate, div, c->sel, c->rate);
|
||||
|
||||
return c->rate;
|
||||
}
|
||||
|
||||
/* Peripheral clock operations */
|
||||
struct clk_ops peri_clk_ops = {
|
||||
.enable = peri_clk_enable,
|
||||
.set_rate = peri_clk_set_rate,
|
||||
.get_rate = peri_clk_get_rate,
|
||||
};
|
||||
|
||||
/* Enable a CCU clock */
|
||||
static int ccu_clk_enable(struct clk *c, int enable)
|
||||
{
|
||||
struct ccu_clock *ccu_clk = to_ccu_clk(c);
|
||||
void *base = (void *)c->ccu_clk_mgr_base;
|
||||
int ret = 0;
|
||||
u32 reg;
|
||||
|
||||
debug("%s: %s\n", __func__, c->name);
|
||||
if (!enable)
|
||||
return -EINVAL; /* CCU clock cannot shutdown */
|
||||
|
||||
/* enable access */
|
||||
writel(CLK_WR_ACCESS_PASSWORD, base + WR_ACCESS_OFFSET);
|
||||
|
||||
/* config enable for policy engine */
|
||||
writel(1, base + ccu_clk->lvm_en_offset);
|
||||
|
||||
/* wait for bit to go to 0 */
|
||||
ret = wait_bit(base, ccu_clk->lvm_en_offset, 0, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* freq ID */
|
||||
if (!ccu_clk->freq_bit_shift)
|
||||
ccu_clk->freq_bit_shift = 8;
|
||||
|
||||
/* Set frequency id for each of the 4 policies */
|
||||
reg = ccu_clk->freq_id |
|
||||
(ccu_clk->freq_id << (ccu_clk->freq_bit_shift)) |
|
||||
(ccu_clk->freq_id << (ccu_clk->freq_bit_shift * 2)) |
|
||||
(ccu_clk->freq_id << (ccu_clk->freq_bit_shift * 3));
|
||||
writel(reg, base + ccu_clk->policy_freq_offset);
|
||||
|
||||
/* enable all clock mask */
|
||||
writel(0x7fffffff, base + ccu_clk->policy0_mask_offset);
|
||||
writel(0x7fffffff, base + ccu_clk->policy1_mask_offset);
|
||||
writel(0x7fffffff, base + ccu_clk->policy2_mask_offset);
|
||||
writel(0x7fffffff, base + ccu_clk->policy3_mask_offset);
|
||||
|
||||
if (ccu_clk->num_policy_masks == 2) {
|
||||
writel(0x7fffffff, base + ccu_clk->policy0_mask2_offset);
|
||||
writel(0x7fffffff, base + ccu_clk->policy1_mask2_offset);
|
||||
writel(0x7fffffff, base + ccu_clk->policy2_mask2_offset);
|
||||
writel(0x7fffffff, base + ccu_clk->policy3_mask2_offset);
|
||||
}
|
||||
|
||||
/* start policy engine */
|
||||
reg = readl(base + ccu_clk->policy_ctl_offset);
|
||||
reg |= (POLICY_CTL_GO + POLICY_CTL_GO_ATL);
|
||||
writel(reg, base + ccu_clk->policy_ctl_offset);
|
||||
|
||||
/* wait till started */
|
||||
ret = wait_bit(base, ccu_clk->policy_ctl_offset, 0, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* disable access */
|
||||
writel(0, base + WR_ACCESS_OFFSET);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Get the CCU clock rate */
|
||||
static unsigned long ccu_clk_get_rate(struct clk *c)
|
||||
{
|
||||
struct ccu_clock *ccu_clk = to_ccu_clk(c);
|
||||
debug("%s: %s\n", __func__, c->name);
|
||||
c->rate = ccu_clk->freq_tbl[ccu_clk->freq_id];
|
||||
return c->rate;
|
||||
}
|
||||
|
||||
/* CCU clock operations */
|
||||
struct clk_ops ccu_clk_ops = {
|
||||
.enable = ccu_clk_enable,
|
||||
.get_rate = ccu_clk_get_rate,
|
||||
};
|
||||
|
||||
/* Enable a bus clock */
|
||||
static int bus_clk_enable(struct clk *c, int enable)
|
||||
{
|
||||
struct bus_clock *bus_clk = to_bus_clk(c);
|
||||
struct bus_clk_data *cd = bus_clk->data;
|
||||
void *base = (void *)c->ccu_clk_mgr_base;
|
||||
int ret = 0;
|
||||
u32 reg;
|
||||
|
||||
debug("%s: %s\n", __func__, c->name);
|
||||
/* enable access */
|
||||
writel(CLK_WR_ACCESS_PASSWORD, base + WR_ACCESS_OFFSET);
|
||||
|
||||
/* enable gating */
|
||||
reg = readl(base + cd->gate.offset);
|
||||
if (!!(reg & (1 << cd->gate.status_bit)) == !!enable)
|
||||
debug("%s already %s\n", c->name,
|
||||
enable ? "enabled" : "disabled");
|
||||
else {
|
||||
int want = (enable) ? 1 : 0;
|
||||
reg |= (1 << cd->gate.hw_sw_sel_bit);
|
||||
|
||||
if (enable)
|
||||
reg |= (1 << cd->gate.en_bit);
|
||||
else
|
||||
reg &= ~(1 << cd->gate.en_bit);
|
||||
|
||||
writel(reg, base + cd->gate.offset);
|
||||
ret = wait_bit(base, cd->gate.offset, cd->gate.status_bit,
|
||||
want);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* disable access */
|
||||
writel(0, base + WR_ACCESS_OFFSET);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Get the rate of a bus clock */
|
||||
static unsigned long bus_clk_get_rate(struct clk *c)
|
||||
{
|
||||
struct bus_clock *bus_clk = to_bus_clk(c);
|
||||
struct ccu_clock *ccu_clk;
|
||||
|
||||
debug("%s: %s\n", __func__, c->name);
|
||||
ccu_clk = to_ccu_clk(c->parent);
|
||||
|
||||
c->rate = bus_clk->freq_tbl[ccu_clk->freq_id];
|
||||
c->div = ccu_clk->freq_tbl[ccu_clk->freq_id] / c->rate;
|
||||
return c->rate;
|
||||
}
|
||||
|
||||
/* Bus clock operations */
|
||||
struct clk_ops bus_clk_ops = {
|
||||
.enable = bus_clk_enable,
|
||||
.get_rate = bus_clk_get_rate,
|
||||
};
|
||||
|
||||
/* Enable a reference clock */
|
||||
static int ref_clk_enable(struct clk *c, int enable)
|
||||
{
|
||||
debug("%s: %s\n", __func__, c->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Reference clock operations */
|
||||
struct clk_ops ref_clk_ops = {
|
||||
.enable = ref_clk_enable,
|
||||
};
|
||||
|
||||
/*
|
||||
* clk.h implementation follows
|
||||
*/
|
||||
|
||||
/* Initialize the clock framework */
|
||||
int clk_init(void)
|
||||
{
|
||||
debug("%s:\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get a clock handle, give a name string */
|
||||
struct clk *clk_get(const char *con_id)
|
||||
{
|
||||
int i;
|
||||
struct clk_lookup *clk_tblp;
|
||||
|
||||
debug("%s: %s\n", __func__, con_id);
|
||||
|
||||
clk_tblp = arch_clk_tbl;
|
||||
for (i = 0; i < arch_clk_tbl_array_size; i++, clk_tblp++) {
|
||||
if (clk_tblp->con_id) {
|
||||
if (!con_id || strcmp(clk_tblp->con_id, con_id))
|
||||
continue;
|
||||
return clk_tblp->clk;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Enable a clock */
|
||||
int clk_enable(struct clk *c)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
debug("%s: %s\n", __func__, c->name);
|
||||
if (!c->ops || !c->ops->enable)
|
||||
return -1;
|
||||
|
||||
/* enable parent clock first */
|
||||
if (c->parent)
|
||||
ret = clk_enable(c->parent);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!c->use_cnt)
|
||||
ret = c->ops->enable(c, 1);
|
||||
c->use_cnt++;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Disable a clock */
|
||||
void clk_disable(struct clk *c)
|
||||
{
|
||||
debug("%s: %s\n", __func__, c->name);
|
||||
if (!c->ops || !c->ops->enable)
|
||||
return;
|
||||
|
||||
if (c->use_cnt > 0) {
|
||||
c->use_cnt--;
|
||||
if (c->use_cnt == 0)
|
||||
c->ops->enable(c, 0);
|
||||
}
|
||||
|
||||
/* disable parent */
|
||||
if (c->parent)
|
||||
clk_disable(c->parent);
|
||||
}
|
||||
|
||||
/* Get the clock rate */
|
||||
unsigned long clk_get_rate(struct clk *c)
|
||||
{
|
||||
unsigned long rate;
|
||||
|
||||
debug("%s: %s\n", __func__, c->name);
|
||||
if (!c || !c->ops || !c->ops->get_rate)
|
||||
return 0;
|
||||
|
||||
rate = c->ops->get_rate(c);
|
||||
debug("%s: rate = %ld\n", __func__, rate);
|
||||
return rate;
|
||||
}
|
||||
|
||||
/* Set the clock rate */
|
||||
int clk_set_rate(struct clk *c, unsigned long rate)
|
||||
{
|
||||
int ret;
|
||||
|
||||
debug("%s: %s rate=%ld\n", __func__, c->name, rate);
|
||||
if (!c || !c->ops || !c->ops->set_rate)
|
||||
return -EINVAL;
|
||||
|
||||
if (c->use_cnt)
|
||||
return -EINVAL;
|
||||
|
||||
ret = c->ops->set_rate(c, rate);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Not required for this arch */
|
||||
/*
|
||||
long clk_round_rate(struct clk *clk, unsigned long rate);
|
||||
int clk_set_parent(struct clk *clk, struct clk *parent);
|
||||
struct clk *clk_get_parent(struct clk *clk);
|
||||
*/
|
||||
491
u-boot/arch/arm/cpu/armv7/bcm235xx/clk-core.h
Normal file
491
u-boot/arch/arm/cpu/armv7/bcm235xx/clk-core.h
Normal file
@@ -0,0 +1,491 @@
|
||||
/*
|
||||
* Copyright 2013 Broadcom Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <linux/stddef.h>
|
||||
|
||||
#ifdef CONFIG_CLK_DEBUG
|
||||
#undef writel
|
||||
#undef readl
|
||||
static inline void writel(u32 val, void *addr)
|
||||
{
|
||||
printf("Write [0x%p] = 0x%08x\n", addr, val);
|
||||
*(u32 *)addr = val;
|
||||
}
|
||||
|
||||
static inline u32 readl(void *addr)
|
||||
{
|
||||
u32 val = *(u32 *)addr;
|
||||
printf("Read [0x%p] = 0x%08x\n", addr, val);
|
||||
return val;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct clk;
|
||||
|
||||
struct clk_lookup {
|
||||
const char *dev_id;
|
||||
const char *con_id;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
extern struct clk_lookup arch_clk_tbl[];
|
||||
extern unsigned int arch_clk_tbl_array_size;
|
||||
|
||||
/**
|
||||
* struct clk_ops - standard clock operations
|
||||
* @enable: enable/disable clock, see clk_enable() and clk_disable()
|
||||
* @set_rate: set the clock rate, see clk_set_rate().
|
||||
* @get_rate: get the clock rate, see clk_get_rate().
|
||||
* @round_rate: round a given clock rate, see clk_round_rate().
|
||||
* @set_parent: set the clock's parent, see clk_set_parent().
|
||||
*
|
||||
* Group the common clock implementations together so that we
|
||||
* don't have to keep setting the same fiels again. We leave
|
||||
* enable in struct clk.
|
||||
*
|
||||
*/
|
||||
struct clk_ops {
|
||||
int (*enable)(struct clk *c, int enable);
|
||||
int (*set_rate)(struct clk *c, unsigned long rate);
|
||||
unsigned long (*get_rate)(struct clk *c);
|
||||
unsigned long (*round_rate)(struct clk *c, unsigned long rate);
|
||||
int (*set_parent)(struct clk *c, struct clk *parent);
|
||||
};
|
||||
|
||||
struct clk {
|
||||
struct clk *parent;
|
||||
const char *name;
|
||||
int use_cnt;
|
||||
unsigned long rate; /* in HZ */
|
||||
|
||||
/* programmable divider. 0 means fixed ratio to parent clock */
|
||||
unsigned long div;
|
||||
|
||||
struct clk_src *src;
|
||||
struct clk_ops *ops;
|
||||
|
||||
unsigned long ccu_clk_mgr_base;
|
||||
int sel;
|
||||
};
|
||||
|
||||
struct refclk *refclk_str_to_clk(const char *name);
|
||||
|
||||
/* The common clock framework uses u8 to represent a parent index */
|
||||
#define PARENT_COUNT_MAX ((u32)U8_MAX)
|
||||
|
||||
#define BAD_CLK_INDEX U8_MAX /* Can't ever be valid */
|
||||
#define BAD_CLK_NAME ((const char *)-1)
|
||||
|
||||
#define BAD_SCALED_DIV_VALUE U64_MAX
|
||||
|
||||
/*
|
||||
* Utility macros for object flag management. If possible, flags
|
||||
* should be defined such that 0 is the desired default value.
|
||||
*/
|
||||
#define FLAG(type, flag) BCM_CLK_ ## type ## _FLAGS_ ## flag
|
||||
#define FLAG_SET(obj, type, flag) ((obj)->flags |= FLAG(type, flag))
|
||||
#define FLAG_CLEAR(obj, type, flag) ((obj)->flags &= ~(FLAG(type, flag)))
|
||||
#define FLAG_FLIP(obj, type, flag) ((obj)->flags ^= FLAG(type, flag))
|
||||
#define FLAG_TEST(obj, type, flag) (!!((obj)->flags & FLAG(type, flag)))
|
||||
|
||||
/* Clock field state tests */
|
||||
|
||||
#define gate_exists(gate) FLAG_TEST(gate, GATE, EXISTS)
|
||||
#define gate_is_enabled(gate) FLAG_TEST(gate, GATE, ENABLED)
|
||||
#define gate_is_hw_controllable(gate) FLAG_TEST(gate, GATE, HW)
|
||||
#define gate_is_sw_controllable(gate) FLAG_TEST(gate, GATE, SW)
|
||||
#define gate_is_sw_managed(gate) FLAG_TEST(gate, GATE, SW_MANAGED)
|
||||
#define gate_is_no_disable(gate) FLAG_TEST(gate, GATE, NO_DISABLE)
|
||||
|
||||
#define gate_flip_enabled(gate) FLAG_FLIP(gate, GATE, ENABLED)
|
||||
|
||||
#define divider_exists(div) FLAG_TEST(div, DIV, EXISTS)
|
||||
#define divider_is_fixed(div) FLAG_TEST(div, DIV, FIXED)
|
||||
#define divider_has_fraction(div) (!divider_is_fixed(div) && \
|
||||
(div)->frac_width > 0)
|
||||
|
||||
#define selector_exists(sel) ((sel)->width != 0)
|
||||
#define trigger_exists(trig) FLAG_TEST(trig, TRIG, EXISTS)
|
||||
|
||||
/* Clock type, used to tell common block what it's part of */
|
||||
enum bcm_clk_type {
|
||||
bcm_clk_none, /* undefined clock type */
|
||||
bcm_clk_bus,
|
||||
bcm_clk_core,
|
||||
bcm_clk_peri
|
||||
};
|
||||
|
||||
/*
|
||||
* Gating control and status is managed by a 32-bit gate register.
|
||||
*
|
||||
* There are several types of gating available:
|
||||
* - (no gate)
|
||||
* A clock with no gate is assumed to be always enabled.
|
||||
* - hardware-only gating (auto-gating)
|
||||
* Enabling or disabling clocks with this type of gate is
|
||||
* managed automatically by the hardware. Such clocks can be
|
||||
* considered by the software to be enabled. The current status
|
||||
* of auto-gated clocks can be read from the gate status bit.
|
||||
* - software-only gating
|
||||
* Auto-gating is not available for this type of clock.
|
||||
* Instead, software manages whether it's enabled by setting or
|
||||
* clearing the enable bit. The current gate status of a gate
|
||||
* under software control can be read from the gate status bit.
|
||||
* To ensure a change to the gating status is complete, the
|
||||
* status bit can be polled to verify that the gate has entered
|
||||
* the desired state.
|
||||
* - selectable hardware or software gating
|
||||
* Gating for this type of clock can be configured to be either
|
||||
* under software or hardware control. Which type is in use is
|
||||
* determined by the hw_sw_sel bit of the gate register.
|
||||
*/
|
||||
struct bcm_clk_gate {
|
||||
u32 offset; /* gate register offset */
|
||||
u32 status_bit; /* 0: gate is disabled; 0: gatge is enabled */
|
||||
u32 en_bit; /* 0: disable; 1: enable */
|
||||
u32 hw_sw_sel_bit; /* 0: hardware gating; 1: software gating */
|
||||
u32 flags; /* BCM_CLK_GATE_FLAGS_* below */
|
||||
};
|
||||
|
||||
/*
|
||||
* Gate flags:
|
||||
* HW means this gate can be auto-gated
|
||||
* SW means the state of this gate can be software controlled
|
||||
* NO_DISABLE means this gate is (only) enabled if under software control
|
||||
* SW_MANAGED means the status of this gate is under software control
|
||||
* ENABLED means this software-managed gate is *supposed* to be enabled
|
||||
*/
|
||||
#define BCM_CLK_GATE_FLAGS_EXISTS ((u32)1 << 0) /* Gate is valid */
|
||||
#define BCM_CLK_GATE_FLAGS_HW ((u32)1 << 1) /* Can auto-gate */
|
||||
#define BCM_CLK_GATE_FLAGS_SW ((u32)1 << 2) /* Software control */
|
||||
#define BCM_CLK_GATE_FLAGS_NO_DISABLE ((u32)1 << 3) /* HW or enabled */
|
||||
#define BCM_CLK_GATE_FLAGS_SW_MANAGED ((u32)1 << 4) /* SW now in control */
|
||||
#define BCM_CLK_GATE_FLAGS_ENABLED ((u32)1 << 5) /* If SW_MANAGED */
|
||||
|
||||
/*
|
||||
* Gate initialization macros.
|
||||
*
|
||||
* Any gate initially under software control will be enabled.
|
||||
*/
|
||||
|
||||
/* A hardware/software gate initially under software control */
|
||||
#define HW_SW_GATE(_offset, _status_bit, _en_bit, _hw_sw_sel_bit) \
|
||||
{ \
|
||||
.offset = (_offset), \
|
||||
.status_bit = (_status_bit), \
|
||||
.en_bit = (_en_bit), \
|
||||
.hw_sw_sel_bit = (_hw_sw_sel_bit), \
|
||||
.flags = FLAG(GATE, HW)|FLAG(GATE, SW)| \
|
||||
FLAG(GATE, SW_MANAGED)|FLAG(GATE, ENABLED)| \
|
||||
FLAG(GATE, EXISTS), \
|
||||
}
|
||||
|
||||
/* A hardware/software gate initially under hardware control */
|
||||
#define HW_SW_GATE_AUTO(_offset, _status_bit, _en_bit, _hw_sw_sel_bit) \
|
||||
{ \
|
||||
.offset = (_offset), \
|
||||
.status_bit = (_status_bit), \
|
||||
.en_bit = (_en_bit), \
|
||||
.hw_sw_sel_bit = (_hw_sw_sel_bit), \
|
||||
.flags = FLAG(GATE, HW)|FLAG(GATE, SW)| \
|
||||
FLAG(GATE, EXISTS), \
|
||||
}
|
||||
|
||||
/* A hardware-or-enabled gate (enabled if not under hardware control) */
|
||||
#define HW_ENABLE_GATE(_offset, _status_bit, _en_bit, _hw_sw_sel_bit) \
|
||||
{ \
|
||||
.offset = (_offset), \
|
||||
.status_bit = (_status_bit), \
|
||||
.en_bit = (_en_bit), \
|
||||
.hw_sw_sel_bit = (_hw_sw_sel_bit), \
|
||||
.flags = FLAG(GATE, HW)|FLAG(GATE, SW)| \
|
||||
FLAG(GATE, NO_DISABLE)|FLAG(GATE, EXISTS), \
|
||||
}
|
||||
|
||||
/* A software-only gate */
|
||||
#define SW_ONLY_GATE(_offset, _status_bit, _en_bit) \
|
||||
{ \
|
||||
.offset = (_offset), \
|
||||
.status_bit = (_status_bit), \
|
||||
.en_bit = (_en_bit), \
|
||||
.flags = FLAG(GATE, SW)|FLAG(GATE, SW_MANAGED)| \
|
||||
FLAG(GATE, ENABLED)|FLAG(GATE, EXISTS), \
|
||||
}
|
||||
|
||||
/* A hardware-only gate */
|
||||
#define HW_ONLY_GATE(_offset, _status_bit) \
|
||||
{ \
|
||||
.offset = (_offset), \
|
||||
.status_bit = (_status_bit), \
|
||||
.flags = FLAG(GATE, HW)|FLAG(GATE, EXISTS), \
|
||||
}
|
||||
|
||||
/*
|
||||
* Each clock can have zero, one, or two dividers which change the
|
||||
* output rate of the clock. Each divider can be either fixed or
|
||||
* variable. If there are two dividers, they are the "pre-divider"
|
||||
* and the "regular" or "downstream" divider. If there is only one,
|
||||
* there is no pre-divider.
|
||||
*
|
||||
* A fixed divider is any non-zero (positive) value, and it
|
||||
* indicates how the input rate is affected by the divider.
|
||||
*
|
||||
* The value of a variable divider is maintained in a sub-field of a
|
||||
* 32-bit divider register. The position of the field in the
|
||||
* register is defined by its offset and width. The value recorded
|
||||
* in this field is always 1 less than the value it represents.
|
||||
*
|
||||
* In addition, a variable divider can indicate that some subset
|
||||
* of its bits represent a "fractional" part of the divider. Such
|
||||
* bits comprise the low-order portion of the divider field, and can
|
||||
* be viewed as representing the portion of the divider that lies to
|
||||
* the right of the decimal point. Most variable dividers have zero
|
||||
* fractional bits. Variable dividers with non-zero fraction width
|
||||
* still record a value 1 less than the value they represent; the
|
||||
* added 1 does *not* affect the low-order bit in this case, it
|
||||
* affects the bits above the fractional part only. (Often in this
|
||||
* code a divider field value is distinguished from the value it
|
||||
* represents by referring to the latter as a "divisor".)
|
||||
*
|
||||
* In order to avoid dealing with fractions, divider arithmetic is
|
||||
* performed using "scaled" values. A scaled value is one that's
|
||||
* been left-shifted by the fractional width of a divider. Dividing
|
||||
* a scaled value by a scaled divisor produces the desired quotient
|
||||
* without loss of precision and without any other special handling
|
||||
* for fractions.
|
||||
*
|
||||
* The recorded value of a variable divider can be modified. To
|
||||
* modify either divider (or both), a clock must be enabled (i.e.,
|
||||
* using its gate). In addition, a trigger register (described
|
||||
* below) must be used to commit the change, and polled to verify
|
||||
* the change is complete.
|
||||
*/
|
||||
struct bcm_clk_div {
|
||||
union {
|
||||
struct { /* variable divider */
|
||||
u32 offset; /* divider register offset */
|
||||
u32 shift; /* field shift */
|
||||
u32 width; /* field width */
|
||||
u32 frac_width; /* field fraction width */
|
||||
|
||||
u64 scaled_div; /* scaled divider value */
|
||||
};
|
||||
u32 fixed; /* non-zero fixed divider value */
|
||||
};
|
||||
u32 flags; /* BCM_CLK_DIV_FLAGS_* below */
|
||||
};
|
||||
|
||||
/*
|
||||
* Divider flags:
|
||||
* EXISTS means this divider exists
|
||||
* FIXED means it is a fixed-rate divider
|
||||
*/
|
||||
#define BCM_CLK_DIV_FLAGS_EXISTS ((u32)1 << 0) /* Divider is valid */
|
||||
#define BCM_CLK_DIV_FLAGS_FIXED ((u32)1 << 1) /* Fixed-value */
|
||||
|
||||
/* Divider initialization macros */
|
||||
|
||||
/* A fixed (non-zero) divider */
|
||||
#define FIXED_DIVIDER(_value) \
|
||||
{ \
|
||||
.fixed = (_value), \
|
||||
.flags = FLAG(DIV, EXISTS)|FLAG(DIV, FIXED), \
|
||||
}
|
||||
|
||||
/* A divider with an integral divisor */
|
||||
#define DIVIDER(_offset, _shift, _width) \
|
||||
{ \
|
||||
.offset = (_offset), \
|
||||
.shift = (_shift), \
|
||||
.width = (_width), \
|
||||
.scaled_div = BAD_SCALED_DIV_VALUE, \
|
||||
.flags = FLAG(DIV, EXISTS), \
|
||||
}
|
||||
|
||||
/* A divider whose divisor has an integer and fractional part */
|
||||
#define FRAC_DIVIDER(_offset, _shift, _width, _frac_width) \
|
||||
{ \
|
||||
.offset = (_offset), \
|
||||
.shift = (_shift), \
|
||||
.width = (_width), \
|
||||
.frac_width = (_frac_width), \
|
||||
.scaled_div = BAD_SCALED_DIV_VALUE, \
|
||||
.flags = FLAG(DIV, EXISTS), \
|
||||
}
|
||||
|
||||
/*
|
||||
* Clocks may have multiple "parent" clocks. If there is more than
|
||||
* one, a selector must be specified to define which of the parent
|
||||
* clocks is currently in use. The selected clock is indicated in a
|
||||
* sub-field of a 32-bit selector register. The range of
|
||||
* representable selector values typically exceeds the number of
|
||||
* available parent clocks. Occasionally the reset value of a
|
||||
* selector field is explicitly set to a (specific) value that does
|
||||
* not correspond to a defined input clock.
|
||||
*
|
||||
* We register all known parent clocks with the common clock code
|
||||
* using a packed array (i.e., no empty slots) of (parent) clock
|
||||
* names, and refer to them later using indexes into that array.
|
||||
* We maintain an array of selector values indexed by common clock
|
||||
* index values in order to map between these common clock indexes
|
||||
* and the selector values used by the hardware.
|
||||
*
|
||||
* Like dividers, a selector can be modified, but to do so a clock
|
||||
* must be enabled, and a trigger must be used to commit the change.
|
||||
*/
|
||||
struct bcm_clk_sel {
|
||||
u32 offset; /* selector register offset */
|
||||
u32 shift; /* field shift */
|
||||
u32 width; /* field width */
|
||||
|
||||
u32 parent_count; /* number of entries in parent_sel[] */
|
||||
u32 *parent_sel; /* array of parent selector values */
|
||||
u8 clk_index; /* current selected index in parent_sel[] */
|
||||
};
|
||||
|
||||
/* Selector initialization macro */
|
||||
#define SELECTOR(_offset, _shift, _width) \
|
||||
{ \
|
||||
.offset = (_offset), \
|
||||
.shift = (_shift), \
|
||||
.width = (_width), \
|
||||
.clk_index = BAD_CLK_INDEX, \
|
||||
}
|
||||
|
||||
/*
|
||||
* Making changes to a variable divider or a selector for a clock
|
||||
* requires the use of a trigger. A trigger is defined by a single
|
||||
* bit within a register. To signal a change, a 1 is written into
|
||||
* that bit. To determine when the change has been completed, that
|
||||
* trigger bit is polled; the read value will be 1 while the change
|
||||
* is in progress, and 0 when it is complete.
|
||||
*
|
||||
* Occasionally a clock will have more than one trigger. In this
|
||||
* case, the "pre-trigger" will be used when changing a clock's
|
||||
* selector and/or its pre-divider.
|
||||
*/
|
||||
struct bcm_clk_trig {
|
||||
u32 offset; /* trigger register offset */
|
||||
u32 bit; /* trigger bit */
|
||||
u32 flags; /* BCM_CLK_TRIG_FLAGS_* below */
|
||||
};
|
||||
|
||||
/*
|
||||
* Trigger flags:
|
||||
* EXISTS means this trigger exists
|
||||
*/
|
||||
#define BCM_CLK_TRIG_FLAGS_EXISTS ((u32)1 << 0) /* Trigger is valid */
|
||||
|
||||
/* Trigger initialization macro */
|
||||
#define TRIGGER(_offset, _bit) \
|
||||
{ \
|
||||
.offset = (_offset), \
|
||||
.bit = (_bit), \
|
||||
.flags = FLAG(TRIG, EXISTS), \
|
||||
}
|
||||
|
||||
struct bus_clk_data {
|
||||
struct bcm_clk_gate gate;
|
||||
};
|
||||
|
||||
struct core_clk_data {
|
||||
struct bcm_clk_gate gate;
|
||||
};
|
||||
|
||||
struct peri_clk_data {
|
||||
struct bcm_clk_gate gate;
|
||||
struct bcm_clk_trig pre_trig;
|
||||
struct bcm_clk_div pre_div;
|
||||
struct bcm_clk_trig trig;
|
||||
struct bcm_clk_div div;
|
||||
struct bcm_clk_sel sel;
|
||||
const char *clocks[]; /* must be last; use CLOCKS() to declare */
|
||||
};
|
||||
#define CLOCKS(...) { __VA_ARGS__, NULL, }
|
||||
#define NO_CLOCKS { NULL, } /* Must use of no parent clocks */
|
||||
|
||||
struct refclk {
|
||||
struct clk clk;
|
||||
};
|
||||
|
||||
struct peri_clock {
|
||||
struct clk clk;
|
||||
struct peri_clk_data *data;
|
||||
};
|
||||
|
||||
struct ccu_clock {
|
||||
struct clk clk;
|
||||
|
||||
int num_policy_masks;
|
||||
unsigned long policy_freq_offset;
|
||||
int freq_bit_shift; /* 8 for most CCUs */
|
||||
unsigned long policy_ctl_offset;
|
||||
unsigned long policy0_mask_offset;
|
||||
unsigned long policy1_mask_offset;
|
||||
unsigned long policy2_mask_offset;
|
||||
unsigned long policy3_mask_offset;
|
||||
unsigned long policy0_mask2_offset;
|
||||
unsigned long policy1_mask2_offset;
|
||||
unsigned long policy2_mask2_offset;
|
||||
unsigned long policy3_mask2_offset;
|
||||
unsigned long lvm_en_offset;
|
||||
|
||||
int freq_id;
|
||||
unsigned long *freq_tbl;
|
||||
};
|
||||
|
||||
struct bus_clock {
|
||||
struct clk clk;
|
||||
struct bus_clk_data *data;
|
||||
unsigned long *freq_tbl;
|
||||
};
|
||||
|
||||
struct ref_clock {
|
||||
struct clk clk;
|
||||
};
|
||||
|
||||
static inline int is_same_clock(struct clk *a, struct clk *b)
|
||||
{
|
||||
return a == b;
|
||||
}
|
||||
|
||||
#define to_clk(p) (&((p)->clk))
|
||||
#define name_to_clk(name) (&((name##_clk).clk))
|
||||
/* declare a struct clk_lookup */
|
||||
#define CLK_LK(name) \
|
||||
{.con_id = __stringify(name##_clk), .clk = name_to_clk(name),}
|
||||
|
||||
static inline struct refclk *to_refclk(struct clk *clock)
|
||||
{
|
||||
return container_of(clock, struct refclk, clk);
|
||||
}
|
||||
|
||||
static inline struct peri_clock *to_peri_clk(struct clk *clock)
|
||||
{
|
||||
return container_of(clock, struct peri_clock, clk);
|
||||
}
|
||||
|
||||
static inline struct ccu_clock *to_ccu_clk(struct clk *clock)
|
||||
{
|
||||
return container_of(clock, struct ccu_clock, clk);
|
||||
}
|
||||
|
||||
static inline struct bus_clock *to_bus_clk(struct clk *clock)
|
||||
{
|
||||
return container_of(clock, struct bus_clock, clk);
|
||||
}
|
||||
|
||||
static inline struct ref_clock *to_ref_clk(struct clk *clock)
|
||||
{
|
||||
return container_of(clock, struct ref_clock, clk);
|
||||
}
|
||||
|
||||
extern struct clk_ops peri_clk_ops;
|
||||
extern struct clk_ops ccu_clk_ops;
|
||||
extern struct clk_ops bus_clk_ops;
|
||||
extern struct clk_ops ref_clk_ops;
|
||||
|
||||
int clk_get_and_enable(char *clkstr);
|
||||
143
u-boot/arch/arm/cpu/armv7/bcm235xx/clk-eth.c
Normal file
143
u-boot/arch/arm/cpu/armv7/bcm235xx/clk-eth.c
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 2014 Broadcom Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/arch/sysmap.h>
|
||||
#include <asm/kona-common/clk.h>
|
||||
#include "clk-core.h"
|
||||
|
||||
#define WR_ACCESS_ADDR ESUB_CLK_BASE_ADDR
|
||||
#define WR_ACCESS_PASSWORD 0xA5A500
|
||||
|
||||
#define PLLE_POST_RESETB_ADDR (ESUB_CLK_BASE_ADDR + 0x00000C00)
|
||||
|
||||
#define PLLE_RESETB_ADDR (ESUB_CLK_BASE_ADDR + 0x00000C58)
|
||||
#define PLLE_RESETB_I_PLL_RESETB_PLLE_MASK 0x00010000
|
||||
#define PLLE_POST_RESETB_I_POST_RESETB_PLLE_MASK 0x00000001
|
||||
|
||||
#define PLL_LOCK_ADDR (ESUB_CLK_BASE_ADDR + 0x00000C38)
|
||||
#define PLL_LOCK_PLL_LOCK_PLLE_MASK 0x00000001
|
||||
|
||||
#define ESW_SYS_DIV_ADDR (ESUB_CLK_BASE_ADDR + 0x00000A04)
|
||||
#define ESW_SYS_DIV_PLL_SELECT_MASK 0x00000300
|
||||
#define ESW_SYS_DIV_DIV_MASK 0x0000001C
|
||||
#define ESW_SYS_DIV_PLL_VAR_208M_CLK_SELECT 0x00000100
|
||||
#define ESW_SYS_DIV_DIV_SELECT 0x4
|
||||
#define ESW_SYS_DIV_TRIGGER_MASK 0x00000001
|
||||
|
||||
#define ESUB_AXI_DIV_DEBUG_ADDR (ESUB_CLK_BASE_ADDR + 0x00000E04)
|
||||
#define ESUB_AXI_DIV_DEBUG_PLL_SELECT_MASK 0x0000001C
|
||||
#define ESUB_AXI_DIV_DEBUG_PLL_SELECT_OVERRIDE_MASK 0x00000040
|
||||
#define ESUB_AXI_DIV_DEBUG_PLL_VAR_208M_CLK_SELECT 0x0
|
||||
#define ESUB_AXI_DIV_DEBUG_TRIGGER_MASK 0x00000001
|
||||
|
||||
#define PLL_MAX_RETRY 100
|
||||
|
||||
/* Enable appropriate clocks for Ethernet */
|
||||
int clk_eth_enable(void)
|
||||
{
|
||||
int rc = -1;
|
||||
int retry_count = 0;
|
||||
rc = clk_get_and_enable("esub_ccu_clk");
|
||||
|
||||
/* Enable Access to CCU registers */
|
||||
writel((1 | WR_ACCESS_PASSWORD), WR_ACCESS_ADDR);
|
||||
|
||||
writel(readl(PLLE_POST_RESETB_ADDR) &
|
||||
~PLLE_POST_RESETB_I_POST_RESETB_PLLE_MASK,
|
||||
PLLE_POST_RESETB_ADDR);
|
||||
|
||||
/* Take PLL out of reset and put into normal mode */
|
||||
writel(readl(PLLE_RESETB_ADDR) | PLLE_RESETB_I_PLL_RESETB_PLLE_MASK,
|
||||
PLLE_RESETB_ADDR);
|
||||
|
||||
/* Wait for PLL lock */
|
||||
rc = -1;
|
||||
while (retry_count < PLL_MAX_RETRY) {
|
||||
udelay(100);
|
||||
if (readl(PLL_LOCK_ADDR) & PLL_LOCK_PLL_LOCK_PLLE_MASK) {
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
retry_count++;
|
||||
}
|
||||
|
||||
if (rc == -1) {
|
||||
printf("%s: ETH-PLL lock timeout, Ethernet is not enabled!\n",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
writel(readl(PLLE_POST_RESETB_ADDR) |
|
||||
PLLE_POST_RESETB_I_POST_RESETB_PLLE_MASK,
|
||||
PLLE_POST_RESETB_ADDR);
|
||||
|
||||
/* Switch esw_sys_clk to use 104MHz(208MHz/2) clock */
|
||||
writel((readl(ESW_SYS_DIV_ADDR) &
|
||||
~(ESW_SYS_DIV_PLL_SELECT_MASK | ESW_SYS_DIV_DIV_MASK)) |
|
||||
ESW_SYS_DIV_PLL_VAR_208M_CLK_SELECT | ESW_SYS_DIV_DIV_SELECT,
|
||||
ESW_SYS_DIV_ADDR);
|
||||
|
||||
writel(readl(ESW_SYS_DIV_ADDR) | ESW_SYS_DIV_TRIGGER_MASK,
|
||||
ESW_SYS_DIV_ADDR);
|
||||
|
||||
/* Wait for trigger complete */
|
||||
rc = -1;
|
||||
retry_count = 0;
|
||||
while (retry_count < PLL_MAX_RETRY) {
|
||||
udelay(100);
|
||||
if (!(readl(ESW_SYS_DIV_ADDR) & ESW_SYS_DIV_TRIGGER_MASK)) {
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
retry_count++;
|
||||
}
|
||||
|
||||
if (rc == -1) {
|
||||
printf("%s: SYS CLK Trigger timeout, Ethernet is not enabled!\n",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* switch Esub AXI clock to 208MHz */
|
||||
writel((readl(ESUB_AXI_DIV_DEBUG_ADDR) &
|
||||
~(ESUB_AXI_DIV_DEBUG_PLL_SELECT_MASK |
|
||||
ESUB_AXI_DIV_DEBUG_PLL_SELECT_OVERRIDE_MASK |
|
||||
ESUB_AXI_DIV_DEBUG_TRIGGER_MASK)) |
|
||||
ESUB_AXI_DIV_DEBUG_PLL_VAR_208M_CLK_SELECT |
|
||||
ESUB_AXI_DIV_DEBUG_PLL_SELECT_OVERRIDE_MASK,
|
||||
ESUB_AXI_DIV_DEBUG_ADDR);
|
||||
|
||||
writel(readl(ESUB_AXI_DIV_DEBUG_ADDR) |
|
||||
ESUB_AXI_DIV_DEBUG_TRIGGER_MASK,
|
||||
ESUB_AXI_DIV_DEBUG_ADDR);
|
||||
|
||||
/* Wait for trigger complete */
|
||||
rc = -1;
|
||||
retry_count = 0;
|
||||
while (retry_count < PLL_MAX_RETRY) {
|
||||
udelay(100);
|
||||
if (!(readl(ESUB_AXI_DIV_DEBUG_ADDR) &
|
||||
ESUB_AXI_DIV_DEBUG_TRIGGER_MASK)) {
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
retry_count++;
|
||||
}
|
||||
|
||||
if (rc == -1) {
|
||||
printf("%s: AXI CLK Trigger timeout, Ethernet is not enabled!\n",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Disable Access to CCU registers */
|
||||
writel(WR_ACCESS_PASSWORD, WR_ACCESS_ADDR);
|
||||
|
||||
return rc;
|
||||
}
|
||||
73
u-boot/arch/arm/cpu/armv7/bcm235xx/clk-sdio.c
Normal file
73
u-boot/arch/arm/cpu/armv7/bcm235xx/clk-sdio.c
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2013 Broadcom Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/arch/sysmap.h>
|
||||
#include <asm/kona-common/clk.h>
|
||||
#include "clk-core.h"
|
||||
|
||||
/* Enable appropriate clocks for an SDIO port */
|
||||
int clk_sdio_enable(void *base, u32 rate, u32 *actual_ratep)
|
||||
{
|
||||
int ret;
|
||||
struct clk *c;
|
||||
|
||||
char *clkstr;
|
||||
char *slpstr;
|
||||
char *ahbstr;
|
||||
|
||||
switch ((u32) base) {
|
||||
case CONFIG_SYS_SDIO_BASE0:
|
||||
clkstr = CONFIG_SYS_SDIO0 "_clk";
|
||||
ahbstr = CONFIG_SYS_SDIO0 "_ahb_clk";
|
||||
slpstr = CONFIG_SYS_SDIO0 "_sleep_clk";
|
||||
break;
|
||||
case CONFIG_SYS_SDIO_BASE1:
|
||||
clkstr = CONFIG_SYS_SDIO1 "_clk";
|
||||
ahbstr = CONFIG_SYS_SDIO1 "_ahb_clk";
|
||||
slpstr = CONFIG_SYS_SDIO1 "_sleep_clk";
|
||||
break;
|
||||
case CONFIG_SYS_SDIO_BASE2:
|
||||
clkstr = CONFIG_SYS_SDIO2 "_clk";
|
||||
ahbstr = CONFIG_SYS_SDIO2 "_ahb_clk";
|
||||
slpstr = CONFIG_SYS_SDIO2 "_sleep_clk";
|
||||
break;
|
||||
case CONFIG_SYS_SDIO_BASE3:
|
||||
clkstr = CONFIG_SYS_SDIO3 "_clk";
|
||||
ahbstr = CONFIG_SYS_SDIO3 "_ahb_clk";
|
||||
slpstr = CONFIG_SYS_SDIO3 "_sleep_clk";
|
||||
break;
|
||||
default:
|
||||
printf("%s: base 0x%p not found\n", __func__, base);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = clk_get_and_enable(ahbstr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_get_and_enable(slpstr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
c = clk_get(clkstr);
|
||||
if (c) {
|
||||
ret = clk_set_rate(c, rate);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_enable(c);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
printf("%s: Couldn't find %s\n", __func__, clkstr);
|
||||
return -EINVAL;
|
||||
}
|
||||
*actual_ratep = rate;
|
||||
return 0;
|
||||
}
|
||||
27
u-boot/arch/arm/cpu/armv7/bcm235xx/clk-usb-otg.c
Normal file
27
u-boot/arch/arm/cpu/armv7/bcm235xx/clk-usb-otg.c
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2014 Broadcom Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/arch/sysmap.h>
|
||||
#include "clk-core.h"
|
||||
|
||||
/* Enable appropriate clocks for the USB OTG port */
|
||||
int clk_usb_otg_enable(void *base)
|
||||
{
|
||||
char *ahbstr;
|
||||
|
||||
switch ((u32) base) {
|
||||
case HSOTG_BASE_ADDR:
|
||||
ahbstr = "usb_otg_ahb_clk";
|
||||
break;
|
||||
default:
|
||||
printf("%s: base 0x%p not found\n", __func__, base);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return clk_get_and_enable(ahbstr);
|
||||
}
|
||||
13
u-boot/arch/arm/cpu/armv7/bcm281xx/Makefile
Normal file
13
u-boot/arch/arm/cpu/armv7/bcm281xx/Makefile
Normal file
@@ -0,0 +1,13 @@
|
||||
#
|
||||
# Copyright 2013 Broadcom Corporation.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y += reset.o
|
||||
obj-y += clk-core.o
|
||||
obj-y += clk-bcm281xx.o
|
||||
obj-y += clk-sdio.o
|
||||
obj-y += clk-bsc.o
|
||||
obj-$(CONFIG_BCM_SF2_ETH) += clk-eth.o
|
||||
obj-y += clk-usb-otg.o
|
||||
573
u-boot/arch/arm/cpu/armv7/bcm281xx/clk-bcm281xx.c
Normal file
573
u-boot/arch/arm/cpu/armv7/bcm281xx/clk-bcm281xx.c
Normal file
@@ -0,0 +1,573 @@
|
||||
/*
|
||||
* Copyright 2013 Broadcom Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* bcm281xx-specific clock tables
|
||||
*
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/arch/sysmap.h>
|
||||
#include <asm/kona-common/clk.h>
|
||||
#include "clk-core.h"
|
||||
|
||||
#define CLOCK_1K 1000
|
||||
#define CLOCK_1M (CLOCK_1K * 1000)
|
||||
|
||||
/* declare a reference clock */
|
||||
#define DECLARE_REF_CLK(clk_name, clk_parent, clk_rate, clk_div) \
|
||||
static struct refclk clk_name = { \
|
||||
.clk = { \
|
||||
.name = #clk_name, \
|
||||
.parent = clk_parent, \
|
||||
.rate = clk_rate, \
|
||||
.div = clk_div, \
|
||||
.ops = &ref_clk_ops, \
|
||||
}, \
|
||||
}
|
||||
|
||||
/*
|
||||
* Reference clocks
|
||||
*/
|
||||
|
||||
/* Declare a list of reference clocks */
|
||||
DECLARE_REF_CLK(ref_crystal, 0, 26 * CLOCK_1M, 1);
|
||||
DECLARE_REF_CLK(var_96m, 0, 96 * CLOCK_1M, 1);
|
||||
DECLARE_REF_CLK(ref_96m, 0, 96 * CLOCK_1M, 1);
|
||||
DECLARE_REF_CLK(ref_312m, 0, 312 * CLOCK_1M, 0);
|
||||
DECLARE_REF_CLK(ref_104m, &ref_312m.clk, 104 * CLOCK_1M, 3);
|
||||
DECLARE_REF_CLK(ref_52m, &ref_104m.clk, 52 * CLOCK_1M, 2);
|
||||
DECLARE_REF_CLK(ref_13m, &ref_52m.clk, 13 * CLOCK_1M, 4);
|
||||
DECLARE_REF_CLK(var_312m, 0, 312 * CLOCK_1M, 0);
|
||||
DECLARE_REF_CLK(var_104m, &var_312m.clk, 104 * CLOCK_1M, 3);
|
||||
DECLARE_REF_CLK(var_52m, &var_104m.clk, 52 * CLOCK_1M, 2);
|
||||
DECLARE_REF_CLK(var_13m, &var_52m.clk, 13 * CLOCK_1M, 4);
|
||||
|
||||
struct refclk_lkup {
|
||||
struct refclk *procclk;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
/* Lookup table for string to clk tranlation */
|
||||
#define MKSTR(x) {&x, #x}
|
||||
static struct refclk_lkup refclk_str_tbl[] = {
|
||||
MKSTR(ref_crystal), MKSTR(var_96m), MKSTR(ref_96m),
|
||||
MKSTR(ref_312m), MKSTR(ref_104m), MKSTR(ref_52m),
|
||||
MKSTR(ref_13m), MKSTR(var_312m), MKSTR(var_104m),
|
||||
MKSTR(var_52m), MKSTR(var_13m),
|
||||
};
|
||||
|
||||
int refclk_entries = sizeof(refclk_str_tbl)/sizeof(refclk_str_tbl[0]);
|
||||
|
||||
/* convert ref clock string to clock structure pointer */
|
||||
struct refclk *refclk_str_to_clk(const char *name)
|
||||
{
|
||||
int i;
|
||||
struct refclk_lkup *tblp = refclk_str_tbl;
|
||||
for (i = 0; i < refclk_entries; i++, tblp++) {
|
||||
if (!(strcmp(name, tblp->name)))
|
||||
return tblp->procclk;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* frequency tables indexed by freq_id */
|
||||
unsigned long master_axi_freq_tbl[8] = {
|
||||
26 * CLOCK_1M,
|
||||
52 * CLOCK_1M,
|
||||
104 * CLOCK_1M,
|
||||
156 * CLOCK_1M,
|
||||
156 * CLOCK_1M,
|
||||
208 * CLOCK_1M,
|
||||
312 * CLOCK_1M,
|
||||
312 * CLOCK_1M
|
||||
};
|
||||
|
||||
unsigned long master_ahb_freq_tbl[8] = {
|
||||
26 * CLOCK_1M,
|
||||
52 * CLOCK_1M,
|
||||
52 * CLOCK_1M,
|
||||
52 * CLOCK_1M,
|
||||
78 * CLOCK_1M,
|
||||
104 * CLOCK_1M,
|
||||
104 * CLOCK_1M,
|
||||
156 * CLOCK_1M
|
||||
};
|
||||
|
||||
unsigned long slave_axi_freq_tbl[8] = {
|
||||
26 * CLOCK_1M,
|
||||
52 * CLOCK_1M,
|
||||
78 * CLOCK_1M,
|
||||
104 * CLOCK_1M,
|
||||
156 * CLOCK_1M,
|
||||
156 * CLOCK_1M
|
||||
};
|
||||
|
||||
unsigned long slave_apb_freq_tbl[8] = {
|
||||
26 * CLOCK_1M,
|
||||
26 * CLOCK_1M,
|
||||
39 * CLOCK_1M,
|
||||
52 * CLOCK_1M,
|
||||
52 * CLOCK_1M,
|
||||
78 * CLOCK_1M
|
||||
};
|
||||
|
||||
unsigned long esub_freq_tbl[8] = {
|
||||
78 * CLOCK_1M,
|
||||
156 * CLOCK_1M,
|
||||
156 * CLOCK_1M,
|
||||
156 * CLOCK_1M,
|
||||
208 * CLOCK_1M,
|
||||
208 * CLOCK_1M,
|
||||
208 * CLOCK_1M
|
||||
};
|
||||
|
||||
static struct bus_clk_data bsc1_apb_data = {
|
||||
.gate = HW_SW_GATE_AUTO(0x0458, 16, 0, 1),
|
||||
};
|
||||
|
||||
static struct bus_clk_data bsc2_apb_data = {
|
||||
.gate = HW_SW_GATE_AUTO(0x045c, 16, 0, 1),
|
||||
};
|
||||
|
||||
static struct bus_clk_data bsc3_apb_data = {
|
||||
.gate = HW_SW_GATE_AUTO(0x0484, 16, 0, 1),
|
||||
};
|
||||
|
||||
/* * Master CCU clocks */
|
||||
static struct peri_clk_data sdio1_data = {
|
||||
.gate = HW_SW_GATE(0x0358, 18, 2, 3),
|
||||
.clocks = CLOCKS("ref_crystal",
|
||||
"var_52m",
|
||||
"ref_52m",
|
||||
"var_96m",
|
||||
"ref_96m"),
|
||||
.sel = SELECTOR(0x0a28, 0, 3),
|
||||
.div = DIVIDER(0x0a28, 4, 14),
|
||||
.trig = TRIGGER(0x0afc, 9),
|
||||
};
|
||||
|
||||
static struct peri_clk_data sdio2_data = {
|
||||
.gate = HW_SW_GATE(0x035c, 18, 2, 3),
|
||||
.clocks = CLOCKS("ref_crystal",
|
||||
"var_52m",
|
||||
"ref_52m",
|
||||
"var_96m",
|
||||
"ref_96m"),
|
||||
.sel = SELECTOR(0x0a2c, 0, 3),
|
||||
.div = DIVIDER(0x0a2c, 4, 14),
|
||||
.trig = TRIGGER(0x0afc, 10),
|
||||
};
|
||||
|
||||
static struct peri_clk_data sdio3_data = {
|
||||
.gate = HW_SW_GATE(0x0364, 18, 2, 3),
|
||||
.clocks = CLOCKS("ref_crystal",
|
||||
"var_52m",
|
||||
"ref_52m",
|
||||
"var_96m",
|
||||
"ref_96m"),
|
||||
.sel = SELECTOR(0x0a34, 0, 3),
|
||||
.div = DIVIDER(0x0a34, 4, 14),
|
||||
.trig = TRIGGER(0x0afc, 12),
|
||||
};
|
||||
|
||||
static struct peri_clk_data sdio4_data = {
|
||||
.gate = HW_SW_GATE(0x0360, 18, 2, 3),
|
||||
.clocks = CLOCKS("ref_crystal",
|
||||
"var_52m",
|
||||
"ref_52m",
|
||||
"var_96m",
|
||||
"ref_96m"),
|
||||
.sel = SELECTOR(0x0a30, 0, 3),
|
||||
.div = DIVIDER(0x0a30, 4, 14),
|
||||
.trig = TRIGGER(0x0afc, 11),
|
||||
};
|
||||
|
||||
static struct peri_clk_data sdio1_sleep_data = {
|
||||
.clocks = CLOCKS("ref_32k"),
|
||||
.gate = SW_ONLY_GATE(0x0358, 20, 4),
|
||||
};
|
||||
|
||||
static struct peri_clk_data sdio2_sleep_data = {
|
||||
.clocks = CLOCKS("ref_32k"),
|
||||
.gate = SW_ONLY_GATE(0x035c, 20, 4),
|
||||
};
|
||||
|
||||
static struct peri_clk_data sdio3_sleep_data = {
|
||||
.clocks = CLOCKS("ref_32k"),
|
||||
.gate = SW_ONLY_GATE(0x0364, 20, 4),
|
||||
};
|
||||
|
||||
static struct peri_clk_data sdio4_sleep_data = {
|
||||
.clocks = CLOCKS("ref_32k"),
|
||||
.gate = SW_ONLY_GATE(0x0360, 20, 4),
|
||||
};
|
||||
|
||||
static struct bus_clk_data usb_otg_ahb_data = {
|
||||
.gate = HW_SW_GATE_AUTO(0x0348, 16, 0, 1),
|
||||
};
|
||||
|
||||
static struct bus_clk_data sdio1_ahb_data = {
|
||||
.gate = HW_SW_GATE_AUTO(0x0358, 16, 0, 1),
|
||||
};
|
||||
|
||||
static struct bus_clk_data sdio2_ahb_data = {
|
||||
.gate = HW_SW_GATE_AUTO(0x035c, 16, 0, 1),
|
||||
};
|
||||
|
||||
static struct bus_clk_data sdio3_ahb_data = {
|
||||
.gate = HW_SW_GATE_AUTO(0x0364, 16, 0, 1),
|
||||
};
|
||||
|
||||
static struct bus_clk_data sdio4_ahb_data = {
|
||||
.gate = HW_SW_GATE_AUTO(0x0360, 16, 0, 1),
|
||||
};
|
||||
|
||||
/* * Slave CCU clocks */
|
||||
static struct peri_clk_data bsc1_data = {
|
||||
.gate = HW_SW_GATE(0x0458, 18, 2, 3),
|
||||
.clocks = CLOCKS("ref_crystal",
|
||||
"var_104m",
|
||||
"ref_104m",
|
||||
"var_13m",
|
||||
"ref_13m"),
|
||||
.sel = SELECTOR(0x0a64, 0, 3),
|
||||
.trig = TRIGGER(0x0afc, 23),
|
||||
};
|
||||
|
||||
static struct peri_clk_data bsc2_data = {
|
||||
.gate = HW_SW_GATE(0x045c, 18, 2, 3),
|
||||
.clocks = CLOCKS("ref_crystal",
|
||||
"var_104m",
|
||||
"ref_104m",
|
||||
"var_13m",
|
||||
"ref_13m"),
|
||||
.sel = SELECTOR(0x0a68, 0, 3),
|
||||
.trig = TRIGGER(0x0afc, 24),
|
||||
};
|
||||
|
||||
static struct peri_clk_data bsc3_data = {
|
||||
.gate = HW_SW_GATE(0x0484, 18, 2, 3),
|
||||
.clocks = CLOCKS("ref_crystal",
|
||||
"var_104m",
|
||||
"ref_104m",
|
||||
"var_13m",
|
||||
"ref_13m"),
|
||||
.sel = SELECTOR(0x0a84, 0, 3),
|
||||
.trig = TRIGGER(0x0b00, 2),
|
||||
};
|
||||
|
||||
/*
|
||||
* CCU clocks
|
||||
*/
|
||||
|
||||
static struct ccu_clock kpm_ccu_clk = {
|
||||
.clk = {
|
||||
.name = "kpm_ccu_clk",
|
||||
.ops = &ccu_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
|
||||
},
|
||||
.num_policy_masks = 1,
|
||||
.policy_freq_offset = 0x00000008,
|
||||
.freq_bit_shift = 8,
|
||||
.policy_ctl_offset = 0x0000000c,
|
||||
.policy0_mask_offset = 0x00000010,
|
||||
.policy1_mask_offset = 0x00000014,
|
||||
.policy2_mask_offset = 0x00000018,
|
||||
.policy3_mask_offset = 0x0000001c,
|
||||
.lvm_en_offset = 0x00000034,
|
||||
.freq_id = 2,
|
||||
.freq_tbl = master_axi_freq_tbl,
|
||||
};
|
||||
|
||||
static struct ccu_clock kps_ccu_clk = {
|
||||
.clk = {
|
||||
.name = "kps_ccu_clk",
|
||||
.ops = &ccu_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR,
|
||||
},
|
||||
.num_policy_masks = 2,
|
||||
.policy_freq_offset = 0x00000008,
|
||||
.freq_bit_shift = 8,
|
||||
.policy_ctl_offset = 0x0000000c,
|
||||
.policy0_mask_offset = 0x00000010,
|
||||
.policy1_mask_offset = 0x00000014,
|
||||
.policy2_mask_offset = 0x00000018,
|
||||
.policy3_mask_offset = 0x0000001c,
|
||||
.policy0_mask2_offset = 0x00000048,
|
||||
.policy1_mask2_offset = 0x0000004c,
|
||||
.policy2_mask2_offset = 0x00000050,
|
||||
.policy3_mask2_offset = 0x00000054,
|
||||
.lvm_en_offset = 0x00000034,
|
||||
.freq_id = 2,
|
||||
.freq_tbl = slave_axi_freq_tbl,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_BCM_SF2_ETH
|
||||
static struct ccu_clock esub_ccu_clk = {
|
||||
.clk = {
|
||||
.name = "esub_ccu_clk",
|
||||
.ops = &ccu_clk_ops,
|
||||
.ccu_clk_mgr_base = ESUB_CLK_BASE_ADDR,
|
||||
},
|
||||
.num_policy_masks = 1,
|
||||
.policy_freq_offset = 0x00000008,
|
||||
.freq_bit_shift = 8,
|
||||
.policy_ctl_offset = 0x0000000c,
|
||||
.policy0_mask_offset = 0x00000010,
|
||||
.policy1_mask_offset = 0x00000014,
|
||||
.policy2_mask_offset = 0x00000018,
|
||||
.policy3_mask_offset = 0x0000001c,
|
||||
.lvm_en_offset = 0x00000034,
|
||||
.freq_id = 2,
|
||||
.freq_tbl = esub_freq_tbl,
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Bus clocks
|
||||
*/
|
||||
|
||||
/* KPM bus clocks */
|
||||
static struct bus_clock usb_otg_ahb_clk = {
|
||||
.clk = {
|
||||
.name = "usb_otg_ahb_clk",
|
||||
.parent = &kpm_ccu_clk.clk,
|
||||
.ops = &bus_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
|
||||
},
|
||||
.freq_tbl = master_ahb_freq_tbl,
|
||||
.data = &usb_otg_ahb_data,
|
||||
};
|
||||
|
||||
static struct bus_clock sdio1_ahb_clk = {
|
||||
.clk = {
|
||||
.name = "sdio1_ahb_clk",
|
||||
.parent = &kpm_ccu_clk.clk,
|
||||
.ops = &bus_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
|
||||
},
|
||||
.freq_tbl = master_ahb_freq_tbl,
|
||||
.data = &sdio1_ahb_data,
|
||||
};
|
||||
|
||||
static struct bus_clock sdio2_ahb_clk = {
|
||||
.clk = {
|
||||
.name = "sdio2_ahb_clk",
|
||||
.parent = &kpm_ccu_clk.clk,
|
||||
.ops = &bus_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
|
||||
},
|
||||
.freq_tbl = master_ahb_freq_tbl,
|
||||
.data = &sdio2_ahb_data,
|
||||
};
|
||||
|
||||
static struct bus_clock sdio3_ahb_clk = {
|
||||
.clk = {
|
||||
.name = "sdio3_ahb_clk",
|
||||
.parent = &kpm_ccu_clk.clk,
|
||||
.ops = &bus_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
|
||||
},
|
||||
.freq_tbl = master_ahb_freq_tbl,
|
||||
.data = &sdio3_ahb_data,
|
||||
};
|
||||
|
||||
static struct bus_clock sdio4_ahb_clk = {
|
||||
.clk = {
|
||||
.name = "sdio4_ahb_clk",
|
||||
.parent = &kpm_ccu_clk.clk,
|
||||
.ops = &bus_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
|
||||
},
|
||||
.freq_tbl = master_ahb_freq_tbl,
|
||||
.data = &sdio4_ahb_data,
|
||||
};
|
||||
|
||||
static struct bus_clock bsc1_apb_clk = {
|
||||
.clk = {
|
||||
.name = "bsc1_apb_clk",
|
||||
.parent = &kps_ccu_clk.clk,
|
||||
.ops = &bus_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR,
|
||||
},
|
||||
.freq_tbl = slave_apb_freq_tbl,
|
||||
.data = &bsc1_apb_data,
|
||||
};
|
||||
|
||||
static struct bus_clock bsc2_apb_clk = {
|
||||
.clk = {
|
||||
.name = "bsc2_apb_clk",
|
||||
.parent = &kps_ccu_clk.clk,
|
||||
.ops = &bus_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR,
|
||||
},
|
||||
.freq_tbl = slave_apb_freq_tbl,
|
||||
.data = &bsc2_apb_data,
|
||||
};
|
||||
|
||||
static struct bus_clock bsc3_apb_clk = {
|
||||
.clk = {
|
||||
.name = "bsc3_apb_clk",
|
||||
.parent = &kps_ccu_clk.clk,
|
||||
.ops = &bus_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR,
|
||||
},
|
||||
.freq_tbl = slave_apb_freq_tbl,
|
||||
.data = &bsc3_apb_data,
|
||||
};
|
||||
|
||||
/* KPM peripheral */
|
||||
static struct peri_clock sdio1_clk = {
|
||||
.clk = {
|
||||
.name = "sdio1_clk",
|
||||
.parent = &ref_52m.clk,
|
||||
.ops = &peri_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
|
||||
},
|
||||
.data = &sdio1_data,
|
||||
};
|
||||
|
||||
static struct peri_clock sdio2_clk = {
|
||||
.clk = {
|
||||
.name = "sdio2_clk",
|
||||
.parent = &ref_52m.clk,
|
||||
.ops = &peri_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
|
||||
},
|
||||
.data = &sdio2_data,
|
||||
};
|
||||
|
||||
static struct peri_clock sdio3_clk = {
|
||||
.clk = {
|
||||
.name = "sdio3_clk",
|
||||
.parent = &ref_52m.clk,
|
||||
.ops = &peri_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
|
||||
},
|
||||
.data = &sdio3_data,
|
||||
};
|
||||
|
||||
static struct peri_clock sdio4_clk = {
|
||||
.clk = {
|
||||
.name = "sdio4_clk",
|
||||
.parent = &ref_52m.clk,
|
||||
.ops = &peri_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
|
||||
},
|
||||
.data = &sdio4_data,
|
||||
};
|
||||
|
||||
static struct peri_clock sdio1_sleep_clk = {
|
||||
.clk = {
|
||||
.name = "sdio1_sleep_clk",
|
||||
.parent = &kpm_ccu_clk.clk,
|
||||
.ops = &bus_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
|
||||
},
|
||||
.data = &sdio1_sleep_data,
|
||||
};
|
||||
|
||||
static struct peri_clock sdio2_sleep_clk = {
|
||||
.clk = {
|
||||
.name = "sdio2_sleep_clk",
|
||||
.parent = &kpm_ccu_clk.clk,
|
||||
.ops = &bus_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
|
||||
},
|
||||
.data = &sdio2_sleep_data,
|
||||
};
|
||||
|
||||
static struct peri_clock sdio3_sleep_clk = {
|
||||
.clk = {
|
||||
.name = "sdio3_sleep_clk",
|
||||
.parent = &kpm_ccu_clk.clk,
|
||||
.ops = &bus_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
|
||||
},
|
||||
.data = &sdio3_sleep_data,
|
||||
};
|
||||
|
||||
static struct peri_clock sdio4_sleep_clk = {
|
||||
.clk = {
|
||||
.name = "sdio4_sleep_clk",
|
||||
.parent = &kpm_ccu_clk.clk,
|
||||
.ops = &bus_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR,
|
||||
},
|
||||
.data = &sdio4_sleep_data,
|
||||
};
|
||||
|
||||
/* KPS peripheral clock */
|
||||
static struct peri_clock bsc1_clk = {
|
||||
.clk = {
|
||||
.name = "bsc1_clk",
|
||||
.parent = &ref_13m.clk,
|
||||
.rate = 13 * CLOCK_1M,
|
||||
.div = 1,
|
||||
.ops = &peri_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR,
|
||||
},
|
||||
.data = &bsc1_data,
|
||||
};
|
||||
|
||||
static struct peri_clock bsc2_clk = {
|
||||
.clk = {
|
||||
.name = "bsc2_clk",
|
||||
.parent = &ref_13m.clk,
|
||||
.rate = 13 * CLOCK_1M,
|
||||
.div = 1,
|
||||
.ops = &peri_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR,
|
||||
},
|
||||
.data = &bsc2_data,
|
||||
};
|
||||
|
||||
static struct peri_clock bsc3_clk = {
|
||||
.clk = {
|
||||
.name = "bsc3_clk",
|
||||
.parent = &ref_13m.clk,
|
||||
.rate = 13 * CLOCK_1M,
|
||||
.div = 1,
|
||||
.ops = &peri_clk_ops,
|
||||
.ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR,
|
||||
},
|
||||
.data = &bsc3_data,
|
||||
};
|
||||
|
||||
/* public table for registering clocks */
|
||||
struct clk_lookup arch_clk_tbl[] = {
|
||||
/* Peripheral clocks */
|
||||
CLK_LK(sdio1),
|
||||
CLK_LK(sdio2),
|
||||
CLK_LK(sdio3),
|
||||
CLK_LK(sdio4),
|
||||
CLK_LK(sdio1_sleep),
|
||||
CLK_LK(sdio2_sleep),
|
||||
CLK_LK(sdio3_sleep),
|
||||
CLK_LK(sdio4_sleep),
|
||||
CLK_LK(bsc1),
|
||||
CLK_LK(bsc2),
|
||||
CLK_LK(bsc3),
|
||||
/* Bus clocks */
|
||||
CLK_LK(usb_otg_ahb),
|
||||
CLK_LK(sdio1_ahb),
|
||||
CLK_LK(sdio2_ahb),
|
||||
CLK_LK(sdio3_ahb),
|
||||
CLK_LK(sdio4_ahb),
|
||||
CLK_LK(bsc1_apb),
|
||||
CLK_LK(bsc2_apb),
|
||||
CLK_LK(bsc3_apb),
|
||||
#ifdef CONFIG_BCM_SF2_ETH
|
||||
CLK_LK(esub_ccu),
|
||||
#endif
|
||||
};
|
||||
|
||||
/* public array size */
|
||||
unsigned int arch_clk_tbl_array_size = ARRAY_SIZE(arch_clk_tbl);
|
||||
52
u-boot/arch/arm/cpu/armv7/bcm281xx/clk-bsc.c
Normal file
52
u-boot/arch/arm/cpu/armv7/bcm281xx/clk-bsc.c
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2013 Broadcom Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/arch/sysmap.h>
|
||||
#include <asm/kona-common/clk.h>
|
||||
#include "clk-core.h"
|
||||
|
||||
/* Enable appropriate clocks for a BSC/I2C port */
|
||||
int clk_bsc_enable(void *base)
|
||||
{
|
||||
int ret;
|
||||
char *bscstr, *apbstr;
|
||||
|
||||
switch ((u32) base) {
|
||||
case PMU_BSC_BASE_ADDR:
|
||||
/* PMU clock is always enabled */
|
||||
return 0;
|
||||
case BSC1_BASE_ADDR:
|
||||
bscstr = "bsc1_clk";
|
||||
apbstr = "bsc1_apb_clk";
|
||||
break;
|
||||
case BSC2_BASE_ADDR:
|
||||
bscstr = "bsc2_clk";
|
||||
apbstr = "bsc2_apb_clk";
|
||||
break;
|
||||
case BSC3_BASE_ADDR:
|
||||
bscstr = "bsc3_clk";
|
||||
apbstr = "bsc3_apb_clk";
|
||||
break;
|
||||
default:
|
||||
printf("%s: base 0x%p not found\n", __func__, base);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Note that the bus clock must be enabled first */
|
||||
|
||||
ret = clk_get_and_enable(apbstr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_get_and_enable(bscstr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
513
u-boot/arch/arm/cpu/armv7/bcm281xx/clk-core.c
Normal file
513
u-boot/arch/arm/cpu/armv7/bcm281xx/clk-core.c
Normal file
@@ -0,0 +1,513 @@
|
||||
/*
|
||||
* Copyright 2013 Broadcom Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* bcm281xx architecture clock framework
|
||||
*
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/errno.h>
|
||||
#include <bitfield.h>
|
||||
#include <asm/arch/sysmap.h>
|
||||
#include <asm/kona-common/clk.h>
|
||||
#include "clk-core.h"
|
||||
|
||||
#define CLK_WR_ACCESS_PASSWORD 0x00a5a501
|
||||
#define WR_ACCESS_OFFSET 0 /* common to all clock blocks */
|
||||
#define POLICY_CTL_GO 1 /* Load and refresh policy masks */
|
||||
#define POLICY_CTL_GO_ATL 4 /* Active Load */
|
||||
|
||||
/* Helper function */
|
||||
int clk_get_and_enable(char *clkstr)
|
||||
{
|
||||
int ret = 0;
|
||||
struct clk *c;
|
||||
|
||||
debug("%s: %s\n", __func__, clkstr);
|
||||
|
||||
c = clk_get(clkstr);
|
||||
if (c) {
|
||||
ret = clk_enable(c);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
printf("%s: Couldn't find %s\n", __func__, clkstr);
|
||||
return -EINVAL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Poll a register in a CCU's address space, returning when the
|
||||
* specified bit in that register's value is set (or clear). Delay
|
||||
* a microsecond after each read of the register. Returns true if
|
||||
* successful, or false if we gave up trying.
|
||||
*
|
||||
* Caller must ensure the CCU lock is held.
|
||||
*/
|
||||
#define CLK_GATE_DELAY_USEC 2000
|
||||
static inline int wait_bit(void *base, u32 offset, u32 bit, bool want)
|
||||
{
|
||||
unsigned int tries;
|
||||
u32 bit_mask = 1 << bit;
|
||||
|
||||
for (tries = 0; tries < CLK_GATE_DELAY_USEC; tries++) {
|
||||
u32 val;
|
||||
bool bit_val;
|
||||
|
||||
val = readl(base + offset);
|
||||
bit_val = (val & bit_mask) ? 1 : 0;
|
||||
if (bit_val == want)
|
||||
return 0; /* success */
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
debug("%s: timeout on addr 0x%p, waiting for bit %d to go to %d\n",
|
||||
__func__, base + offset, bit, want);
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/* Enable a peripheral clock */
|
||||
static int peri_clk_enable(struct clk *c, int enable)
|
||||
{
|
||||
int ret = 0;
|
||||
u32 reg;
|
||||
struct peri_clock *peri_clk = to_peri_clk(c);
|
||||
struct peri_clk_data *cd = peri_clk->data;
|
||||
struct bcm_clk_gate *gate = &cd->gate;
|
||||
void *base = (void *)c->ccu_clk_mgr_base;
|
||||
|
||||
|
||||
debug("%s: %s\n", __func__, c->name);
|
||||
|
||||
clk_get_rate(c); /* Make sure rate and sel are filled in */
|
||||
|
||||
/* enable access */
|
||||
writel(CLK_WR_ACCESS_PASSWORD, base + WR_ACCESS_OFFSET);
|
||||
|
||||
if (enable) {
|
||||
debug("%s %s set rate %lu div %lu sel %d parent %lu\n",
|
||||
__func__, c->name, c->rate, c->div, c->sel,
|
||||
c->parent->rate);
|
||||
|
||||
/*
|
||||
* clkgate - only software controllable gates are
|
||||
* supported by u-boot which includes all clocks
|
||||
* that matter. This avoids bringing in a lot of extra
|
||||
* complexity as done in the kernel framework.
|
||||
*/
|
||||
if (gate_exists(gate)) {
|
||||
reg = readl(base + cd->gate.offset);
|
||||
reg |= (1 << cd->gate.en_bit);
|
||||
writel(reg, base + cd->gate.offset);
|
||||
}
|
||||
|
||||
/* div and pll select */
|
||||
if (divider_exists(&cd->div)) {
|
||||
reg = readl(base + cd->div.offset);
|
||||
bitfield_replace(reg, cd->div.shift, cd->div.width,
|
||||
c->div - 1);
|
||||
writel(reg, base + cd->div.offset);
|
||||
}
|
||||
|
||||
/* frequency selector */
|
||||
if (selector_exists(&cd->sel)) {
|
||||
reg = readl(base + cd->sel.offset);
|
||||
bitfield_replace(reg, cd->sel.shift, cd->sel.width,
|
||||
c->sel);
|
||||
writel(reg, base + cd->sel.offset);
|
||||
}
|
||||
|
||||
/* trigger */
|
||||
if (trigger_exists(&cd->trig)) {
|
||||
writel((1 << cd->trig.bit), base + cd->trig.offset);
|
||||
|
||||
/* wait for trigger status bit to go to 0 */
|
||||
ret = wait_bit(base, cd->trig.offset, cd->trig.bit, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* wait for running (status_bit = 1) */
|
||||
ret = wait_bit(base, cd->gate.offset, cd->gate.status_bit, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
debug("%s disable clock %s\n", __func__, c->name);
|
||||
|
||||
/* clkgate */
|
||||
reg = readl(base + cd->gate.offset);
|
||||
reg &= ~(1 << cd->gate.en_bit);
|
||||
writel(reg, base + cd->gate.offset);
|
||||
|
||||
/* wait for stop (status_bit = 0) */
|
||||
ret = wait_bit(base, cd->gate.offset, cd->gate.status_bit, 0);
|
||||
}
|
||||
|
||||
/* disable access */
|
||||
writel(0, base + WR_ACCESS_OFFSET);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Set the rate of a peripheral clock */
|
||||
static int peri_clk_set_rate(struct clk *c, unsigned long rate)
|
||||
{
|
||||
int ret = 0;
|
||||
int i;
|
||||
unsigned long diff;
|
||||
unsigned long new_rate = 0, div = 1;
|
||||
struct peri_clock *peri_clk = to_peri_clk(c);
|
||||
struct peri_clk_data *cd = peri_clk->data;
|
||||
const char **clock;
|
||||
|
||||
debug("%s: %s\n", __func__, c->name);
|
||||
diff = rate;
|
||||
|
||||
i = 0;
|
||||
for (clock = cd->clocks; *clock; clock++, i++) {
|
||||
struct refclk *ref = refclk_str_to_clk(*clock);
|
||||
if (!ref) {
|
||||
printf("%s: Lookup of %s failed\n", __func__, *clock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* round to the new rate */
|
||||
div = ref->clk.rate / rate;
|
||||
if (div == 0)
|
||||
div = 1;
|
||||
|
||||
new_rate = ref->clk.rate / div;
|
||||
|
||||
/* get the min diff */
|
||||
if (abs(new_rate - rate) < diff) {
|
||||
diff = abs(new_rate - rate);
|
||||
c->sel = i;
|
||||
c->parent = &ref->clk;
|
||||
c->rate = new_rate;
|
||||
c->div = div;
|
||||
}
|
||||
}
|
||||
|
||||
debug("%s %s set rate %lu div %lu sel %d parent %lu\n", __func__,
|
||||
c->name, c->rate, c->div, c->sel, c->parent->rate);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Get the rate of a peripheral clock */
|
||||
static unsigned long peri_clk_get_rate(struct clk *c)
|
||||
{
|
||||
struct peri_clock *peri_clk = to_peri_clk(c);
|
||||
struct peri_clk_data *cd = peri_clk->data;
|
||||
void *base = (void *)c->ccu_clk_mgr_base;
|
||||
int div = 1;
|
||||
const char **clock;
|
||||
struct refclk *ref;
|
||||
u32 reg;
|
||||
|
||||
debug("%s: %s\n", __func__, c->name);
|
||||
if (selector_exists(&cd->sel)) {
|
||||
reg = readl(base + cd->sel.offset);
|
||||
c->sel = bitfield_extract(reg, cd->sel.shift, cd->sel.width);
|
||||
} else {
|
||||
/*
|
||||
* For peri clocks that don't have a selector, the single
|
||||
* reference clock will always exist at index 0.
|
||||
*/
|
||||
c->sel = 0;
|
||||
}
|
||||
|
||||
if (divider_exists(&cd->div)) {
|
||||
reg = readl(base + cd->div.offset);
|
||||
div = bitfield_extract(reg, cd->div.shift, cd->div.width);
|
||||
div += 1;
|
||||
}
|
||||
|
||||
clock = cd->clocks;
|
||||
ref = refclk_str_to_clk(clock[c->sel]);
|
||||
if (!ref) {
|
||||
printf("%s: Can't lookup %s\n", __func__, clock[c->sel]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
c->parent = &ref->clk;
|
||||
c->div = div;
|
||||
c->rate = c->parent->rate / c->div;
|
||||
debug("%s parent rate %lu div %d sel %d rate %lu\n", __func__,
|
||||
c->parent->rate, div, c->sel, c->rate);
|
||||
|
||||
return c->rate;
|
||||
}
|
||||
|
||||
/* Peripheral clock operations */
|
||||
struct clk_ops peri_clk_ops = {
|
||||
.enable = peri_clk_enable,
|
||||
.set_rate = peri_clk_set_rate,
|
||||
.get_rate = peri_clk_get_rate,
|
||||
};
|
||||
|
||||
/* Enable a CCU clock */
|
||||
static int ccu_clk_enable(struct clk *c, int enable)
|
||||
{
|
||||
struct ccu_clock *ccu_clk = to_ccu_clk(c);
|
||||
void *base = (void *)c->ccu_clk_mgr_base;
|
||||
int ret = 0;
|
||||
u32 reg;
|
||||
|
||||
debug("%s: %s\n", __func__, c->name);
|
||||
if (!enable)
|
||||
return -EINVAL; /* CCU clock cannot shutdown */
|
||||
|
||||
/* enable access */
|
||||
writel(CLK_WR_ACCESS_PASSWORD, base + WR_ACCESS_OFFSET);
|
||||
|
||||
/* config enable for policy engine */
|
||||
writel(1, base + ccu_clk->lvm_en_offset);
|
||||
|
||||
/* wait for bit to go to 0 */
|
||||
ret = wait_bit(base, ccu_clk->lvm_en_offset, 0, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* freq ID */
|
||||
if (!ccu_clk->freq_bit_shift)
|
||||
ccu_clk->freq_bit_shift = 8;
|
||||
|
||||
/* Set frequency id for each of the 4 policies */
|
||||
reg = ccu_clk->freq_id |
|
||||
(ccu_clk->freq_id << (ccu_clk->freq_bit_shift)) |
|
||||
(ccu_clk->freq_id << (ccu_clk->freq_bit_shift * 2)) |
|
||||
(ccu_clk->freq_id << (ccu_clk->freq_bit_shift * 3));
|
||||
writel(reg, base + ccu_clk->policy_freq_offset);
|
||||
|
||||
/* enable all clock mask */
|
||||
writel(0x7fffffff, base + ccu_clk->policy0_mask_offset);
|
||||
writel(0x7fffffff, base + ccu_clk->policy1_mask_offset);
|
||||
writel(0x7fffffff, base + ccu_clk->policy2_mask_offset);
|
||||
writel(0x7fffffff, base + ccu_clk->policy3_mask_offset);
|
||||
|
||||
if (ccu_clk->num_policy_masks == 2) {
|
||||
writel(0x7fffffff, base + ccu_clk->policy0_mask2_offset);
|
||||
writel(0x7fffffff, base + ccu_clk->policy1_mask2_offset);
|
||||
writel(0x7fffffff, base + ccu_clk->policy2_mask2_offset);
|
||||
writel(0x7fffffff, base + ccu_clk->policy3_mask2_offset);
|
||||
}
|
||||
|
||||
/* start policy engine */
|
||||
reg = readl(base + ccu_clk->policy_ctl_offset);
|
||||
reg |= (POLICY_CTL_GO + POLICY_CTL_GO_ATL);
|
||||
writel(reg, base + ccu_clk->policy_ctl_offset);
|
||||
|
||||
/* wait till started */
|
||||
ret = wait_bit(base, ccu_clk->policy_ctl_offset, 0, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* disable access */
|
||||
writel(0, base + WR_ACCESS_OFFSET);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Get the CCU clock rate */
|
||||
static unsigned long ccu_clk_get_rate(struct clk *c)
|
||||
{
|
||||
struct ccu_clock *ccu_clk = to_ccu_clk(c);
|
||||
debug("%s: %s\n", __func__, c->name);
|
||||
c->rate = ccu_clk->freq_tbl[ccu_clk->freq_id];
|
||||
return c->rate;
|
||||
}
|
||||
|
||||
/* CCU clock operations */
|
||||
struct clk_ops ccu_clk_ops = {
|
||||
.enable = ccu_clk_enable,
|
||||
.get_rate = ccu_clk_get_rate,
|
||||
};
|
||||
|
||||
/* Enable a bus clock */
|
||||
static int bus_clk_enable(struct clk *c, int enable)
|
||||
{
|
||||
struct bus_clock *bus_clk = to_bus_clk(c);
|
||||
struct bus_clk_data *cd = bus_clk->data;
|
||||
void *base = (void *)c->ccu_clk_mgr_base;
|
||||
int ret = 0;
|
||||
u32 reg;
|
||||
|
||||
debug("%s: %s\n", __func__, c->name);
|
||||
/* enable access */
|
||||
writel(CLK_WR_ACCESS_PASSWORD, base + WR_ACCESS_OFFSET);
|
||||
|
||||
/* enable gating */
|
||||
reg = readl(base + cd->gate.offset);
|
||||
if (!!(reg & (1 << cd->gate.status_bit)) == !!enable)
|
||||
debug("%s already %s\n", c->name,
|
||||
enable ? "enabled" : "disabled");
|
||||
else {
|
||||
int want = (enable) ? 1 : 0;
|
||||
reg |= (1 << cd->gate.hw_sw_sel_bit);
|
||||
|
||||
if (enable)
|
||||
reg |= (1 << cd->gate.en_bit);
|
||||
else
|
||||
reg &= ~(1 << cd->gate.en_bit);
|
||||
|
||||
writel(reg, base + cd->gate.offset);
|
||||
ret = wait_bit(base, cd->gate.offset, cd->gate.status_bit,
|
||||
want);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* disable access */
|
||||
writel(0, base + WR_ACCESS_OFFSET);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Get the rate of a bus clock */
|
||||
static unsigned long bus_clk_get_rate(struct clk *c)
|
||||
{
|
||||
struct bus_clock *bus_clk = to_bus_clk(c);
|
||||
struct ccu_clock *ccu_clk;
|
||||
|
||||
debug("%s: %s\n", __func__, c->name);
|
||||
ccu_clk = to_ccu_clk(c->parent);
|
||||
|
||||
c->rate = bus_clk->freq_tbl[ccu_clk->freq_id];
|
||||
c->div = ccu_clk->freq_tbl[ccu_clk->freq_id] / c->rate;
|
||||
return c->rate;
|
||||
}
|
||||
|
||||
/* Bus clock operations */
|
||||
struct clk_ops bus_clk_ops = {
|
||||
.enable = bus_clk_enable,
|
||||
.get_rate = bus_clk_get_rate,
|
||||
};
|
||||
|
||||
/* Enable a reference clock */
|
||||
static int ref_clk_enable(struct clk *c, int enable)
|
||||
{
|
||||
debug("%s: %s\n", __func__, c->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Reference clock operations */
|
||||
struct clk_ops ref_clk_ops = {
|
||||
.enable = ref_clk_enable,
|
||||
};
|
||||
|
||||
/*
|
||||
* clk.h implementation follows
|
||||
*/
|
||||
|
||||
/* Initialize the clock framework */
|
||||
int clk_init(void)
|
||||
{
|
||||
debug("%s:\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get a clock handle, give a name string */
|
||||
struct clk *clk_get(const char *con_id)
|
||||
{
|
||||
int i;
|
||||
struct clk_lookup *clk_tblp;
|
||||
|
||||
debug("%s: %s\n", __func__, con_id);
|
||||
|
||||
clk_tblp = arch_clk_tbl;
|
||||
for (i = 0; i < arch_clk_tbl_array_size; i++, clk_tblp++) {
|
||||
if (clk_tblp->con_id) {
|
||||
if (!con_id || strcmp(clk_tblp->con_id, con_id))
|
||||
continue;
|
||||
return clk_tblp->clk;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Enable a clock */
|
||||
int clk_enable(struct clk *c)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
debug("%s: %s\n", __func__, c->name);
|
||||
if (!c->ops || !c->ops->enable)
|
||||
return -1;
|
||||
|
||||
/* enable parent clock first */
|
||||
if (c->parent)
|
||||
ret = clk_enable(c->parent);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!c->use_cnt) {
|
||||
c->use_cnt++;
|
||||
ret = c->ops->enable(c, 1);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Disable a clock */
|
||||
void clk_disable(struct clk *c)
|
||||
{
|
||||
debug("%s: %s\n", __func__, c->name);
|
||||
if (!c->ops || !c->ops->enable)
|
||||
return;
|
||||
|
||||
if (c->use_cnt) {
|
||||
c->use_cnt--;
|
||||
c->ops->enable(c, 0);
|
||||
}
|
||||
|
||||
/* disable parent */
|
||||
if (c->parent)
|
||||
clk_disable(c->parent);
|
||||
}
|
||||
|
||||
/* Get the clock rate */
|
||||
unsigned long clk_get_rate(struct clk *c)
|
||||
{
|
||||
unsigned long rate;
|
||||
|
||||
debug("%s: %s\n", __func__, c->name);
|
||||
if (!c || !c->ops || !c->ops->get_rate)
|
||||
return 0;
|
||||
|
||||
rate = c->ops->get_rate(c);
|
||||
debug("%s: rate = %ld\n", __func__, rate);
|
||||
return rate;
|
||||
}
|
||||
|
||||
/* Set the clock rate */
|
||||
int clk_set_rate(struct clk *c, unsigned long rate)
|
||||
{
|
||||
int ret;
|
||||
|
||||
debug("%s: %s rate=%ld\n", __func__, c->name, rate);
|
||||
if (!c || !c->ops || !c->ops->set_rate)
|
||||
return -EINVAL;
|
||||
|
||||
if (c->use_cnt)
|
||||
return -EINVAL;
|
||||
|
||||
ret = c->ops->set_rate(c, rate);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Not required for this arch */
|
||||
/*
|
||||
long clk_round_rate(struct clk *clk, unsigned long rate);
|
||||
int clk_set_parent(struct clk *clk, struct clk *parent);
|
||||
struct clk *clk_get_parent(struct clk *clk);
|
||||
*/
|
||||
491
u-boot/arch/arm/cpu/armv7/bcm281xx/clk-core.h
Normal file
491
u-boot/arch/arm/cpu/armv7/bcm281xx/clk-core.h
Normal file
@@ -0,0 +1,491 @@
|
||||
/*
|
||||
* Copyright 2013 Broadcom Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <linux/stddef.h>
|
||||
|
||||
#ifdef CONFIG_CLK_DEBUG
|
||||
#undef writel
|
||||
#undef readl
|
||||
static inline void writel(u32 val, void *addr)
|
||||
{
|
||||
printf("Write [0x%p] = 0x%08x\n", addr, val);
|
||||
*(u32 *)addr = val;
|
||||
}
|
||||
|
||||
static inline u32 readl(void *addr)
|
||||
{
|
||||
u32 val = *(u32 *)addr;
|
||||
printf("Read [0x%p] = 0x%08x\n", addr, val);
|
||||
return val;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct clk;
|
||||
|
||||
struct clk_lookup {
|
||||
const char *dev_id;
|
||||
const char *con_id;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
extern struct clk_lookup arch_clk_tbl[];
|
||||
extern unsigned int arch_clk_tbl_array_size;
|
||||
|
||||
/**
|
||||
* struct clk_ops - standard clock operations
|
||||
* @enable: enable/disable clock, see clk_enable() and clk_disable()
|
||||
* @set_rate: set the clock rate, see clk_set_rate().
|
||||
* @get_rate: get the clock rate, see clk_get_rate().
|
||||
* @round_rate: round a given clock rate, see clk_round_rate().
|
||||
* @set_parent: set the clock's parent, see clk_set_parent().
|
||||
*
|
||||
* Group the common clock implementations together so that we
|
||||
* don't have to keep setting the same fiels again. We leave
|
||||
* enable in struct clk.
|
||||
*
|
||||
*/
|
||||
struct clk_ops {
|
||||
int (*enable) (struct clk *c, int enable);
|
||||
int (*set_rate) (struct clk *c, unsigned long rate);
|
||||
unsigned long (*get_rate) (struct clk *c);
|
||||
unsigned long (*round_rate) (struct clk *c, unsigned long rate);
|
||||
int (*set_parent) (struct clk *c, struct clk *parent);
|
||||
};
|
||||
|
||||
struct clk {
|
||||
struct clk *parent;
|
||||
const char *name;
|
||||
int use_cnt;
|
||||
unsigned long rate; /* in HZ */
|
||||
|
||||
/* programmable divider. 0 means fixed ratio to parent clock */
|
||||
unsigned long div;
|
||||
|
||||
struct clk_src *src;
|
||||
struct clk_ops *ops;
|
||||
|
||||
unsigned long ccu_clk_mgr_base;
|
||||
int sel;
|
||||
};
|
||||
|
||||
struct refclk *refclk_str_to_clk(const char *name);
|
||||
|
||||
/* The common clock framework uses u8 to represent a parent index */
|
||||
#define PARENT_COUNT_MAX ((u32)U8_MAX)
|
||||
|
||||
#define BAD_CLK_INDEX U8_MAX /* Can't ever be valid */
|
||||
#define BAD_CLK_NAME ((const char *)-1)
|
||||
|
||||
#define BAD_SCALED_DIV_VALUE U64_MAX
|
||||
|
||||
/*
|
||||
* Utility macros for object flag management. If possible, flags
|
||||
* should be defined such that 0 is the desired default value.
|
||||
*/
|
||||
#define FLAG(type, flag) BCM_CLK_ ## type ## _FLAGS_ ## flag
|
||||
#define FLAG_SET(obj, type, flag) ((obj)->flags |= FLAG(type, flag))
|
||||
#define FLAG_CLEAR(obj, type, flag) ((obj)->flags &= ~(FLAG(type, flag)))
|
||||
#define FLAG_FLIP(obj, type, flag) ((obj)->flags ^= FLAG(type, flag))
|
||||
#define FLAG_TEST(obj, type, flag) (!!((obj)->flags & FLAG(type, flag)))
|
||||
|
||||
/* Clock field state tests */
|
||||
|
||||
#define gate_exists(gate) FLAG_TEST(gate, GATE, EXISTS)
|
||||
#define gate_is_enabled(gate) FLAG_TEST(gate, GATE, ENABLED)
|
||||
#define gate_is_hw_controllable(gate) FLAG_TEST(gate, GATE, HW)
|
||||
#define gate_is_sw_controllable(gate) FLAG_TEST(gate, GATE, SW)
|
||||
#define gate_is_sw_managed(gate) FLAG_TEST(gate, GATE, SW_MANAGED)
|
||||
#define gate_is_no_disable(gate) FLAG_TEST(gate, GATE, NO_DISABLE)
|
||||
|
||||
#define gate_flip_enabled(gate) FLAG_FLIP(gate, GATE, ENABLED)
|
||||
|
||||
#define divider_exists(div) FLAG_TEST(div, DIV, EXISTS)
|
||||
#define divider_is_fixed(div) FLAG_TEST(div, DIV, FIXED)
|
||||
#define divider_has_fraction(div) (!divider_is_fixed(div) && \
|
||||
(div)->frac_width > 0)
|
||||
|
||||
#define selector_exists(sel) ((sel)->width != 0)
|
||||
#define trigger_exists(trig) FLAG_TEST(trig, TRIG, EXISTS)
|
||||
|
||||
/* Clock type, used to tell common block what it's part of */
|
||||
enum bcm_clk_type {
|
||||
bcm_clk_none, /* undefined clock type */
|
||||
bcm_clk_bus,
|
||||
bcm_clk_core,
|
||||
bcm_clk_peri
|
||||
};
|
||||
|
||||
/*
|
||||
* Gating control and status is managed by a 32-bit gate register.
|
||||
*
|
||||
* There are several types of gating available:
|
||||
* - (no gate)
|
||||
* A clock with no gate is assumed to be always enabled.
|
||||
* - hardware-only gating (auto-gating)
|
||||
* Enabling or disabling clocks with this type of gate is
|
||||
* managed automatically by the hardware. Such clocks can be
|
||||
* considered by the software to be enabled. The current status
|
||||
* of auto-gated clocks can be read from the gate status bit.
|
||||
* - software-only gating
|
||||
* Auto-gating is not available for this type of clock.
|
||||
* Instead, software manages whether it's enabled by setting or
|
||||
* clearing the enable bit. The current gate status of a gate
|
||||
* under software control can be read from the gate status bit.
|
||||
* To ensure a change to the gating status is complete, the
|
||||
* status bit can be polled to verify that the gate has entered
|
||||
* the desired state.
|
||||
* - selectable hardware or software gating
|
||||
* Gating for this type of clock can be configured to be either
|
||||
* under software or hardware control. Which type is in use is
|
||||
* determined by the hw_sw_sel bit of the gate register.
|
||||
*/
|
||||
struct bcm_clk_gate {
|
||||
u32 offset; /* gate register offset */
|
||||
u32 status_bit; /* 0: gate is disabled; 0: gatge is enabled */
|
||||
u32 en_bit; /* 0: disable; 1: enable */
|
||||
u32 hw_sw_sel_bit; /* 0: hardware gating; 1: software gating */
|
||||
u32 flags; /* BCM_CLK_GATE_FLAGS_* below */
|
||||
};
|
||||
|
||||
/*
|
||||
* Gate flags:
|
||||
* HW means this gate can be auto-gated
|
||||
* SW means the state of this gate can be software controlled
|
||||
* NO_DISABLE means this gate is (only) enabled if under software control
|
||||
* SW_MANAGED means the status of this gate is under software control
|
||||
* ENABLED means this software-managed gate is *supposed* to be enabled
|
||||
*/
|
||||
#define BCM_CLK_GATE_FLAGS_EXISTS ((u32)1 << 0) /* Gate is valid */
|
||||
#define BCM_CLK_GATE_FLAGS_HW ((u32)1 << 1) /* Can auto-gate */
|
||||
#define BCM_CLK_GATE_FLAGS_SW ((u32)1 << 2) /* Software control */
|
||||
#define BCM_CLK_GATE_FLAGS_NO_DISABLE ((u32)1 << 3) /* HW or enabled */
|
||||
#define BCM_CLK_GATE_FLAGS_SW_MANAGED ((u32)1 << 4) /* SW now in control */
|
||||
#define BCM_CLK_GATE_FLAGS_ENABLED ((u32)1 << 5) /* If SW_MANAGED */
|
||||
|
||||
/*
|
||||
* Gate initialization macros.
|
||||
*
|
||||
* Any gate initially under software control will be enabled.
|
||||
*/
|
||||
|
||||
/* A hardware/software gate initially under software control */
|
||||
#define HW_SW_GATE(_offset, _status_bit, _en_bit, _hw_sw_sel_bit) \
|
||||
{ \
|
||||
.offset = (_offset), \
|
||||
.status_bit = (_status_bit), \
|
||||
.en_bit = (_en_bit), \
|
||||
.hw_sw_sel_bit = (_hw_sw_sel_bit), \
|
||||
.flags = FLAG(GATE, HW)|FLAG(GATE, SW)| \
|
||||
FLAG(GATE, SW_MANAGED)|FLAG(GATE, ENABLED)| \
|
||||
FLAG(GATE, EXISTS), \
|
||||
}
|
||||
|
||||
/* A hardware/software gate initially under hardware control */
|
||||
#define HW_SW_GATE_AUTO(_offset, _status_bit, _en_bit, _hw_sw_sel_bit) \
|
||||
{ \
|
||||
.offset = (_offset), \
|
||||
.status_bit = (_status_bit), \
|
||||
.en_bit = (_en_bit), \
|
||||
.hw_sw_sel_bit = (_hw_sw_sel_bit), \
|
||||
.flags = FLAG(GATE, HW)|FLAG(GATE, SW)| \
|
||||
FLAG(GATE, EXISTS), \
|
||||
}
|
||||
|
||||
/* A hardware-or-enabled gate (enabled if not under hardware control) */
|
||||
#define HW_ENABLE_GATE(_offset, _status_bit, _en_bit, _hw_sw_sel_bit) \
|
||||
{ \
|
||||
.offset = (_offset), \
|
||||
.status_bit = (_status_bit), \
|
||||
.en_bit = (_en_bit), \
|
||||
.hw_sw_sel_bit = (_hw_sw_sel_bit), \
|
||||
.flags = FLAG(GATE, HW)|FLAG(GATE, SW)| \
|
||||
FLAG(GATE, NO_DISABLE)|FLAG(GATE, EXISTS), \
|
||||
}
|
||||
|
||||
/* A software-only gate */
|
||||
#define SW_ONLY_GATE(_offset, _status_bit, _en_bit) \
|
||||
{ \
|
||||
.offset = (_offset), \
|
||||
.status_bit = (_status_bit), \
|
||||
.en_bit = (_en_bit), \
|
||||
.flags = FLAG(GATE, SW)|FLAG(GATE, SW_MANAGED)| \
|
||||
FLAG(GATE, ENABLED)|FLAG(GATE, EXISTS), \
|
||||
}
|
||||
|
||||
/* A hardware-only gate */
|
||||
#define HW_ONLY_GATE(_offset, _status_bit) \
|
||||
{ \
|
||||
.offset = (_offset), \
|
||||
.status_bit = (_status_bit), \
|
||||
.flags = FLAG(GATE, HW)|FLAG(GATE, EXISTS), \
|
||||
}
|
||||
|
||||
/*
|
||||
* Each clock can have zero, one, or two dividers which change the
|
||||
* output rate of the clock. Each divider can be either fixed or
|
||||
* variable. If there are two dividers, they are the "pre-divider"
|
||||
* and the "regular" or "downstream" divider. If there is only one,
|
||||
* there is no pre-divider.
|
||||
*
|
||||
* A fixed divider is any non-zero (positive) value, and it
|
||||
* indicates how the input rate is affected by the divider.
|
||||
*
|
||||
* The value of a variable divider is maintained in a sub-field of a
|
||||
* 32-bit divider register. The position of the field in the
|
||||
* register is defined by its offset and width. The value recorded
|
||||
* in this field is always 1 less than the value it represents.
|
||||
*
|
||||
* In addition, a variable divider can indicate that some subset
|
||||
* of its bits represent a "fractional" part of the divider. Such
|
||||
* bits comprise the low-order portion of the divider field, and can
|
||||
* be viewed as representing the portion of the divider that lies to
|
||||
* the right of the decimal point. Most variable dividers have zero
|
||||
* fractional bits. Variable dividers with non-zero fraction width
|
||||
* still record a value 1 less than the value they represent; the
|
||||
* added 1 does *not* affect the low-order bit in this case, it
|
||||
* affects the bits above the fractional part only. (Often in this
|
||||
* code a divider field value is distinguished from the value it
|
||||
* represents by referring to the latter as a "divisor".)
|
||||
*
|
||||
* In order to avoid dealing with fractions, divider arithmetic is
|
||||
* performed using "scaled" values. A scaled value is one that's
|
||||
* been left-shifted by the fractional width of a divider. Dividing
|
||||
* a scaled value by a scaled divisor produces the desired quotient
|
||||
* without loss of precision and without any other special handling
|
||||
* for fractions.
|
||||
*
|
||||
* The recorded value of a variable divider can be modified. To
|
||||
* modify either divider (or both), a clock must be enabled (i.e.,
|
||||
* using its gate). In addition, a trigger register (described
|
||||
* below) must be used to commit the change, and polled to verify
|
||||
* the change is complete.
|
||||
*/
|
||||
struct bcm_clk_div {
|
||||
union {
|
||||
struct { /* variable divider */
|
||||
u32 offset; /* divider register offset */
|
||||
u32 shift; /* field shift */
|
||||
u32 width; /* field width */
|
||||
u32 frac_width; /* field fraction width */
|
||||
|
||||
u64 scaled_div; /* scaled divider value */
|
||||
};
|
||||
u32 fixed; /* non-zero fixed divider value */
|
||||
};
|
||||
u32 flags; /* BCM_CLK_DIV_FLAGS_* below */
|
||||
};
|
||||
|
||||
/*
|
||||
* Divider flags:
|
||||
* EXISTS means this divider exists
|
||||
* FIXED means it is a fixed-rate divider
|
||||
*/
|
||||
#define BCM_CLK_DIV_FLAGS_EXISTS ((u32)1 << 0) /* Divider is valid */
|
||||
#define BCM_CLK_DIV_FLAGS_FIXED ((u32)1 << 1) /* Fixed-value */
|
||||
|
||||
/* Divider initialization macros */
|
||||
|
||||
/* A fixed (non-zero) divider */
|
||||
#define FIXED_DIVIDER(_value) \
|
||||
{ \
|
||||
.fixed = (_value), \
|
||||
.flags = FLAG(DIV, EXISTS)|FLAG(DIV, FIXED), \
|
||||
}
|
||||
|
||||
/* A divider with an integral divisor */
|
||||
#define DIVIDER(_offset, _shift, _width) \
|
||||
{ \
|
||||
.offset = (_offset), \
|
||||
.shift = (_shift), \
|
||||
.width = (_width), \
|
||||
.scaled_div = BAD_SCALED_DIV_VALUE, \
|
||||
.flags = FLAG(DIV, EXISTS), \
|
||||
}
|
||||
|
||||
/* A divider whose divisor has an integer and fractional part */
|
||||
#define FRAC_DIVIDER(_offset, _shift, _width, _frac_width) \
|
||||
{ \
|
||||
.offset = (_offset), \
|
||||
.shift = (_shift), \
|
||||
.width = (_width), \
|
||||
.frac_width = (_frac_width), \
|
||||
.scaled_div = BAD_SCALED_DIV_VALUE, \
|
||||
.flags = FLAG(DIV, EXISTS), \
|
||||
}
|
||||
|
||||
/*
|
||||
* Clocks may have multiple "parent" clocks. If there is more than
|
||||
* one, a selector must be specified to define which of the parent
|
||||
* clocks is currently in use. The selected clock is indicated in a
|
||||
* sub-field of a 32-bit selector register. The range of
|
||||
* representable selector values typically exceeds the number of
|
||||
* available parent clocks. Occasionally the reset value of a
|
||||
* selector field is explicitly set to a (specific) value that does
|
||||
* not correspond to a defined input clock.
|
||||
*
|
||||
* We register all known parent clocks with the common clock code
|
||||
* using a packed array (i.e., no empty slots) of (parent) clock
|
||||
* names, and refer to them later using indexes into that array.
|
||||
* We maintain an array of selector values indexed by common clock
|
||||
* index values in order to map between these common clock indexes
|
||||
* and the selector values used by the hardware.
|
||||
*
|
||||
* Like dividers, a selector can be modified, but to do so a clock
|
||||
* must be enabled, and a trigger must be used to commit the change.
|
||||
*/
|
||||
struct bcm_clk_sel {
|
||||
u32 offset; /* selector register offset */
|
||||
u32 shift; /* field shift */
|
||||
u32 width; /* field width */
|
||||
|
||||
u32 parent_count; /* number of entries in parent_sel[] */
|
||||
u32 *parent_sel; /* array of parent selector values */
|
||||
u8 clk_index; /* current selected index in parent_sel[] */
|
||||
};
|
||||
|
||||
/* Selector initialization macro */
|
||||
#define SELECTOR(_offset, _shift, _width) \
|
||||
{ \
|
||||
.offset = (_offset), \
|
||||
.shift = (_shift), \
|
||||
.width = (_width), \
|
||||
.clk_index = BAD_CLK_INDEX, \
|
||||
}
|
||||
|
||||
/*
|
||||
* Making changes to a variable divider or a selector for a clock
|
||||
* requires the use of a trigger. A trigger is defined by a single
|
||||
* bit within a register. To signal a change, a 1 is written into
|
||||
* that bit. To determine when the change has been completed, that
|
||||
* trigger bit is polled; the read value will be 1 while the change
|
||||
* is in progress, and 0 when it is complete.
|
||||
*
|
||||
* Occasionally a clock will have more than one trigger. In this
|
||||
* case, the "pre-trigger" will be used when changing a clock's
|
||||
* selector and/or its pre-divider.
|
||||
*/
|
||||
struct bcm_clk_trig {
|
||||
u32 offset; /* trigger register offset */
|
||||
u32 bit; /* trigger bit */
|
||||
u32 flags; /* BCM_CLK_TRIG_FLAGS_* below */
|
||||
};
|
||||
|
||||
/*
|
||||
* Trigger flags:
|
||||
* EXISTS means this trigger exists
|
||||
*/
|
||||
#define BCM_CLK_TRIG_FLAGS_EXISTS ((u32)1 << 0) /* Trigger is valid */
|
||||
|
||||
/* Trigger initialization macro */
|
||||
#define TRIGGER(_offset, _bit) \
|
||||
{ \
|
||||
.offset = (_offset), \
|
||||
.bit = (_bit), \
|
||||
.flags = FLAG(TRIG, EXISTS), \
|
||||
}
|
||||
|
||||
struct bus_clk_data {
|
||||
struct bcm_clk_gate gate;
|
||||
};
|
||||
|
||||
struct core_clk_data {
|
||||
struct bcm_clk_gate gate;
|
||||
};
|
||||
|
||||
struct peri_clk_data {
|
||||
struct bcm_clk_gate gate;
|
||||
struct bcm_clk_trig pre_trig;
|
||||
struct bcm_clk_div pre_div;
|
||||
struct bcm_clk_trig trig;
|
||||
struct bcm_clk_div div;
|
||||
struct bcm_clk_sel sel;
|
||||
const char *clocks[]; /* must be last; use CLOCKS() to declare */
|
||||
};
|
||||
#define CLOCKS(...) { __VA_ARGS__, NULL, }
|
||||
#define NO_CLOCKS { NULL, } /* Must use of no parent clocks */
|
||||
|
||||
struct refclk {
|
||||
struct clk clk;
|
||||
};
|
||||
|
||||
struct peri_clock {
|
||||
struct clk clk;
|
||||
struct peri_clk_data *data;
|
||||
};
|
||||
|
||||
struct ccu_clock {
|
||||
struct clk clk;
|
||||
|
||||
int num_policy_masks;
|
||||
unsigned long policy_freq_offset;
|
||||
int freq_bit_shift; /* 8 for most CCUs */
|
||||
unsigned long policy_ctl_offset;
|
||||
unsigned long policy0_mask_offset;
|
||||
unsigned long policy1_mask_offset;
|
||||
unsigned long policy2_mask_offset;
|
||||
unsigned long policy3_mask_offset;
|
||||
unsigned long policy0_mask2_offset;
|
||||
unsigned long policy1_mask2_offset;
|
||||
unsigned long policy2_mask2_offset;
|
||||
unsigned long policy3_mask2_offset;
|
||||
unsigned long lvm_en_offset;
|
||||
|
||||
int freq_id;
|
||||
unsigned long *freq_tbl;
|
||||
};
|
||||
|
||||
struct bus_clock {
|
||||
struct clk clk;
|
||||
struct bus_clk_data *data;
|
||||
unsigned long *freq_tbl;
|
||||
};
|
||||
|
||||
struct ref_clock {
|
||||
struct clk clk;
|
||||
};
|
||||
|
||||
static inline int is_same_clock(struct clk *a, struct clk *b)
|
||||
{
|
||||
return (a == b);
|
||||
}
|
||||
|
||||
#define to_clk(p) (&((p)->clk))
|
||||
#define name_to_clk(name) (&((name##_clk).clk))
|
||||
/* declare a struct clk_lookup */
|
||||
#define CLK_LK(name) \
|
||||
{.con_id = __stringify(name##_clk), .clk = name_to_clk(name),}
|
||||
|
||||
static inline struct refclk *to_refclk(struct clk *clock)
|
||||
{
|
||||
return container_of(clock, struct refclk, clk);
|
||||
}
|
||||
|
||||
static inline struct peri_clock *to_peri_clk(struct clk *clock)
|
||||
{
|
||||
return container_of(clock, struct peri_clock, clk);
|
||||
}
|
||||
|
||||
static inline struct ccu_clock *to_ccu_clk(struct clk *clock)
|
||||
{
|
||||
return container_of(clock, struct ccu_clock, clk);
|
||||
}
|
||||
|
||||
static inline struct bus_clock *to_bus_clk(struct clk *clock)
|
||||
{
|
||||
return container_of(clock, struct bus_clock, clk);
|
||||
}
|
||||
|
||||
static inline struct ref_clock *to_ref_clk(struct clk *clock)
|
||||
{
|
||||
return container_of(clock, struct ref_clock, clk);
|
||||
}
|
||||
|
||||
extern struct clk_ops peri_clk_ops;
|
||||
extern struct clk_ops ccu_clk_ops;
|
||||
extern struct clk_ops bus_clk_ops;
|
||||
extern struct clk_ops ref_clk_ops;
|
||||
|
||||
extern int clk_get_and_enable(char *clkstr);
|
||||
143
u-boot/arch/arm/cpu/armv7/bcm281xx/clk-eth.c
Normal file
143
u-boot/arch/arm/cpu/armv7/bcm281xx/clk-eth.c
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 2014 Broadcom Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/arch/sysmap.h>
|
||||
#include <asm/kona-common/clk.h>
|
||||
#include "clk-core.h"
|
||||
|
||||
#define WR_ACCESS_ADDR ESUB_CLK_BASE_ADDR
|
||||
#define WR_ACCESS_PASSWORD 0xA5A500
|
||||
|
||||
#define PLLE_POST_RESETB_ADDR (ESUB_CLK_BASE_ADDR + 0x00000C00)
|
||||
|
||||
#define PLLE_RESETB_ADDR (ESUB_CLK_BASE_ADDR + 0x00000C58)
|
||||
#define PLLE_RESETB_I_PLL_RESETB_PLLE_MASK 0x00010000
|
||||
#define PLLE_POST_RESETB_I_POST_RESETB_PLLE_MASK 0x00000001
|
||||
|
||||
#define PLL_LOCK_ADDR (ESUB_CLK_BASE_ADDR + 0x00000C38)
|
||||
#define PLL_LOCK_PLL_LOCK_PLLE_MASK 0x00000001
|
||||
|
||||
#define ESW_SYS_DIV_ADDR (ESUB_CLK_BASE_ADDR + 0x00000A04)
|
||||
#define ESW_SYS_DIV_PLL_SELECT_MASK 0x00000300
|
||||
#define ESW_SYS_DIV_DIV_MASK 0x0000001C
|
||||
#define ESW_SYS_DIV_PLL_VAR_208M_CLK_SELECT 0x00000100
|
||||
#define ESW_SYS_DIV_DIV_SELECT 0x4
|
||||
#define ESW_SYS_DIV_TRIGGER_MASK 0x00000001
|
||||
|
||||
#define ESUB_AXI_DIV_DEBUG_ADDR (ESUB_CLK_BASE_ADDR + 0x00000E04)
|
||||
#define ESUB_AXI_DIV_DEBUG_PLL_SELECT_MASK 0x0000001C
|
||||
#define ESUB_AXI_DIV_DEBUG_PLL_SELECT_OVERRIDE_MASK 0x00000040
|
||||
#define ESUB_AXI_DIV_DEBUG_PLL_VAR_208M_CLK_SELECT 0x0
|
||||
#define ESUB_AXI_DIV_DEBUG_TRIGGER_MASK 0x00000001
|
||||
|
||||
#define PLL_MAX_RETRY 100
|
||||
|
||||
/* Enable appropriate clocks for Ethernet */
|
||||
int clk_eth_enable(void)
|
||||
{
|
||||
int rc = -1;
|
||||
int retry_count = 0;
|
||||
rc = clk_get_and_enable("esub_ccu_clk");
|
||||
|
||||
/* Enable Access to CCU registers */
|
||||
writel((1 | WR_ACCESS_PASSWORD), WR_ACCESS_ADDR);
|
||||
|
||||
writel(readl(PLLE_POST_RESETB_ADDR) &
|
||||
~PLLE_POST_RESETB_I_POST_RESETB_PLLE_MASK,
|
||||
PLLE_POST_RESETB_ADDR);
|
||||
|
||||
/* Take PLL out of reset and put into normal mode */
|
||||
writel(readl(PLLE_RESETB_ADDR) | PLLE_RESETB_I_PLL_RESETB_PLLE_MASK,
|
||||
PLLE_RESETB_ADDR);
|
||||
|
||||
/* Wait for PLL lock */
|
||||
rc = -1;
|
||||
while (retry_count < PLL_MAX_RETRY) {
|
||||
udelay(100);
|
||||
if (readl(PLL_LOCK_ADDR) & PLL_LOCK_PLL_LOCK_PLLE_MASK) {
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
retry_count++;
|
||||
}
|
||||
|
||||
if (rc == -1) {
|
||||
printf("%s: ETH-PLL lock timeout, Ethernet is not enabled!\n",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
writel(readl(PLLE_POST_RESETB_ADDR) |
|
||||
PLLE_POST_RESETB_I_POST_RESETB_PLLE_MASK,
|
||||
PLLE_POST_RESETB_ADDR);
|
||||
|
||||
/* Switch esw_sys_clk to use 104MHz(208MHz/2) clock */
|
||||
writel((readl(ESW_SYS_DIV_ADDR) &
|
||||
~(ESW_SYS_DIV_PLL_SELECT_MASK | ESW_SYS_DIV_DIV_MASK)) |
|
||||
ESW_SYS_DIV_PLL_VAR_208M_CLK_SELECT | ESW_SYS_DIV_DIV_SELECT,
|
||||
ESW_SYS_DIV_ADDR);
|
||||
|
||||
writel(readl(ESW_SYS_DIV_ADDR) | ESW_SYS_DIV_TRIGGER_MASK,
|
||||
ESW_SYS_DIV_ADDR);
|
||||
|
||||
/* Wait for trigger complete */
|
||||
rc = -1;
|
||||
retry_count = 0;
|
||||
while (retry_count < PLL_MAX_RETRY) {
|
||||
udelay(100);
|
||||
if (!(readl(ESW_SYS_DIV_ADDR) & ESW_SYS_DIV_TRIGGER_MASK)) {
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
retry_count++;
|
||||
}
|
||||
|
||||
if (rc == -1) {
|
||||
printf("%s: SYS CLK Trigger timeout, Ethernet is not enabled!\n",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* switch Esub AXI clock to 208MHz */
|
||||
writel((readl(ESUB_AXI_DIV_DEBUG_ADDR) &
|
||||
~(ESUB_AXI_DIV_DEBUG_PLL_SELECT_MASK |
|
||||
ESUB_AXI_DIV_DEBUG_PLL_SELECT_OVERRIDE_MASK |
|
||||
ESUB_AXI_DIV_DEBUG_TRIGGER_MASK)) |
|
||||
ESUB_AXI_DIV_DEBUG_PLL_VAR_208M_CLK_SELECT |
|
||||
ESUB_AXI_DIV_DEBUG_PLL_SELECT_OVERRIDE_MASK,
|
||||
ESUB_AXI_DIV_DEBUG_ADDR);
|
||||
|
||||
writel(readl(ESUB_AXI_DIV_DEBUG_ADDR) |
|
||||
ESUB_AXI_DIV_DEBUG_TRIGGER_MASK,
|
||||
ESUB_AXI_DIV_DEBUG_ADDR);
|
||||
|
||||
/* Wait for trigger complete */
|
||||
rc = -1;
|
||||
retry_count = 0;
|
||||
while (retry_count < PLL_MAX_RETRY) {
|
||||
udelay(100);
|
||||
if (!(readl(ESUB_AXI_DIV_DEBUG_ADDR) &
|
||||
ESUB_AXI_DIV_DEBUG_TRIGGER_MASK)) {
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
retry_count++;
|
||||
}
|
||||
|
||||
if (rc == -1) {
|
||||
printf("%s: AXI CLK Trigger timeout, Ethernet is not enabled!\n",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Disable Access to CCU registers */
|
||||
writel(WR_ACCESS_PASSWORD, WR_ACCESS_ADDR);
|
||||
|
||||
return rc;
|
||||
}
|
||||
73
u-boot/arch/arm/cpu/armv7/bcm281xx/clk-sdio.c
Normal file
73
u-boot/arch/arm/cpu/armv7/bcm281xx/clk-sdio.c
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2013 Broadcom Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/arch/sysmap.h>
|
||||
#include <asm/kona-common/clk.h>
|
||||
#include "clk-core.h"
|
||||
|
||||
/* Enable appropriate clocks for an SDIO port */
|
||||
int clk_sdio_enable(void *base, u32 rate, u32 *actual_ratep)
|
||||
{
|
||||
int ret;
|
||||
struct clk *c;
|
||||
|
||||
char *clkstr;
|
||||
char *slpstr;
|
||||
char *ahbstr;
|
||||
|
||||
switch ((u32) base) {
|
||||
case CONFIG_SYS_SDIO_BASE0:
|
||||
clkstr = CONFIG_SYS_SDIO0 "_clk";
|
||||
ahbstr = CONFIG_SYS_SDIO0 "_ahb_clk";
|
||||
slpstr = CONFIG_SYS_SDIO0 "_sleep_clk";
|
||||
break;
|
||||
case CONFIG_SYS_SDIO_BASE1:
|
||||
clkstr = CONFIG_SYS_SDIO1 "_clk";
|
||||
ahbstr = CONFIG_SYS_SDIO1 "_ahb_clk";
|
||||
slpstr = CONFIG_SYS_SDIO1 "_sleep_clk";
|
||||
break;
|
||||
case CONFIG_SYS_SDIO_BASE2:
|
||||
clkstr = CONFIG_SYS_SDIO2 "_clk";
|
||||
ahbstr = CONFIG_SYS_SDIO2 "_ahb_clk";
|
||||
slpstr = CONFIG_SYS_SDIO2 "_sleep_clk";
|
||||
break;
|
||||
case CONFIG_SYS_SDIO_BASE3:
|
||||
clkstr = CONFIG_SYS_SDIO3 "_clk";
|
||||
ahbstr = CONFIG_SYS_SDIO3 "_ahb_clk";
|
||||
slpstr = CONFIG_SYS_SDIO3 "_sleep_clk";
|
||||
break;
|
||||
default:
|
||||
printf("%s: base 0x%p not found\n", __func__, base);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = clk_get_and_enable(ahbstr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_get_and_enable(slpstr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
c = clk_get(clkstr);
|
||||
if (c) {
|
||||
ret = clk_set_rate(c, rate);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_enable(c);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
printf("%s: Couldn't find %s\n", __func__, clkstr);
|
||||
return -EINVAL;
|
||||
}
|
||||
*actual_ratep = rate;
|
||||
return 0;
|
||||
}
|
||||
27
u-boot/arch/arm/cpu/armv7/bcm281xx/clk-usb-otg.c
Normal file
27
u-boot/arch/arm/cpu/armv7/bcm281xx/clk-usb-otg.c
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2014 Broadcom Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/arch/sysmap.h>
|
||||
#include "clk-core.h"
|
||||
|
||||
/* Enable appropriate clocks for the USB OTG port */
|
||||
int clk_usb_otg_enable(void *base)
|
||||
{
|
||||
char *ahbstr;
|
||||
|
||||
switch ((u32) base) {
|
||||
case HSOTG_BASE_ADDR:
|
||||
ahbstr = "usb_otg_ahb_clk";
|
||||
break;
|
||||
default:
|
||||
printf("%s: base 0x%p not found\n", __func__, base);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return clk_get_and_enable(ahbstr);
|
||||
}
|
||||
27
u-boot/arch/arm/cpu/armv7/bcm281xx/reset.c
Normal file
27
u-boot/arch/arm/cpu/armv7/bcm281xx/reset.c
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2013 Broadcom Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/sysmap.h>
|
||||
|
||||
#define EN_MASK 0x08000000 /* Enable timer */
|
||||
#define SRSTEN_MASK 0x04000000 /* Enable soft reset */
|
||||
#define CLKS_SHIFT 20 /* Clock period shift */
|
||||
#define LD_SHIFT 0 /* Reload value shift */
|
||||
|
||||
void reset_cpu(ulong ignored)
|
||||
{
|
||||
/*
|
||||
* Set WD enable, RST enable,
|
||||
* 3.9 msec clock period (8), reload value (8*3.9ms)
|
||||
*/
|
||||
u32 reg = EN_MASK + SRSTEN_MASK + (8 << CLKS_SHIFT) + (8 << LD_SHIFT);
|
||||
writel(reg, SECWD2_BASE_ADDR);
|
||||
|
||||
while (1)
|
||||
; /* loop forever till reset */
|
||||
}
|
||||
7
u-boot/arch/arm/cpu/armv7/bcmcygnus/Makefile
Normal file
7
u-boot/arch/arm/cpu/armv7/bcmcygnus/Makefile
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
# Copyright 2014 Broadcom Corporation.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y += reset.o
|
||||
20
u-boot/arch/arm/cpu/armv7/bcmcygnus/reset.c
Normal file
20
u-boot/arch/arm/cpu/armv7/bcmcygnus/reset.c
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2014 Broadcom Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#define CRMU_MAIL_BOX1 0x03024028
|
||||
#define CRMU_SOFT_RESET_CMD 0xFFFFFFFF
|
||||
|
||||
void reset_cpu(ulong ignored)
|
||||
{
|
||||
/* Send soft reset command via Mailbox. */
|
||||
writel(CRMU_SOFT_RESET_CMD, CRMU_MAIL_BOX1);
|
||||
|
||||
while (1)
|
||||
; /* loop forever till reset */
|
||||
}
|
||||
7
u-boot/arch/arm/cpu/armv7/bcmnsp/Makefile
Normal file
7
u-boot/arch/arm/cpu/armv7/bcmnsp/Makefile
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
# Copyright 2014 Broadcom Corporation.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y += reset.o
|
||||
19
u-boot/arch/arm/cpu/armv7/bcmnsp/reset.c
Normal file
19
u-boot/arch/arm/cpu/armv7/bcmnsp/reset.c
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2014 Broadcom Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#define CRU_RESET_OFFSET 0x1803F184
|
||||
|
||||
void reset_cpu(ulong ignored)
|
||||
{
|
||||
/* Reset the cpu by setting software reset request bit */
|
||||
writel(0x1, CRU_RESET_OFFSET);
|
||||
|
||||
while (1)
|
||||
; /* loop forever till reset */
|
||||
}
|
||||
242
u-boot/arch/arm/cpu/armv7/cache_v7.c
Normal file
242
u-boot/arch/arm/cpu/armv7/cache_v7.c
Normal file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* (C) Copyright 2010
|
||||
* Texas Instruments, <www.ti.com>
|
||||
* Aneesh V <aneesh@ti.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#include <linux/types.h>
|
||||
#include <common.h>
|
||||
#include <asm/armv7.h>
|
||||
#include <asm/utils.h>
|
||||
|
||||
#define ARMV7_DCACHE_INVAL_RANGE 1
|
||||
#define ARMV7_DCACHE_CLEAN_INVAL_RANGE 2
|
||||
|
||||
#ifndef CONFIG_SYS_DCACHE_OFF
|
||||
|
||||
/* Asm functions from cache_v7_asm.S */
|
||||
void v7_flush_dcache_all(void);
|
||||
void v7_invalidate_dcache_all(void);
|
||||
|
||||
static int check_cache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
int ok = 1;
|
||||
|
||||
if (start & (CONFIG_SYS_CACHELINE_SIZE - 1))
|
||||
ok = 0;
|
||||
|
||||
if (stop & (CONFIG_SYS_CACHELINE_SIZE - 1))
|
||||
ok = 0;
|
||||
|
||||
if (!ok)
|
||||
debug("CACHE: Misaligned operation at range [%08lx, %08lx]\n",
|
||||
start, stop);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static u32 get_ccsidr(void)
|
||||
{
|
||||
u32 ccsidr;
|
||||
|
||||
/* Read current CP15 Cache Size ID Register */
|
||||
asm volatile ("mrc p15, 1, %0, c0, c0, 0" : "=r" (ccsidr));
|
||||
return ccsidr;
|
||||
}
|
||||
|
||||
static void v7_dcache_clean_inval_range(u32 start, u32 stop, u32 line_len)
|
||||
{
|
||||
u32 mva;
|
||||
|
||||
/* Align start to cache line boundary */
|
||||
start &= ~(line_len - 1);
|
||||
for (mva = start; mva < stop; mva = mva + line_len) {
|
||||
/* DCCIMVAC - Clean & Invalidate data cache by MVA to PoC */
|
||||
asm volatile ("mcr p15, 0, %0, c7, c14, 1" : : "r" (mva));
|
||||
}
|
||||
}
|
||||
|
||||
static void v7_dcache_inval_range(u32 start, u32 stop, u32 line_len)
|
||||
{
|
||||
u32 mva;
|
||||
|
||||
/*
|
||||
* If start address is not aligned to cache-line do not
|
||||
* invalidate the first cache-line
|
||||
*/
|
||||
if (start & (line_len - 1)) {
|
||||
printf("ERROR: %s - start address is not aligned - 0x%08x\n",
|
||||
__func__, start);
|
||||
/* move to next cache line */
|
||||
start = (start + line_len - 1) & ~(line_len - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* If stop address is not aligned to cache-line do not
|
||||
* invalidate the last cache-line
|
||||
*/
|
||||
if (stop & (line_len - 1)) {
|
||||
printf("ERROR: %s - stop address is not aligned - 0x%08x\n",
|
||||
__func__, stop);
|
||||
/* align to the beginning of this cache line */
|
||||
stop &= ~(line_len - 1);
|
||||
}
|
||||
|
||||
for (mva = start; mva < stop; mva = mva + line_len) {
|
||||
/* DCIMVAC - Invalidate data cache by MVA to PoC */
|
||||
asm volatile ("mcr p15, 0, %0, c7, c6, 1" : : "r" (mva));
|
||||
}
|
||||
}
|
||||
|
||||
static void v7_dcache_maint_range(u32 start, u32 stop, u32 range_op)
|
||||
{
|
||||
u32 line_len, ccsidr;
|
||||
|
||||
ccsidr = get_ccsidr();
|
||||
line_len = ((ccsidr & CCSIDR_LINE_SIZE_MASK) >>
|
||||
CCSIDR_LINE_SIZE_OFFSET) + 2;
|
||||
/* Converting from words to bytes */
|
||||
line_len += 2;
|
||||
/* converting from log2(linelen) to linelen */
|
||||
line_len = 1 << line_len;
|
||||
|
||||
switch (range_op) {
|
||||
case ARMV7_DCACHE_CLEAN_INVAL_RANGE:
|
||||
v7_dcache_clean_inval_range(start, stop, line_len);
|
||||
break;
|
||||
case ARMV7_DCACHE_INVAL_RANGE:
|
||||
v7_dcache_inval_range(start, stop, line_len);
|
||||
break;
|
||||
}
|
||||
|
||||
/* DSB to make sure the operation is complete */
|
||||
DSB;
|
||||
}
|
||||
|
||||
/* Invalidate TLB */
|
||||
static void v7_inval_tlb(void)
|
||||
{
|
||||
/* Invalidate entire unified TLB */
|
||||
asm volatile ("mcr p15, 0, %0, c8, c7, 0" : : "r" (0));
|
||||
/* Invalidate entire data TLB */
|
||||
asm volatile ("mcr p15, 0, %0, c8, c6, 0" : : "r" (0));
|
||||
/* Invalidate entire instruction TLB */
|
||||
asm volatile ("mcr p15, 0, %0, c8, c5, 0" : : "r" (0));
|
||||
/* Full system DSB - make sure that the invalidation is complete */
|
||||
DSB;
|
||||
/* Full system ISB - make sure the instruction stream sees it */
|
||||
ISB;
|
||||
}
|
||||
|
||||
void invalidate_dcache_all(void)
|
||||
{
|
||||
v7_invalidate_dcache_all();
|
||||
|
||||
v7_outer_cache_inval_all();
|
||||
}
|
||||
|
||||
/*
|
||||
* Performs a clean & invalidation of the entire data cache
|
||||
* at all levels
|
||||
*/
|
||||
void flush_dcache_all(void)
|
||||
{
|
||||
v7_flush_dcache_all();
|
||||
|
||||
v7_outer_cache_flush_all();
|
||||
}
|
||||
|
||||
/*
|
||||
* Invalidates range in all levels of D-cache/unified cache used:
|
||||
* Affects the range [start, stop - 1]
|
||||
*/
|
||||
void invalidate_dcache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
check_cache_range(start, stop);
|
||||
|
||||
v7_dcache_maint_range(start, stop, ARMV7_DCACHE_INVAL_RANGE);
|
||||
|
||||
v7_outer_cache_inval_range(start, stop);
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush range(clean & invalidate) from all levels of D-cache/unified
|
||||
* cache used:
|
||||
* Affects the range [start, stop - 1]
|
||||
*/
|
||||
void flush_dcache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
check_cache_range(start, stop);
|
||||
|
||||
v7_dcache_maint_range(start, stop, ARMV7_DCACHE_CLEAN_INVAL_RANGE);
|
||||
|
||||
v7_outer_cache_flush_range(start, stop);
|
||||
}
|
||||
|
||||
void arm_init_before_mmu(void)
|
||||
{
|
||||
v7_outer_cache_enable();
|
||||
invalidate_dcache_all();
|
||||
v7_inval_tlb();
|
||||
}
|
||||
|
||||
void mmu_page_table_flush(unsigned long start, unsigned long stop)
|
||||
{
|
||||
flush_dcache_range(start, stop);
|
||||
v7_inval_tlb();
|
||||
}
|
||||
#else /* #ifndef CONFIG_SYS_DCACHE_OFF */
|
||||
void invalidate_dcache_all(void)
|
||||
{
|
||||
}
|
||||
|
||||
void flush_dcache_all(void)
|
||||
{
|
||||
}
|
||||
|
||||
void arm_init_before_mmu(void)
|
||||
{
|
||||
}
|
||||
|
||||
void mmu_page_table_flush(unsigned long start, unsigned long stop)
|
||||
{
|
||||
}
|
||||
|
||||
void arm_init_domains(void)
|
||||
{
|
||||
}
|
||||
#endif /* #ifndef CONFIG_SYS_DCACHE_OFF */
|
||||
|
||||
#ifndef CONFIG_SYS_ICACHE_OFF
|
||||
/* Invalidate entire I-cache and branch predictor array */
|
||||
void invalidate_icache_all(void)
|
||||
{
|
||||
/*
|
||||
* Invalidate all instruction caches to PoU.
|
||||
* Also flushes branch target cache.
|
||||
*/
|
||||
asm volatile ("mcr p15, 0, %0, c7, c5, 0" : : "r" (0));
|
||||
|
||||
/* Invalidate entire branch predictor array */
|
||||
asm volatile ("mcr p15, 0, %0, c7, c5, 6" : : "r" (0));
|
||||
|
||||
/* Full system DSB - make sure that the invalidation is complete */
|
||||
DSB;
|
||||
|
||||
/* ISB - make sure the instruction stream sees it */
|
||||
ISB;
|
||||
}
|
||||
#else
|
||||
void invalidate_icache_all(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Stub implementations for outer cache operations */
|
||||
__weak void v7_outer_cache_enable(void) {}
|
||||
__weak void v7_outer_cache_disable(void) {}
|
||||
__weak void v7_outer_cache_flush_all(void) {}
|
||||
__weak void v7_outer_cache_inval_all(void) {}
|
||||
__weak void v7_outer_cache_flush_range(u32 start, u32 end) {}
|
||||
__weak void v7_outer_cache_inval_range(u32 start, u32 end) {}
|
||||
154
u-boot/arch/arm/cpu/armv7/cache_v7_asm.S
Normal file
154
u-boot/arch/arm/cpu/armv7/cache_v7_asm.S
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
#ifdef CONFIG_SYS_THUMB_BUILD
|
||||
#define ARM(x...)
|
||||
#define THUMB(x...) x
|
||||
#else
|
||||
#define ARM(x...) x
|
||||
#define THUMB(x...)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* v7_flush_dcache_all()
|
||||
*
|
||||
* Flush the whole D-cache.
|
||||
*
|
||||
* Corrupted registers: r0-r7, r9-r11 (r6 only in Thumb mode)
|
||||
*
|
||||
* Note: copied from arch/arm/mm/cache-v7.S of Linux 4.4
|
||||
*/
|
||||
ENTRY(__v7_flush_dcache_all)
|
||||
dmb @ ensure ordering with previous memory accesses
|
||||
mrc p15, 1, r0, c0, c0, 1 @ read clidr
|
||||
mov r3, r0, lsr #23 @ move LoC into position
|
||||
ands r3, r3, #7 << 1 @ extract LoC*2 from clidr
|
||||
beq finished @ if loc is 0, then no need to clean
|
||||
start_flush_levels:
|
||||
mov r10, #0 @ start clean at cache level 0
|
||||
flush_levels:
|
||||
add r2, r10, r10, lsr #1 @ work out 3x current cache level
|
||||
mov r1, r0, lsr r2 @ extract cache type bits from clidr
|
||||
and r1, r1, #7 @ mask of the bits for current cache only
|
||||
cmp r1, #2 @ see what cache we have at this level
|
||||
blt skip @ skip if no cache, or just i-cache
|
||||
mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr
|
||||
isb @ isb to sych the new cssr&csidr
|
||||
mrc p15, 1, r1, c0, c0, 0 @ read the new csidr
|
||||
and r2, r1, #7 @ extract the length of the cache lines
|
||||
add r2, r2, #4 @ add 4 (line length offset)
|
||||
movw r4, #0x3ff
|
||||
ands r4, r4, r1, lsr #3 @ find maximum number on the way size
|
||||
clz r5, r4 @ find bit position of way size increment
|
||||
movw r7, #0x7fff
|
||||
ands r7, r7, r1, lsr #13 @ extract max number of the index size
|
||||
loop1:
|
||||
mov r9, r7 @ create working copy of max index
|
||||
loop2:
|
||||
ARM( orr r11, r10, r4, lsl r5 ) @ factor way and cache number into r11
|
||||
THUMB( lsl r6, r4, r5 )
|
||||
THUMB( orr r11, r10, r6 ) @ factor way and cache number into r11
|
||||
ARM( orr r11, r11, r9, lsl r2 ) @ factor index number into r11
|
||||
THUMB( lsl r6, r9, r2 )
|
||||
THUMB( orr r11, r11, r6 ) @ factor index number into r11
|
||||
mcr p15, 0, r11, c7, c14, 2 @ clean & invalidate by set/way
|
||||
subs r9, r9, #1 @ decrement the index
|
||||
bge loop2
|
||||
subs r4, r4, #1 @ decrement the way
|
||||
bge loop1
|
||||
skip:
|
||||
add r10, r10, #2 @ increment cache number
|
||||
cmp r3, r10
|
||||
bgt flush_levels
|
||||
finished:
|
||||
mov r10, #0 @ swith back to cache level 0
|
||||
mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr
|
||||
dsb st
|
||||
isb
|
||||
bx lr
|
||||
ENDPROC(__v7_flush_dcache_all)
|
||||
|
||||
ENTRY(v7_flush_dcache_all)
|
||||
ARM( stmfd sp!, {r4-r5, r7, r9-r11, lr} )
|
||||
THUMB( stmfd sp!, {r4-r7, r9-r11, lr} )
|
||||
bl __v7_flush_dcache_all
|
||||
ARM( ldmfd sp!, {r4-r5, r7, r9-r11, lr} )
|
||||
THUMB( ldmfd sp!, {r4-r7, r9-r11, lr} )
|
||||
bx lr
|
||||
ENDPROC(v7_flush_dcache_all)
|
||||
|
||||
/*
|
||||
* v7_invalidate_dcache_all()
|
||||
*
|
||||
* Invalidate the whole D-cache.
|
||||
*
|
||||
* Corrupted registers: r0-r7, r9-r11 (r6 only in Thumb mode)
|
||||
*
|
||||
* Note: copied from __v7_flush_dcache_all above with
|
||||
* mcr p15, 0, r11, c7, c14, 2
|
||||
* Replaced with:
|
||||
* mcr p15, 0, r11, c7, c6, 2
|
||||
*/
|
||||
ENTRY(__v7_invalidate_dcache_all)
|
||||
dmb @ ensure ordering with previous memory accesses
|
||||
mrc p15, 1, r0, c0, c0, 1 @ read clidr
|
||||
mov r3, r0, lsr #23 @ move LoC into position
|
||||
ands r3, r3, #7 << 1 @ extract LoC*2 from clidr
|
||||
beq inval_finished @ if loc is 0, then no need to clean
|
||||
mov r10, #0 @ start clean at cache level 0
|
||||
inval_levels:
|
||||
add r2, r10, r10, lsr #1 @ work out 3x current cache level
|
||||
mov r1, r0, lsr r2 @ extract cache type bits from clidr
|
||||
and r1, r1, #7 @ mask of the bits for current cache only
|
||||
cmp r1, #2 @ see what cache we have at this level
|
||||
blt inval_skip @ skip if no cache, or just i-cache
|
||||
mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr
|
||||
isb @ isb to sych the new cssr&csidr
|
||||
mrc p15, 1, r1, c0, c0, 0 @ read the new csidr
|
||||
and r2, r1, #7 @ extract the length of the cache lines
|
||||
add r2, r2, #4 @ add 4 (line length offset)
|
||||
movw r4, #0x3ff
|
||||
ands r4, r4, r1, lsr #3 @ find maximum number on the way size
|
||||
clz r5, r4 @ find bit position of way size increment
|
||||
movw r7, #0x7fff
|
||||
ands r7, r7, r1, lsr #13 @ extract max number of the index size
|
||||
inval_loop1:
|
||||
mov r9, r7 @ create working copy of max index
|
||||
inval_loop2:
|
||||
ARM( orr r11, r10, r4, lsl r5 ) @ factor way and cache number into r11
|
||||
THUMB( lsl r6, r4, r5 )
|
||||
THUMB( orr r11, r10, r6 ) @ factor way and cache number into r11
|
||||
ARM( orr r11, r11, r9, lsl r2 ) @ factor index number into r11
|
||||
THUMB( lsl r6, r9, r2 )
|
||||
THUMB( orr r11, r11, r6 ) @ factor index number into r11
|
||||
mcr p15, 0, r11, c7, c6, 2 @ invalidate by set/way
|
||||
subs r9, r9, #1 @ decrement the index
|
||||
bge inval_loop2
|
||||
subs r4, r4, #1 @ decrement the way
|
||||
bge inval_loop1
|
||||
inval_skip:
|
||||
add r10, r10, #2 @ increment cache number
|
||||
cmp r3, r10
|
||||
bgt inval_levels
|
||||
inval_finished:
|
||||
mov r10, #0 @ swith back to cache level 0
|
||||
mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr
|
||||
dsb st
|
||||
isb
|
||||
bx lr
|
||||
ENDPROC(__v7_invalidate_dcache_all)
|
||||
|
||||
ENTRY(v7_invalidate_dcache_all)
|
||||
ARM( stmfd sp!, {r4-r5, r7, r9-r11, lr} )
|
||||
THUMB( stmfd sp!, {r4-r7, r9-r11, lr} )
|
||||
bl __v7_invalidate_dcache_all
|
||||
ARM( ldmfd sp!, {r4-r5, r7, r9-r11, lr} )
|
||||
THUMB( ldmfd sp!, {r4-r7, r9-r11, lr} )
|
||||
bx lr
|
||||
ENDPROC(v7_invalidate_dcache_all)
|
||||
13
u-boot/arch/arm/cpu/armv7/config.mk
Normal file
13
u-boot/arch/arm/cpu/armv7/config.mk
Normal file
@@ -0,0 +1,13 @@
|
||||
#
|
||||
# (C) Copyright 2002
|
||||
# Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
# On supported platforms we set the bit which causes us to trap on unaligned
|
||||
# memory access. This is the opposite of what the compiler expects to be
|
||||
# the default so we must pass in -mno-unaligned-access so that it is aware
|
||||
# of our decision.
|
||||
PF_NO_UNALIGNED := $(call cc-option, -mno-unaligned-access,)
|
||||
PLATFORM_CPPFLAGS += $(PF_NO_UNALIGNED)
|
||||
29
u-boot/arch/arm/cpu/armv7/cp15.c
Normal file
29
u-boot/arch/arm/cpu/armv7/cp15.c
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* (C) Copyright 2015 Texas Insturments
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
/*
|
||||
* CP15 specific code
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/cache.h>
|
||||
#include <asm/armv7.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
void __weak v7_arch_cp15_set_l2aux_ctrl(u32 l2actlr, u32 cpu_midr,
|
||||
u32 cpu_rev_comb, u32 cpu_variant,
|
||||
u32 cpu_rev)
|
||||
{
|
||||
asm volatile ("mcr p15, 1, %0, c15, c0, 0\n\t" : : "r"(l2actlr));
|
||||
}
|
||||
|
||||
void __weak v7_arch_cp15_set_acr(u32 acr, u32 cpu_midr, u32 cpu_rev_comb,
|
||||
u32 cpu_variant, u32 cpu_rev)
|
||||
{
|
||||
asm volatile ("mcr p15, 0, %0, c1, c0, 1\n\t" : : "r"(acr));
|
||||
}
|
||||
84
u-boot/arch/arm/cpu/armv7/cpu.c
Normal file
84
u-boot/arch/arm/cpu/armv7/cpu.c
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* (C) Copyright 2008 Texas Insturments
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Marius Groeger <mgroeger@sysgo.de>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
/*
|
||||
* CPU specific code
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/cache.h>
|
||||
#include <asm/armv7.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
void __weak cpu_cache_initialization(void){}
|
||||
|
||||
int cleanup_before_linux_select(int flags)
|
||||
{
|
||||
/*
|
||||
* this function is called just before we call linux
|
||||
* it prepares the processor for linux
|
||||
*
|
||||
* we turn off caches etc ...
|
||||
*/
|
||||
#ifndef CONFIG_SPL_BUILD
|
||||
disable_interrupts();
|
||||
#endif
|
||||
|
||||
if (flags & CBL_DISABLE_CACHES) {
|
||||
/*
|
||||
* turn off D-cache
|
||||
* dcache_disable() in turn flushes the d-cache and disables MMU
|
||||
*/
|
||||
dcache_disable();
|
||||
v7_outer_cache_disable();
|
||||
|
||||
/*
|
||||
* After D-cache is flushed and before it is disabled there may
|
||||
* be some new valid entries brought into the cache. We are
|
||||
* sure that these lines are not dirty and will not affect our
|
||||
* execution. (because unwinding the call-stack and setting a
|
||||
* bit in CP15 SCTRL is all we did during this. We have not
|
||||
* pushed anything on to the stack. Neither have we affected
|
||||
* any static data) So just invalidate the entire d-cache again
|
||||
* to avoid coherency problems for kernel
|
||||
*/
|
||||
invalidate_dcache_all();
|
||||
|
||||
icache_disable();
|
||||
invalidate_icache_all();
|
||||
} else {
|
||||
/*
|
||||
* Turn off I-cache and invalidate it
|
||||
*/
|
||||
icache_disable();
|
||||
invalidate_icache_all();
|
||||
|
||||
flush_dcache_all();
|
||||
invalidate_icache_all();
|
||||
icache_enable();
|
||||
}
|
||||
|
||||
/*
|
||||
* Some CPU need more cache attention before starting the kernel.
|
||||
*/
|
||||
cpu_cache_initialization();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cleanup_before_linux(void)
|
||||
{
|
||||
return cleanup_before_linux_select(CBL_ALL);
|
||||
}
|
||||
9
u-boot/arch/arm/cpu/armv7/iproc-common/Makefile
Normal file
9
u-boot/arch/arm/cpu/armv7/iproc-common/Makefile
Normal file
@@ -0,0 +1,9 @@
|
||||
#
|
||||
# Copyright 2014 Broadcom Corporation.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y += armpll.o
|
||||
obj-y += hwinit-common.o
|
||||
obj-y += timer.o
|
||||
170
u-boot/arch/arm/cpu/armv7/iproc-common/armpll.c
Normal file
170
u-boot/arch/arm/cpu/armv7/iproc-common/armpll.c
Normal file
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright 2014 Broadcom Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/iproc-common/armpll.h>
|
||||
#include <asm/iproc-common/sysmap.h>
|
||||
|
||||
#define NELEMS(x) (sizeof(x) / sizeof(x[0]))
|
||||
|
||||
struct armpll_parameters {
|
||||
unsigned int mode;
|
||||
unsigned int ndiv_int;
|
||||
unsigned int ndiv_frac;
|
||||
unsigned int pdiv;
|
||||
unsigned int freqid;
|
||||
};
|
||||
|
||||
struct armpll_parameters armpll_clk_tab[] = {
|
||||
{ 25, 64, 1, 1, 0},
|
||||
{ 100, 64, 1, 1, 2},
|
||||
{ 400, 64, 1, 1, 6},
|
||||
{ 448, 71, 713050, 1, 6},
|
||||
{ 500, 80, 1, 1, 6},
|
||||
{ 560, 89, 629145, 1, 6},
|
||||
{ 600, 96, 1, 1, 6},
|
||||
{ 800, 64, 1, 1, 7},
|
||||
{ 896, 71, 713050, 1, 7},
|
||||
{ 1000, 80, 1, 1, 7},
|
||||
{ 1100, 88, 1, 1, 7},
|
||||
{ 1120, 89, 629145, 1, 7},
|
||||
{ 1200, 96, 1, 1, 7},
|
||||
};
|
||||
|
||||
uint32_t armpll_config(uint32_t clkmhz)
|
||||
{
|
||||
uint32_t freqid;
|
||||
uint32_t ndiv_frac;
|
||||
uint32_t pll;
|
||||
uint32_t status = 1;
|
||||
uint32_t timeout_countdown;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NELEMS(armpll_clk_tab); i++) {
|
||||
if (armpll_clk_tab[i].mode == clkmhz) {
|
||||
status = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (status) {
|
||||
printf("Error: Clock configuration not supported\n");
|
||||
goto armpll_config_done;
|
||||
}
|
||||
|
||||
/* Enable write access */
|
||||
writel(IPROC_REG_WRITE_ACCESS, IHOST_PROC_CLK_WR_ACCESS);
|
||||
|
||||
if (clkmhz == 25)
|
||||
freqid = 0;
|
||||
else
|
||||
freqid = 2;
|
||||
|
||||
/* Bypass ARM clock and run on sysclk */
|
||||
writel(1 << IHOST_PROC_CLK_POLICY_FREQ__PRIV_ACCESS_MODE |
|
||||
freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY3_FREQ_R |
|
||||
freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY2_FREQ_R |
|
||||
freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY1_FREQ_R |
|
||||
freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY0_FREQ_R,
|
||||
IHOST_PROC_CLK_POLICY_FREQ);
|
||||
|
||||
writel(1 << IHOST_PROC_CLK_POLICY_CTL__GO |
|
||||
1 << IHOST_PROC_CLK_POLICY_CTL__GO_AC,
|
||||
IHOST_PROC_CLK_POLICY_CTL);
|
||||
|
||||
/* Poll CCU until operation complete */
|
||||
timeout_countdown = 0x100000;
|
||||
while (readl(IHOST_PROC_CLK_POLICY_CTL) &
|
||||
(1 << IHOST_PROC_CLK_POLICY_CTL__GO)) {
|
||||
timeout_countdown--;
|
||||
if (timeout_countdown == 0) {
|
||||
printf("CCU polling timedout\n");
|
||||
status = 1;
|
||||
goto armpll_config_done;
|
||||
}
|
||||
}
|
||||
|
||||
if (clkmhz == 25 || clkmhz == 100) {
|
||||
status = 0;
|
||||
goto armpll_config_done;
|
||||
}
|
||||
|
||||
/* Now it is safe to program the PLL */
|
||||
pll = readl(IHOST_PROC_CLK_PLLARMB);
|
||||
pll &= ~((1 << IHOST_PROC_CLK_PLLARMB__PLLARM_NDIV_FRAC_WIDTH) - 1);
|
||||
ndiv_frac =
|
||||
((1 << IHOST_PROC_CLK_PLLARMB__PLLARM_NDIV_FRAC_WIDTH) - 1) &
|
||||
(armpll_clk_tab[i].ndiv_frac <<
|
||||
IHOST_PROC_CLK_PLLARMB__PLLARM_NDIV_FRAC_R);
|
||||
pll |= ndiv_frac;
|
||||
writel(pll, IHOST_PROC_CLK_PLLARMB);
|
||||
|
||||
writel(1 << IHOST_PROC_CLK_PLLARMA__PLLARM_LOCK |
|
||||
armpll_clk_tab[i].ndiv_int <<
|
||||
IHOST_PROC_CLK_PLLARMA__PLLARM_NDIV_INT_R |
|
||||
armpll_clk_tab[i].pdiv <<
|
||||
IHOST_PROC_CLK_PLLARMA__PLLARM_PDIV_R |
|
||||
1 << IHOST_PROC_CLK_PLLARMA__PLLARM_SOFT_RESETB,
|
||||
IHOST_PROC_CLK_PLLARMA);
|
||||
|
||||
/* Poll ARM PLL Lock until operation complete */
|
||||
timeout_countdown = 0x100000;
|
||||
while (readl(IHOST_PROC_CLK_PLLARMA) &
|
||||
(1 << IHOST_PROC_CLK_PLLARMA__PLLARM_LOCK)) {
|
||||
timeout_countdown--;
|
||||
if (timeout_countdown == 0) {
|
||||
printf("ARM PLL lock failed\n");
|
||||
status = 1;
|
||||
goto armpll_config_done;
|
||||
}
|
||||
}
|
||||
|
||||
pll = readl(IHOST_PROC_CLK_PLLARMA);
|
||||
pll |= (1 << IHOST_PROC_CLK_PLLARMA__PLLARM_SOFT_POST_RESETB);
|
||||
writel(pll, IHOST_PROC_CLK_PLLARMA);
|
||||
|
||||
/* Set the policy */
|
||||
writel(1 << IHOST_PROC_CLK_POLICY_FREQ__PRIV_ACCESS_MODE |
|
||||
armpll_clk_tab[i].freqid <<
|
||||
IHOST_PROC_CLK_POLICY_FREQ__POLICY3_FREQ_R |
|
||||
armpll_clk_tab[i].freqid <<
|
||||
IHOST_PROC_CLK_POLICY_FREQ__POLICY2_FREQ_R |
|
||||
armpll_clk_tab[i].freqid <<
|
||||
IHOST_PROC_CLK_POLICY_FREQ__POLICY1_FREQ_R |
|
||||
armpll_clk_tab[i+4].freqid <<
|
||||
IHOST_PROC_CLK_POLICY_FREQ__POLICY0_FREQ_R,
|
||||
IHOST_PROC_CLK_POLICY_FREQ);
|
||||
|
||||
writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_CORE0_CLKGATE);
|
||||
writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_CORE1_CLKGATE);
|
||||
writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_ARM_SWITCH_CLKGATE);
|
||||
writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_ARM_PERIPH_CLKGATE);
|
||||
writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_APB0_CLKGATE);
|
||||
|
||||
writel(1 << IHOST_PROC_CLK_POLICY_CTL__GO |
|
||||
1 << IHOST_PROC_CLK_POLICY_CTL__GO_AC,
|
||||
IHOST_PROC_CLK_POLICY_CTL);
|
||||
|
||||
/* Poll CCU until operation complete */
|
||||
timeout_countdown = 0x100000;
|
||||
while (readl(IHOST_PROC_CLK_POLICY_CTL) &
|
||||
(1 << IHOST_PROC_CLK_POLICY_CTL__GO)) {
|
||||
timeout_countdown--;
|
||||
if (timeout_countdown == 0) {
|
||||
printf("CCU polling failed\n");
|
||||
status = 1;
|
||||
goto armpll_config_done;
|
||||
}
|
||||
}
|
||||
|
||||
status = 0;
|
||||
armpll_config_done:
|
||||
/* Disable access to PLL registers */
|
||||
writel(0, IHOST_PROC_CLK_WR_ACCESS);
|
||||
|
||||
return status;
|
||||
}
|
||||
15
u-boot/arch/arm/cpu/armv7/iproc-common/hwinit-common.c
Normal file
15
u-boot/arch/arm/cpu/armv7/iproc-common/hwinit-common.c
Normal file
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright 2014 Broadcom Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
|
||||
#ifndef CONFIG_SYS_DCACHE_OFF
|
||||
void enable_caches(void)
|
||||
{
|
||||
/* Enable D-cache. I-cache is already enabled in start.S */
|
||||
dcache_enable();
|
||||
}
|
||||
#endif
|
||||
130
u-boot/arch/arm/cpu/armv7/iproc-common/timer.c
Normal file
130
u-boot/arch/arm/cpu/armv7/iproc-common/timer.c
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright 2014 Broadcom Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <div64.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/iproc-common/timer.h>
|
||||
#include <asm/iproc-common/sysmap.h>
|
||||
|
||||
static inline uint64_t timer_global_read(void)
|
||||
{
|
||||
uint64_t cur_tick;
|
||||
uint32_t count_h;
|
||||
uint32_t count_l;
|
||||
|
||||
do {
|
||||
count_h = readl(IPROC_PERIPH_GLB_TIM_REG_BASE +
|
||||
TIMER_GLB_HI_OFFSET);
|
||||
count_l = readl(IPROC_PERIPH_GLB_TIM_REG_BASE +
|
||||
TIMER_GLB_LOW_OFFSET);
|
||||
cur_tick = readl(IPROC_PERIPH_GLB_TIM_REG_BASE +
|
||||
TIMER_GLB_HI_OFFSET);
|
||||
} while (cur_tick != count_h);
|
||||
|
||||
return (cur_tick << 32) + count_l;
|
||||
}
|
||||
|
||||
void timer_global_init(void)
|
||||
{
|
||||
writel(0, IPROC_PERIPH_GLB_TIM_REG_BASE + TIMER_GLB_CTRL_OFFSET);
|
||||
writel(0, IPROC_PERIPH_GLB_TIM_REG_BASE + TIMER_GLB_LOW_OFFSET);
|
||||
writel(0, IPROC_PERIPH_GLB_TIM_REG_BASE + TIMER_GLB_HI_OFFSET);
|
||||
writel(TIMER_GLB_TIM_CTRL_TIM_EN,
|
||||
IPROC_PERIPH_GLB_TIM_REG_BASE + TIMER_GLB_CTRL_OFFSET);
|
||||
}
|
||||
|
||||
int timer_init(void)
|
||||
{
|
||||
timer_global_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long get_timer(unsigned long base)
|
||||
{
|
||||
uint64_t count;
|
||||
uint64_t ret;
|
||||
uint64_t tim_clk;
|
||||
uint64_t periph_clk;
|
||||
|
||||
count = timer_global_read();
|
||||
|
||||
/* default arm clk is 1GHz, periph_clk=arm_clk/2, tick per msec */
|
||||
periph_clk = 500000;
|
||||
tim_clk = lldiv(periph_clk,
|
||||
(((readl(IPROC_PERIPH_GLB_TIM_REG_BASE +
|
||||
TIMER_GLB_CTRL_OFFSET) &
|
||||
TIMER_GLB_TIM_CTRL_PRESC_MASK) >> 8) + 1));
|
||||
|
||||
ret = lldiv(count, (uint32_t)tim_clk);
|
||||
|
||||
/* returns msec */
|
||||
return ret - base;
|
||||
}
|
||||
|
||||
void __udelay(unsigned long usec)
|
||||
{
|
||||
uint64_t cur_tick, end_tick;
|
||||
uint64_t tim_clk;
|
||||
uint64_t periph_clk;
|
||||
|
||||
/* default arm clk is 1GHz, periph_clk=arm_clk/2, tick per usec */
|
||||
periph_clk = 500;
|
||||
|
||||
tim_clk = lldiv(periph_clk,
|
||||
(((readl(IPROC_PERIPH_GLB_TIM_REG_BASE +
|
||||
TIMER_GLB_CTRL_OFFSET) &
|
||||
TIMER_GLB_TIM_CTRL_PRESC_MASK) >> 8) + 1));
|
||||
|
||||
cur_tick = timer_global_read();
|
||||
|
||||
end_tick = tim_clk;
|
||||
end_tick *= usec;
|
||||
end_tick += cur_tick;
|
||||
|
||||
do {
|
||||
cur_tick = timer_global_read();
|
||||
|
||||
} while (cur_tick < end_tick);
|
||||
}
|
||||
|
||||
void timer_systick_init(uint32_t tick_ms)
|
||||
{
|
||||
/* Disable timer and clear interrupt status*/
|
||||
writel(0, IPROC_PERIPH_PVT_TIM_REG_BASE + TIMER_PVT_CTRL_OFFSET);
|
||||
writel(TIMER_PVT_TIM_INT_STATUS_SET,
|
||||
IPROC_PERIPH_PVT_TIM_REG_BASE + TIMER_PVT_STATUS_OFFSET);
|
||||
writel((PLL_AXI_CLK/1000) * tick_ms,
|
||||
IPROC_PERIPH_PVT_TIM_REG_BASE + TIMER_PVT_LOAD_OFFSET);
|
||||
writel(TIMER_PVT_TIM_CTRL_INT_EN |
|
||||
TIMER_PVT_TIM_CTRL_AUTO_RELD |
|
||||
TIMER_PVT_TIM_CTRL_TIM_EN,
|
||||
IPROC_PERIPH_PVT_TIM_REG_BASE + TIMER_PVT_CTRL_OFFSET);
|
||||
}
|
||||
|
||||
void timer_systick_isr(void *data)
|
||||
{
|
||||
writel(TIMER_PVT_TIM_INT_STATUS_SET,
|
||||
IPROC_PERIPH_PVT_TIM_REG_BASE + TIMER_PVT_STATUS_OFFSET);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is derived from PowerPC code (read timebase as long long).
|
||||
* On ARM it just returns the timer value in msec.
|
||||
*/
|
||||
unsigned long long get_ticks(void)
|
||||
{
|
||||
return get_timer(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is used in conjuction with get_ticks, which returns msec as ticks.
|
||||
* Here we just return ticks/sec = msec/sec = 1000
|
||||
*/
|
||||
ulong get_tbclk(void)
|
||||
{
|
||||
return 1000;
|
||||
}
|
||||
10
u-boot/arch/arm/cpu/armv7/kona-common/Makefile
Normal file
10
u-boot/arch/arm/cpu/armv7/kona-common/Makefile
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
# Copyright 2013 Broadcom Corporation.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y += s_init.o
|
||||
obj-y += hwinit-common.o
|
||||
obj-y += clk-stubs.o
|
||||
obj-${CONFIG_KONA_RESET_S} += reset.o
|
||||
26
u-boot/arch/arm/cpu/armv7/kona-common/clk-stubs.c
Normal file
26
u-boot/arch/arm/cpu/armv7/kona-common/clk-stubs.c
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2013 Broadcom Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
|
||||
/*
|
||||
* These weak functions are available to kona architectures that don't
|
||||
* require clock enables from the driver code.
|
||||
*/
|
||||
int __weak clk_sdio_enable(void *base, u32 rate, u32 *actual_ratep)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __weak clk_bsc_enable(void *base, u32 rate, u32 *actual_ratep)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __weak clk_usb_otg_enable(void *base)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
16
u-boot/arch/arm/cpu/armv7/kona-common/hwinit-common.c
Normal file
16
u-boot/arch/arm/cpu/armv7/kona-common/hwinit-common.c
Normal file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2013 Broadcom Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <linux/sizes.h>
|
||||
|
||||
#ifndef CONFIG_SYS_DCACHE_OFF
|
||||
void enable_caches(void)
|
||||
{
|
||||
/* Enable D-cache. I-cache is already enabled in start.S */
|
||||
dcache_enable();
|
||||
}
|
||||
#endif
|
||||
26
u-boot/arch/arm/cpu/armv7/kona-common/reset.S
Normal file
26
u-boot/arch/arm/cpu/armv7/kona-common/reset.S
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2013 Broadcom Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
.globl reset_cpu
|
||||
reset_cpu:
|
||||
ldr r1, =0x35001f00
|
||||
ldr r2, [r1]
|
||||
ldr r4, =0x80000000
|
||||
and r4, r2, r4
|
||||
ldr r3, =0xA5A500
|
||||
orr r4, r4, r3
|
||||
orr r4, r4, #0x1
|
||||
|
||||
str r4, [r1]
|
||||
|
||||
ldr r1, =0x35001f04
|
||||
ldr r2, [r1]
|
||||
ldr r4, =0x80000000
|
||||
and r4, r2, r4
|
||||
str r4, [r1]
|
||||
|
||||
_loop_forever:
|
||||
b _loop_forever
|
||||
12
u-boot/arch/arm/cpu/armv7/kona-common/s_init.c
Normal file
12
u-boot/arch/arm/cpu/armv7/kona-common/s_init.c
Normal file
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright 2014 Broadcom Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
/*
|
||||
* Early system init. Currently empty.
|
||||
*/
|
||||
void s_init(void)
|
||||
{
|
||||
}
|
||||
59
u-boot/arch/arm/cpu/armv7/lowlevel_init.S
Normal file
59
u-boot/arch/arm/cpu/armv7/lowlevel_init.S
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* A lowlevel_init function that sets up the stack to call a C function to
|
||||
* perform further init.
|
||||
*
|
||||
* (C) Copyright 2010
|
||||
* Texas Instruments, <www.ti.com>
|
||||
*
|
||||
* Author :
|
||||
* Aneesh V <aneesh@ti.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <asm-offsets.h>
|
||||
#include <config.h>
|
||||
#include <linux/linkage.h>
|
||||
|
||||
ENTRY(lowlevel_init)
|
||||
/*
|
||||
* Setup a temporary stack. Global data is not available yet.
|
||||
*/
|
||||
ldr sp, =CONFIG_SYS_INIT_SP_ADDR
|
||||
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
|
||||
#ifdef CONFIG_SPL_DM
|
||||
mov r9, #0
|
||||
#else
|
||||
/*
|
||||
* Set up global data for boards that still need it. This will be
|
||||
* removed soon.
|
||||
*/
|
||||
#ifdef CONFIG_SPL_BUILD
|
||||
ldr r9, =gdata
|
||||
#else
|
||||
sub sp, sp, #GD_SIZE
|
||||
bic sp, sp, #7
|
||||
mov r9, sp
|
||||
#endif
|
||||
#endif
|
||||
/*
|
||||
* Save the old lr(passed in ip) and the current lr to stack
|
||||
*/
|
||||
push {ip, lr}
|
||||
|
||||
/*
|
||||
* Call the very early init function. This should do only the
|
||||
* absolute bare minimum to get started. It should not:
|
||||
*
|
||||
* - set up DRAM
|
||||
* - use global_data
|
||||
* - clear BSS
|
||||
* - try to start a console
|
||||
*
|
||||
* For boards with SPL this should be empty since SPL can do all of
|
||||
* this init in the SPL board_init_f() function which is called
|
||||
* immediately after this.
|
||||
*/
|
||||
bl s_init
|
||||
pop {ip, pc}
|
||||
ENDPROC(lowlevel_init)
|
||||
20
u-boot/arch/arm/cpu/armv7/ls102xa/Makefile
Normal file
20
u-boot/arch/arm/cpu/armv7/ls102xa/Makefile
Normal file
@@ -0,0 +1,20 @@
|
||||
#
|
||||
# Copyright 2014 Freescale Semiconductor, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y += cpu.o
|
||||
obj-y += clock.o
|
||||
obj-y += timer.o
|
||||
obj-y += fsl_epu.o
|
||||
obj-y += soc.o
|
||||
|
||||
obj-$(CONFIG_SCSI_AHCI_PLAT) += ls102xa_sata.o
|
||||
obj-$(CONFIG_OF_LIBFDT) += fdt.o
|
||||
obj-$(CONFIG_SYS_HAS_SERDES) += fsl_ls1_serdes.o ls102xa_serdes.o
|
||||
obj-$(CONFIG_SPL) += spl.o
|
||||
|
||||
ifdef CONFIG_ARMV7_PSCI
|
||||
obj-y += psci.o
|
||||
endif
|
||||
130
u-boot/arch/arm/cpu/armv7/ls102xa/clock.c
Normal file
130
u-boot/arch/arm/cpu/armv7/ls102xa/clock.c
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright 2014 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/immap_ls102xa.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <fsl_ifc.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#ifndef CONFIG_SYS_FSL_NUM_CC_PLLS
|
||||
#define CONFIG_SYS_FSL_NUM_CC_PLLS 2
|
||||
#endif
|
||||
|
||||
void get_sys_info(struct sys_info *sys_info)
|
||||
{
|
||||
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
#ifdef CONFIG_FSL_IFC
|
||||
struct fsl_ifc ifc_regs = {(void *)CONFIG_SYS_IFC_ADDR, (void *)NULL};
|
||||
u32 ccr;
|
||||
#endif
|
||||
struct ccsr_clk *clk = (void *)(CONFIG_SYS_FSL_LS1_CLK_ADDR);
|
||||
unsigned int cpu;
|
||||
const u8 core_cplx_pll[6] = {
|
||||
[0] = 0, /* CC1 PPL / 1 */
|
||||
[1] = 0, /* CC1 PPL / 2 */
|
||||
[4] = 1, /* CC2 PPL / 1 */
|
||||
[5] = 1, /* CC2 PPL / 2 */
|
||||
};
|
||||
|
||||
const u8 core_cplx_pll_div[6] = {
|
||||
[0] = 1, /* CC1 PPL / 1 */
|
||||
[1] = 2, /* CC1 PPL / 2 */
|
||||
[4] = 1, /* CC2 PPL / 1 */
|
||||
[5] = 2, /* CC2 PPL / 2 */
|
||||
};
|
||||
|
||||
uint i;
|
||||
uint freq_c_pll[CONFIG_SYS_FSL_NUM_CC_PLLS];
|
||||
uint ratio[CONFIG_SYS_FSL_NUM_CC_PLLS];
|
||||
unsigned long sysclk = CONFIG_SYS_CLK_FREQ;
|
||||
|
||||
sys_info->freq_systembus = sysclk;
|
||||
#ifdef CONFIG_DDR_CLK_FREQ
|
||||
sys_info->freq_ddrbus = CONFIG_DDR_CLK_FREQ;
|
||||
#else
|
||||
sys_info->freq_ddrbus = sysclk;
|
||||
#endif
|
||||
|
||||
sys_info->freq_systembus *= (in_be32(&gur->rcwsr[0]) >>
|
||||
RCWSR0_SYS_PLL_RAT_SHIFT) & RCWSR0_SYS_PLL_RAT_MASK;
|
||||
sys_info->freq_ddrbus *= (in_be32(&gur->rcwsr[0]) >>
|
||||
RCWSR0_MEM_PLL_RAT_SHIFT) & RCWSR0_MEM_PLL_RAT_MASK;
|
||||
|
||||
for (i = 0; i < CONFIG_SYS_FSL_NUM_CC_PLLS; i++) {
|
||||
ratio[i] = (in_be32(&clk->pllcgsr[i].pllcngsr) >> 1) & 0x3f;
|
||||
if (ratio[i] > 4)
|
||||
freq_c_pll[i] = sysclk * ratio[i];
|
||||
else
|
||||
freq_c_pll[i] = sys_info->freq_systembus * ratio[i];
|
||||
}
|
||||
|
||||
for (cpu = 0; cpu < CONFIG_MAX_CPUS; cpu++) {
|
||||
u32 c_pll_sel = (in_be32(&clk->clkcsr[cpu].clkcncsr) >> 27)
|
||||
& 0xf;
|
||||
u32 cplx_pll = core_cplx_pll[c_pll_sel];
|
||||
|
||||
sys_info->freq_processor[cpu] =
|
||||
freq_c_pll[cplx_pll] / core_cplx_pll_div[c_pll_sel];
|
||||
}
|
||||
|
||||
#if defined(CONFIG_FSL_IFC)
|
||||
ccr = in_be32(&ifc_regs.gregs->ifc_ccr);
|
||||
ccr = ((ccr & IFC_CCR_CLK_DIV_MASK) >> IFC_CCR_CLK_DIV_SHIFT) + 1;
|
||||
|
||||
sys_info->freq_localbus = sys_info->freq_systembus / ccr;
|
||||
#endif
|
||||
}
|
||||
|
||||
int get_clocks(void)
|
||||
{
|
||||
struct sys_info sys_info;
|
||||
|
||||
get_sys_info(&sys_info);
|
||||
gd->cpu_clk = sys_info.freq_processor[0];
|
||||
gd->bus_clk = sys_info.freq_systembus;
|
||||
gd->mem_clk = sys_info.freq_ddrbus * 2;
|
||||
|
||||
#if defined(CONFIG_FSL_ESDHC)
|
||||
gd->arch.sdhc_clk = gd->bus_clk;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ulong get_bus_freq(ulong dummy)
|
||||
{
|
||||
return gd->bus_clk;
|
||||
}
|
||||
|
||||
ulong get_ddr_freq(ulong dummy)
|
||||
{
|
||||
return gd->mem_clk;
|
||||
}
|
||||
|
||||
int get_serial_clock(void)
|
||||
{
|
||||
return gd->bus_clk / 2;
|
||||
}
|
||||
|
||||
unsigned int mxc_get_clock(enum mxc_clock clk)
|
||||
{
|
||||
switch (clk) {
|
||||
case MXC_I2C_CLK:
|
||||
return get_bus_freq(0) / 2;
|
||||
case MXC_ESDHC_CLK:
|
||||
return get_bus_freq(0);
|
||||
case MXC_DSPI_CLK:
|
||||
return get_bus_freq(0) / 2;
|
||||
case MXC_UART_CLK:
|
||||
return get_bus_freq(0) / 2;
|
||||
default:
|
||||
printf("Unsupported clock\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
392
u-boot/arch/arm/cpu/armv7/ls102xa/cpu.c
Normal file
392
u-boot/arch/arm/cpu/armv7/ls102xa/cpu.c
Normal file
@@ -0,0 +1,392 @@
|
||||
/*
|
||||
* Copyright 2014 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/immap_ls102xa.h>
|
||||
#include <asm/cache.h>
|
||||
#include <asm/system.h>
|
||||
#include <tsec.h>
|
||||
#include <netdev.h>
|
||||
#include <fsl_esdhc.h>
|
||||
#include <config.h>
|
||||
#include <fsl_wdog.h>
|
||||
|
||||
#include "fsl_epu.h"
|
||||
|
||||
#define DCSR_RCPM2_BLOCK_OFFSET 0x223000
|
||||
#define DCSR_RCPM2_CPMFSMCR0 0x400
|
||||
#define DCSR_RCPM2_CPMFSMSR0 0x404
|
||||
#define DCSR_RCPM2_CPMFSMCR1 0x414
|
||||
#define DCSR_RCPM2_CPMFSMSR1 0x418
|
||||
#define CPMFSMSR_FSM_STATE_MASK 0x7f
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#ifndef CONFIG_SYS_DCACHE_OFF
|
||||
|
||||
/*
|
||||
* Bit[1] of the descriptor indicates the descriptor type,
|
||||
* and bit[0] indicates whether the descriptor is valid.
|
||||
*/
|
||||
#define PMD_TYPE_TABLE 0x3
|
||||
#define PMD_TYPE_SECT 0x1
|
||||
|
||||
/* AttrIndx[2:0] */
|
||||
#define PMD_ATTRINDX(t) ((t) << 2)
|
||||
|
||||
/* Section */
|
||||
#define PMD_SECT_AF (1 << 10)
|
||||
|
||||
#define BLOCK_SIZE_L1 (1UL << 30)
|
||||
#define BLOCK_SIZE_L2 (1UL << 21)
|
||||
|
||||
/* TTBCR flags */
|
||||
#define TTBCR_EAE (1 << 31)
|
||||
#define TTBCR_T0SZ(x) ((x) << 0)
|
||||
#define TTBCR_T1SZ(x) ((x) << 16)
|
||||
#define TTBCR_USING_TTBR0 (TTBCR_T0SZ(0) | TTBCR_T1SZ(0))
|
||||
#define TTBCR_IRGN0_NC (0 << 8)
|
||||
#define TTBCR_IRGN0_WBWA (1 << 8)
|
||||
#define TTBCR_IRGN0_WT (2 << 8)
|
||||
#define TTBCR_IRGN0_WBNWA (3 << 8)
|
||||
#define TTBCR_IRGN0_MASK (3 << 8)
|
||||
#define TTBCR_ORGN0_NC (0 << 10)
|
||||
#define TTBCR_ORGN0_WBWA (1 << 10)
|
||||
#define TTBCR_ORGN0_WT (2 << 10)
|
||||
#define TTBCR_ORGN0_WBNWA (3 << 10)
|
||||
#define TTBCR_ORGN0_MASK (3 << 10)
|
||||
#define TTBCR_SHARED_NON (0 << 12)
|
||||
#define TTBCR_SHARED_OUTER (2 << 12)
|
||||
#define TTBCR_SHARED_INNER (3 << 12)
|
||||
#define TTBCR_EPD0 (0 << 7)
|
||||
#define TTBCR (TTBCR_SHARED_NON | \
|
||||
TTBCR_ORGN0_NC | \
|
||||
TTBCR_IRGN0_NC | \
|
||||
TTBCR_USING_TTBR0 | \
|
||||
TTBCR_EAE)
|
||||
|
||||
/*
|
||||
* Memory region attributes for LPAE (defined in pgtable):
|
||||
*
|
||||
* n = AttrIndx[2:0]
|
||||
*
|
||||
* n MAIR
|
||||
* UNCACHED 000 00000000
|
||||
* BUFFERABLE 001 01000100
|
||||
* DEV_WC 001 01000100
|
||||
* WRITETHROUGH 010 10101010
|
||||
* WRITEBACK 011 11101110
|
||||
* DEV_CACHED 011 11101110
|
||||
* DEV_SHARED 100 00000100
|
||||
* DEV_NONSHARED 100 00000100
|
||||
* unused 101
|
||||
* unused 110
|
||||
* WRITEALLOC 111 11111111
|
||||
*/
|
||||
#define MT_MAIR0 0xeeaa4400
|
||||
#define MT_MAIR1 0xff000004
|
||||
#define MT_STRONLY_ORDER 0
|
||||
#define MT_NORMAL_NC 1
|
||||
#define MT_DEVICE_MEM 4
|
||||
#define MT_NORMAL 7
|
||||
|
||||
/* The phy_addr must be aligned to 4KB */
|
||||
static inline void set_pgtable(u32 *page_table, u32 index, u32 phy_addr)
|
||||
{
|
||||
u32 value = phy_addr | PMD_TYPE_TABLE;
|
||||
|
||||
page_table[2 * index] = value;
|
||||
page_table[2 * index + 1] = 0;
|
||||
}
|
||||
|
||||
/* The phy_addr must be aligned to 4KB */
|
||||
static inline void set_pgsection(u32 *page_table, u32 index, u64 phy_addr,
|
||||
u32 memory_type)
|
||||
{
|
||||
u64 value;
|
||||
|
||||
value = phy_addr | PMD_TYPE_SECT | PMD_SECT_AF;
|
||||
value |= PMD_ATTRINDX(memory_type);
|
||||
page_table[2 * index] = value & 0xFFFFFFFF;
|
||||
page_table[2 * index + 1] = (value >> 32) & 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
/*
|
||||
* Start MMU after DDR is available, we create MMU table in DRAM.
|
||||
* The base address of TTLB is gd->arch.tlb_addr. We use two
|
||||
* levels of translation tables here to cover 40-bit address space.
|
||||
*
|
||||
* The TTLBs are located at PHY 2G~4G.
|
||||
*
|
||||
* VA mapping:
|
||||
*
|
||||
* ------- <---- 0GB
|
||||
* | |
|
||||
* | |
|
||||
* |-------| <---- 0x24000000
|
||||
* |///////| ===> 192MB VA map for PCIe1 with offset 0x40_0000_0000
|
||||
* |-------| <---- 0x300000000
|
||||
* | |
|
||||
* |-------| <---- 0x34000000
|
||||
* |///////| ===> 192MB VA map for PCIe2 with offset 0x48_0000_0000
|
||||
* |-------| <---- 0x40000000
|
||||
* | |
|
||||
* |-------| <---- 0x80000000 DDR0 space start
|
||||
* |\\\\\\\|
|
||||
*.|\\\\\\\| ===> 2GB VA map for 2GB DDR0 Memory space
|
||||
* |\\\\\\\|
|
||||
* ------- <---- 4GB DDR0 space end
|
||||
*/
|
||||
static void mmu_setup(void)
|
||||
{
|
||||
u32 *level0_table = (u32 *)gd->arch.tlb_addr;
|
||||
u32 *level1_table = (u32 *)(gd->arch.tlb_addr + 0x1000);
|
||||
u64 va_start = 0;
|
||||
u32 reg;
|
||||
int i;
|
||||
|
||||
/* Level 0 Table 2-3 are used to map DDR */
|
||||
set_pgsection(level0_table, 3, 3 * BLOCK_SIZE_L1, MT_NORMAL);
|
||||
set_pgsection(level0_table, 2, 2 * BLOCK_SIZE_L1, MT_NORMAL);
|
||||
/* Level 0 Table 1 is used to map device */
|
||||
set_pgsection(level0_table, 1, 1 * BLOCK_SIZE_L1, MT_DEVICE_MEM);
|
||||
/* Level 0 Table 0 is used to map device including PCIe MEM */
|
||||
set_pgtable(level0_table, 0, (u32)level1_table);
|
||||
|
||||
/* Level 1 has 512 entries */
|
||||
for (i = 0; i < 512; i++) {
|
||||
/* Mapping for PCIe 1 */
|
||||
if (va_start >= CONFIG_SYS_PCIE1_VIRT_ADDR &&
|
||||
va_start < (CONFIG_SYS_PCIE1_VIRT_ADDR +
|
||||
CONFIG_SYS_PCIE_MMAP_SIZE))
|
||||
set_pgsection(level1_table, i,
|
||||
CONFIG_SYS_PCIE1_PHYS_BASE + va_start,
|
||||
MT_DEVICE_MEM);
|
||||
/* Mapping for PCIe 2 */
|
||||
else if (va_start >= CONFIG_SYS_PCIE2_VIRT_ADDR &&
|
||||
va_start < (CONFIG_SYS_PCIE2_VIRT_ADDR +
|
||||
CONFIG_SYS_PCIE_MMAP_SIZE))
|
||||
set_pgsection(level1_table, i,
|
||||
CONFIG_SYS_PCIE2_PHYS_BASE + va_start,
|
||||
MT_DEVICE_MEM);
|
||||
else
|
||||
set_pgsection(level1_table, i,
|
||||
va_start,
|
||||
MT_DEVICE_MEM);
|
||||
va_start += BLOCK_SIZE_L2;
|
||||
}
|
||||
|
||||
asm volatile("dsb sy;isb");
|
||||
asm volatile("mcr p15, 0, %0, c2, c0, 2" /* Write RT to TTBCR */
|
||||
: : "r" (TTBCR) : "memory");
|
||||
asm volatile("mcrr p15, 0, %0, %1, c2" /* TTBR 0 */
|
||||
: : "r" ((u32)level0_table), "r" (0) : "memory");
|
||||
asm volatile("mcr p15, 0, %0, c10, c2, 0" /* write MAIR 0 */
|
||||
: : "r" (MT_MAIR0) : "memory");
|
||||
asm volatile("mcr p15, 0, %0, c10, c2, 1" /* write MAIR 1 */
|
||||
: : "r" (MT_MAIR1) : "memory");
|
||||
|
||||
/* Set the access control to all-supervisor */
|
||||
asm volatile("mcr p15, 0, %0, c3, c0, 0"
|
||||
: : "r" (~0));
|
||||
|
||||
/* Enable the mmu */
|
||||
reg = get_cr();
|
||||
set_cr(reg | CR_M);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called from lib/board.c. It recreates MMU
|
||||
* table in main memory. MMU and i/d-cache are enabled here.
|
||||
*/
|
||||
void enable_caches(void)
|
||||
{
|
||||
/* Invalidate all TLB */
|
||||
mmu_page_table_flush(gd->arch.tlb_addr,
|
||||
gd->arch.tlb_addr + gd->arch.tlb_size);
|
||||
/* Set up and enable mmu */
|
||||
mmu_setup();
|
||||
|
||||
/* Invalidate & Enable d-cache */
|
||||
invalidate_dcache_all();
|
||||
set_cr(get_cr() | CR_C);
|
||||
}
|
||||
#endif /* #ifndef CONFIG_SYS_DCACHE_OFF */
|
||||
|
||||
|
||||
uint get_svr(void)
|
||||
{
|
||||
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
|
||||
return in_be32(&gur->svr);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_DISPLAY_CPUINFO)
|
||||
int print_cpuinfo(void)
|
||||
{
|
||||
char buf1[32], buf2[32];
|
||||
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
unsigned int svr, major, minor, ver, i;
|
||||
|
||||
svr = in_be32(&gur->svr);
|
||||
major = SVR_MAJ(svr);
|
||||
minor = SVR_MIN(svr);
|
||||
|
||||
puts("CPU: Freescale LayerScape ");
|
||||
|
||||
ver = SVR_SOC_VER(svr);
|
||||
switch (ver) {
|
||||
case SOC_VER_SLS1020:
|
||||
puts("SLS1020");
|
||||
break;
|
||||
case SOC_VER_LS1020:
|
||||
puts("LS1020");
|
||||
break;
|
||||
case SOC_VER_LS1021:
|
||||
puts("LS1021");
|
||||
break;
|
||||
case SOC_VER_LS1022:
|
||||
puts("LS1022");
|
||||
break;
|
||||
default:
|
||||
puts("Unknown");
|
||||
break;
|
||||
}
|
||||
|
||||
if (IS_E_PROCESSOR(svr) && (ver != SOC_VER_SLS1020))
|
||||
puts("E");
|
||||
|
||||
printf(", Version: %d.%d, (0x%08x)\n", major, minor, svr);
|
||||
|
||||
puts("Clock Configuration:");
|
||||
|
||||
printf("\n CPU0(ARMV7):%-4s MHz, ", strmhz(buf1, gd->cpu_clk));
|
||||
printf("\n Bus:%-4s MHz, ", strmhz(buf1, gd->bus_clk));
|
||||
printf("DDR:%-4s MHz (%s MT/s data rate), ",
|
||||
strmhz(buf1, gd->mem_clk/2), strmhz(buf2, gd->mem_clk));
|
||||
puts("\n");
|
||||
|
||||
/* Display the RCW, so that no one gets confused as to what RCW
|
||||
* we're actually using for this boot.
|
||||
*/
|
||||
puts("Reset Configuration Word (RCW):");
|
||||
for (i = 0; i < ARRAY_SIZE(gur->rcwsr); i++) {
|
||||
u32 rcw = in_be32(&gur->rcwsr[i]);
|
||||
|
||||
if ((i % 4) == 0)
|
||||
printf("\n %08x:", i * 4);
|
||||
printf(" %08x", rcw);
|
||||
}
|
||||
puts("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FSL_ESDHC
|
||||
int cpu_mmc_init(bd_t *bis)
|
||||
{
|
||||
return fsl_esdhc_mmc_init(bis);
|
||||
}
|
||||
#endif
|
||||
|
||||
int cpu_eth_init(bd_t *bis)
|
||||
{
|
||||
#ifdef CONFIG_TSEC_ENET
|
||||
tsec_standard_init(bis);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arch_cpu_init(void)
|
||||
{
|
||||
void *epu_base = (void *)(CONFIG_SYS_DCSRBAR + EPU_BLOCK_OFFSET);
|
||||
void *rcpm2_base =
|
||||
(void *)(CONFIG_SYS_DCSRBAR + DCSR_RCPM2_BLOCK_OFFSET);
|
||||
struct ccsr_scfg *scfg = (void *)CONFIG_SYS_FSL_SCFG_ADDR;
|
||||
u32 state;
|
||||
|
||||
/*
|
||||
* The RCPM FSM state may not be reset after power-on.
|
||||
* So, reset them.
|
||||
*/
|
||||
state = in_be32(rcpm2_base + DCSR_RCPM2_CPMFSMSR0) &
|
||||
CPMFSMSR_FSM_STATE_MASK;
|
||||
if (state != 0) {
|
||||
out_be32(rcpm2_base + DCSR_RCPM2_CPMFSMCR0, 0x80);
|
||||
out_be32(rcpm2_base + DCSR_RCPM2_CPMFSMCR0, 0x0);
|
||||
}
|
||||
|
||||
state = in_be32(rcpm2_base + DCSR_RCPM2_CPMFSMSR1) &
|
||||
CPMFSMSR_FSM_STATE_MASK;
|
||||
if (state != 0) {
|
||||
out_be32(rcpm2_base + DCSR_RCPM2_CPMFSMCR1, 0x80);
|
||||
out_be32(rcpm2_base + DCSR_RCPM2_CPMFSMCR1, 0x0);
|
||||
}
|
||||
|
||||
/*
|
||||
* After wakeup from deep sleep, Clear EPU registers
|
||||
* as early as possible to prevent from possible issue.
|
||||
* It's also safe to clear at normal boot.
|
||||
*/
|
||||
fsl_epu_clean(epu_base);
|
||||
|
||||
setbits_be32(&scfg->snpcnfgcr, SCFG_SNPCNFGCR_SEC_RD_WR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARMV7_NONSEC
|
||||
/* Set the address at which the secondary core starts from.*/
|
||||
void smp_set_core_boot_addr(unsigned long addr, int corenr)
|
||||
{
|
||||
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
|
||||
out_be32(&gur->scratchrw[0], addr);
|
||||
}
|
||||
|
||||
/* Release the secondary core from holdoff state and kick it */
|
||||
void smp_kick_all_cpus(void)
|
||||
{
|
||||
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
|
||||
out_be32(&gur->brrl, 0x2);
|
||||
|
||||
/*
|
||||
* LS1 STANDBYWFE is not captured outside the ARM module in the soc.
|
||||
* So add a delay to wait bootrom execute WFE.
|
||||
*/
|
||||
udelay(1);
|
||||
|
||||
asm volatile("sev");
|
||||
}
|
||||
#endif
|
||||
|
||||
void reset_cpu(ulong addr)
|
||||
{
|
||||
struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
|
||||
|
||||
clrbits_be16(&wdog->wcr, WCR_SRS);
|
||||
|
||||
while (1) {
|
||||
/*
|
||||
* Let the watchdog trigger
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
void arch_preboot_os(void)
|
||||
{
|
||||
unsigned long ctrl;
|
||||
|
||||
/* Disable PL1 Physical Timer */
|
||||
asm("mrc p15, 0, %0, c14, c2, 1" : "=r" (ctrl));
|
||||
ctrl &= ~ARCH_TIMER_CTRL_ENABLE;
|
||||
asm("mcr p15, 0, %0, c14, c2, 1" : : "r" (ctrl));
|
||||
}
|
||||
182
u-boot/arch/arm/cpu/armv7/ls102xa/fdt.c
Normal file
182
u-boot/arch/arm/cpu/armv7/ls102xa/fdt.c
Normal file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright 2014 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <libfdt.h>
|
||||
#include <fdt_support.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <linux/ctype.h>
|
||||
#ifdef CONFIG_FSL_ESDHC
|
||||
#include <fsl_esdhc.h>
|
||||
#endif
|
||||
#include <tsec.h>
|
||||
#include <asm/arch/immap_ls102xa.h>
|
||||
#include <fsl_sec.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
void ft_fixup_enet_phy_connect_type(void *fdt)
|
||||
{
|
||||
struct eth_device *dev;
|
||||
struct tsec_private *priv;
|
||||
const char *enet_path, *phy_path;
|
||||
char enet[16];
|
||||
char phy[16];
|
||||
int phy_node;
|
||||
int i = 0;
|
||||
uint32_t ph;
|
||||
char *name[3] = { "eTSEC1", "eTSEC2", "eTSEC3" };
|
||||
|
||||
for (; i < ARRAY_SIZE(name); i++) {
|
||||
dev = eth_get_dev_by_name(name[i]);
|
||||
if (dev) {
|
||||
sprintf(enet, "ethernet%d", i);
|
||||
sprintf(phy, "enet%d_rgmii_phy", i);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
priv = dev->priv;
|
||||
if (priv->flags & TSEC_SGMII)
|
||||
continue;
|
||||
|
||||
enet_path = fdt_get_alias(fdt, enet);
|
||||
if (!enet_path)
|
||||
continue;
|
||||
|
||||
phy_path = fdt_get_alias(fdt, phy);
|
||||
if (!phy_path)
|
||||
continue;
|
||||
|
||||
phy_node = fdt_path_offset(fdt, phy_path);
|
||||
if (phy_node < 0)
|
||||
continue;
|
||||
|
||||
ph = fdt_create_phandle(fdt, phy_node);
|
||||
if (ph)
|
||||
do_fixup_by_path_u32(fdt, enet_path,
|
||||
"phy-handle", ph, 1);
|
||||
|
||||
do_fixup_by_path(fdt, enet_path, "phy-connection-type",
|
||||
phy_string_for_interface(
|
||||
PHY_INTERFACE_MODE_RGMII_ID),
|
||||
sizeof(phy_string_for_interface(
|
||||
PHY_INTERFACE_MODE_RGMII_ID)),
|
||||
1);
|
||||
}
|
||||
}
|
||||
|
||||
void ft_cpu_setup(void *blob, bd_t *bd)
|
||||
{
|
||||
int off;
|
||||
int val;
|
||||
const char *sysclk_path;
|
||||
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
unsigned int svr;
|
||||
svr = in_be32(&gur->svr);
|
||||
|
||||
unsigned long busclk = get_bus_freq(0);
|
||||
|
||||
/* delete crypto node if not on an E-processor */
|
||||
if (!IS_E_PROCESSOR(svr))
|
||||
fdt_fixup_crypto_node(blob, 0);
|
||||
#if CONFIG_SYS_FSL_SEC_COMPAT >= 4
|
||||
else {
|
||||
ccsr_sec_t __iomem *sec;
|
||||
|
||||
sec = (void __iomem *)CONFIG_SYS_FSL_SEC_ADDR;
|
||||
fdt_fixup_crypto_node(blob, sec_in32(&sec->secvid_ms));
|
||||
}
|
||||
#endif
|
||||
|
||||
fdt_fixup_ethernet(blob);
|
||||
|
||||
off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4);
|
||||
while (off != -FDT_ERR_NOTFOUND) {
|
||||
val = gd->cpu_clk;
|
||||
fdt_setprop(blob, off, "clock-frequency", &val, 4);
|
||||
off = fdt_node_offset_by_prop_value(blob, off,
|
||||
"device_type", "cpu", 4);
|
||||
}
|
||||
|
||||
do_fixup_by_prop_u32(blob, "device_type", "soc",
|
||||
4, "bus-frequency", busclk, 1);
|
||||
|
||||
ft_fixup_enet_phy_connect_type(blob);
|
||||
|
||||
#ifdef CONFIG_SYS_NS16550
|
||||
do_fixup_by_compat_u32(blob, "fsl,16550-FIFO64",
|
||||
"clock-frequency", CONFIG_SYS_NS16550_CLK, 1);
|
||||
#endif
|
||||
|
||||
sysclk_path = fdt_get_alias(blob, "sysclk");
|
||||
if (sysclk_path)
|
||||
do_fixup_by_path_u32(blob, sysclk_path, "clock-frequency",
|
||||
CONFIG_SYS_CLK_FREQ, 1);
|
||||
do_fixup_by_compat_u32(blob, "fsl,qoriq-sysclk-2.0",
|
||||
"clock-frequency", CONFIG_SYS_CLK_FREQ, 1);
|
||||
|
||||
#if defined(CONFIG_DEEP_SLEEP) && defined(CONFIG_SD_BOOT)
|
||||
#define UBOOT_HEAD_LEN 0x1000
|
||||
/*
|
||||
* Reserved memory in SD boot deep sleep case.
|
||||
* Second stage uboot binary and malloc space should be reserved.
|
||||
* If the memory they occupied has not been reserved, then this
|
||||
* space would be used by kernel and overwritten in uboot when
|
||||
* deep sleep resume, which cause deep sleep failed.
|
||||
* Since second uboot binary has a head, that space need to be
|
||||
* reserved either(assuming its size is less than 0x1000).
|
||||
*/
|
||||
off = fdt_add_mem_rsv(blob, CONFIG_SYS_TEXT_BASE - UBOOT_HEAD_LEN,
|
||||
CONFIG_SYS_MONITOR_LEN + CONFIG_SYS_SPL_MALLOC_SIZE +
|
||||
UBOOT_HEAD_LEN);
|
||||
if (off < 0)
|
||||
printf("Failed to reserve memory for SD boot deep sleep: %s\n",
|
||||
fdt_strerror(off));
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_FSL_ESDHC)
|
||||
fdt_fixup_esdhc(blob, bd);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* platform bus clock = system bus clock/2
|
||||
* Here busclk = system bus clock
|
||||
* We are using the platform bus clock as 1588 Timer reference
|
||||
* clock source select
|
||||
*/
|
||||
do_fixup_by_compat_u32(blob, "fsl, gianfar-ptp-timer",
|
||||
"timer-frequency", busclk / 2, 1);
|
||||
|
||||
/*
|
||||
* clock-freq should change to clock-frequency and
|
||||
* flexcan-v1.0 should change to p1010-flexcan respectively
|
||||
* in the future.
|
||||
*/
|
||||
do_fixup_by_compat_u32(blob, "fsl, flexcan-v1.0",
|
||||
"clock_freq", busclk / 2, 1);
|
||||
|
||||
do_fixup_by_compat_u32(blob, "fsl, flexcan-v1.0",
|
||||
"clock-frequency", busclk / 2, 1);
|
||||
|
||||
do_fixup_by_compat_u32(blob, "fsl, ls1021a-flexcan",
|
||||
"clock-frequency", busclk / 2, 1);
|
||||
|
||||
#if defined(CONFIG_QSPI_BOOT) || defined(CONFIG_SD_BOOT_QSPI)
|
||||
off = fdt_node_offset_by_compat_reg(blob, FSL_IFC_COMPAT,
|
||||
CONFIG_SYS_IFC_ADDR);
|
||||
fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0);
|
||||
#else
|
||||
off = fdt_node_offset_by_compat_reg(blob, FSL_QSPI_COMPAT,
|
||||
QSPI0_BASE_ADDR);
|
||||
fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0);
|
||||
off = fdt_node_offset_by_compat_reg(blob, FSL_DSPI_COMPAT,
|
||||
DSPI1_BASE_ADDR);
|
||||
fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0);
|
||||
#endif
|
||||
}
|
||||
57
u-boot/arch/arm/cpu/armv7/ls102xa/fsl_epu.c
Normal file
57
u-boot/arch/arm/cpu/armv7/ls102xa/fsl_epu.c
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2014 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "fsl_epu.h"
|
||||
|
||||
/**
|
||||
* fsl_epu_clean - Clear EPU registers
|
||||
*/
|
||||
void fsl_epu_clean(void *epu_base)
|
||||
{
|
||||
u32 offset;
|
||||
|
||||
/* follow the exact sequence to clear the registers */
|
||||
/* Clear EPACRn */
|
||||
for (offset = EPACR0; offset <= EPACR15; offset += EPACR_STRIDE)
|
||||
out_be32(epu_base + offset, 0);
|
||||
|
||||
/* Clear EPEVTCRn */
|
||||
for (offset = EPEVTCR0; offset <= EPEVTCR9; offset += EPEVTCR_STRIDE)
|
||||
out_be32(epu_base + offset, 0);
|
||||
|
||||
/* Clear EPGCR */
|
||||
out_be32(epu_base + EPGCR, 0);
|
||||
|
||||
/* Clear EPSMCRn */
|
||||
for (offset = EPSMCR0; offset <= EPSMCR15; offset += EPSMCR_STRIDE)
|
||||
out_be32(epu_base + offset, 0);
|
||||
|
||||
/* Clear EPCCRn */
|
||||
for (offset = EPCCR0; offset <= EPCCR31; offset += EPCCR_STRIDE)
|
||||
out_be32(epu_base + offset, 0);
|
||||
|
||||
/* Clear EPCMPRn */
|
||||
for (offset = EPCMPR0; offset <= EPCMPR31; offset += EPCMPR_STRIDE)
|
||||
out_be32(epu_base + offset, 0);
|
||||
|
||||
/* Clear EPCTRn */
|
||||
for (offset = EPCTR0; offset <= EPCTR31; offset += EPCTR_STRIDE)
|
||||
out_be32(epu_base + offset, 0);
|
||||
|
||||
/* Clear EPIMCRn */
|
||||
for (offset = EPIMCR0; offset <= EPIMCR31; offset += EPIMCR_STRIDE)
|
||||
out_be32(epu_base + offset, 0);
|
||||
|
||||
/* Clear EPXTRIGCRn */
|
||||
out_be32(epu_base + EPXTRIGCR, 0);
|
||||
|
||||
/* Clear EPECRn */
|
||||
for (offset = EPECR0; offset <= EPECR15; offset += EPECR_STRIDE)
|
||||
out_be32(epu_base + offset, 0);
|
||||
}
|
||||
68
u-boot/arch/arm/cpu/armv7/ls102xa/fsl_epu.h
Normal file
68
u-boot/arch/arm/cpu/armv7/ls102xa/fsl_epu.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2014 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef __FSL_EPU_H
|
||||
#define __FSL_EPU_H
|
||||
|
||||
#include <asm/types.h>
|
||||
|
||||
#define FSL_STRIDE_4B 4
|
||||
#define FSL_STRIDE_8B 8
|
||||
|
||||
/* Block offsets */
|
||||
#define EPU_BLOCK_OFFSET 0x00000000
|
||||
|
||||
/* EPGCR (Event Processor Global Control Register) */
|
||||
#define EPGCR 0x000
|
||||
|
||||
/* EPEVTCR0-9 (Event Processor EVT Pin Control Registers) */
|
||||
#define EPEVTCR0 0x050
|
||||
#define EPEVTCR9 0x074
|
||||
#define EPEVTCR_STRIDE FSL_STRIDE_4B
|
||||
|
||||
/* EPXTRIGCR (Event Processor Crosstrigger Control Register) */
|
||||
#define EPXTRIGCR 0x090
|
||||
|
||||
/* EPIMCR0-31 (Event Processor Input Mux Control Registers) */
|
||||
#define EPIMCR0 0x100
|
||||
#define EPIMCR31 0x17C
|
||||
#define EPIMCR_STRIDE FSL_STRIDE_4B
|
||||
|
||||
/* EPSMCR0-15 (Event Processor SCU Mux Control Registers) */
|
||||
#define EPSMCR0 0x200
|
||||
#define EPSMCR15 0x278
|
||||
#define EPSMCR_STRIDE FSL_STRIDE_8B
|
||||
|
||||
/* EPECR0-15 (Event Processor Event Control Registers) */
|
||||
#define EPECR0 0x300
|
||||
#define EPECR15 0x33C
|
||||
#define EPECR_STRIDE FSL_STRIDE_4B
|
||||
|
||||
/* EPACR0-15 (Event Processor Action Control Registers) */
|
||||
#define EPACR0 0x400
|
||||
#define EPACR15 0x43C
|
||||
#define EPACR_STRIDE FSL_STRIDE_4B
|
||||
|
||||
/* EPCCRi0-15 (Event Processor Counter Control Registers) */
|
||||
#define EPCCR0 0x800
|
||||
#define EPCCR15 0x83C
|
||||
#define EPCCR31 0x87C
|
||||
#define EPCCR_STRIDE FSL_STRIDE_4B
|
||||
|
||||
/* EPCMPR0-15 (Event Processor Counter Compare Registers) */
|
||||
#define EPCMPR0 0x900
|
||||
#define EPCMPR15 0x93C
|
||||
#define EPCMPR31 0x97C
|
||||
#define EPCMPR_STRIDE FSL_STRIDE_4B
|
||||
|
||||
/* EPCTR0-31 (Event Processor Counter Register) */
|
||||
#define EPCTR0 0xA00
|
||||
#define EPCTR31 0xA7C
|
||||
#define EPCTR_STRIDE FSL_STRIDE_4B
|
||||
|
||||
void fsl_epu_clean(void *epu_base);
|
||||
|
||||
#endif
|
||||
120
u-boot/arch/arm/cpu/armv7/ls102xa/fsl_ls1_serdes.c
Normal file
120
u-boot/arch/arm/cpu/armv7/ls102xa/fsl_ls1_serdes.c
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2014 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch/fsl_serdes.h>
|
||||
#include <asm/arch/immap_ls102xa.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/io.h>
|
||||
#include "fsl_ls1_serdes.h"
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
static u64 serdes1_prtcl_map;
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
static u64 serdes2_prtcl_map;
|
||||
#endif
|
||||
|
||||
int is_serdes_configured(enum srds_prtcl device)
|
||||
{
|
||||
u64 ret = 0;
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
ret |= (1ULL << device) & serdes1_prtcl_map;
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
ret |= (1ULL << device) & serdes2_prtcl_map;
|
||||
#endif
|
||||
|
||||
return !!ret;
|
||||
}
|
||||
|
||||
int serdes_get_first_lane(u32 sd, enum srds_prtcl device)
|
||||
{
|
||||
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
u32 cfg = in_be32(&gur->rcwsr[4]);
|
||||
int i;
|
||||
|
||||
switch (sd) {
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
case FSL_SRDS_1:
|
||||
cfg &= RCWSR4_SRDS1_PRTCL_MASK;
|
||||
cfg >>= RCWSR4_SRDS1_PRTCL_SHIFT;
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
case FSL_SRDS_2:
|
||||
cfg &= RCWSR4_SRDS2_PRTCL_MASK;
|
||||
cfg >>= RCWSR4_SRDS2_PRTCL_SHIFT;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
printf("invalid SerDes%d\n", sd);
|
||||
break;
|
||||
}
|
||||
/* Is serdes enabled at all? */
|
||||
if (unlikely(cfg == 0))
|
||||
return -ENODEV;
|
||||
|
||||
for (i = 0; i < SRDS_MAX_LANES; i++) {
|
||||
if (serdes_get_prtcl(sd, cfg, i) == device)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
u64 serdes_init(u32 sd, u32 sd_addr, u32 sd_prctl_mask, u32 sd_prctl_shift)
|
||||
{
|
||||
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
u64 serdes_prtcl_map = 0;
|
||||
u32 cfg;
|
||||
int lane;
|
||||
|
||||
cfg = in_be32(&gur->rcwsr[4]) & sd_prctl_mask;
|
||||
cfg >>= sd_prctl_shift;
|
||||
printf("Using SERDES%d Protocol: %d (0x%x)\n", sd + 1, cfg, cfg);
|
||||
|
||||
if (!is_serdes_prtcl_valid(sd, cfg))
|
||||
printf("SERDES%d[PRTCL] = 0x%x is not valid\n", sd + 1, cfg);
|
||||
|
||||
for (lane = 0; lane < SRDS_MAX_LANES; lane++) {
|
||||
enum srds_prtcl lane_prtcl = serdes_get_prtcl(sd, cfg, lane);
|
||||
|
||||
serdes_prtcl_map |= (1ULL << lane_prtcl);
|
||||
}
|
||||
|
||||
return serdes_prtcl_map;
|
||||
}
|
||||
|
||||
void fsl_serdes_init(void)
|
||||
{
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_1
|
||||
serdes1_prtcl_map = serdes_init(FSL_SRDS_1,
|
||||
CONFIG_SYS_FSL_SERDES_ADDR,
|
||||
RCWSR4_SRDS1_PRTCL_MASK,
|
||||
RCWSR4_SRDS1_PRTCL_SHIFT);
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_FSL_SRDS_2
|
||||
serdes2_prtcl_map = serdes_init(FSL_SRDS_2,
|
||||
CONFIG_SYS_FSL_SERDES_ADDR +
|
||||
FSL_SRDS_2 * 0x1000,
|
||||
RCWSR4_SRDS2_PRTCL_MASK,
|
||||
RCWSR4_SRDS2_PRTCL_SHIFT);
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *serdes_clock_to_string(u32 clock)
|
||||
{
|
||||
switch (clock) {
|
||||
case SRDS_PLLCR0_RFCK_SEL_100:
|
||||
return "100";
|
||||
case SRDS_PLLCR0_RFCK_SEL_125:
|
||||
return "125";
|
||||
default:
|
||||
return "100";
|
||||
}
|
||||
}
|
||||
12
u-boot/arch/arm/cpu/armv7/ls102xa/fsl_ls1_serdes.h
Normal file
12
u-boot/arch/arm/cpu/armv7/ls102xa/fsl_ls1_serdes.h
Normal file
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright 2014 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef __FSL_LS1_SERDES_H
|
||||
#define __FSL_LS1_SERDES_H
|
||||
|
||||
int is_serdes_prtcl_valid(int serdes, u32 prtcl);
|
||||
int serdes_lane_enabled(int lane);
|
||||
#endif /* __FSL_LS1_SERDES_H */
|
||||
42
u-boot/arch/arm/cpu/armv7/ls102xa/ls102xa_sata.c
Normal file
42
u-boot/arch/arm/cpu/armv7/ls102xa/ls102xa_sata.c
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2015 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/immap_ls102xa.h>
|
||||
#include <ahci.h>
|
||||
#include <scsi.h>
|
||||
|
||||
/* port register default value */
|
||||
#define AHCI_PORT_PHY_1_CFG 0xa003fffe
|
||||
#define AHCI_PORT_PHY_2_CFG 0x28183414
|
||||
#define AHCI_PORT_PHY_3_CFG 0x0e080e06
|
||||
#define AHCI_PORT_PHY_4_CFG 0x064a080b
|
||||
#define AHCI_PORT_PHY_5_CFG 0x2aa86470
|
||||
#define AHCI_PORT_TRANS_CFG 0x08000029
|
||||
|
||||
#define SATA_ECC_REG_ADDR 0x20220520
|
||||
#define SATA_ECC_DISABLE 0x00020000
|
||||
|
||||
int ls1021a_sata_init(void)
|
||||
{
|
||||
struct ccsr_ahci __iomem *ccsr_ahci = (void *)AHCI_BASE_ADDR;
|
||||
|
||||
#ifdef CONFIG_SYS_FSL_ERRATUM_A008407
|
||||
out_le32((void *)SATA_ECC_REG_ADDR, SATA_ECC_DISABLE);
|
||||
#endif
|
||||
|
||||
out_le32(&ccsr_ahci->ppcfg, AHCI_PORT_PHY_1_CFG);
|
||||
out_le32(&ccsr_ahci->pp2c, AHCI_PORT_PHY_2_CFG);
|
||||
out_le32(&ccsr_ahci->pp3c, AHCI_PORT_PHY_3_CFG);
|
||||
out_le32(&ccsr_ahci->pp4c, AHCI_PORT_PHY_4_CFG);
|
||||
out_le32(&ccsr_ahci->pp5c, AHCI_PORT_PHY_5_CFG);
|
||||
out_le32(&ccsr_ahci->ptc, AHCI_PORT_TRANS_CFG);
|
||||
|
||||
ahci_init((void __iomem *)AHCI_BASE_ADDR);
|
||||
scsi_scan(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
41
u-boot/arch/arm/cpu/armv7/ls102xa/ls102xa_serdes.c
Normal file
41
u-boot/arch/arm/cpu/armv7/ls102xa/ls102xa_serdes.c
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2014 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch/fsl_serdes.h>
|
||||
#include <asm/arch/immap_ls102xa.h>
|
||||
|
||||
static u8 serdes_cfg_tbl[][SRDS_MAX_LANES] = {
|
||||
[0x00] = {PCIE1, PCIE1, PCIE1, PCIE1},
|
||||
[0x10] = {PCIE1, SATA1, PCIE2, PCIE2},
|
||||
[0x20] = {PCIE1, SGMII_TSEC1, PCIE2, SGMII_TSEC2},
|
||||
[0x30] = {PCIE1, SATA1, SGMII_TSEC1, SGMII_TSEC2},
|
||||
[0x40] = {PCIE1, PCIE1, SATA1, SGMII_TSEC2},
|
||||
[0x50] = {PCIE1, PCIE1, PCIE2, SGMII_TSEC2},
|
||||
[0x60] = {PCIE1, PCIE1, SGMII_TSEC1, SGMII_TSEC2},
|
||||
[0x70] = {PCIE1, SATA1, PCIE2, SGMII_TSEC2},
|
||||
[0x80] = {PCIE2, PCIE2, PCIE2, PCIE2},
|
||||
};
|
||||
|
||||
enum srds_prtcl serdes_get_prtcl(int serdes, int cfg, int lane)
|
||||
{
|
||||
return serdes_cfg_tbl[cfg][lane];
|
||||
}
|
||||
|
||||
int is_serdes_prtcl_valid(int serdes, u32 prtcl)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (prtcl >= ARRAY_SIZE(serdes_cfg_tbl))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < SRDS_MAX_LANES; i++) {
|
||||
if (serdes_cfg_tbl[prtcl][i] != NONE)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
126
u-boot/arch/arm/cpu/armv7/ls102xa/psci.S
Normal file
126
u-boot/arch/arm/cpu/armv7/ls102xa/psci.S
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright 2015 Freescale Semiconductor, Inc.
|
||||
* Author: Wang Dongsheng <dongsheng.wang@freescale.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <linux/linkage.h>
|
||||
|
||||
#include <asm/armv7.h>
|
||||
#include <asm/arch-armv7/generictimer.h>
|
||||
#include <asm/psci.h>
|
||||
|
||||
#define SCFG_CORE0_SFT_RST 0x130
|
||||
#define SCFG_CORESRENCR 0x204
|
||||
|
||||
#define DCFG_CCSR_BRR 0x0E4
|
||||
#define DCFG_CCSR_SCRATCHRW1 0x200
|
||||
|
||||
.pushsection ._secure.text, "ax"
|
||||
|
||||
.arch_extension sec
|
||||
|
||||
#define ONE_MS (GENERIC_TIMER_CLK / 1000)
|
||||
#define RESET_WAIT (30 * ONE_MS)
|
||||
|
||||
@ r1 = target CPU
|
||||
@ r2 = target PC
|
||||
.globl psci_cpu_on
|
||||
psci_cpu_on:
|
||||
push {lr}
|
||||
|
||||
@ Clear and Get the correct CPU number
|
||||
@ r1 = 0xf01
|
||||
and r1, r1, #0xff
|
||||
|
||||
mov r0, r1
|
||||
bl psci_get_cpu_stack_top
|
||||
str r2, [r0]
|
||||
dsb
|
||||
|
||||
@ Get DCFG base address
|
||||
movw r4, #(CONFIG_SYS_FSL_GUTS_ADDR & 0xffff)
|
||||
movt r4, #(CONFIG_SYS_FSL_GUTS_ADDR >> 16)
|
||||
|
||||
@ Detect target CPU state
|
||||
ldr r2, [r4, #DCFG_CCSR_BRR]
|
||||
rev r2, r2
|
||||
lsr r2, r2, r1
|
||||
ands r2, r2, #1
|
||||
beq holdoff_release
|
||||
|
||||
@ Reset target CPU
|
||||
@ Get SCFG base address
|
||||
movw r0, #(CONFIG_SYS_FSL_SCFG_ADDR & 0xffff)
|
||||
movt r0, #(CONFIG_SYS_FSL_SCFG_ADDR >> 16)
|
||||
|
||||
@ Enable CORE Soft Reset
|
||||
movw r5, #0
|
||||
movt r5, #(1 << 15)
|
||||
rev r5, r5
|
||||
str r5, [r0, #SCFG_CORESRENCR]
|
||||
|
||||
@ Get CPUx offset register
|
||||
mov r6, #0x4
|
||||
mul r6, r6, r1
|
||||
add r2, r0, r6
|
||||
|
||||
@ Do reset on target CPU
|
||||
movw r5, #0
|
||||
movt r5, #(1 << 15)
|
||||
rev r5, r5
|
||||
str r5, [r2, #SCFG_CORE0_SFT_RST]
|
||||
|
||||
@ Wait target CPU up
|
||||
timer_wait r2, RESET_WAIT
|
||||
|
||||
@ Disable CORE soft reset
|
||||
mov r5, #0
|
||||
str r5, [r0, #SCFG_CORESRENCR]
|
||||
|
||||
holdoff_release:
|
||||
@ Release on target CPU
|
||||
ldr r2, [r4, #DCFG_CCSR_BRR]
|
||||
mov r6, #1
|
||||
lsl r6, r6, r1 @ 32 bytes per CPU
|
||||
|
||||
rev r6, r6
|
||||
orr r2, r2, r6
|
||||
str r2, [r4, #DCFG_CCSR_BRR]
|
||||
|
||||
@ Set secondary boot entry
|
||||
ldr r6, =psci_cpu_entry
|
||||
rev r6, r6
|
||||
str r6, [r4, #DCFG_CCSR_SCRATCHRW1]
|
||||
|
||||
isb
|
||||
dsb
|
||||
|
||||
@ Return
|
||||
mov r0, #ARM_PSCI_RET_SUCCESS
|
||||
|
||||
pop {lr}
|
||||
bx lr
|
||||
|
||||
.globl psci_cpu_off
|
||||
psci_cpu_off:
|
||||
bl psci_cpu_off_common
|
||||
|
||||
1: wfi
|
||||
b 1b
|
||||
|
||||
.globl psci_arch_init
|
||||
psci_arch_init:
|
||||
mov r6, lr
|
||||
|
||||
bl psci_get_cpu_id
|
||||
bl psci_get_cpu_stack_top
|
||||
mov sp, r0
|
||||
|
||||
bx r6
|
||||
|
||||
.globl psci_text_end
|
||||
psci_text_end:
|
||||
.popsection
|
||||
138
u-boot/arch/arm/cpu/armv7/ls102xa/soc.c
Normal file
138
u-boot/arch/arm/cpu/armv7/ls102xa/soc.c
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright 2015 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/immap_ls102xa.h>
|
||||
#include <asm/arch/ls102xa_soc.h>
|
||||
#include <asm/arch/ls102xa_stream_id.h>
|
||||
|
||||
struct liodn_id_table sec_liodn_tbl[] = {
|
||||
SET_SEC_JR_LIODN_ENTRY(0, 0x10, 0x10),
|
||||
SET_SEC_JR_LIODN_ENTRY(1, 0x10, 0x10),
|
||||
SET_SEC_JR_LIODN_ENTRY(2, 0x10, 0x10),
|
||||
SET_SEC_JR_LIODN_ENTRY(3, 0x10, 0x10),
|
||||
SET_SEC_RTIC_LIODN_ENTRY(a, 0x10),
|
||||
SET_SEC_RTIC_LIODN_ENTRY(b, 0x10),
|
||||
SET_SEC_RTIC_LIODN_ENTRY(c, 0x10),
|
||||
SET_SEC_RTIC_LIODN_ENTRY(d, 0x10),
|
||||
SET_SEC_DECO_LIODN_ENTRY(0, 0x10, 0x10),
|
||||
SET_SEC_DECO_LIODN_ENTRY(1, 0x10, 0x10),
|
||||
SET_SEC_DECO_LIODN_ENTRY(2, 0x10, 0x10),
|
||||
SET_SEC_DECO_LIODN_ENTRY(3, 0x10, 0x10),
|
||||
SET_SEC_DECO_LIODN_ENTRY(4, 0x10, 0x10),
|
||||
SET_SEC_DECO_LIODN_ENTRY(5, 0x10, 0x10),
|
||||
SET_SEC_DECO_LIODN_ENTRY(6, 0x10, 0x10),
|
||||
SET_SEC_DECO_LIODN_ENTRY(7, 0x10, 0x10),
|
||||
};
|
||||
|
||||
struct smmu_stream_id dev_stream_id[] = {
|
||||
{ 0x100, 0x01, "ETSEC MAC1" },
|
||||
{ 0x104, 0x02, "ETSEC MAC2" },
|
||||
{ 0x108, 0x03, "ETSEC MAC3" },
|
||||
{ 0x10c, 0x04, "PEX1" },
|
||||
{ 0x110, 0x05, "PEX2" },
|
||||
{ 0x114, 0x06, "qDMA" },
|
||||
{ 0x118, 0x07, "SATA" },
|
||||
{ 0x11c, 0x08, "USB3" },
|
||||
{ 0x120, 0x09, "QE" },
|
||||
{ 0x124, 0x0a, "eSDHC" },
|
||||
{ 0x128, 0x0b, "eMA" },
|
||||
{ 0x14c, 0x0c, "2D-ACE" },
|
||||
{ 0x150, 0x0d, "USB2" },
|
||||
{ 0x18c, 0x0e, "DEBUG" },
|
||||
};
|
||||
|
||||
unsigned int get_soc_major_rev(void)
|
||||
{
|
||||
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
|
||||
unsigned int svr, major;
|
||||
|
||||
svr = in_be32(&gur->svr);
|
||||
major = SVR_MAJ(svr);
|
||||
|
||||
return major;
|
||||
}
|
||||
|
||||
int arch_soc_init(void)
|
||||
{
|
||||
struct ccsr_scfg *scfg = (struct ccsr_scfg *)CONFIG_SYS_FSL_SCFG_ADDR;
|
||||
struct ccsr_cci400 *cci = (struct ccsr_cci400 *)CONFIG_SYS_CCI400_ADDR;
|
||||
unsigned int major;
|
||||
|
||||
#ifdef CONFIG_FSL_QSPI
|
||||
out_be32(&scfg->qspi_cfg, SCFG_QSPI_CLKSEL);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FSL_DCU_FB
|
||||
out_be32(&scfg->pixclkcr, SCFG_PIXCLKCR_PXCKEN);
|
||||
#endif
|
||||
|
||||
/* Configure Little endian for SAI, ASRC and SPDIF */
|
||||
out_be32(&scfg->endiancr, SCFG_ENDIANCR_LE);
|
||||
|
||||
/*
|
||||
* Enable snoop requests and DVM message requests for
|
||||
* All the slave insterfaces.
|
||||
*/
|
||||
out_le32(&cci->slave[0].snoop_ctrl,
|
||||
CCI400_DVM_MESSAGE_REQ_EN | CCI400_SNOOP_REQ_EN);
|
||||
out_le32(&cci->slave[1].snoop_ctrl,
|
||||
CCI400_DVM_MESSAGE_REQ_EN | CCI400_SNOOP_REQ_EN);
|
||||
out_le32(&cci->slave[2].snoop_ctrl,
|
||||
CCI400_DVM_MESSAGE_REQ_EN | CCI400_SNOOP_REQ_EN);
|
||||
out_le32(&cci->slave[4].snoop_ctrl,
|
||||
CCI400_DVM_MESSAGE_REQ_EN | CCI400_SNOOP_REQ_EN);
|
||||
|
||||
major = get_soc_major_rev();
|
||||
if (major == SOC_MAJOR_VER_1_0) {
|
||||
/*
|
||||
* Set CCI-400 Slave interface S1, S2 Shareable Override
|
||||
* Register All transactions are treated as non-shareable
|
||||
*/
|
||||
out_le32(&cci->slave[1].sha_ord, CCI400_SHAORD_NON_SHAREABLE);
|
||||
out_le32(&cci->slave[2].sha_ord, CCI400_SHAORD_NON_SHAREABLE);
|
||||
|
||||
/* Workaround for the issue that DDR could not respond to
|
||||
* barrier transaction which is generated by executing DSB/ISB
|
||||
* instruction. Set CCI-400 control override register to
|
||||
* terminate the barrier transaction. After DDR is initialized,
|
||||
* allow barrier transaction to DDR again */
|
||||
out_le32(&cci->ctrl_ord, CCI400_CTRLORD_TERM_BARRIER);
|
||||
}
|
||||
|
||||
/* Enable all the snoop signal for various masters */
|
||||
out_be32(&scfg->snpcnfgcr, SCFG_SNPCNFGCR_SEC_RD_WR |
|
||||
SCFG_SNPCNFGCR_DCU_RD_WR |
|
||||
SCFG_SNPCNFGCR_SATA_RD_WR |
|
||||
SCFG_SNPCNFGCR_USB3_RD_WR |
|
||||
SCFG_SNPCNFGCR_DBG_RD_WR |
|
||||
SCFG_SNPCNFGCR_EDMA_SNP);
|
||||
|
||||
/*
|
||||
* Memory controller require a register write before being enabled.
|
||||
* Affects: DDR
|
||||
* Register: EDDRTQCFG
|
||||
* Description: Memory controller performance is not optimal with
|
||||
* default internal target queue register values.
|
||||
* Workaround: Write a value of 63b2_0042h to address: 157_020Ch.
|
||||
*/
|
||||
out_be32(&scfg->eddrtqcfg, 0x63b20042);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ls102xa_smmu_stream_id_init(void)
|
||||
{
|
||||
ls1021x_config_caam_stream_id(sec_liodn_tbl,
|
||||
ARRAY_SIZE(sec_liodn_tbl));
|
||||
|
||||
ls102xa_config_smmu_stream_id(dev_stream_id,
|
||||
ARRAY_SIZE(dev_stream_id));
|
||||
|
||||
return 0;
|
||||
}
|
||||
33
u-boot/arch/arm/cpu/armv7/ls102xa/spl.c
Normal file
33
u-boot/arch/arm/cpu/armv7/ls102xa/spl.c
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2014 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <spl.h>
|
||||
|
||||
u32 spl_boot_device(void)
|
||||
{
|
||||
#ifdef CONFIG_SPL_MMC_SUPPORT
|
||||
return BOOT_DEVICE_MMC1;
|
||||
#endif
|
||||
return BOOT_DEVICE_NAND;
|
||||
}
|
||||
|
||||
u32 spl_boot_mode(const u32 boot_device)
|
||||
{
|
||||
switch (spl_boot_device()) {
|
||||
case BOOT_DEVICE_MMC1:
|
||||
#ifdef CONFIG_SPL_FAT_SUPPORT
|
||||
return MMCSD_MODE_FS;
|
||||
#else
|
||||
return MMCSD_MODE_RAW;
|
||||
#endif
|
||||
case BOOT_DEVICE_NAND:
|
||||
return 0;
|
||||
default:
|
||||
puts("spl: error: unsupported device\n");
|
||||
hang();
|
||||
}
|
||||
}
|
||||
128
u-boot/arch/arm/cpu/armv7/ls102xa/timer.c
Normal file
128
u-boot/arch/arm/cpu/armv7/ls102xa/timer.c
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2014 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <div64.h>
|
||||
#include <asm/arch/immap_ls102xa.h>
|
||||
#include <asm/arch/clock.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/*
|
||||
* This function is intended for SHORT delays only.
|
||||
* It will overflow at around 10 seconds @ 400MHz,
|
||||
* or 20 seconds @ 200MHz.
|
||||
*/
|
||||
unsigned long usec2ticks(unsigned long usec)
|
||||
{
|
||||
ulong ticks;
|
||||
|
||||
if (usec < 1000)
|
||||
ticks = ((usec * (get_tbclk()/1000)) + 500) / 1000;
|
||||
else
|
||||
ticks = ((usec / 10) * (get_tbclk() / 100000));
|
||||
|
||||
return ticks;
|
||||
}
|
||||
|
||||
static inline unsigned long long tick_to_time(unsigned long long tick)
|
||||
{
|
||||
unsigned long freq;
|
||||
|
||||
asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (freq));
|
||||
|
||||
tick *= CONFIG_SYS_HZ;
|
||||
do_div(tick, freq);
|
||||
|
||||
return tick;
|
||||
}
|
||||
|
||||
static inline unsigned long long us_to_tick(unsigned long long usec)
|
||||
{
|
||||
unsigned long freq;
|
||||
|
||||
asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (freq));
|
||||
|
||||
usec = usec * freq + 999999;
|
||||
do_div(usec, 1000000);
|
||||
|
||||
return usec;
|
||||
}
|
||||
|
||||
int timer_init(void)
|
||||
{
|
||||
struct sctr_regs *sctr = (struct sctr_regs *)SCTR_BASE_ADDR;
|
||||
unsigned long ctrl, freq;
|
||||
unsigned long long val;
|
||||
|
||||
/* Enable System Counter */
|
||||
writel(SYS_COUNTER_CTRL_ENABLE, &sctr->cntcr);
|
||||
|
||||
freq = GENERIC_TIMER_CLK;
|
||||
asm("mcr p15, 0, %0, c14, c0, 0" : : "r" (freq));
|
||||
|
||||
/* Set PL1 Physical Timer Ctrl */
|
||||
ctrl = ARCH_TIMER_CTRL_ENABLE;
|
||||
asm("mcr p15, 0, %0, c14, c2, 1" : : "r" (ctrl));
|
||||
|
||||
/* Set PL1 Physical Comp Value */
|
||||
val = TIMER_COMP_VAL;
|
||||
asm("mcrr p15, 2, %Q0, %R0, c14" : : "r" (val));
|
||||
|
||||
gd->arch.tbl = 0;
|
||||
gd->arch.tbu = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long long get_ticks(void)
|
||||
{
|
||||
unsigned long long now;
|
||||
|
||||
asm("mrrc p15, 0, %Q0, %R0, c14" : "=r" (now));
|
||||
|
||||
gd->arch.tbl = (unsigned long)(now & 0xffffffff);
|
||||
gd->arch.tbu = (unsigned long)(now >> 32);
|
||||
|
||||
return now;
|
||||
}
|
||||
|
||||
unsigned long get_timer_masked(void)
|
||||
{
|
||||
return tick_to_time(get_ticks());
|
||||
}
|
||||
|
||||
unsigned long get_timer(ulong base)
|
||||
{
|
||||
return get_timer_masked() - base;
|
||||
}
|
||||
|
||||
/* delay x useconds and preserve advance timstamp value */
|
||||
void __udelay(unsigned long usec)
|
||||
{
|
||||
unsigned long long start;
|
||||
unsigned long tmo;
|
||||
|
||||
start = get_ticks(); /* get current timestamp */
|
||||
tmo = us_to_tick(usec); /* convert usecs to ticks */
|
||||
|
||||
while ((get_ticks() - start) < tmo)
|
||||
; /* loop till time has passed */
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is derived from PowerPC code (timebase clock frequency).
|
||||
* On ARM it returns the number of timer ticks per second.
|
||||
*/
|
||||
unsigned long get_tbclk(void)
|
||||
{
|
||||
unsigned long freq;
|
||||
|
||||
asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (freq));
|
||||
|
||||
return freq;
|
||||
}
|
||||
28
u-boot/arch/arm/cpu/armv7/mx5/Kconfig
Normal file
28
u-boot/arch/arm/cpu/armv7/mx5/Kconfig
Normal file
@@ -0,0 +1,28 @@
|
||||
if ARCH_MX5
|
||||
|
||||
config MX5
|
||||
bool
|
||||
default y
|
||||
|
||||
config MX51
|
||||
bool
|
||||
|
||||
config MX53
|
||||
bool
|
||||
|
||||
choice
|
||||
prompt "MX5 board select"
|
||||
optional
|
||||
|
||||
config TARGET_USBARMORY
|
||||
bool "Support USB armory"
|
||||
select CPU_V7
|
||||
|
||||
endchoice
|
||||
|
||||
config SYS_SOC
|
||||
default "mx5"
|
||||
|
||||
source "board/inversepath/usbarmory/Kconfig"
|
||||
|
||||
endif
|
||||
11
u-boot/arch/arm/cpu/armv7/mx5/Makefile
Normal file
11
u-boot/arch/arm/cpu/armv7/mx5/Makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
#
|
||||
# (C) Copyright 2000-2006
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
#
|
||||
# (C) Copyright 2009 Freescale Semiconductor, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y := soc.o clock.o
|
||||
obj-y += lowlevel_init.o
|
||||
949
u-boot/arch/arm/cpu/armv7/mx5/clock.c
Normal file
949
u-boot/arch/arm/cpu/armv7/mx5/clock.c
Normal file
@@ -0,0 +1,949 @@
|
||||
/*
|
||||
* (C) Copyright 2007
|
||||
* Sascha Hauer, Pengutronix
|
||||
*
|
||||
* (C) Copyright 2009 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/arch/imx-regs.h>
|
||||
#include <asm/arch/crm_regs.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <div64.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
|
||||
enum pll_clocks {
|
||||
PLL1_CLOCK = 0,
|
||||
PLL2_CLOCK,
|
||||
PLL3_CLOCK,
|
||||
#ifdef CONFIG_MX53
|
||||
PLL4_CLOCK,
|
||||
#endif
|
||||
PLL_CLOCKS,
|
||||
};
|
||||
|
||||
struct mxc_pll_reg *mxc_plls[PLL_CLOCKS] = {
|
||||
[PLL1_CLOCK] = (struct mxc_pll_reg *)PLL1_BASE_ADDR,
|
||||
[PLL2_CLOCK] = (struct mxc_pll_reg *)PLL2_BASE_ADDR,
|
||||
[PLL3_CLOCK] = (struct mxc_pll_reg *)PLL3_BASE_ADDR,
|
||||
#ifdef CONFIG_MX53
|
||||
[PLL4_CLOCK] = (struct mxc_pll_reg *)PLL4_BASE_ADDR,
|
||||
#endif
|
||||
};
|
||||
|
||||
#define AHB_CLK_ROOT 133333333
|
||||
#define SZ_DEC_1M 1000000
|
||||
#define PLL_PD_MAX 16 /* Actual pd+1 */
|
||||
#define PLL_MFI_MAX 15
|
||||
#define PLL_MFI_MIN 5
|
||||
#define ARM_DIV_MAX 8
|
||||
#define IPG_DIV_MAX 4
|
||||
#define AHB_DIV_MAX 8
|
||||
#define EMI_DIV_MAX 8
|
||||
#define NFC_DIV_MAX 8
|
||||
|
||||
#define MX5_CBCMR 0x00015154
|
||||
#define MX5_CBCDR 0x02888945
|
||||
|
||||
struct fixed_pll_mfd {
|
||||
u32 ref_clk_hz;
|
||||
u32 mfd;
|
||||
};
|
||||
|
||||
const struct fixed_pll_mfd fixed_mfd[] = {
|
||||
{MXC_HCLK, 24 * 16},
|
||||
};
|
||||
|
||||
struct pll_param {
|
||||
u32 pd;
|
||||
u32 mfi;
|
||||
u32 mfn;
|
||||
u32 mfd;
|
||||
};
|
||||
|
||||
#define PLL_FREQ_MAX(ref_clk) (4 * (ref_clk) * PLL_MFI_MAX)
|
||||
#define PLL_FREQ_MIN(ref_clk) \
|
||||
((2 * (ref_clk) * (PLL_MFI_MIN - 1)) / PLL_PD_MAX)
|
||||
#define MAX_DDR_CLK 420000000
|
||||
#define NFC_CLK_MAX 34000000
|
||||
|
||||
struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)MXC_CCM_BASE;
|
||||
|
||||
void set_usboh3_clk(void)
|
||||
{
|
||||
clrsetbits_le32(&mxc_ccm->cscmr1,
|
||||
MXC_CCM_CSCMR1_USBOH3_CLK_SEL_MASK,
|
||||
MXC_CCM_CSCMR1_USBOH3_CLK_SEL(1));
|
||||
clrsetbits_le32(&mxc_ccm->cscdr1,
|
||||
MXC_CCM_CSCDR1_USBOH3_CLK_PODF_MASK |
|
||||
MXC_CCM_CSCDR1_USBOH3_CLK_PRED_MASK,
|
||||
MXC_CCM_CSCDR1_USBOH3_CLK_PRED(4) |
|
||||
MXC_CCM_CSCDR1_USBOH3_CLK_PODF(1));
|
||||
}
|
||||
|
||||
void enable_usboh3_clk(bool enable)
|
||||
{
|
||||
unsigned int cg = enable ? MXC_CCM_CCGR_CG_ON : MXC_CCM_CCGR_CG_OFF;
|
||||
|
||||
clrsetbits_le32(&mxc_ccm->CCGR2,
|
||||
MXC_CCM_CCGR2_USBOH3_60M(MXC_CCM_CCGR_CG_MASK),
|
||||
MXC_CCM_CCGR2_USBOH3_60M(cg));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_I2C_MXC
|
||||
/* i2c_num can be from 0, to 1 for i.MX51 and 2 for i.MX53 */
|
||||
int enable_i2c_clk(unsigned char enable, unsigned i2c_num)
|
||||
{
|
||||
u32 mask;
|
||||
|
||||
#if defined(CONFIG_MX51)
|
||||
if (i2c_num > 1)
|
||||
#elif defined(CONFIG_MX53)
|
||||
if (i2c_num > 2)
|
||||
#endif
|
||||
return -EINVAL;
|
||||
mask = MXC_CCM_CCGR_CG_MASK <<
|
||||
(MXC_CCM_CCGR1_I2C1_OFFSET + (i2c_num << 1));
|
||||
if (enable)
|
||||
setbits_le32(&mxc_ccm->CCGR1, mask);
|
||||
else
|
||||
clrbits_le32(&mxc_ccm->CCGR1, mask);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void set_usb_phy_clk(void)
|
||||
{
|
||||
clrbits_le32(&mxc_ccm->cscmr1, MXC_CCM_CSCMR1_USB_PHY_CLK_SEL);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_MX51)
|
||||
void enable_usb_phy1_clk(bool enable)
|
||||
{
|
||||
unsigned int cg = enable ? MXC_CCM_CCGR_CG_ON : MXC_CCM_CCGR_CG_OFF;
|
||||
|
||||
clrsetbits_le32(&mxc_ccm->CCGR2,
|
||||
MXC_CCM_CCGR2_USB_PHY(MXC_CCM_CCGR_CG_MASK),
|
||||
MXC_CCM_CCGR2_USB_PHY(cg));
|
||||
}
|
||||
|
||||
void enable_usb_phy2_clk(bool enable)
|
||||
{
|
||||
/* i.MX51 has a single USB PHY clock, so do nothing here. */
|
||||
}
|
||||
#elif defined(CONFIG_MX53)
|
||||
void enable_usb_phy1_clk(bool enable)
|
||||
{
|
||||
unsigned int cg = enable ? MXC_CCM_CCGR_CG_ON : MXC_CCM_CCGR_CG_OFF;
|
||||
|
||||
clrsetbits_le32(&mxc_ccm->CCGR4,
|
||||
MXC_CCM_CCGR4_USB_PHY1(MXC_CCM_CCGR_CG_MASK),
|
||||
MXC_CCM_CCGR4_USB_PHY1(cg));
|
||||
}
|
||||
|
||||
void enable_usb_phy2_clk(bool enable)
|
||||
{
|
||||
unsigned int cg = enable ? MXC_CCM_CCGR_CG_ON : MXC_CCM_CCGR_CG_OFF;
|
||||
|
||||
clrsetbits_le32(&mxc_ccm->CCGR4,
|
||||
MXC_CCM_CCGR4_USB_PHY2(MXC_CCM_CCGR_CG_MASK),
|
||||
MXC_CCM_CCGR4_USB_PHY2(cg));
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Calculate the frequency of PLLn.
|
||||
*/
|
||||
static uint32_t decode_pll(struct mxc_pll_reg *pll, uint32_t infreq)
|
||||
{
|
||||
uint32_t ctrl, op, mfd, mfn, mfi, pdf, ret;
|
||||
uint64_t refclk, temp;
|
||||
int32_t mfn_abs;
|
||||
|
||||
ctrl = readl(&pll->ctrl);
|
||||
|
||||
if (ctrl & MXC_DPLLC_CTL_HFSM) {
|
||||
mfn = readl(&pll->hfs_mfn);
|
||||
mfd = readl(&pll->hfs_mfd);
|
||||
op = readl(&pll->hfs_op);
|
||||
} else {
|
||||
mfn = readl(&pll->mfn);
|
||||
mfd = readl(&pll->mfd);
|
||||
op = readl(&pll->op);
|
||||
}
|
||||
|
||||
mfd &= MXC_DPLLC_MFD_MFD_MASK;
|
||||
mfn &= MXC_DPLLC_MFN_MFN_MASK;
|
||||
pdf = op & MXC_DPLLC_OP_PDF_MASK;
|
||||
mfi = MXC_DPLLC_OP_MFI_RD(op);
|
||||
|
||||
/* 21.2.3 */
|
||||
if (mfi < 5)
|
||||
mfi = 5;
|
||||
|
||||
/* Sign extend */
|
||||
if (mfn >= 0x04000000) {
|
||||
mfn |= 0xfc000000;
|
||||
mfn_abs = -mfn;
|
||||
} else
|
||||
mfn_abs = mfn;
|
||||
|
||||
refclk = infreq * 2;
|
||||
if (ctrl & MXC_DPLLC_CTL_DPDCK0_2_EN)
|
||||
refclk *= 2;
|
||||
|
||||
do_div(refclk, pdf + 1);
|
||||
temp = refclk * mfn_abs;
|
||||
do_div(temp, mfd + 1);
|
||||
ret = refclk * mfi;
|
||||
|
||||
if ((int)mfn < 0)
|
||||
ret -= temp;
|
||||
else
|
||||
ret += temp;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MX51
|
||||
/*
|
||||
* This function returns the Frequency Pre-Multiplier clock.
|
||||
*/
|
||||
static u32 get_fpm(void)
|
||||
{
|
||||
u32 mult;
|
||||
u32 ccr = readl(&mxc_ccm->ccr);
|
||||
|
||||
if (ccr & MXC_CCM_CCR_FPM_MULT)
|
||||
mult = 1024;
|
||||
else
|
||||
mult = 512;
|
||||
|
||||
return MXC_CLK32 * mult;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This function returns the low power audio clock.
|
||||
*/
|
||||
static u32 get_lp_apm(void)
|
||||
{
|
||||
u32 ret_val = 0;
|
||||
u32 ccsr = readl(&mxc_ccm->ccsr);
|
||||
|
||||
if (ccsr & MXC_CCM_CCSR_LP_APM)
|
||||
#if defined(CONFIG_MX51)
|
||||
ret_val = get_fpm();
|
||||
#elif defined(CONFIG_MX53)
|
||||
ret_val = decode_pll(mxc_plls[PLL4_CLOCK], MXC_HCLK);
|
||||
#endif
|
||||
else
|
||||
ret_val = MXC_HCLK;
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get mcu main rate
|
||||
*/
|
||||
u32 get_mcu_main_clk(void)
|
||||
{
|
||||
u32 reg, freq;
|
||||
|
||||
reg = MXC_CCM_CACRR_ARM_PODF_RD(readl(&mxc_ccm->cacrr));
|
||||
freq = decode_pll(mxc_plls[PLL1_CLOCK], MXC_HCLK);
|
||||
return freq / (reg + 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the rate of peripheral's root clock.
|
||||
*/
|
||||
u32 get_periph_clk(void)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = readl(&mxc_ccm->cbcdr);
|
||||
if (!(reg & MXC_CCM_CBCDR_PERIPH_CLK_SEL))
|
||||
return decode_pll(mxc_plls[PLL2_CLOCK], MXC_HCLK);
|
||||
reg = readl(&mxc_ccm->cbcmr);
|
||||
switch (MXC_CCM_CBCMR_PERIPH_CLK_SEL_RD(reg)) {
|
||||
case 0:
|
||||
return decode_pll(mxc_plls[PLL1_CLOCK], MXC_HCLK);
|
||||
case 1:
|
||||
return decode_pll(mxc_plls[PLL3_CLOCK], MXC_HCLK);
|
||||
case 2:
|
||||
return get_lp_apm();
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the rate of ipg clock.
|
||||
*/
|
||||
static u32 get_ipg_clk(void)
|
||||
{
|
||||
uint32_t freq, reg, div;
|
||||
|
||||
freq = get_ahb_clk();
|
||||
|
||||
reg = readl(&mxc_ccm->cbcdr);
|
||||
div = MXC_CCM_CBCDR_IPG_PODF_RD(reg) + 1;
|
||||
|
||||
return freq / div;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the rate of ipg_per clock.
|
||||
*/
|
||||
static u32 get_ipg_per_clk(void)
|
||||
{
|
||||
u32 freq, pred1, pred2, podf;
|
||||
|
||||
if (readl(&mxc_ccm->cbcmr) & MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL)
|
||||
return get_ipg_clk();
|
||||
|
||||
if (readl(&mxc_ccm->cbcmr) & MXC_CCM_CBCMR_PERCLK_LP_APM_CLK_SEL)
|
||||
freq = get_lp_apm();
|
||||
else
|
||||
freq = get_periph_clk();
|
||||
podf = readl(&mxc_ccm->cbcdr);
|
||||
pred1 = MXC_CCM_CBCDR_PERCLK_PRED1_RD(podf);
|
||||
pred2 = MXC_CCM_CBCDR_PERCLK_PRED2_RD(podf);
|
||||
podf = MXC_CCM_CBCDR_PERCLK_PODF_RD(podf);
|
||||
return freq / ((pred1 + 1) * (pred2 + 1) * (podf + 1));
|
||||
}
|
||||
|
||||
/* Get the output clock rate of a standard PLL MUX for peripherals. */
|
||||
static u32 get_standard_pll_sel_clk(u32 clk_sel)
|
||||
{
|
||||
u32 freq = 0;
|
||||
|
||||
switch (clk_sel & 0x3) {
|
||||
case 0:
|
||||
freq = decode_pll(mxc_plls[PLL1_CLOCK], MXC_HCLK);
|
||||
break;
|
||||
case 1:
|
||||
freq = decode_pll(mxc_plls[PLL2_CLOCK], MXC_HCLK);
|
||||
break;
|
||||
case 2:
|
||||
freq = decode_pll(mxc_plls[PLL3_CLOCK], MXC_HCLK);
|
||||
break;
|
||||
case 3:
|
||||
freq = get_lp_apm();
|
||||
break;
|
||||
}
|
||||
|
||||
return freq;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the rate of uart clk.
|
||||
*/
|
||||
static u32 get_uart_clk(void)
|
||||
{
|
||||
unsigned int clk_sel, freq, reg, pred, podf;
|
||||
|
||||
reg = readl(&mxc_ccm->cscmr1);
|
||||
clk_sel = MXC_CCM_CSCMR1_UART_CLK_SEL_RD(reg);
|
||||
freq = get_standard_pll_sel_clk(clk_sel);
|
||||
|
||||
reg = readl(&mxc_ccm->cscdr1);
|
||||
pred = MXC_CCM_CSCDR1_UART_CLK_PRED_RD(reg);
|
||||
podf = MXC_CCM_CSCDR1_UART_CLK_PODF_RD(reg);
|
||||
freq /= (pred + 1) * (podf + 1);
|
||||
|
||||
return freq;
|
||||
}
|
||||
|
||||
/*
|
||||
* get cspi clock rate.
|
||||
*/
|
||||
static u32 imx_get_cspiclk(void)
|
||||
{
|
||||
u32 ret_val = 0, pdf, pre_pdf, clk_sel, freq;
|
||||
u32 cscmr1 = readl(&mxc_ccm->cscmr1);
|
||||
u32 cscdr2 = readl(&mxc_ccm->cscdr2);
|
||||
|
||||
pre_pdf = MXC_CCM_CSCDR2_CSPI_CLK_PRED_RD(cscdr2);
|
||||
pdf = MXC_CCM_CSCDR2_CSPI_CLK_PODF_RD(cscdr2);
|
||||
clk_sel = MXC_CCM_CSCMR1_CSPI_CLK_SEL_RD(cscmr1);
|
||||
freq = get_standard_pll_sel_clk(clk_sel);
|
||||
ret_val = freq / ((pre_pdf + 1) * (pdf + 1));
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/*
|
||||
* get esdhc clock rate.
|
||||
*/
|
||||
static u32 get_esdhc_clk(u32 port)
|
||||
{
|
||||
u32 clk_sel = 0, pred = 0, podf = 0, freq = 0;
|
||||
u32 cscmr1 = readl(&mxc_ccm->cscmr1);
|
||||
u32 cscdr1 = readl(&mxc_ccm->cscdr1);
|
||||
|
||||
switch (port) {
|
||||
case 0:
|
||||
clk_sel = MXC_CCM_CSCMR1_ESDHC1_MSHC1_CLK_SEL_RD(cscmr1);
|
||||
pred = MXC_CCM_CSCDR1_ESDHC1_MSHC1_CLK_PRED_RD(cscdr1);
|
||||
podf = MXC_CCM_CSCDR1_ESDHC1_MSHC1_CLK_PODF_RD(cscdr1);
|
||||
break;
|
||||
case 1:
|
||||
clk_sel = MXC_CCM_CSCMR1_ESDHC2_MSHC2_CLK_SEL_RD(cscmr1);
|
||||
pred = MXC_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PRED_RD(cscdr1);
|
||||
podf = MXC_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PODF_RD(cscdr1);
|
||||
break;
|
||||
case 2:
|
||||
if (cscmr1 & MXC_CCM_CSCMR1_ESDHC3_CLK_SEL)
|
||||
return get_esdhc_clk(1);
|
||||
else
|
||||
return get_esdhc_clk(0);
|
||||
case 3:
|
||||
if (cscmr1 & MXC_CCM_CSCMR1_ESDHC4_CLK_SEL)
|
||||
return get_esdhc_clk(1);
|
||||
else
|
||||
return get_esdhc_clk(0);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
freq = get_standard_pll_sel_clk(clk_sel) / ((pred + 1) * (podf + 1));
|
||||
return freq;
|
||||
}
|
||||
|
||||
static u32 get_axi_a_clk(void)
|
||||
{
|
||||
u32 cbcdr = readl(&mxc_ccm->cbcdr);
|
||||
u32 pdf = MXC_CCM_CBCDR_AXI_A_PODF_RD(cbcdr);
|
||||
|
||||
return get_periph_clk() / (pdf + 1);
|
||||
}
|
||||
|
||||
static u32 get_axi_b_clk(void)
|
||||
{
|
||||
u32 cbcdr = readl(&mxc_ccm->cbcdr);
|
||||
u32 pdf = MXC_CCM_CBCDR_AXI_B_PODF_RD(cbcdr);
|
||||
|
||||
return get_periph_clk() / (pdf + 1);
|
||||
}
|
||||
|
||||
static u32 get_emi_slow_clk(void)
|
||||
{
|
||||
u32 cbcdr = readl(&mxc_ccm->cbcdr);
|
||||
u32 emi_clk_sel = cbcdr & MXC_CCM_CBCDR_EMI_CLK_SEL;
|
||||
u32 pdf = MXC_CCM_CBCDR_EMI_PODF_RD(cbcdr);
|
||||
|
||||
if (emi_clk_sel)
|
||||
return get_ahb_clk() / (pdf + 1);
|
||||
|
||||
return get_periph_clk() / (pdf + 1);
|
||||
}
|
||||
|
||||
static u32 get_ddr_clk(void)
|
||||
{
|
||||
u32 ret_val = 0;
|
||||
u32 cbcmr = readl(&mxc_ccm->cbcmr);
|
||||
u32 ddr_clk_sel = MXC_CCM_CBCMR_DDR_CLK_SEL_RD(cbcmr);
|
||||
#ifdef CONFIG_MX51
|
||||
u32 cbcdr = readl(&mxc_ccm->cbcdr);
|
||||
if (cbcdr & MXC_CCM_CBCDR_DDR_HIFREQ_SEL) {
|
||||
u32 ddr_clk_podf = MXC_CCM_CBCDR_DDR_PODF_RD(cbcdr);
|
||||
|
||||
ret_val = decode_pll(mxc_plls[PLL1_CLOCK], MXC_HCLK);
|
||||
ret_val /= ddr_clk_podf + 1;
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
#endif
|
||||
switch (ddr_clk_sel) {
|
||||
case 0:
|
||||
ret_val = get_axi_a_clk();
|
||||
break;
|
||||
case 1:
|
||||
ret_val = get_axi_b_clk();
|
||||
break;
|
||||
case 2:
|
||||
ret_val = get_emi_slow_clk();
|
||||
break;
|
||||
case 3:
|
||||
ret_val = get_ahb_clk();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/*
|
||||
* The API of get mxc clocks.
|
||||
*/
|
||||
unsigned int mxc_get_clock(enum mxc_clock clk)
|
||||
{
|
||||
switch (clk) {
|
||||
case MXC_ARM_CLK:
|
||||
return get_mcu_main_clk();
|
||||
case MXC_AHB_CLK:
|
||||
return get_ahb_clk();
|
||||
case MXC_IPG_CLK:
|
||||
return get_ipg_clk();
|
||||
case MXC_IPG_PERCLK:
|
||||
case MXC_I2C_CLK:
|
||||
return get_ipg_per_clk();
|
||||
case MXC_UART_CLK:
|
||||
return get_uart_clk();
|
||||
case MXC_CSPI_CLK:
|
||||
return imx_get_cspiclk();
|
||||
case MXC_ESDHC_CLK:
|
||||
return get_esdhc_clk(0);
|
||||
case MXC_ESDHC2_CLK:
|
||||
return get_esdhc_clk(1);
|
||||
case MXC_ESDHC3_CLK:
|
||||
return get_esdhc_clk(2);
|
||||
case MXC_ESDHC4_CLK:
|
||||
return get_esdhc_clk(3);
|
||||
case MXC_FEC_CLK:
|
||||
return get_ipg_clk();
|
||||
case MXC_SATA_CLK:
|
||||
return get_ahb_clk();
|
||||
case MXC_DDR_CLK:
|
||||
return get_ddr_clk();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
u32 imx_get_uartclk(void)
|
||||
{
|
||||
return get_uart_clk();
|
||||
}
|
||||
|
||||
u32 imx_get_fecclk(void)
|
||||
{
|
||||
return get_ipg_clk();
|
||||
}
|
||||
|
||||
static int gcd(int m, int n)
|
||||
{
|
||||
int t;
|
||||
while (m > 0) {
|
||||
if (n > m) {
|
||||
t = m;
|
||||
m = n;
|
||||
n = t;
|
||||
} /* swap */
|
||||
m -= n;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is to calculate various parameters based on reference clock and
|
||||
* targeted clock based on the equation:
|
||||
* t_clk = 2*ref_freq*(mfi + mfn/(mfd+1))/(pd+1)
|
||||
* This calculation is based on a fixed MFD value for simplicity.
|
||||
*/
|
||||
static int calc_pll_params(u32 ref, u32 target, struct pll_param *pll)
|
||||
{
|
||||
u64 pd, mfi = 1, mfn, mfd, t1;
|
||||
u32 n_target = target;
|
||||
u32 n_ref = ref, i;
|
||||
|
||||
/*
|
||||
* Make sure targeted freq is in the valid range.
|
||||
* Otherwise the following calculation might be wrong!!!
|
||||
*/
|
||||
if (n_target < PLL_FREQ_MIN(ref) ||
|
||||
n_target > PLL_FREQ_MAX(ref)) {
|
||||
printf("Targeted peripheral clock should be"
|
||||
"within [%d - %d]\n",
|
||||
PLL_FREQ_MIN(ref) / SZ_DEC_1M,
|
||||
PLL_FREQ_MAX(ref) / SZ_DEC_1M);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(fixed_mfd); i++) {
|
||||
if (fixed_mfd[i].ref_clk_hz == ref) {
|
||||
mfd = fixed_mfd[i].mfd;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE(fixed_mfd))
|
||||
return -EINVAL;
|
||||
|
||||
/* Use n_target and n_ref to avoid overflow */
|
||||
for (pd = 1; pd <= PLL_PD_MAX; pd++) {
|
||||
t1 = n_target * pd;
|
||||
do_div(t1, (4 * n_ref));
|
||||
mfi = t1;
|
||||
if (mfi > PLL_MFI_MAX)
|
||||
return -EINVAL;
|
||||
else if (mfi < 5)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Now got pd and mfi already
|
||||
*
|
||||
* mfn = (((n_target * pd) / 4 - n_ref * mfi) * mfd) / n_ref;
|
||||
*/
|
||||
t1 = n_target * pd;
|
||||
do_div(t1, 4);
|
||||
t1 -= n_ref * mfi;
|
||||
t1 *= mfd;
|
||||
do_div(t1, n_ref);
|
||||
mfn = t1;
|
||||
debug("ref=%d, target=%d, pd=%d," "mfi=%d,mfn=%d, mfd=%d\n",
|
||||
ref, n_target, (u32)pd, (u32)mfi, (u32)mfn, (u32)mfd);
|
||||
i = 1;
|
||||
if (mfn != 0)
|
||||
i = gcd(mfd, mfn);
|
||||
pll->pd = (u32)pd;
|
||||
pll->mfi = (u32)mfi;
|
||||
do_div(mfn, i);
|
||||
pll->mfn = (u32)mfn;
|
||||
do_div(mfd, i);
|
||||
pll->mfd = (u32)mfd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define calc_div(tgt_clk, src_clk, limit) ({ \
|
||||
u32 v = 0; \
|
||||
if (((src_clk) % (tgt_clk)) <= 100) \
|
||||
v = (src_clk) / (tgt_clk); \
|
||||
else \
|
||||
v = ((src_clk) / (tgt_clk)) + 1;\
|
||||
if (v > limit) \
|
||||
v = limit; \
|
||||
(v - 1); \
|
||||
})
|
||||
|
||||
#define CHANGE_PLL_SETTINGS(pll, pd, fi, fn, fd) \
|
||||
{ \
|
||||
writel(0x1232, &pll->ctrl); \
|
||||
writel(0x2, &pll->config); \
|
||||
writel((((pd) - 1) << 0) | ((fi) << 4), \
|
||||
&pll->op); \
|
||||
writel(fn, &(pll->mfn)); \
|
||||
writel((fd) - 1, &pll->mfd); \
|
||||
writel((((pd) - 1) << 0) | ((fi) << 4), \
|
||||
&pll->hfs_op); \
|
||||
writel(fn, &pll->hfs_mfn); \
|
||||
writel((fd) - 1, &pll->hfs_mfd); \
|
||||
writel(0x1232, &pll->ctrl); \
|
||||
while (!readl(&pll->ctrl) & 0x1) \
|
||||
;\
|
||||
}
|
||||
|
||||
static int config_pll_clk(enum pll_clocks index, struct pll_param *pll_param)
|
||||
{
|
||||
u32 ccsr = readl(&mxc_ccm->ccsr);
|
||||
struct mxc_pll_reg *pll = mxc_plls[index];
|
||||
|
||||
switch (index) {
|
||||
case PLL1_CLOCK:
|
||||
/* Switch ARM to PLL2 clock */
|
||||
writel(ccsr | MXC_CCM_CCSR_PLL1_SW_CLK_SEL,
|
||||
&mxc_ccm->ccsr);
|
||||
CHANGE_PLL_SETTINGS(pll, pll_param->pd,
|
||||
pll_param->mfi, pll_param->mfn,
|
||||
pll_param->mfd);
|
||||
/* Switch back */
|
||||
writel(ccsr & ~MXC_CCM_CCSR_PLL1_SW_CLK_SEL,
|
||||
&mxc_ccm->ccsr);
|
||||
break;
|
||||
case PLL2_CLOCK:
|
||||
/* Switch to pll2 bypass clock */
|
||||
writel(ccsr | MXC_CCM_CCSR_PLL2_SW_CLK_SEL,
|
||||
&mxc_ccm->ccsr);
|
||||
CHANGE_PLL_SETTINGS(pll, pll_param->pd,
|
||||
pll_param->mfi, pll_param->mfn,
|
||||
pll_param->mfd);
|
||||
/* Switch back */
|
||||
writel(ccsr & ~MXC_CCM_CCSR_PLL2_SW_CLK_SEL,
|
||||
&mxc_ccm->ccsr);
|
||||
break;
|
||||
case PLL3_CLOCK:
|
||||
/* Switch to pll3 bypass clock */
|
||||
writel(ccsr | MXC_CCM_CCSR_PLL3_SW_CLK_SEL,
|
||||
&mxc_ccm->ccsr);
|
||||
CHANGE_PLL_SETTINGS(pll, pll_param->pd,
|
||||
pll_param->mfi, pll_param->mfn,
|
||||
pll_param->mfd);
|
||||
/* Switch back */
|
||||
writel(ccsr & ~MXC_CCM_CCSR_PLL3_SW_CLK_SEL,
|
||||
&mxc_ccm->ccsr);
|
||||
break;
|
||||
#ifdef CONFIG_MX53
|
||||
case PLL4_CLOCK:
|
||||
/* Switch to pll4 bypass clock */
|
||||
writel(ccsr | MXC_CCM_CCSR_PLL4_SW_CLK_SEL,
|
||||
&mxc_ccm->ccsr);
|
||||
CHANGE_PLL_SETTINGS(pll, pll_param->pd,
|
||||
pll_param->mfi, pll_param->mfn,
|
||||
pll_param->mfd);
|
||||
/* Switch back */
|
||||
writel(ccsr & ~MXC_CCM_CCSR_PLL4_SW_CLK_SEL,
|
||||
&mxc_ccm->ccsr);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Config CPU clock */
|
||||
static int config_core_clk(u32 ref, u32 freq)
|
||||
{
|
||||
int ret = 0;
|
||||
struct pll_param pll_param;
|
||||
|
||||
memset(&pll_param, 0, sizeof(struct pll_param));
|
||||
|
||||
/* The case that periph uses PLL1 is not considered here */
|
||||
ret = calc_pll_params(ref, freq, &pll_param);
|
||||
if (ret != 0) {
|
||||
printf("Error:Can't find pll parameters: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return config_pll_clk(PLL1_CLOCK, &pll_param);
|
||||
}
|
||||
|
||||
static int config_nfc_clk(u32 nfc_clk)
|
||||
{
|
||||
u32 parent_rate = get_emi_slow_clk();
|
||||
u32 div;
|
||||
|
||||
if (nfc_clk == 0)
|
||||
return -EINVAL;
|
||||
div = parent_rate / nfc_clk;
|
||||
if (div == 0)
|
||||
div++;
|
||||
if (parent_rate / div > NFC_CLK_MAX)
|
||||
div++;
|
||||
clrsetbits_le32(&mxc_ccm->cbcdr,
|
||||
MXC_CCM_CBCDR_NFC_PODF_MASK,
|
||||
MXC_CCM_CBCDR_NFC_PODF(div - 1));
|
||||
while (readl(&mxc_ccm->cdhipr) != 0)
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void enable_nfc_clk(unsigned char enable)
|
||||
{
|
||||
unsigned int cg = enable ? MXC_CCM_CCGR_CG_ON : MXC_CCM_CCGR_CG_OFF;
|
||||
|
||||
clrsetbits_le32(&mxc_ccm->CCGR5,
|
||||
MXC_CCM_CCGR5_EMI_ENFC(MXC_CCM_CCGR_CG_MASK),
|
||||
MXC_CCM_CCGR5_EMI_ENFC(cg));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FSL_IIM
|
||||
void enable_efuse_prog_supply(bool enable)
|
||||
{
|
||||
if (enable)
|
||||
setbits_le32(&mxc_ccm->cgpr,
|
||||
MXC_CCM_CGPR_EFUSE_PROG_SUPPLY_GATE);
|
||||
else
|
||||
clrbits_le32(&mxc_ccm->cgpr,
|
||||
MXC_CCM_CGPR_EFUSE_PROG_SUPPLY_GATE);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Config main_bus_clock for periphs */
|
||||
static int config_periph_clk(u32 ref, u32 freq)
|
||||
{
|
||||
int ret = 0;
|
||||
struct pll_param pll_param;
|
||||
|
||||
memset(&pll_param, 0, sizeof(struct pll_param));
|
||||
|
||||
if (readl(&mxc_ccm->cbcdr) & MXC_CCM_CBCDR_PERIPH_CLK_SEL) {
|
||||
ret = calc_pll_params(ref, freq, &pll_param);
|
||||
if (ret != 0) {
|
||||
printf("Error:Can't find pll parameters: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
switch (MXC_CCM_CBCMR_PERIPH_CLK_SEL_RD(
|
||||
readl(&mxc_ccm->cbcmr))) {
|
||||
case 0:
|
||||
return config_pll_clk(PLL1_CLOCK, &pll_param);
|
||||
break;
|
||||
case 1:
|
||||
return config_pll_clk(PLL3_CLOCK, &pll_param);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int config_ddr_clk(u32 emi_clk)
|
||||
{
|
||||
u32 clk_src;
|
||||
s32 shift = 0, clk_sel, div = 1;
|
||||
u32 cbcmr = readl(&mxc_ccm->cbcmr);
|
||||
|
||||
if (emi_clk > MAX_DDR_CLK) {
|
||||
printf("Warning:DDR clock should not exceed %d MHz\n",
|
||||
MAX_DDR_CLK / SZ_DEC_1M);
|
||||
emi_clk = MAX_DDR_CLK;
|
||||
}
|
||||
|
||||
clk_src = get_periph_clk();
|
||||
/* Find DDR clock input */
|
||||
clk_sel = MXC_CCM_CBCMR_DDR_CLK_SEL_RD(cbcmr);
|
||||
switch (clk_sel) {
|
||||
case 0:
|
||||
shift = 16;
|
||||
break;
|
||||
case 1:
|
||||
shift = 19;
|
||||
break;
|
||||
case 2:
|
||||
shift = 22;
|
||||
break;
|
||||
case 3:
|
||||
shift = 10;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((clk_src % emi_clk) < 10000000)
|
||||
div = clk_src / emi_clk;
|
||||
else
|
||||
div = (clk_src / emi_clk) + 1;
|
||||
if (div > 8)
|
||||
div = 8;
|
||||
|
||||
clrsetbits_le32(&mxc_ccm->cbcdr, 0x7 << shift, (div - 1) << shift);
|
||||
while (readl(&mxc_ccm->cdhipr) != 0)
|
||||
;
|
||||
writel(0x0, &mxc_ccm->ccdr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function assumes the expected core clock has to be changed by
|
||||
* modifying the PLL. This is NOT true always but for most of the times,
|
||||
* it is. So it assumes the PLL output freq is the same as the expected
|
||||
* core clock (presc=1) unless the core clock is less than PLL_FREQ_MIN.
|
||||
* In the latter case, it will try to increase the presc value until
|
||||
* (presc*core_clk) is greater than PLL_FREQ_MIN. It then makes call to
|
||||
* calc_pll_params() and obtains the values of PD, MFI,MFN, MFD based
|
||||
* on the targeted PLL and reference input clock to the PLL. Lastly,
|
||||
* it sets the register based on these values along with the dividers.
|
||||
* Note 1) There is no value checking for the passed-in divider values
|
||||
* so the caller has to make sure those values are sensible.
|
||||
* 2) Also adjust the NFC divider such that the NFC clock doesn't
|
||||
* exceed NFC_CLK_MAX.
|
||||
* 3) IPU HSP clock is independent of AHB clock. Even it can go up to
|
||||
* 177MHz for higher voltage, this function fixes the max to 133MHz.
|
||||
* 4) This function should not have allowed diag_printf() calls since
|
||||
* the serial driver has been stoped. But leave then here to allow
|
||||
* easy debugging by NOT calling the cyg_hal_plf_serial_stop().
|
||||
*/
|
||||
int mxc_set_clock(u32 ref, u32 freq, enum mxc_clock clk)
|
||||
{
|
||||
freq *= SZ_DEC_1M;
|
||||
|
||||
switch (clk) {
|
||||
case MXC_ARM_CLK:
|
||||
if (config_core_clk(ref, freq))
|
||||
return -EINVAL;
|
||||
break;
|
||||
case MXC_PERIPH_CLK:
|
||||
if (config_periph_clk(ref, freq))
|
||||
return -EINVAL;
|
||||
break;
|
||||
case MXC_DDR_CLK:
|
||||
if (config_ddr_clk(freq))
|
||||
return -EINVAL;
|
||||
break;
|
||||
case MXC_NFC_CLK:
|
||||
if (config_nfc_clk(freq))
|
||||
return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
printf("Warning:Unsupported or invalid clock type\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MX53
|
||||
/*
|
||||
* The clock for the external interface can be set to use internal clock
|
||||
* if fuse bank 4, row 3, bit 2 is set.
|
||||
* This is an undocumented feature and it was confirmed by Freescale's support:
|
||||
* Fuses (but not pins) may be used to configure SATA clocks.
|
||||
* Particularly the i.MX53 Fuse_Map contains the next information
|
||||
* about configuring SATA clocks : SATA_ALT_REF_CLK[1:0] (offset 0x180C)
|
||||
* '00' - 100MHz (External)
|
||||
* '01' - 50MHz (External)
|
||||
* '10' - 120MHz, internal (USB PHY)
|
||||
* '11' - Reserved
|
||||
*/
|
||||
void mxc_set_sata_internal_clock(void)
|
||||
{
|
||||
u32 *tmp_base =
|
||||
(u32 *)(IIM_BASE_ADDR + 0x180c);
|
||||
|
||||
set_usb_phy_clk();
|
||||
|
||||
clrsetbits_le32(tmp_base, 0x6, 0x4);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Dump some core clockes.
|
||||
*/
|
||||
int do_mx5_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
u32 freq;
|
||||
|
||||
freq = decode_pll(mxc_plls[PLL1_CLOCK], MXC_HCLK);
|
||||
printf("PLL1 %8d MHz\n", freq / 1000000);
|
||||
freq = decode_pll(mxc_plls[PLL2_CLOCK], MXC_HCLK);
|
||||
printf("PLL2 %8d MHz\n", freq / 1000000);
|
||||
freq = decode_pll(mxc_plls[PLL3_CLOCK], MXC_HCLK);
|
||||
printf("PLL3 %8d MHz\n", freq / 1000000);
|
||||
#ifdef CONFIG_MX53
|
||||
freq = decode_pll(mxc_plls[PLL4_CLOCK], MXC_HCLK);
|
||||
printf("PLL4 %8d MHz\n", freq / 1000000);
|
||||
#endif
|
||||
|
||||
printf("\n");
|
||||
printf("AHB %8d kHz\n", mxc_get_clock(MXC_AHB_CLK) / 1000);
|
||||
printf("IPG %8d kHz\n", mxc_get_clock(MXC_IPG_CLK) / 1000);
|
||||
printf("IPG PERCLK %8d kHz\n", mxc_get_clock(MXC_IPG_PERCLK) / 1000);
|
||||
printf("DDR %8d kHz\n", mxc_get_clock(MXC_DDR_CLK) / 1000);
|
||||
#ifdef CONFIG_MXC_SPI
|
||||
printf("CSPI %8d kHz\n", mxc_get_clock(MXC_CSPI_CLK) / 1000);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
|
||||
U_BOOT_CMD(
|
||||
clocks, CONFIG_SYS_MAXARGS, 1, do_mx5_showclocks,
|
||||
"display clocks",
|
||||
""
|
||||
);
|
||||
429
u-boot/arch/arm/cpu/armv7/mx5/lowlevel_init.S
Normal file
429
u-boot/arch/arm/cpu/armv7/mx5/lowlevel_init.S
Normal file
@@ -0,0 +1,429 @@
|
||||
/*
|
||||
* Copyright (C) 2007, Guennadi Liakhovetski <lg@denx.de>
|
||||
*
|
||||
* (C) Copyright 2009 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <asm/arch/imx-regs.h>
|
||||
#include <generated/asm-offsets.h>
|
||||
#include <linux/linkage.h>
|
||||
|
||||
.section ".text.init", "x"
|
||||
|
||||
.macro init_arm_erratum
|
||||
/* ARM erratum ID #468414 */
|
||||
mrc 15, 0, r1, c1, c0, 1
|
||||
orr r1, r1, #(1 << 5) /* enable L1NEON bit */
|
||||
mcr 15, 0, r1, c1, c0, 1
|
||||
.endm
|
||||
|
||||
/*
|
||||
* L2CC Cache setup/invalidation/disable
|
||||
*/
|
||||
.macro init_l2cc
|
||||
/* explicitly disable L2 cache */
|
||||
mrc 15, 0, r0, c1, c0, 1
|
||||
bic r0, r0, #0x2
|
||||
mcr 15, 0, r0, c1, c0, 1
|
||||
|
||||
/* reconfigure L2 cache aux control reg */
|
||||
ldr r0, =0xC0 | /* tag RAM */ \
|
||||
0x4 | /* data RAM */ \
|
||||
1 << 24 | /* disable write allocate delay */ \
|
||||
1 << 23 | /* disable write allocate combine */ \
|
||||
1 << 22 /* disable write allocate */
|
||||
|
||||
#if defined(CONFIG_MX51)
|
||||
ldr r3, [r4, #ROM_SI_REV]
|
||||
cmp r3, #0x10
|
||||
|
||||
/* disable write combine for TO 2 and lower revs */
|
||||
orrls r0, r0, #1 << 25
|
||||
#endif
|
||||
|
||||
mcr 15, 1, r0, c9, c0, 2
|
||||
|
||||
/* enable L2 cache */
|
||||
mrc 15, 0, r0, c1, c0, 1
|
||||
orr r0, r0, #2
|
||||
mcr 15, 0, r0, c1, c0, 1
|
||||
|
||||
.endm /* init_l2cc */
|
||||
|
||||
/* AIPS setup - Only setup MPROTx registers.
|
||||
* The PACR default values are good.*/
|
||||
.macro init_aips
|
||||
/*
|
||||
* Set all MPROTx to be non-bufferable, trusted for R/W,
|
||||
* not forced to user-mode.
|
||||
*/
|
||||
ldr r0, =AIPS1_BASE_ADDR
|
||||
ldr r1, =0x77777777
|
||||
str r1, [r0, #0x0]
|
||||
str r1, [r0, #0x4]
|
||||
ldr r0, =AIPS2_BASE_ADDR
|
||||
str r1, [r0, #0x0]
|
||||
str r1, [r0, #0x4]
|
||||
/*
|
||||
* Clear the on and off peripheral modules Supervisor Protect bit
|
||||
* for SDMA to access them. Did not change the AIPS control registers
|
||||
* (offset 0x20) access type
|
||||
*/
|
||||
.endm /* init_aips */
|
||||
|
||||
/* M4IF setup */
|
||||
.macro init_m4if
|
||||
#ifdef CONFIG_MX51
|
||||
/* VPU and IPU given higher priority (0x4)
|
||||
* IPU accesses with ID=0x1 given highest priority (=0xA)
|
||||
*/
|
||||
ldr r0, =M4IF_BASE_ADDR
|
||||
|
||||
ldr r1, =0x00000203
|
||||
str r1, [r0, #0x40]
|
||||
|
||||
str r4, [r0, #0x44]
|
||||
|
||||
ldr r1, =0x00120125
|
||||
str r1, [r0, #0x9C]
|
||||
|
||||
ldr r1, =0x001901A3
|
||||
str r1, [r0, #0x48]
|
||||
|
||||
#endif
|
||||
.endm /* init_m4if */
|
||||
|
||||
.macro setup_pll pll, freq
|
||||
ldr r0, =\pll
|
||||
adr r2, W_DP_\freq
|
||||
bl setup_pll_func
|
||||
.endm
|
||||
|
||||
#define W_DP_OP 0
|
||||
#define W_DP_MFD 4
|
||||
#define W_DP_MFN 8
|
||||
|
||||
setup_pll_func:
|
||||
ldr r1, =0x00001232
|
||||
str r1, [r0, #PLL_DP_CTL] /* Set DPLL ON (set UPEN bit): BRMO=1 */
|
||||
mov r1, #0x2
|
||||
str r1, [r0, #PLL_DP_CONFIG] /* Enable auto-restart AREN bit */
|
||||
|
||||
ldr r1, [r2, #W_DP_OP]
|
||||
str r1, [r0, #PLL_DP_OP]
|
||||
str r1, [r0, #PLL_DP_HFS_OP]
|
||||
|
||||
ldr r1, [r2, #W_DP_MFD]
|
||||
str r1, [r0, #PLL_DP_MFD]
|
||||
str r1, [r0, #PLL_DP_HFS_MFD]
|
||||
|
||||
ldr r1, [r2, #W_DP_MFN]
|
||||
str r1, [r0, #PLL_DP_MFN]
|
||||
str r1, [r0, #PLL_DP_HFS_MFN]
|
||||
|
||||
ldr r1, =0x00001232
|
||||
str r1, [r0, #PLL_DP_CTL]
|
||||
1: ldr r1, [r0, #PLL_DP_CTL]
|
||||
ands r1, r1, #0x1
|
||||
beq 1b
|
||||
|
||||
/* r10 saved upper lr */
|
||||
mov pc, lr
|
||||
|
||||
.macro setup_pll_errata pll, freq
|
||||
ldr r2, =\pll
|
||||
str r4, [r2, #PLL_DP_CONFIG] /* Disable auto-restart AREN bit */
|
||||
ldr r1, =0x00001236
|
||||
str r1, [r2, #PLL_DP_CTL] /* Restart PLL with PLM=1 */
|
||||
1: ldr r1, [r2, #PLL_DP_CTL] /* Wait for lock */
|
||||
ands r1, r1, #0x1
|
||||
beq 1b
|
||||
|
||||
ldr r5, \freq
|
||||
str r5, [r2, #PLL_DP_MFN] /* Modify MFN value */
|
||||
str r5, [r2, #PLL_DP_HFS_MFN]
|
||||
|
||||
mov r1, #0x1
|
||||
str r1, [r2, #PLL_DP_CONFIG] /* Reload MFN value */
|
||||
|
||||
2: ldr r1, [r2, #PLL_DP_CONFIG]
|
||||
tst r1, #1
|
||||
bne 2b
|
||||
|
||||
ldr r1, =100 /* Wait at least 4 us */
|
||||
3: subs r1, r1, #1
|
||||
bge 3b
|
||||
|
||||
mov r1, #0x2
|
||||
str r1, [r2, #PLL_DP_CONFIG] /* Enable auto-restart AREN bit */
|
||||
.endm
|
||||
|
||||
.macro init_clock
|
||||
#if defined (CONFIG_MX51)
|
||||
ldr r0, =CCM_BASE_ADDR
|
||||
|
||||
/* Gate of clocks to the peripherals first */
|
||||
ldr r1, =0x3FFFFFFF
|
||||
str r1, [r0, #CLKCTL_CCGR0]
|
||||
str r4, [r0, #CLKCTL_CCGR1]
|
||||
str r4, [r0, #CLKCTL_CCGR2]
|
||||
str r4, [r0, #CLKCTL_CCGR3]
|
||||
|
||||
ldr r1, =0x00030000
|
||||
str r1, [r0, #CLKCTL_CCGR4]
|
||||
ldr r1, =0x00FFF030
|
||||
str r1, [r0, #CLKCTL_CCGR5]
|
||||
ldr r1, =0x00000300
|
||||
str r1, [r0, #CLKCTL_CCGR6]
|
||||
|
||||
/* Disable IPU and HSC dividers */
|
||||
mov r1, #0x60000
|
||||
str r1, [r0, #CLKCTL_CCDR]
|
||||
|
||||
/* Make sure to switch the DDR away from PLL 1 */
|
||||
ldr r1, =0x19239145
|
||||
str r1, [r0, #CLKCTL_CBCDR]
|
||||
/* make sure divider effective */
|
||||
1: ldr r1, [r0, #CLKCTL_CDHIPR]
|
||||
cmp r1, #0x0
|
||||
bne 1b
|
||||
|
||||
/* Switch ARM to step clock */
|
||||
mov r1, #0x4
|
||||
str r1, [r0, #CLKCTL_CCSR]
|
||||
|
||||
#if defined(CONFIG_MX51_PLL_ERRATA)
|
||||
setup_pll PLL1_BASE_ADDR, 864
|
||||
setup_pll_errata PLL1_BASE_ADDR, W_DP_MFN_800_DIT
|
||||
#else
|
||||
setup_pll PLL1_BASE_ADDR, 800
|
||||
#endif
|
||||
|
||||
setup_pll PLL3_BASE_ADDR, 665
|
||||
|
||||
/* Switch peripheral to PLL 3 */
|
||||
ldr r0, =CCM_BASE_ADDR
|
||||
ldr r1, =0x000010C0 | CONFIG_SYS_DDR_CLKSEL
|
||||
str r1, [r0, #CLKCTL_CBCMR]
|
||||
ldr r1, =0x13239145
|
||||
str r1, [r0, #CLKCTL_CBCDR]
|
||||
setup_pll PLL2_BASE_ADDR, 665
|
||||
|
||||
/* Switch peripheral to PLL2 */
|
||||
ldr r0, =CCM_BASE_ADDR
|
||||
ldr r1, =0x19239145
|
||||
str r1, [r0, #CLKCTL_CBCDR]
|
||||
ldr r1, =0x000020C0 | CONFIG_SYS_DDR_CLKSEL
|
||||
str r1, [r0, #CLKCTL_CBCMR]
|
||||
|
||||
setup_pll PLL3_BASE_ADDR, 216
|
||||
|
||||
/* Set the platform clock dividers */
|
||||
ldr r0, =ARM_BASE_ADDR
|
||||
ldr r1, =0x00000725
|
||||
str r1, [r0, #0x14]
|
||||
|
||||
ldr r0, =CCM_BASE_ADDR
|
||||
|
||||
/* Run 3.0 at Full speed, for other TO's wait till we increase VDDGP */
|
||||
ldr r3, [r4, #ROM_SI_REV]
|
||||
cmp r3, #0x10
|
||||
movls r1, #0x1
|
||||
movhi r1, #0
|
||||
|
||||
str r1, [r0, #CLKCTL_CACRR]
|
||||
|
||||
/* Switch ARM back to PLL 1 */
|
||||
str r4, [r0, #CLKCTL_CCSR]
|
||||
|
||||
/* setup the rest */
|
||||
/* Use lp_apm (24MHz) source for perclk */
|
||||
ldr r1, =0x000020C2 | CONFIG_SYS_DDR_CLKSEL
|
||||
str r1, [r0, #CLKCTL_CBCMR]
|
||||
/* ddr clock from PLL 1, all perclk dividers are 1 since using 24MHz */
|
||||
ldr r1, =CONFIG_SYS_CLKTL_CBCDR
|
||||
str r1, [r0, #CLKCTL_CBCDR]
|
||||
|
||||
/* Restore the default values in the Gate registers */
|
||||
ldr r1, =0xFFFFFFFF
|
||||
str r1, [r0, #CLKCTL_CCGR0]
|
||||
str r1, [r0, #CLKCTL_CCGR1]
|
||||
str r1, [r0, #CLKCTL_CCGR2]
|
||||
str r1, [r0, #CLKCTL_CCGR3]
|
||||
str r1, [r0, #CLKCTL_CCGR4]
|
||||
str r1, [r0, #CLKCTL_CCGR5]
|
||||
str r1, [r0, #CLKCTL_CCGR6]
|
||||
|
||||
/* Use PLL 2 for UART's, get 66.5MHz from it */
|
||||
ldr r1, =0xA5A2A020
|
||||
str r1, [r0, #CLKCTL_CSCMR1]
|
||||
ldr r1, =0x00C30321
|
||||
str r1, [r0, #CLKCTL_CSCDR1]
|
||||
/* make sure divider effective */
|
||||
1: ldr r1, [r0, #CLKCTL_CDHIPR]
|
||||
cmp r1, #0x0
|
||||
bne 1b
|
||||
|
||||
str r4, [r0, #CLKCTL_CCDR]
|
||||
|
||||
/* for cko - for ARM div by 8 */
|
||||
mov r1, #0x000A0000
|
||||
add r1, r1, #0x00000F0
|
||||
str r1, [r0, #CLKCTL_CCOSR]
|
||||
#else /* CONFIG_MX53 */
|
||||
ldr r0, =CCM_BASE_ADDR
|
||||
|
||||
/* Gate of clocks to the peripherals first */
|
||||
ldr r1, =0x3FFFFFFF
|
||||
str r1, [r0, #CLKCTL_CCGR0]
|
||||
str r4, [r0, #CLKCTL_CCGR1]
|
||||
str r4, [r0, #CLKCTL_CCGR2]
|
||||
str r4, [r0, #CLKCTL_CCGR3]
|
||||
str r4, [r0, #CLKCTL_CCGR7]
|
||||
ldr r1, =0x00030000
|
||||
str r1, [r0, #CLKCTL_CCGR4]
|
||||
ldr r1, =0x00FFF030
|
||||
str r1, [r0, #CLKCTL_CCGR5]
|
||||
ldr r1, =0x0F00030F
|
||||
str r1, [r0, #CLKCTL_CCGR6]
|
||||
|
||||
/* Switch ARM to step clock */
|
||||
mov r1, #0x4
|
||||
str r1, [r0, #CLKCTL_CCSR]
|
||||
|
||||
setup_pll PLL1_BASE_ADDR, 800
|
||||
|
||||
setup_pll PLL3_BASE_ADDR, 400
|
||||
|
||||
/* Switch peripheral to PLL3 */
|
||||
ldr r0, =CCM_BASE_ADDR
|
||||
ldr r1, =0x00015154
|
||||
str r1, [r0, #CLKCTL_CBCMR]
|
||||
ldr r1, =0x02898945
|
||||
str r1, [r0, #CLKCTL_CBCDR]
|
||||
/* make sure change is effective */
|
||||
1: ldr r1, [r0, #CLKCTL_CDHIPR]
|
||||
cmp r1, #0x0
|
||||
bne 1b
|
||||
|
||||
setup_pll PLL2_BASE_ADDR, 400
|
||||
|
||||
/* Switch peripheral to PLL2 */
|
||||
ldr r0, =CCM_BASE_ADDR
|
||||
ldr r1, =0x00888945
|
||||
str r1, [r0, #CLKCTL_CBCDR]
|
||||
|
||||
ldr r1, =0x00016154
|
||||
str r1, [r0, #CLKCTL_CBCMR]
|
||||
|
||||
/*change uart clk parent to pll2*/
|
||||
ldr r1, [r0, #CLKCTL_CSCMR1]
|
||||
and r1, r1, #0xfcffffff
|
||||
orr r1, r1, #0x01000000
|
||||
str r1, [r0, #CLKCTL_CSCMR1]
|
||||
|
||||
/* make sure change is effective */
|
||||
1: ldr r1, [r0, #CLKCTL_CDHIPR]
|
||||
cmp r1, #0x0
|
||||
bne 1b
|
||||
|
||||
setup_pll PLL3_BASE_ADDR, 216
|
||||
|
||||
setup_pll PLL4_BASE_ADDR, 455
|
||||
|
||||
/* Set the platform clock dividers */
|
||||
ldr r0, =ARM_BASE_ADDR
|
||||
ldr r1, =0x00000124
|
||||
str r1, [r0, #0x14]
|
||||
|
||||
ldr r0, =CCM_BASE_ADDR
|
||||
mov r1, #0
|
||||
str r1, [r0, #CLKCTL_CACRR]
|
||||
|
||||
/* Switch ARM back to PLL 1. */
|
||||
mov r1, #0x0
|
||||
str r1, [r0, #CLKCTL_CCSR]
|
||||
|
||||
/* make uart div=6 */
|
||||
ldr r1, [r0, #CLKCTL_CSCDR1]
|
||||
and r1, r1, #0xffffffc0
|
||||
orr r1, r1, #0x0a
|
||||
str r1, [r0, #CLKCTL_CSCDR1]
|
||||
|
||||
/* Restore the default values in the Gate registers */
|
||||
ldr r1, =0xFFFFFFFF
|
||||
str r1, [r0, #CLKCTL_CCGR0]
|
||||
str r1, [r0, #CLKCTL_CCGR1]
|
||||
str r1, [r0, #CLKCTL_CCGR2]
|
||||
str r1, [r0, #CLKCTL_CCGR3]
|
||||
str r1, [r0, #CLKCTL_CCGR4]
|
||||
str r1, [r0, #CLKCTL_CCGR5]
|
||||
str r1, [r0, #CLKCTL_CCGR6]
|
||||
str r1, [r0, #CLKCTL_CCGR7]
|
||||
|
||||
mov r1, #0x00000
|
||||
str r1, [r0, #CLKCTL_CCDR]
|
||||
|
||||
/* for cko - for ARM div by 8 */
|
||||
mov r1, #0x000A0000
|
||||
add r1, r1, #0x00000F0
|
||||
str r1, [r0, #CLKCTL_CCOSR]
|
||||
|
||||
#endif /* CONFIG_MX53 */
|
||||
.endm
|
||||
|
||||
ENTRY(lowlevel_init)
|
||||
mov r10, lr
|
||||
mov r4, #0 /* Fix R4 to 0 */
|
||||
|
||||
#if defined(CONFIG_SYS_MAIN_PWR_ON)
|
||||
ldr r0, =GPIO1_BASE_ADDR
|
||||
ldr r1, [r0, #0x0]
|
||||
orr r1, r1, #1 << 23
|
||||
str r1, [r0, #0x0]
|
||||
ldr r1, [r0, #0x4]
|
||||
orr r1, r1, #1 << 23
|
||||
str r1, [r0, #0x4]
|
||||
#endif
|
||||
|
||||
init_arm_erratum
|
||||
|
||||
init_l2cc
|
||||
|
||||
init_aips
|
||||
|
||||
init_m4if
|
||||
|
||||
init_clock
|
||||
|
||||
mov pc, r10
|
||||
ENDPROC(lowlevel_init)
|
||||
|
||||
/* Board level setting value */
|
||||
#if defined(CONFIG_MX51_PLL_ERRATA)
|
||||
W_DP_864: .word DP_OP_864
|
||||
.word DP_MFD_864
|
||||
.word DP_MFN_864
|
||||
W_DP_MFN_800_DIT: .word DP_MFN_800_DIT
|
||||
#else
|
||||
W_DP_800: .word DP_OP_800
|
||||
.word DP_MFD_800
|
||||
.word DP_MFN_800
|
||||
#endif
|
||||
#if defined(CONFIG_MX51)
|
||||
W_DP_665: .word DP_OP_665
|
||||
.word DP_MFD_665
|
||||
.word DP_MFN_665
|
||||
#endif
|
||||
W_DP_216: .word DP_OP_216
|
||||
.word DP_MFD_216
|
||||
.word DP_MFN_216
|
||||
W_DP_400: .word DP_OP_400
|
||||
.word DP_MFD_400
|
||||
.word DP_MFN_400
|
||||
W_DP_455: .word DP_OP_455
|
||||
.word DP_MFD_455
|
||||
.word DP_MFN_455
|
||||
116
u-boot/arch/arm/cpu/armv7/mx5/soc.c
Normal file
116
u-boot/arch/arm/cpu/armv7/mx5/soc.c
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* (C) Copyright 2007
|
||||
* Sascha Hauer, Pengutronix
|
||||
*
|
||||
* (C) Copyright 2009 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch/imx-regs.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
|
||||
#include <asm/errno.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/imx-common/boot_mode.h>
|
||||
|
||||
#if !(defined(CONFIG_MX51) || defined(CONFIG_MX53))
|
||||
#error "CPU_TYPE not defined"
|
||||
#endif
|
||||
|
||||
u32 get_cpu_rev(void)
|
||||
{
|
||||
#ifdef CONFIG_MX51
|
||||
int system_rev = 0x51000;
|
||||
#else
|
||||
int system_rev = 0x53000;
|
||||
#endif
|
||||
int reg = __raw_readl(ROM_SI_REV);
|
||||
|
||||
#if defined(CONFIG_MX51)
|
||||
switch (reg) {
|
||||
case 0x02:
|
||||
system_rev |= CHIP_REV_1_1;
|
||||
break;
|
||||
case 0x10:
|
||||
if ((__raw_readl(GPIO1_BASE_ADDR + 0x0) & (0x1 << 22)) == 0)
|
||||
system_rev |= CHIP_REV_2_5;
|
||||
else
|
||||
system_rev |= CHIP_REV_2_0;
|
||||
break;
|
||||
case 0x20:
|
||||
system_rev |= CHIP_REV_3_0;
|
||||
break;
|
||||
default:
|
||||
system_rev |= CHIP_REV_1_0;
|
||||
break;
|
||||
}
|
||||
#else
|
||||
if (reg < 0x20)
|
||||
system_rev |= CHIP_REV_1_0;
|
||||
else
|
||||
system_rev |= reg;
|
||||
#endif
|
||||
return system_rev;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_REVISION_TAG
|
||||
u32 __weak get_board_rev(void)
|
||||
{
|
||||
return get_cpu_rev();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SYS_DCACHE_OFF
|
||||
void enable_caches(void)
|
||||
{
|
||||
/* Enable D-cache. I-cache is already enabled in start.S */
|
||||
dcache_enable();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_FEC_MXC)
|
||||
void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
|
||||
{
|
||||
int i;
|
||||
struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE;
|
||||
struct fuse_bank *bank = &iim->bank[1];
|
||||
struct fuse_bank1_regs *fuse =
|
||||
(struct fuse_bank1_regs *)bank->fuse_regs;
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
mac[i] = readl(&fuse->mac_addr[i]) & 0xff;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MX53
|
||||
void boot_mode_apply(unsigned cfg_val)
|
||||
{
|
||||
writel(cfg_val, &((struct srtc_regs *)SRTC_BASE_ADDR)->lpgr);
|
||||
}
|
||||
/*
|
||||
* cfg_val will be used for
|
||||
* Boot_cfg3[7:0]:Boot_cfg2[7:0]:Boot_cfg1[7:0]
|
||||
*
|
||||
* If bit 28 of LPGR is set upon watchdog reset,
|
||||
* bits[25:0] of LPGR will move to SBMR.
|
||||
*/
|
||||
const struct boot_mode soc_boot_modes[] = {
|
||||
{"normal", MAKE_CFGVAL(0x00, 0x00, 0x00, 0x00)},
|
||||
/* usb or serial download */
|
||||
{"usb", MAKE_CFGVAL(0x00, 0x00, 0x00, 0x13)},
|
||||
{"sata", MAKE_CFGVAL(0x28, 0x00, 0x00, 0x12)},
|
||||
{"escpi1:0", MAKE_CFGVAL(0x38, 0x20, 0x00, 0x12)},
|
||||
{"escpi1:1", MAKE_CFGVAL(0x38, 0x20, 0x04, 0x12)},
|
||||
{"escpi1:2", MAKE_CFGVAL(0x38, 0x20, 0x08, 0x12)},
|
||||
{"escpi1:3", MAKE_CFGVAL(0x38, 0x20, 0x0c, 0x12)},
|
||||
/* 4 bit bus width */
|
||||
{"esdhc1", MAKE_CFGVAL(0x40, 0x20, 0x00, 0x12)},
|
||||
{"esdhc2", MAKE_CFGVAL(0x40, 0x20, 0x08, 0x12)},
|
||||
{"esdhc3", MAKE_CFGVAL(0x40, 0x20, 0x10, 0x12)},
|
||||
{"esdhc4", MAKE_CFGVAL(0x40, 0x20, 0x18, 0x12)},
|
||||
{NULL, 0},
|
||||
};
|
||||
#endif
|
||||
214
u-boot/arch/arm/cpu/armv7/mx6/Kconfig
Normal file
214
u-boot/arch/arm/cpu/armv7/mx6/Kconfig
Normal file
@@ -0,0 +1,214 @@
|
||||
if ARCH_MX6
|
||||
|
||||
config MX6
|
||||
bool
|
||||
default y
|
||||
|
||||
config MX6D
|
||||
bool
|
||||
|
||||
config MX6DL
|
||||
bool
|
||||
|
||||
config MX6Q
|
||||
bool
|
||||
|
||||
config MX6QDL
|
||||
bool
|
||||
|
||||
config MX6S
|
||||
bool
|
||||
|
||||
config MX6SL
|
||||
bool
|
||||
|
||||
config MX6SX
|
||||
select ROM_UNIFIED_SECTIONS
|
||||
bool
|
||||
|
||||
config MX6UL
|
||||
select SYS_L2CACHE_OFF
|
||||
select ROM_UNIFIED_SECTIONS
|
||||
bool
|
||||
|
||||
choice
|
||||
prompt "MX6 board select"
|
||||
optional
|
||||
|
||||
config TARGET_ARISTAINETOS
|
||||
bool "aristainetos"
|
||||
|
||||
config TARGET_ARISTAINETOS2
|
||||
bool "aristainetos2"
|
||||
|
||||
config TARGET_ARISTAINETOS2B
|
||||
bool "Support aristainetos2-revB"
|
||||
|
||||
config TARGET_CGTQMX6EVAL
|
||||
bool "cgtqmx6eval"
|
||||
select SUPPORT_SPL
|
||||
select DM
|
||||
select DM_THERMAL
|
||||
|
||||
config TARGET_CM_FX6
|
||||
bool "CM-FX6"
|
||||
select SUPPORT_SPL
|
||||
select DM
|
||||
select DM_SERIAL
|
||||
select DM_GPIO
|
||||
|
||||
config TARGET_EMBESTMX6BOARDS
|
||||
bool "embestmx6boards"
|
||||
|
||||
config TARGET_GE_B450V3
|
||||
bool "General Electric B450v3"
|
||||
select MX6Q
|
||||
|
||||
config TARGET_GE_B650V3
|
||||
bool "General Electric B650v3"
|
||||
select MX6Q
|
||||
|
||||
config TARGET_GE_B850V3
|
||||
bool "General Electric B850v3"
|
||||
select MX6Q
|
||||
|
||||
config TARGET_GW_VENTANA
|
||||
bool "gw_ventana"
|
||||
select SUPPORT_SPL
|
||||
|
||||
config TARGET_KOSAGI_NOVENA
|
||||
bool "Kosagi Novena"
|
||||
select SUPPORT_SPL
|
||||
|
||||
config TARGET_MX6CUBOXI
|
||||
bool "Solid-run mx6 boards"
|
||||
select SUPPORT_SPL
|
||||
|
||||
config TARGET_MX6QARM2
|
||||
bool "mx6qarm2"
|
||||
|
||||
config TARGET_MX6QSABREAUTO
|
||||
bool "mx6qsabreauto"
|
||||
select DM
|
||||
select DM_THERMAL
|
||||
|
||||
config TARGET_MX6SABRESD
|
||||
bool "mx6sabresd"
|
||||
select SUPPORT_SPL
|
||||
select DM
|
||||
select DM_THERMAL
|
||||
|
||||
config TARGET_MX6SLEVK
|
||||
bool "mx6slevk"
|
||||
select SUPPORT_SPL
|
||||
|
||||
config TARGET_MX6SXSABRESD
|
||||
bool "mx6sxsabresd"
|
||||
select MX6SX
|
||||
select SUPPORT_SPL
|
||||
select DM
|
||||
select DM_THERMAL
|
||||
|
||||
config TARGET_MX6SXSABREAUTO
|
||||
bool "mx6sxsabreauto"
|
||||
select MX6SX
|
||||
select DM
|
||||
select DM_THERMAL
|
||||
|
||||
config TARGET_MX6UL_9X9_EVK
|
||||
bool "mx6ul_9x9_evk"
|
||||
select MX6UL
|
||||
select DM
|
||||
select DM_THERMAL
|
||||
select SUPPORT_SPL
|
||||
|
||||
config TARGET_MX6UL_14X14_EVK
|
||||
bool "mx6ul_14x14_evk"
|
||||
select MX6UL
|
||||
select DM
|
||||
select DM_THERMAL
|
||||
select SUPPORT_SPL
|
||||
|
||||
config TARGET_NITROGEN6X
|
||||
bool "nitrogen6x"
|
||||
|
||||
config TARGET_OT1200
|
||||
bool "Bachmann OT1200"
|
||||
select SUPPORT_SPL
|
||||
|
||||
config TARGET_PICO_IMX6UL
|
||||
bool "PICO-IMX6UL-EMMC"
|
||||
select MX6UL
|
||||
|
||||
config TARGET_PLATINUM_PICON
|
||||
bool "platinum-picon"
|
||||
select SUPPORT_SPL
|
||||
|
||||
config TARGET_PLATINUM_TITANIUM
|
||||
bool "platinum-titanium"
|
||||
select SUPPORT_SPL
|
||||
|
||||
config TARGET_SECOMX6
|
||||
bool "secomx6 boards"
|
||||
|
||||
config TARGET_TBS2910
|
||||
bool "TBS2910 Matrix ARM mini PC"
|
||||
|
||||
config TARGET_TITANIUM
|
||||
bool "titanium"
|
||||
|
||||
config TARGET_TQMA6
|
||||
bool "TQ Systems TQMa6 board"
|
||||
|
||||
config TARGET_UDOO
|
||||
bool "udoo"
|
||||
select SUPPORT_SPL
|
||||
|
||||
config TARGET_WANDBOARD
|
||||
bool "wandboard"
|
||||
select SUPPORT_SPL
|
||||
|
||||
config TARGET_WARP
|
||||
bool "WaRP"
|
||||
|
||||
config TARGET_XPRESS
|
||||
bool "CCV xPress"
|
||||
select MX6UL
|
||||
select DM
|
||||
select DM_THERMAL
|
||||
select SUPPORT_SPL
|
||||
|
||||
endchoice
|
||||
|
||||
config SYS_SOC
|
||||
default "mx6"
|
||||
|
||||
source "board/ge/bx50v3/Kconfig"
|
||||
source "board/aristainetos/Kconfig"
|
||||
source "board/bachmann/ot1200/Kconfig"
|
||||
source "board/barco/platinum/Kconfig"
|
||||
source "board/barco/titanium/Kconfig"
|
||||
source "board/boundary/nitrogen6x/Kconfig"
|
||||
source "board/ccv/xpress/Kconfig"
|
||||
source "board/compulab/cm_fx6/Kconfig"
|
||||
source "board/congatec/cgtqmx6eval/Kconfig"
|
||||
source "board/embest/mx6boards/Kconfig"
|
||||
source "board/freescale/mx6qarm2/Kconfig"
|
||||
source "board/freescale/mx6qsabreauto/Kconfig"
|
||||
source "board/freescale/mx6sabresd/Kconfig"
|
||||
source "board/freescale/mx6slevk/Kconfig"
|
||||
source "board/freescale/mx6sxsabresd/Kconfig"
|
||||
source "board/freescale/mx6sxsabreauto/Kconfig"
|
||||
source "board/freescale/mx6ul_14x14_evk/Kconfig"
|
||||
source "board/gateworks/gw_ventana/Kconfig"
|
||||
source "board/kosagi/novena/Kconfig"
|
||||
source "board/seco/Kconfig"
|
||||
source "board/solidrun/mx6cuboxi/Kconfig"
|
||||
source "board/technexion/pico-imx6ul/Kconfig"
|
||||
source "board/tbs/tbs2910/Kconfig"
|
||||
source "board/tqc/tqma6/Kconfig"
|
||||
source "board/udoo/Kconfig"
|
||||
source "board/wandboard/Kconfig"
|
||||
source "board/warp/Kconfig"
|
||||
|
||||
endif
|
||||
12
u-boot/arch/arm/cpu/armv7/mx6/Makefile
Normal file
12
u-boot/arch/arm/cpu/armv7/mx6/Makefile
Normal file
@@ -0,0 +1,12 @@
|
||||
#
|
||||
# (C) Copyright 2000-2006
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
#
|
||||
# (C) Copyright 2011 Freescale Semiconductor, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y := soc.o clock.o
|
||||
obj-$(CONFIG_SPL_BUILD) += ddr.o
|
||||
obj-$(CONFIG_MP) += mp.o
|
||||
1373
u-boot/arch/arm/cpu/armv7/mx6/clock.c
Normal file
1373
u-boot/arch/arm/cpu/armv7/mx6/clock.c
Normal file
File diff suppressed because it is too large
Load Diff
1497
u-boot/arch/arm/cpu/armv7/mx6/ddr.c
Normal file
1497
u-boot/arch/arm/cpu/armv7/mx6/ddr.c
Normal file
File diff suppressed because it is too large
Load Diff
87
u-boot/arch/arm/cpu/armv7/mx6/mp.c
Normal file
87
u-boot/arch/arm/cpu/armv7/mx6/mp.c
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* (C) Copyright 2014
|
||||
* Gabriel Huau <contact@huau-gabriel.fr>
|
||||
*
|
||||
* (C) Copyright 2009 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
#include <asm/arch/imx-regs.h>
|
||||
|
||||
#define MAX_CPUS 4
|
||||
static struct src *src = (struct src *)SRC_BASE_ADDR;
|
||||
|
||||
static uint32_t cpu_reset_mask[MAX_CPUS] = {
|
||||
0, /* We don't really want to modify the cpu0 */
|
||||
SRC_SCR_CORE_1_RESET_MASK,
|
||||
SRC_SCR_CORE_2_RESET_MASK,
|
||||
SRC_SCR_CORE_3_RESET_MASK
|
||||
};
|
||||
|
||||
static uint32_t cpu_ctrl_mask[MAX_CPUS] = {
|
||||
0, /* We don't really want to modify the cpu0 */
|
||||
SRC_SCR_CORE_1_ENABLE_MASK,
|
||||
SRC_SCR_CORE_2_ENABLE_MASK,
|
||||
SRC_SCR_CORE_3_ENABLE_MASK
|
||||
};
|
||||
|
||||
int cpu_reset(int nr)
|
||||
{
|
||||
/* Software reset of the CPU N */
|
||||
src->scr |= cpu_reset_mask[nr];
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpu_status(int nr)
|
||||
{
|
||||
printf("core %d => %d\n", nr, !!(src->scr & cpu_ctrl_mask[nr]));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpu_release(int nr, int argc, char *const argv[])
|
||||
{
|
||||
uint32_t boot_addr;
|
||||
|
||||
boot_addr = simple_strtoul(argv[0], NULL, 16);
|
||||
|
||||
switch (nr) {
|
||||
case 1:
|
||||
src->gpr3 = boot_addr;
|
||||
break;
|
||||
case 2:
|
||||
src->gpr5 = boot_addr;
|
||||
break;
|
||||
case 3:
|
||||
src->gpr7 = boot_addr;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* CPU N is ready to start */
|
||||
src->scr |= cpu_ctrl_mask[nr];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int is_core_valid(unsigned int core)
|
||||
{
|
||||
uint32_t nr_cores = get_nr_cpus();
|
||||
|
||||
if (core > nr_cores)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cpu_disable(int nr)
|
||||
{
|
||||
/* Disable the CPU N */
|
||||
src->scr &= ~cpu_ctrl_mask[nr];
|
||||
return 0;
|
||||
}
|
||||
650
u-boot/arch/arm/cpu/armv7/mx6/soc.c
Normal file
650
u-boot/arch/arm/cpu/armv7/mx6/soc.c
Normal file
@@ -0,0 +1,650 @@
|
||||
/*
|
||||
* (C) Copyright 2007
|
||||
* Sascha Hauer, Pengutronix
|
||||
*
|
||||
* (C) Copyright 2009 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/imx-regs.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
#include <asm/imx-common/boot_mode.h>
|
||||
#include <asm/imx-common/dma.h>
|
||||
#include <asm/imx-common/hab.h>
|
||||
#include <stdbool.h>
|
||||
#include <asm/arch/mxc_hdmi.h>
|
||||
#include <asm/arch/crm_regs.h>
|
||||
#include <dm.h>
|
||||
#include <imx_thermal.h>
|
||||
#include <mmc.h>
|
||||
|
||||
enum ldo_reg {
|
||||
LDO_ARM,
|
||||
LDO_SOC,
|
||||
LDO_PU,
|
||||
};
|
||||
|
||||
struct scu_regs {
|
||||
u32 ctrl;
|
||||
u32 config;
|
||||
u32 status;
|
||||
u32 invalidate;
|
||||
u32 fpga_rev;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_IMX_THERMAL)
|
||||
static const struct imx_thermal_plat imx6_thermal_plat = {
|
||||
.regs = (void *)ANATOP_BASE_ADDR,
|
||||
.fuse_bank = 1,
|
||||
.fuse_word = 6,
|
||||
};
|
||||
|
||||
U_BOOT_DEVICE(imx6_thermal) = {
|
||||
.name = "imx_thermal",
|
||||
.platdata = &imx6_thermal_plat,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SECURE_BOOT)
|
||||
struct imx_sec_config_fuse_t const imx_sec_config_fuse = {
|
||||
.bank = 0,
|
||||
.word = 6,
|
||||
};
|
||||
#endif
|
||||
|
||||
u32 get_nr_cpus(void)
|
||||
{
|
||||
struct scu_regs *scu = (struct scu_regs *)SCU_BASE_ADDR;
|
||||
return readl(&scu->config) & 3;
|
||||
}
|
||||
|
||||
u32 get_cpu_rev(void)
|
||||
{
|
||||
struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR;
|
||||
u32 reg = readl(&anatop->digprog_sololite);
|
||||
u32 type = ((reg >> 16) & 0xff);
|
||||
u32 major, cfg = 0;
|
||||
|
||||
if (type != MXC_CPU_MX6SL) {
|
||||
reg = readl(&anatop->digprog);
|
||||
struct scu_regs *scu = (struct scu_regs *)SCU_BASE_ADDR;
|
||||
cfg = readl(&scu->config) & 3;
|
||||
type = ((reg >> 16) & 0xff);
|
||||
if (type == MXC_CPU_MX6DL) {
|
||||
if (!cfg)
|
||||
type = MXC_CPU_MX6SOLO;
|
||||
}
|
||||
|
||||
if (type == MXC_CPU_MX6Q) {
|
||||
if (cfg == 1)
|
||||
type = MXC_CPU_MX6D;
|
||||
}
|
||||
|
||||
}
|
||||
major = ((reg >> 8) & 0xff);
|
||||
if ((major >= 1) &&
|
||||
((type == MXC_CPU_MX6Q) || (type == MXC_CPU_MX6D))) {
|
||||
major--;
|
||||
type = MXC_CPU_MX6QP;
|
||||
if (cfg == 1)
|
||||
type = MXC_CPU_MX6DP;
|
||||
}
|
||||
reg &= 0xff; /* mx6 silicon revision */
|
||||
return (type << 12) | (reg + (0x10 * (major + 1)));
|
||||
}
|
||||
|
||||
/*
|
||||
* OCOTP_CFG3[17:16] (see Fusemap Description Table offset 0x440)
|
||||
* defines a 2-bit SPEED_GRADING
|
||||
*/
|
||||
#define OCOTP_CFG3_SPEED_SHIFT 16
|
||||
#define OCOTP_CFG3_SPEED_800MHZ 0
|
||||
#define OCOTP_CFG3_SPEED_850MHZ 1
|
||||
#define OCOTP_CFG3_SPEED_1GHZ 2
|
||||
#define OCOTP_CFG3_SPEED_1P2GHZ 3
|
||||
|
||||
/*
|
||||
* For i.MX6UL
|
||||
*/
|
||||
#define OCOTP_CFG3_SPEED_528MHZ 1
|
||||
#define OCOTP_CFG3_SPEED_696MHZ 2
|
||||
|
||||
u32 get_cpu_speed_grade_hz(void)
|
||||
{
|
||||
struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
|
||||
struct fuse_bank *bank = &ocotp->bank[0];
|
||||
struct fuse_bank0_regs *fuse =
|
||||
(struct fuse_bank0_regs *)bank->fuse_regs;
|
||||
uint32_t val;
|
||||
|
||||
val = readl(&fuse->cfg3);
|
||||
val >>= OCOTP_CFG3_SPEED_SHIFT;
|
||||
val &= 0x3;
|
||||
|
||||
if (is_mx6ul()) {
|
||||
if (val == OCOTP_CFG3_SPEED_528MHZ)
|
||||
return 528000000;
|
||||
else if (val == OCOTP_CFG3_SPEED_696MHZ)
|
||||
return 69600000;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (val) {
|
||||
/* Valid for IMX6DQ */
|
||||
case OCOTP_CFG3_SPEED_1P2GHZ:
|
||||
if (is_mx6dq() || is_mx6dqp())
|
||||
return 1200000000;
|
||||
/* Valid for IMX6SX/IMX6SDL/IMX6DQ */
|
||||
case OCOTP_CFG3_SPEED_1GHZ:
|
||||
return 996000000;
|
||||
/* Valid for IMX6DQ */
|
||||
case OCOTP_CFG3_SPEED_850MHZ:
|
||||
if (is_mx6dq() || is_mx6dqp())
|
||||
return 852000000;
|
||||
/* Valid for IMX6SX/IMX6SDL/IMX6DQ */
|
||||
case OCOTP_CFG3_SPEED_800MHZ:
|
||||
return 792000000;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* OCOTP_MEM0[7:6] (see Fusemap Description Table offset 0x480)
|
||||
* defines a 2-bit Temperature Grade
|
||||
*
|
||||
* return temperature grade and min/max temperature in celcius
|
||||
*/
|
||||
#define OCOTP_MEM0_TEMP_SHIFT 6
|
||||
|
||||
u32 get_cpu_temp_grade(int *minc, int *maxc)
|
||||
{
|
||||
struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
|
||||
struct fuse_bank *bank = &ocotp->bank[1];
|
||||
struct fuse_bank1_regs *fuse =
|
||||
(struct fuse_bank1_regs *)bank->fuse_regs;
|
||||
uint32_t val;
|
||||
|
||||
val = readl(&fuse->mem0);
|
||||
val >>= OCOTP_MEM0_TEMP_SHIFT;
|
||||
val &= 0x3;
|
||||
|
||||
if (minc && maxc) {
|
||||
if (val == TEMP_AUTOMOTIVE) {
|
||||
*minc = -40;
|
||||
*maxc = 125;
|
||||
} else if (val == TEMP_INDUSTRIAL) {
|
||||
*minc = -40;
|
||||
*maxc = 105;
|
||||
} else if (val == TEMP_EXTCOMMERCIAL) {
|
||||
*minc = -20;
|
||||
*maxc = 105;
|
||||
} else {
|
||||
*minc = 0;
|
||||
*maxc = 95;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_REVISION_TAG
|
||||
u32 __weak get_board_rev(void)
|
||||
{
|
||||
u32 cpurev = get_cpu_rev();
|
||||
u32 type = ((cpurev >> 12) & 0xff);
|
||||
if (type == MXC_CPU_MX6SOLO)
|
||||
cpurev = (MXC_CPU_MX6DL) << 12 | (cpurev & 0xFFF);
|
||||
|
||||
if (type == MXC_CPU_MX6D)
|
||||
cpurev = (MXC_CPU_MX6Q) << 12 | (cpurev & 0xFFF);
|
||||
|
||||
return cpurev;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void clear_ldo_ramp(void)
|
||||
{
|
||||
struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR;
|
||||
int reg;
|
||||
|
||||
/* ROM may modify LDO ramp up time according to fuse setting, so in
|
||||
* order to be in the safe side we neeed to reset these settings to
|
||||
* match the reset value: 0'b00
|
||||
*/
|
||||
reg = readl(&anatop->ana_misc2);
|
||||
reg &= ~(0x3f << 24);
|
||||
writel(reg, &anatop->ana_misc2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the PMU_REG_CORE register
|
||||
*
|
||||
* Set LDO_SOC/PU/ARM regulators to the specified millivolt level.
|
||||
* Possible values are from 0.725V to 1.450V in steps of
|
||||
* 0.025V (25mV).
|
||||
*/
|
||||
static int set_ldo_voltage(enum ldo_reg ldo, u32 mv)
|
||||
{
|
||||
struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR;
|
||||
u32 val, step, old, reg = readl(&anatop->reg_core);
|
||||
u8 shift;
|
||||
|
||||
if (mv < 725)
|
||||
val = 0x00; /* Power gated off */
|
||||
else if (mv > 1450)
|
||||
val = 0x1F; /* Power FET switched full on. No regulation */
|
||||
else
|
||||
val = (mv - 700) / 25;
|
||||
|
||||
clear_ldo_ramp();
|
||||
|
||||
switch (ldo) {
|
||||
case LDO_SOC:
|
||||
shift = 18;
|
||||
break;
|
||||
case LDO_PU:
|
||||
shift = 9;
|
||||
break;
|
||||
case LDO_ARM:
|
||||
shift = 0;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
old = (reg & (0x1F << shift)) >> shift;
|
||||
step = abs(val - old);
|
||||
if (step == 0)
|
||||
return 0;
|
||||
|
||||
reg = (reg & ~(0x1F << shift)) | (val << shift);
|
||||
writel(reg, &anatop->reg_core);
|
||||
|
||||
/*
|
||||
* The LDO ramp-up is based on 64 clock cycles of 24 MHz = 2.6 us per
|
||||
* step
|
||||
*/
|
||||
udelay(3 * step);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_ahb_rate(u32 val)
|
||||
{
|
||||
struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
|
||||
u32 reg, div;
|
||||
|
||||
div = get_periph_clk() / val - 1;
|
||||
reg = readl(&mxc_ccm->cbcdr);
|
||||
|
||||
writel((reg & (~MXC_CCM_CBCDR_AHB_PODF_MASK)) |
|
||||
(div << MXC_CCM_CBCDR_AHB_PODF_OFFSET), &mxc_ccm->cbcdr);
|
||||
}
|
||||
|
||||
static void clear_mmdc_ch_mask(void)
|
||||
{
|
||||
struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
|
||||
u32 reg;
|
||||
reg = readl(&mxc_ccm->ccdr);
|
||||
|
||||
/* Clear MMDC channel mask */
|
||||
if (is_mx6sx() || is_mx6ul() || is_mx6sl())
|
||||
reg &= ~(MXC_CCM_CCDR_MMDC_CH1_HS_MASK);
|
||||
else
|
||||
reg &= ~(MXC_CCM_CCDR_MMDC_CH1_HS_MASK | MXC_CCM_CCDR_MMDC_CH0_HS_MASK);
|
||||
writel(reg, &mxc_ccm->ccdr);
|
||||
}
|
||||
|
||||
static void init_bandgap(void)
|
||||
{
|
||||
struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR;
|
||||
/*
|
||||
* Ensure the bandgap has stabilized.
|
||||
*/
|
||||
while (!(readl(&anatop->ana_misc0) & 0x80))
|
||||
;
|
||||
/*
|
||||
* For best noise performance of the analog blocks using the
|
||||
* outputs of the bandgap, the reftop_selfbiasoff bit should
|
||||
* be set.
|
||||
*/
|
||||
writel(BM_ANADIG_ANA_MISC0_REFTOP_SELBIASOFF, &anatop->ana_misc0_set);
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_MX6SL
|
||||
static void set_preclk_from_osc(void)
|
||||
{
|
||||
struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
|
||||
u32 reg;
|
||||
|
||||
reg = readl(&mxc_ccm->cscmr1);
|
||||
reg |= MXC_CCM_CSCMR1_PER_CLK_SEL_MASK;
|
||||
writel(reg, &mxc_ccm->cscmr1);
|
||||
}
|
||||
#endif
|
||||
|
||||
int arch_cpu_init(void)
|
||||
{
|
||||
init_aips();
|
||||
|
||||
/* Need to clear MMDC_CHx_MASK to make warm reset work. */
|
||||
clear_mmdc_ch_mask();
|
||||
|
||||
/*
|
||||
* Disable self-bias circuit in the analog bandap.
|
||||
* The self-bias circuit is used by the bandgap during startup.
|
||||
* This bit should be set after the bandgap has initialized.
|
||||
*/
|
||||
init_bandgap();
|
||||
|
||||
if (!IS_ENABLED(CONFIG_MX6UL)) {
|
||||
/*
|
||||
* When low freq boot is enabled, ROM will not set AHB
|
||||
* freq, so we need to ensure AHB freq is 132MHz in such
|
||||
* scenario.
|
||||
*
|
||||
* To i.MX6UL, when power up, default ARM core and
|
||||
* AHB rate is 396M and 132M.
|
||||
*/
|
||||
if (mxc_get_clock(MXC_ARM_CLK) == 396000000)
|
||||
set_ahb_rate(132000000);
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_MX6UL) && is_soc_rev(CHIP_REV_1_0) == 0) {
|
||||
/*
|
||||
* According to the design team's requirement on i.MX6UL,
|
||||
* the PMIC_STBY_REQ PAD should be configured as open
|
||||
* drain 100K (0x0000b8a0).
|
||||
* Only exists on TO1.0
|
||||
*/
|
||||
writel(0x0000b8a0, IOMUXC_BASE_ADDR + 0x29c);
|
||||
}
|
||||
|
||||
/* Set perclk to source from OSC 24MHz */
|
||||
#if defined(CONFIG_MX6SL)
|
||||
set_preclk_from_osc();
|
||||
#endif
|
||||
|
||||
imx_set_wdog_powerdown(false); /* Disable PDE bit of WMCR register */
|
||||
|
||||
#ifdef CONFIG_APBH_DMA
|
||||
/* Start APBH DMA */
|
||||
mxs_dma_init();
|
||||
#endif
|
||||
|
||||
init_src();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ENV_IS_IN_MMC
|
||||
__weak int board_mmc_get_env_dev(int devno)
|
||||
{
|
||||
return CONFIG_SYS_MMC_ENV_DEV;
|
||||
}
|
||||
|
||||
static int mmc_get_boot_dev(void)
|
||||
{
|
||||
struct src *src_regs = (struct src *)SRC_BASE_ADDR;
|
||||
u32 soc_sbmr = readl(&src_regs->sbmr1);
|
||||
u32 bootsel;
|
||||
int devno;
|
||||
|
||||
/*
|
||||
* Refer to
|
||||
* "i.MX 6Dual/6Quad Applications Processor Reference Manual"
|
||||
* Chapter "8.5.3.1 Expansion Device eFUSE Configuration"
|
||||
* i.MX6SL/SX/UL has same layout.
|
||||
*/
|
||||
bootsel = (soc_sbmr & 0x000000FF) >> 6;
|
||||
|
||||
/* No boot from sd/mmc */
|
||||
if (bootsel != 1)
|
||||
return -1;
|
||||
|
||||
/* BOOT_CFG2[3] and BOOT_CFG2[4] */
|
||||
devno = (soc_sbmr & 0x00001800) >> 11;
|
||||
|
||||
return devno;
|
||||
}
|
||||
|
||||
int mmc_get_env_dev(void)
|
||||
{
|
||||
int devno = mmc_get_boot_dev();
|
||||
|
||||
/* If not boot from sd/mmc, use default value */
|
||||
if (devno < 0)
|
||||
return CONFIG_SYS_MMC_ENV_DEV;
|
||||
|
||||
return board_mmc_get_env_dev(devno);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_MMC_ENV_PART
|
||||
__weak int board_mmc_get_env_part(int devno)
|
||||
{
|
||||
return CONFIG_SYS_MMC_ENV_PART;
|
||||
}
|
||||
|
||||
uint mmc_get_env_part(struct mmc *mmc)
|
||||
{
|
||||
int devno = mmc_get_boot_dev();
|
||||
|
||||
/* If not boot from sd/mmc, use default value */
|
||||
if (devno < 0)
|
||||
return CONFIG_SYS_MMC_ENV_PART;
|
||||
|
||||
return board_mmc_get_env_part(devno);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int board_postclk_init(void)
|
||||
{
|
||||
set_ldo_voltage(LDO_SOC, 1175); /* Set VDDSOC to 1.175V */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_FEC_MXC)
|
||||
void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
|
||||
{
|
||||
struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
|
||||
struct fuse_bank *bank = &ocotp->bank[4];
|
||||
struct fuse_bank4_regs *fuse =
|
||||
(struct fuse_bank4_regs *)bank->fuse_regs;
|
||||
|
||||
if ((is_mx6sx() || is_mx6ul()) && dev_id == 1) {
|
||||
u32 value = readl(&fuse->mac_addr2);
|
||||
mac[0] = value >> 24 ;
|
||||
mac[1] = value >> 16 ;
|
||||
mac[2] = value >> 8 ;
|
||||
mac[3] = value ;
|
||||
|
||||
value = readl(&fuse->mac_addr1);
|
||||
mac[4] = value >> 24 ;
|
||||
mac[5] = value >> 16 ;
|
||||
|
||||
} else {
|
||||
u32 value = readl(&fuse->mac_addr1);
|
||||
mac[0] = (value >> 8);
|
||||
mac[1] = value ;
|
||||
|
||||
value = readl(&fuse->mac_addr0);
|
||||
mac[2] = value >> 24 ;
|
||||
mac[3] = value >> 16 ;
|
||||
mac[4] = value >> 8 ;
|
||||
mac[5] = value ;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* cfg_val will be used for
|
||||
* Boot_cfg4[7:0]:Boot_cfg3[7:0]:Boot_cfg2[7:0]:Boot_cfg1[7:0]
|
||||
* After reset, if GPR10[28] is 1, ROM will use GPR9[25:0]
|
||||
* instead of SBMR1 to determine the boot device.
|
||||
*/
|
||||
const struct boot_mode soc_boot_modes[] = {
|
||||
{"normal", MAKE_CFGVAL(0x00, 0x00, 0x00, 0x00)},
|
||||
/* reserved value should start rom usb */
|
||||
{"usb", MAKE_CFGVAL(0x01, 0x00, 0x00, 0x00)},
|
||||
{"sata", MAKE_CFGVAL(0x20, 0x00, 0x00, 0x00)},
|
||||
{"ecspi1:0", MAKE_CFGVAL(0x30, 0x00, 0x00, 0x08)},
|
||||
{"ecspi1:1", MAKE_CFGVAL(0x30, 0x00, 0x00, 0x18)},
|
||||
{"ecspi1:2", MAKE_CFGVAL(0x30, 0x00, 0x00, 0x28)},
|
||||
{"ecspi1:3", MAKE_CFGVAL(0x30, 0x00, 0x00, 0x38)},
|
||||
/* 4 bit bus width */
|
||||
{"esdhc1", MAKE_CFGVAL(0x40, 0x20, 0x00, 0x00)},
|
||||
{"esdhc2", MAKE_CFGVAL(0x40, 0x28, 0x00, 0x00)},
|
||||
{"esdhc3", MAKE_CFGVAL(0x40, 0x30, 0x00, 0x00)},
|
||||
{"esdhc4", MAKE_CFGVAL(0x40, 0x38, 0x00, 0x00)},
|
||||
{NULL, 0},
|
||||
};
|
||||
|
||||
void reset_misc(void)
|
||||
{
|
||||
#ifdef CONFIG_VIDEO_MXS
|
||||
lcdif_power_down();
|
||||
#endif
|
||||
}
|
||||
|
||||
void s_init(void)
|
||||
{
|
||||
struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR;
|
||||
struct mxc_ccm_reg *ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
|
||||
u32 mask480;
|
||||
u32 mask528;
|
||||
u32 reg, periph1, periph2;
|
||||
|
||||
if (is_mx6sx() || is_mx6ul())
|
||||
return;
|
||||
|
||||
/* Due to hardware limitation, on MX6Q we need to gate/ungate all PFDs
|
||||
* to make sure PFD is working right, otherwise, PFDs may
|
||||
* not output clock after reset, MX6DL and MX6SL have added 396M pfd
|
||||
* workaround in ROM code, as bus clock need it
|
||||
*/
|
||||
|
||||
mask480 = ANATOP_PFD_CLKGATE_MASK(0) |
|
||||
ANATOP_PFD_CLKGATE_MASK(1) |
|
||||
ANATOP_PFD_CLKGATE_MASK(2) |
|
||||
ANATOP_PFD_CLKGATE_MASK(3);
|
||||
mask528 = ANATOP_PFD_CLKGATE_MASK(1) |
|
||||
ANATOP_PFD_CLKGATE_MASK(3);
|
||||
|
||||
reg = readl(&ccm->cbcmr);
|
||||
periph2 = ((reg & MXC_CCM_CBCMR_PRE_PERIPH2_CLK_SEL_MASK)
|
||||
>> MXC_CCM_CBCMR_PRE_PERIPH2_CLK_SEL_OFFSET);
|
||||
periph1 = ((reg & MXC_CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK)
|
||||
>> MXC_CCM_CBCMR_PRE_PERIPH_CLK_SEL_OFFSET);
|
||||
|
||||
/* Checking if PLL2 PFD0 or PLL2 PFD2 is using for periph clock */
|
||||
if ((periph2 != 0x2) && (periph1 != 0x2))
|
||||
mask528 |= ANATOP_PFD_CLKGATE_MASK(0);
|
||||
|
||||
if ((periph2 != 0x1) && (periph1 != 0x1) &&
|
||||
(periph2 != 0x3) && (periph1 != 0x3))
|
||||
mask528 |= ANATOP_PFD_CLKGATE_MASK(2);
|
||||
|
||||
writel(mask480, &anatop->pfd_480_set);
|
||||
writel(mask528, &anatop->pfd_528_set);
|
||||
writel(mask480, &anatop->pfd_480_clr);
|
||||
writel(mask528, &anatop->pfd_528_clr);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IMX_HDMI
|
||||
void imx_enable_hdmi_phy(void)
|
||||
{
|
||||
struct hdmi_regs *hdmi = (struct hdmi_regs *)HDMI_ARB_BASE_ADDR;
|
||||
u8 reg;
|
||||
reg = readb(&hdmi->phy_conf0);
|
||||
reg |= HDMI_PHY_CONF0_PDZ_MASK;
|
||||
writeb(reg, &hdmi->phy_conf0);
|
||||
udelay(3000);
|
||||
reg |= HDMI_PHY_CONF0_ENTMDS_MASK;
|
||||
writeb(reg, &hdmi->phy_conf0);
|
||||
udelay(3000);
|
||||
reg |= HDMI_PHY_CONF0_GEN2_TXPWRON_MASK;
|
||||
writeb(reg, &hdmi->phy_conf0);
|
||||
writeb(HDMI_MC_PHYRSTZ_ASSERT, &hdmi->mc_phyrstz);
|
||||
}
|
||||
|
||||
void imx_setup_hdmi(void)
|
||||
{
|
||||
struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
|
||||
struct hdmi_regs *hdmi = (struct hdmi_regs *)HDMI_ARB_BASE_ADDR;
|
||||
int reg, count;
|
||||
u8 val;
|
||||
|
||||
/* Turn on HDMI PHY clock */
|
||||
reg = readl(&mxc_ccm->CCGR2);
|
||||
reg |= MXC_CCM_CCGR2_HDMI_TX_IAHBCLK_MASK|
|
||||
MXC_CCM_CCGR2_HDMI_TX_ISFRCLK_MASK;
|
||||
writel(reg, &mxc_ccm->CCGR2);
|
||||
writeb(HDMI_MC_PHYRSTZ_DEASSERT, &hdmi->mc_phyrstz);
|
||||
reg = readl(&mxc_ccm->chsccdr);
|
||||
reg &= ~(MXC_CCM_CHSCCDR_IPU1_DI0_PRE_CLK_SEL_MASK|
|
||||
MXC_CCM_CHSCCDR_IPU1_DI0_PODF_MASK|
|
||||
MXC_CCM_CHSCCDR_IPU1_DI0_CLK_SEL_MASK);
|
||||
reg |= (CHSCCDR_PODF_DIVIDE_BY_3
|
||||
<< MXC_CCM_CHSCCDR_IPU1_DI0_PODF_OFFSET)
|
||||
|(CHSCCDR_IPU_PRE_CLK_540M_PFD
|
||||
<< MXC_CCM_CHSCCDR_IPU1_DI0_PRE_CLK_SEL_OFFSET);
|
||||
writel(reg, &mxc_ccm->chsccdr);
|
||||
|
||||
/* Clear the overflow condition */
|
||||
if (readb(&hdmi->ih_fc_stat2) & HDMI_IH_FC_STAT2_OVERFLOW_MASK) {
|
||||
/* TMDS software reset */
|
||||
writeb((u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, &hdmi->mc_swrstz);
|
||||
val = readb(&hdmi->fc_invidconf);
|
||||
/* Need minimum 3 times to write to clear the register */
|
||||
for (count = 0 ; count < 5 ; count++)
|
||||
writeb(val, &hdmi->fc_invidconf);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_IMX_BOOTAUX
|
||||
int arch_auxiliary_core_up(u32 core_id, u32 boot_private_data)
|
||||
{
|
||||
struct src *src_reg;
|
||||
u32 stack, pc;
|
||||
|
||||
if (!boot_private_data)
|
||||
return -EINVAL;
|
||||
|
||||
stack = *(u32 *)boot_private_data;
|
||||
pc = *(u32 *)(boot_private_data + 4);
|
||||
|
||||
/* Set the stack and pc to M4 bootROM */
|
||||
writel(stack, M4_BOOTROM_BASE_ADDR);
|
||||
writel(pc, M4_BOOTROM_BASE_ADDR + 4);
|
||||
|
||||
/* Enable M4 */
|
||||
src_reg = (struct src *)SRC_BASE_ADDR;
|
||||
clrsetbits_le32(&src_reg->scr, SRC_SCR_M4C_NON_SCLR_RST_MASK,
|
||||
SRC_SCR_M4_ENABLE_MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arch_auxiliary_core_check_up(u32 core_id)
|
||||
{
|
||||
struct src *src_reg = (struct src *)SRC_BASE_ADDR;
|
||||
unsigned val;
|
||||
|
||||
val = readl(&src_reg->scr);
|
||||
|
||||
if (val & SRC_SCR_M4C_NON_SCLR_RST_MASK)
|
||||
return 0; /* assert in reset */
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
36
u-boot/arch/arm/cpu/armv7/mx7/Kconfig
Normal file
36
u-boot/arch/arm/cpu/armv7/mx7/Kconfig
Normal file
@@ -0,0 +1,36 @@
|
||||
if ARCH_MX7
|
||||
|
||||
config MX7
|
||||
bool
|
||||
select ROM_UNIFIED_SECTIONS
|
||||
default y
|
||||
|
||||
config MX7D
|
||||
select ROM_UNIFIED_SECTIONS
|
||||
bool
|
||||
|
||||
choice
|
||||
prompt "MX7 board select"
|
||||
optional
|
||||
|
||||
config TARGET_MX7DSABRESD
|
||||
bool "mx7dsabresd"
|
||||
select MX7D
|
||||
select DM
|
||||
select DM_THERMAL
|
||||
|
||||
config TARGET_WARP7
|
||||
bool "warp7"
|
||||
select MX7D
|
||||
select DM
|
||||
select DM_THERMAL
|
||||
|
||||
endchoice
|
||||
|
||||
config SYS_SOC
|
||||
default "mx7"
|
||||
|
||||
source "board/freescale/mx7dsabresd/Kconfig"
|
||||
source "board/warp7/Kconfig"
|
||||
|
||||
endif
|
||||
12
u-boot/arch/arm/cpu/armv7/mx7/Makefile
Normal file
12
u-boot/arch/arm/cpu/armv7/mx7/Makefile
Normal file
@@ -0,0 +1,12 @@
|
||||
#
|
||||
# (C) Copyright 2015 Freescale Semiconductor, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
#
|
||||
|
||||
obj-y := soc.o clock.o clock_slice.o
|
||||
|
||||
ifdef CONFIG_ARMV7_PSCI
|
||||
obj-y += psci-mx7.o psci.o
|
||||
endif
|
||||
1133
u-boot/arch/arm/cpu/armv7/mx7/clock.c
Normal file
1133
u-boot/arch/arm/cpu/armv7/mx7/clock.c
Normal file
File diff suppressed because it is too large
Load Diff
757
u-boot/arch/arm/cpu/armv7/mx7/clock_slice.c
Normal file
757
u-boot/arch/arm/cpu/armv7/mx7/clock_slice.c
Normal file
@@ -0,0 +1,757 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* Author:
|
||||
* Peng Fan <Peng.Fan@freescale.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <div64.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/arch/imx-regs.h>
|
||||
#include <asm/arch/crm_regs.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
|
||||
struct mxc_ccm_reg *imx_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
|
||||
|
||||
static struct clk_root_map root_array[] = {
|
||||
{ARM_A7_CLK_ROOT, CCM_CORE_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_ARM_MAIN_800M_CLK, PLL_ENET_MAIN_500M_CLK,
|
||||
PLL_DRAM_MAIN_1066M_CLK, PLL_SYS_MAIN_480M_CLK,
|
||||
PLL_SYS_PFD0_392M_CLK, PLL_AUDIO_MAIN_CLK, PLL_USB_MAIN_480M_CLK}
|
||||
},
|
||||
{ARM_M4_CLK_ROOT, CCM_BUS_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_MAIN_240M_CLK, PLL_ENET_MAIN_250M_CLK,
|
||||
PLL_SYS_PFD2_270M_CLK, PLL_DRAM_MAIN_533M_CLK, PLL_AUDIO_MAIN_CLK,
|
||||
PLL_VIDEO_MAIN_CLK, PLL_USB_MAIN_480M_CLK}
|
||||
},
|
||||
{ARM_M0_CLK_ROOT, CCM_BUS_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_MAIN_120M_CLK, PLL_ENET_MAIN_125M_CLK,
|
||||
PLL_SYS_PFD2_135M_CLK, PLL_DRAM_MAIN_533M_CLK, PLL_AUDIO_MAIN_CLK,
|
||||
PLL_VIDEO_MAIN_CLK, PLL_USB_MAIN_480M_CLK}
|
||||
},
|
||||
{MAIN_AXI_CLK_ROOT, CCM_BUS_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_PFD1_332M_CLK, PLL_DRAM_MAIN_533M_CLK,
|
||||
PLL_ENET_MAIN_250M_CLK, PLL_SYS_PFD5_CLK, PLL_AUDIO_MAIN_CLK,
|
||||
PLL_VIDEO_MAIN_CLK, PLL_SYS_PFD7_CLK}
|
||||
},
|
||||
{DISP_AXI_CLK_ROOT, CCM_BUS_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_PFD1_332M_CLK, PLL_DRAM_MAIN_533M_CLK,
|
||||
PLL_ENET_MAIN_250M_CLK, PLL_SYS_PFD6_CLK, PLL_SYS_PFD7_CLK,
|
||||
PLL_AUDIO_MAIN_CLK, PLL_VIDEO_MAIN_CLK}
|
||||
},
|
||||
{ENET_AXI_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_PFD2_270M_CLK, PLL_DRAM_MAIN_533M_CLK,
|
||||
PLL_ENET_MAIN_250M_CLK, PLL_SYS_MAIN_240M_CLK, PLL_AUDIO_MAIN_CLK,
|
||||
PLL_VIDEO_MAIN_CLK, PLL_SYS_PFD4_CLK}
|
||||
},
|
||||
{NAND_USDHC_BUS_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_PFD2_270M_CLK, PLL_DRAM_MAIN_533M_CLK,
|
||||
PLL_SYS_MAIN_240M_CLK, PLL_SYS_PFD2_135M_CLK, PLL_SYS_PFD6_CLK,
|
||||
PLL_ENET_MAIN_250M_CLK, PLL_AUDIO_MAIN_CLK}
|
||||
},
|
||||
{AHB_CLK_ROOT, CCM_AHB_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_PFD2_270M_CLK, PLL_DRAM_MAIN_533M_CLK,
|
||||
PLL_SYS_PFD0_392M_CLK, PLL_ENET_MAIN_125M_CLK, PLL_USB_MAIN_480M_CLK,
|
||||
PLL_AUDIO_MAIN_CLK, PLL_VIDEO_MAIN_CLK}
|
||||
},
|
||||
{DRAM_PHYM_CLK_ROOT, CCM_DRAM_PHYM_CHANNEL,
|
||||
{PLL_DRAM_MAIN_1066M_CLK, DRAM_PHYM_ALT_CLK_ROOT}
|
||||
},
|
||||
{DRAM_CLK_ROOT, CCM_DRAM_CHANNEL,
|
||||
{PLL_DRAM_MAIN_1066M_CLK, DRAM_ALT_CLK_ROOT}
|
||||
},
|
||||
{DRAM_PHYM_ALT_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_DRAM_MAIN_533M_CLK, PLL_SYS_MAIN_480M_CLK,
|
||||
PLL_ENET_MAIN_500M_CLK, PLL_USB_MAIN_480M_CLK, PLL_SYS_PFD7_CLK,
|
||||
PLL_AUDIO_MAIN_CLK, PLL_VIDEO_MAIN_CLK}
|
||||
},
|
||||
{DRAM_ALT_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_DRAM_MAIN_533M_CLK, PLL_SYS_MAIN_480M_CLK,
|
||||
PLL_ENET_MAIN_500M_CLK, PLL_ENET_MAIN_250M_CLK,
|
||||
PLL_SYS_PFD0_392M_CLK, PLL_AUDIO_MAIN_CLK, PLL_SYS_PFD2_270M_CLK}
|
||||
},
|
||||
{USB_HSIC_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_MAIN_480M_CLK, PLL_USB_MAIN_480M_CLK,
|
||||
PLL_SYS_PFD3_CLK, PLL_SYS_PFD4_CLK, PLL_SYS_PFD5_CLK,
|
||||
PLL_SYS_PFD6_CLK, PLL_SYS_PFD7_CLK}
|
||||
},
|
||||
{PCIE_CTRL_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_ENET_MAIN_250M_CLK, PLL_SYS_MAIN_240M_CLK,
|
||||
PLL_SYS_PFD2_270M_CLK, PLL_DRAM_MAIN_533M_CLK,
|
||||
PLL_ENET_MAIN_500M_CLK, PLL_SYS_PFD1_332M_CLK, PLL_SYS_PFD6_CLK}
|
||||
},
|
||||
{PCIE_PHY_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_ENET_MAIN_100M_CLK, PLL_ENET_MAIN_500M_CLK,
|
||||
EXT_CLK_1, EXT_CLK_2, EXT_CLK_3,
|
||||
EXT_CLK_4, PLL_SYS_PFD0_392M_CLK}
|
||||
},
|
||||
{EPDC_PIXEL_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_PFD1_332M_CLK, PLL_DRAM_MAIN_533M_CLK,
|
||||
PLL_SYS_MAIN_480M_CLK, PLL_SYS_PFD5_CLK, PLL_SYS_PFD6_CLK,
|
||||
PLL_SYS_PFD7_CLK, PLL_VIDEO_MAIN_CLK}
|
||||
},
|
||||
{LCDIF_PIXEL_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_PFD5_CLK, PLL_DRAM_MAIN_533M_CLK,
|
||||
EXT_CLK_3, PLL_SYS_PFD4_CLK, PLL_SYS_PFD2_270M_CLK,
|
||||
PLL_VIDEO_MAIN_CLK, PLL_USB_MAIN_480M_CLK}
|
||||
},
|
||||
{MIPI_DSI_EXTSER_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_PFD5_CLK, PLL_SYS_PFD3_CLK,
|
||||
PLL_SYS_MAIN_480M_CLK, PLL_SYS_PFD0_196M_CLK, PLL_DRAM_MAIN_533M_CLK,
|
||||
PLL_VIDEO_MAIN_CLK, PLL_AUDIO_MAIN_CLK}
|
||||
},
|
||||
{MIPI_CSI_WARP_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_PFD4_CLK, PLL_SYS_PFD3_CLK,
|
||||
PLL_SYS_MAIN_480M_CLK, PLL_SYS_PFD0_196M_CLK, PLL_DRAM_MAIN_533M_CLK,
|
||||
PLL_VIDEO_MAIN_CLK, PLL_AUDIO_MAIN_CLK}
|
||||
},
|
||||
{MIPI_DPHY_REF_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_MAIN_120M_CLK, PLL_DRAM_MAIN_533M_CLK,
|
||||
PLL_SYS_PFD5_CLK, REF_1M_CLK, EXT_CLK_2,
|
||||
PLL_VIDEO_MAIN_CLK, EXT_CLK_3}
|
||||
},
|
||||
{SAI1_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_PFD2_135M_CLK, PLL_AUDIO_MAIN_CLK,
|
||||
PLL_DRAM_MAIN_533M_CLK, PLL_VIDEO_MAIN_CLK, PLL_SYS_PFD4_CLK,
|
||||
PLL_ENET_MAIN_125M_CLK, EXT_CLK_2}
|
||||
},
|
||||
{SAI2_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_PFD2_135M_CLK, PLL_AUDIO_MAIN_CLK,
|
||||
PLL_DRAM_MAIN_533M_CLK, PLL_VIDEO_MAIN_CLK, PLL_SYS_PFD4_CLK,
|
||||
PLL_ENET_MAIN_125M_CLK, EXT_CLK_2}
|
||||
},
|
||||
{SAI3_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_PFD2_135M_CLK, PLL_AUDIO_MAIN_CLK,
|
||||
PLL_DRAM_MAIN_533M_CLK, PLL_VIDEO_MAIN_CLK, PLL_SYS_PFD4_CLK,
|
||||
PLL_ENET_MAIN_125M_CLK, EXT_CLK_3}
|
||||
},
|
||||
{SPDIF_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_PFD2_135M_CLK, PLL_AUDIO_MAIN_CLK,
|
||||
PLL_DRAM_MAIN_533M_CLK, PLL_VIDEO_MAIN_CLK, PLL_SYS_PFD4_CLK,
|
||||
PLL_ENET_MAIN_125M_CLK, EXT_CLK_3}
|
||||
},
|
||||
{ENET1_REF_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_ENET_MAIN_125M_CLK, PLL_ENET_MAIN_50M_CLK,
|
||||
PLL_ENET_MAIN_25M_CLK, PLL_SYS_MAIN_120M_CLK, PLL_AUDIO_MAIN_CLK,
|
||||
PLL_VIDEO_MAIN_CLK, EXT_CLK_4}
|
||||
},
|
||||
{ENET1_TIME_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_ENET_MAIN_100M_CLK, PLL_AUDIO_MAIN_CLK,
|
||||
EXT_CLK_1, EXT_CLK_2, EXT_CLK_3,
|
||||
EXT_CLK_4, PLL_VIDEO_MAIN_CLK}
|
||||
},
|
||||
{ENET2_REF_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_ENET_MAIN_125M_CLK, PLL_ENET_MAIN_50M_CLK,
|
||||
PLL_ENET_MAIN_25M_CLK, PLL_SYS_MAIN_120M_CLK, PLL_AUDIO_MAIN_CLK,
|
||||
PLL_VIDEO_MAIN_CLK, EXT_CLK_4}
|
||||
},
|
||||
{ENET2_TIME_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_ENET_MAIN_100M_CLK, PLL_AUDIO_MAIN_CLK,
|
||||
EXT_CLK_1, EXT_CLK_2, EXT_CLK_3,
|
||||
EXT_CLK_4, PLL_VIDEO_MAIN_CLK}
|
||||
},
|
||||
{ENET_PHY_REF_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_ENET_MAIN_25M_CLK, PLL_ENET_MAIN_50M_CLK,
|
||||
PLL_ENET_MAIN_125M_CLK, PLL_DRAM_MAIN_533M_CLK, PLL_AUDIO_MAIN_CLK,
|
||||
PLL_VIDEO_MAIN_CLK, PLL_SYS_PFD3_CLK}
|
||||
},
|
||||
{EIM_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_PFD2_135M_CLK, PLL_SYS_MAIN_120M_CLK,
|
||||
PLL_DRAM_MAIN_533M_CLK, PLL_SYS_PFD2_270M_CLK, PLL_SYS_PFD3_CLK,
|
||||
PLL_ENET_MAIN_125M_CLK, PLL_USB_MAIN_480M_CLK}
|
||||
},
|
||||
{NAND_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_MAIN_480M_CLK, PLL_DRAM_MAIN_533M_CLK,
|
||||
PLL_SYS_PFD0_392M_CLK, PLL_SYS_PFD3_CLK, PLL_ENET_MAIN_500M_CLK,
|
||||
PLL_ENET_MAIN_250M_CLK, PLL_VIDEO_MAIN_CLK}
|
||||
},
|
||||
{QSPI_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_PFD4_CLK, PLL_DRAM_MAIN_533M_CLK,
|
||||
PLL_ENET_MAIN_500M_CLK, PLL_SYS_PFD3_CLK, PLL_SYS_PFD2_270M_CLK,
|
||||
PLL_SYS_PFD6_CLK, PLL_SYS_PFD7_CLK}
|
||||
},
|
||||
{USDHC1_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_PFD0_392M_CLK, PLL_DRAM_MAIN_533M_CLK,
|
||||
PLL_ENET_MAIN_500M_CLK, PLL_SYS_PFD4_CLK, PLL_SYS_PFD2_270M_CLK,
|
||||
PLL_SYS_PFD6_CLK, PLL_SYS_PFD7_CLK}
|
||||
},
|
||||
{USDHC2_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_PFD0_392M_CLK, PLL_DRAM_MAIN_533M_CLK,
|
||||
PLL_ENET_MAIN_500M_CLK, PLL_SYS_PFD4_CLK, PLL_SYS_PFD2_270M_CLK,
|
||||
PLL_SYS_PFD6_CLK, PLL_SYS_PFD7_CLK}
|
||||
},
|
||||
{USDHC3_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_PFD0_392M_CLK, PLL_DRAM_MAIN_533M_CLK,
|
||||
PLL_ENET_MAIN_500M_CLK, PLL_SYS_PFD4_CLK, PLL_SYS_PFD2_270M_CLK,
|
||||
PLL_SYS_PFD6_CLK, PLL_SYS_PFD7_CLK}
|
||||
},
|
||||
{CAN1_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_MAIN_120M_CLK, PLL_DRAM_MAIN_533M_CLK,
|
||||
PLL_SYS_MAIN_480M_CLK, PLL_ENET_MAIN_40M_CLK, PLL_USB_MAIN_480M_CLK,
|
||||
EXT_CLK_1, EXT_CLK_4}
|
||||
},
|
||||
{CAN2_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_MAIN_120M_CLK, PLL_DRAM_MAIN_533M_CLK,
|
||||
PLL_SYS_MAIN_480M_CLK, PLL_ENET_MAIN_40M_CLK, PLL_USB_MAIN_480M_CLK,
|
||||
EXT_CLK_1, EXT_CLK_3}
|
||||
},
|
||||
{I2C1_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_MAIN_120M_CLK, PLL_ENET_MAIN_50M_CLK,
|
||||
PLL_DRAM_MAIN_533M_CLK, PLL_AUDIO_MAIN_CLK, PLL_VIDEO_MAIN_CLK,
|
||||
PLL_USB_MAIN_480M_CLK, PLL_SYS_PFD2_135M_CLK}
|
||||
},
|
||||
{I2C2_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_MAIN_120M_CLK, PLL_ENET_MAIN_50M_CLK,
|
||||
PLL_DRAM_MAIN_533M_CLK, PLL_AUDIO_MAIN_CLK, PLL_VIDEO_MAIN_CLK,
|
||||
PLL_USB_MAIN_480M_CLK, PLL_SYS_PFD2_135M_CLK}
|
||||
},
|
||||
{I2C3_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_MAIN_120M_CLK, PLL_ENET_MAIN_50M_CLK,
|
||||
PLL_DRAM_MAIN_533M_CLK, PLL_AUDIO_MAIN_CLK, PLL_VIDEO_MAIN_CLK,
|
||||
PLL_USB_MAIN_480M_CLK, PLL_SYS_PFD2_135M_CLK}
|
||||
},
|
||||
{I2C4_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_MAIN_120M_CLK, PLL_ENET_MAIN_50M_CLK,
|
||||
PLL_DRAM_MAIN_533M_CLK, PLL_AUDIO_MAIN_CLK, PLL_VIDEO_MAIN_CLK,
|
||||
PLL_USB_MAIN_480M_CLK, PLL_SYS_PFD2_135M_CLK}
|
||||
},
|
||||
{UART1_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_MAIN_240M_CLK, PLL_ENET_MAIN_40M_CLK,
|
||||
PLL_ENET_MAIN_100M_CLK, PLL_SYS_MAIN_480M_CLK, EXT_CLK_2,
|
||||
EXT_CLK_4, PLL_USB_MAIN_480M_CLK}
|
||||
},
|
||||
{UART2_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_MAIN_240M_CLK, PLL_ENET_MAIN_40M_CLK,
|
||||
PLL_ENET_MAIN_100M_CLK, PLL_SYS_MAIN_480M_CLK, EXT_CLK_2,
|
||||
EXT_CLK_3, PLL_USB_MAIN_480M_CLK}
|
||||
},
|
||||
{UART3_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_MAIN_240M_CLK, PLL_ENET_MAIN_40M_CLK,
|
||||
PLL_ENET_MAIN_100M_CLK, PLL_SYS_MAIN_480M_CLK, EXT_CLK_2,
|
||||
EXT_CLK_4, PLL_USB_MAIN_480M_CLK}
|
||||
},
|
||||
{UART4_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_MAIN_240M_CLK, PLL_ENET_MAIN_40M_CLK,
|
||||
PLL_ENET_MAIN_100M_CLK, PLL_SYS_MAIN_480M_CLK, EXT_CLK_2,
|
||||
EXT_CLK_3, PLL_USB_MAIN_480M_CLK}
|
||||
},
|
||||
{UART5_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_MAIN_240M_CLK, PLL_ENET_MAIN_40M_CLK,
|
||||
PLL_ENET_MAIN_100M_CLK, PLL_SYS_MAIN_480M_CLK, EXT_CLK_2,
|
||||
EXT_CLK_4, PLL_USB_MAIN_480M_CLK}
|
||||
},
|
||||
{UART6_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_MAIN_240M_CLK, PLL_ENET_MAIN_40M_CLK,
|
||||
PLL_ENET_MAIN_100M_CLK, PLL_SYS_MAIN_480M_CLK, EXT_CLK_2,
|
||||
EXT_CLK_3, PLL_USB_MAIN_480M_CLK}
|
||||
},
|
||||
{UART7_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_MAIN_240M_CLK, PLL_ENET_MAIN_40M_CLK,
|
||||
PLL_ENET_MAIN_100M_CLK, PLL_SYS_MAIN_480M_CLK, EXT_CLK_2,
|
||||
EXT_CLK_4, PLL_USB_MAIN_480M_CLK}
|
||||
},
|
||||
{ECSPI1_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_MAIN_240M_CLK, PLL_ENET_MAIN_40M_CLK,
|
||||
PLL_SYS_MAIN_120M_CLK, PLL_SYS_MAIN_480M_CLK, PLL_SYS_PFD4_CLK,
|
||||
PLL_ENET_MAIN_250M_CLK, PLL_USB_MAIN_480M_CLK}
|
||||
},
|
||||
{ECSPI2_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_MAIN_240M_CLK, PLL_ENET_MAIN_40M_CLK,
|
||||
PLL_SYS_MAIN_120M_CLK, PLL_SYS_MAIN_480M_CLK, PLL_SYS_PFD4_CLK,
|
||||
PLL_ENET_MAIN_250M_CLK, PLL_USB_MAIN_480M_CLK}
|
||||
},
|
||||
{ECSPI3_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_MAIN_240M_CLK, PLL_ENET_MAIN_40M_CLK,
|
||||
PLL_SYS_MAIN_120M_CLK, PLL_SYS_MAIN_480M_CLK, PLL_SYS_PFD4_CLK,
|
||||
PLL_ENET_MAIN_250M_CLK, PLL_USB_MAIN_480M_CLK}
|
||||
},
|
||||
{ECSPI4_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_MAIN_240M_CLK, PLL_ENET_MAIN_40M_CLK,
|
||||
PLL_SYS_MAIN_120M_CLK, PLL_SYS_MAIN_480M_CLK, PLL_SYS_PFD4_CLK,
|
||||
PLL_ENET_MAIN_250M_CLK, PLL_USB_MAIN_480M_CLK}
|
||||
},
|
||||
{PWM1_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_ENET_MAIN_100M_CLK, PLL_SYS_MAIN_120M_CLK,
|
||||
PLL_ENET_MAIN_40M_CLK, PLL_AUDIO_MAIN_CLK, EXT_CLK_1,
|
||||
REF_1M_CLK, PLL_VIDEO_MAIN_CLK}
|
||||
},
|
||||
{PWM2_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_ENET_MAIN_100M_CLK, PLL_SYS_MAIN_120M_CLK,
|
||||
PLL_ENET_MAIN_40M_CLK, PLL_AUDIO_MAIN_CLK, EXT_CLK_1,
|
||||
REF_1M_CLK, PLL_VIDEO_MAIN_CLK}
|
||||
},
|
||||
{PWM3_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_ENET_MAIN_100M_CLK, PLL_SYS_MAIN_120M_CLK,
|
||||
PLL_ENET_MAIN_40M_CLK, PLL_AUDIO_MAIN_CLK, EXT_CLK_2,
|
||||
REF_1M_CLK, PLL_VIDEO_MAIN_CLK}
|
||||
},
|
||||
{PWM4_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_ENET_MAIN_100M_CLK, PLL_SYS_MAIN_120M_CLK,
|
||||
PLL_ENET_MAIN_40M_CLK, PLL_AUDIO_MAIN_CLK, EXT_CLK_2,
|
||||
REF_1M_CLK, PLL_VIDEO_MAIN_CLK}
|
||||
},
|
||||
{FLEXTIMER1_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_ENET_MAIN_100M_CLK, PLL_SYS_MAIN_120M_CLK,
|
||||
PLL_ENET_MAIN_40M_CLK, PLL_AUDIO_MAIN_CLK, EXT_CLK_3,
|
||||
REF_1M_CLK, PLL_VIDEO_MAIN_CLK}
|
||||
},
|
||||
{FLEXTIMER2_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_ENET_MAIN_100M_CLK, PLL_SYS_MAIN_120M_CLK,
|
||||
PLL_ENET_MAIN_40M_CLK, PLL_AUDIO_MAIN_CLK, EXT_CLK_3,
|
||||
REF_1M_CLK, PLL_VIDEO_MAIN_CLK}
|
||||
},
|
||||
{SIM1_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_PFD2_135M_CLK, PLL_SYS_MAIN_120M_CLK,
|
||||
PLL_DRAM_MAIN_533M_CLK, PLL_USB_MAIN_480M_CLK, PLL_AUDIO_MAIN_CLK,
|
||||
PLL_ENET_MAIN_125M_CLK, PLL_SYS_PFD7_CLK}
|
||||
},
|
||||
{SIM2_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_PFD2_135M_CLK, PLL_SYS_MAIN_120M_CLK,
|
||||
PLL_DRAM_MAIN_533M_CLK, PLL_USB_MAIN_480M_CLK, PLL_VIDEO_MAIN_CLK,
|
||||
PLL_ENET_MAIN_125M_CLK, PLL_SYS_PFD7_CLK}
|
||||
},
|
||||
{GPT1_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_ENET_MAIN_100M_CLK, PLL_SYS_PFD0_392M_CLK,
|
||||
PLL_ENET_MAIN_40M_CLK, PLL_VIDEO_MAIN_CLK, REF_1M_CLK,
|
||||
PLL_AUDIO_MAIN_CLK, EXT_CLK_1}
|
||||
},
|
||||
{GPT2_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_ENET_MAIN_100M_CLK, PLL_SYS_PFD0_392M_CLK,
|
||||
PLL_ENET_MAIN_40M_CLK, PLL_VIDEO_MAIN_CLK, REF_1M_CLK,
|
||||
PLL_AUDIO_MAIN_CLK, EXT_CLK_2}
|
||||
},
|
||||
{GPT3_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_ENET_MAIN_100M_CLK, PLL_SYS_PFD0_392M_CLK,
|
||||
PLL_ENET_MAIN_40M_CLK, PLL_VIDEO_MAIN_CLK, REF_1M_CLK,
|
||||
PLL_AUDIO_MAIN_CLK, EXT_CLK_3}
|
||||
},
|
||||
{GPT4_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_ENET_MAIN_100M_CLK, PLL_SYS_PFD0_392M_CLK,
|
||||
PLL_ENET_MAIN_40M_CLK, PLL_VIDEO_MAIN_CLK, REF_1M_CLK,
|
||||
PLL_AUDIO_MAIN_CLK, EXT_CLK_4}
|
||||
},
|
||||
{TRACE_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_PFD2_135M_CLK, PLL_SYS_MAIN_120M_CLK,
|
||||
PLL_DRAM_MAIN_533M_CLK, PLL_ENET_MAIN_125M_CLK, PLL_USB_MAIN_480M_CLK,
|
||||
EXT_CLK_1, EXT_CLK_3}
|
||||
},
|
||||
{WDOG_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_PFD2_135M_CLK, PLL_SYS_MAIN_120M_CLK,
|
||||
PLL_DRAM_MAIN_533M_CLK, PLL_ENET_MAIN_125M_CLK, PLL_USB_MAIN_480M_CLK,
|
||||
REF_1M_CLK, PLL_SYS_PFD1_166M_CLK}
|
||||
},
|
||||
{CSI_MCLK_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_PFD2_135M_CLK, PLL_SYS_MAIN_120M_CLK,
|
||||
PLL_DRAM_MAIN_533M_CLK, PLL_ENET_MAIN_125M_CLK, PLL_AUDIO_MAIN_CLK,
|
||||
PLL_VIDEO_MAIN_CLK, PLL_USB_MAIN_480M_CLK}
|
||||
},
|
||||
{AUDIO_MCLK_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_PFD2_135M_CLK, PLL_SYS_MAIN_120M_CLK,
|
||||
PLL_DRAM_MAIN_533M_CLK, PLL_ENET_MAIN_125M_CLK, PLL_AUDIO_MAIN_CLK,
|
||||
PLL_VIDEO_MAIN_CLK, PLL_USB_MAIN_480M_CLK}
|
||||
},
|
||||
{WRCLK_CLK_ROOT, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_ENET_MAIN_40M_CLK, PLL_DRAM_MAIN_533M_CLK,
|
||||
PLL_USB_MAIN_480M_CLK, PLL_SYS_MAIN_240M_CLK, PLL_SYS_PFD2_270M_CLK,
|
||||
PLL_ENET_MAIN_500M_CLK, PLL_SYS_PFD7_CLK}
|
||||
},
|
||||
{IPP_DO_CLKO1, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_MAIN_480M_CLK, PLL_SYS_MAIN_240M_CLK,
|
||||
PLL_SYS_PFD0_196M_CLK, PLL_SYS_PFD3_CLK, PLL_ENET_MAIN_500M_CLK,
|
||||
PLL_DRAM_MAIN_533M_CLK, REF_1M_CLK}
|
||||
},
|
||||
{IPP_DO_CLKO2, CCM_IP_CHANNEL,
|
||||
{OSC_24M_CLK, PLL_SYS_MAIN_240M_CLK, PLL_SYS_PFD0_392M_CLK,
|
||||
PLL_SYS_PFD1_166M_CLK, PLL_SYS_PFD4_CLK, PLL_AUDIO_MAIN_CLK,
|
||||
PLL_VIDEO_MAIN_CLK, OSC_32K_CLK}
|
||||
},
|
||||
};
|
||||
|
||||
/* select which entry of root_array */
|
||||
static int select(enum clk_root_index clock_id)
|
||||
{
|
||||
int i, size;
|
||||
struct clk_root_map *p = root_array;
|
||||
|
||||
size = ARRAY_SIZE(root_array);
|
||||
|
||||
for (i = 0; i < size; i++, p++) {
|
||||
if (clock_id == p->entry)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int src_supported(int entry, enum clk_root_src clock_src)
|
||||
{
|
||||
int i, size;
|
||||
struct clk_root_map *p = &root_array[entry];
|
||||
|
||||
if ((p->type == CCM_DRAM_PHYM_CHANNEL) || (p->type == CCM_DRAM_CHANNEL))
|
||||
size = 2;
|
||||
else
|
||||
size = 8;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
if (p->src_mux[i] == clock_src)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Set src for clock root slice. */
|
||||
int clock_set_src(enum clk_root_index clock_id, enum clk_root_src clock_src)
|
||||
{
|
||||
int root_entry, src_entry;
|
||||
u32 reg;
|
||||
|
||||
if (clock_id >= CLK_ROOT_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
root_entry = select(clock_id);
|
||||
if (root_entry < 0)
|
||||
return -EINVAL;
|
||||
|
||||
src_entry = src_supported(root_entry, clock_src);
|
||||
if (src_entry < 0)
|
||||
return -EINVAL;
|
||||
|
||||
reg = __raw_readl(&imx_ccm->root[clock_id].target_root);
|
||||
reg &= ~CLK_ROOT_MUX_MASK;
|
||||
reg |= src_entry << CLK_ROOT_MUX_SHIFT;
|
||||
__raw_writel(reg, &imx_ccm->root[clock_id].target_root);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get src of a clock root slice. */
|
||||
int clock_get_src(enum clk_root_index clock_id, enum clk_root_src *p_clock_src)
|
||||
{
|
||||
u32 val;
|
||||
int root_entry;
|
||||
struct clk_root_map *p;
|
||||
|
||||
if (clock_id >= CLK_ROOT_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
val = __raw_readl(&imx_ccm->root[clock_id].target_root);
|
||||
val &= CLK_ROOT_MUX_MASK;
|
||||
val >>= CLK_ROOT_MUX_SHIFT;
|
||||
|
||||
root_entry = select(clock_id);
|
||||
if (root_entry < 0)
|
||||
return -EINVAL;
|
||||
|
||||
p = &root_array[root_entry];
|
||||
*p_clock_src = p->src_mux[val];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clock_set_prediv(enum clk_root_index clock_id, enum root_pre_div pre_div)
|
||||
{
|
||||
int root_entry;
|
||||
struct clk_root_map *p;
|
||||
u32 reg;
|
||||
|
||||
if (clock_id >= CLK_ROOT_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
root_entry = select(clock_id);
|
||||
if (root_entry < 0)
|
||||
return -EINVAL;
|
||||
|
||||
p = &root_array[root_entry];
|
||||
|
||||
if ((p->type == CCM_CORE_CHANNEL) ||
|
||||
(p->type == CCM_DRAM_PHYM_CHANNEL) ||
|
||||
(p->type == CCM_DRAM_CHANNEL)) {
|
||||
if (pre_div != CLK_ROOT_PRE_DIV1) {
|
||||
printf("Error pre div!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
reg = __raw_readl(&imx_ccm->root[clock_id].target_root);
|
||||
reg &= ~CLK_ROOT_PRE_DIV_MASK;
|
||||
reg |= pre_div << CLK_ROOT_PRE_DIV_SHIFT;
|
||||
__raw_writel(reg, &imx_ccm->root[clock_id].target_root);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clock_get_prediv(enum clk_root_index clock_id, enum root_pre_div *pre_div)
|
||||
{
|
||||
u32 val;
|
||||
int root_entry;
|
||||
struct clk_root_map *p;
|
||||
|
||||
if (clock_id >= CLK_ROOT_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
root_entry = select(clock_id);
|
||||
if (root_entry < 0)
|
||||
return -EINVAL;
|
||||
|
||||
p = &root_array[root_entry];
|
||||
|
||||
if ((p->type == CCM_CORE_CHANNEL) ||
|
||||
(p->type == CCM_DRAM_PHYM_CHANNEL) ||
|
||||
(p->type == CCM_DRAM_CHANNEL)) {
|
||||
*pre_div = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
val = __raw_readl(&imx_ccm->root[clock_id].target_root);
|
||||
val &= CLK_ROOT_PRE_DIV_MASK;
|
||||
val >>= CLK_ROOT_PRE_DIV_SHIFT;
|
||||
|
||||
*pre_div = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clock_set_postdiv(enum clk_root_index clock_id, enum root_post_div div)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
if (clock_id >= CLK_ROOT_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (clock_id == DRAM_PHYM_CLK_ROOT) {
|
||||
if (div != CLK_ROOT_POST_DIV1) {
|
||||
printf("Error post div!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Only 3 bit post div. */
|
||||
if ((clock_id == DRAM_CLK_ROOT) && (div > CLK_ROOT_POST_DIV7)) {
|
||||
printf("Error post div!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
reg = __raw_readl(&imx_ccm->root[clock_id].target_root);
|
||||
reg &= ~CLK_ROOT_POST_DIV_MASK;
|
||||
reg |= div << CLK_ROOT_POST_DIV_SHIFT;
|
||||
__raw_writel(reg, &imx_ccm->root[clock_id].target_root);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clock_get_postdiv(enum clk_root_index clock_id, enum root_post_div *div)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (clock_id >= CLK_ROOT_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (clock_id == DRAM_PHYM_CLK_ROOT) {
|
||||
*div = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
val = __raw_readl(&imx_ccm->root[clock_id].target_root);
|
||||
if (clock_id == DRAM_CLK_ROOT)
|
||||
val &= DRAM_CLK_ROOT_POST_DIV_MASK;
|
||||
else
|
||||
val &= CLK_ROOT_POST_DIV_MASK;
|
||||
val >>= CLK_ROOT_POST_DIV_SHIFT;
|
||||
|
||||
*div = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clock_set_autopostdiv(enum clk_root_index clock_id, enum root_auto_div div,
|
||||
int auto_en)
|
||||
{
|
||||
u32 val;
|
||||
int root_entry;
|
||||
struct clk_root_map *p;
|
||||
|
||||
if (clock_id >= CLK_ROOT_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
root_entry = select(clock_id);
|
||||
if (root_entry < 0)
|
||||
return -EINVAL;
|
||||
|
||||
p = &root_array[root_entry];
|
||||
|
||||
if ((p->type != CCM_BUS_CHANNEL) && (p->type != CCM_AHB_CHANNEL)) {
|
||||
printf("Auto postdiv not supported.!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Each time only one filed can be changed, no use target_root_set.
|
||||
*/
|
||||
val = __raw_readl(&imx_ccm->root[clock_id].target_root);
|
||||
val &= ~CLK_ROOT_AUTO_DIV_MASK;
|
||||
val |= (div << CLK_ROOT_AUTO_DIV_SHIFT);
|
||||
|
||||
if (auto_en)
|
||||
val |= CLK_ROOT_AUTO_EN;
|
||||
else
|
||||
val &= ~CLK_ROOT_AUTO_EN;
|
||||
|
||||
__raw_writel(val, &imx_ccm->root[clock_id].target_root);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clock_get_autopostdiv(enum clk_root_index clock_id, enum root_auto_div *div,
|
||||
int *auto_en)
|
||||
{
|
||||
u32 val;
|
||||
int root_entry;
|
||||
struct clk_root_map *p;
|
||||
|
||||
if (clock_id >= CLK_ROOT_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
root_entry = select(clock_id);
|
||||
if (root_entry < 0)
|
||||
return -EINVAL;
|
||||
|
||||
p = &root_array[root_entry];
|
||||
|
||||
/*
|
||||
* Only bus/ahb channel supports auto div.
|
||||
* If unsupported, just set auto_en and div with 0.
|
||||
*/
|
||||
if ((p->type != CCM_BUS_CHANNEL) && (p->type != CCM_AHB_CHANNEL)) {
|
||||
*auto_en = 0;
|
||||
*div = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
val = __raw_readl(&imx_ccm->root[clock_id].target_root);
|
||||
if ((val & CLK_ROOT_AUTO_EN_MASK) == 0)
|
||||
*auto_en = 0;
|
||||
else
|
||||
*auto_en = 1;
|
||||
|
||||
val &= CLK_ROOT_AUTO_DIV_MASK;
|
||||
val >>= CLK_ROOT_AUTO_DIV_SHIFT;
|
||||
|
||||
*div = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clock_get_target_val(enum clk_root_index clock_id, u32 *val)
|
||||
{
|
||||
if (clock_id >= CLK_ROOT_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
*val = __raw_readl(&imx_ccm->root[clock_id].target_root);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clock_set_target_val(enum clk_root_index clock_id, u32 val)
|
||||
{
|
||||
if (clock_id >= CLK_ROOT_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
__raw_writel(val, &imx_ccm->root[clock_id].target_root);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Auto_div and auto_en is ignored, they are rarely used. */
|
||||
int clock_root_cfg(enum clk_root_index clock_id, enum root_pre_div pre_div,
|
||||
enum root_post_div post_div, enum clk_root_src clock_src)
|
||||
{
|
||||
u32 val;
|
||||
int root_entry, src_entry;
|
||||
struct clk_root_map *p;
|
||||
|
||||
if (clock_id >= CLK_ROOT_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
root_entry = select(clock_id);
|
||||
if (root_entry < 0)
|
||||
return -EINVAL;
|
||||
|
||||
p = &root_array[root_entry];
|
||||
|
||||
if ((p->type == CCM_CORE_CHANNEL) ||
|
||||
(p->type == CCM_DRAM_PHYM_CHANNEL) ||
|
||||
(p->type == CCM_DRAM_CHANNEL)) {
|
||||
if (pre_div != CLK_ROOT_PRE_DIV1) {
|
||||
printf("Error pre div!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Only 3 bit post div. */
|
||||
if (p->type == CCM_DRAM_CHANNEL) {
|
||||
if (post_div > CLK_ROOT_POST_DIV7) {
|
||||
printf("Error post div!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (p->type == CCM_DRAM_PHYM_CHANNEL) {
|
||||
if (post_div != CLK_ROOT_POST_DIV1) {
|
||||
printf("Error post div!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
src_entry = src_supported(root_entry, clock_src);
|
||||
if (src_entry < 0)
|
||||
return -EINVAL;
|
||||
|
||||
val = CLK_ROOT_ON | pre_div << CLK_ROOT_PRE_DIV_SHIFT |
|
||||
post_div << CLK_ROOT_POST_DIV_SHIFT |
|
||||
src_entry << CLK_ROOT_MUX_SHIFT;
|
||||
|
||||
__raw_writel(val, &imx_ccm->root[clock_id].target_root);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clock_root_enabled(enum clk_root_index clock_id)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (clock_id >= CLK_ROOT_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* No enable bit for DRAM controller and PHY. Just return enabled.
|
||||
*/
|
||||
if ((clock_id == DRAM_PHYM_CLK_ROOT) || (clock_id == DRAM_CLK_ROOT))
|
||||
return 1;
|
||||
|
||||
val = __raw_readl(&imx_ccm->root[clock_id].target_root);
|
||||
|
||||
return (val & CLK_ROOT_ENABLE_MASK) ? 1 : 0;
|
||||
}
|
||||
|
||||
/* CCGR gate operation */
|
||||
int clock_enable(enum clk_ccgr_index index, bool enable)
|
||||
{
|
||||
if (index >= CCGR_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (enable)
|
||||
__raw_writel(CCM_CLK_ON_MSK,
|
||||
&imx_ccm->ccgr_array[index].ccgr_set);
|
||||
else
|
||||
__raw_writel(CCM_CLK_ON_MSK,
|
||||
&imx_ccm->ccgr_array[index].ccgr_clr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
69
u-boot/arch/arm/cpu/armv7/mx7/psci-mx7.c
Normal file
69
u-boot/arch/arm/cpu/armv7/mx7/psci-mx7.c
Normal file
@@ -0,0 +1,69 @@
|
||||
#include <asm/io.h>
|
||||
#include <asm/psci.h>
|
||||
#include <asm/arch/imx-regs.h>
|
||||
#include <common.h>
|
||||
|
||||
#define __secure __attribute__((section("._secure.text")))
|
||||
|
||||
#define GPC_CPU_PGC_SW_PDN_REQ 0xfc
|
||||
#define GPC_CPU_PGC_SW_PUP_REQ 0xf0
|
||||
#define GPC_PGC_C1 0x840
|
||||
|
||||
#define BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7 0x2
|
||||
|
||||
/* below is for i.MX7D */
|
||||
#define SRC_GPR1_MX7D 0x074
|
||||
#define SRC_A7RCR0 0x004
|
||||
#define SRC_A7RCR1 0x008
|
||||
|
||||
#define BP_SRC_A7RCR0_A7_CORE_RESET0 0
|
||||
#define BP_SRC_A7RCR1_A7_CORE1_ENABLE 1
|
||||
|
||||
static inline void imx_gpcv2_set_m_core_pgc(bool enable, u32 offset)
|
||||
{
|
||||
writel(enable, GPC_IPS_BASE_ADDR + offset);
|
||||
}
|
||||
|
||||
__secure void imx_gpcv2_set_core1_power(bool pdn)
|
||||
{
|
||||
u32 reg = pdn ? GPC_CPU_PGC_SW_PUP_REQ : GPC_CPU_PGC_SW_PDN_REQ;
|
||||
u32 val;
|
||||
|
||||
imx_gpcv2_set_m_core_pgc(true, GPC_PGC_C1);
|
||||
|
||||
val = readl(GPC_IPS_BASE_ADDR + reg);
|
||||
val |= BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7;
|
||||
writel(val, GPC_IPS_BASE_ADDR + reg);
|
||||
|
||||
while ((readl(GPC_IPS_BASE_ADDR + reg) &
|
||||
BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7) != 0)
|
||||
;
|
||||
|
||||
imx_gpcv2_set_m_core_pgc(false, GPC_PGC_C1);
|
||||
}
|
||||
|
||||
__secure void imx_enable_cpu_ca7(int cpu, bool enable)
|
||||
{
|
||||
u32 mask, val;
|
||||
|
||||
mask = 1 << (BP_SRC_A7RCR1_A7_CORE1_ENABLE + cpu - 1);
|
||||
val = readl(SRC_BASE_ADDR + SRC_A7RCR1);
|
||||
val = enable ? val | mask : val & ~mask;
|
||||
writel(val, SRC_BASE_ADDR + SRC_A7RCR1);
|
||||
}
|
||||
|
||||
__secure int imx_cpu_on(int fn, int cpu, int pc)
|
||||
{
|
||||
writel(pc, SRC_BASE_ADDR + cpu * 8 + SRC_GPR1_MX7D);
|
||||
imx_gpcv2_set_core1_power(true);
|
||||
imx_enable_cpu_ca7(cpu, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
__secure int imx_cpu_off(int cpu)
|
||||
{
|
||||
imx_enable_cpu_ca7(cpu, false);
|
||||
imx_gpcv2_set_core1_power(false);
|
||||
writel(0, SRC_BASE_ADDR + cpu * 8 + SRC_GPR1_MX7D + 4);
|
||||
return 0;
|
||||
}
|
||||
54
u-boot/arch/arm/cpu/armv7/mx7/psci.S
Normal file
54
u-boot/arch/arm/cpu/armv7/mx7/psci.S
Normal file
@@ -0,0 +1,54 @@
|
||||
#include <config.h>
|
||||
#include <linux/linkage.h>
|
||||
|
||||
#include <asm/armv7.h>
|
||||
#include <asm/arch-armv7/generictimer.h>
|
||||
#include <asm/psci.h>
|
||||
|
||||
.pushsection ._secure.text, "ax"
|
||||
|
||||
.arch_extension sec
|
||||
|
||||
@ r1 = target CPU
|
||||
@ r2 = target PC
|
||||
|
||||
.globl psci_arch_init
|
||||
psci_arch_init:
|
||||
mov r6, lr
|
||||
|
||||
bl psci_get_cpu_id
|
||||
bl psci_get_cpu_stack_top
|
||||
mov sp, r0
|
||||
|
||||
bx r6
|
||||
|
||||
@ r1 = target CPU
|
||||
@ r2 = target PC
|
||||
|
||||
.globl psci_cpu_on
|
||||
psci_cpu_on:
|
||||
push {lr}
|
||||
|
||||
mov r0, r1
|
||||
bl psci_get_cpu_stack_top
|
||||
str r2, [r0]
|
||||
dsb
|
||||
|
||||
ldr r2, =psci_cpu_entry
|
||||
bl imx_cpu_on
|
||||
|
||||
pop {pc}
|
||||
|
||||
.globl psci_cpu_off
|
||||
psci_cpu_off:
|
||||
|
||||
bl psci_cpu_off_common
|
||||
bl psci_get_cpu_id
|
||||
bl imx_cpu_off
|
||||
|
||||
1: wfi
|
||||
b 1b
|
||||
|
||||
.globl psci_text_end
|
||||
psci_text_end:
|
||||
.popsection
|
||||
451
u-boot/arch/arm/cpu/armv7/mx7/soc.c
Normal file
451
u-boot/arch/arm/cpu/armv7/mx7/soc.c
Normal file
@@ -0,0 +1,451 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/imx-regs.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
#include <asm/imx-common/boot_mode.h>
|
||||
#include <asm/imx-common/dma.h>
|
||||
#include <asm/imx-common/hab.h>
|
||||
#include <asm/imx-common/rdc-sema.h>
|
||||
#include <asm/arch/imx-rdc.h>
|
||||
#include <asm/arch/crm_regs.h>
|
||||
#include <dm.h>
|
||||
#include <imx_thermal.h>
|
||||
|
||||
#if defined(CONFIG_IMX_THERMAL)
|
||||
static const struct imx_thermal_plat imx7_thermal_plat = {
|
||||
.regs = (void *)ANATOP_BASE_ADDR,
|
||||
.fuse_bank = 3,
|
||||
.fuse_word = 3,
|
||||
};
|
||||
|
||||
U_BOOT_DEVICE(imx7_thermal) = {
|
||||
.name = "imx_thermal",
|
||||
.platdata = &imx7_thermal_plat,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_IMX_RDC
|
||||
/*
|
||||
* In current design, if any peripheral was assigned to both A7 and M4,
|
||||
* it will receive ipg_stop or ipg_wait when any of the 2 platforms enter
|
||||
* low power mode. So M4 sleep will cause some peripherals fail to work
|
||||
* at A7 core side. At default, all resources are in domain 0 - 3.
|
||||
*
|
||||
* There are 26 peripherals impacted by this IC issue:
|
||||
* SIM2(sim2/emvsim2)
|
||||
* SIM1(sim1/emvsim1)
|
||||
* UART1/UART2/UART3/UART4/UART5/UART6/UART7
|
||||
* SAI1/SAI2/SAI3
|
||||
* WDOG1/WDOG2/WDOG3/WDOG4
|
||||
* GPT1/GPT2/GPT3/GPT4
|
||||
* PWM1/PWM2/PWM3/PWM4
|
||||
* ENET1/ENET2
|
||||
* Software Workaround:
|
||||
* Here we setup some resources to domain 0 where M4 codes will move
|
||||
* the M4 out of this domain. Then M4 is not able to access them any longer.
|
||||
* This is a workaround for ic issue. So the peripherals are not shared
|
||||
* by them. This way requires the uboot implemented the RDC driver and
|
||||
* set the 26 IPs above to domain 0 only. M4 code will assign resource
|
||||
* to its own domain, if it want to use the resource.
|
||||
*/
|
||||
static rdc_peri_cfg_t const resources[] = {
|
||||
(RDC_PER_SIM1 | RDC_DOMAIN(0)),
|
||||
(RDC_PER_SIM2 | RDC_DOMAIN(0)),
|
||||
(RDC_PER_UART1 | RDC_DOMAIN(0)),
|
||||
(RDC_PER_UART2 | RDC_DOMAIN(0)),
|
||||
(RDC_PER_UART3 | RDC_DOMAIN(0)),
|
||||
(RDC_PER_UART4 | RDC_DOMAIN(0)),
|
||||
(RDC_PER_UART5 | RDC_DOMAIN(0)),
|
||||
(RDC_PER_UART6 | RDC_DOMAIN(0)),
|
||||
(RDC_PER_UART7 | RDC_DOMAIN(0)),
|
||||
(RDC_PER_SAI1 | RDC_DOMAIN(0)),
|
||||
(RDC_PER_SAI2 | RDC_DOMAIN(0)),
|
||||
(RDC_PER_SAI3 | RDC_DOMAIN(0)),
|
||||
(RDC_PER_WDOG1 | RDC_DOMAIN(0)),
|
||||
(RDC_PER_WDOG2 | RDC_DOMAIN(0)),
|
||||
(RDC_PER_WDOG3 | RDC_DOMAIN(0)),
|
||||
(RDC_PER_WDOG4 | RDC_DOMAIN(0)),
|
||||
(RDC_PER_GPT1 | RDC_DOMAIN(0)),
|
||||
(RDC_PER_GPT2 | RDC_DOMAIN(0)),
|
||||
(RDC_PER_GPT3 | RDC_DOMAIN(0)),
|
||||
(RDC_PER_GPT4 | RDC_DOMAIN(0)),
|
||||
(RDC_PER_PWM1 | RDC_DOMAIN(0)),
|
||||
(RDC_PER_PWM2 | RDC_DOMAIN(0)),
|
||||
(RDC_PER_PWM3 | RDC_DOMAIN(0)),
|
||||
(RDC_PER_PWM4 | RDC_DOMAIN(0)),
|
||||
(RDC_PER_ENET1 | RDC_DOMAIN(0)),
|
||||
(RDC_PER_ENET2 | RDC_DOMAIN(0)),
|
||||
};
|
||||
|
||||
static void isolate_resource(void)
|
||||
{
|
||||
imx_rdc_setup_peripherals(resources, ARRAY_SIZE(resources));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SECURE_BOOT)
|
||||
struct imx_sec_config_fuse_t const imx_sec_config_fuse = {
|
||||
.bank = 1,
|
||||
.word = 3,
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* OCOTP_TESTER3[9:8] (see Fusemap Description Table offset 0x440)
|
||||
* defines a 2-bit SPEED_GRADING
|
||||
*/
|
||||
#define OCOTP_TESTER3_SPEED_SHIFT 8
|
||||
#define OCOTP_TESTER3_SPEED_800MHZ 0
|
||||
#define OCOTP_TESTER3_SPEED_850MHZ 1
|
||||
#define OCOTP_TESTER3_SPEED_1GHZ 2
|
||||
|
||||
u32 get_cpu_speed_grade_hz(void)
|
||||
{
|
||||
struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
|
||||
struct fuse_bank *bank = &ocotp->bank[1];
|
||||
struct fuse_bank1_regs *fuse =
|
||||
(struct fuse_bank1_regs *)bank->fuse_regs;
|
||||
uint32_t val;
|
||||
|
||||
val = readl(&fuse->tester3);
|
||||
val >>= OCOTP_TESTER3_SPEED_SHIFT;
|
||||
val &= 0x3;
|
||||
|
||||
switch(val) {
|
||||
case OCOTP_TESTER3_SPEED_800MHZ:
|
||||
return 792000000;
|
||||
case OCOTP_TESTER3_SPEED_850MHZ:
|
||||
return 852000000;
|
||||
case OCOTP_TESTER3_SPEED_1GHZ:
|
||||
return 996000000;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* OCOTP_TESTER3[7:6] (see Fusemap Description Table offset 0x440)
|
||||
* defines a 2-bit SPEED_GRADING
|
||||
*/
|
||||
#define OCOTP_TESTER3_TEMP_SHIFT 6
|
||||
|
||||
u32 get_cpu_temp_grade(int *minc, int *maxc)
|
||||
{
|
||||
struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
|
||||
struct fuse_bank *bank = &ocotp->bank[1];
|
||||
struct fuse_bank1_regs *fuse =
|
||||
(struct fuse_bank1_regs *)bank->fuse_regs;
|
||||
uint32_t val;
|
||||
|
||||
val = readl(&fuse->tester3);
|
||||
val >>= OCOTP_TESTER3_TEMP_SHIFT;
|
||||
val &= 0x3;
|
||||
|
||||
if (minc && maxc) {
|
||||
if (val == TEMP_AUTOMOTIVE) {
|
||||
*minc = -40;
|
||||
*maxc = 125;
|
||||
} else if (val == TEMP_INDUSTRIAL) {
|
||||
*minc = -40;
|
||||
*maxc = 105;
|
||||
} else if (val == TEMP_EXTCOMMERCIAL) {
|
||||
*minc = -20;
|
||||
*maxc = 105;
|
||||
} else {
|
||||
*minc = 0;
|
||||
*maxc = 95;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static bool is_mx7d(void)
|
||||
{
|
||||
struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
|
||||
struct fuse_bank *bank = &ocotp->bank[1];
|
||||
struct fuse_bank1_regs *fuse =
|
||||
(struct fuse_bank1_regs *)bank->fuse_regs;
|
||||
int val;
|
||||
|
||||
val = readl(&fuse->tester4);
|
||||
if (val & 1)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 get_cpu_rev(void)
|
||||
{
|
||||
struct mxc_ccm_anatop_reg *ccm_anatop = (struct mxc_ccm_anatop_reg *)
|
||||
ANATOP_BASE_ADDR;
|
||||
u32 reg = readl(&ccm_anatop->digprog);
|
||||
u32 type = (reg >> 16) & 0xff;
|
||||
|
||||
if (!is_mx7d())
|
||||
type = MXC_CPU_MX7S;
|
||||
|
||||
reg &= 0xff;
|
||||
return (type << 12) | reg;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_REVISION_TAG
|
||||
u32 __weak get_board_rev(void)
|
||||
{
|
||||
return get_cpu_rev();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* enable all periherial can be accessed in nosec mode */
|
||||
static void init_csu(void)
|
||||
{
|
||||
int i = 0;
|
||||
for (i = 0; i < CSU_NUM_REGS; i++)
|
||||
writel(CSU_INIT_SEC_LEVEL0, CSU_IPS_BASE_ADDR + i * 4);
|
||||
}
|
||||
|
||||
static void imx_enet_mdio_fixup(void)
|
||||
{
|
||||
struct iomuxc_gpr_base_regs *gpr_regs =
|
||||
(struct iomuxc_gpr_base_regs *)IOMUXC_GPR_BASE_ADDR;
|
||||
|
||||
/*
|
||||
* The management data input/output (MDIO) requires open-drain,
|
||||
* i.MX7D TO1.0 ENET MDIO pin has no open drain, but TO1.1 supports
|
||||
* this feature. So to TO1.1, need to enable open drain by setting
|
||||
* bits GPR0[8:7].
|
||||
*/
|
||||
|
||||
if (soc_rev() >= CHIP_REV_1_1) {
|
||||
setbits_le32(&gpr_regs->gpr[0],
|
||||
IOMUXC_GPR_GPR0_ENET_MDIO_OPEN_DRAIN_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
int arch_cpu_init(void)
|
||||
{
|
||||
init_aips();
|
||||
|
||||
init_csu();
|
||||
/* Disable PDE bit of WMCR register */
|
||||
imx_set_wdog_powerdown(false);
|
||||
|
||||
imx_enet_mdio_fixup();
|
||||
|
||||
#ifdef CONFIG_APBH_DMA
|
||||
/* Start APBH DMA */
|
||||
mxs_dma_init();
|
||||
#endif
|
||||
|
||||
if (IS_ENABLED(CONFIG_IMX_RDC))
|
||||
isolate_resource();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_TAG
|
||||
void get_board_serial(struct tag_serialnr *serialnr)
|
||||
{
|
||||
struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
|
||||
struct fuse_bank *bank = &ocotp->bank[0];
|
||||
struct fuse_bank0_regs *fuse =
|
||||
(struct fuse_bank0_regs *)bank->fuse_regs;
|
||||
|
||||
serialnr->low = fuse->tester0;
|
||||
serialnr->high = fuse->tester1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_FEC_MXC)
|
||||
void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
|
||||
{
|
||||
struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
|
||||
struct fuse_bank *bank = &ocotp->bank[9];
|
||||
struct fuse_bank9_regs *fuse =
|
||||
(struct fuse_bank9_regs *)bank->fuse_regs;
|
||||
|
||||
if (0 == dev_id) {
|
||||
u32 value = readl(&fuse->mac_addr1);
|
||||
mac[0] = (value >> 8);
|
||||
mac[1] = value;
|
||||
|
||||
value = readl(&fuse->mac_addr0);
|
||||
mac[2] = value >> 24;
|
||||
mac[3] = value >> 16;
|
||||
mac[4] = value >> 8;
|
||||
mac[5] = value;
|
||||
} else {
|
||||
u32 value = readl(&fuse->mac_addr2);
|
||||
mac[0] = value >> 24;
|
||||
mac[1] = value >> 16;
|
||||
mac[2] = value >> 8;
|
||||
mac[3] = value;
|
||||
|
||||
value = readl(&fuse->mac_addr1);
|
||||
mac[4] = value >> 24;
|
||||
mac[5] = value >> 16;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_IMX_BOOTAUX
|
||||
int arch_auxiliary_core_up(u32 core_id, u32 boot_private_data)
|
||||
{
|
||||
u32 stack, pc;
|
||||
struct src *src_reg = (struct src *)SRC_BASE_ADDR;
|
||||
|
||||
if (!boot_private_data)
|
||||
return 1;
|
||||
|
||||
stack = *(u32 *)boot_private_data;
|
||||
pc = *(u32 *)(boot_private_data + 4);
|
||||
|
||||
/* Set the stack and pc to M4 bootROM */
|
||||
writel(stack, M4_BOOTROM_BASE_ADDR);
|
||||
writel(pc, M4_BOOTROM_BASE_ADDR + 4);
|
||||
|
||||
/* Enable M4 */
|
||||
clrsetbits_le32(&src_reg->m4rcr, SRC_M4RCR_M4C_NON_SCLR_RST_MASK,
|
||||
SRC_M4RCR_ENABLE_M4_MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arch_auxiliary_core_check_up(u32 core_id)
|
||||
{
|
||||
uint32_t val;
|
||||
struct src *src_reg = (struct src *)SRC_BASE_ADDR;
|
||||
|
||||
val = readl(&src_reg->m4rcr);
|
||||
if (val & 0x00000001)
|
||||
return 0; /* assert in reset */
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
void set_wdog_reset(struct wdog_regs *wdog)
|
||||
{
|
||||
u32 reg = readw(&wdog->wcr);
|
||||
/*
|
||||
* Output WDOG_B signal to reset external pmic or POR_B decided by
|
||||
* the board desgin. Without external reset, the peripherals/DDR/
|
||||
* PMIC are not reset, that may cause system working abnormal.
|
||||
*/
|
||||
reg = readw(&wdog->wcr);
|
||||
reg |= 1 << 3;
|
||||
/*
|
||||
* WDZST bit is write-once only bit. Align this bit in kernel,
|
||||
* otherwise kernel code will have no chance to set this bit.
|
||||
*/
|
||||
reg |= 1 << 0;
|
||||
writew(reg, &wdog->wcr);
|
||||
}
|
||||
|
||||
/*
|
||||
* cfg_val will be used for
|
||||
* Boot_cfg4[7:0]:Boot_cfg3[7:0]:Boot_cfg2[7:0]:Boot_cfg1[7:0]
|
||||
* After reset, if GPR10[28] is 1, ROM will copy GPR9[25:0]
|
||||
* to SBMR1, which will determine the boot device.
|
||||
*/
|
||||
const struct boot_mode soc_boot_modes[] = {
|
||||
{"ecspi1:0", MAKE_CFGVAL(0x00, 0x60, 0x00, 0x00)},
|
||||
{"ecspi1:1", MAKE_CFGVAL(0x40, 0x62, 0x00, 0x00)},
|
||||
{"ecspi1:2", MAKE_CFGVAL(0x80, 0x64, 0x00, 0x00)},
|
||||
{"ecspi1:3", MAKE_CFGVAL(0xc0, 0x66, 0x00, 0x00)},
|
||||
|
||||
{"weim", MAKE_CFGVAL(0x00, 0x50, 0x00, 0x00)},
|
||||
{"qspi1", MAKE_CFGVAL(0x10, 0x40, 0x00, 0x00)},
|
||||
/* 4 bit bus width */
|
||||
{"usdhc1", MAKE_CFGVAL(0x10, 0x10, 0x00, 0x00)},
|
||||
{"usdhc2", MAKE_CFGVAL(0x10, 0x14, 0x00, 0x00)},
|
||||
{"usdhc3", MAKE_CFGVAL(0x10, 0x18, 0x00, 0x00)},
|
||||
{"mmc1", MAKE_CFGVAL(0x10, 0x20, 0x00, 0x00)},
|
||||
{"mmc2", MAKE_CFGVAL(0x10, 0x24, 0x00, 0x00)},
|
||||
{"mmc3", MAKE_CFGVAL(0x10, 0x28, 0x00, 0x00)},
|
||||
{NULL, 0},
|
||||
};
|
||||
|
||||
enum boot_device get_boot_device(void)
|
||||
{
|
||||
struct bootrom_sw_info **p =
|
||||
(struct bootrom_sw_info **)ROM_SW_INFO_ADDR;
|
||||
|
||||
enum boot_device boot_dev = SD1_BOOT;
|
||||
u8 boot_type = (*p)->boot_dev_type;
|
||||
u8 boot_instance = (*p)->boot_dev_instance;
|
||||
|
||||
switch (boot_type) {
|
||||
case BOOT_TYPE_SD:
|
||||
boot_dev = boot_instance + SD1_BOOT;
|
||||
break;
|
||||
case BOOT_TYPE_MMC:
|
||||
boot_dev = boot_instance + MMC1_BOOT;
|
||||
break;
|
||||
case BOOT_TYPE_NAND:
|
||||
boot_dev = NAND_BOOT;
|
||||
break;
|
||||
case BOOT_TYPE_QSPI:
|
||||
boot_dev = QSPI_BOOT;
|
||||
break;
|
||||
case BOOT_TYPE_WEIM:
|
||||
boot_dev = WEIM_NOR_BOOT;
|
||||
break;
|
||||
case BOOT_TYPE_SPINOR:
|
||||
boot_dev = SPI_NOR_BOOT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return boot_dev;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ENV_IS_IN_MMC
|
||||
__weak int board_mmc_get_env_dev(int devno)
|
||||
{
|
||||
return CONFIG_SYS_MMC_ENV_DEV;
|
||||
}
|
||||
|
||||
int mmc_get_env_dev(void)
|
||||
{
|
||||
struct bootrom_sw_info **p =
|
||||
(struct bootrom_sw_info **)ROM_SW_INFO_ADDR;
|
||||
int devno = (*p)->boot_dev_instance;
|
||||
u8 boot_type = (*p)->boot_dev_type;
|
||||
|
||||
/* If not boot from sd/mmc, use default value */
|
||||
if ((boot_type != BOOT_TYPE_SD) && (boot_type != BOOT_TYPE_MMC))
|
||||
return CONFIG_SYS_MMC_ENV_DEV;
|
||||
|
||||
return board_mmc_get_env_dev(devno);
|
||||
}
|
||||
#endif
|
||||
|
||||
void s_init(void)
|
||||
{
|
||||
#if !defined CONFIG_SPL_BUILD
|
||||
/* Enable SMP mode for CPU0, by setting bit 6 of Auxiliary Ctl reg */
|
||||
asm volatile(
|
||||
"mrc p15, 0, r0, c1, c0, 1\n"
|
||||
"orr r0, r0, #1 << 6\n"
|
||||
"mcr p15, 0, r0, c1, c0, 1\n");
|
||||
#endif
|
||||
/* clock configuration. */
|
||||
clock_init();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void reset_misc(void)
|
||||
{
|
||||
#ifdef CONFIG_VIDEO_MXS
|
||||
lcdif_power_down();
|
||||
#endif
|
||||
}
|
||||
|
||||
219
u-boot/arch/arm/cpu/armv7/nonsec_virt.S
Normal file
219
u-boot/arch/arm/cpu/armv7/nonsec_virt.S
Normal file
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* code for switching cores into non-secure state and into HYP mode
|
||||
*
|
||||
* Copyright (c) 2013 Andre Przywara <andre.przywara@linaro.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/gic.h>
|
||||
#include <asm/armv7.h>
|
||||
#include <asm/proc-armv/ptrace.h>
|
||||
|
||||
.arch_extension sec
|
||||
.arch_extension virt
|
||||
|
||||
.pushsection ._secure.text, "ax"
|
||||
|
||||
.align 5
|
||||
/* the vector table for secure state and HYP mode */
|
||||
_monitor_vectors:
|
||||
.word 0 /* reset */
|
||||
.word 0 /* undef */
|
||||
adr pc, _secure_monitor
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
|
||||
.macro is_cpu_virt_capable tmp
|
||||
mrc p15, 0, \tmp, c0, c1, 1 @ read ID_PFR1
|
||||
and \tmp, \tmp, #CPUID_ARM_VIRT_MASK @ mask virtualization bits
|
||||
cmp \tmp, #(1 << CPUID_ARM_VIRT_SHIFT)
|
||||
.endm
|
||||
|
||||
/*
|
||||
* secure monitor handler
|
||||
* U-Boot calls this "software interrupt" in start.S
|
||||
* This is executed on a "smc" instruction, we use a "smc #0" to switch
|
||||
* to non-secure state.
|
||||
* r0, r1, r2: passed to the callee
|
||||
* ip: target PC
|
||||
*/
|
||||
_secure_monitor:
|
||||
#ifdef CONFIG_ARMV7_PSCI
|
||||
ldr r5, =_psci_vectors @ Switch to the next monitor
|
||||
mcr p15, 0, r5, c12, c0, 1
|
||||
isb
|
||||
|
||||
@ Obtain a secure stack, and configure the PSCI backend
|
||||
bl psci_arch_init
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARM_ERRATA_773022
|
||||
mrc p15, 0, r5, c1, c0, 1
|
||||
orr r5, r5, #(1 << 1)
|
||||
mcr p15, 0, r5, c1, c0, 1
|
||||
isb
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARM_ERRATA_774769
|
||||
mrc p15, 0, r5, c1, c0, 1
|
||||
orr r5, r5, #(1 << 25)
|
||||
mcr p15, 0, r5, c1, c0, 1
|
||||
isb
|
||||
#endif
|
||||
|
||||
mrc p15, 0, r5, c1, c1, 0 @ read SCR
|
||||
bic r5, r5, #0x4a @ clear IRQ, EA, nET bits
|
||||
orr r5, r5, #0x31 @ enable NS, AW, FW bits
|
||||
@ FIQ preserved for secure mode
|
||||
mov r6, #SVC_MODE @ default mode is SVC
|
||||
is_cpu_virt_capable r4
|
||||
#ifdef CONFIG_ARMV7_VIRT
|
||||
orreq r5, r5, #0x100 @ allow HVC instruction
|
||||
moveq r6, #HYP_MODE @ Enter the kernel as HYP
|
||||
#endif
|
||||
|
||||
mcr p15, 0, r5, c1, c1, 0 @ write SCR (with NS bit set)
|
||||
isb
|
||||
|
||||
bne 1f
|
||||
|
||||
@ Reset CNTVOFF to 0 before leaving monitor mode
|
||||
mrc p15, 0, r4, c0, c1, 1 @ read ID_PFR1
|
||||
ands r4, r4, #CPUID_ARM_GENTIMER_MASK @ test arch timer bits
|
||||
movne r4, #0
|
||||
mcrrne p15, 4, r4, r4, c14 @ Reset CNTVOFF to zero
|
||||
1:
|
||||
mov lr, ip
|
||||
mov ip, #(F_BIT | I_BIT | A_BIT) @ Set A, I and F
|
||||
tst lr, #1 @ Check for Thumb PC
|
||||
orrne ip, ip, #T_BIT @ Set T if Thumb
|
||||
orr ip, ip, r6 @ Slot target mode in
|
||||
msr spsr_cxfs, ip @ Set full SPSR
|
||||
movs pc, lr @ ERET to non-secure
|
||||
|
||||
ENTRY(_do_nonsec_entry)
|
||||
mov ip, r0
|
||||
mov r0, r1
|
||||
mov r1, r2
|
||||
mov r2, r3
|
||||
smc #0
|
||||
ENDPROC(_do_nonsec_entry)
|
||||
|
||||
.macro get_cbar_addr addr
|
||||
#ifdef CONFIG_ARM_GIC_BASE_ADDRESS
|
||||
ldr \addr, =CONFIG_ARM_GIC_BASE_ADDRESS
|
||||
#else
|
||||
mrc p15, 4, \addr, c15, c0, 0 @ read CBAR
|
||||
bfc \addr, #0, #15 @ clear reserved bits
|
||||
#endif
|
||||
.endm
|
||||
|
||||
.macro get_gicd_addr addr
|
||||
get_cbar_addr \addr
|
||||
add \addr, \addr, #GIC_DIST_OFFSET @ GIC dist i/f offset
|
||||
.endm
|
||||
|
||||
.macro get_gicc_addr addr, tmp
|
||||
get_cbar_addr \addr
|
||||
is_cpu_virt_capable \tmp
|
||||
movne \tmp, #GIC_CPU_OFFSET_A9 @ GIC CPU offset for A9
|
||||
moveq \tmp, #GIC_CPU_OFFSET_A15 @ GIC CPU offset for A15/A7
|
||||
add \addr, \addr, \tmp
|
||||
.endm
|
||||
|
||||
#ifndef CONFIG_ARMV7_PSCI
|
||||
/*
|
||||
* Secondary CPUs start here and call the code for the core specific parts
|
||||
* of the non-secure and HYP mode transition. The GIC distributor specific
|
||||
* code has already been executed by a C function before.
|
||||
* Then they go back to wfi and wait to be woken up by the kernel again.
|
||||
*/
|
||||
ENTRY(_smp_pen)
|
||||
cpsid i
|
||||
cpsid f
|
||||
|
||||
bl _nonsec_init
|
||||
|
||||
adr r0, _smp_pen @ do not use this address again
|
||||
b smp_waitloop @ wait for IPIs, board specific
|
||||
ENDPROC(_smp_pen)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Switch a core to non-secure state.
|
||||
*
|
||||
* 1. initialize the GIC per-core interface
|
||||
* 2. allow coprocessor access in non-secure modes
|
||||
*
|
||||
* Called from smp_pen by secondary cores and directly by the BSP.
|
||||
* Do not assume that the stack is available and only use registers
|
||||
* r0-r3 and r12.
|
||||
*
|
||||
* PERIPHBASE is used to get the GIC address. This could be 40 bits long,
|
||||
* though, but we check this in C before calling this function.
|
||||
*/
|
||||
ENTRY(_nonsec_init)
|
||||
get_gicd_addr r3
|
||||
|
||||
mvn r1, #0 @ all bits to 1
|
||||
str r1, [r3, #GICD_IGROUPRn] @ allow private interrupts
|
||||
|
||||
get_gicc_addr r3, r1
|
||||
|
||||
mov r1, #3 @ Enable both groups
|
||||
str r1, [r3, #GICC_CTLR] @ and clear all other bits
|
||||
mov r1, #0xff
|
||||
str r1, [r3, #GICC_PMR] @ set priority mask register
|
||||
|
||||
mrc p15, 0, r0, c1, c1, 2
|
||||
movw r1, #0x3fff
|
||||
movt r1, #0x0004
|
||||
orr r0, r0, r1
|
||||
mcr p15, 0, r0, c1, c1, 2 @ NSACR = all copros to non-sec
|
||||
|
||||
/* The CNTFRQ register of the generic timer needs to be
|
||||
* programmed in secure state. Some primary bootloaders / firmware
|
||||
* omit this, so if the frequency is provided in the configuration,
|
||||
* we do this here instead.
|
||||
* But first check if we have the generic timer.
|
||||
*/
|
||||
#ifdef CONFIG_TIMER_CLK_FREQ
|
||||
mrc p15, 0, r0, c0, c1, 1 @ read ID_PFR1
|
||||
and r0, r0, #CPUID_ARM_GENTIMER_MASK @ mask arch timer bits
|
||||
cmp r0, #(1 << CPUID_ARM_GENTIMER_SHIFT)
|
||||
ldreq r1, =CONFIG_TIMER_CLK_FREQ
|
||||
mcreq p15, 0, r1, c14, c0, 0 @ write CNTFRQ
|
||||
#endif
|
||||
|
||||
adr r1, _monitor_vectors
|
||||
mcr p15, 0, r1, c12, c0, 1 @ set MVBAR to secure vectors
|
||||
isb
|
||||
|
||||
mov r0, r3 @ return GICC address
|
||||
bx lr
|
||||
ENDPROC(_nonsec_init)
|
||||
|
||||
#ifdef CONFIG_SMP_PEN_ADDR
|
||||
/* void __weak smp_waitloop(unsigned previous_address); */
|
||||
ENTRY(smp_waitloop)
|
||||
wfi
|
||||
ldr r1, =CONFIG_SMP_PEN_ADDR @ load start address
|
||||
ldr r1, [r1]
|
||||
#ifdef CONFIG_PEN_ADDR_BIG_ENDIAN
|
||||
rev r1, r1
|
||||
#endif
|
||||
cmp r0, r1 @ make sure we dont execute this code
|
||||
beq smp_waitloop @ again (due to a spurious wakeup)
|
||||
mov r0, r1
|
||||
b _do_nonsec_entry
|
||||
ENDPROC(smp_waitloop)
|
||||
.weak smp_waitloop
|
||||
#endif
|
||||
|
||||
.popsection
|
||||
17
u-boot/arch/arm/cpu/armv7/omap-common/Kconfig
Normal file
17
u-boot/arch/arm/cpu/armv7/omap-common/Kconfig
Normal file
@@ -0,0 +1,17 @@
|
||||
config TI_SECURE_DEVICE
|
||||
bool "HS Device Type Support"
|
||||
depends on OMAP54XX || AM43XX
|
||||
help
|
||||
If a high secure (HS) device type is being used, this config
|
||||
must be set. This option impacts various aspects of the
|
||||
build system (to create signed boot images that can be
|
||||
authenticated) and the code. See the doc/README.ti-secure
|
||||
file for further details.
|
||||
|
||||
source "arch/arm/cpu/armv7/omap3/Kconfig"
|
||||
|
||||
source "arch/arm/cpu/armv7/omap4/Kconfig"
|
||||
|
||||
source "arch/arm/cpu/armv7/omap5/Kconfig"
|
||||
|
||||
source "arch/arm/cpu/armv7/am33xx/Kconfig"
|
||||
38
u-boot/arch/arm/cpu/armv7/omap-common/Makefile
Normal file
38
u-boot/arch/arm/cpu/armv7/omap-common/Makefile
Normal file
@@ -0,0 +1,38 @@
|
||||
#
|
||||
# (C) Copyright 2000-2003
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y := reset.o
|
||||
ifeq ($(CONFIG_TIMER),)
|
||||
obj-y += timer.o
|
||||
else
|
||||
ifdef CONFIG_SPL_BUILD
|
||||
obj-y += timer.o
|
||||
endif
|
||||
endif
|
||||
obj-y += utils.o
|
||||
|
||||
ifneq ($(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX),)
|
||||
obj-y += hwinit-common.o
|
||||
obj-y += clocks-common.o
|
||||
obj-y += emif-common.o
|
||||
obj-y += vc.o
|
||||
obj-y += abb.o
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_OMAP54XX),)
|
||||
obj-y += pipe3-phy.o
|
||||
obj-$(CONFIG_SCSI_AHCI_PLAT) += sata.o
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SYS_DCACHE_OFF),)
|
||||
obj-y += omap-cache.o
|
||||
endif
|
||||
|
||||
obj-y += boot-common.o
|
||||
obj-y += lowlevel_init.o
|
||||
|
||||
obj-y += mem-common.o
|
||||
121
u-boot/arch/arm/cpu/armv7/omap-common/abb.c
Normal file
121
u-boot/arch/arm/cpu/armv7/omap-common/abb.c
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Adaptive Body Bias programming sequence for OMAP family
|
||||
*
|
||||
* (C) Copyright 2013
|
||||
* Texas Instruments, <www.ti.com>
|
||||
*
|
||||
* Andrii Tseglytskyi <andrii.tseglytskyi@ti.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/omap_common.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
|
||||
__weak s8 abb_setup_ldovbb(u32 fuse, u32 ldovbb)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void abb_setup_timings(u32 setup)
|
||||
{
|
||||
u32 sys_rate, sr2_cnt, clk_cycles;
|
||||
|
||||
/*
|
||||
* SR2_WTCNT_VALUE is the settling time for the ABB ldo after a
|
||||
* transition and must be programmed with the correct time at boot.
|
||||
* The value programmed into the register is the number of SYS_CLK
|
||||
* clock cycles that match a given wall time profiled for the ldo.
|
||||
* This value depends on:
|
||||
* settling time of ldo in micro-seconds (varies per OMAP family),
|
||||
* of clock cycles per SYS_CLK period (varies per OMAP family),
|
||||
* the SYS_CLK frequency in MHz (varies per board)
|
||||
* The formula is:
|
||||
*
|
||||
* ldo settling time (in micro-seconds)
|
||||
* SR2_WTCNT_VALUE = ------------------------------------------
|
||||
* (# system clock cycles) * (sys_clk period)
|
||||
*
|
||||
* Put another way:
|
||||
*
|
||||
* SR2_WTCNT_VALUE = settling time / (# SYS_CLK cycles / SYS_CLK rate))
|
||||
*
|
||||
* To avoid dividing by zero multiply both "# clock cycles" and
|
||||
* "settling time" by 10 such that the final result is the one we want.
|
||||
*/
|
||||
|
||||
/* calculate SR2_WTCNT_VALUE */
|
||||
sys_rate = DIV_ROUND_CLOSEST(V_OSCK, 1000000);
|
||||
clk_cycles = DIV_ROUND_CLOSEST(OMAP_ABB_CLOCK_CYCLES * 10, sys_rate);
|
||||
sr2_cnt = DIV_ROUND_CLOSEST(OMAP_ABB_SETTLING_TIME * 10, clk_cycles);
|
||||
|
||||
setbits_le32(setup,
|
||||
sr2_cnt << (ffs(OMAP_ABB_SETUP_SR2_WTCNT_VALUE_MASK) - 1));
|
||||
}
|
||||
|
||||
void abb_setup(u32 fuse, u32 ldovbb, u32 setup, u32 control,
|
||||
u32 txdone, u32 txdone_mask, u32 opp)
|
||||
{
|
||||
u32 abb_type_mask, opp_sel_mask;
|
||||
|
||||
/* sanity check */
|
||||
if (!setup || !control || !txdone)
|
||||
return;
|
||||
|
||||
/* setup ABB only in case of Fast or Slow OPP */
|
||||
switch (opp) {
|
||||
case OMAP_ABB_FAST_OPP:
|
||||
abb_type_mask = OMAP_ABB_SETUP_ACTIVE_FBB_SEL_MASK;
|
||||
opp_sel_mask = OMAP_ABB_CONTROL_FAST_OPP_SEL_MASK;
|
||||
break;
|
||||
case OMAP_ABB_SLOW_OPP:
|
||||
abb_type_mask = OMAP_ABB_SETUP_ACTIVE_RBB_SEL_MASK;
|
||||
opp_sel_mask = OMAP_ABB_CONTROL_SLOW_OPP_SEL_MASK;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* For some OMAP silicons additional setup for LDOVBB register is
|
||||
* required. This is determined by data retrieved from corresponding
|
||||
* OPP EFUSE register. Data, which is retrieved from EFUSE - is
|
||||
* ABB enable/disable flag and VSET value, which must be copied
|
||||
* to LDOVBB register. If function call fails - return quietly,
|
||||
* it means no ABB is required for such silicon.
|
||||
*
|
||||
* For silicons, which don't require LDOVBB setup "fuse" and
|
||||
* "ldovbb" offsets are not defined. ABB will be initialized in
|
||||
* the common way for them.
|
||||
*/
|
||||
if (fuse && ldovbb) {
|
||||
if (abb_setup_ldovbb(fuse, ldovbb))
|
||||
return;
|
||||
}
|
||||
|
||||
/* clear ABB registers */
|
||||
writel(0, setup);
|
||||
writel(0, control);
|
||||
|
||||
/* configure timings, based on oscillator value */
|
||||
abb_setup_timings(setup);
|
||||
|
||||
/* clear pending interrupts before setup */
|
||||
setbits_le32(txdone, txdone_mask);
|
||||
|
||||
/* select ABB type */
|
||||
setbits_le32(setup, abb_type_mask | OMAP_ABB_SETUP_SR2EN_MASK);
|
||||
|
||||
/* initiate ABB ldo change */
|
||||
setbits_le32(control, opp_sel_mask | OMAP_ABB_CONTROL_OPP_CHANGE_MASK);
|
||||
|
||||
/* wait until transition complete */
|
||||
if (!wait_on_value(txdone_mask, txdone_mask, (void *)txdone, LDELAY))
|
||||
puts("Error: ABB txdone is not set\n");
|
||||
|
||||
/* clear ABB tranxdone */
|
||||
setbits_le32(txdone, txdone_mask);
|
||||
}
|
||||
247
u-boot/arch/arm/cpu/armv7/omap-common/boot-common.c
Normal file
247
u-boot/arch/arm/cpu/armv7/omap-common/boot-common.c
Normal file
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* boot-common.c
|
||||
*
|
||||
* Common bootmode functions for omap based boards
|
||||
*
|
||||
* Copyright (C) 2011, Texas Instruments, Incorporated - http://www.ti.com/
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <ahci.h>
|
||||
#include <spl.h>
|
||||
#include <asm/omap_common.h>
|
||||
#include <asm/arch/omap.h>
|
||||
#include <asm/arch/mmc_host_def.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
#include <watchdog.h>
|
||||
#include <scsi.h>
|
||||
#include <i2c.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
__weak u32 omap_sys_boot_device(void)
|
||||
{
|
||||
return BOOT_DEVICE_NONE;
|
||||
}
|
||||
|
||||
void save_omap_boot_params(void)
|
||||
{
|
||||
u32 boot_params = *((u32 *)OMAP_SRAM_SCRATCH_BOOT_PARAMS);
|
||||
struct omap_boot_parameters *omap_boot_params;
|
||||
int sys_boot_device = 0;
|
||||
u32 boot_device;
|
||||
u32 boot_mode;
|
||||
|
||||
if ((boot_params < NON_SECURE_SRAM_START) ||
|
||||
(boot_params > NON_SECURE_SRAM_END))
|
||||
return;
|
||||
|
||||
omap_boot_params = (struct omap_boot_parameters *)boot_params;
|
||||
|
||||
boot_device = omap_boot_params->boot_device;
|
||||
boot_mode = MMCSD_MODE_UNDEFINED;
|
||||
|
||||
/* Boot device */
|
||||
|
||||
#ifdef BOOT_DEVICE_NAND_I2C
|
||||
/*
|
||||
* Re-map NAND&I2C boot-device to the "normal" NAND boot-device.
|
||||
* Otherwise the SPL boot IF can't handle this device correctly.
|
||||
* Somehow booting with Hynix 4GBit NAND H27U4G8 on Siemens
|
||||
* Draco leads to this boot-device passed to SPL from the BootROM.
|
||||
*/
|
||||
if (boot_device == BOOT_DEVICE_NAND_I2C)
|
||||
boot_device = BOOT_DEVICE_NAND;
|
||||
#endif
|
||||
#ifdef BOOT_DEVICE_QSPI_4
|
||||
/*
|
||||
* We get different values for QSPI_1 and QSPI_4 being used, but
|
||||
* don't actually care about this difference. Rather than
|
||||
* mangle the later code, if we're coming in as QSPI_4 just
|
||||
* change to the QSPI_1 value.
|
||||
*/
|
||||
if (boot_device == BOOT_DEVICE_QSPI_4)
|
||||
boot_device = BOOT_DEVICE_SPI;
|
||||
#endif
|
||||
/*
|
||||
* When booting from peripheral booting, the boot device is not usable
|
||||
* as-is (unless there is support for it), so the boot device is instead
|
||||
* figured out using the SYS_BOOT pins.
|
||||
*/
|
||||
switch (boot_device) {
|
||||
#if defined(BOOT_DEVICE_UART) && !defined(CONFIG_SPL_YMODEM_SUPPORT)
|
||||
case BOOT_DEVICE_UART:
|
||||
sys_boot_device = 1;
|
||||
break;
|
||||
#endif
|
||||
#if defined(BOOT_DEVICE_USB) && !defined(CONFIG_SPL_USB_SUPPORT)
|
||||
case BOOT_DEVICE_USB:
|
||||
sys_boot_device = 1;
|
||||
break;
|
||||
#endif
|
||||
#if defined(BOOT_DEVICE_USBETH) && !defined(CONFIG_SPL_USBETH_SUPPORT)
|
||||
case BOOT_DEVICE_USBETH:
|
||||
sys_boot_device = 1;
|
||||
break;
|
||||
#endif
|
||||
#if defined(BOOT_DEVICE_CPGMAC) && !defined(CONFIG_SPL_ETH_SUPPORT)
|
||||
case BOOT_DEVICE_CPGMAC:
|
||||
sys_boot_device = 1;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (sys_boot_device) {
|
||||
boot_device = omap_sys_boot_device();
|
||||
|
||||
/* MMC raw mode will fallback to FS mode. */
|
||||
if ((boot_device >= MMC_BOOT_DEVICES_START) &&
|
||||
(boot_device <= MMC_BOOT_DEVICES_END))
|
||||
boot_mode = MMCSD_MODE_RAW;
|
||||
}
|
||||
|
||||
gd->arch.omap_boot_device = boot_device;
|
||||
|
||||
/* Boot mode */
|
||||
|
||||
#ifdef CONFIG_OMAP34XX
|
||||
if ((boot_device >= MMC_BOOT_DEVICES_START) &&
|
||||
(boot_device <= MMC_BOOT_DEVICES_END)) {
|
||||
switch (boot_device) {
|
||||
case BOOT_DEVICE_MMC1:
|
||||
boot_mode = MMCSD_MODE_FS;
|
||||
break;
|
||||
case BOOT_DEVICE_MMC2:
|
||||
boot_mode = MMCSD_MODE_RAW;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* If the boot device was dynamically changed and doesn't match what
|
||||
* the bootrom initially booted, we cannot use the boot device
|
||||
* descriptor to figure out the boot mode.
|
||||
*/
|
||||
if ((boot_device == omap_boot_params->boot_device) &&
|
||||
(boot_device >= MMC_BOOT_DEVICES_START) &&
|
||||
(boot_device <= MMC_BOOT_DEVICES_END)) {
|
||||
boot_params = omap_boot_params->boot_device_descriptor;
|
||||
if ((boot_params < NON_SECURE_SRAM_START) ||
|
||||
(boot_params > NON_SECURE_SRAM_END))
|
||||
return;
|
||||
|
||||
boot_params = *((u32 *)(boot_params + DEVICE_DATA_OFFSET));
|
||||
if ((boot_params < NON_SECURE_SRAM_START) ||
|
||||
(boot_params > NON_SECURE_SRAM_END))
|
||||
return;
|
||||
|
||||
boot_mode = *((u32 *)(boot_params + BOOT_MODE_OFFSET));
|
||||
|
||||
if (boot_mode != MMCSD_MODE_FS &&
|
||||
boot_mode != MMCSD_MODE_RAW)
|
||||
#ifdef CONFIG_SUPPORT_EMMC_BOOT
|
||||
boot_mode = MMCSD_MODE_EMMCBOOT;
|
||||
#else
|
||||
boot_mode = MMCSD_MODE_UNDEFINED;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
gd->arch.omap_boot_mode = boot_mode;
|
||||
|
||||
#if !defined(CONFIG_TI814X) && !defined(CONFIG_TI816X) && \
|
||||
!defined(CONFIG_AM33XX) && !defined(CONFIG_AM43XX)
|
||||
|
||||
/* CH flags */
|
||||
|
||||
gd->arch.omap_ch_flags = omap_boot_params->ch_flags;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPL_BUILD
|
||||
u32 spl_boot_device(void)
|
||||
{
|
||||
return gd->arch.omap_boot_device;
|
||||
}
|
||||
|
||||
u32 spl_boot_mode(const u32 boot_device)
|
||||
{
|
||||
return gd->arch.omap_boot_mode;
|
||||
}
|
||||
|
||||
void spl_board_init(void)
|
||||
{
|
||||
/*
|
||||
* Save the boot parameters passed from romcode.
|
||||
* We cannot delay the saving further than this,
|
||||
* to prevent overwrites.
|
||||
*/
|
||||
save_omap_boot_params();
|
||||
|
||||
/* Prepare console output */
|
||||
preloader_console_init();
|
||||
|
||||
#if defined(CONFIG_SPL_NAND_SUPPORT) || defined(CONFIG_SPL_ONENAND_SUPPORT)
|
||||
gpmc_init();
|
||||
#endif
|
||||
#ifdef CONFIG_SPL_I2C_SUPPORT
|
||||
i2c_init(CONFIG_SYS_OMAP24_I2C_SPEED, CONFIG_SYS_OMAP24_I2C_SLAVE);
|
||||
#endif
|
||||
#if defined(CONFIG_AM33XX) && defined(CONFIG_SPL_MUSB_NEW_SUPPORT)
|
||||
arch_misc_init();
|
||||
#endif
|
||||
#if defined(CONFIG_HW_WATCHDOG)
|
||||
hw_watchdog_init();
|
||||
#endif
|
||||
#ifdef CONFIG_AM33XX
|
||||
am33xx_spl_board_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
__weak int board_mmc_init(bd_t *bis)
|
||||
{
|
||||
switch (spl_boot_device()) {
|
||||
case BOOT_DEVICE_MMC1:
|
||||
omap_mmc_init(0, 0, 0, -1, -1);
|
||||
break;
|
||||
case BOOT_DEVICE_MMC2:
|
||||
case BOOT_DEVICE_MMC2_2:
|
||||
omap_mmc_init(0, 0, 0, -1, -1);
|
||||
omap_mmc_init(1, 0, 0, -1, -1);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image)
|
||||
{
|
||||
typedef void __noreturn (*image_entry_noargs_t)(u32 *);
|
||||
image_entry_noargs_t image_entry =
|
||||
(image_entry_noargs_t) spl_image->entry_point;
|
||||
|
||||
u32 boot_params = *((u32 *)OMAP_SRAM_SCRATCH_BOOT_PARAMS);
|
||||
|
||||
debug("image entry point: 0x%X\n", spl_image->entry_point);
|
||||
/* Pass the saved boot_params from rom code */
|
||||
image_entry((u32 *)boot_params);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SCSI_AHCI_PLAT
|
||||
void arch_preboot_os(void)
|
||||
{
|
||||
ahci_reset((void __iomem *)DWC_AHSATA_BASE);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_FUNCTION_FASTBOOT) && !defined(CONFIG_ENV_IS_NOWHERE)
|
||||
int fb_set_reboot_flag(void)
|
||||
{
|
||||
printf("Setting reboot to fastboot flag ...\n");
|
||||
setenv("dofastboot", "1");
|
||||
saveenv();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
939
u-boot/arch/arm/cpu/armv7/omap-common/clocks-common.c
Normal file
939
u-boot/arch/arm/cpu/armv7/omap-common/clocks-common.c
Normal file
@@ -0,0 +1,939 @@
|
||||
/*
|
||||
*
|
||||
* Clock initialization for OMAP4
|
||||
*
|
||||
* (C) Copyright 2010
|
||||
* Texas Instruments, <www.ti.com>
|
||||
*
|
||||
* Aneesh V <aneesh@ti.com>
|
||||
*
|
||||
* Based on previous work by:
|
||||
* Santosh Shilimkar <santosh.shilimkar@ti.com>
|
||||
* Rajendra Nayak <rnayak@ti.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <i2c.h>
|
||||
#include <asm/omap_common.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
#include <asm/utils.h>
|
||||
#include <asm/omap_gpio.h>
|
||||
#include <asm/emif.h>
|
||||
|
||||
#ifndef CONFIG_SPL_BUILD
|
||||
/*
|
||||
* printing to console doesn't work unless
|
||||
* this code is executed from SPL
|
||||
*/
|
||||
#define printf(fmt, args...)
|
||||
#define puts(s)
|
||||
#endif
|
||||
|
||||
const u32 sys_clk_array[8] = {
|
||||
12000000, /* 12 MHz */
|
||||
20000000, /* 20 MHz */
|
||||
16800000, /* 16.8 MHz */
|
||||
19200000, /* 19.2 MHz */
|
||||
26000000, /* 26 MHz */
|
||||
27000000, /* 27 MHz */
|
||||
38400000, /* 38.4 MHz */
|
||||
};
|
||||
|
||||
static inline u32 __get_sys_clk_index(void)
|
||||
{
|
||||
s8 ind;
|
||||
/*
|
||||
* For ES1 the ROM code calibration of sys clock is not reliable
|
||||
* due to hw issue. So, use hard-coded value. If this value is not
|
||||
* correct for any board over-ride this function in board file
|
||||
* From ES2.0 onwards you will get this information from
|
||||
* CM_SYS_CLKSEL
|
||||
*/
|
||||
if (omap_revision() == OMAP4430_ES1_0)
|
||||
ind = OMAP_SYS_CLK_IND_38_4_MHZ;
|
||||
else {
|
||||
/* SYS_CLKSEL - 1 to match the dpll param array indices */
|
||||
ind = (readl((*prcm)->cm_sys_clksel) &
|
||||
CM_SYS_CLKSEL_SYS_CLKSEL_MASK) - 1;
|
||||
}
|
||||
return ind;
|
||||
}
|
||||
|
||||
u32 get_sys_clk_index(void)
|
||||
__attribute__ ((weak, alias("__get_sys_clk_index")));
|
||||
|
||||
u32 get_sys_clk_freq(void)
|
||||
{
|
||||
u8 index = get_sys_clk_index();
|
||||
return sys_clk_array[index];
|
||||
}
|
||||
|
||||
void setup_post_dividers(u32 const base, const struct dpll_params *params)
|
||||
{
|
||||
struct dpll_regs *const dpll_regs = (struct dpll_regs *)base;
|
||||
|
||||
/* Setup post-dividers */
|
||||
if (params->m2 >= 0)
|
||||
writel(params->m2, &dpll_regs->cm_div_m2_dpll);
|
||||
if (params->m3 >= 0)
|
||||
writel(params->m3, &dpll_regs->cm_div_m3_dpll);
|
||||
if (params->m4_h11 >= 0)
|
||||
writel(params->m4_h11, &dpll_regs->cm_div_m4_h11_dpll);
|
||||
if (params->m5_h12 >= 0)
|
||||
writel(params->m5_h12, &dpll_regs->cm_div_m5_h12_dpll);
|
||||
if (params->m6_h13 >= 0)
|
||||
writel(params->m6_h13, &dpll_regs->cm_div_m6_h13_dpll);
|
||||
if (params->m7_h14 >= 0)
|
||||
writel(params->m7_h14, &dpll_regs->cm_div_m7_h14_dpll);
|
||||
if (params->h21 >= 0)
|
||||
writel(params->h21, &dpll_regs->cm_div_h21_dpll);
|
||||
if (params->h22 >= 0)
|
||||
writel(params->h22, &dpll_regs->cm_div_h22_dpll);
|
||||
if (params->h23 >= 0)
|
||||
writel(params->h23, &dpll_regs->cm_div_h23_dpll);
|
||||
if (params->h24 >= 0)
|
||||
writel(params->h24, &dpll_regs->cm_div_h24_dpll);
|
||||
}
|
||||
|
||||
static inline void do_bypass_dpll(u32 const base)
|
||||
{
|
||||
struct dpll_regs *dpll_regs = (struct dpll_regs *)base;
|
||||
|
||||
clrsetbits_le32(&dpll_regs->cm_clkmode_dpll,
|
||||
CM_CLKMODE_DPLL_DPLL_EN_MASK,
|
||||
DPLL_EN_FAST_RELOCK_BYPASS <<
|
||||
CM_CLKMODE_DPLL_EN_SHIFT);
|
||||
}
|
||||
|
||||
static inline void wait_for_bypass(u32 const base)
|
||||
{
|
||||
struct dpll_regs *const dpll_regs = (struct dpll_regs *)base;
|
||||
|
||||
if (!wait_on_value(ST_DPLL_CLK_MASK, 0, &dpll_regs->cm_idlest_dpll,
|
||||
LDELAY)) {
|
||||
printf("Bypassing DPLL failed %x\n", base);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void do_lock_dpll(u32 const base)
|
||||
{
|
||||
struct dpll_regs *const dpll_regs = (struct dpll_regs *)base;
|
||||
|
||||
clrsetbits_le32(&dpll_regs->cm_clkmode_dpll,
|
||||
CM_CLKMODE_DPLL_DPLL_EN_MASK,
|
||||
DPLL_EN_LOCK << CM_CLKMODE_DPLL_EN_SHIFT);
|
||||
}
|
||||
|
||||
static inline void wait_for_lock(u32 const base)
|
||||
{
|
||||
struct dpll_regs *const dpll_regs = (struct dpll_regs *)base;
|
||||
|
||||
if (!wait_on_value(ST_DPLL_CLK_MASK, ST_DPLL_CLK_MASK,
|
||||
&dpll_regs->cm_idlest_dpll, LDELAY)) {
|
||||
printf("DPLL locking failed for %x\n", base);
|
||||
hang();
|
||||
}
|
||||
}
|
||||
|
||||
inline u32 check_for_lock(u32 const base)
|
||||
{
|
||||
struct dpll_regs *const dpll_regs = (struct dpll_regs *)base;
|
||||
u32 lock = readl(&dpll_regs->cm_idlest_dpll) & ST_DPLL_CLK_MASK;
|
||||
|
||||
return lock;
|
||||
}
|
||||
|
||||
const struct dpll_params *get_mpu_dpll_params(struct dplls const *dpll_data)
|
||||
{
|
||||
u32 sysclk_ind = get_sys_clk_index();
|
||||
return &dpll_data->mpu[sysclk_ind];
|
||||
}
|
||||
|
||||
const struct dpll_params *get_core_dpll_params(struct dplls const *dpll_data)
|
||||
{
|
||||
u32 sysclk_ind = get_sys_clk_index();
|
||||
return &dpll_data->core[sysclk_ind];
|
||||
}
|
||||
|
||||
const struct dpll_params *get_per_dpll_params(struct dplls const *dpll_data)
|
||||
{
|
||||
u32 sysclk_ind = get_sys_clk_index();
|
||||
return &dpll_data->per[sysclk_ind];
|
||||
}
|
||||
|
||||
const struct dpll_params *get_iva_dpll_params(struct dplls const *dpll_data)
|
||||
{
|
||||
u32 sysclk_ind = get_sys_clk_index();
|
||||
return &dpll_data->iva[sysclk_ind];
|
||||
}
|
||||
|
||||
const struct dpll_params *get_usb_dpll_params(struct dplls const *dpll_data)
|
||||
{
|
||||
u32 sysclk_ind = get_sys_clk_index();
|
||||
return &dpll_data->usb[sysclk_ind];
|
||||
}
|
||||
|
||||
const struct dpll_params *get_abe_dpll_params(struct dplls const *dpll_data)
|
||||
{
|
||||
#ifdef CONFIG_SYS_OMAP_ABE_SYSCK
|
||||
u32 sysclk_ind = get_sys_clk_index();
|
||||
return &dpll_data->abe[sysclk_ind];
|
||||
#else
|
||||
return dpll_data->abe;
|
||||
#endif
|
||||
}
|
||||
|
||||
static const struct dpll_params *get_ddr_dpll_params
|
||||
(struct dplls const *dpll_data)
|
||||
{
|
||||
u32 sysclk_ind = get_sys_clk_index();
|
||||
|
||||
if (!dpll_data->ddr)
|
||||
return NULL;
|
||||
return &dpll_data->ddr[sysclk_ind];
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DRIVER_TI_CPSW
|
||||
static const struct dpll_params *get_gmac_dpll_params
|
||||
(struct dplls const *dpll_data)
|
||||
{
|
||||
u32 sysclk_ind = get_sys_clk_index();
|
||||
|
||||
if (!dpll_data->gmac)
|
||||
return NULL;
|
||||
return &dpll_data->gmac[sysclk_ind];
|
||||
}
|
||||
#endif
|
||||
|
||||
static void do_setup_dpll(u32 const base, const struct dpll_params *params,
|
||||
u8 lock, char *dpll)
|
||||
{
|
||||
u32 temp, M, N;
|
||||
struct dpll_regs *const dpll_regs = (struct dpll_regs *)base;
|
||||
|
||||
if (!params)
|
||||
return;
|
||||
|
||||
temp = readl(&dpll_regs->cm_clksel_dpll);
|
||||
|
||||
if (check_for_lock(base)) {
|
||||
/*
|
||||
* The Dpll has already been locked by rom code using CH.
|
||||
* Check if M,N are matching with Ideal nominal opp values.
|
||||
* If matches, skip the rest otherwise relock.
|
||||
*/
|
||||
M = (temp & CM_CLKSEL_DPLL_M_MASK) >> CM_CLKSEL_DPLL_M_SHIFT;
|
||||
N = (temp & CM_CLKSEL_DPLL_N_MASK) >> CM_CLKSEL_DPLL_N_SHIFT;
|
||||
if ((M != (params->m)) || (N != (params->n))) {
|
||||
debug("\n %s Dpll locked, but not for ideal M = %d,"
|
||||
"N = %d values, current values are M = %d,"
|
||||
"N= %d" , dpll, params->m, params->n,
|
||||
M, N);
|
||||
} else {
|
||||
/* Dpll locked with ideal values for nominal opps. */
|
||||
debug("\n %s Dpll already locked with ideal"
|
||||
"nominal opp values", dpll);
|
||||
|
||||
bypass_dpll(base);
|
||||
goto setup_post_dividers;
|
||||
}
|
||||
}
|
||||
|
||||
bypass_dpll(base);
|
||||
|
||||
/* Set M & N */
|
||||
temp &= ~CM_CLKSEL_DPLL_M_MASK;
|
||||
temp |= (params->m << CM_CLKSEL_DPLL_M_SHIFT) & CM_CLKSEL_DPLL_M_MASK;
|
||||
|
||||
temp &= ~CM_CLKSEL_DPLL_N_MASK;
|
||||
temp |= (params->n << CM_CLKSEL_DPLL_N_SHIFT) & CM_CLKSEL_DPLL_N_MASK;
|
||||
|
||||
writel(temp, &dpll_regs->cm_clksel_dpll);
|
||||
|
||||
setup_post_dividers:
|
||||
setup_post_dividers(base, params);
|
||||
|
||||
/* Lock */
|
||||
if (lock)
|
||||
do_lock_dpll(base);
|
||||
|
||||
/* Wait till the DPLL locks */
|
||||
if (lock)
|
||||
wait_for_lock(base);
|
||||
}
|
||||
|
||||
u32 omap_ddr_clk(void)
|
||||
{
|
||||
u32 ddr_clk, sys_clk_khz, omap_rev, divider;
|
||||
const struct dpll_params *core_dpll_params;
|
||||
|
||||
omap_rev = omap_revision();
|
||||
sys_clk_khz = get_sys_clk_freq() / 1000;
|
||||
|
||||
core_dpll_params = get_core_dpll_params(*dplls_data);
|
||||
|
||||
debug("sys_clk %d\n ", sys_clk_khz * 1000);
|
||||
|
||||
/* Find Core DPLL locked frequency first */
|
||||
ddr_clk = sys_clk_khz * 2 * core_dpll_params->m /
|
||||
(core_dpll_params->n + 1);
|
||||
|
||||
if (omap_rev < OMAP5430_ES1_0) {
|
||||
/*
|
||||
* DDR frequency is PHY_ROOT_CLK/2
|
||||
* PHY_ROOT_CLK = Fdpll/2/M2
|
||||
*/
|
||||
divider = 4;
|
||||
} else {
|
||||
/*
|
||||
* DDR frequency is PHY_ROOT_CLK
|
||||
* PHY_ROOT_CLK = Fdpll/2/M2
|
||||
*/
|
||||
divider = 2;
|
||||
}
|
||||
|
||||
ddr_clk = ddr_clk / divider / core_dpll_params->m2;
|
||||
ddr_clk *= 1000; /* convert to Hz */
|
||||
debug("ddr_clk %d\n ", ddr_clk);
|
||||
|
||||
return ddr_clk;
|
||||
}
|
||||
|
||||
/*
|
||||
* Lock MPU dpll
|
||||
*
|
||||
* Resulting MPU frequencies:
|
||||
* 4430 ES1.0 : 600 MHz
|
||||
* 4430 ES2.x : 792 MHz (OPP Turbo)
|
||||
* 4460 : 920 MHz (OPP Turbo) - DCC disabled
|
||||
*/
|
||||
void configure_mpu_dpll(void)
|
||||
{
|
||||
const struct dpll_params *params;
|
||||
struct dpll_regs *mpu_dpll_regs;
|
||||
u32 omap_rev;
|
||||
omap_rev = omap_revision();
|
||||
|
||||
/*
|
||||
* DCC and clock divider settings for 4460.
|
||||
* DCC is required, if more than a certain frequency is required.
|
||||
* For, 4460 > 1GHZ.
|
||||
* 5430 > 1.4GHZ.
|
||||
*/
|
||||
if ((omap_rev >= OMAP4460_ES1_0) && (omap_rev < OMAP5430_ES1_0)) {
|
||||
mpu_dpll_regs =
|
||||
(struct dpll_regs *)((*prcm)->cm_clkmode_dpll_mpu);
|
||||
bypass_dpll((*prcm)->cm_clkmode_dpll_mpu);
|
||||
clrbits_le32((*prcm)->cm_mpu_mpu_clkctrl,
|
||||
MPU_CLKCTRL_CLKSEL_EMIF_DIV_MODE_MASK);
|
||||
setbits_le32((*prcm)->cm_mpu_mpu_clkctrl,
|
||||
MPU_CLKCTRL_CLKSEL_ABE_DIV_MODE_MASK);
|
||||
clrbits_le32(&mpu_dpll_regs->cm_clksel_dpll,
|
||||
CM_CLKSEL_DCC_EN_MASK);
|
||||
}
|
||||
|
||||
params = get_mpu_dpll_params(*dplls_data);
|
||||
|
||||
do_setup_dpll((*prcm)->cm_clkmode_dpll_mpu, params, DPLL_LOCK, "mpu");
|
||||
debug("MPU DPLL locked\n");
|
||||
}
|
||||
|
||||
#if defined(CONFIG_USB_EHCI_OMAP) || defined(CONFIG_USB_XHCI_OMAP) || \
|
||||
defined(CONFIG_USB_MUSB_OMAP2PLUS)
|
||||
static void setup_usb_dpll(void)
|
||||
{
|
||||
const struct dpll_params *params;
|
||||
u32 sys_clk_khz, sd_div, num, den;
|
||||
|
||||
sys_clk_khz = get_sys_clk_freq() / 1000;
|
||||
/*
|
||||
* USB:
|
||||
* USB dpll is J-type. Need to set DPLL_SD_DIV for jitter correction
|
||||
* DPLL_SD_DIV = CEILING ([DPLL_MULT/(DPLL_DIV+1)]* CLKINP / 250)
|
||||
* - where CLKINP is sys_clk in MHz
|
||||
* Use CLKINP in KHz and adjust the denominator accordingly so
|
||||
* that we have enough accuracy and at the same time no overflow
|
||||
*/
|
||||
params = get_usb_dpll_params(*dplls_data);
|
||||
num = params->m * sys_clk_khz;
|
||||
den = (params->n + 1) * 250 * 1000;
|
||||
num += den - 1;
|
||||
sd_div = num / den;
|
||||
clrsetbits_le32((*prcm)->cm_clksel_dpll_usb,
|
||||
CM_CLKSEL_DPLL_DPLL_SD_DIV_MASK,
|
||||
sd_div << CM_CLKSEL_DPLL_DPLL_SD_DIV_SHIFT);
|
||||
|
||||
/* Now setup the dpll with the regular function */
|
||||
do_setup_dpll((*prcm)->cm_clkmode_dpll_usb, params, DPLL_LOCK, "usb");
|
||||
}
|
||||
#endif
|
||||
|
||||
static void setup_dplls(void)
|
||||
{
|
||||
u32 temp;
|
||||
const struct dpll_params *params;
|
||||
struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE;
|
||||
|
||||
debug("setup_dplls\n");
|
||||
|
||||
/* CORE dpll */
|
||||
params = get_core_dpll_params(*dplls_data); /* default - safest */
|
||||
/*
|
||||
* Do not lock the core DPLL now. Just set it up.
|
||||
* Core DPLL will be locked after setting up EMIF
|
||||
* using the FREQ_UPDATE method(freq_update_core())
|
||||
*/
|
||||
if (emif_sdram_type(readl(&emif->emif_sdram_config)) ==
|
||||
EMIF_SDRAM_TYPE_LPDDR2)
|
||||
do_setup_dpll((*prcm)->cm_clkmode_dpll_core, params,
|
||||
DPLL_NO_LOCK, "core");
|
||||
else
|
||||
do_setup_dpll((*prcm)->cm_clkmode_dpll_core, params,
|
||||
DPLL_LOCK, "core");
|
||||
/* Set the ratios for CORE_CLK, L3_CLK, L4_CLK */
|
||||
temp = (CLKSEL_CORE_X2_DIV_1 << CLKSEL_CORE_SHIFT) |
|
||||
(CLKSEL_L3_CORE_DIV_2 << CLKSEL_L3_SHIFT) |
|
||||
(CLKSEL_L4_L3_DIV_2 << CLKSEL_L4_SHIFT);
|
||||
writel(temp, (*prcm)->cm_clksel_core);
|
||||
debug("Core DPLL configured\n");
|
||||
|
||||
/* lock PER dpll */
|
||||
params = get_per_dpll_params(*dplls_data);
|
||||
do_setup_dpll((*prcm)->cm_clkmode_dpll_per,
|
||||
params, DPLL_LOCK, "per");
|
||||
debug("PER DPLL locked\n");
|
||||
|
||||
/* MPU dpll */
|
||||
configure_mpu_dpll();
|
||||
|
||||
#if defined(CONFIG_USB_EHCI_OMAP) || defined(CONFIG_USB_XHCI_OMAP) || \
|
||||
defined(CONFIG_USB_MUSB_OMAP2PLUS)
|
||||
setup_usb_dpll();
|
||||
#endif
|
||||
params = get_ddr_dpll_params(*dplls_data);
|
||||
do_setup_dpll((*prcm)->cm_clkmode_dpll_ddrphy,
|
||||
params, DPLL_LOCK, "ddr");
|
||||
|
||||
#ifdef CONFIG_DRIVER_TI_CPSW
|
||||
params = get_gmac_dpll_params(*dplls_data);
|
||||
do_setup_dpll((*prcm)->cm_clkmode_dpll_gmac, params,
|
||||
DPLL_LOCK, "gmac");
|
||||
#endif
|
||||
}
|
||||
|
||||
u32 get_offset_code(u32 volt_offset, struct pmic_data *pmic)
|
||||
{
|
||||
u32 offset_code;
|
||||
|
||||
volt_offset -= pmic->base_offset;
|
||||
|
||||
offset_code = (volt_offset + pmic->step - 1) / pmic->step;
|
||||
|
||||
/*
|
||||
* Offset codes 1-6 all give the base voltage in Palmas
|
||||
* Offset code 0 switches OFF the SMPS
|
||||
*/
|
||||
return offset_code + pmic->start_code;
|
||||
}
|
||||
|
||||
void do_scale_vcore(u32 vcore_reg, u32 volt_mv, struct pmic_data *pmic)
|
||||
{
|
||||
u32 offset_code;
|
||||
u32 offset = volt_mv;
|
||||
#ifndef CONFIG_DRA7XX
|
||||
int ret = 0;
|
||||
#endif
|
||||
|
||||
if (!volt_mv)
|
||||
return;
|
||||
|
||||
pmic->pmic_bus_init();
|
||||
#ifndef CONFIG_DRA7XX
|
||||
/* See if we can first get the GPIO if needed */
|
||||
if (pmic->gpio_en)
|
||||
ret = gpio_request(pmic->gpio, "PMIC_GPIO");
|
||||
|
||||
if (ret < 0) {
|
||||
printf("%s: gpio %d request failed %d\n", __func__,
|
||||
pmic->gpio, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Pull the GPIO low to select SET0 register, while we program SET1 */
|
||||
if (pmic->gpio_en)
|
||||
gpio_direction_output(pmic->gpio, 0);
|
||||
#endif
|
||||
/* convert to uV for better accuracy in the calculations */
|
||||
offset *= 1000;
|
||||
|
||||
offset_code = get_offset_code(offset, pmic);
|
||||
|
||||
debug("do_scale_vcore: volt - %d offset_code - 0x%x\n", volt_mv,
|
||||
offset_code);
|
||||
|
||||
if (pmic->pmic_write(pmic->i2c_slave_addr, vcore_reg, offset_code))
|
||||
printf("Scaling voltage failed for 0x%x\n", vcore_reg);
|
||||
#ifndef CONFIG_DRA7XX
|
||||
if (pmic->gpio_en)
|
||||
gpio_direction_output(pmic->gpio, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static u32 optimize_vcore_voltage(struct volts const *v)
|
||||
{
|
||||
u32 val;
|
||||
if (!v->value)
|
||||
return 0;
|
||||
if (!v->efuse.reg)
|
||||
return v->value;
|
||||
|
||||
switch (v->efuse.reg_bits) {
|
||||
case 16:
|
||||
val = readw(v->efuse.reg);
|
||||
break;
|
||||
case 32:
|
||||
val = readl(v->efuse.reg);
|
||||
break;
|
||||
default:
|
||||
printf("Error: efuse 0x%08x bits=%d unknown\n",
|
||||
v->efuse.reg, v->efuse.reg_bits);
|
||||
return v->value;
|
||||
}
|
||||
|
||||
if (!val) {
|
||||
printf("Error: efuse 0x%08x bits=%d val=0, using %d\n",
|
||||
v->efuse.reg, v->efuse.reg_bits, v->value);
|
||||
return v->value;
|
||||
}
|
||||
|
||||
debug("%s:efuse 0x%08x bits=%d Vnom=%d, using efuse value %d\n",
|
||||
__func__, v->efuse.reg, v->efuse.reg_bits, v->value, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IODELAY_RECALIBRATION
|
||||
void __weak recalibrate_iodelay(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Setup the voltages for the main SoC core power domains.
|
||||
* We start with the maximum voltages allowed here, as set in the corresponding
|
||||
* vcores_data struct, and then scale (usually down) to the fused values that
|
||||
* are retrieved from the SoC. The scaling happens only if the efuse.reg fields
|
||||
* are initialised.
|
||||
* Rail grouping is supported for the DRA7xx SoCs only, therefore the code is
|
||||
* compiled conditionally. Note that the new code writes the scaled (or zeroed)
|
||||
* values back to the vcores_data struct for eventual reuse. Zero values mean
|
||||
* that the corresponding rails are not controlled separately, and are not sent
|
||||
* to the PMIC.
|
||||
*/
|
||||
void scale_vcores(struct vcores_data const *vcores)
|
||||
{
|
||||
#if defined(CONFIG_DRA7XX)
|
||||
int i;
|
||||
struct volts *pv = (struct volts *)vcores;
|
||||
struct volts *px;
|
||||
|
||||
for (i=0; i<(sizeof(struct vcores_data)/sizeof(struct volts)); i++) {
|
||||
debug("%d -> ", pv->value);
|
||||
if (pv->value) {
|
||||
/* Handle non-empty members only */
|
||||
pv->value = optimize_vcore_voltage(pv);
|
||||
px = (struct volts *)vcores;
|
||||
while (px < pv) {
|
||||
/*
|
||||
* Scan already handled non-empty members to see
|
||||
* if we have a group and find the max voltage,
|
||||
* which is set to the first occurance of the
|
||||
* particular SMPS; the other group voltages are
|
||||
* zeroed.
|
||||
*/
|
||||
if (px->value) {
|
||||
if ((pv->pmic->i2c_slave_addr ==
|
||||
px->pmic->i2c_slave_addr) &&
|
||||
(pv->addr == px->addr)) {
|
||||
/* Same PMIC, same SMPS */
|
||||
if (pv->value > px->value)
|
||||
px->value = pv->value;
|
||||
|
||||
pv->value = 0;
|
||||
}
|
||||
}
|
||||
px++;
|
||||
}
|
||||
}
|
||||
debug("%d\n", pv->value);
|
||||
pv++;
|
||||
}
|
||||
|
||||
debug("cor: %d\n", vcores->core.value);
|
||||
do_scale_vcore(vcores->core.addr, vcores->core.value, vcores->core.pmic);
|
||||
/*
|
||||
* IO delay recalibration should be done immediately after
|
||||
* adjusting AVS voltages for VDD_CORE_L.
|
||||
* Respective boards should call __recalibrate_iodelay()
|
||||
* with proper mux, virtual and manual mode configurations.
|
||||
*/
|
||||
#ifdef CONFIG_IODELAY_RECALIBRATION
|
||||
recalibrate_iodelay();
|
||||
#endif
|
||||
|
||||
debug("mpu: %d\n", vcores->mpu.value);
|
||||
do_scale_vcore(vcores->mpu.addr, vcores->mpu.value, vcores->mpu.pmic);
|
||||
/* Configure MPU ABB LDO after scale */
|
||||
abb_setup(vcores->mpu.efuse.reg,
|
||||
(*ctrl)->control_wkup_ldovbb_mpu_voltage_ctrl,
|
||||
(*prcm)->prm_abbldo_mpu_setup,
|
||||
(*prcm)->prm_abbldo_mpu_ctrl,
|
||||
(*prcm)->prm_irqstatus_mpu_2,
|
||||
vcores->mpu.abb_tx_done_mask,
|
||||
OMAP_ABB_FAST_OPP);
|
||||
|
||||
/* The .mm member is not used for the DRA7xx */
|
||||
|
||||
debug("gpu: %d\n", vcores->gpu.value);
|
||||
do_scale_vcore(vcores->gpu.addr, vcores->gpu.value, vcores->gpu.pmic);
|
||||
/* Configure GPU ABB LDO after scale */
|
||||
abb_setup(vcores->gpu.efuse.reg,
|
||||
(*ctrl)->control_wkup_ldovbb_gpu_voltage_ctrl,
|
||||
(*prcm)->prm_abbldo_gpu_setup,
|
||||
(*prcm)->prm_abbldo_gpu_ctrl,
|
||||
(*prcm)->prm_irqstatus_mpu,
|
||||
vcores->gpu.abb_tx_done_mask,
|
||||
OMAP_ABB_FAST_OPP);
|
||||
debug("eve: %d\n", vcores->eve.value);
|
||||
do_scale_vcore(vcores->eve.addr, vcores->eve.value, vcores->eve.pmic);
|
||||
/* Configure EVE ABB LDO after scale */
|
||||
abb_setup(vcores->eve.efuse.reg,
|
||||
(*ctrl)->control_wkup_ldovbb_eve_voltage_ctrl,
|
||||
(*prcm)->prm_abbldo_eve_setup,
|
||||
(*prcm)->prm_abbldo_eve_ctrl,
|
||||
(*prcm)->prm_irqstatus_mpu,
|
||||
vcores->eve.abb_tx_done_mask,
|
||||
OMAP_ABB_FAST_OPP);
|
||||
debug("iva: %d\n", vcores->iva.value);
|
||||
do_scale_vcore(vcores->iva.addr, vcores->iva.value, vcores->iva.pmic);
|
||||
/* Configure IVA ABB LDO after scale */
|
||||
abb_setup(vcores->iva.efuse.reg,
|
||||
(*ctrl)->control_wkup_ldovbb_iva_voltage_ctrl,
|
||||
(*prcm)->prm_abbldo_iva_setup,
|
||||
(*prcm)->prm_abbldo_iva_ctrl,
|
||||
(*prcm)->prm_irqstatus_mpu,
|
||||
vcores->iva.abb_tx_done_mask,
|
||||
OMAP_ABB_FAST_OPP);
|
||||
/* Might need udelay(1000) here if debug is enabled to see all prints */
|
||||
#else
|
||||
u32 val;
|
||||
|
||||
val = optimize_vcore_voltage(&vcores->core);
|
||||
do_scale_vcore(vcores->core.addr, val, vcores->core.pmic);
|
||||
|
||||
/*
|
||||
* IO delay recalibration should be done immediately after
|
||||
* adjusting AVS voltages for VDD_CORE_L.
|
||||
* Respective boards should call __recalibrate_iodelay()
|
||||
* with proper mux, virtual and manual mode configurations.
|
||||
*/
|
||||
#ifdef CONFIG_IODELAY_RECALIBRATION
|
||||
recalibrate_iodelay();
|
||||
#endif
|
||||
|
||||
val = optimize_vcore_voltage(&vcores->mpu);
|
||||
do_scale_vcore(vcores->mpu.addr, val, vcores->mpu.pmic);
|
||||
|
||||
/* Configure MPU ABB LDO after scale */
|
||||
abb_setup(vcores->mpu.efuse.reg,
|
||||
(*ctrl)->control_wkup_ldovbb_mpu_voltage_ctrl,
|
||||
(*prcm)->prm_abbldo_mpu_setup,
|
||||
(*prcm)->prm_abbldo_mpu_ctrl,
|
||||
(*prcm)->prm_irqstatus_mpu_2,
|
||||
vcores->mpu.abb_tx_done_mask,
|
||||
OMAP_ABB_FAST_OPP);
|
||||
|
||||
val = optimize_vcore_voltage(&vcores->mm);
|
||||
do_scale_vcore(vcores->mm.addr, val, vcores->mm.pmic);
|
||||
|
||||
/* Configure MM ABB LDO after scale */
|
||||
abb_setup(vcores->mm.efuse.reg,
|
||||
(*ctrl)->control_wkup_ldovbb_mm_voltage_ctrl,
|
||||
(*prcm)->prm_abbldo_mm_setup,
|
||||
(*prcm)->prm_abbldo_mm_ctrl,
|
||||
(*prcm)->prm_irqstatus_mpu,
|
||||
vcores->mm.abb_tx_done_mask,
|
||||
OMAP_ABB_FAST_OPP);
|
||||
|
||||
val = optimize_vcore_voltage(&vcores->gpu);
|
||||
do_scale_vcore(vcores->gpu.addr, val, vcores->gpu.pmic);
|
||||
|
||||
val = optimize_vcore_voltage(&vcores->eve);
|
||||
do_scale_vcore(vcores->eve.addr, val, vcores->eve.pmic);
|
||||
|
||||
val = optimize_vcore_voltage(&vcores->iva);
|
||||
do_scale_vcore(vcores->iva.addr, val, vcores->iva.pmic);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void enable_clock_domain(u32 const clkctrl_reg, u32 enable_mode)
|
||||
{
|
||||
clrsetbits_le32(clkctrl_reg, CD_CLKCTRL_CLKTRCTRL_MASK,
|
||||
enable_mode << CD_CLKCTRL_CLKTRCTRL_SHIFT);
|
||||
debug("Enable clock domain - %x\n", clkctrl_reg);
|
||||
}
|
||||
|
||||
static inline void disable_clock_domain(u32 const clkctrl_reg)
|
||||
{
|
||||
clrsetbits_le32(clkctrl_reg, CD_CLKCTRL_CLKTRCTRL_MASK,
|
||||
CD_CLKCTRL_CLKTRCTRL_SW_SLEEP <<
|
||||
CD_CLKCTRL_CLKTRCTRL_SHIFT);
|
||||
debug("Disable clock domain - %x\n", clkctrl_reg);
|
||||
}
|
||||
|
||||
static inline void wait_for_clk_enable(u32 clkctrl_addr)
|
||||
{
|
||||
u32 clkctrl, idlest = MODULE_CLKCTRL_IDLEST_DISABLED;
|
||||
u32 bound = LDELAY;
|
||||
|
||||
while ((idlest == MODULE_CLKCTRL_IDLEST_DISABLED) ||
|
||||
(idlest == MODULE_CLKCTRL_IDLEST_TRANSITIONING)) {
|
||||
|
||||
clkctrl = readl(clkctrl_addr);
|
||||
idlest = (clkctrl & MODULE_CLKCTRL_IDLEST_MASK) >>
|
||||
MODULE_CLKCTRL_IDLEST_SHIFT;
|
||||
if (--bound == 0) {
|
||||
printf("Clock enable failed for 0x%x idlest 0x%x\n",
|
||||
clkctrl_addr, clkctrl);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void enable_clock_module(u32 const clkctrl_addr, u32 enable_mode,
|
||||
u32 wait_for_enable)
|
||||
{
|
||||
clrsetbits_le32(clkctrl_addr, MODULE_CLKCTRL_MODULEMODE_MASK,
|
||||
enable_mode << MODULE_CLKCTRL_MODULEMODE_SHIFT);
|
||||
debug("Enable clock module - %x\n", clkctrl_addr);
|
||||
if (wait_for_enable)
|
||||
wait_for_clk_enable(clkctrl_addr);
|
||||
}
|
||||
|
||||
static inline void wait_for_clk_disable(u32 clkctrl_addr)
|
||||
{
|
||||
u32 clkctrl, idlest = MODULE_CLKCTRL_IDLEST_FULLY_FUNCTIONAL;
|
||||
u32 bound = LDELAY;
|
||||
|
||||
while ((idlest != MODULE_CLKCTRL_IDLEST_DISABLED)) {
|
||||
clkctrl = readl(clkctrl_addr);
|
||||
idlest = (clkctrl & MODULE_CLKCTRL_IDLEST_MASK) >>
|
||||
MODULE_CLKCTRL_IDLEST_SHIFT;
|
||||
if (--bound == 0) {
|
||||
printf("Clock disable failed for 0x%x idlest 0x%x\n",
|
||||
clkctrl_addr, clkctrl);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void disable_clock_module(u32 const clkctrl_addr,
|
||||
u32 wait_for_disable)
|
||||
{
|
||||
clrsetbits_le32(clkctrl_addr, MODULE_CLKCTRL_MODULEMODE_MASK,
|
||||
MODULE_CLKCTRL_MODULEMODE_SW_DISABLE <<
|
||||
MODULE_CLKCTRL_MODULEMODE_SHIFT);
|
||||
debug("Disable clock module - %x\n", clkctrl_addr);
|
||||
if (wait_for_disable)
|
||||
wait_for_clk_disable(clkctrl_addr);
|
||||
}
|
||||
|
||||
void freq_update_core(void)
|
||||
{
|
||||
u32 freq_config1 = 0;
|
||||
const struct dpll_params *core_dpll_params;
|
||||
u32 omap_rev = omap_revision();
|
||||
|
||||
core_dpll_params = get_core_dpll_params(*dplls_data);
|
||||
/* Put EMIF clock domain in sw wakeup mode */
|
||||
enable_clock_domain((*prcm)->cm_memif_clkstctrl,
|
||||
CD_CLKCTRL_CLKTRCTRL_SW_WKUP);
|
||||
wait_for_clk_enable((*prcm)->cm_memif_emif_1_clkctrl);
|
||||
wait_for_clk_enable((*prcm)->cm_memif_emif_2_clkctrl);
|
||||
|
||||
freq_config1 = SHADOW_FREQ_CONFIG1_FREQ_UPDATE_MASK |
|
||||
SHADOW_FREQ_CONFIG1_DLL_RESET_MASK;
|
||||
|
||||
freq_config1 |= (DPLL_EN_LOCK << SHADOW_FREQ_CONFIG1_DPLL_EN_SHIFT) &
|
||||
SHADOW_FREQ_CONFIG1_DPLL_EN_MASK;
|
||||
|
||||
freq_config1 |= (core_dpll_params->m2 <<
|
||||
SHADOW_FREQ_CONFIG1_M2_DIV_SHIFT) &
|
||||
SHADOW_FREQ_CONFIG1_M2_DIV_MASK;
|
||||
|
||||
writel(freq_config1, (*prcm)->cm_shadow_freq_config1);
|
||||
if (!wait_on_value(SHADOW_FREQ_CONFIG1_FREQ_UPDATE_MASK, 0,
|
||||
(u32 *) (*prcm)->cm_shadow_freq_config1, LDELAY)) {
|
||||
puts("FREQ UPDATE procedure failed!!");
|
||||
hang();
|
||||
}
|
||||
|
||||
/*
|
||||
* Putting EMIF in HW_AUTO is seen to be causing issues with
|
||||
* EMIF clocks and the master DLL. Keep EMIF in SW_WKUP
|
||||
* in OMAP5430 ES1.0 silicon
|
||||
*/
|
||||
if (omap_rev != OMAP5430_ES1_0) {
|
||||
/* Put EMIF clock domain back in hw auto mode */
|
||||
enable_clock_domain((*prcm)->cm_memif_clkstctrl,
|
||||
CD_CLKCTRL_CLKTRCTRL_HW_AUTO);
|
||||
wait_for_clk_enable((*prcm)->cm_memif_emif_1_clkctrl);
|
||||
wait_for_clk_enable((*prcm)->cm_memif_emif_2_clkctrl);
|
||||
}
|
||||
}
|
||||
|
||||
void bypass_dpll(u32 const base)
|
||||
{
|
||||
do_bypass_dpll(base);
|
||||
wait_for_bypass(base);
|
||||
}
|
||||
|
||||
void lock_dpll(u32 const base)
|
||||
{
|
||||
do_lock_dpll(base);
|
||||
wait_for_lock(base);
|
||||
}
|
||||
|
||||
static void setup_clocks_for_console(void)
|
||||
{
|
||||
/* Do not add any spl_debug prints in this function */
|
||||
clrsetbits_le32((*prcm)->cm_l4per_clkstctrl, CD_CLKCTRL_CLKTRCTRL_MASK,
|
||||
CD_CLKCTRL_CLKTRCTRL_SW_WKUP <<
|
||||
CD_CLKCTRL_CLKTRCTRL_SHIFT);
|
||||
|
||||
/* Enable all UARTs - console will be on one of them */
|
||||
clrsetbits_le32((*prcm)->cm_l4per_uart1_clkctrl,
|
||||
MODULE_CLKCTRL_MODULEMODE_MASK,
|
||||
MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN <<
|
||||
MODULE_CLKCTRL_MODULEMODE_SHIFT);
|
||||
|
||||
clrsetbits_le32((*prcm)->cm_l4per_uart2_clkctrl,
|
||||
MODULE_CLKCTRL_MODULEMODE_MASK,
|
||||
MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN <<
|
||||
MODULE_CLKCTRL_MODULEMODE_SHIFT);
|
||||
|
||||
clrsetbits_le32((*prcm)->cm_l4per_uart3_clkctrl,
|
||||
MODULE_CLKCTRL_MODULEMODE_MASK,
|
||||
MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN <<
|
||||
MODULE_CLKCTRL_MODULEMODE_SHIFT);
|
||||
|
||||
clrsetbits_le32((*prcm)->cm_l4per_uart4_clkctrl,
|
||||
MODULE_CLKCTRL_MODULEMODE_MASK,
|
||||
MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN <<
|
||||
MODULE_CLKCTRL_MODULEMODE_SHIFT);
|
||||
|
||||
clrsetbits_le32((*prcm)->cm_l4per_clkstctrl, CD_CLKCTRL_CLKTRCTRL_MASK,
|
||||
CD_CLKCTRL_CLKTRCTRL_HW_AUTO <<
|
||||
CD_CLKCTRL_CLKTRCTRL_SHIFT);
|
||||
}
|
||||
|
||||
void do_enable_clocks(u32 const *clk_domains,
|
||||
u32 const *clk_modules_hw_auto,
|
||||
u32 const *clk_modules_explicit_en,
|
||||
u8 wait_for_enable)
|
||||
{
|
||||
u32 i, max = 100;
|
||||
|
||||
/* Put the clock domains in SW_WKUP mode */
|
||||
for (i = 0; (i < max) && clk_domains[i]; i++) {
|
||||
enable_clock_domain(clk_domains[i],
|
||||
CD_CLKCTRL_CLKTRCTRL_SW_WKUP);
|
||||
}
|
||||
|
||||
/* Clock modules that need to be put in HW_AUTO */
|
||||
for (i = 0; (i < max) && clk_modules_hw_auto[i]; i++) {
|
||||
enable_clock_module(clk_modules_hw_auto[i],
|
||||
MODULE_CLKCTRL_MODULEMODE_HW_AUTO,
|
||||
wait_for_enable);
|
||||
};
|
||||
|
||||
/* Clock modules that need to be put in SW_EXPLICIT_EN mode */
|
||||
for (i = 0; (i < max) && clk_modules_explicit_en[i]; i++) {
|
||||
enable_clock_module(clk_modules_explicit_en[i],
|
||||
MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN,
|
||||
wait_for_enable);
|
||||
};
|
||||
|
||||
/* Put the clock domains in HW_AUTO mode now */
|
||||
for (i = 0; (i < max) && clk_domains[i]; i++) {
|
||||
enable_clock_domain(clk_domains[i],
|
||||
CD_CLKCTRL_CLKTRCTRL_HW_AUTO);
|
||||
}
|
||||
}
|
||||
|
||||
void do_disable_clocks(u32 const *clk_domains,
|
||||
u32 const *clk_modules_disable,
|
||||
u8 wait_for_disable)
|
||||
{
|
||||
u32 i, max = 100;
|
||||
|
||||
|
||||
/* Clock modules that need to be put in SW_DISABLE */
|
||||
for (i = 0; (i < max) && clk_modules_disable[i]; i++)
|
||||
disable_clock_module(clk_modules_disable[i],
|
||||
wait_for_disable);
|
||||
|
||||
/* Put the clock domains in SW_SLEEP mode */
|
||||
for (i = 0; (i < max) && clk_domains[i]; i++)
|
||||
disable_clock_domain(clk_domains[i]);
|
||||
}
|
||||
|
||||
/**
|
||||
* setup_early_clocks() - Setup early clocks needed for SoC
|
||||
*
|
||||
* Setup clocks for console, SPL basic initialization clocks and initialize
|
||||
* the timer. This is invoked prior prcm_init.
|
||||
*/
|
||||
void setup_early_clocks(void)
|
||||
{
|
||||
switch (omap_hw_init_context()) {
|
||||
case OMAP_INIT_CONTEXT_SPL:
|
||||
case OMAP_INIT_CONTEXT_UBOOT_FROM_NOR:
|
||||
case OMAP_INIT_CONTEXT_UBOOT_AFTER_CH:
|
||||
setup_clocks_for_console();
|
||||
enable_basic_clocks();
|
||||
timer_init();
|
||||
/* Fall through */
|
||||
}
|
||||
}
|
||||
|
||||
void prcm_init(void)
|
||||
{
|
||||
switch (omap_hw_init_context()) {
|
||||
case OMAP_INIT_CONTEXT_SPL:
|
||||
case OMAP_INIT_CONTEXT_UBOOT_FROM_NOR:
|
||||
case OMAP_INIT_CONTEXT_UBOOT_AFTER_CH:
|
||||
scale_vcores(*omap_vcores);
|
||||
setup_dplls();
|
||||
setup_warmreset_time();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (OMAP_INIT_CONTEXT_SPL != omap_hw_init_context())
|
||||
enable_basic_uboot_clocks();
|
||||
}
|
||||
|
||||
void gpi2c_init(void)
|
||||
{
|
||||
static int gpi2c = 1;
|
||||
|
||||
if (gpi2c) {
|
||||
i2c_init(CONFIG_SYS_OMAP24_I2C_SPEED,
|
||||
CONFIG_SYS_OMAP24_I2C_SLAVE);
|
||||
gpi2c = 0;
|
||||
}
|
||||
}
|
||||
66
u-boot/arch/arm/cpu/armv7/omap-common/config_secure.mk
Normal file
66
u-boot/arch/arm/cpu/armv7/omap-common/config_secure.mk
Normal file
@@ -0,0 +1,66 @@
|
||||
#
|
||||
# Copyright (C) 2016, Texas Instruments, Incorporated - http://www.ti.com/
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
quiet_cmd_mkomapsecimg = MKIMAGE $@
|
||||
ifneq ($(TI_SECURE_DEV_PKG),)
|
||||
ifneq ($(wildcard $(TI_SECURE_DEV_PKG)/scripts/create-boot-image.sh),)
|
||||
ifneq ($(CONFIG_SPL_BUILD),)
|
||||
cmd_mkomapsecimg = $(TI_SECURE_DEV_PKG)/scripts/create-boot-image.sh \
|
||||
$(patsubst u-boot-spl_HS_%,%,$(@F)) $< $@ $(CONFIG_ISW_ENTRY_ADDR) \
|
||||
$(if $(KBUILD_VERBOSE:1=), >/dev/null)
|
||||
else
|
||||
cmd_mkomapsecimg = $(TI_SECURE_DEV_PKG)/scripts/create-boot-image.sh \
|
||||
$(patsubst u-boot_HS_%,%,$(@F)) $< $@ $(CONFIG_ISW_ENTRY_ADDR) \
|
||||
$(if $(KBUILD_VERBOSE:1=), >/dev/null)
|
||||
endif
|
||||
else
|
||||
cmd_mkomapsecimg = echo "WARNING:" \
|
||||
"$(TI_SECURE_DEV_PKG)/scripts/create-boot-image.sh not found." \
|
||||
"$@ was NOT created!"
|
||||
endif
|
||||
else
|
||||
cmd_mkomapsecimg = echo "WARNING: TI_SECURE_DEV_PKG environment" \
|
||||
"variable must be defined for TI secure devices. $@ was NOT created!"
|
||||
endif
|
||||
|
||||
# Standard X-LOADER target (QPSI, NOR flash)
|
||||
u-boot-spl_HS_X-LOADER: $(obj)/u-boot-spl.bin
|
||||
$(call if_changed,mkomapsecimg)
|
||||
|
||||
# For MLO targets (SD card boot) the final file name
|
||||
# that is copied to the SD card fAT partition must
|
||||
# be MLO, so we make a copy of the output file to a
|
||||
# new file with that name
|
||||
u-boot-spl_HS_MLO: $(obj)/u-boot-spl.bin
|
||||
$(call if_changed,mkomapsecimg)
|
||||
@if [ -f $@ ]; then \
|
||||
cp -f $@ MLO; \
|
||||
fi
|
||||
|
||||
# Standard 2ND target (certain peripheral boot modes)
|
||||
u-boot-spl_HS_2ND: $(obj)/u-boot-spl.bin
|
||||
$(call if_changed,mkomapsecimg)
|
||||
|
||||
# Standard ULO target (certain peripheral boot modes)
|
||||
u-boot-spl_HS_ULO: $(obj)/u-boot-spl.bin
|
||||
$(call if_changed,mkomapsecimg)
|
||||
|
||||
# Standard ISSW target (certain devices, various boot modes)
|
||||
u-boot-spl_HS_ISSW: $(obj)/u-boot-spl.bin
|
||||
$(call if_changed,mkomapsecimg)
|
||||
|
||||
# For SPI flash on AM335x and AM43xx, these
|
||||
# require special byte swap handling so we use
|
||||
# the SPI_X-LOADER target instead of X-LOADER
|
||||
# and let the create-boot-image.sh script handle
|
||||
# that
|
||||
u-boot-spl_HS_SPI_X-LOADER: $(obj)/u-boot-spl.bin
|
||||
$(call if_changed,mkomapsecimg)
|
||||
|
||||
# For supporting single stage XiP QSPI on AM43xx, the
|
||||
# image is a full u-boot file, not an SPL. In this case
|
||||
# the mkomapsecimg command looks for a u-boot-HS_* prefix
|
||||
u-boot_HS_XIP_X-LOADER: $(obj)/u-boot.bin
|
||||
$(call if_changed,mkomapsecimg)
|
||||
1488
u-boot/arch/arm/cpu/armv7/omap-common/emif-common.c
Normal file
1488
u-boot/arch/arm/cpu/armv7/omap-common/emif-common.c
Normal file
File diff suppressed because it is too large
Load Diff
297
u-boot/arch/arm/cpu/armv7/omap-common/hwinit-common.c
Normal file
297
u-boot/arch/arm/cpu/armv7/omap-common/hwinit-common.c
Normal file
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
*
|
||||
* Common functions for OMAP4/5 based boards
|
||||
*
|
||||
* (C) Copyright 2010
|
||||
* Texas Instruments, <www.ti.com>
|
||||
*
|
||||
* Author :
|
||||
* Aneesh V <aneesh@ti.com>
|
||||
* Steve Sakoman <steve@sakoman.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <spl.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <asm/emif.h>
|
||||
#include <asm/omap_common.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
void do_set_mux(u32 base, struct pad_conf_entry const *array, int size)
|
||||
{
|
||||
int i;
|
||||
struct pad_conf_entry *pad = (struct pad_conf_entry *) array;
|
||||
|
||||
for (i = 0; i < size; i++, pad++)
|
||||
writew(pad->val, base + pad->offset);
|
||||
}
|
||||
|
||||
static void set_mux_conf_regs(void)
|
||||
{
|
||||
switch (omap_hw_init_context()) {
|
||||
case OMAP_INIT_CONTEXT_SPL:
|
||||
set_muxconf_regs();
|
||||
break;
|
||||
case OMAP_INIT_CONTEXT_UBOOT_AFTER_SPL:
|
||||
break;
|
||||
case OMAP_INIT_CONTEXT_UBOOT_FROM_NOR:
|
||||
case OMAP_INIT_CONTEXT_UBOOT_AFTER_CH:
|
||||
set_muxconf_regs();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
u32 cortex_rev(void)
|
||||
{
|
||||
|
||||
unsigned int rev;
|
||||
|
||||
/* Read Main ID Register (MIDR) */
|
||||
asm ("mrc p15, 0, %0, c0, c0, 0" : "=r" (rev));
|
||||
|
||||
return rev;
|
||||
}
|
||||
|
||||
static void omap_rev_string(void)
|
||||
{
|
||||
u32 omap_rev = omap_revision();
|
||||
u32 soc_variant = (omap_rev & 0xF0000000) >> 28;
|
||||
u32 omap_variant = (omap_rev & 0xFFFF0000) >> 16;
|
||||
u32 major_rev = (omap_rev & 0x00000F00) >> 8;
|
||||
u32 minor_rev = (omap_rev & 0x000000F0) >> 4;
|
||||
|
||||
const char *sec_s;
|
||||
|
||||
switch (get_device_type()) {
|
||||
case TST_DEVICE:
|
||||
sec_s = "TST";
|
||||
break;
|
||||
case EMU_DEVICE:
|
||||
sec_s = "EMU";
|
||||
break;
|
||||
case HS_DEVICE:
|
||||
sec_s = "HS";
|
||||
break;
|
||||
case GP_DEVICE:
|
||||
sec_s = "GP";
|
||||
break;
|
||||
default:
|
||||
sec_s = "?";
|
||||
}
|
||||
|
||||
if (soc_variant)
|
||||
printf("OMAP");
|
||||
else
|
||||
printf("DRA");
|
||||
printf("%x-%s ES%x.%x\n", omap_variant, sec_s, major_rev, minor_rev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPL_BUILD
|
||||
void spl_display_print(void)
|
||||
{
|
||||
omap_rev_string();
|
||||
}
|
||||
#endif
|
||||
|
||||
void __weak srcomp_enable(void)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* do_board_detect() - Detect board description
|
||||
*
|
||||
* Function to detect board description. This is expected to be
|
||||
* overridden in the SoC family board file where desired.
|
||||
*/
|
||||
void __weak do_board_detect(void)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* vcores_init() - Assign omap_vcores based on board
|
||||
*
|
||||
* Function to pick the vcores based on board. This is expected to be
|
||||
* overridden in the SoC family board file where desired.
|
||||
*/
|
||||
void __weak vcores_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
void s_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* early_system_init - Does Early system initialization.
|
||||
*
|
||||
* Does early system init of watchdog, muxing, andclocks
|
||||
* Watchdog disable is done always. For the rest what gets done
|
||||
* depends on the boot mode in which this function is executed when
|
||||
* 1. SPL running from SRAM
|
||||
* 2. U-Boot running from FLASH
|
||||
* 3. U-Boot loaded to SDRAM by SPL
|
||||
* 4. U-Boot loaded to SDRAM by ROM code using the
|
||||
* Configuration Header feature
|
||||
* Please have a look at the respective functions to see what gets
|
||||
* done in each of these cases
|
||||
* This function is called with SRAM stack.
|
||||
*/
|
||||
void early_system_init(void)
|
||||
{
|
||||
init_omap_revision();
|
||||
hw_data_init();
|
||||
|
||||
#ifdef CONFIG_SPL_BUILD
|
||||
if (warm_reset() &&
|
||||
(is_omap44xx() || (omap_revision() == OMAP5430_ES1_0)))
|
||||
force_emif_self_refresh();
|
||||
#endif
|
||||
watchdog_init();
|
||||
set_mux_conf_regs();
|
||||
#ifdef CONFIG_SPL_BUILD
|
||||
srcomp_enable();
|
||||
do_io_settings();
|
||||
#endif
|
||||
setup_early_clocks();
|
||||
do_board_detect();
|
||||
vcores_init();
|
||||
prcm_init();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPL_BUILD
|
||||
void board_init_f(ulong dummy)
|
||||
{
|
||||
early_system_init();
|
||||
#ifdef CONFIG_BOARD_EARLY_INIT_F
|
||||
board_early_init_f();
|
||||
#endif
|
||||
/* For regular u-boot sdram_init() is called from dram_init() */
|
||||
sdram_init();
|
||||
}
|
||||
#endif
|
||||
|
||||
int arch_cpu_init_dm(void)
|
||||
{
|
||||
early_system_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Routine: wait_for_command_complete
|
||||
* Description: Wait for posting to finish on watchdog
|
||||
*/
|
||||
void wait_for_command_complete(struct watchdog *wd_base)
|
||||
{
|
||||
int pending = 1;
|
||||
do {
|
||||
pending = readl(&wd_base->wwps);
|
||||
} while (pending);
|
||||
}
|
||||
|
||||
/*
|
||||
* Routine: watchdog_init
|
||||
* Description: Shut down watch dogs
|
||||
*/
|
||||
void watchdog_init(void)
|
||||
{
|
||||
struct watchdog *wd2_base = (struct watchdog *)WDT2_BASE;
|
||||
|
||||
writel(WD_UNLOCK1, &wd2_base->wspr);
|
||||
wait_for_command_complete(wd2_base);
|
||||
writel(WD_UNLOCK2, &wd2_base->wspr);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function finds the SDRAM size available in the system
|
||||
* based on DMM section configurations
|
||||
* This is needed because the size of memory installed may be
|
||||
* different on different versions of the board
|
||||
*/
|
||||
u32 omap_sdram_size(void)
|
||||
{
|
||||
u32 section, i, valid;
|
||||
u64 sdram_start = 0, sdram_end = 0, addr,
|
||||
size, total_size = 0, trap_size = 0, trap_start = 0;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
section = __raw_readl(DMM_BASE + i*4);
|
||||
valid = (section & EMIF_SDRC_ADDRSPC_MASK) >>
|
||||
(EMIF_SDRC_ADDRSPC_SHIFT);
|
||||
addr = section & EMIF_SYS_ADDR_MASK;
|
||||
|
||||
/* See if the address is valid */
|
||||
if ((addr >= TI_ARMV7_DRAM_ADDR_SPACE_START) &&
|
||||
(addr < TI_ARMV7_DRAM_ADDR_SPACE_END)) {
|
||||
size = ((section & EMIF_SYS_SIZE_MASK) >>
|
||||
EMIF_SYS_SIZE_SHIFT);
|
||||
size = 1 << size;
|
||||
size *= SZ_16M;
|
||||
|
||||
if (valid != DMM_SDRC_ADDR_SPC_INVALID) {
|
||||
if (!sdram_start || (addr < sdram_start))
|
||||
sdram_start = addr;
|
||||
if (!sdram_end || ((addr + size) > sdram_end))
|
||||
sdram_end = addr + size;
|
||||
} else {
|
||||
trap_size = size;
|
||||
trap_start = addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((trap_start >= sdram_start) && (trap_start < sdram_end))
|
||||
total_size = (sdram_end - sdram_start) - (trap_size);
|
||||
else
|
||||
total_size = sdram_end - sdram_start;
|
||||
|
||||
return total_size;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Routine: dram_init
|
||||
* Description: sets uboots idea of sdram size
|
||||
*/
|
||||
int dram_init(void)
|
||||
{
|
||||
sdram_init();
|
||||
gd->ram_size = omap_sdram_size();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print board information
|
||||
*/
|
||||
int checkboard(void)
|
||||
{
|
||||
puts(sysinfo.board_string);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* get_device_type(): tell if GP/HS/EMU/TST
|
||||
*/
|
||||
u32 get_device_type(void)
|
||||
{
|
||||
return (readl((*ctrl)->control_status) &
|
||||
(DEVICE_TYPE_MASK)) >> DEVICE_TYPE_SHIFT;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_DISPLAY_CPUINFO)
|
||||
/*
|
||||
* Print CPU information
|
||||
*/
|
||||
int print_cpuinfo(void)
|
||||
{
|
||||
puts("CPU : ");
|
||||
omap_rev_string();
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
39
u-boot/arch/arm/cpu/armv7/omap-common/lowlevel_init.S
Normal file
39
u-boot/arch/arm/cpu/armv7/omap-common/lowlevel_init.S
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Board specific setup info
|
||||
*
|
||||
* (C) Copyright 2010
|
||||
* Texas Instruments, <www.ti.com>
|
||||
*
|
||||
* Author :
|
||||
* Aneesh V <aneesh@ti.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <asm/arch/omap.h>
|
||||
#include <asm/omap_common.h>
|
||||
#include <asm/arch/spl.h>
|
||||
#include <linux/linkage.h>
|
||||
|
||||
#ifdef CONFIG_SPL
|
||||
ENTRY(save_boot_params)
|
||||
|
||||
ldr r1, =OMAP_SRAM_SCRATCH_BOOT_PARAMS
|
||||
str r0, [r1]
|
||||
b save_boot_params_ret
|
||||
ENDPROC(save_boot_params)
|
||||
#endif
|
||||
|
||||
ENTRY(omap_smc1)
|
||||
PUSH {r4-r12, lr} @ save registers - ROM code may pollute
|
||||
@ our registers
|
||||
MOV r12, r0 @ Service
|
||||
MOV r0, r1 @ Argument
|
||||
DSB
|
||||
DMB
|
||||
.word 0xe1600070 @ SMC #0 - hand assembled for GCC versions
|
||||
@ call ROM Code API for the service requested
|
||||
|
||||
POP {r4-r12, pc}
|
||||
ENDPROC(omap_smc1)
|
||||
144
u-boot/arch/arm/cpu/armv7/omap-common/mem-common.c
Normal file
144
u-boot/arch/arm/cpu/armv7/omap-common/mem-common.c
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* (C) Copyright 2010
|
||||
* Texas Instruments, <www.ti.com>
|
||||
*
|
||||
* Author :
|
||||
* Mansoor Ahamed <mansoor.ahamed@ti.com>
|
||||
*
|
||||
* Initial Code from:
|
||||
* Manikandan Pillai <mani.pillai@ti.com>
|
||||
* Richard Woodruff <r-woodruff2@ti.com>
|
||||
* Syed Mohammed Khasim <khasim@ti.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/cpu.h>
|
||||
#include <asm/arch/mem.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
#include <command.h>
|
||||
#include <linux/mtd/omap_gpmc.h>
|
||||
|
||||
struct gpmc *gpmc_cfg;
|
||||
|
||||
#if defined(CONFIG_OMAP34XX)
|
||||
/********************************************************
|
||||
* mem_ok() - test used to see if timings are correct
|
||||
* for a part. Helps in guessing which part
|
||||
* we are currently using.
|
||||
*******************************************************/
|
||||
u32 mem_ok(u32 cs)
|
||||
{
|
||||
u32 val1, val2, addr;
|
||||
u32 pattern = 0x12345678;
|
||||
|
||||
addr = OMAP34XX_SDRC_CS0 + get_sdr_cs_offset(cs);
|
||||
|
||||
writel(0x0, addr + 0x400); /* clear pos A */
|
||||
writel(pattern, addr); /* pattern to pos B */
|
||||
writel(0x0, addr + 4); /* remove pattern off the bus */
|
||||
val1 = readl(addr + 0x400); /* get pos A value */
|
||||
val2 = readl(addr); /* get val2 */
|
||||
writel(0x0, addr + 0x400); /* clear pos A */
|
||||
|
||||
if ((val1 != 0) || (val2 != pattern)) /* see if pos A val changed */
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
void enable_gpmc_cs_config(const u32 *gpmc_config, struct gpmc_cs *cs, u32 base,
|
||||
u32 size)
|
||||
{
|
||||
writel(0, &cs->config7);
|
||||
sdelay(1000);
|
||||
/* Delay for settling */
|
||||
writel(gpmc_config[0], &cs->config1);
|
||||
writel(gpmc_config[1], &cs->config2);
|
||||
writel(gpmc_config[2], &cs->config3);
|
||||
writel(gpmc_config[3], &cs->config4);
|
||||
writel(gpmc_config[4], &cs->config5);
|
||||
writel(gpmc_config[5], &cs->config6);
|
||||
/* Enable the config */
|
||||
writel((((size & 0xF) << 8) | ((base >> 24) & 0x3F) |
|
||||
(1 << 6)), &cs->config7);
|
||||
sdelay(2000);
|
||||
}
|
||||
|
||||
/*****************************************************
|
||||
* gpmc_init(): init gpmc bus
|
||||
* Init GPMC for x16, MuxMode (SDRAM in x32).
|
||||
* This code can only be executed from SRAM or SDRAM.
|
||||
*****************************************************/
|
||||
void gpmc_init(void)
|
||||
{
|
||||
/* putting a blanket check on GPMC based on ZeBu for now */
|
||||
gpmc_cfg = (struct gpmc *)GPMC_BASE;
|
||||
#if defined(CONFIG_NOR)
|
||||
/* configure GPMC for NOR */
|
||||
const u32 gpmc_regs[GPMC_MAX_REG] = { STNOR_GPMC_CONFIG1,
|
||||
STNOR_GPMC_CONFIG2,
|
||||
STNOR_GPMC_CONFIG3,
|
||||
STNOR_GPMC_CONFIG4,
|
||||
STNOR_GPMC_CONFIG5,
|
||||
STNOR_GPMC_CONFIG6,
|
||||
STNOR_GPMC_CONFIG7
|
||||
};
|
||||
u32 base = CONFIG_SYS_FLASH_BASE;
|
||||
u32 size = (CONFIG_SYS_FLASH_SIZE > 0x08000000) ? GPMC_SIZE_256M :
|
||||
/* > 64MB */ ((CONFIG_SYS_FLASH_SIZE > 0x04000000) ? GPMC_SIZE_128M :
|
||||
/* > 32MB */ ((CONFIG_SYS_FLASH_SIZE > 0x02000000) ? GPMC_SIZE_64M :
|
||||
/* > 16MB */ ((CONFIG_SYS_FLASH_SIZE > 0x01000000) ? GPMC_SIZE_32M :
|
||||
/* min 16MB */ GPMC_SIZE_16M)));
|
||||
#elif defined(CONFIG_NAND) || defined(CONFIG_CMD_NAND)
|
||||
/* configure GPMC for NAND */
|
||||
const u32 gpmc_regs[GPMC_MAX_REG] = { M_NAND_GPMC_CONFIG1,
|
||||
M_NAND_GPMC_CONFIG2,
|
||||
M_NAND_GPMC_CONFIG3,
|
||||
M_NAND_GPMC_CONFIG4,
|
||||
M_NAND_GPMC_CONFIG5,
|
||||
M_NAND_GPMC_CONFIG6,
|
||||
0
|
||||
};
|
||||
u32 base = CONFIG_SYS_NAND_BASE;
|
||||
u32 size = GPMC_SIZE_16M;
|
||||
|
||||
#elif defined(CONFIG_CMD_ONENAND)
|
||||
const u32 gpmc_regs[GPMC_MAX_REG] = { ONENAND_GPMC_CONFIG1,
|
||||
ONENAND_GPMC_CONFIG2,
|
||||
ONENAND_GPMC_CONFIG3,
|
||||
ONENAND_GPMC_CONFIG4,
|
||||
ONENAND_GPMC_CONFIG5,
|
||||
ONENAND_GPMC_CONFIG6,
|
||||
0
|
||||
};
|
||||
u32 size = GPMC_SIZE_128M;
|
||||
u32 base = CONFIG_SYS_ONENAND_BASE;
|
||||
#else
|
||||
const u32 gpmc_regs[GPMC_MAX_REG] = { 0, 0, 0, 0, 0, 0, 0 };
|
||||
u32 size = 0;
|
||||
u32 base = 0;
|
||||
#endif
|
||||
/* global settings */
|
||||
writel(0x00000008, &gpmc_cfg->sysconfig);
|
||||
writel(0x00000000, &gpmc_cfg->irqstatus);
|
||||
writel(0x00000000, &gpmc_cfg->irqenable);
|
||||
/* disable timeout, set a safe reset value */
|
||||
writel(0x00001ff0, &gpmc_cfg->timeout_control);
|
||||
#ifdef CONFIG_NOR
|
||||
writel(0x00000200, &gpmc_cfg->config);
|
||||
#else
|
||||
writel(0x00000012, &gpmc_cfg->config);
|
||||
#endif
|
||||
/*
|
||||
* Disable the GPMC0 config set by ROM code
|
||||
*/
|
||||
writel(0, &gpmc_cfg->cs[0].config7);
|
||||
sdelay(1000);
|
||||
/* enable chip-select specific configurations */
|
||||
if (base != 0)
|
||||
enable_gpmc_cs_config(gpmc_regs, &gpmc_cfg->cs[0], base, size);
|
||||
}
|
||||
56
u-boot/arch/arm/cpu/armv7/omap-common/omap-cache.c
Normal file
56
u-boot/arch/arm/cpu/armv7/omap-common/omap-cache.c
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
*
|
||||
* Common functions for OMAP4/5 based boards
|
||||
*
|
||||
* (C) Copyright 2010
|
||||
* Texas Instruments, <www.ti.com>
|
||||
*
|
||||
* Author :
|
||||
* Aneesh V <aneesh@ti.com>
|
||||
* Steve Sakoman <steve@sakoman.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/cache.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#define ARMV7_DCACHE_WRITEBACK 0xe
|
||||
#define ARMV7_DOMAIN_CLIENT 1
|
||||
#define ARMV7_DOMAIN_MASK (0x3 << 0)
|
||||
|
||||
void enable_caches(void)
|
||||
{
|
||||
/* Enable D-cache. I-cache is already enabled in start.S */
|
||||
dcache_enable();
|
||||
}
|
||||
|
||||
void dram_bank_mmu_setup(int bank)
|
||||
{
|
||||
bd_t *bd = gd->bd;
|
||||
int i;
|
||||
|
||||
u32 start = bd->bi_dram[bank].start >> 20;
|
||||
u32 size = bd->bi_dram[bank].size >> 20;
|
||||
u32 end = start + size;
|
||||
|
||||
debug("%s: bank: %d\n", __func__, bank);
|
||||
for (i = start; i < end; i++)
|
||||
set_section_dcache(i, ARMV7_DCACHE_WRITEBACK);
|
||||
}
|
||||
|
||||
void arm_init_domains(void)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = get_dacr();
|
||||
/*
|
||||
* Set DOMAIN to client access so that all permissions
|
||||
* set in pagetables are validated by the mmu.
|
||||
*/
|
||||
reg &= ~ARMV7_DOMAIN_MASK;
|
||||
reg |= ARMV7_DOMAIN_CLIENT;
|
||||
set_dacr(reg);
|
||||
}
|
||||
231
u-boot/arch/arm/cpu/armv7/omap-common/pipe3-phy.c
Normal file
231
u-boot/arch/arm/cpu/armv7/omap-common/pipe3-phy.c
Normal file
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* TI PIPE3 PHY
|
||||
*
|
||||
* (C) Copyright 2013
|
||||
* Texas Instruments, <www.ti.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <sata.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/errno.h>
|
||||
#include "pipe3-phy.h"
|
||||
|
||||
/* PLLCTRL Registers */
|
||||
#define PLL_STATUS 0x00000004
|
||||
#define PLL_GO 0x00000008
|
||||
#define PLL_CONFIGURATION1 0x0000000C
|
||||
#define PLL_CONFIGURATION2 0x00000010
|
||||
#define PLL_CONFIGURATION3 0x00000014
|
||||
#define PLL_CONFIGURATION4 0x00000020
|
||||
|
||||
#define PLL_REGM_MASK 0x001FFE00
|
||||
#define PLL_REGM_SHIFT 9
|
||||
#define PLL_REGM_F_MASK 0x0003FFFF
|
||||
#define PLL_REGM_F_SHIFT 0
|
||||
#define PLL_REGN_MASK 0x000001FE
|
||||
#define PLL_REGN_SHIFT 1
|
||||
#define PLL_SELFREQDCO_MASK 0x0000000E
|
||||
#define PLL_SELFREQDCO_SHIFT 1
|
||||
#define PLL_SD_MASK 0x0003FC00
|
||||
#define PLL_SD_SHIFT 10
|
||||
#define SET_PLL_GO 0x1
|
||||
#define PLL_TICOPWDN BIT(16)
|
||||
#define PLL_LDOPWDN BIT(15)
|
||||
#define PLL_LOCK 0x2
|
||||
#define PLL_IDLE 0x1
|
||||
|
||||
/* PHY POWER CONTROL Register */
|
||||
#define OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK 0x003FC000
|
||||
#define OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT 0xE
|
||||
|
||||
#define OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_MASK 0xFFC00000
|
||||
#define OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT 0x16
|
||||
|
||||
#define OMAP_CTRL_PIPE3_PHY_TX_RX_POWERON 0x3
|
||||
#define OMAP_CTRL_PIPE3_PHY_TX_RX_POWEROFF 0x0
|
||||
|
||||
|
||||
#define PLL_IDLE_TIME 100 /* in milliseconds */
|
||||
#define PLL_LOCK_TIME 100 /* in milliseconds */
|
||||
|
||||
static inline u32 omap_pipe3_readl(void __iomem *addr, unsigned offset)
|
||||
{
|
||||
return __raw_readl(addr + offset);
|
||||
}
|
||||
|
||||
static inline void omap_pipe3_writel(void __iomem *addr, unsigned offset,
|
||||
u32 data)
|
||||
{
|
||||
__raw_writel(data, addr + offset);
|
||||
}
|
||||
|
||||
static struct pipe3_dpll_params *omap_pipe3_get_dpll_params(struct omap_pipe3
|
||||
*pipe3)
|
||||
{
|
||||
u32 rate;
|
||||
struct pipe3_dpll_map *dpll_map = pipe3->dpll_map;
|
||||
|
||||
rate = get_sys_clk_freq();
|
||||
|
||||
for (; dpll_map->rate; dpll_map++) {
|
||||
if (rate == dpll_map->rate)
|
||||
return &dpll_map->params;
|
||||
}
|
||||
|
||||
printf("%s: No DPLL configuration for %u Hz SYS CLK\n",
|
||||
__func__, rate);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int omap_pipe3_wait_lock(struct omap_pipe3 *phy)
|
||||
{
|
||||
u32 val;
|
||||
int timeout = PLL_LOCK_TIME;
|
||||
|
||||
do {
|
||||
mdelay(1);
|
||||
val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
|
||||
if (val & PLL_LOCK)
|
||||
break;
|
||||
} while (--timeout);
|
||||
|
||||
if (!(val & PLL_LOCK)) {
|
||||
printf("%s: DPLL failed to lock\n", __func__);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omap_pipe3_dpll_program(struct omap_pipe3 *phy)
|
||||
{
|
||||
u32 val;
|
||||
struct pipe3_dpll_params *dpll_params;
|
||||
|
||||
dpll_params = omap_pipe3_get_dpll_params(phy);
|
||||
if (!dpll_params) {
|
||||
printf("%s: Invalid DPLL parameters\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1);
|
||||
val &= ~PLL_REGN_MASK;
|
||||
val |= dpll_params->n << PLL_REGN_SHIFT;
|
||||
omap_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val);
|
||||
|
||||
val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
|
||||
val &= ~PLL_SELFREQDCO_MASK;
|
||||
val |= dpll_params->freq << PLL_SELFREQDCO_SHIFT;
|
||||
omap_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
|
||||
|
||||
val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1);
|
||||
val &= ~PLL_REGM_MASK;
|
||||
val |= dpll_params->m << PLL_REGM_SHIFT;
|
||||
omap_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val);
|
||||
|
||||
val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION4);
|
||||
val &= ~PLL_REGM_F_MASK;
|
||||
val |= dpll_params->mf << PLL_REGM_F_SHIFT;
|
||||
omap_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION4, val);
|
||||
|
||||
val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION3);
|
||||
val &= ~PLL_SD_MASK;
|
||||
val |= dpll_params->sd << PLL_SD_SHIFT;
|
||||
omap_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION3, val);
|
||||
|
||||
omap_pipe3_writel(phy->pll_ctrl_base, PLL_GO, SET_PLL_GO);
|
||||
|
||||
return omap_pipe3_wait_lock(phy);
|
||||
}
|
||||
|
||||
static void omap_control_phy_power(struct omap_pipe3 *phy, int on)
|
||||
{
|
||||
u32 val, rate;
|
||||
|
||||
val = readl(phy->power_reg);
|
||||
|
||||
rate = get_sys_clk_freq();
|
||||
rate = rate/1000000;
|
||||
|
||||
if (on) {
|
||||
val &= ~(OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK |
|
||||
OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_MASK);
|
||||
val |= OMAP_CTRL_PIPE3_PHY_TX_RX_POWERON <<
|
||||
OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT;
|
||||
val |= rate <<
|
||||
OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT;
|
||||
} else {
|
||||
val &= ~OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK;
|
||||
val |= OMAP_CTRL_PIPE3_PHY_TX_RX_POWEROFF <<
|
||||
OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT;
|
||||
}
|
||||
|
||||
writel(val, phy->power_reg);
|
||||
}
|
||||
|
||||
int phy_pipe3_power_on(struct omap_pipe3 *phy)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
/* Program the DPLL only if not locked */
|
||||
val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
|
||||
if (!(val & PLL_LOCK)) {
|
||||
ret = omap_pipe3_dpll_program(phy);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
/* else just bring it out of IDLE mode */
|
||||
val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
|
||||
if (val & PLL_IDLE) {
|
||||
val &= ~PLL_IDLE;
|
||||
omap_pipe3_writel(phy->pll_ctrl_base,
|
||||
PLL_CONFIGURATION2, val);
|
||||
ret = omap_pipe3_wait_lock(phy);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Power up the PHY */
|
||||
omap_control_phy_power(phy, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int phy_pipe3_power_off(struct omap_pipe3 *phy)
|
||||
{
|
||||
u32 val;
|
||||
int timeout = PLL_IDLE_TIME;
|
||||
|
||||
/* Power down the PHY */
|
||||
omap_control_phy_power(phy, 0);
|
||||
|
||||
/* Put DPLL in IDLE mode */
|
||||
val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
|
||||
val |= PLL_IDLE;
|
||||
omap_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
|
||||
|
||||
/* wait for LDO and Oscillator to power down */
|
||||
do {
|
||||
mdelay(1);
|
||||
val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
|
||||
if ((val & PLL_TICOPWDN) && (val & PLL_LDOPWDN))
|
||||
break;
|
||||
} while (--timeout);
|
||||
|
||||
if (!(val & PLL_TICOPWDN) || !(val & PLL_LDOPWDN)) {
|
||||
printf("%s: Failed to power down DPLL: PLL_STATUS 0x%x\n",
|
||||
__func__, val);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
36
u-boot/arch/arm/cpu/armv7/omap-common/pipe3-phy.h
Normal file
36
u-boot/arch/arm/cpu/armv7/omap-common/pipe3-phy.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* TI PIPE3 PHY
|
||||
*
|
||||
* (C) Copyright 2013
|
||||
* Texas Instruments, <www.ti.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef __OMAP_PIPE3_PHY_H
|
||||
#define __OMAP_PIPE3_PHY_H
|
||||
|
||||
struct pipe3_dpll_params {
|
||||
u16 m;
|
||||
u8 n;
|
||||
u8 freq:3;
|
||||
u8 sd;
|
||||
u32 mf;
|
||||
};
|
||||
|
||||
struct pipe3_dpll_map {
|
||||
unsigned long rate;
|
||||
struct pipe3_dpll_params params;
|
||||
};
|
||||
|
||||
struct omap_pipe3 {
|
||||
void __iomem *pll_ctrl_base;
|
||||
void __iomem *power_reg;
|
||||
struct pipe3_dpll_map *dpll_map;
|
||||
};
|
||||
|
||||
|
||||
int phy_pipe3_power_on(struct omap_pipe3 *phy);
|
||||
int phy_pipe3_power_off(struct omap_pipe3 *pipe3);
|
||||
|
||||
#endif /* __OMAP_PIPE3_PHY_H */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user