2024-03-20 22:39:04

by Judith Mendez

[permalink] [raw]
Subject: [PATCH v5 0/7] Add tuning algorithm for delay chain

This patch series introduces a new tuning algorithm for
mmc. The new algorithm should be used when delay chain is
enabled. The ITAPDLY is selected from the largest passing
window and the buffer is not viewed as a circular buffer.
The new tuning algorithm is implemented as per the paper
published here [0] and has been tested on the following
platforms: AM62x SK, AM62A SK, AM62p SK, AM64x SK, and AM64x
EVM.

The series also includes a few fixes in the sdhci_am654
driver on OTAPDLYEN/ITAPDLYEN and ITAPDELSEL.

Changelog:
v4->v5:
- Add dll_enable = false
v3->v4:
- Add acked-by
- Remove extra newline
v2->v3:
- Remove fixes tags when not needed
- Fix return for tuning algorithm
- Fix ITAPDLY_LAST_INDEX
- Use reverse fir tree order for variable declarations
- Save all ITAPDLYENA changes in itap_del_ena[]
- Remove unnecessary parenthesis
- Remove unnecessary variables
- Save itapdlyena for HS400 timing
v1->v2:
- Remove unnecessary indentations and if/else in
sdhci_am654_calculate_itap
- Optimize sdhci_am654_calculate_itap()
- Call sdhci_am654_write_itapdly() in sdhci_am654_set_clock()
instead of sdhci_am654_setup_dll()
- Change otap_del_sel[], itap_del_sel[], and itap_del_ena[]
to type u32
- Revert unnecessary reformating in sdhci_am654_set_clock()
and sdhci_j721e_4bit_set_clock()

Judith Mendez (7):
mmc: sdhci_am654: Add tuning algorithm for delay chain
mmc: sdhci_am654: Write ITAPDLY for DDR52 timing
mmc: sdhci_am654: Add OTAP/ITAP delay enable
mmc: sdhci_am654: Fix itapdly/otapdly array type
mmc: sdhci_am654: Update comments in sdhci_am654_set_clock
mmc: sdhci_am654: Add ITAPDLYSEL in sdhci_j721e_4bit_set_clock
mmc: sdhci_am654: Fix ITAPDLY for HS400 timing

drivers/mmc/host/sdhci_am654.c | 176 ++++++++++++++++++++++++++-------
1 file changed, 138 insertions(+), 38 deletions(-)


base-commit: faf3b8014c357d71c7a9414302e217a1dd1679af
--
2.43.2



2024-03-20 22:39:17

by Judith Mendez

[permalink] [raw]
Subject: [PATCH v5 2/7] mmc: sdhci_am654: Write ITAPDLY for DDR52 timing

For DDR52 timing, DLL is enabled but tuning is not carried
out, therefore the ITAPDLY value in PHY CTRL 4 register is
not correct. Fix this by writing ITAPDLY after enabling DLL.

