diff options
author | Andre Renaud <andre@designa-electronics.com> | 2016-05-05 07:28:22 -0600 |
---|---|---|
committer | Andreas Bießmann <andreas@biessmann.org> | 2016-06-12 23:49:38 +0200 |
commit | 885fc03aab946d3c0a842aaf32f9513e3a7c8c20 (patch) | |
tree | b10ac573d74615b7f282f17d6cf4e717d61a3eff /board/bluewater/gurnard/gurnard.c | |
parent | 04b9dd10cc11e4f603a2bae9cf4cc21af1229534 (diff) | |
download | u-boot-imx-885fc03aab946d3c0a842aaf32f9513e3a7c8c20.zip u-boot-imx-885fc03aab946d3c0a842aaf32f9513e3a7c8c20.tar.gz u-boot-imx-885fc03aab946d3c0a842aaf32f9513e3a7c8c20.tar.bz2 |
arm: at91: Add support for gurnard
This board is based on Snapper 9G45 which has an Atmel AT91SAM9G45 chip and
128MB of SDRAM. It includes a small LCD, 2xUSB host, SD card, Ethernet and
two UARTs.
Signed-off-by: Andre Renaud <andre@designa-electronics.com>
Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Andreas Bießmann <andreas@biessmann.org>
[apply CONFIG_BOOTDELAY transition]
Signed-off-by: Andreas Bießmann <andreas@biessmann.org>
Diffstat (limited to 'board/bluewater/gurnard/gurnard.c')
-rw-r--r-- | board/bluewater/gurnard/gurnard.c | 449 |
1 files changed, 449 insertions, 0 deletions
diff --git a/board/bluewater/gurnard/gurnard.c b/board/bluewater/gurnard/gurnard.c new file mode 100644 index 0000000..2a36d29 --- /dev/null +++ b/board/bluewater/gurnard/gurnard.c @@ -0,0 +1,449 @@ +/* + * Bluewater Systems Snapper 9260/9G20 modules + * + * (C) Copyright 2011 Bluewater Systems + * Author: Andre Renaud <andre@bluewatersys.com> + * Author: Ryan Mallon <ryan@bluewatersys.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <atmel_lcd.h> +#include <atmel_lcdc.h> +#include <atmel_mci.h> +#include <dm.h> +#include <lcd.h> +#include <net.h> +#ifndef CONFIG_DM_ETH +#include <netdev.h> +#endif +#include <spi.h> +#include <asm/gpio.h> +#include <asm/io.h> +#include <asm/arch/at91sam9g45_matrix.h> +#include <asm/arch/at91sam9_smc.h> +#include <asm/arch/at91_common.h> +#include <asm/arch/at91_emac.h> +#include <asm/arch/at91_rstc.h> +#include <asm/arch/at91_rtc.h> +#include <asm/arch/at91_sck.h> +#include <asm/arch/atmel_serial.h> +#include <asm/arch/clk.h> +#include <asm/arch/gpio.h> +#include <dm/uclass-internal.h> + +#ifdef CONFIG_GURNARD_SPLASH +#include "splash_logo.h" +#endif + +DECLARE_GLOBAL_DATA_PTR; + +/* IO Expander pins */ +#define IO_EXP_ETH_RESET (0 << 1) +#define IO_EXP_ETH_POWER (1 << 1) + +#ifdef CONFIG_MACB +static void gurnard_macb_hw_init(void) +{ + struct at91_port *pioa = (struct at91_port *)ATMEL_BASE_PIOA; + + at91_periph_clk_enable(ATMEL_ID_EMAC); + + /* + * Enable pull-up on: + * RXDV (PA12) => MODE0 - PHY also has pull-up + * ERX0 (PA13) => MODE1 - PHY also has pull-up + * ERX1 (PA15) => MODE2 - PHY also has pull-up + */ + writel(pin_to_mask(AT91_PIN_PA15) | + pin_to_mask(AT91_PIN_PA12) | + pin_to_mask(AT91_PIN_PA13), + &pioa->puer); + + at91_phy_reset(); + + at91_macb_hw_init(); +} +#endif + +#ifdef CONFIG_CMD_NAND +static int gurnard_nand_hw_init(void) +{ + struct at91_matrix *matrix = (struct at91_matrix *)ATMEL_BASE_MATRIX; + struct at91_smc *smc = (struct at91_smc *)ATMEL_BASE_SMC; + ulong flags; + int ret; + + /* Enable CS3 as NAND/SmartMedia */ + setbits_le32(&matrix->ebicsa, AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA); + + /* Configure SMC CS3 for NAND/SmartMedia */ + writel(AT91_SMC_SETUP_NWE(2) | AT91_SMC_SETUP_NCS_WR(0) | + AT91_SMC_SETUP_NRD(2) | AT91_SMC_SETUP_NCS_RD(0), + &smc->cs[3].setup); + writel(AT91_SMC_PULSE_NWE(4) | AT91_SMC_PULSE_NCS_WR(4) | + AT91_SMC_PULSE_NRD(4) | AT91_SMC_PULSE_NCS_RD(4), + &smc->cs[3].pulse); + writel(AT91_SMC_CYCLE_NWE(7) | AT91_SMC_CYCLE_NRD(7), + &smc->cs[3].cycle); +#ifdef CONFIG_SYS_NAND_DBW_16 + flags = AT91_SMC_MODE_DBW_16; +#else + flags = AT91_SMC_MODE_DBW_8; +#endif + writel(AT91_SMC_MODE_RM_NRD | AT91_SMC_MODE_WM_NWE | + AT91_SMC_MODE_EXNW_DISABLE | + flags | + AT91_SMC_MODE_TDF_CYCLE(3), + &smc->cs[3].mode); + + ret = gpio_request(CONFIG_SYS_NAND_READY_PIN, "nand_rdy"); + if (ret) + return ret; + gpio_direction_input(CONFIG_SYS_NAND_READY_PIN); + + /* Enable NandFlash */ + ret = gpio_request(CONFIG_SYS_NAND_ENABLE_PIN, "nand_ce"); + if (ret) + return ret; + gpio_direction_output(CONFIG_SYS_NAND_ENABLE_PIN, 1); + + return 0; +} +#endif + +#ifdef CONFIG_GURNARD_SPLASH +static void lcd_splash(int width, int height) +{ + u16 colour; + int x, y; + u16 *base_addr = (u16 *)gd->video_bottom; + + memset(base_addr, 0xff, width * height * 2); + /* + * Blit the logo to the center of the screen + */ + for (y = 0; y < BMP_LOGO_HEIGHT; y++) { + for (x = 0; x < BMP_LOGO_WIDTH; x++) { + int posx, posy; + colour = bmp_logo_palette[bmp_logo_bitmap[ + y * BMP_LOGO_WIDTH + x]]; + posx = x + (width - BMP_LOGO_WIDTH) / 2; + posy = y; + base_addr[posy * width + posx] = colour; + } + } +} +#endif + +#ifdef CONFIG_DM_VIDEO +static void at91sam9g45_lcd_hw_init(void) +{ + at91_set_A_periph(AT91_PIN_PE0, 0); /* LCDDPWR */ + at91_set_A_periph(AT91_PIN_PE2, 0); /* LCDCC */ + at91_set_A_periph(AT91_PIN_PE3, 0); /* LCDVSYNC */ + at91_set_A_periph(AT91_PIN_PE4, 0); /* LCDHSYNC */ + at91_set_A_periph(AT91_PIN_PE5, 0); /* LCDDOTCK */ + + at91_set_A_periph(AT91_PIN_PE7, 0); /* LCDD0 */ + at91_set_A_periph(AT91_PIN_PE8, 0); /* LCDD1 */ + at91_set_A_periph(AT91_PIN_PE9, 0); /* LCDD2 */ + at91_set_A_periph(AT91_PIN_PE10, 0); /* LCDD3 */ + at91_set_A_periph(AT91_PIN_PE11, 0); /* LCDD4 */ + at91_set_A_periph(AT91_PIN_PE12, 0); /* LCDD5 */ + at91_set_A_periph(AT91_PIN_PE13, 0); /* LCDD6 */ + at91_set_A_periph(AT91_PIN_PE14, 0); /* LCDD7 */ + at91_set_A_periph(AT91_PIN_PE15, 0); /* LCDD8 */ + at91_set_A_periph(AT91_PIN_PE16, 0); /* LCDD9 */ + at91_set_A_periph(AT91_PIN_PE17, 0); /* LCDD10 */ + at91_set_A_periph(AT91_PIN_PE18, 0); /* LCDD11 */ + at91_set_A_periph(AT91_PIN_PE19, 0); /* LCDD12 */ + at91_set_B_periph(AT91_PIN_PE20, 0); /* LCDD13 */ + at91_set_A_periph(AT91_PIN_PE21, 0); /* LCDD14 */ + at91_set_A_periph(AT91_PIN_PE22, 0); /* LCDD15 */ + at91_set_A_periph(AT91_PIN_PE23, 0); /* LCDD16 */ + at91_set_A_periph(AT91_PIN_PE24, 0); /* LCDD17 */ + at91_set_A_periph(AT91_PIN_PE25, 0); /* LCDD18 */ + at91_set_A_periph(AT91_PIN_PE26, 0); /* LCDD19 */ + at91_set_A_periph(AT91_PIN_PE27, 0); /* LCDD20 */ + at91_set_B_periph(AT91_PIN_PE28, 0); /* LCDD21 */ + at91_set_A_periph(AT91_PIN_PE29, 0); /* LCDD22 */ + at91_set_A_periph(AT91_PIN_PE30, 0); /* LCDD23 */ + + at91_periph_clk_enable(ATMEL_ID_LCDC); +} +#endif + +#ifdef CONFIG_GURNARD_FPGA +/** + * Initialise the memory bus settings so that we can talk to the + * memory mapped FPGA + */ +static int fpga_hw_init(void) +{ + struct at91_matrix *matrix = (struct at91_matrix *)ATMEL_BASE_MATRIX; + struct at91_smc *smc = (struct at91_smc *)ATMEL_BASE_SMC; + int i; + + setbits_le32(&matrix->ebicsa, AT91_MATRIX_EBI_CS1A_SDRAMC); + + at91_set_a_periph(2, 4, 0); /* EBIA21 */ + at91_set_a_periph(2, 5, 0); /* EBIA22 */ + at91_set_a_periph(2, 6, 0); /* EBIA23 */ + at91_set_a_periph(2, 7, 0); /* EBIA24 */ + at91_set_a_periph(2, 12, 0); /* EBIA25 */ + for (i = 15; i <= 31; i++) /* EBINWAIT & EBID16 - 31 */ + at91_set_a_periph(2, i, 0); + + /* configure SMC cs0 for FPGA access timing */ + writel(AT91_SMC_SETUP_NWE(1) | AT91_SMC_SETUP_NCS_WR(2) | + AT91_SMC_SETUP_NRD(0) | AT91_SMC_SETUP_NCS_RD(2), + &smc->cs[0].setup); + writel(AT91_SMC_PULSE_NWE(5) | AT91_SMC_PULSE_NCS_WR(4) | + AT91_SMC_PULSE_NRD(6) | AT91_SMC_PULSE_NCS_RD(4), + &smc->cs[0].pulse); + writel(AT91_SMC_CYCLE_NWE(6) | AT91_SMC_CYCLE_NRD(6), + &smc->cs[0].cycle); + writel(AT91_SMC_MODE_BAT | + AT91_SMC_MODE_EXNW_DISABLE | + AT91_SMC_MODE_DBW_32 | + AT91_SMC_MODE_TDF | + AT91_SMC_MODE_TDF_CYCLE(2), + &smc->cs[0].mode); + + /* Do a write to within EBI_CS1 to enable the SDCK */ + writel(0, ATMEL_BASE_CS1); + + return 0; +} +#endif + +#ifdef CONFIG_CMD_USB + +#define USB0_ENABLE_PIN AT91_PIN_PB22 +#define USB1_ENABLE_PIN AT91_PIN_PB23 + +void gurnard_usb_init(void) +{ + at91_set_gpio_output(USB0_ENABLE_PIN, 1); + at91_set_gpio_value(USB0_ENABLE_PIN, 0); + at91_set_gpio_output(USB1_ENABLE_PIN, 1); + at91_set_gpio_value(USB1_ENABLE_PIN, 0); +} +#endif + +#ifdef CONFIG_GENERIC_ATMEL_MCI +int cpu_mmc_init(bd_t *bis) +{ + return atmel_mci_init((void *)ATMEL_BASE_MCI0); +} +#endif + +static void gurnard_enable_console(int enable) +{ + at91_set_gpio_output(AT91_PIN_PB14, 1); + at91_set_gpio_value(AT91_PIN_PB14, enable ? 0 : 1); +} + +void at91sam9g45_slowclock_init(void) +{ + /* + * On AT91SAM9G45 revC CPUs, the slow clock can be based on an + * internal impreciseRC oscillator or an external 32kHz oscillator. + * Switch to the latter. + */ + unsigned i, tmp; + ulong *reg = (ulong *)ATMEL_BASE_SCKCR; + + tmp = readl(reg); + if ((tmp & AT91SAM9G45_SCKCR_OSCSEL) == AT91SAM9G45_SCKCR_OSCSEL_RC) { + timer_init(); + tmp |= AT91SAM9G45_SCKCR_OSC32EN; + writel(tmp, reg); + for (i = 0; i < 1200; i++) + udelay(1000); + tmp |= AT91SAM9G45_SCKCR_OSCSEL_32; + writel(tmp, reg); + udelay(200); + tmp &= ~AT91SAM9G45_SCKCR_RCEN; + writel(tmp, reg); + } +} + +int board_early_init_f(void) +{ + at91_seriald_hw_init(); + gurnard_enable_console(1); + + return 0; +} + +int board_init(void) +{ + const char *rev_str; +#ifdef CONFIG_CMD_NAND + int ret; +#endif + + at91_periph_clk_enable(ATMEL_ID_PIOA); + at91_periph_clk_enable(ATMEL_ID_PIOB); + at91_periph_clk_enable(ATMEL_ID_PIOC); + at91_periph_clk_enable(ATMEL_ID_PIODE); + + at91sam9g45_slowclock_init(); + + /* + * Clear the RTC IDR to disable all IRQs. Avoid issues when Linux + * boots with spurious IRQs. + */ + writel(0xffffffff, AT91_RTC_IDR); + + /* Make sure that the reset signal is attached properly */ + setbits_le32(AT91_ASM_RSTC_MR, AT91_RSTC_KEY | AT91_RSTC_MR_URSTEN); + + gd->bd->bi_arch_number = MACH_TYPE_SNAPPER_9260; + + /* Address of boot parameters */ + gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100; + +#ifdef CONFIG_CMD_NAND + ret = gurnard_nand_hw_init(); + if (ret) + return ret; +#endif +#ifdef CONFIG_ATMEL_SPI + at91_spi0_hw_init(1 << 4); +#endif + +#ifdef CONFIG_MACB + gurnard_macb_hw_init(); +#endif + +#ifdef CONFIG_GURNARD_FPGA + fpga_hw_init(); +#endif + +#ifdef CONFIG_CMD_USB + gurnard_usb_init(); +#endif + +#ifdef CONFIG_CMD_MMC + at91_set_A_periph(AT91_PIN_PA12, 0); + at91_set_gpio_output(AT91_PIN_PA8, 1); + at91_set_gpio_value(AT91_PIN_PA8, 0); + at91_mci_hw_init(); +#endif + +#ifdef CONFIG_DM_VIDEO + at91sam9g45_lcd_hw_init(); + at91_set_A_periph(AT91_PIN_PE6, 1); /* power up */ + + /* Select the second timing index for board rev 2 */ + rev_str = getenv("board_rev"); + if (rev_str && !strncmp(rev_str, "2", 1)) { + struct udevice *dev; + + uclass_find_first_device(UCLASS_VIDEO, &dev); + if (dev) { + struct atmel_lcd_platdata *plat = dev_get_platdata(dev); + + plat->timing_index = 1; + } + } +#endif + + return 0; +} + +int board_late_init(void) +{ + u_int8_t env_enetaddr[8]; + char *env_str; + char *end; + int i; + + /* + * Set MAC address so we do not need to init Ethernet before Linux + * boot + */ + env_str = getenv("ethaddr"); + if (env_str) { + struct at91_emac *emac = (struct at91_emac *)ATMEL_BASE_EMAC; + /* Parse MAC address */ + for (i = 0; i < 6; i++) { + env_enetaddr[i] = env_str ? + simple_strtoul(env_str, &end, 16) : 0; + if (env_str) + env_str = (*end) ? end+1 : end; + } + + /* Set hardware address */ + writel(env_enetaddr[0] | env_enetaddr[1] << 8 | + env_enetaddr[2] << 16 | env_enetaddr[3] << 24, + &emac->sa2l); + writel((env_enetaddr[4] | env_enetaddr[5] << 8), &emac->sa2h); + + printf("MAC: %s\n", getenv("ethaddr")); + } else { + /* Not set in environment */ + printf("MAC: not set\n"); + } +#ifdef CONFIG_GURNARD_SPLASH + lcd_splash(480, 272); +#endif + + return 0; +} + +#ifndef CONFIG_DM_ETH +int board_eth_init(bd_t *bis) +{ + return macb_eth_initialize(0, (void *)ATMEL_BASE_EMAC, 0); +} +#endif + +int dram_init(void) +{ + gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE, + CONFIG_SYS_SDRAM_SIZE); + return 0; +} + +void reset_phy(void) +{ +} + +/* This breaks the Ethernet MAC at present */ +void enable_caches(void) +{ + dcache_enable(); +} + +/* SPI chip select control - only used for FPGA programming */ +#ifdef CONFIG_ATMEL_SPI + +int spi_cs_is_valid(unsigned int bus, unsigned int cs) +{ + return bus == 0 && cs == 0; +} + +void spi_cs_activate(struct spi_slave *slave) +{ + /* We don't use chipselects for FPGA programming */ +} + +void spi_cs_deactivate(struct spi_slave *slave) +{ + /* We don't use chipselects for FPGA programming */ +} +#endif /* CONFIG_ATMEL_SPI */ + +static struct atmel_serial_platdata at91sam9260_serial_plat = { + .base_addr = ATMEL_BASE_DBGU, +}; + +U_BOOT_DEVICE(at91sam9260_serial) = { + .name = "serial_atmel", + .platdata = &at91sam9260_serial_plat, +}; |