Booting mx25 based device from SD and NOR
Roberto Nibali
rnibali at gmail.com
Tue May 29 05:26:34 EDT 2012
Hi Sascha
Thank you so much for taking your time explaining things the way you did.
It certainly cleared things up a lot, albeit it still does not work;
comment below.
> > I read the different board initialization routines over and over again,
> > but can't find a common pattern. From what I see the lowlevel_init (which
> > has been converted nicely into a C file), only AIPS, MAX, MPLL core
> clock,
> > all clocks, SDRAM are initialized, but I have seen AIPS and MAX setups in
> > core_init functions (eukrea_cpuimx35.c), as well as clock setups in
> > console_init and other places. So, what's the bare minimum in lowlevel to
> > set up? SDRAM/MDDR? What's the order of things?
> >
> > I am merely asking because I have come a long way trying to debug an
> issue
> > with weird I/O and clock behaviour on the ESDHC and other parts of my
> mx25
> > device.
>
> - MAX setup is not needed for barebox
> - AIPS can most probably be done later aswell
> - I'm unsure with the MPLL, that depends on whether the SDRAM clock
> depends on it.
>
In my case I am fairly certain that SDRAM clock does not depend on MPLL. I
will be moving MAX and AIPS setup out of lowlevel init, so as to keep it
tiny.
> You should only setup all dependencies for SDRAM and the SDRAM itself.
> Everything else can be done later. What that is for the i.MX25 you
> can see in the dcd, here from the Eukrea mx25:
>
> struct imx_dcd_entry __dcd_entry_section dcd_entry[] = {
> { .ptr_type = 4, .addr = 0xb8001010, .val = 0x00000004, },
> { .ptr_type = 4, .addr = 0xb8001000, .val = 0x92100000, },
> { .ptr_type = 1, .addr = 0x80000400, .val = 0x12344321, },
> { .ptr_type = 4, .addr = 0xb8001000, .val = 0xa2100000, },
> { .ptr_type = 4, .addr = 0x80000000, .val = 0x12344321, },
> { .ptr_type = 4, .addr = 0x80000000, .val = 0x12344321, },
> { .ptr_type = 4, .addr = 0xb8001000, .val = 0xb2100000, },
> { .ptr_type = 1, .addr = 0x80000033, .val = 0xda, },
> { .ptr_type = 1, .addr = 0x81000000, .val = 0xff, },
> { .ptr_type = 4, .addr = 0xb8001000, .val = 0x82216080, },
> { .ptr_type = 4, .addr = 0xb8001004, .val = 0x00295729, },
> { .ptr_type = 4, .addr = 0x53f80008, .val = 0x20034000, },
> };
>
> So basically this means that the SDRAM does not seem to have any
> dependencies.
>
This is the first time I have realized that the DCD actually represents
more or less what should be done in the lowlevel init. After carefully
reading what you explained and cross-checking with the old uboot, I have
come up with the following DCD:
struct imx_dcd_entry __dcd_entry_section dcd_entry[] = {
/* NOR flash, CS0_CSCRU, CS0_CSCRL, CS0_CSCRA */
{ .ptr_type = 4, .addr = 0xB8002000, .val = 0x0000D003, },
{ .ptr_type = 4, .addr = 0xB8002004, .val = 0x00330D01, },
{ .ptr_type = 4, .addr = 0xB8002008, .val = 0x00220800, },
/* DDR2 init */
{ .ptr_type = 4, .addr = 0xb8001004, .val = 0x0076e83a, }, /* initial value
for ESDCFG0 */
{ .ptr_type = 4, .addr = 0xb8001010, .val = 0x00000204, }, /* ESD_MISC */
{ .ptr_type = 4, .addr = 0xb8001000, .val = 0x92210000, }, /* CS0 precharge
command */
{ .ptr_type = 4, .addr = 0x80000f00, .val = 0x12344321, }, /* precharge
all dummy write */
{ .ptr_type = 4, .addr = 0xb8001000, .val = 0xb2210000, }, /* Load Mode
Register command */
{ .ptr_type = 1, .addr = 0x82000000, .val = 0xda, }, /* dummy write Load
EMR2 */
{ .ptr_type = 1, .addr = 0x83000000, .val = 0xda, }, /* dummy write Load
EMR3 */
{ .ptr_type = 1, .addr = 0x81000400, .val = 0xda, }, /* dummy write Load
EMR1; enable DLL */
{ .ptr_type = 1, .addr = 0x80000333, .val = 0xda, }, /* dummy write Load
MR; reset DLL */
{ .ptr_type = 4, .addr = 0xb8001000, .val = 0x92210000, }, /* CS0 precharge
command */
{ .ptr_type = 4, .addr = 0x80000400, .val = 0x12345678, }, /* precharge all
dummy write */
{ .ptr_type = 4, .addr = 0xb8001000, .val = 0xA2210000, }, /* select
manual refresh mode */
{ .ptr_type = 4, .addr = 0x80000000, .val = 0x87654321, }, /* manual
refresh */
{ .ptr_type = 4, .addr = 0x80000000, .val = 0x87654321, }, /* manual
refresh twice */
{ .ptr_type = 4, .addr = 0xb8001000, .val = 0xb2210000, }, /* Load Mode
Register command */
{ .ptr_type = 1, .addr = 0x80000233, .val = 0xda, }, /* Load MR; CL=3,
BL=8, end DLL reset */
{ .ptr_type = 1, .addr = 0x81000780, .val = 0xda, }, /* Load EMR1; OCD
default */
{ .ptr_type = 1, .addr = 0x81000400, .val = 0xda, }, /* Load EMR1; OCD
exit */
{ .ptr_type = 4, .addr = 0xb8001000, .val = 0x82216080, }, /* normal mode */
/* IOMUX_SW_PAD setup */
{ .ptr_type = 4, .addr = 0x43FAC454, .val = 0x00001000, }, /*
IOMUXC_SW_PAD_CTL_GRP_DDRTYPE(1-5) */
{ .ptr_type = 4, .addr = 0x43FAC448, .val = 0x00002000, }, /*
IOMUXC_SW_PAD NFC voltage 1.8 */
/* CLKCTL */
{ .ptr_type = 4, .addr = 0x53f80008, .val = 0x20034000, }, /* CLKCTL
ARM=399 AHB=133 */
};
> All the things in lowlevel_init are then done when running from SDRAM
> anyway (at least when doing a dcd based boot), so they can safely be
> done later.
>
> The next thing is that the clocks are correctly initialized before the
> corresponding devices are registered.
>
I have seen that some devices simply enable all clocks in lowlevel and some
enable the necessary ones at a later stage. To be sure, I have included
both versions in my setup, so I can assure that all the necessary clocks
are running on boot init.
> So let's analyze Eukreas lowlevel init:
>
>
> > void __bare_init __naked board_init_lowlevel(void)
> > {
> > uint32_t r;
> > #ifdef CONFIG_NAND_IMX_BOOT
> > unsigned int *trg, *src;
> > int i;
> > #endif
> > register uint32_t loops = 0x20000;
> >
> > /* restart the MPLL and wait until it's stable */
> > writel(readl(IMX_CCM_BASE + CCM_CCTL) | (1 << 27),
> > IMX_CCM_BASE + CCM_CCTL);
> > while (readl(IMX_CCM_BASE + CCM_CCTL) & (1 << 27)) {};
> >
> > /* Configure dividers and ARM clock source
> > * ARM @ 400 MHz
> > * AHB @ 133 MHz
> > */
> > writel(0x20034000, IMX_CCM_BASE + CCM_CCTL);
>
> This may influence the timer clock, so it can be here.
>
I have copied this, since it was also done in the old uboot version that
works.
> >
> > /* Enable UART1 / FEC / */
> > /* writel(0x1FFFFFFF, IMX_CCM_BASE + CCM_CGCR0);
> > writel(0xFFFFFFFF, IMX_CCM_BASE + CCM_CGCR1);
> > writel(0x000FDFFF, IMX_CCM_BASE + CCM_CGCR2);*/
>
> This brings the Clock gate registers to reset default. This may be a
> good idea, but can be done later.
>
Ok, I have copied this.
>
> >
> > /* AIPS setup - Only setup MPROTx registers. The PACR default
> values are good.
> > * Set all MPROTx to be non-bufferable, trusted for R/W,
> > * not forced to user-mode.
> > */
> > writel(0x77777777, 0x43f00000);
> > writel(0x77777777, 0x43f00004);
> > writel(0x77777777, 0x53f00000);
> > writel(0x77777777, 0x53f00004);
>
> This can be done later. This is duplicated in many boards and is always
> the same. Look for example at the i.MX53 code, there we have
> imx53_init_lowlevel() which sets up the AIPS. This is common for all
> i.MX53 and is called from an initcall. Similar could be done for i.MX25
> aswell, if somebody is willing to implement it.
>
I like the imx53_init_lowlevel() approach a lot, it's very clean and helps
avoiding redundancy and maintenance costs. If I get my device to boot from
NOR, I might be inclined to give it a shot.
> >
> > /* MAX (Multi-Layer AHB Crossbar Switch) setup
> > * MPR - priority for MX25 is (SDHC2/SDMA)>USBOTG>RTIC>IAHB>DAHB
> > */
> > writel(0x00002143, 0x43f04000);
> > writel(0x00002143, 0x43f04100);
> > writel(0x00002143, 0x43f04200);
> > writel(0x00002143, 0x43f04300);
> > writel(0x00002143, 0x43f04400);
> > /* SGPCR - always park on last master */
> > writel(0x10, 0x43f04010);
> > writel(0x10, 0x43f04110);
> > writel(0x10, 0x43f04210);
> > writel(0x10, 0x43f04310);
> > writel(0x10, 0x43f04410);
> > /* MGPCR - restore default values */
> > writel(0x0, 0x43f04800);
> > writel(0x0, 0x43f04900);
> > writel(0x0, 0x43f04a00);
> > writel(0x0, 0x43f04b00);
> > writel(0x0, 0x43f04c00);
> >
> > /* Configure M3IF registers
> > * M3IF Control Register (M3IFCTL) for MX25
> > * MRRP[0] = LCDC on priority list (1 << 0) = 0x00000001
> > * MRRP[1] = MAX1 not on priority list (0 << 1) = 0x00000000
> > * MRRP[2] = MAX0 not on priority list (0 << 2) = 0x00000000
> > * MRRP[3] = USB HOST not on priority list (0 << 3) = 0x00000000
> > * MRRP[4] = SDMA not on priority list (0 << 4) = 0x00000000
> > * MRRP[5] = SD/ATA/FEC not on priority list (0 << 5) = 0x00000000
> > * MRRP[6] = SCMFBC not on priority list (0 << 6) = 0x00000000
> > * MRRP[7] = CSI not on priority list (0 << 7) = 0x00000000
> > * ----------
> > * 0x00000001
> > */
> > writel(0x1, 0xb8003000);
>
> Same as above.
>
> >
> > /* Speed up NAND controller by adjusting the NFC divider */
> > r = readl(IMX_CCM_BASE + CCM_PCDR2);
> > r &= ~0xf;
> > r |= 0x1;
> > writel(r, IMX_CCM_BASE + CCM_PCDR2);
>
> This is necessary for external NAND boot. The NAND controller comes up
> with a low speed which makes the copying of the image
> (CONFIG_NAND_IMX_BOOT below) slow. This is optional but has to be done
> here to get a faster boot.
>
> Ok, I reckon there is nothing comparable which should be done in the NOR
case.
> >
> > /* Skip SDRAM initialization if we run from RAM */
> > r = get_pc();
> > if (r > 0x80000000 && r < 0x90000000)
> > board_init_lowlevel_return();
>
> Here we bail out for second stage boots (and also internal bootmode
> where we are already running from SDRAM
>
It's this place where I wanted to put a printf() to see where the code is
actually branching and if my setting of the corresponding WEIM CS0
registers upset the processor already. However, it seems as if printf()'s
here is a no-go.
> >
> > /* Init Mobile DDR */
> > writel(0x0000000E, ESDMISC);
> > writel(0x00000004, ESDMISC);
> > __asm__ volatile ("1:\n"
> > "subs %0, %1, #1\n"
> > "bne 1b":"=r" (loops):"0" (loops));
> >
> > writel(0x0029572B, ESDCFG0);
> > writel(0x92210000, ESDCTL0);
> > writeb(0xda, IMX_SDRAM_CS0 + 0x400);
> > writel(0xA2210000, ESDCTL0);
> > writeb(0xda, IMX_SDRAM_CS0);
> > writeb(0xda, IMX_SDRAM_CS0);
> > writel(0xB2210000, ESDCTL0);
> > writeb(0xda, IMX_SDRAM_CS0 + 0x33);
> > writeb(0xda, IMX_SDRAM_CS0 + 0x1000000);
> > writel(0x82216080, ESDCTL0);
>
> RAM init for external bootmode, has to be done here.
>
I left it there.
>
> >
> > #ifdef CONFIG_NAND_IMX_BOOT
> > /* skip NAND boot if not running from NFC space */
> > r = get_pc();
> > if (r < IMX_NFC_BASE || r > IMX_NFC_BASE + 0x800)
> > board_init_lowlevel_return();
> >
> > src = (unsigned int *)IMX_NFC_BASE;
> > trg = (unsigned int *)TEXT_BASE;
> >
> > /* Move ourselves out of NFC SRAM */
> > for (i = 0; i < 0x800 / sizeof(int); i++)
> > *trg++ = *src++;
> >
> > /* Jump to SDRAM */
> > r = (unsigned int)&insdram;
> > __asm__ __volatile__("mov pc, %0" : : "r"(r));
> > #else
> > board_init_lowlevel_return();
> > #endif
>
> Finally copy the image from NAND SRAM to SDRAM, only needed for external
> NAND boot.
>
> And since I am trying to perform an internal MMC or NOR boot, this does
not affect me at all.
> Often the whole lowlevel stuff is setup in early assembly code. This has
> mostly historical reasons and 'hey, this is hardcore stuff we configure
> here, we must do it early and we must do it in assembly'. Much of the
> lowlevel stuff we have in barebox is just copied from a working U-Boot
> or redboot setup and never touched again, hence the slightly chaotic
> situation.
>
This is what I have slowly come to understand while reading more source
code over the weekend. I have also found the old uboot init part for this
device from 2009.08 and have adapted my lowlevel and device part code
accordingly. I wonder if someone could write a quick and dirty perl/shell
script to auto-port devices from uboot to barebox, at least the basic
booting facility.
In my case, there is one peculiarity in the u-boot sources, which I haven't
been able to map to barebox yet and it's best described by the
corresponding code:
#include <common.h>
#include <asm/io.h>
#include <asm/errno.h>
#include <asm/arch/mx25.h>
#include <asm/arch/mx25-regs.h>
#include <asm/arch/mx25_pins.h>
#include <asm/arch/iomux.h>
#include <asm/arch/gpio.h>
#include <imx_spi.h>
#ifdef CONFIG_CMD_MMC
#include <mmc.h>
#include <fsl_esdhc.h>
#endif
DECLARE_GLOBAL_DATA_PTR;
static u32 system_rev;
u32 get_board_rev(void)
{
return system_rev;
}
static inline void setup_soc_rev(void)
{
int reg;
reg = __REG(IIM_BASE + IIM_SREV);
if (!reg) {
reg = __REG(ROMPATCH_REV);
reg <<= 4;
} else
reg += CHIP_REV_1_0;
system_rev = 0x25000 + (reg & 0xFF);
}
inline int is_soc_rev(int rev)
{
return (system_rev & 0xFF) - rev;
}
int dram_init(void)
{
gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
return 0;
}
#ifdef CONFIG_CMD_MMC
u32 *imx_esdhc_base_addr;
int esdhc_gpio_init(void)
{
u32 interface_esdhc = 0, val = 0;
interface_esdhc = (readl(CCM_RCSR) & (0x00300000)) >> 20;
switch (interface_esdhc) {
case 0:
imx_esdhc_base_addr = (u32 *)MMC_SDHC1_BASE;
/* Pins */
writel(0x10, IOMUXC_BASE + 0x190); /* SD1_CMD */
writel(0x10, IOMUXC_BASE + 0x194); /* SD1_CLK */
writel(0x00, IOMUXC_BASE + 0x198); /* SD1_DATA0 */
writel(0x00, IOMUXC_BASE + 0x19c); /* SD1_DATA1 */
writel(0x00, IOMUXC_BASE + 0x1a0); /* SD1_DATA2 */
writel(0x00, IOMUXC_BASE + 0x1a4); /* SD1_DATA3 */
/*ENABLE NOR
writel(0x06, IOMUXC_BASE + 0x094); // D12 (SD1_DATA4)
writel(0x06, IOMUXC_BASE + 0x090); // D13 (SD1_DATA5)
writel(0x06, IOMUXC_BASE + 0x08c); // D14 (SD1_DATA6)
writel(0x06, IOMUXC_BASE + 0x088); // D15 (SD1_DATA7)
writel(0x05, IOMUXC_BASE + 0x010); // A14 (SD1_WP)
writel(0x05, IOMUXC_BASE + 0x014); // A15 (SD1_DET)
*/
/* Pads */
writel(0xD1, IOMUXC_BASE + 0x388); /* SD1_CMD */
writel(0xD1, IOMUXC_BASE + 0x38c); /* SD1_CLK */
writel(0xD1, IOMUXC_BASE + 0x390); /* SD1_DATA0 */
writel(0xD1, IOMUXC_BASE + 0x394); /* SD1_DATA1 */
writel(0xD1, IOMUXC_BASE + 0x398); /* SD1_DATA2 */
writel(0xD1, IOMUXC_BASE + 0x39c); /* SD1_DATA3 */
/* ENABLE NOR
writel(0xD1, IOMUXC_BASE + 0x28c); // D12 (SD1_DATA4)
writel(0xD1, IOMUXC_BASE + 0x288); // D13 (SD1_DATA5)
writel(0xD1, IOMUXC_BASE + 0x284); // D14 (SD1_DATA6)
writel(0xD1, IOMUXC_BASE + 0x280); // D15 (SD1_DATA7)
writel(0xD1, IOMUXC_BASE + 0x230); // A14 (SD1_WP)
writel(0xD1, IOMUXC_BASE + 0x234); // A15 (SD1_DET)
*/
/*
* Set write protect and card detect gpio as inputs
* A14 (SD1_WP) and A15 (SD1_DET)
*/
val = ~(3 << 0) & readl(GPIO1_BASE + GPIO_GDIR);
writel(val, GPIO1_BASE + GPIO_GDIR);
break;
case 1:
imx_esdhc_base_addr = (u32 *)MMC_SDHC2_BASE;
/* Pins */
writel(0x16, IOMUXC_BASE + 0x0e8); /* LD8 (SD1_CMD) */
writel(0x16, IOMUXC_BASE + 0x0ec); /* LD9 (SD1_CLK) */
writel(0x06, IOMUXC_BASE + 0x0f0); /* LD10 (SD1_DATA0) */
writel(0x06, IOMUXC_BASE + 0x0f4); /* LD11 (SD1_DATA1) */
writel(0x06, IOMUXC_BASE + 0x0f8); /* LD12 (SD1_DATA2) */
writel(0x06, IOMUXC_BASE + 0x0fc); /* LD13 (SD1_DATA3) */
writel(0x02, IOMUXC_BASE + 0x120); /* CSI_D2 (SD1_DATA4) */
writel(0x02, IOMUXC_BASE + 0x124); /* CSI_D3 (SD1_DATA5) */
writel(0x02, IOMUXC_BASE + 0x128); /* CSI_D4 (SD1_DATA6) */
writel(0x02, IOMUXC_BASE + 0x12c); /* CSI_D5 (SD1_DATA7) */
/* Pads */
writel(0xD1, IOMUXC_BASE + 0x2e0); /* LD8 (SD1_CMD) */
writel(0xD1, IOMUXC_BASE + 0x2e4); /* LD9 (SD1_CLK) */
writel(0xD1, IOMUXC_BASE + 0x2e8); /* LD10 (SD1_DATA0) */
writel(0xD1, IOMUXC_BASE + 0x2ec); /* LD11 (SD1_DATA1) */
writel(0xD1, IOMUXC_BASE + 0x2f0); /* LD12 (SD1_DATA2) */
writel(0xD1, IOMUXC_BASE + 0x2f4); /* LD13 (SD1_DATA3) */
writel(0xD1, IOMUXC_BASE + 0x318); /* CSI_D2 (SD1_DATA4) */
writel(0xD1, IOMUXC_BASE + 0x31c); /* CSI_D3 (SD1_DATA5) */
writel(0xD1, IOMUXC_BASE + 0x320); /* CSI_D4 (SD1_DATA6) */
writel(0xD1, IOMUXC_BASE + 0x324); /* CSI_D5 (SD1_DATA7) */
break;
default:
break;
}
return 0;
}
int board_mmc_init(void)
{
if (!esdhc_gpio_init())
return fsl_esdhc_mmc_init(gd->bd);
else
return -1;
}
#endif
void spi_io_init(struct imx_spi_dev_t *dev)
{
switch (dev->base) {
case CSPI1_BASE:
writel(0, IOMUXC_BASE + 0x180); /* CSPI1 SCLK */
writel(0x1C0, IOMUXC_BASE + 0x5c4);
writel(0, IOMUXC_BASE + 0x184); /* SPI_RDY */
writel(0x1E0, IOMUXC_BASE + 0x5c8);
writel(0, IOMUXC_BASE + 0x170); /* MOSI */
writel(0x1C0, IOMUXC_BASE + 0x5b4);
writel(0, IOMUXC_BASE + 0x174); /* MISO */
writel(0x1C0, IOMUXC_BASE + 0x5b8);
writel(0, IOMUXC_BASE + 0x17C); /* SS1 */
writel(0x1E0, IOMUXC_BASE + 0x5C0);
break;
default:
break;
}
}
int board_init(void)
{
setup_soc_rev();
/* setup pins for UART1 */
/* UART 1 IOMUX Configs */
mxc_request_iomux(MX25_PIN_UART1_RXD, MUX_CONFIG_FUNC);
mxc_request_iomux(MX25_PIN_UART1_TXD, MUX_CONFIG_FUNC);
mxc_request_iomux(MX25_PIN_UART1_RTS, MUX_CONFIG_FUNC);
mxc_request_iomux(MX25_PIN_UART1_CTS, MUX_CONFIG_FUNC);
mxc_iomux_set_pad(MX25_PIN_UART1_RXD,
PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE |
PAD_CTL_PUE_PUD | PAD_CTL_100K_PU);
mxc_iomux_set_pad(MX25_PIN_UART1_TXD,
PAD_CTL_PUE_PUD | PAD_CTL_100K_PD);
mxc_iomux_set_pad(MX25_PIN_UART1_RTS,
PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE |
PAD_CTL_PUE_PUD | PAD_CTL_100K_PU);
mxc_iomux_set_pad(MX25_PIN_UART1_CTS,
PAD_CTL_PUE_PUD | PAD_CTL_100K_PD);
/* setup pins for FEC */
mxc_request_iomux(MX25_PIN_FEC_TX_CLK, MUX_CONFIG_FUNC);
mxc_request_iomux(MX25_PIN_FEC_RX_DV, MUX_CONFIG_FUNC);
mxc_request_iomux(MX25_PIN_FEC_RDATA0, MUX_CONFIG_FUNC);
mxc_request_iomux(MX25_PIN_FEC_TDATA0, MUX_CONFIG_FUNC);
mxc_request_iomux(MX25_PIN_FEC_TX_EN, MUX_CONFIG_FUNC);
mxc_request_iomux(MX25_PIN_FEC_MDC, MUX_CONFIG_FUNC);
mxc_request_iomux(MX25_PIN_FEC_MDIO, MUX_CONFIG_FUNC);
mxc_request_iomux(MX25_PIN_FEC_RDATA1, MUX_CONFIG_FUNC);
mxc_request_iomux(MX25_PIN_FEC_TDATA1, MUX_CONFIG_FUNC);
mxc_request_iomux(MX25_PIN_POWER_FAIL, MUX_CONFIG_FUNC); /* PHY INT */
#define FEC_PAD_CTL1 (PAD_CTL_HYS_SCHMITZ | PAD_CTL_PUE_PUD | \
PAD_CTL_PKE_ENABLE)
#define FEC_PAD_CTL2 (PAD_CTL_PUE_PUD)
mxc_iomux_set_pad(MX25_PIN_FEC_TX_CLK, FEC_PAD_CTL1);
mxc_iomux_set_pad(MX25_PIN_FEC_RX_DV, FEC_PAD_CTL1);
mxc_iomux_set_pad(MX25_PIN_FEC_RDATA0, FEC_PAD_CTL1);
mxc_iomux_set_pad(MX25_PIN_FEC_TDATA0, FEC_PAD_CTL2);
mxc_iomux_set_pad(MX25_PIN_FEC_TX_EN, FEC_PAD_CTL2);
mxc_iomux_set_pad(MX25_PIN_FEC_MDC, FEC_PAD_CTL2);
mxc_iomux_set_pad(MX25_PIN_FEC_MDIO, FEC_PAD_CTL1 | PAD_CTL_22K_PU);
mxc_iomux_set_pad(MX25_PIN_FEC_RDATA1, FEC_PAD_CTL1);
mxc_iomux_set_pad(MX25_PIN_FEC_TDATA1, FEC_PAD_CTL2);
mxc_iomux_set_pad(MX25_PIN_POWER_FAIL, FEC_PAD_CTL1);
/*
* Set up the FEC_RESET_B and FEC_ENABLE GPIO pins.
* Assert FEC_RESET_B, then power up the PHY by asserting
* FEC_ENABLE, at the same time lifting FEC_RESET_B.
*
* FEC_RESET_B: gpio2[3] is ALT 5 mode of pin D12
* FEC_ENABLE_B: gpio4[8] is ALT 5 mode of pin A17
*/
/*FQ FOR ENABLE NOR
mxc_request_iomux(MX25_PIN_A17, MUX_CONFIG_ALT5); // FEC_EN
mxc_request_iomux(MX25_PIN_D12, MUX_CONFIG_ALT5); // FEC_RESET_B
mxc_iomux_set_pad(MX25_PIN_A17, PAD_CTL_ODE_OpenDrain);
mxc_iomux_set_pad(MX25_PIN_D12, 0);
mxc_set_gpio_direction(MX25_PIN_A17, 0); // FEC_EN
mxc_set_gpio_direction(MX25_PIN_D12, 0); // FEC_RESET_B
/* drop PHY power
mxc_set_gpio_dataout(MX25_PIN_A17, 0); // FEC_EN
// assert reset
mxc_set_gpio_dataout(MX25_PIN_D12, 0); // FEC_RESET_B
udelay(2); // spec says 1us min
// turn on PHY power and lift reset
mxc_set_gpio_dataout(MX25_PIN_A17, 1); // FEC_EN
mxc_set_gpio_dataout(MX25_PIN_D12, 1); // FEC_RESET_B
*/
#define I2C_PAD_CTL (PAD_CTL_HYS_SCHMITZ | PAD_CTL_PKE_ENABLE | \
PAD_CTL_PUE_PUD | PAD_CTL_100K_PU | PAD_CTL_ODE_OpenDrain)
mxc_request_iomux(MX25_PIN_I2C1_CLK, MUX_CONFIG_SION);
mxc_request_iomux(MX25_PIN_I2C1_DAT, MUX_CONFIG_SION);
mxc_iomux_set_pad(MX25_PIN_I2C1_CLK, 0x1E8);
mxc_iomux_set_pad(MX25_PIN_I2C1_DAT, 0x1E8);
gd->bd->bi_arch_number = MACH_TYPE_MX25_3DS; /* board id for linux */
gd->bd->bi_boot_params = 0x80000100; /* address of boot parameters */
return 0;
#undef FEC_PAD_CTL1
#undef FEC_PAD_CTL2
#undef I2C_PAD_CTL
}
#ifdef BOARD_LATE_INIT
int board_late_init(void)
{
u8 reg[4];
/* Turn PMIC On*/
reg[0] = 0x09;
i2c_write(0x54, 0x02, 1, reg, 1);
#ifdef CONFIG_IMX_SPI_CPLD
mxc_cpld_spi_init();
#endif
return 0;
}
#endif
int checkboard(void)
{
printf("Boot Device: SD Card \n");
printf("Board: SID1 i.MX25 \n");
return 0;
}
int board_eth_init(bd_t *bis)
{
int rc = -ENODEV;
#if defined(CONFIG_SMC911X)
rc = smc911x_initialize(0, CONFIG_SMC911X_BASE);
#endif
return rc;
}
It seems as if in order to support NOR upon boot, the following PADs and
PINs have to be disabled:
writel(0x06, IOMUXC_BASE + 0x094); // D12 (SD1_DATA4)
writel(0x06, IOMUXC_BASE + 0x090); // D13 (SD1_DATA5)
writel(0x06, IOMUXC_BASE + 0x08c); // D14 (SD1_DATA6)
writel(0x06, IOMUXC_BASE + 0x088); // D15 (SD1_DATA7)
writel(0x05, IOMUXC_BASE + 0x010); // A14 (SD1_WP)
writel(0x05, IOMUXC_BASE + 0x014); // A15 (SD1_DET)
Why, and how could I find the corresponding barebox mappings? I recall that
last week someone wanted to synchronize the IOMUX settings with the kernel
ones. But still, why this change and could this affect my issue I am seeing
with barebox? I still cannot initialize the NOR upon MMC internal boot on
my device.
Hope I could help you a bit.
>
>
A lot, let me know where I can send the beers or any beverage to as soon as
I get the bloody thing booting from NOR and showing up my NOR :).
Take care
Roberto
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.infradead.org/pipermail/barebox/attachments/20120529/7de01a63/attachment-0001.html>
More information about the barebox
mailing list