Fixes: a161c45f2979 ("mmc: sdhci_am654: Enable DLL only for some speed modes")
Signed-off-by: Judith Mendez <[email protected]>
Reviewed-by: Andrew Davis <[email protected]>
Acked-by: Adrian Hunter <[email protected]>
---
Changelog:
v4->v5:
- no change
---
drivers/mmc/host/sdhci_am654.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c
index d8c9821b0b66..cfb614d0b42b 100644
--- a/drivers/mmc/host/sdhci_am654.c
+++ b/drivers/mmc/host/sdhci_am654.c
@@ -300,6 +300,7 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock)
if (timing > MMC_TIMING_UHS_SDR25 && clock >= CLOCK_TOO_SLOW_HZ) {
sdhci_am654_setup_dll(host, clock);
sdhci_am654->dll_enable = true;
+ sdhci_am654_write_itapdly(sdhci_am654, sdhci_am654->itap_del_sel[timing]);
} else {
sdhci_am654_setup_delay_chain(sdhci_am654, timing);
sdhci_am654->dll_enable = false;
--
2.43.2


2024-03-20 22:39:18

by Judith Mendez

[permalink] [raw]
Subject: [PATCH v5 7/7] mmc: sdhci_am654: Fix ITAPDLY for HS400 timing

While STRB is currently used for DATA and CRC responses, the CMD
responses from the device to the host still require ITAPDLY for
HS400 timing.

Currently what is stored for HS400 is the ITAPDLY from High Speed
mode which is incorrect. The ITAPDLY for HS400 speed mode should
be the same as ITAPDLY as HS200 timing after tuning is executed.
Add the functionality to save ITAPDLY from HS200 tuning and save
as HS400 ITAPDLY.

Fixes: a161c45f2979 ("mmc: sdhci_am654: Enable DLL only for some speed modes")
Signed-off-by: Judith Mendez <[email protected]>
Acked-by: Adrian Hunter <[email protected]>
---
Changelog:
v4->v5:
- no change
---
drivers/mmc/host/sdhci_am654.c | 9 +++++++++
1 file changed, 9 insertions(+)

diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c
index 53d538b767ac..ba36123e4ccc 100644
--- a/drivers/mmc/host/sdhci_am654.c
+++ b/drivers/mmc/host/sdhci_am654.c
@@ -301,6 +301,12 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock)
if (timing > MMC_TIMING_UHS_SDR25 && clock >= CLOCK_TOO_SLOW_HZ) {
sdhci_am654_setup_dll(host, clock);
sdhci_am654->dll_enable = true;
+
+ if (timing == MMC_TIMING_MMC_HS400) {
+ sdhci_am654->itap_del_ena[timing] = 0x1;
+ sdhci_am654->itap_del_sel[timing] = sdhci_am654->itap_del_sel[timing - 1];
+ }
+
sdhci_am654_write_itapdly(sdhci_am654, sdhci_am654->itap_del_sel[timing],
sdhci_am654->itap_del_ena[timing]);
} else {
@@ -531,6 +537,9 @@ static int sdhci_am654_platform_execute_tuning(struct sdhci_host *host,

sdhci_am654_write_itapdly(sdhci_am654, itap, sdhci_am654->itap_del_ena[timing]);

+ /* Save ITAPDLY */
+ sdhci_am654->itap_del_sel[timing] = itap;
+
return 0;
}

--
2.43.2


2024-03-20 22:40:03

by Judith Mendez

[permalink] [raw]
Subject: [PATCH v5 6/7] mmc: sdhci_am654: Add ITAPDLYSEL in sdhci_j721e_4bit_set_clock

Add ITAPDLYSEL to sdhci_j721e_4bit_set_clock function.
This allows to set the correct ITAPDLY for timings that
do not carry out tuning.

Fixes: 1accbced1c32 ("mmc: sdhci_am654: Add Support for 4 bit IP on J721E")
Signed-off-by: Judith Mendez <[email protected]>
Acked-by: Adrian Hunter <[email protected]>
---
Changelog:
v4->v5:
- no change
---
drivers/mmc/host/sdhci_am654.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c
index 119e41005342..53d538b767ac 100644
--- a/drivers/mmc/host/sdhci_am654.c
+++ b/drivers/mmc/host/sdhci_am654.c
@@ -320,6 +320,7 @@ static void sdhci_j721e_4bit_set_clock(struct sdhci_host *host,
unsigned char timing = host->mmc->ios.timing;
u32 otap_del_sel;
u32 itap_del_ena;
+ u32 itap_del_sel;
u32 mask, val;

/* Setup Output TAP delay */
@@ -329,13 +330,18 @@ static void sdhci_j721e_4bit_set_clock(struct sdhci_host *host,
val = (0x1 << OTAPDLYENA_SHIFT) |
(otap_del_sel << OTAPDLYSEL_SHIFT);

+ /* Setup Input TAP delay */
itap_del_ena = sdhci_am654->itap_del_ena[timing];
+ itap_del_sel = sdhci_am654->itap_del_sel[timing];

- mask |= ITAPDLYENA_MASK;
- val |= (itap_del_ena << ITAPDLYENA_SHIFT);
+ mask |= ITAPDLYENA_MASK | ITAPDLYSEL_MASK;
+ val |= (itap_del_ena << ITAPDLYENA_SHIFT) |
+ (itap_del_sel << ITAPDLYSEL_SHIFT);

+ regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPCHGWIN_MASK,
+ 1 << ITAPCHGWIN_SHIFT);
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val);
-
+ regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPCHGWIN_MASK, 0);
regmap_update_bits(sdhci_am654->base, PHY_CTRL5, CLKBUFSEL_MASK,
sdhci_am654->clkbuf_sel);

