1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Freescale i.MX28 Boot setup
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
5*4882a593Smuzhiyun * on behalf of DENX Software Engineering GmbH
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <common.h>
11*4882a593Smuzhiyun #include <config.h>
12*4882a593Smuzhiyun #include <asm/io.h>
13*4882a593Smuzhiyun #include <asm/arch/imx-regs.h>
14*4882a593Smuzhiyun #include <asm/arch/sys_proto.h>
15*4882a593Smuzhiyun #include <asm/gpio.h>
16*4882a593Smuzhiyun #include <linux/compiler.h>
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #include "mxs_init.h"
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
21*4882a593Smuzhiyun static gd_t gdata __section(".data");
22*4882a593Smuzhiyun #ifdef CONFIG_SPL_SERIAL_SUPPORT
23*4882a593Smuzhiyun static bd_t bdata __section(".data");
24*4882a593Smuzhiyun #endif
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun /*
27*4882a593Smuzhiyun * This delay function is intended to be used only in early stage of boot, where
28*4882a593Smuzhiyun * clock are not set up yet. The timer used here is reset on every boot and
29*4882a593Smuzhiyun * takes a few seconds to roll. The boot doesn't take that long, so to keep the
30*4882a593Smuzhiyun * code simple, it doesn't take rolling into consideration.
31*4882a593Smuzhiyun */
early_delay(int delay)32*4882a593Smuzhiyun void early_delay(int delay)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun struct mxs_digctl_regs *digctl_regs =
35*4882a593Smuzhiyun (struct mxs_digctl_regs *)MXS_DIGCTL_BASE;
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun uint32_t st = readl(&digctl_regs->hw_digctl_microseconds);
38*4882a593Smuzhiyun st += delay;
39*4882a593Smuzhiyun while (st > readl(&digctl_regs->hw_digctl_microseconds))
40*4882a593Smuzhiyun ;
41*4882a593Smuzhiyun }
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun #if defined(CONFIG_MX23)
44*4882a593Smuzhiyun #define MUX_CONFIG_BOOTMODE_PAD (MXS_PAD_3V3 | MXS_PAD_4MA | MXS_PAD_NOPULL)
45*4882a593Smuzhiyun static const iomux_cfg_t iomux_boot[] = {
46*4882a593Smuzhiyun MX23_PAD_LCD_D00__GPIO_1_0 | MUX_CONFIG_BOOTMODE_PAD,
47*4882a593Smuzhiyun MX23_PAD_LCD_D01__GPIO_1_1 | MUX_CONFIG_BOOTMODE_PAD,
48*4882a593Smuzhiyun MX23_PAD_LCD_D02__GPIO_1_2 | MUX_CONFIG_BOOTMODE_PAD,
49*4882a593Smuzhiyun MX23_PAD_LCD_D03__GPIO_1_3 | MUX_CONFIG_BOOTMODE_PAD,
50*4882a593Smuzhiyun MX23_PAD_LCD_D04__GPIO_1_4 | MUX_CONFIG_BOOTMODE_PAD,
51*4882a593Smuzhiyun MX23_PAD_LCD_D05__GPIO_1_5 | MUX_CONFIG_BOOTMODE_PAD,
52*4882a593Smuzhiyun };
53*4882a593Smuzhiyun #endif
54*4882a593Smuzhiyun
mxs_get_bootmode_index(void)55*4882a593Smuzhiyun static uint8_t mxs_get_bootmode_index(void)
56*4882a593Smuzhiyun {
57*4882a593Smuzhiyun uint8_t bootmode = 0;
58*4882a593Smuzhiyun int i;
59*4882a593Smuzhiyun uint8_t masked;
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun #if defined(CONFIG_MX23)
62*4882a593Smuzhiyun /* Setup IOMUX of bootmode pads to GPIO */
63*4882a593Smuzhiyun mxs_iomux_setup_multiple_pads(iomux_boot, ARRAY_SIZE(iomux_boot));
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun /* Setup bootmode pins as GPIO input */
66*4882a593Smuzhiyun gpio_direction_input(MX23_PAD_LCD_D00__GPIO_1_0);
67*4882a593Smuzhiyun gpio_direction_input(MX23_PAD_LCD_D01__GPIO_1_1);
68*4882a593Smuzhiyun gpio_direction_input(MX23_PAD_LCD_D02__GPIO_1_2);
69*4882a593Smuzhiyun gpio_direction_input(MX23_PAD_LCD_D03__GPIO_1_3);
70*4882a593Smuzhiyun gpio_direction_input(MX23_PAD_LCD_D05__GPIO_1_5);
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun /* Read bootmode pads */
73*4882a593Smuzhiyun bootmode |= (gpio_get_value(MX23_PAD_LCD_D00__GPIO_1_0) ? 1 : 0) << 0;
74*4882a593Smuzhiyun bootmode |= (gpio_get_value(MX23_PAD_LCD_D01__GPIO_1_1) ? 1 : 0) << 1;
75*4882a593Smuzhiyun bootmode |= (gpio_get_value(MX23_PAD_LCD_D02__GPIO_1_2) ? 1 : 0) << 2;
76*4882a593Smuzhiyun bootmode |= (gpio_get_value(MX23_PAD_LCD_D03__GPIO_1_3) ? 1 : 0) << 3;
77*4882a593Smuzhiyun bootmode |= (gpio_get_value(MX23_PAD_LCD_D05__GPIO_1_5) ? 1 : 0) << 5;
78*4882a593Smuzhiyun #elif defined(CONFIG_MX28)
79*4882a593Smuzhiyun /* The global boot mode will be detected by ROM code and its value
80*4882a593Smuzhiyun * is stored at the fixed address 0x00019BF0 in OCRAM.
81*4882a593Smuzhiyun */
82*4882a593Smuzhiyun #define GLOBAL_BOOT_MODE_ADDR 0x00019BF0
83*4882a593Smuzhiyun bootmode = __raw_readl(GLOBAL_BOOT_MODE_ADDR);
84*4882a593Smuzhiyun #endif
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(mxs_boot_modes); i++) {
87*4882a593Smuzhiyun masked = bootmode & mxs_boot_modes[i].boot_mask;
88*4882a593Smuzhiyun if (masked == mxs_boot_modes[i].boot_pads)
89*4882a593Smuzhiyun break;
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun return i;
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun
mxs_spl_fixup_vectors(void)95*4882a593Smuzhiyun static void mxs_spl_fixup_vectors(void)
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun /*
98*4882a593Smuzhiyun * Copy our vector table to 0x0, since due to HAB, we cannot
99*4882a593Smuzhiyun * be loaded to 0x0. We want to have working vectoring though,
100*4882a593Smuzhiyun * thus this fixup. Our vectoring table is PIC, so copying is
101*4882a593Smuzhiyun * fine.
102*4882a593Smuzhiyun */
103*4882a593Smuzhiyun extern uint32_t _start;
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun /* cppcheck-suppress nullPointer */
106*4882a593Smuzhiyun memcpy(0x0, &_start, 0x60);
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun
mxs_spl_console_init(void)109*4882a593Smuzhiyun static void mxs_spl_console_init(void)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun #ifdef CONFIG_SPL_SERIAL_SUPPORT
112*4882a593Smuzhiyun gd->bd = &bdata;
113*4882a593Smuzhiyun gd->baudrate = CONFIG_BAUDRATE;
114*4882a593Smuzhiyun serial_init();
115*4882a593Smuzhiyun gd->have_console = 1;
116*4882a593Smuzhiyun #endif
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun
mxs_common_spl_init(const uint32_t arg,const uint32_t * resptr,const iomux_cfg_t * iomux_setup,const unsigned int iomux_size)119*4882a593Smuzhiyun void mxs_common_spl_init(const uint32_t arg, const uint32_t *resptr,
120*4882a593Smuzhiyun const iomux_cfg_t *iomux_setup,
121*4882a593Smuzhiyun const unsigned int iomux_size)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun struct mxs_spl_data *data = (struct mxs_spl_data *)
124*4882a593Smuzhiyun ((CONFIG_SYS_TEXT_BASE - sizeof(struct mxs_spl_data)) & ~0xf);
125*4882a593Smuzhiyun uint8_t bootmode = mxs_get_bootmode_index();
126*4882a593Smuzhiyun gd = &gdata;
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun mxs_spl_fixup_vectors();
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun mxs_iomux_setup_multiple_pads(iomux_setup, iomux_size);
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun mxs_spl_console_init();
133*4882a593Smuzhiyun debug("SPL: Serial Console Initialised\n");
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun mxs_power_init();
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun mxs_mem_init();
138*4882a593Smuzhiyun data->mem_dram_size = mxs_mem_get_size();
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun data->boot_mode_idx = bootmode;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun mxs_power_wait_pswitch();
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun if (mxs_boot_modes[data->boot_mode_idx].boot_pads == MXS_BM_JTAG) {
145*4882a593Smuzhiyun debug("SPL: Waiting for JTAG user\n");
146*4882a593Smuzhiyun asm volatile ("x: b x");
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun /* Support aparatus */
board_init_f(unsigned long bootflag)151*4882a593Smuzhiyun inline void board_init_f(unsigned long bootflag)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun for (;;)
154*4882a593Smuzhiyun ;
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun
board_init_r(gd_t * id,ulong dest_addr)157*4882a593Smuzhiyun inline void board_init_r(gd_t *id, ulong dest_addr)
158*4882a593Smuzhiyun {
159*4882a593Smuzhiyun for (;;)
160*4882a593Smuzhiyun ;
161*4882a593Smuzhiyun }
162