Skip to content

Commit 8de2819

Browse files
committed
Merge tag 'memory-controller-drv-ti-6.14' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl into soc/drivers
Memory controller drivers for v6.14 - TI TI AEMIF driver enhancements: some refactoring around timing parameters and finally adding plus exporting interfaces for devices using the AEMIF interface (e.g. TI Davinci NAND controller) to better configure the memory interface. The exported functions are going to be used by: drivers/mtd/nand/raw/davinci_nand.c * tag 'memory-controller-drv-ti-6.14' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl: memory: ti-aemif: Export aemif_*_cs_timings() memory: ti-aemif: Create aemif_set_cs_timings() memory: ti-aemif: Create aemif_check_cs_timings() memory: ti-aemif: Wrap CS timings into a struct memory: ti-aemif: Remove unnecessary local variables memory: ti-aemif: Store timings parameter in number of cycles - 1 Link: https://lore.kernel.org/r/20241231133534.136771-2-krzysztof.kozlowski@linaro.org Signed-off-by: Arnd Bergmann <arnd@arndb.de>
2 parents 3292e5a + df8e786 commit 8de2819

2 files changed

Lines changed: 148 additions & 76 deletions

File tree

drivers/memory/ti-aemif.c

Lines changed: 116 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
#include <linux/err.h>
1414
#include <linux/io.h>
1515
#include <linux/kernel.h>
16+
#include <linux/memory/ti-aemif.h>
1617
#include <linux/module.h>
18+
#include <linux/mutex.h>
1719
#include <linux/of.h>
1820
#include <linux/of_platform.h>
1921
#include <linux/platform_device.h>
@@ -69,39 +71,27 @@
6971
#define ACR_SSTROBE_MASK BIT(31)
7072
#define ASIZE_16BIT 1
7173

72-
#define CONFIG_MASK (TA(TA_MAX) | \
73-
RHOLD(RHOLD_MAX) | \
74-
RSTROBE(RSTROBE_MAX) | \
75-
RSETUP(RSETUP_MAX) | \
76-
WHOLD(WHOLD_MAX) | \
77-
WSTROBE(WSTROBE_MAX) | \
78-
WSETUP(WSETUP_MAX) | \
79-
EW(EW_MAX) | SSTROBE(SSTROBE_MAX) | \
80-
ASIZE_MAX)
74+
#define TIMINGS_MASK (TA(TA_MAX) | \
75+
RHOLD(RHOLD_MAX) | \
76+
RSTROBE(RSTROBE_MAX) | \
77+
RSETUP(RSETUP_MAX) | \
78+
WHOLD(WHOLD_MAX) | \
79+
WSTROBE(WSTROBE_MAX) | \
80+
WSETUP(WSETUP_MAX))
81+
82+
#define CONFIG_MASK (EW(EW_MAX) | SSTROBE(SSTROBE_MAX) | ASIZE_MAX)
8183

