mirror of
https://github.com/Fishwaldo/u-boot.git
synced 2025-03-18 13:11:31 +00:00
clk: rockchip: Add rk3328 gamc clock support
The rk3328 soc has two gmac controllers, one is gmac2io, the other is gmac2phy. We use the gmac2io rgmii interface for 1000M phy here. Signed-off-by: David Wu <david.wu@rock-chips.com> Acked-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com> Reviewed-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
This commit is contained in:
parent
dfb886d4f2
commit
7cd4ebab2b
2 changed files with 181 additions and 3 deletions
|
@ -13,6 +13,7 @@
|
|||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/cru_rk3328.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
#include <asm/arch/grf_rk3328.h>
|
||||
#include <asm/io.h>
|
||||
#include <dm/lists.h>
|
||||
#include <dt-bindings/clock/rk3328-cru.h>
|
||||
|
@ -94,6 +95,14 @@ enum {
|
|||
PCLK_DBG_DIV_SHIFT = 0,
|
||||
PCLK_DBG_DIV_MASK = 0xF << PCLK_DBG_DIV_SHIFT,
|
||||
|
||||
/* CLKSEL_CON27 */
|
||||
GMAC2IO_PLL_SEL_SHIFT = 7,
|
||||
GMAC2IO_PLL_SEL_MASK = 1 << GMAC2IO_PLL_SEL_SHIFT,
|
||||
GMAC2IO_PLL_SEL_CPLL = 0,
|
||||
GMAC2IO_PLL_SEL_GPLL = 1,
|
||||
GMAC2IO_CLK_DIV_MASK = 0x1f,
|
||||
GMAC2IO_CLK_DIV_SHIFT = 0,
|
||||
|
||||
/* CLKSEL_CON28 */
|
||||
ACLK_PERIHP_PLL_SEL_CPLL = 0,
|
||||
ACLK_PERIHP_PLL_SEL_GPLL,
|
||||
|
@ -393,6 +402,44 @@ static ulong rk3328_i2c_set_clk(struct rk3328_cru *cru, ulong clk_id, uint hz)
|
|||
return DIV_TO_RATE(GPLL_HZ, src_clk_div);
|
||||
}
|
||||
|
||||
static ulong rk3328_gmac2io_set_clk(struct rk3328_cru *cru, ulong rate)
|
||||
{
|
||||
struct rk3328_grf_regs *grf;
|
||||
ulong ret;
|
||||
|
||||
grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
|
||||
|
||||
/*
|
||||
* The RGMII CLK can be derived either from an external "clkin"
|
||||
* or can be generated from internally by a divider from SCLK_MAC.
|
||||
*/
|
||||
if (readl(&grf->mac_con[1]) & BIT(10) &&
|
||||
readl(&grf->soc_con[4]) & BIT(14)) {
|
||||
/* An external clock will always generate the right rate... */
|
||||
ret = rate;
|
||||
} else {
|
||||
u32 con = readl(&cru->clksel_con[27]);
|
||||
ulong pll_rate;
|
||||
u8 div;
|
||||
|
||||
if ((con >> GMAC2IO_PLL_SEL_SHIFT) & GMAC2IO_PLL_SEL_GPLL)
|
||||
pll_rate = GPLL_HZ;
|
||||
else
|
||||
pll_rate = CPLL_HZ;
|
||||
|
||||
div = DIV_ROUND_UP(pll_rate, rate) - 1;
|
||||
if (div <= 0x1f)
|
||||
rk_clrsetreg(&cru->clksel_con[27], GMAC2IO_CLK_DIV_MASK,
|
||||
div << GMAC2IO_CLK_DIV_SHIFT);
|
||||
else
|
||||
debug("Unsupported div for gmac:%d\n", div);
|
||||
|
||||
return DIV_TO_RATE(pll_rate, div);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ulong rk3328_mmc_get_clk(struct rk3328_cru *cru, uint clk_id)
|
||||
{
|
||||
u32 div, con, con_id;
|
||||
|
@ -558,12 +605,48 @@ static ulong rk3328_clk_set_rate(struct clk *clk, ulong rate)
|
|||
case SCLK_I2C3:
|
||||
ret = rk3328_i2c_set_clk(priv->cru, clk->id, rate);
|
||||
break;
|
||||
case SCLK_MAC2IO:
|
||||
ret = rk3328_gmac2io_set_clk(priv->cru, rate);
|
||||
break;
|
||||
case SCLK_PWM:
|
||||
ret = rk3328_pwm_set_clk(priv->cru, rate);
|
||||
break;
|
||||
case SCLK_SARADC:
|
||||
ret = rk3328_saradc_set_clk(priv->cru, rate);
|
||||
break;
|
||||
case DCLK_LCDC:
|
||||
case SCLK_PDM:
|
||||
case SCLK_RTC32K:
|
||||
case SCLK_UART0:
|
||||
case SCLK_UART1:
|
||||
case SCLK_UART2:
|
||||
case SCLK_SDIO:
|
||||
case SCLK_TSP:
|
||||
case SCLK_WIFI:
|
||||
case ACLK_BUS_PRE:
|
||||
case HCLK_BUS_PRE:
|
||||
case PCLK_BUS_PRE:
|
||||
case ACLK_PERI_PRE:
|
||||
case HCLK_PERI:
|
||||
case PCLK_PERI:
|
||||
case ACLK_VIO_PRE:
|
||||
case HCLK_VIO_PRE:
|
||||
case ACLK_RGA_PRE:
|
||||
case SCLK_RGA:
|
||||
case ACLK_VOP_PRE:
|
||||
case ACLK_RKVDEC_PRE:
|
||||
case ACLK_RKVENC:
|
||||
case ACLK_VPU_PRE:
|
||||
case SCLK_VDEC_CABAC:
|
||||
case SCLK_VDEC_CORE:
|
||||
case SCLK_VENC_CORE:
|
||||
case SCLK_VENC_DSP:
|
||||
case SCLK_EFUSE:
|
||||
case PCLK_DDR:
|
||||
case ACLK_GMAC:
|
||||
case PCLK_GMAC:
|
||||
case SCLK_USB3OTG_SUSPEND:
|
||||
return 0;
|
||||
default:
|
||||
return -ENOENT;
|
||||
}
|
||||
|
@ -571,9 +654,104 @@ static ulong rk3328_clk_set_rate(struct clk *clk, ulong rate)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int rk3328_gmac2io_set_parent(struct clk *clk, struct clk *parent)
|
||||
{
|
||||
struct rk3328_grf_regs *grf;
|
||||
const char *clock_output_name;
|
||||
int ret;
|
||||
|
||||
grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
|
||||
|
||||
/*
|
||||
* If the requested parent is in the same clock-controller and the id
|
||||
* is SCLK_MAC2IO_SRC ("clk_mac2io_src"), switch to the internal clock.
|
||||
*/
|
||||
if ((parent->dev == clk->dev) && (parent->id == SCLK_MAC2IO_SRC)) {
|
||||
debug("%s: switching RGMII to SCLK_MAC2IO_SRC\n", __func__);
|
||||
rk_clrreg(&grf->mac_con[1], BIT(10));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise, we need to check the clock-output-names of the
|
||||
* requested parent to see if the requested id is "gmac_clkin".
|
||||
*/
|
||||
ret = dev_read_string_index(parent->dev, "clock-output-names",
|
||||
parent->id, &clock_output_name);
|
||||
if (ret < 0)
|
||||
return -ENODATA;
|
||||
|
||||
/* If this is "gmac_clkin", switch to the external clock input */
|
||||
if (!strcmp(clock_output_name, "gmac_clkin")) {
|
||||
debug("%s: switching RGMII to CLKIN\n", __func__);
|
||||
rk_setreg(&grf->mac_con[1], BIT(10));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int rk3328_gmac2io_ext_set_parent(struct clk *clk, struct clk *parent)
|
||||
{
|
||||
struct rk3328_grf_regs *grf;
|
||||
const char *clock_output_name;
|
||||
int ret;
|
||||
|
||||
grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
|
||||
|
||||
/*
|
||||
* If the requested parent is in the same clock-controller and the id
|
||||
* is SCLK_MAC2IO ("clk_mac2io"), switch to the internal clock.
|
||||
*/
|
||||
if ((parent->dev == clk->dev) && (parent->id == SCLK_MAC2IO)) {
|
||||
debug("%s: switching RGMII to SCLK_MAC2IO\n", __func__);
|
||||
rk_clrreg(&grf->soc_con[4], BIT(14));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise, we need to check the clock-output-names of the
|
||||
* requested parent to see if the requested id is "gmac_clkin".
|
||||
*/
|
||||
ret = dev_read_string_index(parent->dev, "clock-output-names",
|
||||
parent->id, &clock_output_name);
|
||||
if (ret < 0)
|
||||
return -ENODATA;
|
||||
|
||||
/* If this is "gmac_clkin", switch to the external clock input */
|
||||
if (!strcmp(clock_output_name, "gmac_clkin")) {
|
||||
debug("%s: switching RGMII to CLKIN\n", __func__);
|
||||
rk_setreg(&grf->soc_con[4], BIT(14));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int rk3328_clk_set_parent(struct clk *clk, struct clk *parent)
|
||||
{
|
||||
switch (clk->id) {
|
||||
case SCLK_MAC2IO:
|
||||
return rk3328_gmac2io_set_parent(clk, parent);
|
||||
case SCLK_MAC2IO_EXT:
|
||||
return rk3328_gmac2io_ext_set_parent(clk, parent);
|
||||
case DCLK_LCDC:
|
||||
case SCLK_PDM:
|
||||
case SCLK_RTC32K:
|
||||
case SCLK_UART0:
|
||||
case SCLK_UART1:
|
||||
case SCLK_UART2:
|
||||
return 0;
|
||||
}
|
||||
|
||||
debug("%s: unsupported clk %ld\n", __func__, clk->id);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static struct clk_ops rk3328_clk_ops = {
|
||||
.get_rate = rk3328_clk_get_rate,
|
||||
.set_rate = rk3328_clk_set_rate,
|
||||
.set_parent = rk3328_clk_set_parent,
|
||||
};
|
||||
|
||||
static int rk3328_clk_probe(struct udevice *dev)
|
||||
|
|
|
@ -86,6 +86,9 @@
|
|||
#define SCLK_USB3OTG_SUSPEND 97
|
||||
#define SCLK_REF_USB3OTG_SRC 98
|
||||
#define SCLK_MAC2IO_SRC 99
|
||||
#define SCLK_MAC2IO 100
|
||||
#define SCLK_MAC2PHY 101
|
||||
#define SCLK_MAC2IO_EXT 102
|
||||
|
||||
/* dclk gates */
|
||||
#define DCLK_LCDC 180
|
||||
|
@ -199,9 +202,6 @@
|
|||
|
||||
#define CLK_NR_CLKS (HCLK_HDCP + 1)
|
||||
|
||||
#define SCLK_MAC2IO 0
|
||||
#define SCLK_MAC2PHY 1
|
||||
|
||||
#define CLKGRF_NR_CLKS (SCLK_MAC2PHY + 1)
|
||||
|
||||
/* soft-reset indices */
|
||||
|
|
Loading…
Add table
Reference in a new issue