Skip to content

Commit 376a0b9

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 nand/next
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 # -----BEGIN PGP SIGNATURE----- # # iQJEBAABCgAuFiEE3dJiKD0RGyM7briowTdm5oaLg9cFAmddXowQHGtyemtAa2Vy # bmVsLm9yZwAKCRDBN2bmhouD15LAD/9E/LtoM//W6VHRIItF0AmYH7e2E4D2ECwl # MQyLCsj4zieIg5TLlnZMC/P2P1BIZoerCPN4QC+M/r5NZrMfufZYNdlpY0sqpkd2 # CoW2w8TjN+PHpzOGncHvbxdD5h/SHS0cRoOqiTJmZXeVf4FCq7riv8piGyoontNC # puzsSjjCOk/AHMHsHBVB3/VbWelvQbjq/qKyW/+aWl8tw3W+Ck4qiPcUMWXkLHhx # FfsrsUXWqOP7di2zcwWx4N+rNJWuYaM6xv6FoTlkVAhc094vDE/uKvBbQcizX/fd # 1iMgUsvt6BpLGKbJ8G3ZBL/DY+ugJv5oC7Cql0AWi9/NjW/Yil9C2a0RqKl48TCW # a4EeJrrXnocK5l0PDodQbyNL+D9c7tiwzs10/VEg2MnchaN8ZvdP/YfLICkJiXcF # ZAio89mG6r/S/AAe05M1vKso1Le/D0Lhx5IiJ9MDnHvJ5Hw2JPnGs7Dcqq5Xm47K # toY0kJmUfPZyAyavax7z1nGAAglpsXGN1m52AEoCcwMyU0DTamSUTf+a7pjKph78 # jrv1g2MB06kjGhXVT//8fS07C5b0v/Rn5CB2LgakgGsug1g6+YD0/rAylGNUTjHX # Dx9lVDz8llr68OP+bdUOTO9mlx+t1gI6SVg9U9gUKHbr95xVhMlyRuwwmqwdsPK8 # U+8kZyAi9w== # =uAGp # -----END PGP SIGNATURE----- # gpg: Signature made Sat 14 Dec 2024 11:31:40 AM CET # gpg: using RSA key DDD262283D111B233B6EB8A8C13766E6868B83D7 # gpg: issuer "[email protected]" # gpg: Good signature from "Krzysztof Kozlowski <[email protected]>" [marginal] # gpg: aka "Krzysztof Kozlowski <[email protected]>" [marginal] # gpg: aka "Krzysztof Kozlowski <[email protected]>" [marginal] # gpg: aka "Krzysztof Kozlowski <[email protected]>" [marginal] # gpg: aka "Krzysztof Kozłowski <[email protected]>" [marginal] # gpg: [email protected]: Verified 3 signatures in the past 3 years. Encrypted 0 # messages. # gpg: Warning: you have yet to encrypt a message to this key! # gpg: Warning: if you think you've seen more signatures by this key and user # id, then this key might be a forgery! Carefully examine the email address # for small variations. If the key is suspect, then use # gpg --tofu-policy bad 9BD07E0E0C51F8D59677B7541B93437D3B41629B # to mark it as being bad. # gpg: WARNING: The key's User ID is not certified with sufficiently trusted signatures! # gpg: It is not certain that the signature belongs to the owner. # Primary key fingerprint: 9BD0 7E0E 0C51 F8D5 9677 B754 1B93 437D 3B41 629B # Subkey fingerprint: DDD2 6228 3D11 1B23 3B6E B8A8 C137 66E6 868B 83D7
2 parents 1f05f82 + df8e786 commit 376a0b9

File tree

2 files changed

+148
-76
lines changed

2 files changed

+148
-76
lines changed

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)