GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# (C) Copyright 2000-2006
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
|
||||
extra-$(CONFIG_SPL_BUILD) := start.o
|
||||
|
||||
obj-y = clock.o mxs.o iomux.o timer.o
|
||||
|
||||
ifdef CONFIG_SPL_BUILD
|
||||
obj-y += spl_boot.o spl_lradc_init.o spl_mem_init.o spl_power_init.o
|
||||
endif
|
||||
|
||||
# Specify the target for use in elftosb call
|
||||
MKIMAGE_TARGET-$(CONFIG_MX23) = mxsimage$(CONFIG_SPL_FRAMEWORK:%=-spl).mx23.cfg
|
||||
MKIMAGE_TARGET-$(CONFIG_MX28) = mxsimage$(CONFIG_SPL_FRAMEWORK:%=-spl).mx28.cfg
|
||||
|
||||
# Generate HAB-capable IVT
|
||||
#
|
||||
# Note on computing the post-IVT size field value for the U-Boot binary.
|
||||
# The value is the result of adding the following:
|
||||
# -> The size of U-Boot binary aligned to 64B (u-boot.bin)
|
||||
# -> The size of IVT block aligned to 64B (u-boot.ivt)
|
||||
# -> The size of U-Boot signature (u-boot.sig), 3904 B
|
||||
# -> The 64B hole in front of U-Boot binary for 'struct mxs_spl_data' passing
|
||||
#
|
||||
quiet_cmd_mkivt_mxs = MXSIVT $@
|
||||
cmd_mkivt_mxs = \
|
||||
sz=`expr \`stat -c "%s" $^\` + 64 + 3904 + 128` ; \
|
||||
echo -n "0x402000d1 $2 0 0 0 $3 $4 0 $$sz 0 0 0 0 0 0 0" | \
|
||||
tr -s " " | xargs -d " " -i printf "%08x\n" "{}" | rev | \
|
||||
sed "s/\(.\)\(.\)/\\\\\\\\x\2\1\n/g" | xargs -i printf "{}" >$@
|
||||
|
||||
# Align binary to 64B
|
||||
quiet_cmd_mkalign_mxs = MXSALGN $@
|
||||
cmd_mkalign_mxs = \
|
||||
dd if=$^ of=$@ ibs=64 conv=sync 2>/dev/null && \
|
||||
mv $@ $^
|
||||
|
||||
# Assemble the CSF file
|
||||
quiet_cmd_mkcsfreq_mxs = MXSCSFR $@
|
||||
cmd_mkcsfreq_mxs = \
|
||||
ivt=$(word 1,$^) ; \
|
||||
bin=$(word 2,$^) ; \
|
||||
csf=$(word 3,$^) ; \
|
||||
sed "s@VENDOR@$(VENDOR)@g;s@BOARD@$(BOARD)@g" "$$csf" | \
|
||||
sed '/^\#\#Blocks/ d' > $@ ; \
|
||||
echo " Blocks = $2 0x0 `stat -c '%s' $$bin` \"$$bin\" , \\" >> $@ ; \
|
||||
echo " $3 0x0 0x40 \"$$ivt\"" >> $@
|
||||
|
||||
# Sign files
|
||||
quiet_cmd_mkcst_mxs = MXSCST $@
|
||||
cmd_mkcst_mxs = cst -o $@ < $^ \
|
||||
$(if $(KBUILD_VERBOSE:1=), >/dev/null)
|
||||
|
||||
spl/u-boot-spl.ivt: spl/u-boot-spl.bin
|
||||
$(call if_changed,mkalign_mxs)
|
||||
$(call if_changed,mkivt_mxs,$(CONFIG_SPL_TEXT_BASE),\
|
||||
0x00008000,0x00008040)
|
||||
|
||||
u-boot.ivt: u-boot.bin
|
||||
$(call if_changed,mkalign_mxs)
|
||||
$(call if_changed,mkivt_mxs,$(CONFIG_SYS_TEXT_BASE),\
|
||||
0x40001000,0x40001040)
|
||||
|
||||
spl/u-boot-spl.csf: spl/u-boot-spl.ivt spl/u-boot-spl.bin board/$(VENDOR)/$(BOARD)/sign/u-boot-spl.csf
|
||||
$(call if_changed,mkcsfreq_mxs,$(CONFIG_SPL_TEXT_BASE),0x8000)
|
||||
|
||||
u-boot.csf: u-boot.ivt u-boot.bin board/$(VENDOR)/$(BOARD)/sign/u-boot.csf
|
||||
$(call if_changed,mkcsfreq_mxs,$(CONFIG_SYS_TEXT_BASE),0x40001000)
|
||||
|
||||
%.sig: %.csf
|
||||
$(call if_changed,mkcst_mxs)
|
||||
|
||||
MKIMAGEFLAGS_u-boot.sb = -n $< -T mxsimage
|
||||
u-boot.sb: $(src)/$(MKIMAGE_TARGET-y) u-boot.bin spl/u-boot-spl.bin FORCE
|
||||
$(call if_changed,mkimage)
|
||||
|
||||
MKIMAGEFLAGS_u-boot-signed.sb = -n $< -T mxsimage
|
||||
u-boot-signed.sb: $(src)/mxsimage-signed.cfg u-boot.ivt u-boot.sig spl/u-boot-spl.ivt spl/u-boot-spl.sig FORCE
|
||||
$(call if_changed,mkimage)
|
||||
@@ -0,0 +1,435 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Freescale i.MX23/i.MX28 clock setup code
|
||||
*
|
||||
* Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
|
||||
* on behalf of DENX Software Engineering GmbH
|
||||
*
|
||||
* Based on code from LTIB:
|
||||
* Copyright (C) 2010 Freescale Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <linux/errno.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/imx-regs.h>
|
||||
|
||||
/*
|
||||
* The PLL frequency is 480MHz and XTAL frequency is 24MHz
|
||||
* iMX23: datasheet section 4.2
|
||||
* iMX28: datasheet section 10.2
|
||||
*/
|
||||
#define PLL_FREQ_KHZ 480000
|
||||
#define PLL_FREQ_COEF 18
|
||||
#define XTAL_FREQ_KHZ 24000
|
||||
|
||||
#define PLL_FREQ_MHZ (PLL_FREQ_KHZ / 1000)
|
||||
#define XTAL_FREQ_MHZ (XTAL_FREQ_KHZ / 1000)
|
||||
|
||||
#if defined(CONFIG_MX23)
|
||||
#define MXC_SSPCLK_MAX MXC_SSPCLK0
|
||||
#elif defined(CONFIG_MX28)
|
||||
#define MXC_SSPCLK_MAX MXC_SSPCLK3
|
||||
#endif
|
||||
|
||||
static uint32_t mxs_get_pclk(void)
|
||||
{
|
||||
struct mxs_clkctrl_regs *clkctrl_regs =
|
||||
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
|
||||
|
||||
uint32_t clkctrl, clkseq, div;
|
||||
uint8_t clkfrac, frac;
|
||||
|
||||
clkctrl = readl(&clkctrl_regs->hw_clkctrl_cpu);
|
||||
|
||||
/* No support of fractional divider calculation */
|
||||
if (clkctrl &
|
||||
(CLKCTRL_CPU_DIV_XTAL_FRAC_EN | CLKCTRL_CPU_DIV_CPU_FRAC_EN)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
|
||||
|
||||
/* XTAL Path */
|
||||
if (clkseq & CLKCTRL_CLKSEQ_BYPASS_CPU) {
|
||||
div = (clkctrl & CLKCTRL_CPU_DIV_XTAL_MASK) >>
|
||||
CLKCTRL_CPU_DIV_XTAL_OFFSET;
|
||||
return XTAL_FREQ_MHZ / div;
|
||||
}
|
||||
|
||||
/* REF Path */
|
||||
clkfrac = readb(&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_CPU]);
|
||||
frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK;
|
||||
div = clkctrl & CLKCTRL_CPU_DIV_CPU_MASK;
|
||||
return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
|
||||
}
|
||||
|
||||
static uint32_t mxs_get_hclk(void)
|
||||
{
|
||||
struct mxs_clkctrl_regs *clkctrl_regs =
|
||||
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
|
||||
|
||||
uint32_t div;
|
||||
uint32_t clkctrl;
|
||||
|
||||
clkctrl = readl(&clkctrl_regs->hw_clkctrl_hbus);
|
||||
|
||||
/* No support of fractional divider calculation */
|
||||
if (clkctrl & CLKCTRL_HBUS_DIV_FRAC_EN)
|
||||
return 0;
|
||||
|
||||
div = clkctrl & CLKCTRL_HBUS_DIV_MASK;
|
||||
return mxs_get_pclk() / div;
|
||||
}
|
||||
|
||||
static uint32_t mxs_get_emiclk(void)
|
||||
{
|
||||
struct mxs_clkctrl_regs *clkctrl_regs =
|
||||
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
|
||||
|
||||
uint32_t clkctrl, clkseq, div;
|
||||
uint8_t clkfrac, frac;
|
||||
|
||||
clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
|
||||
clkctrl = readl(&clkctrl_regs->hw_clkctrl_emi);
|
||||
|
||||
/* XTAL Path */
|
||||
if (clkseq & CLKCTRL_CLKSEQ_BYPASS_EMI) {
|
||||
div = (clkctrl & CLKCTRL_EMI_DIV_XTAL_MASK) >>
|
||||
CLKCTRL_EMI_DIV_XTAL_OFFSET;
|
||||
return XTAL_FREQ_MHZ / div;
|
||||
}
|
||||
|
||||
/* REF Path */
|
||||
clkfrac = readb(&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_EMI]);
|
||||
frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK;
|
||||
div = clkctrl & CLKCTRL_EMI_DIV_EMI_MASK;
|
||||
return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
|
||||
}
|
||||
|
||||
static uint32_t mxs_get_gpmiclk(void)
|
||||
{
|
||||
struct mxs_clkctrl_regs *clkctrl_regs =
|
||||
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
|
||||
#if defined(CONFIG_MX23)
|
||||
uint8_t *reg =
|
||||
&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_CPU];
|
||||
#elif defined(CONFIG_MX28)
|
||||
uint8_t *reg =
|
||||
&clkctrl_regs->hw_clkctrl_frac1[CLKCTRL_FRAC1_GPMI];
|
||||
#endif
|
||||
uint32_t clkctrl, clkseq, div;
|
||||
uint8_t clkfrac, frac;
|
||||
|
||||
clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
|
||||
clkctrl = readl(&clkctrl_regs->hw_clkctrl_gpmi);
|
||||
|
||||
/* XTAL Path */
|
||||
if (clkseq & CLKCTRL_CLKSEQ_BYPASS_GPMI) {
|
||||
div = clkctrl & CLKCTRL_GPMI_DIV_MASK;
|
||||
return XTAL_FREQ_MHZ / div;
|
||||
}
|
||||
|
||||
/* REF Path */
|
||||
clkfrac = readb(reg);
|
||||
frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK;
|
||||
div = clkctrl & CLKCTRL_GPMI_DIV_MASK;
|
||||
return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set IO clock frequency, in kHz
|
||||
*/
|
||||
void mxs_set_ioclk(enum mxs_ioclock io, uint32_t freq)
|
||||
{
|
||||
struct mxs_clkctrl_regs *clkctrl_regs =
|
||||
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
|
||||
uint32_t div;
|
||||
int io_reg;
|
||||
|
||||
if (freq == 0)
|
||||
return;
|
||||
|
||||
if ((io < MXC_IOCLK0) || (io > MXC_IOCLK1))
|
||||
return;
|
||||
|
||||
div = (PLL_FREQ_KHZ * PLL_FREQ_COEF) / freq;
|
||||
|
||||
if (div < 18)
|
||||
div = 18;
|
||||
|
||||
if (div > 35)
|
||||
div = 35;
|
||||
|
||||
io_reg = CLKCTRL_FRAC0_IO0 - io; /* Register order is reversed */
|
||||
writeb(CLKCTRL_FRAC_CLKGATE,
|
||||
&clkctrl_regs->hw_clkctrl_frac0_set[io_reg]);
|
||||
writeb(CLKCTRL_FRAC_CLKGATE | (div & CLKCTRL_FRAC_FRAC_MASK),
|
||||
&clkctrl_regs->hw_clkctrl_frac0[io_reg]);
|
||||
writeb(CLKCTRL_FRAC_CLKGATE,
|
||||
&clkctrl_regs->hw_clkctrl_frac0_clr[io_reg]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get IO clock, returns IO clock in kHz
|
||||
*/
|
||||
static uint32_t mxs_get_ioclk(enum mxs_ioclock io)
|
||||
{
|
||||
struct mxs_clkctrl_regs *clkctrl_regs =
|
||||
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
|
||||
uint8_t ret;
|
||||
int io_reg;
|
||||
|
||||
if ((io < MXC_IOCLK0) || (io > MXC_IOCLK1))
|
||||
return 0;
|
||||
|
||||
io_reg = CLKCTRL_FRAC0_IO0 - io; /* Register order is reversed */
|
||||
|
||||
ret = readb(&clkctrl_regs->hw_clkctrl_frac0[io_reg]) &
|
||||
CLKCTRL_FRAC_FRAC_MASK;
|
||||
|
||||
return (PLL_FREQ_KHZ * PLL_FREQ_COEF) / ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure SSP clock frequency, in kHz
|
||||
*/
|
||||
void mxs_set_sspclk(enum mxs_sspclock ssp, uint32_t freq, int xtal)
|
||||
{
|
||||
struct mxs_clkctrl_regs *clkctrl_regs =
|
||||
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
|
||||
uint32_t clk, clkreg;
|
||||
|
||||
if (ssp > MXC_SSPCLK_MAX)
|
||||
return;
|
||||
|
||||
clkreg = (uint32_t)(&clkctrl_regs->hw_clkctrl_ssp0) +
|
||||
(ssp * sizeof(struct mxs_register_32));
|
||||
|
||||
clrbits_le32(clkreg, CLKCTRL_SSP_CLKGATE);
|
||||
while (readl(clkreg) & CLKCTRL_SSP_CLKGATE)
|
||||
;
|
||||
|
||||
if (xtal)
|
||||
clk = XTAL_FREQ_KHZ;
|
||||
else
|
||||
clk = mxs_get_ioclk(ssp >> 1);
|
||||
|
||||
if (freq > clk)
|
||||
return;
|
||||
|
||||
/* Calculate the divider and cap it if necessary */
|
||||
clk /= freq;
|
||||
if (clk > CLKCTRL_SSP_DIV_MASK)
|
||||
clk = CLKCTRL_SSP_DIV_MASK;
|
||||
|
||||
clrsetbits_le32(clkreg, CLKCTRL_SSP_DIV_MASK, clk);
|
||||
while (readl(clkreg) & CLKCTRL_SSP_BUSY)
|
||||
;
|
||||
|
||||
if (xtal)
|
||||
writel(CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp,
|
||||
&clkctrl_regs->hw_clkctrl_clkseq_set);
|
||||
else
|
||||
writel(CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp,
|
||||
&clkctrl_regs->hw_clkctrl_clkseq_clr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return SSP frequency, in kHz
|
||||
*/
|
||||
static uint32_t mxs_get_sspclk(enum mxs_sspclock ssp)
|
||||
{
|
||||
struct mxs_clkctrl_regs *clkctrl_regs =
|
||||
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
|
||||
uint32_t clkreg;
|
||||
uint32_t clk, tmp;
|
||||
|
||||
if (ssp > MXC_SSPCLK_MAX)
|
||||
return 0;
|
||||
|
||||
tmp = readl(&clkctrl_regs->hw_clkctrl_clkseq);
|
||||
if (tmp & (CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp))
|
||||
return XTAL_FREQ_KHZ;
|
||||
|
||||
clkreg = (uint32_t)(&clkctrl_regs->hw_clkctrl_ssp0) +
|
||||
(ssp * sizeof(struct mxs_register_32));
|
||||
|
||||
tmp = readl(clkreg) & CLKCTRL_SSP_DIV_MASK;
|
||||
|
||||
if (tmp == 0)
|
||||
return 0;
|
||||
|
||||
clk = mxs_get_ioclk(ssp >> 1);
|
||||
|
||||
return clk / tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set SSP/MMC bus frequency, in kHz)
|
||||
*/
|
||||
void mxs_set_ssp_busclock(unsigned int bus, uint32_t freq)
|
||||
{
|
||||
struct mxs_ssp_regs *ssp_regs;
|
||||
const enum mxs_sspclock clk = mxs_ssp_clock_by_bus(bus);
|
||||
const uint32_t sspclk = mxs_get_sspclk(clk);
|
||||
uint32_t reg;
|
||||
uint32_t divide, rate, tgtclk;
|
||||
|
||||
ssp_regs = mxs_ssp_regs_by_bus(bus);
|
||||
|
||||
/*
|
||||
* SSP bit rate = SSPCLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE)),
|
||||
* CLOCK_DIVIDE has to be an even value from 2 to 254, and
|
||||
* CLOCK_RATE could be any integer from 0 to 255.
|
||||
*/
|
||||
for (divide = 2; divide < 254; divide += 2) {
|
||||
rate = sspclk / freq / divide;
|
||||
if (rate <= 256)
|
||||
break;
|
||||
}
|
||||
|
||||
tgtclk = sspclk / divide / rate;
|
||||
while (tgtclk > freq) {
|
||||
rate++;
|
||||
tgtclk = sspclk / divide / rate;
|
||||
}
|
||||
if (rate > 256)
|
||||
rate = 256;
|
||||
|
||||
/* Always set timeout the maximum */
|
||||
reg = SSP_TIMING_TIMEOUT_MASK |
|
||||
(divide << SSP_TIMING_CLOCK_DIVIDE_OFFSET) |
|
||||
((rate - 1) << SSP_TIMING_CLOCK_RATE_OFFSET);
|
||||
writel(reg, &ssp_regs->hw_ssp_timing);
|
||||
|
||||
debug("SPI%d: Set freq rate to %d KHz (requested %d KHz)\n",
|
||||
bus, tgtclk, freq);
|
||||
}
|
||||
|
||||
void mxs_set_lcdclk(uint32_t __maybe_unused lcd_base, uint32_t freq)
|
||||
{
|
||||
struct mxs_clkctrl_regs *clkctrl_regs =
|
||||
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
|
||||
uint32_t fp, x, k_rest, k_best, x_best, tk;
|
||||
int32_t k_best_l = 999, k_best_t = 0, x_best_l = 0xff, x_best_t = 0xff;
|
||||
|
||||
if (freq == 0)
|
||||
return;
|
||||
|
||||
#if defined(CONFIG_MX23)
|
||||
writel(CLKCTRL_CLKSEQ_BYPASS_PIX, &clkctrl_regs->hw_clkctrl_clkseq_clr);
|
||||
#elif defined(CONFIG_MX28)
|
||||
writel(CLKCTRL_CLKSEQ_BYPASS_DIS_LCDIF, &clkctrl_regs->hw_clkctrl_clkseq_clr);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* / 18 \ 1 1
|
||||
* freq kHz = | 480000000 Hz * -- | * --- * ------
|
||||
* \ x / k 1000
|
||||
*
|
||||
* 480000000 Hz 18
|
||||
* ------------ * --
|
||||
* freq kHz x
|
||||
* k = -------------------
|
||||
* 1000
|
||||
*/
|
||||
|
||||
fp = ((PLL_FREQ_KHZ * 1000) / freq) * 18;
|
||||
|
||||
for (x = 18; x <= 35; x++) {
|
||||
tk = fp / x;
|
||||
if ((tk / 1000 == 0) || (tk / 1000 > 255))
|
||||
continue;
|
||||
|
||||
k_rest = tk % 1000;
|
||||
|
||||
if (k_rest < (k_best_l % 1000)) {
|
||||
k_best_l = tk;
|
||||
x_best_l = x;
|
||||
}
|
||||
|
||||
if (k_rest > (k_best_t % 1000)) {
|
||||
k_best_t = tk;
|
||||
x_best_t = x;
|
||||
}
|
||||
}
|
||||
|
||||
if (1000 - (k_best_t % 1000) > (k_best_l % 1000)) {
|
||||
k_best = k_best_l;
|
||||
x_best = x_best_l;
|
||||
} else {
|
||||
k_best = k_best_t;
|
||||
x_best = x_best_t;
|
||||
}
|
||||
|
||||
k_best /= 1000;
|
||||
|
||||
#if defined(CONFIG_MX23)
|
||||
writeb(CLKCTRL_FRAC_CLKGATE,
|
||||
&clkctrl_regs->hw_clkctrl_frac0_set[CLKCTRL_FRAC0_PIX]);
|
||||
writeb(CLKCTRL_FRAC_CLKGATE | (x_best & CLKCTRL_FRAC_FRAC_MASK),
|
||||
&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_PIX]);
|
||||
writeb(CLKCTRL_FRAC_CLKGATE,
|
||||
&clkctrl_regs->hw_clkctrl_frac0_clr[CLKCTRL_FRAC0_PIX]);
|
||||
|
||||
writel(CLKCTRL_PIX_CLKGATE,
|
||||
&clkctrl_regs->hw_clkctrl_pix_set);
|
||||
clrsetbits_le32(&clkctrl_regs->hw_clkctrl_pix,
|
||||
CLKCTRL_PIX_DIV_MASK | CLKCTRL_PIX_CLKGATE,
|
||||
k_best << CLKCTRL_PIX_DIV_OFFSET);
|
||||
|
||||
while (readl(&clkctrl_regs->hw_clkctrl_pix) & CLKCTRL_PIX_BUSY)
|
||||
;
|
||||
#elif defined(CONFIG_MX28)
|
||||
writeb(CLKCTRL_FRAC_CLKGATE,
|
||||
&clkctrl_regs->hw_clkctrl_frac1_set[CLKCTRL_FRAC1_PIX]);
|
||||
writeb(CLKCTRL_FRAC_CLKGATE | (x_best & CLKCTRL_FRAC_FRAC_MASK),
|
||||
&clkctrl_regs->hw_clkctrl_frac1[CLKCTRL_FRAC1_PIX]);
|
||||
writeb(CLKCTRL_FRAC_CLKGATE,
|
||||
&clkctrl_regs->hw_clkctrl_frac1_clr[CLKCTRL_FRAC1_PIX]);
|
||||
|
||||
writel(CLKCTRL_DIS_LCDIF_CLKGATE,
|
||||
&clkctrl_regs->hw_clkctrl_lcdif_set);
|
||||
clrsetbits_le32(&clkctrl_regs->hw_clkctrl_lcdif,
|
||||
CLKCTRL_DIS_LCDIF_DIV_MASK | CLKCTRL_DIS_LCDIF_CLKGATE,
|
||||
k_best << CLKCTRL_DIS_LCDIF_DIV_OFFSET);
|
||||
|
||||
while (readl(&clkctrl_regs->hw_clkctrl_lcdif) & CLKCTRL_DIS_LCDIF_BUSY)
|
||||
;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t mxc_get_clock(enum mxc_clock clk)
|
||||
{
|
||||
switch (clk) {
|
||||
case MXC_ARM_CLK:
|
||||
return mxs_get_pclk() * 1000000;
|
||||
case MXC_GPMI_CLK:
|
||||
return mxs_get_gpmiclk() * 1000000;
|
||||
case MXC_AHB_CLK:
|
||||
case MXC_IPG_CLK:
|
||||
return mxs_get_hclk() * 1000000;
|
||||
case MXC_EMI_CLK:
|
||||
return mxs_get_emiclk();
|
||||
case MXC_IO0_CLK:
|
||||
return mxs_get_ioclk(MXC_IOCLK0);
|
||||
case MXC_IO1_CLK:
|
||||
return mxs_get_ioclk(MXC_IOCLK1);
|
||||
case MXC_XTAL_CLK:
|
||||
return XTAL_FREQ_KHZ * 1000;
|
||||
case MXC_SSP0_CLK:
|
||||
return mxs_get_sspclk(MXC_SSPCLK0);
|
||||
#ifdef CONFIG_MX28
|
||||
case MXC_SSP1_CLK:
|
||||
return mxs_get_sspclk(MXC_SSPCLK1);
|
||||
case MXC_SSP2_CLK:
|
||||
return mxs_get_sspclk(MXC_SSPCLK2);
|
||||
case MXC_SSP3_CLK:
|
||||
return mxs_get_sspclk(MXC_SSPCLK3);
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2004-2006,2010 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
* Copyright (C) 2008 by Sascha Hauer <kernel@pengutronix.de>
|
||||
* Copyright (C) 2009 by Jan Weitzel Phytec Messtechnik GmbH,
|
||||
* <armlinux@phytec.de>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <linux/errno.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/iomux.h>
|
||||
#include <asm/arch/imx-regs.h>
|
||||
|
||||
#if defined(CONFIG_MX23)
|
||||
#define DRIVE_OFFSET 0x200
|
||||
#define PULL_OFFSET 0x400
|
||||
#elif defined(CONFIG_MX28)
|
||||
#define DRIVE_OFFSET 0x300
|
||||
#define PULL_OFFSET 0x600
|
||||
#else
|
||||
#error "Please select CONFIG_MX23 or CONFIG_MX28"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* configures a single pad in the iomuxer
|
||||
*/
|
||||
int mxs_iomux_setup_pad(iomux_cfg_t pad)
|
||||
{
|
||||
u32 reg, ofs, bp, bm;
|
||||
void *iomux_base = (void *)MXS_PINCTRL_BASE;
|
||||
struct mxs_register_32 *mxs_reg;
|
||||
|
||||
/* muxsel */
|
||||
ofs = 0x100;
|
||||
ofs += PAD_BANK(pad) * 0x20 + PAD_PIN(pad) / 16 * 0x10;
|
||||
bp = PAD_PIN(pad) % 16 * 2;
|
||||
bm = 0x3 << bp;
|
||||
reg = readl(iomux_base + ofs);
|
||||
reg &= ~bm;
|
||||
reg |= PAD_MUXSEL(pad) << bp;
|
||||
writel(reg, iomux_base + ofs);
|
||||
|
||||
/* drive */
|
||||
ofs = DRIVE_OFFSET;
|
||||
ofs += PAD_BANK(pad) * 0x40 + PAD_PIN(pad) / 8 * 0x10;
|
||||
/* mA */
|
||||
if (PAD_MA_VALID(pad)) {
|
||||
bp = PAD_PIN(pad) % 8 * 4;
|
||||
bm = 0x3 << bp;
|
||||
reg = readl(iomux_base + ofs);
|
||||
reg &= ~bm;
|
||||
reg |= PAD_MA(pad) << bp;
|
||||
writel(reg, iomux_base + ofs);
|
||||
}
|
||||
/* vol */
|
||||
if (PAD_VOL_VALID(pad)) {
|
||||
bp = PAD_PIN(pad) % 8 * 4 + 2;
|
||||
mxs_reg = (struct mxs_register_32 *)(iomux_base + ofs);
|
||||
if (PAD_VOL(pad))
|
||||
writel(1 << bp, &mxs_reg->reg_set);
|
||||
else
|
||||
writel(1 << bp, &mxs_reg->reg_clr);
|
||||
}
|
||||
|
||||
/* pull */
|
||||
if (PAD_PULL_VALID(pad)) {
|
||||
ofs = PULL_OFFSET;
|
||||
ofs += PAD_BANK(pad) * 0x10;
|
||||
bp = PAD_PIN(pad);
|
||||
mxs_reg = (struct mxs_register_32 *)(iomux_base + ofs);
|
||||
if (PAD_PULL(pad))
|
||||
writel(1 << bp, &mxs_reg->reg_set);
|
||||
else
|
||||
writel(1 << bp, &mxs_reg->reg_clr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mxs_iomux_setup_multiple_pads(const iomux_cfg_t *pad_list, unsigned count)
|
||||
{
|
||||
const iomux_cfg_t *p = pad_list;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
ret = mxs_iomux_setup_pad(*p);
|
||||
if (ret)
|
||||
return ret;
|
||||
p++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,284 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Freescale i.MX23/i.MX28 common code
|
||||
*
|
||||
* Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
|
||||
* on behalf of DENX Software Engineering GmbH
|
||||
*
|
||||
* Based on code from LTIB:
|
||||
* Copyright (C) 2010 Freescale Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <linux/errno.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/mach-imx/dma.h>
|
||||
#include <asm/arch/gpio.h>
|
||||
#include <asm/arch/iomux.h>
|
||||
#include <asm/arch/imx-regs.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/* Lowlevel init isn't used on i.MX28, so just have a dummy here */
|
||||
__weak void lowlevel_init(void) {}
|
||||
|
||||
void reset_cpu(ulong ignored) __attribute__((noreturn));
|
||||
|
||||
void reset_cpu(ulong ignored)
|
||||
{
|
||||
struct mxs_rtc_regs *rtc_regs =
|
||||
(struct mxs_rtc_regs *)MXS_RTC_BASE;
|
||||
struct mxs_lcdif_regs *lcdif_regs =
|
||||
(struct mxs_lcdif_regs *)MXS_LCDIF_BASE;
|
||||
|
||||
/*
|
||||
* Shut down the LCD controller as it interferes with BootROM boot mode
|
||||
* pads sampling.
|
||||
*/
|
||||
writel(LCDIF_CTRL_RUN, &lcdif_regs->hw_lcdif_ctrl_clr);
|
||||
|
||||
/* Wait 1 uS before doing the actual watchdog reset */
|
||||
writel(1, &rtc_regs->hw_rtc_watchdog);
|
||||
writel(RTC_CTRL_WATCHDOGEN, &rtc_regs->hw_rtc_ctrl_set);
|
||||
|
||||
/* Endless loop, reset will exit from here */
|
||||
for (;;)
|
||||
;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function will craft a jumptable at 0x0 which will redirect interrupt
|
||||
* vectoring to proper location of U-Boot in RAM.
|
||||
*
|
||||
* The structure of the jumptable will be as follows:
|
||||
* ldr pc, [pc, #0x18] ..... for each vector, thus repeated 8 times
|
||||
* <destination address> ... for each previous ldr, thus also repeated 8 times
|
||||
*
|
||||
* The "ldr pc, [pc, #0x18]" instruction above loads address from memory at
|
||||
* offset 0x18 from current value of PC register. Note that PC is already
|
||||
* incremented by 4 when computing the offset, so the effective offset is
|
||||
* actually 0x20, this the associated <destination address>. Loading the PC
|
||||
* register with an address performs a jump to that address.
|
||||
*/
|
||||
void mx28_fixup_vt(uint32_t start_addr)
|
||||
{
|
||||
/* ldr pc, [pc, #0x18] */
|
||||
const uint32_t ldr_pc = 0xe59ff018;
|
||||
/* Jumptable location is 0x0 */
|
||||
uint32_t *vt = (uint32_t *)0x0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
/* cppcheck-suppress nullPointer */
|
||||
vt[i] = ldr_pc;
|
||||
/* cppcheck-suppress nullPointer */
|
||||
vt[i + 8] = start_addr + (4 * i);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARCH_MISC_INIT
|
||||
int arch_misc_init(void)
|
||||
{
|
||||
mx28_fixup_vt(gd->relocaddr);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int arch_cpu_init(void)
|
||||
{
|
||||
struct mxs_clkctrl_regs *clkctrl_regs =
|
||||
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
|
||||
extern uint32_t _start;
|
||||
|
||||
mx28_fixup_vt((uint32_t)&_start);
|
||||
|
||||
/*
|
||||
* Enable NAND clock
|
||||
*/
|
||||
/* Clear bypass bit */
|
||||
writel(CLKCTRL_CLKSEQ_BYPASS_GPMI,
|
||||
&clkctrl_regs->hw_clkctrl_clkseq_set);
|
||||
|
||||
/* Set GPMI clock to ref_gpmi / 12 */
|
||||
clrsetbits_le32(&clkctrl_regs->hw_clkctrl_gpmi,
|
||||
CLKCTRL_GPMI_CLKGATE | CLKCTRL_GPMI_DIV_MASK, 1);
|
||||
|
||||
udelay(1000);
|
||||
|
||||
/*
|
||||
* Configure GPIO unit
|
||||
*/
|
||||
mxs_gpio_init();
|
||||
|
||||
#ifdef CONFIG_APBH_DMA
|
||||
/* Start APBH DMA */
|
||||
mxs_dma_init();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 get_cpu_rev(void)
|
||||
{
|
||||
struct mxs_digctl_regs *digctl_regs =
|
||||
(struct mxs_digctl_regs *)MXS_DIGCTL_BASE;
|
||||
uint8_t rev = readl(&digctl_regs->hw_digctl_chipid) & 0x000000FF;
|
||||
|
||||
switch (readl(&digctl_regs->hw_digctl_chipid) & HW_DIGCTL_CHIPID_MASK) {
|
||||
case HW_DIGCTL_CHIPID_MX23:
|
||||
switch (rev) {
|
||||
case 0x0:
|
||||
case 0x1:
|
||||
case 0x2:
|
||||
case 0x3:
|
||||
case 0x4:
|
||||
return (MXC_CPU_MX23 << 12) | (rev + 0x10);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
case HW_DIGCTL_CHIPID_MX28:
|
||||
switch (rev) {
|
||||
case 0x1:
|
||||
return (MXC_CPU_MX28 << 12) | 0x12;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_DISPLAY_CPUINFO)
|
||||
const char *get_imx_type(u32 imxtype)
|
||||
{
|
||||
switch (imxtype) {
|
||||
case MXC_CPU_MX23:
|
||||
return "23";
|
||||
case MXC_CPU_MX28:
|
||||
return "28";
|
||||
default:
|
||||
return "??";
|
||||
}
|
||||
}
|
||||
|
||||
int print_cpuinfo(void)
|
||||
{
|
||||
u32 cpurev;
|
||||
struct mxs_spl_data *data = MXS_SPL_DATA;
|
||||
|
||||
cpurev = get_cpu_rev();
|
||||
printf("CPU: Freescale i.MX%s rev%d.%d at %d MHz\n",
|
||||
get_imx_type((cpurev & 0xFF000) >> 12),
|
||||
(cpurev & 0x000F0) >> 4,
|
||||
(cpurev & 0x0000F) >> 0,
|
||||
mxc_get_clock(MXC_ARM_CLK) / 1000000);
|
||||
printf("BOOT: %s\n", mxs_boot_modes[data->boot_mode_idx].mode);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int do_mx28_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
|
||||
{
|
||||
printf("CPU: %3d MHz\n", mxc_get_clock(MXC_ARM_CLK) / 1000000);
|
||||
printf("BUS: %3d MHz\n", mxc_get_clock(MXC_AHB_CLK) / 1000000);
|
||||
printf("EMI: %3d MHz\n", mxc_get_clock(MXC_EMI_CLK));
|
||||
printf("GPMI: %3d MHz\n", mxc_get_clock(MXC_GPMI_CLK) / 1000000);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initializes on-chip ethernet controllers.
|
||||
*/
|
||||
#if defined(CONFIG_MX28) && defined(CONFIG_CMD_NET)
|
||||
int cpu_eth_init(bd_t *bis)
|
||||
{
|
||||
struct mxs_clkctrl_regs *clkctrl_regs =
|
||||
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
|
||||
|
||||
/* Turn on ENET clocks */
|
||||
clrbits_le32(&clkctrl_regs->hw_clkctrl_enet,
|
||||
CLKCTRL_ENET_SLEEP | CLKCTRL_ENET_DISABLE);
|
||||
|
||||
/* Set up ENET PLL for 50 MHz */
|
||||
/* Power on ENET PLL */
|
||||
writel(CLKCTRL_PLL2CTRL0_POWER,
|
||||
&clkctrl_regs->hw_clkctrl_pll2ctrl0_set);
|
||||
|
||||
udelay(10);
|
||||
|
||||
/* Gate on ENET PLL */
|
||||
writel(CLKCTRL_PLL2CTRL0_CLKGATE,
|
||||
&clkctrl_regs->hw_clkctrl_pll2ctrl0_clr);
|
||||
|
||||
/* Enable pad output */
|
||||
setbits_le32(&clkctrl_regs->hw_clkctrl_enet, CLKCTRL_ENET_CLK_OUT_EN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
__weak void mx28_adjust_mac(int dev_id, unsigned char *mac)
|
||||
{
|
||||
mac[0] = 0x00;
|
||||
mac[1] = 0x04; /* Use FSL vendor MAC address by default */
|
||||
|
||||
if (dev_id == 1) /* Let MAC1 be MAC0 + 1 by default */
|
||||
mac[5] += 1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MX28_FEC_MAC_IN_OCOTP
|
||||
|
||||
#define MXS_OCOTP_MAX_TIMEOUT 1000000
|
||||
void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
|
||||
{
|
||||
struct mxs_ocotp_regs *ocotp_regs =
|
||||
(struct mxs_ocotp_regs *)MXS_OCOTP_BASE;
|
||||
uint32_t data;
|
||||
|
||||
memset(mac, 0, 6);
|
||||
|
||||
writel(OCOTP_CTRL_RD_BANK_OPEN, &ocotp_regs->hw_ocotp_ctrl_set);
|
||||
|
||||
if (mxs_wait_mask_clr(&ocotp_regs->hw_ocotp_ctrl_reg, OCOTP_CTRL_BUSY,
|
||||
MXS_OCOTP_MAX_TIMEOUT)) {
|
||||
printf("MXS FEC: Can't get MAC from OCOTP\n");
|
||||
return;
|
||||
}
|
||||
|
||||
data = readl(&ocotp_regs->hw_ocotp_cust0);
|
||||
|
||||
mac[2] = (data >> 24) & 0xff;
|
||||
mac[3] = (data >> 16) & 0xff;
|
||||
mac[4] = (data >> 8) & 0xff;
|
||||
mac[5] = data & 0xff;
|
||||
mx28_adjust_mac(dev_id, mac);
|
||||
}
|
||||
#else
|
||||
void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
|
||||
{
|
||||
memset(mac, 0, 6);
|
||||
}
|
||||
#endif
|
||||
|
||||
int mxs_dram_init(void)
|
||||
{
|
||||
struct mxs_spl_data *data = MXS_SPL_DATA;
|
||||
|
||||
if (data->mem_dram_size == 0) {
|
||||
printf("MXS:\n"
|
||||
"Error, the RAM size passed up from SPL is 0!\n");
|
||||
hang();
|
||||
}
|
||||
|
||||
gd->ram_size = data->mem_dram_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
clocks, CONFIG_SYS_MAXARGS, 1, do_mx28_showclocks,
|
||||
"display clocks",
|
||||
""
|
||||
);
|
||||
@@ -0,0 +1,28 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Freescale i.MX28 SPL functions
|
||||
*
|
||||
* Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
|
||||
* on behalf of DENX Software Engineering GmbH
|
||||
*/
|
||||
|
||||
#ifndef __M28_INIT_H__
|
||||
#define __M28_INIT_H__
|
||||
|
||||
void early_delay(int delay);
|
||||
|
||||
void mxs_power_init(void);
|
||||
|
||||
#ifdef CONFIG_SPL_MXS_PSWITCH_WAIT
|
||||
void mxs_power_wait_pswitch(void);
|
||||
#else
|
||||
static inline void mxs_power_wait_pswitch(void) { }
|
||||
#endif
|
||||
|
||||
void mxs_mem_init(void);
|
||||
uint32_t mxs_mem_get_size(void);
|
||||
|
||||
void mxs_lradc_init(void);
|
||||
void mxs_lradc_enable_batt_measurement(void);
|
||||
|
||||
#endif /* __M28_INIT_H__ */
|
||||
@@ -0,0 +1,11 @@
|
||||
DISPLAYPROGRESS
|
||||
SECTION 0x0 BOOTABLE
|
||||
TAG LAST
|
||||
LOAD 0x1000 spl/u-boot-spl.bin
|
||||
LOAD 0x8000 spl/u-boot-spl.ivt
|
||||
LOAD 0x8040 spl/u-boot-spl.sig
|
||||
CALL HAB 0x8000 0x0
|
||||
LOAD 0x40002000 u-boot.bin
|
||||
LOAD 0x40001000 u-boot.ivt
|
||||
LOAD 0x40001040 u-boot.sig
|
||||
CALL HAB 0x40001000 0x0
|
||||
@@ -0,0 +1,5 @@
|
||||
DISPLAYPROGRESS
|
||||
SECTION 0x0 BOOTABLE
|
||||
TAG LAST
|
||||
LOAD 0x1000 spl/u-boot-spl.bin
|
||||
CALL 0x1000 0x0
|
||||
@@ -0,0 +1,6 @@
|
||||
DISPLAYPROGRESS
|
||||
SECTION 0x0 BOOTABLE
|
||||
TAG LAST
|
||||
LOAD 0x1000 spl/u-boot-spl.bin
|
||||
LOAD IVT 0x8000 0x1000
|
||||
CALL HAB 0x8000 0x0
|
||||
@@ -0,0 +1,7 @@
|
||||
DISPLAYPROGRESS
|
||||
SECTION 0x0 BOOTABLE
|
||||
TAG LAST
|
||||
LOAD 0x1000 spl/u-boot-spl.bin
|
||||
CALL 0x1000 0x0
|
||||
LOAD 0x40002000 u-boot.bin
|
||||
CALL 0x40002000 0x0
|
||||
@@ -0,0 +1,9 @@
|
||||
DISPLAYPROGRESS
|
||||
SECTION 0x0 BOOTABLE
|
||||
TAG LAST
|
||||
LOAD 0x1000 spl/u-boot-spl.bin
|
||||
LOAD IVT 0x8000 0x1000
|
||||
CALL HAB 0x8000 0x0
|
||||
LOAD 0x40002000 u-boot.bin
|
||||
LOAD IVT 0x8000 0x40002000
|
||||
CALL HAB 0x8000 0x0
|
||||
@@ -0,0 +1,162 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Freescale i.MX28 Boot setup
|
||||
*
|
||||
* Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
|
||||
* on behalf of DENX Software Engineering GmbH
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <config.h>
|
||||
#include <serial.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/imx-regs.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
#include "mxs_init.h"
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
static gd_t gdata __section(".data");
|
||||
#ifdef CONFIG_SPL_SERIAL_SUPPORT
|
||||
static bd_t bdata __section(".data");
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This delay function is intended to be used only in early stage of boot, where
|
||||
* clock are not set up yet. The timer used here is reset on every boot and
|
||||
* takes a few seconds to roll. The boot doesn't take that long, so to keep the
|
||||
* code simple, it doesn't take rolling into consideration.
|
||||
*/
|
||||
void early_delay(int delay)
|
||||
{
|
||||
struct mxs_digctl_regs *digctl_regs =
|
||||
(struct mxs_digctl_regs *)MXS_DIGCTL_BASE;
|
||||
|
||||
uint32_t st = readl(&digctl_regs->hw_digctl_microseconds);
|
||||
st += delay;
|
||||
while (st > readl(&digctl_regs->hw_digctl_microseconds))
|
||||
;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_MX23)
|
||||
#define MUX_CONFIG_BOOTMODE_PAD (MXS_PAD_3V3 | MXS_PAD_4MA | MXS_PAD_NOPULL)
|
||||
static const iomux_cfg_t iomux_boot[] = {
|
||||
MX23_PAD_LCD_D00__GPIO_1_0 | MUX_CONFIG_BOOTMODE_PAD,
|
||||
MX23_PAD_LCD_D01__GPIO_1_1 | MUX_CONFIG_BOOTMODE_PAD,
|
||||
MX23_PAD_LCD_D02__GPIO_1_2 | MUX_CONFIG_BOOTMODE_PAD,
|
||||
MX23_PAD_LCD_D03__GPIO_1_3 | MUX_CONFIG_BOOTMODE_PAD,
|
||||
MX23_PAD_LCD_D04__GPIO_1_4 | MUX_CONFIG_BOOTMODE_PAD,
|
||||
MX23_PAD_LCD_D05__GPIO_1_5 | MUX_CONFIG_BOOTMODE_PAD,
|
||||
};
|
||||
#endif
|
||||
|
||||
static uint8_t mxs_get_bootmode_index(void)
|
||||
{
|
||||
uint8_t bootmode = 0;
|
||||
int i;
|
||||
uint8_t masked;
|
||||
|
||||
#if defined(CONFIG_MX23)
|
||||
/* Setup IOMUX of bootmode pads to GPIO */
|
||||
mxs_iomux_setup_multiple_pads(iomux_boot, ARRAY_SIZE(iomux_boot));
|
||||
|
||||
/* Setup bootmode pins as GPIO input */
|
||||
gpio_direction_input(MX23_PAD_LCD_D00__GPIO_1_0);
|
||||
gpio_direction_input(MX23_PAD_LCD_D01__GPIO_1_1);
|
||||
gpio_direction_input(MX23_PAD_LCD_D02__GPIO_1_2);
|
||||
gpio_direction_input(MX23_PAD_LCD_D03__GPIO_1_3);
|
||||
gpio_direction_input(MX23_PAD_LCD_D05__GPIO_1_5);
|
||||
|
||||
/* Read bootmode pads */
|
||||
bootmode |= (gpio_get_value(MX23_PAD_LCD_D00__GPIO_1_0) ? 1 : 0) << 0;
|
||||
bootmode |= (gpio_get_value(MX23_PAD_LCD_D01__GPIO_1_1) ? 1 : 0) << 1;
|
||||
bootmode |= (gpio_get_value(MX23_PAD_LCD_D02__GPIO_1_2) ? 1 : 0) << 2;
|
||||
bootmode |= (gpio_get_value(MX23_PAD_LCD_D03__GPIO_1_3) ? 1 : 0) << 3;
|
||||
bootmode |= (gpio_get_value(MX23_PAD_LCD_D05__GPIO_1_5) ? 1 : 0) << 5;
|
||||
#elif defined(CONFIG_MX28)
|
||||
/* The global boot mode will be detected by ROM code and its value
|
||||
* is stored at the fixed address 0x00019BF0 in OCRAM.
|
||||
*/
|
||||
#define GLOBAL_BOOT_MODE_ADDR 0x00019BF0
|
||||
bootmode = __raw_readl(GLOBAL_BOOT_MODE_ADDR);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(mxs_boot_modes); i++) {
|
||||
masked = bootmode & mxs_boot_modes[i].boot_mask;
|
||||
if (masked == mxs_boot_modes[i].boot_pads)
|
||||
break;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static void mxs_spl_fixup_vectors(void)
|
||||
{
|
||||
/*
|
||||
* Copy our vector table to 0x0, since due to HAB, we cannot
|
||||
* be loaded to 0x0. We want to have working vectoring though,
|
||||
* thus this fixup. Our vectoring table is PIC, so copying is
|
||||
* fine.
|
||||
*/
|
||||
extern uint32_t _start;
|
||||
|
||||
/* cppcheck-suppress nullPointer */
|
||||
memcpy(0x0, &_start, 0x60);
|
||||
}
|
||||
|
||||
static void mxs_spl_console_init(void)
|
||||
{
|
||||
#ifdef CONFIG_SPL_SERIAL_SUPPORT
|
||||
gd->bd = &bdata;
|
||||
gd->baudrate = CONFIG_BAUDRATE;
|
||||
serial_init();
|
||||
gd->have_console = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void mxs_common_spl_init(const uint32_t arg, const uint32_t *resptr,
|
||||
const iomux_cfg_t *iomux_setup,
|
||||
const unsigned int iomux_size)
|
||||
{
|
||||
struct mxs_spl_data *data = MXS_SPL_DATA;
|
||||
uint8_t bootmode = mxs_get_bootmode_index();
|
||||
gd = &gdata;
|
||||
|
||||
mxs_spl_fixup_vectors();
|
||||
|
||||
mxs_iomux_setup_multiple_pads(iomux_setup, iomux_size);
|
||||
|
||||
mxs_spl_console_init();
|
||||
debug("SPL: Serial Console Initialised\n");
|
||||
|
||||
mxs_power_init();
|
||||
|
||||
mxs_mem_init();
|
||||
data->mem_dram_size = mxs_mem_get_size();
|
||||
|
||||
data->boot_mode_idx = bootmode;
|
||||
|
||||
mxs_power_wait_pswitch();
|
||||
|
||||
if (mxs_boot_modes[data->boot_mode_idx].boot_pads == MXS_BM_JTAG) {
|
||||
debug("SPL: Waiting for JTAG user\n");
|
||||
asm volatile ("x: b x");
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SPL_FRAMEWORK
|
||||
/* Support aparatus */
|
||||
inline void board_init_f(unsigned long bootflag)
|
||||
{
|
||||
for (;;)
|
||||
;
|
||||
}
|
||||
|
||||
inline void board_init_r(gd_t *id, ulong dest_addr)
|
||||
{
|
||||
for (;;)
|
||||
;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,78 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Freescale i.MX28 Battery measurement init
|
||||
*
|
||||
* Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
|
||||
* on behalf of DENX Software Engineering GmbH
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <config.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/imx-regs.h>
|
||||
|
||||
#include "mxs_init.h"
|
||||
|
||||
void mxs_lradc_init(void)
|
||||
{
|
||||
struct mxs_lradc_regs *regs = (struct mxs_lradc_regs *)MXS_LRADC_BASE;
|
||||
|
||||
debug("SPL: Initialisating LRADC\n");
|
||||
|
||||
writel(LRADC_CTRL0_SFTRST, ®s->hw_lradc_ctrl0_clr);
|
||||
writel(LRADC_CTRL0_CLKGATE, ®s->hw_lradc_ctrl0_clr);
|
||||
writel(LRADC_CTRL0_ONCHIP_GROUNDREF, ®s->hw_lradc_ctrl0_clr);
|
||||
|
||||
clrsetbits_le32(®s->hw_lradc_ctrl3,
|
||||
LRADC_CTRL3_CYCLE_TIME_MASK,
|
||||
LRADC_CTRL3_CYCLE_TIME_6MHZ);
|
||||
|
||||
clrsetbits_le32(®s->hw_lradc_ctrl4,
|
||||
LRADC_CTRL4_LRADC7SELECT_MASK |
|
||||
LRADC_CTRL4_LRADC6SELECT_MASK,
|
||||
LRADC_CTRL4_LRADC7SELECT_CHANNEL7 |
|
||||
LRADC_CTRL4_LRADC6SELECT_CHANNEL10);
|
||||
}
|
||||
|
||||
void mxs_lradc_enable_batt_measurement(void)
|
||||
{
|
||||
struct mxs_lradc_regs *regs = (struct mxs_lradc_regs *)MXS_LRADC_BASE;
|
||||
|
||||
debug("SPL: Enabling LRADC battery measurement\n");
|
||||
|
||||
/* Check if the channel is present at all. */
|
||||
if (!(readl(®s->hw_lradc_status) & LRADC_STATUS_CHANNEL7_PRESENT)) {
|
||||
debug("SPL: LRADC channel 7 is not present - aborting\n");
|
||||
return;
|
||||
}
|
||||
|
||||
debug("SPL: LRADC channel 7 is present - configuring\n");
|
||||
|
||||
writel(LRADC_CTRL1_LRADC7_IRQ_EN, ®s->hw_lradc_ctrl1_clr);
|
||||
writel(LRADC_CTRL1_LRADC7_IRQ, ®s->hw_lradc_ctrl1_clr);
|
||||
|
||||
clrsetbits_le32(®s->hw_lradc_conversion,
|
||||
LRADC_CONVERSION_SCALE_FACTOR_MASK,
|
||||
LRADC_CONVERSION_SCALE_FACTOR_LI_ION);
|
||||
writel(LRADC_CONVERSION_AUTOMATIC, ®s->hw_lradc_conversion_set);
|
||||
|
||||
/* Configure the channel. */
|
||||
writel((1 << 7) << LRADC_CTRL2_DIVIDE_BY_TWO_OFFSET,
|
||||
®s->hw_lradc_ctrl2_clr);
|
||||
writel(0xffffffff, ®s->hw_lradc_ch7_clr);
|
||||
clrbits_le32(®s->hw_lradc_ch7, LRADC_CH_NUM_SAMPLES_MASK);
|
||||
writel(LRADC_CH_ACCUMULATE, ®s->hw_lradc_ch7_clr);
|
||||
|
||||
/* Schedule the channel. */
|
||||
writel(1 << 7, ®s->hw_lradc_ctrl0_set);
|
||||
|
||||
/* Start the channel sampling. */
|
||||
writel(((1 << 7) << LRADC_DELAY_TRIGGER_LRADCS_OFFSET) |
|
||||
((1 << 3) << LRADC_DELAY_TRIGGER_DELAYS_OFFSET) |
|
||||
100, ®s->hw_lradc_delay3);
|
||||
|
||||
writel(0xffffffff, ®s->hw_lradc_ch7_clr);
|
||||
writel(LRADC_DELAY_KICK, ®s->hw_lradc_delay3_set);
|
||||
|
||||
debug("SPL: LRADC channel 7 configuration complete\n");
|
||||
}
|
||||
@@ -0,0 +1,359 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Freescale i.MX28 RAM init
|
||||
*
|
||||
* Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
|
||||
* on behalf of DENX Software Engineering GmbH
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <config.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/imx-regs.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
#include "mxs_init.h"
|
||||
|
||||
__weak uint32_t mxs_dram_vals[] = {
|
||||
/*
|
||||
* i.MX28 DDR2 at 200MHz
|
||||
*/
|
||||
#if defined(CONFIG_MX28)
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000100, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00010101, 0x01010101,
|
||||
0x000f0f01, 0x0f02020a, 0x00000000, 0x00010101,
|
||||
0x00000100, 0x00000100, 0x00000000, 0x00000002,
|
||||
0x01010000, 0x07080403, 0x06005003, 0x0a0000c8,
|
||||
0x02009c40, 0x0002030c, 0x0036a609, 0x031a0612,
|
||||
0x02030202, 0x00c8001c, 0x00000000, 0x00000000,
|
||||
0x00012100, 0xffff0303, 0x00012100, 0xffff0303,
|
||||
0x00012100, 0xffff0303, 0x00012100, 0xffff0303,
|
||||
0x00000003, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000612, 0x01000F02,
|
||||
0x06120612, 0x00000200, 0x00020007, 0xf4004a27,
|
||||
0xf4004a27, 0xf4004a27, 0xf4004a27, 0x07000300,
|
||||
0x07000300, 0x07400300, 0x07400300, 0x00000005,
|
||||
0x00000000, 0x00000000, 0x01000000, 0x01020408,
|
||||
0x08040201, 0x000f1133, 0x00000000, 0x00001f04,
|
||||
0x00001f04, 0x00001f04, 0x00001f04, 0x00001f04,
|
||||
0x00001f04, 0x00001f04, 0x00001f04, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00010000, 0x00030404,
|
||||
0x00000003, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x01010000,
|
||||
0x01000000, 0x03030000, 0x00010303, 0x01020202,
|
||||
0x00000000, 0x02040303, 0x21002103, 0x00061200,
|
||||
0x06120612, 0x04420442, 0x04420442, 0x00040004,
|
||||
0x00040004, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0xffffffff
|
||||
|
||||
/*
|
||||
* i.MX23 DDR at 133MHz
|
||||
*/
|
||||
#elif defined(CONFIG_MX23)
|
||||
0x01010001, 0x00010100, 0x01000101, 0x00000001,
|
||||
0x00000101, 0x00000000, 0x00010000, 0x01000001,
|
||||
0x00000000, 0x00000001, 0x07000200, 0x00070202,
|
||||
0x02020000, 0x04040a01, 0x00000201, 0x02040000,
|
||||
0x02000000, 0x19000f08, 0x0d0d0000, 0x02021313,
|
||||
0x02061521, 0x0000000a, 0x00080008, 0x00200020,
|
||||
0x00200020, 0x00200020, 0x000003f7, 0x00000000,
|
||||
0x00000000, 0x00000020, 0x00000020, 0x00c80000,
|
||||
0x000a23cd, 0x000000c8, 0x00006665, 0x00000000,
|
||||
0x00000101, 0x00040001, 0x00000000, 0x00000000,
|
||||
0x00010000
|
||||
#else
|
||||
#error Unsupported memory initialization
|
||||
#endif
|
||||
};
|
||||
|
||||
__weak void mxs_adjust_memory_params(uint32_t *dram_vals)
|
||||
{
|
||||
debug("SPL: Using default SDRAM parameters\n");
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MX28
|
||||
static void initialize_dram_values(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
debug("SPL: Setting mx28 board specific SDRAM parameters\n");
|
||||
mxs_adjust_memory_params(mxs_dram_vals);
|
||||
|
||||
debug("SPL: Applying SDRAM parameters\n");
|
||||
for (i = 0; i < ARRAY_SIZE(mxs_dram_vals); i++)
|
||||
writel(mxs_dram_vals[i], MXS_DRAM_BASE + (4 * i));
|
||||
}
|
||||
#else
|
||||
static void initialize_dram_values(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
debug("SPL: Setting mx23 board specific SDRAM parameters\n");
|
||||
mxs_adjust_memory_params(mxs_dram_vals);
|
||||
|
||||
/*
|
||||
* HW_DRAM_CTL27, HW_DRAM_CTL28 and HW_DRAM_CTL35 are not initialized as
|
||||
* per FSL bootlets code.
|
||||
*
|
||||
* mx23 Reference Manual marks HW_DRAM_CTL27 and HW_DRAM_CTL28 as
|
||||
* "reserved".
|
||||
* HW_DRAM_CTL8 is setup as the last element.
|
||||
* So skip the initialization of these HW_DRAM_CTL registers.
|
||||
*/
|
||||
debug("SPL: Applying SDRAM parameters\n");
|
||||
for (i = 0; i < ARRAY_SIZE(mxs_dram_vals); i++) {
|
||||
if (i == 8 || i == 27 || i == 28 || i == 35)
|
||||
continue;
|
||||
writel(mxs_dram_vals[i], MXS_DRAM_BASE + (4 * i));
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable tRAS lockout in HW_DRAM_CTL08 ; it must be the last
|
||||
* element to be set
|
||||
*/
|
||||
writel((1 << 24), MXS_DRAM_BASE + (4 * 8));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void mxs_mem_init_clock(void)
|
||||
{
|
||||
struct mxs_clkctrl_regs *clkctrl_regs =
|
||||
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
|
||||
#if defined(CONFIG_MX23)
|
||||
/* Fractional divider for ref_emi is 33 ; 480 * 18 / 33 = 266MHz */
|
||||
const unsigned char divider = 33;
|
||||
#elif defined(CONFIG_MX28)
|
||||
/* Fractional divider for ref_emi is 21 ; 480 * 18 / 21 = 411MHz */
|
||||
const unsigned char divider = 21;
|
||||
#endif
|
||||
|
||||
debug("SPL: Initialising FRAC0\n");
|
||||
|
||||
/* Gate EMI clock */
|
||||
writeb(CLKCTRL_FRAC_CLKGATE,
|
||||
&clkctrl_regs->hw_clkctrl_frac0_set[CLKCTRL_FRAC0_EMI]);
|
||||
|
||||
/* Set fractional divider for ref_emi */
|
||||
writeb(CLKCTRL_FRAC_CLKGATE | (divider & CLKCTRL_FRAC_FRAC_MASK),
|
||||
&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_EMI]);
|
||||
|
||||
/* Ungate EMI clock */
|
||||
writeb(CLKCTRL_FRAC_CLKGATE,
|
||||
&clkctrl_regs->hw_clkctrl_frac0_clr[CLKCTRL_FRAC0_EMI]);
|
||||
|
||||
early_delay(11000);
|
||||
|
||||
/* Set EMI clock divider for EMI clock to 411 / 2 = 205MHz */
|
||||
writel((2 << CLKCTRL_EMI_DIV_EMI_OFFSET) |
|
||||
(1 << CLKCTRL_EMI_DIV_XTAL_OFFSET),
|
||||
&clkctrl_regs->hw_clkctrl_emi);
|
||||
|
||||
/* Unbypass EMI */
|
||||
writel(CLKCTRL_CLKSEQ_BYPASS_EMI,
|
||||
&clkctrl_regs->hw_clkctrl_clkseq_clr);
|
||||
|
||||
early_delay(10000);
|
||||
debug("SPL: FRAC0 Initialised\n");
|
||||
}
|
||||
|
||||
static void mxs_mem_setup_cpu_and_hbus(void)
|
||||
{
|
||||
struct mxs_clkctrl_regs *clkctrl_regs =
|
||||
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
|
||||
|
||||
debug("SPL: Setting CPU and HBUS clock frequencies\n");
|
||||
|
||||
/* Set fractional divider for ref_cpu to 480 * 18 / 19 = 454MHz
|
||||
* and ungate CPU clock */
|
||||
writeb(19 & CLKCTRL_FRAC_FRAC_MASK,
|
||||
(uint8_t *)&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_CPU]);
|
||||
|
||||
/* Set CPU bypass */
|
||||
writel(CLKCTRL_CLKSEQ_BYPASS_CPU,
|
||||
&clkctrl_regs->hw_clkctrl_clkseq_set);
|
||||
|
||||
/* HBUS = 151MHz */
|
||||
writel(CLKCTRL_HBUS_DIV_MASK, &clkctrl_regs->hw_clkctrl_hbus_set);
|
||||
writel(((~3) << CLKCTRL_HBUS_DIV_OFFSET) & CLKCTRL_HBUS_DIV_MASK,
|
||||
&clkctrl_regs->hw_clkctrl_hbus_clr);
|
||||
|
||||
early_delay(10000);
|
||||
|
||||
/* CPU clock divider = 1 */
|
||||
clrsetbits_le32(&clkctrl_regs->hw_clkctrl_cpu,
|
||||
CLKCTRL_CPU_DIV_CPU_MASK, 1);
|
||||
|
||||
/* Disable CPU bypass */
|
||||
writel(CLKCTRL_CLKSEQ_BYPASS_CPU,
|
||||
&clkctrl_regs->hw_clkctrl_clkseq_clr);
|
||||
|
||||
early_delay(15000);
|
||||
}
|
||||
|
||||
static void mxs_mem_setup_vdda(void)
|
||||
{
|
||||
struct mxs_power_regs *power_regs =
|
||||
(struct mxs_power_regs *)MXS_POWER_BASE;
|
||||
|
||||
debug("SPL: Configuring VDDA\n");
|
||||
|
||||
writel((0xc << POWER_VDDACTRL_TRG_OFFSET) |
|
||||
(0x7 << POWER_VDDACTRL_BO_OFFSET_OFFSET) |
|
||||
POWER_VDDACTRL_LINREG_OFFSET_1STEPS_BELOW,
|
||||
&power_regs->hw_power_vddactrl);
|
||||
}
|
||||
|
||||
uint32_t mxs_mem_get_size(void)
|
||||
{
|
||||
uint32_t sz, da;
|
||||
uint32_t *vt = (uint32_t *)0x20;
|
||||
/* The following is "subs pc, r14, #4", used as return from DABT. */
|
||||
const uint32_t data_abort_memdetect_handler = 0xe25ef004;
|
||||
|
||||
/* Replace the DABT handler. */
|
||||
da = vt[4];
|
||||
vt[4] = data_abort_memdetect_handler;
|
||||
|
||||
sz = get_ram_size((long *)PHYS_SDRAM_1, PHYS_SDRAM_1_SIZE);
|
||||
|
||||
/* Restore the old DABT handler. */
|
||||
vt[4] = da;
|
||||
|
||||
return sz;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MX23
|
||||
static void mx23_mem_setup_vddmem(void)
|
||||
{
|
||||
struct mxs_power_regs *power_regs =
|
||||
(struct mxs_power_regs *)MXS_POWER_BASE;
|
||||
|
||||
debug("SPL: Setting mx23 VDDMEM\n");
|
||||
|
||||
/* We must wait before and after disabling the current limiter! */
|
||||
early_delay(10000);
|
||||
|
||||
clrbits_le32(&power_regs->hw_power_vddmemctrl,
|
||||
POWER_VDDMEMCTRL_ENABLE_ILIMIT);
|
||||
|
||||
early_delay(10000);
|
||||
|
||||
}
|
||||
|
||||
static void mx23_mem_init(void)
|
||||
{
|
||||
debug("SPL: Initialising mx23 SDRAM Controller\n");
|
||||
|
||||
/*
|
||||
* Reset/ungate the EMI block. This is essential, otherwise the system
|
||||
* suffers from memory instability. This thing is mx23 specific and is
|
||||
* no longer present on mx28.
|
||||
*/
|
||||
mxs_reset_block((struct mxs_register_32 *)MXS_EMI_BASE);
|
||||
|
||||
mx23_mem_setup_vddmem();
|
||||
|
||||
/*
|
||||
* Configure the DRAM registers
|
||||
*/
|
||||
|
||||
/* Clear START and SREFRESH bit from DRAM_CTL8 */
|
||||
clrbits_le32(MXS_DRAM_BASE + 0x20, (1 << 16) | (1 << 8));
|
||||
|
||||
initialize_dram_values();
|
||||
|
||||
/* Set START bit in DRAM_CTL8 */
|
||||
setbits_le32(MXS_DRAM_BASE + 0x20, 1 << 16);
|
||||
|
||||
clrbits_le32(MXS_DRAM_BASE + 0x40, 1 << 17);
|
||||
|
||||
/* Wait for EMI_STAT bit DRAM_HALTED */
|
||||
for (;;) {
|
||||
if (!(readl(MXS_EMI_BASE + 0x10) & (1 << 1)))
|
||||
break;
|
||||
early_delay(1000);
|
||||
}
|
||||
|
||||
/* Adjust EMI port priority. */
|
||||
clrsetbits_le32(0x80020000, 0x1f << 16, 0x2);
|
||||
early_delay(20000);
|
||||
|
||||
setbits_le32(MXS_DRAM_BASE + 0x40, 1 << 19);
|
||||
setbits_le32(MXS_DRAM_BASE + 0x40, 1 << 11);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MX28
|
||||
static void mx28_mem_init(void)
|
||||
{
|
||||
struct mxs_pinctrl_regs *pinctrl_regs =
|
||||
(struct mxs_pinctrl_regs *)MXS_PINCTRL_BASE;
|
||||
|
||||
debug("SPL: Initialising mx28 SDRAM Controller\n");
|
||||
|
||||
/* Set DDR2 mode */
|
||||
writel(PINCTRL_EMI_DS_CTRL_DDR_MODE_DDR2,
|
||||
&pinctrl_regs->hw_pinctrl_emi_ds_ctrl_set);
|
||||
|
||||
/*
|
||||
* Configure the DRAM registers
|
||||
*/
|
||||
|
||||
/* Clear START bit from DRAM_CTL16 */
|
||||
clrbits_le32(MXS_DRAM_BASE + 0x40, 1);
|
||||
|
||||
initialize_dram_values();
|
||||
|
||||
/* Clear SREFRESH bit from DRAM_CTL17 */
|
||||
clrbits_le32(MXS_DRAM_BASE + 0x44, 1);
|
||||
|
||||
/* Set START bit in DRAM_CTL16 */
|
||||
setbits_le32(MXS_DRAM_BASE + 0x40, 1);
|
||||
|
||||
/* Wait for bit 20 (DRAM init complete) in DRAM_CTL58 */
|
||||
while (!(readl(MXS_DRAM_BASE + 0xe8) & (1 << 20)))
|
||||
;
|
||||
}
|
||||
#endif
|
||||
|
||||
void mxs_mem_init(void)
|
||||
{
|
||||
early_delay(11000);
|
||||
|
||||
mxs_mem_init_clock();
|
||||
|
||||
mxs_mem_setup_vdda();
|
||||
|
||||
#if defined(CONFIG_MX23)
|
||||
mx23_mem_init();
|
||||
#elif defined(CONFIG_MX28)
|
||||
mx28_mem_init();
|
||||
#endif
|
||||
|
||||
early_delay(10000);
|
||||
|
||||
mxs_mem_setup_cpu_and_hbus();
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,95 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* armboot - Startup Code for ARM926EJS CPU-core
|
||||
*
|
||||
* Copyright (c) 2003 Texas Instruments
|
||||
*
|
||||
* ----- Adapted for OMAP1610 OMAP730 from ARM925t code ------
|
||||
*
|
||||
* Copyright (c) 2001 Marius Groger <mag@sysgo.de>
|
||||
* Copyright (c) 2002 Alex Zupke <azu@sysgo.de>
|
||||
* Copyright (c) 2002 Gary Jennejohn <garyj@denx.de>
|
||||
* Copyright (c) 2003 Richard Woodruff <r-woodruff2@ti.com>
|
||||
* Copyright (c) 2003 Kshitij <kshitij@ti.com>
|
||||
* Copyright (c) 2010 Albert Aribaud <albert.u.boot@aribaud.net>
|
||||
*
|
||||
* Change to support call back into iMX28 bootrom
|
||||
* Copyright (c) 2011 Marek Vasut <marek.vasut@gmail.com>
|
||||
* on behalf of DENX Software Engineering GmbH
|
||||
*/
|
||||
|
||||
#include <asm-offsets.h>
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
|
||||
/*
|
||||
*************************************************************************
|
||||
*
|
||||
* Startup Code (reset vector)
|
||||
*
|
||||
* do important init only if we don't start from memory!
|
||||
* setup Memory and board specific bits prior to relocation.
|
||||
* relocate armboot to ram
|
||||
* setup stack
|
||||
*
|
||||
*************************************************************************
|
||||
*/
|
||||
|
||||
.globl reset
|
||||
reset:
|
||||
/*
|
||||
* If the CPU is configured in "Wait JTAG connection mode", the stack
|
||||
* pointer is not configured and is zero. This will cause crash when
|
||||
* trying to push data onto stack right below here. Load the SP and make
|
||||
* it point to the end of OCRAM if the SP is zero.
|
||||
*/
|
||||
cmp sp, #0x00000000
|
||||
ldreq sp, =CONFIG_SYS_INIT_SP_ADDR
|
||||
|
||||
/*
|
||||
* Store all registers on old stack pointer, this will allow us later to
|
||||
* return to the BootROM and let the BootROM load U-Boot into RAM.
|
||||
*
|
||||
* WARNING: Register r0 and r1 are used by the BootROM to pass data
|
||||
* to the called code. Register r0 will contain arbitrary
|
||||
* data that are set in the BootStream. In case this code
|
||||
* was started with CALL instruction, register r1 will contain
|
||||
* pointer to the return value this function can then set.
|
||||
* The code below MUST NOT CHANGE register r0 and r1 !
|
||||
*/
|
||||
push {r0-r12,r14}
|
||||
|
||||
/* Save control register c1 */
|
||||
mrc p15, 0, r2, c1, c0, 0
|
||||
push {r2}
|
||||
|
||||
/* Set the cpu to SVC32 mode and store old CPSR register content. */
|
||||
mrs r2, cpsr
|
||||
push {r2}
|
||||
bic r2, r2, #0x1f
|
||||
orr r2, r2, #0xd3
|
||||
msr cpsr, r2
|
||||
|
||||
bl board_init_ll
|
||||
|
||||
/* Restore BootROM's CPU mode (especially FIQ). */
|
||||
pop {r2}
|
||||
msr cpsr,r2
|
||||
|
||||
/*
|
||||
* Restore c1 register. Especially set exception vector location
|
||||
* back to BootROM space which is required by bootrom for USB boot.
|
||||
*/
|
||||
pop {r2}
|
||||
mcr p15, 0, r2, c1, c0, 0
|
||||
|
||||
pop {r0-r12,r14}
|
||||
|
||||
/*
|
||||
* In case this code was started by the CALL instruction, the register
|
||||
* r0 is examined by the BootROM after this code returns. The value in
|
||||
* r0 must be set to 0 to indicate successful return.
|
||||
*/
|
||||
mov r0, #0
|
||||
|
||||
bx lr
|
||||
@@ -0,0 +1,156 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Freescale i.MX28 timer driver
|
||||
*
|
||||
* Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
|
||||
* on behalf of DENX Software Engineering GmbH
|
||||
*
|
||||
* Based on code from LTIB:
|
||||
* (C) Copyright 2009-2010 Freescale Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <time.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/imx-regs.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
|
||||
/* Maximum fixed count */
|
||||
#if defined(CONFIG_MX23)
|
||||
#define TIMER_LOAD_VAL 0xffff
|
||||
#elif defined(CONFIG_MX28)
|
||||
#define TIMER_LOAD_VAL 0xffffffff
|
||||
#endif
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#define timestamp (gd->arch.tbl)
|
||||
#define lastdec (gd->arch.lastinc)
|
||||
|
||||
/*
|
||||
* This driver uses 1kHz clock source.
|
||||
*/
|
||||
#define MXS_INCREMENTER_HZ 1000
|
||||
|
||||
static inline unsigned long tick_to_time(unsigned long tick)
|
||||
{
|
||||
return tick / (MXS_INCREMENTER_HZ / CONFIG_SYS_HZ);
|
||||
}
|
||||
|
||||
static inline unsigned long time_to_tick(unsigned long time)
|
||||
{
|
||||
return time * (MXS_INCREMENTER_HZ / CONFIG_SYS_HZ);
|
||||
}
|
||||
|
||||
/* Calculate how many ticks happen in "us" microseconds */
|
||||
static inline unsigned long us_to_tick(unsigned long us)
|
||||
{
|
||||
return (us * MXS_INCREMENTER_HZ) / 1000000;
|
||||
}
|
||||
|
||||
int timer_init(void)
|
||||
{
|
||||
struct mxs_timrot_regs *timrot_regs =
|
||||
(struct mxs_timrot_regs *)MXS_TIMROT_BASE;
|
||||
|
||||
/* Reset Timers and Rotary Encoder module */
|
||||
mxs_reset_block(&timrot_regs->hw_timrot_rotctrl_reg);
|
||||
|
||||
/* Set fixed_count to 0 */
|
||||
#if defined(CONFIG_MX23)
|
||||
writel(0, &timrot_regs->hw_timrot_timcount0);
|
||||
#elif defined(CONFIG_MX28)
|
||||
writel(0, &timrot_regs->hw_timrot_fixed_count0);
|
||||
#endif
|
||||
|
||||
/* Set UPDATE bit and 1Khz frequency */
|
||||
writel(TIMROT_TIMCTRLn_UPDATE | TIMROT_TIMCTRLn_RELOAD |
|
||||
TIMROT_TIMCTRLn_SELECT_1KHZ_XTAL,
|
||||
&timrot_regs->hw_timrot_timctrl0);
|
||||
|
||||
/* Set fixed_count to maximal value */
|
||||
#if defined(CONFIG_MX23)
|
||||
writel(TIMER_LOAD_VAL - 1, &timrot_regs->hw_timrot_timcount0);
|
||||
#elif defined(CONFIG_MX28)
|
||||
writel(TIMER_LOAD_VAL, &timrot_regs->hw_timrot_fixed_count0);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long long get_ticks(void)
|
||||
{
|
||||
struct mxs_timrot_regs *timrot_regs =
|
||||
(struct mxs_timrot_regs *)MXS_TIMROT_BASE;
|
||||
uint32_t now;
|
||||
|
||||
/* Current tick value */
|
||||
#if defined(CONFIG_MX23)
|
||||
/* Upper bits are the valid ones. */
|
||||
now = readl(&timrot_regs->hw_timrot_timcount0) >>
|
||||
TIMROT_RUNNING_COUNTn_RUNNING_COUNT_OFFSET;
|
||||
#elif defined(CONFIG_MX28)
|
||||
now = readl(&timrot_regs->hw_timrot_running_count0);
|
||||
#else
|
||||
#error "Don't know how to read timrot_regs"
|
||||
#endif
|
||||
|
||||
if (lastdec >= now) {
|
||||
/*
|
||||
* normal mode (non roll)
|
||||
* move stamp forward with absolut diff ticks
|
||||
*/
|
||||
timestamp += (lastdec - now);
|
||||
} else {
|
||||
/* we have rollover of decrementer */
|
||||
timestamp += (TIMER_LOAD_VAL - now) + lastdec;
|
||||
|
||||
}
|
||||
lastdec = now;
|
||||
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
ulong get_timer(ulong base)
|
||||
{
|
||||
return tick_to_time(get_ticks()) - base;
|
||||
}
|
||||
|
||||
/* We use the HW_DIGCTL_MICROSECONDS register for sub-millisecond timer. */
|
||||
#define MXS_HW_DIGCTL_MICROSECONDS 0x8001c0c0
|
||||
|
||||
void __udelay(unsigned long usec)
|
||||
{
|
||||
uint32_t old, new, incr;
|
||||
uint32_t counter = 0;
|
||||
|
||||
old = readl(MXS_HW_DIGCTL_MICROSECONDS);
|
||||
|
||||
while (counter < usec) {
|
||||
new = readl(MXS_HW_DIGCTL_MICROSECONDS);
|
||||
|
||||
/* Check if the timer wrapped. */
|
||||
if (new < old) {
|
||||
incr = 0xffffffff - old;
|
||||
incr += new;
|
||||
} else {
|
||||
incr = new - old;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if we are close to the maximum time and the counter
|
||||
* would wrap if incremented. If that's the case, break out
|
||||
* from the loop as the requested delay time passed.
|
||||
*/
|
||||
if (counter + incr < counter)
|
||||
break;
|
||||
|
||||
counter += incr;
|
||||
old = new;
|
||||
}
|
||||
}
|
||||
|
||||
ulong get_tbclk(void)
|
||||
{
|
||||
return MXS_INCREMENTER_HZ;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
options {
|
||||
driveTag = 0x00;
|
||||
flags = 0x01;
|
||||
}
|
||||
|
||||
sources {
|
||||
u_boot_spl="spl/u-boot-spl.bin";
|
||||
u_boot="u-boot.bin";
|
||||
}
|
||||
|
||||
section (0) {
|
||||
load u_boot_spl > 0x0000;
|
||||
load ivt (entry = 0x0014) > 0x8000;
|
||||
call 0x8000;
|
||||
|
||||
load u_boot > 0x40000100;
|
||||
call 0x40000100;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
sources {
|
||||
u_boot_spl="spl/u-boot-spl.bin";
|
||||
u_boot="u-boot.bin";
|
||||
}
|
||||
|
||||
section (0) {
|
||||
load u_boot_spl > 0x0000;
|
||||
load ivt (entry = 0x0014) > 0x8000;
|
||||
hab call 0x8000;
|
||||
|
||||
load u_boot > 0x40000100;
|
||||
load ivt (entry = 0x40000100) > 0x8000;
|
||||
hab call 0x8000;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
|
||||
* on behalf of DENX Software Engineering GmbH
|
||||
*
|
||||
* January 2004 - Changed to support H4 device
|
||||
* Copyright (c) 2004-2008 Texas Instruments
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
|
||||
*/
|
||||
|
||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
|
||||
OUTPUT_ARCH(arm)
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
. = IMAGE_TEXT_BASE;
|
||||
|
||||
. = ALIGN(4);
|
||||
.text :
|
||||
{
|
||||
*(.vectors)
|
||||
arch/arm/cpu/arm926ejs/mxs/start.o (.text*)
|
||||
*(.text*)
|
||||
}
|
||||
|
||||
. = ALIGN(4);
|
||||
.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
|
||||
|
||||
. = ALIGN(4);
|
||||
.data : {
|
||||
*(.data*)
|
||||
}
|
||||
|
||||
. = ALIGN(4);
|
||||
|
||||
.rel.dyn : {
|
||||
__rel_dyn_start = .;
|
||||
*(.rel*)
|
||||
__rel_dyn_end = .;
|
||||
}
|
||||
|
||||
.bss : {
|
||||
. = ALIGN(4);
|
||||
__bss_start = .;
|
||||
*(.bss*)
|
||||
. = ALIGN(4);
|
||||
__bss_end = .;
|
||||
}
|
||||
|
||||
.end :
|
||||
{
|
||||
*(.__end)
|
||||
}
|
||||
|
||||
_image_binary_end = .;
|
||||
|
||||
.dynsym _image_binary_end : { *(.dynsym) }
|
||||
.dynbss : { *(.dynbss) }
|
||||
.dynstr : { *(.dynstr*) }
|
||||
.dynamic : { *(.dynamic*) }
|
||||
.hash : { *(.hash*) }
|
||||
.plt : { *(.plt*) }
|
||||
.interp : { *(.interp*) }
|
||||
.gnu : { *(.gnu*) }
|
||||
.ARM.exidx : { *(.ARM.exidx*) }
|
||||
}
|
||||
Reference in New Issue
Block a user