forked from openwrt/openwrt
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
rockchip: correct patches from coolsnowwolf
- Loading branch information
Showing
13 changed files
with
507 additions
and
1,310 deletions.
There are no files selected for viewing
73 changes: 73 additions & 0 deletions
73
target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3328-dram-dmc.dtsi
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
// SPDX-License-Identifier: (GPL-2.0+ OR MIT) | ||
/* | ||
* Copyright (c) 2017 Fuzhou Rockchip Electronics Co., Ltd. | ||
*/ | ||
|
||
#include "rk3328-dram-default-timing.dtsi" | ||
|
||
/ { | ||
dmc: dmc { | ||
compatible = "rockchip,rk3328-dmc"; | ||
devfreq-events = <&dfi>; | ||
center-supply = <&vdd_log>; | ||
clocks = <&cru SCLK_DDRCLK>; | ||
clock-names = "dmc_clk"; | ||
operating-points-v2 = <&dmc_opp_table>; | ||
ddr_timing = <&ddr_timing>; | ||
upthreshold = <40>; | ||
downdifferential = <20>; | ||
auto-min-freq = <786000>; | ||
auto-freq-en = <0>; | ||
#cooling-cells = <2>; | ||
|
||
ddr_power_model: ddr_power_model { | ||
compatible = "ddr_power_model"; | ||
dynamic-power-coefficient = <120>; | ||
static-power-coefficient = <200>; | ||
ts = <32000 4700 (-80) 2>; | ||
thermal-zone = "soc-thermal"; | ||
}; | ||
}; | ||
|
||
dmc_opp_table: dmc-opp-table { | ||
compatible = "operating-points-v2"; | ||
|
||
rockchip,leakage-voltage-sel = < | ||
1 10 0 | ||
11 254 1 | ||
>; | ||
nvmem-cells = <&logic_leakage>; | ||
nvmem-cell-names = "ddr_leakage"; | ||
|
||
opp-786000000 { | ||
opp-hz = /bits/ 64 <786000000>; | ||
opp-microvolt = <1075000>; | ||
opp-microvolt-L0 = <1075000>; | ||
opp-microvolt-L1 = <1050000>; | ||
}; | ||
opp-798000000 { | ||
opp-hz = /bits/ 64 <798000000>; | ||
opp-microvolt = <1075000>; | ||
opp-microvolt-L0 = <1075000>; | ||
opp-microvolt-L1 = <1050000>; | ||
}; | ||
opp-840000000 { | ||
opp-hz = /bits/ 64 <840000000>; | ||
opp-microvolt = <1075000>; | ||
opp-microvolt-L0 = <1075000>; | ||
opp-microvolt-L1 = <1050000>; | ||
}; | ||
opp-924000000 { | ||
opp-hz = /bits/ 64 <924000000>; | ||
opp-microvolt = <1100000>; | ||
opp-microvolt-L0 = <1100000>; | ||
opp-microvolt-L1 = <1075000>; | ||
}; | ||
opp-1056000000 { | ||
opp-hz = /bits/ 64 <1056000000>; | ||
opp-microvolt = <1175000>; | ||
opp-microvolt-L0 = <1175000>; | ||
opp-microvolt-L1 = <1150000>; | ||
}; | ||
}; | ||
}; |
33 changes: 33 additions & 0 deletions
33
target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2c-plus.dts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later OR MIT | ||
/* | ||
* Copyright (c) 2021 FriendlyElec Computer Tech. Co., Ltd. | ||
* (http://www.friendlyarm.com) | ||
* | ||
* Copyright (c) 2023 Tianling Shen <[email protected]> | ||
*/ | ||
|
||
/dts-v1/; | ||
#include "rk3328-nanopi-r2c.dts" | ||
|
||
/ { | ||
model = "FriendlyElec NanoPi R2C Plus"; | ||
compatible = "friendlyarm,nanopi-r2c-plus", "rockchip,rk3328"; | ||
|
||
aliases { | ||
mmc1 = &emmc; | ||
}; | ||
}; | ||
|
||
&emmc { | ||
bus-width = <8>; | ||
cap-mmc-highspeed; | ||
max-frequency = <150000000>; | ||
mmc-ddr-1_8v; | ||
mmc-hs200-1_8v; | ||
non-removable; | ||
pinctrl-names = "default"; | ||
pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8>; | ||
vmmc-supply = <&vcc_io_33>; | ||
vqmmc-supply = <&vcc18_emmc>; | ||
status = "okay"; | ||
}; |
30 changes: 30 additions & 0 deletions
30
target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s-plus.dts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
// SPDX-License-Identifier: (GPL-2.0+ OR MIT) | ||
/* | ||
* (C) Copyright 2018 FriendlyElec Computer Tech. Co., Ltd. | ||
* (http://www.friendlyarm.com) | ||
* | ||
* (C) Copyright 2016 Rockchip Electronics Co., Ltd | ||
*/ | ||
|
||
/dts-v1/; | ||
#include "rk3328-nanopi-r2s.dts" | ||
|
||
/ { | ||
compatible = "friendlyarm,nanopi-r2s-plus", "rockchip,rk3328"; | ||
model = "FriendlyElec NanoPi R2S Plus"; | ||
|
||
aliases { | ||
mmc1 = &emmc; | ||
}; | ||
}; | ||
|
||
&emmc { | ||
bus-width = <8>; | ||
cap-mmc-highspeed; | ||
disable-wp; | ||
mmc-hs200-1_8v; | ||
non-removable; | ||
pinctrl-names = "default"; | ||
pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8>; | ||
status = "okay"; | ||
}; |
260 changes: 260 additions & 0 deletions
260
...ux/rockchip/patches-6.6/035-01-v6.12-mmc-dw_mmc-rockchip-Add-internal-phase-support.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,260 @@ | ||
From 59903441f5e49d46478fefcccec41e2ba896b740 Mon Sep 17 00:00:00 2001 | ||
From: Shawn Lin <[email protected]> | ||
Date: Wed, 28 Aug 2024 15:24:55 +0000 | ||
Subject: [PATCH] mmc: dw_mmc-rockchip: Add internal phase support | ||
|
||
Some Rockchip devices put the phase settings into the dw_mmc controller. | ||
|
||
When the feature is present, the ciu-drive and ciu-sample clocks are | ||
not used and the phase configuration is done directly through the mmc | ||
controller. | ||
|
||
Signed-off-by: Shawn Lin <[email protected]> | ||
Signed-off-by: Detlev Casanova <[email protected]> | ||
Acked-by: Shawn Lin <[email protected]> | ||
Reviewed-by: Heiko Stuebner <[email protected]> | ||
Link: https://lore.kernel.org/r/010201919996fdae-8a9f843e-00a8-4131-98bf-a9da4ed04bfd-000000@eu-west-1.amazonses.com | ||
Signed-off-by: Ulf Hansson <[email protected]> | ||
--- | ||
drivers/mmc/host/dw_mmc-rockchip.c | 171 +++++++++++++++++++++++++++-- | ||
1 file changed, 160 insertions(+), 11 deletions(-) | ||
|
||
--- a/drivers/mmc/host/dw_mmc-rockchip.c | ||
+++ b/drivers/mmc/host/dw_mmc-rockchip.c | ||
@@ -15,7 +15,17 @@ | ||
#include "dw_mmc.h" | ||
#include "dw_mmc-pltfm.h" | ||
|
||
-#define RK3288_CLKGEN_DIV 2 | ||
+#define RK3288_CLKGEN_DIV 2 | ||
+#define SDMMC_TIMING_CON0 0x130 | ||
+#define SDMMC_TIMING_CON1 0x134 | ||
+#define ROCKCHIP_MMC_DELAY_SEL BIT(10) | ||
+#define ROCKCHIP_MMC_DEGREE_MASK 0x3 | ||
+#define ROCKCHIP_MMC_DEGREE_OFFSET 1 | ||
+#define ROCKCHIP_MMC_DELAYNUM_OFFSET 2 | ||
+#define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET) | ||
+#define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60 | ||
+#define HIWORD_UPDATE(val, mask, shift) \ | ||
+ ((val) << (shift) | (mask) << ((shift) + 16)) | ||
|
||
static const unsigned int freqs[] = { 100000, 200000, 300000, 400000 }; | ||
|
||
@@ -24,8 +34,143 @@ struct dw_mci_rockchip_priv_data { | ||
struct clk *sample_clk; | ||
int default_sample_phase; | ||
int num_phases; | ||
+ bool internal_phase; | ||
}; | ||
|
||
+/* | ||
+ * Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to | ||
+ * simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg. | ||
+ */ | ||
+static int rockchip_mmc_get_internal_phase(struct dw_mci *host, bool sample) | ||
+{ | ||
+ unsigned long rate = clk_get_rate(host->ciu_clk); | ||
+ u32 raw_value; | ||
+ u16 degrees; | ||
+ u32 delay_num = 0; | ||
+ | ||
+ /* Constant signal, no measurable phase shift */ | ||
+ if (!rate) | ||
+ return 0; | ||
+ | ||
+ if (sample) | ||
+ raw_value = mci_readl(host, TIMING_CON1); | ||
+ else | ||
+ raw_value = mci_readl(host, TIMING_CON0); | ||
+ | ||
+ raw_value >>= ROCKCHIP_MMC_DEGREE_OFFSET; | ||
+ degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90; | ||
+ | ||
+ if (raw_value & ROCKCHIP_MMC_DELAY_SEL) { | ||
+ /* degrees/delaynum * 1000000 */ | ||
+ unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) * | ||
+ 36 * (rate / 10000); | ||
+ | ||
+ delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK); | ||
+ delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET; | ||
+ degrees += DIV_ROUND_CLOSEST(delay_num * factor, 1000000); | ||
+ } | ||
+ | ||
+ return degrees % 360; | ||
+} | ||
+ | ||
+static int rockchip_mmc_get_phase(struct dw_mci *host, bool sample) | ||
+{ | ||
+ struct dw_mci_rockchip_priv_data *priv = host->priv; | ||
+ struct clk *clock = sample ? priv->sample_clk : priv->drv_clk; | ||
+ | ||
+ if (priv->internal_phase) | ||
+ return rockchip_mmc_get_internal_phase(host, sample); | ||
+ else | ||
+ return clk_get_phase(clock); | ||
+} | ||
+ | ||
+static int rockchip_mmc_set_internal_phase(struct dw_mci *host, bool sample, int degrees) | ||
+{ | ||
+ unsigned long rate = clk_get_rate(host->ciu_clk); | ||
+ u8 nineties, remainder; | ||
+ u8 delay_num; | ||
+ u32 raw_value; | ||
+ u32 delay; | ||
+ | ||
+ /* | ||
+ * The below calculation is based on the output clock from | ||
+ * MMC host to the card, which expects the phase clock inherits | ||
+ * the clock rate from its parent, namely the output clock | ||
+ * provider of MMC host. However, things may go wrong if | ||
+ * (1) It is orphan. | ||
+ * (2) It is assigned to the wrong parent. | ||
+ * | ||
+ * This check help debug the case (1), which seems to be the | ||
+ * most likely problem we often face and which makes it difficult | ||
+ * for people to debug unstable mmc tuning results. | ||
+ */ | ||
+ if (!rate) { | ||
+ dev_err(host->dev, "%s: invalid clk rate\n", __func__); | ||
+ return -EINVAL; | ||
+ } | ||
+ | ||
+ nineties = degrees / 90; | ||
+ remainder = (degrees % 90); | ||
+ | ||
+ /* | ||
+ * Due to the inexact nature of the "fine" delay, we might | ||
+ * actually go non-monotonic. We don't go _too_ monotonic | ||
+ * though, so we should be OK. Here are options of how we may | ||
+ * work: | ||
+ * | ||
+ * Ideally we end up with: | ||
+ * 1.0, 2.0, ..., 69.0, 70.0, ..., 89.0, 90.0 | ||
+ * | ||
+ * On one extreme (if delay is actually 44ps): | ||
+ * .73, 1.5, ..., 50.6, 51.3, ..., 65.3, 90.0 | ||
+ * The other (if delay is actually 77ps): | ||
+ * 1.3, 2.6, ..., 88.6. 89.8, ..., 114.0, 90 | ||
+ * | ||
+ * It's possible we might make a delay that is up to 25 | ||
+ * degrees off from what we think we're making. That's OK | ||
+ * though because we should be REALLY far from any bad range. | ||
+ */ | ||
+ | ||
+ /* | ||
+ * Convert to delay; do a little extra work to make sure we | ||
+ * don't overflow 32-bit / 64-bit numbers. | ||
+ */ | ||
+ delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */ | ||
+ delay *= remainder; | ||
+ delay = DIV_ROUND_CLOSEST(delay, | ||
+ (rate / 1000) * 36 * | ||
+ (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10)); | ||
+ | ||
+ delay_num = (u8) min_t(u32, delay, 255); | ||
+ | ||
+ raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0; | ||
+ raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET; | ||
+ raw_value |= nineties; | ||
+ | ||
+ if (sample) | ||
+ mci_writel(host, TIMING_CON1, HIWORD_UPDATE(raw_value, 0x07ff, 1)); | ||
+ else | ||
+ mci_writel(host, TIMING_CON0, HIWORD_UPDATE(raw_value, 0x07ff, 1)); | ||
+ | ||
+ dev_dbg(host->dev, "set %s_phase(%d) delay_nums=%u actual_degrees=%d\n", | ||
+ sample ? "sample" : "drv", degrees, delay_num, | ||
+ rockchip_mmc_get_phase(host, sample) | ||
+ ); | ||
+ | ||
+ return 0; | ||
+} | ||
+ | ||
+static int rockchip_mmc_set_phase(struct dw_mci *host, bool sample, int degrees) | ||
+{ | ||
+ struct dw_mci_rockchip_priv_data *priv = host->priv; | ||
+ struct clk *clock = sample ? priv->sample_clk : priv->drv_clk; | ||
+ | ||
+ if (priv->internal_phase) | ||
+ return rockchip_mmc_set_internal_phase(host, sample, degrees); | ||
+ else | ||
+ return clk_set_phase(clock, degrees); | ||
+} | ||
+ | ||
static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios) | ||
{ | ||
struct dw_mci_rockchip_priv_data *priv = host->priv; | ||
@@ -64,7 +209,7 @@ static void dw_mci_rk3288_set_ios(struct | ||
|
||
/* Make sure we use phases which we can enumerate with */ | ||
if (!IS_ERR(priv->sample_clk) && ios->timing <= MMC_TIMING_SD_HS) | ||
- clk_set_phase(priv->sample_clk, priv->default_sample_phase); | ||
+ rockchip_mmc_set_phase(host, true, priv->default_sample_phase); | ||
|
||
/* | ||
* Set the drive phase offset based on speed mode to achieve hold times. | ||
@@ -127,7 +272,7 @@ static void dw_mci_rk3288_set_ios(struct | ||
break; | ||
} | ||
|
||
- clk_set_phase(priv->drv_clk, phase); | ||
+ rockchip_mmc_set_phase(host, false, phase); | ||
} | ||
} | ||
|
||
@@ -151,6 +296,7 @@ static int dw_mci_rk3288_execute_tuning( | ||
int longest_range_len = -1; | ||
int longest_range = -1; | ||
int middle_phase; | ||
+ int phase; | ||
|
||
if (IS_ERR(priv->sample_clk)) { | ||
dev_err(host->dev, "Tuning clock (sample_clk) not defined.\n"); | ||
@@ -164,8 +310,10 @@ static int dw_mci_rk3288_execute_tuning( | ||
|
||
/* Try each phase and extract good ranges */ | ||
for (i = 0; i < priv->num_phases; ) { | ||
- clk_set_phase(priv->sample_clk, | ||
- TUNING_ITERATION_TO_PHASE(i, priv->num_phases)); | ||
+ rockchip_mmc_set_phase(host, true, | ||
+ TUNING_ITERATION_TO_PHASE( | ||
+ i, | ||
+ priv->num_phases)); | ||
|
||
v = !mmc_send_tuning(mmc, opcode, NULL); | ||
|
||
@@ -211,7 +359,8 @@ static int dw_mci_rk3288_execute_tuning( | ||
} | ||
|
||
if (ranges[0].start == 0 && ranges[0].end == priv->num_phases - 1) { | ||
- clk_set_phase(priv->sample_clk, priv->default_sample_phase); | ||
+ rockchip_mmc_set_phase(host, true, priv->default_sample_phase); | ||
+ | ||
dev_info(host->dev, "All phases work, using default phase %d.", | ||
priv->default_sample_phase); | ||
goto free; | ||
@@ -248,12 +397,10 @@ static int dw_mci_rk3288_execute_tuning( | ||
|
||
middle_phase = ranges[longest_range].start + longest_range_len / 2; | ||
middle_phase %= priv->num_phases; | ||
- dev_info(host->dev, "Successfully tuned phase to %d\n", | ||
- TUNING_ITERATION_TO_PHASE(middle_phase, priv->num_phases)); | ||
+ phase = TUNING_ITERATION_TO_PHASE(middle_phase, priv->num_phases); | ||
+ dev_info(host->dev, "Successfully tuned phase to %d\n", phase); | ||
|
||
- clk_set_phase(priv->sample_clk, | ||
- TUNING_ITERATION_TO_PHASE(middle_phase, | ||
- priv->num_phases)); | ||
+ rockchip_mmc_set_phase(host, true, phase); | ||
|
||
free: | ||
kfree(ranges); | ||
@@ -287,6 +434,8 @@ static int dw_mci_rk3288_parse_dt(struct | ||
|
||
host->priv = priv; | ||
|
||
+ priv->internal_phase = false; | ||
+ | ||
return 0; | ||
} | ||
|
Oops, something went wrong.