rockchip: clk: Add rv1108 clock driver

Add clock driver support for Rockchip rv1108 soc

Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Andy Yan 2017-06-01 18:00:36 +08:00 committed by Simon Glass
parent 09aa7c468c
commit bae2f282a9
5 changed files with 605 additions and 0 deletions

View file

@ -0,0 +1,111 @@
/*
* (C) Copyright 2016 Rockchip Electronics Co., Ltd
* Author: Andy Yan <andy.yan@rock-chips.com>
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef _ASM_ARCH_CRU_RV1108_H
#define _ASM_ARCH_CRU_RV1108_H
#include <common.h>
#define OSC_HZ (24 * 1000 * 1000)
#define APLL_HZ (600 * 1000000)
#define GPLL_HZ (594 * 1000000)
struct rv1108_clk_priv {
struct rv1108_cru *cru;
ulong rate;
};
struct rv1108_cru {
struct rv1108_pll {
unsigned int con0;
unsigned int con1;
unsigned int con2;
unsigned int con3;
unsigned int con4;
unsigned int con5;
unsigned int reserved[2];
} pll[3];
unsigned int clksel_con[46];
unsigned int reserved1[2];
unsigned int clkgate_con[20];
unsigned int reserved2[4];
unsigned int softrst_con[13];
unsigned int reserved3[3];
unsigned int glb_srst_fst_val;
unsigned int glb_srst_snd_val;
unsigned int glb_cnt_th;
unsigned int misc_con;
unsigned int glb_rst_con;
unsigned int glb_rst_st;
unsigned int sdmmc_con[2];
unsigned int sdio_con[2];
unsigned int emmc_con[2];
};
check_member(rv1108_cru, emmc_con[1], 0x01ec);
struct pll_div {
u32 refdiv;
u32 fbdiv;
u32 postdiv1;
u32 postdiv2;
u32 frac;
};
enum {
/* PLL CON0 */
FBDIV_MASK = 0xfff,
FBDIV_SHIFT = 0,
/* PLL CON1 */
POSTDIV2_SHIFT = 12,
POSTDIV2_MASK = 7 << POSTDIV2_SHIFT,
POSTDIV1_SHIFT = 8,
POSTDIV1_MASK = 7 << POSTDIV1_SHIFT,
REFDIV_MASK = 0x3f,
REFDIV_SHIFT = 0,
/* PLL CON2 */
LOCK_STA_SHIFT = 31,
LOCK_STA_MASK = 1 << LOCK_STA_SHIFT,
FRACDIV_MASK = 0xffffff,
FRACDIV_SHIFT = 0,
/* PLL CON3 */
WORK_MODE_SHIFT = 8,
WORK_MODE_MASK = 1 << WORK_MODE_SHIFT,
WORK_MODE_SLOW = 0,
WORK_MODE_NORMAL = 1,
DSMPD_SHIFT = 3,
DSMPD_MASK = 1 << DSMPD_SHIFT,
/* CLKSEL0_CON */
CORE_PLL_SEL_SHIFT = 8,
CORE_PLL_SEL_MASK = 3 << CORE_PLL_SEL_SHIFT,
CORE_PLL_SEL_APLL = 0,
CORE_PLL_SEL_GPLL = 1,
CORE_PLL_SEL_DPLL = 2,
CORE_CLK_DIV_SHIFT = 0,
CORE_CLK_DIV_MASK = 0x1f << CORE_CLK_DIV_SHIFT,
/* CLKSEL24_CON */
MAC_PLL_SEL_SHIFT = 12,
MAC_PLL_SEL_MASK = 1 << MAC_PLL_SEL_SHIFT,
MAC_PLL_SEL_APLL = 0,
MAC_PLL_SEL_GPLL = 1,
RMII_EXTCLK_SEL_SHIFT = 8,
RMII_EXTCLK_SEL_MASK = 1 << RMII_EXTCLK_SEL_SHIFT,
MAC_CLK_DIV_MASK = 0x1f,
MAC_CLK_DIV_SHIFT = 0,
/* CLKSEL27_CON */
SFC_PLL_SEL_SHIFT = 7,
SFC_PLL_SEL_MASK = 1 << SFC_PLL_SEL_SHIFT,
SFC_PLL_SEL_DPLL = 0,
SFC_PLL_SEL_GPLL = 1,
SFC_CLK_DIV_SHIFT = 0,
SFC_CLK_DIV_MASK = 0x3f << SFC_CLK_DIV_SHIFT,
};
#endif

