1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
From e1cf48a13626d0c42c5191dc4852f4dc271de010 Mon Sep 17 00:00:00 2001
From: Han Xu <han.xu@nxp.com>
Date: Tue, 9 Jul 2019 16:21:14 -0500
Subject: [PATCH] spi: spi-fsl-qspi: dynamically alloc AHB memory for QSPI
dynamically alloc AHB memory for QSPI controller.
Signed-off-by: Han Xu <han.xu@nxp.com>
[rebase]
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
drivers/spi/spi-fsl-qspi.c | 60 +++++++++++++++++++++++++++++++++-------------
1 file changed, 43 insertions(+), 17 deletions(-)
--- a/drivers/spi/spi-fsl-qspi.c
+++ b/drivers/spi/spi-fsl-qspi.c
@@ -192,6 +192,8 @@
*/
#define QUADSPI_QUIRK_USE_TDH_SETTING BIT(5)
+#define QUADSPI_MIN_IOMAP SZ_4M
+
struct fsl_qspi_devtype_data {
unsigned int rxfifo;
unsigned int txfifo;
@@ -254,6 +256,9 @@ struct fsl_qspi {
void __iomem *iobase;
void __iomem *ahb_addr;
u32 memmap_phy;
+ u32 memmap_phy_size;
+ u32 memmap_start;
+ u32 memmap_len;
struct clk *clk, *clk_en;
struct device *dev;
struct completion c;
@@ -537,11 +542,34 @@ static void fsl_qspi_select_mem(struct f
fsl_qspi_invalidate(q);
}
-static void fsl_qspi_read_ahb(struct fsl_qspi *q, const struct spi_mem_op *op)
+static int fsl_qspi_read_ahb(struct fsl_qspi *q, const struct spi_mem_op *op)
{
+ u32 start = op->addr.val + q->selected * q->memmap_phy_size / 4;
+ u32 len = op->data.nbytes;
+
+ /* if necessary, ioremap before AHB read */
+ if ((!q->ahb_addr) || start < q->memmap_start ||
+ start + len > q->memmap_start + q->memmap_len) {
+ if (q->ahb_addr) {
+ iounmap(q->ahb_addr);
+ }
+
+ q->memmap_start = start;
+ q->memmap_len = len > QUADSPI_MIN_IOMAP ?
+ len : QUADSPI_MIN_IOMAP;
+
+ q->ahb_addr = ioremap_wc(q->memmap_phy + q->memmap_start,
+ q->memmap_len);
+ if (!q->ahb_addr) {
+ dev_err(q->dev, "failed to alloc memory\n");
+ return -ENOMEM;
+ }
+ }
+
memcpy_fromio(op->data.buf.in,
- q->ahb_addr + q->selected * q->devtype_data->ahb_buf_size,
- op->data.nbytes);
+ q->ahb_addr + start - q->memmap_start, len);
+
+ return 0;
}
static void fsl_qspi_fill_txfifo(struct fsl_qspi *q,
@@ -646,7 +674,7 @@ static int fsl_qspi_exec_op(struct spi_m
addr_offset = q->memmap_phy;
qspi_writel(q,
- q->selected * q->devtype_data->ahb_buf_size + addr_offset,
+ q->selected * q->memmap_phy_size / 4 + addr_offset,
base + QUADSPI_SFAR);
qspi_writel(q, qspi_readl(q, base + QUADSPI_MCR) |
@@ -665,7 +693,7 @@ static int fsl_qspi_exec_op(struct spi_m
*/
if (op->data.nbytes > (q->devtype_data->rxfifo - 4) &&
op->data.dir == SPI_MEM_DATA_IN) {
- fsl_qspi_read_ahb(q, op);
+ err = fsl_qspi_read_ahb(q, op);
} else {
qspi_writel(q, QUADSPI_RBCT_WMRK_MASK |
QUADSPI_RBCT_RXBRD_USEIPS, base + QUADSPI_RBCT);
@@ -763,16 +791,16 @@ static int fsl_qspi_default_setup(struct
* In HW there can be a maximum of four chips on two buses with
* two chip selects on each bus. We use four chip selects in SW
* to differentiate between the four chips.
- * We use ahb_buf_size for each chip and set SFA1AD, SFA2AD, SFB1AD,
- * SFB2AD accordingly.
+ * We divide the total memory region size equally for each chip
+ * and set SFA1AD, SFA2AD, SFB1AD, SFB2AD accordingly.
*/
- qspi_writel(q, q->devtype_data->ahb_buf_size + addr_offset,
+ qspi_writel(q, q->memmap_phy_size / 4 + addr_offset,
base + QUADSPI_SFA1AD);
- qspi_writel(q, q->devtype_data->ahb_buf_size * 2 + addr_offset,
+ qspi_writel(q, q->memmap_phy_size / 4 * 2 + addr_offset,
base + QUADSPI_SFA2AD);
- qspi_writel(q, q->devtype_data->ahb_buf_size * 3 + addr_offset,
+ qspi_writel(q, q->memmap_phy_size / 4 * 3 + addr_offset,
base + QUADSPI_SFB1AD);
- qspi_writel(q, q->devtype_data->ahb_buf_size * 4 + addr_offset,
+ qspi_writel(q, q->memmap_phy_size / 4 * 4 + addr_offset,
base + QUADSPI_SFB2AD);
q->selected = -1;
@@ -859,13 +887,8 @@ static int fsl_qspi_probe(struct platfor
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"QuadSPI-memory");
- q->ahb_addr = devm_ioremap_resource(dev, res);
- if (IS_ERR(q->ahb_addr)) {
- ret = PTR_ERR(q->ahb_addr);
- goto err_put_ctrl;
- }
-
q->memmap_phy = res->start;
+ q->memmap_phy_size = resource_size(res);
/* find the clocks */
q->clk_en = devm_clk_get(dev, "qspi_en");
@@ -939,6 +962,9 @@ static int fsl_qspi_remove(struct platfo
mutex_destroy(&q->lock);
+ if (q->ahb_addr)
+ iounmap(q->ahb_addr);
+
return 0;
}
|