mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-12-23 19:43:33 +00:00
85bb3a4eee
Adjust clock to stay compatible with those used by the Linux kernel device tree. Signed-off-by: Joel Stanley <joel@jms.id.au>
1220 lines
29 KiB
C
1220 lines
29 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (C) ASPEED Technology Inc.
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <clk-uclass.h>
|
|
#include <dm.h>
|
|
#include <asm/io.h>
|
|
#include <dm/lists.h>
|
|
#include <linux/delay.h>
|
|
#include <asm/arch/scu_ast2600.h>
|
|
#include <asm/global_data.h>
|
|
#include <dt-bindings/clock/ast2600-clock.h>
|
|
#include <dt-bindings/reset/ast2600-reset.h>
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
#define CLKIN_25M 25000000UL
|
|
|
|
/* MAC Clock Delay settings */
|
|
#define MAC12_DEF_DELAY_1G 0x0028a410
|
|
#define MAC12_DEF_DELAY_100M 0x00410410
|
|
#define MAC12_DEF_DELAY_10M 0x00410410
|
|
#define MAC34_DEF_DELAY_1G 0x00104208
|
|
#define MAC34_DEF_DELAY_100M 0x00104208
|
|
#define MAC34_DEF_DELAY_10M 0x00104208
|
|
|
|
/*
|
|
* 3-bit encode of CPU freqeucy
|
|
* Some code is duplicated
|
|
*/
|
|
enum ast2600_cpu_freq {
|
|
CPU_FREQ_1200M_1,
|
|
CPU_FREQ_1600M_1,
|
|
CPU_FREQ_1200M_2,
|
|
CPU_FREQ_1600M_2,
|
|
CPU_FREQ_800M_1,
|
|
CPU_FREQ_800M_2,
|
|
CPU_FREQ_800M_3,
|
|
CPU_FREQ_800M_4,
|
|
};
|
|
|
|
struct ast2600_clk_priv {
|
|
struct ast2600_scu *scu;
|
|
};
|
|
|
|
/*
|
|
* Clock divider/multiplier configuration struct.
|
|
* For H-PLL and M-PLL the formula is
|
|
* (Output Frequency) = CLKIN * ((M + 1) / (N + 1)) / (P + 1)
|
|
* M - Numerator
|
|
* N - Denumerator
|
|
* P - Post Divider
|
|
* They have the same layout in their control register.
|
|
*
|
|
* D-PLL and D2-PLL have extra divider (OD + 1), which is not
|
|
* yet needed and ignored by clock configurations.
|
|
*/
|
|
union ast2600_pll_reg {
|
|
uint32_t w;
|
|
struct {
|
|
unsigned int m : 13;
|
|
unsigned int n : 6;
|
|
unsigned int p : 4;
|
|
unsigned int off : 1;
|
|
unsigned int bypass : 1;
|
|
unsigned int reset : 1;
|
|
unsigned int reserved : 6;
|
|
} b;
|
|
};
|
|
|
|
struct ast2600_pll_cfg {
|
|
union ast2600_pll_reg reg;
|
|
unsigned int ext_reg;
|
|
};
|
|
|
|
struct ast2600_pll_desc {
|
|
uint32_t in;
|
|
uint32_t out;
|
|
struct ast2600_pll_cfg cfg;
|
|
};
|
|
|
|
static const struct ast2600_pll_desc ast2600_pll_lookup[] = {
|
|
{
|
|
.in = CLKIN_25M,
|
|
.out = 400000000,
|
|
.cfg.reg.b.m = 95,
|
|
.cfg.reg.b.n = 2,
|
|
.cfg.reg.b.p = 1,
|
|
.cfg.ext_reg = 0x31,
|
|
},
|
|
{
|
|
.in = CLKIN_25M,
|
|
.out = 200000000,
|
|
.cfg.reg.b.m = 127,
|
|
.cfg.reg.b.n = 0,
|
|
.cfg.reg.b.p = 15,
|
|
.cfg.ext_reg = 0x3f,
|
|
},
|
|
{
|
|
.in = CLKIN_25M,
|
|
.out = 334000000,
|
|
.cfg.reg.b.m = 667,
|
|
.cfg.reg.b.n = 4,
|
|
.cfg.reg.b.p = 9,
|
|
.cfg.ext_reg = 0x14d,
|
|
},
|
|
{
|
|
.in = CLKIN_25M,
|
|
.out = 1000000000,
|
|
.cfg.reg.b.m = 119,
|
|
.cfg.reg.b.n = 2,
|
|
.cfg.reg.b.p = 0,
|
|
.cfg.ext_reg = 0x3d,
|
|
},
|
|
{
|
|
.in = CLKIN_25M,
|
|
.out = 50000000,
|
|
.cfg.reg.b.m = 95,
|
|
.cfg.reg.b.n = 2,
|
|
.cfg.reg.b.p = 15,
|
|
.cfg.ext_reg = 0x31,
|
|
},
|
|
};
|
|
|
|
/* divisor tables */
|
|
static uint32_t axi_ahb_div0_table[] = {
|
|
3, 2, 3, 4,
|
|
};
|
|
|
|
static uint32_t axi_ahb_div1_table[] = {
|
|
3, 4, 6, 8,
|
|
};
|
|
|
|
static uint32_t axi_ahb_default_table[] = {
|
|
3, 4, 3, 4, 2, 2, 2, 2,
|
|
};
|
|
|
|
extern uint32_t ast2600_get_pll_rate(struct ast2600_scu *scu, int pll_idx)
|
|
{
|
|
union ast2600_pll_reg pll_reg;
|
|
uint32_t hwstrap1;
|
|
uint32_t cpu_freq;
|
|
uint32_t mul = 1, div = 1;
|
|
|
|
switch (pll_idx) {
|
|
case ASPEED_CLK_APLL:
|
|
pll_reg.w = readl(&scu->apll);
|
|
break;
|
|
case ASPEED_CLK_DPLL:
|
|
pll_reg.w = readl(&scu->dpll);
|
|
break;
|
|
case ASPEED_CLK_EPLL:
|
|
pll_reg.w = readl(&scu->epll);
|
|
break;
|
|
case ASPEED_CLK_HPLL:
|
|
pll_reg.w = readl(&scu->hpll);
|
|
break;
|
|
case ASPEED_CLK_MPLL:
|
|
pll_reg.w = readl(&scu->mpll);
|
|
break;
|
|
}
|
|
|
|
if (!pll_reg.b.bypass) {
|
|
/* F = 25Mhz * [(M + 2) / (n + 1)] / (p + 1)
|
|
* HPLL Numerator (M) = fix 0x5F when SCU500[10]=1
|
|
* Fixed 0xBF when SCU500[10]=0 and SCU500[8]=1
|
|
* SCU200[12:0] (default 0x8F) when SCU510[10]=0 and SCU510[8]=0
|
|
* HPLL Denumerator (N) = SCU200[18:13] (default 0x2)
|
|
* HPLL Divider (P) = SCU200[22:19] (default 0x0)
|
|
* HPLL Bandwidth Adj (NB) = fix 0x2F when SCU500[10]=1
|
|
* Fixed 0x5F when SCU500[10]=0 and SCU500[8]=1
|
|
* SCU204[11:0] (default 0x31) when SCU500[10]=0 and SCU500[8]=0
|
|
*/
|
|
if (pll_idx == ASPEED_CLK_HPLL) {
|
|
hwstrap1 = readl(&scu->hwstrap1);
|
|
cpu_freq = (hwstrap1 & SCU_HWSTRAP1_CPU_FREQ_MASK) >>
|
|
SCU_HWSTRAP1_CPU_FREQ_SHIFT;
|
|
|
|
switch (cpu_freq) {
|
|
case CPU_FREQ_800M_1:
|
|
case CPU_FREQ_800M_2:
|
|
case CPU_FREQ_800M_3:
|
|
case CPU_FREQ_800M_4:
|
|
pll_reg.b.m = 0x5f;
|
|
break;
|
|
case CPU_FREQ_1600M_1:
|
|
case CPU_FREQ_1600M_2:
|
|
pll_reg.b.m = 0xbf;
|
|
break;
|
|
default:
|
|
pll_reg.b.m = 0x8f;
|
|
break;
|
|
}
|
|
}
|
|
|
|
mul = (pll_reg.b.m + 1) / (pll_reg.b.n + 1);
|
|
div = (pll_reg.b.p + 1);
|
|
}
|
|
|
|
return ((CLKIN_25M * mul) / div);
|
|
}
|
|
|
|
static uint32_t ast2600_get_hclk_rate(struct ast2600_scu *scu)
|
|
{
|
|
uint32_t rate = ast2600_get_pll_rate(scu, ASPEED_CLK_HPLL);
|
|
uint32_t axi_div, ahb_div;
|
|
uint32_t hwstrap1 = readl(&scu->hwstrap1);
|
|
uint32_t cpu_freq = (hwstrap1 & SCU_HWSTRAP1_CPU_FREQ_MASK) >>
|
|
SCU_HWSTRAP1_CPU_FREQ_SHIFT;
|
|
uint32_t axi_ahb_ratio = (hwstrap1 & SCU_HWSTRAP1_AXI_AHB_CLK_RATIO_MASK) >>
|
|
SCU_HWSTRAP1_AXI_AHB_CLK_RATIO_SHIFT;
|
|
|
|
if (hwstrap1 & SCU_HWSTRAP1_CPU_AXI_CLK_RATIO) {
|
|
axi_ahb_div1_table[0] = axi_ahb_default_table[cpu_freq] * 2;
|
|
axi_div = 1;
|
|
ahb_div = axi_ahb_div1_table[axi_ahb_ratio];
|
|
} else {
|
|
axi_ahb_div0_table[0] = axi_ahb_default_table[cpu_freq];
|
|
axi_div = 2;
|
|
ahb_div = axi_ahb_div0_table[axi_ahb_ratio];
|
|
}
|
|
|
|
return (rate / axi_div / ahb_div);
|
|
}
|
|
|
|
static uint32_t ast2600_get_bclk_rate(struct ast2600_scu *scu)
|
|
{
|
|
uint32_t rate = ast2600_get_pll_rate(scu, ASPEED_CLK_HPLL);
|
|
uint32_t clksrc1 = readl(&scu->clksrc1);
|
|
uint32_t bclk_div = (clksrc1 & SCU_CLKSRC1_BCLK_DIV_MASK) >>
|
|
SCU_CLKSRC1_BCLK_DIV_SHIFT;
|
|
|
|
return (rate / ((bclk_div + 1) * 4));
|
|
}
|
|
|
|
static uint32_t ast2600_get_pclk1_rate(struct ast2600_scu *scu)
|
|
{
|
|
uint32_t rate = ast2600_get_pll_rate(scu, ASPEED_CLK_HPLL);
|
|
uint32_t clksrc1 = readl(&scu->clksrc1);
|
|
uint32_t pclk_div = (clksrc1 & SCU_CLKSRC1_PCLK_DIV_MASK) >>
|
|
SCU_CLKSRC1_PCLK_DIV_SHIFT;
|
|
|
|
return (rate / ((pclk_div + 1) * 4));
|
|
}
|
|
|
|
static uint32_t ast2600_get_pclk2_rate(struct ast2600_scu *scu)
|
|
{
|
|
uint32_t rate = ast2600_get_hclk_rate(scu);
|
|
uint32_t clksrc4 = readl(&scu->clksrc4);
|
|
uint32_t pclk_div = (clksrc4 & SCU_CLKSRC4_PCLK_DIV_MASK) >>
|
|
SCU_CLKSRC4_PCLK_DIV_SHIFT;
|
|
|
|
return (rate / ((pclk_div + 1) * 2));
|
|
}
|
|
|
|
static uint32_t ast2600_get_uxclk_in_rate(struct ast2600_scu *scu)
|
|
{
|
|
uint32_t rate = 0;
|
|
uint32_t clksrc5 = readl(&scu->clksrc5);
|
|
uint32_t uxclk = (clksrc5 & SCU_CLKSRC5_UXCLK_MASK) >>
|
|
SCU_CLKSRC5_UXCLK_SHIFT;
|
|
|
|
switch (uxclk) {
|
|
case 0:
|
|
rate = ast2600_get_pll_rate(scu, ASPEED_CLK_APLL) / 4;
|
|
break;
|
|
case 1:
|
|
rate = ast2600_get_pll_rate(scu, ASPEED_CLK_APLL) / 2;
|
|
break;
|
|
case 2:
|
|
rate = ast2600_get_pll_rate(scu, ASPEED_CLK_APLL);
|
|
break;
|
|
case 3:
|
|
rate = ast2600_get_hclk_rate(scu);
|
|
break;
|
|
}
|
|
|
|
return rate;
|
|
}
|
|
|
|
static uint32_t ast2600_get_huxclk_in_rate(struct ast2600_scu *scu)
|
|
{
|
|
uint32_t rate = 0;
|
|
uint32_t clksrc5 = readl(&scu->clksrc5);
|
|
uint32_t huxclk = (clksrc5 & SCU_CLKSRC5_HUXCLK_MASK) >>
|
|
SCU_CLKSRC5_HUXCLK_SHIFT;
|
|
|
|
switch (huxclk) {
|
|
case 0:
|
|
rate = ast2600_get_pll_rate(scu, ASPEED_CLK_APLL) / 4;
|
|
break;
|
|
case 1:
|
|
rate = ast2600_get_pll_rate(scu, ASPEED_CLK_APLL) / 2;
|
|
break;
|
|
case 2:
|
|
rate = ast2600_get_pll_rate(scu, ASPEED_CLK_APLL);
|
|
break;
|
|
case 3:
|
|
rate = ast2600_get_hclk_rate(scu);
|
|
break;
|
|
}
|
|
|
|
return rate;
|
|
}
|
|
|
|
static uint32_t ast2600_get_uart_uxclk_rate(struct ast2600_scu *scu)
|
|
{
|
|
uint32_t rate = ast2600_get_uxclk_in_rate(scu);
|
|
uint32_t uart_clkgen = readl(&scu->uart_clkgen);
|
|
uint32_t n = (uart_clkgen & SCU_UART_CLKGEN_N_MASK) >>
|
|
SCU_UART_CLKGEN_N_SHIFT;
|
|
uint32_t r = (uart_clkgen & SCU_UART_CLKGEN_R_MASK) >>
|
|
SCU_UART_CLKGEN_R_SHIFT;
|
|
|
|
return ((rate * r) / (n * 2));
|
|
}
|
|
|
|
static uint32_t ast2600_get_uart_huxclk_rate(struct ast2600_scu *scu)
|
|
{
|
|
uint32_t rate = ast2600_get_huxclk_in_rate(scu);
|
|
uint32_t huart_clkgen = readl(&scu->huart_clkgen);
|
|
uint32_t n = (huart_clkgen & SCU_HUART_CLKGEN_N_MASK) >>
|
|
SCU_HUART_CLKGEN_N_SHIFT;
|
|
uint32_t r = (huart_clkgen & SCU_HUART_CLKGEN_R_MASK) >>
|
|
SCU_HUART_CLKGEN_R_SHIFT;
|
|
|
|
return ((rate * r) / (n * 2));
|
|
}
|
|
|
|
static uint32_t ast2600_get_sdio_clk_rate(struct ast2600_scu *scu)
|
|
{
|
|
uint32_t rate = 0;
|
|
uint32_t clksrc4 = readl(&scu->clksrc4);
|
|
uint32_t sdio_div = (clksrc4 & SCU_CLKSRC4_SDIO_DIV_MASK) >>
|
|
SCU_CLKSRC4_SDIO_DIV_SHIFT;
|
|
|
|
if (clksrc4 & SCU_CLKSRC4_SDIO)
|
|
rate = ast2600_get_pll_rate(scu, ASPEED_CLK_APLL);
|
|
else
|
|
rate = ast2600_get_hclk_rate(scu);
|
|
|
|
return (rate / ((sdio_div + 1) * 2));
|
|
}
|
|
|
|
static uint32_t ast2600_get_emmc_clk_rate(struct ast2600_scu *scu)
|
|
{
|
|
uint32_t rate = ast2600_get_pll_rate(scu, ASPEED_CLK_HPLL);
|
|
uint32_t clksrc1 = readl(&scu->clksrc1);
|
|
uint32_t emmc_div = (clksrc1 & SCU_CLKSRC1_EMMC_DIV_MASK) >>
|
|
SCU_CLKSRC1_EMMC_DIV_SHIFT;
|
|
|
|
return (rate / ((emmc_div + 1) * 4));
|
|
}
|
|
|
|
static uint32_t ast2600_get_uart_clk_rate(struct ast2600_scu *scu, int uart_idx)
|
|
{
|
|
uint32_t rate = 0;
|
|
uint32_t uart5_clk = 0;
|
|
uint32_t clksrc2 = readl(&scu->clksrc2);
|
|
uint32_t clksrc4 = readl(&scu->clksrc4);
|
|
uint32_t clksrc5 = readl(&scu->clksrc5);
|
|
uint32_t misc_ctrl1 = readl(&scu->misc_ctrl1);
|
|
|
|
switch (uart_idx) {
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
case 6:
|
|
if (clksrc4 & BIT(uart_idx - 1))
|
|
rate = ast2600_get_uart_huxclk_rate(scu);
|
|
else
|
|
rate = ast2600_get_uart_uxclk_rate(scu);
|
|
break;
|
|
case 5:
|
|
/*
|
|
* SCU0C[12] and SCU304[14] together decide
|
|
* the UART5 clock generation
|
|
*/
|
|
if (misc_ctrl1 & SCU_MISC_CTRL1_UART5_DIV)
|
|
uart5_clk = 0x1 << 1;
|
|
|
|
if (clksrc2 & SCU_CLKSRC2_UART5)
|
|
uart5_clk |= 0x1;
|
|
|
|
switch (uart5_clk) {
|
|
case 0:
|
|
rate = 24000000;
|
|
break;
|
|
case 1:
|
|
rate = 192000000;
|
|
break;
|
|
case 2:
|
|
rate = 24000000 / 13;
|
|
break;
|
|
case 3:
|
|
rate = 192000000 / 13;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case 7:
|
|
case 8:
|
|
case 9:
|
|
case 10:
|
|
case 11:
|
|
case 12:
|
|
case 13:
|
|
if (clksrc5 & BIT(uart_idx - 1))
|
|
rate = ast2600_get_uart_huxclk_rate(scu);
|
|
else
|
|
rate = ast2600_get_uart_uxclk_rate(scu);
|
|
break;
|
|
}
|
|
|
|
return rate;
|
|
}
|
|
|
|
static ulong ast2600_clk_get_rate(struct clk *clk)
|
|
{
|
|
struct ast2600_clk_priv *priv = dev_get_priv(clk->dev);
|
|
ulong rate = 0;
|
|
|
|
switch (clk->id) {
|
|
case ASPEED_CLK_HPLL:
|
|
case ASPEED_CLK_EPLL:
|
|
case ASPEED_CLK_DPLL:
|
|
case ASPEED_CLK_MPLL:
|
|
case ASPEED_CLK_APLL:
|
|
rate = ast2600_get_pll_rate(priv->scu, clk->id);
|
|
break;
|
|
case ASPEED_CLK_AHB:
|
|
rate = ast2600_get_hclk_rate(priv->scu);
|
|
break;
|
|
case ASPEED_CLK_APB1:
|
|
rate = ast2600_get_pclk1_rate(priv->scu);
|
|
break;
|
|
case ASPEED_CLK_APB2:
|
|
rate = ast2600_get_pclk2_rate(priv->scu);
|
|
break;
|
|
case ASPEED_CLK_GATE_UART1CLK:
|
|
rate = ast2600_get_uart_clk_rate(priv->scu, 1);
|
|
break;
|
|
case ASPEED_CLK_GATE_UART2CLK:
|
|
rate = ast2600_get_uart_clk_rate(priv->scu, 2);
|
|
break;
|
|
case ASPEED_CLK_GATE_UART3CLK:
|
|
rate = ast2600_get_uart_clk_rate(priv->scu, 3);
|
|
break;
|
|
case ASPEED_CLK_GATE_UART4CLK:
|
|
rate = ast2600_get_uart_clk_rate(priv->scu, 4);
|
|
break;
|
|
case ASPEED_CLK_GATE_UART5CLK:
|
|
rate = ast2600_get_uart_clk_rate(priv->scu, 5);
|
|
break;
|
|
case ASPEED_CLK_BCLK:
|
|
rate = ast2600_get_bclk_rate(priv->scu);
|
|
break;
|
|
case ASPEED_CLK_SDIO:
|
|
rate = ast2600_get_sdio_clk_rate(priv->scu);
|
|
break;
|
|
case ASPEED_CLK_EMMC:
|
|
rate = ast2600_get_emmc_clk_rate(priv->scu);
|
|
break;
|
|
case ASPEED_CLK_UARTX:
|
|
rate = ast2600_get_uart_uxclk_rate(priv->scu);
|
|
break;
|
|
case ASPEED_CLK_HUARTX:
|
|
rate = ast2600_get_uart_huxclk_rate(priv->scu);
|
|
break;
|
|
default:
|
|
debug("%s: unknown clk %ld\n", __func__, clk->id);
|
|
return -ENOENT;
|
|
}
|
|
|
|
return rate;
|
|
}
|
|
|
|
/**
|
|
* @brief lookup PLL divider config by input/output rate
|
|
* @param[in] *pll - PLL descriptor
|
|
* Return: true - if PLL divider config is found, false - else
|
|
* The function caller shall fill "pll->in" and "pll->out",
|
|
* then this function will search the lookup table
|
|
* to find a valid PLL divider configuration.
|
|
*/
|
|
static bool ast2600_search_clock_config(struct ast2600_pll_desc *pll)
|
|
{
|
|
uint32_t i;
|
|
const struct ast2600_pll_desc *def_desc;
|
|
bool is_found = false;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(ast2600_pll_lookup); i++) {
|
|
def_desc = &ast2600_pll_lookup[i];
|
|
|
|
if (def_desc->in == pll->in && def_desc->out == pll->out) {
|
|
is_found = true;
|
|
pll->cfg.reg.w = def_desc->cfg.reg.w;
|
|
pll->cfg.ext_reg = def_desc->cfg.ext_reg;
|
|
break;
|
|
}
|
|
}
|
|
return is_found;
|
|
}
|
|
|
|
static uint32_t ast2600_configure_pll(struct ast2600_scu *scu,
|
|
struct ast2600_pll_cfg *p_cfg, int pll_idx)
|
|
{
|
|
uint32_t addr, addr_ext;
|
|
uint32_t reg;
|
|
|
|
switch (pll_idx) {
|
|
case ASPEED_CLK_HPLL:
|
|
addr = (uint32_t)(&scu->hpll);
|
|
addr_ext = (uint32_t)(&scu->hpll_ext);
|
|
break;
|
|
case ASPEED_CLK_MPLL:
|
|
addr = (uint32_t)(&scu->mpll);
|
|
addr_ext = (uint32_t)(&scu->mpll_ext);
|
|
break;
|
|
case ASPEED_CLK_DPLL:
|
|
addr = (uint32_t)(&scu->dpll);
|
|
addr_ext = (uint32_t)(&scu->dpll_ext);
|
|
break;
|
|
case ASPEED_CLK_EPLL:
|
|
addr = (uint32_t)(&scu->epll);
|
|
addr_ext = (uint32_t)(&scu->epll_ext);
|
|
break;
|
|
case ASPEED_CLK_APLL:
|
|
addr = (uint32_t)(&scu->apll);
|
|
addr_ext = (uint32_t)(&scu->apll_ext);
|
|
break;
|
|
default:
|
|
debug("unknown PLL index\n");
|
|
return 1;
|
|
}
|
|
|
|
p_cfg->reg.b.bypass = 0;
|
|
p_cfg->reg.b.off = 1;
|
|
p_cfg->reg.b.reset = 1;
|
|
|
|
reg = readl(addr);
|
|
reg &= ~GENMASK(25, 0);
|
|
reg |= p_cfg->reg.w;
|
|
writel(reg, addr);
|
|
|
|
/* write extend parameter */
|
|
writel(p_cfg->ext_reg, addr_ext);
|
|
udelay(100);
|
|
p_cfg->reg.b.off = 0;
|
|
p_cfg->reg.b.reset = 0;
|
|
reg &= ~GENMASK(25, 0);
|
|
reg |= p_cfg->reg.w;
|
|
writel(reg, addr);
|
|
while (!(readl(addr_ext) & BIT(31)))
|
|
;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static uint32_t ast2600_configure_ddr(struct ast2600_scu *scu, ulong rate)
|
|
{
|
|
struct ast2600_pll_desc mpll;
|
|
|
|
mpll.in = CLKIN_25M;
|
|
mpll.out = rate;
|
|
if (ast2600_search_clock_config(&mpll) == false) {
|
|
printf("error!! unable to find valid DDR clock setting\n");
|
|
return 0;
|
|
}
|
|
ast2600_configure_pll(scu, &mpll.cfg, ASPEED_CLK_MPLL);
|
|
|
|
return ast2600_get_pll_rate(scu, ASPEED_CLK_MPLL);
|
|
}
|
|
|
|
static ulong ast2600_clk_set_rate(struct clk *clk, ulong rate)
|
|
{
|
|
struct ast2600_clk_priv *priv = dev_get_priv(clk->dev);
|
|
ulong new_rate;
|
|
|
|
switch (clk->id) {
|
|
case ASPEED_CLK_MPLL:
|
|
new_rate = ast2600_configure_ddr(priv->scu, rate);
|
|
break;
|
|
default:
|
|
return -ENOENT;
|
|
}
|
|
|
|
return new_rate;
|
|
}
|
|
|
|
static uint32_t ast2600_configure_mac12_clk(struct ast2600_scu *scu)
|
|
{
|
|
/* scu340[25:0]: 1G default delay */
|
|
clrsetbits_le32(&scu->mac12_clk_delay, GENMASK(25, 0),
|
|
MAC12_DEF_DELAY_1G);
|
|
|
|
/* set 100M/10M default delay */
|
|
writel(MAC12_DEF_DELAY_100M, &scu->mac12_clk_delay_100M);
|
|
writel(MAC12_DEF_DELAY_10M, &scu->mac12_clk_delay_10M);
|
|
|
|
/* MAC AHB = HPLL / 6 */
|
|
clrsetbits_le32(&scu->clksrc1, SCU_CLKSRC1_MAC_DIV_MASK,
|
|
(0x2 << SCU_CLKSRC1_MAC_DIV_SHIFT));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static uint32_t ast2600_configure_mac34_clk(struct ast2600_scu *scu)
|
|
{
|
|
/*
|
|
* scu350[31] RGMII 125M source: 0 = from IO pin
|
|
* scu350[25:0] MAC 1G delay
|
|
*/
|
|
clrsetbits_le32(&scu->mac34_clk_delay, (BIT(31) | GENMASK(25, 0)),
|
|
MAC34_DEF_DELAY_1G);
|
|
writel(MAC34_DEF_DELAY_100M, &scu->mac34_clk_delay_100M);
|
|
writel(MAC34_DEF_DELAY_10M, &scu->mac34_clk_delay_10M);
|
|
|
|
/*
|
|
* clock source seletion and divider
|
|
* scu310[26:24] : MAC AHB bus clock = HCLK / 2
|
|
* scu310[18:16] : RMII 50M = HCLK_200M / 4
|
|
*/
|
|
clrsetbits_le32(&scu->clksrc4,
|
|
(SCU_CLKSRC4_MAC_DIV_MASK | SCU_CLKSRC4_RMII34_DIV_MASK),
|
|
((0x0 << SCU_CLKSRC4_MAC_DIV_SHIFT)
|
|
| (0x3 << SCU_CLKSRC4_RMII34_DIV_SHIFT)));
|
|
|
|
/*
|
|
* set driving strength
|
|
* scu458[3:2] : MAC4 driving strength
|
|
* scu458[1:0] : MAC3 driving strength
|
|
*/
|
|
clrsetbits_le32(&scu->pinmux16,
|
|
SCU_PINCTRL16_MAC4_DRIVING_MASK | SCU_PINCTRL16_MAC3_DRIVING_MASK,
|
|
(0x3 << SCU_PINCTRL16_MAC4_DRIVING_SHIFT)
|
|
| (0x3 << SCU_PINCTRL16_MAC3_DRIVING_SHIFT));
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* ast2600 RGMII clock source tree
|
|
* 125M from external PAD -------->|\
|
|
* HPLL -->|\ | |---->RGMII 125M for MAC#1 & MAC#2
|
|
* | |---->| divider |---->|/ +
|
|
* EPLL -->|/ |
|
|
* |
|
|
* +---------<-----------|RGMIICK PAD output enable|<-------------+
|
|
* |
|
|
* +--------------------------->|\
|
|
* | |----> RGMII 125M for MAC#3 & MAC#4
|
|
* HCLK 200M ---->|divider|---->|/
|
|
* To simplify the control flow:
|
|
* 1. RGMII 1/2 always use EPLL as the internal clock source
|
|
* 2. RGMII 3/4 always use RGMIICK pad as the RGMII 125M source
|
|
* 125M from external PAD -------->|\
|
|
* | |---->RGMII 125M for MAC#1 & MAC#2
|
|
* EPLL---->| divider |--->|/ +
|
|
* |
|
|
* +<--------------------|RGMIICK PAD output enable|<-------------+
|
|
* |
|
|
* +--------------------------->RGMII 125M for MAC#3 & MAC#4
|
|
*/
|
|
#define RGMIICK_SRC_PAD 0
|
|
#define RGMIICK_SRC_EPLL 1 /* recommended */
|
|
#define RGMIICK_SRC_HPLL 2
|
|
|
|
#define RGMIICK_DIV2 1
|
|
#define RGMIICK_DIV3 2
|
|
#define RGMIICK_DIV4 3
|
|
#define RGMIICK_DIV5 4
|
|
#define RGMIICK_DIV6 5
|
|
#define RGMIICK_DIV7 6
|
|
#define RGMIICK_DIV8 7 /* recommended */
|
|
|
|
#define RMIICK_DIV4 0
|
|
#define RMIICK_DIV8 1
|
|
#define RMIICK_DIV12 2
|
|
#define RMIICK_DIV16 3
|
|
#define RMIICK_DIV20 4 /* recommended */
|
|
#define RMIICK_DIV24 5
|
|
#define RMIICK_DIV28 6
|
|
#define RMIICK_DIV32 7
|
|
|
|
struct ast2600_mac_clk_div {
|
|
uint32_t src; /* 0=external PAD, 1=internal PLL */
|
|
uint32_t fin; /* divider input speed */
|
|
uint32_t n; /* 0=div2, 1=div2, 2=div3, 3=div4,...,7=div8 */
|
|
uint32_t fout; /* fout = fin / n */
|
|
};
|
|
|
|
struct ast2600_mac_clk_div rgmii_clk_defconfig = {
|
|
.src = ASPEED_CLK_EPLL,
|
|
.fin = 1000000000,
|
|
.n = RGMIICK_DIV8,
|
|
.fout = 125000000,
|
|
};
|
|
|
|
struct ast2600_mac_clk_div rmii_clk_defconfig = {
|
|
.src = ASPEED_CLK_EPLL,
|
|
.fin = 1000000000,
|
|
.n = RMIICK_DIV20,
|
|
.fout = 50000000,
|
|
};
|
|
|
|
static void ast2600_init_mac_pll(struct ast2600_scu *p_scu,
|
|
struct ast2600_mac_clk_div *p_cfg)
|
|
{
|
|
struct ast2600_pll_desc pll;
|
|
|
|
pll.in = CLKIN_25M;
|
|
pll.out = p_cfg->fin;
|
|
if (ast2600_search_clock_config(&pll) == false) {
|
|
pr_err("unable to find valid ETHNET MAC clock setting\n");
|
|
return;
|
|
}
|
|
ast2600_configure_pll(p_scu, &pll.cfg, p_cfg->src);
|
|
}
|
|
|
|
static void ast2600_init_rgmii_clk(struct ast2600_scu *p_scu,
|
|
struct ast2600_mac_clk_div *p_cfg)
|
|
{
|
|
uint32_t reg_304 = readl(&p_scu->clksrc2);
|
|
uint32_t reg_340 = readl(&p_scu->mac12_clk_delay);
|
|
uint32_t reg_350 = readl(&p_scu->mac34_clk_delay);
|
|
|
|
reg_340 &= ~GENMASK(31, 29);
|
|
/* scu340[28]: RGMIICK PAD output enable (to MAC 3/4) */
|
|
reg_340 |= BIT(28);
|
|
if (p_cfg->src == ASPEED_CLK_EPLL || p_cfg->src == ASPEED_CLK_HPLL) {
|
|
/*
|
|
* re-init PLL if the current PLL output frequency doesn't match
|
|
* the divider setting
|
|
*/
|
|
if (p_cfg->fin != ast2600_get_pll_rate(p_scu, p_cfg->src))
|
|
ast2600_init_mac_pll(p_scu, p_cfg);
|
|
/* scu340[31]: select RGMII 125M from internal source */
|
|
reg_340 |= BIT(31);
|
|
}
|
|
|
|
reg_304 &= ~GENMASK(23, 20);
|
|
|
|
/* set clock divider */
|
|
reg_304 |= (p_cfg->n & 0x7) << 20;
|
|
|
|
/* select internal clock source */
|
|
if (p_cfg->src == ASPEED_CLK_HPLL)
|
|
reg_304 |= BIT(23);
|
|
|
|
/* RGMII 3/4 clock source select */
|
|
reg_350 &= ~BIT(31);
|
|
|
|
writel(reg_304, &p_scu->clksrc2);
|
|
writel(reg_340, &p_scu->mac12_clk_delay);
|
|
writel(reg_350, &p_scu->mac34_clk_delay);
|
|
}
|
|
|
|
/**
|
|
* ast2600 RMII/NCSI clock source tree
|
|
* HPLL -->|\
|
|
* | |---->| divider |----> RMII 50M for MAC#1 & MAC#2
|
|
* EPLL -->|/
|
|
* HCLK(SCLICLK)---->| divider |----> RMII 50M for MAC#3 & MAC#4
|
|
*/
|
|
static void ast2600_init_rmii_clk(struct ast2600_scu *p_scu,
|
|
struct ast2600_mac_clk_div *p_cfg)
|
|
{
|
|
uint32_t clksrc2 = readl(&p_scu->clksrc2);
|
|
uint32_t clksrc4 = readl(&p_scu->clksrc4);
|
|
|
|
if (p_cfg->src == ASPEED_CLK_EPLL || p_cfg->src == ASPEED_CLK_HPLL) {
|
|
/*
|
|
* re-init PLL if the current PLL output frequency doesn't match
|
|
* the divider setting
|
|
*/
|
|
if (p_cfg->fin != ast2600_get_pll_rate(p_scu, p_cfg->src))
|
|
ast2600_init_mac_pll(p_scu, p_cfg);
|
|
}
|
|
|
|
clksrc2 &= ~(SCU_CLKSRC2_RMII12 | SCU_CLKSRC2_RMII12_DIV_MASK);
|
|
|
|
/* set RMII 1/2 clock divider */
|
|
clksrc2 |= (p_cfg->n & 0x7) << 16;
|
|
|
|
/* RMII clock source selection */
|
|
if (p_cfg->src == ASPEED_CLK_HPLL)
|
|
clksrc2 |= SCU_CLKSRC2_RMII12;
|
|
|
|
/* set RMII 3/4 clock divider */
|
|
clksrc4 &= ~SCU_CLKSRC4_RMII34_DIV_MASK;
|
|
clksrc4 |= (0x3 << SCU_CLKSRC4_RMII34_DIV_SHIFT);
|
|
|
|
writel(clksrc2, &p_scu->clksrc2);
|
|
writel(clksrc4, &p_scu->clksrc4);
|
|
}
|
|
|
|
static uint32_t ast2600_configure_mac(struct ast2600_scu *scu, int index)
|
|
{
|
|
uint32_t reset_bit;
|
|
uint32_t clkgate_bit;
|
|
|
|
switch (index) {
|
|
case 1:
|
|
reset_bit = BIT(ASPEED_RESET_MAC1);
|
|
clkgate_bit = SCU_CLKGATE1_MAC1;
|
|
writel(reset_bit, &scu->modrst_ctrl1);
|
|
udelay(100);
|
|
writel(clkgate_bit, &scu->clkgate_clr1);
|
|
mdelay(10);
|
|
writel(reset_bit, &scu->modrst_clr1);
|
|
break;
|
|
case 2:
|
|
reset_bit = BIT(ASPEED_RESET_MAC2);
|
|
clkgate_bit = SCU_CLKGATE1_MAC2;
|
|
writel(reset_bit, &scu->modrst_ctrl1);
|
|
udelay(100);
|
|
writel(clkgate_bit, &scu->clkgate_clr1);
|
|
mdelay(10);
|
|
writel(reset_bit, &scu->modrst_clr1);
|
|
break;
|
|
case 3:
|
|
reset_bit = BIT(ASPEED_RESET_MAC3 - 32);
|
|
clkgate_bit = SCU_CLKGATE2_MAC3;
|
|
writel(reset_bit, &scu->modrst_ctrl2);
|
|
udelay(100);
|
|
writel(clkgate_bit, &scu->clkgate_clr2);
|
|
mdelay(10);
|
|
writel(reset_bit, &scu->modrst_clr2);
|
|
break;
|
|
case 4:
|
|
reset_bit = BIT(ASPEED_RESET_MAC4 - 32);
|
|
clkgate_bit = SCU_CLKGATE2_MAC4;
|
|
writel(reset_bit, &scu->modrst_ctrl2);
|
|
udelay(100);
|
|
writel(clkgate_bit, &scu->clkgate_clr2);
|
|
mdelay(10);
|
|
writel(reset_bit, &scu->modrst_clr2);
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void ast2600_configure_rsa_ecc_clk(struct ast2600_scu *scu)
|
|
{
|
|
uint32_t clksrc1 = readl(&scu->clksrc1);
|
|
|
|
/* Configure RSA clock = HPLL/3 */
|
|
clksrc1 |= SCU_CLKSRC1_ECC_RSA;
|
|
clksrc1 &= ~SCU_CLKSRC1_ECC_RSA_DIV_MASK;
|
|
clksrc1 |= (2 << SCU_CLKSRC1_ECC_RSA_DIV_SHIFT);
|
|
|
|
writel(clksrc1, &scu->clksrc1);
|
|
}
|
|
|
|
static ulong ast2600_enable_sdclk(struct ast2600_scu *scu)
|
|
{
|
|
uint32_t reset_bit;
|
|
uint32_t clkgate_bit;
|
|
|
|
reset_bit = BIT(ASPEED_RESET_SD - 32);
|
|
clkgate_bit = SCU_CLKGATE2_SDIO;
|
|
|
|
writel(reset_bit, &scu->modrst_ctrl2);
|
|
udelay(100);
|
|
writel(clkgate_bit, &scu->clkgate_clr2);
|
|
mdelay(10);
|
|
writel(reset_bit, &scu->modrst_clr2);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static ulong ast2600_enable_extsdclk(struct ast2600_scu *scu)
|
|
{
|
|
int i = 0;
|
|
uint32_t div = 0;
|
|
uint32_t rate = 0;
|
|
uint32_t clksrc4 = readl(&scu->clksrc4);
|
|
|
|
/*
|
|
* ast2600 SD controller max clk is 200Mhz
|
|
* use apll for clock source 800/4 = 200
|
|
* controller max is 200mhz
|
|
*/
|
|
rate = ast2600_get_pll_rate(scu, ASPEED_CLK_APLL);
|
|
for (i = 0; i < 8; i++) {
|
|
div = (i + 1) * 2;
|
|
if ((rate / div) <= 200000000)
|
|
break;
|
|
}
|
|
clksrc4 &= ~SCU_CLKSRC4_SDIO_DIV_MASK;
|
|
clksrc4 |= (i << SCU_CLKSRC4_SDIO_DIV_SHIFT);
|
|
clksrc4 |= SCU_CLKSRC4_SDIO;
|
|
writel(clksrc4, &scu->clksrc4);
|
|
|
|
setbits_le32(&scu->clksrc4, SCU_CLKSRC4_SDIO_EN);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static ulong ast2600_enable_emmcclk(struct ast2600_scu *scu)
|
|
{
|
|
uint32_t reset_bit;
|
|
uint32_t clkgate_bit;
|
|
|
|
reset_bit = BIT(ASPEED_RESET_EMMC);
|
|
clkgate_bit = SCU_CLKGATE1_EMMC;
|
|
|
|
writel(reset_bit, &scu->modrst_ctrl1);
|
|
udelay(100);
|
|
writel(clkgate_bit, &scu->clkgate_clr1);
|
|
mdelay(10);
|
|
writel(reset_bit, &scu->modrst_clr1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static ulong ast2600_enable_extemmcclk(struct ast2600_scu *scu)
|
|
{
|
|
int i = 0;
|
|
uint32_t div = 0;
|
|
uint32_t rate = 0;
|
|
uint32_t clksrc1 = readl(&scu->clksrc1);
|
|
|
|
/*
|
|
* ast2600 eMMC controller max clk is 200Mhz
|
|
* HPll->1/2->|\
|
|
* |->SCU300[11]->SCU300[14:12][1/N] +
|
|
* MPLL------>|/ |
|
|
* +----------------------------------------------+
|
|
* |
|
|
* +---------> EMMC12C[15:8][1/N]-> eMMC clk
|
|
*/
|
|
rate = ast2600_get_pll_rate(scu, ASPEED_CLK_MPLL);
|
|
for (i = 0; i < 8; i++) {
|
|
div = (i + 1) * 2;
|
|
if ((rate / div) <= 200000000)
|
|
break;
|
|
}
|
|
|
|
clksrc1 &= ~SCU_CLKSRC1_EMMC_DIV_MASK;
|
|
clksrc1 |= (i << SCU_CLKSRC1_EMMC_DIV_SHIFT);
|
|
clksrc1 |= SCU_CLKSRC1_EMMC;
|
|
writel(clksrc1, &scu->clksrc1);
|
|
|
|
setbits_le32(&scu->clksrc1, SCU_CLKSRC1_EMMC_EN);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static ulong ast2600_enable_fsiclk(struct ast2600_scu *scu)
|
|
{
|
|
uint32_t reset_bit;
|
|
uint32_t clkgate_bit;
|
|
|
|
reset_bit = BIT(ASPEED_RESET_FSI % 32);
|
|
clkgate_bit = SCU_CLKGATE2_FSI;
|
|
|
|
/* The FSI clock is shared between masters. If it's already on
|
|
* don't touch it, as that will reset the existing master.
|
|
*/
|
|
if (!(readl(&scu->clkgate_ctrl2) & clkgate_bit)) {
|
|
debug("%s: already running, not touching it\n", __func__);
|
|
return 0;
|
|
}
|
|
|
|
writel(reset_bit, &scu->modrst_ctrl2);
|
|
udelay(100);
|
|
writel(clkgate_bit, &scu->clkgate_clr2);
|
|
mdelay(10);
|
|
writel(reset_bit, &scu->modrst_clr2);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static ulong ast2600_enable_usbahclk(struct ast2600_scu *scu)
|
|
{
|
|
uint32_t reset_bit;
|
|
uint32_t clkgate_bit;
|
|
|
|
reset_bit = BIT(ASPEED_RESET_EHCI_P1);
|
|
clkgate_bit = SCU_CLKGATE1_USB_HUB;
|
|
|
|
writel(reset_bit, &scu->modrst_ctrl1);
|
|
udelay(100);
|
|
writel(clkgate_bit, &scu->clkgate_ctrl1);
|
|
mdelay(20);
|
|
writel(reset_bit, &scu->modrst_clr1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static ulong ast2600_enable_usbbhclk(struct ast2600_scu *scu)
|
|
{
|
|
uint32_t reset_bit;
|
|
uint32_t clkgate_bit;
|
|
|
|
reset_bit = BIT(ASPEED_RESET_EHCI_P2);
|
|
clkgate_bit = SCU_CLKGATE1_USB_HOST2;
|
|
|
|
writel(reset_bit, &scu->modrst_ctrl1);
|
|
udelay(100);
|
|
writel(clkgate_bit, &scu->clkgate_clr1);
|
|
mdelay(20);
|
|
writel(reset_bit, &scu->modrst_clr1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static ulong ast2600_enable_haceclk(struct ast2600_scu *scu)
|
|
{
|
|
uint32_t reset_bit;
|
|
uint32_t clkgate_bit;
|
|
|
|
/* share the same reset control bit with ACRY */
|
|
reset_bit = BIT(ASPEED_RESET_HACE);
|
|
clkgate_bit = SCU_CLKGATE1_HACE;
|
|
|
|
/*
|
|
* we don't do reset assertion here as HACE
|
|
* shares the same reset control with ACRY
|
|
*/
|
|
writel(clkgate_bit, &scu->clkgate_clr1);
|
|
mdelay(20);
|
|
writel(reset_bit, &scu->modrst_clr1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static ulong ast2600_enable_rsaclk(struct ast2600_scu *scu)
|
|
{
|
|
uint32_t reset_bit;
|
|
uint32_t clkgate_bit;
|
|
|
|
/* same reset control bit with HACE */
|
|
reset_bit = BIT(ASPEED_RESET_HACE);
|
|
clkgate_bit = SCU_CLKGATE1_ACRY;
|
|
|
|
/*
|
|
* we don't do reset assertion here as HACE
|
|
* shares the same reset control with ACRY
|
|
*/
|
|
writel(clkgate_bit, &scu->clkgate_clr1);
|
|
mdelay(20);
|
|
writel(reset_bit, &scu->modrst_clr1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ast2600_clk_enable(struct clk *clk)
|
|
{
|
|
struct ast2600_clk_priv *priv = dev_get_priv(clk->dev);
|
|
|
|
switch (clk->id) {
|
|
case ASPEED_CLK_GATE_MAC1CLK:
|
|
ast2600_configure_mac(priv->scu, 1);
|
|
break;
|
|
case ASPEED_CLK_GATE_MAC2CLK:
|
|
ast2600_configure_mac(priv->scu, 2);
|
|
break;
|
|
case ASPEED_CLK_GATE_MAC3CLK:
|
|
ast2600_configure_mac(priv->scu, 3);
|
|
break;
|
|
case ASPEED_CLK_GATE_MAC4CLK:
|
|
ast2600_configure_mac(priv->scu, 4);
|
|
break;
|
|
case ASPEED_CLK_GATE_SDCLK:
|
|
ast2600_enable_sdclk(priv->scu);
|
|
break;
|
|
case ASPEED_CLK_SDIO:
|
|
ast2600_enable_extsdclk(priv->scu);
|
|
break;
|
|
case ASPEED_CLK_GATE_EMMCCLK:
|
|
ast2600_enable_emmcclk(priv->scu);
|
|
break;
|
|
case ASPEED_CLK_EMMC:
|
|
ast2600_enable_extemmcclk(priv->scu);
|
|
break;
|
|
case ASPEED_CLK_GATE_FSICLK:
|
|
ast2600_enable_fsiclk(priv->scu);
|
|
break;
|
|
case ASPEED_CLK_GATE_USBPORT1CLK:
|
|
ast2600_enable_usbahclk(priv->scu);
|
|
break;
|
|
case ASPEED_CLK_GATE_USBPORT2CLK:
|
|
ast2600_enable_usbbhclk(priv->scu);
|
|
break;
|
|
case ASPEED_CLK_GATE_YCLK:
|
|
ast2600_enable_haceclk(priv->scu);
|
|
break;
|
|
case ASPEED_CLK_GATE_RSACLK:
|
|
ast2600_enable_rsaclk(priv->scu);
|
|
break;
|
|
default:
|
|
debug("%s: unknown clk %ld\n", __func__, clk->id);
|
|
return -ENOENT;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct clk_ops ast2600_clk_ops = {
|
|
.get_rate = ast2600_clk_get_rate,
|
|
.set_rate = ast2600_clk_set_rate,
|
|
.enable = ast2600_clk_enable,
|
|
};
|
|
|
|
static int ast2600_clk_probe(struct udevice *dev)
|
|
{
|
|
struct ast2600_clk_priv *priv = dev_get_priv(dev);
|
|
|
|
priv->scu = devfdt_get_addr_ptr(dev);
|
|
if (IS_ERR(priv->scu))
|
|
return PTR_ERR(priv->scu);
|
|
|
|
ast2600_init_rgmii_clk(priv->scu, &rgmii_clk_defconfig);
|
|
ast2600_init_rmii_clk(priv->scu, &rmii_clk_defconfig);
|
|
ast2600_configure_mac12_clk(priv->scu);
|
|
ast2600_configure_mac34_clk(priv->scu);
|
|
ast2600_configure_rsa_ecc_clk(priv->scu);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ast2600_clk_bind(struct udevice *dev)
|
|
{
|
|
int ret;
|
|
|
|
/* The reset driver does not have a device node, so bind it here */
|
|
ret = device_bind_driver(gd->dm_root, "ast_sysreset", "reset", &dev);
|
|
if (ret)
|
|
debug("Warning: No reset driver: ret=%d\n", ret);
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct aspeed_clks {
|
|
ulong id;
|
|
const char *name;
|
|
};
|
|
|
|
static struct aspeed_clks aspeed_clk_names[] = {
|
|
{ ASPEED_CLK_HPLL, "hpll" },
|
|
{ ASPEED_CLK_MPLL, "mpll" },
|
|
{ ASPEED_CLK_APLL, "apll" },
|
|
{ ASPEED_CLK_EPLL, "epll" },
|
|
{ ASPEED_CLK_DPLL, "dpll" },
|
|
{ ASPEED_CLK_AHB, "hclk" },
|
|
{ ASPEED_CLK_APB1, "pclk1" },
|
|
{ ASPEED_CLK_APB2, "pclk2" },
|
|
{ ASPEED_CLK_BCLK, "bclk" },
|
|
{ ASPEED_CLK_UARTX, "uxclk" },
|
|
{ ASPEED_CLK_HUARTX, "huxclk" },
|
|
};
|
|
|
|
int soc_clk_dump(void)
|
|
{
|
|
struct udevice *dev;
|
|
struct clk clk;
|
|
unsigned long rate;
|
|
int i, ret;
|
|
|
|
ret = uclass_get_device_by_driver(UCLASS_CLK, DM_DRIVER_GET(aspeed_scu),
|
|
&dev);
|
|
if (ret)
|
|
return ret;
|
|
|
|
printf("Clk\t\tHz\n");
|
|
|
|
for (i = 0; i < ARRAY_SIZE(aspeed_clk_names); i++) {
|
|
clk.id = aspeed_clk_names[i].id;
|
|
ret = clk_request(dev, &clk);
|
|
if (ret < 0) {
|
|
debug("%s clk_request() failed: %d\n", __func__, ret);
|
|
continue;
|
|
}
|
|
|
|
ret = clk_get_rate(&clk);
|
|
rate = ret;
|
|
|
|
clk_free(&clk);
|
|
|
|
if (ret == -EINVAL) {
|
|
printf("clk ID %lu not supported yet\n",
|
|
aspeed_clk_names[i].id);
|
|
continue;
|
|
}
|
|
if (ret < 0) {
|
|
printf("%s %lu: get_rate err: %d\n", __func__,
|
|
aspeed_clk_names[i].id, ret);
|
|
continue;
|
|
}
|
|
|
|
printf("%s(%3lu):\t%lu\n", aspeed_clk_names[i].name,
|
|
aspeed_clk_names[i].id, rate);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct udevice_id ast2600_clk_ids[] = {
|
|
{ .compatible = "aspeed,ast2600-scu", },
|
|
{ },
|
|
};
|
|
|
|
U_BOOT_DRIVER(aspeed_ast2600_scu) = {
|
|
.name = "aspeed_ast2600_scu",
|
|
.id = UCLASS_CLK,
|
|
.of_match = ast2600_clk_ids,
|
|
.priv_auto = sizeof(struct ast2600_clk_priv),
|
|
.ops = &ast2600_clk_ops,
|
|
.bind = ast2600_clk_bind,
|
|
.probe = ast2600_clk_probe,
|
|
};
|