blob: 9c077f3ff90621f9c6e28383a4ab9a94e9b754c3 [file] [log] [blame]
Kongyang Liu61c9f282024-04-20 15:08:23 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2024, Kongyang Liu <seashell11234455@gmail.com>
4 */
5
6#include <clk.h>
7#include <dm.h>
8#include <linux/bitops.h>
9#include <linux/io.h>
10#include <linux/kernel.h>
11#include <spi-mem.h>
12#include <spi.h>
13#include <spi_flash.h>
14#include <wait_bit.h>
15
16#define CV1800B_SPI_CTRL_SCK_DIV_MASK GENMASK(10, 0)
17#define CV1800B_SPI_CTRL_CPHA BIT(12)
18#define CV1800B_SPI_CTRL_CPOL BIT(13)
19
20#define CV1800B_SPI_CE_MANUAL BIT(0)
21#define CV1800B_SPI_CE_MANUAL_EN BIT(1)
22#define CV1800B_SPI_CE_ENABLE (CV1800B_SPI_CE_MANUAL | \
23 CV1800B_SPI_CE_MANUAL_EN)
24#define CV1800B_SPI_CE_DISABLE CV1800B_SPI_CE_MANUAL_EN
25#define CV1800B_SPI_CE_HARDWARE 0
26
27#define CV1800B_SPI_DLY_CTRL_NEG_SAMPLE BIT(14)
28
29#define CV1800B_SPI_TRAN_MODE_RX BIT(0)
30#define CV1800B_SPI_TRAN_MODE_TX BIT(1)
31#define CV1800B_SPI_TRAN_FAST_MODE BIT(3)
32#define CV1800B_SPI_TRAN_BUS_WIDTH_1_BIT 0x0
33#define CV1800B_SPI_TRAN_BUS_WIDTH_2_BIT BIT(4)
34#define CV1800B_SPI_TRAN_BUS_WIDTH_4_BIT BIT(5)
35#define CV1800B_SPI_TRAN_ADDR_3_BYTES (3 << 8)
36#define CV1800B_SPI_TRAN_ADDR_4_BYTES (4 << 8)
37#define CV1800B_SPI_TRAN_WITH_CMD BIT(11)
38#define CV1800B_SPI_TRAN_GO_BUSY BIT(15)
39#define CV1800B_SPI_TRAN_DUMMY_CYC_MASK GENMASK(19, 16)
40#define CV1800B_SPI_TRAN_DUMMY_CYC_OFFSET 16
41#define CV1800B_SPI_TRAN_BYTE4_EN BIT(20)
42#define CV1800B_SPI_TRAN_BYTE4_CMD BIT(21)
43
44#define CV1800B_SPI_FF_PT_AVAILABLE_MASK GENMASK(3, 0)
45
46#define CV1800B_SPI_INT_TRAN_DONE BIT(0)
47#define CV1800B_SPI_INT_RD_FIFO BIT(2)
48#define CV1800B_SPI_INT_WR_FIFO BIT(3)
49
50#define CV1800B_FIFO_CAPACITY 8
51#define CV1800B_DEFAULT_DIV 4
52
53struct cv1800b_spif_regs {
54 u32 spi_ctrl;
55 u32 ce_ctrl;
56 u32 dly_ctrl;
57 u32 dmmr_ctrl;
58 u32 tran_csr;
59 u32 tran_num;
60 u32 ff_port;
61 u32 reserved0;
62 u32 ff_pt;
63 u32 reserved1;
64 u32 int_sts;
65 u32 int_en;
66};
67
68struct cv1800b_spi_priv {
69 struct cv1800b_spif_regs *regs;
70 uint clk_freq;
71 uint mode;
72 int div;
73};
74
75static int cv1800b_spi_probe(struct udevice *bus)
76{
77 struct cv1800b_spi_priv *priv = dev_get_priv(bus);
78 struct clk clkdev;
79 int ret;
80
81 priv->regs = (struct cv1800b_spif_regs *)dev_read_addr_ptr(bus);
82 if (priv->regs == 0)
83 return -EINVAL;
84
85 ret = clk_get_by_index(bus, 0, &clkdev);
86 if (ret)
87 return ret;
88 priv->clk_freq = clk_get_rate(&clkdev);
89
90 /* DMMR mode is enabled by default, disable it */
91 writel(0, &priv->regs->dmmr_ctrl);
92
93 return 0;
94}
95
96static void cv1800b_spi_config_dmmr(struct cv1800b_spi_priv *priv, struct spi_nor *flash)
97{
98 struct cv1800b_spif_regs *regs = priv->regs;
99 u32 read_cmd = flash->read_opcode;
100 u32 val;
101
102 val = CV1800B_SPI_TRAN_MODE_RX | CV1800B_SPI_TRAN_WITH_CMD;
103
104 switch (read_cmd) {
105 case SPINOR_OP_READ_4B:
106 case SPINOR_OP_READ_FAST_4B:
107 case SPINOR_OP_READ_1_1_2_4B:
108 case SPINOR_OP_READ_1_1_4_4B:
109 val |= CV1800B_SPI_TRAN_ADDR_4_BYTES |
110 CV1800B_SPI_TRAN_BYTE4_EN | CV1800B_SPI_TRAN_BYTE4_CMD;
111 break;
112 case SPINOR_OP_READ:
113 case SPINOR_OP_READ_FAST:
114 case SPINOR_OP_READ_1_1_2:
115 case SPINOR_OP_READ_1_1_4:
116 val |= CV1800B_SPI_TRAN_ADDR_3_BYTES;
117 break;
118 }
119
120 switch (read_cmd) {
121 case SPINOR_OP_READ_FAST:
122 case SPINOR_OP_READ_FAST_4B:
123 val |= CV1800B_SPI_TRAN_FAST_MODE;
124 break;
125 }
126
127 switch (read_cmd) {
128 case SPINOR_OP_READ_1_1_2:
129 case SPINOR_OP_READ_1_1_2_4B:
130 val |= CV1800B_SPI_TRAN_BUS_WIDTH_2_BIT;
131 break;
132 case SPINOR_OP_READ_1_1_4:
133 case SPINOR_OP_READ_1_1_4_4B:
134 val |= CV1800B_SPI_TRAN_BUS_WIDTH_4_BIT;
135 break;
136 }
137
138 val |= (flash->read_dummy & CV1800B_SPI_TRAN_DUMMY_CYC_MASK)
139 << CV1800B_SPI_TRAN_DUMMY_CYC_OFFSET;
140 writel(val, &regs->tran_csr);
141}
142
143static void cv1800b_set_clk_div(struct cv1800b_spi_priv *priv, u32 div)
144{
145 struct cv1800b_spif_regs *regs = priv->regs;
146 u32 neg_sample = 0;
147
148 clrsetbits_le32(&regs->spi_ctrl, CV1800B_SPI_CTRL_SCK_DIV_MASK, div);
149
150 if (div < CV1800B_DEFAULT_DIV)
151 neg_sample = CV1800B_SPI_DLY_CTRL_NEG_SAMPLE;
152 clrsetbits_le32(&regs->dly_ctrl, CV1800B_SPI_DLY_CTRL_NEG_SAMPLE, neg_sample);
153}
154
155static int cv1800b_spi_transfer(struct cv1800b_spi_priv *priv,
156 u8 *din, const u8 *dout, uint len, ulong flags)
157{
158 struct cv1800b_spif_regs *regs = priv->regs;
159 u32 tran_csr;
160 u32 xfer_size, off;
161 u32 fifo_cnt;
162 u32 interrupt_mask;
163
164 if (din) {
165 /* Slow down on receiving */
166 cv1800b_set_clk_div(priv, CV1800B_DEFAULT_DIV);
167 interrupt_mask = CV1800B_SPI_INT_RD_FIFO;
168 } else {
169 interrupt_mask = CV1800B_SPI_INT_WR_FIFO;
170 }
171
172 writel(0, &regs->ff_pt);
173 writel(len, &regs->tran_num);
174
175 tran_csr = CV1800B_SPI_TRAN_GO_BUSY;
176 if (din) {
177 tran_csr |= CV1800B_SPI_TRAN_MODE_RX;
178 } else {
179 tran_csr |= CV1800B_SPI_TRAN_MODE_TX;
180 if (!(flags & SPI_XFER_BEGIN) && (priv->mode & SPI_TX_QUAD))
181 tran_csr |= CV1800B_SPI_TRAN_BUS_WIDTH_4_BIT;
182 }
183 writel(tran_csr, &regs->tran_csr);
184
185 wait_for_bit_le32(&regs->int_sts, interrupt_mask, true, 3000, false);
186
187 off = 0;
188 while (off < len) {
189 xfer_size = min_t(u32, len - off, CV1800B_FIFO_CAPACITY);
190
191 fifo_cnt = readl(&regs->ff_pt) & CV1800B_SPI_FF_PT_AVAILABLE_MASK;
192 if (din)
193 xfer_size = min(xfer_size, fifo_cnt);
194 else
195 xfer_size = min(xfer_size, CV1800B_FIFO_CAPACITY - fifo_cnt);
196
197 while (xfer_size--) {
198 if (din)
199 din[off++] = readb(&regs->ff_port);
200 else
201 writeb(dout[off++], &regs->ff_port);
202 }
203 }
204
205 wait_for_bit_le32(&regs->int_sts, CV1800B_SPI_INT_TRAN_DONE, true, 3000, false);
206 writel(0, &regs->ff_pt);
207 clrbits_le32(&regs->int_sts, CV1800B_SPI_INT_TRAN_DONE | interrupt_mask);
208
209 if (din)
210 cv1800b_set_clk_div(priv, priv->div);
211 return 0;
212}
213
214static int cv1800b_spi_xfer(struct udevice *dev, unsigned int bitlen,
215 const void *dout, void *din, unsigned long flags)
216{
217 struct udevice *bus = dev->parent;
218 struct cv1800b_spi_priv *priv = dev_get_priv(bus);
219 struct cv1800b_spif_regs *regs = priv->regs;
220
221 if (bitlen == 0)
222 goto out;
223
224 if (bitlen % 8) {
225 flags |= SPI_XFER_END;
226 goto out;
227 }
228
229 if (flags & SPI_XFER_BEGIN)
230 writel(CV1800B_SPI_CE_DISABLE, &regs->ce_ctrl);
231
232 if (din || dout)
233 cv1800b_spi_transfer(priv, din, dout, bitlen / 8, flags);
234
235out:
236 if (flags & SPI_XFER_END)
237 writel(CV1800B_SPI_CE_ENABLE, &regs->ce_ctrl);
238 return 0;
239}
240
241static int cv1800b_spi_set_speed(struct udevice *bus, uint speed)
242{
243 struct cv1800b_spi_priv *priv = dev_get_priv(bus);
244
245 priv->div = DIV_ROUND_CLOSEST(priv->clk_freq, speed * 2) - 1;
246 if (priv->div <= 0)
247 priv->div = CV1800B_DEFAULT_DIV;
248
249 cv1800b_set_clk_div(priv, priv->div);
250
251 return 0;
252}
253
254static int cv1800b_spi_set_mode(struct udevice *bus, uint mode)
255{
256 struct cv1800b_spi_priv *priv = dev_get_priv(bus);
257 struct cv1800b_spif_regs *regs = priv->regs;
258 u32 val = 0;
259
260 if (mode & SPI_CPHA)
261 val |= CV1800B_SPI_CTRL_CPHA;
262 if (mode & SPI_CPOL)
263 val |= CV1800B_SPI_CTRL_CPOL;
264 clrsetbits_le32(&regs->spi_ctrl, CV1800B_SPI_CTRL_CPHA | CV1800B_SPI_CTRL_CPOL, val);
265
266 priv->mode = mode;
267
268 return 0;
269}
270
271static int cv1800b_spi_exec_op(struct spi_slave *slave, const struct spi_mem_op *op)
272{
273 struct udevice *bus = slave->dev->parent;
274 struct cv1800b_spi_priv *priv = dev_get_priv(bus);
275 struct cv1800b_spif_regs *regs = priv->regs;
276 struct spi_nor *flash = dev_get_uclass_priv(slave->dev);
277 u32 old_tran_csr;
278
279 if (!(op->data.nbytes > 0 && op->data.dir == SPI_MEM_DATA_IN) ||
280 !(op->addr.nbytes > 0 && op->addr.nbytes <= 4))
281 return -ENOTSUPP;
282
283 old_tran_csr = readl(&regs->tran_csr);
284 writel(CV1800B_SPI_CE_HARDWARE, &regs->ce_ctrl);
285
286 cv1800b_spi_config_dmmr(priv, flash);
287
288 writel(1, &regs->dmmr_ctrl);
289 memcpy(op->data.buf.in, (void *)priv->regs + op->addr.val, op->data.nbytes);
290 writel(0, &regs->dmmr_ctrl);
291
292 writel(CV1800B_SPI_CE_ENABLE, &regs->ce_ctrl);
293 writel(old_tran_csr, &regs->tran_csr);
294
295 return 0;
296}
297
298static const struct spi_controller_mem_ops cv1800b_spi_mem_ops = {
299 .exec_op = cv1800b_spi_exec_op,
300};
301
302static const struct dm_spi_ops cv1800b_spi_ops = {
303 .xfer = cv1800b_spi_xfer,
304 .mem_ops = &cv1800b_spi_mem_ops,
305 .set_speed = cv1800b_spi_set_speed,
306 .set_mode = cv1800b_spi_set_mode,
307};
308
309static const struct udevice_id cv1800b_spi_ids[] = {
310 { .compatible = "sophgo,cv1800b-spif" },
311 { }
312};
313
314U_BOOT_DRIVER(cv1800b_spi) = {
315 .name = "cv1800b_spif",
316 .id = UCLASS_SPI,
317 .of_match = cv1800b_spi_ids,
318 .ops = &cv1800b_spi_ops,
319 .priv_auto = sizeof(struct cv1800b_spi_priv),
320 .probe = cv1800b_spi_probe,
321};