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