Commit 1a0e8a52 authored by Kukjin Kim's avatar Kukjin Kim Committed by Ben Dooks

ARM: S5P6440: Add Clock and PLL support

This patch adds clock and pll support for S5P6440. This patch are based on
Harald Welte's patches and Ben's plat-samsung.
Signed-off-by: default avatarThomas Abraham <thomas.ab@samsung.com>
Signed-off-by: default avatarKukjin Kim <kgene.kim@samsung.com>
Signed-off-by: default avatarBen Dooks <ben-linux@fluff.org>
parent 209fecd1
/* linux/arch/arm/mach-s5p6440/include/mach/regs-clock.h
*
* Copyright (c) 2009 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
* S5P6440 - Clock register definitions
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __ASM_ARCH_REGS_CLOCK_H
#define __ASM_ARCH_REGS_CLOCK_H __FILE__
#include <mach/map.h>
#define S5P_CLKREG(x) (S5P_VA_CLK + (x))
#define S5P_APLL_LOCK S5P_CLKREG(0x00)
#define S5P_MPLL_LOCK S5P_CLKREG(0x04)
#define S5P_EPLL_LOCK S5P_CLKREG(0x08)
#define S5P_APLL_CON S5P_CLKREG(0x0C)
#define S5P_MPLL_CON S5P_CLKREG(0x10)
#define S5P_EPLL_CON S5P_CLKREG(0x14)
#define S5P_EPLL_CON_K S5P_CLKREG(0x18)
#define S5P_CLK_SRC0 S5P_CLKREG(0x1C)
#define S5P_CLK_DIV0 S5P_CLKREG(0x20)
#define S5P_CLK_DIV1 S5P_CLKREG(0x24)
#define S5P_CLK_DIV2 S5P_CLKREG(0x28)
#define S5P_CLK_OUT S5P_CLKREG(0x2C)
#define S5P_CLK_GATE_HCLK0 S5P_CLKREG(0x30)
#define S5P_CLK_GATE_PCLK S5P_CLKREG(0x34)
#define S5P_CLK_GATE_SCLK0 S5P_CLKREG(0x38)
#define S5P_CLK_GATE_MEM0 S5P_CLKREG(0x3C)
#define S5P_CLK_DIV3 S5P_CLKREG(0x40)
#define S5P_CLK_GATE_HCLK1 S5P_CLKREG(0x44)
#define S5P_CLK_GATE_SCLK1 S5P_CLKREG(0x48)
#define S5P_AHB_CON0 S5P_CLKREG(0x100)
#define S5P_CLK_SRC1 S5P_CLKREG(0x10C)
#define S5P_SWRESET S5P_CLKREG(0x114)
#define S5P_SYS_ID S5P_CLKREG(0x118)
#define S5P_SYS_OTHERS S5P_CLKREG(0x11C)
#define S5P_MEM_CFG_STAT S5P_CLKREG(0x12C)
#define S5P_PWR_CFG S5P_CLKREG(0x804)
#define S5P_EINT_WAKEUP_MASK S5P_CLKREG(0x808)
#define S5P_NORMAL_CFG S5P_CLKREG(0x810)
#define S5P_STOP_CFG S5P_CLKREG(0x814)
#define S5P_SLEEP_CFG S5P_CLKREG(0x818)
#define S5P_OSC_FREQ S5P_CLKREG(0x820)
#define S5P_OSC_STABLE S5P_CLKREG(0x824)
#define S5P_PWR_STABLE S5P_CLKREG(0x828)
#define S5P_MTC_STABLE S5P_CLKREG(0x830)
#define S5P_OTHERS S5P_CLKREG(0x900)
#define S5P_RST_STAT S5P_CLKREG(0x904)
#define S5P_WAKEUP_STAT S5P_CLKREG(0x908)
#define S5P_SLPEN S5P_CLKREG(0x930)
#define S5P_INFORM0 S5P_CLKREG(0xA00)
#define S5P_INFORM1 S5P_CLKREG(0xA04)
#define S5P_INFORM2 S5P_CLKREG(0xA08)
#define S5P_INFORM3 S5P_CLKREG(0xA0C)
/* CLKDIV0 */
#define S5P_CLKDIV0_PCLK_MASK (0xf << 12)
#define S5P_CLKDIV0_PCLK_SHIFT (12)
#define S5P_CLKDIV0_HCLK_MASK (0xf << 8)
#define S5P_CLKDIV0_HCLK_SHIFT (8)
#define S5P_CLKDIV0_MPLL_MASK (0x1 << 4)
#define S5P_CLKDIV0_ARM_MASK (0xf << 0)
#define S5P_CLKDIV0_ARM_SHIFT (0)
/* CLKDIV3 */
#define S5P_CLKDIV3_PCLK_LOW_MASK (0xf << 12)
#define S5P_CLKDIV3_PCLK_LOW_SHIFT (12)
#define S5P_CLKDIV3_HCLK_LOW_MASK (0xf << 8)
#define S5P_CLKDIV3_HCLK_LOW_SHIFT (8)
/* HCLK0 GATE Registers */
#define S5P_CLKCON_HCLK0_USB (1<<20)
#define S5P_CLKCON_HCLK0_HSMMC2 (1<<19)
#define S5P_CLKCON_HCLK0_HSMMC1 (1<<18)
#define S5P_CLKCON_HCLK0_HSMMC0 (1<<17)
#define S5P_CLKCON_HCLK0_POST0 (1<<5)
/* HCLK1 GATE Registers */
#define S5P_CLKCON_HCLK1_DISPCON (1<<1)
/* PCLK GATE Registers */
#define S5P_CLKCON_PCLK_IIS2 (1<<26)
#define S5P_CLKCON_PCLK_SPI1 (1<<22)
#define S5P_CLKCON_PCLK_SPI0 (1<<21)
#define S5P_CLKCON_PCLK_GPIO (1<<18)
#define S5P_CLKCON_PCLK_IIC0 (1<<17)
#define S5P_CLKCON_PCLK_TSADC (1<<12)
#define S5P_CLKCON_PCLK_PWM (1<<7)
#define S5P_CLKCON_PCLK_RTC (1<<6)
#define S5P_CLKCON_PCLK_WDT (1<<5)
#define S5P_CLKCON_PCLK_UART3 (1<<4)
#define S5P_CLKCON_PCLK_UART2 (1<<3)
#define S5P_CLKCON_PCLK_UART1 (1<<2)
#define S5P_CLKCON_PCLK_UART0 (1<<1)
/* SCLK0 GATE Registers */
#define S5P_CLKCON_SCLK0_MMC2_48 (1<<29)
#define S5P_CLKCON_SCLK0_MMC1_48 (1<<28)
#define S5P_CLKCON_SCLK0_MMC0_48 (1<<27)
#define S5P_CLKCON_SCLK0_MMC2 (1<<26)
#define S5P_CLKCON_SCLK0_MMC1 (1<<25)
#define S5P_CLKCON_SCLK0_MMC0 (1<<24)
#define S5P_CLKCON_SCLK0_SPI1_48 (1<<23)
#define S5P_CLKCON_SCLK0_SPI0_48 (1<<22)
#define S5P_CLKCON_SCLK0_SPI1 (1<<21)
#define S5P_CLKCON_SCLK0_SPI0 (1<<20)
#define S5P_CLKCON_SCLK0_UART (1<<5)
/* SCLK1 GATE Registers */
/* MEM0 GATE Registers */
#define S5P_CLKCON_MEM0_HCLK_NFCON (1<<2)
/*OTHERS Resgister */
#define S5P_OTHERS_USB_SIG_MASK (1<<16)
#define S5P_OTHERS_HCLK_LOW_SEL_MPLL (1<<6)
/* Compatibility defines */
#define ARM_CLK_DIV S5P_CLK_DIV0
#define ARM_DIV_RATIO_SHIFT 0
#define ARM_DIV_MASK (0xf << ARM_DIV_RATIO_SHIFT)
#endif /* __ASM_ARCH_REGS_CLOCK_H */
/* linux/arch/arm/plat-s5p/clock.c
*
* Copyright 2009 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
* S5P - Common clock support
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/sysdev.h>
#include <linux/io.h>
#include <asm/div64.h>
#include <plat/clock.h>
#include <plat/clock-clksrc.h>
#include <plat/s5p-clock.h>
/* fin_apll, fin_mpll and fin_epll are all the same clock, which we call
* clk_ext_xtal_mux.
*/
struct clk clk_ext_xtal_mux = {
.name = "ext_xtal",
.id = -1,
};
/* 48MHz USB Phy clock output */
struct clk clk_48m = {
.name = "clk_48m",
.id = -1,
.rate = 48000000,
};
/* APLL clock output
* No need .ctrlbit, this is always on
*/
struct clk clk_fout_apll = {
.name = "fout_apll",
.id = -1,
};
/* MPLL clock output
* No need .ctrlbit, this is always on
*/
struct clk clk_fout_mpll = {
.name = "fout_mpll",
.id = -1,
};
/* EPLL clock output */
struct clk clk_fout_epll = {
.name = "fout_epll",
.id = -1,
.ctrlbit = (1 << 31),
};
/* ARM clock */
struct clk clk_arm = {
.name = "armclk",
.id = -1,
.rate = 0,
.ctrlbit = 0,
};
/* Possible clock sources for APLL Mux */
static struct clk *clk_src_apll_list[] = {
[0] = &clk_fin_apll,
[1] = &clk_fout_apll,
};
struct clksrc_sources clk_src_apll = {
.sources = clk_src_apll_list,
.nr_sources = ARRAY_SIZE(clk_src_apll_list),
};
/* Possible clock sources for MPLL Mux */
static struct clk *clk_src_mpll_list[] = {
[0] = &clk_fin_mpll,
[1] = &clk_fout_mpll,
};
struct clksrc_sources clk_src_mpll = {
.sources = clk_src_mpll_list,
.nr_sources = ARRAY_SIZE(clk_src_mpll_list),
};
/* Possible clock sources for EPLL Mux */
static struct clk *clk_src_epll_list[] = {
[0] = &clk_fin_epll,
[1] = &clk_fout_epll,
};
struct clksrc_sources clk_src_epll = {
.sources = clk_src_epll_list,
.nr_sources = ARRAY_SIZE(clk_src_epll_list),
};
int s5p_gatectrl(void __iomem *reg, struct clk *clk, int enable)
{
unsigned int ctrlbit = clk->ctrlbit;
u32 con;
con = __raw_readl(reg);
con = enable ? (con | ctrlbit) : (con & ~ctrlbit);
__raw_writel(con, reg);
return 0;
}
static struct clk *s5p_clks[] __initdata = {
&clk_ext_xtal_mux,
&clk_48m,
&clk_fout_apll,
&clk_fout_mpll,
&clk_fout_epll,
&clk_arm,
};
void __init s5p_register_clocks(unsigned long xtal_freq)
{
int ret;
clk_ext_xtal_mux.rate = xtal_freq;
ret = s3c24xx_register_clocks(s5p_clks, ARRAY_SIZE(s5p_clks));
if (ret > 0)
printk(KERN_ERR "Failed to register s5p clocks\n");
}
/* arch/arm/plat-s5p/include/plat/pll.h
*
* Copyright (c) 2009 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
* S5P PLL code
*
* Based on arch/arm/plat-s3c64xx/include/plat/pll.h
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#define PLL45XX_MDIV_MASK (0x3FF)
#define PLL45XX_PDIV_MASK (0x3F)
#define PLL45XX_SDIV_MASK (0x7)
#define PLL45XX_MDIV_SHIFT (16)
#define PLL45XX_PDIV_SHIFT (8)
#define PLL45XX_SDIV_SHIFT (0)
#include <asm/div64.h>
enum pll45xx_type_t {
pll_4500,
pll_4502,
pll_4508
};
static inline unsigned long s5p_get_pll45xx(unsigned long baseclk, u32 pll_con,
enum pll45xx_type_t pll_type)
{
u32 mdiv, pdiv, sdiv;
u64 fvco = baseclk;
mdiv = (pll_con >> PLL45XX_MDIV_SHIFT) & PLL45XX_MDIV_MASK;
pdiv = (pll_con >> PLL45XX_PDIV_SHIFT) & PLL45XX_PDIV_MASK;
sdiv = (pll_con >> PLL45XX_SDIV_SHIFT) & PLL45XX_SDIV_MASK;
if (pll_type == pll_4508)
sdiv = sdiv - 1;
fvco *= mdiv;
do_div(fvco, (pdiv << sdiv));
return (unsigned long)fvco;
}
#define PLL90XX_MDIV_MASK (0xFF)
#define PLL90XX_PDIV_MASK (0x3F)
#define PLL90XX_SDIV_MASK (0x7)
#define PLL90XX_KDIV_MASK (0xffff)
#define PLL90XX_MDIV_SHIFT (16)
#define PLL90XX_PDIV_SHIFT (8)
#define PLL90XX_SDIV_SHIFT (0)
#define PLL90XX_KDIV_SHIFT (0)
static inline unsigned long s5p_get_pll90xx(unsigned long baseclk,
u32 pll_con, u32 pll_conk)
{
unsigned long result;
u32 mdiv, pdiv, sdiv, kdiv;
u64 tmp;
mdiv = (pll_con >> PLL90XX_MDIV_SHIFT) & PLL90XX_MDIV_MASK;
pdiv = (pll_con >> PLL90XX_PDIV_SHIFT) & PLL90XX_PDIV_MASK;
sdiv = (pll_con >> PLL90XX_SDIV_SHIFT) & PLL90XX_SDIV_MASK;
kdiv = pll_conk & PLL90XX_KDIV_MASK;
/* We need to multiple baseclk by mdiv (the integer part) and kdiv
* which is in 2^16ths, so shift mdiv up (does not overflow) and
* add kdiv before multiplying. The use of tmp is to avoid any
* overflows before shifting bac down into result when multipling
* by the mdiv and kdiv pair.
*/
tmp = baseclk;
tmp *= (mdiv << 16) + kdiv;
do_div(tmp, (pdiv << sdiv));
result = tmp >> 16;
return result;
}
/* linux/arch/arm/plat-s5p/include/plat/s5p-clock.h
*
* Copyright 2009 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
* Header file for s5p clock support
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __ASM_PLAT_S5P_CLOCK_H
#define __ASM_PLAT_S5P_CLOCK_H __FILE__
#include <linux/clk.h>
#define GET_DIV(clk, field) ((((clk) & field##_MASK) >> field##_SHIFT) + 1)
#define clk_fin_apll clk_ext_xtal_mux
#define clk_fin_mpll clk_ext_xtal_mux
#define clk_fin_epll clk_ext_xtal_mux
extern struct clk clk_ext_xtal_mux;
extern struct clk clk_48m;
extern struct clk clk_fout_apll;
extern struct clk clk_fout_mpll;
extern struct clk clk_fout_epll;
extern struct clk clk_arm;
extern struct clksrc_sources clk_src_apll;
extern struct clksrc_sources clk_src_mpll;
extern struct clksrc_sources clk_src_epll;
extern int s5p6440_clk48m_ctrl(struct clk *clk, int enable);
extern int s5p_gatectrl(void __iomem *reg, struct clk *clk, int enable);
#endif /* __ASM_PLAT_S5P_CLOCK_H */
This diff is collapsed.
......@@ -95,6 +95,7 @@ extern void s3c_register_clocks(struct clk *clk, int nr_clks);
extern int s3c24xx_register_baseclocks(unsigned long xtal);
extern void s3c64xx_register_clocks(void);
extern void s5p_register_clocks(unsigned long xtal_freq);
extern void s3c24xx_setup_clocks(unsigned long fclk,
unsigned long hclk,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment