Commit 04fe4273d3a3a6d0a0de25d6bfa91e89917d60fb
Committed by
Stefano Babic
1 parent
fc10272856
Exists in
master
and in
55 other branches
M28: Add MMC SPL
This patch adds SPL code for the M28 board. Signed-off-by: Marek Vasut <marek.vasut@gmail.com> Cc: Andy Fleming <afleming@gmail.com> Cc: Stefano Babic <sbabic@denx.de> Cc: Wolfgang Denk <wd@denx.de> Cc: Detlev Zundel <dzu@denx.de>
Showing 9 changed files with 1953 additions and 0 deletions Side-by-side Diff
board/denx/m28evk/Makefile
... | ... | @@ -25,13 +25,21 @@ |
25 | 25 | |
26 | 26 | LIB = $(obj)lib$(BOARD).o |
27 | 27 | |
28 | +ifndef CONFIG_SPL_BUILD | |
28 | 29 | COBJS := m28evk.o |
30 | +endif | |
29 | 31 | |
32 | +ifdef CONFIG_SPL_BUILD | |
33 | +COBJS := mem_init.o mmc_boot.o power_init.o | |
34 | +endif | |
35 | + | |
30 | 36 | SRCS := $(COBJS:.o=.c) |
31 | 37 | OBJS := $(addprefix $(obj),$(COBJS)) |
32 | 38 | |
33 | 39 | $(LIB): $(obj).depend $(OBJS) |
34 | 40 | $(call cmd_link_o_target, $(OBJS)) |
41 | + | |
42 | +all: $(ALL) | |
35 | 43 | |
36 | 44 | ######################################################################### |
37 | 45 |
board/denx/m28evk/m28_init.h
1 | +/* | |
2 | + * Freescale i.MX28 SPL functions | |
3 | + * | |
4 | + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> | |
5 | + * on behalf of DENX Software Engineering GmbH | |
6 | + * | |
7 | + * See file CREDITS for list of people who contributed to this | |
8 | + * project. | |
9 | + * | |
10 | + * This program is free software; you can redistribute it and/or | |
11 | + * modify it under the terms of the GNU General Public License as | |
12 | + * published by the Free Software Foundation; either version 2 of | |
13 | + * the License, or (at your option) any later version. | |
14 | + * | |
15 | + * This program is distributed in the hope that it will be useful, | |
16 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | + * GNU General Public License for more details. | |
19 | + * | |
20 | + * You should have received a copy of the GNU General Public License | |
21 | + * along with this program; if not, write to the Free Software | |
22 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
23 | + * MA 02111-1307 USA | |
24 | + */ | |
25 | + | |
26 | +#ifndef __M28_INIT_H__ | |
27 | +#define __M28_INIT_H__ | |
28 | + | |
29 | +void early_delay(int delay); | |
30 | + | |
31 | +void mx28_power_init(void); | |
32 | + | |
33 | +#ifdef CONFIG_SPL_MX28_PSWITCH_WAIT | |
34 | +void mx28_power_wait_pswitch(void); | |
35 | +#else | |
36 | +static inline void mx28_power_wait_pswitch(void) { } | |
37 | +#endif | |
38 | + | |
39 | +void mx28_mem_init(void); | |
40 | + | |
41 | +#endif /* __M28_INIT_H__ */ |
board/denx/m28evk/mem_init.c
1 | +/* | |
2 | + * Freescale i.MX28 RAM init | |
3 | + * | |
4 | + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> | |
5 | + * on behalf of DENX Software Engineering GmbH | |
6 | + * | |
7 | + * See file CREDITS for list of people who contributed to this | |
8 | + * project. | |
9 | + * | |
10 | + * This program is free software; you can redistribute it and/or | |
11 | + * modify it under the terms of the GNU General Public License as | |
12 | + * published by the Free Software Foundation; either version 2 of | |
13 | + * the License, or (at your option) any later version. | |
14 | + * | |
15 | + * This program is distributed in the hope that it will be useful, | |
16 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | + * GNU General Public License for more details. | |
19 | + * | |
20 | + * You should have received a copy of the GNU General Public License | |
21 | + * along with this program; if not, write to the Free Software | |
22 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
23 | + * MA 02111-1307 USA | |
24 | + */ | |
25 | + | |
26 | +#include <common.h> | |
27 | +#include <config.h> | |
28 | +#include <asm/io.h> | |
29 | +#include <asm/arch/iomux-mx28.h> | |
30 | +#include <asm/arch/imx-regs.h> | |
31 | + | |
32 | +#include "m28_init.h" | |
33 | + | |
34 | +uint32_t dram_vals[] = { | |
35 | + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | |
36 | + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | |
37 | + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | |
38 | + 0x00000000, 0x00000000, 0x00000100, 0x00000000, 0x00000000, | |
39 | + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | |
40 | + 0x00000000, 0x00010101, 0x01010101, 0x000f0f01, 0x0f02020a, | |
41 | + 0x00000000, 0x00010101, 0x00000100, 0x00000100, 0x00000000, | |
42 | + 0x00000002, 0x01010000, 0x05060302, 0x06005003, 0x0a0000c8, | |
43 | + 0x02009c40, 0x0000030c, 0x0036a609, 0x031a0612, 0x02030202, | |
44 | + 0x00c8001c, 0x00000000, 0x00000000, 0x00012100, 0xffff0303, | |
45 | + 0x00012100, 0xffff0303, 0x00012100, 0xffff0303, 0x00012100, | |
46 | + 0xffff0303, 0x00000003, 0x00000000, 0x00000000, 0x00000000, | |
47 | + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | |
48 | + 0x00000000, 0x00000612, 0x01000F02, 0x06120612, 0x00000200, | |
49 | + 0x00020007, 0xf5014b27, 0xf5014b27, 0xf5014b27, 0xf5014b27, | |
50 | + 0x07000300, 0x07000300, 0x07000300, 0x07000300, 0x00000006, | |
51 | + 0x00000000, 0x00000000, 0x01000000, 0x01020408, 0x08040201, | |
52 | + 0x000f1133, 0x00000000, 0x00001f04, 0x00001f04, 0x00001f04, | |
53 | + 0x00001f04, 0x00001f04, 0x00001f04, 0x00001f04, 0x00001f04, | |
54 | + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | |
55 | + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | |
56 | + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | |
57 | + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | |
58 | + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | |
59 | + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | |
60 | + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | |
61 | + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | |
62 | + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | |
63 | + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | |
64 | + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | |
65 | + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | |
66 | + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | |
67 | + 0x00000000, 0x00000000, 0x00010000, 0x00020304, 0x00000004, | |
68 | + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | |
69 | + 0x00000000, 0x01010000, 0x01000000, 0x03030000, 0x00010303, | |
70 | + 0x01020202, 0x00000000, 0x02040303, 0x21002103, 0x00061200, | |
71 | + 0x06120612, 0x04320432, 0x04320432, 0x00040004, 0x00040004, | |
72 | + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00010001 | |
73 | +}; | |
74 | + | |
75 | +void init_m28_200mhz_ddr2(void) | |
76 | +{ | |
77 | + int i; | |
78 | + | |
79 | + for (i = 0; i < ARRAY_SIZE(dram_vals); i++) | |
80 | + writel(dram_vals[i], MXS_DRAM_BASE + (4 * i)); | |
81 | +} | |
82 | + | |
83 | +void mx28_mem_init_clock(void) | |
84 | +{ | |
85 | + struct mx28_clkctrl_regs *clkctrl_regs = | |
86 | + (struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE; | |
87 | + | |
88 | + /* Gate EMI clock */ | |
89 | + writel(CLKCTRL_FRAC0_CLKGATEEMI, | |
90 | + &clkctrl_regs->hw_clkctrl_frac0_set); | |
91 | + | |
92 | + /* EMI = 205MHz */ | |
93 | + writel(CLKCTRL_FRAC0_EMIFRAC_MASK, | |
94 | + &clkctrl_regs->hw_clkctrl_frac0_set); | |
95 | + writel((0x2a << CLKCTRL_FRAC0_EMIFRAC_OFFSET) & | |
96 | + CLKCTRL_FRAC0_EMIFRAC_MASK, | |
97 | + &clkctrl_regs->hw_clkctrl_frac0_clr); | |
98 | + | |
99 | + /* Ungate EMI clock */ | |
100 | + writel(CLKCTRL_FRAC0_CLKGATEEMI, | |
101 | + &clkctrl_regs->hw_clkctrl_frac0_clr); | |
102 | + | |
103 | + early_delay(11000); | |
104 | + | |
105 | + writel((2 << CLKCTRL_EMI_DIV_EMI_OFFSET) | | |
106 | + (1 << CLKCTRL_EMI_DIV_XTAL_OFFSET), | |
107 | + &clkctrl_regs->hw_clkctrl_emi); | |
108 | + | |
109 | + /* Unbypass EMI */ | |
110 | + writel(CLKCTRL_CLKSEQ_BYPASS_EMI, | |
111 | + &clkctrl_regs->hw_clkctrl_clkseq_clr); | |
112 | + | |
113 | + early_delay(10000); | |
114 | +} | |
115 | + | |
116 | +void mx28_mem_setup_cpu_and_hbus(void) | |
117 | +{ | |
118 | + struct mx28_clkctrl_regs *clkctrl_regs = | |
119 | + (struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE; | |
120 | + | |
121 | + /* CPU = 454MHz and ungate CPU clock */ | |
122 | + clrsetbits_le32(&clkctrl_regs->hw_clkctrl_frac0, | |
123 | + CLKCTRL_FRAC0_CPUFRAC_MASK | CLKCTRL_FRAC0_CLKGATECPU, | |
124 | + 19 << CLKCTRL_FRAC0_CPUFRAC_OFFSET); | |
125 | + | |
126 | + /* Set CPU bypass */ | |
127 | + writel(CLKCTRL_CLKSEQ_BYPASS_CPU, | |
128 | + &clkctrl_regs->hw_clkctrl_clkseq_set); | |
129 | + | |
130 | + /* HBUS = 151MHz */ | |
131 | + writel(CLKCTRL_HBUS_DIV_MASK, &clkctrl_regs->hw_clkctrl_hbus_set); | |
132 | + writel(((~3) << CLKCTRL_HBUS_DIV_OFFSET) & CLKCTRL_HBUS_DIV_MASK, | |
133 | + &clkctrl_regs->hw_clkctrl_hbus_clr); | |
134 | + | |
135 | + early_delay(10000); | |
136 | + | |
137 | + /* CPU clock divider = 1 */ | |
138 | + clrsetbits_le32(&clkctrl_regs->hw_clkctrl_cpu, | |
139 | + CLKCTRL_CPU_DIV_CPU_MASK, 1); | |
140 | + | |
141 | + /* Disable CPU bypass */ | |
142 | + writel(CLKCTRL_CLKSEQ_BYPASS_CPU, | |
143 | + &clkctrl_regs->hw_clkctrl_clkseq_clr); | |
144 | +} | |
145 | + | |
146 | +void mx28_mem_setup_vdda(void) | |
147 | +{ | |
148 | + struct mx28_power_regs *power_regs = | |
149 | + (struct mx28_power_regs *)MXS_POWER_BASE; | |
150 | + | |
151 | + writel((0xc << POWER_VDDACTRL_TRG_OFFSET) | | |
152 | + (0x7 << POWER_VDDACTRL_BO_OFFSET_OFFSET) | | |
153 | + POWER_VDDACTRL_LINREG_OFFSET_1STEPS_BELOW, | |
154 | + &power_regs->hw_power_vddactrl); | |
155 | +} | |
156 | + | |
157 | +void mx28_mem_setup_vddd(void) | |
158 | +{ | |
159 | + struct mx28_power_regs *power_regs = | |
160 | + (struct mx28_power_regs *)MXS_POWER_BASE; | |
161 | + | |
162 | + writel((0x1c << POWER_VDDDCTRL_TRG_OFFSET) | | |
163 | + (0x7 << POWER_VDDDCTRL_BO_OFFSET_OFFSET) | | |
164 | + POWER_VDDDCTRL_LINREG_OFFSET_1STEPS_BELOW, | |
165 | + &power_regs->hw_power_vdddctrl); | |
166 | +} | |
167 | + | |
168 | +void mx28_mem_init(void) | |
169 | +{ | |
170 | + struct mx28_clkctrl_regs *clkctrl_regs = | |
171 | + (struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE; | |
172 | + struct mx28_pinctrl_regs *pinctrl_regs = | |
173 | + (struct mx28_pinctrl_regs *)MXS_PINCTRL_BASE; | |
174 | + | |
175 | + /* Set DDR2 mode */ | |
176 | + writel(PINCTRL_EMI_DS_CTRL_DDR_MODE_DDR2, | |
177 | + &pinctrl_regs->hw_pinctrl_emi_ds_ctrl_set); | |
178 | + | |
179 | + /* Power up PLL0 */ | |
180 | + writel(CLKCTRL_PLL0CTRL0_POWER, | |
181 | + &clkctrl_regs->hw_clkctrl_pll0ctrl0_set); | |
182 | + | |
183 | + early_delay(11000); | |
184 | + | |
185 | + mx28_mem_init_clock(); | |
186 | + | |
187 | + mx28_mem_setup_vdda(); | |
188 | + | |
189 | + /* | |
190 | + * Configure the DRAM registers | |
191 | + */ | |
192 | + | |
193 | + /* Clear START bit from DRAM_CTL16 */ | |
194 | + clrbits_le32(MXS_DRAM_BASE + 0x40, 1); | |
195 | + | |
196 | + init_m28_200mhz_ddr2(); | |
197 | + | |
198 | + /* Clear SREFRESH bit from DRAM_CTL17 */ | |
199 | + clrbits_le32(MXS_DRAM_BASE + 0x44, 1); | |
200 | + | |
201 | + /* Set START bit in DRAM_CTL16 */ | |
202 | + setbits_le32(MXS_DRAM_BASE + 0x40, 1); | |
203 | + | |
204 | + /* Wait for bit 20 (DRAM init complete) in DRAM_CTL58 */ | |
205 | + while (!(readl(MXS_DRAM_BASE + 0xe8) & (1 << 20))) | |
206 | + ; | |
207 | + | |
208 | + mx28_mem_setup_vddd(); | |
209 | + | |
210 | + early_delay(10000); | |
211 | + | |
212 | + mx28_mem_setup_cpu_and_hbus(); | |
213 | +} |
board/denx/m28evk/mmc_boot.c
1 | +/* | |
2 | + * Freescale i.MX28 Boot setup | |
3 | + * | |
4 | + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> | |
5 | + * on behalf of DENX Software Engineering GmbH | |
6 | + * | |
7 | + * See file CREDITS for list of people who contributed to this | |
8 | + * project. | |
9 | + * | |
10 | + * This program is free software; you can redistribute it and/or | |
11 | + * modify it under the terms of the GNU General Public License as | |
12 | + * published by the Free Software Foundation; either version 2 of | |
13 | + * the License, or (at your option) any later version. | |
14 | + * | |
15 | + * This program is distributed in the hope that it will be useful, | |
16 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | + * GNU General Public License for more details. | |
19 | + * | |
20 | + * You should have received a copy of the GNU General Public License | |
21 | + * along with this program; if not, write to the Free Software | |
22 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
23 | + * MA 02111-1307 USA | |
24 | + */ | |
25 | + | |
26 | +#include <common.h> | |
27 | +#include <config.h> | |
28 | +#include <asm/io.h> | |
29 | +#include <asm/arch/iomux-mx28.h> | |
30 | + | |
31 | +#include "m28_init.h" | |
32 | + | |
33 | +/* | |
34 | + * This delay function is intended to be used only in early stage of boot, where | |
35 | + * clock are not set up yet. The timer used here is reset on every boot and | |
36 | + * takes a few seconds to roll. The boot doesn't take that long, so to keep the | |
37 | + * code simple, it doesn't take rolling into consideration. | |
38 | + */ | |
39 | +#define HW_DIGCTRL_MICROSECONDS 0x8001c0c0 | |
40 | +void early_delay(int delay) | |
41 | +{ | |
42 | + uint32_t st = readl(HW_DIGCTRL_MICROSECONDS); | |
43 | + st += delay; | |
44 | + while (st > readl(HW_DIGCTRL_MICROSECONDS)) | |
45 | + ; | |
46 | +} | |
47 | + | |
48 | +#define MUX_CONFIG_LED (MXS_PAD_3V3 | MXS_PAD_4MA | MXS_PAD_NOPULL) | |
49 | +#define MUX_CONFIG_LCD (MXS_PAD_3V3 | MXS_PAD_4MA) | |
50 | +#define MUX_CONFIG_TSC (MXS_PAD_3V3 | MXS_PAD_8MA | MXS_PAD_PULLUP) | |
51 | +#define MUX_CONFIG_SSP0 (MXS_PAD_3V3 | MXS_PAD_12MA | MXS_PAD_PULLUP) | |
52 | +#define MUX_CONFIG_SSP2 (MXS_PAD_3V3 | MXS_PAD_4MA | MXS_PAD_PULLUP) | |
53 | +#define MUX_CONFIG_GPMI (MXS_PAD_1V8 | MXS_PAD_4MA | MXS_PAD_NOPULL) | |
54 | +#define MUX_CONFIG_ENET (MXS_PAD_3V3 | MXS_PAD_4MA | MXS_PAD_PULLUP) | |
55 | +#define MUX_CONFIG_EMI (MXS_PAD_3V3 | MXS_PAD_12MA | MXS_PAD_NOPULL) | |
56 | + | |
57 | +const iomux_cfg_t iomux_setup[] = { | |
58 | + /* LED */ | |
59 | + MX28_PAD_ENET0_RXD3__GPIO_4_10 | MUX_CONFIG_LED, | |
60 | + | |
61 | + /* framebuffer */ | |
62 | + MX28_PAD_LCD_D00__LCD_D0 | MUX_CONFIG_LCD, | |
63 | + MX28_PAD_LCD_D01__LCD_D1 | MUX_CONFIG_LCD, | |
64 | + MX28_PAD_LCD_D02__LCD_D2 | MUX_CONFIG_LCD, | |
65 | + MX28_PAD_LCD_D03__LCD_D3 | MUX_CONFIG_LCD, | |
66 | + MX28_PAD_LCD_D04__LCD_D4 | MUX_CONFIG_LCD, | |
67 | + MX28_PAD_LCD_D05__LCD_D5 | MUX_CONFIG_LCD, | |
68 | + MX28_PAD_LCD_D06__LCD_D6 | MUX_CONFIG_LCD, | |
69 | + MX28_PAD_LCD_D07__LCD_D7 | MUX_CONFIG_LCD, | |
70 | + MX28_PAD_LCD_D08__LCD_D8 | MUX_CONFIG_LCD, | |
71 | + MX28_PAD_LCD_D09__LCD_D9 | MUX_CONFIG_LCD, | |
72 | + MX28_PAD_LCD_D10__LCD_D10 | MUX_CONFIG_LCD, | |
73 | + MX28_PAD_LCD_D11__LCD_D11 | MUX_CONFIG_LCD, | |
74 | + MX28_PAD_LCD_D12__LCD_D12 | MUX_CONFIG_LCD, | |
75 | + MX28_PAD_LCD_D13__LCD_D13 | MUX_CONFIG_LCD, | |
76 | + MX28_PAD_LCD_D14__LCD_D14 | MUX_CONFIG_LCD, | |
77 | + MX28_PAD_LCD_D15__LCD_D15 | MUX_CONFIG_LCD, | |
78 | + MX28_PAD_LCD_D16__LCD_D16 | MUX_CONFIG_LCD, | |
79 | + MX28_PAD_LCD_D17__LCD_D17 | MUX_CONFIG_LCD, | |
80 | + MX28_PAD_LCD_D18__LCD_D18 | MUX_CONFIG_LCD, | |
81 | + MX28_PAD_LCD_D19__LCD_D19 | MUX_CONFIG_LCD, | |
82 | + MX28_PAD_LCD_D20__LCD_D20 | MUX_CONFIG_LCD, | |
83 | + MX28_PAD_LCD_D21__LCD_D21 | MUX_CONFIG_LCD, | |
84 | + MX28_PAD_LCD_D22__LCD_D22 | MUX_CONFIG_LCD, | |
85 | + MX28_PAD_LCD_D23__LCD_D23 | MUX_CONFIG_LCD, | |
86 | + MX28_PAD_LCD_RD_E__LCD_VSYNC | MUX_CONFIG_LCD, | |
87 | + MX28_PAD_LCD_WR_RWN__LCD_HSYNC | MUX_CONFIG_LCD, | |
88 | + MX28_PAD_LCD_RS__LCD_DOTCLK | MUX_CONFIG_LCD, | |
89 | + MX28_PAD_LCD_CS__LCD_CS | MUX_CONFIG_LCD, | |
90 | + MX28_PAD_LCD_VSYNC__LCD_VSYNC | MUX_CONFIG_LCD, | |
91 | + MX28_PAD_LCD_HSYNC__LCD_HSYNC | MUX_CONFIG_LCD, | |
92 | + MX28_PAD_LCD_DOTCLK__LCD_DOTCLK | MUX_CONFIG_LCD, | |
93 | + MX28_PAD_LCD_ENABLE__GPIO_1_31 | MUX_CONFIG_LCD, | |
94 | + MX28_PAD_LCD_RESET__GPIO_3_30 | MUX_CONFIG_LCD, | |
95 | + | |
96 | + /* UART1 */ | |
97 | + MX28_PAD_PWM0__DUART_RX, | |
98 | + MX28_PAD_PWM1__DUART_TX, | |
99 | + MX28_PAD_AUART0_TX__DUART_RTS, | |
100 | + MX28_PAD_AUART0_RX__DUART_CTS, | |
101 | + | |
102 | + /* UART2 */ | |
103 | + MX28_PAD_AUART1_RX__AUART1_RX, | |
104 | + MX28_PAD_AUART1_TX__AUART1_TX, | |
105 | + MX28_PAD_AUART1_RTS__AUART1_RTS, | |
106 | + MX28_PAD_AUART1_CTS__AUART1_CTS, | |
107 | + | |
108 | + /* CAN */ | |
109 | + MX28_PAD_GPMI_RDY2__CAN0_TX, | |
110 | + MX28_PAD_GPMI_RDY3__CAN0_RX, | |
111 | + | |
112 | + /* I2C */ | |
113 | + MX28_PAD_I2C0_SCL__I2C0_SCL, | |
114 | + MX28_PAD_I2C0_SDA__I2C0_SDA, | |
115 | + | |
116 | + /* TSC2007 */ | |
117 | + MX28_PAD_SAIF0_MCLK__GPIO_3_20 | MUX_CONFIG_TSC, | |
118 | + | |
119 | + /* MMC0 */ | |
120 | + MX28_PAD_SSP0_DATA0__SSP0_D0 | MUX_CONFIG_SSP0, | |
121 | + MX28_PAD_SSP0_DATA1__SSP0_D1 | MUX_CONFIG_SSP0, | |
122 | + MX28_PAD_SSP0_DATA2__SSP0_D2 | MUX_CONFIG_SSP0, | |
123 | + MX28_PAD_SSP0_DATA3__SSP0_D3 | MUX_CONFIG_SSP0, | |
124 | + MX28_PAD_SSP0_DATA4__SSP0_D4 | MUX_CONFIG_SSP0, | |
125 | + MX28_PAD_SSP0_DATA5__SSP0_D5 | MUX_CONFIG_SSP0, | |
126 | + MX28_PAD_SSP0_DATA6__SSP0_D6 | MUX_CONFIG_SSP0, | |
127 | + MX28_PAD_SSP0_DATA7__SSP0_D7 | MUX_CONFIG_SSP0, | |
128 | + MX28_PAD_SSP0_CMD__SSP0_CMD | MUX_CONFIG_SSP0, | |
129 | + MX28_PAD_SSP0_DETECT__SSP0_CARD_DETECT | | |
130 | + (MXS_PAD_3V3 | MXS_PAD_12MA | MXS_PAD_NOPULL), | |
131 | + MX28_PAD_SSP0_SCK__SSP0_SCK | | |
132 | + (MXS_PAD_3V3 | MXS_PAD_12MA | MXS_PAD_NOPULL), | |
133 | + MX28_PAD_PWM3__GPIO_3_28 | MUX_CONFIG_SSP0, /* Power .. FIXME */ | |
134 | + MX28_PAD_AUART2_CTS__GPIO_3_10, /* WP ... FIXME */ | |
135 | + | |
136 | + /* GPMI NAND */ | |
137 | + MX28_PAD_GPMI_D00__GPMI_D0 | MUX_CONFIG_GPMI, | |
138 | + MX28_PAD_GPMI_D01__GPMI_D1 | MUX_CONFIG_GPMI, | |
139 | + MX28_PAD_GPMI_D02__GPMI_D2 | MUX_CONFIG_GPMI, | |
140 | + MX28_PAD_GPMI_D03__GPMI_D3 | MUX_CONFIG_GPMI, | |
141 | + MX28_PAD_GPMI_D04__GPMI_D4 | MUX_CONFIG_GPMI, | |
142 | + MX28_PAD_GPMI_D05__GPMI_D5 | MUX_CONFIG_GPMI, | |
143 | + MX28_PAD_GPMI_D06__GPMI_D6 | MUX_CONFIG_GPMI, | |
144 | + MX28_PAD_GPMI_D07__GPMI_D7 | MUX_CONFIG_GPMI, | |
145 | + MX28_PAD_GPMI_CE0N__GPMI_CE0N | MUX_CONFIG_GPMI, | |
146 | + MX28_PAD_GPMI_RDY0__GPMI_READY0 | MUX_CONFIG_GPMI, | |
147 | + MX28_PAD_GPMI_RDN__GPMI_RDN | | |
148 | + (MXS_PAD_1V8 | MXS_PAD_8MA | MXS_PAD_PULLUP), | |
149 | + MX28_PAD_GPMI_WRN__GPMI_WRN | MUX_CONFIG_GPMI, | |
150 | + MX28_PAD_GPMI_ALE__GPMI_ALE | MUX_CONFIG_GPMI, | |
151 | + MX28_PAD_GPMI_CLE__GPMI_CLE | MUX_CONFIG_GPMI, | |
152 | + MX28_PAD_GPMI_RESETN__GPMI_RESETN | MUX_CONFIG_GPMI, | |
153 | + | |
154 | + /* FEC Ethernet */ | |
155 | + MX28_PAD_ENET0_MDC__ENET0_MDC | MUX_CONFIG_ENET, | |
156 | + MX28_PAD_ENET0_MDIO__ENET0_MDIO | MUX_CONFIG_ENET, | |
157 | + MX28_PAD_ENET0_RX_EN__ENET0_RX_EN | MUX_CONFIG_ENET, | |
158 | + MX28_PAD_ENET0_TX_EN__ENET0_TX_EN | MUX_CONFIG_ENET, | |
159 | + MX28_PAD_ENET0_RXD0__ENET0_RXD0 | MUX_CONFIG_ENET, | |
160 | + MX28_PAD_ENET0_RXD1__ENET0_RXD1 | MUX_CONFIG_ENET, | |
161 | + MX28_PAD_ENET0_TXD0__ENET0_TXD0 | MUX_CONFIG_ENET, | |
162 | + MX28_PAD_ENET0_TXD1__ENET0_TXD1 | MUX_CONFIG_ENET, | |
163 | + MX28_PAD_ENET_CLK__CLKCTRL_ENET | MUX_CONFIG_ENET, | |
164 | + | |
165 | + MX28_PAD_ENET0_COL__ENET1_TX_EN | MUX_CONFIG_ENET, | |
166 | + MX28_PAD_ENET0_CRS__ENET1_RX_EN | MUX_CONFIG_ENET, | |
167 | + MX28_PAD_ENET0_RXD2__ENET1_RXD0 | MUX_CONFIG_ENET, | |
168 | + MX28_PAD_ENET0_RXD3__ENET1_RXD1 | MUX_CONFIG_ENET, | |
169 | + MX28_PAD_ENET0_TXD2__ENET1_TXD0 | MUX_CONFIG_ENET, | |
170 | + MX28_PAD_ENET0_TXD3__ENET1_TXD1 | MUX_CONFIG_ENET, | |
171 | + | |
172 | + /* I2C */ | |
173 | + MX28_PAD_I2C0_SCL__I2C0_SCL, | |
174 | + MX28_PAD_I2C0_SDA__I2C0_SDA, | |
175 | + | |
176 | + /* EMI */ | |
177 | + MX28_PAD_EMI_D00__EMI_DATA0 | MUX_CONFIG_EMI, | |
178 | + MX28_PAD_EMI_D01__EMI_DATA1 | MUX_CONFIG_EMI, | |
179 | + MX28_PAD_EMI_D02__EMI_DATA2 | MUX_CONFIG_EMI, | |
180 | + MX28_PAD_EMI_D03__EMI_DATA3 | MUX_CONFIG_EMI, | |
181 | + MX28_PAD_EMI_D04__EMI_DATA4 | MUX_CONFIG_EMI, | |
182 | + MX28_PAD_EMI_D05__EMI_DATA5 | MUX_CONFIG_EMI, | |
183 | + MX28_PAD_EMI_D06__EMI_DATA6 | MUX_CONFIG_EMI, | |
184 | + MX28_PAD_EMI_D07__EMI_DATA7 | MUX_CONFIG_EMI, | |
185 | + MX28_PAD_EMI_D08__EMI_DATA8 | MUX_CONFIG_EMI, | |
186 | + MX28_PAD_EMI_D09__EMI_DATA9 | MUX_CONFIG_EMI, | |
187 | + MX28_PAD_EMI_D10__EMI_DATA10 | MUX_CONFIG_EMI, | |
188 | + MX28_PAD_EMI_D11__EMI_DATA11 | MUX_CONFIG_EMI, | |
189 | + MX28_PAD_EMI_D12__EMI_DATA12 | MUX_CONFIG_EMI, | |
190 | + MX28_PAD_EMI_D13__EMI_DATA13 | MUX_CONFIG_EMI, | |
191 | + MX28_PAD_EMI_D14__EMI_DATA14 | MUX_CONFIG_EMI, | |
192 | + MX28_PAD_EMI_D15__EMI_DATA15 | MUX_CONFIG_EMI, | |
193 | + MX28_PAD_EMI_ODT0__EMI_ODT0 | MUX_CONFIG_EMI, | |
194 | + MX28_PAD_EMI_DQM0__EMI_DQM0 | MUX_CONFIG_EMI, | |
195 | + MX28_PAD_EMI_ODT1__EMI_ODT1 | MUX_CONFIG_EMI, | |
196 | + MX28_PAD_EMI_DQM1__EMI_DQM1 | MUX_CONFIG_EMI, | |
197 | + MX28_PAD_EMI_DDR_OPEN_FB__EMI_DDR_OPEN_FEEDBACK | MUX_CONFIG_EMI, | |
198 | + MX28_PAD_EMI_CLK__EMI_CLK | MUX_CONFIG_EMI, | |
199 | + MX28_PAD_EMI_DQS0__EMI_DQS0 | MUX_CONFIG_EMI, | |
200 | + MX28_PAD_EMI_DQS1__EMI_DQS1 | MUX_CONFIG_EMI, | |
201 | + MX28_PAD_EMI_DDR_OPEN__EMI_DDR_OPEN | MUX_CONFIG_EMI, | |
202 | + | |
203 | + MX28_PAD_EMI_A00__EMI_ADDR0 | MUX_CONFIG_EMI, | |
204 | + MX28_PAD_EMI_A01__EMI_ADDR1 | MUX_CONFIG_EMI, | |
205 | + MX28_PAD_EMI_A02__EMI_ADDR2 | MUX_CONFIG_EMI, | |
206 | + MX28_PAD_EMI_A03__EMI_ADDR3 | MUX_CONFIG_EMI, | |
207 | + MX28_PAD_EMI_A04__EMI_ADDR4 | MUX_CONFIG_EMI, | |
208 | + MX28_PAD_EMI_A05__EMI_ADDR5 | MUX_CONFIG_EMI, | |
209 | + MX28_PAD_EMI_A06__EMI_ADDR6 | MUX_CONFIG_EMI, | |
210 | + MX28_PAD_EMI_A07__EMI_ADDR7 | MUX_CONFIG_EMI, | |
211 | + MX28_PAD_EMI_A08__EMI_ADDR8 | MUX_CONFIG_EMI, | |
212 | + MX28_PAD_EMI_A09__EMI_ADDR9 | MUX_CONFIG_EMI, | |
213 | + MX28_PAD_EMI_A10__EMI_ADDR10 | MUX_CONFIG_EMI, | |
214 | + MX28_PAD_EMI_A11__EMI_ADDR11 | MUX_CONFIG_EMI, | |
215 | + MX28_PAD_EMI_A12__EMI_ADDR12 | MUX_CONFIG_EMI, | |
216 | + MX28_PAD_EMI_A13__EMI_ADDR13 | MUX_CONFIG_EMI, | |
217 | + MX28_PAD_EMI_A14__EMI_ADDR14 | MUX_CONFIG_EMI, | |
218 | + MX28_PAD_EMI_BA0__EMI_BA0 | MUX_CONFIG_EMI, | |
219 | + MX28_PAD_EMI_BA1__EMI_BA1 | MUX_CONFIG_EMI, | |
220 | + MX28_PAD_EMI_BA2__EMI_BA2 | MUX_CONFIG_EMI, | |
221 | + MX28_PAD_EMI_CASN__EMI_CASN | MUX_CONFIG_EMI, | |
222 | + MX28_PAD_EMI_RASN__EMI_RASN | MUX_CONFIG_EMI, | |
223 | + MX28_PAD_EMI_WEN__EMI_WEN | MUX_CONFIG_EMI, | |
224 | + MX28_PAD_EMI_CE0N__EMI_CE0N | MUX_CONFIG_EMI, | |
225 | + MX28_PAD_EMI_CE1N__EMI_CE1N | MUX_CONFIG_EMI, | |
226 | + MX28_PAD_EMI_CKE__EMI_CKE | MUX_CONFIG_EMI, | |
227 | + | |
228 | + /* SPI2 (for flash) */ | |
229 | + MX28_PAD_SSP2_SCK__SSP2_SCK | MUX_CONFIG_SSP2, | |
230 | + MX28_PAD_SSP2_MOSI__SSP2_CMD | MUX_CONFIG_SSP2, | |
231 | + MX28_PAD_SSP2_MISO__SSP2_D0 | MUX_CONFIG_SSP2, | |
232 | + MX28_PAD_SSP2_SS0__SSP2_D3 | | |
233 | + (MXS_PAD_3V3 | MXS_PAD_8MA | MXS_PAD_PULLUP), | |
234 | +}; | |
235 | + | |
236 | +void board_init_ll(void) | |
237 | +{ | |
238 | + mxs_iomux_setup_multiple_pads(iomux_setup, ARRAY_SIZE(iomux_setup)); | |
239 | + mx28_power_init(); | |
240 | + mx28_mem_init(); | |
241 | + mx28_power_wait_pswitch(); | |
242 | +} | |
243 | + | |
244 | +/* Support aparatus */ | |
245 | +inline void board_init_f(unsigned long bootflag) | |
246 | +{ | |
247 | + for (;;) | |
248 | + ; | |
249 | +} | |
250 | + | |
251 | +inline void board_init_r(gd_t *id, ulong dest_addr) | |
252 | +{ | |
253 | + for (;;) | |
254 | + ; | |
255 | +} | |
256 | + | |
257 | +inline int printf(const char *fmt, ...) | |
258 | +{ | |
259 | + return 0; | |
260 | +} | |
261 | + | |
262 | +inline void __coloured_LED_init(void) {} | |
263 | +inline void __red_LED_on(void) {} | |
264 | +void coloured_LED_init(void) | |
265 | + __attribute__((weak, alias("__coloured_LED_init"))); | |
266 | +void red_LED_on(void) | |
267 | + __attribute__((weak, alias("__red_LED_on"))); | |
268 | +void hang(void) __attribute__ ((noreturn)); | |
269 | +void hang(void) | |
270 | +{ | |
271 | + for (;;) | |
272 | + ; | |
273 | +} |
board/denx/m28evk/power_init.c
1 | +/* | |
2 | + * Freescale i.MX28 Boot PMIC init | |
3 | + * | |
4 | + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> | |
5 | + * on behalf of DENX Software Engineering GmbH | |
6 | + * | |
7 | + * See file CREDITS for list of people who contributed to this | |
8 | + * project. | |
9 | + * | |
10 | + * This program is free software; you can redistribute it and/or | |
11 | + * modify it under the terms of the GNU General Public License as | |
12 | + * published by the Free Software Foundation; either version 2 of | |
13 | + * the License, or (at your option) any later version. | |
14 | + * | |
15 | + * This program is distributed in the hope that it will be useful, | |
16 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | + * GNU General Public License for more details. | |
19 | + * | |
20 | + * You should have received a copy of the GNU General Public License | |
21 | + * along with this program; if not, write to the Free Software | |
22 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
23 | + * MA 02111-1307 USA | |
24 | + */ | |
25 | + | |
26 | +#include <common.h> | |
27 | +#include <config.h> | |
28 | +#include <asm/io.h> | |
29 | +#include <asm/arch/imx-regs.h> | |
30 | + | |
31 | +#include "m28_init.h" | |
32 | + | |
33 | +void mx28_power_clock2xtal(void) | |
34 | +{ | |
35 | + struct mx28_clkctrl_regs *clkctrl_regs = | |
36 | + (struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE; | |
37 | + | |
38 | + /* Set XTAL as CPU reference clock */ | |
39 | + writel(CLKCTRL_CLKSEQ_BYPASS_CPU, | |
40 | + &clkctrl_regs->hw_clkctrl_clkseq_set); | |
41 | +} | |
42 | + | |
43 | +void mx28_power_clock2pll(void) | |
44 | +{ | |
45 | + struct mx28_clkctrl_regs *clkctrl_regs = | |
46 | + (struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE; | |
47 | + | |
48 | + writel(CLKCTRL_PLL0CTRL0_POWER, | |
49 | + &clkctrl_regs->hw_clkctrl_pll0ctrl0_set); | |
50 | + early_delay(100); | |
51 | + writel(CLKCTRL_CLKSEQ_BYPASS_CPU, | |
52 | + &clkctrl_regs->hw_clkctrl_clkseq_clr); | |
53 | +} | |
54 | + | |
55 | +void mx28_power_clear_auto_restart(void) | |
56 | +{ | |
57 | + struct mx28_rtc_regs *rtc_regs = | |
58 | + (struct mx28_rtc_regs *)MXS_RTC_BASE; | |
59 | + | |
60 | + writel(RTC_CTRL_SFTRST, &rtc_regs->hw_rtc_ctrl_clr); | |
61 | + while (readl(&rtc_regs->hw_rtc_ctrl) & RTC_CTRL_SFTRST) | |
62 | + ; | |
63 | + | |
64 | + writel(RTC_CTRL_CLKGATE, &rtc_regs->hw_rtc_ctrl_clr); | |
65 | + while (readl(&rtc_regs->hw_rtc_ctrl) & RTC_CTRL_CLKGATE) | |
66 | + ; | |
67 | + | |
68 | + /* | |
69 | + * Due to the hardware design bug of mx28 EVK-A | |
70 | + * we need to set the AUTO_RESTART bit. | |
71 | + */ | |
72 | + if (readl(&rtc_regs->hw_rtc_persistent0) & RTC_PERSISTENT0_AUTO_RESTART) | |
73 | + return; | |
74 | + | |
75 | + while (readl(&rtc_regs->hw_rtc_stat) & RTC_STAT_NEW_REGS_MASK) | |
76 | + ; | |
77 | + | |
78 | + setbits_le32(&rtc_regs->hw_rtc_persistent0, | |
79 | + RTC_PERSISTENT0_AUTO_RESTART); | |
80 | + writel(RTC_CTRL_FORCE_UPDATE, &rtc_regs->hw_rtc_ctrl_set); | |
81 | + writel(RTC_CTRL_FORCE_UPDATE, &rtc_regs->hw_rtc_ctrl_clr); | |
82 | + while (readl(&rtc_regs->hw_rtc_stat) & RTC_STAT_NEW_REGS_MASK) | |
83 | + ; | |
84 | + while (readl(&rtc_regs->hw_rtc_stat) & RTC_STAT_STALE_REGS_MASK) | |
85 | + ; | |
86 | +} | |
87 | + | |
88 | +void mx28_power_set_linreg(void) | |
89 | +{ | |
90 | + struct mx28_power_regs *power_regs = | |
91 | + (struct mx28_power_regs *)MXS_POWER_BASE; | |
92 | + | |
93 | + /* Set linear regulator 25mV below switching converter */ | |
94 | + clrsetbits_le32(&power_regs->hw_power_vdddctrl, | |
95 | + POWER_VDDDCTRL_LINREG_OFFSET_MASK, | |
96 | + POWER_VDDDCTRL_LINREG_OFFSET_1STEPS_BELOW); | |
97 | + | |
98 | + clrsetbits_le32(&power_regs->hw_power_vddactrl, | |
99 | + POWER_VDDACTRL_LINREG_OFFSET_MASK, | |
100 | + POWER_VDDACTRL_LINREG_OFFSET_1STEPS_BELOW); | |
101 | + | |
102 | + clrsetbits_le32(&power_regs->hw_power_vddioctrl, | |
103 | + POWER_VDDIOCTRL_LINREG_OFFSET_MASK, | |
104 | + POWER_VDDIOCTRL_LINREG_OFFSET_1STEPS_BELOW); | |
105 | +} | |
106 | + | |
107 | +void mx28_power_setup_5v_detect(void) | |
108 | +{ | |
109 | + struct mx28_power_regs *power_regs = | |
110 | + (struct mx28_power_regs *)MXS_POWER_BASE; | |
111 | + | |
112 | + /* Start 5V detection */ | |
113 | + clrsetbits_le32(&power_regs->hw_power_5vctrl, | |
114 | + POWER_5VCTRL_VBUSVALID_TRSH_MASK, | |
115 | + POWER_5VCTRL_VBUSVALID_TRSH_4V4 | | |
116 | + POWER_5VCTRL_PWRUP_VBUS_CMPS); | |
117 | +} | |
118 | + | |
119 | +void mx28_src_power_init(void) | |
120 | +{ | |
121 | + struct mx28_power_regs *power_regs = | |
122 | + (struct mx28_power_regs *)MXS_POWER_BASE; | |
123 | + | |
124 | + /* Improve efficieny and reduce transient ripple */ | |
125 | + writel(POWER_LOOPCTRL_TOGGLE_DIF | POWER_LOOPCTRL_EN_CM_HYST | | |
126 | + POWER_LOOPCTRL_EN_DF_HYST, &power_regs->hw_power_loopctrl_set); | |
127 | + | |
128 | + clrsetbits_le32(&power_regs->hw_power_dclimits, | |
129 | + POWER_DCLIMITS_POSLIMIT_BUCK_MASK, | |
130 | + 0x30 << POWER_DCLIMITS_POSLIMIT_BUCK_OFFSET); | |
131 | + | |
132 | + setbits_le32(&power_regs->hw_power_battmonitor, | |
133 | + POWER_BATTMONITOR_EN_BATADJ); | |
134 | + | |
135 | + /* Increase the RCSCALE level for quick DCDC response to dynamic load */ | |
136 | + clrsetbits_le32(&power_regs->hw_power_loopctrl, | |
137 | + POWER_LOOPCTRL_EN_RCSCALE_MASK, | |
138 | + POWER_LOOPCTRL_RCSCALE_THRESH | | |
139 | + POWER_LOOPCTRL_EN_RCSCALE_8X); | |
140 | + | |
141 | + clrsetbits_le32(&power_regs->hw_power_minpwr, | |
142 | + POWER_MINPWR_HALFFETS, POWER_MINPWR_DOUBLE_FETS); | |
143 | + | |
144 | + /* 5V to battery handoff ... FIXME */ | |
145 | + setbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_DCDC_XFER); | |
146 | + early_delay(30); | |
147 | + clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_DCDC_XFER); | |
148 | +} | |
149 | + | |
150 | +void mx28_power_init_4p2_params(void) | |
151 | +{ | |
152 | + struct mx28_power_regs *power_regs = | |
153 | + (struct mx28_power_regs *)MXS_POWER_BASE; | |
154 | + | |
155 | + /* Setup 4P2 parameters */ | |
156 | + clrsetbits_le32(&power_regs->hw_power_dcdc4p2, | |
157 | + POWER_DCDC4P2_CMPTRIP_MASK | POWER_DCDC4P2_TRG_MASK, | |
158 | + POWER_DCDC4P2_TRG_4V2 | (31 << POWER_DCDC4P2_CMPTRIP_OFFSET)); | |
159 | + | |
160 | + clrsetbits_le32(&power_regs->hw_power_5vctrl, | |
161 | + POWER_5VCTRL_HEADROOM_ADJ_MASK, | |
162 | + 0x4 << POWER_5VCTRL_HEADROOM_ADJ_OFFSET); | |
163 | + | |
164 | + clrsetbits_le32(&power_regs->hw_power_dcdc4p2, | |
165 | + POWER_DCDC4P2_DROPOUT_CTRL_MASK, | |
166 | + POWER_DCDC4P2_DROPOUT_CTRL_100MV | | |
167 | + POWER_DCDC4P2_DROPOUT_CTRL_SRC_SEL); | |
168 | + | |
169 | + clrsetbits_le32(&power_regs->hw_power_5vctrl, | |
170 | + POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK, | |
171 | + 0x3f << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET); | |
172 | +} | |
173 | + | |
174 | +void mx28_enable_4p2_dcdc_input(int xfer) | |
175 | +{ | |
176 | + struct mx28_power_regs *power_regs = | |
177 | + (struct mx28_power_regs *)MXS_POWER_BASE; | |
178 | + uint32_t tmp, vbus_thresh, vbus_5vdetect, pwd_bo; | |
179 | + uint32_t prev_5v_brnout, prev_5v_droop; | |
180 | + | |
181 | + prev_5v_brnout = readl(&power_regs->hw_power_5vctrl) & | |
182 | + POWER_5VCTRL_PWDN_5VBRNOUT; | |
183 | + prev_5v_droop = readl(&power_regs->hw_power_ctrl) & | |
184 | + POWER_CTRL_ENIRQ_VDD5V_DROOP; | |
185 | + | |
186 | + clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_PWDN_5VBRNOUT); | |
187 | + writel(POWER_RESET_UNLOCK_KEY | POWER_RESET_PWD_OFF, | |
188 | + &power_regs->hw_power_reset); | |
189 | + | |
190 | + clrbits_le32(&power_regs->hw_power_ctrl, POWER_CTRL_ENIRQ_VDD5V_DROOP); | |
191 | + | |
192 | + if (xfer && (readl(&power_regs->hw_power_5vctrl) & | |
193 | + POWER_5VCTRL_ENABLE_DCDC)) { | |
194 | + return; | |
195 | + } | |
196 | + | |
197 | + /* | |
198 | + * Recording orignal values that will be modified temporarlily | |
199 | + * to handle a chip bug. See chip errata for CQ ENGR00115837 | |
200 | + */ | |
201 | + tmp = readl(&power_regs->hw_power_5vctrl); | |
202 | + vbus_thresh = tmp & POWER_5VCTRL_VBUSVALID_TRSH_MASK; | |
203 | + vbus_5vdetect = tmp & POWER_5VCTRL_VBUSVALID_5VDETECT; | |
204 | + | |
205 | + pwd_bo = readl(&power_regs->hw_power_minpwr) & POWER_MINPWR_PWD_BO; | |
206 | + | |
207 | + /* | |
208 | + * Disable mechanisms that get erroneously tripped by when setting | |
209 | + * the DCDC4P2 EN_DCDC | |
210 | + */ | |
211 | + clrbits_le32(&power_regs->hw_power_5vctrl, | |
212 | + POWER_5VCTRL_VBUSVALID_5VDETECT | | |
213 | + POWER_5VCTRL_VBUSVALID_TRSH_MASK); | |
214 | + | |
215 | + writel(POWER_MINPWR_PWD_BO, &power_regs->hw_power_minpwr_set); | |
216 | + | |
217 | + if (xfer) { | |
218 | + setbits_le32(&power_regs->hw_power_5vctrl, | |
219 | + POWER_5VCTRL_DCDC_XFER); | |
220 | + early_delay(20); | |
221 | + clrbits_le32(&power_regs->hw_power_5vctrl, | |
222 | + POWER_5VCTRL_DCDC_XFER); | |
223 | + | |
224 | + setbits_le32(&power_regs->hw_power_5vctrl, | |
225 | + POWER_5VCTRL_ENABLE_DCDC); | |
226 | + } else { | |
227 | + setbits_le32(&power_regs->hw_power_dcdc4p2, | |
228 | + POWER_DCDC4P2_ENABLE_DCDC); | |
229 | + } | |
230 | + | |
231 | + early_delay(25); | |
232 | + | |
233 | + clrsetbits_le32(&power_regs->hw_power_5vctrl, | |
234 | + POWER_5VCTRL_VBUSVALID_TRSH_MASK, vbus_thresh); | |
235 | + | |
236 | + if (vbus_5vdetect) | |
237 | + writel(vbus_5vdetect, &power_regs->hw_power_5vctrl_set); | |
238 | + | |
239 | + if (!pwd_bo) | |
240 | + clrbits_le32(&power_regs->hw_power_minpwr, POWER_MINPWR_PWD_BO); | |
241 | + | |
242 | + while (readl(&power_regs->hw_power_ctrl) & POWER_CTRL_VBUS_VALID_IRQ) | |
243 | + clrbits_le32(&power_regs->hw_power_ctrl, | |
244 | + POWER_CTRL_VBUS_VALID_IRQ); | |
245 | + | |
246 | + if (prev_5v_brnout) { | |
247 | + writel(POWER_5VCTRL_PWDN_5VBRNOUT, | |
248 | + &power_regs->hw_power_5vctrl_set); | |
249 | + writel(POWER_RESET_UNLOCK_KEY, | |
250 | + &power_regs->hw_power_reset); | |
251 | + } else { | |
252 | + writel(POWER_5VCTRL_PWDN_5VBRNOUT, | |
253 | + &power_regs->hw_power_5vctrl_clr); | |
254 | + writel(POWER_RESET_UNLOCK_KEY | POWER_RESET_PWD_OFF, | |
255 | + &power_regs->hw_power_reset); | |
256 | + } | |
257 | + | |
258 | + while (readl(&power_regs->hw_power_ctrl) & POWER_CTRL_VDD5V_DROOP_IRQ) | |
259 | + clrbits_le32(&power_regs->hw_power_ctrl, | |
260 | + POWER_CTRL_VDD5V_DROOP_IRQ); | |
261 | + | |
262 | + if (prev_5v_droop) | |
263 | + clrbits_le32(&power_regs->hw_power_ctrl, | |
264 | + POWER_CTRL_ENIRQ_VDD5V_DROOP); | |
265 | + else | |
266 | + setbits_le32(&power_regs->hw_power_ctrl, | |
267 | + POWER_CTRL_ENIRQ_VDD5V_DROOP); | |
268 | +} | |
269 | + | |
270 | +void mx28_power_init_4p2_regulator(void) | |
271 | +{ | |
272 | + struct mx28_power_regs *power_regs = | |
273 | + (struct mx28_power_regs *)MXS_POWER_BASE; | |
274 | + uint32_t tmp, tmp2; | |
275 | + | |
276 | + setbits_le32(&power_regs->hw_power_dcdc4p2, POWER_DCDC4P2_ENABLE_4P2); | |
277 | + | |
278 | + writel(POWER_CHARGE_ENABLE_LOAD, &power_regs->hw_power_charge_set); | |
279 | + | |
280 | + writel(POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK, | |
281 | + &power_regs->hw_power_5vctrl_clr); | |
282 | + clrbits_le32(&power_regs->hw_power_dcdc4p2, POWER_DCDC4P2_TRG_MASK); | |
283 | + | |
284 | + /* Power up the 4p2 rail and logic/control */ | |
285 | + writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK, | |
286 | + &power_regs->hw_power_5vctrl_clr); | |
287 | + | |
288 | + /* | |
289 | + * Start charging up the 4p2 capacitor. We ramp of this charge | |
290 | + * gradually to avoid large inrush current from the 5V cable which can | |
291 | + * cause transients/problems | |
292 | + */ | |
293 | + mx28_enable_4p2_dcdc_input(0); | |
294 | + | |
295 | + if (readl(&power_regs->hw_power_ctrl) & POWER_CTRL_VBUS_VALID_IRQ) { | |
296 | + /* | |
297 | + * If we arrived here, we were unable to recover from mx23 chip | |
298 | + * errata 5837. 4P2 is disabled and sufficient battery power is | |
299 | + * not present. Exiting to not enable DCDC power during 5V | |
300 | + * connected state. | |
301 | + */ | |
302 | + clrbits_le32(&power_regs->hw_power_dcdc4p2, | |
303 | + POWER_DCDC4P2_ENABLE_DCDC); | |
304 | + writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK, | |
305 | + &power_regs->hw_power_5vctrl_set); | |
306 | + hang(); | |
307 | + } | |
308 | + | |
309 | + /* | |
310 | + * Here we set the 4p2 brownout level to something very close to 4.2V. | |
311 | + * We then check the brownout status. If the brownout status is false, | |
312 | + * the voltage is already close to the target voltage of 4.2V so we | |
313 | + * can go ahead and set the 4P2 current limit to our max target limit. | |
314 | + * If the brownout status is true, we need to ramp us the current limit | |
315 | + * so that we don't cause large inrush current issues. We step up the | |
316 | + * current limit until the brownout status is false or until we've | |
317 | + * reached our maximum defined 4p2 current limit. | |
318 | + */ | |
319 | + clrsetbits_le32(&power_regs->hw_power_dcdc4p2, | |
320 | + POWER_DCDC4P2_BO_MASK, | |
321 | + 22 << POWER_DCDC4P2_BO_OFFSET); /* 4.15V */ | |
322 | + | |
323 | + if (!(readl(&power_regs->hw_power_sts) & POWER_STS_DCDC_4P2_BO)) { | |
324 | + setbits_le32(&power_regs->hw_power_5vctrl, | |
325 | + 0x3f << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET); | |
326 | + } else { | |
327 | + tmp = (readl(&power_regs->hw_power_5vctrl) & | |
328 | + POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK) >> | |
329 | + POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET; | |
330 | + while (tmp < 0x3f) { | |
331 | + if (!(readl(&power_regs->hw_power_sts) & | |
332 | + POWER_STS_DCDC_4P2_BO)) { | |
333 | + tmp = readl(&power_regs->hw_power_5vctrl); | |
334 | + tmp |= POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK; | |
335 | + early_delay(100); | |
336 | + writel(tmp, &power_regs->hw_power_5vctrl); | |
337 | + break; | |
338 | + } else { | |
339 | + tmp++; | |
340 | + tmp2 = readl(&power_regs->hw_power_5vctrl); | |
341 | + tmp2 &= ~POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK; | |
342 | + tmp2 |= tmp << | |
343 | + POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET; | |
344 | + writel(tmp2, &power_regs->hw_power_5vctrl); | |
345 | + early_delay(100); | |
346 | + } | |
347 | + } | |
348 | + } | |
349 | + | |
350 | + clrbits_le32(&power_regs->hw_power_dcdc4p2, POWER_DCDC4P2_BO_MASK); | |
351 | + writel(POWER_CTRL_DCDC4P2_BO_IRQ, &power_regs->hw_power_ctrl_clr); | |
352 | +} | |
353 | + | |
354 | +void mx28_power_init_dcdc_4p2_source(void) | |
355 | +{ | |
356 | + struct mx28_power_regs *power_regs = | |
357 | + (struct mx28_power_regs *)MXS_POWER_BASE; | |
358 | + | |
359 | + if (!(readl(&power_regs->hw_power_dcdc4p2) & | |
360 | + POWER_DCDC4P2_ENABLE_DCDC)) { | |
361 | + hang(); | |
362 | + } | |
363 | + | |
364 | + mx28_enable_4p2_dcdc_input(1); | |
365 | + | |
366 | + if (readl(&power_regs->hw_power_ctrl) & POWER_CTRL_VBUS_VALID_IRQ) { | |
367 | + clrbits_le32(&power_regs->hw_power_dcdc4p2, | |
368 | + POWER_DCDC4P2_ENABLE_DCDC); | |
369 | + writel(POWER_5VCTRL_ENABLE_DCDC, | |
370 | + &power_regs->hw_power_5vctrl_clr); | |
371 | + writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK, | |
372 | + &power_regs->hw_power_5vctrl_set); | |
373 | + } | |
374 | +} | |
375 | + | |
376 | +void mx28_power_enable_4p2(void) | |
377 | +{ | |
378 | + struct mx28_power_regs *power_regs = | |
379 | + (struct mx28_power_regs *)MXS_POWER_BASE; | |
380 | + uint32_t vdddctrl, vddactrl, vddioctrl; | |
381 | + uint32_t tmp; | |
382 | + | |
383 | + vdddctrl = readl(&power_regs->hw_power_vdddctrl); | |
384 | + vddactrl = readl(&power_regs->hw_power_vddactrl); | |
385 | + vddioctrl = readl(&power_regs->hw_power_vddioctrl); | |
386 | + | |
387 | + setbits_le32(&power_regs->hw_power_vdddctrl, | |
388 | + POWER_VDDDCTRL_DISABLE_FET | POWER_VDDDCTRL_ENABLE_LINREG | | |
389 | + POWER_VDDDCTRL_PWDN_BRNOUT); | |
390 | + | |
391 | + setbits_le32(&power_regs->hw_power_vddactrl, | |
392 | + POWER_VDDACTRL_DISABLE_FET | POWER_VDDACTRL_ENABLE_LINREG | | |
393 | + POWER_VDDACTRL_PWDN_BRNOUT); | |
394 | + | |
395 | + setbits_le32(&power_regs->hw_power_vddioctrl, | |
396 | + POWER_VDDIOCTRL_DISABLE_FET | POWER_VDDIOCTRL_PWDN_BRNOUT); | |
397 | + | |
398 | + mx28_power_init_4p2_params(); | |
399 | + mx28_power_init_4p2_regulator(); | |
400 | + | |
401 | + /* Shutdown battery (none present) */ | |
402 | + clrbits_le32(&power_regs->hw_power_dcdc4p2, POWER_DCDC4P2_BO_MASK); | |
403 | + writel(POWER_CTRL_DCDC4P2_BO_IRQ, &power_regs->hw_power_ctrl_clr); | |
404 | + writel(POWER_CTRL_ENIRQ_DCDC4P2_BO, &power_regs->hw_power_ctrl_clr); | |
405 | + | |
406 | + mx28_power_init_dcdc_4p2_source(); | |
407 | + | |
408 | + writel(vdddctrl, &power_regs->hw_power_vdddctrl); | |
409 | + early_delay(20); | |
410 | + writel(vddactrl, &power_regs->hw_power_vddactrl); | |
411 | + early_delay(20); | |
412 | + writel(vddioctrl, &power_regs->hw_power_vddioctrl); | |
413 | + | |
414 | + /* | |
415 | + * Check if FET is enabled on either powerout and if so, | |
416 | + * disable load. | |
417 | + */ | |
418 | + tmp = 0; | |
419 | + tmp |= !(readl(&power_regs->hw_power_vdddctrl) & | |
420 | + POWER_VDDDCTRL_DISABLE_FET); | |
421 | + tmp |= !(readl(&power_regs->hw_power_vddactrl) & | |
422 | + POWER_VDDACTRL_DISABLE_FET); | |
423 | + tmp |= !(readl(&power_regs->hw_power_vddioctrl) & | |
424 | + POWER_VDDIOCTRL_DISABLE_FET); | |
425 | + if (tmp) | |
426 | + writel(POWER_CHARGE_ENABLE_LOAD, | |
427 | + &power_regs->hw_power_charge_clr); | |
428 | +} | |
429 | + | |
430 | +void mx28_boot_valid_5v(void) | |
431 | +{ | |
432 | + struct mx28_power_regs *power_regs = | |
433 | + (struct mx28_power_regs *)MXS_POWER_BASE; | |
434 | + | |
435 | + /* | |
436 | + * Use VBUSVALID level instead of VDD5V_GT_VDDIO level to trigger a 5V | |
437 | + * disconnect event. FIXME | |
438 | + */ | |
439 | + writel(POWER_5VCTRL_VBUSVALID_5VDETECT, | |
440 | + &power_regs->hw_power_5vctrl_set); | |
441 | + | |
442 | + /* Configure polarity to check for 5V disconnection. */ | |
443 | + writel(POWER_CTRL_POLARITY_VBUSVALID | | |
444 | + POWER_CTRL_POLARITY_VDD5V_GT_VDDIO, | |
445 | + &power_regs->hw_power_ctrl_clr); | |
446 | + | |
447 | + writel(POWER_CTRL_VBUS_VALID_IRQ | POWER_CTRL_VDD5V_GT_VDDIO_IRQ, | |
448 | + &power_regs->hw_power_ctrl_clr); | |
449 | + | |
450 | + mx28_power_enable_4p2(); | |
451 | +} | |
452 | + | |
453 | +void mx28_powerdown(void) | |
454 | +{ | |
455 | + struct mx28_power_regs *power_regs = | |
456 | + (struct mx28_power_regs *)MXS_POWER_BASE; | |
457 | + writel(POWER_RESET_UNLOCK_KEY, &power_regs->hw_power_reset); | |
458 | + writel(POWER_RESET_UNLOCK_KEY | POWER_RESET_PWD_OFF, | |
459 | + &power_regs->hw_power_reset); | |
460 | +} | |
461 | + | |
462 | +void mx28_handle_5v_conflict(void) | |
463 | +{ | |
464 | + struct mx28_power_regs *power_regs = | |
465 | + (struct mx28_power_regs *)MXS_POWER_BASE; | |
466 | + uint32_t tmp; | |
467 | + | |
468 | + setbits_le32(&power_regs->hw_power_vddioctrl, | |
469 | + POWER_VDDIOCTRL_BO_OFFSET_MASK); | |
470 | + | |
471 | + for (;;) { | |
472 | + tmp = readl(&power_regs->hw_power_sts); | |
473 | + | |
474 | + if (tmp & POWER_STS_VDDIO_BO) { | |
475 | + mx28_powerdown(); | |
476 | + break; | |
477 | + } | |
478 | + | |
479 | + if (tmp & POWER_STS_VDD5V_GT_VDDIO) { | |
480 | + mx28_boot_valid_5v(); | |
481 | + break; | |
482 | + } else { | |
483 | + mx28_powerdown(); | |
484 | + break; | |
485 | + } | |
486 | + } | |
487 | +} | |
488 | + | |
489 | +int mx28_get_batt_volt(void) | |
490 | +{ | |
491 | + struct mx28_power_regs *power_regs = | |
492 | + (struct mx28_power_regs *)MXS_POWER_BASE; | |
493 | + uint32_t volt = readl(&power_regs->hw_power_battmonitor); | |
494 | + volt &= POWER_BATTMONITOR_BATT_VAL_MASK; | |
495 | + volt >>= POWER_BATTMONITOR_BATT_VAL_OFFSET; | |
496 | + volt *= 8; | |
497 | + return volt; | |
498 | +} | |
499 | + | |
500 | +int mx28_is_batt_ready(void) | |
501 | +{ | |
502 | + return (mx28_get_batt_volt() >= 3600); | |
503 | +} | |
504 | + | |
505 | +void mx28_5v_boot(void) | |
506 | +{ | |
507 | + struct mx28_power_regs *power_regs = | |
508 | + (struct mx28_power_regs *)MXS_POWER_BASE; | |
509 | + | |
510 | + /* | |
511 | + * NOTE: In original IMX-Bootlets, this also checks for VBUSVALID, | |
512 | + * but their implementation always returns 1 so we omit it here. | |
513 | + */ | |
514 | + if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) { | |
515 | + mx28_boot_valid_5v(); | |
516 | + return; | |
517 | + } | |
518 | + | |
519 | + early_delay(1000); | |
520 | + if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) { | |
521 | + mx28_boot_valid_5v(); | |
522 | + return; | |
523 | + } | |
524 | + | |
525 | + mx28_handle_5v_conflict(); | |
526 | +} | |
527 | + | |
528 | +void mx28_init_batt_bo(void) | |
529 | +{ | |
530 | + struct mx28_power_regs *power_regs = | |
531 | + (struct mx28_power_regs *)MXS_POWER_BASE; | |
532 | + | |
533 | + /* Brownout at 3V */ | |
534 | + clrsetbits_le32(&power_regs->hw_power_battmonitor, | |
535 | + POWER_BATTMONITOR_BRWNOUT_LVL_MASK, | |
536 | + 15 << POWER_BATTMONITOR_BRWNOUT_LVL_OFFSET); | |
537 | + | |
538 | + writel(POWER_CTRL_BATT_BO_IRQ, &power_regs->hw_power_ctrl_clr); | |
539 | + writel(POWER_CTRL_ENIRQ_BATT_BO, &power_regs->hw_power_ctrl_clr); | |
540 | +} | |
541 | + | |
542 | +void mx28_switch_vddd_to_dcdc_source(void) | |
543 | +{ | |
544 | + struct mx28_power_regs *power_regs = | |
545 | + (struct mx28_power_regs *)MXS_POWER_BASE; | |
546 | + | |
547 | + clrsetbits_le32(&power_regs->hw_power_vdddctrl, | |
548 | + POWER_VDDDCTRL_LINREG_OFFSET_MASK, | |
549 | + POWER_VDDDCTRL_LINREG_OFFSET_1STEPS_BELOW); | |
550 | + | |
551 | + clrbits_le32(&power_regs->hw_power_vdddctrl, | |
552 | + POWER_VDDDCTRL_DISABLE_FET | POWER_VDDDCTRL_ENABLE_LINREG | | |
553 | + POWER_VDDDCTRL_DISABLE_STEPPING); | |
554 | +} | |
555 | + | |
556 | +int mx28_is_batt_good(void) | |
557 | +{ | |
558 | + struct mx28_power_regs *power_regs = | |
559 | + (struct mx28_power_regs *)MXS_POWER_BASE; | |
560 | + uint32_t volt; | |
561 | + | |
562 | + volt = readl(&power_regs->hw_power_battmonitor); | |
563 | + volt &= POWER_BATTMONITOR_BATT_VAL_MASK; | |
564 | + volt >>= POWER_BATTMONITOR_BATT_VAL_OFFSET; | |
565 | + volt *= 8; | |
566 | + | |
567 | + if ((volt >= 2400) && (volt <= 4300)) | |
568 | + return 1; | |
569 | + | |
570 | + clrsetbits_le32(&power_regs->hw_power_5vctrl, | |
571 | + POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK, | |
572 | + 0x3 << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET); | |
573 | + writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK, | |
574 | + &power_regs->hw_power_5vctrl_clr); | |
575 | + | |
576 | + clrsetbits_le32(&power_regs->hw_power_charge, | |
577 | + POWER_CHARGE_STOP_ILIMIT_MASK | POWER_CHARGE_BATTCHRG_I_MASK, | |
578 | + POWER_CHARGE_STOP_ILIMIT_10MA | 0x3); | |
579 | + | |
580 | + writel(POWER_CHARGE_PWD_BATTCHRG, &power_regs->hw_power_charge_clr); | |
581 | + writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK, | |
582 | + &power_regs->hw_power_5vctrl_clr); | |
583 | + | |
584 | + early_delay(500000); | |
585 | + | |
586 | + volt = readl(&power_regs->hw_power_battmonitor); | |
587 | + volt &= POWER_BATTMONITOR_BATT_VAL_MASK; | |
588 | + volt >>= POWER_BATTMONITOR_BATT_VAL_OFFSET; | |
589 | + volt *= 8; | |
590 | + | |
591 | + if (volt >= 3500) | |
592 | + return 0; | |
593 | + | |
594 | + if (volt >= 2400) | |
595 | + return 1; | |
596 | + | |
597 | + writel(POWER_CHARGE_STOP_ILIMIT_MASK | POWER_CHARGE_BATTCHRG_I_MASK, | |
598 | + &power_regs->hw_power_charge_clr); | |
599 | + writel(POWER_CHARGE_PWD_BATTCHRG, &power_regs->hw_power_charge_set); | |
600 | + | |
601 | + return 0; | |
602 | +} | |
603 | + | |
604 | +void mx28_power_configure_power_source(void) | |
605 | +{ | |
606 | + mx28_src_power_init(); | |
607 | + | |
608 | + mx28_5v_boot(); | |
609 | + mx28_power_clock2pll(); | |
610 | + | |
611 | + mx28_init_batt_bo(); | |
612 | + mx28_switch_vddd_to_dcdc_source(); | |
613 | +} | |
614 | + | |
615 | +void mx28_enable_output_rail_protection(void) | |
616 | +{ | |
617 | + struct mx28_power_regs *power_regs = | |
618 | + (struct mx28_power_regs *)MXS_POWER_BASE; | |
619 | + | |
620 | + writel(POWER_CTRL_VDDD_BO_IRQ | POWER_CTRL_VDDA_BO_IRQ | | |
621 | + POWER_CTRL_VDDIO_BO_IRQ, &power_regs->hw_power_ctrl_clr); | |
622 | + | |
623 | + setbits_le32(&power_regs->hw_power_vdddctrl, | |
624 | + POWER_VDDDCTRL_PWDN_BRNOUT); | |
625 | + | |
626 | + setbits_le32(&power_regs->hw_power_vddactrl, | |
627 | + POWER_VDDACTRL_PWDN_BRNOUT); | |
628 | + | |
629 | + setbits_le32(&power_regs->hw_power_vddioctrl, | |
630 | + POWER_VDDIOCTRL_PWDN_BRNOUT); | |
631 | +} | |
632 | + | |
633 | +int mx28_get_vddio_power_source_off(void) | |
634 | +{ | |
635 | + struct mx28_power_regs *power_regs = | |
636 | + (struct mx28_power_regs *)MXS_POWER_BASE; | |
637 | + uint32_t tmp; | |
638 | + | |
639 | + if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) { | |
640 | + tmp = readl(&power_regs->hw_power_vddioctrl); | |
641 | + if (tmp & POWER_VDDIOCTRL_DISABLE_FET) { | |
642 | + if ((tmp & POWER_VDDIOCTRL_LINREG_OFFSET_MASK) == | |
643 | + POWER_VDDDCTRL_LINREG_OFFSET_0STEPS) { | |
644 | + return 1; | |
645 | + } | |
646 | + } | |
647 | + | |
648 | + if (!(readl(&power_regs->hw_power_5vctrl) & | |
649 | + POWER_5VCTRL_ENABLE_DCDC)) { | |
650 | + if ((tmp & POWER_VDDIOCTRL_LINREG_OFFSET_MASK) == | |
651 | + POWER_VDDDCTRL_LINREG_OFFSET_0STEPS) { | |
652 | + return 1; | |
653 | + } | |
654 | + } | |
655 | + } | |
656 | + | |
657 | + return 0; | |
658 | + | |
659 | +} | |
660 | + | |
661 | +int mx28_get_vddd_power_source_off(void) | |
662 | +{ | |
663 | + struct mx28_power_regs *power_regs = | |
664 | + (struct mx28_power_regs *)MXS_POWER_BASE; | |
665 | + uint32_t tmp; | |
666 | + | |
667 | + tmp = readl(&power_regs->hw_power_vdddctrl); | |
668 | + if (tmp & POWER_VDDDCTRL_DISABLE_FET) { | |
669 | + if ((tmp & POWER_VDDDCTRL_LINREG_OFFSET_MASK) == | |
670 | + POWER_VDDDCTRL_LINREG_OFFSET_0STEPS) { | |
671 | + return 1; | |
672 | + } | |
673 | + } | |
674 | + | |
675 | + if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) { | |
676 | + if (!(readl(&power_regs->hw_power_5vctrl) & | |
677 | + POWER_5VCTRL_ENABLE_DCDC)) { | |
678 | + return 1; | |
679 | + } | |
680 | + } | |
681 | + | |
682 | + if (!(tmp & POWER_VDDDCTRL_ENABLE_LINREG)) { | |
683 | + if ((tmp & POWER_VDDDCTRL_LINREG_OFFSET_MASK) == | |
684 | + POWER_VDDDCTRL_LINREG_OFFSET_1STEPS_BELOW) { | |
685 | + return 1; | |
686 | + } | |
687 | + } | |
688 | + | |
689 | + return 0; | |
690 | +} | |
691 | + | |
692 | +void mx28_power_set_vddio(uint32_t new_target, uint32_t new_brownout) | |
693 | +{ | |
694 | + struct mx28_power_regs *power_regs = | |
695 | + (struct mx28_power_regs *)MXS_POWER_BASE; | |
696 | + uint32_t cur_target, diff, bo_int = 0; | |
697 | + uint32_t powered_by_linreg = 0; | |
698 | + | |
699 | + new_brownout = new_target - new_brownout; | |
700 | + | |
701 | + cur_target = readl(&power_regs->hw_power_vddioctrl); | |
702 | + cur_target &= POWER_VDDIOCTRL_TRG_MASK; | |
703 | + cur_target *= 50; /* 50 mV step*/ | |
704 | + cur_target += 2800; /* 2800 mV lowest */ | |
705 | + | |
706 | + powered_by_linreg = mx28_get_vddio_power_source_off(); | |
707 | + if (new_target > cur_target) { | |
708 | + | |
709 | + if (powered_by_linreg) { | |
710 | + bo_int = readl(&power_regs->hw_power_vddioctrl); | |
711 | + clrbits_le32(&power_regs->hw_power_vddioctrl, | |
712 | + POWER_CTRL_ENIRQ_VDDIO_BO); | |
713 | + } | |
714 | + | |
715 | + setbits_le32(&power_regs->hw_power_vddioctrl, | |
716 | + POWER_VDDIOCTRL_BO_OFFSET_MASK); | |
717 | + do { | |
718 | + if (new_target - cur_target > 100) | |
719 | + diff = cur_target + 100; | |
720 | + else | |
721 | + diff = new_target; | |
722 | + | |
723 | + diff -= 2800; | |
724 | + diff /= 50; | |
725 | + | |
726 | + clrsetbits_le32(&power_regs->hw_power_vddioctrl, | |
727 | + POWER_VDDIOCTRL_TRG_MASK, diff); | |
728 | + | |
729 | + if (powered_by_linreg) | |
730 | + early_delay(1500); | |
731 | + else { | |
732 | + while (!(readl(&power_regs->hw_power_sts) & | |
733 | + POWER_STS_DC_OK)) | |
734 | + ; | |
735 | + | |
736 | + } | |
737 | + | |
738 | + cur_target = readl(&power_regs->hw_power_vddioctrl); | |
739 | + cur_target &= POWER_VDDIOCTRL_TRG_MASK; | |
740 | + cur_target *= 50; /* 50 mV step*/ | |
741 | + cur_target += 2800; /* 2800 mV lowest */ | |
742 | + } while (new_target > cur_target); | |
743 | + | |
744 | + if (powered_by_linreg) { | |
745 | + writel(POWER_CTRL_VDDIO_BO_IRQ, | |
746 | + &power_regs->hw_power_ctrl_clr); | |
747 | + if (bo_int & POWER_CTRL_ENIRQ_VDDIO_BO) | |
748 | + setbits_le32(&power_regs->hw_power_vddioctrl, | |
749 | + POWER_CTRL_ENIRQ_VDDIO_BO); | |
750 | + } | |
751 | + } else { | |
752 | + do { | |
753 | + if (cur_target - new_target > 100) | |
754 | + diff = cur_target - 100; | |
755 | + else | |
756 | + diff = new_target; | |
757 | + | |
758 | + diff -= 2800; | |
759 | + diff /= 50; | |
760 | + | |
761 | + clrsetbits_le32(&power_regs->hw_power_vddioctrl, | |
762 | + POWER_VDDIOCTRL_TRG_MASK, diff); | |
763 | + | |
764 | + if (powered_by_linreg) | |
765 | + early_delay(1500); | |
766 | + else { | |
767 | + while (!(readl(&power_regs->hw_power_sts) & | |
768 | + POWER_STS_DC_OK)) | |
769 | + ; | |
770 | + | |
771 | + } | |
772 | + | |
773 | + cur_target = readl(&power_regs->hw_power_vddioctrl); | |
774 | + cur_target &= POWER_VDDIOCTRL_TRG_MASK; | |
775 | + cur_target *= 50; /* 50 mV step*/ | |
776 | + cur_target += 2800; /* 2800 mV lowest */ | |
777 | + } while (new_target < cur_target); | |
778 | + } | |
779 | + | |
780 | + clrsetbits_le32(&power_regs->hw_power_vddioctrl, | |
781 | + POWER_VDDDCTRL_BO_OFFSET_MASK, | |
782 | + new_brownout << POWER_VDDDCTRL_BO_OFFSET_OFFSET); | |
783 | +} | |
784 | + | |
785 | +void mx28_power_set_vddd(uint32_t new_target, uint32_t new_brownout) | |
786 | +{ | |
787 | + struct mx28_power_regs *power_regs = | |
788 | + (struct mx28_power_regs *)MXS_POWER_BASE; | |
789 | + uint32_t cur_target, diff, bo_int = 0; | |
790 | + uint32_t powered_by_linreg = 0; | |
791 | + | |
792 | + new_brownout = new_target - new_brownout; | |
793 | + | |
794 | + cur_target = readl(&power_regs->hw_power_vdddctrl); | |
795 | + cur_target &= POWER_VDDDCTRL_TRG_MASK; | |
796 | + cur_target *= 25; /* 25 mV step*/ | |
797 | + cur_target += 800; /* 800 mV lowest */ | |
798 | + | |
799 | + powered_by_linreg = mx28_get_vddd_power_source_off(); | |
800 | + if (new_target > cur_target) { | |
801 | + if (powered_by_linreg) { | |
802 | + bo_int = readl(&power_regs->hw_power_vdddctrl); | |
803 | + clrbits_le32(&power_regs->hw_power_vdddctrl, | |
804 | + POWER_CTRL_ENIRQ_VDDD_BO); | |
805 | + } | |
806 | + | |
807 | + setbits_le32(&power_regs->hw_power_vdddctrl, | |
808 | + POWER_VDDDCTRL_BO_OFFSET_MASK); | |
809 | + | |
810 | + do { | |
811 | + if (new_target - cur_target > 100) | |
812 | + diff = cur_target + 100; | |
813 | + else | |
814 | + diff = new_target; | |
815 | + | |
816 | + diff -= 800; | |
817 | + diff /= 25; | |
818 | + | |
819 | + clrsetbits_le32(&power_regs->hw_power_vdddctrl, | |
820 | + POWER_VDDDCTRL_TRG_MASK, diff); | |
821 | + | |
822 | + if (powered_by_linreg) | |
823 | + early_delay(1500); | |
824 | + else { | |
825 | + while (!(readl(&power_regs->hw_power_sts) & | |
826 | + POWER_STS_DC_OK)) | |
827 | + ; | |
828 | + | |
829 | + } | |
830 | + | |
831 | + cur_target = readl(&power_regs->hw_power_vdddctrl); | |
832 | + cur_target &= POWER_VDDDCTRL_TRG_MASK; | |
833 | + cur_target *= 25; /* 25 mV step*/ | |
834 | + cur_target += 800; /* 800 mV lowest */ | |
835 | + } while (new_target > cur_target); | |
836 | + | |
837 | + if (powered_by_linreg) { | |
838 | + writel(POWER_CTRL_VDDD_BO_IRQ, | |
839 | + &power_regs->hw_power_ctrl_clr); | |
840 | + if (bo_int & POWER_CTRL_ENIRQ_VDDD_BO) | |
841 | + setbits_le32(&power_regs->hw_power_vdddctrl, | |
842 | + POWER_CTRL_ENIRQ_VDDD_BO); | |
843 | + } | |
844 | + } else { | |
845 | + do { | |
846 | + if (cur_target - new_target > 100) | |
847 | + diff = cur_target - 100; | |
848 | + else | |
849 | + diff = new_target; | |
850 | + | |
851 | + diff -= 800; | |
852 | + diff /= 25; | |
853 | + | |
854 | + clrsetbits_le32(&power_regs->hw_power_vdddctrl, | |
855 | + POWER_VDDDCTRL_TRG_MASK, diff); | |
856 | + | |
857 | + if (powered_by_linreg) | |
858 | + early_delay(1500); | |
859 | + else { | |
860 | + while (!(readl(&power_regs->hw_power_sts) & | |
861 | + POWER_STS_DC_OK)) | |
862 | + ; | |
863 | + | |
864 | + } | |
865 | + | |
866 | + cur_target = readl(&power_regs->hw_power_vdddctrl); | |
867 | + cur_target &= POWER_VDDDCTRL_TRG_MASK; | |
868 | + cur_target *= 25; /* 25 mV step*/ | |
869 | + cur_target += 800; /* 800 mV lowest */ | |
870 | + } while (new_target < cur_target); | |
871 | + } | |
872 | + | |
873 | + clrsetbits_le32(&power_regs->hw_power_vdddctrl, | |
874 | + POWER_VDDDCTRL_BO_OFFSET_MASK, | |
875 | + new_brownout << POWER_VDDDCTRL_BO_OFFSET_OFFSET); | |
876 | +} | |
877 | + | |
878 | +void mx28_power_init(void) | |
879 | +{ | |
880 | + struct mx28_power_regs *power_regs = | |
881 | + (struct mx28_power_regs *)MXS_POWER_BASE; | |
882 | + | |
883 | + mx28_power_clock2xtal(); | |
884 | + mx28_power_clear_auto_restart(); | |
885 | + mx28_power_set_linreg(); | |
886 | + mx28_power_setup_5v_detect(); | |
887 | + mx28_power_configure_power_source(); | |
888 | + mx28_enable_output_rail_protection(); | |
889 | + | |
890 | + mx28_power_set_vddio(3300, 3150); | |
891 | + | |
892 | + mx28_power_set_vddd(1350, 1200); | |
893 | + | |
894 | + writel(POWER_CTRL_VDDD_BO_IRQ | POWER_CTRL_VDDA_BO_IRQ | | |
895 | + POWER_CTRL_VDDIO_BO_IRQ | POWER_CTRL_VDD5V_DROOP_IRQ | | |
896 | + POWER_CTRL_VBUS_VALID_IRQ | POWER_CTRL_BATT_BO_IRQ | | |
897 | + POWER_CTRL_DCDC4P2_BO_IRQ, &power_regs->hw_power_ctrl_clr); | |
898 | + | |
899 | + writel(POWER_5VCTRL_PWDN_5VBRNOUT, &power_regs->hw_power_5vctrl_set); | |
900 | + | |
901 | + early_delay(1000); | |
902 | +} | |
903 | + | |
904 | +#ifdef CONFIG_SPL_MX28_PSWITCH_WAIT | |
905 | +void mx28_power_wait_pswitch(void) | |
906 | +{ | |
907 | + struct mx28_power_regs *power_regs = | |
908 | + (struct mx28_power_regs *)MXS_POWER_BASE; | |
909 | + | |
910 | + while (!(readl(&power_regs->hw_power_sts) & POWER_STS_PSWITCH_MASK)) | |
911 | + ; | |
912 | +} | |
913 | +#endif |
board/denx/m28evk/start.S
1 | +/* | |
2 | + * armboot - Startup Code for ARM926EJS CPU-core | |
3 | + * | |
4 | + * Copyright (c) 2003 Texas Instruments | |
5 | + * | |
6 | + * ----- Adapted for OMAP1610 OMAP730 from ARM925t code ------ | |
7 | + * | |
8 | + * Copyright (c) 2001 Marius Groger <mag@sysgo.de> | |
9 | + * Copyright (c) 2002 Alex Zupke <azu@sysgo.de> | |
10 | + * Copyright (c) 2002 Gary Jennejohn <garyj@denx.de> | |
11 | + * Copyright (c) 2003 Richard Woodruff <r-woodruff2@ti.com> | |
12 | + * Copyright (c) 2003 Kshitij <kshitij@ti.com> | |
13 | + * Copyright (c) 2010 Albert Aribaud <albert.u.boot@aribaud.net> | |
14 | + * | |
15 | + * Change to support call back into iMX28 bootrom | |
16 | + * Copyright (c) 2011 Marek Vasut <marek.vasut@gmail.com> | |
17 | + * on behalf of DENX Software Engineering GmbH | |
18 | + * | |
19 | + * See file CREDITS for list of people who contributed to this | |
20 | + * project. | |
21 | + * | |
22 | + * This program is free software; you can redistribute it and/or | |
23 | + * modify it under the terms of the GNU General Public License as | |
24 | + * published by the Free Software Foundation; either version 2 of | |
25 | + * the License, or (at your option) any later version. | |
26 | + * | |
27 | + * This program is distributed in the hope that it will be useful, | |
28 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
29 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
30 | + * GNU General Public License for more details. | |
31 | + * | |
32 | + * You should have received a copy of the GNU General Public License | |
33 | + * along with this program; if not, write to the Free Software | |
34 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
35 | + * MA 02111-1307 USA | |
36 | + */ | |
37 | + | |
38 | +#include <asm-offsets.h> | |
39 | +#include <config.h> | |
40 | +#include <common.h> | |
41 | +#include <version.h> | |
42 | + | |
43 | +#if defined(CONFIG_OMAP1610) | |
44 | +#include <./configs/omap1510.h> | |
45 | +#elif defined(CONFIG_OMAP730) | |
46 | +#include <./configs/omap730.h> | |
47 | +#endif | |
48 | + | |
49 | +/* | |
50 | + ************************************************************************* | |
51 | + * | |
52 | + * Jump vector table as in table 3.1 in [1] | |
53 | + * | |
54 | + ************************************************************************* | |
55 | + */ | |
56 | + | |
57 | + | |
58 | +.globl _start | |
59 | +_start: | |
60 | + b reset | |
61 | +#ifdef CONFIG_SPL_BUILD | |
62 | +/* No exception handlers in preloader */ | |
63 | + ldr pc, _hang | |
64 | + ldr pc, _hang | |
65 | + ldr pc, _hang | |
66 | + ldr pc, _hang | |
67 | + b reset | |
68 | + ldr pc, _hang | |
69 | + ldr pc, _hang | |
70 | + | |
71 | +_hang: | |
72 | + .word do_hang | |
73 | +/* pad to 64 byte boundary */ | |
74 | + .word 0x12345678 | |
75 | + .word 0x12345678 | |
76 | + .word 0x12345678 | |
77 | + .word 0x12345678 | |
78 | + .word 0x12345678 | |
79 | + .word 0x12345678 | |
80 | + .word 0x12345678 | |
81 | +#else | |
82 | + ldr pc, _undefined_instruction | |
83 | + ldr pc, _software_interrupt | |
84 | + ldr pc, _prefetch_abort | |
85 | + ldr pc, _data_abort | |
86 | + ldr pc, _not_used | |
87 | + ldr pc, _irq | |
88 | + ldr pc, _fiq | |
89 | + | |
90 | +_undefined_instruction: | |
91 | + .word undefined_instruction | |
92 | +_software_interrupt: | |
93 | + .word software_interrupt | |
94 | +_prefetch_abort: | |
95 | + .word prefetch_abort | |
96 | +_data_abort: | |
97 | + .word data_abort | |
98 | +_not_used: | |
99 | + .word not_used | |
100 | +_irq: | |
101 | + .word irq | |
102 | +_fiq: | |
103 | + .word fiq | |
104 | + | |
105 | +#endif /* CONFIG_SPL_BUILD */ | |
106 | + .balignl 16,0xdeadbeef | |
107 | + | |
108 | + | |
109 | +/* | |
110 | + ************************************************************************* | |
111 | + * | |
112 | + * Startup Code (reset vector) | |
113 | + * | |
114 | + * do important init only if we don't start from memory! | |
115 | + * setup Memory and board specific bits prior to relocation. | |
116 | + * relocate armboot to ram | |
117 | + * setup stack | |
118 | + * | |
119 | + ************************************************************************* | |
120 | + */ | |
121 | + | |
122 | +.globl _TEXT_BASE | |
123 | +_TEXT_BASE: | |
124 | + .word CONFIG_SYS_TEXT_BASE | |
125 | + | |
126 | +/* | |
127 | + * These are defined in the board-specific linker script. | |
128 | + * Subtracting _start from them lets the linker put their | |
129 | + * relative position in the executable instead of leaving | |
130 | + * them null. | |
131 | + */ | |
132 | +.globl _bss_start_ofs | |
133 | +_bss_start_ofs: | |
134 | + .word __bss_start - _start | |
135 | + | |
136 | +.globl _bss_end_ofs | |
137 | +_bss_end_ofs: | |
138 | + .word __bss_end__ - _start | |
139 | + | |
140 | +.globl _end_ofs | |
141 | +_end_ofs: | |
142 | + .word _end - _start | |
143 | + | |
144 | +#ifdef CONFIG_USE_IRQ | |
145 | +/* IRQ stack memory (calculated at run-time) */ | |
146 | +.globl IRQ_STACK_START | |
147 | +IRQ_STACK_START: | |
148 | + .word 0x0badc0de | |
149 | + | |
150 | +/* IRQ stack memory (calculated at run-time) */ | |
151 | +.globl FIQ_STACK_START | |
152 | +FIQ_STACK_START: | |
153 | + .word 0x0badc0de | |
154 | +#endif | |
155 | + | |
156 | +/* IRQ stack memory (calculated at run-time) + 8 bytes */ | |
157 | +.globl IRQ_STACK_START_IN | |
158 | +IRQ_STACK_START_IN: | |
159 | + .word 0x0badc0de | |
160 | + | |
161 | +/* | |
162 | + * the actual reset code | |
163 | + */ | |
164 | + | |
165 | +reset: | |
166 | + /* | |
167 | + * Store all registers on old stack pointer, this will allow us later to | |
168 | + * return to the BootROM and let the BootROM load U-Boot into RAM. | |
169 | + */ | |
170 | + push {r0-r12,r14} | |
171 | + | |
172 | + /* | |
173 | + * set the cpu to SVC32 mode | |
174 | + */ | |
175 | + mrs r0,cpsr | |
176 | + bic r0,r0,#0x1f | |
177 | + orr r0,r0,#0xd3 | |
178 | + msr cpsr,r0 | |
179 | + | |
180 | + /* | |
181 | + * we do sys-critical inits only at reboot, | |
182 | + * not when booting from ram! | |
183 | + */ | |
184 | +#ifndef CONFIG_SKIP_LOWLEVEL_INIT | |
185 | + bl cpu_init_crit | |
186 | +#endif | |
187 | + | |
188 | + bl board_init_ll | |
189 | + | |
190 | + pop {r0-r12,r14} | |
191 | + bx lr | |
192 | + | |
193 | +/* | |
194 | + ************************************************************************* | |
195 | + * | |
196 | + * CPU_init_critical registers | |
197 | + * | |
198 | + * setup important registers | |
199 | + * setup memory timing | |
200 | + * | |
201 | + ************************************************************************* | |
202 | + */ | |
203 | +#ifndef CONFIG_SKIP_LOWLEVEL_INIT | |
204 | +cpu_init_crit: | |
205 | + /* | |
206 | + * flush v4 I/D caches | |
207 | + */ | |
208 | + mov r0, #0 | |
209 | + mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */ | |
210 | + mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */ | |
211 | + | |
212 | + /* | |
213 | + * disable MMU stuff and caches | |
214 | + */ | |
215 | + mrc p15, 0, r0, c1, c0, 0 | |
216 | + bic r0, r0, #0x00002300 /* clear bits 13, 9:8 (--V- --RS) */ | |
217 | + bic r0, r0, #0x00000087 /* clear bits 7, 2:0 (B--- -CAM) */ | |
218 | + orr r0, r0, #0x00000002 /* set bit 2 (A) Align */ | |
219 | + orr r0, r0, #0x00001000 /* set bit 12 (I) I-Cache */ | |
220 | + mcr p15, 0, r0, c1, c0, 0 | |
221 | + | |
222 | + mov pc, lr /* back to my caller */ | |
223 | +#endif /* CONFIG_SKIP_LOWLEVEL_INIT */ | |
224 | + | |
225 | +#ifndef CONFIG_SPL_BUILD | |
226 | +/* | |
227 | + ************************************************************************* | |
228 | + * | |
229 | + * Interrupt handling | |
230 | + * | |
231 | + ************************************************************************* | |
232 | + */ | |
233 | + | |
234 | +@ | |
235 | +@ IRQ stack frame. | |
236 | +@ | |
237 | +#define S_FRAME_SIZE 72 | |
238 | + | |
239 | +#define S_OLD_R0 68 | |
240 | +#define S_PSR 64 | |
241 | +#define S_PC 60 | |
242 | +#define S_LR 56 | |
243 | +#define S_SP 52 | |
244 | + | |
245 | +#define S_IP 48 | |
246 | +#define S_FP 44 | |
247 | +#define S_R10 40 | |
248 | +#define S_R9 36 | |
249 | +#define S_R8 32 | |
250 | +#define S_R7 28 | |
251 | +#define S_R6 24 | |
252 | +#define S_R5 20 | |
253 | +#define S_R4 16 | |
254 | +#define S_R3 12 | |
255 | +#define S_R2 8 | |
256 | +#define S_R1 4 | |
257 | +#define S_R0 0 | |
258 | + | |
259 | +#define MODE_SVC 0x13 | |
260 | +#define I_BIT 0x80 | |
261 | + | |
262 | +/* | |
263 | + * use bad_save_user_regs for abort/prefetch/undef/swi ... | |
264 | + * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling | |
265 | + */ | |
266 | + | |
267 | + .macro bad_save_user_regs | |
268 | + @ carve out a frame on current user stack | |
269 | + sub sp, sp, #S_FRAME_SIZE | |
270 | + stmia sp, {r0 - r12} @ Save user registers (now in svc mode) r0-r12 | |
271 | + ldr r2, IRQ_STACK_START_IN | |
272 | + @ get values for "aborted" pc and cpsr (into parm regs) | |
273 | + ldmia r2, {r2 - r3} | |
274 | + add r0, sp, #S_FRAME_SIZE @ grab pointer to old stack | |
275 | + add r5, sp, #S_SP | |
276 | + mov r1, lr | |
277 | + stmia r5, {r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr | |
278 | + mov r0, sp @ save current stack into r0 (param register) | |
279 | + .endm | |
280 | + | |
281 | + .macro irq_save_user_regs | |
282 | + sub sp, sp, #S_FRAME_SIZE | |
283 | + stmia sp, {r0 - r12} @ Calling r0-r12 | |
284 | + @ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good. | |
285 | + add r8, sp, #S_PC | |
286 | + stmdb r8, {sp, lr}^ @ Calling SP, LR | |
287 | + str lr, [r8, #0] @ Save calling PC | |
288 | + mrs r6, spsr | |
289 | + str r6, [r8, #4] @ Save CPSR | |
290 | + str r0, [r8, #8] @ Save OLD_R0 | |
291 | + mov r0, sp | |
292 | + .endm | |
293 | + | |
294 | + .macro irq_restore_user_regs | |
295 | + ldmia sp, {r0 - lr}^ @ Calling r0 - lr | |
296 | + mov r0, r0 | |
297 | + ldr lr, [sp, #S_PC] @ Get PC | |
298 | + add sp, sp, #S_FRAME_SIZE | |
299 | + subs pc, lr, #4 @ return & move spsr_svc into cpsr | |
300 | + .endm | |
301 | + | |
302 | + .macro get_bad_stack | |
303 | + ldr r13, IRQ_STACK_START_IN @ setup our mode stack | |
304 | + | |
305 | + str lr, [r13] @ save caller lr in position 0 of saved stack | |
306 | + mrs lr, spsr @ get the spsr | |
307 | + str lr, [r13, #4] @ save spsr in position 1 of saved stack | |
308 | + mov r13, #MODE_SVC @ prepare SVC-Mode | |
309 | + @ msr spsr_c, r13 | |
310 | + msr spsr, r13 @ switch modes, make sure moves will execute | |
311 | + mov lr, pc @ capture return pc | |
312 | + movs pc, lr @ jump to next instruction & switch modes. | |
313 | + .endm | |
314 | + | |
315 | + .macro get_irq_stack @ setup IRQ stack | |
316 | + ldr sp, IRQ_STACK_START | |
317 | + .endm | |
318 | + | |
319 | + .macro get_fiq_stack @ setup FIQ stack | |
320 | + ldr sp, FIQ_STACK_START | |
321 | + .endm | |
322 | +#endif /* CONFIG_SPL_BUILD */ | |
323 | + | |
324 | +/* | |
325 | + * exception handlers | |
326 | + */ | |
327 | +#ifdef CONFIG_SPL_BUILD | |
328 | + .align 5 | |
329 | +do_hang: | |
330 | + ldr sp, _TEXT_BASE /* switch to abort stack */ | |
331 | +1: | |
332 | + bl 1b /* hang and never return */ | |
333 | +#else /* !CONFIG_SPL_BUILD */ | |
334 | + .align 5 | |
335 | +undefined_instruction: | |
336 | + get_bad_stack | |
337 | + bad_save_user_regs | |
338 | + bl do_undefined_instruction | |
339 | + | |
340 | + .align 5 | |
341 | +software_interrupt: | |
342 | + get_bad_stack | |
343 | + bad_save_user_regs | |
344 | + bl do_software_interrupt | |
345 | + | |
346 | + .align 5 | |
347 | +prefetch_abort: | |
348 | + get_bad_stack | |
349 | + bad_save_user_regs | |
350 | + bl do_prefetch_abort | |
351 | + | |
352 | + .align 5 | |
353 | +data_abort: | |
354 | + get_bad_stack | |
355 | + bad_save_user_regs | |
356 | + bl do_data_abort | |
357 | + | |
358 | + .align 5 | |
359 | +not_used: | |
360 | + get_bad_stack | |
361 | + bad_save_user_regs | |
362 | + bl do_not_used | |
363 | + | |
364 | +#ifdef CONFIG_USE_IRQ | |
365 | + | |
366 | + .align 5 | |
367 | +irq: | |
368 | + get_irq_stack | |
369 | + irq_save_user_regs | |
370 | + bl do_irq | |
371 | + irq_restore_user_regs | |
372 | + | |
373 | + .align 5 | |
374 | +fiq: | |
375 | + get_fiq_stack | |
376 | + /* someone ought to write a more effiction fiq_save_user_regs */ | |
377 | + irq_save_user_regs | |
378 | + bl do_fiq | |
379 | + irq_restore_user_regs | |
380 | + | |
381 | +#else | |
382 | + | |
383 | + .align 5 | |
384 | +irq: | |
385 | + get_bad_stack | |
386 | + bad_save_user_regs | |
387 | + bl do_irq | |
388 | + | |
389 | + .align 5 | |
390 | +fiq: | |
391 | + get_bad_stack | |
392 | + bad_save_user_regs | |
393 | + bl do_fiq | |
394 | + | |
395 | +#endif | |
396 | +#endif /* CONFIG_SPL_BUILD */ |
board/denx/m28evk/u-boot-spl.lds
1 | +/* | |
2 | + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> | |
3 | + * on behalf of DENX Software Engineering GmbH | |
4 | + * | |
5 | + * January 2004 - Changed to support H4 device | |
6 | + * Copyright (c) 2004-2008 Texas Instruments | |
7 | + * | |
8 | + * (C) Copyright 2002 | |
9 | + * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de> | |
10 | + * | |
11 | + * See file CREDITS for list of people who contributed to this | |
12 | + * project. | |
13 | + * | |
14 | + * This program is free software; you can redistribute it and/or | |
15 | + * modify it under the terms of the GNU General Public License as | |
16 | + * published by the Free Software Foundation; either version 2 of | |
17 | + * the License, or (at your option) any later version. | |
18 | + * | |
19 | + * This program is distributed in the hope that it will be useful, | |
20 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
21 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
22 | + * GNU General Public License for more details. | |
23 | + * | |
24 | + * You should have received a copy of the GNU General Public License | |
25 | + * along with this program; if not, write to the Free Software | |
26 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
27 | + * MA 02111-1307 USA | |
28 | + */ | |
29 | + | |
30 | +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") | |
31 | +OUTPUT_ARCH(arm) | |
32 | +ENTRY(_start) | |
33 | +SECTIONS | |
34 | +{ | |
35 | + . = 0x00000000; | |
36 | + | |
37 | + . = ALIGN(4); | |
38 | + .text : | |
39 | + { | |
40 | + board/denx/m28evk/start.o (.text) | |
41 | + *(.text) | |
42 | + } | |
43 | + | |
44 | + . = ALIGN(4); | |
45 | + .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } | |
46 | + | |
47 | + . = ALIGN(4); | |
48 | + .data : { | |
49 | + *(.data) | |
50 | + } | |
51 | + | |
52 | + . = ALIGN(4); | |
53 | + __u_boot_cmd_start = .; | |
54 | + .u_boot_cmd : { *(.u_boot_cmd) } | |
55 | + __u_boot_cmd_end = .; | |
56 | + | |
57 | + . = ALIGN(4); | |
58 | + | |
59 | + .rel.dyn : { | |
60 | + __rel_dyn_start = .; | |
61 | + *(.rel*) | |
62 | + __rel_dyn_end = .; | |
63 | + } | |
64 | + | |
65 | + .dynsym : { | |
66 | + __dynsym_start = .; | |
67 | + *(.dynsym) | |
68 | + } | |
69 | + | |
70 | + _end = .; | |
71 | + | |
72 | + .bss __rel_dyn_start (OVERLAY) : { | |
73 | + __bss_start = .; | |
74 | + *(.bss) | |
75 | + . = ALIGN(4); | |
76 | + __bss_end__ = .; | |
77 | + } | |
78 | + | |
79 | + /DISCARD/ : { *(.bss*) } | |
80 | + /DISCARD/ : { *(.dynstr*) } | |
81 | + /DISCARD/ : { *(.dynsym*) } | |
82 | + /DISCARD/ : { *(.dynamic*) } | |
83 | + /DISCARD/ : { *(.hash*) } | |
84 | + /DISCARD/ : { *(.plt*) } | |
85 | + /DISCARD/ : { *(.interp*) } | |
86 | + /DISCARD/ : { *(.gnu*) } | |
87 | +} |
board/denx/m28evk/u-boot.bd
1 | +sources { | |
2 | + u_boot_spl="spl/u-boot-spl.bin"; | |
3 | + u_boot="u-boot.bin"; | |
4 | +} | |
5 | + | |
6 | +section (0) { | |
7 | + load u_boot_spl > 0x0000; | |
8 | + load ivt (entry = 0x0014) > 0x8000; | |
9 | + hab call 0x8000; | |
10 | + | |
11 | + load u_boot > 0x40000100; | |
12 | + load ivt (entry = 0x40000100) > 0x8000; | |
13 | + hab call 0x8000; | |
14 | +} |
include/configs/m28evk.h
... | ... | @@ -43,6 +43,14 @@ |
43 | 43 | #define CONFIG_ARCH_CPU_INIT |
44 | 44 | |
45 | 45 | /* |
46 | + * SPL | |
47 | + */ | |
48 | +#define CONFIG_SPL | |
49 | +#define CONFIG_SPL_NO_CPU_SUPPORT_CODE | |
50 | +#define CONFIG_SPL_START_S_PATH "board/denx/m28evk" | |
51 | +#define CONFIG_SPL_LDSCRIPT "board/denx/m28evk/u-boot-spl.lds" | |
52 | + | |
53 | +/* | |
46 | 54 | * U-Boot Commands |
47 | 55 | */ |
48 | 56 | #include <config_cmd_default.h> |