* [PATCH v5 1/9] memory: ti-aemif: Store timings parameter in number of cycles - 1
2024-12-04 9:43 [PATCH v5 0/9] Implement setup_interface() in the DaVinci NAND controller Bastien Curutchet
@ 2024-12-04 9:43 ` Bastien Curutchet
2024-12-04 9:43 ` [PATCH v5 2/9] memory: ti-aemif: Remove unnecessary local variables Bastien Curutchet
` (8 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Bastien Curutchet @ 2024-12-04 9:43 UTC (permalink / raw)
To: Santosh Shilimkar, Krzysztof Kozlowski, Miquel Raynal,
Richard Weinberger, Vignesh Raghavendra
Cc: linux-kernel, linux-mtd, Thomas Petazzoni, Herve Codina,
Christopher Cordahi, Bastien Curutchet
The CS configuration register expects timings to be expressed in
'number of cycles - 1' but they are stored in ns in the struct
aemif_cs_data. So at init, the timings currently set are converted to ns
by aemif_get_hw_params(), updated with values from the device-tree
properties, and then converted back to 'number of cycles - 1' before
being applied.
Store the timings directly in 'number of cycles - 1' instead of
nanoseconds.
Perform the conversion from nanosecond during the device-tree parsing.
Remove aemif_cycles_to_nsec() as it isn't used anymore.
Signed-off-by: Bastien Curutchet <bastien.curutchet@bootlin.com>
Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/memory/ti-aemif.c | 135 ++++++++++++++++++++++----------------
1 file changed, 79 insertions(+), 56 deletions(-)
diff --git a/drivers/memory/ti-aemif.c b/drivers/memory/ti-aemif.c
index d54dc3cfff73..f23a549b219b 100644
--- a/drivers/memory/ti-aemif.c
+++ b/drivers/memory/ti-aemif.c
@@ -82,26 +82,26 @@
/**
* struct aemif_cs_data: structure to hold cs parameters
* @cs: chip-select number
- * @wstrobe: write strobe width, ns
- * @rstrobe: read strobe width, ns
- * @wsetup: write setup width, ns
- * @whold: write hold width, ns
- * @rsetup: read setup width, ns
- * @rhold: read hold width, ns
- * @ta: minimum turn around time, ns
+ * @wstrobe: write strobe width, number of cycles - 1
+ * @rstrobe: read strobe width, number of cycles - 1
+ * @wsetup: write setup width, number of cycles - 1
+ * @whold: write hold width, number of cycles - 1
+ * @rsetup: read setup width, number of cycles - 1
+ * @rhold: read hold width, number of cycles - 1
+ * @ta: minimum turn around time, number of cycles - 1
* @enable_ss: enable/disable select strobe mode
* @enable_ew: enable/disable extended wait mode
* @asize: width of the asynchronous device's data bus
*/
struct aemif_cs_data {
u8 cs;
- u16 wstrobe;
- u16 rstrobe;
- u8 wsetup;
- u8 whold;
- u8 rsetup;
- u8 rhold;
- u8 ta;
+ u32 wstrobe;
+ u32 rstrobe;
+ u32 wsetup;
+ u32 whold;
+ u32 rsetup;
+ u32 rhold;
+ u32 ta;
u8 enable_ss;
u8 enable_ew;
u8 asize;
@@ -175,26 +175,18 @@ static int aemif_config_abus(struct platform_device *pdev, int csnum)
struct aemif_device *aemif = platform_get_drvdata(pdev);
struct aemif_cs_data *data = &aemif->cs_data[csnum];
int ta, rhold, rstrobe, rsetup, whold, wstrobe, wsetup;
- unsigned long clk_rate = aemif->clk_rate;
unsigned offset;
u32 set, val;
offset = A1CR_OFFSET + (data->cs - aemif->cs_offset) * 4;
- ta = aemif_calc_rate(pdev, data->ta, clk_rate, TA_MAX);
- rhold = aemif_calc_rate(pdev, data->rhold, clk_rate, RHOLD_MAX);
- rstrobe = aemif_calc_rate(pdev, data->rstrobe, clk_rate, RSTROBE_MAX);
- rsetup = aemif_calc_rate(pdev, data->rsetup, clk_rate, RSETUP_MAX);
- whold = aemif_calc_rate(pdev, data->whold, clk_rate, WHOLD_MAX);
- wstrobe = aemif_calc_rate(pdev, data->wstrobe, clk_rate, WSTROBE_MAX);
- wsetup = aemif_calc_rate(pdev, data->wsetup, clk_rate, WSETUP_MAX);
-
- if (ta < 0 || rhold < 0 || rstrobe < 0 || rsetup < 0 ||
- whold < 0 || wstrobe < 0 || wsetup < 0) {
- dev_err(&pdev->dev, "%s: cannot get suitable timings\n",
- __func__);
- return -EINVAL;
- }
+ ta = data->ta;
+ rhold = data->rhold;
+ rstrobe = data->rstrobe;
+ rsetup = data->rsetup;
+ whold = data->whold;
+ wstrobe = data->wstrobe;
+ wsetup = data->wsetup;
set = TA(ta) | RHOLD(rhold) | RSTROBE(rstrobe) | RSETUP(rsetup) |
WHOLD(whold) | WSTROBE(wstrobe) | WSETUP(wsetup);
@@ -213,11 +205,6 @@ static int aemif_config_abus(struct platform_device *pdev, int csnum)
return 0;
}
-static inline int aemif_cycles_to_nsec(int val, unsigned long clk_rate)
-{
- return ((val + 1) * NSEC_PER_MSEC) / clk_rate;
-}
-
/**
* aemif_get_hw_params - function to read hw register values
* @pdev: platform device to read for
@@ -231,19 +218,18 @@ static void aemif_get_hw_params(struct platform_device *pdev, int csnum)
{
struct aemif_device *aemif = platform_get_drvdata(pdev);
struct aemif_cs_data *data = &aemif->cs_data[csnum];
- unsigned long clk_rate = aemif->clk_rate;
u32 val, offset;
offset = A1CR_OFFSET + (data->cs - aemif->cs_offset) * 4;
val = readl(aemif->base + offset);
- data->ta = aemif_cycles_to_nsec(TA_VAL(val), clk_rate);
- data->rhold = aemif_cycles_to_nsec(RHOLD_VAL(val), clk_rate);
- data->rstrobe = aemif_cycles_to_nsec(RSTROBE_VAL(val), clk_rate);
- data->rsetup = aemif_cycles_to_nsec(RSETUP_VAL(val), clk_rate);
- data->whold = aemif_cycles_to_nsec(WHOLD_VAL(val), clk_rate);
- data->wstrobe = aemif_cycles_to_nsec(WSTROBE_VAL(val), clk_rate);
- data->wsetup = aemif_cycles_to_nsec(WSETUP_VAL(val), clk_rate);
+ data->ta = TA_VAL(val);
+ data->rhold = RHOLD_VAL(val);
+ data->rstrobe = RSTROBE_VAL(val);
+ data->rsetup = RSETUP_VAL(val);
+ data->whold = WHOLD_VAL(val);
+ data->wstrobe = WSTROBE_VAL(val);
+ data->wsetup = WSETUP_VAL(val);
data->enable_ew = EW_VAL(val);
data->enable_ss = SSTROBE_VAL(val);
data->asize = val & ASIZE_MAX;
@@ -261,7 +247,9 @@ static int of_aemif_parse_abus_config(struct platform_device *pdev,
struct device_node *np)
{
struct aemif_device *aemif = platform_get_drvdata(pdev);
+ unsigned long clk_rate = aemif->clk_rate;
struct aemif_cs_data *data;
+ int ret;
u32 cs;
u32 val;
@@ -287,26 +275,61 @@ static int of_aemif_parse_abus_config(struct platform_device *pdev,
aemif_get_hw_params(pdev, aemif->num_cs++);
/* override the values from device node */
- if (!of_property_read_u32(np, "ti,cs-min-turnaround-ns", &val))
- data->ta = val;
+ if (!of_property_read_u32(np, "ti,cs-min-turnaround-ns", &val)) {
+ ret = aemif_calc_rate(pdev, val, clk_rate, TA_MAX);
+ if (ret < 0)
+ return ret;
- if (!of_property_read_u32(np, "ti,cs-read-hold-ns", &val))
- data->rhold = val;
+ data->ta = ret;
+ }
- if (!of_property_read_u32(np, "ti,cs-read-strobe-ns", &val))
- data->rstrobe = val;
+ if (!of_property_read_u32(np, "ti,cs-read-hold-ns", &val)) {
+ ret = aemif_calc_rate(pdev, val, clk_rate, RHOLD_MAX);
+ if (ret < 0)
+ return ret;
- if (!of_property_read_u32(np, "ti,cs-read-setup-ns", &val))
- data->rsetup = val;
+ data->rhold = ret;
+ }
- if (!of_property_read_u32(np, "ti,cs-write-hold-ns", &val))
- data->whold = val;
+ if (!of_property_read_u32(np, "ti,cs-read-strobe-ns", &val)) {
+ ret = aemif_calc_rate(pdev, val, clk_rate, RSTROBE_MAX);
+ if (ret < 0)
+ return ret;
- if (!of_property_read_u32(np, "ti,cs-write-strobe-ns", &val))
- data->wstrobe = val;
+ data->rstrobe = ret;
+ }
- if (!of_property_read_u32(np, "ti,cs-write-setup-ns", &val))
- data->wsetup = val;
+ if (!of_property_read_u32(np, "ti,cs-read-setup-ns", &val)) {
+ ret = aemif_calc_rate(pdev, val, clk_rate, RSETUP_MAX);
+ if (ret < 0)
+ return ret;
+
+ data->rsetup = ret;
+ }
+
+ if (!of_property_read_u32(np, "ti,cs-write-hold-ns", &val)) {
+ ret = aemif_calc_rate(pdev, val, clk_rate, WHOLD_MAX);
+ if (ret < 0)
+ return ret;
+
+ data->whold = ret;
+ }
+
+ if (!of_property_read_u32(np, "ti,cs-write-strobe-ns", &val)) {
+ ret = aemif_calc_rate(pdev, val, clk_rate, WSTROBE_MAX);
+ if (ret < 0)
+ return ret;
+
+ data->wstrobe = ret;
+ }
+
+ if (!of_property_read_u32(np, "ti,cs-write-setup-ns", &val)) {
+ ret = aemif_calc_rate(pdev, val, clk_rate, WSETUP_MAX);
+ if (ret < 0)
+ return ret;
+
+ data->wsetup = ret;
+ }
if (!of_property_read_u32(np, "ti,cs-bus-width", &val))
if (val == 16)
--
2.47.0
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v5 2/9] memory: ti-aemif: Remove unnecessary local variables
2024-12-04 9:43 [PATCH v5 0/9] Implement setup_interface() in the DaVinci NAND controller Bastien Curutchet
2024-12-04 9:43 ` [PATCH v5 1/9] memory: ti-aemif: Store timings parameter in number of cycles - 1 Bastien Curutchet
@ 2024-12-04 9:43 ` Bastien Curutchet
2024-12-04 9:43 ` [PATCH v5 3/9] memory: ti-aemif: Wrap CS timings into a struct Bastien Curutchet
` (7 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Bastien Curutchet @ 2024-12-04 9:43 UTC (permalink / raw)
To: Santosh Shilimkar, Krzysztof Kozlowski, Miquel Raynal,
Richard Weinberger, Vignesh Raghavendra
Cc: linux-kernel, linux-mtd, Thomas Petazzoni, Herve Codina,
Christopher Cordahi, Bastien Curutchet
CS timings are copied to local variables that are then used as is,
without any modifications.
Remove these unneeded local variables and deal directly with the timings
stored in the struct aemif_cs_data.
Signed-off-by: Bastien Curutchet <bastien.curutchet@bootlin.com>
Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/memory/ti-aemif.c | 14 +++-----------
1 file changed, 3 insertions(+), 11 deletions(-)
diff --git a/drivers/memory/ti-aemif.c b/drivers/memory/ti-aemif.c
index f23a549b219b..a0e1a6b53256 100644
--- a/drivers/memory/ti-aemif.c
+++ b/drivers/memory/ti-aemif.c
@@ -174,22 +174,14 @@ static int aemif_config_abus(struct platform_device *pdev, int csnum)
{
struct aemif_device *aemif = platform_get_drvdata(pdev);
struct aemif_cs_data *data = &aemif->cs_data[csnum];
- int ta, rhold, rstrobe, rsetup, whold, wstrobe, wsetup;
unsigned offset;
u32 set, val;
offset = A1CR_OFFSET + (data->cs - aemif->cs_offset) * 4;
- ta = data->ta;
- rhold = data->rhold;
- rstrobe = data->rstrobe;
- rsetup = data->rsetup;
- whold = data->whold;
- wstrobe = data->wstrobe;
- wsetup = data->wsetup;
-
- set = TA(ta) | RHOLD(rhold) | RSTROBE(rstrobe) | RSETUP(rsetup) |
- WHOLD(whold) | WSTROBE(wstrobe) | WSETUP(wsetup);
+ set = TA(data->ta) |
+ RHOLD(data->rhold) | RSTROBE(data->rstrobe) | RSETUP(data->rsetup) |
+ WHOLD(data->whold) | WSTROBE(data->wstrobe) | WSETUP(data->wsetup);
set |= (data->asize & ACR_ASIZE_MASK);
if (data->enable_ew)
--
2.47.0
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v5 3/9] memory: ti-aemif: Wrap CS timings into a struct
2024-12-04 9:43 [PATCH v5 0/9] Implement setup_interface() in the DaVinci NAND controller Bastien Curutchet
2024-12-04 9:43 ` [PATCH v5 1/9] memory: ti-aemif: Store timings parameter in number of cycles - 1 Bastien Curutchet
2024-12-04 9:43 ` [PATCH v5 2/9] memory: ti-aemif: Remove unnecessary local variables Bastien Curutchet
@ 2024-12-04 9:43 ` Bastien Curutchet
2024-12-04 9:43 ` [PATCH v5 4/9] memory: ti-aemif: Create aemif_check_cs_timings() Bastien Curutchet
` (6 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Bastien Curutchet @ 2024-12-04 9:43 UTC (permalink / raw)
To: Santosh Shilimkar, Krzysztof Kozlowski, Miquel Raynal,
Richard Weinberger, Vignesh Raghavendra
Cc: linux-kernel, linux-mtd, Thomas Petazzoni, Herve Codina,
Christopher Cordahi, Bastien Curutchet
CS timings are store in the struct aemif_cs_data along with other CS
parameters. It isn't convenient for exposing CS timings to other drivers
without also exposing the other parameters.
Wrap the CS timings in a new struct aemif_cs_timings to simplify their
export in upcoming patches.
Signed-off-by: Bastien Curutchet <bastien.curutchet@bootlin.com>
Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/memory/ti-aemif.c | 57 ++++++++++++++++++++++-----------------
1 file changed, 33 insertions(+), 24 deletions(-)
diff --git a/drivers/memory/ti-aemif.c b/drivers/memory/ti-aemif.c
index a0e1a6b53256..1d1b30112af5 100644
--- a/drivers/memory/ti-aemif.c
+++ b/drivers/memory/ti-aemif.c
@@ -80,8 +80,7 @@
ASIZE_MAX)
/**
- * struct aemif_cs_data: structure to hold cs parameters
- * @cs: chip-select number
+ * struct aemif_cs_timings: structure to hold CS timings
* @wstrobe: write strobe width, number of cycles - 1
* @rstrobe: read strobe width, number of cycles - 1
* @wsetup: write setup width, number of cycles - 1
@@ -89,12 +88,8 @@
* @rsetup: read setup width, number of cycles - 1
* @rhold: read hold width, number of cycles - 1
* @ta: minimum turn around time, number of cycles - 1
- * @enable_ss: enable/disable select strobe mode
- * @enable_ew: enable/disable extended wait mode
- * @asize: width of the asynchronous device's data bus
*/
-struct aemif_cs_data {
- u8 cs;
+struct aemif_cs_timings {
u32 wstrobe;
u32 rstrobe;
u32 wsetup;
@@ -102,6 +97,19 @@ struct aemif_cs_data {
u32 rsetup;
u32 rhold;
u32 ta;
+};
+
+/**
+ * struct aemif_cs_data: structure to hold CS parameters
+ * @timings: timings configuration
+ * @cs: chip-select number
+ * @enable_ss: enable/disable select strobe mode
+ * @enable_ew: enable/disable extended wait mode
+ * @asize: width of the asynchronous device's data bus
+ */
+struct aemif_cs_data {
+ struct aemif_cs_timings timings;
+ u8 cs;
u8 enable_ss;
u8 enable_ew;
u8 asize;
@@ -179,9 +187,10 @@ static int aemif_config_abus(struct platform_device *pdev, int csnum)
offset = A1CR_OFFSET + (data->cs - aemif->cs_offset) * 4;
- set = TA(data->ta) |
- RHOLD(data->rhold) | RSTROBE(data->rstrobe) | RSETUP(data->rsetup) |
- WHOLD(data->whold) | WSTROBE(data->wstrobe) | WSETUP(data->wsetup);
+ set = TA(data->timings.ta) |
+ RHOLD(data->timings.rhold) | RSTROBE(data->timings.rstrobe) |
+ RSETUP(data->timings.rsetup) | WHOLD(data->timings.whold) |
+ WSTROBE(data->timings.wstrobe) | WSETUP(data->timings.wsetup);
set |= (data->asize & ACR_ASIZE_MASK);
if (data->enable_ew)
@@ -215,13 +224,13 @@ static void aemif_get_hw_params(struct platform_device *pdev, int csnum)
offset = A1CR_OFFSET + (data->cs - aemif->cs_offset) * 4;
val = readl(aemif->base + offset);
- data->ta = TA_VAL(val);
- data->rhold = RHOLD_VAL(val);
- data->rstrobe = RSTROBE_VAL(val);
- data->rsetup = RSETUP_VAL(val);
- data->whold = WHOLD_VAL(val);
- data->wstrobe = WSTROBE_VAL(val);
- data->wsetup = WSETUP_VAL(val);
+ data->timings.ta = TA_VAL(val);
+ data->timings.rhold = RHOLD_VAL(val);
+ data->timings.rstrobe = RSTROBE_VAL(val);
+ data->timings.rsetup = RSETUP_VAL(val);
+ data->timings.whold = WHOLD_VAL(val);
+ data->timings.wstrobe = WSTROBE_VAL(val);
+ data->timings.wsetup = WSETUP_VAL(val);
data->enable_ew = EW_VAL(val);
data->enable_ss = SSTROBE_VAL(val);
data->asize = val & ASIZE_MAX;
@@ -272,7 +281,7 @@ static int of_aemif_parse_abus_config(struct platform_device *pdev,
if (ret < 0)
return ret;
- data->ta = ret;
+ data->timings.ta = ret;
}
if (!of_property_read_u32(np, "ti,cs-read-hold-ns", &val)) {
@@ -280,7 +289,7 @@ static int of_aemif_parse_abus_config(struct platform_device *pdev,
if (ret < 0)
return ret;
- data->rhold = ret;
+ data->timings.rhold = ret;
}
if (!of_property_read_u32(np, "ti,cs-read-strobe-ns", &val)) {
@@ -288,7 +297,7 @@ static int of_aemif_parse_abus_config(struct platform_device *pdev,
if (ret < 0)
return ret;
- data->rstrobe = ret;
+ data->timings.rstrobe = ret;
}
if (!of_property_read_u32(np, "ti,cs-read-setup-ns", &val)) {
@@ -296,7 +305,7 @@ static int of_aemif_parse_abus_config(struct platform_device *pdev,
if (ret < 0)
return ret;
- data->rsetup = ret;
+ data->timings.rsetup = ret;
}
if (!of_property_read_u32(np, "ti,cs-write-hold-ns", &val)) {
@@ -304,7 +313,7 @@ static int of_aemif_parse_abus_config(struct platform_device *pdev,
if (ret < 0)
return ret;
- data->whold = ret;
+ data->timings.whold = ret;
}
if (!of_property_read_u32(np, "ti,cs-write-strobe-ns", &val)) {
@@ -312,7 +321,7 @@ static int of_aemif_parse_abus_config(struct platform_device *pdev,
if (ret < 0)
return ret;
- data->wstrobe = ret;
+ data->timings.wstrobe = ret;
}
if (!of_property_read_u32(np, "ti,cs-write-setup-ns", &val)) {
@@ -320,7 +329,7 @@ static int of_aemif_parse_abus_config(struct platform_device *pdev,
if (ret < 0)
return ret;
- data->wsetup = ret;
+ data->timings.wsetup = ret;
}
if (!of_property_read_u32(np, "ti,cs-bus-width", &val))
--
2.47.0
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v5 4/9] memory: ti-aemif: Create aemif_check_cs_timings()
2024-12-04 9:43 [PATCH v5 0/9] Implement setup_interface() in the DaVinci NAND controller Bastien Curutchet
` (2 preceding siblings ...)
2024-12-04 9:43 ` [PATCH v5 3/9] memory: ti-aemif: Wrap CS timings into a struct Bastien Curutchet
@ 2024-12-04 9:43 ` Bastien Curutchet
2024-12-04 9:43 ` [PATCH v5 5/9] memory: ti-aemif: Create aemif_set_cs_timings() Bastien Curutchet
` (5 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Bastien Curutchet @ 2024-12-04 9:43 UTC (permalink / raw)
To: Santosh Shilimkar, Krzysztof Kozlowski, Miquel Raynal,
Richard Weinberger, Vignesh Raghavendra
Cc: linux-kernel, linux-mtd, Thomas Petazzoni, Herve Codina,
Christopher Cordahi, Bastien Curutchet
aemif_calc_rate() checks the validity of a new computed timing against a
'max' value given as input. This isn't convenient if we want to check
the CS timing configuration somewhere else in the code.
Wrap the verification of all the chip select's timing configuration into a
single function to ease its exportation in upcoming patches.
Remove the validity check from aemif_calc_rate(). Also remove the no
longer used 'max' input and change the return type to u32.
Remove the check of the aemif_calc_rate()'s return value during
device-tree parsing as aemif_calc_rate() can't fail anymore.
Signed-off-by: Bastien Curutchet <bastien.curutchet@bootlin.com>
Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/memory/ti-aemif.c | 111 ++++++++++++++++++--------------------
1 file changed, 51 insertions(+), 60 deletions(-)
diff --git a/drivers/memory/ti-aemif.c b/drivers/memory/ti-aemif.c
index 1d1b30112af5..ec770a2668e7 100644
--- a/drivers/memory/ti-aemif.c
+++ b/drivers/memory/ti-aemif.c
@@ -133,18 +133,48 @@ struct aemif_device {
struct aemif_cs_data cs_data[NUM_CS];
};
+/**
+ * aemif_check_cs_timings() - Check the validity of a CS timing configuration.
+ * @timings: timings configuration
+ *
+ * @return: 0 if the timing configuration is valid, negative error number otherwise.
+ */
+static int aemif_check_cs_timings(struct aemif_cs_timings *timings)
+{
+ if (timings->ta > TA_MAX)
+ return -EINVAL;
+
+ if (timings->rhold > RHOLD_MAX)
+ return -EINVAL;
+
+ if (timings->rstrobe > RSTROBE_MAX)
+ return -EINVAL;
+
+ if (timings->rsetup > RSETUP_MAX)
+ return -EINVAL;
+
+ if (timings->whold > WHOLD_MAX)
+ return -EINVAL;
+
+ if (timings->wstrobe > WSTROBE_MAX)
+ return -EINVAL;
+
+ if (timings->wsetup > WSETUP_MAX)
+ return -EINVAL;
+
+ return 0;
+}
+
/**
* aemif_calc_rate - calculate timing data.
* @pdev: platform device to calculate for
* @wanted: The cycle time needed in nanoseconds.
* @clk: The input clock rate in kHz.
- * @max: The maximum divider value that can be programmed.
*
- * On success, returns the calculated timing value minus 1 for easy
- * programming into AEMIF timing registers, else negative errno.
+ * @return: the calculated timing value minus 1 for easy
+ * programming into AEMIF timing registers.
*/
-static int aemif_calc_rate(struct platform_device *pdev, int wanted,
- unsigned long clk, int max)
+static u32 aemif_calc_rate(struct platform_device *pdev, int wanted, unsigned long clk)
{
int result;
@@ -157,10 +187,6 @@ static int aemif_calc_rate(struct platform_device *pdev, int wanted,
if (result < 0)
result = 0;
- /* ... But configuring tighter timings is not an option. */
- else if (result > max)
- result = -EINVAL;
-
return result;
}
@@ -250,7 +276,6 @@ static int of_aemif_parse_abus_config(struct platform_device *pdev,
struct aemif_device *aemif = platform_get_drvdata(pdev);
unsigned long clk_rate = aemif->clk_rate;
struct aemif_cs_data *data;
- int ret;
u32 cs;
u32 val;
@@ -276,68 +301,34 @@ static int of_aemif_parse_abus_config(struct platform_device *pdev,
aemif_get_hw_params(pdev, aemif->num_cs++);
/* override the values from device node */
- if (!of_property_read_u32(np, "ti,cs-min-turnaround-ns", &val)) {
- ret = aemif_calc_rate(pdev, val, clk_rate, TA_MAX);
- if (ret < 0)
- return ret;
-
- data->timings.ta = ret;
- }
+ if (!of_property_read_u32(np, "ti,cs-min-turnaround-ns", &val))
+ data->timings.ta = aemif_calc_rate(pdev, val, clk_rate);
- if (!of_property_read_u32(np, "ti,cs-read-hold-ns", &val)) {
- ret = aemif_calc_rate(pdev, val, clk_rate, RHOLD_MAX);
- if (ret < 0)
- return ret;
-
- data->timings.rhold = ret;
- }
+ if (!of_property_read_u32(np, "ti,cs-read-hold-ns", &val))
+ data->timings.rhold = aemif_calc_rate(pdev, val, clk_rate);
- if (!of_property_read_u32(np, "ti,cs-read-strobe-ns", &val)) {
- ret = aemif_calc_rate(pdev, val, clk_rate, RSTROBE_MAX);
- if (ret < 0)
- return ret;
+ if (!of_property_read_u32(np, "ti,cs-read-strobe-ns", &val))
+ data->timings.rstrobe = aemif_calc_rate(pdev, val, clk_rate);
- data->timings.rstrobe = ret;
- }
+ if (!of_property_read_u32(np, "ti,cs-read-setup-ns", &val))
+ data->timings.rsetup = aemif_calc_rate(pdev, val, clk_rate);
- if (!of_property_read_u32(np, "ti,cs-read-setup-ns", &val)) {
- ret = aemif_calc_rate(pdev, val, clk_rate, RSETUP_MAX);
- if (ret < 0)
- return ret;
+ if (!of_property_read_u32(np, "ti,cs-write-hold-ns", &val))
+ data->timings.whold = aemif_calc_rate(pdev, val, clk_rate);
- data->timings.rsetup = ret;
- }
+ if (!of_property_read_u32(np, "ti,cs-write-strobe-ns", &val))
+ data->timings.wstrobe = aemif_calc_rate(pdev, val, clk_rate);
- if (!of_property_read_u32(np, "ti,cs-write-hold-ns", &val)) {
- ret = aemif_calc_rate(pdev, val, clk_rate, WHOLD_MAX);
- if (ret < 0)
- return ret;
-
- data->timings.whold = ret;
- }
-
- if (!of_property_read_u32(np, "ti,cs-write-strobe-ns", &val)) {
- ret = aemif_calc_rate(pdev, val, clk_rate, WSTROBE_MAX);
- if (ret < 0)
- return ret;
-
- data->timings.wstrobe = ret;
- }
-
- if (!of_property_read_u32(np, "ti,cs-write-setup-ns", &val)) {
- ret = aemif_calc_rate(pdev, val, clk_rate, WSETUP_MAX);
- if (ret < 0)
- return ret;
-
- data->timings.wsetup = ret;
- }
+ if (!of_property_read_u32(np, "ti,cs-write-setup-ns", &val))
+ data->timings.wsetup = aemif_calc_rate(pdev, val, clk_rate);
if (!of_property_read_u32(np, "ti,cs-bus-width", &val))
if (val == 16)
data->asize = 1;
data->enable_ew = of_property_read_bool(np, "ti,cs-extended-wait-mode");
data->enable_ss = of_property_read_bool(np, "ti,cs-select-strobe-mode");
- return 0;
+
+ return aemif_check_cs_timings(&data->timings);
}
static const struct of_device_id aemif_of_match[] = {
--
2.47.0
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v5 5/9] memory: ti-aemif: Create aemif_set_cs_timings()
2024-12-04 9:43 [PATCH v5 0/9] Implement setup_interface() in the DaVinci NAND controller Bastien Curutchet
` (3 preceding siblings ...)
2024-12-04 9:43 ` [PATCH v5 4/9] memory: ti-aemif: Create aemif_check_cs_timings() Bastien Curutchet
@ 2024-12-04 9:43 ` Bastien Curutchet
2024-12-09 19:41 ` Krzysztof Kozlowski
2024-12-04 9:43 ` [PATCH v5 6/9] memory: ti-aemif: Export aemif_*_cs_timings() Bastien Curutchet
` (4 subsequent siblings)
9 siblings, 1 reply; 14+ messages in thread
From: Bastien Curutchet @ 2024-12-04 9:43 UTC (permalink / raw)
To: Santosh Shilimkar, Krzysztof Kozlowski, Miquel Raynal,
Richard Weinberger, Vignesh Raghavendra
Cc: linux-kernel, linux-mtd, Thomas Petazzoni, Herve Codina,
Christopher Cordahi, Bastien Curutchet
Create an aemif_set_cs_timings() function to isolate the setting of a
chip select timing configuration and ease its exportation.
Signed-off-by: Bastien Curutchet <bastien.curutchet@bootlin.com>
Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/memory/ti-aemif.c | 65 +++++++++++++++++++++++++++++----------
1 file changed, 49 insertions(+), 16 deletions(-)
diff --git a/drivers/memory/ti-aemif.c b/drivers/memory/ti-aemif.c
index ec770a2668e7..83fb308a831b 100644
--- a/drivers/memory/ti-aemif.c
+++ b/drivers/memory/ti-aemif.c
@@ -69,15 +69,15 @@
#define ACR_SSTROBE_MASK BIT(31)
#define ASIZE_16BIT 1
-#define CONFIG_MASK (TA(TA_MAX) | \
- RHOLD(RHOLD_MAX) | \
- RSTROBE(RSTROBE_MAX) | \
- RSETUP(RSETUP_MAX) | \
- WHOLD(WHOLD_MAX) | \
- WSTROBE(WSTROBE_MAX) | \
- WSETUP(WSETUP_MAX) | \
- EW(EW_MAX) | SSTROBE(SSTROBE_MAX) | \
- ASIZE_MAX)
+#define TIMINGS_MASK (TA(TA_MAX) | \
+ RHOLD(RHOLD_MAX) | \
+ RSTROBE(RSTROBE_MAX) | \
+ RSETUP(RSETUP_MAX) | \
+ WHOLD(WHOLD_MAX) | \
+ WSTROBE(WSTROBE_MAX) | \
+ WSETUP(WSETUP_MAX))
+
+#define CONFIG_MASK (EW(EW_MAX) | SSTROBE(SSTROBE_MAX) | ASIZE_MAX)
/**
* struct aemif_cs_timings: structure to hold CS timings
@@ -165,6 +165,44 @@ static int aemif_check_cs_timings(struct aemif_cs_timings *timings)
return 0;
}
+/**
+ * aemif_set_cs_timings() - Set the timing configuration of a given chip select.
+ * @aemif: aemif device to configure
+ * @cs: index of the chip select to configure
+ * @timings: timings configuration to set
+ *
+ * @return: 0 on success, else negative errno.
+ */
+static int aemif_set_cs_timings(struct aemif_device *aemif, u8 cs, struct aemif_cs_timings *timings)
+{
+ unsigned int offset;
+ u32 val, set;
+ int ret;
+
+ if (!timings || !aemif)
+ return -EINVAL;
+
+ if (cs > aemif->num_cs)
+ return -EINVAL;
+
+ ret = aemif_check_cs_timings(timings);
+ if (ret)
+ return ret;
+
+ set = TA(timings->ta) | RHOLD(timings->rhold) | RSTROBE(timings->rstrobe) |
+ RSETUP(timings->rsetup) | WHOLD(timings->whold) |
+ WSTROBE(timings->wstrobe) | WSETUP(timings->wsetup);
+
+ offset = A1CR_OFFSET + cs * 4;
+
+ val = readl(aemif->base + offset);
+ val &= ~TIMINGS_MASK;
+ val |= set;
+ writel(val, aemif->base + offset);
+
+ return 0;
+}
+
/**
* aemif_calc_rate - calculate timing data.
* @pdev: platform device to calculate for
@@ -213,12 +251,7 @@ static int aemif_config_abus(struct platform_device *pdev, int csnum)
offset = A1CR_OFFSET + (data->cs - aemif->cs_offset) * 4;
- set = TA(data->timings.ta) |
- RHOLD(data->timings.rhold) | RSTROBE(data->timings.rstrobe) |
- RSETUP(data->timings.rsetup) | WHOLD(data->timings.whold) |
- WSTROBE(data->timings.wstrobe) | WSETUP(data->timings.wsetup);
-
- set |= (data->asize & ACR_ASIZE_MASK);
+ set = (data->asize & ACR_ASIZE_MASK);
if (data->enable_ew)
set |= ACR_EW_MASK;
if (data->enable_ss)
@@ -229,7 +262,7 @@ static int aemif_config_abus(struct platform_device *pdev, int csnum)
val |= set;
writel(val, aemif->base + offset);
- return 0;
+ return aemif_set_cs_timings(aemif, data->cs - aemif->cs_offset, &data->timings);
}
/**
--
2.47.0
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply related [flat|nested] 14+ messages in thread* Re: [PATCH v5 5/9] memory: ti-aemif: Create aemif_set_cs_timings()
2024-12-04 9:43 ` [PATCH v5 5/9] memory: ti-aemif: Create aemif_set_cs_timings() Bastien Curutchet
@ 2024-12-09 19:41 ` Krzysztof Kozlowski
2024-12-10 7:23 ` Bastien Curutchet
0 siblings, 1 reply; 14+ messages in thread
From: Krzysztof Kozlowski @ 2024-12-09 19:41 UTC (permalink / raw)
To: Bastien Curutchet, Santosh Shilimkar, Miquel Raynal,
Richard Weinberger, Vignesh Raghavendra
Cc: linux-kernel, linux-mtd, Thomas Petazzoni, Herve Codina,
Christopher Cordahi
On 04/12/2024 10:43, Bastien Curutchet wrote:
> Create an aemif_set_cs_timings() function to isolate the setting of a
> chip select timing configuration and ease its exportation.
>
> Signed-off-by: Bastien Curutchet <bastien.curutchet@bootlin.com>
> Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
> drivers/memory/ti-aemif.c | 65 +++++++++++++++++++++++++++++----------
> 1 file changed, 49 insertions(+), 16 deletions(-)
...
>
> /**
> * struct aemif_cs_timings: structure to hold CS timings
> @@ -165,6 +165,44 @@ static int aemif_check_cs_timings(struct aemif_cs_timings *timings)
> return 0;
> }
>
> +/**
> + * aemif_set_cs_timings() - Set the timing configuration of a given chip select.
> + * @aemif: aemif device to configure
> + * @cs: index of the chip select to configure
> + * @timings: timings configuration to set
> + *
> + * @return: 0 on success, else negative errno.
> + */
> +static int aemif_set_cs_timings(struct aemif_device *aemif, u8 cs, struct aemif_cs_timings *timings)
In the future, please stick to 80-char wrapping unless exceeding makes
code more readable (see Coding style). I fixed it up while applying.
Best regards,
Krzysztof
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v5 5/9] memory: ti-aemif: Create aemif_set_cs_timings()
2024-12-09 19:41 ` Krzysztof Kozlowski
@ 2024-12-10 7:23 ` Bastien Curutchet
0 siblings, 0 replies; 14+ messages in thread
From: Bastien Curutchet @ 2024-12-10 7:23 UTC (permalink / raw)
To: Krzysztof Kozlowski, Santosh Shilimkar, Miquel Raynal,
Richard Weinberger, Vignesh Raghavendra
Cc: linux-kernel, linux-mtd, Thomas Petazzoni, Herve Codina,
Christopher Cordahi
Hi Krzysztof,
On 12/9/24 8:41 PM, Krzysztof Kozlowski wrote:
> On 04/12/2024 10:43, Bastien Curutchet wrote:
>> Create an aemif_set_cs_timings() function to isolate the setting of a
>> chip select timing configuration and ease its exportation.
>>
>> Signed-off-by: Bastien Curutchet <bastien.curutchet@bootlin.com>
>> Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
>> ---
>> drivers/memory/ti-aemif.c | 65 +++++++++++++++++++++++++++++----------
>> 1 file changed, 49 insertions(+), 16 deletions(-)
>
> ...
>
>>
>> /**
>> * struct aemif_cs_timings: structure to hold CS timings
>> @@ -165,6 +165,44 @@ static int aemif_check_cs_timings(struct aemif_cs_timings *timings)
>> return 0;
>> }
>>
>> +/**
>> + * aemif_set_cs_timings() - Set the timing configuration of a given chip select.
>> + * @aemif: aemif device to configure
>> + * @cs: index of the chip select to configure
>> + * @timings: timings configuration to set
>> + *
>> + * @return: 0 on success, else negative errno.
>> + */
>> +static int aemif_set_cs_timings(struct aemif_device *aemif, u8 cs, struct aemif_cs_timings *timings)
>
> In the future, please stick to 80-char wrapping unless exceeding makes
> code more readable (see Coding style). I fixed it up while applying.
>
Ok, thank you.
Best regards,
Bastien
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v5 6/9] memory: ti-aemif: Export aemif_*_cs_timings()
2024-12-04 9:43 [PATCH v5 0/9] Implement setup_interface() in the DaVinci NAND controller Bastien Curutchet
` (4 preceding siblings ...)
2024-12-04 9:43 ` [PATCH v5 5/9] memory: ti-aemif: Create aemif_set_cs_timings() Bastien Curutchet
@ 2024-12-04 9:43 ` Bastien Curutchet
2024-12-04 9:43 ` [PATCH v5 7/9] mtd: rawnand: davinci: Always depends on TI_AEMIF Bastien Curutchet
` (3 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Bastien Curutchet @ 2024-12-04 9:43 UTC (permalink / raw)
To: Santosh Shilimkar, Krzysztof Kozlowski, Miquel Raynal,
Richard Weinberger, Vignesh Raghavendra
Cc: linux-kernel, linux-mtd, Thomas Petazzoni, Herve Codina,
Christopher Cordahi, Bastien Curutchet
Export the aemif_set_cs_timing() and aemif_check_cs_timing() symbols so
they can be used by other drivers
Add a mutex to protect the CS configuration register from concurrent
accesses between the AEMIF and its 'children'.
Signed-off-by: Bastien Curutchet <bastien.curutchet@bootlin.com>
Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/memory/ti-aemif.c | 35 ++++++++++++---------------------
include/linux/memory/ti-aemif.h | 32 ++++++++++++++++++++++++++++++
2 files changed, 45 insertions(+), 22 deletions(-)
create mode 100644 include/linux/memory/ti-aemif.h
diff --git a/drivers/memory/ti-aemif.c b/drivers/memory/ti-aemif.c
index 83fb308a831b..541fc8b8b640 100644
--- a/drivers/memory/ti-aemif.c
+++ b/drivers/memory/ti-aemif.c
@@ -13,7 +13,9 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/kernel.h>
+#include <linux/memory/ti-aemif.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
@@ -79,26 +81,6 @@
#define CONFIG_MASK (EW(EW_MAX) | SSTROBE(SSTROBE_MAX) | ASIZE_MAX)
-/**
- * struct aemif_cs_timings: structure to hold CS timings
- * @wstrobe: write strobe width, number of cycles - 1
- * @rstrobe: read strobe width, number of cycles - 1
- * @wsetup: write setup width, number of cycles - 1
- * @whold: write hold width, number of cycles - 1
- * @rsetup: read setup width, number of cycles - 1
- * @rhold: read hold width, number of cycles - 1
- * @ta: minimum turn around time, number of cycles - 1
- */
-struct aemif_cs_timings {
- u32 wstrobe;
- u32 rstrobe;
- u32 wsetup;
- u32 whold;
- u32 rsetup;
- u32 rhold;
- u32 ta;
-};
-
/**
* struct aemif_cs_data: structure to hold CS parameters
* @timings: timings configuration
@@ -123,6 +105,7 @@ struct aemif_cs_data {
* @num_cs: number of assigned chip-selects
* @cs_offset: start number of cs nodes
* @cs_data: array of chip-select settings
+ * @config_cs_lock: lock used to access CS configuration
*/
struct aemif_device {
void __iomem *base;
@@ -131,6 +114,7 @@ struct aemif_device {
u8 num_cs;
int cs_offset;
struct aemif_cs_data cs_data[NUM_CS];
+ struct mutex config_cs_lock;
};
/**
@@ -139,7 +123,7 @@ struct aemif_device {
*
* @return: 0 if the timing configuration is valid, negative error number otherwise.
*/
-static int aemif_check_cs_timings(struct aemif_cs_timings *timings)
+int aemif_check_cs_timings(struct aemif_cs_timings *timings)
{
if (timings->ta > TA_MAX)
return -EINVAL;
@@ -164,6 +148,7 @@ static int aemif_check_cs_timings(struct aemif_cs_timings *timings)
return 0;
}
+EXPORT_SYMBOL_GPL(aemif_check_cs_timings);
/**
* aemif_set_cs_timings() - Set the timing configuration of a given chip select.
@@ -173,7 +158,7 @@ static int aemif_check_cs_timings(struct aemif_cs_timings *timings)
*
* @return: 0 on success, else negative errno.
*/
-static int aemif_set_cs_timings(struct aemif_device *aemif, u8 cs, struct aemif_cs_timings *timings)
+int aemif_set_cs_timings(struct aemif_device *aemif, u8 cs, struct aemif_cs_timings *timings)
{
unsigned int offset;
u32 val, set;
@@ -195,13 +180,16 @@ static int aemif_set_cs_timings(struct aemif_device *aemif, u8 cs, struct aemif_
offset = A1CR_OFFSET + cs * 4;
+ mutex_lock(&aemif->config_cs_lock);
val = readl(aemif->base + offset);
val &= ~TIMINGS_MASK;
val |= set;
writel(val, aemif->base + offset);
+ mutex_unlock(&aemif->config_cs_lock);
return 0;
}
+EXPORT_SYMBOL_GPL(aemif_set_cs_timings);
/**
* aemif_calc_rate - calculate timing data.
@@ -257,10 +245,12 @@ static int aemif_config_abus(struct platform_device *pdev, int csnum)
if (data->enable_ss)
set |= ACR_SSTROBE_MASK;
+ mutex_lock(&aemif->config_cs_lock);
val = readl(aemif->base + offset);
val &= ~CONFIG_MASK;
val |= set;
writel(val, aemif->base + offset);
+ mutex_unlock(&aemif->config_cs_lock);
return aemif_set_cs_timings(aemif, data->cs - aemif->cs_offset, &data->timings);
}
@@ -399,6 +389,7 @@ static int aemif_probe(struct platform_device *pdev)
if (IS_ERR(aemif->base))
return PTR_ERR(aemif->base);
+ mutex_init(&aemif->config_cs_lock);
if (np) {
/*
* For every controller device node, there is a cs device node
diff --git a/include/linux/memory/ti-aemif.h b/include/linux/memory/ti-aemif.h
new file mode 100644
index 000000000000..da94a9d985e7
--- /dev/null
+++ b/include/linux/memory/ti-aemif.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __MEMORY_TI_AEMIF_H
+#define __MEMORY_TI_AEMIF_H
+
+/**
+ * struct aemif_cs_timings: structure to hold CS timing configuration
+ * values are expressed in number of clock cycles - 1
+ * @ta: minimum turn around time
+ * @rhold: read hold width
+ * @rstrobe: read strobe width
+ * @rsetup: read setup width
+ * @whold: write hold width
+ * @wstrobe: write strobe width
+ * @wsetup: write setup width
+ */
+struct aemif_cs_timings {
+ u32 ta;
+ u32 rhold;
+ u32 rstrobe;
+ u32 rsetup;
+ u32 whold;
+ u32 wstrobe;
+ u32 wsetup;
+};
+
+struct aemif_device;
+
+int aemif_set_cs_timings(struct aemif_device *aemif, u8 cs, struct aemif_cs_timings *timings);
+int aemif_check_cs_timings(struct aemif_cs_timings *timings);
+
+#endif // __MEMORY_TI_AEMIF_H
--
2.47.0
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v5 7/9] mtd: rawnand: davinci: Always depends on TI_AEMIF
2024-12-04 9:43 [PATCH v5 0/9] Implement setup_interface() in the DaVinci NAND controller Bastien Curutchet
` (5 preceding siblings ...)
2024-12-04 9:43 ` [PATCH v5 6/9] memory: ti-aemif: Export aemif_*_cs_timings() Bastien Curutchet
@ 2024-12-04 9:43 ` Bastien Curutchet
2024-12-04 9:43 ` [PATCH v5 8/9] mtd: rawnand: davinci: Add clock resource Bastien Curutchet
` (2 subsequent siblings)
9 siblings, 0 replies; 14+ messages in thread
From: Bastien Curutchet @ 2024-12-04 9:43 UTC (permalink / raw)
To: Santosh Shilimkar, Krzysztof Kozlowski, Miquel Raynal,
Richard Weinberger, Vignesh Raghavendra
Cc: linux-kernel, linux-mtd, Thomas Petazzoni, Herve Codina,
Christopher Cordahi, Bastien Curutchet, kernel test robot
DAVINCI_NAND depends on TI_AEMIF only when ARCH_KEYSTONE is selected
while the NAND controller is also always a part of the AEMIF controller
on DaVinci SoCs.
Set a dependency on TI_AEMIF regardless of the selected architecture.
Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202411020140.3wsKJOSB-lkp@intel.com/
Closes: https://lore.kernel.org/oe-kbuild-all/202411020957.X1T8T9ZR-lkp@intel.com/
Signed-off-by: Bastien Curutchet <bastien.curutchet@bootlin.com>
---
drivers/mtd/nand/raw/Kconfig | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
index d0aaccf72d78..bb61434347bd 100644
--- a/drivers/mtd/nand/raw/Kconfig
+++ b/drivers/mtd/nand/raw/Kconfig
@@ -279,8 +279,8 @@ config MTD_NAND_SH_FLCTL
config MTD_NAND_DAVINCI
tristate "DaVinci/Keystone NAND controller"
- depends on ARCH_DAVINCI || (ARCH_KEYSTONE && TI_AEMIF) || COMPILE_TEST
- depends on HAS_IOMEM
+ depends on COMPILE_TEST || ARCH_DAVINCI || ARCH_KEYSTONE
+ depends on HAS_IOMEM && TI_AEMIF
help
Enable the driver for NAND flash chips on Texas Instruments
DaVinci/Keystone processors.
--
2.47.0
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v5 8/9] mtd: rawnand: davinci: Add clock resource
2024-12-04 9:43 [PATCH v5 0/9] Implement setup_interface() in the DaVinci NAND controller Bastien Curutchet
` (6 preceding siblings ...)
2024-12-04 9:43 ` [PATCH v5 7/9] mtd: rawnand: davinci: Always depends on TI_AEMIF Bastien Curutchet
@ 2024-12-04 9:43 ` Bastien Curutchet
2024-12-04 9:43 ` [PATCH v5 9/9] mtd: rawnand: davinci: Implement setup_interface() operation Bastien Curutchet
2024-12-09 19:40 ` (subset) [PATCH v5 0/9] Implement setup_interface() in the DaVinci NAND controller Krzysztof Kozlowski
9 siblings, 0 replies; 14+ messages in thread
From: Bastien Curutchet @ 2024-12-04 9:43 UTC (permalink / raw)
To: Santosh Shilimkar, Krzysztof Kozlowski, Miquel Raynal,
Richard Weinberger, Vignesh Raghavendra
Cc: linux-kernel, linux-mtd, Thomas Petazzoni, Herve Codina,
Christopher Cordahi, Bastien Curutchet
NAND controller has a reference clock inherited from the AEMIF
(cf. Documentation/devicetree/bindings/memory-controllers/ti-aemif.txt)
This clock isn't used yet by the driver.
Add a struct clock in the struct davinci_nand_info so it can be used
to compute timings.
Signed-off-by: Bastien Curutchet <bastien.curutchet@bootlin.com>
---
drivers/mtd/nand/raw/davinci_nand.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/mtd/nand/raw/davinci_nand.c b/drivers/mtd/nand/raw/davinci_nand.c
index 1f8354acfb50..4fb5c2623f5a 100644
--- a/drivers/mtd/nand/raw/davinci_nand.c
+++ b/drivers/mtd/nand/raw/davinci_nand.c
@@ -10,6 +10,7 @@
* Dirk Behme <Dirk.Behme@gmail.com>
*/
+#include <linux/clk.h>
#include <linux/err.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
@@ -117,6 +118,8 @@ struct davinci_nand_info {
uint32_t mask_cle;
uint32_t core_chipsel;
+
+ struct clk *clk;
};
static DEFINE_SPINLOCK(davinci_nand_lock);
@@ -822,6 +825,10 @@ static int nand_davinci_probe(struct platform_device *pdev)
return -EADDRNOTAVAIL;
}
+ info->clk = devm_clk_get_enabled(&pdev->dev, "aemif");
+ if (IS_ERR(info->clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(info->clk), "failed to get clock");
+
info->pdev = pdev;
info->base = base;
info->vaddr = vaddr;
--
2.47.0
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v5 9/9] mtd: rawnand: davinci: Implement setup_interface() operation
2024-12-04 9:43 [PATCH v5 0/9] Implement setup_interface() in the DaVinci NAND controller Bastien Curutchet
` (7 preceding siblings ...)
2024-12-04 9:43 ` [PATCH v5 8/9] mtd: rawnand: davinci: Add clock resource Bastien Curutchet
@ 2024-12-04 9:43 ` Bastien Curutchet
2024-12-09 19:40 ` (subset) [PATCH v5 0/9] Implement setup_interface() in the DaVinci NAND controller Krzysztof Kozlowski
9 siblings, 0 replies; 14+ messages in thread
From: Bastien Curutchet @ 2024-12-04 9:43 UTC (permalink / raw)
To: Santosh Shilimkar, Krzysztof Kozlowski, Miquel Raynal,
Richard Weinberger, Vignesh Raghavendra
Cc: linux-kernel, linux-mtd, Thomas Petazzoni, Herve Codina,
Christopher Cordahi, Bastien Curutchet
The setup_interface() operation isn't implemented. It forces the driver
to use the ONFI mode 0, though it could use more optimal modes.
Implement the setup_interface() operation. It uses the
aemif_set_cs_timings() function from the AEMIF driver to update the
chip select timings. The calculation of the register's contents is
directly extracted from §20.3.2.3 of the DaVinci TRM [1]
MAX_TH_PS and MAX_TSU_PS are the worst case timings based on the
Keystone2 and DaVinci datasheets.
[1] : https://www.ti.com/lit/ug/spruh77c/spruh77c.pdf
Signed-off-by: Bastien Curutchet <bastien.curutchet@bootlin.com>
---
drivers/mtd/nand/raw/davinci_nand.c | 79 +++++++++++++++++++++++++++++
1 file changed, 79 insertions(+)
diff --git a/drivers/mtd/nand/raw/davinci_nand.c b/drivers/mtd/nand/raw/davinci_nand.c
index 4fb5c2623f5a..2a1b3cd49415 100644
--- a/drivers/mtd/nand/raw/davinci_nand.c
+++ b/drivers/mtd/nand/raw/davinci_nand.c
@@ -14,6 +14,7 @@
#include <linux/err.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
+#include <linux/memory/ti-aemif.h>
#include <linux/module.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/rawnand.h>
@@ -44,6 +45,9 @@
#define MASK_ALE 0x08
#define MASK_CLE 0x10
+#define MAX_TSU_PS 3000 /* Input setup time in ps */
+#define MAX_TH_PS 1600 /* Input hold time in ps */
+
struct davinci_nand_pdata {
uint32_t mask_ale;
uint32_t mask_cle;
@@ -120,6 +124,7 @@ struct davinci_nand_info {
uint32_t core_chipsel;
struct clk *clk;
+ struct aemif_device *aemif;
};
static DEFINE_SPINLOCK(davinci_nand_lock);
@@ -767,9 +772,82 @@ static int davinci_nand_exec_op(struct nand_chip *chip,
return 0;
}
+#define TO_CYCLES(ps, period_ns) (DIV_ROUND_UP((ps) / 1000, (period_ns)))
+
+static int davinci_nand_setup_interface(struct nand_chip *chip, int chipnr,
+ const struct nand_interface_config *conf)
+{
+ struct davinci_nand_info *info = to_davinci_nand(nand_to_mtd(chip));
+ const struct nand_sdr_timings *sdr;
+ struct aemif_cs_timings timings;
+ s32 cfg, min, cyc_ns;
+ int ret;
+
+ cyc_ns = 1000000000 / clk_get_rate(info->clk);
+
+ sdr = nand_get_sdr_timings(conf);
+ if (IS_ERR(sdr))
+ return PTR_ERR(sdr);
+
+ cfg = TO_CYCLES(sdr->tCLR_min, cyc_ns) - 1;
+ timings.rsetup = cfg > 0 ? cfg : 0;
+
+ cfg = max_t(s32, TO_CYCLES(sdr->tREA_max + MAX_TSU_PS, cyc_ns),
+ TO_CYCLES(sdr->tRP_min, cyc_ns)) - 1;
+ timings.rstrobe = cfg > 0 ? cfg : 0;
+
+ min = TO_CYCLES(sdr->tCEA_max + MAX_TSU_PS, cyc_ns) - 2;
+ while ((s32)(timings.rsetup + timings.rstrobe) < min)
+ timings.rstrobe++;
+
+ cfg = TO_CYCLES((s32)(MAX_TH_PS - sdr->tCHZ_max), cyc_ns) - 1;
+ timings.rhold = cfg > 0 ? cfg : 0;
+
+ min = TO_CYCLES(sdr->tRC_min, cyc_ns) - 3;
+ while ((s32)(timings.rsetup + timings.rstrobe + timings.rhold) < min)
+ timings.rhold++;
+
+ cfg = TO_CYCLES((s32)(sdr->tRHZ_max - (timings.rhold + 1) * cyc_ns * 1000), cyc_ns);
+ cfg = max_t(s32, cfg, TO_CYCLES(sdr->tCHZ_max, cyc_ns)) - 1;
+ timings.ta = cfg > 0 ? cfg : 0;
+
+ cfg = TO_CYCLES(sdr->tWP_min, cyc_ns) - 1;
+ timings.wstrobe = cfg > 0 ? cfg : 0;
+
+ cfg = max_t(s32, TO_CYCLES(sdr->tCLS_min, cyc_ns), TO_CYCLES(sdr->tALS_min, cyc_ns));
+ cfg = max_t(s32, cfg, TO_CYCLES(sdr->tCS_min, cyc_ns)) - 1;
+ timings.wsetup = cfg > 0 ? cfg : 0;
+
+ min = TO_CYCLES(sdr->tDS_min, cyc_ns) - 2;
+ while ((s32)(timings.wsetup + timings.wstrobe) < min)
+ timings.wstrobe++;
+
+ cfg = max_t(s32, TO_CYCLES(sdr->tCLH_min, cyc_ns), TO_CYCLES(sdr->tALH_min, cyc_ns));
+ cfg = max_t(s32, cfg, TO_CYCLES(sdr->tCH_min, cyc_ns));
+ cfg = max_t(s32, cfg, TO_CYCLES(sdr->tDH_min, cyc_ns)) - 1;
+ timings.whold = cfg > 0 ? cfg : 0;
+
+ min = TO_CYCLES(sdr->tWC_min, cyc_ns) - 2;
+ while ((s32)(timings.wsetup + timings.wstrobe + timings.whold) < min)
+ timings.whold++;
+
+ dev_dbg(&info->pdev->dev, "RSETUP %x RSTROBE %x RHOLD %x\n",
+ timings.rsetup, timings.rstrobe, timings.rhold);
+ dev_dbg(&info->pdev->dev, "TA %x\n", timings.ta);
+ dev_dbg(&info->pdev->dev, "WSETUP %x WSTROBE %x WHOLD %x\n",
+ timings.wsetup, timings.wstrobe, timings.whold);
+
+ ret = aemif_check_cs_timings(&timings);
+ if (ret || chipnr == NAND_DATA_IFACE_CHECK_ONLY)
+ return ret;
+
+ return aemif_set_cs_timings(info->aemif, info->core_chipsel, &timings);
+}
+
static const struct nand_controller_ops davinci_nand_controller_ops = {
.attach_chip = davinci_nand_attach_chip,
.exec_op = davinci_nand_exec_op,
+ .setup_interface = davinci_nand_setup_interface,
};
static int nand_davinci_probe(struct platform_device *pdev)
@@ -832,6 +910,7 @@ static int nand_davinci_probe(struct platform_device *pdev)
info->pdev = pdev;
info->base = base;
info->vaddr = vaddr;
+ info->aemif = dev_get_drvdata(pdev->dev.parent);
mtd = nand_to_mtd(&info->chip);
mtd->dev.parent = &pdev->dev;
--
2.47.0
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply related [flat|nested] 14+ messages in thread* Re: (subset) [PATCH v5 0/9] Implement setup_interface() in the DaVinci NAND controller
2024-12-04 9:43 [PATCH v5 0/9] Implement setup_interface() in the DaVinci NAND controller Bastien Curutchet
` (8 preceding siblings ...)
2024-12-04 9:43 ` [PATCH v5 9/9] mtd: rawnand: davinci: Implement setup_interface() operation Bastien Curutchet
@ 2024-12-09 19:40 ` Krzysztof Kozlowski
2024-12-09 20:53 ` Miquel Raynal
9 siblings, 1 reply; 14+ messages in thread
From: Krzysztof Kozlowski @ 2024-12-09 19:40 UTC (permalink / raw)
To: Santosh Shilimkar, Krzysztof Kozlowski, Miquel Raynal,
Richard Weinberger, Vignesh Raghavendra, Bastien Curutchet
Cc: Krzysztof Kozlowski, linux-kernel, linux-mtd, Thomas Petazzoni,
Herve Codina, Christopher Cordahi
On Wed, 04 Dec 2024 10:43:10 +0100, Bastien Curutchet wrote:
> This patch series aims to implement the setup_interface() operation in
> the DaVinci NAND controller to enable the use of all ONFI modes and
> improve the NAND access speed.
>
> PATCH 6 depends on PATCH 1-2-3-4-5
> PATCH 9 depends on PATCH 6-8
>
> [...]
Applied, thanks!
[1/9] memory: ti-aemif: Store timings parameter in number of cycles - 1
https://git.kernel.org/krzk/linux-mem-ctrl/c/1ec0fa90070c9468d22b3c3ea5f4bd6c27810907
[2/9] memory: ti-aemif: Remove unnecessary local variables
https://git.kernel.org/krzk/linux-mem-ctrl/c/b3d57e179607106d5b08a635c49b338c409357d4
[3/9] memory: ti-aemif: Wrap CS timings into a struct
https://git.kernel.org/krzk/linux-mem-ctrl/c/30b4da67655469bf8d4b8ba7c001096a1e10c7bf
[4/9] memory: ti-aemif: Create aemif_check_cs_timings()
https://git.kernel.org/krzk/linux-mem-ctrl/c/2c7b585d19cc1a7185a3a0b58cb643d28fd19cc1
[5/9] memory: ti-aemif: Create aemif_set_cs_timings()
https://git.kernel.org/krzk/linux-mem-ctrl/c/a6d60e3376065752137ec23d103f7d039c363e41
[6/9] memory: ti-aemif: Export aemif_*_cs_timings()
https://git.kernel.org/krzk/linux-mem-ctrl/c/df8e78607d4795806b59564ba7a3e2e125d119fc
I'll wait till it hit next and got build reports and provide these as stable
tag/branch.
Best regards,
--
Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: (subset) [PATCH v5 0/9] Implement setup_interface() in the DaVinci NAND controller
2024-12-09 19:40 ` (subset) [PATCH v5 0/9] Implement setup_interface() in the DaVinci NAND controller Krzysztof Kozlowski
@ 2024-12-09 20:53 ` Miquel Raynal
0 siblings, 0 replies; 14+ messages in thread
From: Miquel Raynal @ 2024-12-09 20:53 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Santosh Shilimkar, Krzysztof Kozlowski, Richard Weinberger,
Vignesh Raghavendra, Bastien Curutchet, linux-kernel, linux-mtd,
Thomas Petazzoni, Herve Codina, Christopher Cordahi
Hello,
> I'll wait till it hit next and got build reports and provide these as stable
> tag/branch.
Perfect.
Thanks,
Miquèl
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply [flat|nested] 14+ messages in thread