blob: 9709966bfab153d23b88a51334d9642a6c69d667 [file] [log] [blame]
/*
* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of Code Aurora 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, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 <stdint.h>
#include <debug.h>
#include <kernel/thread.h>
#include <platform/iomap.h>
#include <platform/clock.h>
#include <reg.h>
/* Read, modify, then write-back a register. */
static void rmwreg(uint32_t val, uint32_t reg, uint32_t mask)
{
uint32_t regval = readl(reg);
regval &= ~mask;
regval |= val;
writel(regval, reg);
}
void config_mdp_axi_clk(uint8_t use_pxo){
/* Program MM_PLL0 (PLL1) @ 1320 MHz and turn it on. */
rmwreg(0, MM_PLL0_MODE_REG, (1<<0)); /* Disable output */
writel(48, MM_PLL0_L_VAL_REG);
writel(8, MM_PLL0_M_VAL_REG);
writel(9, MM_PLL0_N_VAL_REG);
/* Set ref, enable. */
if (use_pxo)
rmwreg((1<<1), MM_PLL0_MODE_REG, (1<<4)|(1<<1)); /* PXO */
else
rmwreg((1<<4)|(1<<1), MM_PLL0_MODE_REG, (1<<4)|(1<<1)); /* MXO */
udelay(10);
writel(0x14580, MM_PLL0_CONFIG_REG); /* Enable MN, set VCO, misc */
rmwreg((1<<2), MM_PLL0_MODE_REG, (1<<2)); /* Deassert reset */
rmwreg((1<<0), MM_PLL0_MODE_REG, (1<<0)); /* Enable output */
/* Set up MM AHB clock to PLL8/5. */
//local_src_enable(PLL_8);
rmwreg(0x0102, AHB_NS_REG, 0x43C7);
udelay(200); /* Wait before using registers clocked by MM AHB_CLK. */
/* Set up MM Fabric (AXI). */
writel(0x4248451, AXI_NS_REG);
}
/* Enable/disable for non-shared NT PLLs. */
int nt_pll_enable(uint8_t src, uint8_t enable)
{
static const struct {
uint32_t const mode_reg;
uint32_t const status_reg;
} pll_reg[] = {
[PLL_1] = { MM_PLL0_MODE_REG, MM_PLL0_STATUS_REG },
[PLL_2] = { MM_PLL1_MODE_REG, MM_PLL1_STATUS_REG },
[PLL_3] = { MM_PLL2_MODE_REG, MM_PLL2_STATUS_REG },
};
uint32_t pll_mode;
pll_mode = readl(pll_reg[src].mode_reg);
if (enable) {
/* Disable PLL bypass mode. */
pll_mode |= (1<<1);
writel( pll_mode, pll_reg[src].mode_reg);
/* H/W requires a 5us delay between disabling the bypass and
* de-asserting the reset. Delay 10us just to be safe. */
udelay(10);
/* De-assert active-low PLL reset. */
pll_mode |= (1<<2);
writel( pll_mode, pll_reg[src].mode_reg);
/* Enable PLL output. */
pll_mode |= (1<<0);
writel( pll_mode, pll_reg[src].mode_reg);
/* Wait until PLL is enabled. */
while (!readl(pll_reg[src].status_reg));
} else {
/* Disable the PLL output, disable test mode, enable
* the bypass mode, and assert the reset. */
pll_mode &= 0xFFFFFFF0;
writel( pll_mode, pll_reg[src].mode_reg);
}
return 0;
}
/* Write the M,N,D values and enable the MDP Core Clock */
void config_mdp_clk( uint32_t ns,
uint32_t md,
uint32_t cc,
uint32_t ns_addr,
uint32_t md_addr,
uint32_t cc_addr)
{
int val = 0;
/* MN counter reset */
val = 1 << 31;
writel(val, ns_addr);
/* Write the MD and CC register values */
writel(md, md_addr);
writel(cc, cc_addr);
/* Reset the clk control, and Write ns val */
val = 1 << 31;
val |= ns;
writel(val, ns_addr);
/* Clear MN counter reset */
val = 1 << 31;
val = ~val;
val = val & readl(ns_addr);
writel(val, ns_addr);
/* Enable MND counter */
val = 1 << 8;
val = val | readl(cc_addr);
writel(val, cc_addr);
/* Enable the root of the clock tree */
val = 1 << 2;
val = val | readl(cc_addr);
writel(val, cc_addr);
/* Enable the MDP Clock */
val = 1 << 0;
val = val | readl(cc_addr);
writel(val, cc_addr);
}
/* Write the M,N,D values and enable the Pixel Core Clock */
void config_pixel_clk( uint32_t ns,
uint32_t md,
uint32_t cc,
uint32_t ns_addr,
uint32_t md_addr,
uint32_t cc_addr){
unsigned int val = 0;
/* Activate the reset for the M/N Counter */
val = 1 << 7;
writel(val, ns_addr);
/* Write the MD and CC register values */
writel(md, md_addr);
writel(cc, cc_addr);
/* Write the ns value, and active reset for M/N Counter, again */
val = 1 << 7;
val |= ns;
writel(val, ns_addr);
/* De-activate the reset for M/N Counter */
val = 1 << 7;
val = ~val;
val = val & readl(ns_addr);
writel(val, ns_addr);
/* Enable MND counter */
val = 1 << 5;
val = val | readl(cc_addr);
writel(val, cc_addr);
/* Enable the root of the clock tree */
val = 1 << 2;
val = val | readl(cc_addr);
writel(val, cc_addr);
/* Enable the MDP Clock */
val = 1 << 0;
val = val | readl(cc_addr);
writel(val, cc_addr);
/* Enable the LCDC Clock */
val = 1 << 8;
val = val | readl(cc_addr);
writel(val, cc_addr);
}
/* Set rate and enable the clock */
void clock_config(uint32_t ns,
uint32_t md,
uint32_t ns_addr,
uint32_t md_addr)
{
unsigned int val = 0;
/* Activate the reset for the M/N Counter */
val = 1 << 7;
writel(val, ns_addr);
/* Write the MD value into the MD register */
writel(md, md_addr);
/* Write the ns value, and active reset for M/N Counter, again */
val = 1 << 7;
val |= ns;
writel(val, ns_addr);
/* De-activate the reset for M/N Counter */
val = 1 << 7;
val = ~val;
val = val & readl(ns_addr);
writel(val, ns_addr);
/* Enable the M/N Counter */
val = 1 << 8;
val = val | readl(ns_addr);
writel(val, ns_addr);
/* Enable the Clock Root */
val = 1 << 11;
val = val | readl(ns_addr);
writel(val, ns_addr);
/* Enable the Clock Branch */
val = 1 << 9;
val = val | readl(ns_addr);
writel(val, ns_addr);
}
void acpu_clock_init (void)
{
}
void hsusb_clock_init(void)
{
int val;
/* Vote for PLL8 */
val = readl(0x009034C0);
val |= (1<<8);
writel(val, 0x009034C0);
/* Wait until PLL is enabled. */
while (!(readl(0x00903158) & (1<<16)));
//Set 7th bit in NS Register
val = 1 << 7;
writel(val, USB_HS1_XVCR_FS_CLK_NS);
//Set rate specific value in MD
writel(0x000500DF, USB_HS1_XVCR_FS_CLK_MD);
//Set value in NS register
val = 1 << 7;
val |= 0x00E400C3;
writel(val, USB_HS1_XVCR_FS_CLK_NS);
// Clear 7th bit
val = 1 << 7;
val = ~val;
val = val & readl(USB_HS1_XVCR_FS_CLK_NS);
writel(val, USB_HS1_XVCR_FS_CLK_NS);
//set 11th bit
val = 1 << 11;
val |= readl(USB_HS1_XVCR_FS_CLK_NS);
writel(val, USB_HS1_XVCR_FS_CLK_NS);
//set 9th bit
val = 1 << 9;
val |= readl(USB_HS1_XVCR_FS_CLK_NS);
writel(val, USB_HS1_XVCR_FS_CLK_NS);
//set 8th bit
val = 1 << 8;
val |= readl(USB_HS1_XVCR_FS_CLK_NS);
writel(val, USB_HS1_XVCR_FS_CLK_NS);
}
/* Return true if PXO is 27MHz. */
int pxo_is_27mhz(void)
{
uint32_t xo_sel;
int pll8_ref_is_27mhz = 0;
/* PLL8 is assumed to be at 384MHz. Check if the 384/(L+M/N) == 27. */
if (readl(BB_PLL8_L_VAL_REG) == 14 && readl(BB_PLL8_M_VAL_REG) == 2
&& readl(BB_PLL8_N_VAL_REG) == 9)
pll8_ref_is_27mhz = 1;
/* Check which source is used with above L, M, N vals.
* xo_sel: 0=PXO, else MXO */
xo_sel = readl(BB_PLL8_MODE_REG) & (1 << 4);
return (xo_sel == 0 && pll8_ref_is_27mhz);
}