]>
Commit | Line | Data |
---|---|---|
885fc03a AR |
1 | /* |
2 | * Bluewater Systems Snapper 9260/9G20 modules | |
3 | * | |
4 | * (C) Copyright 2011 Bluewater Systems | |
5 | * Author: Andre Renaud <andre@bluewatersys.com> | |
6 | * Author: Ryan Mallon <ryan@bluewatersys.com> | |
7 | * | |
8 | * SPDX-License-Identifier: GPL-2.0+ | |
9 | */ | |
10 | ||
11 | #include <common.h> | |
12 | #include <atmel_lcd.h> | |
13 | #include <atmel_lcdc.h> | |
14 | #include <atmel_mci.h> | |
15 | #include <dm.h> | |
16 | #include <lcd.h> | |
17 | #include <net.h> | |
18 | #ifndef CONFIG_DM_ETH | |
19 | #include <netdev.h> | |
20 | #endif | |
21 | #include <spi.h> | |
22 | #include <asm/gpio.h> | |
23 | #include <asm/io.h> | |
c62db35d | 24 | #include <asm/mach-types.h> |
885fc03a AR |
25 | #include <asm/arch/at91sam9g45_matrix.h> |
26 | #include <asm/arch/at91sam9_smc.h> | |
27 | #include <asm/arch/at91_common.h> | |
28 | #include <asm/arch/at91_emac.h> | |
29 | #include <asm/arch/at91_rstc.h> | |
30 | #include <asm/arch/at91_rtc.h> | |
31 | #include <asm/arch/at91_sck.h> | |
32 | #include <asm/arch/atmel_serial.h> | |
33 | #include <asm/arch/clk.h> | |
34 | #include <asm/arch/gpio.h> | |
35 | #include <dm/uclass-internal.h> | |
36 | ||
37 | #ifdef CONFIG_GURNARD_SPLASH | |
38 | #include "splash_logo.h" | |
39 | #endif | |
40 | ||
41 | DECLARE_GLOBAL_DATA_PTR; | |
42 | ||
43 | /* IO Expander pins */ | |
44 | #define IO_EXP_ETH_RESET (0 << 1) | |
45 | #define IO_EXP_ETH_POWER (1 << 1) | |
46 | ||
47 | #ifdef CONFIG_MACB | |
48 | static void gurnard_macb_hw_init(void) | |
49 | { | |
50 | struct at91_port *pioa = (struct at91_port *)ATMEL_BASE_PIOA; | |
51 | ||
52 | at91_periph_clk_enable(ATMEL_ID_EMAC); | |
53 | ||
54 | /* | |
55 | * Enable pull-up on: | |
56 | * RXDV (PA12) => MODE0 - PHY also has pull-up | |
57 | * ERX0 (PA13) => MODE1 - PHY also has pull-up | |
58 | * ERX1 (PA15) => MODE2 - PHY also has pull-up | |
59 | */ | |
60 | writel(pin_to_mask(AT91_PIN_PA15) | | |
61 | pin_to_mask(AT91_PIN_PA12) | | |
62 | pin_to_mask(AT91_PIN_PA13), | |
63 | &pioa->puer); | |
64 | ||
65 | at91_phy_reset(); | |
66 | ||
67 | at91_macb_hw_init(); | |
68 | } | |
69 | #endif | |
70 | ||
71 | #ifdef CONFIG_CMD_NAND | |
72 | static int gurnard_nand_hw_init(void) | |
73 | { | |
74 | struct at91_matrix *matrix = (struct at91_matrix *)ATMEL_BASE_MATRIX; | |
75 | struct at91_smc *smc = (struct at91_smc *)ATMEL_BASE_SMC; | |
76 | ulong flags; | |
77 | int ret; | |
78 | ||
79 | /* Enable CS3 as NAND/SmartMedia */ | |
80 | setbits_le32(&matrix->ebicsa, AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA); | |
81 | ||
82 | /* Configure SMC CS3 for NAND/SmartMedia */ | |
83 | writel(AT91_SMC_SETUP_NWE(2) | AT91_SMC_SETUP_NCS_WR(0) | | |
84 | AT91_SMC_SETUP_NRD(2) | AT91_SMC_SETUP_NCS_RD(0), | |
85 | &smc->cs[3].setup); | |
86 | writel(AT91_SMC_PULSE_NWE(4) | AT91_SMC_PULSE_NCS_WR(4) | | |
87 | AT91_SMC_PULSE_NRD(4) | AT91_SMC_PULSE_NCS_RD(4), | |
88 | &smc->cs[3].pulse); | |
89 | writel(AT91_SMC_CYCLE_NWE(7) | AT91_SMC_CYCLE_NRD(7), | |
90 | &smc->cs[3].cycle); | |
91 | #ifdef CONFIG_SYS_NAND_DBW_16 | |
92 | flags = AT91_SMC_MODE_DBW_16; | |
93 | #else | |
94 | flags = AT91_SMC_MODE_DBW_8; | |
95 | #endif | |
96 | writel(AT91_SMC_MODE_RM_NRD | AT91_SMC_MODE_WM_NWE | | |
97 | AT91_SMC_MODE_EXNW_DISABLE | | |
98 | flags | | |
99 | AT91_SMC_MODE_TDF_CYCLE(3), | |
100 | &smc->cs[3].mode); | |
101 | ||
102 | ret = gpio_request(CONFIG_SYS_NAND_READY_PIN, "nand_rdy"); | |
103 | if (ret) | |
104 | return ret; | |
105 | gpio_direction_input(CONFIG_SYS_NAND_READY_PIN); | |
106 | ||
107 | /* Enable NandFlash */ | |
108 | ret = gpio_request(CONFIG_SYS_NAND_ENABLE_PIN, "nand_ce"); | |
109 | if (ret) | |
110 | return ret; | |
111 | gpio_direction_output(CONFIG_SYS_NAND_ENABLE_PIN, 1); | |
112 | ||
113 | return 0; | |
114 | } | |
115 | #endif | |
116 | ||
117 | #ifdef CONFIG_GURNARD_SPLASH | |
118 | static void lcd_splash(int width, int height) | |
119 | { | |
120 | u16 colour; | |
121 | int x, y; | |
122 | u16 *base_addr = (u16 *)gd->video_bottom; | |
123 | ||
124 | memset(base_addr, 0xff, width * height * 2); | |
125 | /* | |
126 | * Blit the logo to the center of the screen | |
127 | */ | |
128 | for (y = 0; y < BMP_LOGO_HEIGHT; y++) { | |
129 | for (x = 0; x < BMP_LOGO_WIDTH; x++) { | |
130 | int posx, posy; | |
131 | colour = bmp_logo_palette[bmp_logo_bitmap[ | |
132 | y * BMP_LOGO_WIDTH + x]]; | |
133 | posx = x + (width - BMP_LOGO_WIDTH) / 2; | |
134 | posy = y; | |
135 | base_addr[posy * width + posx] = colour; | |
136 | } | |
137 | } | |
138 | } | |
139 | #endif | |
140 | ||
141 | #ifdef CONFIG_DM_VIDEO | |
142 | static void at91sam9g45_lcd_hw_init(void) | |
143 | { | |
144 | at91_set_A_periph(AT91_PIN_PE0, 0); /* LCDDPWR */ | |
145 | at91_set_A_periph(AT91_PIN_PE2, 0); /* LCDCC */ | |
146 | at91_set_A_periph(AT91_PIN_PE3, 0); /* LCDVSYNC */ | |
147 | at91_set_A_periph(AT91_PIN_PE4, 0); /* LCDHSYNC */ | |
148 | at91_set_A_periph(AT91_PIN_PE5, 0); /* LCDDOTCK */ | |
149 | ||
150 | at91_set_A_periph(AT91_PIN_PE7, 0); /* LCDD0 */ | |
151 | at91_set_A_periph(AT91_PIN_PE8, 0); /* LCDD1 */ | |
152 | at91_set_A_periph(AT91_PIN_PE9, 0); /* LCDD2 */ | |
153 | at91_set_A_periph(AT91_PIN_PE10, 0); /* LCDD3 */ | |
154 | at91_set_A_periph(AT91_PIN_PE11, 0); /* LCDD4 */ | |
155 | at91_set_A_periph(AT91_PIN_PE12, 0); /* LCDD5 */ | |
156 | at91_set_A_periph(AT91_PIN_PE13, 0); /* LCDD6 */ | |
157 | at91_set_A_periph(AT91_PIN_PE14, 0); /* LCDD7 */ | |
158 | at91_set_A_periph(AT91_PIN_PE15, 0); /* LCDD8 */ | |
159 | at91_set_A_periph(AT91_PIN_PE16, 0); /* LCDD9 */ | |
160 | at91_set_A_periph(AT91_PIN_PE17, 0); /* LCDD10 */ | |
161 | at91_set_A_periph(AT91_PIN_PE18, 0); /* LCDD11 */ | |
162 | at91_set_A_periph(AT91_PIN_PE19, 0); /* LCDD12 */ | |
163 | at91_set_B_periph(AT91_PIN_PE20, 0); /* LCDD13 */ | |
164 | at91_set_A_periph(AT91_PIN_PE21, 0); /* LCDD14 */ | |
165 | at91_set_A_periph(AT91_PIN_PE22, 0); /* LCDD15 */ | |
166 | at91_set_A_periph(AT91_PIN_PE23, 0); /* LCDD16 */ | |
167 | at91_set_A_periph(AT91_PIN_PE24, 0); /* LCDD17 */ | |
168 | at91_set_A_periph(AT91_PIN_PE25, 0); /* LCDD18 */ | |
169 | at91_set_A_periph(AT91_PIN_PE26, 0); /* LCDD19 */ | |
170 | at91_set_A_periph(AT91_PIN_PE27, 0); /* LCDD20 */ | |
171 | at91_set_B_periph(AT91_PIN_PE28, 0); /* LCDD21 */ | |
172 | at91_set_A_periph(AT91_PIN_PE29, 0); /* LCDD22 */ | |
173 | at91_set_A_periph(AT91_PIN_PE30, 0); /* LCDD23 */ | |
174 | ||
175 | at91_periph_clk_enable(ATMEL_ID_LCDC); | |
176 | } | |
177 | #endif | |
178 | ||
179 | #ifdef CONFIG_GURNARD_FPGA | |
180 | /** | |
181 | * Initialise the memory bus settings so that we can talk to the | |
182 | * memory mapped FPGA | |
183 | */ | |
184 | static int fpga_hw_init(void) | |
185 | { | |
186 | struct at91_matrix *matrix = (struct at91_matrix *)ATMEL_BASE_MATRIX; | |
187 | struct at91_smc *smc = (struct at91_smc *)ATMEL_BASE_SMC; | |
188 | int i; | |
189 | ||
190 | setbits_le32(&matrix->ebicsa, AT91_MATRIX_EBI_CS1A_SDRAMC); | |
191 | ||
192 | at91_set_a_periph(2, 4, 0); /* EBIA21 */ | |
193 | at91_set_a_periph(2, 5, 0); /* EBIA22 */ | |
194 | at91_set_a_periph(2, 6, 0); /* EBIA23 */ | |
195 | at91_set_a_periph(2, 7, 0); /* EBIA24 */ | |
196 | at91_set_a_periph(2, 12, 0); /* EBIA25 */ | |
197 | for (i = 15; i <= 31; i++) /* EBINWAIT & EBID16 - 31 */ | |
198 | at91_set_a_periph(2, i, 0); | |
199 | ||
200 | /* configure SMC cs0 for FPGA access timing */ | |
201 | writel(AT91_SMC_SETUP_NWE(1) | AT91_SMC_SETUP_NCS_WR(2) | | |
202 | AT91_SMC_SETUP_NRD(0) | AT91_SMC_SETUP_NCS_RD(2), | |
203 | &smc->cs[0].setup); | |
204 | writel(AT91_SMC_PULSE_NWE(5) | AT91_SMC_PULSE_NCS_WR(4) | | |
205 | AT91_SMC_PULSE_NRD(6) | AT91_SMC_PULSE_NCS_RD(4), | |
206 | &smc->cs[0].pulse); | |
207 | writel(AT91_SMC_CYCLE_NWE(6) | AT91_SMC_CYCLE_NRD(6), | |
208 | &smc->cs[0].cycle); | |
209 | writel(AT91_SMC_MODE_BAT | | |
210 | AT91_SMC_MODE_EXNW_DISABLE | | |
211 | AT91_SMC_MODE_DBW_32 | | |
212 | AT91_SMC_MODE_TDF | | |
213 | AT91_SMC_MODE_TDF_CYCLE(2), | |
214 | &smc->cs[0].mode); | |
215 | ||
216 | /* Do a write to within EBI_CS1 to enable the SDCK */ | |
217 | writel(0, ATMEL_BASE_CS1); | |
218 | ||
219 | return 0; | |
220 | } | |
221 | #endif | |
222 | ||
223 | #ifdef CONFIG_CMD_USB | |
224 | ||
225 | #define USB0_ENABLE_PIN AT91_PIN_PB22 | |
226 | #define USB1_ENABLE_PIN AT91_PIN_PB23 | |
227 | ||
228 | void gurnard_usb_init(void) | |
229 | { | |
230 | at91_set_gpio_output(USB0_ENABLE_PIN, 1); | |
231 | at91_set_gpio_value(USB0_ENABLE_PIN, 0); | |
232 | at91_set_gpio_output(USB1_ENABLE_PIN, 1); | |
233 | at91_set_gpio_value(USB1_ENABLE_PIN, 0); | |
234 | } | |
235 | #endif | |
236 | ||
237 | #ifdef CONFIG_GENERIC_ATMEL_MCI | |
238 | int cpu_mmc_init(bd_t *bis) | |
239 | { | |
240 | return atmel_mci_init((void *)ATMEL_BASE_MCI0); | |
241 | } | |
242 | #endif | |
243 | ||
244 | static void gurnard_enable_console(int enable) | |
245 | { | |
246 | at91_set_gpio_output(AT91_PIN_PB14, 1); | |
247 | at91_set_gpio_value(AT91_PIN_PB14, enable ? 0 : 1); | |
248 | } | |
249 | ||
250 | void at91sam9g45_slowclock_init(void) | |
251 | { | |
252 | /* | |
253 | * On AT91SAM9G45 revC CPUs, the slow clock can be based on an | |
254 | * internal impreciseRC oscillator or an external 32kHz oscillator. | |
255 | * Switch to the latter. | |
256 | */ | |
257 | unsigned i, tmp; | |
258 | ulong *reg = (ulong *)ATMEL_BASE_SCKCR; | |
259 | ||
260 | tmp = readl(reg); | |
261 | if ((tmp & AT91SAM9G45_SCKCR_OSCSEL) == AT91SAM9G45_SCKCR_OSCSEL_RC) { | |
262 | timer_init(); | |
263 | tmp |= AT91SAM9G45_SCKCR_OSC32EN; | |
264 | writel(tmp, reg); | |
265 | for (i = 0; i < 1200; i++) | |
266 | udelay(1000); | |
267 | tmp |= AT91SAM9G45_SCKCR_OSCSEL_32; | |
268 | writel(tmp, reg); | |
269 | udelay(200); | |
270 | tmp &= ~AT91SAM9G45_SCKCR_RCEN; | |
271 | writel(tmp, reg); | |
272 | } | |
273 | } | |
274 | ||
275 | int board_early_init_f(void) | |
276 | { | |
277 | at91_seriald_hw_init(); | |
278 | gurnard_enable_console(1); | |
279 | ||
280 | return 0; | |
281 | } | |
282 | ||
283 | int board_init(void) | |
284 | { | |
285 | const char *rev_str; | |
286 | #ifdef CONFIG_CMD_NAND | |
287 | int ret; | |
288 | #endif | |
289 | ||
290 | at91_periph_clk_enable(ATMEL_ID_PIOA); | |
291 | at91_periph_clk_enable(ATMEL_ID_PIOB); | |
292 | at91_periph_clk_enable(ATMEL_ID_PIOC); | |
293 | at91_periph_clk_enable(ATMEL_ID_PIODE); | |
294 | ||
295 | at91sam9g45_slowclock_init(); | |
296 | ||
297 | /* | |
298 | * Clear the RTC IDR to disable all IRQs. Avoid issues when Linux | |
299 | * boots with spurious IRQs. | |
300 | */ | |
301 | writel(0xffffffff, AT91_RTC_IDR); | |
302 | ||
303 | /* Make sure that the reset signal is attached properly */ | |
304 | setbits_le32(AT91_ASM_RSTC_MR, AT91_RSTC_KEY | AT91_RSTC_MR_URSTEN); | |
305 | ||
306 | gd->bd->bi_arch_number = MACH_TYPE_SNAPPER_9260; | |
307 | ||
308 | /* Address of boot parameters */ | |
309 | gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100; | |
310 | ||
311 | #ifdef CONFIG_CMD_NAND | |
312 | ret = gurnard_nand_hw_init(); | |
313 | if (ret) | |
314 | return ret; | |
315 | #endif | |
316 | #ifdef CONFIG_ATMEL_SPI | |
317 | at91_spi0_hw_init(1 << 4); | |
318 | #endif | |
319 | ||
320 | #ifdef CONFIG_MACB | |
321 | gurnard_macb_hw_init(); | |
322 | #endif | |
323 | ||
324 | #ifdef CONFIG_GURNARD_FPGA | |
325 | fpga_hw_init(); | |
326 | #endif | |
327 | ||
328 | #ifdef CONFIG_CMD_USB | |
329 | gurnard_usb_init(); | |
330 | #endif | |
331 | ||
332 | #ifdef CONFIG_CMD_MMC | |
333 | at91_set_A_periph(AT91_PIN_PA12, 0); | |
334 | at91_set_gpio_output(AT91_PIN_PA8, 1); | |
335 | at91_set_gpio_value(AT91_PIN_PA8, 0); | |
336 | at91_mci_hw_init(); | |
337 | #endif | |
338 | ||
339 | #ifdef CONFIG_DM_VIDEO | |
340 | at91sam9g45_lcd_hw_init(); | |
341 | at91_set_A_periph(AT91_PIN_PE6, 1); /* power up */ | |
342 | ||
343 | /* Select the second timing index for board rev 2 */ | |
00caae6d | 344 | rev_str = env_get("board_rev"); |
885fc03a AR |
345 | if (rev_str && !strncmp(rev_str, "2", 1)) { |
346 | struct udevice *dev; | |
347 | ||
348 | uclass_find_first_device(UCLASS_VIDEO, &dev); | |
349 | if (dev) { | |
350 | struct atmel_lcd_platdata *plat = dev_get_platdata(dev); | |
351 | ||
352 | plat->timing_index = 1; | |
353 | } | |
354 | } | |
355 | #endif | |
356 | ||
357 | return 0; | |
358 | } | |
359 | ||
360 | int board_late_init(void) | |
361 | { | |
362 | u_int8_t env_enetaddr[8]; | |
363 | char *env_str; | |
364 | char *end; | |
365 | int i; | |
366 | ||
367 | /* | |
368 | * Set MAC address so we do not need to init Ethernet before Linux | |
369 | * boot | |
370 | */ | |
00caae6d | 371 | env_str = env_get("ethaddr"); |
885fc03a AR |
372 | if (env_str) { |
373 | struct at91_emac *emac = (struct at91_emac *)ATMEL_BASE_EMAC; | |
374 | /* Parse MAC address */ | |
375 | for (i = 0; i < 6; i++) { | |
376 | env_enetaddr[i] = env_str ? | |
377 | simple_strtoul(env_str, &end, 16) : 0; | |
378 | if (env_str) | |
379 | env_str = (*end) ? end+1 : end; | |
380 | } | |
381 | ||
382 | /* Set hardware address */ | |
383 | writel(env_enetaddr[0] | env_enetaddr[1] << 8 | | |
384 | env_enetaddr[2] << 16 | env_enetaddr[3] << 24, | |
385 | &emac->sa2l); | |
386 | writel((env_enetaddr[4] | env_enetaddr[5] << 8), &emac->sa2h); | |
387 | ||
00caae6d | 388 | printf("MAC: %s\n", env_get("ethaddr")); |
885fc03a AR |
389 | } else { |
390 | /* Not set in environment */ | |
391 | printf("MAC: not set\n"); | |
392 | } | |
393 | #ifdef CONFIG_GURNARD_SPLASH | |
394 | lcd_splash(480, 272); | |
395 | #endif | |
396 | ||
397 | return 0; | |
398 | } | |
399 | ||
400 | #ifndef CONFIG_DM_ETH | |
401 | int board_eth_init(bd_t *bis) | |
402 | { | |
403 | return macb_eth_initialize(0, (void *)ATMEL_BASE_EMAC, 0); | |
404 | } | |
405 | #endif | |
406 | ||
407 | int dram_init(void) | |
408 | { | |
409 | gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE, | |
410 | CONFIG_SYS_SDRAM_SIZE); | |
411 | return 0; | |
412 | } | |
413 | ||
414 | void reset_phy(void) | |
415 | { | |
416 | } | |
417 | ||
885fc03a AR |
418 | /* SPI chip select control - only used for FPGA programming */ |
419 | #ifdef CONFIG_ATMEL_SPI | |
420 | ||
421 | int spi_cs_is_valid(unsigned int bus, unsigned int cs) | |
422 | { | |
423 | return bus == 0 && cs == 0; | |
424 | } | |
425 | ||
426 | void spi_cs_activate(struct spi_slave *slave) | |
427 | { | |
428 | /* We don't use chipselects for FPGA programming */ | |
429 | } | |
430 | ||
431 | void spi_cs_deactivate(struct spi_slave *slave) | |
432 | { | |
433 | /* We don't use chipselects for FPGA programming */ | |
434 | } | |
435 | #endif /* CONFIG_ATMEL_SPI */ | |
436 | ||
437 | static struct atmel_serial_platdata at91sam9260_serial_plat = { | |
438 | .base_addr = ATMEL_BASE_DBGU, | |
439 | }; | |
440 | ||
441 | U_BOOT_DEVICE(at91sam9260_serial) = { | |
442 | .name = "serial_atmel", | |
443 | .platdata = &at91sam9260_serial_plat, | |
444 | }; |