342 lines
11 KiB
C
342 lines
11 KiB
C
|
/*
|
||
|
* Copyright (c) 2011-2012, Freescale Semiconductor, Inc.
|
||
|
* All rights reserved.
|
||
|
*
|
||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||
|
* are permitted provided that the following conditions are met:
|
||
|
*
|
||
|
* o Redistributions of source code must retain the above copyright notice, this list
|
||
|
* of conditions and the following disclaimer.
|
||
|
*
|
||
|
* o Redistributions in binary form must reproduce the above copyright notice, this
|
||
|
* list of conditions and the following disclaimer in the documentation and/or
|
||
|
* other materials provided with the distribution.
|
||
|
*
|
||
|
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
|
||
|
* contributors may be used to endorse or promote products derived from this
|
||
|
* software without specific prior written permission.
|
||
|
*
|
||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
|
*/
|
||
|
|
||
|
#include "sdk.h"
|
||
|
#include "registers/regsccm.h"
|
||
|
#include "registers/regsccmanalog.h"
|
||
|
#include "registers/regsuart.h"
|
||
|
#include "registers/regsepit.h"
|
||
|
#include "registers/regsspba.h"
|
||
|
#include "registers/regssdmaarm.h"
|
||
|
#include "registers/regsgpt.h"
|
||
|
#include "registers/regsi2c.h"
|
||
|
#include "registers/regsecspi.h"
|
||
|
#include "ccm_pll.h"
|
||
|
//#include "hardware.h"
|
||
|
//#include "soc_memory_map.h"
|
||
|
#define HW_ANADIG_REG_CORE (ANATOP_IPS_BASE_ADDR + 0x140)
|
||
|
#define HW_ANADIG_PLL_SYS_RW (ANATOP_IPS_BASE_ADDR + 0x000)
|
||
|
#define HW_ANADIG_REG_CORE_V_CORE_VALUE_mv(x) ((((x)-700)/25) << 0)
|
||
|
#define HW_ANADIG_REG_CORE_V_SOC_VALUE_mv(x) ((((x)-700)/25) << 18)
|
||
|
#define HW_ANADIG_REG_CORE_V_CORE_MSK 0x1F
|
||
|
#define HW_ANADIG_REG_CORE_V_SOC_MSK (0x1F << 18)
|
||
|
|
||
|
uint32_t g_arm_clk = 528000000;
|
||
|
|
||
|
const uint32_t PLL2_OUTPUT[] = { 528000000, 396000000, 352000000, 198000000 };
|
||
|
const uint32_t PLL3_OUTPUT[] = { 480000000, 720000000, 540000000, 508235294, 454736842 };
|
||
|
const uint32_t PLL4_OUTPUT = 650000000;
|
||
|
const uint32_t PLL5_OUTPUT = 650000000;
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
// Code
|
||
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
void set_soc_core_voltage(unsigned int v_core_mv, unsigned int v_soc_mv)
|
||
|
{
|
||
|
unsigned int val, val_v_core, val_v_soc;
|
||
|
|
||
|
val = reg32_read(HW_ANADIG_REG_CORE);
|
||
|
val &= ~HW_ANADIG_REG_CORE_V_CORE_MSK;
|
||
|
val &= ~HW_ANADIG_REG_CORE_V_SOC_MSK;
|
||
|
|
||
|
val_v_core = HW_ANADIG_REG_CORE_V_CORE_VALUE_mv(v_core_mv);
|
||
|
val_v_soc = HW_ANADIG_REG_CORE_V_SOC_VALUE_mv(v_soc_mv);
|
||
|
|
||
|
val |= val_v_core | val_v_soc;
|
||
|
reg32_write(HW_ANADIG_REG_CORE, val);
|
||
|
}
|
||
|
|
||
|
void setup_clk(void)
|
||
|
{
|
||
|
uint32_t div_select;
|
||
|
uint32_t temp;
|
||
|
uint32_t arm_clk = g_arm_clk/1000000;
|
||
|
|
||
|
switch(arm_clk)
|
||
|
{
|
||
|
case 400:
|
||
|
div_select = 33;
|
||
|
set_soc_core_voltage(1150, 1175);
|
||
|
return;
|
||
|
case 528:
|
||
|
div_select = 44;
|
||
|
set_soc_core_voltage(1250, 1250);
|
||
|
break;
|
||
|
case 756:
|
||
|
div_select = 63;
|
||
|
set_soc_core_voltage(1250, 1250);
|
||
|
printf("ARM Clock set to 756MHz\r\n");
|
||
|
break;
|
||
|
default:
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// first, make sure ARM_PODF is clear
|
||
|
HW_CCM_CACRR_WR(0);
|
||
|
// write the div_select value into HW_ANADIG_PLL_SYS_RW
|
||
|
// this will re-program the PLL to the new freq
|
||
|
|
||
|
temp = readl(HW_ANADIG_PLL_SYS_RW);
|
||
|
temp |= 0x10000;// set BYBASS
|
||
|
writel(temp, HW_ANADIG_PLL_SYS_RW);
|
||
|
|
||
|
temp = readl(HW_ANADIG_PLL_SYS_RW);
|
||
|
temp &= ~(0x0000007F);
|
||
|
temp |= div_select; // Update div
|
||
|
writel(temp, HW_ANADIG_PLL_SYS_RW);
|
||
|
|
||
|
/* Wait for PLL to lock */
|
||
|
while(!(readl(HW_ANADIG_PLL_SYS_RW) & 0x80000000));
|
||
|
|
||
|
/*disable BYPASS*/
|
||
|
temp = readl(HW_ANADIG_PLL_SYS_RW);
|
||
|
temp &= ~0x10000;
|
||
|
writel(temp, HW_ANADIG_PLL_SYS_RW);
|
||
|
}
|
||
|
|
||
|
void ccm_init(void)
|
||
|
{
|
||
|
HW_CCM_CCGR0_WR(0xffffffff);
|
||
|
HW_CCM_CCGR1_WR(0xffffffff); // EPIT, ESAI, GPT enabled by driver
|
||
|
HW_CCM_CCGR2_WR(0xffffffff); // I2C enabled by driver
|
||
|
HW_CCM_CCGR3_WR(0xffffffff);
|
||
|
HW_CCM_CCGR4_WR(0xffffffff); // GPMI, Perfmon enabled by driver
|
||
|
HW_CCM_CCGR5_WR(0xffffffff); // UART, SATA enabled by driver
|
||
|
HW_CCM_CCGR6_WR(0xffffffff);
|
||
|
|
||
|
/*
|
||
|
* Keep default settings at reset.
|
||
|
* pre_periph_clk_sel is by default at 0, so the selected output
|
||
|
* of PLL2 is the main output at 528MHz.
|
||
|
* => by default, ahb_podf divides by 4 => AHB_CLK@132MHz.
|
||
|
* => by default, ipg_podf divides by 2 => IPG_CLK@66MHz.
|
||
|
*/
|
||
|
HW_CCM_CBCDR.U = BF_CCM_CBCDR_AHB_PODF(3)
|
||
|
| BF_CCM_CBCDR_AXI_PODF(1)
|
||
|
| BF_CCM_CBCDR_IPG_PODF(1);
|
||
|
|
||
|
setup_clk();
|
||
|
|
||
|
/* Power up 480MHz PLL */
|
||
|
reg32_write_mask(HW_CCM_ANALOG_PLL_USB1_ADDR, 0x00001000, 0x00001000);
|
||
|
|
||
|
/* Enable 480MHz PLL */
|
||
|
reg32_write_mask(HW_CCM_ANALOG_PLL_USB1_ADDR, 0x00002000, 0x00002000);
|
||
|
|
||
|
reg32_write_mask(HW_CCM_CSCDR1_ADDR, 0x00000000, 0x0000003F);
|
||
|
}
|
||
|
|
||
|
uint32_t get_main_clock(main_clocks_t clock)
|
||
|
{
|
||
|
uint32_t ret_val = 0;
|
||
|
uint32_t pre_periph_clk_sel = HW_CCM_CBCMR.B.PRE_PERIPH_CLK_SEL;
|
||
|
|
||
|
switch (clock) {
|
||
|
case CPU_CLK:
|
||
|
ret_val = g_arm_clk;
|
||
|
break;
|
||
|
case AXI_CLK:
|
||
|
ret_val = PLL2_OUTPUT[pre_periph_clk_sel] / (HW_CCM_CBCDR.B.AXI_PODF + 1);
|
||
|
break;
|
||
|
case MMDC_CH0_AXI_CLK:
|
||
|
ret_val = PLL2_OUTPUT[pre_periph_clk_sel] / (HW_CCM_CBCDR.B.MMDC_CH0_AXI_PODF + 1);
|
||
|
break;
|
||
|
case AHB_CLK:
|
||
|
ret_val = PLL2_OUTPUT[pre_periph_clk_sel] / (HW_CCM_CBCDR.B.AHB_PODF + 1);
|
||
|
break;
|
||
|
case IPG_CLK:
|
||
|
ret_val =
|
||
|
PLL2_OUTPUT[pre_periph_clk_sel] / (HW_CCM_CBCDR.B.AHB_PODF +
|
||
|
1) / (HW_CCM_CBCDR.B.IPG_PODF + 1);
|
||
|
break;
|
||
|
case IPG_PER_CLK:
|
||
|
ret_val =
|
||
|
PLL2_OUTPUT[pre_periph_clk_sel] / (HW_CCM_CBCDR.B.AHB_PODF +
|
||
|
1) / (HW_CCM_CBCDR.B.IPG_PODF +
|
||
|
1) / (HW_CCM_CSCMR1.B.PERCLK_PODF + 1);
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return ret_val;
|
||
|
}
|
||
|
|
||
|
uint32_t get_peri_clock(peri_clocks_t clock)
|
||
|
{
|
||
|
uint32_t ret_val = 0;
|
||
|
|
||
|
switch (clock)
|
||
|
{
|
||
|
case UART1_MODULE_CLK:
|
||
|
case UART2_MODULE_CLK:
|
||
|
case UART3_MODULE_CLK:
|
||
|
case UART4_MODULE_CLK:
|
||
|
case UART5_MODULE_CLK:
|
||
|
case UART6_MODULE_CLK:
|
||
|
case UART7_MODULE_CLK:
|
||
|
case UART8_MODULE_CLK:
|
||
|
// UART source clock is a fixed PLL3 / 6
|
||
|
ret_val = PLL3_OUTPUT[0] / 6 / (HW_CCM_CSCDR1.B.UART_CLK_PODF + 1);
|
||
|
break;
|
||
|
case SPI_CLK:
|
||
|
ret_val = PLL3_OUTPUT[0] / 8 / (HW_CCM_CSCDR2.B.ECSPI_CLK_PODF + 1);
|
||
|
break;
|
||
|
case RAWNAND_CLK:
|
||
|
ret_val =
|
||
|
PLL3_OUTPUT[0] / (HW_CCM_CS2CDR.B.ENFC_CLK_PRED + 1) / (HW_CCM_CS2CDR.B.ENFC_CLK_PODF +
|
||
|
1);
|
||
|
break;
|
||
|
case CAN_CLK:
|
||
|
// For i.mx6dq/sdl CAN source clock is a fixed PLL3 / 8
|
||
|
ret_val = PLL3_OUTPUT[0] / 8 / (HW_CCM_CSCMR2.B.CAN_CLK_PODF + 1);
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return ret_val;
|
||
|
}
|
||
|
|
||
|
void ccm_ccgr_config(uint32_t ccm_ccgrx, uint32_t cgx_offset, uint32_t gating_mode)
|
||
|
{
|
||
|
if (gating_mode == CLOCK_ON)
|
||
|
{
|
||
|
*(volatile uint32_t *)(ccm_ccgrx) |= cgx_offset;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*(volatile uint32_t *)(ccm_ccgrx) &= ~cgx_offset;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void clock_gating_config(uint32_t base_address, uint32_t gating_mode)
|
||
|
{
|
||
|
uint32_t ccm_ccgrx = 0;
|
||
|
uint32_t cgx_offset = 0;
|
||
|
|
||
|
switch (base_address)
|
||
|
{
|
||
|
case REGS_UART1_BASE:
|
||
|
ccm_ccgrx = HW_CCM_CCGR5_ADDR;
|
||
|
cgx_offset = CG(12);
|
||
|
break;
|
||
|
case REGS_UART2_BASE:
|
||
|
ccm_ccgrx = HW_CCM_CCGR0_ADDR;
|
||
|
cgx_offset = CG(14);
|
||
|
break;
|
||
|
case REGS_UART3_BASE:
|
||
|
ccm_ccgrx = HW_CCM_CCGR1_ADDR;
|
||
|
cgx_offset = CG(5);
|
||
|
break;
|
||
|
case REGS_UART4_BASE:
|
||
|
ccm_ccgrx = HW_CCM_CCGR1_ADDR;
|
||
|
cgx_offset = CG(12);
|
||
|
break;
|
||
|
case REGS_UART5_BASE:
|
||
|
ccm_ccgrx = HW_CCM_CCGR3_ADDR;
|
||
|
cgx_offset = CG(1);
|
||
|
break;
|
||
|
case REGS_UART6_BASE:
|
||
|
ccm_ccgrx = HW_CCM_CCGR3_ADDR;
|
||
|
cgx_offset = CG(3);
|
||
|
break;
|
||
|
case REGS_UART7_BASE:
|
||
|
ccm_ccgrx = HW_CCM_CCGR5_ADDR;
|
||
|
cgx_offset = CG(13);
|
||
|
break;
|
||
|
case REGS_UART8_BASE:
|
||
|
ccm_ccgrx = HW_CCM_CCGR6_ADDR;
|
||
|
cgx_offset = CG(7);
|
||
|
break;
|
||
|
case REGS_SPBA_BASE:
|
||
|
ccm_ccgrx = HW_CCM_CCGR5_ADDR;
|
||
|
cgx_offset = CG(6);
|
||
|
break;
|
||
|
case REGS_SDMAARM_BASE:
|
||
|
ccm_ccgrx = HW_CCM_CCGR5_ADDR;
|
||
|
cgx_offset = CG(3);
|
||
|
break;
|
||
|
case REGS_EPIT1_BASE:
|
||
|
ccm_ccgrx = HW_CCM_CCGR1_ADDR;
|
||
|
cgx_offset = CG(6);
|
||
|
break;
|
||
|
case REGS_EPIT2_BASE:
|
||
|
ccm_ccgrx = HW_CCM_CCGR1_ADDR;
|
||
|
cgx_offset = CG(7);
|
||
|
break;
|
||
|
case REGS_GPT1_BASE:
|
||
|
case REGS_GPT2_BASE:
|
||
|
ccm_ccgrx = HW_CCM_CCGR1_ADDR;
|
||
|
cgx_offset = CG(10)|CG(11);
|
||
|
break;
|
||
|
case REGS_I2C1_BASE:
|
||
|
ccm_ccgrx = HW_CCM_CCGR2_ADDR;
|
||
|
cgx_offset = CG(3);
|
||
|
break;
|
||
|
case REGS_I2C2_BASE:
|
||
|
ccm_ccgrx = HW_CCM_CCGR2_ADDR;
|
||
|
cgx_offset = CG(4);
|
||
|
break;
|
||
|
case REGS_I2C3_BASE:
|
||
|
ccm_ccgrx = HW_CCM_CCGR2_ADDR;
|
||
|
cgx_offset = CG(5);
|
||
|
break;
|
||
|
case REGS_ECSPI1_BASE:
|
||
|
ccm_ccgrx = HW_CCM_CCGR1_ADDR;
|
||
|
cgx_offset = CG(0);
|
||
|
break;
|
||
|
case REGS_ECSPI2_BASE:
|
||
|
ccm_ccgrx = HW_CCM_CCGR1_ADDR;
|
||
|
cgx_offset = CG(1);
|
||
|
break;
|
||
|
case REGS_ECSPI3_BASE:
|
||
|
ccm_ccgrx = HW_CCM_CCGR1_ADDR;
|
||
|
cgx_offset = CG(2);
|
||
|
break;
|
||
|
case REGS_ECSPI4_BASE:
|
||
|
ccm_ccgrx = HW_CCM_CCGR1_ADDR;
|
||
|
cgx_offset = CG(3);
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// apply changes only if a valid address was found
|
||
|
if (ccm_ccgrx != 0)
|
||
|
{
|
||
|
ccm_ccgr_config(ccm_ccgrx, cgx_offset, gating_mode);
|
||
|
}
|
||
|
}
|
||
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
// End of file
|
||
|
////////////////////////////////////////////////////////////////////////////////
|