diff options
Diffstat (limited to 'board/freescale/mx6q_sabrelite/mx6q_sabrelite.c')
-rw-r--r-- | board/freescale/mx6q_sabrelite/mx6q_sabrelite.c | 623 |
1 files changed, 623 insertions, 0 deletions
diff --git a/board/freescale/mx6q_sabrelite/mx6q_sabrelite.c b/board/freescale/mx6q_sabrelite/mx6q_sabrelite.c new file mode 100644 index 0000000..39cd827 --- /dev/null +++ b/board/freescale/mx6q_sabrelite/mx6q_sabrelite.c @@ -0,0 +1,623 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/mx6.h> +#include <asm/arch/mx6_pins.h> +#include <asm/arch/iomux-v3.h> +#include <asm/errno.h> +#include <miiphy.h> +#if CONFIG_I2C_MXC +#include <i2c.h> +#endif + +#ifdef CONFIG_CMD_MMC +#include <mmc.h> +#include <fsl_esdhc.h> +#endif + +#ifdef CONFIG_ARCH_MMU +#include <asm/mmu.h> +#include <asm/arch/mmu.h> +#endif + +#ifdef CONFIG_GET_FEC_MAC_ADDR_FROM_IIM +#include <asm/imx_iim.h> +#endif + +#ifdef CONFIG_CMD_CLOCK +#include <asm/clock.h> +#endif + +#ifdef CONFIG_IMX_ECSPI +#include <imx_spi.h> +#endif + +DECLARE_GLOBAL_DATA_PTR; + +static u32 system_rev; +static enum boot_device boot_dev; + +static void set_gpio_output_val(unsigned base, unsigned mask, unsigned val) +{ + unsigned reg = readl(base + GPIO_DR); + if (val & 1) + reg |= mask; /* set high */ + else + reg &= ~mask; /* clear low */ + writel(reg, base + GPIO_DR); + + reg = readl(base + GPIO_GDIR); + reg |= mask; /* configure GPIO line as output */ + writel(reg, base + GPIO_GDIR); +} + +static inline void setup_boot_device(void) +{ + uint soc_sbmr = readl(SRC_BASE_ADDR + 0x4); + uint bt_mem_ctl = (soc_sbmr & 0x000000FF) >> 4; + uint bt_mem_type = (soc_sbmr & 0x00000008) >> 3; + + switch (bt_mem_ctl) { + case 0x0: + if (bt_mem_type) + boot_dev = ONE_NAND_BOOT; + else + boot_dev = WEIM_NOR_BOOT; + break; + case 0x2: + boot_dev = SATA_BOOT; + break; + case 0x3: + if (bt_mem_type) + boot_dev = SPI_NOR_BOOT; + else + boot_dev = I2C_BOOT; + break; + case 0x4: + case 0x5: + boot_dev = SD_BOOT; + break; + case 0x6: + case 0x7: + boot_dev = MMC_BOOT; + break; + case 0x8 ... 0xf: + boot_dev = NAND_BOOT; + break; + default: + boot_dev = UNKNOWN_BOOT; + break; + } +} + +enum boot_device get_boot_device(void) +{ + return boot_dev; +} + +u32 get_board_rev(void) +{ + + system_rev = 0x63000; + + return system_rev; +} + +#ifdef CONFIG_ARCH_MMU +void board_mmu_init(void) +{ + unsigned long ttb_base = PHYS_SDRAM_1 + 0x4000; + unsigned long i; + + /* + * Set the TTB register + */ + asm volatile ("mcr p15,0,%0,c2,c0,0" : : "r" (ttb_base) /*: */); + + /* + * Set the Domain Access Control Register + */ + i = ARM_ACCESS_DACR_DEFAULT; + asm volatile ("mcr p15,0,%0,c3,c0,0" : : "r" (i) /*: */); + + /* + * First clear all TT entries - ie Set them to Faulting + */ + memset((void *)ttb_base, 0, ARM_FIRST_LEVEL_PAGE_TABLE_SIZE); + /* Actual Virtual Size Attributes Function */ + /* Base Base MB cached? buffered? access permissions */ + /* xxx00000 xxx00000 */ + X_ARM_MMU_SECTION(0x000, 0x000, 0x001, ARM_UNCACHEABLE, ARM_UNBUFFERABLE, ARM_ACCESS_PERM_RW_RW); /* ROM, 1M */ + X_ARM_MMU_SECTION(0x001, 0x001, 0x008, ARM_UNCACHEABLE, ARM_UNBUFFERABLE, ARM_ACCESS_PERM_RW_RW); /* 8M */ + X_ARM_MMU_SECTION(0x009, 0x009, 0x001, ARM_UNCACHEABLE, ARM_UNBUFFERABLE, ARM_ACCESS_PERM_RW_RW); /* IRAM */ + X_ARM_MMU_SECTION(0x00A, 0x00A, 0x0F6, ARM_UNCACHEABLE, ARM_UNBUFFERABLE, ARM_ACCESS_PERM_RW_RW); /* 246M */ + /* 2 GB memory starting at 0x10000000, only map 1.875 GB */ + X_ARM_MMU_SECTION(0x100, 0x100, 0x780, + ARM_CACHEABLE, ARM_BUFFERABLE, ARM_ACCESS_PERM_RW_RW); + /* uncached alias of the same 1.875 GB memory */ + X_ARM_MMU_SECTION(0x100, 0x880, 0x780, + ARM_UNCACHEABLE, ARM_UNBUFFERABLE, + ARM_ACCESS_PERM_RW_RW); + + /* Enable MMU */ + MMU_ON(); +} +#endif + +int dram_init(void) +{ + gd->bd->bi_dram[0].start = PHYS_SDRAM_1; + gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE; + return 0; +} + +static void setup_uart(void) +{ + /* UART1 TXD */ + mxc_iomux_v3_setup_pad(MX6Q_PAD_SD3_DAT6__UART1_TXD); + + /* UART1 RXD */ + mxc_iomux_v3_setup_pad(MX6Q_PAD_SD3_DAT7__UART1_RXD); + + /* UART2 TXD */ + mxc_iomux_v3_setup_pad(MX6Q_PAD_EIM_D26__UART2_TXD); + + /* UART2 RXD */ + mxc_iomux_v3_setup_pad(MX6Q_PAD_EIM_D27__UART2_RXD); +} + +#ifdef CONFIG_I2C_MXC +static void setup_i2c(unsigned int module_base) +{ + unsigned int reg; + + switch (module_base) { + case I2C1_BASE_ADDR: + /* i2c1 SDA */ + mxc_iomux_v3_setup_pad(MX6Q_PAD_CSI0_DAT8__I2C1_SDA); + + /* i2c1 SCL */ + mxc_iomux_v3_setup_pad(MX6Q_PAD_CSI0_DAT9__I2C1_SCL); + + /* Enable i2c clock */ + reg = readl(CCM_BASE_ADDR + CLKCTL_CCGR2); + reg |= 0xC0; + writel(reg, CCM_BASE_ADDR + CLKCTL_CCGR2); + + break; + case I2C2_BASE_ADDR: + /* i2c2 SDA */ + mxc_iomux_v3_setup_pad(MX6Q_PAD_KEY_ROW3__I2C2_SDA); + + /* i2c2 SCL */ + mxc_iomux_v3_setup_pad(MX6Q_PAD_KEY_COL3__I2C2_SCL); + + /* Enable i2c clock */ + reg = readl(CCM_BASE_ADDR + CLKCTL_CCGR2); + reg |= 0x300; + writel(reg, CCM_BASE_ADDR + CLKCTL_CCGR2); + + break; + case I2C3_BASE_ADDR: + /* GPIO_5 for I2C3_SCL */ + mxc_iomux_v3_setup_pad(MX6Q_PAD_GPIO_5__I2C3_SCL); + + /* GPIO_16 for I2C3_SDA */ + mxc_iomux_v3_setup_pad(MX6Q_PAD_GPIO_16__I2C3_SDA); + + /* Enable i2c clock */ + reg = readl(CCM_BASE_ADDR + CLKCTL_CCGR2); + reg |= 0xC00; + writel(reg, CCM_BASE_ADDR + CLKCTL_CCGR2); + + break; + default: + printf("Invalid I2C base: 0x%x\n", module_base); + break; + } +} + +#endif + +#ifdef CONFIG_IMX_ECSPI +s32 spi_get_cfg(struct imx_spi_dev_t *dev) +{ + switch (dev->slave.cs) { + case 0: + /* PMIC */ + dev->base = ECSPI1_BASE_ADDR; + dev->freq = 25000000; + dev->ss_pol = IMX_SPI_ACTIVE_HIGH; + dev->ss = 0; + dev->fifo_sz = 64 * 4; + dev->us_delay = 0; + break; + case 1: + /* SPI-NOR */ + dev->base = ECSPI1_BASE_ADDR; + dev->freq = 25000000; + dev->ss_pol = IMX_SPI_ACTIVE_LOW; + dev->ss = 1; + dev->fifo_sz = 64 * 4; + dev->us_delay = 0; + break; + default: + printf("Invalid Bus ID!\n"); + } + + return 0; +} + +void spi_io_init(struct imx_spi_dev_t *dev) +{ + switch (dev->base) { + case ECSPI1_BASE_ADDR: + /* SCLK */ + mxc_iomux_v3_setup_pad(MX6Q_PAD_EIM_D16__ECSPI1_SCLK); + + /* MISO */ + mxc_iomux_v3_setup_pad(MX6Q_PAD_EIM_D17__ECSPI1_MISO); + + /* MOSI */ + mxc_iomux_v3_setup_pad(MX6Q_PAD_EIM_D18__ECSPI1_MOSI); + + if (dev->ss == 1) + mxc_iomux_v3_setup_pad(MX6Q_PAD_EIM_D19__ECSPI1_SS1); + break; + case ECSPI2_BASE_ADDR: + case ECSPI3_BASE_ADDR: + /* ecspi2-3 fall through */ + break; + default: + break; + } +} +#endif + +#define HW_OCOTP_MACn(n) (0x00000620 + (n) * 0x10) + +#ifdef CONFIG_MXC_FEC +#ifdef CONFIG_GET_FEC_MAC_ADDR_FROM_IIM + +int fec_get_mac_addr(unsigned char *mac) +{ + u32 *ocotp_mac_base = (u32 *) (OCOTP_BASE_ADDR + HW_OCOTP_MACn(0)); + int i; + + for (i = 0; i < 6; ++i, ++ocotp_mac_base) + mac[6 - 1 - i] = readl(++ocotp_mac_base); + return 0; +} + +#endif +#endif + +#ifdef CONFIG_NET_MULTI +int board_eth_init(bd_t *bis) +{ + int rc = -ENODEV; + + return rc; +} +#endif + +#ifdef CONFIG_CMD_MMC + +struct fsl_esdhc_cfg usdhc_cfg[2] = { + {USDHC3_BASE_ADDR, 1, 1, 1}, + {USDHC4_BASE_ADDR, 1, 1, 1}, +}; + +#ifdef CONFIG_DYNAMIC_MMC_DEVNO +int get_mmc_env_devno(void) +{ + uint soc_sbmr = readl(SRC_BASE_ADDR + 0x4); + + /* BOOT_CFG2[3] and BOOT_CFG2[4] */ + return (soc_sbmr & 0x00001800) >> 11; +} +#endif + +iomux_v3_cfg_t mx6q_usdhc1_pads[] = { + MX6Q_PAD_SD1_CLK__USDHC1_CLK, + MX6Q_PAD_SD1_CMD__USDHC1_CMD, + MX6Q_PAD_SD1_DAT0__USDHC1_DAT0, + MX6Q_PAD_SD1_DAT1__USDHC1_DAT1, + MX6Q_PAD_SD1_DAT2__USDHC1_DAT2, + MX6Q_PAD_SD1_DAT3__USDHC1_DAT3, +}; + +iomux_v3_cfg_t mx6q_usdhc2_pads[] = { + MX6Q_PAD_SD2_CLK__USDHC2_CLK, + MX6Q_PAD_SD2_CMD__USDHC2_CMD, + MX6Q_PAD_SD2_DAT0__USDHC2_DAT0, + MX6Q_PAD_SD2_DAT1__USDHC2_DAT1, + MX6Q_PAD_SD2_DAT2__USDHC2_DAT2, + MX6Q_PAD_SD2_DAT3__USDHC2_DAT3, +}; + +iomux_v3_cfg_t mx6q_usdhc3_pads[] = { + MX6Q_PAD_SD3_CLK__USDHC3_CLK, + MX6Q_PAD_SD3_CMD__USDHC3_CMD, + MX6Q_PAD_SD3_DAT0__USDHC3_DAT0, + MX6Q_PAD_SD3_DAT1__USDHC3_DAT1, + MX6Q_PAD_SD3_DAT2__USDHC3_DAT2, + MX6Q_PAD_SD3_DAT3__USDHC3_DAT3, +}; + +iomux_v3_cfg_t mx6q_usdhc4_pads[] = { + MX6Q_PAD_SD4_CLK__USDHC4_CLK, + MX6Q_PAD_SD4_CMD__USDHC4_CMD, + MX6Q_PAD_SD4_DAT0__USDHC4_DAT0, + MX6Q_PAD_SD4_DAT1__USDHC4_DAT1, + MX6Q_PAD_SD4_DAT2__USDHC4_DAT2, + MX6Q_PAD_SD4_DAT3__USDHC4_DAT3, +}; + +int usdhc_gpio_init(bd_t *bis) +{ + s32 status = 0; + u32 index = 0; + + for (index = 0; index < CONFIG_SYS_FSL_USDHC_NUM; index++) { + switch (index) { + case 0: + mxc_iomux_v3_setup_multiple_pads(mx6q_usdhc3_pads, + sizeof + (mx6q_usdhc3_pads) / + sizeof(mx6q_usdhc3_pads + [0])); + break; + case 1: + mxc_iomux_v3_setup_multiple_pads(mx6q_usdhc4_pads, + sizeof + (mx6q_usdhc4_pads) / + sizeof(mx6q_usdhc4_pads + [0])); + break; + default: + printf("Warning: you configured more USDHC controllers" + "(%d) then supported by the board (%d)\n", + index + 1, CONFIG_SYS_FSL_USDHC_NUM); + return status; + } + status |= fsl_esdhc_initialize(bis, &usdhc_cfg[index]); + } + + return status; +} + +int board_mmc_init(bd_t *bis) +{ + if (!usdhc_gpio_init(bis)) + return 0; + else + return -1; +} + +/* For DDR mode operation, provide target delay parameter for each SD port. + * Use cfg->esdhc_base to distinguish the SD port #. The delay for each port + * is dependent on signal layout for that particular port. If the following + * CONFIG is not defined, then the default target delay value will be used. + */ +#ifdef CONFIG_GET_DDR_TARGET_DELAY +u32 get_ddr_delay(struct fsl_esdhc *cfg) +{ + /* No delay required */ + return 0; +} +#endif + +#endif + +int board_init(void) +{ +#ifdef CONFIG_MFG +/* MFG firmware need reset usb to avoid host crash firstly */ +#define USBCMD 0x140 + int val = readl(OTG_BASE_ADDR + USBCMD); + val &= ~0x1; /*RS bit */ + writel(val, OTG_BASE_ADDR + USBCMD); +#endif + mxc_iomux_v3_init((void *)IOMUXC_BASE_ADDR); + setup_boot_device(); + + /* board id for linux */ + gd->bd->bi_arch_number = MACH_TYPE_MX6Q_SABRELITE; + + /* address of boot parameters */ + gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100; + + setup_uart(); + +#ifdef CONFIG_I2C_MXC + setup_i2c(CONFIG_SYS_I2C_PORT); +#endif + + return 0; +} + +int board_late_init(void) +{ + return 0; +} + +iomux_v3_cfg_t enet_pads[] = { + MX6Q_PAD_ENET_MDIO__ENET_MDIO, + MX6Q_PAD_ENET_MDC__ENET_MDC, + MX6Q_PAD_RGMII_TXC__ENET_RGMII_TXC, + MX6Q_PAD_RGMII_TD0__ENET_RGMII_TD0, + MX6Q_PAD_RGMII_TD1__ENET_RGMII_TD1, + MX6Q_PAD_RGMII_TD2__ENET_RGMII_TD2, + MX6Q_PAD_RGMII_TD3__ENET_RGMII_TD3, + MX6Q_PAD_RGMII_TX_CTL__ENET_RGMII_TX_CTL, + /* pin 35 - 1 (PHY_AD2) on reset */ + MX6Q_PAD_RGMII_RXC__GPIO_6_30, + /* pin 32 - 1 - (MODE0) all */ + MX6Q_PAD_RGMII_RD0__GPIO_6_25, + /* pin 31 - 1 - (MODE1) all */ + MX6Q_PAD_RGMII_RD1__GPIO_6_27, + /* pin 28 - 1 - (MODE2) all */ + MX6Q_PAD_RGMII_RD2__GPIO_6_28, + /* pin 27 - 1 - (MODE3) all */ + MX6Q_PAD_RGMII_RD3__GPIO_6_29, + /* pin 33 - 1 - (CLK125_EN) 125Mhz clockout enabled */ + MX6Q_PAD_RGMII_RX_CTL__GPIO_6_24, + MX6Q_PAD_GPIO_0__CCM_CLKO, + MX6Q_PAD_GPIO_3__CCM_CLKO2, + MX6Q_PAD_ENET_REF_CLK__ENET_TX_CLK, +}; + +iomux_v3_cfg_t enet_pads_final[] = { + MX6Q_PAD_RGMII_RXC__ENET_RGMII_RXC, + MX6Q_PAD_RGMII_RD0__ENET_RGMII_RD0, + MX6Q_PAD_RGMII_RD1__ENET_RGMII_RD1, + MX6Q_PAD_RGMII_RD2__ENET_RGMII_RD2, + MX6Q_PAD_RGMII_RD3__ENET_RGMII_RD3, + MX6Q_PAD_RGMII_RX_CTL__ENET_RGMII_RX_CTL, +}; + +static int phy_read(char *devname, unsigned char addr, unsigned char reg, + unsigned short *pdata) +{ + int ret = miiphy_read(devname, addr, reg, pdata); + if (ret) + printf("Error reading from %s PHY addr=%02x reg=%02x\n", + devname, addr, reg); + return ret; +} + +static int phy_write(char *devname, unsigned char addr, unsigned char reg, + unsigned short value) +{ + int ret = miiphy_write(devname, addr, reg, value); + if (ret) + printf("Error writing to %s PHY addr=%02x reg=%02x\n", devname, + addr, reg); + + return ret; +} + +int mx6_rgmii_rework(char *devname, int phy_addr) +{ +#if 0 + /* To advertise only 10 Mbs */ + phy_write(devname, phy_addr, 0x4, 0x61); + phy_write(devname, phy_addr, 0x9, 0x0c00); +#endif + + /* prefer master mode, 1000 Base-T capable */ + phy_write(devname, phy_addr, 0x9, 0x0f00); + + /* min rx data delay */ + phy_write(devname, phy_addr, 0x0b, 0x8105); + phy_write(devname, phy_addr, 0x0c, 0x0000); + + /* max rx/tx clock delay, min rx/tx control delay */ + phy_write(devname, phy_addr, 0x0b, 0x8104); + phy_write(devname, phy_addr, 0x0c, 0xf0f0); + phy_write(devname, phy_addr, 0x0b, 0x104); + return 0; +} + +void enet_board_init(void) +{ + iomux_v3_cfg_t enet_reset = + (MX6Q_PAD_EIM_D23__GPIO_3_23 & + ~MUX_PAD_CTRL_MASK) | MUX_PAD_CTRL(0x48); + + /* phy reset: gpio3-23 */ + set_gpio_output_val(GPIO3_BASE_ADDR, (1 << 23), 0); + set_gpio_output_val(GPIO6_BASE_ADDR, (1 << 30), + (CONFIG_FEC0_PHY_ADDR >> 2)); + set_gpio_output_val(GPIO6_BASE_ADDR, (1 << 25), 1); + set_gpio_output_val(GPIO6_BASE_ADDR, (1 << 27), 1); + set_gpio_output_val(GPIO6_BASE_ADDR, (1 << 28), 1); + set_gpio_output_val(GPIO6_BASE_ADDR, (1 << 29), 1); + mxc_iomux_v3_setup_multiple_pads(enet_pads, ARRAY_SIZE(enet_pads)); + mxc_iomux_v3_setup_pad(enet_reset); + set_gpio_output_val(GPIO6_BASE_ADDR, (1 << 24), 1); + + udelay(500); + set_gpio_output_val(GPIO3_BASE_ADDR, (1 << 23), 1); + mxc_iomux_v3_setup_multiple_pads(enet_pads_final, + ARRAY_SIZE(enet_pads_final)); +} + +int checkboard(void) +{ + printf("Board: MX6Q-SABRELITE:[ "); + + switch (__REG(SRC_BASE_ADDR + 0x8)) { + case 0x0001: + printf("POR"); + break; + case 0x0009: + printf("RST"); + break; + case 0x0010: + case 0x0011: + printf("WDOG"); + break; + default: + printf("unknown"); + } + printf("]\n"); + + printf("Boot Device: "); + switch (get_boot_device()) { + case WEIM_NOR_BOOT: + printf("NOR\n"); + break; + case ONE_NAND_BOOT: + printf("ONE NAND\n"); + break; + case PATA_BOOT: + printf("PATA\n"); + break; + case SATA_BOOT: + printf("SATA\n"); + break; + case I2C_BOOT: + printf("I2C\n"); + break; + case SPI_NOR_BOOT: + printf("SPI NOR\n"); + break; + case SD_BOOT: + printf("SD\n"); + break; + case MMC_BOOT: + printf("MMC\n"); + break; + case NAND_BOOT: + printf("NAND\n"); + break; + case UNKNOWN_BOOT: + default: + printf("UNKNOWN\n"); + break; + } + return 0; +} |