]>
Commit | Line | Data |
---|---|---|
81e35203 CK |
1 | /* |
2 | * Copyright (C) 2012 Samsung Electronics | |
3 | * | |
1a459660 | 4 | * SPDX-License-Identifier: GPL-2.0+ |
81e35203 CK |
5 | */ |
6 | ||
4b9ca093 VG |
7 | #include <common.h> |
8 | #include <config.h> | |
81e35203 | 9 | |
c748be0d A |
10 | #include <asm/arch/clock.h> |
11 | #include <asm/arch/clk.h> | |
643be9c0 | 12 | #include <asm/arch/dmc.h> |
347e45d7 RS |
13 | #include <asm/arch/periph.h> |
14 | #include <asm/arch/pinmux.h> | |
643be9c0 | 15 | #include <asm/arch/power.h> |
493c073f | 16 | #include <asm/arch/spl.h> |
347e45d7 | 17 | #include <asm/arch/spi.h> |
c748be0d | 18 | |
643be9c0 | 19 | #include "common_setup.h" |
c748be0d A |
20 | #include "clock_init.h" |
21 | ||
643be9c0 | 22 | DECLARE_GLOBAL_DATA_PTR; |
643be9c0 | 23 | |
c748be0d A |
24 | /* Index into irom ptr table */ |
25 | enum index { | |
26 | MMC_INDEX, | |
27 | EMMC44_INDEX, | |
28 | EMMC44_END_INDEX, | |
29 | SPI_INDEX, | |
30 | USB_INDEX, | |
31 | }; | |
32 | ||
33 | /* IROM Function Pointers Table */ | |
34 | u32 irom_ptr_table[] = { | |
35 | [MMC_INDEX] = 0x02020030, /* iROM Function Pointer-SDMMC boot */ | |
36 | [EMMC44_INDEX] = 0x02020044, /* iROM Function Pointer-EMMC4.4 boot*/ | |
37 | [EMMC44_END_INDEX] = 0x02020048,/* iROM Function Pointer | |
38 | -EMMC4.4 end boot operation */ | |
39 | [SPI_INDEX] = 0x02020058, /* iROM Function Pointer-SPI boot */ | |
40 | [USB_INDEX] = 0x02020070, /* iROM Function Pointer-USB boot*/ | |
41 | }; | |
42 | ||
c748be0d A |
43 | void *get_irom_func(int index) |
44 | { | |
45 | return (void *)*(u32 *)irom_ptr_table[index]; | |
46 | } | |
70656c79 | 47 | |
643be9c0 | 48 | #ifdef CONFIG_USB_BOOTING |
70656c79 VG |
49 | /* |
50 | * Set/clear program flow prediction and return the previous state. | |
51 | */ | |
52 | static int config_branch_prediction(int set_cr_z) | |
53 | { | |
54 | unsigned int cr; | |
55 | ||
56 | /* System Control Register: 11th bit Z Branch prediction enable */ | |
57 | cr = get_cr(); | |
58 | set_cr(set_cr_z ? cr | CR_Z : cr & ~CR_Z); | |
59 | ||
60 | return cr & CR_Z; | |
61 | } | |
643be9c0 | 62 | #endif |
7a533773 | 63 | |
d8fa31a7 | 64 | #ifdef CONFIG_SPI_BOOTING |
347e45d7 RS |
65 | static void spi_rx_tx(struct exynos_spi *regs, int todo, |
66 | void *dinp, void const *doutp, int i) | |
67 | { | |
68 | uint *rxp = (uint *)(dinp + (i * (32 * 1024))); | |
69 | int rx_lvl, tx_lvl; | |
70 | uint out_bytes, in_bytes; | |
71 | ||
72 | out_bytes = todo; | |
73 | in_bytes = todo; | |
74 | setbits_le32(®s->ch_cfg, SPI_CH_RST); | |
75 | clrbits_le32(®s->ch_cfg, SPI_CH_RST); | |
76 | writel(((todo * 8) / 32) | SPI_PACKET_CNT_EN, ®s->pkt_cnt); | |
77 | ||
78 | while (in_bytes) { | |
79 | uint32_t spi_sts; | |
80 | int temp; | |
81 | ||
82 | spi_sts = readl(®s->spi_sts); | |
83 | rx_lvl = ((spi_sts >> 15) & 0x7f); | |
84 | tx_lvl = ((spi_sts >> 6) & 0x7f); | |
85 | while (tx_lvl < 32 && out_bytes) { | |
86 | temp = 0xffffffff; | |
87 | writel(temp, ®s->tx_data); | |
88 | out_bytes -= 4; | |
89 | tx_lvl += 4; | |
90 | } | |
91 | while (rx_lvl >= 4 && in_bytes) { | |
92 | temp = readl(®s->rx_data); | |
93 | if (rxp) | |
94 | *rxp++ = temp; | |
95 | in_bytes -= 4; | |
96 | rx_lvl -= 4; | |
97 | } | |
98 | } | |
99 | } | |
100 | ||
101 | /* | |
102 | * Copy uboot from spi flash to RAM | |
103 | * | |
104 | * @parma uboot_size size of u-boot to copy | |
105 | * @param uboot_addr address in u-boot to copy | |
106 | */ | |
107 | static void exynos_spi_copy(unsigned int uboot_size, unsigned int uboot_addr) | |
108 | { | |
109 | int upto, todo; | |
110 | int i, timeout = 100; | |
111 | struct exynos_spi *regs = (struct exynos_spi *)CONFIG_ENV_SPI_BASE; | |
112 | ||
113 | set_spi_clk(PERIPH_ID_SPI1, 50000000); /* set spi clock to 50Mhz */ | |
114 | /* set the spi1 GPIO */ | |
115 | exynos_pinmux_config(PERIPH_ID_SPI1, PINMUX_FLAG_NONE); | |
116 | ||
117 | /* set pktcnt and enable it */ | |
118 | writel(4 | SPI_PACKET_CNT_EN, ®s->pkt_cnt); | |
119 | /* set FB_CLK_SEL */ | |
120 | writel(SPI_FB_DELAY_180, ®s->fb_clk); | |
121 | /* set CH_WIDTH and BUS_WIDTH as word */ | |
122 | setbits_le32(®s->mode_cfg, SPI_MODE_CH_WIDTH_WORD | | |
123 | SPI_MODE_BUS_WIDTH_WORD); | |
124 | clrbits_le32(®s->ch_cfg, SPI_CH_CPOL_L); /* CPOL: active high */ | |
125 | ||
126 | /* clear rx and tx channel if set priveously */ | |
127 | clrbits_le32(®s->ch_cfg, SPI_RX_CH_ON | SPI_TX_CH_ON); | |
128 | ||
129 | setbits_le32(®s->swap_cfg, SPI_RX_SWAP_EN | | |
130 | SPI_RX_BYTE_SWAP | | |
131 | SPI_RX_HWORD_SWAP); | |
132 | ||
133 | /* do a soft reset */ | |
134 | setbits_le32(®s->ch_cfg, SPI_CH_RST); | |
135 | clrbits_le32(®s->ch_cfg, SPI_CH_RST); | |
136 | ||
137 | /* now set rx and tx channel ON */ | |
138 | setbits_le32(®s->ch_cfg, SPI_RX_CH_ON | SPI_TX_CH_ON | SPI_CH_HS_EN); | |
139 | clrbits_le32(®s->cs_reg, SPI_SLAVE_SIG_INACT); /* CS low */ | |
140 | ||
141 | /* Send read instruction (0x3h) followed by a 24 bit addr */ | |
142 | writel((SF_READ_DATA_CMD << 24) | SPI_FLASH_UBOOT_POS, ®s->tx_data); | |
143 | ||
144 | /* waiting for TX done */ | |
145 | while (!(readl(®s->spi_sts) & SPI_ST_TX_DONE)) { | |
146 | if (!timeout) { | |
147 | debug("SPI TIMEOUT\n"); | |
148 | break; | |
149 | } | |
150 | timeout--; | |
151 | } | |
152 | ||
153 | for (upto = 0, i = 0; upto < uboot_size; upto += todo, i++) { | |
b4141195 | 154 | todo = min(uboot_size - upto, (unsigned int)(1 << 15)); |
347e45d7 RS |
155 | spi_rx_tx(regs, todo, (void *)(uboot_addr), |
156 | (void *)(SPI_FLASH_UBOOT_POS), i); | |
157 | } | |
158 | ||
159 | setbits_le32(®s->cs_reg, SPI_SLAVE_SIG_INACT);/* make the CS high */ | |
160 | ||
161 | /* | |
162 | * Let put controller mode to BYTE as | |
163 | * SPI driver does not support WORD mode yet | |
164 | */ | |
165 | clrbits_le32(®s->mode_cfg, SPI_MODE_CH_WIDTH_WORD | | |
166 | SPI_MODE_BUS_WIDTH_WORD); | |
167 | writel(0, ®s->swap_cfg); | |
168 | ||
169 | /* | |
170 | * Flush spi tx, rx fifos and reset the SPI controller | |
171 | * and clear rx/tx channel | |
172 | */ | |
173 | clrsetbits_le32(®s->ch_cfg, SPI_CH_HS_EN, SPI_CH_RST); | |
174 | clrbits_le32(®s->ch_cfg, SPI_CH_RST); | |
175 | clrbits_le32(®s->ch_cfg, SPI_TX_CH_ON | SPI_RX_CH_ON); | |
176 | } | |
d8fa31a7 | 177 | #endif |
347e45d7 | 178 | |
81e35203 | 179 | /* |
a187559e | 180 | * Copy U-Boot from mmc to RAM: |
81e35203 CK |
181 | * COPY_BL2_FNPTR_ADDR: Address in iRAM, which Contains |
182 | * Pointer to API (Data transfer from mmc to ram) | |
183 | */ | |
184 | void copy_uboot_to_ram(void) | |
185 | { | |
4fb4d55a | 186 | unsigned int bootmode = BOOT_MODE_OM; |
c748be0d | 187 | |
643be9c0 RS |
188 | u32 (*copy_bl2)(u32 offset, u32 nblock, u32 dst) = NULL; |
189 | u32 offset = 0, size = 0; | |
d8fa31a7 | 190 | #ifdef CONFIG_SPI_BOOTING |
347e45d7 | 191 | struct spl_machine_param *param = spl_get_machine_params(); |
d8fa31a7 | 192 | #endif |
643be9c0 | 193 | #ifdef CONFIG_SUPPORT_EMMC_BOOT |
c748be0d A |
194 | u32 (*copy_bl2_from_emmc)(u32 nblock, u32 dst); |
195 | void (*end_bootop_from_emmc)(void); | |
643be9c0 RS |
196 | #endif |
197 | #ifdef CONFIG_USB_BOOTING | |
643be9c0 RS |
198 | int is_cr_z_set; |
199 | unsigned int sec_boot_check; | |
7a533773 | 200 | |
4f298624 VB |
201 | /* |
202 | * Note that older hardware (before Exynos5800) does not expect any | |
203 | * arguments, but it does not hurt to pass them, so a common function | |
204 | * prototype is used. | |
205 | */ | |
206 | u32 (*usb_copy)(u32 num_of_block, u32 *dst); | |
207 | ||
70656c79 VG |
208 | /* Read iRAM location to check for secondary USB boot mode */ |
209 | sec_boot_check = readl(EXYNOS_IRAM_SECONDARY_BASE); | |
210 | if (sec_boot_check == EXYNOS_USB_SECONDARY_BOOT) | |
211 | bootmode = BOOT_MODE_USB; | |
643be9c0 | 212 | #endif |
70656c79 VG |
213 | |
214 | if (bootmode == BOOT_MODE_OM) | |
4fb4d55a | 215 | bootmode = get_boot_mode(); |
81e35203 | 216 | |
7a533773 | 217 | switch (bootmode) { |
643be9c0 | 218 | #ifdef CONFIG_SPI_BOOTING |
7a533773 | 219 | case BOOT_MODE_SERIAL: |
347e45d7 RS |
220 | /* Customised function to copy u-boot from SF */ |
221 | exynos_spi_copy(param->uboot_size, CONFIG_SYS_TEXT_BASE); | |
7a533773 | 222 | break; |
643be9c0 | 223 | #endif |
4fb4d55a | 224 | case BOOT_MODE_SD: |
643be9c0 RS |
225 | offset = BL2_START_OFFSET; |
226 | size = BL2_SIZE_BLOC_COUNT; | |
c748be0d | 227 | copy_bl2 = get_irom_func(MMC_INDEX); |
c748be0d | 228 | break; |
643be9c0 | 229 | #ifdef CONFIG_SUPPORT_EMMC_BOOT |
c748be0d A |
230 | case BOOT_MODE_EMMC: |
231 | /* Set the FSYS1 clock divisor value for EMMC boot */ | |
232 | emmc_boot_clk_div_set(); | |
233 | ||
234 | copy_bl2_from_emmc = get_irom_func(EMMC44_INDEX); | |
235 | end_bootop_from_emmc = get_irom_func(EMMC44_END_INDEX); | |
236 | ||
237 | copy_bl2_from_emmc(BL2_SIZE_BLOC_COUNT, CONFIG_SYS_TEXT_BASE); | |
238 | end_bootop_from_emmc(); | |
7a533773 | 239 | break; |
643be9c0 RS |
240 | #endif |
241 | #ifdef CONFIG_USB_BOOTING | |
70656c79 VG |
242 | case BOOT_MODE_USB: |
243 | /* | |
244 | * iROM needs program flow prediction to be disabled | |
245 | * before copy from USB device to RAM | |
246 | */ | |
247 | is_cr_z_set = config_branch_prediction(0); | |
c748be0d | 248 | usb_copy = get_irom_func(USB_INDEX); |
4f298624 | 249 | usb_copy(0, (u32 *)CONFIG_SYS_TEXT_BASE); |
70656c79 VG |
250 | config_branch_prediction(is_cr_z_set); |
251 | break; | |
643be9c0 | 252 | #endif |
7a533773 RS |
253 | default: |
254 | break; | |
255 | } | |
643be9c0 RS |
256 | |
257 | if (copy_bl2) | |
258 | copy_bl2(offset, size, CONFIG_SYS_TEXT_BASE); | |
259 | } | |
260 | ||
261 | void memzero(void *s, size_t n) | |
262 | { | |
263 | char *ptr = s; | |
264 | size_t i; | |
265 | ||
266 | for (i = 0; i < n; i++) | |
267 | *ptr++ = '\0'; | |
268 | } | |
269 | ||
270 | /** | |
271 | * Set up the U-Boot global_data pointer | |
272 | * | |
273 | * This sets the address of the global data, and sets up basic values. | |
274 | * | |
275 | * @param gdp Value to give to gd | |
276 | */ | |
277 | static void setup_global_data(gd_t *gdp) | |
278 | { | |
279 | gd = gdp; | |
280 | memzero((void *)gd, sizeof(gd_t)); | |
281 | gd->flags |= GD_FLG_RELOC; | |
282 | gd->baudrate = CONFIG_BAUDRATE; | |
283 | gd->have_console = 1; | |
81e35203 CK |
284 | } |
285 | ||
286 | void board_init_f(unsigned long bootflag) | |
287 | { | |
643be9c0 | 288 | __aligned(8) gd_t local_gd; |
81e35203 | 289 | __attribute__((noreturn)) void (*uboot)(void); |
643be9c0 RS |
290 | |
291 | setup_global_data(&local_gd); | |
292 | ||
293 | if (do_lowlevel_init()) | |
294 | power_exit_wakeup(); | |
295 | ||
81e35203 CK |
296 | copy_uboot_to_ram(); |
297 | ||
298 | /* Jump to U-Boot image */ | |
299 | uboot = (void *)CONFIG_SYS_TEXT_BASE; | |
300 | (*uboot)(); | |
301 | /* Never returns Here */ | |
302 | } | |
303 | ||
304 | /* Place Holders */ | |
305 | void board_init_r(gd_t *id, ulong dest_addr) | |
306 | { | |
307 | /* Function attribute is no-return */ | |
308 | /* This Function never executes */ | |
309 | while (1) | |
310 | ; | |
311 | } |