123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869 |
- // SPDX-License-Identifier: GPL-2.0+
- /*
- * (C) Copyright 2016 Nexell
- * Hyunseok, Jung <hsjung@nexell.co.kr>
- */
- #include <common.h>
- #include <command.h>
- #include <linux/err.h>
- #include <asm/io.h>
- #include <asm/arch/nexell.h>
- #include <asm/arch/clk.h>
- /*
- * clock generator macros
- */
- #define I_PLL0_BIT (0)
- #define I_PLL1_BIT (1)
- #define I_PLL2_BIT (2)
- #define I_PLL3_BIT (3)
- #define I_EXT1_BIT (4)
- #define I_EXT2_BIT (5)
- #define I_CLKn_BIT (7)
- #define I_EXT1_BIT_FORCE (8)
- #define I_EXT2_BIT_FORCE (9)
- #define I_CLOCK_NUM 6 /* PLL0, PLL1, PLL2, PLL3, EXT1, EXT2 */
- #define I_EXECEPT_CLK (0)
- #define I_CLOCK_MASK (((1 << I_CLOCK_NUM) - 1) & ~I_EXECEPT_CLK)
- #define I_PLL0 (1 << I_PLL0_BIT)
- #define I_PLL1 (1 << I_PLL1_BIT)
- #define I_PLL2 (1 << I_PLL2_BIT)
- #define I_PLL3 (1 << I_PLL3_BIT)
- #define I_EXTCLK1 (1 << I_EXT1_BIT)
- #define I_EXTCLK2 (1 << I_EXT2_BIT)
- #define I_EXTCLK1_FORCE (1 << I_EXT1_BIT_FORCE)
- #define I_EXTCLK2_FORCE (1 << I_EXT2_BIT_FORCE)
- #define I_PLL_0_1 (I_PLL0 | I_PLL1)
- #define I_PLL_0_2 (I_PLL_0_1 | I_PLL2)
- #define I_PLL_0_3 (I_PLL_0_2 | I_PLL3)
- #define I_CLKnOUT (0)
- #define I_PCLK (1 << 16)
- #define I_BCLK (1 << 17)
- #define I_GATE_PCLK (1 << 20)
- #define I_GATE_BCLK (1 << 21)
- #define I_PCLK_MASK (I_GATE_PCLK | I_PCLK)
- #define I_BCLK_MASK (I_GATE_BCLK | I_BCLK)
- struct clk_dev_peri {
- const char *dev_name;
- void __iomem *base;
- int dev_id;
- int periph_id;
- int clk_step;
- u32 in_mask;
- u32 in_mask1;
- int div_src_0;
- int div_val_0;
- int invert_0;
- int div_src_1;
- int div_val_1;
- int invert_1;
- int in_extclk_1;
- int in_extclk_2;
- };
- struct clk_dev {
- struct clk clk;
- struct clk *link;
- const char *name;
- struct clk_dev_peri *peri;
- };
- struct clk_dev_map {
- unsigned int con_enb;
- unsigned int con_gen[4];
- };
- #define CLK_PERI_1S(name, devid, id, addr, mk)[id] = \
- { .dev_name = name, .dev_id = devid, .periph_id = id, .clk_step = 1, \
- .base = (void *)addr, .in_mask = mk, }
- #define CLK_PERI_2S(name, devid, id, addr, mk, mk2)[id] = \
- { .dev_name = name, .dev_id = devid, .periph_id = id, .clk_step = 2, \
- .base = (void *)addr, .in_mask = mk, .in_mask1 = mk2, }
- static const char * const clk_core[] = {
- CORECLK_NAME_PLL0, CORECLK_NAME_PLL1, CORECLK_NAME_PLL2,
- CORECLK_NAME_PLL3, CORECLK_NAME_FCLK, CORECLK_NAME_MCLK,
- CORECLK_NAME_BCLK, CORECLK_NAME_PCLK, CORECLK_NAME_HCLK,
- };
- /*
- * Section ".data" must be used because BSS is not available before relocation,
- * in board_init_f(), respectively! I.e. global variables can not be used!
- */
- static struct clk_dev_peri clk_periphs[]
- __section(".data") = {
- CLK_PERI_1S(DEV_NAME_TIMER, 0, CLK_ID_TIMER_0,
- PHY_BASEADDR_CLKGEN14, (I_PLL_0_2)),
- CLK_PERI_1S(DEV_NAME_TIMER, 1, CLK_ID_TIMER_1,
- PHY_BASEADDR_CLKGEN0, (I_PLL_0_2)),
- CLK_PERI_1S(DEV_NAME_TIMER, 2, CLK_ID_TIMER_2,
- PHY_BASEADDR_CLKGEN1, (I_PLL_0_2)),
- CLK_PERI_1S(DEV_NAME_TIMER, 3, CLK_ID_TIMER_3,
- PHY_BASEADDR_CLKGEN2, (I_PLL_0_2)),
- CLK_PERI_1S(DEV_NAME_UART, 0, CLK_ID_UART_0,
- PHY_BASEADDR_CLKGEN22, (I_PLL_0_2)),
- CLK_PERI_1S(DEV_NAME_UART, 1, CLK_ID_UART_1,
- PHY_BASEADDR_CLKGEN24, (I_PLL_0_2)),
- CLK_PERI_1S(DEV_NAME_UART, 2, CLK_ID_UART_2,
- PHY_BASEADDR_CLKGEN23, (I_PLL_0_2)),
- CLK_PERI_1S(DEV_NAME_UART, 3, CLK_ID_UART_3,
- PHY_BASEADDR_CLKGEN25, (I_PLL_0_2)),
- CLK_PERI_1S(DEV_NAME_UART, 4, CLK_ID_UART_4,
- PHY_BASEADDR_CLKGEN26, (I_PLL_0_2)),
- CLK_PERI_1S(DEV_NAME_UART, 5, CLK_ID_UART_5,
- PHY_BASEADDR_CLKGEN27, (I_PLL_0_2)),
- CLK_PERI_1S(DEV_NAME_PWM, 0, CLK_ID_PWM_0,
- PHY_BASEADDR_CLKGEN13, (I_PLL_0_2)),
- CLK_PERI_1S(DEV_NAME_PWM, 1, CLK_ID_PWM_1,
- PHY_BASEADDR_CLKGEN3, (I_PLL_0_2)),
- CLK_PERI_1S(DEV_NAME_PWM, 2, CLK_ID_PWM_2,
- PHY_BASEADDR_CLKGEN4, (I_PLL_0_2)),
- CLK_PERI_1S(DEV_NAME_PWM, 3, CLK_ID_PWM_3,
- PHY_BASEADDR_CLKGEN5, (I_PLL_0_2)),
- CLK_PERI_1S(DEV_NAME_I2C, 0, CLK_ID_I2C_0,
- PHY_BASEADDR_CLKGEN6, (I_GATE_PCLK)),
- CLK_PERI_1S(DEV_NAME_I2C, 1, CLK_ID_I2C_1,
- PHY_BASEADDR_CLKGEN7, (I_GATE_PCLK)),
- CLK_PERI_1S(DEV_NAME_I2C, 2, CLK_ID_I2C_2,
- PHY_BASEADDR_CLKGEN8, (I_GATE_PCLK)),
- CLK_PERI_2S(DEV_NAME_GMAC, 0, CLK_ID_GMAC,
- PHY_BASEADDR_CLKGEN10,
- (I_PLL_0_3 | I_EXTCLK1 | I_EXTCLK1_FORCE),
- (I_CLKnOUT)),
- CLK_PERI_2S(DEV_NAME_I2S, 0, CLK_ID_I2S_0,
- PHY_BASEADDR_CLKGEN15, (I_PLL_0_3 | I_EXTCLK1),
- (I_CLKnOUT)),
- CLK_PERI_2S(DEV_NAME_I2S, 1, CLK_ID_I2S_1,
- PHY_BASEADDR_CLKGEN16, (I_PLL_0_3 | I_EXTCLK1),
- (I_CLKnOUT)),
- CLK_PERI_2S(DEV_NAME_I2S, 2, CLK_ID_I2S_2,
- PHY_BASEADDR_CLKGEN17, (I_PLL_0_3 | I_EXTCLK1),
- (I_CLKnOUT)),
- CLK_PERI_1S(DEV_NAME_SDHC, 0, CLK_ID_SDHC_0,
- PHY_BASEADDR_CLKGEN18, (I_PLL_0_2 | I_GATE_PCLK)),
- CLK_PERI_1S(DEV_NAME_SDHC, 1, CLK_ID_SDHC_1,
- PHY_BASEADDR_CLKGEN19, (I_PLL_0_2 | I_GATE_PCLK)),
- CLK_PERI_1S(DEV_NAME_SDHC, 2, CLK_ID_SDHC_2,
- PHY_BASEADDR_CLKGEN20, (I_PLL_0_2 | I_GATE_PCLK)),
- CLK_PERI_1S(DEV_NAME_SPI, 0, CLK_ID_SPI_0,
- PHY_BASEADDR_CLKGEN37, (I_PLL_0_2)),
- CLK_PERI_1S(DEV_NAME_SPI, 1, CLK_ID_SPI_1,
- PHY_BASEADDR_CLKGEN38, (I_PLL_0_2)),
- CLK_PERI_1S(DEV_NAME_SPI, 2, CLK_ID_SPI_2,
- PHY_BASEADDR_CLKGEN39, (I_PLL_0_2)),
- };
- #define CLK_PERI_NUM ((int)ARRAY_SIZE(clk_periphs))
- #define CLK_CORE_NUM ((int)ARRAY_SIZE(clk_core))
- #define CLK_DEVS_NUM (CLK_CORE_NUM + CLK_PERI_NUM)
- #define MAX_DIVIDER ((1 << 8) - 1) /* 256, align 2 */
- static struct clk_dev st_clk_devs[CLK_DEVS_NUM]
- __section(".data");
- #define clk_dev_get(n) ((struct clk_dev *)&st_clk_devs[n])
- #define clk_container(p) (container_of(p, struct clk_dev, clk))
- /*
- * Core frequencys
- */
- struct _core_hz_ {
- unsigned long pll[4]; /* PLL */
- unsigned long cpu_fclk, cpu_bclk; /* cpu */
- unsigned long mem_fclk, mem_dclk, mem_bclk, mem_pclk; /* ddr */
- unsigned long bus_bclk, bus_pclk; /* bus */
- #if defined(CONFIG_ARCH_S5P6818)
- unsigned long cci4_bclk, cci4_pclk; /* cci */
- #endif
- /* ip */
- unsigned long g3d_bclk;
- unsigned long coda_bclk, coda_pclk;
- #if defined(CONFIG_ARCH_S5P6818)
- unsigned long disp_bclk, disp_pclk;
- unsigned long hdmi_pclk;
- #endif
- };
- /*
- * Section ".data" must be used because BSS is not available before relocation,
- * in board_init_f(), respectively! I.e. global variables can not be used!
- */
- /* core clock */
- static struct _core_hz_ core_hz __section(".data");
- #define CORE_HZ_SIZE (sizeof(core_hz) / 4)
- /*
- * CLKGEN HW
- */
- static inline void clk_dev_bclk(void *base, int on)
- {
- struct clk_dev_map *reg = base;
- unsigned int val = readl(®->con_enb) & ~(0x3);
- val |= (on ? 3 : 0) & 0x3; /* always BCLK */
- writel(val, ®->con_enb);
- }
- static inline void clk_dev_pclk(void *base, int on)
- {
- struct clk_dev_map *reg = base;
- unsigned int val = 0;
- if (!on)
- return;
- val = readl(®->con_enb) & ~(1 << 3);
- val |= (1 << 3);
- writel(val, ®->con_enb);
- }
- static inline void clk_dev_rate(void *base, int step, int src, int div)
- {
- struct clk_dev_map *reg = base;
- unsigned int val = 0;
- val = readl(®->con_gen[step << 1]);
- val &= ~(0x07 << 2);
- val |= (src << 2); /* source */
- val &= ~(0xFF << 5);
- val |= (div - 1) << 5; /* divider */
- writel(val, ®->con_gen[step << 1]);
- }
- static inline void clk_dev_inv(void *base, int step, int inv)
- {
- struct clk_dev_map *reg = base;
- unsigned int val = readl(®->con_gen[step << 1]) & ~(1 << 1);
- val |= (inv << 1);
- writel(val, ®->con_gen[step << 1]);
- }
- static inline void clk_dev_enb(void *base, int on)
- {
- struct clk_dev_map *reg = base;
- unsigned int val = readl(®->con_enb) & ~(1 << 2);
- val |= ((on ? 1 : 0) << 2);
- writel(val, ®->con_enb);
- }
- /*
- * CORE FREQUENCY
- *
- * PLL0 [P,M,S] ------- | | ----- [DIV0] --- CPU-G0
- * |M| ----- [DIV1] --- BCLK/PCLK
- * PLL1 [P,M,S] ------- | | ----- [DIV2] --- DDR
- * |U| ----- [DIV3] --- 3D
- * PLL2 [P,M,S,K]-------| | ----- [DIV4] --- CODA
- * |X| ----- [DIV5] --- DISPLAY
- * PLL3 [P,M,S,K]-------| | ----- [DIV6] --- HDMI
- * | | ----- [DIV7] --- CPU-G1
- * | | ----- [DIV8] --- CCI-400(FASTBUS)
- *
- */
- struct nx_clkpwr_registerset {
- u32 clkmodereg0; /* 0x000 : Clock Mode Register0 */
- u32 __reserved0; /* 0x004 */
- u32 pllsetreg[4]; /* 0x008 ~ 0x014 : PLL Setting Register */
- u32 __reserved1[2]; /* 0x018 ~ 0x01C */
- u32 dvoreg[9]; /* 0x020 ~ 0x040 : Divider Setting Register */
- u32 __Reserved2; /* 0x044 */
- u32 pllsetreg_sscg[6]; /* 0x048 ~ 0x05C */
- u32 __reserved3[8]; /* 0x060 ~ 0x07C */
- u8 __reserved4[0x200 - 0x80]; /* padding (0x80 ~ 0x1FF) */
- u32 gpiowakeupriseenb; /* 0x200 : GPIO Rising Edge Detect En. Reg. */
- u32 gpiowakeupfallenb; /* 0x204 : GPIO Falling Edge Detect En. Reg. */
- u32 gpiorstenb; /* 0x208 : GPIO Reset Enable Register */
- u32 gpiowakeupenb; /* 0x20C : GPIO Wakeup Source Enable */
- u32 gpiointenb; /* 0x210 : Interrupt Enable Register */
- u32 gpiointpend; /* 0x214 : Interrupt Pend Register */
- u32 resetstatus; /* 0x218 : Reset Status Register */
- u32 intenable; /* 0x21C : Interrupt Enable Register */
- u32 intpend; /* 0x220 : Interrupt Pend Register */
- u32 pwrcont; /* 0x224 : Power Control Register */
- u32 pwrmode; /* 0x228 : Power Mode Register */
- u32 __reserved5; /* 0x22C : Reserved Region */
- u32 scratch[3]; /* 0x230 ~ 0x238 : Scratch Register */
- u32 sysrstconfig; /* 0x23C : System Reset Configuration Reg. */
- u8 __reserved6[0x2A0 - 0x240]; /* padding (0x240 ~ 0x29F) */
- u32 cpupowerdownreq; /* 0x2A0 : CPU Power Down Request Register */
- u32 cpupoweronreq; /* 0x2A4 : CPU Power On Request Register */
- u32 cpuresetmode; /* 0x2A8 : CPU Reset Mode Register */
- u32 cpuwarmresetreq; /* 0x2AC : CPU Warm Reset Request Register */
- u32 __reserved7; /* 0x2B0 */
- u32 cpustatus; /* 0x2B4 : CPU Status Register */
- u8 __reserved8[0x400 - 0x2B8]; /* padding (0x2B8 ~ 0x33F) */
- };
- static struct nx_clkpwr_registerset * const clkpwr =
- (struct nx_clkpwr_registerset *)PHY_BASEADDR_CLKPWR;
- #define getquotient(v, d) ((v) / (d))
- #define DIV_CPUG0 0
- #define DIV_BUS 1
- #define DIV_MEM 2
- #define DIV_G3D 3
- #define DIV_CODA 4
- #if defined(CONFIG_ARCH_S5P6818)
- #define DIV_DISP 5
- #define DIV_HDMI 6
- #define DIV_CPUG1 7
- #define DIV_CCI4 8
- #endif
- #define DVO0 3
- #define DVO1 9
- #define DVO2 15
- #define DVO3 21
- static unsigned int pll_rate(unsigned int plln, unsigned int xtal)
- {
- unsigned int val, val1, nP, nM, nS, nK;
- unsigned int temp = 0;
- val = clkpwr->pllsetreg[plln];
- val1 = clkpwr->pllsetreg_sscg[plln];
- xtal /= 1000; /* Unit Khz */
- nP = (val >> 18) & 0x03F;
- nM = (val >> 8) & 0x3FF;
- nS = (val >> 0) & 0x0FF;
- nK = (val1 >> 16) & 0xFFFF;
- if (plln > 1 && nK) {
- temp = (unsigned int)(getquotient((getquotient((nK * 1000),
- 65536) * xtal), nP) >> nS);
- }
- temp = (unsigned int)((getquotient((nM * xtal), nP) >> nS) * 1000)
- + temp;
- return temp;
- }
- static unsigned int pll_dvo(int dvo)
- {
- unsigned int val;
- val = (clkpwr->dvoreg[dvo] & 0x7);
- return val;
- }
- static unsigned int pll_div(int dvo)
- {
- unsigned int val = clkpwr->dvoreg[dvo];
- return ((((val >> DVO3) & 0x3F) + 1) << 24) |
- ((((val >> DVO2) & 0x3F) + 1) << 16) |
- ((((val >> DVO1) & 0x3F) + 1) << 8) |
- ((((val >> DVO0) & 0x3F) + 1) << 0);
- }
- #define PLLN_RATE(n) (pll_rate(n, CONFIG_SYS_PLLFIN)) /* 0~ 3 */
- #define CPU_FCLK_RATE(n) (pll_rate(pll_dvo(n), CONFIG_SYS_PLLFIN) / \
- ((pll_div(n) >> 0) & 0x3F))
- #define CPU_BCLK_RATE(n) (pll_rate(pll_dvo(n), CONFIG_SYS_PLLFIN) / \
- ((pll_div(n) >> 0) & 0x3F) / \
- ((pll_div(n) >> 8) & 0x3F))
- #define MEM_FCLK_RATE() (pll_rate(pll_dvo(DIV_MEM), CONFIG_SYS_PLLFIN) / \
- ((pll_div(DIV_MEM) >> 0) & 0x3F) / \
- ((pll_div(DIV_MEM) >> 8) & 0x3F))
- #define MEM_DCLK_RATE() (pll_rate(pll_dvo(DIV_MEM), CONFIG_SYS_PLLFIN) / \
- ((pll_div(DIV_MEM) >> 0) & 0x3F))
- #define MEM_BCLK_RATE() (pll_rate(pll_dvo(DIV_MEM), CONFIG_SYS_PLLFIN) / \
- ((pll_div(DIV_MEM) >> 0) & 0x3F) / \
- ((pll_div(DIV_MEM) >> 8) & 0x3F) / \
- ((pll_div(DIV_MEM) >> 16) & 0x3F))
- #define MEM_PCLK_RATE() (pll_rate(pll_dvo(DIV_MEM), CONFIG_SYS_PLLFIN) / \
- ((pll_div(DIV_MEM) >> 0) & 0x3F) / \
- ((pll_div(DIV_MEM) >> 8) & 0x3F) / \
- ((pll_div(DIV_MEM) >> 16) & 0x3F) / \
- ((pll_div(DIV_MEM) >> 24) & 0x3F))
- #define BUS_BCLK_RATE() (pll_rate(pll_dvo(DIV_BUS), CONFIG_SYS_PLLFIN) / \
- ((pll_div(DIV_BUS) >> 0) & 0x3F))
- #define BUS_PCLK_RATE() (pll_rate(pll_dvo(DIV_BUS), CONFIG_SYS_PLLFIN) / \
- ((pll_div(DIV_BUS) >> 0) & 0x3F) / \
- ((pll_div(DIV_BUS) >> 8) & 0x3F))
- #define G3D_BCLK_RATE() (pll_rate(pll_dvo(DIV_G3D), CONFIG_SYS_PLLFIN) / \
- ((pll_div(DIV_G3D) >> 0) & 0x3F))
- #define MPG_BCLK_RATE() (pll_rate(pll_dvo(DIV_CODA), CONFIG_SYS_PLLFIN) / \
- ((pll_div(DIV_CODA) >> 0) & 0x3F))
- #define MPG_PCLK_RATE() (pll_rate(pll_dvo(DIV_CODA), CONFIG_SYS_PLLFIN) / \
- ((pll_div(DIV_CODA) >> 0) & 0x3F) / \
- ((pll_div(DIV_CODA) >> 8) & 0x3F))
- #if defined(CONFIG_ARCH_S5P6818)
- #define DISP_BCLK_RATE() (pll_rate(pll_dvo(DIV_DISP), CONFIG_SYS_PLLFIN) / \
- ((pll_div(DIV_DISP) >> 0) & 0x3F))
- #define DISP_PCLK_RATE() (pll_rate(pll_dvo(DIV_DISP), CONFIG_SYS_PLLFIN) / \
- ((pll_div(DIV_DISP) >> 0) & 0x3F) / \
- ((pll_div(DIV_DISP) >> 8) & 0x3F))
- #define HDMI_PCLK_RATE() (pll_rate(pll_dvo(DIV_HDMI), CONFIG_SYS_PLLFIN) / \
- ((pll_div(DIV_HDMI) >> 0) & 0x3F))
- #define CCI4_BCLK_RATE() (pll_rate(pll_dvo(DIV_CCI4), CONFIG_SYS_PLLFIN) / \
- ((pll_div(DIV_CCI4) >> 0) & 0x3F))
- #define CCI4_PCLK_RATE() (pll_rate(pll_dvo(DIV_CCI4), CONFIG_SYS_PLLFIN) / \
- ((pll_div(DIV_CCI4) >> 0) & 0x3F) / \
- ((pll_div(DIV_CCI4) >> 8) & 0x3F))
- #endif
- static void core_update_rate(int type)
- {
- switch (type) {
- case 0:
- core_hz.pll[0] = PLLN_RATE(0); break;
- case 1:
- core_hz.pll[1] = PLLN_RATE(1); break;
- case 2:
- core_hz.pll[2] = PLLN_RATE(2); break;
- case 3:
- core_hz.pll[3] = PLLN_RATE(3); break;
- case 4:
- core_hz.cpu_fclk = CPU_FCLK_RATE(DIV_CPUG0); break;
- case 5:
- core_hz.mem_fclk = MEM_FCLK_RATE(); break;
- case 6:
- core_hz.bus_bclk = BUS_BCLK_RATE(); break;
- case 7:
- core_hz.bus_pclk = BUS_PCLK_RATE(); break;
- case 8:
- core_hz.cpu_bclk = CPU_BCLK_RATE(DIV_CPUG0); break;
- case 9:
- core_hz.mem_dclk = MEM_DCLK_RATE(); break;
- case 10:
- core_hz.mem_bclk = MEM_BCLK_RATE(); break;
- case 11:
- core_hz.mem_pclk = MEM_PCLK_RATE(); break;
- case 12:
- core_hz.g3d_bclk = G3D_BCLK_RATE(); break;
- case 13:
- core_hz.coda_bclk = MPG_BCLK_RATE(); break;
- case 14:
- core_hz.coda_pclk = MPG_PCLK_RATE(); break;
- #if defined(CONFIG_ARCH_S5P6818)
- case 15:
- core_hz.disp_bclk = DISP_BCLK_RATE(); break;
- case 16:
- core_hz.disp_pclk = DISP_PCLK_RATE(); break;
- case 17:
- core_hz.hdmi_pclk = HDMI_PCLK_RATE(); break;
- case 18:
- core_hz.cci4_bclk = CCI4_BCLK_RATE(); break;
- case 19:
- core_hz.cci4_pclk = CCI4_PCLK_RATE(); break;
- #endif
- };
- }
- static unsigned long core_get_rate(int type)
- {
- unsigned long rate = 0;
- switch (type) {
- case 0:
- rate = core_hz.pll[0]; break;
- case 1:
- rate = core_hz.pll[1]; break;
- case 2:
- rate = core_hz.pll[2]; break;
- case 3:
- rate = core_hz.pll[3]; break;
- case 4:
- rate = core_hz.cpu_fclk; break;
- case 5:
- rate = core_hz.mem_fclk; break;
- case 6:
- rate = core_hz.bus_bclk; break;
- case 7:
- rate = core_hz.bus_pclk; break;
- case 8:
- rate = core_hz.cpu_bclk; break;
- case 9:
- rate = core_hz.mem_dclk; break;
- case 10:
- rate = core_hz.mem_bclk; break;
- case 11:
- rate = core_hz.mem_pclk; break;
- case 12:
- rate = core_hz.g3d_bclk; break;
- case 13:
- rate = core_hz.coda_bclk; break;
- case 14:
- rate = core_hz.coda_pclk; break;
- #if defined(CONFIG_ARCH_S5P6818)
- case 15:
- rate = core_hz.disp_bclk; break;
- case 16:
- rate = core_hz.disp_pclk; break;
- case 17:
- rate = core_hz.hdmi_pclk; break;
- case 18:
- rate = core_hz.cci4_bclk; break;
- case 19:
- rate = core_hz.cci4_pclk; break;
- #endif
- default:
- printf("unknown core clock type %d ...\n", type);
- break;
- };
- return rate;
- }
- static long core_set_rate(struct clk *clk, long rate)
- {
- return clk->rate;
- }
- static void core_rate_init(void)
- {
- int i;
- for (i = 0; i < CORE_HZ_SIZE; i++)
- core_update_rate(i);
- }
- /*
- * Clock Interfaces
- */
- static inline long clk_divide(long rate, long request,
- int align, int *divide)
- {
- int div = (rate / request);
- int max = MAX_DIVIDER & ~(align - 1);
- int adv = (div & ~(align - 1)) + align;
- long ret;
- if (!div) {
- if (divide)
- *divide = 1;
- return rate;
- }
- if (div != 1)
- div &= ~(align - 1);
- if (div != adv && abs(request - rate / div) > abs(request - rate / adv))
- div = adv;
- div = (div > max ? max : div);
- if (divide)
- *divide = div;
- ret = rate / div;
- return ret;
- }
- void clk_put(struct clk *clk)
- {
- }
- struct clk *clk_get(const char *id)
- {
- struct clk_dev *cdev = clk_dev_get(0);
- struct clk *clk = NULL;
- const char *str = NULL, *c = NULL;
- int i, devid;
- if (id)
- str = id;
- for (i = 0; i < CLK_DEVS_NUM; i++, cdev++) {
- if (!cdev->name)
- continue;
- if (!strncmp(cdev->name, str, strlen(cdev->name))) {
- c = strrchr((const char *)str, (int)'.');
- if (!c || !cdev->peri)
- break;
- devid = dectoul(++c, NULL);
- if (cdev->peri->dev_id == devid)
- break;
- }
- }
- if (i < CLK_DEVS_NUM)
- clk = &cdev->clk;
- else
- clk = &(clk_dev_get(7))->clk; /* pclk */
- return clk ? clk : ERR_PTR(-ENOENT);
- }
- long clk_round_rate(struct clk *clk, unsigned long rate)
- {
- struct clk_dev *pll = NULL, *cdev = clk_container(clk);
- struct clk_dev_peri *peri = cdev->peri;
- unsigned long request = rate, rate_hz = 0;
- unsigned int mask;
- int step, div[2] = { 0, };
- int i, n, clk2 = 0;
- int start_src = 0, max_src = I_CLOCK_NUM;
- short s1 = 0, s2 = 0, d1 = 0, d2 = 0;
- if (!peri)
- return core_set_rate(clk, rate);
- step = peri->clk_step;
- mask = peri->in_mask;
- debug("clk: %s.%d request = %ld [input=0x%x]\n", peri->dev_name,
- peri->dev_id, rate, mask);
- if (!(I_CLOCK_MASK & mask)) {
- if (I_PCLK_MASK & mask)
- return core_get_rate(CORECLK_ID_PCLK);
- else if (I_BCLK_MASK & mask)
- return core_get_rate(CORECLK_ID_BCLK);
- else
- return clk->rate;
- }
- next:
- if (peri->in_mask & I_EXTCLK1_FORCE) {
- start_src = 4; max_src = 5;
- }
- for (n = start_src ; max_src > n; n++) {
- if (!(((mask & I_CLOCK_MASK) >> n) & 0x1))
- continue;
- if (n == I_EXT1_BIT) {
- rate = peri->in_extclk_1;
- } else if (n == I_EXT2_BIT) {
- rate = peri->in_extclk_2;
- } else {
- pll = clk_dev_get(n);
- rate = pll->clk.rate;
- }
- if (!rate)
- continue;
- for (i = 0; step > i ; i++)
- rate = clk_divide(rate, request, 2, &div[i]);
- if (rate_hz && (abs(rate - request) > abs(rate_hz - request)))
- continue;
- debug("clk: %s.%d, pll.%d[%lu] request[%ld] calc[%ld]\n",
- peri->dev_name, peri->dev_id, n, pll->clk.rate,
- request, rate);
- if (clk2) {
- s1 = -1, d1 = -1; /* not use */
- s2 = n, d2 = div[0];
- } else {
- s1 = n, d1 = div[0];
- s2 = I_CLKn_BIT, d2 = div[1];
- }
- rate_hz = rate;
- }
- /* search 2th clock from input */
- if (!clk2 && abs(rate_hz - request) &&
- peri->in_mask1 & ((1 << I_CLOCK_NUM) - 1)) {
- clk2 = 1;
- mask = peri->in_mask1;
- step = 1;
- goto next;
- }
- if (peri->in_mask & I_EXTCLK1_FORCE) {
- if (s1 == 0) {
- s1 = 4; s2 = 7;
- d1 = 1; d2 = 1;
- }
- }
- peri->div_src_0 = s1, peri->div_val_0 = d1;
- peri->div_src_1 = s2, peri->div_val_1 = d2;
- clk->rate = rate_hz;
- debug("clk: %s.%d, step[%d] src[%d,%d] %ld", peri->dev_name,
- peri->dev_id, peri->clk_step, peri->div_src_0, peri->div_src_1,
- rate);
- debug("/(div0: %d * div1: %d) = %ld, %ld diff (%ld)\n",
- peri->div_val_0, peri->div_val_1, rate_hz, request,
- abs(rate_hz - request));
- return clk->rate;
- }
- unsigned long clk_get_rate(struct clk *clk)
- {
- struct clk_dev *cdev = clk_container(clk);
- if (cdev->link)
- clk = cdev->link;
- return clk->rate;
- }
- int clk_set_rate(struct clk *clk, unsigned long rate)
- {
- struct clk_dev *cdev = clk_container(clk);
- struct clk_dev_peri *peri = cdev->peri;
- int i;
- if (!peri)
- return core_set_rate(clk, rate);
- clk_round_rate(clk, rate);
- for (i = 0; peri->clk_step > i ; i++) {
- int s = (i == 0 ? peri->div_src_0 : peri->div_src_1);
- int d = (i == 0 ? peri->div_val_0 : peri->div_val_1);
- if (-1 == s)
- continue;
- clk_dev_rate(peri->base, i, s, d);
- debug("clk: %s.%d (%p) set_rate [%d] src[%d] div[%d]\n",
- peri->dev_name, peri->dev_id, peri->base, i, s, d);
- }
- return clk->rate;
- }
- int clk_enable(struct clk *clk)
- {
- struct clk_dev *cdev = clk_container(clk);
- struct clk_dev_peri *peri = cdev->peri;
- int i = 0, inv = 0;
- if (!peri)
- return 0;
- debug("clk: %s.%d enable (BCLK=%s, PCLK=%s)\n", peri->dev_name,
- peri->dev_id, I_GATE_BCLK & peri->in_mask ? "ON" : "PASS",
- I_GATE_PCLK & peri->in_mask ? "ON" : "PASS");
- if (!(I_CLOCK_MASK & peri->in_mask)) {
- /* Gated BCLK/PCLK enable */
- if (I_GATE_BCLK & peri->in_mask)
- clk_dev_bclk(peri->base, 1);
- if (I_GATE_PCLK & peri->in_mask)
- clk_dev_pclk(peri->base, 1);
- return 0;
- }
- /* invert */
- inv = peri->invert_0;
- for (; peri->clk_step > i; i++, inv = peri->invert_1)
- clk_dev_inv(peri->base, i, inv);
- /* Gated BCLK/PCLK enable */
- if (I_GATE_BCLK & peri->in_mask)
- clk_dev_bclk(peri->base, 1);
- if (I_GATE_PCLK & peri->in_mask)
- clk_dev_pclk(peri->base, 1);
- /* restore clock rate */
- for (i = 0; peri->clk_step > i ; i++) {
- int s = (i == 0 ? peri->div_src_0 : peri->div_src_1);
- int d = (i == 0 ? peri->div_val_0 : peri->div_val_1);
- if (s == -1)
- continue;
- clk_dev_rate(peri->base, i, s, d);
- }
- clk_dev_enb(peri->base, 1);
- return 0;
- }
- void clk_disable(struct clk *clk)
- {
- struct clk_dev *cdev = clk_container(clk);
- struct clk_dev_peri *peri = cdev->peri;
- if (!peri)
- return;
- debug("clk: %s.%d disable\n", peri->dev_name, peri->dev_id);
- if (!(I_CLOCK_MASK & peri->in_mask)) {
- /* Gated BCLK/PCLK disable */
- if (I_GATE_BCLK & peri->in_mask)
- clk_dev_bclk(peri->base, 0);
- if (I_GATE_PCLK & peri->in_mask)
- clk_dev_pclk(peri->base, 0);
- return;
- }
- clk_dev_rate(peri->base, 0, 7, 256); /* for power save */
- clk_dev_enb(peri->base, 0);
- /* Gated BCLK/PCLK disable */
- if (I_GATE_BCLK & peri->in_mask)
- clk_dev_bclk(peri->base, 0);
- if (I_GATE_PCLK & peri->in_mask)
- clk_dev_pclk(peri->base, 0);
- }
- /*
- * Core clocks APIs
- */
- void __init clk_init(void)
- {
- struct clk_dev *cdev = st_clk_devs;
- struct clk_dev_peri *peri = clk_periphs;
- struct clk *clk = NULL;
- int i = 0;
- memset(cdev, 0, sizeof(st_clk_devs));
- core_rate_init();
- for (i = 0; (CLK_CORE_NUM + CLK_PERI_NUM) > i; i++, cdev++) {
- if (i < CLK_CORE_NUM) {
- cdev->name = clk_core[i];
- clk = &cdev->clk;
- clk->rate = core_get_rate(i);
- continue;
- }
- peri = &clk_periphs[i - CLK_CORE_NUM];
- peri->base = (void *)peri->base;
- cdev->peri = peri;
- cdev->name = peri->dev_name;
- if (!(I_CLOCK_MASK & peri->in_mask)) {
- if (I_BCLK_MASK & peri->in_mask)
- cdev->clk.rate = core_get_rate(CORECLK_ID_BCLK);
- if (I_PCLK_MASK & peri->in_mask)
- cdev->clk.rate = core_get_rate(CORECLK_ID_PCLK);
- }
- /* prevent uart clock disable for low step debug message */
- #ifndef CONFIG_DEBUG_NX_UART
- if (peri->dev_name) {
- #ifdef CONFIG_BACKLIGHT_PWM
- if (!strcmp(peri->dev_name, DEV_NAME_PWM))
- continue;
- #endif
- }
- #endif
- }
- debug("CPU : Clock Generator= %d EA, ", CLK_DEVS_NUM);
- }
|