blob: 1ca0833e16d4dab4badfdc63dc24a89220357da4 [file] [log] [blame]
/*
* Copyright 2017, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "../../arch/arm/clock.h"
#include "../../mach/exynos/clock.h"
#if defined(CONFIG_PLAT_EXYNOS5422)
#include "exynos_5422_clock.h"
#else
#include "exynos_common_clock.h"
#endif
#include "../../services.h"
#include <assert.h>
#include <string.h>
#include <utils/util.h>
#define EXYNOS5_CMU_CPU_PADDR 0x10010000
#define EXYNOS5_CMU_CORE_PADDR 0x10014000
#define EXYNOS5_CMU_ACP_PADDR 0x10018000
#define EXYNOS5_CMU_ISP_PADDR 0x1001C000
#define EXYNOS5_CMU_TOP_PADDR 0x10020000
#define EXYNOS5_CMU_LEX_PADDR 0x10024000
#define EXYNOS5_CMU_R0X_PADDR 0x10028000
#define EXYNOS5_CMU_R1X_PADDR 0x1002C000
#define EXYNOS5_CMU_CDREX_PADDR 0x10030000
#define EXYNOS5_CMU_MEM_PADDR 0x10038000
#define EXYNOS5_CMU_SIZE 0x1000
#define EXYNOS5_CMU_CPU_SIZE EXYNOS5_CMU_SIZE
#define EXYNOS5_CMU_CORE_SIZE EXYNOS5_CMU_SIZE
#define EXYNOS5_CMU_ACP_SIZE EXYNOS5_CMU_SIZE
#define EXYNOS5_CMU_ISP_SIZE EXYNOS5_CMU_SIZE
#define EXYNOS5_CMU_TOP_SIZE EXYNOS5_CMU_SIZE
#define EXYNOS5_CMU_LEX_SIZE EXYNOS5_CMU_SIZE
#define EXYNOS5_CMU_R0X_SIZE EXYNOS5_CMU_SIZE
#define EXYNOS5_CMU_R1X_SIZE EXYNOS5_CMU_SIZE
#define EXYNOS5_CMU_CDREX_SIZE EXYNOS5_CMU_SIZE
#define EXYNOS5_CMU_MEM_SIZE EXYNOS5_CMU_SIZE
#define CLKID_UART0 CLKID(TOP, 20, 0)
#define CLKID_UART1 CLKID(TOP, 20, 1)
#define CLKID_UART2 CLKID(TOP, 20, 2)
#define CLKID_UART3 CLKID(TOP, 20, 3)
#define CLKID_PWM CLKID(TOP, 20, 5)
#define CLKID_SPI0 CLKID(TOP, 21, 4)
#define CLKID_SPI1 CLKID(TOP, 21, 5)
#define CLKID_SPI2 CLKID(TOP, 21, 6)
#define CLKID_SPI0_ISP CLKID(TOP, 28, 0)
#define CLKID_SPI1_ISP CLKID(TOP, 28, 1)
volatile struct clk_regs* _clk_regs[NCLKREGS];
static struct clock master_clk = { CLK_OPS(MASTER, default_clk, NULL) };
static struct mpsk_tbl _ambcgpll_tbl[] = {
{ 200, PLL_MPS( 100, 3, 2), 0 },
{ 333, PLL_MPS( 222, 4, 2), 0 },
{ 400, PLL_MPS( 100, 3, 1), 0 },
{ 533, PLL_MPS( 533, 12, 1), 0 },
{ 600, PLL_MPS( 200, 4, 1), 0 },
{ 667, PLL_MPS( 389, 7, 1), 0 },
{ 800, PLL_MPS( 100, 3, 0), 0 },
{ 1000, PLL_MPS( 125, 3, 0), 0 },
{ 1066, PLL_MPS( 533, 12, 0), 0 },
{ 1200, PLL_MPS( 150, 3, 0), 0 },
{ 1400, PLL_MPS( 175, 3, 0), 0 },
{ 1600, PLL_MPS( 200, 3, 0), 0 }
};
static struct mpsk_tbl _epll_tbl[] = {
{ 33, PLL_MPS( 131, 3, 5), 4719 },
{ 45, PLL_MPS( 90, 3, 4), 20762 },
{ 48, PLL_MPS( 64, 2, 4), 0 },
{ 49, PLL_MPS( 98, 3, 4), 19923 },
{ 50, PLL_MPS( 67, 2, 4), 43691 },
{ 68, PLL_MPS( 90, 2, 4), 20762 },
{ 74, PLL_MPS( 98, 2, 4), 19923 },
{ 80, PLL_MPS( 107, 2, 4), 43691 },
{ 84, PLL_MPS( 112, 2, 4), 0 },
{ 96, PLL_MPS( 64, 2, 3), 0 },
{ 144, PLL_MPS( 96, 2, 3), 0 },
{ 192, PLL_MPS( 64, 2, 2), 0 },
{ 288, PLL_MPS( 96, 2, 2), 0 },
};
static struct mpsk_tbl _vpll_tbl[] = {
{ 27, PLL_MPS( 72, 2, 5), 0 },
{ 54, PLL_MPS( 72, 2, 4), 0 },
{ 74, PLL_MPS( 99, 2, 4), 0 },
{ 108, PLL_MPS( 72, 2, 3), 0 },
{ 148, PLL_MPS( 99, 2, 3), 59070 },
{ 149, PLL_MPS( 99, 2, 3), 0 },
{ 223, PLL_MPS( 74, 2, 2), 16384 },
{ 300, PLL_MPS( 100, 2, 2), 0 },
{ 320, PLL_MPS( 107, 2, 2), 43691 },
{ 330, PLL_MPS( 110, 2, 2), 0 },
{ 333, PLL_MPS( 111, 2, 2), 0 },
{ 335, PLL_MPS( 112, 2, 2), 43691 },
{ 371, PLL_MPS( 62, 2, 1), 53292 },
{ 445, PLL_MPS( 111, 3, 1), 17285 },
{ 446, PLL_MPS( 74, 2, 1), 16384 },
{ 519, PLL_MPS( 130, 3, 1), 52937 },
{ 600, PLL_MPS( 100, 2, 1), 0 },
};
static struct pll_priv sclkmpll_priv = PLL_PRIV(SCLKMPLL, MPS, _ambcgpll_tbl);
static struct pll_priv sclkcpll_priv = PLL_PRIV(SCLKCPLL, MPS, _ambcgpll_tbl);
static struct pll_priv sclkepll_priv = PLL_PRIV(SCLKEPLL, MPSK, _epll_tbl);
static struct pll_priv sclkvpll_priv = PLL_PRIV(SCLKVPLL, MPSK, _vpll_tbl);
static struct clock sclkmpll_clk = { CLK_OPS(SCLKMPLL, pll, &sclkmpll_priv) };
static struct clock sclkcpll_clk = { CLK_OPS(SCLKCPLL, pll, &sclkcpll_priv) };
static struct clock sclkepll_clk = { CLK_OPS(SCLKEPLL, pll, &sclkepll_priv) };
static struct clock sclkvpll_clk = { CLK_OPS(SCLKVPLL, pll, &sclkvpll_priv) };
#if !defined(CONFIG_PLAT_EXYNOS5422)
static struct pll_priv sclkbpll_priv = PLL_PRIV(SCLKBPLL, MPS, _ambcgpll_tbl);
static struct pll_priv sclkgpll_priv = PLL_PRIV(SCLKGPLL, MPS, _ambcgpll_tbl);
static struct clock sclkgpll_clk = { CLK_OPS(SCLKGPLL, pll, &sclkgpll_priv) };
static struct clock sclkbpll_clk = { CLK_OPS(SCLKBPLL, pll, &sclkbpll_priv) };
#endif
/* The SPI div register is a special case as we have 2 dividers, one of which
* is 2 nibbles wide */
static freq_t
_spi_get_freq(clk_t* clk)
{
freq_t fin;
int clkid;
int rpre, r;
clkid = exynos_clk_get_priv_id(clk);
switch (clk->id) {
case CLK_SPI0_ISP:
clkid += 32;
break;
case CLK_SPI1_ISP:
clkid += 35;
break;
case CLK_SPI0:
clkid += 12;
break;
case CLK_SPI1:
clkid += 15;
break;
case CLK_SPI2:
clkid += 18;
break;
default:
return 0;
}
r = exynos_cmu_get_div(_clk_regs, clkid, 1);
rpre = exynos_cmu_get_div(_clk_regs, clkid + 2, 2);
fin = clk_get_freq(clk->parent);
return fin / (r + 1) / (rpre + 1);
}
static freq_t
_spi_set_freq(clk_t* clk, freq_t hz)
{
freq_t fin;
int clkid;
int rpre, r;
clkid = exynos_clk_get_priv_id(clk);
switch (clk->id) {
case CLK_SPI0_ISP:
clkid += 32;
break;
case CLK_SPI1_ISP:
clkid += 35;
break;
case CLK_SPI0:
clkid += 12;
break;
case CLK_SPI1:
clkid += 15;
break;
case CLK_SPI2:
clkid += 18;
break;
default:
return 0;
}
fin = clk_get_freq(clk->parent);
rpre = fin / 0xf / hz;
r = fin / (rpre + 1) / hz;
exynos_cmu_set_div(_clk_regs, clkid, 1, r);
exynos_cmu_set_div(_clk_regs, clkid + 2, 2, rpre);
return clk_get_freq(clk);
}
static void
_spi_recal(clk_t* clk)
{
assert(!"Not implemented");
}
static clk_t*
_spi_init(clk_t* clk)
{
/* MUX -> DIVspix -> DIVspipre */
clk_t* parent;
int clkid;
int src;
clkid = exynos_clk_get_priv_id(clk);
src = exynos_cmu_get_src(_clk_regs, clkid);
assert(src < ARRAY_SIZE(clk_src_peri_blk) && src >= 0);
assert(clk_src_peri_blk[src] != -1);
parent = clk_get_clock(clk->clk_sys, clk_src_peri_blk[src]);
assert(parent);
clk_init(parent);
clk_register_child(parent, clk);
return clk;
}
static struct clock spi0_clk = { CLK_OPS(SPI0 , spi, CLKID_SPI0 ) };
static struct clock spi1_clk = { CLK_OPS(SPI1 , spi, CLKID_SPI1 ) };
static struct clock spi2_clk = { CLK_OPS(SPI2 , spi, CLKID_SPI2 ) };
static struct clock spi0_isp_clk = { CLK_OPS(SPI0_ISP, spi, CLKID_SPI0_ISP) };
static struct clock spi1_isp_clk = { CLK_OPS(SPI1_ISP, spi, CLKID_SPI1_ISP) };
static freq_t
_peric_clk_get_freq(clk_t* clk)
{
freq_t fin;
int clkid;
int div;
clkid = exynos_clk_get_priv_id(clk);
/* The DIV register has an additional 2 word offset */
clkid += 16;
div = exynos_cmu_get_div(_clk_regs, clkid, 1);
fin = clk_get_freq(clk->parent);
return fin / (div + 1);
}
static freq_t
_peric_clk_set_freq(clk_t* clk, freq_t hz)
{
freq_t fin;
int clkid;
int div;
fin = clk_get_freq(clk->parent);
div = fin / hz;
clkid = exynos_clk_get_priv_id(clk);
/* The DIV register has an additional 2 word offset */
clkid += 16;
exynos_cmu_set_div(_clk_regs, clkid, 1, div);
return clk_get_freq(clk);
}
static void
_peric_clk_recal(clk_t* clk)
{
assert(!"Not implemented");
}
static clk_t*
_peric_clk_init(clk_t* clk)
{
/* MUX -> DIVuartx -> DIVuartpre */
clk_t* parent;
int clkid;
int src;
clkid = exynos_clk_get_priv_id(clk);
src = exynos_cmu_get_src(_clk_regs, clkid);
assert(src < ARRAY_SIZE(clk_src_peri_blk) && src >= 0);
assert(clk_src_peri_blk[src] != -1);
parent = clk_get_clock(clk->clk_sys, clk_src_peri_blk[src]);
assert(parent);
clk_init(parent);
clk_register_child(parent, clk);
return clk;
}
static struct clock uart0_clk = { CLK_OPS(UART0, peric_clk, CLKID_UART0) };
static struct clock uart1_clk = { CLK_OPS(UART1, peric_clk, CLKID_UART1) };
static struct clock uart2_clk = { CLK_OPS(UART2, peric_clk, CLKID_UART2) };
static struct clock uart3_clk = { CLK_OPS(UART3, peric_clk, CLKID_UART3) };
static struct clock pwm_clk = { CLK_OPS(PWM , peric_clk, CLKID_PWM ) };
static int
exynos5_gate_enable(clock_sys_t* clock_sys, enum clock_gate gate, enum clock_gate_mode mode)
{
return -1;
}
static int
clock_sys_common_init(clock_sys_t* clock_sys)
{
clock_sys->priv = (void*)&_clk_regs;
clock_sys->get_clock = &ps_get_clock;
clock_sys->gate_enable = &exynos5_gate_enable;
return 0;
}
int
exynos5_clock_sys_init(void* cpu, void* core, void* acp, void* isp, void* top,
void* lex, void* r0x, void* r1x, void* cdrex, void* mem,
clock_sys_t* clock_sys)
{
if (cpu) {
_clk_regs[CLKREGS_CPU] = cpu;
}
if (core) {
_clk_regs[CLKREGS_CORE] = core;
}
if (acp) {
_clk_regs[CLKREGS_ACP] = acp;
}
if (isp) {
_clk_regs[CLKREGS_ISP] = isp;
}
if (top) {
_clk_regs[CLKREGS_TOP] = top;
}
if (lex) {
_clk_regs[CLKREGS_LEX] = lex;
}
if (r0x) {
_clk_regs[CLKREGS_R0X] = r0x;
}
if (r1x) {
_clk_regs[CLKREGS_R1X] = r1x;
}
if (cdrex) {
_clk_regs[CLKREGS_CDREX] = cdrex;
}
if (mem) {
_clk_regs[CLKREGS_MEM] = mem;
}
return clock_sys_common_init(clock_sys);
}
int
clock_sys_init(ps_io_ops_t* o, clock_sys_t* clock_sys)
{
MAP_IF_NULL(o, EXYNOS5_CMU_CPU, _clk_regs[CLKREGS_CPU]);
MAP_IF_NULL(o, EXYNOS5_CMU_CORE, _clk_regs[CLKREGS_CORE]);
MAP_IF_NULL(o, EXYNOS5_CMU_ACP, _clk_regs[CLKREGS_ACP]);
MAP_IF_NULL(o, EXYNOS5_CMU_ISP, _clk_regs[CLKREGS_ISP]);
MAP_IF_NULL(o, EXYNOS5_CMU_TOP, _clk_regs[CLKREGS_TOP]);
MAP_IF_NULL(o, EXYNOS5_CMU_LEX, _clk_regs[CLKREGS_LEX]);
MAP_IF_NULL(o, EXYNOS5_CMU_R0X, _clk_regs[CLKREGS_R0X]);
MAP_IF_NULL(o, EXYNOS5_CMU_R1X, _clk_regs[CLKREGS_R1X]);
MAP_IF_NULL(o, EXYNOS5_CMU_CDREX, _clk_regs[CLKREGS_CDREX]);
return clock_sys_common_init(clock_sys);
}
void
clk_print_clock_tree(clock_sys_t* sys)
{
(void)sys;
clk_t* clk = ps_clocks[CLK_MASTER];
clk_print_tree(clk, "");
}
clk_t* ps_clocks[] = {
[CLK_MASTER ] = &master_clk,
[CLK_SPI0 ] = &spi0_clk,
[CLK_SPI1 ] = &spi1_clk,
[CLK_SPI2 ] = &spi2_clk,
[CLK_SPI0_ISP] = &spi0_isp_clk,
[CLK_SPI1_ISP] = &spi1_isp_clk,
[CLK_UART0 ] = &uart0_clk,
[CLK_UART1 ] = &uart1_clk,
[CLK_UART2 ] = &uart2_clk,
[CLK_UART3 ] = &uart3_clk,
[CLK_PWM ] = &pwm_clk,
[CLK_SCLKMPLL] = &sclkmpll_clk,
[CLK_SCLKCPLL] = &sclkcpll_clk,
[CLK_SCLKEPLL] = &sclkepll_clk,
[CLK_SCLKVPLL] = &sclkvpll_clk,
#if !defined(CONFIG_PLAT_EXYNOS5422)
[CLK_SCLKBPLL] = &sclkbpll_clk,
[CLK_SCLKGPLL] = &sclkgpll_clk,
#endif
};
/* These frequencies are NOT the recommended
* frequencies. They are to be used when we
* need to make assumptions about what u-boot
* has left us with. */
freq_t ps_freq_default[] = {
[CLK_MASTER ] = 24 * MHZ,
[CLK_SCLKVPLL] = 24 * MHZ,
[CLK_SCLKGPLL] = 1056 * MHZ,
[CLK_SCLKBPLL] = 800 * MHZ,
[CLK_PWM ] = 24 * MHZ,
[CLK_SCLKCPLL] = 640 * MHZ,
[CLK_UART3 ] = 64 * MHZ,
[CLK_UART2 ] = 64 * MHZ,
[CLK_UART1 ] = 64 * MHZ,
[CLK_UART0 ] = 64 * MHZ,
[CLK_SPI1_ISP] = 24 * MHZ,
[CLK_SPI0_ISP] = 24 * MHZ,
[CLK_SCLKMPLL] = 532 * MHZ,
[CLK_SPI1 ] = 53200 * KHZ,
[CLK_SCLKEPLL] = 24 * MHZ,
[CLK_SPI2 ] = 6 * MHZ,
[CLK_SPI0 ] = 6 * MHZ,
};