4113 lines
139 KiB
Diff
4113 lines
139 KiB
Diff
From 6197ff4fc8190d487ab907ecd86477c3812c042c Mon Sep 17 00:00:00 2001
|
|
From: Elaine Zhang <zhangqing@rock-chips.com>
|
|
Date: Wed, 14 Oct 2020 10:28:08 +0800
|
|
Subject: [PATCH] clk: rockchip: Add supprot to limit input rate for fractional
|
|
divider
|
|
|
|
From Rockchips fractional divider usage, some clocks can be generated
|
|
by fractional divider, but the input clock frequency of fractional
|
|
divider should be less than a specified value.
|
|
.i.e:
|
|
|--\
|
|
---[GPLL]---| \ |--\
|
|
---[CPLL]---|mux|--[GATE]--[DIV]-----------------------| \
|
|
---[NPLL]---| / | |mux|--[GATE]--
|
|
|--/ |--[GATE]--[FRACDIV]--| /
|
|
|--/
|
|
|
|
The FRACDIV frequency is designed to be only 300M(Different SOC
|
|
implementations are different).But the GPLL or CPLL may be 1200M.
|
|
Must be added to limit to ensure that the design is not exceeded.
|
|
|
|
Signed-off-by: Finley Xiao <finley.xiao@rock-chips.com>
|
|
Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
|
|
---
|
|
drivers/clk/rockchip/clk-px30.c | 29 +++++++++----------
|
|
drivers/clk/rockchip/clk-rk3036.c | 13 +++++----
|
|
drivers/clk/rockchip/clk-rk3128.c | 15 ++++++----
|
|
drivers/clk/rockchip/clk-rk3188.c | 24 +++++++++-------
|
|
drivers/clk/rockchip/clk-rk3228.c | 18 +++++++-----
|
|
drivers/clk/rockchip/clk-rk3288.c | 19 +++++++------
|
|
drivers/clk/rockchip/clk-rk3308.c | 46 +++++++++++++++++--------------
|
|
drivers/clk/rockchip/clk-rk3328.c | 17 +++++++-----
|
|
drivers/clk/rockchip/clk-rk3368.c | 17 +++++++-----
|
|
drivers/clk/rockchip/clk-rk3399.c | 32 ++++++++++++---------
|
|
drivers/clk/rockchip/clk-rv1108.c | 14 ++++++----
|
|
drivers/clk/rockchip/clk.c | 21 ++++++++++++--
|
|
drivers/clk/rockchip/clk.h | 10 +++++--
|
|
include/linux/clk-provider.h | 2 ++
|
|
14 files changed, 168 insertions(+), 109 deletions(-)
|
|
|
|
diff --git a/drivers/clk/rockchip/clk-px30.c b/drivers/clk/rockchip/clk-px30.c
|
|
index 6fb9c98b7d24..f075eb922bab 100644
|
|
--- a/drivers/clk/rockchip/clk-px30.c
|
|
+++ b/drivers/clk/rockchip/clk-px30.c
|
|
@@ -13,6 +13,7 @@
|
|
#include "clk.h"
|
|
|
|
#define PX30_GRF_SOC_STATUS0 0x480
|
|
+#define PX30_FRAC_MAX_PRATE 600000000
|
|
|
|
enum px30_plls {
|
|
apll, dpll, cpll, npll, apll_b_h, apll_b_l,
|
|
@@ -424,7 +425,7 @@ static struct rockchip_clk_branch px30_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "dclk_vopb_frac", "dclk_vopb_src", CLK_SET_RATE_PARENT,
|
|
PX30_CLKSEL_CON(6), 0,
|
|
PX30_CLKGATE_CON(2), 3, GFLAGS,
|
|
- &px30_dclk_vopb_fracmux),
|
|
+ &px30_dclk_vopb_fracmux, 0),
|
|
GATE(DCLK_VOPB, "dclk_vopb", "dclk_vopb_mux", CLK_SET_RATE_PARENT,
|
|
PX30_CLKGATE_CON(2), 4, GFLAGS),
|
|
COMPOSITE(0, "dclk_vopl_src", mux_npll_cpll_p, 0,
|
|
@@ -433,7 +434,7 @@ static struct rockchip_clk_branch px30_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "dclk_vopl_frac", "dclk_vopl_src", CLK_SET_RATE_PARENT,
|
|
PX30_CLKSEL_CON(9), 0,
|
|
PX30_CLKGATE_CON(2), 7, GFLAGS,
|
|
- &px30_dclk_vopl_fracmux),
|
|
+ &px30_dclk_vopl_fracmux, 0),
|
|
GATE(DCLK_VOPL, "dclk_vopl", "dclk_vopl_mux", CLK_SET_RATE_PARENT,
|
|
PX30_CLKGATE_CON(2), 8, GFLAGS),
|
|
|
|
@@ -591,7 +592,7 @@ static struct rockchip_clk_branch px30_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_pdm_frac", "clk_pdm_src", CLK_SET_RATE_PARENT,
|
|
PX30_CLKSEL_CON(27), 0,
|
|
PX30_CLKGATE_CON(9), 10, GFLAGS,
|
|
- &px30_pdm_fracmux),
|
|
+ &px30_pdm_fracmux, PX30_FRAC_MAX_PRATE),
|
|
GATE(SCLK_PDM, "clk_pdm", "clk_pdm_mux", CLK_SET_RATE_PARENT,
|
|
PX30_CLKGATE_CON(9), 11, GFLAGS),
|
|
|
|
@@ -601,7 +602,7 @@ static struct rockchip_clk_branch px30_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_i2s0_tx_frac", "clk_i2s0_tx_src", CLK_SET_RATE_PARENT,
|
|
PX30_CLKSEL_CON(29), 0,
|
|
PX30_CLKGATE_CON(9), 13, GFLAGS,
|
|
- &px30_i2s0_tx_fracmux),
|
|
+ &px30_i2s0_tx_fracmux, PX30_FRAC_MAX_PRATE),
|
|
COMPOSITE_NODIV(SCLK_I2S0_TX, "clk_i2s0_tx", mux_i2s0_tx_rx_p, CLK_SET_RATE_PARENT,
|
|
PX30_CLKSEL_CON(28), 12, 1, MFLAGS,
|
|
PX30_CLKGATE_CON(9), 14, GFLAGS),
|
|
@@ -617,7 +618,7 @@ static struct rockchip_clk_branch px30_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_i2s0_rx_frac", "clk_i2s0_rx_src", CLK_SET_RATE_PARENT,
|
|
PX30_CLKSEL_CON(59), 0,
|
|
PX30_CLKGATE_CON(17), 1, GFLAGS,
|
|
- &px30_i2s0_rx_fracmux),
|
|
+ &px30_i2s0_rx_fracmux, PX30_FRAC_MAX_PRATE),
|
|
COMPOSITE_NODIV(SCLK_I2S0_RX, "clk_i2s0_rx", mux_i2s0_rx_tx_p, CLK_SET_RATE_PARENT,
|
|
PX30_CLKSEL_CON(58), 12, 1, MFLAGS,
|
|
PX30_CLKGATE_CON(17), 2, GFLAGS),
|
|
@@ -633,7 +634,7 @@ static struct rockchip_clk_branch px30_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_i2s1_frac", "clk_i2s1_src", CLK_SET_RATE_PARENT,
|
|
PX30_CLKSEL_CON(31), 0,
|
|
PX30_CLKGATE_CON(10), 1, GFLAGS,
|
|
- &px30_i2s1_fracmux),
|
|
+ &px30_i2s1_fracmux, PX30_FRAC_MAX_PRATE),
|
|
GATE(SCLK_I2S1, "clk_i2s1", "clk_i2s1_mux", CLK_SET_RATE_PARENT,
|
|
PX30_CLKGATE_CON(10), 2, GFLAGS),
|
|
COMPOSITE_NODIV(0, "clk_i2s1_out_pre", mux_i2s1_out_p, 0,
|
|
@@ -648,7 +649,7 @@ static struct rockchip_clk_branch px30_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_i2s2_frac", "clk_i2s2_src", CLK_SET_RATE_PARENT,
|
|
PX30_CLKSEL_CON(33), 0,
|
|
PX30_CLKGATE_CON(10), 5, GFLAGS,
|
|
- &px30_i2s2_fracmux),
|
|
+ &px30_i2s2_fracmux, PX30_FRAC_MAX_PRATE),
|
|
GATE(SCLK_I2S2, "clk_i2s2", "clk_i2s2_mux", CLK_SET_RATE_PARENT,
|
|
PX30_CLKGATE_CON(10), 6, GFLAGS),
|
|
COMPOSITE_NODIV(0, "clk_i2s2_out_pre", mux_i2s2_out_p, 0,
|
|
@@ -666,7 +667,7 @@ static struct rockchip_clk_branch px30_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_uart1_frac", "clk_uart1_src", CLK_SET_RATE_PARENT,
|
|
PX30_CLKSEL_CON(36), 0,
|
|
PX30_CLKGATE_CON(10), 14, GFLAGS,
|
|
- &px30_uart1_fracmux),
|
|
+ &px30_uart1_fracmux, PX30_FRAC_MAX_PRATE),
|
|
GATE(SCLK_UART1, "clk_uart1", "clk_uart1_mux", CLK_SET_RATE_PARENT,
|
|
PX30_CLKGATE_CON(10), 15, GFLAGS),
|
|
|
|
@@ -679,7 +680,7 @@ static struct rockchip_clk_branch px30_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_uart2_frac", "clk_uart2_src", CLK_SET_RATE_PARENT,
|
|
PX30_CLKSEL_CON(39), 0,
|
|
PX30_CLKGATE_CON(11), 2, GFLAGS,
|
|
- &px30_uart2_fracmux),
|
|
+ &px30_uart2_fracmux, PX30_FRAC_MAX_PRATE),
|
|
GATE(SCLK_UART2, "clk_uart2", "clk_uart2_mux", CLK_SET_RATE_PARENT,
|
|
PX30_CLKGATE_CON(11), 3, GFLAGS),
|
|
|
|
@@ -692,7 +693,7 @@ static struct rockchip_clk_branch px30_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_uart3_frac", "clk_uart3_src", CLK_SET_RATE_PARENT,
|
|
PX30_CLKSEL_CON(42), 0,
|
|
PX30_CLKGATE_CON(11), 6, GFLAGS,
|
|
- &px30_uart3_fracmux),
|
|
+ &px30_uart3_fracmux, PX30_FRAC_MAX_PRATE),
|
|
GATE(SCLK_UART3, "clk_uart3", "clk_uart3_mux", CLK_SET_RATE_PARENT,
|
|
PX30_CLKGATE_CON(11), 7, GFLAGS),
|
|
|
|
@@ -705,7 +706,7 @@ static struct rockchip_clk_branch px30_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_uart4_frac", "clk_uart4_src", CLK_SET_RATE_PARENT,
|
|
PX30_CLKSEL_CON(45), 0,
|
|
PX30_CLKGATE_CON(11), 10, GFLAGS,
|
|
- &px30_uart4_fracmux),
|
|
+ &px30_uart4_fracmux, PX30_FRAC_MAX_PRATE),
|
|
GATE(SCLK_UART4, "clk_uart4", "clk_uart4_mux", CLK_SET_RATE_PARENT,
|
|
PX30_CLKGATE_CON(11), 11, GFLAGS),
|
|
|
|
@@ -718,7 +719,7 @@ static struct rockchip_clk_branch px30_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_uart5_frac", "clk_uart5_src", CLK_SET_RATE_PARENT,
|
|
PX30_CLKSEL_CON(48), 0,
|
|
PX30_CLKGATE_CON(11), 14, GFLAGS,
|
|
- &px30_uart5_fracmux),
|
|
+ &px30_uart5_fracmux, PX30_FRAC_MAX_PRATE),
|
|
GATE(SCLK_UART5, "clk_uart5", "clk_uart5_mux", CLK_SET_RATE_PARENT,
|
|
PX30_CLKGATE_CON(11), 15, GFLAGS),
|
|
|
|
@@ -918,7 +919,7 @@ static struct rockchip_clk_branch px30_clk_pmu_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_rtc32k_frac", "xin24m", CLK_IGNORE_UNUSED,
|
|
PX30_PMU_CLKSEL_CON(1), 0,
|
|
PX30_PMU_CLKGATE_CON(0), 13, GFLAGS,
|
|
- &px30_rtc32k_pmu_fracmux),
|
|
+ &px30_rtc32k_pmu_fracmux, 0),
|
|
|
|
COMPOSITE_NOMUX(XIN24M_DIV, "xin24m_div", "xin24m", CLK_IGNORE_UNUSED,
|
|
PX30_PMU_CLKSEL_CON(0), 8, 5, DFLAGS,
|
|
@@ -940,7 +941,7 @@ static struct rockchip_clk_branch px30_clk_pmu_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_uart0_frac", "clk_uart0_pmu_src", CLK_SET_RATE_PARENT,
|
|
PX30_PMU_CLKSEL_CON(5), 0,
|
|
PX30_PMU_CLKGATE_CON(1), 2, GFLAGS,
|
|
- &px30_uart0_pmu_fracmux),
|
|
+ &px30_uart0_pmu_fracmux, PX30_FRAC_MAX_PRATE),
|
|
GATE(SCLK_UART0_PMU, "clk_uart0_pmu", "clk_uart0_pmu_mux", CLK_SET_RATE_PARENT,
|
|
PX30_PMU_CLKGATE_CON(1), 3, GFLAGS),
|
|
|
|
diff --git a/drivers/clk/rockchip/clk-rk3036.c b/drivers/clk/rockchip/clk-rk3036.c
|
|
index 6a46f85ad837..80876c8f8c9d 100644
|
|
--- a/drivers/clk/rockchip/clk-rk3036.c
|
|
+++ b/drivers/clk/rockchip/clk-rk3036.c
|
|
@@ -16,6 +16,9 @@
|
|
#include "clk.h"
|
|
|
|
#define RK3036_GRF_SOC_STATUS0 0x14c
|
|
+#define RK3036_UART_FRAC_MAX_PRATE 600000000
|
|
+#define RK3036_I2S_FRAC_MAX_PRATE 600000000
|
|
+#define RK3036_SPDIF_FRAC_MAX_PRATE 600000000
|
|
|
|
enum rk3036_plls {
|
|
apll, dpll, gpll,
|
|
@@ -248,15 +251,15 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT,
|
|
RK2928_CLKSEL_CON(17), 0,
|
|
RK2928_CLKGATE_CON(1), 9, GFLAGS,
|
|
- &rk3036_uart0_fracmux),
|
|
+ &rk3036_uart0_fracmux, RK3036_UART_FRAC_MAX_PRATE),
|
|
COMPOSITE_FRACMUX(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT,
|
|
RK2928_CLKSEL_CON(18), 0,
|
|
RK2928_CLKGATE_CON(1), 11, GFLAGS,
|
|
- &rk3036_uart1_fracmux),
|
|
+ &rk3036_uart1_fracmux, RK3036_UART_FRAC_MAX_PRATE),
|
|
COMPOSITE_FRACMUX(0, "uart2_frac", "uart2_src", CLK_SET_RATE_PARENT,
|
|
RK2928_CLKSEL_CON(19), 0,
|
|
RK2928_CLKGATE_CON(1), 13, GFLAGS,
|
|
- &rk3036_uart2_fracmux),
|
|
+ &rk3036_uart2_fracmux, RK3036_UART_FRAC_MAX_PRATE),
|
|
|
|
COMPOSITE(0, "aclk_vcodec", mux_pll_src_3plls_p, 0,
|
|
RK2928_CLKSEL_CON(32), 14, 2, MFLAGS, 8, 5, DFLAGS,
|
|
@@ -309,7 +312,7 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "i2s_frac", "i2s_src", CLK_SET_RATE_PARENT,
|
|
RK2928_CLKSEL_CON(7), 0,
|
|
RK2928_CLKGATE_CON(0), 10, GFLAGS,
|
|
- &rk3036_i2s_fracmux),
|
|
+ &rk3036_i2s_fracmux, RK3036_I2S_FRAC_MAX_PRATE),
|
|
COMPOSITE_NODIV(SCLK_I2S_OUT, "i2s_clkout", mux_i2s_clkout_p, 0,
|
|
RK2928_CLKSEL_CON(3), 12, 1, MFLAGS,
|
|
RK2928_CLKGATE_CON(0), 13, GFLAGS),
|
|
@@ -322,7 +325,7 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "spdif_frac", "spdif_src", 0,
|
|
RK2928_CLKSEL_CON(9), 0,
|
|
RK2928_CLKGATE_CON(2), 12, GFLAGS,
|
|
- &rk3036_spdif_fracmux),
|
|
+ &rk3036_spdif_fracmux, RK3036_SPDIF_FRAC_MAX_PRATE),
|
|
|
|
GATE(SCLK_OTGPHY0, "sclk_otgphy0", "xin12m", CLK_IGNORE_UNUSED,
|
|
RK2928_CLKGATE_CON(1), 5, GFLAGS),
|
|
diff --git a/drivers/clk/rockchip/clk-rk3128.c b/drivers/clk/rockchip/clk-rk3128.c
|
|
index 4b1122e98e16..9eecd56d06db 100644
|
|
--- a/drivers/clk/rockchip/clk-rk3128.c
|
|
+++ b/drivers/clk/rockchip/clk-rk3128.c
|
|
@@ -13,6 +13,9 @@
|
|
#include "clk.h"
|
|
|
|
#define RK3128_GRF_SOC_STATUS0 0x14c
|
|
+#define RK3128_UART_FRAC_MAX_PRATE 600000000
|
|
+#define RK3128_I2S_FRAC_MAX_PRATE 600000000
|
|
+#define RK3128_SPDIF_FRAC_MAX_PRATE 600000000
|
|
|
|
enum rk3128_plls {
|
|
apll, dpll, cpll, gpll,
|
|
@@ -359,7 +362,7 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "i2s0_frac", "i2s0_src", CLK_SET_RATE_PARENT,
|
|
RK2928_CLKSEL_CON(8), 0,
|
|
RK2928_CLKGATE_CON(4), 5, GFLAGS,
|
|
- &rk3128_i2s0_fracmux),
|
|
+ &rk3128_i2s0_fracmux, RK3128_I2S_FRAC_MAX_PRATE),
|
|
GATE(SCLK_I2S0, "sclk_i2s0", "i2s0_pre", CLK_SET_RATE_PARENT,
|
|
RK2928_CLKGATE_CON(4), 6, GFLAGS),
|
|
|
|
@@ -369,7 +372,7 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "i2s1_frac", "i2s1_src", CLK_SET_RATE_PARENT,
|
|
RK2928_CLKSEL_CON(7), 0,
|
|
RK2928_CLKGATE_CON(0), 10, GFLAGS,
|
|
- &rk3128_i2s1_fracmux),
|
|
+ &rk3128_i2s1_fracmux, RK3128_I2S_FRAC_MAX_PRATE),
|
|
GATE(SCLK_I2S1, "sclk_i2s1", "i2s1_pre", CLK_SET_RATE_PARENT,
|
|
RK2928_CLKGATE_CON(0), 14, GFLAGS),
|
|
COMPOSITE_NODIV(SCLK_I2S_OUT, "i2s_out", mux_i2s_out_p, 0,
|
|
@@ -382,7 +385,7 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "spdif_frac", "sclk_spdif_src", CLK_SET_RATE_PARENT,
|
|
RK2928_CLKSEL_CON(20), 0,
|
|
RK2928_CLKGATE_CON(2), 12, GFLAGS,
|
|
- &rk3128_spdif_fracmux),
|
|
+ &rk3128_spdif_fracmux, RK3128_SPDIF_FRAC_MAX_PRATE),
|
|
|
|
GATE(0, "jtag", "ext_jtag", CLK_IGNORE_UNUSED,
|
|
RK2928_CLKGATE_CON(1), 3, GFLAGS),
|
|
@@ -419,15 +422,15 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT,
|
|
RK2928_CLKSEL_CON(17), 0,
|
|
RK2928_CLKGATE_CON(1), 9, GFLAGS,
|
|
- &rk3128_uart0_fracmux),
|
|
+ &rk3128_uart0_fracmux, RK3128_UART_FRAC_MAX_PRATE),
|
|
COMPOSITE_FRACMUX(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT,
|
|
RK2928_CLKSEL_CON(18), 0,
|
|
RK2928_CLKGATE_CON(1), 11, GFLAGS,
|
|
- &rk3128_uart1_fracmux),
|
|
+ &rk3128_uart1_fracmux, RK3128_UART_FRAC_MAX_PRATE),
|
|
COMPOSITE_FRACMUX(0, "uart2_frac", "uart2_src", CLK_SET_RATE_PARENT,
|
|
RK2928_CLKSEL_CON(19), 0,
|
|
RK2928_CLKGATE_CON(1), 13, GFLAGS,
|
|
- &rk3128_uart2_fracmux),
|
|
+ &rk3128_uart2_fracmux, RK3128_UART_FRAC_MAX_PRATE),
|
|
|
|
COMPOSITE(SCLK_MAC_SRC, "sclk_gmac_src", mux_pll_src_3plls_p, 0,
|
|
RK2928_CLKSEL_CON(5), 6, 2, MFLAGS, 0, 5, DFLAGS,
|
|
diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c
|
|
index 0b76ad34de00..78c3d0c80edf 100644
|
|
--- a/drivers/clk/rockchip/clk-rk3188.c
|
|
+++ b/drivers/clk/rockchip/clk-rk3188.c
|
|
@@ -14,6 +14,10 @@
|
|
|
|
#define RK3066_GRF_SOC_STATUS 0x15c
|
|
#define RK3188_GRF_SOC_STATUS 0xac
|
|
+#define RK3188_UART_FRAC_MAX_PRATE 600000000
|
|
+#define RK3188_I2S_FRAC_MAX_PRATE 600000000
|
|
+#define RK3188_SPDIF_FRAC_MAX_PRATE 600000000
|
|
+#define RK3188_HSADC_FRAC_MAX_PRATE 300000000
|
|
|
|
enum rk3188_plls {
|
|
apll, cpll, dpll, gpll,
|
|
@@ -363,7 +367,7 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "hsadc_frac", "hsadc_src", 0,
|
|
RK2928_CLKSEL_CON(23), 0,
|
|
RK2928_CLKGATE_CON(2), 7, GFLAGS,
|
|
- &common_hsadc_out_fracmux),
|
|
+ &common_hsadc_out_fracmux, RK3188_HSADC_FRAC_MAX_PRATE),
|
|
INVERTER(SCLK_HSADC, "sclk_hsadc", "sclk_hsadc_out",
|
|
RK2928_CLKSEL_CON(22), 7, IFLAGS),
|
|
|
|
@@ -377,7 +381,7 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "spdif_frac", "spdif_pre", CLK_SET_RATE_PARENT,
|
|
RK2928_CLKSEL_CON(9), 0,
|
|
RK2928_CLKGATE_CON(0), 14, GFLAGS,
|
|
- &common_spdif_fracmux),
|
|
+ &common_spdif_fracmux, RK3188_SPDIF_FRAC_MAX_PRATE),
|
|
|
|
/*
|
|
* Clock-Architecture Diagram 4
|
|
@@ -411,28 +415,28 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_pre", CLK_SET_RATE_PARENT,
|
|
RK2928_CLKSEL_CON(17), 0,
|
|
RK2928_CLKGATE_CON(1), 9, GFLAGS,
|
|
- &common_uart0_fracmux),
|
|
+ &common_uart0_fracmux, RK3188_UART_FRAC_MAX_PRATE),
|
|
COMPOSITE_NOMUX(0, "uart1_pre", "uart_src", 0,
|
|
RK2928_CLKSEL_CON(14), 0, 7, DFLAGS,
|
|
RK2928_CLKGATE_CON(1), 10, GFLAGS),
|
|
COMPOSITE_FRACMUX(0, "uart1_frac", "uart1_pre", CLK_SET_RATE_PARENT,
|
|
RK2928_CLKSEL_CON(18), 0,
|
|
RK2928_CLKGATE_CON(1), 11, GFLAGS,
|
|
- &common_uart1_fracmux),
|
|
+ &common_uart1_fracmux, RK3188_UART_FRAC_MAX_PRATE),
|
|
COMPOSITE_NOMUX(0, "uart2_pre", "uart_src", 0,
|
|
RK2928_CLKSEL_CON(15), 0, 7, DFLAGS,
|
|
RK2928_CLKGATE_CON(1), 12, GFLAGS),
|
|
COMPOSITE_FRACMUX(0, "uart2_frac", "uart2_pre", CLK_SET_RATE_PARENT,
|
|
RK2928_CLKSEL_CON(19), 0,
|
|
RK2928_CLKGATE_CON(1), 13, GFLAGS,
|
|
- &common_uart2_fracmux),
|
|
+ &common_uart2_fracmux, RK3188_UART_FRAC_MAX_PRATE),
|
|
COMPOSITE_NOMUX(0, "uart3_pre", "uart_src", 0,
|
|
RK2928_CLKSEL_CON(16), 0, 7, DFLAGS,
|
|
RK2928_CLKGATE_CON(1), 14, GFLAGS),
|
|
COMPOSITE_FRACMUX(0, "uart3_frac", "uart3_pre", CLK_SET_RATE_PARENT,
|
|
RK2928_CLKSEL_CON(20), 0,
|
|
RK2928_CLKGATE_CON(1), 15, GFLAGS,
|
|
- &common_uart3_fracmux),
|
|
+ &common_uart3_fracmux, RK3188_UART_FRAC_MAX_PRATE),
|
|
|
|
GATE(SCLK_JTAG, "jtag", "ext_jtag", 0, RK2928_CLKGATE_CON(1), 3, GFLAGS),
|
|
|
|
@@ -617,21 +621,21 @@ static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "i2s0_frac", "i2s0_pre", CLK_SET_RATE_PARENT,
|
|
RK2928_CLKSEL_CON(6), 0,
|
|
RK2928_CLKGATE_CON(0), 8, GFLAGS,
|
|
- &rk3066a_i2s0_fracmux),
|
|
+ &rk3066a_i2s0_fracmux, RK3188_I2S_FRAC_MAX_PRATE),
|
|
COMPOSITE_NOMUX(0, "i2s1_pre", "i2s_src", 0,
|
|
RK2928_CLKSEL_CON(3), 0, 7, DFLAGS,
|
|
RK2928_CLKGATE_CON(0), 9, GFLAGS),
|
|
COMPOSITE_FRACMUX(0, "i2s1_frac", "i2s1_pre", CLK_SET_RATE_PARENT,
|
|
RK2928_CLKSEL_CON(7), 0,
|
|
RK2928_CLKGATE_CON(0), 10, GFLAGS,
|
|
- &rk3066a_i2s1_fracmux),
|
|
+ &rk3066a_i2s1_fracmux, RK3188_I2S_FRAC_MAX_PRATE),
|
|
COMPOSITE_NOMUX(0, "i2s2_pre", "i2s_src", 0,
|
|
RK2928_CLKSEL_CON(4), 0, 7, DFLAGS,
|
|
RK2928_CLKGATE_CON(0), 11, GFLAGS),
|
|
COMPOSITE_FRACMUX(0, "i2s2_frac", "i2s2_pre", CLK_SET_RATE_PARENT,
|
|
RK2928_CLKSEL_CON(8), 0,
|
|
RK2928_CLKGATE_CON(0), 12, GFLAGS,
|
|
- &rk3066a_i2s2_fracmux),
|
|
+ &rk3066a_i2s2_fracmux, RK3188_I2S_FRAC_MAX_PRATE),
|
|
|
|
GATE(HCLK_I2S0, "hclk_i2s0", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 4, GFLAGS),
|
|
GATE(HCLK_I2S1, "hclk_i2s1", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 2, GFLAGS),
|
|
@@ -726,7 +730,7 @@ static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "i2s0_frac", "i2s0_pre", CLK_SET_RATE_PARENT,
|
|
RK2928_CLKSEL_CON(7), 0,
|
|
RK2928_CLKGATE_CON(0), 10, GFLAGS,
|
|
- &rk3188_i2s0_fracmux),
|
|
+ &rk3188_i2s0_fracmux, RK3188_I2S_FRAC_MAX_PRATE),
|
|
|
|
GATE(HCLK_I2S0, "hclk_i2s0", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 2, GFLAGS),
|
|
GATE(0, "hclk_imem0", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 14, GFLAGS),
|
|
diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c
|
|
index 47d6482dda9d..c1ef00247e26 100644
|
|
--- a/drivers/clk/rockchip/clk-rk3228.c
|
|
+++ b/drivers/clk/rockchip/clk-rk3228.c
|
|
@@ -15,6 +15,10 @@
|
|
|
|
#define RK3228_GRF_SOC_STATUS0 0x480
|
|
|
|
+#define RK3228_UART_FRAC_MAX_PRATE 600000000
|
|
+#define RK3228_SPDIF_FRAC_MAX_PRATE 600000000
|
|
+#define RK3228_I2S_FRAC_MAX_PRATE 600000000
|
|
+
|
|
enum rk3228_plls {
|
|
apll, dpll, cpll, gpll,
|
|
};
|
|
@@ -419,7 +423,7 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "i2s0_frac", "i2s0_src", CLK_SET_RATE_PARENT,
|
|
RK2928_CLKSEL_CON(8), 0,
|
|
RK2928_CLKGATE_CON(0), 4, GFLAGS,
|
|
- &rk3228_i2s0_fracmux),
|
|
+ &rk3228_i2s0_fracmux, RK3228_I2S_FRAC_MAX_PRATE),
|
|
GATE(SCLK_I2S0, "sclk_i2s0", "i2s0_pre", CLK_SET_RATE_PARENT,
|
|
RK2928_CLKGATE_CON(0), 5, GFLAGS),
|
|
|
|
@@ -429,7 +433,7 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "i2s1_frac", "i2s1_src", CLK_SET_RATE_PARENT,
|
|
RK2928_CLKSEL_CON(7), 0,
|
|
RK2928_CLKGATE_CON(0), 11, GFLAGS,
|
|
- &rk3228_i2s1_fracmux),
|
|
+ &rk3228_i2s1_fracmux, RK3228_I2S_FRAC_MAX_PRATE),
|
|
GATE(SCLK_I2S1, "sclk_i2s1", "i2s1_pre", CLK_SET_RATE_PARENT,
|
|
RK2928_CLKGATE_CON(0), 14, GFLAGS),
|
|
COMPOSITE_NODIV(SCLK_I2S_OUT, "i2s_out", mux_i2s_out_p, 0,
|
|
@@ -442,7 +446,7 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "i2s2_frac", "i2s2_src", CLK_SET_RATE_PARENT,
|
|
RK2928_CLKSEL_CON(30), 0,
|
|
RK2928_CLKGATE_CON(0), 8, GFLAGS,
|
|
- &rk3228_i2s2_fracmux),
|
|
+ &rk3228_i2s2_fracmux, RK3228_I2S_FRAC_MAX_PRATE),
|
|
GATE(SCLK_I2S2, "sclk_i2s2", "i2s2_pre", CLK_SET_RATE_PARENT,
|
|
RK2928_CLKGATE_CON(0), 9, GFLAGS),
|
|
|
|
@@ -452,7 +456,7 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "spdif_frac", "sclk_spdif_src", CLK_SET_RATE_PARENT,
|
|
RK2928_CLKSEL_CON(20), 0,
|
|
RK2928_CLKGATE_CON(2), 12, GFLAGS,
|
|
- &rk3228_spdif_fracmux),
|
|
+ &rk3228_spdif_fracmux, RK3228_SPDIF_FRAC_MAX_PRATE),
|
|
|
|
GATE(0, "jtag", "ext_jtag", CLK_IGNORE_UNUSED,
|
|
RK2928_CLKGATE_CON(1), 3, GFLAGS),
|
|
@@ -487,15 +491,15 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT,
|
|
RK2928_CLKSEL_CON(17), 0,
|
|
RK2928_CLKGATE_CON(1), 9, GFLAGS,
|
|
- &rk3228_uart0_fracmux),
|
|
+ &rk3228_uart0_fracmux, RK3228_UART_FRAC_MAX_PRATE),
|
|
COMPOSITE_FRACMUX(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT,
|
|
RK2928_CLKSEL_CON(18), 0,
|
|
RK2928_CLKGATE_CON(1), 11, GFLAGS,
|
|
- &rk3228_uart1_fracmux),
|
|
+ &rk3228_uart1_fracmux, RK3228_UART_FRAC_MAX_PRATE),
|
|
COMPOSITE_FRACMUX(0, "uart2_frac", "uart2_src", CLK_SET_RATE_PARENT,
|
|
RK2928_CLKSEL_CON(19), 0,
|
|
RK2928_CLKGATE_CON(1), 13, GFLAGS,
|
|
- &rk3228_uart2_fracmux),
|
|
+ &rk3228_uart2_fracmux, RK3228_UART_FRAC_MAX_PRATE),
|
|
|
|
COMPOSITE(SCLK_NANDC, "sclk_nandc", mux_pll_src_2plls_p, 0,
|
|
RK2928_CLKSEL_CON(2), 14, 1, MFLAGS, 8, 5, DFLAGS,
|
|
diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c
|
|
index 93c794695c46..15c8f1dcba9a 100644
|
|
--- a/drivers/clk/rockchip/clk-rk3288.c
|
|
+++ b/drivers/clk/rockchip/clk-rk3288.c
|
|
@@ -14,6 +14,9 @@
|
|
|
|
#define RK3288_GRF_SOC_CON(x) (0x244 + x * 4)
|
|
#define RK3288_GRF_SOC_STATUS1 0x284
|
|
+#define RK3288_UART_FRAC_MAX_PRATE 600000000
|
|
+#define RK3288_I2S_FRAC_MAX_PRATE 600000000
|
|
+#define RK3288_SPDIF_FRAC_MAX_PRATE 600000000
|
|
|
|
enum rk3288_variant {
|
|
RK3288_CRU,
|
|
@@ -362,7 +365,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "i2s_frac", "i2s_src", CLK_SET_RATE_PARENT,
|
|
RK3288_CLKSEL_CON(8), 0,
|
|
RK3288_CLKGATE_CON(4), 2, GFLAGS,
|
|
- &rk3288_i2s_fracmux),
|
|
+ &rk3288_i2s_fracmux, RK3288_I2S_FRAC_MAX_PRATE),
|
|
COMPOSITE_NODIV(SCLK_I2S0_OUT, "i2s0_clkout", mux_i2s_clkout_p, 0,
|
|
RK3288_CLKSEL_CON(4), 12, 1, MFLAGS,
|
|
RK3288_CLKGATE_CON(4), 0, GFLAGS),
|
|
@@ -377,7 +380,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "spdif_frac", "spdif_src", CLK_SET_RATE_PARENT,
|
|
RK3288_CLKSEL_CON(9), 0,
|
|
RK3288_CLKGATE_CON(4), 5, GFLAGS,
|
|
- &rk3288_spdif_fracmux),
|
|
+ &rk3288_spdif_fracmux, RK3288_SPDIF_FRAC_MAX_PRATE),
|
|
GATE(SCLK_SPDIF, "sclk_spdif", "spdif_mux", CLK_SET_RATE_PARENT,
|
|
RK3288_CLKGATE_CON(4), 6, GFLAGS),
|
|
COMPOSITE_NOMUX(0, "spdif_8ch_pre", "spdif_src", CLK_SET_RATE_PARENT,
|
|
@@ -386,7 +389,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "spdif_8ch_frac", "spdif_8ch_pre", CLK_SET_RATE_PARENT,
|
|
RK3288_CLKSEL_CON(41), 0,
|
|
RK3288_CLKGATE_CON(4), 8, GFLAGS,
|
|
- &rk3288_spdif_8ch_fracmux),
|
|
+ &rk3288_spdif_8ch_fracmux, RK3288_SPDIF_FRAC_MAX_PRATE),
|
|
GATE(SCLK_SPDIF8CH, "sclk_spdif_8ch", "spdif_8ch_mux", CLK_SET_RATE_PARENT,
|
|
RK3288_CLKGATE_CON(4), 9, GFLAGS),
|
|
|
|
@@ -587,7 +590,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT,
|
|
RK3288_CLKSEL_CON(17), 0,
|
|
RK3288_CLKGATE_CON(1), 9, GFLAGS,
|
|
- &rk3288_uart0_fracmux),
|
|
+ &rk3288_uart0_fracmux, RK3288_UART_FRAC_MAX_PRATE),
|
|
MUX(0, "uart_src", mux_pll_src_cpll_gpll_p, 0,
|
|
RK3288_CLKSEL_CON(13), 15, 1, MFLAGS),
|
|
COMPOSITE_NOMUX(0, "uart1_src", "uart_src", 0,
|
|
@@ -596,28 +599,28 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT,
|
|
RK3288_CLKSEL_CON(18), 0,
|
|
RK3288_CLKGATE_CON(1), 11, GFLAGS,
|
|
- &rk3288_uart1_fracmux),
|
|
+ &rk3288_uart1_fracmux, RK3288_UART_FRAC_MAX_PRATE),
|
|
COMPOSITE_NOMUX(0, "uart2_src", "uart_src", 0,
|
|
RK3288_CLKSEL_CON(15), 0, 7, DFLAGS,
|
|
RK3288_CLKGATE_CON(1), 12, GFLAGS),
|
|
COMPOSITE_FRACMUX(0, "uart2_frac", "uart2_src", CLK_SET_RATE_PARENT,
|
|
RK3288_CLKSEL_CON(19), 0,
|
|
RK3288_CLKGATE_CON(1), 13, GFLAGS,
|
|
- &rk3288_uart2_fracmux),
|
|
+ &rk3288_uart2_fracmux, RK3288_UART_FRAC_MAX_PRATE),
|
|
COMPOSITE_NOMUX(0, "uart3_src", "uart_src", 0,
|
|
RK3288_CLKSEL_CON(16), 0, 7, DFLAGS,
|
|
RK3288_CLKGATE_CON(1), 14, GFLAGS),
|
|
COMPOSITE_FRACMUX(0, "uart3_frac", "uart3_src", CLK_SET_RATE_PARENT,
|
|
RK3288_CLKSEL_CON(20), 0,
|
|
RK3288_CLKGATE_CON(1), 15, GFLAGS,
|
|
- &rk3288_uart3_fracmux),
|
|
+ &rk3288_uart3_fracmux, RK3288_UART_FRAC_MAX_PRATE),
|
|
COMPOSITE_NOMUX(0, "uart4_src", "uart_src", 0,
|
|
RK3288_CLKSEL_CON(3), 0, 7, DFLAGS,
|
|
RK3288_CLKGATE_CON(2), 12, GFLAGS),
|
|
COMPOSITE_FRACMUX(0, "uart4_frac", "uart4_src", CLK_SET_RATE_PARENT,
|
|
RK3288_CLKSEL_CON(7), 0,
|
|
RK3288_CLKGATE_CON(2), 13, GFLAGS,
|
|
- &rk3288_uart4_fracmux),
|
|
+ &rk3288_uart4_fracmux, RK3288_UART_FRAC_MAX_PRATE),
|
|
|
|
COMPOSITE(0, "mac_pll_src", mux_pll_src_npll_cpll_gpll_p, 0,
|
|
RK3288_CLKSEL_CON(21), 0, 2, MFLAGS, 8, 5, DFLAGS,
|
|
diff --git a/drivers/clk/rockchip/clk-rk3308.c b/drivers/clk/rockchip/clk-rk3308.c
|
|
index 5bf15f2a44b7..f7cf9b61eec2 100644
|
|
--- a/drivers/clk/rockchip/clk-rk3308.c
|
|
+++ b/drivers/clk/rockchip/clk-rk3308.c
|
|
@@ -13,6 +13,12 @@
|
|
#include "clk.h"
|
|
|
|
#define RK3308_GRF_SOC_STATUS0 0x380
|
|
+#define RK3308_VOP_FRAC_MAX_PRATE 270000000
|
|
+#define RK3308B_VOP_FRAC_MAX_PRATE 800000000
|
|
+#define RK3308_UART_FRAC_MAX_PRATE 800000000
|
|
+#define RK3308_PDM_FRAC_MAX_PRATE 800000000
|
|
+#define RK3308_SPDIF_FRAC_MAX_PRATE 800000000
|
|
+#define RK3308_I2S_FRAC_MAX_PRATE 800000000
|
|
|
|
enum rk3308_plls {
|
|
apll, dpll, vpll0, vpll1,
|
|
@@ -332,7 +338,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_uart0_frac", "clk_uart0_src", CLK_SET_RATE_PARENT,
|
|
RK3308_CLKSEL_CON(12), 0,
|
|
RK3308_CLKGATE_CON(1), 11, GFLAGS,
|
|
- &rk3308_uart0_fracmux),
|
|
+ &rk3308_uart0_fracmux, RK3308_UART_FRAC_MAX_PRATE),
|
|
GATE(SCLK_UART0, "clk_uart0", "clk_uart0_mux", 0,
|
|
RK3308_CLKGATE_CON(1), 12, GFLAGS),
|
|
|
|
@@ -342,7 +348,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_uart1_frac", "clk_uart1_src", CLK_SET_RATE_PARENT,
|
|
RK3308_CLKSEL_CON(15), 0,
|
|
RK3308_CLKGATE_CON(1), 15, GFLAGS,
|
|
- &rk3308_uart1_fracmux),
|
|
+ &rk3308_uart1_fracmux, RK3308_UART_FRAC_MAX_PRATE),
|
|
GATE(SCLK_UART1, "clk_uart1", "clk_uart1_mux", 0,
|
|
RK3308_CLKGATE_CON(2), 0, GFLAGS),
|
|
|
|
@@ -352,7 +358,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_uart2_frac", "clk_uart2_src", CLK_SET_RATE_PARENT,
|
|
RK3308_CLKSEL_CON(18), 0,
|
|
RK3308_CLKGATE_CON(2), 3, GFLAGS,
|
|
- &rk3308_uart2_fracmux),
|
|
+ &rk3308_uart2_fracmux, RK3308_UART_FRAC_MAX_PRATE),
|
|
GATE(SCLK_UART2, "clk_uart2", "clk_uart2_mux", CLK_SET_RATE_PARENT,
|
|
RK3308_CLKGATE_CON(2), 4, GFLAGS),
|
|
|
|
@@ -362,7 +368,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_uart3_frac", "clk_uart3_src", CLK_SET_RATE_PARENT,
|
|
RK3308_CLKSEL_CON(21), 0,
|
|
RK3308_CLKGATE_CON(2), 7, GFLAGS,
|
|
- &rk3308_uart3_fracmux),
|
|
+ &rk3308_uart3_fracmux, RK3308_UART_FRAC_MAX_PRATE),
|
|
GATE(SCLK_UART3, "clk_uart3", "clk_uart3_mux", 0,
|
|
RK3308_CLKGATE_CON(2), 8, GFLAGS),
|
|
|
|
@@ -372,7 +378,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_uart4_frac", "clk_uart4_src", CLK_SET_RATE_PARENT,
|
|
RK3308_CLKSEL_CON(24), 0,
|
|
RK3308_CLKGATE_CON(2), 11, GFLAGS,
|
|
- &rk3308_uart4_fracmux),
|
|
+ &rk3308_uart4_fracmux, RK3308_UART_FRAC_MAX_PRATE),
|
|
GATE(SCLK_UART4, "clk_uart4", "clk_uart4_mux", 0,
|
|
RK3308_CLKGATE_CON(2), 12, GFLAGS),
|
|
|
|
@@ -452,7 +458,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "dclk_vop_frac", "dclk_vop_src", CLK_SET_RATE_PARENT,
|
|
RK3308_CLKSEL_CON(9), 0,
|
|
RK3308_CLKGATE_CON(1), 7, GFLAGS,
|
|
- &rk3308_dclk_vop_fracmux),
|
|
+ &rk3308_dclk_vop_fracmux, RK3308B_VOP_FRAC_MAX_PRATE),
|
|
GATE(DCLK_VOP, "dclk_vop", "dclk_vop_mux", 0,
|
|
RK3308_CLKGATE_CON(1), 8, GFLAGS),
|
|
|
|
@@ -583,7 +589,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_rtc32k_frac", "xin24m", CLK_IGNORE_UNUSED,
|
|
RK3308_CLKSEL_CON(3), 0,
|
|
RK3308_CLKGATE_CON(4), 3, GFLAGS,
|
|
- &rk3308_rtc32k_fracmux),
|
|
+ &rk3308_rtc32k_fracmux, 0),
|
|
MUX(0, "clk_rtc32k_div_src", mux_vpll0_vpll1_p, 0,
|
|
RK3308_CLKSEL_CON(2), 10, 1, MFLAGS),
|
|
COMPOSITE_NOMUX(0, "clk_rtc32k_div", "clk_rtc32k_div_src", CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT,
|
|
@@ -633,7 +639,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_pdm_frac", "clk_pdm_src", CLK_SET_RATE_PARENT,
|
|
RK3308_CLKSEL_CON(47), 0,
|
|
RK3308_CLKGATE_CON(10), 4, GFLAGS,
|
|
- &rk3308_pdm_fracmux),
|
|
+ &rk3308_pdm_fracmux, RK3308_PDM_FRAC_MAX_PRATE),
|
|
GATE(SCLK_PDM, "clk_pdm", "clk_pdm_mux", 0,
|
|
RK3308_CLKGATE_CON(10), 5, GFLAGS),
|
|
|
|
@@ -643,7 +649,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_i2s0_8ch_tx_frac", "clk_i2s0_8ch_tx_src", CLK_SET_RATE_PARENT,
|
|
RK3308_CLKSEL_CON(53), 0,
|
|
RK3308_CLKGATE_CON(10), 13, GFLAGS,
|
|
- &rk3308_i2s0_8ch_tx_fracmux),
|
|
+ &rk3308_i2s0_8ch_tx_fracmux, RK3308_I2S_FRAC_MAX_PRATE),
|
|
COMPOSITE_NODIV(SCLK_I2S0_8CH_TX, "clk_i2s0_8ch_tx", mux_i2s0_8ch_tx_rx_p, CLK_SET_RATE_PARENT,
|
|
RK3308_CLKSEL_CON(52), 12, 1, MFLAGS,
|
|
RK3308_CLKGATE_CON(10), 14, GFLAGS),
|
|
@@ -657,7 +663,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_i2s0_8ch_rx_frac", "clk_i2s0_8ch_rx_src", CLK_SET_RATE_PARENT,
|
|
RK3308_CLKSEL_CON(55), 0,
|
|
RK3308_CLKGATE_CON(11), 1, GFLAGS,
|
|
- &rk3308_i2s0_8ch_rx_fracmux),
|
|
+ &rk3308_i2s0_8ch_rx_fracmux, RK3308_I2S_FRAC_MAX_PRATE),
|
|
COMPOSITE_NODIV(SCLK_I2S0_8CH_RX, "clk_i2s0_8ch_rx", mux_i2s0_8ch_rx_tx_p, CLK_SET_RATE_PARENT,
|
|
RK3308_CLKSEL_CON(54), 12, 1, MFLAGS,
|
|
RK3308_CLKGATE_CON(11), 2, GFLAGS),
|
|
@@ -670,7 +676,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_i2s1_8ch_tx_frac", "clk_i2s1_8ch_tx_src", CLK_SET_RATE_PARENT,
|
|
RK3308_CLKSEL_CON(57), 0,
|
|
RK3308_CLKGATE_CON(11), 5, GFLAGS,
|
|
- &rk3308_i2s1_8ch_tx_fracmux),
|
|
+ &rk3308_i2s1_8ch_tx_fracmux, RK3308_I2S_FRAC_MAX_PRATE),
|
|
COMPOSITE_NODIV(SCLK_I2S1_8CH_TX, "clk_i2s1_8ch_tx", mux_i2s1_8ch_tx_rx_p, CLK_SET_RATE_PARENT,
|
|
RK3308_CLKSEL_CON(56), 12, 1, MFLAGS,
|
|
RK3308_CLKGATE_CON(11), 6, GFLAGS),
|
|
@@ -684,7 +690,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_i2s1_8ch_rx_frac", "clk_i2s1_8ch_rx_src", CLK_SET_RATE_PARENT,
|
|
RK3308_CLKSEL_CON(59), 0,
|
|
RK3308_CLKGATE_CON(11), 9, GFLAGS,
|
|
- &rk3308_i2s1_8ch_rx_fracmux),
|
|
+ &rk3308_i2s1_8ch_rx_fracmux, RK3308_I2S_FRAC_MAX_PRATE),
|
|
COMPOSITE_NODIV(SCLK_I2S1_8CH_RX, "clk_i2s1_8ch_rx", mux_i2s1_8ch_rx_tx_p, CLK_SET_RATE_PARENT,
|
|
RK3308_CLKSEL_CON(58), 12, 1, MFLAGS,
|
|
RK3308_CLKGATE_CON(11), 10, GFLAGS),
|
|
@@ -697,7 +703,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_i2s2_8ch_tx_frac", "clk_i2s2_8ch_tx_src", CLK_SET_RATE_PARENT,
|
|
RK3308_CLKSEL_CON(61), 0,
|
|
RK3308_CLKGATE_CON(11), 13, GFLAGS,
|
|
- &rk3308_i2s2_8ch_tx_fracmux),
|
|
+ &rk3308_i2s2_8ch_tx_fracmux, RK3308_I2S_FRAC_MAX_PRATE),
|
|
COMPOSITE_NODIV(SCLK_I2S2_8CH_TX, "clk_i2s2_8ch_tx", mux_i2s2_8ch_tx_rx_p, CLK_SET_RATE_PARENT,
|
|
RK3308_CLKSEL_CON(60), 12, 1, MFLAGS,
|
|
RK3308_CLKGATE_CON(11), 14, GFLAGS),
|
|
@@ -711,7 +717,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_i2s2_8ch_rx_frac", "clk_i2s2_8ch_rx_src", CLK_SET_RATE_PARENT,
|
|
RK3308_CLKSEL_CON(63), 0,
|
|
RK3308_CLKGATE_CON(12), 1, GFLAGS,
|
|
- &rk3308_i2s2_8ch_rx_fracmux),
|
|
+ &rk3308_i2s2_8ch_rx_fracmux, RK3308_I2S_FRAC_MAX_PRATE),
|
|
COMPOSITE_NODIV(SCLK_I2S2_8CH_RX, "clk_i2s2_8ch_rx", mux_i2s2_8ch_rx_tx_p, CLK_SET_RATE_PARENT,
|
|
RK3308_CLKSEL_CON(62), 12, 1, MFLAGS,
|
|
RK3308_CLKGATE_CON(12), 2, GFLAGS),
|
|
@@ -724,7 +730,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_i2s3_8ch_tx_frac", "clk_i2s3_8ch_tx_src", CLK_SET_RATE_PARENT,
|
|
RK3308_CLKSEL_CON(65), 0,
|
|
RK3308_CLKGATE_CON(12), 5, GFLAGS,
|
|
- &rk3308_i2s3_8ch_tx_fracmux),
|
|
+ &rk3308_i2s3_8ch_tx_fracmux, RK3308_I2S_FRAC_MAX_PRATE),
|
|
COMPOSITE_NODIV(SCLK_I2S3_8CH_TX, "clk_i2s3_8ch_tx", mux_i2s3_8ch_tx_rx_p, CLK_SET_RATE_PARENT,
|
|
RK3308_CLKSEL_CON(64), 12, 1, MFLAGS,
|
|
RK3308_CLKGATE_CON(12), 6, GFLAGS),
|
|
@@ -738,7 +744,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_i2s3_8ch_rx_frac", "clk_i2s3_8ch_rx_src", CLK_SET_RATE_PARENT,
|
|
RK3308_CLKSEL_CON(67), 0,
|
|
RK3308_CLKGATE_CON(12), 9, GFLAGS,
|
|
- &rk3308_i2s3_8ch_rx_fracmux),
|
|
+ &rk3308_i2s3_8ch_rx_fracmux, RK3308_I2S_FRAC_MAX_PRATE),
|
|
COMPOSITE_NODIV(SCLK_I2S3_8CH_RX, "clk_i2s3_8ch_rx", mux_i2s3_8ch_rx_tx_p, CLK_SET_RATE_PARENT,
|
|
RK3308_CLKSEL_CON(66), 12, 1, MFLAGS,
|
|
RK3308_CLKGATE_CON(12), 10, GFLAGS),
|
|
@@ -751,7 +757,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_i2s0_2ch_frac", "clk_i2s0_2ch_src", CLK_SET_RATE_PARENT,
|
|
RK3308_CLKSEL_CON(69), 0,
|
|
RK3308_CLKGATE_CON(12), 13, GFLAGS,
|
|
- &rk3308_i2s0_2ch_fracmux),
|
|
+ &rk3308_i2s0_2ch_fracmux, RK3308_I2S_FRAC_MAX_PRATE),
|
|
GATE(SCLK_I2S0_2CH, "clk_i2s0_2ch", "clk_i2s0_2ch_mux", 0,
|
|
RK3308_CLKGATE_CON(12), 14, GFLAGS),
|
|
COMPOSITE_NODIV(SCLK_I2S0_2CH_OUT, "clk_i2s0_2ch_out", mux_i2s0_2ch_out_p, CLK_SET_RATE_PARENT,
|
|
@@ -764,7 +770,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_i2s1_2ch_frac", "clk_i2s1_2ch_src", CLK_SET_RATE_PARENT,
|
|
RK3308_CLKSEL_CON(71), 0,
|
|
RK3308_CLKGATE_CON(13), 1, GFLAGS,
|
|
- &rk3308_i2s1_2ch_fracmux),
|
|
+ &rk3308_i2s1_2ch_fracmux, RK3308_I2S_FRAC_MAX_PRATE),
|
|
GATE(SCLK_I2S1_2CH, "clk_i2s1_2ch", "clk_i2s1_2ch_mux", 0,
|
|
RK3308_CLKGATE_CON(13), 2, GFLAGS),
|
|
COMPOSITE_NODIV(SCLK_I2S1_2CH_OUT, "clk_i2s1_2ch_out", mux_i2s1_2ch_out_p, CLK_SET_RATE_PARENT,
|
|
@@ -782,7 +788,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_spdif_tx_frac", "clk_spdif_tx_src", CLK_SET_RATE_PARENT,
|
|
RK3308_CLKSEL_CON(49), 0,
|
|
RK3308_CLKGATE_CON(10), 7, GFLAGS,
|
|
- &rk3308_spdif_tx_fracmux),
|
|
+ &rk3308_spdif_tx_fracmux, RK3308_SPDIF_FRAC_MAX_PRATE),
|
|
GATE(SCLK_SPDIF_TX, "clk_spdif_tx", "clk_spdif_tx_mux", 0,
|
|
RK3308_CLKGATE_CON(10), 8, GFLAGS),
|
|
|
|
@@ -797,7 +803,7 @@ static struct rockchip_clk_branch rk3308_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_spdif_rx_frac", "clk_spdif_rx_src", CLK_SET_RATE_PARENT,
|
|
RK3308_CLKSEL_CON(51), 0,
|
|
RK3308_CLKGATE_CON(10), 10, GFLAGS,
|
|
- &rk3308_spdif_rx_fracmux),
|
|
+ &rk3308_spdif_rx_fracmux, RK3308_SPDIF_FRAC_MAX_PRATE),
|
|
GATE(SCLK_SPDIF_RX, "clk_spdif_rx", "clk_spdif_rx_mux", 0,
|
|
RK3308_CLKGATE_CON(10), 11, GFLAGS),
|
|
|
|
diff --git a/drivers/clk/rockchip/clk-rk3328.c b/drivers/clk/rockchip/clk-rk3328.c
|
|
index 2429b7c2a8b3..cc18dbc18ae8 100644
|
|
--- a/drivers/clk/rockchip/clk-rk3328.c
|
|
+++ b/drivers/clk/rockchip/clk-rk3328.c
|
|
@@ -16,6 +16,9 @@
|
|
#define RK3328_GRF_SOC_STATUS0 0x480
|
|
#define RK3328_GRF_MAC_CON1 0x904
|
|
#define RK3328_GRF_MAC_CON2 0x908
|
|
+#define RK3328_I2S_FRAC_MAX_PRATE 600000000
|
|
+#define RK3328_UART_FRAC_MAX_PRATE 600000000
|
|
+#define RK3328_SPDIF_FRAC_MAX_PRATE 600000000
|
|
|
|
enum rk3328_plls {
|
|
apll, dpll, cpll, gpll, npll,
|
|
@@ -372,7 +375,7 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_i2s0_frac", "clk_i2s0_div", CLK_SET_RATE_PARENT,
|
|
RK3328_CLKSEL_CON(7), 0,
|
|
RK3328_CLKGATE_CON(1), 2, GFLAGS,
|
|
- &rk3328_i2s0_fracmux),
|
|
+ &rk3328_i2s0_fracmux, RK3328_I2S_FRAC_MAX_PRATE),
|
|
GATE(SCLK_I2S0, "clk_i2s0", "i2s0_pre", CLK_SET_RATE_PARENT,
|
|
RK3328_CLKGATE_CON(1), 3, GFLAGS),
|
|
|
|
@@ -382,7 +385,7 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_i2s1_frac", "clk_i2s1_div", CLK_SET_RATE_PARENT,
|
|
RK3328_CLKSEL_CON(9), 0,
|
|
RK3328_CLKGATE_CON(1), 5, GFLAGS,
|
|
- &rk3328_i2s1_fracmux),
|
|
+ &rk3328_i2s1_fracmux, RK3328_I2S_FRAC_MAX_PRATE),
|
|
GATE(SCLK_I2S1, "clk_i2s1", "i2s1_pre", CLK_SET_RATE_PARENT,
|
|
RK3328_CLKGATE_CON(1), 6, GFLAGS),
|
|
COMPOSITE_NODIV(SCLK_I2S1_OUT, "i2s1_out", mux_i2s1out_p, 0,
|
|
@@ -395,7 +398,7 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_i2s2_frac", "clk_i2s2_div", CLK_SET_RATE_PARENT,
|
|
RK3328_CLKSEL_CON(11), 0,
|
|
RK3328_CLKGATE_CON(1), 9, GFLAGS,
|
|
- &rk3328_i2s2_fracmux),
|
|
+ &rk3328_i2s2_fracmux, RK3328_I2S_FRAC_MAX_PRATE),
|
|
GATE(SCLK_I2S2, "clk_i2s2", "i2s2_pre", CLK_SET_RATE_PARENT,
|
|
RK3328_CLKGATE_CON(1), 10, GFLAGS),
|
|
COMPOSITE_NODIV(SCLK_I2S2_OUT, "i2s2_out", mux_i2s2out_p, 0,
|
|
@@ -408,7 +411,7 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_spdif_frac", "clk_spdif_div", CLK_SET_RATE_PARENT,
|
|
RK3328_CLKSEL_CON(13), 0,
|
|
RK3328_CLKGATE_CON(1), 13, GFLAGS,
|
|
- &rk3328_spdif_fracmux),
|
|
+ &rk3328_spdif_fracmux, RK3328_SPDIF_FRAC_MAX_PRATE),
|
|
|
|
/* PD_UART */
|
|
COMPOSITE(0, "clk_uart0_div", mux_2plls_u480m_p, 0,
|
|
@@ -423,15 +426,15 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_uart0_frac", "clk_uart0_div", CLK_SET_RATE_PARENT,
|
|
RK3328_CLKSEL_CON(15), 0,
|
|
RK3328_CLKGATE_CON(1), 15, GFLAGS,
|
|
- &rk3328_uart0_fracmux),
|
|
+ &rk3328_uart0_fracmux, RK3328_UART_FRAC_MAX_PRATE),
|
|
COMPOSITE_FRACMUX(0, "clk_uart1_frac", "clk_uart1_div", CLK_SET_RATE_PARENT,
|
|
RK3328_CLKSEL_CON(17), 0,
|
|
RK3328_CLKGATE_CON(2), 1, GFLAGS,
|
|
- &rk3328_uart1_fracmux),
|
|
+ &rk3328_uart1_fracmux, RK3328_UART_FRAC_MAX_PRATE),
|
|
COMPOSITE_FRACMUX(0, "clk_uart2_frac", "clk_uart2_div", CLK_SET_RATE_PARENT,
|
|
RK3328_CLKSEL_CON(19), 0,
|
|
RK3328_CLKGATE_CON(2), 3, GFLAGS,
|
|
- &rk3328_uart2_fracmux),
|
|
+ &rk3328_uart2_fracmux, RK3328_UART_FRAC_MAX_PRATE),
|
|
|
|
/*
|
|
* Clock-Architecture Diagram 4
|
|
diff --git a/drivers/clk/rockchip/clk-rk3368.c b/drivers/clk/rockchip/clk-rk3368.c
|
|
index 55443349439b..d20e51dabb63 100644
|
|
--- a/drivers/clk/rockchip/clk-rk3368.c
|
|
+++ b/drivers/clk/rockchip/clk-rk3368.c
|
|
@@ -12,6 +12,9 @@
|
|
#include "clk.h"
|
|
|
|
#define RK3368_GRF_SOC_STATUS0 0x480
|
|
+#define RK3368_I2S_FRAC_MAX_PRATE 600000000
|
|
+#define RK3368_UART_FRAC_MAX_PRATE 600000000
|
|
+#define RK3368_SPDIF_FRAC_MAX_PRATE 600000000
|
|
|
|
enum rk3368_plls {
|
|
apllb, aplll, dpll, cpll, gpll, npll,
|
|
@@ -368,7 +371,7 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "i2s_8ch_frac", "i2s_8ch_src", CLK_SET_RATE_PARENT,
|
|
RK3368_CLKSEL_CON(28), 0,
|
|
RK3368_CLKGATE_CON(6), 2, GFLAGS,
|
|
- &rk3368_i2s_8ch_fracmux),
|
|
+ &rk3368_i2s_8ch_fracmux, RK3368_I2S_FRAC_MAX_PRATE),
|
|
COMPOSITE_NODIV(SCLK_I2S_8CH_OUT, "i2s_8ch_clkout", mux_i2s_8ch_clkout_p, 0,
|
|
RK3368_CLKSEL_CON(27), 15, 1, MFLAGS,
|
|
RK3368_CLKGATE_CON(6), 0, GFLAGS),
|
|
@@ -380,7 +383,7 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "spdif_8ch_frac", "spdif_8ch_src", CLK_SET_RATE_PARENT,
|
|
RK3368_CLKSEL_CON(32), 0,
|
|
RK3368_CLKGATE_CON(6), 5, GFLAGS,
|
|
- &rk3368_spdif_8ch_fracmux),
|
|
+ &rk3368_spdif_8ch_fracmux, RK3368_SPDIF_FRAC_MAX_PRATE),
|
|
GATE(SCLK_SPDIF_8CH, "sclk_spdif_8ch", "spdif_8ch_pre", CLK_SET_RATE_PARENT,
|
|
RK3368_CLKGATE_CON(6), 6, GFLAGS),
|
|
COMPOSITE(0, "i2s_2ch_src", mux_pll_src_cpll_gpll_p, 0,
|
|
@@ -389,7 +392,7 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "i2s_2ch_frac", "i2s_2ch_src", CLK_SET_RATE_PARENT,
|
|
RK3368_CLKSEL_CON(54), 0,
|
|
RK3368_CLKGATE_CON(5), 14, GFLAGS,
|
|
- &rk3368_i2s_2ch_fracmux),
|
|
+ &rk3368_i2s_2ch_fracmux, RK3368_I2S_FRAC_MAX_PRATE),
|
|
GATE(SCLK_I2S_2CH, "sclk_i2s_2ch", "i2s_2ch_pre", CLK_SET_RATE_PARENT,
|
|
RK3368_CLKGATE_CON(5), 15, GFLAGS),
|
|
|
|
@@ -590,7 +593,7 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT,
|
|
RK3368_CLKSEL_CON(34), 0,
|
|
RK3368_CLKGATE_CON(2), 1, GFLAGS,
|
|
- &rk3368_uart0_fracmux),
|
|
+ &rk3368_uart0_fracmux, RK3368_UART_FRAC_MAX_PRATE),
|
|
|
|
COMPOSITE_NOMUX(0, "uart1_src", "uart_src", 0,
|
|
RK3368_CLKSEL_CON(35), 0, 7, DFLAGS,
|
|
@@ -598,7 +601,7 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT,
|
|
RK3368_CLKSEL_CON(36), 0,
|
|
RK3368_CLKGATE_CON(2), 3, GFLAGS,
|
|
- &rk3368_uart1_fracmux),
|
|
+ &rk3368_uart1_fracmux, RK3368_UART_FRAC_MAX_PRATE),
|
|
|
|
COMPOSITE_NOMUX(0, "uart3_src", "uart_src", 0,
|
|
RK3368_CLKSEL_CON(39), 0, 7, DFLAGS,
|
|
@@ -606,7 +609,7 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "uart3_frac", "uart3_src", CLK_SET_RATE_PARENT,
|
|
RK3368_CLKSEL_CON(40), 0,
|
|
RK3368_CLKGATE_CON(2), 7, GFLAGS,
|
|
- &rk3368_uart3_fracmux),
|
|
+ &rk3368_uart3_fracmux, RK3368_UART_FRAC_MAX_PRATE),
|
|
|
|
COMPOSITE_NOMUX(0, "uart4_src", "uart_src", 0,
|
|
RK3368_CLKSEL_CON(41), 0, 7, DFLAGS,
|
|
@@ -614,7 +617,7 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "uart4_frac", "uart4_src", CLK_SET_RATE_PARENT,
|
|
RK3368_CLKSEL_CON(42), 0,
|
|
RK3368_CLKGATE_CON(2), 9, GFLAGS,
|
|
- &rk3368_uart4_fracmux),
|
|
+ &rk3368_uart4_fracmux, RK3368_UART_FRAC_MAX_PRATE),
|
|
|
|
COMPOSITE(0, "mac_pll_src", mux_pll_src_npll_cpll_gpll_p, 0,
|
|
RK3368_CLKSEL_CON(43), 6, 2, MFLAGS, 0, 5, DFLAGS,
|
|
diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c
|
|
index 7df2f1e00347..3682d5675cf7 100644
|
|
--- a/drivers/clk/rockchip/clk-rk3399.c
|
|
+++ b/drivers/clk/rockchip/clk-rk3399.c
|
|
@@ -15,6 +15,12 @@
|
|
#include <dt-bindings/clock/rk3399-cru.h>
|
|
#include "clk.h"
|
|
|
|
+#define RK3399_I2S_FRAC_MAX_PRATE 800000000
|
|
+#define RK3399_UART_FRAC_MAX_PRATE 800000000
|
|
+#define RK3399_SPDIF_FRAC_MAX_PRATE 600000000
|
|
+#define RK3399_VOP_FRAC_MAX_PRATE 600000000
|
|
+#define RK3399_WIFI_FRAC_MAX_PRATE 600000000
|
|
+
|
|
enum rk3399_plls {
|
|
lpll, bpll, dpll, cpll, gpll, npll, vpll,
|
|
};
|
|
@@ -584,7 +590,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_spdif_frac", "clk_spdif_div", 0,
|
|
RK3399_CLKSEL_CON(99), 0,
|
|
RK3399_CLKGATE_CON(8), 14, GFLAGS,
|
|
- &rk3399_spdif_fracmux),
|
|
+ &rk3399_spdif_fracmux, RK3399_SPDIF_FRAC_MAX_PRATE),
|
|
GATE(SCLK_SPDIF_8CH, "clk_spdif", "clk_spdif_mux", CLK_SET_RATE_PARENT,
|
|
RK3399_CLKGATE_CON(8), 15, GFLAGS),
|
|
|
|
@@ -598,7 +604,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_i2s0_frac", "clk_i2s0_div", 0,
|
|
RK3399_CLKSEL_CON(96), 0,
|
|
RK3399_CLKGATE_CON(8), 4, GFLAGS,
|
|
- &rk3399_i2s0_fracmux),
|
|
+ &rk3399_i2s0_fracmux, RK3399_I2S_FRAC_MAX_PRATE),
|
|
GATE(SCLK_I2S0_8CH, "clk_i2s0", "clk_i2s0_mux", CLK_SET_RATE_PARENT,
|
|
RK3399_CLKGATE_CON(8), 5, GFLAGS),
|
|
|
|
@@ -608,7 +614,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_i2s1_frac", "clk_i2s1_div", 0,
|
|
RK3399_CLKSEL_CON(97), 0,
|
|
RK3399_CLKGATE_CON(8), 7, GFLAGS,
|
|
- &rk3399_i2s1_fracmux),
|
|
+ &rk3399_i2s1_fracmux, RK3399_I2S_FRAC_MAX_PRATE),
|
|
GATE(SCLK_I2S1_8CH, "clk_i2s1", "clk_i2s1_mux", CLK_SET_RATE_PARENT,
|
|
RK3399_CLKGATE_CON(8), 8, GFLAGS),
|
|
|
|
@@ -618,7 +624,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_i2s2_frac", "clk_i2s2_div", 0,
|
|
RK3399_CLKSEL_CON(98), 0,
|
|
RK3399_CLKGATE_CON(8), 10, GFLAGS,
|
|
- &rk3399_i2s2_fracmux),
|
|
+ &rk3399_i2s2_fracmux, RK3399_I2S_FRAC_MAX_PRATE),
|
|
GATE(SCLK_I2S2_8CH, "clk_i2s2", "clk_i2s2_mux", CLK_SET_RATE_PARENT,
|
|
RK3399_CLKGATE_CON(8), 11, GFLAGS),
|
|
|
|
@@ -637,7 +643,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_uart0_frac", "clk_uart0_div", 0,
|
|
RK3399_CLKSEL_CON(100), 0,
|
|
RK3399_CLKGATE_CON(9), 1, GFLAGS,
|
|
- &rk3399_uart0_fracmux),
|
|
+ &rk3399_uart0_fracmux, RK3399_UART_FRAC_MAX_PRATE),
|
|
|
|
MUX(0, "clk_uart_src", mux_pll_src_cpll_gpll_p, 0,
|
|
RK3399_CLKSEL_CON(33), 15, 1, MFLAGS),
|
|
@@ -647,7 +653,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_uart1_frac", "clk_uart1_div", 0,
|
|
RK3399_CLKSEL_CON(101), 0,
|
|
RK3399_CLKGATE_CON(9), 3, GFLAGS,
|
|
- &rk3399_uart1_fracmux),
|
|
+ &rk3399_uart1_fracmux, RK3399_UART_FRAC_MAX_PRATE),
|
|
|
|
COMPOSITE_NOMUX(0, "clk_uart2_div", "clk_uart_src", 0,
|
|
RK3399_CLKSEL_CON(35), 0, 7, DFLAGS,
|
|
@@ -655,7 +661,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_uart2_frac", "clk_uart2_div", 0,
|
|
RK3399_CLKSEL_CON(102), 0,
|
|
RK3399_CLKGATE_CON(9), 5, GFLAGS,
|
|
- &rk3399_uart2_fracmux),
|
|
+ &rk3399_uart2_fracmux, RK3399_UART_FRAC_MAX_PRATE),
|
|
|
|
COMPOSITE_NOMUX(0, "clk_uart3_div", "clk_uart_src", 0,
|
|
RK3399_CLKSEL_CON(36), 0, 7, DFLAGS,
|
|
@@ -663,7 +669,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_uart3_frac", "clk_uart3_div", 0,
|
|
RK3399_CLKSEL_CON(103), 0,
|
|
RK3399_CLKGATE_CON(9), 7, GFLAGS,
|
|
- &rk3399_uart3_fracmux),
|
|
+ &rk3399_uart3_fracmux, RK3399_UART_FRAC_MAX_PRATE),
|
|
|
|
COMPOSITE(PCLK_DDR, "pclk_ddr", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED,
|
|
RK3399_CLKSEL_CON(6), 15, 1, MFLAGS, 8, 5, DFLAGS,
|
|
@@ -1166,7 +1172,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
|
|
|
|
COMPOSITE_FRACMUX_NOGATE(DCLK_VOP0_FRAC, "dclk_vop0_frac", "dclk_vop0_div", 0,
|
|
RK3399_CLKSEL_CON(106), 0,
|
|
- &rk3399_dclk_vop0_fracmux),
|
|
+ &rk3399_dclk_vop0_fracmux, RK3399_VOP_FRAC_MAX_PRATE),
|
|
|
|
COMPOSITE(SCLK_VOP0_PWM, "clk_vop0_pwm", mux_pll_src_vpll_cpll_gpll_24m_p, 0,
|
|
RK3399_CLKSEL_CON(51), 6, 2, MFLAGS, 0, 5, DFLAGS,
|
|
@@ -1196,7 +1202,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
|
|
|
|
COMPOSITE_FRACMUX_NOGATE(DCLK_VOP1_FRAC, "dclk_vop1_frac", "dclk_vop1_div", 0,
|
|
RK3399_CLKSEL_CON(107), 0,
|
|
- &rk3399_dclk_vop1_fracmux),
|
|
+ &rk3399_dclk_vop1_fracmux, RK3399_VOP_FRAC_MAX_PRATE),
|
|
|
|
COMPOSITE(SCLK_VOP1_PWM, "clk_vop1_pwm", mux_pll_src_vpll_cpll_gpll_24m_p, CLK_IGNORE_UNUSED,
|
|
RK3399_CLKSEL_CON(52), 6, 2, MFLAGS, 0, 5, DFLAGS,
|
|
@@ -1313,7 +1319,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
|
|
RK3399_CLKSEL_CON(58), 7, 1, MFLAGS),
|
|
COMPOSITE_FRAC(0, "clk_test_frac", "clk_test_pre", 0,
|
|
RK3399_CLKSEL_CON(105), 0,
|
|
- RK3399_CLKGATE_CON(13), 9, GFLAGS),
|
|
+ RK3399_CLKGATE_CON(13), 9, GFLAGS, 0),
|
|
|
|
DIV(0, "clk_test_24m", "xin24m", 0,
|
|
RK3399_CLKSEL_CON(57), 6, 10, DFLAGS),
|
|
@@ -1418,7 +1424,7 @@ static struct rockchip_clk_branch rk3399_clk_pmu_branches[] __initdata = {
|
|
|
|
COMPOSITE_FRACMUX_NOGATE(0, "clk_wifi_frac", "clk_wifi_div", 0,
|
|
RK3399_PMU_CLKSEL_CON(7), 0,
|
|
- &rk3399_pmuclk_wifi_fracmux),
|
|
+ &rk3399_pmuclk_wifi_fracmux, RK3399_WIFI_FRAC_MAX_PRATE),
|
|
|
|
MUX(0, "clk_timer_src_pmu", mux_pll_p, CLK_IGNORE_UNUSED,
|
|
RK3399_PMU_CLKSEL_CON(1), 15, 1, MFLAGS),
|
|
@@ -1447,7 +1453,7 @@ static struct rockchip_clk_branch rk3399_clk_pmu_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "clk_uart4_frac", "clk_uart4_div", 0,
|
|
RK3399_PMU_CLKSEL_CON(6), 0,
|
|
RK3399_PMU_CLKGATE_CON(0), 6, GFLAGS,
|
|
- &rk3399_uart4_pmu_fracmux),
|
|
+ &rk3399_uart4_pmu_fracmux, RK3399_UART_FRAC_MAX_PRATE),
|
|
|
|
DIV(PCLK_SRC_PMU, "pclk_pmu_src", "ppll", CLK_IGNORE_UNUSED,
|
|
RK3399_PMU_CLKSEL_CON(0), 0, 5, DFLAGS),
|
|
diff --git a/drivers/clk/rockchip/clk-rv1108.c b/drivers/clk/rockchip/clk-rv1108.c
|
|
index 5947d3192866..04b7f1161942 100644
|
|
--- a/drivers/clk/rockchip/clk-rv1108.c
|
|
+++ b/drivers/clk/rockchip/clk-rv1108.c
|
|
@@ -14,6 +14,8 @@
|
|
#include "clk.h"
|
|
|
|
#define RV1108_GRF_SOC_STATUS0 0x480
|
|
+#define RV1108_I2S_FRAC_MAX_RATE 600000000
|
|
+#define RV1108_UART_FRAC_MAX_RATE 600000000
|
|
|
|
enum rv1108_plls {
|
|
apll, dpll, gpll,
|
|
@@ -503,7 +505,7 @@ static struct rockchip_clk_branch rv1108_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "i2s0_frac", "i2s0_src", CLK_SET_RATE_PARENT,
|
|
RV1108_CLKSEL_CON(8), 0,
|
|
RV1108_CLKGATE_CON(2), 1, GFLAGS,
|
|
- &rv1108_i2s0_fracmux),
|
|
+ &rv1108_i2s0_fracmux, RV1108_I2S_FRAC_MAX_RATE),
|
|
GATE(SCLK_I2S0, "sclk_i2s0", "i2s0_pre", CLK_SET_RATE_PARENT,
|
|
RV1108_CLKGATE_CON(2), 2, GFLAGS),
|
|
COMPOSITE_NODIV(0, "i2s_out", mux_i2s_out_p, 0,
|
|
@@ -516,7 +518,7 @@ static struct rockchip_clk_branch rv1108_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "i2s1_frac", "i2s1_src", CLK_SET_RATE_PARENT,
|
|
RK2928_CLKSEL_CON(9), 0,
|
|
RK2928_CLKGATE_CON(2), 5, GFLAGS,
|
|
- &rv1108_i2s1_fracmux),
|
|
+ &rv1108_i2s1_fracmux, RV1108_I2S_FRAC_MAX_RATE),
|
|
GATE(SCLK_I2S1, "sclk_i2s1", "i2s1_pre", CLK_SET_RATE_PARENT,
|
|
RV1108_CLKGATE_CON(2), 6, GFLAGS),
|
|
|
|
@@ -526,7 +528,7 @@ static struct rockchip_clk_branch rv1108_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "i2s2_frac", "i2s2_src", CLK_SET_RATE_PARENT,
|
|
RV1108_CLKSEL_CON(10), 0,
|
|
RV1108_CLKGATE_CON(2), 9, GFLAGS,
|
|
- &rv1108_i2s2_fracmux),
|
|
+ &rv1108_i2s2_fracmux, RV1108_I2S_FRAC_MAX_RATE),
|
|
GATE(SCLK_I2S2, "sclk_i2s2", "i2s2_pre", CLK_SET_RATE_PARENT,
|
|
RV1108_CLKGATE_CON(2), 10, GFLAGS),
|
|
|
|
@@ -592,15 +594,15 @@ static struct rockchip_clk_branch rv1108_clk_branches[] __initdata = {
|
|
COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT,
|
|
RV1108_CLKSEL_CON(16), 0,
|
|
RV1108_CLKGATE_CON(3), 2, GFLAGS,
|
|
- &rv1108_uart0_fracmux),
|
|
+ &rv1108_uart0_fracmux, RV1108_UART_FRAC_MAX_RATE),
|
|
COMPOSITE_FRACMUX(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT,
|
|
RV1108_CLKSEL_CON(17), 0,
|
|
RV1108_CLKGATE_CON(3), 4, GFLAGS,
|
|
- &rv1108_uart1_fracmux),
|
|
+ &rv1108_uart1_fracmux, RV1108_UART_FRAC_MAX_RATE),
|
|
COMPOSITE_FRACMUX(0, "uart2_frac", "uart2_src", CLK_SET_RATE_PARENT,
|
|
RV1108_CLKSEL_CON(18), 0,
|
|
RV1108_CLKGATE_CON(3), 6, GFLAGS,
|
|
- &rv1108_uart2_fracmux),
|
|
+ &rv1108_uart2_fracmux, RV1108_UART_FRAC_MAX_RATE),
|
|
GATE(PCLK_UART0, "pclk_uart0", "pclk_bus_pre", 0,
|
|
RV1108_CLKGATE_CON(13), 10, GFLAGS),
|
|
GATE(PCLK_UART1, "pclk_uart1", "pclk_bus_pre", 0,
|
|
diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c
|
|
index 336481bc6cc7..fcbe33c4027f 100644
|
|
--- a/drivers/clk/rockchip/clk.c
|
|
+++ b/drivers/clk/rockchip/clk.c
|
|
@@ -182,12 +182,26 @@ static void rockchip_fractional_approximation(struct clk_hw *hw,
|
|
unsigned long p_rate, p_parent_rate;
|
|
struct clk_hw *p_parent;
|
|
unsigned long scale;
|
|
+ u32 div;
|
|
|
|
p_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
|
|
- if ((rate * 20 > p_rate) && (p_rate % rate != 0)) {
|
|
+ if (((rate * 20 > p_rate) && (p_rate % rate != 0)) ||
|
|
+ (fd->max_prate && fd->max_prate < p_rate)) {
|
|
p_parent = clk_hw_get_parent(clk_hw_get_parent(hw));
|
|
p_parent_rate = clk_hw_get_rate(p_parent);
|
|
*parent_rate = p_parent_rate;
|
|
+ if (fd->max_prate && p_parent_rate > fd->max_prate) {
|
|
+ div = DIV_ROUND_UP(p_parent_rate, fd->max_prate);
|
|
+ *parent_rate = p_parent_rate / div;
|
|
+ }
|
|
+
|
|
+ if (*parent_rate < rate * 20) {
|
|
+ pr_err("%s parent_rate(%ld) is low than rate(%ld)*20, fractional div is not allowed\n",
|
|
+ clk_hw_get_name(hw), *parent_rate, rate);
|
|
+ *m = 0;
|
|
+ *n = 1;
|
|
+ return;
|
|
+ }
|
|
}
|
|
|
|
/*
|
|
@@ -210,7 +224,7 @@ static struct clk *rockchip_clk_register_frac_branch(
|
|
void __iomem *base, int muxdiv_offset, u8 div_flags,
|
|
int gate_offset, u8 gate_shift, u8 gate_flags,
|
|
unsigned long flags, struct rockchip_clk_branch *child,
|
|
- spinlock_t *lock)
|
|
+ unsigned long max_prate, spinlock_t *lock)
|
|
{
|
|
struct clk_hw *hw;
|
|
struct rockchip_clk_frac *frac;
|
|
@@ -251,6 +265,7 @@ static struct clk *rockchip_clk_register_frac_branch(
|
|
div->nmask = GENMASK(div->nwidth - 1, 0) << div->nshift;
|
|
div->lock = lock;
|
|
div->approximation = rockchip_fractional_approximation;
|
|
+ div->max_prate = max_prate;
|
|
div_ops = &clk_fractional_divider_ops;
|
|
|
|
hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
|
|
@@ -488,7 +503,7 @@ void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx,
|
|
list->div_flags,
|
|
list->gate_offset, list->gate_shift,
|
|
list->gate_flags, flags, list->child,
|
|
- &ctx->lock);
|
|
+ list->max_prate, &ctx->lock);
|
|
break;
|
|
case branch_half_divider:
|
|
clk = rockchip_clk_register_halfdiv(list->name,
|
|
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
|
|
index 2271a84124b0..0d401ce09a54 100644
|
|
--- a/drivers/clk/rockchip/clk.h
|
|
+++ b/drivers/clk/rockchip/clk.h
|
|
@@ -420,6 +420,7 @@ struct rockchip_clk_branch {
|
|
u8 gate_shift;
|
|
u8 gate_flags;
|
|
struct rockchip_clk_branch *child;
|
|
+ unsigned long max_prate;
|
|
};
|
|
|
|
#define COMPOSITE(_id, cname, pnames, f, mo, ms, mw, mf, ds, dw,\
|
|
@@ -559,7 +560,7 @@ struct rockchip_clk_branch {
|
|
.gate_offset = -1, \
|
|
}
|
|
|
|
-#define COMPOSITE_FRAC(_id, cname, pname, f, mo, df, go, gs, gf)\
|
|
+#define COMPOSITE_FRAC(_id, cname, pname, f, mo, df, go, gs, gf, prate)\
|
|
{ \
|
|
.id = _id, \
|
|
.branch_type = branch_fraction_divider, \
|
|
@@ -574,9 +575,10 @@ struct rockchip_clk_branch {
|
|
.gate_offset = go, \
|
|
.gate_shift = gs, \
|
|
.gate_flags = gf, \
|
|
+ .max_prate = prate, \
|
|
}
|
|
|
|
-#define COMPOSITE_FRACMUX(_id, cname, pname, f, mo, df, go, gs, gf, ch) \
|
|
+#define COMPOSITE_FRACMUX(_id, cname, pname, f, mo, df, go, gs, gf, ch, prate) \
|
|
{ \
|
|
.id = _id, \
|
|
.branch_type = branch_fraction_divider, \
|
|
@@ -592,9 +594,10 @@ struct rockchip_clk_branch {
|
|
.gate_shift = gs, \
|
|
.gate_flags = gf, \
|
|
.child = ch, \
|
|
+ .max_prate = prate, \
|
|
}
|
|
|
|
-#define COMPOSITE_FRACMUX_NOGATE(_id, cname, pname, f, mo, df, ch) \
|
|
+#define COMPOSITE_FRACMUX_NOGATE(_id, cname, pname, f, mo, df, ch, prate) \
|
|
{ \
|
|
.id = _id, \
|
|
.branch_type = branch_fraction_divider, \
|
|
@@ -608,6 +611,7 @@ struct rockchip_clk_branch {
|
|
.div_flags = df, \
|
|
.gate_offset = -1, \
|
|
.child = ch, \
|
|
+ .max_prate = prate, \
|
|
}
|
|
|
|
#define COMPOSITE_DDRCLK(_id, cname, pnames, f, mo, ms, mw, \
|
|
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
|
|
index 03a5de5f99f4..b6b28a097526 100644
|
|
--- a/include/linux/clk-provider.h
|
|
+++ b/include/linux/clk-provider.h
|
|
@@ -924,6 +924,7 @@ void clk_hw_unregister_fixed_factor(struct clk_hw *hw);
|
|
* @mwidth: width of the numerator bit field
|
|
* @nshift: shift to the denominator bit field
|
|
* @nwidth: width of the denominator bit field
|
|
+ * @max_parent: the maximum frequency of fractional divider parent clock
|
|
* @lock: register lock
|
|
*
|
|
* Clock with adjustable fractional divider affecting its output frequency.
|
|
@@ -947,6 +948,7 @@ struct clk_fractional_divider {
|
|
u8 nwidth;
|
|
u32 nmask;
|
|
u8 flags;
|
|
+ unsigned long max_prate;
|
|
void (*approximation)(struct clk_hw *hw,
|
|
unsigned long rate, unsigned long *parent_rate,
|
|
unsigned long *m, unsigned long *n);
|
|
|
|
From 40a00285ecec36dbf0581904f91735c26a87a157 Mon Sep 17 00:00:00 2001
|
|
From: Elaine Zhang <zhangqing@rock-chips.com>
|
|
Date: Wed, 14 Oct 2020 10:28:09 +0800
|
|
Subject: [PATCH] clk: rockchip: fix up the frac clk get rate error
|
|
|
|
support fractional divider with one level and two level parent clock
|
|
.i.e:
|
|
|
|
normal fractional divider is:
|
|
|--\
|
|
---[GPLL]---| \ |--\
|
|
---[CPLL]---|mux|--[GATE]--[DIV]-----------------------| \
|
|
---[NPLL]---| / | |mux|--[GATE]--[UART0]
|
|
|--/ |--[GATE]--[FRACDIV]--| /
|
|
|--/
|
|
but rk3399 uart is special:
|
|
|--\
|
|
---[GPLL]---| \ |--\
|
|
---[CPLL]---|mux|--|--[GATE]--[DIV]-----------------------| \
|
|
---[NPLL]---| / | | |mux|--[GATE]--[UART1]
|
|
|--/ | |--[GATE]--[FRACDIV]--| /
|
|
| |--/
|
|
|
|
|
| |--\
|
|
|--[GATE]--[DIV]-----------------------| \
|
|
| | |mux|--[GATE]--[UART2]
|
|
| |--[GATE]--[FRACDIV]--| /
|
|
| |--/
|
|
|
|
|
| |--\
|
|
|--[GATE]--[DIV]-----------------------| \
|
|
| |mux|--[GATE]--[UART3]
|
|
|--[GATE]--[FRACDIV]--| /
|
|
|--/
|
|
|
|
The special fractional divider, there are two levels of clock between FRACDIV and PLL.
|
|
|
|
Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
|
|
---
|
|
drivers/clk/rockchip/clk.c | 19 ++++++++++++-------
|
|
1 file changed, 12 insertions(+), 7 deletions(-)
|
|
|
|
diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c
|
|
index fcbe33c4027f..92aee3e8be36 100644
|
|
--- a/drivers/clk/rockchip/clk.c
|
|
+++ b/drivers/clk/rockchip/clk.c
|
|
@@ -188,16 +188,21 @@ static void rockchip_fractional_approximation(struct clk_hw *hw,
|
|
if (((rate * 20 > p_rate) && (p_rate % rate != 0)) ||
|
|
(fd->max_prate && fd->max_prate < p_rate)) {
|
|
p_parent = clk_hw_get_parent(clk_hw_get_parent(hw));
|
|
- p_parent_rate = clk_hw_get_rate(p_parent);
|
|
- *parent_rate = p_parent_rate;
|
|
- if (fd->max_prate && p_parent_rate > fd->max_prate) {
|
|
- div = DIV_ROUND_UP(p_parent_rate, fd->max_prate);
|
|
- *parent_rate = p_parent_rate / div;
|
|
+ if (!p_parent) {
|
|
+ *parent_rate = p_rate;
|
|
+ } else {
|
|
+ p_parent_rate = clk_hw_get_rate(p_parent);
|
|
+ *parent_rate = p_parent_rate;
|
|
+ if (fd->max_prate && p_parent_rate > fd->max_prate) {
|
|
+ div = DIV_ROUND_UP(p_parent_rate,
|
|
+ fd->max_prate);
|
|
+ *parent_rate = p_parent_rate / div;
|
|
+ }
|
|
}
|
|
|
|
if (*parent_rate < rate * 20) {
|
|
- pr_err("%s parent_rate(%ld) is low than rate(%ld)*20, fractional div is not allowed\n",
|
|
- clk_hw_get_name(hw), *parent_rate, rate);
|
|
+ pr_warn("%s p_rate(%ld) is low than rate(%ld)*20, use integer or half-div\n",
|
|
+ clk_hw_get_name(hw), *parent_rate, rate);
|
|
*m = 0;
|
|
*n = 1;
|
|
return;
|
|
|
|
From d03627a3b247b65dcd6935d23e75792b9aa56505 Mon Sep 17 00:00:00 2001
|
|
From: Elaine Zhang <zhangqing@rock-chips.com>
|
|
Date: Wed, 14 Oct 2020 10:28:10 +0800
|
|
Subject: [PATCH] clk: rockchip: add a clock-type for muxes based in the pmugrf
|
|
|
|
Rockchip socs often have some tiny number of muxes not controlled from
|
|
the core clock controller but through bits set in the pmugrf.
|
|
Use MUXPMUGRF() to cover this special clock-type.
|
|
|
|
Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
|
|
---
|
|
drivers/clk/rockchip/clk.c | 9 +++++++++
|
|
drivers/clk/rockchip/clk.h | 17 +++++++++++++++++
|
|
2 files changed, 26 insertions(+)
|
|
|
|
diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c
|
|
index 92aee3e8be36..2df0a239448e 100644
|
|
--- a/drivers/clk/rockchip/clk.c
|
|
+++ b/drivers/clk/rockchip/clk.c
|
|
@@ -407,6 +407,8 @@ struct rockchip_clk_provider *rockchip_clk_init(struct device_node *np,
|
|
|
|
ctx->grf = syscon_regmap_lookup_by_phandle(ctx->cru_node,
|
|
"rockchip,grf");
|
|
+ ctx->pmugrf = syscon_regmap_lookup_by_phandle(ctx->cru_node,
|
|
+ "rockchip,pmugrf");
|
|
|
|
return ctx;
|
|
|
|
@@ -485,6 +487,13 @@ void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx,
|
|
list->mux_shift, list->mux_width,
|
|
list->mux_flags);
|
|
break;
|
|
+ case branch_muxpmugrf:
|
|
+ clk = rockchip_clk_register_muxgrf(list->name,
|
|
+ list->parent_names, list->num_parents,
|
|
+ flags, ctx->pmugrf, list->muxdiv_offset,
|
|
+ list->mux_shift, list->mux_width,
|
|
+ list->mux_flags);
|
|
+ break;
|
|
case branch_divider:
|
|
if (list->div_table)
|
|
clk = clk_register_divider_table(NULL,
|
|
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
|
|
index 0d401ce09a54..ae059b7744f9 100644
|
|
--- a/drivers/clk/rockchip/clk.h
|
|
+++ b/drivers/clk/rockchip/clk.h
|
|
@@ -238,6 +238,7 @@ struct rockchip_clk_provider {
|
|
struct clk_onecell_data clk_data;
|
|
struct device_node *cru_node;
|
|
struct regmap *grf;
|
|
+ struct regmap *pmugrf;
|
|
spinlock_t lock;
|
|
};
|
|
|
|
@@ -390,6 +391,7 @@ enum rockchip_clk_branch_type {
|
|
branch_composite,
|
|
branch_mux,
|
|
branch_muxgrf,
|
|
+ branch_muxpmugrf,
|
|
branch_divider,
|
|
branch_fraction_divider,
|
|
branch_gate,
|
|
@@ -662,6 +664,21 @@ struct rockchip_clk_branch {
|
|
.gate_offset = -1, \
|
|
}
|
|
|
|
+#define MUXPMUGRF(_id, cname, pnames, f, o, s, w, mf) \
|
|
+ { \
|
|
+ .id = _id, \
|
|
+ .branch_type = branch_muxpmugrf, \
|
|
+ .name = cname, \
|
|
+ .parent_names = pnames, \
|
|
+ .num_parents = ARRAY_SIZE(pnames), \
|
|
+ .flags = f, \
|
|
+ .muxdiv_offset = o, \
|
|
+ .mux_shift = s, \
|
|
+ .mux_width = w, \
|
|
+ .mux_flags = mf, \
|
|
+ .gate_offset = -1, \
|
|
+ }
|
|
+
|
|
#define DIV(_id, cname, pname, f, o, s, w, df) \
|
|
{ \
|
|
.id = _id, \
|
|
|
|
From 51dc79ce294c10b8fd7cd787d60107ab84ba77bb Mon Sep 17 00:00:00 2001
|
|
From: Elaine Zhang <zhangqing@rock-chips.com>
|
|
Date: Wed, 14 Oct 2020 10:28:11 +0800
|
|
Subject: [PATCH] clk: rockchip: add pll up and down when change pll freq
|
|
|
|
set pll sequence:
|
|
->set pll to slow mode or other plls
|
|
->set pll down
|
|
->set pll params
|
|
->set pll up
|
|
->wait pll lock status
|
|
->set pll to normal mode
|
|
|
|
To slove the system error:
|
|
wait_pll_lock: timeout waiting for pll to lock
|
|
pll_set_params: pll update unsucessful,
|
|
trying to restore old params
|
|
|
|
Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
|
|
---
|
|
drivers/clk/rockchip/clk-pll.c | 21 +++++++++++++++++++++
|
|
1 file changed, 21 insertions(+)
|
|
|
|
diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c
|
|
index 4c6c9167ef50..8adc6f54a605 100644
|
|
--- a/drivers/clk/rockchip/clk-pll.c
|
|
+++ b/drivers/clk/rockchip/clk-pll.c
|
|
@@ -210,6 +210,11 @@ static int rockchip_rk3036_pll_set_params(struct rockchip_clk_pll *pll,
|
|
rate_change_remuxed = 1;
|
|
}
|
|
|
|
+ /* set pll power down */
|
|
+ writel(HIWORD_UPDATE(RK3036_PLLCON1_PWRDOWN,
|
|
+ RK3036_PLLCON1_PWRDOWN, 0),
|
|
+ pll->reg_base + RK3036_PLLCON(1));
|
|
+
|
|
/* update pll values */
|
|
writel_relaxed(HIWORD_UPDATE(rate->fbdiv, RK3036_PLLCON0_FBDIV_MASK,
|
|
RK3036_PLLCON0_FBDIV_SHIFT) |
|
|
@@ -231,6 +236,11 @@ static int rockchip_rk3036_pll_set_params(struct rockchip_clk_pll *pll,
|
|
pllcon |= rate->frac << RK3036_PLLCON2_FRAC_SHIFT;
|
|
writel_relaxed(pllcon, pll->reg_base + RK3036_PLLCON(2));
|
|
|
|
+ /* set pll power up */
|
|
+ writel(HIWORD_UPDATE(0, RK3036_PLLCON1_PWRDOWN, 0),
|
|
+ pll->reg_base + RK3036_PLLCON(1));
|
|
+ udelay(1);
|
|
+
|
|
/* wait for the pll to lock */
|
|
ret = rockchip_rk3036_pll_wait_lock(pll);
|
|
if (ret) {
|
|
@@ -692,6 +702,11 @@ static int rockchip_rk3399_pll_set_params(struct rockchip_clk_pll *pll,
|
|
rate_change_remuxed = 1;
|
|
}
|
|
|
|
+ /* set pll power down */
|
|
+ writel(HIWORD_UPDATE(RK3399_PLLCON3_PWRDOWN,
|
|
+ RK3399_PLLCON3_PWRDOWN, 0),
|
|
+ pll->reg_base + RK3399_PLLCON(3));
|
|
+
|
|
/* update pll values */
|
|
writel_relaxed(HIWORD_UPDATE(rate->fbdiv, RK3399_PLLCON0_FBDIV_MASK,
|
|
RK3399_PLLCON0_FBDIV_SHIFT),
|
|
@@ -715,6 +730,12 @@ static int rockchip_rk3399_pll_set_params(struct rockchip_clk_pll *pll,
|
|
RK3399_PLLCON3_DSMPD_SHIFT),
|
|
pll->reg_base + RK3399_PLLCON(3));
|
|
|
|
+ /* set pll power up */
|
|
+ writel(HIWORD_UPDATE(0,
|
|
+ RK3399_PLLCON3_PWRDOWN, 0),
|
|
+ pll->reg_base + RK3399_PLLCON(3));
|
|
+ udelay(1);
|
|
+
|
|
/* wait for the pll to lock */
|
|
ret = rockchip_rk3399_pll_wait_lock(pll);
|
|
if (ret) {
|
|
|
|
From c08635123f25692c92cc0ac30a54661ae4f552e8 Mon Sep 17 00:00:00 2001
|
|
From: Elaine Zhang <zhangqing@rock-chips.com>
|
|
Date: Wed, 14 Oct 2020 10:28:53 +0800
|
|
Subject: [PATCH] clk: rockchip: support pll setting by auto
|
|
|
|
If setting freq is not support in rockchip_pll_rate_table,
|
|
It can calculate and set pll params by auto.
|
|
|
|
Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
|
|
---
|
|
drivers/clk/rockchip/clk-pll.c | 215 ++++++++++++++++++++++++++++++---
|
|
1 file changed, 200 insertions(+), 15 deletions(-)
|
|
|
|
diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c
|
|
index 8adc6f54a605..e8ca86f5b7d1 100644
|
|
--- a/drivers/clk/rockchip/clk-pll.c
|
|
+++ b/drivers/clk/rockchip/clk-pll.c
|
|
@@ -15,6 +15,7 @@
|
|
#include <linux/iopoll.h>
|
|
#include <linux/regmap.h>
|
|
#include <linux/clk.h>
|
|
+#include <linux/gcd.h>
|
|
#include "clk.h"
|
|
|
|
#define PLL_MODE_MASK 0x3
|
|
@@ -47,6 +48,198 @@ struct rockchip_clk_pll {
|
|
#define to_rockchip_clk_pll_nb(nb) \
|
|
container_of(nb, struct rockchip_clk_pll, clk_nb)
|
|
|
|
+#define MHZ (1000UL * 1000UL)
|
|
+#define KHZ (1000UL)
|
|
+
|
|
+/* CLK_PLL_TYPE_RK3066_AUTO type ops */
|
|
+#define PLL_FREF_MIN (269 * KHZ)
|
|
+#define PLL_FREF_MAX (2200 * MHZ)
|
|
+
|
|
+#define PLL_FVCO_MIN (440 * MHZ)
|
|
+#define PLL_FVCO_MAX (2200 * MHZ)
|
|
+
|
|
+#define PLL_FOUT_MIN (27500 * KHZ)
|
|
+#define PLL_FOUT_MAX (2200 * MHZ)
|
|
+
|
|
+#define PLL_NF_MAX (4096)
|
|
+#define PLL_NR_MAX (64)
|
|
+#define PLL_NO_MAX (16)
|
|
+
|
|
+/* CLK_PLL_TYPE_RK3036/3366/3399_AUTO type ops */
|
|
+#define MIN_FOUTVCO_FREQ (800 * MHZ)
|
|
+#define MAX_FOUTVCO_FREQ (2000 * MHZ)
|
|
+
|
|
+static struct rockchip_pll_rate_table auto_table;
|
|
+
|
|
+static struct rockchip_pll_rate_table *rk_pll_rate_table_get(void)
|
|
+{
|
|
+ return &auto_table;
|
|
+}
|
|
+
|
|
+static int rockchip_pll_clk_set_postdiv(unsigned long fout_hz,
|
|
+ u32 *postdiv1,
|
|
+ u32 *postdiv2,
|
|
+ u32 *foutvco)
|
|
+{
|
|
+ unsigned long freq;
|
|
+
|
|
+ if (fout_hz < MIN_FOUTVCO_FREQ) {
|
|
+ for (*postdiv1 = 1; *postdiv1 <= 7; (*postdiv1)++) {
|
|
+ for (*postdiv2 = 1; *postdiv2 <= 7; (*postdiv2)++) {
|
|
+ freq = fout_hz * (*postdiv1) * (*postdiv2);
|
|
+ if (freq >= MIN_FOUTVCO_FREQ &&
|
|
+ freq <= MAX_FOUTVCO_FREQ) {
|
|
+ *foutvco = freq;
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ pr_err("CANNOT FIND postdiv1/2 to make fout in range from 800M to 2000M,fout = %lu\n",
|
|
+ fout_hz);
|
|
+ } else {
|
|
+ *postdiv1 = 1;
|
|
+ *postdiv2 = 1;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static struct rockchip_pll_rate_table *
|
|
+rockchip_pll_clk_set_by_auto(struct rockchip_clk_pll *pll,
|
|
+ unsigned long fin_hz,
|
|
+ unsigned long fout_hz)
|
|
+{
|
|
+ struct rockchip_pll_rate_table *rate_table = rk_pll_rate_table_get();
|
|
+ /* FIXME set postdiv1/2 always 1*/
|
|
+ u32 foutvco = fout_hz;
|
|
+ u64 fin_64, frac_64;
|
|
+ u32 f_frac, postdiv1, postdiv2;
|
|
+ unsigned long clk_gcd = 0;
|
|
+
|
|
+ if (fin_hz == 0 || fout_hz == 0 || fout_hz == fin_hz)
|
|
+ return NULL;
|
|
+
|
|
+ rockchip_pll_clk_set_postdiv(fout_hz, &postdiv1, &postdiv2, &foutvco);
|
|
+ rate_table->postdiv1 = postdiv1;
|
|
+ rate_table->postdiv2 = postdiv2;
|
|
+ rate_table->dsmpd = 1;
|
|
+
|
|
+ if (fin_hz / MHZ * MHZ == fin_hz && fout_hz / MHZ * MHZ == fout_hz) {
|
|
+ fin_hz /= MHZ;
|
|
+ foutvco /= MHZ;
|
|
+ clk_gcd = gcd(fin_hz, foutvco);
|
|
+ rate_table->refdiv = fin_hz / clk_gcd;
|
|
+ rate_table->fbdiv = foutvco / clk_gcd;
|
|
+
|
|
+ rate_table->frac = 0;
|
|
+
|
|
+ pr_debug("fin = %lu, fout = %lu, clk_gcd = %lu, refdiv = %u, fbdiv = %u, postdiv1 = %u, postdiv2 = %u, frac = %u\n",
|
|
+ fin_hz, fout_hz, clk_gcd, rate_table->refdiv,
|
|
+ rate_table->fbdiv, rate_table->postdiv1,
|
|
+ rate_table->postdiv2, rate_table->frac);
|
|
+ } else {
|
|
+ pr_debug("frac div running, fin_hz = %lu, fout_hz = %lu, fin_INT_mhz = %lu, fout_INT_mhz = %lu\n",
|
|
+ fin_hz, fout_hz,
|
|
+ fin_hz / MHZ * MHZ,
|
|
+ fout_hz / MHZ * MHZ);
|
|
+ pr_debug("frac get postdiv1 = %u, postdiv2 = %u, foutvco = %u\n",
|
|
+ rate_table->postdiv1, rate_table->postdiv2, foutvco);
|
|
+ clk_gcd = gcd(fin_hz / MHZ, foutvco / MHZ);
|
|
+ rate_table->refdiv = fin_hz / MHZ / clk_gcd;
|
|
+ rate_table->fbdiv = foutvco / MHZ / clk_gcd;
|
|
+ pr_debug("frac get refdiv = %u, fbdiv = %u\n",
|
|
+ rate_table->refdiv, rate_table->fbdiv);
|
|
+
|
|
+ rate_table->frac = 0;
|
|
+
|
|
+ f_frac = (foutvco % MHZ);
|
|
+ fin_64 = fin_hz;
|
|
+ do_div(fin_64, (u64)rate_table->refdiv);
|
|
+ frac_64 = (u64)f_frac << 24;
|
|
+ do_div(frac_64, fin_64);
|
|
+ rate_table->frac = (u32)frac_64;
|
|
+ if (rate_table->frac > 0)
|
|
+ rate_table->dsmpd = 0;
|
|
+ pr_debug("frac = %x\n", rate_table->frac);
|
|
+ }
|
|
+ return rate_table;
|
|
+}
|
|
+
|
|
+static struct rockchip_pll_rate_table *
|
|
+rockchip_rk3066_pll_clk_set_by_auto(struct rockchip_clk_pll *pll,
|
|
+ unsigned long fin_hz,
|
|
+ unsigned long fout_hz)
|
|
+{
|
|
+ struct rockchip_pll_rate_table *rate_table = rk_pll_rate_table_get();
|
|
+ u32 nr, nf, no, nonr;
|
|
+ u32 nr_out, nf_out, no_out;
|
|
+ u32 n;
|
|
+ u32 numerator, denominator;
|
|
+ u64 fref, fvco, fout;
|
|
+ unsigned long clk_gcd = 0;
|
|
+
|
|
+ nr_out = PLL_NR_MAX + 1;
|
|
+ no_out = 0;
|
|
+ nf_out = 0;
|
|
+
|
|
+ if (fin_hz == 0 || fout_hz == 0 || fout_hz == fin_hz)
|
|
+ return NULL;
|
|
+
|
|
+ clk_gcd = gcd(fin_hz, fout_hz);
|
|
+
|
|
+ numerator = fout_hz / clk_gcd;
|
|
+ denominator = fin_hz / clk_gcd;
|
|
+
|
|
+ for (n = 1;; n++) {
|
|
+ nf = numerator * n;
|
|
+ nonr = denominator * n;
|
|
+ if (nf > PLL_NF_MAX || nonr > (PLL_NO_MAX * PLL_NR_MAX))
|
|
+ break;
|
|
+
|
|
+ for (no = 1; no <= PLL_NO_MAX; no++) {
|
|
+ if (!(no == 1 || !(no % 2)))
|
|
+ continue;
|
|
+
|
|
+ if (nonr % no)
|
|
+ continue;
|
|
+ nr = nonr / no;
|
|
+
|
|
+ if (nr > PLL_NR_MAX)
|
|
+ continue;
|
|
+
|
|
+ fref = fin_hz / nr;
|
|
+ if (fref < PLL_FREF_MIN || fref > PLL_FREF_MAX)
|
|
+ continue;
|
|
+
|
|
+ fvco = fref * nf;
|
|
+ if (fvco < PLL_FVCO_MIN || fvco > PLL_FVCO_MAX)
|
|
+ continue;
|
|
+
|
|
+ fout = fvco / no;
|
|
+ if (fout < PLL_FOUT_MIN || fout > PLL_FOUT_MAX)
|
|
+ continue;
|
|
+
|
|
+ /* select the best from all available PLL settings */
|
|
+ if ((no > no_out) ||
|
|
+ ((no == no_out) && (nr < nr_out))) {
|
|
+ nr_out = nr;
|
|
+ nf_out = nf;
|
|
+ no_out = no;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* output the best PLL setting */
|
|
+ if ((nr_out <= PLL_NR_MAX) && (no_out > 0)) {
|
|
+ rate_table->nr = nr_out;
|
|
+ rate_table->nf = nf_out;
|
|
+ rate_table->no = no_out;
|
|
+ } else {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return rate_table;
|
|
+}
|
|
+
|
|
static const struct rockchip_pll_rate_table *rockchip_get_pll_settings(
|
|
struct rockchip_clk_pll *pll, unsigned long rate)
|
|
{
|
|
@@ -58,24 +251,16 @@ static const struct rockchip_pll_rate_table *rockchip_get_pll_settings(
|
|
return &rate_table[i];
|
|
}
|
|
|
|
- return NULL;
|
|
+ if (pll->type == pll_rk3066)
|
|
+ return rockchip_rk3066_pll_clk_set_by_auto(pll, 24 * MHZ, rate);
|
|
+ else
|
|
+ return rockchip_pll_clk_set_by_auto(pll, 24 * MHZ, rate);
|
|
}
|
|
|
|
static long rockchip_pll_round_rate(struct clk_hw *hw,
|
|
unsigned long drate, unsigned long *prate)
|
|
{
|
|
- struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
|
|
- const struct rockchip_pll_rate_table *rate_table = pll->rate_table;
|
|
- int i;
|
|
-
|
|
- /* Assumming rate_table is in descending order */
|
|
- for (i = 0; i < pll->rate_count; i++) {
|
|
- if (drate >= rate_table[i].rate)
|
|
- return rate_table[i].rate;
|
|
- }
|
|
-
|
|
- /* return minimum supported value */
|
|
- return rate_table[i - 1].rate;
|
|
+ return drate;
|
|
}
|
|
|
|
/*
|
|
@@ -165,7 +350,7 @@ static unsigned long rockchip_rk3036_pll_recalc_rate(struct clk_hw *hw,
|
|
{
|
|
struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
|
|
struct rockchip_pll_rate_table cur;
|
|
- u64 rate64 = prate;
|
|
+ u64 rate64 = prate, frac_rate64 = prate;
|
|
|
|
rockchip_rk3036_pll_get_params(pll, &cur);
|
|
|
|
@@ -174,7 +359,7 @@ static unsigned long rockchip_rk3036_pll_recalc_rate(struct clk_hw *hw,
|
|
|
|
if (cur.dsmpd == 0) {
|
|
/* fractional mode */
|
|
- u64 frac_rate64 = prate * cur.frac;
|
|
+ frac_rate64 *= cur.frac;
|
|
|
|
do_div(frac_rate64, cur.refdiv);
|
|
rate64 += frac_rate64 >> 24;
|
|
|
|
From a408bfd669ef9e3f1a135d568dd13d4a460029c6 Mon Sep 17 00:00:00 2001
|
|
From: Yifeng Zhao <yifeng.zhao@rock-chips.com>
|
|
Date: Thu, 10 Dec 2020 08:21:31 +0800
|
|
Subject: [PATCH] dt-bindings: mtd: Describe Rockchip RK3xxx NAND flash
|
|
controller
|
|
|
|
Documentation support for Rockchip RK3xxx NAND flash controllers
|
|
|
|
Reviewed-by: Rob Herring <robh@kernel.org>
|
|
Signed-off-by: Yifeng Zhao <yifeng.zhao@rock-chips.com>
|
|
---
|
|
.../mtd/rockchip,nand-controller.yaml | 161 ++++++++++++++++++
|
|
1 file changed, 161 insertions(+)
|
|
create mode 100644 Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml
|
|
|
|
diff --git a/Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml b/Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml
|
|
new file mode 100644
|
|
index 000000000000..0922536b1811
|
|
--- /dev/null
|
|
+++ b/Documentation/devicetree/bindings/mtd/rockchip,nand-controller.yaml
|
|
@@ -0,0 +1,161 @@
|
|
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
|
+%YAML 1.2
|
|
+---
|
|
+$id: http://devicetree.org/schemas/mtd/rockchip,nand-controller.yaml#
|
|
+$schema: http://devicetree.org/meta-schemas/core.yaml#
|
|
+
|
|
+title: Rockchip SoCs NAND FLASH Controller (NFC)
|
|
+
|
|
+allOf:
|
|
+ - $ref: "nand-controller.yaml#"
|
|
+
|
|
+maintainers:
|
|
+ - Heiko Stuebner <heiko@sntech.de>
|
|
+
|
|
+properties:
|
|
+ compatible:
|
|
+ oneOf:
|
|
+ - const: rockchip,px30-nfc
|
|
+ - const: rockchip,rk2928-nfc
|
|
+ - const: rockchip,rv1108-nfc
|
|
+ - items:
|
|
+ - const: rockchip,rk3036-nfc
|
|
+ - const: rockchip,rk2928-nfc
|
|
+ - items:
|
|
+ - const: rockchip,rk3308-nfc
|
|
+ - const: rockchip,rv1108-nfc
|
|
+
|
|
+ reg:
|
|
+ maxItems: 1
|
|
+
|
|
+ interrupts:
|
|
+ maxItems: 1
|
|
+
|
|
+ clocks:
|
|
+ minItems: 1
|
|
+ items:
|
|
+ - description: Bus Clock
|
|
+ - description: Module Clock
|
|
+
|
|
+ clock-names:
|
|
+ minItems: 1
|
|
+ items:
|
|
+ - const: ahb
|
|
+ - const: nfc
|
|
+
|
|
+ assigned-clocks:
|
|
+ maxItems: 1
|
|
+
|
|
+ assigned-clock-rates:
|
|
+ maxItems: 1
|
|
+
|
|
+ power-domains:
|
|
+ maxItems: 1
|
|
+
|
|
+patternProperties:
|
|
+ "^nand@[0-7]$":
|
|
+ type: object
|
|
+ properties:
|
|
+ reg:
|
|
+ minimum: 0
|
|
+ maximum: 7
|
|
+
|
|
+ nand-ecc-mode:
|
|
+ const: hw
|
|
+
|
|
+ nand-ecc-step-size:
|
|
+ const: 1024
|
|
+
|
|
+ nand-ecc-strength:
|
|
+ enum: [16, 24, 40, 60, 70]
|
|
+ description: |
|
|
+ The ECC configurations that can be supported are as follows.
|
|
+ NFC v600 ECC 16, 24, 40, 60
|
|
+ RK2928, RK3066, RK3188
|
|
+
|
|
+ NFC v622 ECC 16, 24, 40, 60
|
|
+ RK3036, RK3128
|
|
+
|
|
+ NFC v800 ECC 16
|
|
+ RK3308, RV1108
|
|
+
|
|
+ NFC v900 ECC 16, 40, 60, 70
|
|
+ RK3326, PX30
|
|
+
|
|
+ nand-bus-width:
|
|
+ const: 8
|
|
+
|
|
+ rockchip,boot-blks:
|
|
+ $ref: /schemas/types.yaml#/definitions/uint32
|
|
+ minimum: 2
|
|
+ default: 16
|
|
+ description:
|
|
+ The NFC driver need this information to select ECC
|
|
+ algorithms supported by the boot ROM.
|
|
+ Only used in combination with 'nand-is-boot-medium'.
|
|
+
|
|
+ rockchip,boot-ecc-strength:
|
|
+ enum: [16, 24, 40, 60, 70]
|
|
+ allOf:
|
|
+ - $ref: /schemas/types.yaml#/definitions/uint32
|
|
+ description: |
|
|
+ If specified it indicates that a different BCH/ECC setting is
|
|
+ supported by the boot ROM.
|
|
+ NFC v600 ECC 16, 24
|
|
+ RK2928, RK3066, RK3188
|
|
+
|
|
+ NFC v622 ECC 16, 24, 40, 60
|
|
+ RK3036, RK3128
|
|
+
|
|
+ NFC v800 ECC 16
|
|
+ RK3308, RV1108
|
|
+
|
|
+ NFC v900 ECC 16, 70
|
|
+ RK3326, PX30
|
|
+
|
|
+ Only used in combination with 'nand-is-boot-medium'.
|
|
+
|
|
+required:
|
|
+ - compatible
|
|
+ - reg
|
|
+ - interrupts
|
|
+ - clocks
|
|
+ - clock-names
|
|
+
|
|
+unevaluatedProperties: false
|
|
+
|
|
+examples:
|
|
+ - |
|
|
+ #include <dt-bindings/clock/rk3308-cru.h>
|
|
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
|
|
+ nfc: nand-controller@ff4b0000 {
|
|
+ compatible = "rockchip,rk3308-nfc",
|
|
+ "rockchip,rv1108-nfc";
|
|
+ reg = <0xff4b0000 0x4000>;
|
|
+ interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ clocks = <&cru HCLK_NANDC>, <&cru SCLK_NANDC>;
|
|
+ clock-names = "ahb", "nfc";
|
|
+ assigned-clocks = <&clks SCLK_NANDC>;
|
|
+ assigned-clock-rates = <150000000>;
|
|
+
|
|
+ pinctrl-0 = <&flash_ale &flash_bus8 &flash_cle &flash_csn0
|
|
+ &flash_rdn &flash_rdy &flash_wrn>;
|
|
+ pinctrl-names = "default";
|
|
+
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+
|
|
+ nand@0 {
|
|
+ reg = <0>;
|
|
+ label = "rk-nand";
|
|
+ nand-bus-width = <8>;
|
|
+ nand-ecc-mode = "hw";
|
|
+ nand-ecc-step-size = <1024>;
|
|
+ nand-ecc-strength = <16>;
|
|
+ nand-is-boot-medium;
|
|
+ rockchip,boot-blks = <8>;
|
|
+ rockchip,boot-ecc-strength = <16>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+...
|
|
|
|
From 7cce4b781394b2f4f31b4dd4e2c0ce9e7c10f4ca Mon Sep 17 00:00:00 2001
|
|
From: Yifeng Zhao <yifeng.zhao@rock-chips.com>
|
|
Date: Thu, 10 Dec 2020 08:21:32 +0800
|
|
Subject: [PATCH] mtd: rawnand: rockchip: NFC drivers for RK3308, RK2928 and
|
|
others
|
|
|
|
This driver supports Rockchip NFC (NAND Flash Controller) found on RK3308,
|
|
RK2928, RKPX30, RV1108 and other SOCs. The driver has been tested using
|
|
8-bit NAND interface on the ARM based RK3308 platform.
|
|
|
|
Support Rockchip SoCs and NFC versions:
|
|
- PX30 and RK3326(NFCv900).
|
|
ECC: 16/40/60/70 bits/1KB.
|
|
CLOCK: ahb and nfc.
|
|
- RK3308 and RV1108(NFCv800).
|
|
ECC: 16 bits/1KB.
|
|
CLOCK: ahb and nfc.
|
|
- RK3036 and RK3128(NFCv622).
|
|
ECC: 16/24/40/60 bits/1KB.
|
|
CLOCK: ahb and nfc.
|
|
- RK3066, RK3188 and RK2928(NFCv600).
|
|
ECC: 16/24/40/60 bits/1KB.
|
|
CLOCK: ahb.
|
|
|
|
Supported features:
|
|
- Read full page data by DMA.
|
|
- Support HW ECC(one step is 1KB).
|
|
- Support 2 - 32K page size.
|
|
- Support 8 CS(depend on SoCs)
|
|
|
|
Limitations:
|
|
- No support for the ecc step size is 512.
|
|
- Untested on some SoCs.
|
|
- No support for subpages.
|
|
- No support for the builtin randomizer.
|
|
- The original bad block mask is not supported. It is recommended to use
|
|
the BBT(bad block table).
|
|
|
|
Suggested-by: Johan Jonker <jbx6244@gmail.com>
|
|
Signed-off-by: Yifeng Zhao <yifeng.zhao@rock-chips.com>
|
|
---
|
|
drivers/mtd/nand/raw/Kconfig | 12 +
|
|
drivers/mtd/nand/raw/Makefile | 1 +
|
|
.../mtd/nand/raw/rockchip-nand-controller.c | 1495 +++++++++++++++++
|
|
3 files changed, 1508 insertions(+)
|
|
create mode 100644 drivers/mtd/nand/raw/rockchip-nand-controller.c
|
|
|
|
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
|
|
index 6c46f25b57e2..2cc533e4e239 100644
|
|
--- a/drivers/mtd/nand/raw/Kconfig
|
|
+++ b/drivers/mtd/nand/raw/Kconfig
|
|
@@ -462,6 +462,18 @@ config MTD_NAND_ARASAN
|
|
Enables the driver for the Arasan NAND flash controller on
|
|
Zynq Ultrascale+ MPSoC.
|
|
|
|
+config MTD_NAND_ROCKCHIP
|
|
+ tristate "Rockchip NAND controller"
|
|
+ depends on ARCH_ROCKCHIP && HAS_IOMEM
|
|
+ help
|
|
+ Enables support for NAND controller on Rockchip SoCs.
|
|
+ There are four different versions of NAND FLASH Controllers,
|
|
+ including:
|
|
+ NFC v600: RK2928, RK3066, RK3188
|
|
+ NFC v622: RK3036, RK3128
|
|
+ NFC v800: RK3308, RV1108
|
|
+ NFC v900: PX30, RK3326
|
|
+
|
|
comment "Misc"
|
|
|
|
config MTD_SM_COMMON
|
|
diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile
|
|
index 2930f5b9015d..960c9be25204 100644
|
|
--- a/drivers/mtd/nand/raw/Makefile
|
|
+++ b/drivers/mtd/nand/raw/Makefile
|
|
@@ -58,6 +58,7 @@ obj-$(CONFIG_MTD_NAND_STM32_FMC2) += stm32_fmc2_nand.o
|
|
obj-$(CONFIG_MTD_NAND_MESON) += meson_nand.o
|
|
obj-$(CONFIG_MTD_NAND_CADENCE) += cadence-nand-controller.o
|
|
obj-$(CONFIG_MTD_NAND_ARASAN) += arasan-nand-controller.o
|
|
+obj-$(CONFIG_MTD_NAND_ROCKCHIP) += rockchip-nand-controller.o
|
|
|
|
nand-objs := nand_base.o nand_legacy.o nand_bbt.o nand_timings.o nand_ids.o
|
|
nand-objs += nand_onfi.o
|
|
diff --git a/drivers/mtd/nand/raw/rockchip-nand-controller.c b/drivers/mtd/nand/raw/rockchip-nand-controller.c
|
|
new file mode 100644
|
|
index 000000000000..796b678cb108
|
|
--- /dev/null
|
|
+++ b/drivers/mtd/nand/raw/rockchip-nand-controller.c
|
|
@@ -0,0 +1,1495 @@
|
|
+// SPDX-License-Identifier: GPL-2.0 OR MIT
|
|
+/*
|
|
+ * Rockchip NAND Flash controller driver.
|
|
+ * Copyright (C) 2020 Rockchip Inc.
|
|
+ * Author: Yifeng Zhao <yifeng.zhao@rock-chips.com>
|
|
+ */
|
|
+
|
|
+#include <linux/clk.h>
|
|
+#include <linux/delay.h>
|
|
+#include <linux/dma-mapping.h>
|
|
+#include <linux/dmaengine.h>
|
|
+#include <linux/interrupt.h>
|
|
+#include <linux/iopoll.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/mtd/mtd.h>
|
|
+#include <linux/mtd/rawnand.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/of_device.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/slab.h>
|
|
+
|
|
+/*
|
|
+ * NFC Page Data Layout:
|
|
+ * 1024 bytes data + 4Bytes sys data + 28Bytes~124Bytes ECC data +
|
|
+ * 1024 bytes data + 4Bytes sys data + 28Bytes~124Bytes ECC data +
|
|
+ * ......
|
|
+ * NAND Page Data Layout:
|
|
+ * 1024 * n data + m Bytes oob
|
|
+ * Original Bad Block Mask Location:
|
|
+ * First byte of oob(spare).
|
|
+ * nand_chip->oob_poi data layout:
|
|
+ * 4Bytes sys data + .... + 4Bytes sys data + ECC data.
|
|
+ */
|
|
+
|
|
+/* NAND controller register definition */
|
|
+#define NFC_READ (0)
|
|
+#define NFC_WRITE (1)
|
|
+
|
|
+#define NFC_FMCTL (0x00)
|
|
+#define FMCTL_CE_SEL_M 0xFF
|
|
+#define FMCTL_CE_SEL(x) (1 << (x))
|
|
+#define FMCTL_WP BIT(8)
|
|
+#define FMCTL_RDY BIT(9)
|
|
+
|
|
+#define NFC_FMWAIT (0x04)
|
|
+#define FLCTL_RST BIT(0)
|
|
+#define FLCTL_WR (1) /* 0: read, 1: write */
|
|
+#define FLCTL_XFER_ST BIT(2)
|
|
+#define FLCTL_XFER_EN BIT(3)
|
|
+#define FLCTL_ACORRECT BIT(10) /* Auto correct error bits. */
|
|
+#define FLCTL_XFER_READY BIT(20)
|
|
+#define FLCTL_XFER_SECTOR (22)
|
|
+#define FLCTL_TOG_FIX BIT(29)
|
|
+
|
|
+#define BCHCTL_BANK_M (7 << 5)
|
|
+#define BCHCTL_BANK (5)
|
|
+
|
|
+#define DMA_ST BIT(0)
|
|
+#define DMA_WR (1) /* 0: write, 1: read */
|
|
+#define DMA_EN BIT(2)
|
|
+#define DMA_AHB_SIZE (3) /* 0: 1, 1: 2, 2: 4 */
|
|
+#define DMA_BURST_SIZE (6) /* 0: 1, 3: 4, 5: 8, 7: 16 */
|
|
+#define DMA_INC_NUM (9) /* 1 - 16 */
|
|
+
|
|
+#define ECC_ERR_CNT(x, e) ((((x) >> (e).low) & (e).low_mask) |\
|
|
+ (((x) >> (e).high) & (e).high_mask) << (e).low_bn)
|
|
+#define INT_DMA BIT(0)
|
|
+#define NFC_BANK (0x800)
|
|
+#define NFC_BANK_STEP (0x100)
|
|
+#define BANK_DATA (0x00)
|
|
+#define BANK_ADDR (0x04)
|
|
+#define BANK_CMD (0x08)
|
|
+#define NFC_SRAM0 (0x1000)
|
|
+#define NFC_SRAM1 (0x1400)
|
|
+#define NFC_SRAM_SIZE (0x400)
|
|
+#define NFC_TIMEOUT (500000)
|
|
+#define NFC_MAX_OOB_PER_STEP 128
|
|
+#define NFC_MIN_OOB_PER_STEP 64
|
|
+#define MAX_DATA_SIZE 0xFFFC
|
|
+#define MAX_ADDRESS_CYC 6
|
|
+#define NFC_ECC_MAX_MODES 4
|
|
+#define NFC_MAX_NSELS (8) /* Some Socs only have 1 or 2 CSs. */
|
|
+#define NFC_SYS_DATA_SIZE (4) /* 4 bytes sys data in oob pre 1024 data.*/
|
|
+#define RK_DEFAULT_CLOCK_RATE (150 * 1000 * 1000) /* 150 Mhz */
|
|
+#define ACCTIMING(csrw, rwpw, rwcs) ((csrw) << 12 | (rwpw) << 5 | (rwcs))
|
|
+
|
|
+enum nfc_type {
|
|
+ NFC_V6,
|
|
+ NFC_V8,
|
|
+ NFC_V9,
|
|
+};
|
|
+
|
|
+/**
|
|
+ * struct rk_ecc_cnt_status: represent a ecc status data.
|
|
+ * @err_flag_bit: error flag bit index at register.
|
|
+ * @low: ECC count low bit index at register.
|
|
+ * @low_mask: mask bit.
|
|
+ * @low_bn: ECC count low bit number.
|
|
+ * @high: ECC count high bit index at register.
|
|
+ * @high_mask: mask bit
|
|
+ */
|
|
+struct ecc_cnt_status {
|
|
+ u8 err_flag_bit;
|
|
+ u8 low;
|
|
+ u8 low_mask;
|
|
+ u8 low_bn;
|
|
+ u8 high;
|
|
+ u8 high_mask;
|
|
+};
|
|
+
|
|
+/**
|
|
+ * @type: NFC version
|
|
+ * @ecc_strengths: ECC strengths
|
|
+ * @ecc_cfgs: ECC config values
|
|
+ * @flctl_off: FLCTL register offset
|
|
+ * @bchctl_off: BCHCTL register offset
|
|
+ * @dma_data_buf_off: DMA_DATA_BUF register offset
|
|
+ * @dma_oob_buf_off: DMA_OOB_BUF register offset
|
|
+ * @dma_cfg_off: DMA_CFG register offset
|
|
+ * @dma_st_off: DMA_ST register offset
|
|
+ * @bch_st_off: BCG_ST register offset
|
|
+ * @randmz_off: RANDMZ register offset
|
|
+ * @int_en_off: interrupt enable register offset
|
|
+ * @int_clr_off: interrupt clean register offset
|
|
+ * @int_st_off: interrupt status register offset
|
|
+ * @oob0_off: oob0 register offset
|
|
+ * @oob1_off: oob1 register offset
|
|
+ * @ecc0: represent ECC0 status data
|
|
+ * @ecc1: represent ECC1 status data
|
|
+ */
|
|
+struct nfc_cfg {
|
|
+ enum nfc_type type;
|
|
+ u8 ecc_strengths[NFC_ECC_MAX_MODES];
|
|
+ u32 ecc_cfgs[NFC_ECC_MAX_MODES];
|
|
+ u32 flctl_off;
|
|
+ u32 bchctl_off;
|
|
+ u32 dma_cfg_off;
|
|
+ u32 dma_data_buf_off;
|
|
+ u32 dma_oob_buf_off;
|
|
+ u32 dma_st_off;
|
|
+ u32 bch_st_off;
|
|
+ u32 randmz_off;
|
|
+ u32 int_en_off;
|
|
+ u32 int_clr_off;
|
|
+ u32 int_st_off;
|
|
+ u32 oob0_off;
|
|
+ u32 oob1_off;
|
|
+ struct ecc_cnt_status ecc0;
|
|
+ struct ecc_cnt_status ecc1;
|
|
+};
|
|
+
|
|
+struct rk_nfc_nand_chip {
|
|
+ struct list_head node;
|
|
+ struct nand_chip chip;
|
|
+
|
|
+ u16 boot_blks;
|
|
+ u16 metadata_size;
|
|
+ u32 boot_ecc;
|
|
+ u32 timing;
|
|
+
|
|
+ u8 nsels;
|
|
+ u8 sels[0];
|
|
+ /* Nothing after this field. */
|
|
+};
|
|
+
|
|
+struct rk_nfc {
|
|
+ struct nand_controller controller;
|
|
+ const struct nfc_cfg *cfg;
|
|
+ struct device *dev;
|
|
+
|
|
+ struct clk *nfc_clk;
|
|
+ struct clk *ahb_clk;
|
|
+ void __iomem *regs;
|
|
+
|
|
+ u32 selected_bank;
|
|
+ u32 band_offset;
|
|
+ u32 cur_ecc;
|
|
+ u32 cur_timing;
|
|
+
|
|
+ struct completion done;
|
|
+ struct list_head chips;
|
|
+
|
|
+ u8 *page_buf;
|
|
+ u32 *oob_buf;
|
|
+ u32 page_buf_size;
|
|
+ u32 oob_buf_size;
|
|
+
|
|
+ unsigned long assigned_cs;
|
|
+};
|
|
+
|
|
+static inline struct rk_nfc_nand_chip *rk_nfc_to_rknand(struct nand_chip *chip)
|
|
+{
|
|
+ return container_of(chip, struct rk_nfc_nand_chip, chip);
|
|
+}
|
|
+
|
|
+static inline u8 *rk_nfc_buf_to_data_ptr(struct nand_chip *chip, const u8 *p, int i)
|
|
+{
|
|
+ return (u8 *)p + i * chip->ecc.size;
|
|
+}
|
|
+
|
|
+static inline u8 *rk_nfc_buf_to_oob_ptr(struct nand_chip *chip, int i)
|
|
+{
|
|
+ u8 *poi;
|
|
+
|
|
+ poi = chip->oob_poi + i * NFC_SYS_DATA_SIZE;
|
|
+
|
|
+ return poi;
|
|
+}
|
|
+
|
|
+static inline u8 *rk_nfc_buf_to_oob_ecc_ptr(struct nand_chip *chip, int i)
|
|
+{
|
|
+ struct rk_nfc_nand_chip *rknand = rk_nfc_to_rknand(chip);
|
|
+ u8 *poi;
|
|
+
|
|
+ poi = chip->oob_poi + rknand->metadata_size + chip->ecc.bytes * i;
|
|
+
|
|
+ return poi;
|
|
+}
|
|
+
|
|
+static inline int rk_nfc_data_len(struct nand_chip *chip)
|
|
+{
|
|
+ return chip->ecc.size + chip->ecc.bytes + NFC_SYS_DATA_SIZE;
|
|
+}
|
|
+
|
|
+static inline u8 *rk_nfc_data_ptr(struct nand_chip *chip, int i)
|
|
+{
|
|
+ struct rk_nfc *nfc = nand_get_controller_data(chip);
|
|
+
|
|
+ return nfc->page_buf + i * rk_nfc_data_len(chip);
|
|
+}
|
|
+
|
|
+static inline u8 *rk_nfc_oob_ptr(struct nand_chip *chip, int i)
|
|
+{
|
|
+ struct rk_nfc *nfc = nand_get_controller_data(chip);
|
|
+
|
|
+ return nfc->page_buf + i * rk_nfc_data_len(chip) + chip->ecc.size;
|
|
+}
|
|
+
|
|
+static int rk_nfc_hw_ecc_setup(struct nand_chip *chip, u32 strength)
|
|
+{
|
|
+ struct rk_nfc *nfc = nand_get_controller_data(chip);
|
|
+ u32 reg, i;
|
|
+
|
|
+ for (i = 0; i < NFC_ECC_MAX_MODES; i++) {
|
|
+ if (strength == nfc->cfg->ecc_strengths[i]) {
|
|
+ reg = nfc->cfg->ecc_cfgs[i];
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (i >= NFC_ECC_MAX_MODES)
|
|
+ return -EINVAL;
|
|
+
|
|
+ writel(reg, nfc->regs + nfc->cfg->bchctl_off);
|
|
+
|
|
+ /* Save chip ECC setting */
|
|
+ nfc->cur_ecc = strength;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void rk_nfc_select_chip(struct nand_chip *chip, int cs)
|
|
+{
|
|
+ struct rk_nfc *nfc = nand_get_controller_data(chip);
|
|
+ struct rk_nfc_nand_chip *rknand = rk_nfc_to_rknand(chip);
|
|
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
|
|
+ u32 val;
|
|
+
|
|
+ if (cs < 0) {
|
|
+ nfc->selected_bank = -1;
|
|
+ /* Deselect the currently selected target. */
|
|
+ val = readl_relaxed(nfc->regs + NFC_FMCTL);
|
|
+ val &= ~FMCTL_CE_SEL_M;
|
|
+ writel(val, nfc->regs + NFC_FMCTL);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ nfc->selected_bank = rknand->sels[cs];
|
|
+ nfc->band_offset = NFC_BANK + nfc->selected_bank * NFC_BANK_STEP;
|
|
+
|
|
+ val = readl_relaxed(nfc->regs + NFC_FMCTL);
|
|
+ val &= ~FMCTL_CE_SEL_M;
|
|
+ val |= FMCTL_CE_SEL(nfc->selected_bank);
|
|
+
|
|
+ writel(val, nfc->regs + NFC_FMCTL);
|
|
+
|
|
+ /*
|
|
+ * Compare current chip timing with selected chip timing and
|
|
+ * change if needed.
|
|
+ */
|
|
+ if (nfc->cur_timing != rknand->timing) {
|
|
+ writel(rknand->timing, nfc->regs + NFC_FMWAIT);
|
|
+ nfc->cur_timing = rknand->timing;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Compare current chip ECC setting with selected chip ECC setting and
|
|
+ * change if needed.
|
|
+ */
|
|
+ if (nfc->cur_ecc != ecc->strength)
|
|
+ rk_nfc_hw_ecc_setup(chip, ecc->strength);
|
|
+}
|
|
+
|
|
+static inline int rk_nfc_wait_ioready(struct rk_nfc *nfc)
|
|
+{
|
|
+ int rc;
|
|
+ u32 val;
|
|
+
|
|
+ rc = readl_relaxed_poll_timeout(nfc->regs + NFC_FMCTL, val,
|
|
+ val & FMCTL_RDY, 10, NFC_TIMEOUT);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static void rk_nfc_read_buf(struct rk_nfc *nfc, u8 *buf, int len)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < len; i++)
|
|
+ buf[i] = readb_relaxed(nfc->regs + nfc->band_offset +
|
|
+ BANK_DATA);
|
|
+}
|
|
+
|
|
+static void rk_nfc_write_buf(struct rk_nfc *nfc, const u8 *buf, int len)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < len; i++)
|
|
+ writeb(buf[i], nfc->regs + nfc->band_offset + BANK_DATA);
|
|
+}
|
|
+
|
|
+static int rk_nfc_cmd(struct nand_chip *chip,
|
|
+ const struct nand_subop *subop)
|
|
+{
|
|
+ struct rk_nfc *nfc = nand_get_controller_data(chip);
|
|
+ unsigned int i, j, remaining, start;
|
|
+ int reg_offset = nfc->band_offset;
|
|
+ u8 *inbuf = NULL;
|
|
+ const u8 *outbuf;
|
|
+ u32 cnt = 0;
|
|
+ int ret = 0;
|
|
+
|
|
+ for (i = 0; i < subop->ninstrs; i++) {
|
|
+ const struct nand_op_instr *instr = &subop->instrs[i];
|
|
+
|
|
+ switch (instr->type) {
|
|
+ case NAND_OP_CMD_INSTR:
|
|
+ writeb(instr->ctx.cmd.opcode,
|
|
+ nfc->regs + reg_offset + BANK_CMD);
|
|
+ break;
|
|
+
|
|
+ case NAND_OP_ADDR_INSTR:
|
|
+ remaining = nand_subop_get_num_addr_cyc(subop, i);
|
|
+ start = nand_subop_get_addr_start_off(subop, i);
|
|
+
|
|
+ for (j = 0; j < 8 && j + start < remaining; j++)
|
|
+ writeb(instr->ctx.addr.addrs[j + start],
|
|
+ nfc->regs + reg_offset + BANK_ADDR);
|
|
+ break;
|
|
+
|
|
+ case NAND_OP_DATA_IN_INSTR:
|
|
+ case NAND_OP_DATA_OUT_INSTR:
|
|
+ start = nand_subop_get_data_start_off(subop, i);
|
|
+ cnt = nand_subop_get_data_len(subop, i);
|
|
+
|
|
+ if (instr->type == NAND_OP_DATA_OUT_INSTR) {
|
|
+ outbuf = instr->ctx.data.buf.out + start;
|
|
+ rk_nfc_write_buf(nfc, outbuf, cnt);
|
|
+ } else {
|
|
+ inbuf = instr->ctx.data.buf.in + start;
|
|
+ rk_nfc_read_buf(nfc, inbuf, cnt);
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case NAND_OP_WAITRDY_INSTR:
|
|
+ if (rk_nfc_wait_ioready(nfc) < 0) {
|
|
+ ret = -ETIMEDOUT;
|
|
+ dev_err(nfc->dev, "IO not ready\n");
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static const struct nand_op_parser rk_nfc_op_parser = NAND_OP_PARSER(
|
|
+ NAND_OP_PARSER_PATTERN(
|
|
+ rk_nfc_cmd,
|
|
+ NAND_OP_PARSER_PAT_CMD_ELEM(true),
|
|
+ NAND_OP_PARSER_PAT_ADDR_ELEM(true, MAX_ADDRESS_CYC),
|
|
+ NAND_OP_PARSER_PAT_CMD_ELEM(true),
|
|
+ NAND_OP_PARSER_PAT_WAITRDY_ELEM(true),
|
|
+ NAND_OP_PARSER_PAT_DATA_IN_ELEM(true, MAX_DATA_SIZE)),
|
|
+ NAND_OP_PARSER_PATTERN(
|
|
+ rk_nfc_cmd,
|
|
+ NAND_OP_PARSER_PAT_CMD_ELEM(true),
|
|
+ NAND_OP_PARSER_PAT_ADDR_ELEM(true, MAX_ADDRESS_CYC),
|
|
+ NAND_OP_PARSER_PAT_DATA_OUT_ELEM(true, MAX_DATA_SIZE),
|
|
+ NAND_OP_PARSER_PAT_CMD_ELEM(true),
|
|
+ NAND_OP_PARSER_PAT_WAITRDY_ELEM(true)),
|
|
+);
|
|
+
|
|
+static int rk_nfc_exec_op(struct nand_chip *chip,
|
|
+ const struct nand_operation *op,
|
|
+ bool check_only)
|
|
+{
|
|
+ if (!check_only)
|
|
+ rk_nfc_select_chip(chip, op->cs);
|
|
+
|
|
+ return nand_op_parser_exec_op(chip, &rk_nfc_op_parser, op,
|
|
+ check_only);
|
|
+}
|
|
+
|
|
+static int rk_nfc_setup_interface(struct nand_chip *chip, int target,
|
|
+ const struct nand_interface_config *conf)
|
|
+{
|
|
+ struct rk_nfc_nand_chip *rknand = rk_nfc_to_rknand(chip);
|
|
+ struct rk_nfc *nfc = nand_get_controller_data(chip);
|
|
+ const struct nand_sdr_timings *timings;
|
|
+ u32 rate, tc2rw, trwpw, trw2c;
|
|
+ u32 temp;
|
|
+
|
|
+ if (target < 0)
|
|
+ return 0;
|
|
+
|
|
+ timings = nand_get_sdr_timings(conf);
|
|
+ if (IS_ERR(timings))
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ if (IS_ERR(nfc->nfc_clk))
|
|
+ rate = clk_get_rate(nfc->ahb_clk);
|
|
+ else
|
|
+ rate = clk_get_rate(nfc->nfc_clk);
|
|
+
|
|
+ /* Turn clock rate into kHz. */
|
|
+ rate /= 1000;
|
|
+
|
|
+ tc2rw = 1;
|
|
+ trw2c = 1;
|
|
+
|
|
+ trwpw = max(timings->tWC_min, timings->tRC_min) / 1000;
|
|
+ trwpw = DIV_ROUND_UP(trwpw * rate, 1000000);
|
|
+
|
|
+ temp = timings->tREA_max / 1000;
|
|
+ temp = DIV_ROUND_UP(temp * rate, 1000000);
|
|
+
|
|
+ if (trwpw < temp)
|
|
+ trwpw = temp;
|
|
+
|
|
+ /*
|
|
+ * ACCON: access timing control register
|
|
+ * -------------------------------------
|
|
+ * 31:18: reserved
|
|
+ * 17:12: csrw, clock cycles from the falling edge of CSn to the
|
|
+ * falling edge of RDn or WRn
|
|
+ * 11:11: reserved
|
|
+ * 10:05: rwpw, the width of RDn or WRn in processor clock cycles
|
|
+ * 04:00: rwcs, clock cycles from the rising edge of RDn or WRn to the
|
|
+ * rising edge of CSn
|
|
+ */
|
|
+
|
|
+ /* Save chip timing */
|
|
+ rknand->timing = ACCTIMING(tc2rw, trwpw, trw2c);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void rk_nfc_xfer_start(struct rk_nfc *nfc, u8 rw, u8 n_KB,
|
|
+ dma_addr_t dma_data, dma_addr_t dma_oob)
|
|
+{
|
|
+ u32 dma_reg, fl_reg, bch_reg;
|
|
+
|
|
+ dma_reg = DMA_ST | ((!rw) << DMA_WR) | DMA_EN | (2 << DMA_AHB_SIZE) |
|
|
+ (7 << DMA_BURST_SIZE) | (16 << DMA_INC_NUM);
|
|
+
|
|
+ fl_reg = (rw << FLCTL_WR) | FLCTL_XFER_EN | FLCTL_ACORRECT |
|
|
+ (n_KB << FLCTL_XFER_SECTOR) | FLCTL_TOG_FIX;
|
|
+
|
|
+ if (nfc->cfg->type == NFC_V6 || nfc->cfg->type == NFC_V8) {
|
|
+ bch_reg = readl_relaxed(nfc->regs + nfc->cfg->bchctl_off);
|
|
+ bch_reg = (bch_reg & (~BCHCTL_BANK_M)) |
|
|
+ (nfc->selected_bank << BCHCTL_BANK);
|
|
+ writel(bch_reg, nfc->regs + nfc->cfg->bchctl_off);
|
|
+ }
|
|
+
|
|
+ writel(dma_reg, nfc->regs + nfc->cfg->dma_cfg_off);
|
|
+ writel((u32)dma_data, nfc->regs + nfc->cfg->dma_data_buf_off);
|
|
+ writel((u32)dma_oob, nfc->regs + nfc->cfg->dma_oob_buf_off);
|
|
+ writel(fl_reg, nfc->regs + nfc->cfg->flctl_off);
|
|
+ fl_reg |= FLCTL_XFER_ST;
|
|
+ writel(fl_reg, nfc->regs + nfc->cfg->flctl_off);
|
|
+}
|
|
+
|
|
+static int rk_nfc_wait_for_xfer_done(struct rk_nfc *nfc)
|
|
+{
|
|
+ void __iomem *ptr;
|
|
+ u32 reg;
|
|
+
|
|
+ ptr = nfc->regs + nfc->cfg->flctl_off;
|
|
+
|
|
+ return readl_relaxed_poll_timeout(ptr, reg,
|
|
+ reg & FLCTL_XFER_READY,
|
|
+ 10, NFC_TIMEOUT);
|
|
+}
|
|
+
|
|
+static int rk_nfc_write_page_raw(struct nand_chip *chip, const u8 *buf,
|
|
+ int oob_on, int page)
|
|
+{
|
|
+ struct rk_nfc_nand_chip *rknand = rk_nfc_to_rknand(chip);
|
|
+ struct rk_nfc *nfc = nand_get_controller_data(chip);
|
|
+ struct mtd_info *mtd = nand_to_mtd(chip);
|
|
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
|
|
+ int i, pages_per_blk;
|
|
+
|
|
+ pages_per_blk = mtd->erasesize / mtd->writesize;
|
|
+ if ((chip->options & NAND_IS_BOOT_MEDIUM) &&
|
|
+ (page < (pages_per_blk * rknand->boot_blks)) &&
|
|
+ rknand->boot_ecc != ecc->strength) {
|
|
+ /*
|
|
+ * There's currently no method to notify the MTD framework that
|
|
+ * a different ECC strength is in use for the boot blocks.
|
|
+ */
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ if (!buf)
|
|
+ memset(nfc->page_buf, 0xff, mtd->writesize + mtd->oobsize);
|
|
+
|
|
+ for (i = 0; i < ecc->steps; i++) {
|
|
+ /* Copy data to the NFC buffer. */
|
|
+ if (buf)
|
|
+ memcpy(rk_nfc_data_ptr(chip, i),
|
|
+ rk_nfc_buf_to_data_ptr(chip, buf, i),
|
|
+ ecc->size);
|
|
+ /*
|
|
+ * The first four bytes of OOB are reserved for the
|
|
+ * boot ROM. In some debugging cases, such as with a
|
|
+ * read, erase and write back test these 4 bytes stored
|
|
+ * in OOB also need to be written back.
|
|
+ *
|
|
+ * The function nand_block_bad detects bad blocks like:
|
|
+ *
|
|
+ * bad = chip->oob_poi[chip->badblockpos];
|
|
+ *
|
|
+ * chip->badblockpos == 0 for a large page NAND Flash,
|
|
+ * so chip->oob_poi[0] is the bad block mask (BBM).
|
|
+ *
|
|
+ * The OOB data layout on the NFC is:
|
|
+ *
|
|
+ * PA0 PA1 PA2 PA3 | BBM OOB1 OOB2 OOB3 | ...
|
|
+ *
|
|
+ * or
|
|
+ *
|
|
+ * 0xFF 0xFF 0xFF 0xFF | BBM OOB1 OOB2 OOB3 | ...
|
|
+ *
|
|
+ * The code here just swaps the first 4 bytes with the last
|
|
+ * 4 bytes without losing any data.
|
|
+ *
|
|
+ * The chip->oob_poi data layout:
|
|
+ *
|
|
+ * BBM OOB1 OOB2 OOB3 |......| PA0 PA1 PA2 PA3
|
|
+ *
|
|
+ * The rk_nfc_ooblayout_free() function already has reserved
|
|
+ * these 4 bytes with:
|
|
+ *
|
|
+ * oob_region->offset = NFC_SYS_DATA_SIZE + 2;
|
|
+ */
|
|
+ if (!i)
|
|
+ memcpy(rk_nfc_oob_ptr(chip, i),
|
|
+ rk_nfc_buf_to_oob_ptr(chip, ecc->steps - 1),
|
|
+ NFC_SYS_DATA_SIZE);
|
|
+ else
|
|
+ memcpy(rk_nfc_oob_ptr(chip, i),
|
|
+ rk_nfc_buf_to_oob_ptr(chip, i - 1),
|
|
+ NFC_SYS_DATA_SIZE);
|
|
+ /* Copy ECC data to the NFC buffer. */
|
|
+ memcpy(rk_nfc_oob_ptr(chip, i) + NFC_SYS_DATA_SIZE,
|
|
+ rk_nfc_buf_to_oob_ecc_ptr(chip, i),
|
|
+ ecc->bytes);
|
|
+ }
|
|
+
|
|
+ nand_prog_page_begin_op(chip, page, 0, NULL, 0);
|
|
+ rk_nfc_write_buf(nfc, buf, mtd->writesize + mtd->oobsize);
|
|
+ return nand_prog_page_end_op(chip);
|
|
+}
|
|
+
|
|
+static int rk_nfc_write_page_hwecc(struct nand_chip *chip, const u8 *buf,
|
|
+ int oob_on, int page)
|
|
+{
|
|
+ struct mtd_info *mtd = nand_to_mtd(chip);
|
|
+ struct rk_nfc *nfc = nand_get_controller_data(chip);
|
|
+ struct rk_nfc_nand_chip *rknand = rk_nfc_to_rknand(chip);
|
|
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
|
|
+ int oob_step = (ecc->bytes > 60) ? NFC_MAX_OOB_PER_STEP :
|
|
+ NFC_MIN_OOB_PER_STEP;
|
|
+ int pages_per_blk = mtd->erasesize / mtd->writesize;
|
|
+ int ret = 0, i, boot_rom_mode = 0;
|
|
+ dma_addr_t dma_data, dma_oob;
|
|
+ u32 reg;
|
|
+ u8 *oob;
|
|
+
|
|
+ nand_prog_page_begin_op(chip, page, 0, NULL, 0);
|
|
+
|
|
+ if (buf)
|
|
+ memcpy(nfc->page_buf, buf, mtd->writesize);
|
|
+ else
|
|
+ memset(nfc->page_buf, 0xFF, mtd->writesize);
|
|
+
|
|
+ /*
|
|
+ * The first blocks (4, 8 or 16 depending on the device) are used
|
|
+ * by the boot ROM and the first 32 bits of OOB need to link to
|
|
+ * the next page address in the same block. We can't directly copy
|
|
+ * OOB data from the MTD framework, because this page address
|
|
+ * conflicts for example with the bad block marker (BBM),
|
|
+ * so we shift all OOB data including the BBM with 4 byte positions.
|
|
+ * As a consequence the OOB size available to the MTD framework is
|
|
+ * also reduced with 4 bytes.
|
|
+ *
|
|
+ * PA0 PA1 PA2 PA3 | BBM OOB1 OOB2 OOB3 | ...
|
|
+ *
|
|
+ * If a NAND is not a boot medium or the page is not a boot block,
|
|
+ * the first 4 bytes are left untouched by writing 0xFF to them.
|
|
+ *
|
|
+ * 0xFF 0xFF 0xFF 0xFF | BBM OOB1 OOB2 OOB3 | ...
|
|
+ *
|
|
+ * Configure the ECC algorithm supported by the boot ROM.
|
|
+ */
|
|
+ if ((page < (pages_per_blk * rknand->boot_blks)) &&
|
|
+ (chip->options & NAND_IS_BOOT_MEDIUM)) {
|
|
+ boot_rom_mode = 1;
|
|
+ if (rknand->boot_ecc != ecc->strength)
|
|
+ rk_nfc_hw_ecc_setup(chip, rknand->boot_ecc);
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < ecc->steps; i++) {
|
|
+ if (!i) {
|
|
+ reg = 0xFFFFFFFF;
|
|
+ } else {
|
|
+ oob = chip->oob_poi + (i - 1) * NFC_SYS_DATA_SIZE;
|
|
+ reg = oob[0] | oob[1] << 8 | oob[2] << 16 |
|
|
+ oob[3] << 24;
|
|
+ }
|
|
+
|
|
+ if (!i && boot_rom_mode)
|
|
+ reg = (page & (pages_per_blk - 1)) * 4;
|
|
+
|
|
+ if (nfc->cfg->type == NFC_V9)
|
|
+ nfc->oob_buf[i] = reg;
|
|
+ else
|
|
+ nfc->oob_buf[i * (oob_step / 4)] = reg;
|
|
+ }
|
|
+
|
|
+ dma_data = dma_map_single(nfc->dev, (void *)nfc->page_buf,
|
|
+ mtd->writesize, DMA_TO_DEVICE);
|
|
+ dma_oob = dma_map_single(nfc->dev, nfc->oob_buf,
|
|
+ ecc->steps * oob_step,
|
|
+ DMA_TO_DEVICE);
|
|
+
|
|
+ reinit_completion(&nfc->done);
|
|
+ writel(INT_DMA, nfc->regs + nfc->cfg->int_en_off);
|
|
+
|
|
+ rk_nfc_xfer_start(nfc, NFC_WRITE, ecc->steps, dma_data,
|
|
+ dma_oob);
|
|
+ ret = wait_for_completion_timeout(&nfc->done,
|
|
+ msecs_to_jiffies(100));
|
|
+ if (!ret)
|
|
+ dev_warn(nfc->dev, "write: wait dma done timeout.\n");
|
|
+ /*
|
|
+ * Whether the DMA transfer is completed or not. The driver
|
|
+ * needs to check the NFC`s status register to see if the data
|
|
+ * transfer was completed.
|
|
+ */
|
|
+ ret = rk_nfc_wait_for_xfer_done(nfc);
|
|
+
|
|
+ dma_unmap_single(nfc->dev, dma_data, mtd->writesize,
|
|
+ DMA_TO_DEVICE);
|
|
+ dma_unmap_single(nfc->dev, dma_oob, ecc->steps * oob_step,
|
|
+ DMA_TO_DEVICE);
|
|
+
|
|
+ if (boot_rom_mode && rknand->boot_ecc != ecc->strength)
|
|
+ rk_nfc_hw_ecc_setup(chip, ecc->strength);
|
|
+
|
|
+ if (ret) {
|
|
+ dev_err(nfc->dev, "write: wait transfer done timeout.\n");
|
|
+ return -ETIMEDOUT;
|
|
+ }
|
|
+
|
|
+ return nand_prog_page_end_op(chip);
|
|
+}
|
|
+
|
|
+static int rk_nfc_write_oob(struct nand_chip *chip, int page)
|
|
+{
|
|
+ return rk_nfc_write_page_hwecc(chip, NULL, 1, page);
|
|
+}
|
|
+
|
|
+static int rk_nfc_read_page_raw(struct nand_chip *chip, u8 *buf, int oob_on,
|
|
+ int page)
|
|
+{
|
|
+ struct rk_nfc_nand_chip *rknand = rk_nfc_to_rknand(chip);
|
|
+ struct rk_nfc *nfc = nand_get_controller_data(chip);
|
|
+ struct mtd_info *mtd = nand_to_mtd(chip);
|
|
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
|
|
+ int i, pages_per_blk;
|
|
+
|
|
+ pages_per_blk = mtd->erasesize / mtd->writesize;
|
|
+ if ((chip->options & NAND_IS_BOOT_MEDIUM) &&
|
|
+ (page < (pages_per_blk * rknand->boot_blks)) &&
|
|
+ rknand->boot_ecc != ecc->strength) {
|
|
+ /*
|
|
+ * There's currently no method to notify the MTD framework that
|
|
+ * a different ECC strength is in use for the boot blocks.
|
|
+ */
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ nand_read_page_op(chip, page, 0, NULL, 0);
|
|
+ rk_nfc_read_buf(nfc, nfc->page_buf, mtd->writesize + mtd->oobsize);
|
|
+ for (i = 0; i < ecc->steps; i++) {
|
|
+ /*
|
|
+ * The first four bytes of OOB are reserved for the
|
|
+ * boot ROM. In some debugging cases, such as with a read,
|
|
+ * erase and write back test, these 4 bytes also must be
|
|
+ * saved somewhere, otherwise this information will be
|
|
+ * lost during a write back.
|
|
+ */
|
|
+ if (!i)
|
|
+ memcpy(rk_nfc_buf_to_oob_ptr(chip, ecc->steps - 1),
|
|
+ rk_nfc_oob_ptr(chip, i),
|
|
+ NFC_SYS_DATA_SIZE);
|
|
+ else
|
|
+ memcpy(rk_nfc_buf_to_oob_ptr(chip, i - 1),
|
|
+ rk_nfc_oob_ptr(chip, i),
|
|
+ NFC_SYS_DATA_SIZE);
|
|
+
|
|
+ /* Copy ECC data from the NFC buffer. */
|
|
+ memcpy(rk_nfc_buf_to_oob_ecc_ptr(chip, i),
|
|
+ rk_nfc_oob_ptr(chip, i) + NFC_SYS_DATA_SIZE,
|
|
+ ecc->bytes);
|
|
+
|
|
+ /* Copy data from the NFC buffer. */
|
|
+ if (buf)
|
|
+ memcpy(rk_nfc_buf_to_data_ptr(chip, buf, i),
|
|
+ rk_nfc_data_ptr(chip, i),
|
|
+ ecc->size);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int rk_nfc_read_page_hwecc(struct nand_chip *chip, u8 *buf, int oob_on,
|
|
+ int page)
|
|
+{
|
|
+ struct mtd_info *mtd = nand_to_mtd(chip);
|
|
+ struct rk_nfc *nfc = nand_get_controller_data(chip);
|
|
+ struct rk_nfc_nand_chip *rknand = rk_nfc_to_rknand(chip);
|
|
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
|
|
+ int oob_step = (ecc->bytes > 60) ? NFC_MAX_OOB_PER_STEP :
|
|
+ NFC_MIN_OOB_PER_STEP;
|
|
+ int pages_per_blk = mtd->erasesize / mtd->writesize;
|
|
+ dma_addr_t dma_data, dma_oob;
|
|
+ int ret = 0, i, cnt, boot_rom_mode = 0;
|
|
+ int max_bitflips = 0, bch_st, ecc_fail = 0;
|
|
+ u8 *oob;
|
|
+ u32 tmp;
|
|
+
|
|
+ nand_read_page_op(chip, page, 0, NULL, 0);
|
|
+
|
|
+ dma_data = dma_map_single(nfc->dev, nfc->page_buf,
|
|
+ mtd->writesize,
|
|
+ DMA_FROM_DEVICE);
|
|
+ dma_oob = dma_map_single(nfc->dev, nfc->oob_buf,
|
|
+ ecc->steps * oob_step,
|
|
+ DMA_FROM_DEVICE);
|
|
+
|
|
+ /*
|
|
+ * The first blocks (4, 8 or 16 depending on the device)
|
|
+ * are used by the boot ROM.
|
|
+ * Configure the ECC algorithm supported by the boot ROM.
|
|
+ */
|
|
+ if ((page < (pages_per_blk * rknand->boot_blks)) &&
|
|
+ (chip->options & NAND_IS_BOOT_MEDIUM)) {
|
|
+ boot_rom_mode = 1;
|
|
+ if (rknand->boot_ecc != ecc->strength)
|
|
+ rk_nfc_hw_ecc_setup(chip, rknand->boot_ecc);
|
|
+ }
|
|
+
|
|
+ reinit_completion(&nfc->done);
|
|
+ writel(INT_DMA, nfc->regs + nfc->cfg->int_en_off);
|
|
+ rk_nfc_xfer_start(nfc, NFC_READ, ecc->steps, dma_data,
|
|
+ dma_oob);
|
|
+ ret = wait_for_completion_timeout(&nfc->done,
|
|
+ msecs_to_jiffies(100));
|
|
+ if (!ret)
|
|
+ dev_warn(nfc->dev, "read: wait dma done timeout.\n");
|
|
+ /*
|
|
+ * Whether the DMA transfer is completed or not. The driver
|
|
+ * needs to check the NFC`s status register to see if the data
|
|
+ * transfer was completed.
|
|
+ */
|
|
+ ret = rk_nfc_wait_for_xfer_done(nfc);
|
|
+
|
|
+ dma_unmap_single(nfc->dev, dma_data, mtd->writesize,
|
|
+ DMA_FROM_DEVICE);
|
|
+ dma_unmap_single(nfc->dev, dma_oob, ecc->steps * oob_step,
|
|
+ DMA_FROM_DEVICE);
|
|
+
|
|
+ if (ret) {
|
|
+ ret = -ETIMEDOUT;
|
|
+ dev_err(nfc->dev, "read: wait transfer done timeout.\n");
|
|
+ goto timeout_err;
|
|
+ }
|
|
+
|
|
+ for (i = 1; i < ecc->steps; i++) {
|
|
+ oob = chip->oob_poi + (i - 1) * NFC_SYS_DATA_SIZE;
|
|
+ if (nfc->cfg->type == NFC_V9)
|
|
+ tmp = nfc->oob_buf[i];
|
|
+ else
|
|
+ tmp = nfc->oob_buf[i * (oob_step / 4)];
|
|
+ *oob++ = (u8)tmp;
|
|
+ *oob++ = (u8)(tmp >> 8);
|
|
+ *oob++ = (u8)(tmp >> 16);
|
|
+ *oob++ = (u8)(tmp >> 24);
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < (ecc->steps / 2); i++) {
|
|
+ bch_st = readl_relaxed(nfc->regs +
|
|
+ nfc->cfg->bch_st_off + i * 4);
|
|
+ if (bch_st & BIT(nfc->cfg->ecc0.err_flag_bit) ||
|
|
+ bch_st & BIT(nfc->cfg->ecc1.err_flag_bit)) {
|
|
+ mtd->ecc_stats.failed++;
|
|
+ ecc_fail = 1;
|
|
+ } else {
|
|
+ cnt = ECC_ERR_CNT(bch_st, nfc->cfg->ecc0);
|
|
+ mtd->ecc_stats.corrected += cnt;
|
|
+ max_bitflips = max_t(u32, max_bitflips, cnt);
|
|
+
|
|
+ cnt = ECC_ERR_CNT(bch_st, nfc->cfg->ecc1);
|
|
+ mtd->ecc_stats.corrected += cnt;
|
|
+ max_bitflips = max_t(u32, max_bitflips, cnt);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (buf)
|
|
+ memcpy(buf, nfc->page_buf, mtd->writesize);
|
|
+
|
|
+timeout_err:
|
|
+ if (boot_rom_mode && rknand->boot_ecc != ecc->strength)
|
|
+ rk_nfc_hw_ecc_setup(chip, ecc->strength);
|
|
+
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ if (ecc_fail) {
|
|
+ dev_err(nfc->dev, "read page: %x ecc error!\n", page);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ return max_bitflips;
|
|
+}
|
|
+
|
|
+static int rk_nfc_read_oob(struct nand_chip *chip, int page)
|
|
+{
|
|
+ return rk_nfc_read_page_hwecc(chip, NULL, 1, page);
|
|
+}
|
|
+
|
|
+static inline void rk_nfc_hw_init(struct rk_nfc *nfc)
|
|
+{
|
|
+ /* Disable flash wp. */
|
|
+ writel(FMCTL_WP, nfc->regs + NFC_FMCTL);
|
|
+ /* Config default timing 40ns at 150 Mhz NFC clock. */
|
|
+ writel(0x1081, nfc->regs + NFC_FMWAIT);
|
|
+ nfc->cur_timing = 0x1081;
|
|
+ /* Disable randomizer and DMA. */
|
|
+ writel(0, nfc->regs + nfc->cfg->randmz_off);
|
|
+ writel(0, nfc->regs + nfc->cfg->dma_cfg_off);
|
|
+ writel(FLCTL_RST, nfc->regs + nfc->cfg->flctl_off);
|
|
+}
|
|
+
|
|
+static irqreturn_t rk_nfc_irq(int irq, void *id)
|
|
+{
|
|
+ struct rk_nfc *nfc = id;
|
|
+ u32 sta, ien;
|
|
+
|
|
+ sta = readl_relaxed(nfc->regs + nfc->cfg->int_st_off);
|
|
+ ien = readl_relaxed(nfc->regs + nfc->cfg->int_en_off);
|
|
+
|
|
+ if (!(sta & ien))
|
|
+ return IRQ_NONE;
|
|
+
|
|
+ writel(sta, nfc->regs + nfc->cfg->int_clr_off);
|
|
+ writel(~sta & ien, nfc->regs + nfc->cfg->int_en_off);
|
|
+
|
|
+ complete(&nfc->done);
|
|
+
|
|
+ return IRQ_HANDLED;
|
|
+}
|
|
+
|
|
+static int rk_nfc_enable_clks(struct device *dev, struct rk_nfc *nfc)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ if (!IS_ERR(nfc->nfc_clk)) {
|
|
+ ret = clk_prepare_enable(nfc->nfc_clk);
|
|
+ if (ret) {
|
|
+ dev_err(dev, "failed to enable NFC clk\n");
|
|
+ return ret;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ret = clk_prepare_enable(nfc->ahb_clk);
|
|
+ if (ret) {
|
|
+ dev_err(dev, "failed to enable ahb clk\n");
|
|
+ if (!IS_ERR(nfc->nfc_clk))
|
|
+ clk_disable_unprepare(nfc->nfc_clk);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void rk_nfc_disable_clks(struct rk_nfc *nfc)
|
|
+{
|
|
+ if (!IS_ERR(nfc->nfc_clk))
|
|
+ clk_disable_unprepare(nfc->nfc_clk);
|
|
+ clk_disable_unprepare(nfc->ahb_clk);
|
|
+}
|
|
+
|
|
+static int rk_nfc_ooblayout_free(struct mtd_info *mtd, int section,
|
|
+ struct mtd_oob_region *oob_region)
|
|
+{
|
|
+ struct nand_chip *chip = mtd_to_nand(mtd);
|
|
+ struct rk_nfc_nand_chip *rknand = rk_nfc_to_rknand(chip);
|
|
+
|
|
+ if (section)
|
|
+ return -ERANGE;
|
|
+
|
|
+ /*
|
|
+ * The beginning of the OOB area stores the reserved data for the NFC,
|
|
+ * the size of the reserved data is NFC_SYS_DATA_SIZE bytes.
|
|
+ */
|
|
+ oob_region->length = rknand->metadata_size - NFC_SYS_DATA_SIZE - 2;
|
|
+ oob_region->offset = NFC_SYS_DATA_SIZE + 2;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int rk_nfc_ooblayout_ecc(struct mtd_info *mtd, int section,
|
|
+ struct mtd_oob_region *oob_region)
|
|
+{
|
|
+ struct nand_chip *chip = mtd_to_nand(mtd);
|
|
+ struct rk_nfc_nand_chip *rknand = rk_nfc_to_rknand(chip);
|
|
+
|
|
+ if (section)
|
|
+ return -ERANGE;
|
|
+
|
|
+ oob_region->length = mtd->oobsize - rknand->metadata_size;
|
|
+ oob_region->offset = rknand->metadata_size;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct mtd_ooblayout_ops rk_nfc_ooblayout_ops = {
|
|
+ .free = rk_nfc_ooblayout_free,
|
|
+ .ecc = rk_nfc_ooblayout_ecc,
|
|
+};
|
|
+
|
|
+static int rk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
|
|
+{
|
|
+ struct nand_chip *chip = mtd_to_nand(mtd);
|
|
+ struct rk_nfc *nfc = nand_get_controller_data(chip);
|
|
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
|
|
+ const u8 *strengths = nfc->cfg->ecc_strengths;
|
|
+ u8 max_strength, nfc_max_strength;
|
|
+ int i;
|
|
+
|
|
+ nfc_max_strength = nfc->cfg->ecc_strengths[0];
|
|
+ /* If optional dt settings not present. */
|
|
+ if (!ecc->size || !ecc->strength ||
|
|
+ ecc->strength > nfc_max_strength) {
|
|
+ chip->ecc.size = 1024;
|
|
+ ecc->steps = mtd->writesize / ecc->size;
|
|
+
|
|
+ /*
|
|
+ * HW ECC always requests the number of ECC bytes per 1024 byte
|
|
+ * blocks. The first 4 OOB bytes are reserved for sys data.
|
|
+ */
|
|
+ max_strength = ((mtd->oobsize / ecc->steps) - 4) * 8 /
|
|
+ fls(8 * 1024);
|
|
+ if (max_strength > nfc_max_strength)
|
|
+ max_strength = nfc_max_strength;
|
|
+
|
|
+ for (i = 0; i < 4; i++) {
|
|
+ if (max_strength >= strengths[i])
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (i >= 4) {
|
|
+ dev_err(nfc->dev, "unsupported ECC strength\n");
|
|
+ return -EOPNOTSUPP;
|
|
+ }
|
|
+
|
|
+ ecc->strength = strengths[i];
|
|
+ }
|
|
+ ecc->steps = mtd->writesize / ecc->size;
|
|
+ ecc->bytes = DIV_ROUND_UP(ecc->strength * fls(8 * chip->ecc.size), 8);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int rk_nfc_attach_chip(struct nand_chip *chip)
|
|
+{
|
|
+ struct mtd_info *mtd = nand_to_mtd(chip);
|
|
+ struct device *dev = mtd->dev.parent;
|
|
+ struct rk_nfc *nfc = nand_get_controller_data(chip);
|
|
+ struct rk_nfc_nand_chip *rknand = rk_nfc_to_rknand(chip);
|
|
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
|
|
+ int new_page_len, new_oob_len;
|
|
+ void *buf;
|
|
+ int ret;
|
|
+
|
|
+ if (chip->options & NAND_BUSWIDTH_16) {
|
|
+ dev_err(dev, "16 bits bus width not supported");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (ecc->engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST)
|
|
+ return 0;
|
|
+
|
|
+ ret = rk_nfc_ecc_init(dev, mtd);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ rknand->metadata_size = NFC_SYS_DATA_SIZE * ecc->steps;
|
|
+
|
|
+ if (rknand->metadata_size < NFC_SYS_DATA_SIZE + 2) {
|
|
+ dev_err(dev,
|
|
+ "driver needs at least %d bytes of meta data\n",
|
|
+ NFC_SYS_DATA_SIZE + 2);
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ /* Check buffer first, avoid duplicate alloc buffer. */
|
|
+ new_page_len = mtd->writesize + mtd->oobsize;
|
|
+ if (nfc->page_buf && new_page_len > nfc->page_buf_size) {
|
|
+ buf = krealloc(nfc->page_buf, new_page_len,
|
|
+ GFP_KERNEL | GFP_DMA);
|
|
+ if (!buf)
|
|
+ return -ENOMEM;
|
|
+ nfc->page_buf = buf;
|
|
+ nfc->page_buf_size = new_page_len;
|
|
+ }
|
|
+
|
|
+ new_oob_len = ecc->steps * NFC_MAX_OOB_PER_STEP;
|
|
+ if (nfc->oob_buf && new_oob_len > nfc->oob_buf_size) {
|
|
+ buf = krealloc(nfc->oob_buf, new_oob_len,
|
|
+ GFP_KERNEL | GFP_DMA);
|
|
+ if (!buf) {
|
|
+ kfree(nfc->page_buf);
|
|
+ nfc->page_buf = NULL;
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ nfc->oob_buf = buf;
|
|
+ nfc->oob_buf_size = new_oob_len;
|
|
+ }
|
|
+
|
|
+ if (!nfc->page_buf) {
|
|
+ nfc->page_buf = kzalloc(new_page_len, GFP_KERNEL | GFP_DMA);
|
|
+ if (!nfc->page_buf)
|
|
+ return -ENOMEM;
|
|
+ nfc->page_buf_size = new_page_len;
|
|
+ }
|
|
+
|
|
+ if (!nfc->oob_buf) {
|
|
+ nfc->oob_buf = kzalloc(new_oob_len, GFP_KERNEL | GFP_DMA);
|
|
+ if (!nfc->oob_buf) {
|
|
+ kfree(nfc->page_buf);
|
|
+ nfc->page_buf = NULL;
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ nfc->oob_buf_size = new_oob_len;
|
|
+ }
|
|
+
|
|
+ chip->ecc.write_page_raw = rk_nfc_write_page_raw;
|
|
+ chip->ecc.write_page = rk_nfc_write_page_hwecc;
|
|
+ chip->ecc.write_oob = rk_nfc_write_oob;
|
|
+
|
|
+ chip->ecc.read_page_raw = rk_nfc_read_page_raw;
|
|
+ chip->ecc.read_page = rk_nfc_read_page_hwecc;
|
|
+ chip->ecc.read_oob = rk_nfc_read_oob;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct nand_controller_ops rk_nfc_controller_ops = {
|
|
+ .attach_chip = rk_nfc_attach_chip,
|
|
+ .exec_op = rk_nfc_exec_op,
|
|
+ .setup_interface = rk_nfc_setup_interface,
|
|
+};
|
|
+
|
|
+static int rk_nfc_nand_chip_init(struct device *dev, struct rk_nfc *nfc,
|
|
+ struct device_node *np)
|
|
+{
|
|
+ struct rk_nfc_nand_chip *rknand;
|
|
+ struct nand_chip *chip;
|
|
+ struct mtd_info *mtd;
|
|
+ int nsels;
|
|
+ u32 tmp;
|
|
+ int ret;
|
|
+ int i;
|
|
+
|
|
+ if (!of_get_property(np, "reg", &nsels))
|
|
+ return -ENODEV;
|
|
+ nsels /= sizeof(u32);
|
|
+ if (!nsels || nsels > NFC_MAX_NSELS) {
|
|
+ dev_err(dev, "invalid reg property size %d\n", nsels);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ rknand = devm_kzalloc(dev, sizeof(*rknand) + nsels * sizeof(u8),
|
|
+ GFP_KERNEL);
|
|
+ if (!rknand)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ rknand->nsels = nsels;
|
|
+ for (i = 0; i < nsels; i++) {
|
|
+ ret = of_property_read_u32_index(np, "reg", i, &tmp);
|
|
+ if (ret) {
|
|
+ dev_err(dev, "reg property failure : %d\n", ret);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ if (tmp >= NFC_MAX_NSELS) {
|
|
+ dev_err(dev, "invalid CS: %u\n", tmp);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (test_and_set_bit(tmp, &nfc->assigned_cs)) {
|
|
+ dev_err(dev, "CS %u already assigned\n", tmp);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ rknand->sels[i] = tmp;
|
|
+ }
|
|
+
|
|
+ chip = &rknand->chip;
|
|
+ chip->controller = &nfc->controller;
|
|
+
|
|
+ nand_set_flash_node(chip, np);
|
|
+
|
|
+ nand_set_controller_data(chip, nfc);
|
|
+
|
|
+ chip->options |= NAND_USES_DMA | NAND_NO_SUBPAGE_WRITE;
|
|
+ chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
|
|
+
|
|
+ /* Set default mode in case dt entry is missing. */
|
|
+ chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
|
|
+
|
|
+ mtd = nand_to_mtd(chip);
|
|
+ mtd->owner = THIS_MODULE;
|
|
+ mtd->dev.parent = dev;
|
|
+
|
|
+ if (!mtd->name) {
|
|
+ dev_err(nfc->dev, "NAND label property is mandatory\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ mtd_set_ooblayout(mtd, &rk_nfc_ooblayout_ops);
|
|
+ rk_nfc_hw_init(nfc);
|
|
+ ret = nand_scan(chip, nsels);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ if (chip->options & NAND_IS_BOOT_MEDIUM) {
|
|
+ ret = of_property_read_u32(np, "rockchip,boot-blks", &tmp);
|
|
+ rknand->boot_blks = ret ? 0 : tmp;
|
|
+
|
|
+ ret = of_property_read_u32(np, "rockchip,boot-ecc-strength",
|
|
+ &tmp);
|
|
+ rknand->boot_ecc = ret ? chip->ecc.strength : tmp;
|
|
+ }
|
|
+
|
|
+ ret = mtd_device_register(mtd, NULL, 0);
|
|
+ if (ret) {
|
|
+ dev_err(dev, "MTD parse partition error\n");
|
|
+ nand_cleanup(chip);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ list_add_tail(&rknand->node, &nfc->chips);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void rk_nfc_chips_cleanup(struct rk_nfc *nfc)
|
|
+{
|
|
+ struct rk_nfc_nand_chip *rknand, *tmp;
|
|
+ struct nand_chip *chip;
|
|
+ int ret;
|
|
+
|
|
+ list_for_each_entry_safe(rknand, tmp, &nfc->chips, node) {
|
|
+ chip = &rknand->chip;
|
|
+ ret = mtd_device_unregister(nand_to_mtd(chip));
|
|
+ WARN_ON(ret);
|
|
+ nand_cleanup(chip);
|
|
+ list_del(&rknand->node);
|
|
+ }
|
|
+}
|
|
+
|
|
+static int rk_nfc_nand_chips_init(struct device *dev, struct rk_nfc *nfc)
|
|
+{
|
|
+ struct device_node *np = dev->of_node, *nand_np;
|
|
+ int nchips = of_get_child_count(np);
|
|
+ int ret;
|
|
+
|
|
+ if (!nchips || nchips > NFC_MAX_NSELS) {
|
|
+ dev_err(nfc->dev, "incorrect number of NAND chips (%d)\n",
|
|
+ nchips);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ for_each_child_of_node(np, nand_np) {
|
|
+ ret = rk_nfc_nand_chip_init(dev, nfc, nand_np);
|
|
+ if (ret) {
|
|
+ of_node_put(nand_np);
|
|
+ rk_nfc_chips_cleanup(nfc);
|
|
+ return ret;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static struct nfc_cfg nfc_v6_cfg = {
|
|
+ .type = NFC_V6,
|
|
+ .ecc_strengths = {60, 40, 24, 16},
|
|
+ .ecc_cfgs = {
|
|
+ 0x00040011, 0x00040001, 0x00000011, 0x00000001,
|
|
+ },
|
|
+ .flctl_off = 0x08,
|
|
+ .bchctl_off = 0x0C,
|
|
+ .dma_cfg_off = 0x10,
|
|
+ .dma_data_buf_off = 0x14,
|
|
+ .dma_oob_buf_off = 0x18,
|
|
+ .dma_st_off = 0x1C,
|
|
+ .bch_st_off = 0x20,
|
|
+ .randmz_off = 0x150,
|
|
+ .int_en_off = 0x16C,
|
|
+ .int_clr_off = 0x170,
|
|
+ .int_st_off = 0x174,
|
|
+ .oob0_off = 0x200,
|
|
+ .oob1_off = 0x230,
|
|
+ .ecc0 = {
|
|
+ .err_flag_bit = 2,
|
|
+ .low = 3,
|
|
+ .low_mask = 0x1F,
|
|
+ .low_bn = 5,
|
|
+ .high = 27,
|
|
+ .high_mask = 0x1,
|
|
+ },
|
|
+ .ecc1 = {
|
|
+ .err_flag_bit = 15,
|
|
+ .low = 16,
|
|
+ .low_mask = 0x1F,
|
|
+ .low_bn = 5,
|
|
+ .high = 29,
|
|
+ .high_mask = 0x1,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct nfc_cfg nfc_v8_cfg = {
|
|
+ .type = NFC_V8,
|
|
+ .ecc_strengths = {16, 16, 16, 16},
|
|
+ .ecc_cfgs = {
|
|
+ 0x00000001, 0x00000001, 0x00000001, 0x00000001,
|
|
+ },
|
|
+ .flctl_off = 0x08,
|
|
+ .bchctl_off = 0x0C,
|
|
+ .dma_cfg_off = 0x10,
|
|
+ .dma_data_buf_off = 0x14,
|
|
+ .dma_oob_buf_off = 0x18,
|
|
+ .dma_st_off = 0x1C,
|
|
+ .bch_st_off = 0x20,
|
|
+ .randmz_off = 0x150,
|
|
+ .int_en_off = 0x16C,
|
|
+ .int_clr_off = 0x170,
|
|
+ .int_st_off = 0x174,
|
|
+ .oob0_off = 0x200,
|
|
+ .oob1_off = 0x230,
|
|
+ .ecc0 = {
|
|
+ .err_flag_bit = 2,
|
|
+ .low = 3,
|
|
+ .low_mask = 0x1F,
|
|
+ .low_bn = 5,
|
|
+ .high = 27,
|
|
+ .high_mask = 0x1,
|
|
+ },
|
|
+ .ecc1 = {
|
|
+ .err_flag_bit = 15,
|
|
+ .low = 16,
|
|
+ .low_mask = 0x1F,
|
|
+ .low_bn = 5,
|
|
+ .high = 29,
|
|
+ .high_mask = 0x1,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct nfc_cfg nfc_v9_cfg = {
|
|
+ .type = NFC_V9,
|
|
+ .ecc_strengths = {70, 60, 40, 16},
|
|
+ .ecc_cfgs = {
|
|
+ 0x00000001, 0x06000001, 0x04000001, 0x02000001,
|
|
+ },
|
|
+ .flctl_off = 0x10,
|
|
+ .bchctl_off = 0x20,
|
|
+ .dma_cfg_off = 0x30,
|
|
+ .dma_data_buf_off = 0x34,
|
|
+ .dma_oob_buf_off = 0x38,
|
|
+ .dma_st_off = 0x3C,
|
|
+ .bch_st_off = 0x150,
|
|
+ .randmz_off = 0x208,
|
|
+ .int_en_off = 0x120,
|
|
+ .int_clr_off = 0x124,
|
|
+ .int_st_off = 0x128,
|
|
+ .oob0_off = 0x200,
|
|
+ .oob1_off = 0x204,
|
|
+ .ecc0 = {
|
|
+ .err_flag_bit = 2,
|
|
+ .low = 3,
|
|
+ .low_mask = 0x7F,
|
|
+ .low_bn = 7,
|
|
+ .high = 0,
|
|
+ .high_mask = 0x0,
|
|
+ },
|
|
+ .ecc1 = {
|
|
+ .err_flag_bit = 18,
|
|
+ .low = 19,
|
|
+ .low_mask = 0x7F,
|
|
+ .low_bn = 7,
|
|
+ .high = 0,
|
|
+ .high_mask = 0x0,
|
|
+ },
|
|
+};
|
|
+
|
|
+static const struct of_device_id rk_nfc_id_table[] = {
|
|
+ {
|
|
+ .compatible = "rockchip,px30-nfc",
|
|
+ .data = &nfc_v9_cfg
|
|
+ },
|
|
+ {
|
|
+ .compatible = "rockchip,rk2928-nfc",
|
|
+ .data = &nfc_v6_cfg
|
|
+ },
|
|
+ {
|
|
+ .compatible = "rockchip,rv1108-nfc",
|
|
+ .data = &nfc_v8_cfg
|
|
+ },
|
|
+ { /* sentinel */ }
|
|
+};
|
|
+MODULE_DEVICE_TABLE(of, rk_nfc_id_table);
|
|
+
|
|
+static int rk_nfc_probe(struct platform_device *pdev)
|
|
+{
|
|
+ struct device *dev = &pdev->dev;
|
|
+ struct rk_nfc *nfc;
|
|
+ int ret, irq;
|
|
+
|
|
+ nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
|
|
+ if (!nfc)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ nand_controller_init(&nfc->controller);
|
|
+ INIT_LIST_HEAD(&nfc->chips);
|
|
+ nfc->controller.ops = &rk_nfc_controller_ops;
|
|
+
|
|
+ nfc->cfg = of_device_get_match_data(dev);
|
|
+ nfc->dev = dev;
|
|
+
|
|
+ init_completion(&nfc->done);
|
|
+
|
|
+ nfc->regs = devm_platform_ioremap_resource(pdev, 0);
|
|
+ if (IS_ERR(nfc->regs)) {
|
|
+ ret = PTR_ERR(nfc->regs);
|
|
+ goto release_nfc;
|
|
+ }
|
|
+
|
|
+ nfc->nfc_clk = devm_clk_get(dev, "nfc");
|
|
+ if (IS_ERR(nfc->nfc_clk)) {
|
|
+ dev_dbg(dev, "no NFC clk\n");
|
|
+ /* Some earlier models, such as rk3066, have no NFC clk. */
|
|
+ }
|
|
+
|
|
+ nfc->ahb_clk = devm_clk_get(dev, "ahb");
|
|
+ if (IS_ERR(nfc->ahb_clk)) {
|
|
+ dev_err(dev, "no ahb clk\n");
|
|
+ ret = PTR_ERR(nfc->ahb_clk);
|
|
+ goto release_nfc;
|
|
+ }
|
|
+
|
|
+ ret = rk_nfc_enable_clks(dev, nfc);
|
|
+ if (ret)
|
|
+ goto release_nfc;
|
|
+
|
|
+ irq = platform_get_irq(pdev, 0);
|
|
+ if (irq < 0) {
|
|
+ dev_err(dev, "no NFC irq resource\n");
|
|
+ ret = -EINVAL;
|
|
+ goto clk_disable;
|
|
+ }
|
|
+
|
|
+ writel(0, nfc->regs + nfc->cfg->int_en_off);
|
|
+ ret = devm_request_irq(dev, irq, rk_nfc_irq, 0x0, "rk-nand", nfc);
|
|
+ if (ret) {
|
|
+ dev_err(dev, "failed to request NFC irq\n");
|
|
+ goto clk_disable;
|
|
+ }
|
|
+
|
|
+ platform_set_drvdata(pdev, nfc);
|
|
+
|
|
+ ret = rk_nfc_nand_chips_init(dev, nfc);
|
|
+ if (ret) {
|
|
+ dev_err(dev, "failed to init NAND chips\n");
|
|
+ goto clk_disable;
|
|
+ }
|
|
+ return 0;
|
|
+
|
|
+clk_disable:
|
|
+ rk_nfc_disable_clks(nfc);
|
|
+release_nfc:
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int rk_nfc_remove(struct platform_device *pdev)
|
|
+{
|
|
+ struct rk_nfc *nfc = platform_get_drvdata(pdev);
|
|
+
|
|
+ kfree(nfc->page_buf);
|
|
+ kfree(nfc->oob_buf);
|
|
+ rk_nfc_chips_cleanup(nfc);
|
|
+ rk_nfc_disable_clks(nfc);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int __maybe_unused rk_nfc_suspend(struct device *dev)
|
|
+{
|
|
+ struct rk_nfc *nfc = dev_get_drvdata(dev);
|
|
+
|
|
+ rk_nfc_disable_clks(nfc);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int __maybe_unused rk_nfc_resume(struct device *dev)
|
|
+{
|
|
+ struct rk_nfc *nfc = dev_get_drvdata(dev);
|
|
+ struct rk_nfc_nand_chip *rknand;
|
|
+ struct nand_chip *chip;
|
|
+ int ret;
|
|
+ u32 i;
|
|
+
|
|
+ ret = rk_nfc_enable_clks(dev, nfc);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ /* Reset NAND chip if VCC was powered off. */
|
|
+ list_for_each_entry(rknand, &nfc->chips, node) {
|
|
+ chip = &rknand->chip;
|
|
+ for (i = 0; i < rknand->nsels; i++)
|
|
+ nand_reset(chip, i);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct dev_pm_ops rk_nfc_pm_ops = {
|
|
+ SET_SYSTEM_SLEEP_PM_OPS(rk_nfc_suspend, rk_nfc_resume)
|
|
+};
|
|
+
|
|
+static struct platform_driver rk_nfc_driver = {
|
|
+ .probe = rk_nfc_probe,
|
|
+ .remove = rk_nfc_remove,
|
|
+ .driver = {
|
|
+ .name = "rockchip-nfc",
|
|
+ .of_match_table = rk_nfc_id_table,
|
|
+ .pm = &rk_nfc_pm_ops,
|
|
+ },
|
|
+};
|
|
+
|
|
+module_platform_driver(rk_nfc_driver);
|
|
+
|
|
+MODULE_LICENSE("Dual MIT/GPL");
|
|
+MODULE_AUTHOR("Yifeng Zhao <yifeng.zhao@rock-chips.com>");
|
|
+MODULE_DESCRIPTION("Rockchip Nand Flash Controller Driver");
|
|
+MODULE_ALIAS("platform:rockchip-nand-controller");
|
|
|
|
From eaf9cd3f96b027c7e51aa7031315a32bc4f1abd3 Mon Sep 17 00:00:00 2001
|
|
From: Yifeng Zhao <yifeng.zhao@rock-chips.com>
|
|
Date: Thu, 10 Dec 2020 08:21:33 +0800
|
|
Subject: [PATCH] MAINTAINERS: add maintainers to ROCKCHIP NFC
|
|
|
|
Add maintainers to ROCKCHIP NFC.
|
|
|
|
Signed-off-by: Yifeng Zhao <yifeng.zhao@rock-chips.com>
|
|
---
|
|
MAINTAINERS | 4 ++--
|
|
1 file changed, 2 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/MAINTAINERS b/MAINTAINERS
|
|
index 281de213ef47..af53d0c45407 100644
|
|
--- a/MAINTAINERS
|
|
+++ b/MAINTAINERS
|
|
@@ -2371,12 +2371,12 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
|
L: linux-rockchip@lists.infradead.org
|
|
S: Maintained
|
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git
|
|
+F: Documentation/devicetree/bindings/*/*rockchip*.yaml
|
|
F: Documentation/devicetree/bindings/i2c/i2c-rk3x.yaml
|
|
-F: Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.yaml
|
|
-F: Documentation/devicetree/bindings/spi/spi-rockchip.yaml
|
|
F: arch/arm/boot/dts/rk3*
|
|
F: arch/arm/boot/dts/rv1108*
|
|
F: arch/arm/mach-rockchip/
|
|
+F: drivers/*/*/*/*rockchip*
|
|
F: drivers/*/*/*rockchip*
|
|
F: drivers/*/*rockchip*
|
|
F: drivers/clk/rockchip/
|
|
|
|
From 49f112f3169f78312b6879c3e1b4959d6060b6dc Mon Sep 17 00:00:00 2001
|
|
From: Yifeng Zhao <yifeng.zhao@rock-chips.com>
|
|
Date: Thu, 10 Dec 2020 08:21:34 +0800
|
|
Subject: [PATCH] arm64: dts: rockchip: Add NFC node for RK3308 SoC
|
|
|
|
Add NAND FLASH Controller(NFC) node for RK3308 SoC.
|
|
|
|
Signed-off-by: Yifeng Zhao <yifeng.zhao@rock-chips.com>
|
|
---
|
|
arch/arm64/boot/dts/rockchip/rk3308.dtsi | 15 +++++++++++++++
|
|
1 file changed, 15 insertions(+)
|
|
|
|
diff --git a/arch/arm64/boot/dts/rockchip/rk3308.dtsi b/arch/arm64/boot/dts/rockchip/rk3308.dtsi
|
|
index 2560b98771ca..7211fab7a6e4 100644
|
|
--- a/arch/arm64/boot/dts/rockchip/rk3308.dtsi
|
|
+++ b/arch/arm64/boot/dts/rockchip/rk3308.dtsi
|
|
@@ -629,6 +629,21 @@ sdio: mmc@ff4a0000 {
|
|
status = "disabled";
|
|
};
|
|
|
|
+ nfc: nand-controller@ff4b0000 {
|
|
+ compatible = "rockchip,rk3308-nfc",
|
|
+ "rockchip,rv1108-nfc";
|
|
+ reg = <0x0 0xff4b0000 0x0 0x4000>;
|
|
+ interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ clocks = <&cru HCLK_NANDC>, <&cru SCLK_NANDC>;
|
|
+ clock-names = "ahb", "nfc";
|
|
+ assigned-clocks = <&cru SCLK_NANDC>;
|
|
+ assigned-clock-rates = <150000000>;
|
|
+ pinctrl-0 = <&flash_ale &flash_bus8 &flash_cle &flash_csn0
|
|
+ &flash_rdn &flash_rdy &flash_wrn>;
|
|
+ pinctrl-names = "default";
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
cru: clock-controller@ff500000 {
|
|
compatible = "rockchip,rk3308-cru";
|
|
reg = <0x0 0xff500000 0x0 0x1000>;
|
|
|
|
From 4f115c807f1f8cf6899798bc3f2a01adc68bc593 Mon Sep 17 00:00:00 2001
|
|
From: Yifeng Zhao <yifeng.zhao@rock-chips.com>
|
|
Date: Thu, 10 Dec 2020 08:22:16 +0800
|
|
Subject: [PATCH] arm64: dts: rockchip: Add NFC node for PX30 SoC
|
|
|
|
Add NAND FLASH Controller(NFC) node for PX30 SoC.
|
|
|
|
Signed-off-by: Yifeng Zhao <yifeng.zhao@rock-chips.com>
|
|
---
|
|
arch/arm64/boot/dts/rockchip/px30.dtsi | 15 +++++++++++++++
|
|
1 file changed, 15 insertions(+)
|
|
|
|
diff --git a/arch/arm64/boot/dts/rockchip/px30.dtsi b/arch/arm64/boot/dts/rockchip/px30.dtsi
|
|
index 2695ea8cda14..6cd67e80d623 100644
|
|
--- a/arch/arm64/boot/dts/rockchip/px30.dtsi
|
|
+++ b/arch/arm64/boot/dts/rockchip/px30.dtsi
|
|
@@ -973,6 +973,21 @@ emmc: mmc@ff390000 {
|
|
status = "disabled";
|
|
};
|
|
|
|
+ nfc: nand-controller@ff3b0000 {
|
|
+ compatible = "rockchip,px30-nfc";
|
|
+ reg = <0x0 0xff3b0000 0x0 0x4000>;
|
|
+ interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ clocks = <&cru HCLK_NANDC>, <&cru SCLK_NANDC>;
|
|
+ clock-names = "ahb", "nfc";
|
|
+ assigned-clocks = <&cru SCLK_NANDC>;
|
|
+ assigned-clock-rates = <150000000>;
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&flash_ale &flash_bus8 &flash_cle &flash_cs0
|
|
+ &flash_rdn &flash_rdy &flash_wrn &flash_dqs>;
|
|
+ power-domains = <&power PX30_PD_MMC_NAND>;
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
gpu: gpu@ff400000 {
|
|
compatible = "rockchip,px30-mali", "arm,mali-bifrost";
|
|
reg = <0x0 0xff400000 0x0 0x4000>;
|
|
|
|
From c078249d7f7f201bb0a4f1daaf38a7aade05882f Mon Sep 17 00:00:00 2001
|
|
From: Yifeng Zhao <yifeng.zhao@rock-chips.com>
|
|
Date: Thu, 10 Dec 2020 08:22:17 +0800
|
|
Subject: [PATCH] arm: dts: rockchip: Add NFC node for RV1108 SoC
|
|
|
|
Add NAND FLASH Controller(NFC) node for RV1108 SoC.
|
|
|
|
Signed-off-by: Yifeng Zhao <yifeng.zhao@rock-chips.com>
|
|
---
|
|
arch/arm/boot/dts/rv1108.dtsi | 11 +++++++++++
|
|
1 file changed, 11 insertions(+)
|
|
|
|
diff --git a/arch/arm/boot/dts/rv1108.dtsi b/arch/arm/boot/dts/rv1108.dtsi
|
|
index e491964b1c3d..15fa25585ea4 100644
|
|
--- a/arch/arm/boot/dts/rv1108.dtsi
|
|
+++ b/arch/arm/boot/dts/rv1108.dtsi
|
|
@@ -452,6 +452,17 @@ cru: clock-controller@20200000 {
|
|
#reset-cells = <1>;
|
|
};
|
|
|
|
+ nfc: nand-controller@30100000 {
|
|
+ compatible = "rockchip,rv1108-nfc";
|
|
+ reg = <0x30100000 0x1000>;
|
|
+ interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ clocks = <&cru HCLK_NANDC>, <&cru SCLK_NANDC>;
|
|
+ clock-names = "ahb", "nfc";
|
|
+ assigned-clocks = <&cru SCLK_NANDC>;
|
|
+ assigned-clock-rates = <150000000>;
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
emmc: mmc@30110000 {
|
|
compatible = "rockchip,rv1108-dw-mshc", "rockchip,rk3288-dw-mshc";
|
|
reg = <0x30110000 0x4000>;
|
|
|
|
From a2b3dcfa3009e4a5626619ece0b4e863e0b80c6e Mon Sep 17 00:00:00 2001
|
|
From: Yifeng Zhao <yifeng.zhao@rock-chips.com>
|
|
Date: Thu, 10 Dec 2020 08:22:18 +0800
|
|
Subject: [PATCH] arm: dts: rockchip: Add NFC node for RK2928 and other SoCs
|
|
|
|
Add NAND FLASH Controller(NFC) node for RK2928, RK3066, RK3168
|
|
and RK3188 SoCs.
|
|
|
|
Signed-off-by: Yifeng Zhao <yifeng.zhao@rock-chips.com>
|
|
---
|
|
arch/arm/boot/dts/rk3xxx.dtsi | 9 +++++++++
|
|
1 file changed, 9 insertions(+)
|
|
|
|
diff --git a/arch/arm/boot/dts/rk3xxx.dtsi b/arch/arm/boot/dts/rk3xxx.dtsi
|
|
index 859a7477909f..97415180d5bb 100644
|
|
--- a/arch/arm/boot/dts/rk3xxx.dtsi
|
|
+++ b/arch/arm/boot/dts/rk3xxx.dtsi
|
|
@@ -276,6 +276,15 @@ emmc: mmc@1021c000 {
|
|
status = "disabled";
|
|
};
|
|
|
|
+ nfc: nand-controller@10500000 {
|
|
+ compatible = "rockchip,rk2928-nfc";
|
|
+ reg = <0x10500000 0x4000>;
|
|
+ interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ clocks = <&cru HCLK_NANDC0>;
|
|
+ clock-names = "ahb";
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
pmu: pmu@20004000 {
|
|
compatible = "rockchip,rk3066-pmu", "syscon", "simple-mfd";
|
|
reg = <0x20004000 0x100>;
|
|
|
|
From 30fdf17b93046c1836b53a4e029433a898e0b0ff Mon Sep 17 00:00:00 2001
|
|
From: Yifeng Zhao <yifeng.zhao@rock-chips.com>
|
|
Date: Thu, 10 Dec 2020 08:22:19 +0800
|
|
Subject: [PATCH] arm: dts: rockchip: Add NFC node for RK3036 SoC
|
|
|
|
Add NAND FLASH Controller(NFC) node for RK3036 SoC.
|
|
|
|
Signed-off-by: Yifeng Zhao <yifeng.zhao@rock-chips.com>
|
|
---
|
|
arch/arm/boot/dts/rk3036.dtsi | 52 +++++++++++++++++++++++++++++++++++
|
|
1 file changed, 52 insertions(+)
|
|
|
|
diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi
|
|
index 093567022386..dda5a1f79aca 100644
|
|
--- a/arch/arm/boot/dts/rk3036.dtsi
|
|
+++ b/arch/arm/boot/dts/rk3036.dtsi
|
|
@@ -292,6 +292,21 @@ i2s: i2s@10220000 {
|
|
status = "disabled";
|
|
};
|
|
|
|
+ nfc: nand-controller@10500000 {
|
|
+ compatible = "rockchip,rk3036-nfc",
|
|
+ "rockchip,rk2928-nfc";
|
|
+ reg = <0x10500000 0x4000>;
|
|
+ interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ clocks = <&cru HCLK_NANDC>, <&cru SCLK_NANDC>;
|
|
+ clock-names = "ahb", "nfc";
|
|
+ assigned-clocks = <&cru SCLK_NANDC>;
|
|
+ assigned-clock-rates = <150000000>;
|
|
+ pinctrl-0 = <&flash_ale &flash_bus8 &flash_cle &flash_csn0
|
|
+ &flash_rdn &flash_rdy &flash_wrn>;
|
|
+ pinctrl-names = "default";
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
cru: clock-controller@20000000 {
|
|
compatible = "rockchip,rk3036-cru";
|
|
reg = <0x20000000 0x1000>;
|
|
@@ -643,6 +658,43 @@ emmc_bus8: emmc-bus8 {
|
|
};
|
|
};
|
|
|
|
+ nfc {
|
|
+ flash_ale: flash-ale {
|
|
+ rockchip,pins = <2 RK_PA0 1 &pcfg_pull_default>;
|
|
+ };
|
|
+
|
|
+ flash_bus8: flash-bus8 {
|
|
+ rockchip,pins = <1 RK_PD0 1 &pcfg_pull_default>,
|
|
+ <1 RK_PD1 1 &pcfg_pull_default>,
|
|
+ <1 RK_PD2 1 &pcfg_pull_default>,
|
|
+ <1 RK_PD3 1 &pcfg_pull_default>,
|
|
+ <1 RK_PD4 1 &pcfg_pull_default>,
|
|
+ <1 RK_PD5 1 &pcfg_pull_default>,
|
|
+ <1 RK_PD6 1 &pcfg_pull_default>,
|
|
+ <1 RK_PD7 1 &pcfg_pull_default>;
|
|
+ };
|
|
+
|
|
+ flash_cle: flash-cle {
|
|
+ rockchip,pins = <2 RK_PA1 1 &pcfg_pull_default>;
|
|
+ };
|
|
+
|
|
+ flash_csn0: flash-csn0 {
|
|
+ rockchip,pins = <2 RK_PA6 1 &pcfg_pull_default>;
|
|
+ };
|
|
+
|
|
+ flash_rdn: flash-rdn {
|
|
+ rockchip,pins = <2 RK_PA3 1 &pcfg_pull_default>;
|
|
+ };
|
|
+
|
|
+ flash_rdy: flash-rdy {
|
|
+ rockchip,pins = <2 RK_PA4 1 &pcfg_pull_default>;
|
|
+ };
|
|
+
|
|
+ flash_wrn: flash-wrn {
|
|
+ rockchip,pins = <2 RK_PA2 1 &pcfg_pull_default>;
|
|
+ };
|
|
+ };
|
|
+
|
|
emac {
|
|
emac_xfer: emac-xfer {
|
|
rockchip,pins = <2 RK_PB2 1 &pcfg_pull_default>, /* crs_dvalid */
|
|
|
|
From cbfd2b0ef3a8f9fd9f01c624ec8c6d1f2d88c03e Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Sat, 10 Oct 2020 15:32:18 +0000
|
|
Subject: [PATCH] phy/rockchip: inno-hdmi: use correct vco_div_5 macro on
|
|
rk3328
|
|
|
|
inno_hdmi_phy_rk3328_clk_set_rate() is using the RK3228 macro
|
|
when configuring vco_div_5 on RK3328.
|
|
|
|
Fix this by using correct vco_div_5 macro for RK3328.
|
|
|
|
Fixes: 53706a116863 ("phy: add Rockchip Innosilicon hdmi phy")
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 4 ++--
|
|
1 file changed, 2 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
index 9ca20c947283..b0ac1d3ee390 100644
|
|
--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
@@ -790,8 +790,8 @@ static int inno_hdmi_phy_rk3328_clk_set_rate(struct clk_hw *hw,
|
|
RK3328_PRE_PLL_POWER_DOWN);
|
|
|
|
/* Configure pre-pll */
|
|
- inno_update_bits(inno, 0xa0, RK3228_PCLK_VCO_DIV_5_MASK,
|
|
- RK3228_PCLK_VCO_DIV_5(cfg->vco_div_5_en));
|
|
+ inno_update_bits(inno, 0xa0, RK3328_PCLK_VCO_DIV_5_MASK,
|
|
+ RK3328_PCLK_VCO_DIV_5(cfg->vco_div_5_en));
|
|
inno_write(inno, 0xa1, RK3328_PRE_PLL_PRE_DIV(cfg->prediv));
|
|
|
|
val = RK3328_SPREAD_SPECTRUM_MOD_DISABLE;
|
|
|
|
From c06d0adeb1b8a7ac9425babd62735b8a0c6b9d56 Mon Sep 17 00:00:00 2001
|
|
From: Zheng Yang <zhengyang@rock-chips.com>
|
|
Date: Sat, 10 Oct 2020 15:32:18 +0000
|
|
Subject: [PATCH] phy/rockchip: inno-hdmi: round fractal pixclock in rk3328
|
|
recalc_rate
|
|
|
|
inno_hdmi_phy_rk3328_clk_recalc_rate() is returning a rate not found
|
|
in the pre pll config table when the fractal divider is used.
|
|
This can prevent proper power_on because a tmdsclock for the new rate
|
|
is not found in the pre pll config table.
|
|
|
|
Fix this by saving and returning a rounded pixel rate that exist
|
|
in the pre pll config table.
|
|
|
|
Fixes: 53706a116863 ("phy: add Rockchip Innosilicon hdmi phy")
|
|
Signed-off-by: Zheng Yang <zhengyang@rock-chips.com>
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 8 +++++---
|
|
1 file changed, 5 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
index b0ac1d3ee390..093d2334e8cd 100644
|
|
--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
@@ -745,10 +745,12 @@ unsigned long inno_hdmi_phy_rk3328_clk_recalc_rate(struct clk_hw *hw,
|
|
do_div(vco, (nd * (no_a == 1 ? no_b : no_a) * no_d * 2));
|
|
}
|
|
|
|
- inno->pixclock = vco;
|
|
- dev_dbg(inno->dev, "%s rate %lu\n", __func__, inno->pixclock);
|
|
+ inno->pixclock = DIV_ROUND_CLOSEST((unsigned long)vco, 1000) * 1000;
|
|
|
|
- return vco;
|
|
+ dev_dbg(inno->dev, "%s rate %lu vco %llu\n",
|
|
+ __func__, inno->pixclock, vco);
|
|
+
|
|
+ return inno->pixclock;
|
|
}
|
|
|
|
static long inno_hdmi_phy_rk3328_clk_round_rate(struct clk_hw *hw,
|
|
|
|
From 6dc85616fe294fb654e9fb56dd0337dc8db7c327 Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Sat, 10 Oct 2020 15:32:19 +0000
|
|
Subject: [PATCH] phy/rockchip: inno-hdmi: remove unused no_c from rk3328
|
|
recalc_rate
|
|
|
|
no_c is not used in any calculation, lets remove it.
|
|
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 5 +----
|
|
1 file changed, 1 insertion(+), 4 deletions(-)
|
|
|
|
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
index 093d2334e8cd..06db69c8373e 100644
|
|
--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
@@ -714,7 +714,7 @@ unsigned long inno_hdmi_phy_rk3328_clk_recalc_rate(struct clk_hw *hw,
|
|
{
|
|
struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw);
|
|
unsigned long frac;
|
|
- u8 nd, no_a, no_b, no_c, no_d;
|
|
+ u8 nd, no_a, no_b, no_d;
|
|
u64 vco;
|
|
u16 nf;
|
|
|
|
@@ -737,9 +737,6 @@ unsigned long inno_hdmi_phy_rk3328_clk_recalc_rate(struct clk_hw *hw,
|
|
no_b = inno_read(inno, 0xa5) & RK3328_PRE_PLL_PCLK_DIV_B_MASK;
|
|
no_b >>= RK3328_PRE_PLL_PCLK_DIV_B_SHIFT;
|
|
no_b += 2;
|
|
- no_c = inno_read(inno, 0xa6) & RK3328_PRE_PLL_PCLK_DIV_C_MASK;
|
|
- no_c >>= RK3328_PRE_PLL_PCLK_DIV_C_SHIFT;
|
|
- no_c = 1 << no_c;
|
|
no_d = inno_read(inno, 0xa6) & RK3328_PRE_PLL_PCLK_DIV_D_MASK;
|
|
|
|
do_div(vco, (nd * (no_a == 1 ? no_b : no_a) * no_d * 2));
|
|
|
|
From 632faab3a9357dfafa106dfb9dc79a8fda5b9244 Mon Sep 17 00:00:00 2001
|
|
From: Jonas Karlman <jonas@kwiboo.se>
|
|
Date: Sat, 10 Oct 2020 15:32:19 +0000
|
|
Subject: [PATCH] phy/rockchip: inno-hdmi: do not power on rk3328 post pll on
|
|
reg write
|
|
|
|
inno_write is used to configure 0xaa reg, that also hold the
|
|
POST_PLL_POWER_DOWN bit.
|
|
When POST_PLL_REFCLK_SEL_TMDS is configured the power down bit is not
|
|
taken into consideration.
|
|
|
|
Fix this by keeping the power down bit until configuration is complete.
|
|
Also reorder the reg write order for consistency.
|
|
|
|
Fixes: 53706a116863 ("phy: add Rockchip Innosilicon hdmi phy")
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 6 ++++--
|
|
1 file changed, 4 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
index 06db69c8373e..3a59a6da0440 100644
|
|
--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
@@ -1020,9 +1020,10 @@ inno_hdmi_phy_rk3328_power_on(struct inno_hdmi_phy *inno,
|
|
|
|
inno_write(inno, 0xac, RK3328_POST_PLL_FB_DIV_7_0(cfg->fbdiv));
|
|
if (cfg->postdiv == 1) {
|
|
- inno_write(inno, 0xaa, RK3328_POST_PLL_REFCLK_SEL_TMDS);
|
|
inno_write(inno, 0xab, RK3328_POST_PLL_FB_DIV_8(cfg->fbdiv) |
|
|
RK3328_POST_PLL_PRE_DIV(cfg->prediv));
|
|
+ inno_write(inno, 0xaa, RK3328_POST_PLL_REFCLK_SEL_TMDS |
|
|
+ RK3328_POST_PLL_POWER_DOWN);
|
|
} else {
|
|
v = (cfg->postdiv / 2) - 1;
|
|
v &= RK3328_POST_PLL_POST_DIV_MASK;
|
|
@@ -1030,7 +1031,8 @@ inno_hdmi_phy_rk3328_power_on(struct inno_hdmi_phy *inno,
|
|
inno_write(inno, 0xab, RK3328_POST_PLL_FB_DIV_8(cfg->fbdiv) |
|
|
RK3328_POST_PLL_PRE_DIV(cfg->prediv));
|
|
inno_write(inno, 0xaa, RK3328_POST_PLL_POST_DIV_ENABLE |
|
|
- RK3328_POST_PLL_REFCLK_SEL_TMDS);
|
|
+ RK3328_POST_PLL_REFCLK_SEL_TMDS |
|
|
+ RK3328_POST_PLL_POWER_DOWN);
|
|
}
|
|
|
|
for (v = 0; v < 14; v++)
|
|
|
|
From e56866c52176763055e0e40c7d252d2ff186f56d Mon Sep 17 00:00:00 2001
|
|
From: Huicong Xu <xhc@rock-chips.com>
|
|
Date: Sat, 10 Oct 2020 15:32:20 +0000
|
|
Subject: [PATCH] phy/rockchip: inno-hdmi: force set_rate on power_on
|
|
|
|
Regular 8-bit and Deep Color video formats mainly differ in TMDS rate and
|
|
not in pixel clock rate.
|
|
When the hdmiphy clock is configured with the same pixel clock rate using
|
|
clk_set_rate() the clock framework do not signal the hdmi phy driver
|
|
to set_rate when switching between 8-bit and Deep Color.
|
|
This result in pre/post pll not being re-configured when switching between
|
|
regular 8-bit and Deep Color video formats.
|
|
|
|
Fix this by calling set_rate in power_on to force pre pll re-configuration.
|
|
|
|
Signed-off-by: Huicong Xu <xhc@rock-chips.com>
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
---
|
|
drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 13 +++++++++++++
|
|
1 file changed, 13 insertions(+)
|
|
|
|
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
index 3a59a6da0440..3719309ad0d0 100644
|
|
--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
@@ -245,6 +245,7 @@ struct inno_hdmi_phy {
|
|
struct clk_hw hw;
|
|
struct clk *phyclk;
|
|
unsigned long pixclock;
|
|
+ unsigned long tmdsclock;
|
|
};
|
|
|
|
struct pre_pll_config {
|
|
@@ -485,6 +486,8 @@ static int inno_hdmi_phy_power_on(struct phy *phy)
|
|
|
|
dev_dbg(inno->dev, "Inno HDMI PHY Power On\n");
|
|
|
|
+ inno->plat_data->clk_ops->set_rate(&inno->hw, inno->pixclock, 24000000);
|
|
+
|
|
ret = clk_prepare_enable(inno->phyclk);
|
|
if (ret)
|
|
return ret;
|
|
@@ -509,6 +512,8 @@ static int inno_hdmi_phy_power_off(struct phy *phy)
|
|
|
|
clk_disable_unprepare(inno->phyclk);
|
|
|
|
+ inno->tmdsclock = 0;
|
|
+
|
|
dev_dbg(inno->dev, "Inno HDMI PHY Power Off\n");
|
|
|
|
return 0;
|
|
@@ -628,6 +633,9 @@ static int inno_hdmi_phy_rk3228_clk_set_rate(struct clk_hw *hw,
|
|
dev_dbg(inno->dev, "%s rate %lu tmdsclk %lu\n",
|
|
__func__, rate, tmdsclock);
|
|
|
|
+ if (inno->pixclock == rate && inno->tmdsclock == tmdsclock)
|
|
+ return 0;
|
|
+
|
|
cfg = inno_hdmi_phy_get_pre_pll_cfg(inno, rate);
|
|
if (IS_ERR(cfg))
|
|
return PTR_ERR(cfg);
|
|
@@ -670,6 +678,7 @@ static int inno_hdmi_phy_rk3228_clk_set_rate(struct clk_hw *hw,
|
|
}
|
|
|
|
inno->pixclock = rate;
|
|
+ inno->tmdsclock = tmdsclock;
|
|
|
|
return 0;
|
|
}
|
|
@@ -781,6 +790,9 @@ static int inno_hdmi_phy_rk3328_clk_set_rate(struct clk_hw *hw,
|
|
dev_dbg(inno->dev, "%s rate %lu tmdsclk %lu\n",
|
|
__func__, rate, tmdsclock);
|
|
|
|
+ if (inno->pixclock == rate && inno->tmdsclock == tmdsclock)
|
|
+ return 0;
|
|
+
|
|
cfg = inno_hdmi_phy_get_pre_pll_cfg(inno, rate);
|
|
if (IS_ERR(cfg))
|
|
return PTR_ERR(cfg);
|
|
@@ -820,6 +832,7 @@ static int inno_hdmi_phy_rk3328_clk_set_rate(struct clk_hw *hw,
|
|
}
|
|
|
|
inno->pixclock = rate;
|
|
+ inno->tmdsclock = tmdsclock;
|
|
|
|
return 0;
|
|
}
|
|
|
|
From f9ca0e800d2db88c3e8e25d8183b35c5ea2cdbc4 Mon Sep 17 00:00:00 2001
|
|
From: Algea Cao <algea.cao@rock-chips.com>
|
|
Date: Sat, 10 Oct 2020 15:32:20 +0000
|
|
Subject: [PATCH] phy/rockchip: inno-hdmi: Support more pre-pll configuration
|
|
|
|
Adding the following freq cfg in 8-bit and 10-bit color depth:
|
|
|
|
{
|
|
40000000, 65000000, 71000000, 83500000, 85750000,
|
|
88750000, 108000000, 119000000, 162000000
|
|
}
|
|
|
|
New freq has been validated by quantumdata 980.
|
|
|
|
For some freq which can't be got by only using integer freq div,
|
|
frac freq div is needed, Such as 88.75Mhz 10-bit. But The actual
|
|
freq is different from the target freq, We must try to narrow
|
|
the gap between them. RK322X only support integer freq div.
|
|
|
|
The VCO of pre-PLL must be more than 2Ghz, otherwise PLL may be
|
|
unlocked.
|
|
|
|
Signed-off-by: Algea Cao <algea.cao@rock-chips.com>
|
|
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
|
Acked-by: Heiko Stuebner <heiko@sntech.de>
|
|
---
|
|
drivers/phy/rockchip/phy-rockchip-inno-hdmi.c | 74 ++++++++++++-------
|
|
1 file changed, 49 insertions(+), 25 deletions(-)
|
|
|
|
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
index 3719309ad0d0..bb8bdf5e3301 100644
|
|
--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
|
|
@@ -291,32 +291,56 @@ struct inno_hdmi_phy_drv_data {
|
|
const struct phy_config *phy_cfg_table;
|
|
};
|
|
|
|
+/*
|
|
+ * If only using integer freq div can't get frequency we want, frac
|
|
+ * freq div is needed. For example, pclk 88.75 Mhz and tmdsclk
|
|
+ * 110.9375 Mhz must use frac div 0xF00000. The actual frequency is different
|
|
+ * from the target frequency. Such as the tmds clock 110.9375 Mhz,
|
|
+ * the actual tmds clock we get is 110.93719 Mhz. It is important
|
|
+ * to note that RK322X platforms do not support frac div.
|
|
+ */
|
|
static const struct pre_pll_config pre_pll_cfg_table[] = {
|
|
- { 27000000, 27000000, 1, 90, 3, 2, 2, 10, 3, 3, 4, 0, 0},
|
|
- { 27000000, 33750000, 1, 90, 1, 3, 3, 10, 3, 3, 4, 0, 0},
|
|
- { 40000000, 40000000, 1, 80, 2, 2, 2, 12, 2, 2, 2, 0, 0},
|
|
- { 59341000, 59341000, 1, 98, 3, 1, 2, 1, 3, 3, 4, 0, 0xE6AE6B},
|
|
- { 59400000, 59400000, 1, 99, 3, 1, 1, 1, 3, 3, 4, 0, 0},
|
|
- { 59341000, 74176250, 1, 98, 0, 3, 3, 1, 3, 3, 4, 0, 0xE6AE6B},
|
|
- { 59400000, 74250000, 1, 99, 1, 2, 2, 1, 3, 3, 4, 0, 0},
|
|
- { 74176000, 74176000, 1, 98, 1, 2, 2, 1, 2, 3, 4, 0, 0xE6AE6B},
|
|
- { 74250000, 74250000, 1, 99, 1, 2, 2, 1, 2, 3, 4, 0, 0},
|
|
- { 74176000, 92720000, 4, 494, 1, 2, 2, 1, 3, 3, 4, 0, 0x816817},
|
|
- { 74250000, 92812500, 4, 495, 1, 2, 2, 1, 3, 3, 4, 0, 0},
|
|
- {148352000, 148352000, 1, 98, 1, 1, 1, 1, 2, 2, 2, 0, 0xE6AE6B},
|
|
- {148500000, 148500000, 1, 99, 1, 1, 1, 1, 2, 2, 2, 0, 0},
|
|
- {148352000, 185440000, 4, 494, 0, 2, 2, 1, 3, 2, 2, 0, 0x816817},
|
|
- {148500000, 185625000, 4, 495, 0, 2, 2, 1, 3, 2, 2, 0, 0},
|
|
- {296703000, 296703000, 1, 98, 0, 1, 1, 1, 0, 2, 2, 0, 0xE6AE6B},
|
|
- {297000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 2, 2, 0, 0},
|
|
- {296703000, 370878750, 4, 494, 1, 2, 0, 1, 3, 1, 1, 0, 0x816817},
|
|
- {297000000, 371250000, 4, 495, 1, 2, 0, 1, 3, 1, 1, 0, 0},
|
|
- {593407000, 296703500, 1, 98, 0, 1, 1, 1, 0, 2, 1, 0, 0xE6AE6B},
|
|
- {594000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 2, 1, 0, 0},
|
|
- {593407000, 370879375, 4, 494, 1, 2, 0, 1, 3, 1, 1, 1, 0x816817},
|
|
- {594000000, 371250000, 4, 495, 1, 2, 0, 1, 3, 1, 1, 1, 0},
|
|
- {593407000, 593407000, 1, 98, 0, 2, 0, 1, 0, 1, 1, 0, 0xE6AE6B},
|
|
- {594000000, 594000000, 1, 99, 0, 2, 0, 1, 0, 1, 1, 0, 0},
|
|
+ { 27000000, 27000000, 1, 90, 3, 2, 2, 10, 3, 3, 4, 0, 0},
|
|
+ { 27000000, 33750000, 1, 90, 1, 3, 3, 10, 3, 3, 4, 0, 0},
|
|
+ { 40000000, 40000000, 1, 80, 2, 2, 2, 12, 2, 2, 2, 0, 0},
|
|
+ { 40000000, 50000000, 1, 100, 2, 2, 2, 1, 0, 0, 15, 0, 0},
|
|
+ { 59341000, 59341000, 1, 98, 3, 1, 2, 1, 3, 3, 4, 0, 0xE6AE6B},
|
|
+ { 59400000, 59400000, 1, 99, 3, 1, 1, 1, 3, 3, 4, 0, 0},
|
|
+ { 59341000, 74176250, 1, 98, 0, 3, 3, 1, 3, 3, 4, 0, 0xE6AE6B},
|
|
+ { 59400000, 74250000, 1, 99, 1, 2, 2, 1, 3, 3, 4, 0, 0},
|
|
+ { 65000000, 65000000, 1, 130, 2, 2, 2, 1, 0, 0, 12, 0, 0},
|
|
+ { 65000000, 81250000, 3, 325, 0, 3, 3, 1, 0, 0, 10, 0, 0},
|
|
+ { 71000000, 71000000, 3, 284, 0, 3, 3, 1, 0, 0, 8, 0, 0},
|
|
+ { 71000000, 88750000, 3, 355, 0, 3, 3, 1, 0, 0, 10, 0, 0},
|
|
+ { 74176000, 74176000, 1, 98, 1, 2, 2, 1, 2, 3, 4, 0, 0xE6AE6B},
|
|
+ { 74250000, 74250000, 1, 99, 1, 2, 2, 1, 2, 3, 4, 0, 0},
|
|
+ { 74176000, 92720000, 4, 494, 1, 2, 2, 1, 3, 3, 4, 0, 0x816817},
|
|
+ { 74250000, 92812500, 4, 495, 1, 2, 2, 1, 3, 3, 4, 0, 0},
|
|
+ { 83500000, 83500000, 2, 167, 2, 1, 1, 1, 0, 0, 6, 0, 0},
|
|
+ { 83500000, 104375000, 1, 104, 2, 1, 1, 1, 1, 0, 5, 0, 0x600000},
|
|
+ { 85750000, 85750000, 3, 343, 0, 3, 3, 1, 0, 0, 8, 0, 0},
|
|
+ { 88750000, 88750000, 3, 355, 0, 3, 3, 1, 0, 0, 8, 0, 0},
|
|
+ { 88750000, 110937500, 1, 110, 2, 1, 1, 1, 1, 0, 5, 0, 0xF00000},
|
|
+ {108000000, 108000000, 1, 90, 3, 0, 0, 1, 0, 0, 5, 0, 0},
|
|
+ {108000000, 135000000, 1, 90, 0, 2, 2, 1, 0, 0, 5, 0, 0},
|
|
+ {119000000, 119000000, 1, 119, 2, 1, 1, 1, 0, 0, 6, 0, 0},
|
|
+ {119000000, 148750000, 1, 99, 0, 2, 2, 1, 0, 0, 5, 0, 0x2AAAAA},
|
|
+ {148352000, 148352000, 1, 98, 1, 1, 1, 1, 2, 2, 2, 0, 0xE6AE6B},
|
|
+ {148500000, 148500000, 1, 99, 1, 1, 1, 1, 2, 2, 2, 0, 0},
|
|
+ {148352000, 185440000, 4, 494, 0, 2, 2, 1, 3, 2, 2, 0, 0x816817},
|
|
+ {148500000, 185625000, 4, 495, 0, 2, 2, 1, 3, 2, 2, 0, 0},
|
|
+ {162000000, 162000000, 1, 108, 0, 2, 2, 1, 0, 0, 4, 0, 0},
|
|
+ {162000000, 202500000, 1, 135, 0, 2, 2, 1, 0, 0, 5, 0, 0},
|
|
+ {296703000, 296703000, 1, 98, 0, 1, 1, 1, 0, 2, 2, 0, 0xE6AE6B},
|
|
+ {297000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 2, 2, 0, 0},
|
|
+ {296703000, 370878750, 4, 494, 1, 2, 0, 1, 3, 1, 1, 0, 0x816817},
|
|
+ {297000000, 371250000, 4, 495, 1, 2, 0, 1, 3, 1, 1, 0, 0},
|
|
+ {593407000, 296703500, 1, 98, 0, 1, 1, 1, 0, 2, 1, 0, 0xE6AE6B},
|
|
+ {594000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 2, 1, 0, 0},
|
|
+ {593407000, 370879375, 4, 494, 1, 2, 0, 1, 3, 1, 1, 1, 0x816817},
|
|
+ {594000000, 371250000, 4, 495, 1, 2, 0, 1, 3, 1, 1, 1, 0},
|
|
+ {593407000, 593407000, 1, 98, 0, 2, 0, 1, 0, 1, 1, 0, 0xE6AE6B},
|
|
+ {594000000, 594000000, 1, 99, 0, 2, 0, 1, 0, 1, 1, 0, 0},
|
|
{ /* sentinel */ }
|
|
};
|
|
|