]>
Commit | Line | Data |
---|---|---|
98d62e61 PB |
1 | /* |
2 | * Copyright (C) 2015 Beckhoff Automation GmbH & Co. KG | |
3 | * Patrick Bruenn <p.bruenn@beckhoff.com> | |
4 | * | |
5 | * Based on <u-boot>/board/freescale/mx53loco/mx53loco.c | |
6 | * Copyright (C) 2011 Freescale Semiconductor, Inc. | |
7 | * | |
8 | * SPDX-License-Identifier: GPL-2.0+ | |
9 | */ | |
10 | ||
11 | #include <common.h> | |
9d922450 | 12 | #include <dm.h> |
98d62e61 PB |
13 | #include <asm/io.h> |
14 | #include <asm/arch/imx-regs.h> | |
15 | #include <asm/arch/sys_proto.h> | |
16 | #include <asm/arch/crm_regs.h> | |
17 | #include <asm/arch/clock.h> | |
18 | #include <asm/arch/iomux-mx53.h> | |
19 | #include <asm/arch/clock.h> | |
552a848e | 20 | #include <asm/mach-imx/mx5_video.h> |
98d62e61 PB |
21 | #include <ACEX1K.h> |
22 | #include <netdev.h> | |
23 | #include <i2c.h> | |
24 | #include <mmc.h> | |
25 | #include <fsl_esdhc.h> | |
26 | #include <asm/gpio.h> | |
27 | #include <linux/fb.h> | |
28 | #include <ipu_pixfmt.h> | |
7594c51a | 29 | #include <input.h> |
98d62e61 | 30 | #include <fs.h> |
98d62e61 PB |
31 | #include <dm/platform_data/serial_mxc.h> |
32 | ||
33 | enum LED_GPIOS { | |
34 | GPIO_SD1_CD = IMX_GPIO_NR(1, 1), | |
35 | GPIO_SD2_CD = IMX_GPIO_NR(1, 4), | |
36 | GPIO_LED_SD2_R = IMX_GPIO_NR(3, 16), | |
37 | GPIO_LED_SD2_B = IMX_GPIO_NR(3, 17), | |
38 | GPIO_LED_SD2_G = IMX_GPIO_NR(3, 18), | |
39 | GPIO_LED_SD1_R = IMX_GPIO_NR(3, 19), | |
40 | GPIO_LED_SD1_B = IMX_GPIO_NR(3, 20), | |
41 | GPIO_LED_SD1_G = IMX_GPIO_NR(3, 21), | |
42 | GPIO_LED_PWR_R = IMX_GPIO_NR(3, 22), | |
43 | GPIO_LED_PWR_B = IMX_GPIO_NR(3, 23), | |
44 | GPIO_LED_PWR_G = IMX_GPIO_NR(3, 24), | |
45 | GPIO_SUPS_INT = IMX_GPIO_NR(3, 31), | |
46 | GPIO_C3_CONFIG = IMX_GPIO_NR(6, 8), | |
47 | GPIO_C3_STATUS = IMX_GPIO_NR(6, 7), | |
48 | GPIO_C3_DONE = IMX_GPIO_NR(6, 9), | |
49 | }; | |
50 | ||
51 | #define CCAT_BASE_ADDR ((void *)0xf0000000) | |
52 | #define CCAT_END_ADDR (CCAT_BASE_ADDR + (1024 * 1024 * 32)) | |
53 | #define CCAT_SIZE 1191788 | |
54 | #define CCAT_SIGN_ADDR (CCAT_BASE_ADDR + 12) | |
55 | static const char CCAT_SIGNATURE[] = "CCAT"; | |
56 | ||
57 | static const u32 CCAT_MODE_CONFIG = 0x0024DC81; | |
58 | static const u32 CCAT_MODE_RUN = 0x0033DC8F; | |
59 | ||
60 | DECLARE_GLOBAL_DATA_PTR; | |
61 | ||
98d62e61 PB |
62 | phys_size_t get_effective_memsize(void) |
63 | { | |
64 | /* | |
65 | * WARNING: We must override get_effective_memsize() function here | |
66 | * to report only the size of the first DRAM bank. This is to make | |
67 | * U-Boot relocator place U-Boot into valid memory, that is, at the | |
68 | * end of the first DRAM bank. If we did not override this function | |
69 | * like so, U-Boot would be placed at the address of the first DRAM | |
70 | * bank + total DRAM size - sizeof(uboot), which in the setup where | |
71 | * each DRAM bank contains 512MiB of DRAM would result in placing | |
72 | * U-Boot into invalid memory area close to the end of the first | |
73 | * DRAM bank. | |
74 | */ | |
a75a3ef3 | 75 | return get_ram_size((void *)PHYS_SDRAM_1, 1 << 30); |
98d62e61 PB |
76 | } |
77 | ||
78 | int dram_init(void) | |
79 | { | |
a75a3ef3 PB |
80 | gd->ram_size = get_ram_size((void *)PHYS_SDRAM_1, 1 << 30); |
81 | gd->ram_size += get_ram_size((void *)PHYS_SDRAM_2, 1 << 30); | |
98d62e61 PB |
82 | |
83 | return 0; | |
84 | } | |
85 | ||
76b00aca | 86 | int dram_init_banksize(void) |
98d62e61 PB |
87 | { |
88 | gd->bd->bi_dram[0].start = PHYS_SDRAM_1; | |
a75a3ef3 | 89 | gd->bd->bi_dram[0].size = get_ram_size((void *)PHYS_SDRAM_1, 1 << 30); |
98d62e61 PB |
90 | |
91 | gd->bd->bi_dram[1].start = PHYS_SDRAM_2; | |
a75a3ef3 | 92 | gd->bd->bi_dram[1].size = get_ram_size((void *)PHYS_SDRAM_2, 1 << 30); |
76b00aca SG |
93 | |
94 | return 0; | |
98d62e61 PB |
95 | } |
96 | ||
97 | u32 get_board_rev(void) | |
98 | { | |
99 | struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE; | |
100 | struct fuse_bank *bank = &iim->bank[0]; | |
101 | struct fuse_bank0_regs *fuse = | |
102 | (struct fuse_bank0_regs *)bank->fuse_regs; | |
103 | ||
104 | int rev = readl(&fuse->gp[6]); | |
105 | ||
106 | return (get_cpu_rev() & ~(0xF << 8)) | (rev & 0xF) << 8; | |
107 | } | |
108 | ||
109 | /* | |
110 | * Set CCAT mode | |
111 | * @mode: use CCAT_MODE_CONFIG or CCAT_MODE_RUN | |
112 | */ | |
113 | void weim_cs0_settings(u32 mode) | |
114 | { | |
115 | struct weim *weim_regs = (struct weim *)WEIM_BASE_ADDR; | |
116 | ||
117 | writel(0x0, &weim_regs->cs0gcr1); | |
118 | writel(mode, &weim_regs->cs0gcr1); | |
119 | writel(0x00001002, &weim_regs->cs0gcr2); | |
120 | ||
121 | writel(0x04000000, &weim_regs->cs0rcr1); | |
122 | writel(0x00000000, &weim_regs->cs0rcr2); | |
123 | ||
124 | writel(0x04000000, &weim_regs->cs0wcr1); | |
125 | writel(0x00000000, &weim_regs->cs0wcr2); | |
126 | } | |
127 | ||
128 | static void setup_gpio_eim(void) | |
129 | { | |
130 | gpio_direction_input(GPIO_C3_STATUS); | |
131 | gpio_direction_input(GPIO_C3_DONE); | |
132 | gpio_direction_output(GPIO_C3_CONFIG, 1); | |
133 | ||
134 | weim_cs0_settings(CCAT_MODE_RUN); | |
135 | } | |
136 | ||
137 | static void setup_gpio_sups(void) | |
138 | { | |
139 | gpio_direction_input(GPIO_SUPS_INT); | |
140 | ||
141 | static const int BLINK_INTERVALL = 50000; | |
142 | int status = 1; | |
143 | while (gpio_get_value(GPIO_SUPS_INT)) { | |
144 | /* signal "CX SUPS power fail" */ | |
145 | gpio_set_value(GPIO_LED_PWR_R, | |
146 | (++status / BLINK_INTERVALL) % 2); | |
147 | } | |
148 | ||
149 | /* signal "CX power up" */ | |
150 | gpio_set_value(GPIO_LED_PWR_R, 1); | |
151 | } | |
152 | ||
153 | static void setup_gpio_leds(void) | |
154 | { | |
155 | gpio_direction_output(GPIO_LED_SD2_R, 0); | |
156 | gpio_direction_output(GPIO_LED_SD2_B, 0); | |
157 | gpio_direction_output(GPIO_LED_SD2_G, 0); | |
158 | gpio_direction_output(GPIO_LED_SD1_R, 0); | |
159 | gpio_direction_output(GPIO_LED_SD1_B, 0); | |
160 | gpio_direction_output(GPIO_LED_SD1_G, 0); | |
161 | gpio_direction_output(GPIO_LED_PWR_R, 0); | |
162 | gpio_direction_output(GPIO_LED_PWR_B, 0); | |
163 | gpio_direction_output(GPIO_LED_PWR_G, 0); | |
164 | } | |
165 | ||
166 | #ifdef CONFIG_USB_EHCI_MX5 | |
167 | int board_ehci_hcd_init(int port) | |
168 | { | |
169 | /* request VBUS power enable pin, GPIO7_8 */ | |
170 | gpio_direction_output(IMX_GPIO_NR(7, 8), 1); | |
171 | return 0; | |
172 | } | |
173 | #endif | |
174 | ||
175 | #ifdef CONFIG_FSL_ESDHC | |
176 | struct fsl_esdhc_cfg esdhc_cfg[2] = { | |
177 | {MMC_SDHC1_BASE_ADDR}, | |
178 | {MMC_SDHC2_BASE_ADDR}, | |
179 | }; | |
180 | ||
181 | int board_mmc_getcd(struct mmc *mmc) | |
182 | { | |
183 | struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; | |
184 | int ret; | |
185 | ||
186 | gpio_direction_input(GPIO_SD1_CD); | |
187 | gpio_direction_input(GPIO_SD2_CD); | |
188 | ||
189 | if (cfg->esdhc_base == MMC_SDHC1_BASE_ADDR) | |
190 | ret = !gpio_get_value(GPIO_SD1_CD); | |
191 | else | |
192 | ret = !gpio_get_value(GPIO_SD2_CD); | |
193 | ||
194 | return ret; | |
195 | } | |
196 | ||
197 | int board_mmc_init(bd_t *bis) | |
198 | { | |
199 | u32 index; | |
200 | int ret; | |
201 | ||
202 | esdhc_cfg[0].sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK); | |
203 | esdhc_cfg[1].sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK); | |
204 | ||
205 | for (index = 0; index < CONFIG_SYS_FSL_ESDHC_NUM; index++) { | |
206 | switch (index) { | |
207 | case 0: | |
208 | break; | |
209 | case 1: | |
210 | break; | |
211 | default: | |
212 | printf("Warning: you configured more ESDHC controller(%d) as supported by the board(2)\n", | |
213 | CONFIG_SYS_FSL_ESDHC_NUM); | |
214 | return -EINVAL; | |
215 | } | |
216 | ret = fsl_esdhc_initialize(bis, &esdhc_cfg[index]); | |
217 | if (ret) | |
218 | return ret; | |
219 | } | |
220 | ||
221 | return 0; | |
222 | } | |
223 | #endif | |
224 | ||
225 | static int power_init(void) | |
226 | { | |
227 | /* nothing to do on CX9020 */ | |
228 | return 0; | |
229 | } | |
230 | ||
231 | static void clock_1GHz(void) | |
232 | { | |
233 | int ret; | |
234 | u32 ref_clk = MXC_HCLK; | |
235 | /* | |
236 | * After increasing voltage to 1.25V, we can switch | |
237 | * CPU clock to 1GHz and DDR to 400MHz safely | |
238 | */ | |
239 | ret = mxc_set_clock(ref_clk, 1000, MXC_ARM_CLK); | |
240 | if (ret) | |
241 | printf("CPU: Switch CPU clock to 1GHZ failed\n"); | |
242 | ||
243 | ret = mxc_set_clock(ref_clk, 400, MXC_PERIPH_CLK); | |
244 | ret |= mxc_set_clock(ref_clk, 400, MXC_DDR_CLK); | |
245 | if (ret) | |
246 | printf("CPU: Switch DDR clock to 400MHz failed\n"); | |
247 | } | |
248 | ||
249 | int board_early_init_f(void) | |
250 | { | |
251 | setup_gpio_leds(); | |
252 | setup_gpio_sups(); | |
253 | setup_gpio_eim(); | |
254 | setup_iomux_lcd(); | |
255 | ||
256 | return 0; | |
257 | } | |
258 | ||
259 | /* | |
260 | * Do not overwrite the console | |
261 | * Use always serial for U-Boot console | |
262 | */ | |
263 | int overwrite_console(void) | |
264 | { | |
265 | return 1; | |
266 | } | |
267 | ||
268 | int board_init(void) | |
269 | { | |
270 | gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100; | |
271 | ||
272 | mxc_set_sata_internal_clock(); | |
273 | ||
274 | return 0; | |
275 | } | |
276 | ||
277 | int checkboard(void) | |
278 | { | |
279 | puts("Board: Beckhoff CX9020\n"); | |
280 | ||
281 | return 0; | |
282 | } | |
283 | ||
284 | static int ccat_config_fn(int assert_config, int flush, int cookie) | |
285 | { | |
286 | /* prepare FPGA for programming */ | |
287 | weim_cs0_settings(CCAT_MODE_CONFIG); | |
288 | gpio_set_value(GPIO_C3_CONFIG, 0); | |
289 | udelay(1); | |
290 | gpio_set_value(GPIO_C3_CONFIG, 1); | |
291 | udelay(230); | |
292 | ||
293 | return FPGA_SUCCESS; | |
294 | } | |
295 | ||
296 | static int ccat_status_fn(int cookie) | |
297 | { | |
298 | return FPGA_FAIL; | |
299 | } | |
300 | ||
301 | static int ccat_write_fn(const void *buf, size_t buf_len, int flush, int cookie) | |
302 | { | |
303 | const uint8_t *const buffer = buf; | |
304 | ||
305 | /* program CCAT */ | |
306 | int i; | |
307 | for (i = 0; i < buf_len; ++i) | |
308 | writeb(buffer[i], CCAT_BASE_ADDR); | |
309 | ||
310 | writeb(0xff, CCAT_BASE_ADDR); | |
311 | writeb(0xff, CCAT_BASE_ADDR); | |
312 | ||
313 | return FPGA_SUCCESS; | |
314 | } | |
315 | ||
316 | static int ccat_done_fn(int cookie) | |
317 | { | |
318 | /* programming complete? */ | |
319 | return gpio_get_value(GPIO_C3_DONE); | |
320 | } | |
321 | ||
322 | static int ccat_post_fn(int cookie) | |
323 | { | |
324 | /* switch to FPGA run mode */ | |
325 | weim_cs0_settings(CCAT_MODE_RUN); | |
326 | invalidate_dcache_range((ulong) CCAT_BASE_ADDR, (ulong) CCAT_END_ADDR); | |
327 | ||
328 | if (memcmp(CCAT_SIGN_ADDR, CCAT_SIGNATURE, sizeof(CCAT_SIGNATURE))) { | |
329 | printf("Verifing CCAT firmware failed, signature not found\n"); | |
330 | return FPGA_FAIL; | |
331 | } | |
332 | ||
333 | /* signal "CX booting OS" */ | |
334 | gpio_set_value(GPIO_LED_PWR_R, 1); | |
335 | gpio_set_value(GPIO_LED_PWR_G, 1); | |
336 | gpio_set_value(GPIO_LED_PWR_B, 0); | |
337 | return FPGA_SUCCESS; | |
338 | } | |
339 | ||
340 | static Altera_CYC2_Passive_Serial_fns ccat_fns = { | |
341 | .config = ccat_config_fn, | |
342 | .status = ccat_status_fn, | |
343 | .done = ccat_done_fn, | |
344 | .write = ccat_write_fn, | |
345 | .abort = ccat_post_fn, | |
346 | .post = ccat_post_fn, | |
347 | }; | |
348 | ||
349 | static Altera_desc ccat_fpga = { | |
350 | .family = Altera_CYC2, | |
351 | .iface = passive_serial, | |
352 | .size = CCAT_SIZE, | |
353 | .iface_fns = &ccat_fns, | |
354 | .base = CCAT_BASE_ADDR, | |
355 | }; | |
356 | ||
357 | int board_late_init(void) | |
358 | { | |
359 | if (!power_init()) | |
360 | clock_1GHz(); | |
361 | ||
362 | fpga_init(); | |
363 | fpga_add(fpga_altera, &ccat_fpga); | |
364 | ||
365 | return 0; | |
366 | } |