8284
/**
83-
* struct aemif_cs_data: structure to hold cs parameters
85+
* struct aemif_cs_data: structure to hold CS parameters
86+
* @timings: timings configuration
8487
* @cs: chip-select number
85-
* @wstrobe: write strobe width, ns
86-
* @rstrobe: read strobe width, ns
87-
* @wsetup: write setup width, ns
88-
* @whold: write hold width, ns
89-
* @rsetup: read setup width, ns
90-
* @rhold: read hold width, ns
91-
* @ta: minimum turn around time, ns
9288
* @enable_ss: enable/disable select strobe mode
9389
* @enable_ew: enable/disable extended wait mode
9490
* @asize: width of the asynchronous device's data bus
9591
*/
9692
struct aemif_cs_data {
93+
struct aemif_cs_timings timings;
9794
u8 cs;
98-
u16 wstrobe;
99-
u16 rstrobe;
100-
u8 wsetup;
101-
u8 whold;
102-
u8 rsetup;
103-
u8 rhold;
104-
u8 ta;
10595
u8 enable_ss;
10696
u8 enable_ew;
10797
u8 asize;
@@ -115,6 +105,7 @@ struct aemif_cs_data {
115105
* @num_cs: number of assigned chip-selects
116106
* @cs_offset: start number of cs nodes
117107
* @cs_data: array of chip-select settings
108+
* @config_cs_lock: lock used to access CS configuration
118109
*/
119110
struct aemif_device {
120111
void __iomem *base;
@@ -123,20 +114,94 @@ struct aemif_device {
123114
u8 num_cs;
124115
int cs_offset;
125116
struct aemif_cs_data cs_data[NUM_CS];
117+
struct mutex config_cs_lock;
126118
};
127119

120+
/**
121+
* aemif_check_cs_timings() - Check the validity of a CS timing configuration.
122+
* @timings: timings configuration
123+
*
124+
* @return: 0 if the timing configuration is valid, negative error number otherwise.
125+
*/
126+
int aemif_check_cs_timings(struct aemif_cs_timings *timings)
127+
{
128+
if (timings->ta > TA_MAX)
129+
return -EINVAL;
130+
131+
if (timings->rhold > RHOLD_MAX)
132+
return -EINVAL;
133+
134+
if (timings->rstrobe > RSTROBE_MAX)
135+
return -EINVAL;
136+
137+
if (timings->rsetup > RSETUP_MAX)
138+
return -EINVAL;
139+
140+
if (timings->whold > WHOLD_MAX)
141+
return -EINVAL;
142+
143+
if (timings->wstrobe > WSTROBE_MAX)
144+
return -EINVAL;
145+
146+
if (timings->wsetup > WSETUP_MAX)
147+
return -EINVAL;
148+
149+
return 0;
150+
}
151+
EXPORT_SYMBOL_GPL(aemif_check_cs_timings);
152+
153+
/**
154+
* aemif_set_cs_timings() - Set the timing configuration of a given chip select.
155+
* @aemif: aemif device to configure
156+
* @cs: index of the chip select to configure
157+
* @timings: timings configuration to set
158+
*
159+
* @return: 0 on success, else negative errno.
160+
*/
161+
int aemif_set_cs_timings(struct aemif_device *aemif, u8 cs,
162+
struct aemif_cs_timings *timings)
163+
{
164+
unsigned int offset;
165+
u32 val, set;
166+
int ret;
167+
168+
if (!timings || !aemif)
169+
return -EINVAL;
170+
171+
if (cs > aemif->num_cs)
172+
return -EINVAL;
173+
174+
ret = aemif_check_cs_timings(timings);
175+
if (ret)
176+
return ret;
177+
178+
set = TA(timings->ta) | RHOLD(timings->rhold) | RSTROBE(timings->rstrobe) |
179+
RSETUP(timings->rsetup) | WHOLD(timings->whold) |
180+
WSTROBE(timings->wstrobe) | WSETUP(timings->wsetup);
181+
182+
offset = A1CR_OFFSET + cs * 4;
183+
184+
mutex_lock(&aemif->config_cs_lock);
185+
val = readl(aemif->base + offset);
186+
val &= ~TIMINGS_MASK;
187+
val |= set;
188+
writel(val, aemif->base + offset);
189+
mutex_unlock(&aemif->config_cs_lock);
190+
191+
return 0;
192+
}
193+
EXPORT_SYMBOL_GPL(aemif_set_cs_timings);
194+
128195
/**
129196
* aemif_calc_rate - calculate timing data.
130197
* @pdev: platform device to calculate for
131198
* @wanted: The cycle time needed in nanoseconds.
132199
* @clk: The input clock rate in kHz.
133-
* @max: The maximum divider value that can be programmed.
134200
*
135-
* On success, returns the calculated timing value minus 1 for easy
136-
* programming into AEMIF timing registers, else negative errno.
201+
* @return: the calculated timing value minus 1 for easy
202+
* programming into AEMIF timing registers.
137203
*/
138-
static int aemif_calc_rate(struct platform_device *pdev, int wanted,
139-
unsigned long clk, int max)
204+
static u32 aemif_calc_rate(struct platform_device *pdev, int wanted, unsigned long clk)
140205
{
141206
int result;
142207

@@ -149,10 +214,6 @@ static int aemif_calc_rate(struct platform_device *pdev, int wanted,
149214
if (result < 0)
150215
result = 0;
151216

152-
/* ... But configuring tighter timings is not an option. */
153-
else if (result > max)
154-
result = -EINVAL;
155-
156217
return result;
157218
}
158219

@@ -174,48 +235,25 @@ static int aemif_config_abus(struct platform_device *pdev, int csnum)
174235
{
175236
struct aemif_device *aemif = platform_get_drvdata(pdev);
176237
struct aemif_cs_data *data = &aemif->cs_data[csnum];
177-
int ta, rhold, rstrobe, rsetup, whold, wstrobe, wsetup;
178-
unsigned long clk_rate = aemif->clk_rate;
179238
unsigned offset;
180239
u32 set, val;
181240

182241
offset = A1CR_OFFSET + (data->cs - aemif->cs_offset) * 4;
183242

184-
ta = aemif_calc_rate(pdev, data->ta, clk_rate, TA_MAX);
185-
rhold = aemif_calc_rate(pdev, data->rhold, clk_rate, RHOLD_MAX);
186-
rstrobe = aemif_calc_rate(pdev, data->rstrobe, clk_rate, RSTROBE_MAX);
187-
rsetup = aemif_calc_rate(pdev, data->rsetup, clk_rate, RSETUP_MAX);
188-
whold = aemif_calc_rate(pdev, data->whold, clk_rate, WHOLD_MAX);
189-
wstrobe = aemif_calc_rate(pdev, data->wstrobe, clk_rate, WSTROBE_MAX);
190-
wsetup = aemif_calc_rate(pdev, data->wsetup, clk_rate, WSETUP_MAX);
191-
192-
if (ta < 0 || rhold < 0 || rstrobe < 0 || rsetup < 0 ||
193-
whold < 0 || wstrobe < 0 || wsetup < 0) {
194-
dev_err(&pdev->dev, "%s: cannot get suitable timings\n",
195-
__func__);
196-
return -EINVAL;
197-
}
198-
199-
set = TA(ta) | RHOLD(rhold) | RSTROBE(rstrobe) | RSETUP(rsetup) |
200-
WHOLD(whold) | WSTROBE(wstrobe) | WSETUP(wsetup);
201-
202-
set |= (data->asize & ACR_ASIZE_MASK);
243+
set = (data->asize & ACR_ASIZE_MASK);
203244
if (data->enable_ew)
204245
set |= ACR_EW_MASK;
205246
if (data->enable_ss)
206247
set |= ACR_SSTROBE_MASK;
207248

249+
mutex_lock(&aemif->config_cs_lock);
208250
val = readl(aemif->base + offset);
209251
val &= ~CONFIG_MASK;
210252
val |= set;
211253
writel(val, aemif->base + offset);
254+
mutex_unlock(&aemif->config_cs_lock);
212255

213-
return 0;
214-
}
215-
216-
static inline int aemif_cycles_to_nsec(int val, unsigned long clk_rate)
217-
{
218-
return ((val + 1) * NSEC_PER_MSEC) / clk_rate;
256+
return aemif_set_cs_timings(aemif, data->cs - aemif->cs_offset, &data->timings);
219257
}
220258

221259
/**
@@ -231,19 +269,18 @@ static void aemif_get_hw_params(struct platform_device *pdev, int csnum)
231269
{
232270
struct aemif_device *aemif = platform_get_drvdata(pdev);
233271
struct aemif_cs_data *data = &aemif->cs_data[csnum];
234-
unsigned long clk_rate = aemif->clk_rate;
235272
u32 val, offset;
236273

237274
offset = A1CR_OFFSET + (data->cs - aemif->cs_offset) * 4;
238275
val = readl(aemif->base + offset);
239276

240-
data->ta = aemif_cycles_to_nsec(TA_VAL(val), clk_rate);
241-
data->rhold = aemif_cycles_to_nsec(RHOLD_VAL(val), clk_rate);
242-
data->rstrobe = aemif_cycles_to_nsec(RSTROBE_VAL(val), clk_rate);
243-
data->rsetup = aemif_cycles_to_nsec(RSETUP_VAL(val), clk_rate);
244-
data->whold = aemif_cycles_to_nsec(WHOLD_VAL(val), clk_rate);
245-
data->wstrobe = aemif_cycles_to_nsec(WSTROBE_VAL(val), clk_rate);
246-
data->wsetup = aemif_cycles_to_nsec(WSETUP_VAL(val), clk_rate);
277+
data->timings.ta = TA_VAL(val);
278+
data->timings.rhold = RHOLD_VAL(val);
279+
data->timings.rstrobe = RSTROBE_VAL(val);
280+
data->timings.rsetup = RSETUP_VAL(val);
281+
data->timings.whold = WHOLD_VAL(val);
282+
data->timings.wstrobe = WSTROBE_VAL(val);
283+
data->timings.wsetup = WSETUP_VAL(val);
247284
data->enable_ew = EW_VAL(val);
248285
data->enable_ss = SSTROBE_VAL(val);
249286
data->asize = val & ASIZE_MAX;
@@ -261,6 +298,7 @@ static int of_aemif_parse_abus_config(struct platform_device *pdev,
261298
struct device_node *np)
262299
{
263300
struct aemif_device *aemif = platform_get_drvdata(pdev);
301+
unsigned long clk_rate = aemif->clk_rate;
264302
struct aemif_cs_data *data;
265303
u32 cs;
266304
u32 val;
@@ -288,32 +326,33 @@ static int of_aemif_parse_abus_config(struct platform_device *pdev,
288326

289327
/* override the values from device node */
290328
if (!of_property_read_u32(np, "ti,cs-min-turnaround-ns", &val))
291-
data->ta = val;
329+
data->timings.ta = aemif_calc_rate(pdev, val, clk_rate);
292330

293331
if (!of_property_read_u32(np, "ti,cs-read-hold-ns", &val))
294-
data->rhold = val;
332+
data->timings.rhold = aemif_calc_rate(pdev, val, clk_rate);
295333

296334
if (!of_property_read_u32(np, "ti,cs-read-strobe-ns", &val))
297-
data->rstrobe = val;
335+
data->timings.rstrobe = aemif_calc_rate(pdev, val, clk_rate);
298336

299337
if (!of_property_read_u32(np, "ti,cs-read-setup-ns", &val))
300-
data->rsetup = val;
338+
data->timings.rsetup = aemif_calc_rate(pdev, val, clk_rate);
301339

302340
if (!of_property_read_u32(np, "ti,cs-write-hold-ns", &val))
303-
data->whold = val;
341+
data->timings.whold = aemif_calc_rate(pdev, val, clk_rate);
304342

305343
if (!of_property_read_u32(np, "ti,cs-write-strobe-ns", &val))
306-
data->wstrobe = val;
344+
data->timings.wstrobe = aemif_calc_rate(pdev, val, clk_rate);
307345

308346
if (!of_property_read_u32(np, "ti,cs-write-setup-ns", &val))
309-
data->wsetup = val;
347+
data->timings.wsetup = aemif_calc_rate(pdev, val, clk_rate);
310348

311349
if (!of_property_read_u32(np, "ti,cs-bus-width", &val))
312350
if (val == 16)
313351
data->asize = 1;
314352
data->enable_ew = of_property_read_bool(np, "ti,cs-extended-wait-mode");
315353
data->enable_ss = of_property_read_bool(np, "ti,cs-select-strobe-mode");
316-
return 0;
354+
355+
return aemif_check_cs_timings(&data->timings);
317356
}
318357

319358
static const struct of_device_id aemif_of_match[] = {
@@ -351,6 +390,7 @@ static int aemif_probe(struct platform_device *pdev)
351390
if (IS_ERR(aemif->base))
352391
return PTR_ERR(aemif->base);
353392

393+
mutex_init(&aemif->config_cs_lock);
354394
if (np) {
355395
/*
356396
* For every controller device node, there is a cs device node

include/linux/memory/ti-aemif.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
3+
#ifndef __MEMORY_TI_AEMIF_H
4+
#define __MEMORY_TI_AEMIF_H
5+
6+
/**
7+
* struct aemif_cs_timings: structure to hold CS timing configuration
8+
* values are expressed in number of clock cycles - 1
9+
* @ta: minimum turn around time
10+
* @rhold: read hold width
11+
* @rstrobe: read strobe width
12+
* @rsetup: read setup width
13+
* @whold: write hold width
14+
* @wstrobe: write strobe width
15+
* @wsetup: write setup width
16+
*/
17+
struct aemif_cs_timings {
18+
u32 ta;
19+
u32 rhold;
20+
u32 rstrobe;
21+
u32 rsetup;
22+
u32 whold;
23+
u32 wstrobe;
24+
u32 wsetup;
25+
};
26+
27+
struct aemif_device;
28+
29+
int aemif_set_cs_timings(struct aemif_device *aemif, u8 cs, struct aemif_cs_timings *timings);
30+
int aemif_check_cs_timings(struct aemif_cs_timings *timings);
31+
32+
#endif // __MEMORY_TI_AEMIF_H

0 commit comments

Comments
 (0)