blob: 6ec9c49ba17aec8bb1f2fb2072ee71182c71a5b6 [file] [log] [blame]
/*
* (C) Copyright 2006
* Mindspeed Technologies, Inc. <www.mindspeed.com>
*
* 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/arch/hardware.h>
#include <asm/arch/bsp.h>
/*
* SoC_cs_cfg - configure Chip Select settings
*
* cs - chip select id
*
* enable - enable or disable the CS
* 1 = enable
* 0 = disable
*
* cfg - chip select configuration, ignored if enable = 0
*
*/
int SoC_cs_cfg(int cs, int enable, struct cs_cfg *cfg)
{
u32 segment_size = 0;
u32 baseaddr = 0;
if ((cs != EXP_CSSD0) && (cs != EXP_CSSD1) && (cs != EXP_CSBOOT) &&
(cs != EXP_CSP0))
goto err;
if (enable == CS_DISABLE) {
/* Disable the CS and exit */
*(volatile u32 *) ASD_CSE &= ~(1 << cs);
goto out;
}
if (cfg->memtype == CS_MEMTYPE_SDRAM) {
/* Other CS don't support SDRAM */
if (cs != EXP_CSSD0)
goto err;
}
if ((cs == EXP_CSSD0) || (cs == EXP_CSSD1)) {
baseaddr = cfg->baseaddr & 0x07FFFFFF;
switch (cfg->size) {
case 0x10000: segment_size = 0x0; /* 64KB */
break;
case 0x20000: segment_size = 0x5; /* 128KB */
break;
case 0x40000: segment_size = 0x6; /* 256KB */
break;
case 0x80000: segment_size = 0x7; /* 512KB */
break;
case 0x100000: segment_size = 0x8; /* 1MB */
break;
case 0x200000: segment_size = 0x9; /* 2MB */
break;
case 0x400000: segment_size = 0xa; /* 4MB */
break;
case 0x800000: segment_size = 0xb; /* 8MB */
break;
case 0x1000000: segment_size = 0xc; /* 16MB */
break;
case 0x2000000: segment_size = 0xd; /* 32MB */
break;
default:
case 0x4000000:
segment_size = 0xe; /* 64MB */
cfg->size = 0x4000000;
break;
}
/* Make sure the base address is aligned on size boundary */
baseaddr &= ~(cfg->size - 1);
}
switch (cs) {
case EXP_CSSD0:
*(volatile u32 *) ASD_MBA_EXP_CSSD0 = ((baseaddr >> 16) << 4) | segment_size;
if (cfg->memtype == CS_MEMTYPE_SDRAM) {
*(volatile u32 *) SDC0_CSSD0_CFG = (((u32)cfg->memtype & 0x1) << 9);
*(volatile u32 *) SDC0_SDRAM_CFG1 = (((u32)cfg->tras & 0x7) << 13) |
(((u32)cfg->trc & 0xf) << 9) |
(((u32)cfg->trcd & 0x7) << 6) |
(((u32)cfg->trp & 0x7) << 3) |
((u32)cfg->cl & 0x7);
*(volatile u32 *) SDC0_SDRAM_REFRESH = (u32)cfg->refcnt & 0xfff;
*(volatile u32 *) SDC0_SDRAM_POWERON = (u32)cfg->pwroncnt & 0xffff;
*(volatile u32 *) SDC0_SDRAM_CFG2 = (((u32)cfg->memchip_dtype & 0x3) << 11) |
(((u32)cfg->twr & 0x3) << 8) |
(1 << 7) |
(1 << 6) |
(((u32)cfg->buswidth & 0x1) << 5) |
(((u32)cfg->tmrd & 0x7) << 2) |
((u32)cfg->trrd & 0x3);
} else {
*(volatile u32 *) SDC0_CSSD0_CFG = (((u32)cfg->buswidth & 0x3) << 11) |
((((u32)cfg->addrsetup >> 2) & 0x1) << 10) |
(((u32)cfg->memtype & 0x1) << 9) |
(((u32)cfg->addrsetup & 0x3) << 7) |
(((u32)cfg->level & 0x1) << 6) |
(((u32)cfg->dqm_mode & 0x1) << 5) |
(((u32)cfg->cmdwidth & 0xf) << 1);
}
*(volatile u32 *) ASD_CSE |= (1 << EXP_CSSD0);
break;
case EXP_CSSD1:
*(volatile u32 *) ASD_MBA_EXP_CSSD1 = ((baseaddr >> 16) << 4) | segment_size;
*(volatile u32 *) SDC0_CSSD1_CFG = (((u32)cfg->buswidth & 0x3) << 11) |
((((u32)cfg->addrsetup >> 2) & 0x1) << 10) |
(((u32)cfg->memtype & 0x1) << 9) |
(((u32)cfg->addrsetup & 0x3) << 7) |
(((u32)cfg->level & 0x1) << 6) |
(((u32)cfg->dqm_mode & 0x1) << 5) |
(((u32)cfg->cmdwidth & 0xf) << 1);
*(volatile u32 *) ASD_CSE |= (1 << EXP_CSSD1);
break;
case EXP_CSBOOT:
*(volatile u32 *)SDC0_CSBOOT_CFG = (((u32)cfg->buswidth & 0x3) << 11) |
((((u32)cfg->addrsetup >> 2) & 0x1) << 10) |
(((u32)cfg->memtype & 0x1) << 9) |
(((u32)cfg->addrsetup & 0x3) << 7) |
(((u32)cfg->level & 0x1) << 6) |
(((u32)cfg->dqm_mode & 0x1) << 5) |
(((u32)cfg->cmdwidth & 0xf) << 1);
*(volatile u32 *)ASD_CSE |= (1 << EXP_CSBOOT);
break;
case EXP_CSP0:
*(volatile u32 *)SDC0_CSP0_CFG = (((u32)cfg->buswidth & 0x3) << 11) |
((((u32)cfg->addrsetup >> 2) & 0x1) << 10) |
(((u32)cfg->memtype & 0x1) << 9) |
(((u32)cfg->addrsetup & 0x3) << 7) |
(((u32)cfg->level & 0x1) << 6) |
(((u32)cfg->dqm_mode & 0x1) << 5) |
(((u32)cfg->cmdwidth & 0xf) << 1);
*(volatile u32 *)ASD_CSE |= (1 << EXP_CSP0);
break;
}
out:
return 0;
err:
return -1;
}
int SoC_high_mem_cfg (int cs)
{
switch (cs) {
case EXP_CSSD0:
*(volatile u32 *)ASD_CSE &= ~(1 << 7);
break;
case EXP_CSSD1:
*(volatile u32 *)ASD_CSE |= (1 << 7);
break;
default:
goto err;
}
return 0;
err:
return -1;
}
/*
* SoC_pll_cfg - used to configure ARM and AMBA bus clock frequencies
*
* mode - ARM clock mode,
* 1 = async, independent ARM and AMBA bus clock frequencies (PLL2 used for bus clock).
* 0 = sync, AMBA bus clock half ARM clock frequency (PLL2 not used)
*
* arm_clk - ARM clock frequency in Hz
*
* bus_clk - AMBA BUS clock frequency in Hz
*
*/
int SoC_pll_cfg (int mode, unsigned int arm_clk, unsigned int bus_clk)
{
volatile u32 delay_count;
u32 clkf;
u32 i;
if (mode == CLK_MODE_ASYNC) {
/* set ARM async clock mode */
asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
i |= 0xC0000000;
asm ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
/* async mode */
clkf = (4 * bus_clk) / CFG_REFCLKFREQ;
/* bus setup */
/* set PLL into BYPASS mode */
*(volatile u32 *)CLKCORE_AMBA_PLL |= PLL_BYPASS;
/* wait 500us for PLL to lock */
delay_count = 1000;
while (delay_count--);
/* Disable the PLL, by writing PLL Control Register bit 25 = 1. */
*(volatile u32 *)CLKCORE_AMBA_PLL |= PLL_POWER;
/* Program the PLL to the desired value and enable the PLL, by writing PLL Control Register fields W, X, and Y, */
*(volatile u32 *)CLKCORE_AMBA_PLL = PLL_BYPASS | PLL_POWER | (clkf & 0x7f);
/* and writing bit 25 = 0. */
*(volatile u32 *)CLKCORE_AMBA_PLL = PLL_MUXSEL | (clkf & 0x7f);
} else {
/* set ARM sync clock mode */
asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
i |= 0x40000000;
asm ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
}
/* ARM setup */
clkf = (2 * arm_clk) / CFG_REFCLKFREQ;
/* set PLL into BYPASS mode */
*(volatile u32 *)CLKCORE_ARM_PLL |= PLL_BYPASS;
/* wait 500us for PLL to lock */
delay_count = 1000;
while (delay_count--);
/* Disable the PLL, by writing PLL Control Register bit 25 = 1. */
*(volatile u32 *)CLKCORE_ARM_PLL |= PLL_POWER;
/* Program the PLL to the desired value and enable the PLL, by writing PLL Control Register fields W, X, and Y */
*(volatile u32 *)CLKCORE_ARM_PLL = PLL_BYPASS | PLL_POWER | (clkf & 0x7f);
/*and writing bit 25 = 0. */
*(volatile u32 *)CLKCORE_ARM_PLL &= ~PLL_POWER;
/* Take the PLL out of bypass mode, by writing PLL Control Register bit 24 = 0. */
*(volatile u32 *)CLKCORE_ARM_PLL &= ~PLL_BYPASS;
// Ref:
// 1) PLL Initialization Procedure (82XXX-ERR-001-A.pdf )
// 2) M825xx PLL Registers chapter.pdf
return 0;
}
/*
* SoC_gpio_cfg - configure GPIO pins as input or output pins
*
* gpio - gpio pin
*
* mode - gpio pin mode
* GPIO_TYPE_OUTPUT = output
* GPIO_TYPE_INPUT = input
*
*/
int SoC_gpio_cfg(int gpio, int mode)
{
if ((gpio < 0) || (gpio > 7))
goto err;
switch (mode) {
case GPIO_TYPE_INPUT:
*(volatile u32 *) GPIO_OUTPUT_ENABLE &= ~(1 << gpio);
break;
case GPIO_TYPE_OUTPUT:
*(volatile u32 *) GPIO_OUTPUT_ENABLE |= 1 << gpio;
break;
default:
goto err;
break;
}
return 0;
err:
return -1;
}