/* * (C) Copyright 2004-2006 * Texas Instruments, * Richard Woodruff * * 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 #include #include #include #include #include #include #include #include #include /****** DATA STRUCTURES ************/ /* Only One NAND allowed on board at a time. * The GPMC CS Base for the same */ unsigned int nand_cs_base = 0; unsigned int onenand_cs_base = 0; unsigned int boot_flash_base = 0; unsigned int boot_flash_off = 0; unsigned int boot_flash_sec = 0; volatile unsigned int boot_flash_env_addr = 0; /* help common/env_flash.c */ #ifdef ENV_IS_VARIABLE ulong NOR_FLASH_BANKS_LIST[CFG_MAX_FLASH_BANKS]; int NOR_MAX_FLASH_BANKS = 0 ; /* max number of flash banks */ uchar(*boot_env_get_char_spec) (int index); int (*boot_env_init) (void); int (*boot_saveenv) (void); void (*boot_env_relocate_spec) (void); /* StrataNor */ extern uchar flash_env_get_char_spec(int index); extern int flash_env_init(void); extern int flash_saveenv(void); extern void flash_env_relocate_spec(void); extern char *flash_env_name_spec; /* 16 bit NAND */ extern uchar nand_env_get_char_spec(int index); extern int nand_env_init(void); extern int nand_saveenv(void); extern void nand_env_relocate_spec(void); extern char *nand_env_name_spec; /* OneNAND */ #if (CONFIG_COMMANDS & CFG_CMD_ONENAND) extern char *onenand_env; extern uchar onenand_env_get_char_spec(int index); extern int onenand_env_init(void); extern int onenand_saveenv(void); extern void onenand_env_relocate_spec(void); extern char *onenand_env_name_spec; #endif /* Global fellows */ #if (CONFIG_COMMANDS & CFG_CMD_NAND) u8 is_nand = 0; #endif #if (CONFIG_COMMANDS & CFG_CMD_FLASH) u8 is_flash = 0; #endif #if (CONFIG_COMMANDS & CFG_CMD_ONENAND) u8 is_onenand = 0; #endif #ifndef CONFIG_STORAGE_EMMC char *env_name_spec = 0; env_t *env_ptr = 0; #endif #if ((CONFIG_COMMANDS&(CFG_CMD_ENV|CFG_CMD_FLASH)) == (CFG_CMD_ENV|CFG_CMD_FLASH)) extern env_t *flash_addr; #endif #endif /* ENV_IS_VARIABLE */ /* Following CS organization may Different from Board to Board */ static const unsigned char chip_sel[][GPMC_MAX_CS] = { #ifdef CONFIG_3630SDP /* GPMC CS Indices (ON=0, OFF=1)*/ /* S8-1 2 3 4 IDX CS0, CS1, CS2 .. CS7 */ /*0 0 0 0*/{PISMO1_NOR, PISMO1_NAND, PISMO1_ONENAND, DBG_MPDB, 0, 0, 0, 0}, /*0 0 0 1*/{PISMO1_ONENAND, PISMO1_NAND, PISMO1_NOR, DBG_MPDB, 0, 0, 0, 0}, /*0 0 1 0*/{PISMO1_NAND, PISMO1_ONENAND, PISMO1_NOR, DBG_MPDB, 0, 0, 0, 0}, /*0 0 1 1*/{PISMO1_NOR, PISMO2_CS0, PISMO2_CS1, DBG_MPDB, 0, 0, 0, 0}, /*0 1 0 0*/{PISMO1_ONENAND, PISMO2_CS0, PISMO2_CS1, DBG_MPDB, 0, 0, 0, 0}, /*0 1 0 1*/{PISMO1_NAND, PISMO2_CS0, PISMO2_CS1, DBG_MPDB, 0, 0, 0, 0}, /*0 1 1 0*/{PISMO1_NOR, PISMO2_NAND_CS0, PISMO2_NAND_CS1, DBG_MPDB, 0, 0, 0, 0}, /*0 1 1 1*/ {PISMO1_ONENAND, PISMO2_NAND_CS0, PISMO2_NAND_CS1, DBG_MPDB, 0, 0, 0, 0} #else /*ON OFF ON OFF*/{PISMO1_NAND, 0, 0, 0, 0, 0, 0, 0} #endif }; /* Values for each of the chips */ #ifdef CONFIG_3630SDP static u32 gpmc_mpdb[GPMC_MAX_REG] = { SDPV2_MPDB_GPMC_CONFIG1, SDPV2_MPDB_GPMC_CONFIG2, SDPV2_MPDB_GPMC_CONFIG3, SDPV2_MPDB_GPMC_CONFIG4, SDPV2_MPDB_GPMC_CONFIG5, SDPV2_MPDB_GPMC_CONFIG6, 0 }; #else static u32 gpmc_enet[GPMC_MAX_REG] = { LAB_ENET_GPMC_CONFIG1, LAB_ENET_GPMC_CONFIG2, LAB_ENET_GPMC_CONFIG3, LAB_ENET_GPMC_CONFIG4, LAB_ENET_GPMC_CONFIG5, LAB_ENET_GPMC_CONFIG6, 0 }; #endif #ifdef CONFIG_3430ZOOM2 static u32 gpmc_serial_TL16CP754C[GPMC_MAX_REG] = { 0x00011000, 0x001F1F01, 0x00080803, 0x1D091D09, 0x041D1F1F, 0x1D0904C4, 0 }; #endif #if (CONFIG_COMMANDS & CFG_CMD_FLASH) static u32 gpmc_sibnor[GPMC_MAX_REG] = { SIBNOR_GPMC_CONFIG1, SIBNOR_GPMC_CONFIG2, SIBNOR_GPMC_CONFIG3, SIBNOR_GPMC_CONFIG4, SIBNOR_GPMC_CONFIG5, SIBNOR_GPMC_CONFIG6, 0 }; #endif static u32 gpmc_pismo2[GPMC_MAX_REG] = { P2_GPMC_CONFIG1, P2_GPMC_CONFIG2, P2_GPMC_CONFIG3, P2_GPMC_CONFIG4, P2_GPMC_CONFIG5, P2_GPMC_CONFIG6, 0 }; #if (CONFIG_COMMANDS & CFG_CMD_ONENAND) static u32 gpmc_onenand[GPMC_MAX_REG] = { ONENAND_GPMC_CONFIG1, ONENAND_GPMC_CONFIG2, ONENAND_GPMC_CONFIG3, ONENAND_GPMC_CONFIG4, ONENAND_GPMC_CONFIG5, ONENAND_GPMC_CONFIG6, 0 }; #endif static u32 gpmc_m_nand[GPMC_MAX_REG] = { M_NAND_GPMC_CONFIG1, M_NAND_GPMC_CONFIG2, M_NAND_GPMC_CONFIG3, M_NAND_GPMC_CONFIG4, M_NAND_GPMC_CONFIG5, M_NAND_GPMC_CONFIG6, 0 }; /********** Functions ****/ /* ENV Functions */ #ifdef ENV_IS_VARIABLE uchar env_get_char_spec(int index) { if (!boot_env_get_char_spec) { puts("ERROR!! env_get_char_spec not available\n"); } else return boot_env_get_char_spec(index); return 0; } int env_init(void) { if (!boot_env_init) { puts("ERROR!! boot_env_init not available\n"); } else return boot_env_init(); return -1; } int saveenv(void) { if (!boot_saveenv) { puts("ERROR!! boot_saveenv not available\n"); } else return boot_saveenv(); return -1; } void env_relocate_spec(void) { if (!boot_env_relocate_spec) { puts("ERROR!! boot_env_relocate_spec not available\n"); } else boot_env_relocate_spec(); } #endif /************************************************************************** * make_cs1_contiguous() - for es2 and above remap cs1 behind cs0 to allow * command line mem=xyz use all memory with out discontinuous support * compiled in. Could do it at the ATAG, but there really is two banks... * Called as part of 2nd phase DDR init. **************************************************************************/ void make_cs1_contiguous(void) { u32 size, a_add_low, a_add_high; size = get_sdr_cs_size(SDRC_CS0_OSET); size /= SZ_32M; /* find size to offset CS1 */ a_add_high = (size & 3) << 8; /* set up low field */ a_add_low = (size & 0x3C) >> 2; /* set up high field */ __raw_writel((a_add_high | a_add_low), SDRC_CS_CFG); } /******************************************************** * mem_ok() - test used to see if timings are correct * for a part. Helps in guessing which part * we are currently using. *******************************************************/ u32 mem_ok(void) { u32 val1, val2, orig1, orig2, addr; u32 pattern = 0x12345678; addr = OMAP34XX_SDRC_CS0; orig1 = __raw_readl(addr + 0x400); /* try to save original value */ orig2 = __raw_readl(addr); __raw_writel(0x0, addr + 0x400); /* clear pos A */ __raw_writel(pattern, addr); /* pattern to pos B */ __raw_writel(0x0, addr + 4); /* remove pattern off the bus */ val1 = __raw_readl(addr + 0x400); /* get pos A value */ val2 = __raw_readl(addr); /* get val2 */ if ((val1 != 0) || (val2 != pattern)) /* see if pos A value changed */ return (0); else { /* restore original values and return pass */ __raw_writel(orig1, addr + 0x400); __raw_writel(orig2, addr); return (1); } } /******************************************************** * sdrc_init() - init the sdrc chip selects CS0 and CS1 * - early init routines, called from flash or * SRAM. *******************************************************/ void sdrc_init(void) { #define EARLY_INIT 1 do_sdrc_init(SDRC_CS0_OSET, EARLY_INIT); /* only init up first bank here */ } /************************************************************************* * do_sdrc_init(): initialize the SDRAM for use. * -code sets up SDRAM basic SDRC timings for CS0 * -optimal settings can be placed here, or redone after i2c * inspection of board info * * - code called ones in C-Stack only context for CS0 and a possible 2nd * time depending on memory configuration from stack+global context **************************************************************************/ void do_sdrc_init(u32 offset, u32 early) { u32 common = 0, cs0 = 0, pmask = 0, pass_type, mtype, mono = 0; if (offset == SDRC_CS0_OSET) cs0 = common = 1; /* int regs shared between both chip select */ pass_type = IP_DDR; /* If this is a 2nd pass init of a CS1, make it contiguous with CS0 */ if (!early && (((mtype = get_mem_type()) == DDR_COMBO) || (mtype == DDR_STACKED))) { if (mtype == DDR_COMBO) { pmask = BIT2; /* if shared CKE don't use */ pass_type = COMBO_DDR; /* CS1 config */ __raw_writel((__raw_readl(SDRC_POWER)) & ~pmask, SDRC_POWER); } make_cs1_contiguous(); } next_mem_type: if (common) { /* do a SDRC reset between types to clear regs */ /* check if its h/w or s/w reset for warm reset workaround */ if (__raw_readl(PRM_RSTTST) & 0x2) { /* Enable SDRC clock & wait SDRC idle status to access*/ sr32(CM_ICLKEN1_CORE, 1, 1, 0x1); wait_on_value(BIT1, 0, CM_IDLEST1_CORE, LDELAY); } else { /* do a SDRC reset between types to clear regs */ __raw_writel(SOFTRESET, SDRC_SYSCONFIG);/* reset sdrc */ /* wait on reset */ wait_on_value(BIT0, BIT0, SDRC_STATUS, 12000000); __raw_writel(0, SDRC_SYSCONFIG);/* clear soft reset */ } /* Clear reset sources */ __raw_writel(0xfff, PRM_RSTTST); __raw_writel(SDP_SDRC_SHARING, SDRC_SHARING); /* If its a 3430 ES1.0 silicon, configure WAKEUPPROC to 1 as per Errata 1.22 */ /* Need to change the condition to silicon and rev check */ if(1) __raw_writel((__raw_readl(SDRC_POWER)) | WAKEUPPROC , SDRC_POWER); #ifdef POWER_SAVE __raw_writel(__raw_readl(SMS_SYSCONFIG) | SMART_IDLE, SMS_SYSCONFIG); __raw_writel(SDP_SDRC_SHARING | SMART_IDLE, SDRC_SHARING); __raw_writel((__raw_readl(SDRC_POWER) | BIT6), SDRC_POWER); #endif } /* set MDCFG_0 values */ if ((pass_type == IP_DDR) || (pass_type == STACKED)) { __raw_writel(SDP_SDRC_MDCFG_0_DDR, SDRC_MCFG_0 + offset); if (mono) /* Stacked with memory on CS1 only */ __raw_writel(SDP_SDRC_MDCFG_MONO_DDR, SDRC_MCFG_0 + offset); } else if (pass_type == COMBO_DDR) { /* (combo-CS0/CS1) */ __raw_writel(SDP_COMBO_MDCFG_0_DDR, SDRC_MCFG_0 + offset); } else if (pass_type == IP_SDR) { /* ip sdr-CS0 */ __raw_writel(SDP_SDRC_MDCFG_0_SDR, SDRC_MCFG_0 + offset); } /* Set ACTIM values */ if (cs0) { __raw_writel(SDP_SDRC_ACTIM_CTRLA_0, SDRC_ACTIM_CTRLA_0); __raw_writel(SDP_SDRC_ACTIM_CTRLB_0, SDRC_ACTIM_CTRLB_0); } else { __raw_writel(SDP_SDRC_ACTIM_CTRLA_0, SDRC_ACTIM_CTRLA_1); __raw_writel(SDP_SDRC_ACTIM_CTRLB_0, SDRC_ACTIM_CTRLB_1); } __raw_writel(SDP_SDRC_RFR_CTRL, SDRC_RFR_CTRL_0 + offset); /* init sequence for mDDR/mSDR using manual commands (DDR is different) */ __raw_writel(CMD_NOP, SDRC_MANUAL_0 + offset); sdelay(5000); /* supposed to be 100us per design spec for mddr/msdr */ __raw_writel(CMD_PRECHARGE, SDRC_MANUAL_0 + offset); __raw_writel(CMD_AUTOREFRESH, SDRC_MANUAL_0 + offset); __raw_writel(CMD_AUTOREFRESH, SDRC_MANUAL_0 + offset); /* Set MR0 values */ if (pass_type == IP_SDR) __raw_writel(SDP_SDRC_MR_0_SDR, SDRC_MR_0 + offset); else __raw_writel(SDP_SDRC_MR_0_DDR, SDRC_MR_0 + offset); /* setup 343x DLL values (DDR only) */ if (common && (pass_type != IP_SDR)) { __raw_writel(SDP_SDRC_DLLAB_CTRL, SDRC_DLLA_CTRL); sdelay(0x2000); /* give time to lock, at least 1000 L3 */ } sdelay(0x1000); if (mono) /* Used if Stacked memory is on CS1 only */ make_cs1_contiguous(); /* make CS1 appear at CS0 */ if (mem_ok()) return; /* STACKED, other configured type */ ++pass_type; /* IPDDR->COMBODDR->IPSDR for CS0 */ goto next_mem_type; } void enable_gpmc_config(u32 * gpmc_config, u32 gpmc_base, u32 base, u32 size) { __raw_writel(0, GPMC_CONFIG7 + gpmc_base); sdelay(1000); /* Delay for settling */ __raw_writel(gpmc_config[0], GPMC_CONFIG1 + gpmc_base); __raw_writel(gpmc_config[1], GPMC_CONFIG2 + gpmc_base); __raw_writel(gpmc_config[2], GPMC_CONFIG3 + gpmc_base); __raw_writel(gpmc_config[3], GPMC_CONFIG4 + gpmc_base); __raw_writel(gpmc_config[4], GPMC_CONFIG5 + gpmc_base); __raw_writel(gpmc_config[5], GPMC_CONFIG6 + gpmc_base); /* Enable the config */ __raw_writel((((size & 0xF) << 8) | ((base >> 24) & 0x3F) | (1 << 6)), GPMC_CONFIG7 + gpmc_base); sdelay(2000); } /***************************************************** * gpmc_init(): init gpmc bus * Init GPMC for x16, MuxMode (SDRAM in x32). * This code can only be executed from SRAM or SDRAM. *****************************************************/ void gpmc_init(void) { /* putting a blanket check on GPMC based on ZeBu for now */ u32 mux = 0, mwidth; u32 *gpmc_config = NULL; u32 gpmc_base = 0; u32 base = 0; u8 idx = 0; u32 size = 0; u32 f_off = CFG_MONITOR_LEN; u32 f_sec = 0; u32 config = 0; unsigned char *config_sel = NULL; u32 i = 0; mux = BIT9; mwidth = get_gpmc0_width(); /* global settings */ __raw_writel(0x10, GPMC_SYSCONFIG); /* smart idle */ __raw_writel(0x0, GPMC_IRQENABLE); /* isr's sources masked */ __raw_writel(0, GPMC_TIMEOUT_CONTROL); /* timeout disable */ #if (!defined(CONFIG_STRASBOURG) && !defined(CONFIG_SANTIAGO)) config = __raw_readl(GPMC_CONFIG); config &= (~0xf00); __raw_writel(config, GPMC_CONFIG); /* Disable the GPMC0 config set by ROM code * It conflicts with our MPDB (both at 0x08000000) */ __raw_writel(0 , GPMC_CONFIG7 + GPMC_CONFIG_CS0); sdelay(1000); #ifdef CONFIG_3630SDP gpmc_config = gpmc_mpdb; /* GPMC3 is always MPDB.. need to know the chip info */ gpmc_base = GPMC_CONFIG_CS0 + (3 * GPMC_CONFIG_WIDTH); gpmc_config[0] |= mux; #elif defined(CONFIG_3430ZOOM2) /* LAN9221 is on CS 7 on Zoom2 */ gpmc_config = gpmc_enet; gpmc_base = GPMC_CONFIG_CS0 + (7 * GPMC_CONFIG_WIDTH); #else /* LAN9x18 is on CS 1 on Zoom1 */ gpmc_config = gpmc_enet; gpmc_base = GPMC_CONFIG_CS0 + (1 * GPMC_CONFIG_WIDTH); #endif enable_gpmc_config(gpmc_config, gpmc_base, DEBUG_BASE, DBG_MPDB_SIZE); #ifdef CONFIG_3430ZOOM2 /* Configure UART4 console support on zoom2 */ gpmc_config = gpmc_serial_TL16CP754C; gpmc_base = GPMC_CONFIG_CS0 + (3 * GPMC_CONFIG_WIDTH); enable_gpmc_config(gpmc_config, gpmc_base, SERIAL_TL16CP754C_BASE, SERIAL_TL16CP754C_SIZE); #endif /* Look up chip select map */ i = 0; idx = get_gpmc0_type(); config_sel = (unsigned char *)(chip_sel[idx]); /* Initialize each chip selects timings (may be to 0) */ for (idx = 0; idx < GPMC_MAX_CS; idx++) { gpmc_base = GPMC_CONFIG_CS0 + (idx * GPMC_CONFIG_WIDTH); switch (config_sel[idx]) { #if (CONFIG_COMMANDS & CFG_CMD_FLASH) case PISMO1_NOR: gpmc_config = gpmc_sibnor; f_sec = SZ_256K; NOR_MAX_FLASH_BANKS = 1; size = PISMO1_NOR_SIZE_SDPV2; for (i = 0; i < NOR_MAX_FLASH_BANKS; i++) NOR_FLASH_BANKS_LIST[i] = FLASH_BASE_SDPV2 + PHYS_FLASH_SIZE_SDPV2*i; gpmc_config[0] |= mux | TYPE_NOR | mwidth; base = NOR_FLASH_BANKS_LIST[0]; is_flash = 1; break; #endif #if (CONFIG_COMMANDS & CFG_CMD_NAND) case PISMO1_NAND: base = PISMO1_NAND_BASE; size = PISMO1_NAND_SIZE; gpmc_config = gpmc_m_nand; nand_cs_base = gpmc_base; f_off = SMNAND_ENV_OFFSET; is_nand = 1; break; #endif case PISMO2_CS0: case PISMO2_CS1: base = PISMO2_BASE; size = PISMO2_SIZE; gpmc_config = gpmc_pismo2; gpmc_config[0] |= mux | TYPE_NOR | mwidth; break; /* Either OneNand or Normal Nand at a time!! */ #if (CONFIG_COMMANDS & CFG_CMD_ONENAND) case PISMO1_ONENAND: base = PISMO1_ONEN_BASE; size = PISMO1_ONEN_SIZE; gpmc_config = gpmc_onenand; onenand_cs_base = gpmc_base; f_off = ONENAND_ENV_OFFSET; is_onenand = 1; break; #endif default: /* MPDB/Unsupported/Corrupt config- try Next GPMC CS!!!! */ continue; } /* handle boot CS0 */ if (idx == 0) { boot_flash_base = base; boot_flash_off = f_off; boot_flash_sec = f_sec; /* boot_flash_type = config_sel[idx]; */ boot_flash_env_addr = f_off; #ifdef ENV_IS_VARIABLE switch (config_sel[0]) { #if (CONFIG_COMMANDS & CFG_CMD_FLASH) case PISMO1_NOR: boot_env_get_char_spec = flash_env_get_char_spec; boot_env_init = flash_env_init; boot_saveenv = flash_saveenv; boot_env_relocate_spec = flash_env_relocate_spec; flash_addr = env_ptr = (env_t *) (boot_flash_base + boot_flash_off); env_name_spec = flash_env_name_spec; boot_flash_env_addr = (u32) flash_addr; break; #endif #if (CONFIG_COMMANDS & CFG_CMD_NAND) case PISMO1_NAND: boot_env_get_char_spec = nand_env_get_char_spec; boot_env_init = nand_env_init; boot_saveenv = nand_saveenv; boot_env_relocate_spec = nand_env_relocate_spec; env_ptr = 0; /* This gets filled elsewhere!! */ env_name_spec = nand_env_name_spec; break; #endif #if (CONFIG_COMMANDS & CFG_CMD_ONENAND) case PISMO1_ONENAND: boot_env_get_char_spec = onenand_env_get_char_spec; boot_env_init = onenand_env_init; boot_saveenv = onenand_saveenv; boot_env_relocate_spec = onenand_env_relocate_spec; env_ptr = (env_t *) onenand_env; env_name_spec = onenand_env_name_spec; break; #endif default: /* unknown variant!! */ puts("Unknown Boot chip!!!\n"); break; } #endif /* ENV_IS_VARIABLE */ } enable_gpmc_config(gpmc_config, gpmc_base, base, size); } #ifdef OPTIONAL_NOR /* CS 2 (fixme -- sizes for optional s-nor)*/ gpmc_config = gpmc_stnor; gpmc_config[0] |= mux | TYPE_NOR | mwidth; gpmc_base = GPMC_CONFIG_CS0 + (2 * GPMC_CONFIG_WIDTH); enable_gpmc_config(gpmc_config, gpmc_base, DEBUG_BASE, DBG_MPDB_SIZE); /* handle flash probe setup */ f_sec = SZ_128K; NOR_MAX_FLASH_BANKS = 2; size = PISMO1_NOR_SIZE; for(i=0; i < NOR_MAX_FLASH_BANKS; i++) NOR_FLASH_BANKS_LIST[i] = FLASH_BASE_SDPV1 + PHYS_FLASH_SIZE*i; } #endif #endif /* CONFIG_STRASBOURG || CONFIG_SANTIAGO */ }