View file

@ -42,6 +42,7 @@ enum periph_id {
PERIPH_ID_SDMMC2,
PERIPH_ID_HDMI,
PERIPH_ID_GMAC,
PERIPH_ID_SFC,
PERIPH_ID_COUNT,

View file

@ -10,3 +10,4 @@ obj-$(CONFIG_ROCKCHIP_RK3288) += clk_rk3288.o
obj-$(CONFIG_ROCKCHIP_RK3328) += clk_rk3328.o
obj-$(CONFIG_ROCKCHIP_RK3368) += clk_rk3368.o
obj-$(CONFIG_ROCKCHIP_RK3399) += clk_rk3399.o
obj-$(CONFIG_ROCKCHIP_RV1108) += clk_rv1108.o

View file

@ -0,0 +1,223 @@
/*
* (C) Copyright 2016 Rockchip Electronics Co., Ltd
* Author: Andy Yan <andy.yan@rock-chips.com>
* SPDX-License-Identifier: GPL-2.0
*/
#include <common.h>
#include <clk-uclass.h>
#include <dm.h>
#include <errno.h>
#include <syscon.h>
#include <asm/io.h>
#include <asm/arch/clock.h>
#include <asm/arch/cru_rv1108.h>
#include <asm/arch/hardware.h>
#include <dm/lists.h>
#include <dt-bindings/clock/rv1108-cru.h>
DECLARE_GLOBAL_DATA_PTR;
enum {
VCO_MAX_HZ = 2400U * 1000000,
VCO_MIN_HZ = 600 * 1000000,
OUTPUT_MAX_HZ = 2400U * 1000000,
OUTPUT_MIN_HZ = 24 * 1000000,
};
#define RATE_TO_DIV(input_rate, output_rate) \
((input_rate) / (output_rate) - 1);
#define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1))
#define PLL_DIVISORS(hz, _refdiv, _postdiv1, _postdiv2) {\
.refdiv = _refdiv,\
.fbdiv = (u32)((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ),\
.postdiv1 = _postdiv1, .postdiv2 = _postdiv2};\
_Static_assert(((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ) *\
OSC_HZ / (_refdiv * _postdiv1 * _postdiv2) == hz,\
#hz "Hz cannot be hit with PLL "\
"divisors on line " __stringify(__LINE__));
/* use interge mode*/
static const struct pll_div apll_init_cfg = PLL_DIVISORS(APLL_HZ, 1, 3, 1);
static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 2, 2, 1);
static inline int rv1108_pll_id(enum rk_clk_id clk_id)
{
int id = 0;
switch (clk_id) {
case CLK_ARM:
case CLK_DDR:
id = clk_id - 1;
break;
case CLK_GENERAL:
id = 2;
break;
default:
printf("invalid pll id:%d\n", clk_id);
id = -1;
break;
}
return id;
}
static uint32_t rkclk_pll_get_rate(struct rv1108_cru *cru,
enum rk_clk_id clk_id)
{
uint32_t refdiv, fbdiv, postdiv1, postdiv2;
uint32_t con0, con1, con3;
int pll_id = rv1108_pll_id(clk_id);
struct rv1108_pll *pll = &cru->pll[pll_id];
uint32_t freq;
con3 = readl(&pll->con3);
if (con3 & WORK_MODE_MASK) {
con0 = readl(&pll->con0);
con1 = readl(&pll->con1);
fbdiv = (con0 >> FBDIV_SHIFT) & FBDIV_MASK;
postdiv1 = (con1 & POSTDIV1_MASK) >> POSTDIV1_SHIFT;
postdiv2 = (con1 & POSTDIV2_MASK) >> POSTDIV2_SHIFT;
refdiv = (con1 & REFDIV_MASK) >> REFDIV_SHIFT;
freq = (24 * fbdiv / (refdiv * postdiv1 * postdiv2)) * 1000000;
} else {
freq = OSC_HZ;
}
return freq;
}
static int rv1108_mac_set_clk(struct rv1108_cru *cru, ulong rate)
{
uint32_t con = readl(&cru->clksel_con[24]);
ulong pll_rate;
uint8_t div;
if ((con >> MAC_PLL_SEL_SHIFT) & MAC_PLL_SEL_GPLL)
pll_rate = rkclk_pll_get_rate(cru, CLK_GENERAL);
else
pll_rate = rkclk_pll_get_rate(cru, CLK_ARM);
/*default set 50MHZ for gmac*/
if (!rate)
rate = 50000000;
div = DIV_ROUND_UP(pll_rate, rate) - 1;
if (div <= 0x1f)
rk_clrsetreg(&cru->clksel_con[24], MAC_CLK_DIV_MASK,
div << MAC_CLK_DIV_SHIFT);
else
debug("Unsupported div for gmac:%d\n", div);
return DIV_TO_RATE(pll_rate, div);
}
static int rv1108_sfc_set_clk(struct rv1108_cru *cru, uint rate)
{
u32 con = readl(&cru->clksel_con[27]);
u32 pll_rate;
u32 div;
if ((con >> SFC_PLL_SEL_SHIFT) && SFC_PLL_SEL_GPLL)
pll_rate = rkclk_pll_get_rate(cru, CLK_GENERAL);
else
pll_rate = rkclk_pll_get_rate(cru, CLK_DDR);
div = DIV_ROUND_UP(pll_rate, rate) - 1;
if (div <= 0x3f)
rk_clrsetreg(&cru->clksel_con[27], SFC_CLK_DIV_MASK,
div << SFC_CLK_DIV_SHIFT);
else
debug("Unsupported sfc clk rate:%d\n", rate);
return DIV_TO_RATE(pll_rate, div);
}
static ulong rv1108_clk_get_rate(struct clk *clk)
{
struct rv1108_clk_priv *priv = dev_get_priv(clk->dev);
switch (clk->id) {
case 0 ... 63:
return rkclk_pll_get_rate(priv->cru, clk->id);
default:
return -ENOENT;
}
}
static ulong rv1108_clk_set_rate(struct clk *clk, ulong rate)
{
struct rv1108_clk_priv *priv = dev_get_priv(clk->dev);
ulong new_rate;
switch (clk->id) {
case SCLK_MAC:
new_rate = rv1108_mac_set_clk(priv->cru, rate);
break;
case SCLK_SFC:
new_rate = rv1108_sfc_set_clk(priv->cru, rate);
break;
default:
return -ENOENT;
}
return new_rate;
}
static const struct clk_ops rv1108_clk_ops = {
.get_rate = rv1108_clk_get_rate,
.set_rate = rv1108_clk_set_rate,
};
static void rkclk_init(struct rv1108_cru *cru)
{
unsigned int apll = rkclk_pll_get_rate(cru, CLK_ARM);
unsigned int dpll = rkclk_pll_get_rate(cru, CLK_DDR);
unsigned int gpll = rkclk_pll_get_rate(cru, CLK_GENERAL);
rk_clrsetreg(&cru->clksel_con[0], CORE_CLK_DIV_MASK,
0 << MAC_CLK_DIV_SHIFT);
printf("APLL: %d DPLL:%d GPLL:%d\n", apll, dpll, gpll);
}
static int rv1108_clk_probe(struct udevice *dev)
{
struct rv1108_clk_priv *priv = dev_get_priv(dev);
priv->cru = (struct rv1108_cru *)devfdt_get_addr(dev);
rkclk_init(priv->cru);
return 0;
}
static int rv1108_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, "rv1108_sysreset", "reset", &dev);
if (ret)
error("No Rv1108 reset driver: ret=%d\n", ret);
return 0;
}
static const struct udevice_id rv1108_clk_ids[] = {
{ .compatible = "rockchip,rv1108-cru" },
{ }
};
U_BOOT_DRIVER(clk_rv1108) = {
.name = "clk_rv1108",
.id = UCLASS_CLK,
.of_match = rv1108_clk_ids,
.priv_auto_alloc_size = sizeof(struct rv1108_clk_priv),
.ops = &rv1108_clk_ops,
.bind = rv1108_clk_bind,
.probe = rv1108_clk_probe,
};

View file

@ -0,0 +1,269 @@
/*
* Copyright (c) 2017 Rockchip Electronics Co. Ltd.
* Author: Shawn Lin <shawn.lin@rock-chips.com>
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef _DT_BINDINGS_CLK_ROCKCHIP_RV1108_H
#define _DT_BINDINGS_CLK_ROCKCHIP_RV1108_H
/* pll id */
#define PLL_APLL 0
#define PLL_DPLL 1
#define PLL_GPLL 2
#define ARMCLK 3
/* sclk gates (special clocks) */
#define SCLK_MAC 64
#define SCLK_SPI0 65
#define SCLK_NANDC 67
#define SCLK_SDMMC 68
#define SCLK_SDIO 69
#define SCLK_EMMC 71
#define SCLK_UART0 72
#define SCLK_UART1 73
#define SCLK_UART2 74
#define SCLK_I2S0 75
#define SCLK_I2S1 76
#define SCLK_I2S2 77
#define SCLK_TIMER0 78
#define SCLK_TIMER1 79
#define SCLK_SFC 80
#define SCLK_SDMMC_DRV 81
#define SCLK_SDIO_DRV 82
#define SCLK_EMMC_DRV 83
#define SCLK_SDMMC_SAMPLE 84
#define SCLK_SDIO_SAMPLE 85
#define SCLK_EMMC_SAMPLE 86
#define SCLK_MAC_RX 87
#define SCLK_MAC_TX 88
#define SCLK_MACREF 89
#define SCLK_MACREF_OUT 90
/* aclk gates */
#define ACLK_DMAC 192
#define ACLK_PRE 193
#define ACLK_CORE 194
#define ACLK_ENMCORE 195
#define ACLK_GMAC 196
/* pclk gates */
#define PCLK_GPIO1 256
#define PCLK_GPIO2 257
#define PCLK_GPIO3 258
#define PCLK_GRF 259
#define PCLK_I2C1 260
#define PCLK_I2C2 261
#define PCLK_I2C3 262
#define PCLK_SPI 263
#define PCLK_SFC 264
#define PCLK_UART0 265
#define PCLK_UART1 266
#define PCLK_UART2 267
#define PCLK_TSADC 268
#define PCLK_PWM 269
#define PCLK_TIMER 270
#define PCLK_PERI 271
#define PCLK_GMAC 272
/* hclk gates */
#define HCLK_I2S0_8CH 320
#define HCLK_I2S1_8CH 321
#define HCLK_I2S2_2CH 322
#define HCLK_NANDC 323
#define HCLK_SDMMC 324
#define HCLK_SDIO 325
#define HCLK_EMMC 326
#define HCLK_PERI 327
#define HCLK_SFC 328
#define CLK_NR_CLKS (HCLK_SFC + 1)
/* reset id */
#define SRST_CORE_PO_AD 0
#define SRST_CORE_AD 1
#define SRST_L2_AD 2
#define SRST_CPU_NIU_AD 3
#define SRST_CORE_PO 4
#define SRST_CORE 5
#define SRST_L2 6
#define SRST_CORE_DBG 8
#define PRST_DBG 9
#define RST_DAP 10
#define PRST_DBG_NIU 11
#define ARST_STRC_SYS_AD 15
#define SRST_DDRPHY_CLKDIV 16
#define SRST_DDRPHY 17
#define PRST_DDRPHY 18
#define PRST_HDMIPHY 19
#define PRST_VDACPHY 20
#define PRST_VADCPHY 21
#define PRST_MIPI_CSI_PHY 22
#define PRST_MIPI_DSI_PHY 23
#define PRST_ACODEC 24
#define ARST_BUS_NIU 25
#define PRST_TOP_NIU 26
#define ARST_INTMEM 27
#define HRST_ROM 28
#define ARST_DMAC 29
#define SRST_MSCH_NIU 30
#define PRST_MSCH_NIU 31
#define PRST_DDRUPCTL 32
#define NRST_DDRUPCTL 33
#define PRST_DDRMON 34
#define HRST_I2S0_8CH 35
#define MRST_I2S0_8CH 36
#define HRST_I2S1_2CH 37
#define MRST_IS21_2CH 38
#define HRST_I2S2_2CH 39
#define MRST_I2S2_2CH 40
#define HRST_CRYPTO 41
#define SRST_CRYPTO 42
#define PRST_SPI 43
#define SRST_SPI 44
#define PRST_UART0 45
#define PRST_UART1 46
#define PRST_UART2 47
#define SRST_UART0 48
#define SRST_UART1 49
#define SRST_UART2 50
#define PRST_I2C1 51
#define PRST_I2C2 52
#define PRST_I2C3 53
#define SRST_I2C1 54
#define SRST_I2C2 55
#define SRST_I2C3 56
#define PRST_PWM1 58
#define SRST_PWM1 60
#define PRST_WDT 61
#define PRST_GPIO1 62
#define PRST_GPIO2 63
#define PRST_GPIO3 64
#define PRST_GRF 65
#define PRST_EFUSE 66
#define PRST_EFUSE512 67
#define PRST_TIMER0 68
#define SRST_TIMER0 69
#define SRST_TIMER1 70
#define PRST_TSADC 71
#define SRST_TSADC 72
#define PRST_SARADC 73
#define SRST_SARADC 74
#define HRST_SYSBUS 75
#define PRST_USBGRF 76
#define ARST_PERIPH_NIU 80
#define HRST_PERIPH_NIU 81
#define PRST_PERIPH_NIU 82
#define HRST_PERIPH 83
#define HRST_SDMMC 84
#define HRST_SDIO 85
#define HRST_EMMC 86
#define HRST_NANDC 87
#define NRST_NANDC 88
#define HRST_SFC 89
#define SRST_SFC 90
#define ARST_GMAC 91
#define HRST_OTG 92
#define SRST_OTG 93
#define SRST_OTG_ADP 94
#define HRST_HOST0 95
#define HRST_HOST0_AUX 96
#define HRST_HOST0_ARB 97
#define SRST_HOST0_EHCIPHY 98
#define SRST_HOST0_UTMI 99
#define SRST_USBPOR 100
#define SRST_UTMI0 101
#define SRST_UTMI1 102
#define ARST_VIO0_NIU 102
#define ARST_VIO1_NIU 103
#define HRST_VIO_NIU 104
#define PRST_VIO_NIU 105
#define ARST_VOP 106
#define HRST_VOP 107
#define DRST_VOP 108
#define ARST_IEP 109
#define HRST_IEP 110
#define ARST_RGA 111
#define HRST_RGA 112
#define SRST_RGA 113
#define PRST_CVBS 114
#define PRST_HDMI 115
#define SRST_HDMI 116
#define PRST_MIPI_DSI 117
#define ARST_ISP_NIU 118
#define HRST_ISP_NIU 119
#define HRST_ISP 120
#define SRST_ISP 121
#define ARST_VIP0 122
#define HRST_VIP0 123
#define PRST_VIP0 124
#define ARST_VIP1 125
#define HRST_VIP1 126
#define PRST_VIP1 127
#define ARST_VIP2 128
#define HRST_VIP2 129
#define PRST_VIP2 120
#define ARST_VIP3 121
#define HRST_VIP3 122
#define PRST_VIP4 123
#define PRST_CIF1TO4 124
#define SRST_CVBS_CLK 125
#define HRST_CVBS 126
#define ARST_VPU_NIU 140
#define HRST_VPU_NIU 141
#define ARST_VPU 142
#define HRST_VPU 143
#define ARST_RKVDEC_NIU 144
#define HRST_RKVDEC_NIU 145
#define ARST_RKVDEC 146
#define HRST_RKVDEC 147
#define SRST_RKVDEC_CABAC 148
#define SRST_RKVDEC_CORE 149
#define ARST_RKVENC_NIU 150
#define HRST_RKVENC_NIU 151
#define ARST_RKVENC 152
#define HRST_RKVENC 153
#define SRST_RKVENC_CORE 154
#define SRST_DSP_CORE 156
#define SRST_DSP_SYS 157
#define SRST_DSP_GLOBAL 158
#define SRST_DSP_OECM 159
#define PRST_DSP_IOP_NIU 160
#define ARST_DSP_EPP_NIU 161
#define ARST_DSP_EDP_NIU 162
#define PRST_DSP_DBG_NIU 163
#define PRST_DSP_CFG_NIU 164
#define PRST_DSP_GRF 165
#define PRST_DSP_MAILBOX 166
#define PRST_DSP_INTC 167
#define PRST_DSP_PFM_MON 169
#define SRST_DSP_PFM_MON 170
#define ARST_DSP_EDAP_NIU 171
#define SRST_PMU 172
#define SRST_PMU_I2C0 173
#define PRST_PMU_I2C0 174
#define PRST_PMU_GPIO0 175
#define PRST_PMU_INTMEM 176
#define PRST_PMU_PWM0 177
#define SRST_PMU_PWM0 178
#define PRST_PMU_GRF 179
#define SRST_PMU_NIU 180
#define SRST_PMU_PVTM 181
#define ARST_DSP_EDP_PERF 184
#define ARST_DSP_EPP_PERF 185
#endif /* _DT_BINDINGS_CLK_ROCKCHIP_RV1108_H */