--
2.43.2


2024-03-20 22:40:05

by Judith Mendez

[permalink] [raw]
Subject: [PATCH v5 4/7] mmc: sdhci_am654: Fix itapdly/otapdly array type

While integer type works, the otap_del_sel and itap_del_sel
arrays are manipulated as u32, so change array types to u32.

Signed-off-by: Judith Mendez <[email protected]>
Acked-by: Adrian Hunter <[email protected]>
---
Changelog:
v4->v5:
- no change
---
drivers/mmc/host/sdhci_am654.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c
index 888bfda0ebc0..ebef68308fd8 100644
--- a/drivers/mmc/host/sdhci_am654.c
+++ b/drivers/mmc/host/sdhci_am654.c
@@ -141,8 +141,8 @@ static const struct timing_data td[] = {

struct sdhci_am654_data {
struct regmap *base;
- int otap_del_sel[ARRAY_SIZE(td)];
- int itap_del_sel[ARRAY_SIZE(td)];
+ u32 otap_del_sel[ARRAY_SIZE(td)];
+ u32 itap_del_sel[ARRAY_SIZE(td)];
u32 itap_del_ena[ARRAY_SIZE(td)];
int clkbuf_sel;
int trm_icp;
--
2.43.2


2024-03-20 22:40:23

by Judith Mendez

[permalink] [raw]
Subject: [PATCH v5 1/7] mmc: sdhci_am654: Add tuning algorithm for delay chain

Currently the sdhci_am654 driver only supports one tuning
algorithm which should be used only when DLL is enabled. The
ITAPDLY is selected from the largest passing window and the
buffer is viewed as a circular buffer.

The new algorithm should be used when the delay chain
is enabled. The ITAPDLY is selected from the largest passing
window and the buffer is not viewed as a circular buffer.

This implementation is based off of the following paper: [1].

Also add support for multiple failing windows.

[1] https://www.ti.com/lit/an/spract9/spract9.pdf

Fixes: 13ebeae68ac9 ("mmc: sdhci_am654: Add support for software tuning")
Signed-off-by: Judith Mendez <[email protected]>
Acked-by: Adrian Hunter <[email protected]>
---
Changelog:
v4->v5:
- Add dll_enable = false
---
drivers/mmc/host/sdhci_am654.c | 112 +++++++++++++++++++++++++++------
1 file changed, 92 insertions(+), 20 deletions(-)

diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c
index d659c59422e1..d8c9821b0b66 100644
--- a/drivers/mmc/host/sdhci_am654.c
+++ b/drivers/mmc/host/sdhci_am654.c
@@ -149,10 +149,17 @@ struct sdhci_am654_data {
int strb_sel;
u32 flags;
u32 quirks;
+ bool dll_enable;

#define SDHCI_AM654_QUIRK_FORCE_CDTEST BIT(0)
};

+struct window {
+ u8 start;
+ u8 end;
+ u8 length;
+};
+
struct sdhci_am654_driver_data {
const struct sdhci_pltfm_data *pdata;
u32 flags;
@@ -290,10 +297,13 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock)

regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val);

- if (timing > MMC_TIMING_UHS_SDR25 && clock >= CLOCK_TOO_SLOW_HZ)
+ if (timing > MMC_TIMING_UHS_SDR25 && clock >= CLOCK_TOO_SLOW_HZ) {
sdhci_am654_setup_dll(host, clock);
- else
+ sdhci_am654->dll_enable = true;
+ } else {
sdhci_am654_setup_delay_chain(sdhci_am654, timing);
+ sdhci_am654->dll_enable = false;
+ }

regmap_update_bits(sdhci_am654->base, PHY_CTRL5, CLKBUFSEL_MASK,
sdhci_am654->clkbuf_sel);
@@ -408,39 +418,101 @@ static u32 sdhci_am654_cqhci_irq(struct sdhci_host *host, u32 intmask)
return 0;
}

-#define ITAP_MAX 32
+#define ITAPDLY_LENGTH 32
+#define ITAPDLY_LAST_INDEX (ITAPDLY_LENGTH - 1)
+
+static u32 sdhci_am654_calculate_itap(struct sdhci_host *host, struct window
+ *fail_window, u8 num_fails, bool circular_buffer)
+{
+ u8 itap = 0, start_fail = 0, end_fail = 0, pass_length = 0;
+ u8 first_fail_start = 0, last_fail_end = 0;
+ struct device *dev = mmc_dev(host->mmc);
+ struct window pass_window = {0, 0, 0};
+ int prev_fail_end = -1;
+ u8 i;
+
+ if (!num_fails)
+ return ITAPDLY_LAST_INDEX >> 1;
+
+ if (fail_window->length == ITAPDLY_LENGTH) {
+ dev_err(dev, "No passing ITAPDLY, return 0\n");
+ return 0;
+ }
+
+ first_fail_start = fail_window->start;
+ last_fail_end = fail_window[num_fails - 1].end;
+
+ for (i = 0; i < num_fails; i++) {
+ start_fail = fail_window[i].start;
+ end_fail = fail_window[i].end;
+ pass_length = start_fail - (prev_fail_end + 1);
+
+ if (pass_length > pass_window.length) {
+ pass_window.start = prev_fail_end + 1;
+ pass_window.length = pass_length;
+ }
+ prev_fail_end = end_fail;
+ }
+
+ if (!circular_buffer)
+ pass_length = ITAPDLY_LAST_INDEX - last_fail_end;
+ else
+ pass_length = ITAPDLY_LAST_INDEX - last_fail_end + first_fail_start;
+
+ if (pass_length > pass_window.length) {
+ pass_window.start = last_fail_end + 1;
+ pass_window.length = pass_length;
+ }
+
+ if (!circular_buffer)
+ itap = pass_window.start + (pass_window.length >> 1);
+ else
+ itap = (pass_window.start + (pass_window.length >> 1)) % ITAPDLY_LENGTH;
+
+ return (itap > ITAPDLY_LAST_INDEX) ? ITAPDLY_LAST_INDEX >> 1 : itap;
+}
+
static int sdhci_am654_platform_execute_tuning(struct sdhci_host *host,
u32 opcode)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
- int cur_val, prev_val = 1, fail_len = 0, pass_window = 0, pass_len;
- u32 itap;
+ struct window fail_window[ITAPDLY_LENGTH];
+ u8 curr_pass, itap;
+ u8 fail_index = 0;
+ u8 prev_pass = 1;
+
+ memset(fail_window, 0, sizeof(fail_window));

/* Enable ITAPDLY */
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPDLYENA_MASK,
1 << ITAPDLYENA_SHIFT);

- for (itap = 0; itap < ITAP_MAX; itap++) {
+ for (itap = 0; itap < ITAPDLY_LENGTH; itap++) {
sdhci_am654_write_itapdly(sdhci_am654, itap);

- cur_val = !mmc_send_tuning(host->mmc, opcode, NULL);
- if (cur_val && !prev_val)
- pass_window = itap;
+ curr_pass = !mmc_send_tuning(host->mmc, opcode, NULL);

- if (!cur_val)
- fail_len++;
+ if (!curr_pass && prev_pass)
+ fail_window[fail_index].start = itap;

- prev_val = cur_val;
+ if (!curr_pass) {
+ fail_window[fail_index].end = itap;
+ fail_window[fail_index].length++;
+ }
+
+ if (curr_pass && !prev_pass)
+ fail_index++;
+
+ prev_pass = curr_pass;
}
- /*
- * Having determined the length of the failing window and start of
- * the passing window calculate the length of the passing window and
- * set the final value halfway through it considering the range as a
- * circular buffer
- */
- pass_len = ITAP_MAX - fail_len;
- itap = (pass_window + (pass_len >> 1)) % ITAP_MAX;
+
+ if (fail_window[fail_index].length != 0)
+ fail_index++;
+
+ itap = sdhci_am654_calculate_itap(host, fail_window, fail_index,
+ sdhci_am654->dll_enable);
+
sdhci_am654_write_itapdly(sdhci_am654, itap);

return 0;
--
2.43.2


2024-03-25 15:57:08

by Ulf Hansson

[permalink] [raw]
Subject: Re: [PATCH v5 0/7] Add tuning algorithm for delay chain

On Wed, 20 Mar 2024 at 23:38, Judith Mendez <[email protected]> wrote:
>
> This patch series introduces a new tuning algorithm for
> mmc. The new algorithm should be used when delay chain is
> enabled. The ITAPDLY is selected from the largest passing
> window and the buffer is not viewed as a circular buffer.
> The new tuning algorithm is implemented as per the paper
> published here [0] and has been tested on the following
> platforms: AM62x SK, AM62A SK, AM62p SK, AM64x SK, and AM64x
> EVM.
>
> The series also includes a few fixes in the sdhci_am654
> driver on OTAPDLYEN/ITAPDLYEN and ITAPDELSEL.
>
> Changelog:
> v4->v5:
> - Add dll_enable = false
> v3->v4:
> - Add acked-by
> - Remove extra newline
> v2->v3:
> - Remove fixes tags when not needed
> - Fix return for tuning algorithm
> - Fix ITAPDLY_LAST_INDEX
> - Use reverse fir tree order for variable declarations
> - Save all ITAPDLYENA changes in itap_del_ena[]
> - Remove unnecessary parenthesis
> - Remove unnecessary variables
> - Save itapdlyena for HS400 timing
> v1->v2:
> - Remove unnecessary indentations and if/else in
> sdhci_am654_calculate_itap
> - Optimize sdhci_am654_calculate_itap()
> - Call sdhci_am654_write_itapdly() in sdhci_am654_set_clock()
> instead of sdhci_am654_setup_dll()
> - Change otap_del_sel[], itap_del_sel[], and itap_del_ena[]
> to type u32
> - Revert unnecessary reformating in sdhci_am654_set_clock()
> and sdhci_j721e_4bit_set_clock()
>
> Judith Mendez (7):
> mmc: sdhci_am654: Add tuning algorithm for delay chain
> mmc: sdhci_am654: Write ITAPDLY for DDR52 timing
> mmc: sdhci_am654: Add OTAP/ITAP delay enable
> mmc: sdhci_am654: Fix itapdly/otapdly array type
> mmc: sdhci_am654: Update comments in sdhci_am654_set_clock
> mmc: sdhci_am654: Add ITAPDLYSEL in sdhci_j721e_4bit_set_clock
> mmc: sdhci_am654: Fix ITAPDLY for HS400 timing
>
> drivers/mmc/host/sdhci_am654.c | 176 ++++++++++++++++++++++++++-------
> 1 file changed, 138 insertions(+), 38 deletions(-)
>

It's a bit unclear to me whether this series is actually fixing a
regression or whether it should be considered as improvements for the
tuning logic. For now, I decided that it looks like the latter (please
tell me if you don't agree). That said, the series is applied for
*next*, but I also took the liberty of re-ordering the patches, so
those without a fixes tag comes last.

Thanks and kind regards
Uffe