[PATCH 01/13] mmc: renesas-sdhi: R-Car M3 r1.3 also uses 4 tuning taps

From: Hai Pham hai.pham.ud@renesas.com
Early ES revisions of M3-W SoCs requires 4-tap HS400. Reflect the status from datasheet.
Reviewed-by: Marek Vasut marek.vasut+renesas@mailbox.org Signed-off-by: Hai Pham hai.pham.ud@renesas.com Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org --- drivers/mmc/renesas-sdhi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index 9ad92648a34..9f8a272d03d 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -934,12 +934,12 @@ static void renesas_sdhi_filter_caps(struct udevice *dev) r8a77990_calib_table[!rmobile_is_gen3_mmc0(priv)]; }
- /* H3 ES1.x, ES2.0 and M3W ES1.0, ES1.1, ES1.2 uses 4 tuning taps */ + /* H3 ES1.x, ES2.0 and M3W ES1.[0123] uses 4 tuning taps */ if (((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7795) && (rmobile_get_cpu_rev_integer() <= 2)) || ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7796) && (rmobile_get_cpu_rev_integer() == 1) && - (rmobile_get_cpu_rev_fraction() <= 2))) + (rmobile_get_cpu_rev_fraction() <= 3))) priv->nrtaps = 4; else priv->nrtaps = 8;

From: Hai Pham hai.pham.ud@renesas.com
Further filter out HS400 support on certain SoCs.
Since M3-W r1.2 does not support HS400, drop the calibration table and rename the one for M3-W r1.3 to r8a7796_rev13_calib_table
Reviewed-by: Marek Vasut marek.vasut+renesas@mailbox.org Signed-off-by: Hai Pham hai.pham.ud@renesas.com Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org --- drivers/mmc/renesas-sdhi.c | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-)
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index 9f8a272d03d..3ec0444700e 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -78,14 +78,7 @@ static const u8 r8a7795_calib_table[2][CALIB_TABLE_MAX] = { 16, 16, 17, 17, 17, 17, 17, 18, 18, 18, 18, 19, 20, 21, 22, 22 } };
-static const u8 r8a7796_rev1_calib_table[2][CALIB_TABLE_MAX] = { - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 4, 9, - 15, 15, 15, 16, 16, 16, 16, 16, 17, 18, 19, 20, 21, 21, 22, 22 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, - 2, 9, 16, 17, 17, 17, 18, 18, 18, 18, 19, 20, 21, 22, 23, 24} -}; - -static const u8 r8a7796_rev3_calib_table[2][CALIB_TABLE_MAX] = { +static const u8 r8a7796_rev13_calib_table[2][CALIB_TABLE_MAX] = { { 0, 0, 0, 0, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 9, 10, 11, 12, 13, 15, 16, 17, 17, 18, 19, 19, 20, 21, 21, 22, 23, 23 }, { 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, @@ -871,12 +864,16 @@ static void renesas_sdhi_filter_caps(struct udevice *dev) CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) struct tmio_sd_plat *plat = dev_get_plat(dev);
- /* HS400 is not supported on H3 ES1.x and M3W ES1.0, ES1.1 */ + /* HS400 is not supported on H3 ES1.x, M3W ES1.[012], V3M, V3H ES1.x, D3 */ if (((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7795) && (rmobile_get_cpu_rev_integer() <= 1)) || ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7796) && (rmobile_get_cpu_rev_integer() == 1) && - (rmobile_get_cpu_rev_fraction() < 2))) + (rmobile_get_cpu_rev_fraction() <= 2)) || + (rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A77970) || + ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A77980) && + (rmobile_get_cpu_rev_integer() <= 1)) || + (rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A77995)) plat->cfg.host_caps &= ~MMC_MODE_HS400;
/* H3 ES2.0, ES3.0 and M3W ES1.2 and M3N bad taps */ @@ -897,16 +894,6 @@ static void renesas_sdhi_filter_caps(struct udevice *dev) r8a7795_calib_table[!rmobile_is_gen3_mmc0(priv)]; }
- /* M3W ES1.2 can use HS400 with manual adjustment */ - if ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7796) && - (rmobile_get_cpu_rev_integer() == 1) && - (rmobile_get_cpu_rev_fraction() == 2)) { - priv->adjust_hs400_enable = true; - priv->adjust_hs400_offset = 3; - priv->adjust_hs400_calib_table = - r8a7796_rev1_calib_table[!rmobile_is_gen3_mmc0(priv)]; - } - /* M3W ES1.x for x>2 can use HS400 with manual adjustment and taps */ if ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7796) && (rmobile_get_cpu_rev_integer() == 1) && @@ -915,7 +902,7 @@ static void renesas_sdhi_filter_caps(struct udevice *dev) priv->adjust_hs400_offset = 0; priv->hs400_bad_tap = BIT(1) | BIT(3) | BIT(5) | BIT(7); priv->adjust_hs400_calib_table = - r8a7796_rev3_calib_table[!rmobile_is_gen3_mmc0(priv)]; + r8a7796_rev13_calib_table[!rmobile_is_gen3_mmc0(priv)]; }
/* M3N can use HS400 with manual adjustment */

On 1/27/23 05:05, Marek Vasut wrote:
From: Hai Pham hai.pham.ud@renesas.com
Further filter out HS400 support on certain SoCs.
Since M3-W r1.2 does not support HS400, drop the calibration table and rename the one for M3-W r1.3 to r8a7796_rev13_calib_table
Reviewed-by: Marek Vasut marek.vasut+renesas@mailbox.org Signed-off-by: Hai Pham hai.pham.ud@renesas.com Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org
Reviewed-by: Jaehoon Chung jh80.chung@samsung.com
Best Regards, Jaehoon Chung
drivers/mmc/renesas-sdhi.c | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-)
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index 9f8a272d03d..3ec0444700e 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -78,14 +78,7 @@ static const u8 r8a7795_calib_table[2][CALIB_TABLE_MAX] = { 16, 16, 17, 17, 17, 17, 17, 18, 18, 18, 18, 19, 20, 21, 22, 22 } };
-static const u8 r8a7796_rev1_calib_table[2][CALIB_TABLE_MAX] = {
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 4, 9,
15, 15, 15, 16, 16, 16, 16, 16, 17, 18, 19, 20, 21, 21, 22, 22 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
2, 9, 16, 17, 17, 17, 18, 18, 18, 18, 19, 20, 21, 22, 23, 24}
-};
-static const u8 r8a7796_rev3_calib_table[2][CALIB_TABLE_MAX] = { +static const u8 r8a7796_rev13_calib_table[2][CALIB_TABLE_MAX] = { { 0, 0, 0, 0, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 9, 10, 11, 12, 13, 15, 16, 17, 17, 18, 19, 19, 20, 21, 21, 22, 23, 23 }, { 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, @@ -871,12 +864,16 @@ static void renesas_sdhi_filter_caps(struct udevice *dev) CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) struct tmio_sd_plat *plat = dev_get_plat(dev);
- /* HS400 is not supported on H3 ES1.x and M3W ES1.0, ES1.1 */
- /* HS400 is not supported on H3 ES1.x, M3W ES1.[012], V3M, V3H ES1.x, D3 */ if (((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7795) && (rmobile_get_cpu_rev_integer() <= 1)) || ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7796) && (rmobile_get_cpu_rev_integer() == 1) &&
(rmobile_get_cpu_rev_fraction() < 2)))
(rmobile_get_cpu_rev_fraction() <= 2)) ||
(rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A77970) ||
((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A77980) &&
(rmobile_get_cpu_rev_integer() <= 1)) ||
(rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A77995))
plat->cfg.host_caps &= ~MMC_MODE_HS400;
/* H3 ES2.0, ES3.0 and M3W ES1.2 and M3N bad taps */
@@ -897,16 +894,6 @@ static void renesas_sdhi_filter_caps(struct udevice *dev) r8a7795_calib_table[!rmobile_is_gen3_mmc0(priv)]; }
- /* M3W ES1.2 can use HS400 with manual adjustment */
- if ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7796) &&
(rmobile_get_cpu_rev_integer() == 1) &&
(rmobile_get_cpu_rev_fraction() == 2)) {
priv->adjust_hs400_enable = true;
priv->adjust_hs400_offset = 3;
priv->adjust_hs400_calib_table =
r8a7796_rev1_calib_table[!rmobile_is_gen3_mmc0(priv)];
- }
- /* M3W ES1.x for x>2 can use HS400 with manual adjustment and taps */ if ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7796) && (rmobile_get_cpu_rev_integer() == 1) &&
@@ -915,7 +902,7 @@ static void renesas_sdhi_filter_caps(struct udevice *dev) priv->adjust_hs400_offset = 0; priv->hs400_bad_tap = BIT(1) | BIT(3) | BIT(5) | BIT(7); priv->adjust_hs400_calib_table =
r8a7796_rev3_calib_table[!rmobile_is_gen3_mmc0(priv)];
r8a7796_rev13_calib_table[!rmobile_is_gen3_mmc0(priv)];
}
/* M3N can use HS400 with manual adjustment */

From: Hai Pham hai.pham.ud@renesas.com
Adjust HS400 calibration tables based on Linux settings
Reviewed-by: Marek Vasut marek.vasut+renesas@mailbox.org Signed-off-by: Hai Pham hai.pham.ud@renesas.com Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org --- drivers/mmc/renesas-sdhi.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index 3ec0444700e..f9155bc44de 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -79,24 +79,24 @@ static const u8 r8a7795_calib_table[2][CALIB_TABLE_MAX] = { };
static const u8 r8a7796_rev13_calib_table[2][CALIB_TABLE_MAX] = { - { 0, 0, 0, 0, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 9, 10, - 11, 12, 13, 15, 16, 17, 17, 18, 19, 19, 20, 21, 21, 22, 23, 23 }, - { 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, - 13, 14, 15, 16, 17, 17, 18, 19, 20, 20, 21, 22, 22, 23, 24, 24 } + { 3, 3, 3, 3, 3, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 15, + 16, 16, 16, 16, 16, 16, 17, 18, 18, 19, 20, 21, 22, 23, 24, 25 }, + { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 7, 8, 11, + 12, 17, 18, 18, 18, 18, 18, 18, 18, 19, 20, 21, 22, 23, 25, 25 } };
static const u8 r8a77965_calib_table[2][CALIB_TABLE_MAX] = { - { 0, 1, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, - 16, 17, 18, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 29 }, - { 0, 1, 2, 2, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 15, - 16, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 31 } + { 1, 2, 6, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 25, 26, 27, 28, 29, 30, 31 }, + { 2, 3, 4, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 17, 17, 20, 21, 22, 23, 24, 25, 27, 28, 29, 30, 31, 31, 31, 31 } };
static const u8 r8a77990_calib_table[2][CALIB_TABLE_MAX] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 1, 2, 3, 4, 4, 4, 4, 5, 5, 6, 7, 8, 10, 11, - 12, 13, 14, 16, 17, 18, 18, 18, 19, 19, 20, 24, 26, 26, 26, 26 } + { 0, 0, 0, 1, 2, 3, 3, 4, 4, 4, 5, 5, 6, 8, 9, 10, + 11, 12, 13, 15, 16, 17, 17, 18, 18, 19, 20, 22, 24, 25, 26, 26 } };
static int rmobile_is_gen3_mmc0(struct tmio_sd_priv *priv)

On 1/27/23 05:05, Marek Vasut wrote:
From: Hai Pham hai.pham.ud@renesas.com
Adjust HS400 calibration tables based on Linux settings
Reviewed-by: Marek Vasut marek.vasut+renesas@mailbox.org Signed-off-by: Hai Pham hai.pham.ud@renesas.com Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org
Reviewed-by: Jaehoon Chung jh80.chung@samsung.com
Best Regards, Jaehoon Chung
drivers/mmc/renesas-sdhi.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index 3ec0444700e..f9155bc44de 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -79,24 +79,24 @@ static const u8 r8a7795_calib_table[2][CALIB_TABLE_MAX] = { };
static const u8 r8a7796_rev13_calib_table[2][CALIB_TABLE_MAX] = {
- { 0, 0, 0, 0, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 9, 10,
11, 12, 13, 15, 16, 17, 17, 18, 19, 19, 20, 21, 21, 22, 23, 23 },
- { 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12,
13, 14, 15, 16, 17, 17, 18, 19, 20, 20, 21, 22, 22, 23, 24, 24 }
- { 3, 3, 3, 3, 3, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 15,
16, 16, 16, 16, 16, 16, 17, 18, 18, 19, 20, 21, 22, 23, 24, 25 },
- { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 7, 8, 11,
12, 17, 18, 18, 18, 18, 18, 18, 18, 19, 20, 21, 22, 23, 25, 25 }
};
static const u8 r8a77965_calib_table[2][CALIB_TABLE_MAX] = {
- { 0, 1, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15,
16, 17, 18, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 29 },
- { 0, 1, 2, 2, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 15,
16, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 31 }
- { 1, 2, 6, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 25, 26, 27, 28, 29, 30, 31 },
- { 2, 3, 4, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 16, 17,
17, 17, 20, 21, 22, 23, 24, 25, 27, 28, 29, 30, 31, 31, 31, 31 }
};
static const u8 r8a77990_calib_table[2][CALIB_TABLE_MAX] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 1, 2, 3, 4, 4, 4, 4, 5, 5, 6, 7, 8, 10, 11,
12, 13, 14, 16, 17, 18, 18, 18, 19, 19, 20, 24, 26, 26, 26, 26 }
- { 0, 0, 0, 1, 2, 3, 3, 4, 4, 4, 5, 5, 6, 8, 9, 10,
11, 12, 13, 15, 16, 17, 17, 18, 18, 19, 20, 22, 24, 25, 26, 26 }
};
static int rmobile_is_gen3_mmc0(struct tmio_sd_priv *priv)

From: Hai Pham hai.pham.ud@renesas.com
Still uses 0x3 for now, adjust the offset value to TMPPORT3 accordingly
Reviewed-by: Marek Vasut marek.vasut+renesas@mailbox.org Signed-off-by: Hai Pham hai.pham.ud@renesas.com Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org --- drivers/mmc/renesas-sdhi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index f9155bc44de..90e8aaddb05 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -899,7 +899,7 @@ static void renesas_sdhi_filter_caps(struct udevice *dev) (rmobile_get_cpu_rev_integer() == 1) && (rmobile_get_cpu_rev_fraction() > 2)) { priv->adjust_hs400_enable = true; - priv->adjust_hs400_offset = 0; + priv->adjust_hs400_offset = 3; priv->hs400_bad_tap = BIT(1) | BIT(3) | BIT(5) | BIT(7); priv->adjust_hs400_calib_table = r8a7796_rev13_calib_table[!rmobile_is_gen3_mmc0(priv)];

On 1/27/23 05:05, Marek Vasut wrote:
From: Hai Pham hai.pham.ud@renesas.com
Still uses 0x3 for now, adjust the offset value to TMPPORT3 accordingly
Reviewed-by: Marek Vasut marek.vasut+renesas@mailbox.org Signed-off-by: Hai Pham hai.pham.ud@renesas.com Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org
Reviewed-by: Jaehoon Chung jh80.chung@samsung.com
Best Regards, Jaehoon Chung
drivers/mmc/renesas-sdhi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index f9155bc44de..90e8aaddb05 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -899,7 +899,7 @@ static void renesas_sdhi_filter_caps(struct udevice *dev) (rmobile_get_cpu_rev_integer() == 1) && (rmobile_get_cpu_rev_fraction() > 2)) { priv->adjust_hs400_enable = true;
priv->adjust_hs400_offset = 0;
priv->hs400_bad_tap = BIT(1) | BIT(3) | BIT(5) | BIT(7); priv->adjust_hs400_calib_table = r8a7796_rev13_calib_table[!rmobile_is_gen3_mmc0(priv)];priv->adjust_hs400_offset = 3;

From: Hai Pham hai.pham.ud@renesas.com
Support R8A77961 M3-W+ SoC.
Reviewed-by: Marek Vasut marek.vasut+renesas@mailbox.org Signed-off-by: Hai Pham hai.pham.ud@renesas.com Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org --- drivers/mmc/renesas-sdhi.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index 90e8aaddb05..95db8aca931 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -836,6 +836,7 @@ static const struct udevice_id renesas_sdhi_match[] = { { .compatible = "renesas,sdhi-r8a7794", .data = RENESAS_GEN2_QUIRKS }, { .compatible = "renesas,sdhi-r8a7795", .data = RENESAS_GEN3_QUIRKS }, { .compatible = "renesas,sdhi-r8a7796", .data = RENESAS_GEN3_QUIRKS }, + { .compatible = "renesas,sdhi-r8a77961", .data = RENESAS_GEN3_QUIRKS }, { .compatible = "renesas,rcar-gen3-sdhi", .data = RENESAS_GEN3_QUIRKS }, { .compatible = "renesas,sdhi-r8a77965", .data = RENESAS_GEN3_QUIRKS }, { .compatible = "renesas,sdhi-r8a77970", .data = RENESAS_GEN3_QUIRKS }, @@ -905,6 +906,11 @@ static void renesas_sdhi_filter_caps(struct udevice *dev) r8a7796_rev13_calib_table[!rmobile_is_gen3_mmc0(priv)]; }
+ /* M3W+ bad taps */ + if ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7796) && + (rmobile_get_cpu_rev_integer() == 3)) + priv->hs400_bad_tap = BIT(1) | BIT(3) | BIT(5) | BIT(7); + /* M3N can use HS400 with manual adjustment */ if (rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A77965) { priv->adjust_hs400_enable = true;

On 1/27/23 05:05, Marek Vasut wrote:
From: Hai Pham hai.pham.ud@renesas.com
Support R8A77961 M3-W+ SoC.
Reviewed-by: Marek Vasut marek.vasut+renesas@mailbox.org Signed-off-by: Hai Pham hai.pham.ud@renesas.com Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org
Reviewed-by: Jaehoon Chung jh80.chung@samsung.com
Best Regards, Jaehoon Chung
drivers/mmc/renesas-sdhi.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index 90e8aaddb05..95db8aca931 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -836,6 +836,7 @@ static const struct udevice_id renesas_sdhi_match[] = { { .compatible = "renesas,sdhi-r8a7794", .data = RENESAS_GEN2_QUIRKS }, { .compatible = "renesas,sdhi-r8a7795", .data = RENESAS_GEN3_QUIRKS }, { .compatible = "renesas,sdhi-r8a7796", .data = RENESAS_GEN3_QUIRKS },
- { .compatible = "renesas,sdhi-r8a77961", .data = RENESAS_GEN3_QUIRKS }, { .compatible = "renesas,rcar-gen3-sdhi", .data = RENESAS_GEN3_QUIRKS }, { .compatible = "renesas,sdhi-r8a77965", .data = RENESAS_GEN3_QUIRKS }, { .compatible = "renesas,sdhi-r8a77970", .data = RENESAS_GEN3_QUIRKS },
@@ -905,6 +906,11 @@ static void renesas_sdhi_filter_caps(struct udevice *dev) r8a7796_rev13_calib_table[!rmobile_is_gen3_mmc0(priv)]; }
- /* M3W+ bad taps */
- if ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7796) &&
(rmobile_get_cpu_rev_integer() == 3))
priv->hs400_bad_tap = BIT(1) | BIT(3) | BIT(5) | BIT(7);
- /* M3N can use HS400 with manual adjustment */ if (rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A77965) { priv->adjust_hs400_enable = true;

From: Hai Pham hai.pham.ud@renesas.com
It is unnecessary, so clean it up.
Reviewed-by: Marek Vasut marek.vasut+renesas@mailbox.org Signed-off-by: Hai Pham hai.pham.ud@renesas.com Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org # update commit message, mention ES3.0 --- drivers/mmc/renesas-sdhi.c | 16 ---------------- 1 file changed, 16 deletions(-)
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index 95db8aca931..f85ced26ed8 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -71,13 +71,6 @@
#define CALIB_TABLE_MAX (RENESAS_SDHI_SCC_TMPPORT_CALIB_CODE_MASK + 1)
-static const u8 r8a7795_calib_table[2][CALIB_TABLE_MAX] = { - { 0, 0, 0, 0, 0, 1, 1, 2, 3, 4, 5, 5, 6, 6, 7, 11, - 15, 16, 16, 17, 17, 17, 17, 17, 18, 18, 18, 18, 19, 20, 21, 21 }, - { 3, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 9, 10, 11, 12, 15, - 16, 16, 17, 17, 17, 17, 17, 18, 18, 18, 18, 19, 20, 21, 22, 22 } -}; - static const u8 r8a7796_rev13_calib_table[2][CALIB_TABLE_MAX] = { { 3, 3, 3, 3, 3, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 15, 16, 16, 16, 16, 16, 16, 17, 18, 18, 19, 20, 21, 22, 23, 24, 25 }, @@ -886,15 +879,6 @@ static void renesas_sdhi_filter_caps(struct udevice *dev) (rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A77965)) priv->hs400_bad_tap = BIT(2) | BIT(3) | BIT(6) | BIT(7);
- /* H3 ES3.0 can use HS400 with manual adjustment */ - if ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7795) && - (rmobile_get_cpu_rev_integer() >= 3)) { - priv->adjust_hs400_enable = true; - priv->adjust_hs400_offset = 0; - priv->adjust_hs400_calib_table = - r8a7795_calib_table[!rmobile_is_gen3_mmc0(priv)]; - } - /* M3W ES1.x for x>2 can use HS400 with manual adjustment and taps */ if ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7796) && (rmobile_get_cpu_rev_integer() == 1) &&

On 1/27/23 05:06, Marek Vasut wrote:
From: Hai Pham hai.pham.ud@renesas.com
It is unnecessary, so clean it up.
Reviewed-by: Marek Vasut marek.vasut+renesas@mailbox.org Signed-off-by: Hai Pham hai.pham.ud@renesas.com Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org # update commit message, mention ES3.0
Reviewed-by: Jaehoon Chung jh80.chung@samsung.com
Best Regards, Jaehoon Chung
drivers/mmc/renesas-sdhi.c | 16 ---------------- 1 file changed, 16 deletions(-)
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index 95db8aca931..f85ced26ed8 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -71,13 +71,6 @@
#define CALIB_TABLE_MAX (RENESAS_SDHI_SCC_TMPPORT_CALIB_CODE_MASK + 1)
-static const u8 r8a7795_calib_table[2][CALIB_TABLE_MAX] = {
- { 0, 0, 0, 0, 0, 1, 1, 2, 3, 4, 5, 5, 6, 6, 7, 11,
15, 16, 16, 17, 17, 17, 17, 17, 18, 18, 18, 18, 19, 20, 21, 21 },
- { 3, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 9, 10, 11, 12, 15,
16, 16, 17, 17, 17, 17, 17, 18, 18, 18, 18, 19, 20, 21, 22, 22 }
-};
static const u8 r8a7796_rev13_calib_table[2][CALIB_TABLE_MAX] = { { 3, 3, 3, 3, 3, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 15, 16, 16, 16, 16, 16, 16, 17, 18, 18, 19, 20, 21, 22, 23, 24, 25 }, @@ -886,15 +879,6 @@ static void renesas_sdhi_filter_caps(struct udevice *dev) (rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A77965)) priv->hs400_bad_tap = BIT(2) | BIT(3) | BIT(6) | BIT(7);
- /* H3 ES3.0 can use HS400 with manual adjustment */
- if ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7795) &&
(rmobile_get_cpu_rev_integer() >= 3)) {
priv->adjust_hs400_enable = true;
priv->adjust_hs400_offset = 0;
priv->adjust_hs400_calib_table =
r8a7795_calib_table[!rmobile_is_gen3_mmc0(priv)];
- }
- /* M3W ES1.x for x>2 can use HS400 with manual adjustment and taps */ if ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7796) && (rmobile_get_cpu_rev_integer() == 1) &&

From: Hai Pham hai.pham.ud@renesas.com
V3M handles SDnH differently than other Gen3 SoCs, so let's add a separate entry for that. This will allow better SDnH handling in the future.
Based on Linux commit 627151b4966f ("mmc: renesas_sdhi: Flag non-standard SDnH handling for V3M") by Wolfram Sang
Signed-off-by: Hai Pham hai.pham.ud@renesas.com --- drivers/mmc/renesas-sdhi.c | 6 ++++++ drivers/mmc/tmio-common.h | 1 + 2 files changed, 7 insertions(+)
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index f85ced26ed8..f30d7847bf2 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -930,6 +930,12 @@ static void renesas_sdhi_filter_caps(struct udevice *dev) priv->read_poll_flag = TMIO_SD_DMA_INFO1_END_RD; else priv->read_poll_flag = TMIO_SD_DMA_INFO1_END_RD2; + + /* V3M handles SD0H differently than other Gen3 SoCs */ + if (rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A77970) + priv->needs_clkh_fallback = true; + else + priv->needs_clkh_fallback = false; }
static int renesas_sdhi_probe(struct udevice *dev) diff --git a/drivers/mmc/tmio-common.h b/drivers/mmc/tmio-common.h index 59d5a0e22e9..e517ed978bf 100644 --- a/drivers/mmc/tmio-common.h +++ b/drivers/mmc/tmio-common.h @@ -151,6 +151,7 @@ struct tmio_sd_priv { u8 hs400_bad_tap; const u8 *adjust_hs400_calib_table; u32 quirks; + bool needs_clkh_fallback; #endif ulong (*clk_get_rate)(struct tmio_sd_priv *); };

On 1/27/23 05:06, Marek Vasut wrote:
From: Hai Pham hai.pham.ud@renesas.com
V3M handles SDnH differently than other Gen3 SoCs, so let's add a separate entry for that. This will allow better SDnH handling in the future.
Based on Linux commit 627151b4966f ("mmc: renesas_sdhi: Flag non-standard SDnH handling for V3M") by Wolfram Sang
Signed-off-by: Hai Pham hai.pham.ud@renesas.com
Reviewed-by: Jaehoon Chung jh80.chung@samsung.com
Best Regards, Jaehoon Chung
drivers/mmc/renesas-sdhi.c | 6 ++++++ drivers/mmc/tmio-common.h | 1 + 2 files changed, 7 insertions(+)
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index f85ced26ed8..f30d7847bf2 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -930,6 +930,12 @@ static void renesas_sdhi_filter_caps(struct udevice *dev) priv->read_poll_flag = TMIO_SD_DMA_INFO1_END_RD; else priv->read_poll_flag = TMIO_SD_DMA_INFO1_END_RD2;
- /* V3M handles SD0H differently than other Gen3 SoCs */
- if (rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A77970)
priv->needs_clkh_fallback = true;
- else
priv->needs_clkh_fallback = false;
}
static int renesas_sdhi_probe(struct udevice *dev) diff --git a/drivers/mmc/tmio-common.h b/drivers/mmc/tmio-common.h index 59d5a0e22e9..e517ed978bf 100644 --- a/drivers/mmc/tmio-common.h +++ b/drivers/mmc/tmio-common.h @@ -151,6 +151,7 @@ struct tmio_sd_priv { u8 hs400_bad_tap; const u8 *adjust_hs400_calib_table; u32 quirks;
- bool needs_clkh_fallback;
#endif ulong (*clk_get_rate)(struct tmio_sd_priv *); };

Replace custom local structure with matching one from clk-provider.h . No functional change.
Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org --- drivers/clk/renesas/clk-rcar-gen2.c | 6 +----- drivers/clk/renesas/clk-rcar-gen3.c | 8 ++------ 2 files changed, 3 insertions(+), 11 deletions(-)
diff --git a/drivers/clk/renesas/clk-rcar-gen2.c b/drivers/clk/renesas/clk-rcar-gen2.c index 3a68c5ad0eb..850d6411190 100644 --- a/drivers/clk/renesas/clk-rcar-gen2.c +++ b/drivers/clk/renesas/clk-rcar-gen2.c @@ -17,6 +17,7 @@ #include <log.h> #include <asm/global_data.h> #include <asm/io.h> +#include <linux/clk-provider.h>
#include <dt-bindings/clock/renesas-cpg-mssr.h>
@@ -26,11 +27,6 @@ #define CPG_PLL0CR 0x00d8 #define CPG_SDCKCR 0x0074
-struct clk_div_table { - u8 val; - u8 div; -}; - /* SDHI divisors */ static const struct clk_div_table cpg_sdh_div_table[] = { { 0, 2 }, { 1, 3 }, { 2, 4 }, { 3, 6 }, diff --git a/drivers/clk/renesas/clk-rcar-gen3.c b/drivers/clk/renesas/clk-rcar-gen3.c index dd61fe0c7cd..3df6aaabf0f 100644 --- a/drivers/clk/renesas/clk-rcar-gen3.c +++ b/drivers/clk/renesas/clk-rcar-gen3.c @@ -21,6 +21,7 @@ #include <asm/global_data.h> #include <asm/io.h> #include <linux/bitops.h> +#include <linux/clk-provider.h> #include <reset-uclass.h>
#include <dt-bindings/clock/renesas-cpg-mssr.h> @@ -55,11 +56,6 @@ .div = (sd_div), \ }
-struct sd_div_table { - u32 val; - unsigned int div; -}; - /* SDn divider * sd_srcfc sd_fc div * stp_hck stp_ck (div) (div) = sd_srcfc x sd_fc @@ -75,7 +71,7 @@ struct sd_div_table { * 1 0 3 (8) 0 (2) 16 * 1 0 4 (16) 0 (2) 32 */ -static const struct sd_div_table cpg_sd_div_table[] = { +static const struct clk_div_table cpg_sd_div_table[] = { /* CPG_SD_DIV_TABLE_DATA(stp_hck, stp_ck, sd_srcfc, sd_fc, sd_div) */ CPG_SD_DIV_TABLE_DATA(0, 0, 0, 1, 4), CPG_SD_DIV_TABLE_DATA(0, 0, 1, 1, 8),

From: Hai Pham hai.pham.ud@renesas.com
Introduce new helper function to handle clock type that uses clk_div_table struct. Based vaguely on Linux code. Make use of clk_div_table in RPC clocks handling.
The E3/D3 RPCSRC need to be handled differently and will be addressed in subsequence patch.
Based on Linux commit db4a0073cc82 ("clk: renesas: rcar-gen3: Add RPC clocks") by Sergei Shtylyov.
Signed-off-by: Hai Pham hai.pham.ud@renesas.com Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org Marek: - Squash patches to avoid adding unused code: clk: renesas: Make use of clk_div_table in RPC clocks handling clk: renesas: Introduce rcar_clk_get_rate64_div_table function - Move the new code to the beginning of clk-rcar-gen3 to avoid tables mixed with code - Use rcar_ prefix for get_table_div function - Get rid of custom macros, use GENMASK. Use custom field_get implementation as the generic FIELD_GET does not support constant mask and u32_get_bits requires higher optimization level - Pass in the register bit mask instead of width/shift combination - Turn rcar_clk_get_rate64_div_table into s64, as it can return -EINVAL --- drivers/clk/renesas/clk-rcar-gen3.c | 95 ++++++++++++++++++----------- drivers/clk/renesas/rcar-gen3-cpg.h | 3 + 2 files changed, 64 insertions(+), 34 deletions(-)
diff --git a/drivers/clk/renesas/clk-rcar-gen3.c b/drivers/clk/renesas/clk-rcar-gen3.c index 3df6aaabf0f..84bd7fe8b00 100644 --- a/drivers/clk/renesas/clk-rcar-gen3.c +++ b/drivers/clk/renesas/clk-rcar-gen3.c @@ -20,6 +20,7 @@ #include <wait_bit.h> #include <asm/global_data.h> #include <asm/io.h> +#include <linux/bitfield.h> #include <linux/bitops.h> #include <linux/clk-provider.h> #include <reset-uclass.h> @@ -33,10 +34,8 @@ #define CPG_PLL2CR 0x002c #define CPG_PLL4CR 0x01f4
-#define CPG_RPC_PREDIV_MASK 0x3 -#define CPG_RPC_PREDIV_OFFSET 3 -#define CPG_RPC_POSTDIV_MASK 0x7 -#define CPG_RPC_POSTDIV_OFFSET 0 +/* Non-constant mask variant of FIELD_GET */ +#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1))
/* * SDn Clock @@ -85,6 +84,45 @@ static const struct clk_div_table cpg_sd_div_table[] = { CPG_SD_DIV_TABLE_DATA(1, 0, 4, 0, 32), };
+static const struct clk_div_table cpg_rpcsrc_div_table[] = { + { 2, 5 }, { 3, 6 }, { 0, 0 }, +}; + +static const struct clk_div_table cpg_rpc_div_table[] = { + { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 }, { 0, 0 }, +}; + +static unsigned int rcar_clk_get_table_div(const struct clk_div_table *table, + const u32 value) +{ + const struct clk_div_table *clkt; + + for (clkt = table; clkt->div; clkt++) + if (clkt->val == value) + return clkt->div; + return 0; +} + +static __always_inline s64 +rcar_clk_get_rate64_div_table(unsigned int parent, u64 parent_rate, + void __iomem *reg, const u32 mask, + const struct clk_div_table *table, char *name) +{ + u32 value, div; + u64 rate; + + value = field_get(mask, readl(reg)); + div = rcar_clk_get_table_div(table, value); + if (!div) + return -EINVAL; + + rate = parent_rate / div; + debug("%s[%i] %s clk: parent=%i div=%u => rate=%llu\n", + __func__, __LINE__, name, parent, div, rate); + + return rate; +} + static int gen3_clk_get_parent(struct gen3_clk_priv *priv, struct clk *clk, struct cpg_mssr_info *info, struct clk *parent) { @@ -183,7 +221,7 @@ static u64 gen3_clk_get_rate64(struct clk *clk) const struct cpg_core_clk *core; const struct rcar_gen3_cpg_pll_config *pll_config = priv->cpg_pll_config; - u32 value, div, prediv, postdiv; + u32 value, div; u64 rate = 0; int i, ret;
@@ -313,40 +351,29 @@ static u64 gen3_clk_get_rate64(struct clk *clk)
return -EINVAL;
+ case CLK_TYPE_GEN3_RPCSRC: + return rcar_clk_get_rate64_div_table(core->parent, + gen3_clk_get_rate64(&parent), + priv->base + CPG_RPCCKCR, + CPG_RPCCKCR_DIV_POST_MASK, + cpg_rpcsrc_div_table, "RPCSRC"); + case CLK_TYPE_GEN3_RPC: - case CLK_TYPE_GEN3_RPCD2: case CLK_TYPE_GEN4_RPC: - case CLK_TYPE_GEN4_RPCD2: - rate = gen3_clk_get_rate64(&parent); - - value = readl(priv->base + CPG_RPCCKCR); - - prediv = (value >> CPG_RPC_PREDIV_OFFSET) & - CPG_RPC_PREDIV_MASK; - if (prediv == 2) - rate /= 5; - else if (prediv == 3) - rate /= 6; - else - return -EINVAL; - - postdiv = (value >> CPG_RPC_POSTDIV_OFFSET) & - CPG_RPC_POSTDIV_MASK; - - if (postdiv % 2 != 0) { - rate /= postdiv + 1; + return rcar_clk_get_rate64_div_table(core->parent, + gen3_clk_get_rate64(&parent), + priv->base + CPG_RPCCKCR, + CPG_RPCCKCR_DIV_PRE_MASK, + cpg_rpc_div_table, "RPC");
- if (core->type == CLK_TYPE_GEN3_RPCD2) - rate /= 2; - - debug("%s[%i] RPC clk: parent=%i prediv=%i postdiv=%i => rate=%llu\n", - __func__, __LINE__, - core->parent, prediv, postdiv, rate); + case CLK_TYPE_GEN3_RPCD2: + case CLK_TYPE_GEN4_RPCD2: + rate = gen3_clk_get_rate64(&parent) / 2;
- return rate; - } + debug("%s[%i] RPCD2 clk: parent=%i => rate=%llu\n", + __func__, __LINE__, core->parent, rate);
- return -EINVAL; + return rate;
}
diff --git a/drivers/clk/renesas/rcar-gen3-cpg.h b/drivers/clk/renesas/rcar-gen3-cpg.h index 007610bb4d9..41a30c569c7 100644 --- a/drivers/clk/renesas/rcar-gen3-cpg.h +++ b/drivers/clk/renesas/rcar-gen3-cpg.h @@ -112,6 +112,9 @@ struct rcar_gen3_cpg_pll_config { #define CPG_RST_MODEMR 0x060
#define CPG_RPCCKCR 0x238 +#define CPG_RPCCKCR_DIV_POST_MASK GENMASK(4, 3) +#define CPG_RPCCKCR_DIV_PRE_MASK GENMASK(2, 0) + #define CPG_RCKCR 0x240
struct gen3_clk_priv {

From: Hai Pham hai.pham.ud@renesas.com
The RPCSRC clock divider on R-Car D3 is very similar to the one on R-Car E3, but uses a different pre-divider for the PLL0 parent. Add a new macro to describe it, reusing the existing clock type for R-Car E3.
As both E3/D3 RPCSRC clock divider are different from the rest of R-Car Gen3, keep the original implementation from Linux.
Based on Linux commit 40745482eec8 ("clk: renesas: r8a774c0: Add RPC clocks") by Lad Prabhakar and 9d18f81b3535 ("clk: renesas: r8a77995: Add RPC clocks") by Geert Uytterhoeven.
Signed-off-by: Hai Pham hai.pham.ud@renesas.com Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org # Add D3 tweaks --- drivers/clk/renesas/clk-rcar-gen3.c | 31 +++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+)
diff --git a/drivers/clk/renesas/clk-rcar-gen3.c b/drivers/clk/renesas/clk-rcar-gen3.c index 84bd7fe8b00..aea8b1e8390 100644 --- a/drivers/clk/renesas/clk-rcar-gen3.c +++ b/drivers/clk/renesas/clk-rcar-gen3.c @@ -358,6 +358,37 @@ static u64 gen3_clk_get_rate64(struct clk *clk) CPG_RPCCKCR_DIV_POST_MASK, cpg_rpcsrc_div_table, "RPCSRC");
+ case CLK_TYPE_GEN3_D3_RPCSRC: + case CLK_TYPE_GEN3_E3_RPCSRC: + /* + * Register RPCSRC as fixed factor clock based on the + * MD[4:1] pins and CPG_RPCCKCR[4:3] register value for + * which has been set prior to booting the kernel. + */ + value = (readl(priv->base + CPG_RPCCKCR) & GENMASK(4, 3)) >> 3; + + switch (value) { + case 0: + div = 5; + break; + case 1: + div = 3; + break; + case 2: + div = core->div; + break; + case 3: + default: + div = 2; + break; + } + + rate = gen3_clk_get_rate64(&parent) / div; + debug("%s[%i] E3/D3 RPCSRC clk: parent=%i div=%u => rate=%llu\n", + __func__, __LINE__, (core->parent >> 16) & 0xffff, div, rate); + + return rate; + case CLK_TYPE_GEN3_RPC: case CLK_TYPE_GEN4_RPC: return rcar_clk_get_rate64_div_table(core->parent,

From: Hai Pham hai.pham.ud@renesas.com
On R-Car V3M (AKA R8A77970), the SD0CKCR is laid out differently than on the other R-Car gen3 SoCs. Hence, new clock types are introduced respectively.
Based on Linux commit 381081ffc294 ("clk: renesas: r8a77970: Add SD0H/SD0 clocks for SDHI") by Sergei Shtylyov sergei.shtylyov@cogentembedded.com
Signed-off-by: Hai Pham hai.pham.ud@renesas.com Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org Marek: - Fix missing ~ in GENMASK(a, b), use clrsetbits_le32 instead - Do not modify r8a77970-cpg-mssr.c much, drop enum r8a77970_clk_types which is now part of common clock types in rcar-gen3-cpg.h instead --- drivers/clk/renesas/clk-rcar-gen3.c | 39 +++++++++++++++++++++++++ drivers/clk/renesas/r8a77970-cpg-mssr.c | 5 ---- drivers/clk/renesas/rcar-gen3-cpg.h | 5 ++++ 3 files changed, 44 insertions(+), 5 deletions(-)
diff --git a/drivers/clk/renesas/clk-rcar-gen3.c b/drivers/clk/renesas/clk-rcar-gen3.c index 53f16dfb1e0..f8a23623223 100644 --- a/drivers/clk/renesas/clk-rcar-gen3.c +++ b/drivers/clk/renesas/clk-rcar-gen3.c @@ -57,6 +57,18 @@ static const struct clk_div_table cpg_sd_div_table[] = { { 0, 2 }, { 1, 4 }, { 0, 0 }, };
+static const struct clk_div_table r8a77970_cpg_sd0h_div_table[] = { + { 0, 2 }, { 1, 3 }, { 2, 4 }, { 3, 6 }, + { 4, 8 }, { 5, 12 }, { 6, 16 }, { 7, 18 }, + { 8, 24 }, { 10, 36 }, { 11, 48 }, { 0, 0 }, +}; + +static const struct clk_div_table r8a77970_cpg_sd0_div_table[] = { + { 4, 8 }, { 5, 12 }, { 6, 16 }, { 7, 18 }, + { 8, 24 }, { 10, 36 }, { 11, 48 }, { 12, 10 }, + { 0, 0 }, +}; + static unsigned int rcar_clk_get_table_div(const struct clk_div_table *table, const u32 value) { @@ -205,6 +217,19 @@ static int gen3_clk_setup_sdif_div(struct clk *clk, ulong rate) debug("%s[%i] SD clk: parent=%i offset=%x div=%u rate=%lu => val=%u\n", __func__, __LINE__, core->parent, core->offset, div, rate, value); break; + + case CLK_TYPE_R8A77970_SD0: + div = gen3_clk_get_rate64(&grandparent) / rate; + value = rcar_clk_get_table_val(cpg_sd_div_table, div); + if (!value) + return -EINVAL; + + clrsetbits_le32(priv->base + core->offset, + GENMASK(7, 4), value << 4); + + debug("%s[%i] SD clk: parent=%i offset=%x div=%u rate=%lu => val=%u\n", + __func__, __LINE__, core->parent, core->offset, div, rate, value); + break; }
return 0; @@ -358,6 +383,13 @@ static u64 gen3_clk_get_rate64(struct clk *clk) GENMASK(9, 5), cpg_sdh_div_table, "SDH");
+ case CLK_TYPE_R8A77970_SD0H: + return rcar_clk_get_rate64_div_table(core->parent, + gen3_clk_get_rate64(&parent), + priv->base + core->offset, + CPG_SDCKCR_SDHFC_MASK, + r8a77970_cpg_sd0h_div_table, "SDH"); + case CLK_TYPE_GEN3_SD: fallthrough; case CLK_TYPE_GEN4_SD: @@ -367,6 +399,13 @@ static u64 gen3_clk_get_rate64(struct clk *clk) CPG_SDCKCR_FC_MASK, cpg_sd_div_table, "SD");
+ case CLK_TYPE_R8A77970_SD0: + return rcar_clk_get_rate64_div_table(core->parent, + gen3_clk_get_rate64(&parent), + priv->base + core->offset, + CPG_SDCKCR_SD0FC_MASK, + r8a77970_cpg_sd0_div_table, "SD"); + case CLK_TYPE_GEN3_RPCSRC: return rcar_clk_get_rate64_div_table(core->parent, gen3_clk_get_rate64(&parent), diff --git a/drivers/clk/renesas/r8a77970-cpg-mssr.c b/drivers/clk/renesas/r8a77970-cpg-mssr.c index 4d72ec1fae8..f5d77df4233 100644 --- a/drivers/clk/renesas/r8a77970-cpg-mssr.c +++ b/drivers/clk/renesas/r8a77970-cpg-mssr.c @@ -22,11 +22,6 @@
#define CPG_SD0CKCR 0x0074
-enum r8a77970_clk_types { - CLK_TYPE_R8A77970_SD0H = CLK_TYPE_GEN3_SOC_BASE, - CLK_TYPE_R8A77970_SD0, -}; - enum clk_ids { /* Core Clock Outputs exported to DT */ LAST_DT_CORE_CLK = R8A77970_CLK_OSC, diff --git a/drivers/clk/renesas/rcar-gen3-cpg.h b/drivers/clk/renesas/rcar-gen3-cpg.h index 008e8928e59..200e4adb906 100644 --- a/drivers/clk/renesas/rcar-gen3-cpg.h +++ b/drivers/clk/renesas/rcar-gen3-cpg.h @@ -18,7 +18,9 @@ enum rcar_gen3_clk_types { CLK_TYPE_GEN3_PLL3, CLK_TYPE_GEN3_PLL4, CLK_TYPE_GEN3_SDH, + CLK_TYPE_R8A77970_SD0H, CLK_TYPE_GEN3_SD, + CLK_TYPE_R8A77970_SD0, CLK_TYPE_GEN3_R, CLK_TYPE_GEN3_MDSEL, /* Select parent/divider using mode pin */ CLK_TYPE_GEN3_Z, @@ -115,6 +117,9 @@ struct rcar_gen3_cpg_pll_config { #define CPG_SDCKCR_STPnCK BIT(8) #define CPG_SDCKCR_SRCFC_MASK GENMASK(4, 2) #define CPG_SDCKCR_FC_MASK GENMASK(1, 0) +/* V3M specifics */ +#define CPG_SDCKCR_SDHFC_MASK GENMASK(11, 8) +#define CPG_SDCKCR_SD0FC_MASK GENMASK(7, 4)
#define CPG_RPCCKCR 0x238 #define CPG_RPCCKCR_DIV_POST_MASK GENMASK(4, 3)

From: Hai Pham hai.pham.ud@renesas.com
R-Car V3U has a CPG different enough to not be a generic Gen3 CPG but similar enough to reuse code. Introduce a new CPG library, factor out the SD clock and RPC clock handling and hook them to the generic Gen3 CPG driver so we have an equal state.
Based on Linux commit [1] and [2] by Wolfram Sang
[1] 8bb67d87346a ("clk: renesas: rcar-gen3: Factor out CPG library") [2] 6f21d145b90f ("clk: renesas: cpg-lib: Move RPC clock registration to the library")
Signed-off-by: Hai Pham hai.pham.ud@renesas.com Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org Marek: - Add rcar_clk_* prefix to all functions - Rebase on changes to clk: renesas: Introduce and use rcar_clk_get_rate64_div_table function - Use u32_encode_bits/GENMASK bitfield ops --- drivers/clk/renesas/Kconfig | 4 + drivers/clk/renesas/Makefile | 1 + drivers/clk/renesas/clk-rcar-gen3.c | 145 ++++-------------------- drivers/clk/renesas/rcar-cpg-lib.c | 169 ++++++++++++++++++++++++++++ drivers/clk/renesas/rcar-cpg-lib.h | 33 ++++++ 5 files changed, 230 insertions(+), 122 deletions(-) create mode 100644 drivers/clk/renesas/rcar-cpg-lib.c create mode 100644 drivers/clk/renesas/rcar-cpg-lib.h
diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig index a538e7e7aa0..1686410d6d3 100644 --- a/drivers/clk/renesas/Kconfig +++ b/drivers/clk/renesas/Kconfig @@ -4,6 +4,9 @@ config CLK_RENESAS help Enable support for clock present on Renesas RCar SoCs.
+config CLK_RCAR_CPG_LIB + bool "CPG/MSSR library functions" + config CLK_RCAR_GEN2 bool "Renesas RCar Gen2 clock driver" def_bool y if RCAR_32 @@ -45,6 +48,7 @@ config CLK_RCAR_GEN3 bool "Renesas RCar Gen3 clock driver" def_bool y if RCAR_GEN3 depends on CLK_RENESAS + select CLK_RCAR_CPG_LIB help Enable this to support the clocks on Renesas RCar Gen3 SoC.
diff --git a/drivers/clk/renesas/Makefile b/drivers/clk/renesas/Makefile index df6bbc20bc3..8f82a7aa3e0 100644 --- a/drivers/clk/renesas/Makefile +++ b/drivers/clk/renesas/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_CLK_RENESAS) += renesas-cpg-mssr.o +obj-$(CONFIG_CLK_RCAR_CPG_LIB) += rcar-cpg-lib.o obj-$(CONFIG_CLK_RCAR_GEN2) += clk-rcar-gen2.o obj-$(CONFIG_CLK_R8A774A1) += r8a774a1-cpg-mssr.o obj-$(CONFIG_CLK_R8A774B1) += r8a774b1-cpg-mssr.o diff --git a/drivers/clk/renesas/clk-rcar-gen3.c b/drivers/clk/renesas/clk-rcar-gen3.c index f8a23623223..d778db6569d 100644 --- a/drivers/clk/renesas/clk-rcar-gen3.c +++ b/drivers/clk/renesas/clk-rcar-gen3.c @@ -29,34 +29,16 @@
#include "renesas-cpg-mssr.h" #include "rcar-gen3-cpg.h" +#include "rcar-cpg-lib.h"
#define CPG_PLL0CR 0x00d8 #define CPG_PLL2CR 0x002c #define CPG_PLL4CR 0x01f4
-#define SDnSRCFC_SHIFT 2 -#define STPnHCK_TABLE (CPG_SDCKCR_STPnHCK >> SDnSRCFC_SHIFT) - -/* Non-constant mask variant of FIELD_GET/FIELD_PREP */ -#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) - static const struct clk_div_table cpg_rpcsrc_div_table[] = { { 2, 5 }, { 3, 6 }, { 0, 0 }, };
-static const struct clk_div_table cpg_rpc_div_table[] = { - { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 }, { 0, 0 }, -}; - -static const struct clk_div_table cpg_sdh_div_table[] = { - { 0, 1 }, { 1, 2 }, { STPnHCK_TABLE | 2, 4 }, { STPnHCK_TABLE | 3, 8 }, - { STPnHCK_TABLE | 4, 16 }, { 0, 0 }, -}; - -static const struct clk_div_table cpg_sd_div_table[] = { - { 0, 2 }, { 1, 4 }, { 0, 0 }, -}; - static const struct clk_div_table r8a77970_cpg_sd0h_div_table[] = { { 0, 2 }, { 1, 3 }, { 2, 4 }, { 3, 6 }, { 4, 8 }, { 5, 12 }, { 6, 16 }, { 7, 18 }, @@ -69,48 +51,6 @@ static const struct clk_div_table r8a77970_cpg_sd0_div_table[] = { { 0, 0 }, };
-static unsigned int rcar_clk_get_table_div(const struct clk_div_table *table, - const u32 value) -{ - const struct clk_div_table *clkt; - - for (clkt = table; clkt->div; clkt++) - if (clkt->val == value) - return clkt->div; - return 0; -} - -static int rcar_clk_get_table_val(const struct clk_div_table *table, - unsigned int div) -{ - const struct clk_div_table *clkt; - - for (clkt = table; clkt->div; clkt++) - if (clkt->div == div) - return clkt->val; - return -EINVAL; -} - -static __always_inline s64 -rcar_clk_get_rate64_div_table(unsigned int parent, u64 parent_rate, - void __iomem *reg, const u32 mask, - const struct clk_div_table *table, char *name) -{ - u32 value, div; - u64 rate; - - value = field_get(mask, readl(reg)); - div = rcar_clk_get_table_div(table, value); - if (!div) - return -EINVAL; - - rate = parent_rate / div; - debug("%s[%i] %s clk: parent=%i div=%u => rate=%llu\n", - __func__, __LINE__, name, parent, div, rate); - - return rate; -} - static int gen3_clk_get_parent(struct gen3_clk_priv *priv, struct clk *clk, struct cpg_mssr_info *info, struct clk *parent) { @@ -156,7 +96,6 @@ static int gen3_clk_setup_sdif_div(struct clk *clk, ulong rate) const struct cpg_core_clk *core; struct clk parent, grandparent; int ret; - u32 value = 0, div = 0;
/* * The clk may be either CPG_MOD or core clock, in case this is MOD @@ -191,45 +130,23 @@ static int gen3_clk_setup_sdif_div(struct clk *clk, ulong rate) case CLK_TYPE_GEN3_SDH: fallthrough; case CLK_TYPE_GEN4_SDH: - div = DIV_ROUND_CLOSEST(gen3_clk_get_rate64(&grandparent), rate); - value = rcar_clk_get_table_val(cpg_sdh_div_table, div); - if (value < 0) - return value; - - clrsetbits_le32(priv->base + core->offset, - GENMASK(9, 2), value << 2); - - debug("%s[%i] SDH clk: parent=%i offset=%x div=%u rate=%lu => val=%u\n", - __func__, __LINE__, core->parent, core->offset, div, rate, value); - break; + return rcar_clk_set_rate64_sdh(core->parent, + gen3_clk_get_rate64(&grandparent), + rate, priv->base + core->offset);
case CLK_TYPE_GEN3_SD: fallthrough; case CLK_TYPE_GEN4_SD: - div = DIV_ROUND_CLOSEST(gen3_clk_get_rate64(&grandparent), rate); - value = rcar_clk_get_table_val(cpg_sd_div_table, div); - if (value < 0) - return value; - - clrsetbits_le32(priv->base + core->offset, - GENMASK(1, 0), value); - - debug("%s[%i] SD clk: parent=%i offset=%x div=%u rate=%lu => val=%u\n", - __func__, __LINE__, core->parent, core->offset, div, rate, value); - break; + return rcar_clk_set_rate64_sd(core->parent, + gen3_clk_get_rate64(&grandparent), + rate, priv->base + core->offset);
case CLK_TYPE_R8A77970_SD0: - div = gen3_clk_get_rate64(&grandparent) / rate; - value = rcar_clk_get_table_val(cpg_sd_div_table, div); - if (!value) - return -EINVAL; - - clrsetbits_le32(priv->base + core->offset, - GENMASK(7, 4), value << 4); - - debug("%s[%i] SD clk: parent=%i offset=%x div=%u rate=%lu => val=%u\n", - __func__, __LINE__, core->parent, core->offset, div, rate, value); - break; + return rcar_clk_set_rate64_div_table(core->parent, + gen3_clk_get_rate64(&grandparent), + rate, priv->base + core->offset, + CPG_SDCKCR_SD0FC_MASK, + r8a77970_cpg_sd0_div_table, "SD"); }
return 0; @@ -371,17 +288,9 @@ static u64 gen3_clk_get_rate64(struct clk *clk) case CLK_TYPE_GEN3_SDH: /* Fixed factor 1:1 */ fallthrough; case CLK_TYPE_GEN4_SDH: /* Fixed factor 1:1 */ - /* - * This takes STPnHCK and STPnCK bits into consideration - * in the table look up too, hence the inobvious GENMASK - * below. Bits [7:5] always read zero, so this is OKish. - */ - return rcar_clk_get_rate64_div_table(core->parent, - gen3_clk_get_rate64(&parent), - priv->base + core->offset, - CPG_SDCKCR_SRCFC_MASK | - GENMASK(9, 5), - cpg_sdh_div_table, "SDH"); + return rcar_clk_get_rate64_sdh(core->parent, + gen3_clk_get_rate64(&parent), + priv->base + core->offset);
case CLK_TYPE_R8A77970_SD0H: return rcar_clk_get_rate64_div_table(core->parent, @@ -393,11 +302,9 @@ static u64 gen3_clk_get_rate64(struct clk *clk) case CLK_TYPE_GEN3_SD: fallthrough; case CLK_TYPE_GEN4_SD: - return rcar_clk_get_rate64_div_table(core->parent, - gen3_clk_get_rate64(&parent), - priv->base + core->offset, - CPG_SDCKCR_FC_MASK, - cpg_sd_div_table, "SD"); + return rcar_clk_get_rate64_sd(core->parent, + gen3_clk_get_rate64(&parent), + priv->base + core->offset);
case CLK_TYPE_R8A77970_SD0: return rcar_clk_get_rate64_div_table(core->parent, @@ -446,20 +353,14 @@ static u64 gen3_clk_get_rate64(struct clk *clk)
case CLK_TYPE_GEN3_RPC: case CLK_TYPE_GEN4_RPC: - return rcar_clk_get_rate64_div_table(core->parent, - gen3_clk_get_rate64(&parent), - priv->base + CPG_RPCCKCR, - CPG_RPCCKCR_DIV_PRE_MASK, - cpg_rpc_div_table, "RPC"); + return rcar_clk_get_rate64_rpc(core->parent, + gen3_clk_get_rate64(&parent), + priv->base + CPG_RPCCKCR);
case CLK_TYPE_GEN3_RPCD2: case CLK_TYPE_GEN4_RPCD2: - rate = gen3_clk_get_rate64(&parent) / 2; - - debug("%s[%i] RPCD2 clk: parent=%i => rate=%llu\n", - __func__, __LINE__, core->parent, rate); - - return rate; + return rcar_clk_get_rate64_rpcd2(core->parent, + gen3_clk_get_rate64(&parent));
}
diff --git a/drivers/clk/renesas/rcar-cpg-lib.c b/drivers/clk/renesas/rcar-cpg-lib.c new file mode 100644 index 00000000000..a2fca660a8e --- /dev/null +++ b/drivers/clk/renesas/rcar-cpg-lib.c @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Renesas RCar Gen3 CPG MSSR driver + * + * Copyright (C) 2017 Marek Vasut marek.vasut@gmail.com + * + * Based on the following driver from Linux kernel: + * r8a7796 Clock Pulse Generator / Module Standby and Software Reset + * + * Copyright (C) 2016 Glider bvba + */ + +#include <common.h> +#include <clk-uclass.h> +#include <dm.h> +#include <errno.h> +#include <log.h> +#include <wait_bit.h> +#include <asm/global_data.h> +#include <asm/io.h> +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/clk-provider.h> + +#include <dt-bindings/clock/renesas-cpg-mssr.h> + +#include "renesas-cpg-mssr.h" +#include "rcar-gen3-cpg.h" +#include "rcar-cpg-lib.h" + +#define SDnSRCFC_SHIFT 2 +#define STPnHCK_TABLE (CPG_SDCKCR_STPnHCK >> SDnSRCFC_SHIFT) + +/* Non-constant mask variant of FIELD_GET/FIELD_PREP */ +#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) +#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) + +static const struct clk_div_table cpg_sdh_div_table[] = { + { 0, 1 }, { 1, 2 }, { STPnHCK_TABLE | 2, 4 }, { STPnHCK_TABLE | 3, 8 }, + { STPnHCK_TABLE | 4, 16 }, { 0, 0 }, +}; + +static const struct clk_div_table cpg_sd_div_table[] = { + { 0, 2 }, { 1, 4 }, { 0, 0 }, +}; + +static const struct clk_div_table cpg_rpc_div_table[] = { + { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 }, { 0, 0 }, +}; + +static unsigned int rcar_clk_get_table_div(const struct clk_div_table *table, + const u32 value) +{ + const struct clk_div_table *clkt; + + for (clkt = table; clkt->div; clkt++) + if (clkt->val == value) + return clkt->div; + return 0; +} + +static int rcar_clk_get_table_val(const struct clk_div_table *table, + unsigned int div) +{ + const struct clk_div_table *clkt; + + for (clkt = table; clkt->div; clkt++) + if (clkt->div == div) + return clkt->val; + return -EINVAL; +} + +s64 rcar_clk_get_rate64_div_table(unsigned int parent, u64 parent_rate, + void __iomem *reg, const u32 mask, + const struct clk_div_table *table, char *name) +{ + u32 value, div; + u64 rate; + + value = field_get(mask, readl(reg)); + div = rcar_clk_get_table_div(table, value); + if (!div) + return -EINVAL; + + rate = parent_rate / div; + debug("%s[%i] %s clk: parent=%i div=%u => rate=%llu\n", + __func__, __LINE__, name, parent, div, rate); + + return rate; +} + +int rcar_clk_set_rate64_div_table(unsigned int parent, u64 parent_rate, ulong rate, + void __iomem *reg, const u32 mask, + const struct clk_div_table *table, char *name) +{ + u32 value = 0, div = 0; + + div = DIV_ROUND_CLOSEST(parent_rate, rate); + value = rcar_clk_get_table_val(table, div); + if (value < 0) + return value; + + clrsetbits_le32(reg, mask, field_prep(mask, value)); + + debug("%s[%i] %s clk: parent=%i div=%u rate=%lu => val=%u\n", + __func__, __LINE__, name, parent, div, rate, value); + + return 0; +} + +s64 rcar_clk_get_rate64_rpc(unsigned int parent, u64 parent_rate, void __iomem *reg) +{ + return rcar_clk_get_rate64_div_table(parent, parent_rate, reg, + CPG_RPCCKCR_DIV_PRE_MASK, + cpg_rpc_div_table, "RPC"); +} + +u64 rcar_clk_get_rate64_rpcd2(unsigned int parent, u64 parent_rate) +{ + u64 rate = 0; + + rate = parent_rate / 2; + debug("%s[%i] RPCD2 clk: parent=%i => rate=%llu\n", + __func__, __LINE__, parent, rate); + + return rate; +} + +s64 rcar_clk_get_rate64_sdh(unsigned int parent, u64 parent_rate, void __iomem *reg) +{ + /* + * This takes STPnHCK and STPnCK bits into consideration + * in the table look up too, hence the inobvious GENMASK + * below. Bits [7:5] always read zero, so this is OKish. + */ + return rcar_clk_get_rate64_div_table(parent, parent_rate, reg, + CPG_SDCKCR_SRCFC_MASK | + GENMASK(9, 5), + cpg_sdh_div_table, "SDH"); +} + +s64 rcar_clk_get_rate64_sd(unsigned int parent, u64 parent_rate, void __iomem *reg) +{ + return rcar_clk_get_rate64_div_table(parent, parent_rate, reg, + CPG_SDCKCR_FC_MASK, + cpg_sd_div_table, "SD"); +} + +int rcar_clk_set_rate64_sdh(unsigned int parent, u64 parent_rate, ulong rate, + void __iomem *reg) +{ + /* + * This takes STPnHCK and STPnCK bits into consideration + * in the table look up too, hence the inobvious GENMASK + * below. Bits [7:5] always read zero, so this is OKish. + */ + return rcar_clk_set_rate64_div_table(parent, parent_rate, rate, reg, + CPG_SDCKCR_SRCFC_MASK | + GENMASK(9, 5), + cpg_sdh_div_table, "SDH"); +} + +int rcar_clk_set_rate64_sd(unsigned int parent, u64 parent_rate, ulong rate, + void __iomem *reg) +{ + return rcar_clk_set_rate64_div_table(parent, parent_rate, rate, reg, + CPG_SDCKCR_FC_MASK, + cpg_sd_div_table, "SD"); +} diff --git a/drivers/clk/renesas/rcar-cpg-lib.h b/drivers/clk/renesas/rcar-cpg-lib.h new file mode 100644 index 00000000000..09b3e50918b --- /dev/null +++ b/drivers/clk/renesas/rcar-cpg-lib.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * R-Car Gen3 Clock Pulse Generator Library + * + * Copyright (C) 2015-2018 Glider bvba + * Copyright (C) 2019 Renesas Electronics Corp. + * + * Based on clk-rcar-gen3.c + * + * Copyright (C) 2015 Renesas Electronics Corp. + */ + +#ifndef __CLK_RENESAS_RCAR_CPG_LIB_H__ +#define __CLK_RENESAS_RCAR_CPG_LIB_H__ + +s64 rcar_clk_get_rate64_div_table(unsigned int parent, u64 parent_rate, + void __iomem *reg, const u32 mask, + const struct clk_div_table *table, char *name); + +int rcar_clk_set_rate64_div_table(unsigned int parent, u64 parent_rate, ulong rate, + void __iomem *reg, const u32 mask, + const struct clk_div_table *table, char *name); + +s64 rcar_clk_get_rate64_sdh(unsigned int parent, u64 parent_rate, void __iomem *reg); +s64 rcar_clk_get_rate64_sd(unsigned int parent, u64 parent_rate, void __iomem *reg); +s64 rcar_clk_get_rate64_rpc(unsigned int parent, u64 parent_rate, void __iomem *reg); +u64 rcar_clk_get_rate64_rpcd2(unsigned int parent, u64 parent_rate); +int rcar_clk_set_rate64_sdh(unsigned int parent, u64 parent_rate, ulong rate, + void __iomem *reg); +int rcar_clk_set_rate64_sd(unsigned int parent, u64 parent_rate, ulong rate, + void __iomem *reg); + +#endif

From: Hai Pham hai.pham.ud@renesas.com
The old SD handling code was huge and could not handle all the details which showed up on R-Car Gen3 SoCs meanwhile. It is time to switch to another design. Have SDnH a separate clock, use the existing divider clocks and move the errata handling from the clock driver to the SDHI driver where it belongs.
Based on Linux series by Wolfram Sang, commit bb6d3fa98a41 ("clk: renesas: rcar-gen3: Switch to new SD clock handling") and commit e5f7e81ee430a ("mmc: renesas_sdhi: Parse DT for SDnH")
Signed-off-by: Hai Pham hai.pham.ud@renesas.com Signed-off-by: Marek Vasut marek.vasut+renesas@mailbox.org Marek: - Add rcar_clk_* prefix to all functions - Fix missing ~ in GENMASK(a, b), use clrsetbits_le32 instead - Use DIV_ROUND_CLOSEST, else if parent clock = 199999992 and rate = 200000000, the divider would be 0 and table lookup would fail. - Turn rcar_clk_get_table_val into signed integer, so it can return 0 as a valid value and negative values as errors. - Make the code operate on correct clock and add comment which explains the reasoning behind it. - Rebase on changes to clk: renesas: Introduce and use rcar_clk_get_rate64_div_table function --- NOTE: This patch didn't make it due to ML spam filter crash --- drivers/clk/renesas/clk-rcar-gen3.c | 198 +++++++++++++++------------- drivers/clk/renesas/rcar-gen3-cpg.h | 5 + drivers/mmc/renesas-sdhi.c | 21 ++- drivers/mmc/tmio-common.h | 1 + 4 files changed, 130 insertions(+), 95 deletions(-)
diff --git a/drivers/clk/renesas/clk-rcar-gen3.c b/drivers/clk/renesas/clk-rcar-gen3.c index aea8b1e8390..53f16dfb1e0 100644 --- a/drivers/clk/renesas/clk-rcar-gen3.c +++ b/drivers/clk/renesas/clk-rcar-gen3.c @@ -34,55 +34,11 @@ #define CPG_PLL2CR 0x002c #define CPG_PLL4CR 0x01f4
-/* Non-constant mask variant of FIELD_GET */ -#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) - -/* - * SDn Clock - */ -#define CPG_SD_STP_HCK BIT(9) -#define CPG_SD_STP_CK BIT(8) - -#define CPG_SD_STP_MASK (CPG_SD_STP_HCK | CPG_SD_STP_CK) -#define CPG_SD_FC_MASK (0x7 << 2 | 0x3 << 0) - -#define CPG_SD_DIV_TABLE_DATA(stp_hck, stp_ck, sd_srcfc, sd_fc, sd_div) \ -{ \ - .val = ((stp_hck) ? CPG_SD_STP_HCK : 0) | \ - ((stp_ck) ? CPG_SD_STP_CK : 0) | \ - ((sd_srcfc) << 2) | \ - ((sd_fc) << 0), \ - .div = (sd_div), \ -} +#define SDnSRCFC_SHIFT 2 +#define STPnHCK_TABLE (CPG_SDCKCR_STPnHCK >> SDnSRCFC_SHIFT)
-/* SDn divider - * sd_srcfc sd_fc div - * stp_hck stp_ck (div) (div) = sd_srcfc x sd_fc - *------------------------------------------------------------------- - * 0 0 0 (1) 1 (4) 4 - * 0 0 1 (2) 1 (4) 8 - * 1 0 2 (4) 1 (4) 16 - * 1 0 3 (8) 1 (4) 32 - * 1 0 4 (16) 1 (4) 64 - * 0 0 0 (1) 0 (2) 2 - * 0 0 1 (2) 0 (2) 4 - * 1 0 2 (4) 0 (2) 8 - * 1 0 3 (8) 0 (2) 16 - * 1 0 4 (16) 0 (2) 32 - */ -static const struct clk_div_table cpg_sd_div_table[] = { -/* CPG_SD_DIV_TABLE_DATA(stp_hck, stp_ck, sd_srcfc, sd_fc, sd_div) */ - CPG_SD_DIV_TABLE_DATA(0, 0, 0, 1, 4), - CPG_SD_DIV_TABLE_DATA(0, 0, 1, 1, 8), - CPG_SD_DIV_TABLE_DATA(1, 0, 2, 1, 16), - CPG_SD_DIV_TABLE_DATA(1, 0, 3, 1, 32), - CPG_SD_DIV_TABLE_DATA(1, 0, 4, 1, 64), - CPG_SD_DIV_TABLE_DATA(0, 0, 0, 0, 2), - CPG_SD_DIV_TABLE_DATA(0, 0, 1, 0, 4), - CPG_SD_DIV_TABLE_DATA(1, 0, 2, 0, 8), - CPG_SD_DIV_TABLE_DATA(1, 0, 3, 0, 16), - CPG_SD_DIV_TABLE_DATA(1, 0, 4, 0, 32), -}; +/* Non-constant mask variant of FIELD_GET/FIELD_PREP */ +#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1))
static const struct clk_div_table cpg_rpcsrc_div_table[] = { { 2, 5 }, { 3, 6 }, { 0, 0 }, @@ -92,6 +48,15 @@ static const struct clk_div_table cpg_rpc_div_table[] = { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 }, { 0, 0 }, };
+static const struct clk_div_table cpg_sdh_div_table[] = { + { 0, 1 }, { 1, 2 }, { STPnHCK_TABLE | 2, 4 }, { STPnHCK_TABLE | 3, 8 }, + { STPnHCK_TABLE | 4, 16 }, { 0, 0 }, +}; + +static const struct clk_div_table cpg_sd_div_table[] = { + { 0, 2 }, { 1, 4 }, { 0, 0 }, +}; + static unsigned int rcar_clk_get_table_div(const struct clk_div_table *table, const u32 value) { @@ -103,6 +68,17 @@ static unsigned int rcar_clk_get_table_div(const struct clk_div_table *table, return 0; }
+static int rcar_clk_get_table_val(const struct clk_div_table *table, + unsigned int div) +{ + const struct clk_div_table *clkt; + + for (clkt = table; clkt->div; clkt++) + if (clkt->div == div) + return clkt->val; + return -EINVAL; +} + static __always_inline s64 rcar_clk_get_rate64_div_table(unsigned int parent, u64 parent_rate, void __iomem *reg, const u32 mask, @@ -145,18 +121,45 @@ static int gen3_clk_get_parent(struct gen3_clk_priv *priv, struct clk *clk, return renesas_clk_get_parent(clk, info, parent); }
+static int gen3_clk_enable(struct clk *clk) +{ + struct gen3_clk_priv *priv = dev_get_priv(clk->dev); + + return renesas_clk_endisable(clk, priv->base, priv->info, true); +} + +static int gen3_clk_disable(struct clk *clk) +{ + struct gen3_clk_priv *priv = dev_get_priv(clk->dev); + + return renesas_clk_endisable(clk, priv->base, priv->info, false); +} + +static u64 gen3_clk_get_rate64(struct clk *clk); + static int gen3_clk_setup_sdif_div(struct clk *clk, ulong rate) { struct gen3_clk_priv *priv = dev_get_priv(clk->dev); struct cpg_mssr_info *info = priv->info; const struct cpg_core_clk *core; - struct clk parent; + struct clk parent, grandparent; int ret; - - ret = gen3_clk_get_parent(priv, clk, info, &parent); - if (ret) { - printf("%s[%i] parent fail, ret=%i\n", __func__, __LINE__, ret); - return ret; + u32 value = 0, div = 0; + + /* + * The clk may be either CPG_MOD or core clock, in case this is MOD + * clock, use core clock one level up, otherwise use the clock as-is. + * Note that parent clock here always represents core clock. Also note + * that grandparent clock are the parent clock of the core clock here. + */ + if (renesas_clk_is_mod(clk)) { + ret = gen3_clk_get_parent(priv, clk, info, &parent); + if (ret) { + printf("%s[%i] parent fail, ret=%i\n", __func__, __LINE__, ret); + return ret; + } + } else { + parent = *clk; }
if (renesas_clk_is_mod(&parent)) @@ -166,32 +169,47 @@ static int gen3_clk_setup_sdif_div(struct clk *clk, ulong rate) if (ret) return ret;
- if (core->type != CLK_TYPE_GEN3_SD) - return 0; + ret = renesas_clk_get_parent(&parent, info, &grandparent); + if (ret) { + printf("%s[%i] grandparent fail, ret=%i\n", __func__, __LINE__, ret); + return ret; + }
- debug("%s[%i] SDIF offset=%x\n", __func__, __LINE__, core->offset); + switch (core->type) { + case CLK_TYPE_GEN3_SDH: + fallthrough; + case CLK_TYPE_GEN4_SDH: + div = DIV_ROUND_CLOSEST(gen3_clk_get_rate64(&grandparent), rate); + value = rcar_clk_get_table_val(cpg_sdh_div_table, div); + if (value < 0) + return value;
- writel((rate == 400000000) ? 0x4 : 0x1, priv->base + core->offset); + clrsetbits_le32(priv->base + core->offset, + GENMASK(9, 2), value << 2);
- return 0; -} + debug("%s[%i] SDH clk: parent=%i offset=%x div=%u rate=%lu => val=%u\n", + __func__, __LINE__, core->parent, core->offset, div, rate, value); + break;
-static int gen3_clk_enable(struct clk *clk) -{ - struct gen3_clk_priv *priv = dev_get_priv(clk->dev); + case CLK_TYPE_GEN3_SD: + fallthrough; + case CLK_TYPE_GEN4_SD: + div = DIV_ROUND_CLOSEST(gen3_clk_get_rate64(&grandparent), rate); + value = rcar_clk_get_table_val(cpg_sd_div_table, div); + if (value < 0) + return value;
- return renesas_clk_endisable(clk, priv->base, priv->info, true); -} + clrsetbits_le32(priv->base + core->offset, + GENMASK(1, 0), value);
-static int gen3_clk_disable(struct clk *clk) -{ - struct gen3_clk_priv *priv = dev_get_priv(clk->dev); + debug("%s[%i] SD clk: parent=%i offset=%x div=%u rate=%lu => val=%u\n", + __func__, __LINE__, core->parent, core->offset, div, rate, value); + break; + }
- return renesas_clk_endisable(clk, priv->base, priv->info, false); + return 0; }
-static u64 gen3_clk_get_rate64(struct clk *clk); - static u64 gen3_clk_get_rate64_pll_mul_reg(struct gen3_clk_priv *priv, struct clk *parent, u32 mul_reg, u32 mult, u32 div, @@ -223,7 +241,7 @@ static u64 gen3_clk_get_rate64(struct clk *clk) priv->cpg_pll_config; u32 value, div; u64 rate = 0; - int i, ret; + int ret;
debug("%s[%i] Clock: id=%lu\n", __func__, __LINE__, clk->id);
@@ -328,28 +346,26 @@ static u64 gen3_clk_get_rate64(struct clk *clk) case CLK_TYPE_GEN3_SDH: /* Fixed factor 1:1 */ fallthrough; case CLK_TYPE_GEN4_SDH: /* Fixed factor 1:1 */ - return gen3_clk_get_rate64(&parent); + /* + * This takes STPnHCK and STPnCK bits into consideration + * in the table look up too, hence the inobvious GENMASK + * below. Bits [7:5] always read zero, so this is OKish. + */ + return rcar_clk_get_rate64_div_table(core->parent, + gen3_clk_get_rate64(&parent), + priv->base + core->offset, + CPG_SDCKCR_SRCFC_MASK | + GENMASK(9, 5), + cpg_sdh_div_table, "SDH");
- case CLK_TYPE_GEN3_SD: /* FIXME */ + case CLK_TYPE_GEN3_SD: fallthrough; case CLK_TYPE_GEN4_SD: - value = readl(priv->base + core->offset); - value &= CPG_SD_STP_MASK | CPG_SD_FC_MASK; - - for (i = 0; i < ARRAY_SIZE(cpg_sd_div_table); i++) { - if (cpg_sd_div_table[i].val != value) - continue; - - rate = gen3_clk_get_rate64(&parent) / - cpg_sd_div_table[i].div; - debug("%s[%i] SD clk: parent=%i div=%i => rate=%llu\n", - __func__, __LINE__, - core->parent, cpg_sd_div_table[i].div, rate); - - return rate; - } - - return -EINVAL; + return rcar_clk_get_rate64_div_table(core->parent, + gen3_clk_get_rate64(&parent), + priv->base + core->offset, + CPG_SDCKCR_FC_MASK, + cpg_sd_div_table, "SD");
case CLK_TYPE_GEN3_RPCSRC: return rcar_clk_get_rate64_div_table(core->parent, diff --git a/drivers/clk/renesas/rcar-gen3-cpg.h b/drivers/clk/renesas/rcar-gen3-cpg.h index 41a30c569c7..008e8928e59 100644 --- a/drivers/clk/renesas/rcar-gen3-cpg.h +++ b/drivers/clk/renesas/rcar-gen3-cpg.h @@ -111,6 +111,11 @@ struct rcar_gen3_cpg_pll_config {
#define CPG_RST_MODEMR 0x060
+#define CPG_SDCKCR_STPnHCK BIT(9) +#define CPG_SDCKCR_STPnCK BIT(8) +#define CPG_SDCKCR_SRCFC_MASK GENMASK(4, 2) +#define CPG_SDCKCR_FC_MASK GENMASK(1, 0) + #define CPG_RPCCKCR 0x238 #define CPG_RPCCKCR_DIV_POST_MASK GENMASK(4, 3) #define CPG_RPCCKCR_DIV_PRE_MASK GENMASK(2, 0) diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index f30d7847bf2..4a1accebfcb 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -358,13 +358,21 @@ static int renesas_sdhi_hs400(struct udevice *dev) struct mmc *mmc = mmc_get_mmc_dev(dev); bool hs400 = (mmc->selected_mode == MMC_HS_400); int ret, taps = hs400 ? priv->nrtaps : 8; + const u32 sdn_rate = 200000000; + u32 sdnh_rate = 800000000; unsigned long new_tap; u32 reg;
- if (taps == 4) /* HS400 on 4tap SoC needs different clock */ - ret = clk_set_rate(&priv->clk, 400000000); - else - ret = clk_set_rate(&priv->clk, 200000000); + if (clk_valid(&priv->clkh) && !priv->needs_clkh_fallback) { + /* HS400 on 4tap SoC => SDnH=400 MHz, SDn=200 MHz */ + if (taps == 4) + sdnh_rate /= 2; + ret = clk_set_rate(&priv->clkh, sdnh_rate); + if (ret < 0) + return ret; + } + + ret = clk_set_rate(&priv->clk, sdn_rate); if (ret < 0) return ret;
@@ -967,6 +975,11 @@ static int renesas_sdhi_probe(struct udevice *dev) return ret; }
+ /* optional SDnH clock */ + ret = clk_get_by_name(dev, "clkh", &priv->clkh); + if (ret < 0) + dev_dbg(dev, "failed to get clkh\n"); + /* set to max rate */ ret = clk_set_rate(&priv->clk, 200000000); if (ret < 0) { diff --git a/drivers/mmc/tmio-common.h b/drivers/mmc/tmio-common.h index e517ed978bf..88244e878b4 100644 --- a/drivers/mmc/tmio-common.h +++ b/drivers/mmc/tmio-common.h @@ -138,6 +138,7 @@ struct tmio_sd_priv { #endif #if CONFIG_IS_ENABLED(CLK) struct clk clk; + struct clk clkh; #endif #if CONFIG_IS_ENABLED(RENESAS_SDHI) unsigned int smpcmp;
participants (2)
-
Jaehoon Chung
-
Marek Vasut