* [PATCH v3 0/5] clk: rockchip: Support for some new features
From: Elaine Zhang @ 2019-09-27 3:00 UTC (permalink / raw)
To: heiko
Cc: huangtao, xxx, xf, sboyd, mturquette, Elaine Zhang, linux-kernel,
linux-rockchip, linux-clk, linux-arm-kernel
1. Support for some new features
2. fix up some error
Chang in V3:
[PATCH v2 3/6] : It's been merged
So rebased and resubmit.
Chang in V2:
[PATCH v2 5/6] : fix up the Register error, and add delay.
Elaine Zhang (4):
clk: rockchip: fix up the frac clk get rate error
clk: rockchip: add a clock-type for muxes based in the pmugrf
clk: rockchip: add pll up and down when change pll freq
clk: rockchip: support pll setting by auto
Finley Xiao (1):
clk: rockchip: Add supprot to limit input rate for fractional divider
drivers/clk/rockchip/clk-pll.c | 236 +++++++++++++++++++++++++++++++++++---
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 | 39 ++++++-
drivers/clk/rockchip/clk.h | 27 ++++-
include/linux/clk-provider.h | 2 +
15 files changed, 422 insertions(+), 126 deletions(-)
--
1.9.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v3 1/5] clk: rockchip: Add supprot to limit input rate for fractional divider
From: Elaine Zhang @ 2019-09-27 3:00 UTC (permalink / raw)
To: heiko
Cc: huangtao, xxx, xf, sboyd, mturquette, Elaine Zhang, linux-kernel,
linux-rockchip, Finley Xiao, linux-clk, linux-arm-kernel
In-Reply-To: <1569553244-3165-1-git-send-email-zhangqing@rock-chips.com>
From: Finley Xiao <finley.xiao@rock-chips.com>
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.
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 3a501896b280..6c2f53dc73b6 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,
@@ -420,7 +421,7 @@ enum px30_pmu_plls {
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,
@@ -429,7 +430,7 @@ enum px30_pmu_plls {
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),
@@ -555,7 +556,7 @@ enum px30_pmu_plls {
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),
@@ -565,7 +566,7 @@ enum px30_pmu_plls {
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),
@@ -581,7 +582,7 @@ enum px30_pmu_plls {
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),
@@ -597,7 +598,7 @@ enum px30_pmu_plls {
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,
@@ -612,7 +613,7 @@ enum px30_pmu_plls {
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,
@@ -630,7 +631,7 @@ enum px30_pmu_plls {
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),
@@ -643,7 +644,7 @@ enum px30_pmu_plls {
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),
@@ -656,7 +657,7 @@ enum px30_pmu_plls {
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),
@@ -669,7 +670,7 @@ enum px30_pmu_plls {
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),
@@ -682,7 +683,7 @@ enum px30_pmu_plls {
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),
@@ -882,7 +883,7 @@ enum px30_pmu_plls {
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,
@@ -904,7 +905,7 @@ enum px30_pmu_plls {
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 @@ enum rk3036_plls {
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 @@ enum rk3036_plls {
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 @@ enum rk3036_plls {
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 @@ enum rk3128_plls {
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 @@ enum rk3128_plls {
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 @@ enum rk3128_plls {
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 @@ enum rk3128_plls {
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 77aebfb1d6d5..4823f5ca943d 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 @@ enum rk3188_plls {
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 @@ enum rk3188_plls {
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 @@ enum rk3188_plls {
COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_pre", 0,
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", 0,
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", 0,
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", 0,
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),
@@ -618,21 +622,21 @@ enum rk3188_plls {
COMPOSITE_FRACMUX(0, "i2s0_frac", "i2s0_pre", 0,
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", 0,
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", 0,
RK2928_CLKSEL_CON(8), 0,
RK2928_CLKGATE_CON(0), 12, GFLAGS,
- &rk3066a_i2s2_fracmux),
+ &rk3066a_i2s2_fracmux, RK3188_I2S_FRAC_MAX_PRATE),
GATE(HCLK_I2S1, "hclk_i2s1", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 3, GFLAGS),
GATE(HCLK_I2S2, "hclk_i2s2", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 4, GFLAGS),
@@ -726,7 +730,7 @@ enum rk3188_plls {
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(0, "hclk_imem0", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 14, GFLAGS),
GATE(0, "hclk_imem1", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 15, GFLAGS),
diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c
index d17cfb7a3ff4..f5178c77de3a 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,
};
@@ -421,7 +425,7 @@ enum rk3228_plls {
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),
@@ -431,7 +435,7 @@ enum rk3228_plls {
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,
@@ -444,7 +448,7 @@ enum rk3228_plls {
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),
@@ -454,7 +458,7 @@ enum rk3228_plls {
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),
@@ -496,15 +500,15 @@ enum rk3228_plls {
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 cc2a177bbdbf..5f2b6f125c79 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_plls {
apll, dpll, cpll, gpll, npll,
@@ -357,7 +360,7 @@ enum rk3288_plls {
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),
@@ -372,7 +375,7 @@ enum rk3288_plls {
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,
@@ -381,7 +384,7 @@ enum rk3288_plls {
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),
@@ -584,7 +587,7 @@ enum rk3288_plls {
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,
@@ -593,28 +596,28 @@ enum rk3288_plls {
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 b0baf87a283e..f3942a9a38c6 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,
@@ -333,7 +339,7 @@ enum rk3308_plls {
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),
@@ -343,7 +349,7 @@ enum rk3308_plls {
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),
@@ -353,7 +359,7 @@ enum rk3308_plls {
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),
@@ -363,7 +369,7 @@ enum rk3308_plls {
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),
@@ -373,7 +379,7 @@ enum rk3308_plls {
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),
@@ -453,7 +459,7 @@ enum rk3308_plls {
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),
@@ -584,7 +590,7 @@ enum rk3308_plls {
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,
@@ -634,7 +640,7 @@ enum rk3308_plls {
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),
@@ -644,7 +650,7 @@ enum rk3308_plls {
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),
@@ -658,7 +664,7 @@ enum rk3308_plls {
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),
@@ -671,7 +677,7 @@ enum rk3308_plls {
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),
@@ -685,7 +691,7 @@ enum rk3308_plls {
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),
@@ -698,7 +704,7 @@ enum rk3308_plls {
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),
@@ -712,7 +718,7 @@ enum rk3308_plls {
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),
@@ -725,7 +731,7 @@ enum rk3308_plls {
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),
@@ -739,7 +745,7 @@ enum rk3308_plls {
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),
@@ -752,7 +758,7 @@ enum rk3308_plls {
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,
@@ -765,7 +771,7 @@ enum rk3308_plls {
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,
@@ -783,7 +789,7 @@ enum rk3308_plls {
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),
@@ -798,7 +804,7 @@ enum rk3308_plls {
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 c186a1985bf4..12b1f645cacd 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 @@ enum rk3328_plls {
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 @@ enum rk3328_plls {
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 @@ enum rk3328_plls {
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 @@ enum rk3328_plls {
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 @@ enum rk3328_plls {
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 @@ enum rk3368_plls {
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 @@ enum rk3368_plls {
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 @@ enum rk3368_plls {
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 @@ enum rk3368_plls {
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 @@ enum rk3368_plls {
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 @@ enum rk3368_plls {
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 @@ enum rk3368_plls {
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 ce1d2446f142..bda5d50c5319 100644
--- a/drivers/clk/rockchip/clk-rk3399.c
+++ b/drivers/clk/rockchip/clk-rk3399.c
@@ -13,6 +13,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,
};
@@ -582,7 +588,7 @@ enum rk3399_pmu_plls {
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),
@@ -596,7 +602,7 @@ enum rk3399_pmu_plls {
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),
@@ -606,7 +612,7 @@ enum rk3399_pmu_plls {
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),
@@ -616,7 +622,7 @@ enum rk3399_pmu_plls {
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),
@@ -635,7 +641,7 @@ enum rk3399_pmu_plls {
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),
@@ -645,7 +651,7 @@ enum rk3399_pmu_plls {
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,
@@ -653,7 +659,7 @@ enum rk3399_pmu_plls {
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,
@@ -661,7 +667,7 @@ enum rk3399_pmu_plls {
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,
@@ -1164,7 +1170,7 @@ enum rk3399_pmu_plls {
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,
@@ -1194,7 +1200,7 @@ enum rk3399_pmu_plls {
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,
@@ -1311,7 +1317,7 @@ enum rk3399_pmu_plls {
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),
@@ -1416,7 +1422,7 @@ enum rk3399_pmu_plls {
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),
@@ -1445,7 +1451,7 @@ enum rk3399_pmu_plls {
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 @@ enum rv1108_plls {
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 @@ enum rv1108_plls {
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 @@ enum rv1108_plls {
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 @@ enum rv1108_plls {
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 546e810c3560..fac5a4a3f5c3 100644
--- a/drivers/clk/rockchip/clk.c
+++ b/drivers/clk/rockchip/clk.c
@@ -184,12 +184,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;
+ }
}
/*
@@ -212,7 +226,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 rockchip_clk_frac *frac;
struct clk *clk;
@@ -253,6 +267,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;
clk = clk_register_composite(NULL, name, parent_names, num_parents,
@@ -485,7 +500,7 @@ void __init rockchip_clk_register_branches(
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 2ae7604783dd..30993c0630a3 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -624,6 +624,7 @@ struct clk_hw *clk_hw_register_fixed_factor(struct device *dev,
* @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.
@@ -647,6 +648,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);
--
1.9.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v3 2/5] clk: rockchip: fix up the frac clk get rate error
From: Elaine Zhang @ 2019-09-27 3:00 UTC (permalink / raw)
To: heiko
Cc: huangtao, xxx, xf, sboyd, mturquette, Elaine Zhang, linux-kernel,
linux-rockchip, linux-clk, linux-arm-kernel
In-Reply-To: <1569553244-3165-1-git-send-email-zhangqing@rock-chips.com>
support fractional divider with only one level parent clock
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 fac5a4a3f5c3..8f77c3f9fab7 100644
--- a/drivers/clk/rockchip/clk.c
+++ b/drivers/clk/rockchip/clk.c
@@ -190,16 +190,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;
--
1.9.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v3 4/5] clk: rockchip: add pll up and down when change pll freq
From: Elaine Zhang @ 2019-09-27 3:00 UTC (permalink / raw)
To: heiko
Cc: huangtao, xxx, xf, sboyd, mturquette, Elaine Zhang, linux-kernel,
linux-rockchip, linux-clk, linux-arm-kernel
In-Reply-To: <1569553244-3165-1-git-send-email-zhangqing@rock-chips.com>
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 198417d56300..390e9473807a 100644
--- a/drivers/clk/rockchip/clk-pll.c
+++ b/drivers/clk/rockchip/clk-pll.c
@@ -199,6 +199,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) |
@@ -220,6 +225,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_pll_wait_lock(pll);
if (ret) {
@@ -676,6 +686,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),
@@ -699,6 +714,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) {
--
1.9.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v3 3/5] clk: rockchip: add a clock-type for muxes based in the pmugrf
From: Elaine Zhang @ 2019-09-27 3:00 UTC (permalink / raw)
To: heiko
Cc: huangtao, xxx, xf, sboyd, mturquette, Elaine Zhang, linux-kernel,
linux-rockchip, linux-clk, linux-arm-kernel
In-Reply-To: <1569553244-3165-1-git-send-email-zhangqing@rock-chips.com>
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 8f77c3f9fab7..4f238f2851ac 100644
--- a/drivers/clk/rockchip/clk.c
+++ b/drivers/clk/rockchip/clk.c
@@ -407,6 +407,8 @@ struct rockchip_clk_provider * __init 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;
@@ -482,6 +484,13 @@ void __init rockchip_clk_register_branches(
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, \
--
1.9.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [RFC PATCH 18/18] net: wireguard - switch to crypto API for packet encryption
From: Linus Torvalds @ 2019-09-27 2:54 UTC (permalink / raw)
To: Pascal Van Leeuwen
Cc: Jason A . Donenfeld, Catalin Marinas, Herbert Xu, Arnd Bergmann,
Ard Biesheuvel, Greg KH, Eric Biggers, Samuel Neves,
Linux Crypto Mailing List, Andy Lutomirski, Marc Zyngier,
Dan Carpenter, Will Deacon, David Miller, Linux ARM
In-Reply-To: <CAHk-=wjr1w7x9Rjre_ALnDLASYNjsEHxu6VJpk4eUwZXN0ntqw@mail.gmail.com>
On Thu, Sep 26, 2019 at 6:30 PM Linus Torvalds
<torvalds@linux-foundation.org> wrote:
>
> And once you have that cookie, and you see "ok, I didn't get the
> answer immediately" only THEN do you start filling in things like
> callback stuff, or maybe you set up a wait-queue and start waiting for
> it, or whatever".
Side note: almost nobody does this.
Almost every single async interface I've ever seen ends up being "only
designed for async".
And I think the reason is that everybody first does the simply
synchronous interfaces, and people start using those, and a lot of
people are perfectly happy with them. They are simple, and they work
fine for the huge majority of users.
And then somebody comes along and says "no, _we_ need to do this
asynchronously", and by definition that person does *not* care for the
synchronous case, since that interface already existed and was simpler
and already was mostly sufficient for the people who used it, and so
the async interface ends up being _only_ designed for the new async
workflow. Because that whole new world was written with just that case
is mind, and the synchronous case clearly didn't matter.
So then you end up with that kind of dichotomous situation, where you
have a strict black-and-white either-synchronous-or-async model.
And then some people - quite reasonably - just want the simplicity of
the synchronous code and it performs better for them because the
interfaces are simpler and better suited to their lack of extra work.
And other people feel they need the async code, because they can take
advantage of it.
And never the twain shall meet, because the async interface is
actively _bad_ for the people who have sync workloads and the sync
interface doesn't work for the async people.
Non-crypto example: [p]read() vs aio_read(). They do the same thing
(on a high level) apart from that sync/async issue. And there's no way
to get the best of both worlds.
Doing aio_read() on something that is already cached is actively much
worse than just doing a synchronous read() of cached data.
But aio_read() _can_ be much better if you know your workload doesn't
cache well and read() blocks too much for you.
There's no "read_potentially_async()" interface that just does the
synchronous read for any cached portion of the data, and then delays
just the IO parts and returns a "here, I gave you X bytes right now,
use this cookie to wait for the rest".
Maybe nobody would use it. But it really should be possibly to have
interfaces where a good synchronous implementation is _possible_
without the extra overhead, while also allowing async implementations.
Linus
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH V9 2/2] mailbox: introduce ARM SMC based mailbox
From: Florian Fainelli @ 2019-09-27 2:39 UTC (permalink / raw)
To: Peng Fan, robh+dt@kernel.org, mark.rutland@arm.com,
jassisinghbrar@gmail.com, sudeep.holla@arm.com,
andre.przywara@arm.com
Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, dl-linux-imx
In-Reply-To: <1569377224-5755-3-git-send-email-peng.fan@nxp.com>
On 9/24/2019 7:09 PM, Peng Fan wrote:
> From: Peng Fan <peng.fan@nxp.com>
>
> This mailbox driver implements a mailbox which signals transmitted data
> via an ARM smc (secure monitor call) instruction. The mailbox receiver
> is implemented in firmware and can synchronously return data when it
> returns execution to the non-secure world again.
> An asynchronous receive path is not implemented.
> This allows the usage of a mailbox to trigger firmware actions on SoCs
> which either don't have a separate management processor or on which such
> a core is not available. A user of this mailbox could be the SCP
> interface.
>
> Modified from Andre Przywara's v2 patch
> https://lore.kernel.org/patchwork/patch/812999/
>
> Cc: Andre Przywara <andre.przywara@arm.com>
> Signed-off-by: Peng Fan <peng.fan@nxp.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Thanks for your persistence working on this!
--
Florian
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH V2 2/2] nvmem: imx: scu: support write
From: Peng Fan @ 2019-09-27 2:23 UTC (permalink / raw)
To: srinivas.kandagatla@linaro.org, shawnguo@kernel.org,
s.hauer@pengutronix.de
Cc: Aisheng Dong, Peng Fan, linux-kernel@vger.kernel.org,
dl-linux-imx, kernel@pengutronix.de, festevam@gmail.com,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <1569550913-10176-1-git-send-email-peng.fan@nxp.com>
From: Peng Fan <peng.fan@nxp.com>
The fuse programming from non-secure world is blocked, so we could
only use Arm Trusted Firmware SIP call to let ATF program fuse.
Because there is ECC region that could only be programmed once,
so add a heler in_ecc to check the ecc region.
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
V2:
Rebased on Latest linux-next
drivers/nvmem/imx-ocotp-scu.c | 73 ++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 72 insertions(+), 1 deletion(-)
diff --git a/drivers/nvmem/imx-ocotp-scu.c b/drivers/nvmem/imx-ocotp-scu.c
index 030e27ba4dfb..03f1ab23ad51 100644
--- a/drivers/nvmem/imx-ocotp-scu.c
+++ b/drivers/nvmem/imx-ocotp-scu.c
@@ -7,6 +7,7 @@
* Peng Fan <peng.fan@nxp.com>
*/
+#include <linux/arm-smccc.h>
#include <linux/firmware/imx/sci.h>
#include <linux/module.h>
#include <linux/nvmem-provider.h>
@@ -14,6 +15,9 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
+#define IMX_SIP_OTP 0xC200000A
+#define IMX_SIP_OTP_WRITE 0x2
+
enum ocotp_devtype {
IMX8QXP,
IMX8QM,
@@ -46,6 +50,8 @@ struct imx_sc_msg_misc_fuse_read {
u32 word;
} __packed;
+static DEFINE_MUTEX(scu_ocotp_mutex);
+
static struct ocotp_devtype_data imx8qxp_data = {
.devtype = IMX8QXP,
.nregs = 800,
@@ -84,6 +90,23 @@ static bool in_hole(void *context, u32 index)
return false;
}
+static bool in_ecc(void *context, u32 index)
+{
+ struct ocotp_priv *priv = context;
+ const struct ocotp_devtype_data *data = priv->data;
+ int i;
+
+ for (i = 0; i < data->num_region; i++) {
+ if (data->region[i].flag & ECC_REGION) {
+ if ((index >= data->region[i].start) &&
+ (index <= data->region[i].end))
+ return true;
+ }
+ }
+
+ return false;
+}
+
static int imx_sc_misc_otp_fuse_read(struct imx_sc_ipc *ipc, u32 word,
u32 *val)
{
@@ -127,6 +150,8 @@ static int imx_scu_ocotp_read(void *context, unsigned int offset,
if (!p)
return -ENOMEM;
+ mutex_lock(&scu_ocotp_mutex);
+
buf = p;
for (i = index; i < (index + count); i++) {
@@ -137,6 +162,7 @@ static int imx_scu_ocotp_read(void *context, unsigned int offset,
ret = imx_sc_misc_otp_fuse_read(priv->nvmem_ipc, i, buf);
if (ret) {
+ mutex_unlock(&scu_ocotp_mutex);
kfree(p);
return ret;
}
@@ -145,18 +171,63 @@ static int imx_scu_ocotp_read(void *context, unsigned int offset,
memcpy(val, (u8 *)p + offset % 4, bytes);
+ mutex_unlock(&scu_ocotp_mutex);
+
kfree(p);
return 0;
}
+static int imx_scu_ocotp_write(void *context, unsigned int offset,
+ void *val, size_t bytes)
+{
+ struct ocotp_priv *priv = context;
+ struct arm_smccc_res res;
+ u32 *buf = val;
+ u32 tmp;
+ u32 index;
+ int ret;
+
+ /* allow only writing one complete OTP word at a time */
+ if ((bytes != 4) || (offset % 4))
+ return -EINVAL;
+
+ index = offset >> 2;
+
+ if (in_hole(context, index))
+ return -EINVAL;
+
+ if (in_ecc(context, index)) {
+ pr_warn("ECC region, only program once\n");
+ mutex_lock(&scu_ocotp_mutex);
+ ret = imx_sc_misc_otp_fuse_read(priv->nvmem_ipc, index, &tmp);
+ mutex_unlock(&scu_ocotp_mutex);
+ if (ret)
+ return ret;
+ if (tmp) {
+ pr_warn("ECC region, already has value: %x\n", tmp);
+ return -EIO;
+ }
+ }
+
+ mutex_lock(&scu_ocotp_mutex);
+
+ arm_smccc_smc(IMX_SIP_OTP, IMX_SIP_OTP_WRITE, index, *buf,
+ 0, 0, 0, 0, &res);
+
+ mutex_unlock(&scu_ocotp_mutex);
+
+ return res.a0;
+}
+
static struct nvmem_config imx_scu_ocotp_nvmem_config = {
.name = "imx-scu-ocotp",
- .read_only = true,
+ .read_only = false,
.word_size = 4,
.stride = 1,
.owner = THIS_MODULE,
.reg_read = imx_scu_ocotp_read,
+ .reg_write = imx_scu_ocotp_write,
};
static const struct of_device_id imx_scu_ocotp_dt_ids[] = {
--
2.16.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH V2 1/2] nvmem: imx: scu: support hole region check
From: Peng Fan @ 2019-09-27 2:23 UTC (permalink / raw)
To: srinivas.kandagatla@linaro.org, shawnguo@kernel.org,
s.hauer@pengutronix.de
Cc: Aisheng Dong, Peng Fan, linux-kernel@vger.kernel.org,
dl-linux-imx, kernel@pengutronix.de, festevam@gmail.com,
linux-arm-kernel@lists.infradead.org
From: Peng Fan <peng.fan@nxp.com>
Introduce HOLE/ECC_REGION flag and in_hole helper to ease the check
of hole region. The ECC_REGION is also introduced here which is
preparing for programming support. ECC_REGION could only be programmed
once, so need take care.
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
V2:
Rebased on latest linux-next
drivers/nvmem/imx-ocotp-scu.c | 47 ++++++++++++++++++++++++++++++++++++++-----
1 file changed, 42 insertions(+), 5 deletions(-)
diff --git a/drivers/nvmem/imx-ocotp-scu.c b/drivers/nvmem/imx-ocotp-scu.c
index 61a17f943f47..030e27ba4dfb 100644
--- a/drivers/nvmem/imx-ocotp-scu.c
+++ b/drivers/nvmem/imx-ocotp-scu.c
@@ -19,9 +19,20 @@ enum ocotp_devtype {
IMX8QM,
};
+#define ECC_REGION BIT(0)
+#define HOLE_REGION BIT(1)
+
+struct ocotp_region {
+ u32 start;
+ u32 end;
+ u32 flag;
+};
+
struct ocotp_devtype_data {
int devtype;
int nregs;
+ u32 num_region;
+ struct ocotp_region region[];
};
struct ocotp_priv {
@@ -38,13 +49,41 @@ struct imx_sc_msg_misc_fuse_read {
static struct ocotp_devtype_data imx8qxp_data = {
.devtype = IMX8QXP,
.nregs = 800,
+ .num_region = 3,
+ .region = {
+ {0x10, 0x10f, ECC_REGION},
+ {0x110, 0x21F, HOLE_REGION},
+ {0x220, 0x31F, ECC_REGION},
+ },
};
static struct ocotp_devtype_data imx8qm_data = {
.devtype = IMX8QM,
.nregs = 800,
+ .num_region = 2,
+ .region = {
+ {0x10, 0x10f, ECC_REGION},
+ {0x1a0, 0x1ff, ECC_REGION},
+ },
};
+static bool in_hole(void *context, u32 index)
+{
+ struct ocotp_priv *priv = context;
+ const struct ocotp_devtype_data *data = priv->data;
+ int i;
+
+ for (i = 0; i < data->num_region; i++) {
+ if (data->region[i].flag & HOLE_REGION) {
+ if ((index >= data->region[i].start) &&
+ (index <= data->region[i].end))
+ return true;
+ }
+ }
+
+ return false;
+}
+
static int imx_sc_misc_otp_fuse_read(struct imx_sc_ipc *ipc, u32 word,
u32 *val)
{
@@ -91,11 +130,9 @@ static int imx_scu_ocotp_read(void *context, unsigned int offset,
buf = p;
for (i = index; i < (index + count); i++) {
- if (priv->data->devtype == IMX8QXP) {
- if ((i > 271) && (i < 544)) {
- *buf++ = 0;
- continue;
- }
+ if (in_hole(context, i)) {
+ *buf++ = 0;
+ continue;
}
ret = imx_sc_misc_otp_fuse_read(priv->nvmem_ipc, i, buf);
--
2.16.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [RFC PATCH 18/18] net: wireguard - switch to crypto API for packet encryption
From: Linus Torvalds @ 2019-09-27 2:06 UTC (permalink / raw)
To: Pascal Van Leeuwen
Cc: Jason A . Donenfeld, Catalin Marinas, Herbert Xu, Arnd Bergmann,
Ard Biesheuvel, Greg KH, Eric Biggers, Samuel Neves,
Linux Crypto Mailing List, Andy Lutomirski, Marc Zyngier,
Dan Carpenter, Will Deacon, David Miller, Linux ARM
In-Reply-To: <MN2PR20MB297317D9870A3B93B5E506C9CA810@MN2PR20MB2973.namprd20.prod.outlook.com>
On Thu, Sep 26, 2019 at 5:15 PM Pascal Van Leeuwen
<pvanleeuwen@verimatrix.com> wrote:
>
> But even the CPU only thing may have several implementations, of which
> you want to select the fastest one supported by the _detected_ CPU
> features (i.e. SSE, AES-NI, AVX, AVX512, NEON, etc. etc.)
> Do you think this would still be efficient if that would be some
> large if-else tree? Also, such a fixed implementation wouldn't scale.
Just a note on this part.
Yes, with retpoline a large if-else tree is actually *way* better for
performance these days than even just one single indirect call. I
think the cross-over point is somewhere around 20 if-statements.
But those kinds of things also are things that we already handle well
with instruction rewriting, so they can actually have even less of an
overhead than a conditional branch. Using code like
if (static_cpu_has(X86_FEATURE_AVX2))
actually ends up patching the code at run-time, so you end up having
just an unconditional branch. Exactly because CPU feature choices
often end up being in critical code-paths where you have
one-or-the-other kind of setup.
And yes, one of the big users of this is very much the crypto library code.
The code to do the above is disgusting, and when you look at the
generated code you see odd unreachable jumps and what looks like a
slow "bts" instruction that does the testing dynamically.
And then the kernel instruction stream gets rewritten fairly early
during the boot depending on the actual CPU capabilities, and the
dynamic tests get overwritten by a direct jump.
Admittedly I don't think the arm64 people go to quite those lengths,
but it certainly wouldn't be impossible there either. It just takes a
bit of architecture knowledge and a strong stomach ;)
Linus
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* RE: [PATCH v5 11/15] dmaengine: imx-sdma: fix ecspi1 rx dma not work on i.mx8mm
From: Robin Gong @ 2019-09-27 1:55 UTC (permalink / raw)
To: Schrempf Frieder
Cc: Fabio Estevam, s.hauer@pengutronix.de,
linux-kernel@vger.kernel.org, linux-spi@vger.kernel.org,
vkoul@kernel.org, dl-linux-imx, Pengutronix Kernel Team,
dmaengine@vger.kernel.org, dan.j.williams@intel.com,
shawnguo@kernel.org, linux-arm-kernel@lists.infradead.org
In-Reply-To: <1307d229-4c49-80e3-04ba-377c0caeae9c@kontron.de>
On 2019-9-25 22:53 Schrempf Frieder <frieder.schrempf@kontron.de> wrote:
> On 25.09.19 13:26, Robin Gong wrote:
> > On 2019-9-24 21:28 Schrempf Frieder <frieder.schrempf@kontron.de>
> wrote:
> >>
> >> Hi Robin,
> >>
> >>> From: Robin Gong <yibin.gong at nxp.com>
> >>>
> >>> Because the number of ecspi1 rx event on i.mx8mm is 0, the condition
> >>> check ignore such special case without dma channel enabled, which
> >>> caused
> >>> ecspi1 rx works failed. Actually, no need to check
> >>> event_id0/event_id1 and replace checking 'event_id1' with
> >>> 'DMA_DEV_TO_DEV', so that configure
> >>> event_id1 only in case DEV_TO_DEV.
> >>>
> >>> Signed-off-by: Robin Gong <yibin.gong at nxp.com>
> >>> Acked-by: Vinod Koul <vkoul at kernel.org>
> >>
> >> I have a custom board with i.MX8MM and SPI flash on ecspi1. I'm
> >> currently testing with v5.3 and as SPI didn't work, I tried two different
> things:
> >>
> >> 1. Removing 'dmas' and 'dma-names' from the ecspi1 node in
> imx8mm.dtsi,
> >> to use PIO instead of DMA. This works as expected and the driver
> >> boots with the following messages:
> >>
> >> spi_imx 30820000.spi: dma setup error -19, use pio
> >> m25p80 spi0.0: mx25v8035f (1024 Kbytes)
> >> spi_imx 30820000.spi: probed
> >>
> >> 2. Applying your patchset and use DMA. In this case, the flash also
> >> works fine, but there are some error messages printed while
> booting:
> >>
> >> spi_master spi0: I/O Error in DMA RX
> >> m25p80 spi0.0: SPI transfer failed: -110
> >> spi_master spi0: failed to transfer one message from queue
> >> m25p80 spi0.0: mx25v8035f (1024 Kbytes)
> >> spi_imx 30820000.spi: probed
> >>
> >> It would be great to get your patches merged and fix SPI + DMA, but
> >> for i.MX8MM, we need to get rid of the error messages. Do you have an
> >> idea, what's wrong?
>
> > Could you check if the length of spi message is bigger than fifo_size
> > during spi_nor probe? If yes, at that time maybe sdma firmware not loaded.
> > if (transfer->len < spi_imx->devtype_data->fifo_size)
>
> Indeed, most of the transfers triggered by the SPI NOR dirver are below
> fifo_size and work fine, but some are bigger. The transfers therefore try to
> use DMA, but the firmware is not loaded yet.
>
> How is this supposed to work? Shouldn't all transfers use PIO as long as the
> SDMA firmware is not loaded yet?
Yes, for ecspi should work with ram script, it's better check if sdma firmware
is ready in spi_imx_dma_configure(), need modification in sdma driver too.
I'll create another patch after this patch set accepted.
>
> (+ Cc: linux-spi@vger.kernel.org)
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v8 6/6] PM / devfreq: Use PM QoS for sysfs min/max_freq
From: Chanwoo Choi @ 2019-09-27 1:58 UTC (permalink / raw)
To: Matthias Kaehlcke
Cc: Artur Świgoń, Abel Vesa, Saravana Kannan, linux-pm,
Viresh Kumar, NXP Linux Team, Krzysztof Kozlowski, Lukasz Luba,
Kyungmin Park, MyungJoo Ham, Alexandre Bailon, Leonard Crestez,
Georgi Djakov, linux-arm-kernel, Jacky Bai
In-Reply-To: <20190926160445.GO133864@google.com>
On 19. 9. 27. 오전 1:04, Matthias Kaehlcke wrote:
> On Thu, Sep 26, 2019 at 10:25:41AM +0900, Chanwoo Choi wrote:
>> On 19. 9. 26. 오전 1:45, Matthias Kaehlcke wrote:
>>> On Wed, Sep 25, 2019 at 11:41:07AM +0900, Chanwoo Choi wrote:
>>>> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>>>>> Switch the handling of min_freq and max_freq from sysfs to use the
>>>>> dev_pm_qos_request interface.
>>>>>
>>>>> Since PM QoS handles frequencies as kHz this change reduces the
>>>>> precision of min_freq and max_freq. This shouldn't introduce problems
>>>>> because frequencies which are not an integer number of kHz are likely
>>>>> not an integer number of Hz either.
>>>>>
>>>>> Try to ensure compatibility by rounding min values down and rounding
>>>>> max values up.
>>>>>
>>>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>>>> ---
>>>>> drivers/devfreq/devfreq.c | 46 ++++++++++++++++++++++++---------------
>>>>> include/linux/devfreq.h | 9 ++++----
>>>>> 2 files changed, 33 insertions(+), 22 deletions(-)
>>>>>
>>>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>>>> index 784f3e40536a..8bb7efd821ab 100644
>>>>> --- a/drivers/devfreq/devfreq.c
>>>>> +++ b/drivers/devfreq/devfreq.c
>>>>> @@ -137,14 +137,10 @@ static void get_freq_range(struct devfreq *devfreq,
>>>>> qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>> DEV_PM_QOS_MIN_FREQUENCY);
>>>>> *min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>>>>> *max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>>>>>
>>>>> - /* constraints from sysfs */
>>>>> - *min_freq = max(*min_freq, devfreq->min_freq);
>>>>> - *max_freq = min(*max_freq, devfreq->max_freq);
>>>>> -
>>>>> /* constraints from OPP interface */
>>>>> *min_freq = max(*min_freq, devfreq->scaling_min_freq);
>>>>> /* scaling_max_freq can be zero on error */
>>>>> if (devfreq->scaling_max_freq)
>>>>> *max_freq = min(*max_freq, devfreq->scaling_max_freq);
>>>>> @@ -679,10 +675,12 @@ static void devfreq_dev_release(struct device *dev)
>>>>> DEV_PM_QOS_MIN_FREQUENCY);
>>>>>
>>>>> if (devfreq->profile->exit)
>>>>> devfreq->profile->exit(devfreq->dev.parent);
>>>>>
>>>>> + dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
>>>>> + dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
>>>>
>>>> Please check the return value if error happen, just print the err with dev_err()
>>>> without stopping the release steps.
>>>
>>> I wonder if dev_warn() would be more appropriate, since the current operation
>>> is not aborted.
>>>
>>>>> kfree(devfreq->time_in_state);
>>>>> kfree(devfreq->trans_table);
>>>>> mutex_destroy(&devfreq->lock);
>>>>> kfree(devfreq);
>>>>> }
>>>>> @@ -747,18 +745,25 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>> devfreq->scaling_min_freq = find_available_min_freq(devfreq);
>>>>> if (!devfreq->scaling_min_freq) {
>>>>> err = -EINVAL;
>>>>> goto err_dev;
>>>>> }
>>>>> - devfreq->min_freq = devfreq->scaling_min_freq;
>>>>>
>>>>> devfreq->scaling_max_freq = find_available_max_freq(devfreq);
>>>>> if (!devfreq->scaling_max_freq) {
>>>>> err = -EINVAL;
>>>>> goto err_dev;
>>>>> }
>>>>> - devfreq->max_freq = devfreq->scaling_max_freq;
>>>>> +
>>>>> + err = dev_pm_qos_add_request(dev, &devfreq->user_min_freq_req,
>>>>> + DEV_PM_QOS_MIN_FREQUENCY, 0);
>>>>> + if (err < 0)
>>>>> + goto err_dev;
>>>>> + err = dev_pm_qos_add_request(dev, &devfreq->user_max_freq_req,
>>>>> + DEV_PM_QOS_MAX_FREQUENCY, S32_MAX);
>>>>> + if (err < 0)
>>>>> + goto err_dev;
>>>>>
>>>>> devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
>>>>> atomic_set(&devfreq->suspend_count, 0);
>>>>>
>>>>> devfreq->trans_table = kzalloc(
>>>>> @@ -843,10 +848,14 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>> err_dev:
>>>>> /*
>>>>> * Cleanup path for errors that happen before registration.
>>>>> * Otherwise we rely on devfreq_dev_release.
>>>>> */
>>>>> + if (dev_pm_qos_request_active(&devfreq->user_max_freq_req))
>>>>> + dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
>>>>
>>>> Please check the return value if error happen, just print the err with dev_err()
>>>> without stopping the release steps.
>>>>
>>>> dev_err(... "failed to remove request of DEV_PM_QOS_MAX_FREQUENCY\n");
>>>
>>> dev_warn() for the same reason as above?
>>
>> Actually, I think that is not critical error but need to print the error
>> So, I think that dev_err() is enough. If this thing is critical,
>> better to use dev_warn.
>
> We agree that this is not critical, but not when to use dev_err()
> and dev_warn(). You seem to imply that dev_warn() is more severe
> than dev_err(), however it's the other way around:
>
> #define KERN_ERR KERN_SOH "3" /* error conditions */
> #define KERN_WARNING KERN_SOH "4" /* warning conditions */
> #define KERN_NOTICE KERN_SOH "5" /* normal but significant condition */
>
> I think in this case you can go either way, it's certainly an error,
> but the driver continues with the normal execution path.
I agree to use dev_warn. Thanks for detailed explanation.
>
>>>
>>> I think the message would be better with a slight change:
>>>
>>> "failed to remove DEV_PM_QOS_MAX_FREQUENCY request\n"
>>
>> OK.
>>
>>>
>>>>
>>>>> + if (dev_pm_qos_request_active(&devfreq->user_min_freq_req))
>>>>> + dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
>>>>
>>>> dev_err(... "failed to remove request of DEV_PM_QOS_MIN_FREQUENCY\n");
>>>
>>> ditto
>>>
>>>>> kfree(devfreq->time_in_state);
>>>>> kfree(devfreq->trans_table);
>>>>> kfree(devfreq);
>>>>> err_out:
>>>>> return ERR_PTR(err);
>>>>> @@ -1407,14 +1416,15 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
>>>>>
>>>>> ret = sscanf(buf, "%lu", &value);
>>>>> if (ret != 1)
>>>>> return -EINVAL;
>>>>>
>>>>> - mutex_lock(&df->lock);
>>>>> - df->min_freq = value;
>>>>> - update_devfreq(df);
>>>>> - mutex_unlock(&df->lock);
>>>>> + /* round down to kHz for PM QoS */
>>>>
>>>> I prefer more detailed description as following:
>>>>
>>>> /*
>>>> * Round down to KHz to decide the proper minimum frequency
>>>
>>> it should be kHz, with a lower-case 'k', as in the original comment.
>>
>> Good.
>>
>>>
>>>> * which is closed to user request.
>>>> */
>>>
>>> The comment you suggest doesn't provide any information about why the
>>> conversion to kHz is done, in this sense the original comment that
>>> mentions PM QoS provides more value.
>>>
>>> With whatever we end up, I suggest to use 'convert' instead of
>>> 'round down'.
>>
>> I agree to use 'convert' instead of 'round down'
>> if some expression indicates the correct meaning.
>>
>>>
>>>>> + ret = dev_pm_qos_update_request(&df->user_min_freq_req,
>>>>> + value / HZ_PER_KHZ);
>>>>> + if (ret < 0)
>>>>> + return ret;
>>>>>
>>>>> return count;
>>>>> }
>>>>>
>>>>> static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
>>>>> @@ -1439,19 +1449,19 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
>>>>>
>>>>> ret = sscanf(buf, "%lu", &value);
>>>>> if (ret != 1)
>>>>> return -EINVAL;
>>>>>
>>>>> - mutex_lock(&df->lock);
>>>>> -
>>>>> - /* Interpret zero as "don't care" */
>>>>> - if (!value)
>>>>> - value = ULONG_MAX;
>>>>> + /* round up to kHz for PM QoS and interpret zero as "don't care" */
>>>>
>>>> I think that "don't care" comment style is not good.
>>>>
>>>> I referred to the Documentation/ABI/testing/sysfs-class-devfreq file.
>>>> I prefer more detailed description as following:
>>>> /*
>>>> * Round up to KHz to decide the proper maximum frequency
>>>
>>> kHz
>>>
>>>> * which is closed to user request. If value is zero,
>>>> * the user does not care.
>>>
>>> "the user does not care" is still very casual you didn't like initially.
>>> How about "A value of zero is interpreted as 'no limit'."?
>>>
>>> As for the min freq, I think PM QoS should be mentioned to make clear why
>>> the conversion to kHz is needed.
>>
>> Agree. I expect that Leonard will mention that.
>>
>>>
>>>> */
>>>>
>>>>
>>>>> + if (value)
>>>>> + value = DIV_ROUND_UP(value, HZ_PER_KHZ);
>>>>> + else
>>>>> + value = S32_MAX;
>>>>>
>>>>> - df->max_freq = value;
>>>>> - update_devfreq(df);
>>>>> - mutex_unlock(&df->lock);
>>>>> + ret = dev_pm_qos_update_request(&df->user_max_freq_req, value);
>>>>> + if (ret < 0)
>>>>> + return ret;
>>>>>
>>>>> return count;
>>>>> }
>>>>> static DEVICE_ATTR_RW(min_freq);
>>>>>
>>>>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>>>>> index dac0dffeabb4..7849fe4c666d 100644
>>>>> --- a/include/linux/devfreq.h
>>>>> +++ b/include/linux/devfreq.h
>>>>> @@ -11,10 +11,11 @@
>>>>> #define __LINUX_DEVFREQ_H__
>>>>>
>>>>> #include <linux/device.h>
>>>>> #include <linux/notifier.h>
>>>>> #include <linux/pm_opp.h>
>>>>> +#include <linux/pm_qos.h>
>>>>>
>>>>> #define DEVFREQ_NAME_LEN 16
>>>>>
>>>>> /* DEVFREQ governor name */
>>>>> #define DEVFREQ_GOV_SIMPLE_ONDEMAND "simple_ondemand"
>>>>> @@ -121,12 +122,12 @@ struct devfreq_dev_profile {
>>>>> * devfreq.nb to the corresponding register notifier call chain.
>>>>> * @work: delayed work for load monitoring.
>>>>> * @previous_freq: previously configured frequency value.
>>>>> * @data: Private data of the governor. The devfreq framework does not
>>>>> * touch this.
>>>>> - * @min_freq: Limit minimum frequency requested by user (0: none)
>>>>> - * @max_freq: Limit maximum frequency requested by user (0: none)
>>>>> + * @user_min_freq_req: PM QoS min frequency request from user (via sysfs)
>>>>
>>>> min -> minimum and then remove parenthesis as following:
>>>> PM QoS minimum frequency request by user via sysfs
>>>>
>>>>> + * @user_max_freq_req: PM QoS max frequency request from user (via sysfs)
>>>>
>>>> ditto. max -> maximum
>>>> PM QoS maximum frequency request by user via sysfs
>>>>
>>>>> * @scaling_min_freq: Limit minimum frequency requested by OPP interface
>>>>> * @scaling_max_freq: Limit maximum frequency requested by OPP interface
>>>>> * @stop_polling: devfreq polling status of a device.
>>>>> * @suspend_freq: frequency of a device set during suspend phase.
>>>>> * @resume_freq: frequency of a device set in resume phase.
>>>>> @@ -161,12 +162,12 @@ struct devfreq {
>>>>> unsigned long previous_freq;
>>>>> struct devfreq_dev_status last_status;
>>>>>
>>>>> void *data; /* private data for governors */
>>>>>
>>>>> - unsigned long min_freq;
>>>>> - unsigned long max_freq;
>>>>> + struct dev_pm_qos_request user_min_freq_req;
>>>>> + struct dev_pm_qos_request user_max_freq_req;
>>>>> unsigned long scaling_min_freq;
>>>>> unsigned long scaling_max_freq;
>>>>> bool stop_polling;
>>>>>
>>>>> unsigned long suspend_freq;
>>>>>
>>>>
>>>>
>>>> --
>>>> Best Regards,
>>>> Chanwoo Choi
>>>> Samsung Electronics
>>>
>>>
>>
>>
>> --
>> Best Regards,
>> Chanwoo Choi
>> Samsung Electronics
>
>
--
Best Regards,
Chanwoo Choi
Samsung Electronics
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v8 5/6] PM / devfreq: Add PM QoS support
From: Chanwoo Choi @ 2019-09-27 1:49 UTC (permalink / raw)
To: Leonard Crestez, Matthias Kaehlcke
Cc: Artur Świgoń, Abel Vesa, Saravana Kannan,
linux-pm@vger.kernel.org, Viresh Kumar, dl-linux-imx,
Krzysztof Kozlowski, Lukasz Luba, Kyungmin Park, MyungJoo Ham,
Alexandre Bailon, Georgi Djakov,
linux-arm-kernel@lists.infradead.org, Jacky Bai
In-Reply-To: <VI1PR04MB702397D04A0F2FFE8111E341EE860@VI1PR04MB7023.eurprd04.prod.outlook.com>
On 19. 9. 26. 오후 10:43, Leonard Crestez wrote:
> On 2019-09-26 4:07 AM, Chanwoo Choi wrote:
>> On 19. 9. 26. 오전 6:18, Leonard Crestez wrote:
>>> On 25.09.2019 05:11, Chanwoo Choi wrote:
>>>> On 19. 9. 24. 오후 7:11, Leonard Crestez wrote:
>>>>> Register notifiers with the PM QoS framework in order to respond to
>>>>> requests for DEV_PM_QOS_MIN_FREQUENCY and DEV_PM_QOS_MAX_FREQUENCY.
>>>>>
>>>>> No notifiers are added by this patch but PM QoS constraints can be
>>>>> imposed externally (for example from other devices).
>>>>>
>>>>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>>>>> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
>>>>> ---
>>>>> drivers/devfreq/devfreq.c | 75 +++++++++++++++++++++++++++++++++++++++
>>>>> include/linux/devfreq.h | 5 +++
>>>>> 2 files changed, 80 insertions(+)
>>>>>
>>>>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>>>>> index eee403e70c84..784f3e40536a 100644
>>>>> --- a/drivers/devfreq/devfreq.c
>>>>> +++ b/drivers/devfreq/devfreq.c
>>>>> @@ -22,15 +22,18 @@
>>>>> #include <linux/platform_device.h>
>>>>> #include <linux/list.h>
>>>>> #include <linux/printk.h>
>>>>> #include <linux/hrtimer.h>
>>>>> #include <linux/of.h>
>>>>> +#include <linux/pm_qos.h>
>>>>> #include "governor.h"
>>>>>
>>>>> #define CREATE_TRACE_POINTS
>>>>> #include <trace/events/devfreq.h>
>>>>>
>>>>> +#define HZ_PER_KHZ 1000
>>>>> +
>>>>> static struct class *devfreq_class;
>>>>>
>>>>> /*
>>>>> * devfreq core provides delayed work based load monitoring helper
>>>>> * functions. Governors can use these or can implement their own
>>>>> @@ -109,10 +112,11 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
>>>>> static void get_freq_range(struct devfreq *devfreq,
>>>>> unsigned long *min_freq,
>>>>> unsigned long *max_freq)
>>>>> {
>>>>> unsigned long *freq_table = devfreq->profile->freq_table;
>>>>> + unsigned long qos_min_freq, qos_max_freq;
>>>>>
>>>>> lockdep_assert_held(&devfreq->lock);
>>>>>
>>>>> /*
>>>>> * Init min/max frequency from freq table.
>>>>> @@ -125,10 +129,18 @@ static void get_freq_range(struct devfreq *devfreq,
>>>>> } else {
>>>>> *min_freq = freq_table[devfreq->profile->max_state - 1];
>>>>> *max_freq = freq_table[0];
>>>>> }
>>>>>
>>>>> + /* constraints from PM QoS */
>>>>
>>>> As I commented on patch4,
>>>> 'constraints' -> 'Constraint' because first verb have to be used
>>>> as the sigular verbs.
>>>
>>> Already discussed for another patch; I will modify to "Apply constraints
>>> from PM QoS" instead.
>>
>> I agree the new comment with 'Apply constraints ... '.
>>
>>>
>>>> I prefer to use following comments:
>>>>
>>>> /* Constraint minimum/maximum frequency from PM QoS constraints */
>>>>
>>>>> + qos_min_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>> + DEV_PM_QOS_MIN_FREQUENCY);
>>>>> + qos_max_freq = dev_pm_qos_read_value(devfreq->dev.parent,
>>>>> + DEV_PM_QOS_MIN_FREQUENCY);
>>>>> + *min_freq = max(*min_freq, HZ_PER_KHZ * qos_min_freq);
>>>>> + *max_freq = min(*max_freq, HZ_PER_KHZ * qos_max_freq);
>>>>> +
>>>>> /* constraints from sysfs */
>>>>> *min_freq = max(*min_freq, devfreq->min_freq);
>>>>> *max_freq = min(*max_freq, devfreq->max_freq);
>>>>>
>>>>> /* constraints from OPP interface */
>>>>> @@ -606,10 +618,49 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
>>>>> mutex_unlock(&devfreq->lock);
>>>>>
>>>>> return ret;
>>>>> }
>>>>>
>>>>> +/**
>>>>> + * qos_notifier_call() - Common handler for QoS constraints.
>>>>> + * @devfreq: the devfreq instance.
>>>>> + */
>>>>> +static int qos_notifier_call(struct devfreq *devfreq)
>>>>> +{
>>>>> + int err;
>>>>> +
>>>>> + mutex_lock(&devfreq->lock);
>>>>> + err = update_devfreq(devfreq);
>>>>> + mutex_unlock(&devfreq->lock);
>>>>> + if (err)
>>>>> + dev_err(devfreq->dev.parent,
>>>>> + "failed to update frequency for PM QoS constraints (%d)\n",
>>>>
>>>> Is it not over 80 char?
>>>
>>> Yes but coding style explicitly forbids breaking strings.
>>>
>>>>> + err);
>>>>> +
>>>>> + return NOTIFY_OK;
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * qos_min_notifier_call() - Callback for QoS min_freq changes.
>>>>> + * @nb: Should be devfreq->nb_min
>>>>> + */
>>>>> +static int qos_min_notifier_call(struct notifier_block *nb,
>>>>> + unsigned long val, void *ptr)
>>>>> +{
>>>>> + return qos_notifier_call(container_of(nb, struct devfreq, nb_min));
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * qos_max_notifier_call() - Callback for QoS max_freq changes.
>>>>> + * @nb: Should be devfreq->nb_max
>>>>> + */
>>>>> +static int qos_max_notifier_call(struct notifier_block *nb,
>>>>> + unsigned long val, void *ptr)
>>>>> +{
>>>>> + return qos_notifier_call(container_of(nb, struct devfreq, nb_max));
>>>>> +}
>>>>> +
>>>>> /**
>>>>> * devfreq_dev_release() - Callback for struct device to release the device.
>>>>> * @dev: the devfreq device
>>>>> *
>>>>> * Remove devfreq from the list and release its resources.
>>>>> @@ -620,10 +671,15 @@ static void devfreq_dev_release(struct device *dev)
>>>>>
>>>>> mutex_lock(&devfreq_list_lock);
>>>>> list_del(&devfreq->node);
>>>>> mutex_unlock(&devfreq_list_lock);
>>>>>
>>>>> + dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>>> + DEV_PM_QOS_MAX_FREQUENCY);
>>>>> + dev_pm_qos_remove_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>>> + DEV_PM_QOS_MIN_FREQUENCY);
>>>>> +
>>>>
>>>> Just print error with dev_err() without stopping the release step.
>>>>
>>>> I prefer to handle the return value if kernel API provides
>>>> the error code.
>>
>> How about?
>
> Modified to dev_warn. This also applies to PATCH 6 so I replied there.
>
>>>>> if (devfreq->profile->exit)
>>>>> devfreq->profile->exit(devfreq->dev.parent);
>>>>>
>>>>> kfree(devfreq->time_in_state);
>>>>> kfree(devfreq->trans_table);
>>>>> @@ -733,10 +789,28 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>> if (err) {
>>>>> put_device(&devfreq->dev);
>>>>> goto err_out;
>>>>> }
>>>>>
>>>>> + /*
>>>>> + * Register notifiers for updates to min/max_freq after device is
>>>>> + * initialized (and we can handle notifications) but before the
>>>>> + * governor is started (which should do an initial enforcement of
>>>>> + * constraints).
>>>>> + */
>>>>
>>>> My previous comment is not enough why I prefer to remove it. Sorry.
>>>> Actually, until now, the devfreq_add_device() don't have the detailed
>>>> comments because the line code is not too long. But, at the present time,
>>>> devfreq_add_device() is too long. It means that the detailed comment
>>>> are necessary.
>>>>
>>>> So, I'll add the detailed comment for each step of devfreq_add_device()
>>>> on separate patch to keep the same style. I'll send the patch to you
>>>> for the review.
>>>
>>> This is very likely to result in merge conflicts, maybe wait for my
>>> series to go in first?
>>
>> I'll send the separate patch after finished the review of these patches.
>> So, if you agree, please remove this comment on this patch.
>>
>> You can review the detailed comments on separate patch when I send.
> This patch already contains comments and they explain the code being
> added. Doesn't it make more sense for comments and code to go in together?
>
> I think the comment is a resonable explanation as to why notifiers are
> registered at that specific step in the initialization sequence.
If you add this comment on this patch, OK. just I have some comments.
/*
* Register notifiers for updates to min/max_freq after device is
* initialized (and we can handle notifications) but before the
I think that 'device is initialized' is not needed.
It is always true, it don't need to add the additional comments.
because dev_pm_qos_add_notifier() must need the 'devfreq->dev'.
The this code prove the call sequence between them.
About 'us', don't use 'we'. The subject is 'devfreq' or other device instead of us.
* governor is started (which should do an initial enforcement of
* constraints).
*/
Actually, it doesn't matter the initialization step between governor
and PM_QOS registration.
If start governor and then register PM_QOS,
the governor can decide the new frequency. And then PM_QOS request
the new constraints for min/max frequency. On request time of PM_QOS,
devfreq can detect this time and then apply the constraints from PM_QOS.
The user of devfreq's PM_QOS must need the phandle or device instance
of devfreq deivce. It means that user of devfreq's PM_QOS can request
the any constraints of PM_QOS_MIN/MAX through PM_QOS interface.
So, it doesn't need to add the following comments
because following comment is not always mandatory.
" governor is started (which should do an initial enforcement of constraints)."
Also, you don't need to use parentheses on comments.
Actually, I think that following comments are enough.
/* Register PM QoS notifiers for updating to min/max freq */
>
>>>>> + devfreq->nb_min.notifier_call = qos_min_notifier_call;
>>>>> + err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_min,
>>>>> + DEV_PM_QOS_MIN_FREQUENCY);
>>>>> + if (err)
>>>>> + goto err_devfreq;
>>>>> +
>>>>> + devfreq->nb_max.notifier_call = qos_max_notifier_call;
>>>>> + err = dev_pm_qos_add_notifier(devfreq->dev.parent, &devfreq->nb_max,
>>>>> + DEV_PM_QOS_MAX_FREQUENCY);
>>>>> + if (err)
>>>>> + goto err_devfreq;
>>>>> +
>>>>> mutex_lock(&devfreq_list_lock);
>>>>>
>>>>> governor = try_then_request_governor(devfreq->governor_name);
>>>>> if (IS_ERR(governor)) {
>>>>> dev_err(dev, "%s: Unable to find governor for the device\n",
>>>>> @@ -760,10 +834,11 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>>>>
>>>>> return devfreq;
>>>>>
>>>>> err_init:
>>>>> mutex_unlock(&devfreq_list_lock);
>>>>> +err_devfreq:
>>>>> devfreq_remove_device(devfreq);
>>>>> return ERR_PTR(err);
>>>>>
>>>>> err_dev:
>>>>> /*
>>>>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>>>>> index c3cbc15fdf08..dac0dffeabb4 100644
>>>>> --- a/include/linux/devfreq.h
>>>>> +++ b/include/linux/devfreq.h
>>>>> @@ -134,10 +134,12 @@ struct devfreq_dev_profile {
>>>>> * @total_trans: Number of devfreq transitions
>>>>> * @trans_table: Statistics of devfreq transitions
>>>>> * @time_in_state: Statistics of devfreq states
>>>>> * @last_stat_updated: The last time stat updated
>>>>> * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
>>>>> + * @nb_min: Notifier block for DEV_PM_QOS_MIN_FREQUENCY
>>>>> + * @nb_max: Notifier block for DEV_PM_QOS_MAX_FREQUENCY
>>>>> *
>>>>> * This structure stores the devfreq information for a give device.
>>>>> *
>>>>> * Note that when a governor accesses entries in struct devfreq in its
>>>>> * functions except for the context of callbacks defined in struct
>>>>> @@ -176,10 +178,13 @@ struct devfreq {
>>>>> unsigned int *trans_table;
>>>>> unsigned long *time_in_state;
>>>>> unsigned long last_stat_updated;
>>>>>
>>>>> struct srcu_notifier_head transition_notifier_list;
>>>>> +
>>>>> + struct notifier_block nb_min;
>>>>> + struct notifier_block nb_max;
>>>>> };
>>>>>
>>>>> struct devfreq_freqs {
>>>>> unsigned long old;
>>>>> unsigned long new;
--
Best Regards,
Chanwoo Choi
Samsung Electronics
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [RFC PATCH 18/18] net: wireguard - switch to crypto API for packet encryption
From: Linus Torvalds @ 2019-09-27 1:30 UTC (permalink / raw)
To: Pascal Van Leeuwen
Cc: Jason A . Donenfeld, Catalin Marinas, Herbert Xu, Arnd Bergmann,
Ard Biesheuvel, Greg KH, Eric Biggers, Samuel Neves,
Linux Crypto Mailing List, Andy Lutomirski, Marc Zyngier,
Dan Carpenter, Will Deacon, David Miller, Linux ARM
In-Reply-To: <MN2PR20MB297317D9870A3B93B5E506C9CA810@MN2PR20MB2973.namprd20.prod.outlook.com>
On Thu, Sep 26, 2019 at 5:15 PM Pascal Van Leeuwen
<pvanleeuwen@verimatrix.com> wrote:
>
> That remark is just very stupid. The hardware ALREADY exists, and
> more hardware is in the pipeline. Once this stuff is designed in, it
> usually stays in for many years to come. And these are chips sold in
> _serious_ quantities, to be used in things like wireless routers and
> DSL, cable and FTTH modems, 5G base stations, etc. etc.
Yes, I very much mentioned routers. I believe those can happen much
more quickly.
But I would very much hope that that is not the only situation where
you'd see wireguard used.
I'd want to see wireguard in an end-to-end situation from the very
client hardware. So laptops, phones, desktops. Not the untrusted (to
me) hw in between.
> No, these are just the routers going into *everyone's* home. And 5G
> basestations arriving at every other street corner. I wouldn't call
> that rare, exactly.
That's fine for a corporate tunnel between devices. Which is certainly
one use case for wireguard.
But if you want VPN for your own needs for security, you want it at
the _client_. Not at the router box. So that case really does matter.
And I really don't see the hardware happening in that space. So the
bad crypto interfaces only make the client _worse_.
See?
But on to the arguments that we actually agree on:
> Hey, no argument there. I don't see any good reason why the key can't
> be on the stack. I doubt any hardware would be able to DMA that as-is
> directly, and in any case, key changes should be infrequent, so copying
> it to some DMA buffer should not be a performance problem.
> So maybe that's an area for improvement: allow that to be on the stack.
It's not even just the stack. It's really that the crypto interfaces
are *designed* so that you have to allocate things separately, and
can't embed these things in your own data structures.
And they are that way, because the crypto interfaces aren't actually
about (just) hiding the hardware interface: they are about hiding
_all_ the encryption details.
There's no way to say "hey, I know the crypto I use, I know the key
size I have, I know the state size it needs, I can preallocate those
AS PART of my own data structures".
Because the interface is designed to be so "generic" that you simply
can't do those things, they are all external allocations, which is
inevitably slower when you don't have hardware.
And you've shown that you don't care about that "don't have hardware"
situation, and seem to think it's the only case that matters. That's
your job, after all.
But however much you try to claim otherwise, there's all these
situations where the hardware just isn't there, and the crypto
interface just forces nasty overhead for absolutely no good reason.
> I already explained the reasons for _not_ doing direct calls above.
And I've tried to explain how direct calls that do the synchronous
thing efficiently would be possible, but then _if_ there is hardware,
they can then fall back to an async interface.
> > So there is absolutely NO DOWNSIDE for hw accelerated crypto to just
> > do it right, and use an interface like this:
> >
> > if (!chacha20poly1305_decrypt_sg(sg, sg, skb->len, NULL, 0,
> > PACKET_CB(skb)->nonce, key->key,
> > simd_context))
> > return false;
> >
> Well, for one thing, a HW API should not expect the result to be
> available when the function call returns. (if that's what you
> mean here). That would just be WRONG.
Right. But that also shouldn't mean that when you have synchronous
hardware (ie CPU) you have to set everything up even though it will
never be used.
Put another way: even with hardware acceleration, the queuing
interface should be a simple "do this" interface.
The current crypto interface is basically something that requires all
the setup up-front, whether it's needed or not. And it forces those
very inconvenient and slow external allocations.
And I'm saying that causes problems, because it fundamentally means
that you can't do a good job for the common CPU case, because you're
paying all those costs even when you need absolutely none of them.
Both at setup time, but also at run-time due to the extra indirection
and cache misses etc.
> Again, HW acceleration does not depend on the indirection _at all_,
> that's there for entirely different purposes I explained above.
> HW acceleration _does_ depend greatly on a truly async ifc though.
Can you realize that the world isn't just all hw acceleration?
Can you admit that the current crypto interface is just horrid for the
non-accelerated case?
Can you perhaps then also think that "maybe there are better models".
> So queue requests on one side, handle results from the other side
> in some callback func off of an interrupt handler.
Actually, what you can do - and what people *have* done - is to admit
that the synchronous case is real and important, and then design
interfaces that work for that one too.
You don't need to allocate resources ahead of time, and you don't have
to disallow just having the state buffer allocated by the caller.
So here's the *wrong* way to do it (and the way that crypto does it):
- dynamically allocate buffers at "init time"
- fill in "callback fields" etc before starting the crypto, whether
they are needed or not
- call a "decrypt" function that then uses the indirect functions you
set up at init time, and possibly waits for it (or calls the callbacks
you set up)
note how it's all this "state machine" model where you add data to the
state machine, and at some point you say "execute" and then either you
wait for things or you get callbacks.
That makes sense for a hw crypto engine. It's how a lot of them work, after all.
But it makes _zero_ sense for the synchronous case. You did a lot of
extra work for that case, and because it was all a styate machine, you
did it particularly inefficiently: not only do you have those separate
allocations with pointer following, the "decrypt()" call ends up doing
an indirect call to the CPU implementation, which is just quite slow
to begin with, particularly in this day and age with retpoline etc.
So what's the alternative?
I claim that a good interface would accept that "Oh, a lot of cases
will be synchronous, and a lot of cases use one fixed
encryption/decryption model".
And it's quite doable. Instead of having those callback fields and
indirection etc, you could have something more akin to this:
- let the caller know what the state size is and allocate the
synchronous state in its own data structures
- let the caller just call a static "decrypt_xyz()" function for xyz
decryptrion.
- if you end up doing it synchronously, that function just returns
"done". No overhead. No extra allocations. No unnecessary stuff. Just
do it, using the buffers provided. End of story. Efficient and simple.
- BUT.
- any hardware could have registered itself for "I can do xyz", and
the decrypt_xyz() function would know about those, and *if* it has a
list of accelerators (hopefully sorted by preference etc), it would
try to use them. And if they take the job (they might not - maybe
their queues are full, maybe they don't have room for new keys at the
moment, which might be a separate setup from the queues), the
"decrypt_xyz()" function returns a _cookie_ for that job. It's
probably a pre-allocated one (the hw accelerator might preallocate a
fixed number of in-progress data structures).
And once you have that cookie, and you see "ok, I didn't get the
answer immediately" only THEN do you start filling in things like
callback stuff, or maybe you set up a wait-queue and start waiting for
it, or whatever".
See the difference in models? One forces that asynchronous model, and
actively penalizes the synchronous one.
The other _allows_ an asynchronous model, but is fine with a synchronous one.
> > aead_request_set_callback(req, 0, NULL, NULL);
> >
> This is just inevitable for HW acceration ...
See above. It really isn't. You could do it *after* the fact, when
you've gotten that ticket from the hardware. Then you say "ok, if the
ticket is done, use these callbacks". Or "I'll now wait for this
ticket to be done" (which is what the above does by setting the
callbacks to zero).
Wouldn't that be lovely for a user?
I suspect it would be a nice model for a hw accelerator too. If you
have full queues or have problems allocating new memory or whatever,
you just let the code fall back to the synchronous interface.
> Trust me, I have whole list of things I don't like about the
> API myself, it's not exacty ideal for HW acceleration either.
That';s the thing. It's actively detrimental for "I have no HW acceleration".
And apparently it's not optimal for you guys either.
> But the point is - there are those case where you _don't_ know and
> _that_ is what the Crypto API is for. And just generally, crypto
> really _should_ be switchable.
It's very much not what wireguard does.
And honestly, most of the switchable ones have caused way more
security problems than they have "fixed" by being switchable.
Linus
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* RE: [PATCH] firmware: imx: Skip return value check for some special SCU firmware APIs
From: Anson Huang @ 2019-09-27 1:20 UTC (permalink / raw)
To: Leonard Crestez, Marco Felsch, Aisheng Dong
Cc: shawnguo@kernel.org, s.hauer@pengutronix.de,
linux-kernel@vger.kernel.org, dl-linux-imx, kernel@pengutronix.de,
festevam@gmail.com, linux-arm-kernel@lists.infradead.org
In-Reply-To: <VI1PR04MB702336F648EA1BF0E4AC584BEE860@VI1PR04MB7023.eurprd04.prod.outlook.com>
Hi, Leonard
> On 2019-09-26 1:06 PM, Marco Felsch wrote:
> > On 19-09-26 08:03, Anson Huang wrote:
> >>> On 19-09-25 18:07, Anson Huang wrote:
> >>>> The SCU firmware does NOT always have return value stored in
> >>>> message header's function element even the API has response data,
> >>>> those special APIs are defined as void function in SCU firmware, so
> >>>> they should be treated as return success always.
> >>>>
> >>>> +static const struct imx_sc_rpc_msg whitelist[] = {
> >>>> + { .svc = IMX_SC_RPC_SVC_MISC, .func =
> >>> IMX_SC_MISC_FUNC_UNIQUE_ID },
> >>>> + { .svc = IMX_SC_RPC_SVC_MISC, .func =
> >>>> +IMX_SC_MISC_FUNC_GET_BUTTON_STATUS }, };
> >>>
> >>> Is this going to be extended in the near future? I see some upcoming
> >>> problems here if someone uses a different scu-fw<->kernel
> >>> combination as nxp would suggest.
> >>
> >> Could be, but I checked the current APIs, ONLY these 2 will be used
> >> in Linux kernel, so I ONLY add these 2 APIs for now.
> >
> > Okay.
> >
> >> However, after rethink, maybe we should add another imx_sc_rpc API
> >> for those special APIs? To avoid checking it for all the APIs called which
> may impact some performance.
> >> Still under discussion, if you have better idea, please advise, thanks!
>
> My suggestion is to refactor the code and add a new API for the this "no
> error value" convention. Internally they can call a common function with
> flags.
If I understand your point correctly, that means the loop check of whether the API
is with "no error value" for every API still NOT be skipped, it is just refactoring the code,
right?
>
> > Adding a special api shouldn't be the right fix. Imagine if someone
> > (not a nxp-developer) wants to add a new driver. How could he be
> > expected to know which api he should use. The better abbroach would be
> > to fix the scu-fw instead of adding quirks..
Yes, fixing SCU FW is the best solution, but we have talked to SCU FW owner, the SCU
FW released has been finalized, so the API implementation can NOT be changed, but
they will pay attention to this issue for new added APIs later. That means the number
of APIs having this issue a very limited.
>
> Right now developers who want to make SCFW calls in upstream need to
> define the message struct in their driver based on protocol documentation.
> This includes:
>
> * Binary layout of the message (a packed struct)
> * If the message has a response (already a bool flag)
> * If an error code is returned (this patch adds support for it)
>
> Since callers are already exposed to the binary protocol exposing them to
> minor quirks of the calling convention also seems reasonable. Having the
> low-level IPC code peek at message IDs seems like a hack; this belong at a
> slightly higher level.
A little confused, so what you suggested is to add make the imx_scu_call_rpc()
becomes the "slightly higher level" API, then in this API, check the message IDs
to decide whether to return error value, then calls a new API which will have
the low-level IPC code, the this new API will have a flag passed from imx_scu_call_rpc()
function, am I right?
Anson
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH 11/11] of/address: Fix of_pci_range_parser_one translation of DMA addresses
From: Rob Herring @ 2019-09-27 0:24 UTC (permalink / raw)
To: devicetree, linux-arm-kernel
Cc: Florian Fainelli, Arnd Bergmann, Frank Rowand, linux-pci,
linux-kernel, Marek Vasut, Lorenzo Pieralisi, Oza Pawandeep,
Stefan Wahren, Simon Horman, Geert Uytterhoeven, Robin Murphy,
Nicolas Saenz Julienne
In-Reply-To: <20190927002455.13169-1-robh@kernel.org>
of_pci_range_parser_one() has a bug when parsing dma-ranges. When it
translates the parent address (aka cpu address in the code), 'ranges' is
always being used. This happens to work because most users are just 1:1
translation.
Cc: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Rob Herring <robh@kernel.org>
---
drivers/of/address.c | 15 ++++++++++++---
include/linux/of_address.h | 1 +
2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/drivers/of/address.c b/drivers/of/address.c
index 5b835d332709..54011a355b81 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -243,6 +243,7 @@ static int parser_init(struct of_pci_range_parser *parser,
parser->node = node;
parser->pna = of_n_addr_cells(node);
parser->np = parser->pna + na + ns;
+ parser->dma = !strcmp(name, "dma-ranges");
parser->range = of_get_property(node, name, &rlen);
if (parser->range == NULL)
@@ -281,7 +282,11 @@ struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
range->pci_space = be32_to_cpup(parser->range);
range->flags = of_bus_pci_get_flags(parser->range);
range->pci_addr = of_read_number(parser->range + 1, ns);
- range->cpu_addr = of_translate_address(parser->node,
+ if (parser->dma)
+ range->cpu_addr = of_translate_dma_address(parser->node,
+ parser->range + na);
+ else
+ range->cpu_addr = of_translate_address(parser->node,
parser->range + na);
range->size = of_read_number(parser->range + parser->pna + na, ns);
@@ -294,8 +299,12 @@ struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
flags = of_bus_pci_get_flags(parser->range);
pci_addr = of_read_number(parser->range + 1, ns);
- cpu_addr = of_translate_address(parser->node,
- parser->range + na);
+ if (parser->dma)
+ cpu_addr = of_translate_dma_address(parser->node,
+ parser->range + na);
+ else
+ cpu_addr = of_translate_address(parser->node,
+ parser->range + na);
size = of_read_number(parser->range + parser->pna + na, ns);
if (flags != range->flags)
diff --git a/include/linux/of_address.h b/include/linux/of_address.h
index ddda3936039c..eac7ab109df4 100644
--- a/include/linux/of_address.h
+++ b/include/linux/of_address.h
@@ -12,6 +12,7 @@ struct of_pci_range_parser {
const __be32 *end;
int np;
int pna;
+ bool dma;
};
struct of_pci_range {
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 10/11] of/address: Translate 'dma-ranges' for parent nodes missing 'dma-ranges'
From: Rob Herring @ 2019-09-27 0:24 UTC (permalink / raw)
To: devicetree, linux-arm-kernel
Cc: Florian Fainelli, Arnd Bergmann, Frank Rowand, linux-pci,
linux-kernel, Marek Vasut, Lorenzo Pieralisi, Oza Pawandeep,
Stefan Wahren, Simon Horman, Geert Uytterhoeven, Robin Murphy,
Nicolas Saenz Julienne
In-Reply-To: <20190927002455.13169-1-robh@kernel.org>
'dma-ranges' frequently exists without parent nodes having 'dma-ranges'.
While this is an error for 'ranges', this is fine because DMA capable
devices always have a translatable DMA address. Also, with no
'dma-ranges' at all, the assumption is that DMA addresses are 1:1 with
no restrictions unless perhaps the device itself has implicit
restrictions.
Cc: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Rob Herring <robh@kernel.org>
---
drivers/of/address.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/of/address.c b/drivers/of/address.c
index e918001c7798..5b835d332709 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -519,9 +519,13 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
*
* As far as we know, this damage only exists on Apple machines, so
* This code is only enabled on powerpc. --gcl
+ *
+ * This quirk also applies for 'dma-ranges' which frequently exist in
+ * child nodes without 'dma-ranges' in the parent nodes. --RobH
*/
ranges = of_get_property(parent, rprop, &rlen);
- if (ranges == NULL && !of_empty_ranges_quirk(parent)) {
+ if (ranges == NULL && !of_empty_ranges_quirk(parent) &&
+ strcmp(rprop, "dma-ranges")) {
pr_debug("no ranges; cannot translate\n");
return 1;
}
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 09/11] of: Make of_dma_get_range() work on bus nodes
From: Rob Herring @ 2019-09-27 0:24 UTC (permalink / raw)
To: devicetree, linux-arm-kernel
Cc: Florian Fainelli, Arnd Bergmann, Frank Rowand, linux-pci,
linux-kernel, Marek Vasut, Lorenzo Pieralisi, Oza Pawandeep,
Stefan Wahren, Simon Horman, Geert Uytterhoeven, Robin Murphy,
Nicolas Saenz Julienne
In-Reply-To: <20190927002455.13169-1-robh@kernel.org>
From: Robin Murphy <robin.murphy@arm.com>
Since the "dma-ranges" property is only valid for a node representing a
bus, of_dma_get_range() currently assumes the node passed in is a leaf
representing a device, and starts the walk from its parent. In cases
like PCI host controllers on typical FDT systems, however, where the PCI
endpoints are probed dynamically the initial leaf node represents the
'bus' itself, and this logic means we fail to consider any "dma-ranges"
describing the host bridge itself. Rework the logic such that
of_dma_get_range() works correctly starting from a bus node containing
"dma-ranges".
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
[robh: Allow for the bus child node to still be passed in]
Signed-off-by: Rob Herring <robh@kernel.org>
---
drivers/of/address.c | 24 +++++-------------------
1 file changed, 5 insertions(+), 19 deletions(-)
diff --git a/drivers/of/address.c b/drivers/of/address.c
index 887c0413f648..e918001c7798 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -922,18 +922,9 @@ int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, u64 *siz
if (!node)
return -EINVAL;
- while (1) {
- struct device_node *parent;
-
- naddr = of_n_addr_cells(node);
- nsize = of_n_size_cells(node);
-
- parent = __of_get_dma_parent(node);
- of_node_put(node);
-
- node = parent;
- if (!node)
- break;
+ while (node) {
+ naddr = of_bus_n_addr_cells(node);
+ nsize = of_bus_n_size_cells(node);
ranges = of_get_property(node, "dma-ranges", &len);
@@ -941,12 +932,7 @@ int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, u64 *siz
if (ranges && len > 0)
break;
- /*
- * At least empty ranges has to be defined for parent node if
- * DMA is supported
- */
- if (!ranges)
- break;
+ node = of_get_next_dma_parent(node);
}
if (!ranges) {
@@ -965,7 +951,7 @@ int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, u64 *siz
* size : nsize cells
*/
dmaaddr = of_read_number(ranges, naddr);
- *paddr = of_translate_dma_address(np, ranges);
+ *paddr = of_translate_dma_address(node, ranges + naddr);
if (*paddr == OF_BAD_ADDR) {
pr_err("translation of DMA address(%llx) to CPU address failed node(%pOF)\n",
dmaaddr, np);
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 08/11] of: Factor out #{addr,size}-cells parsing
From: Rob Herring @ 2019-09-27 0:24 UTC (permalink / raw)
To: devicetree, linux-arm-kernel
Cc: Florian Fainelli, Arnd Bergmann, Frank Rowand, linux-pci,
linux-kernel, Marek Vasut, Lorenzo Pieralisi, Oza Pawandeep,
Stefan Wahren, Simon Horman, Geert Uytterhoeven, Robin Murphy,
Nicolas Saenz Julienne
In-Reply-To: <20190927002455.13169-1-robh@kernel.org>
From: Robin Murphy <robin.murphy@arm.com>
In some cases such as PCI host controllers, we may have a "parent bus"
which is an OF leaf node, but still need to correctly parse ranges from
the point of view of that bus. For that, factor out variants of the
"#addr-cells" and "#size-cells" parsers which do not assume they have a
device node and thus immediately traverse upwards before reading the
relevant property.
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
[robh: don't make of_bus_n_{addr,size}_cells() public]
Signed-off-by: Rob Herring <robh@kernel.org>
---
drivers/of/address.c | 2 ++
drivers/of/base.c | 32 ++++++++++++++++++++++----------
drivers/of/of_private.h | 3 +++
3 files changed, 27 insertions(+), 10 deletions(-)
diff --git a/drivers/of/address.c b/drivers/of/address.c
index 3fd34f7ad772..887c0413f648 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -14,6 +14,8 @@
#include <linux/slab.h>
#include <linux/string.h>
+#include "of_private.h"
+
/* Max address size we deal with */
#define OF_MAX_ADDR_CELLS 4
#define OF_CHECK_ADDR_COUNT(na) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS)
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 55e7f5bb0549..12b2e9287117 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -86,34 +86,46 @@ static bool __of_node_is_type(const struct device_node *np, const char *type)
return np && match && type && !strcmp(match, type);
}
-int of_n_addr_cells(struct device_node *np)
+int of_bus_n_addr_cells(struct device_node *np)
{
u32 cells;
- do {
- if (np->parent)
- np = np->parent;
+ for (; np; np = np->parent)
if (!of_property_read_u32(np, "#address-cells", &cells))
return cells;
- } while (np->parent);
+
/* No #address-cells property for the root node */
return OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
}
+
+int of_n_addr_cells(struct device_node *np)
+{
+ if (np->parent)
+ np = np->parent;
+
+ return of_bus_n_addr_cells(np);
+}
EXPORT_SYMBOL(of_n_addr_cells);
-int of_n_size_cells(struct device_node *np)
+int of_bus_n_size_cells(struct device_node *np)
{
u32 cells;
- do {
- if (np->parent)
- np = np->parent;
+ for (; np; np = np->parent)
if (!of_property_read_u32(np, "#size-cells", &cells))
return cells;
- } while (np->parent);
+
/* No #size-cells property for the root node */
return OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
}
+
+int of_n_size_cells(struct device_node *np)
+{
+ if (np->parent)
+ np = np->parent;
+
+ return of_bus_n_size_cells(np);
+}
EXPORT_SYMBOL(of_n_size_cells);
#ifdef CONFIG_NUMA
diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h
index f8c58615c393..66294d29942a 100644
--- a/drivers/of/of_private.h
+++ b/drivers/of/of_private.h
@@ -158,6 +158,9 @@ extern void __of_sysfs_remove_bin_file(struct device_node *np,
#define for_each_transaction_entry_reverse(_oft, _te) \
list_for_each_entry_reverse(_te, &(_oft)->te_list, node)
+extern int of_bus_n_addr_cells(struct device_node *np);
+extern int of_bus_n_size_cells(struct device_node *np);
+
#ifdef CONFIG_OF_ADDRESS
extern int of_dma_get_range(struct device_node *np, u64 *dma_addr,
u64 *paddr, u64 *size);
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 07/11] of: address: Follow DMA parent for "dma-coherent"
From: Rob Herring @ 2019-09-27 0:24 UTC (permalink / raw)
To: devicetree, linux-arm-kernel
Cc: Florian Fainelli, Arnd Bergmann, Frank Rowand, linux-pci,
linux-kernel, Marek Vasut, Lorenzo Pieralisi, Oza Pawandeep,
Stefan Wahren, Simon Horman, Geert Uytterhoeven, Robin Murphy,
Nicolas Saenz Julienne
In-Reply-To: <20190927002455.13169-1-robh@kernel.org>
From: Robin Murphy <robin.murphy@arm.com>
Much like for address translation, when checking for DMA coherence we
should be sure to walk up the DMA hierarchy, rather than the MMIO one,
now that we can accommodate them being different.
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Rob Herring <robh@kernel.org>
---
drivers/of/address.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/of/address.c b/drivers/of/address.c
index e9188c82fdae..3fd34f7ad772 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -999,7 +999,7 @@ bool of_dma_is_coherent(struct device_node *np)
of_node_put(node);
return true;
}
- node = of_get_next_parent(node);
+ node = of_get_next_dma_parent(node);
}
of_node_put(node);
return false;
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 05/11] of: Ratify of_dma_configure() interface
From: Rob Herring @ 2019-09-27 0:24 UTC (permalink / raw)
To: devicetree, linux-arm-kernel
Cc: Florian Fainelli, Arnd Bergmann, Frank Rowand, linux-pci,
linux-kernel, Marek Vasut, Lorenzo Pieralisi, Oza Pawandeep,
Stefan Wahren, Simon Horman, Geert Uytterhoeven, Robin Murphy,
Nicolas Saenz Julienne
In-Reply-To: <20190927002455.13169-1-robh@kernel.org>
From: Robin Murphy <robin.murphy@arm.com>
For various DMA masters not directly represented in DT, we pass the OF
node of their parent or bridge device as the master_np argument to
of_dma_configure(), such that they can inherit the appropriate DMA
configuration from whatever is described there. This creates an
ambiguity for properties which are not valid for a device itself but
only for its parent bus, since we don't know whether to start looking
for those at master_np or master_np->parent.
Fortunately, the de-facto interface since the prototype change in
1f5c69aa51f9 ("of: Move of_dma_configure() to device.c to help re-use")
is pretty clear-cut: either master_np is redundant with dev->of_node, or
dev->of_node is NULL and master_np is already the relevant parent. Let's
formally ratify that so we can start relying on it.
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Rob Herring <robh@kernel.org>
---
drivers/of/device.c | 12 ++++++++++--
include/linux/of_device.h | 4 ++--
2 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/drivers/of/device.c b/drivers/of/device.c
index da8158392010..a45261e21144 100644
--- a/drivers/of/device.c
+++ b/drivers/of/device.c
@@ -75,7 +75,8 @@ int of_device_add(struct platform_device *ofdev)
/**
* of_dma_configure - Setup DMA configuration
* @dev: Device to apply DMA configuration
- * @np: Pointer to OF node having DMA configuration
+ * @parent: OF node of parent device having DMA configuration, if
+ * @dev->of_node is NULL (ignored otherwise)
* @force_dma: Whether device is to be set up by of_dma_configure() even if
* DMA capability is not explicitly described by firmware.
*
@@ -86,15 +87,22 @@ int of_device_add(struct platform_device *ofdev)
* can use a platform bus notifier and handle BUS_NOTIFY_ADD_DEVICE events
* to fix up DMA configuration.
*/
-int of_dma_configure(struct device *dev, struct device_node *np, bool force_dma)
+int of_dma_configure(struct device *dev, struct device_node *parent, bool force_dma)
{
u64 dma_addr, paddr, size = 0;
int ret;
bool coherent;
unsigned long offset;
const struct iommu_ops *iommu;
+ struct device_node *np;
u64 mask;
+ np = dev->of_node;
+ if (!np)
+ np = parent;
+ if (!np)
+ return -ENODEV;
+
ret = of_dma_get_range(np, &dma_addr, &paddr, &size);
if (ret < 0) {
/*
diff --git a/include/linux/of_device.h b/include/linux/of_device.h
index 8d31e39dd564..a4fe418e57f6 100644
--- a/include/linux/of_device.h
+++ b/include/linux/of_device.h
@@ -56,7 +56,7 @@ static inline struct device_node *of_cpu_device_node_get(int cpu)
}
int of_dma_configure(struct device *dev,
- struct device_node *np,
+ struct device_node *parent,
bool force_dma);
#else /* CONFIG_OF */
@@ -107,7 +107,7 @@ static inline struct device_node *of_cpu_device_node_get(int cpu)
}
static inline int of_dma_configure(struct device *dev,
- struct device_node *np,
+ struct device_node *parent,
bool force_dma)
{
return 0;
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 04/11] of/unittest: Add dma-ranges address translation tests
From: Rob Herring @ 2019-09-27 0:24 UTC (permalink / raw)
To: devicetree, linux-arm-kernel
Cc: Florian Fainelli, Arnd Bergmann, Frank Rowand, linux-pci,
linux-kernel, Marek Vasut, Lorenzo Pieralisi, Oza Pawandeep,
Stefan Wahren, Simon Horman, Geert Uytterhoeven, Robin Murphy,
Nicolas Saenz Julienne
In-Reply-To: <20190927002455.13169-1-robh@kernel.org>
The functions for parsing 'dma-ranges' ranges are buggy and fail to
handle several conditions. Add new tests for of_dma_get_range() and
for_each_of_pci_range().
With this test, we get 5 new failures which are fixed in subsequent
commits:
OF: translation of DMA address(0) to CPU address failed node(/testcase-data/address-tests/device@70000000)
FAIL of_unittest_dma_ranges_one():798 of_dma_get_range failed on node /testcase-data/address-tests/device@70000000 rc=-22
OF: translation of DMA address(10000000) to CPU address failed node(/testcase-data/address-tests/bus@80000000/device@1000)
FAIL of_unittest_dma_ranges_one():798 of_dma_get_range failed on node /testcase-data/address-tests/bus@80000000/device@1000 rc=-22
OF: translation of DMA address(0) to CPU address failed node(/testcase-data/address-tests/pci@90000000)
FAIL of_unittest_dma_ranges_one():798 of_dma_get_range failed on node /testcase-data/address-tests/pci@90000000 rc=-22
FAIL of_unittest_pci_dma_ranges():851 for_each_of_pci_range wrong CPU addr (d0000000) on node /testcase-data/address-tests/pci@90000000
FAIL of_unittest_pci_dma_ranges():861 for_each_of_pci_range wrong CPU addr (ffffffffffffffff) on node /testcase-data/address-tests/pci@90000000
Cc: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Rob Herring <robh@kernel.org>
---
drivers/of/unittest-data/testcases.dts | 1 +
drivers/of/unittest-data/tests-address.dtsi | 48 +++++++++++
drivers/of/unittest.c | 92 +++++++++++++++++++++
3 files changed, 141 insertions(+)
create mode 100644 drivers/of/unittest-data/tests-address.dtsi
diff --git a/drivers/of/unittest-data/testcases.dts b/drivers/of/unittest-data/testcases.dts
index 55fe0ee20109..a85b5e1c381a 100644
--- a/drivers/of/unittest-data/testcases.dts
+++ b/drivers/of/unittest-data/testcases.dts
@@ -15,5 +15,6 @@
#include "tests-phandle.dtsi"
#include "tests-interrupts.dtsi"
#include "tests-match.dtsi"
+#include "tests-address.dtsi"
#include "tests-platform.dtsi"
#include "tests-overlay.dtsi"
diff --git a/drivers/of/unittest-data/tests-address.dtsi b/drivers/of/unittest-data/tests-address.dtsi
new file mode 100644
index 000000000000..3fe5d3987beb
--- /dev/null
+++ b/drivers/of/unittest-data/tests-address.dtsi
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ testcase-data {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ address-tests {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ /* ranges here is to make sure we don't use it for
+ * dma-ranges translation */
+ ranges = <0x70000000 0x70000000 0x40000000>,
+ <0x00000000 0xd0000000 0x20000000>;
+ dma-ranges = <0x0 0x20000000 0x40000000>;
+
+ device@70000000 {
+ reg = <0x70000000 0x1000>;
+ };
+
+ bus@80000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x80000000 0x100000>;
+ dma-ranges = <0x10000000 0x0 0x40000000>;
+
+ device@1000 {
+ reg = <0x1000 0x1000>;
+ };
+ };
+
+ pci@90000000 {
+ device_type = "pci";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ reg = <0x90000000 0x1000>;
+ ranges = <0x42000000 0x0 0x40000000 0x40000000 0x0 0x10000000>;
+ dma-ranges = <0x42000000 0x0 0x80000000 0x00000000 0x0 0x10000000>,
+ <0x42000000 0x0 0xc0000000 0x20000000 0x0 0x10000000>;
+ };
+
+ };
+ };
+};
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index e6b175370f2e..3969075194c5 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -12,6 +12,7 @@
#include <linux/hashtable.h>
#include <linux/libfdt.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/of_fdt.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
@@ -779,6 +780,95 @@ static void __init of_unittest_changeset(void)
#endif
}
+static void __init of_unittest_dma_ranges_one(const char *path,
+ u64 expect_dma_addr, u64 expect_paddr, u64 expect_size)
+{
+ struct device_node *np;
+ u64 dma_addr, paddr, size;
+ int rc;
+
+ np = of_find_node_by_path(path);
+ if (!np) {
+ pr_err("missing testcase data\n");
+ return;
+ }
+
+ rc = of_dma_get_range(np, &dma_addr, &paddr, &size);
+
+ unittest(!rc, "of_dma_get_range failed on node %pOF rc=%i\n", np, rc);
+ if (!rc) {
+ unittest(size == expect_size,
+ "of_dma_get_range wrong size on node %pOF size=%llx\n", np, size);
+ unittest(paddr == expect_paddr,
+ "of_dma_get_range wrong phys addr (%llx) on node %pOF", paddr, np);
+ unittest(dma_addr == expect_dma_addr,
+ "of_dma_get_range wrong DMA addr (%llx) on node %pOF", dma_addr, np);
+ }
+ of_node_put(np);
+}
+
+static void __init of_unittest_parse_dma_ranges(void)
+{
+ of_unittest_dma_ranges_one("/testcase-data/address-tests/device@70000000",
+ 0x0, 0x20000000, 0x40000000);
+ of_unittest_dma_ranges_one("/testcase-data/address-tests/bus@80000000/device@1000",
+ 0x10000000, 0x20000000, 0x40000000);
+ of_unittest_dma_ranges_one("/testcase-data/address-tests/pci@90000000",
+ 0x80000000, 0x20000000, 0x10000000);
+}
+
+static void __init of_unittest_pci_dma_ranges(void)
+{
+ struct device_node *np;
+ struct of_pci_range range;
+ struct of_pci_range_parser parser;
+ int i = 0;
+
+ if (!IS_ENABLED(CONFIG_PCI))
+ return;
+
+ np = of_find_node_by_path("/testcase-data/address-tests/pci@90000000");
+ if (!np) {
+ pr_err("missing testcase data\n");
+ return;
+ }
+
+ if (of_pci_dma_range_parser_init(&parser, np)) {
+ pr_err("missing dma-ranges property\n");
+ return;
+ }
+
+ /*
+ * Get the dma-ranges from the device tree
+ */
+ for_each_of_pci_range(&parser, &range) {
+ if (!i) {
+ unittest(range.size == 0x10000000,
+ "for_each_of_pci_range wrong size on node %pOF size=%llx\n",
+ np, range.size);
+ unittest(range.cpu_addr == 0x20000000,
+ "for_each_of_pci_range wrong CPU addr (%llx) on node %pOF",
+ range.cpu_addr, np);
+ unittest(range.pci_addr == 0x80000000,
+ "for_each_of_pci_range wrong DMA addr (%llx) on node %pOF",
+ range.pci_addr, np);
+ } else {
+ unittest(range.size == 0x10000000,
+ "for_each_of_pci_range wrong size on node %pOF size=%llx\n",
+ np, range.size);
+ unittest(range.cpu_addr == 0x40000000,
+ "for_each_of_pci_range wrong CPU addr (%llx) on node %pOF",
+ range.cpu_addr, np);
+ unittest(range.pci_addr == 0xc0000000,
+ "for_each_of_pci_range wrong DMA addr (%llx) on node %pOF",
+ range.pci_addr, np);
+ }
+ i++;
+ }
+
+ of_node_put(np);
+}
+
static void __init of_unittest_parse_interrupts(void)
{
struct device_node *np;
@@ -2552,6 +2642,8 @@ static int __init of_unittest(void)
of_unittest_changeset();
of_unittest_parse_interrupts();
of_unittest_parse_interrupts_extended();
+ of_unittest_parse_dma_ranges();
+ of_unittest_pci_dma_ranges();
of_unittest_match_node();
of_unittest_platform_populate();
of_unittest_overlay();
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 06/11] of/address: Introduce of_get_next_dma_parent() helper
From: Rob Herring @ 2019-09-27 0:24 UTC (permalink / raw)
To: devicetree, linux-arm-kernel
Cc: Florian Fainelli, Arnd Bergmann, Frank Rowand, linux-pci,
linux-kernel, Marek Vasut, Lorenzo Pieralisi, Oza Pawandeep,
Stefan Wahren, Simon Horman, Geert Uytterhoeven, Robin Murphy,
Nicolas Saenz Julienne
In-Reply-To: <20190927002455.13169-1-robh@kernel.org>
From: Robin Murphy <robin.murphy@arm.com>
Add of_get_next_dma_parent() helper which is similar to
__of_get_dma_parent(), but can be used in iterators and decrements the
ref count on the prior parent.
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Rob Herring <robh@kernel.org>
---
drivers/of/address.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/drivers/of/address.c b/drivers/of/address.c
index 53d2656c2269..e9188c82fdae 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -695,6 +695,16 @@ static struct device_node *__of_get_dma_parent(const struct device_node *np)
return of_node_get(args.np);
}
+static struct device_node *of_get_next_dma_parent(struct device_node *np)
+{
+ struct device_node *parent;
+
+ parent = __of_get_dma_parent(np);
+ of_node_put(np);
+
+ return parent;
+}
+
u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr)
{
struct device_node *host;
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 03/11] of: address: Report of_dma_get_range() errors meaningfully
From: Rob Herring @ 2019-09-27 0:24 UTC (permalink / raw)
To: devicetree, linux-arm-kernel
Cc: Florian Fainelli, Arnd Bergmann, Frank Rowand, linux-pci,
linux-kernel, Marek Vasut, Lorenzo Pieralisi, Oza Pawandeep,
Stefan Wahren, Simon Horman, Geert Uytterhoeven, Robin Murphy,
Nicolas Saenz Julienne
In-Reply-To: <20190927002455.13169-1-robh@kernel.org>
From: Robin Murphy <robin.murphy@arm.com>
If we failed to translate a DMA address, at least show the offending
address rather than the uninitialised contents of the destination
argument.
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Rob Herring <robh@kernel.org>
---
drivers/of/address.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/of/address.c b/drivers/of/address.c
index 8e354d12fb04..53d2656c2269 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -955,8 +955,8 @@ int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, u64 *siz
dmaaddr = of_read_number(ranges, naddr);
*paddr = of_translate_dma_address(np, ranges);
if (*paddr == OF_BAD_ADDR) {
- pr_err("translation of DMA address(%pad) to CPU address failed node(%pOF)\n",
- dma_addr, np);
+ pr_err("translation of DMA address(%llx) to CPU address failed node(%pOF)\n",
+ dmaaddr, np);
ret = -EINVAL;
goto out;
}
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 02/11] of: Make of_dma_get_range() private
From: Rob Herring @ 2019-09-27 0:24 UTC (permalink / raw)
To: devicetree, linux-arm-kernel
Cc: Florian Fainelli, Arnd Bergmann, Frank Rowand, linux-pci,
linux-kernel, Marek Vasut, Lorenzo Pieralisi, Oza Pawandeep,
Stefan Wahren, Simon Horman, Geert Uytterhoeven, Robin Murphy,
Nicolas Saenz Julienne
In-Reply-To: <20190927002455.13169-1-robh@kernel.org>
of_dma_get_range() is only used within the DT core code, so remove the
export and move the header declaration to the private header.
Cc: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Rob Herring <robh@kernel.org>
---
drivers/of/address.c | 1 -
drivers/of/of_private.h | 11 +++++++++++
include/linux/of_address.h | 8 --------
3 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/drivers/of/address.c b/drivers/of/address.c
index 0c3cf515c510..8e354d12fb04 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -972,7 +972,6 @@ int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, u64 *siz
return ret;
}
-EXPORT_SYMBOL_GPL(of_dma_get_range);
/**
* of_dma_is_coherent - Check if device is coherent
diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h
index 24786818e32e..f8c58615c393 100644
--- a/drivers/of/of_private.h
+++ b/drivers/of/of_private.h
@@ -158,4 +158,15 @@ extern void __of_sysfs_remove_bin_file(struct device_node *np,
#define for_each_transaction_entry_reverse(_oft, _te) \
list_for_each_entry_reverse(_te, &(_oft)->te_list, node)
+#ifdef CONFIG_OF_ADDRESS
+extern int of_dma_get_range(struct device_node *np, u64 *dma_addr,
+ u64 *paddr, u64 *size);
+#else
+static inline int of_dma_get_range(struct device_node *np, u64 *dma_addr,
+ u64 *paddr, u64 *size)
+{
+ return -ENODEV;
+}
+#endif
+
#endif /* _LINUX_OF_PRIVATE_H */
diff --git a/include/linux/of_address.h b/include/linux/of_address.h
index e317f375374a..ddda3936039c 100644
--- a/include/linux/of_address.h
+++ b/include/linux/of_address.h
@@ -51,8 +51,6 @@ extern int of_pci_dma_range_parser_init(struct of_pci_range_parser *parser,
extern struct of_pci_range *of_pci_range_parser_one(
struct of_pci_range_parser *parser,
struct of_pci_range *range);
-extern int of_dma_get_range(struct device_node *np, u64 *dma_addr,
- u64 *paddr, u64 *size);
extern bool of_dma_is_coherent(struct device_node *np);
#else /* CONFIG_OF_ADDRESS */
static inline void __iomem *of_io_request_and_map(struct device_node *device,
@@ -92,12 +90,6 @@ static inline struct of_pci_range *of_pci_range_parser_one(
return NULL;
}
-static inline int of_dma_get_range(struct device_node *np, u64 *dma_addr,
- u64 *paddr, u64 *size)
-{
- return -ENODEV;
-}
-
static inline bool of_dma_is_coherent(struct device_node *np)
{
return false;
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox