File Index
Files and directories
Sign in
FILE

spi-sg2044-nor.c

File preview with syntax highlighting.

linux-6.19.14/drivers/spi/spi-sg2044-nor.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * SG2044 SPI NOR controller driver
  4 *
  5 * Copyright (c) 2025 Longbin Li <looong.bin@gmail.com>
  6 */
  7
  8#include <linux/bitfield.h>
  9#include <linux/clk.h>
 10#include <linux/iopoll.h>
 11#include <linux/module.h>
 12#include <linux/of.h>
 13#include <linux/platform_device.h>
 14#include <linux/spi/spi-mem.h>
 15
 16/* Hardware register definitions */
 17#define SPIFMC_CTRL				0x00
 18#define SPIFMC_CTRL_CPHA			BIT(12)
 19#define SPIFMC_CTRL_CPOL			BIT(13)
 20#define SPIFMC_CTRL_HOLD_OL			BIT(14)
 21#define SPIFMC_CTRL_WP_OL			BIT(15)
 22#define SPIFMC_CTRL_LSBF			BIT(20)
 23#define SPIFMC_CTRL_SRST			BIT(21)
 24#define SPIFMC_CTRL_SCK_DIV_SHIFT		0
 25#define SPIFMC_CTRL_FRAME_LEN_SHIFT		16
 26#define SPIFMC_CTRL_SCK_DIV_MASK		0x7FF
 27
 28#define SPIFMC_CE_CTRL				0x04
 29#define SPIFMC_CE_CTRL_CEMANUAL			BIT(0)
 30#define SPIFMC_CE_CTRL_CEMANUAL_EN		BIT(1)
 31
 32#define SPIFMC_DLY_CTRL				0x08
 33#define SPIFMC_CTRL_FM_INTVL_MASK		0x000f
 34#define SPIFMC_CTRL_FM_INTVL			BIT(0)
 35#define SPIFMC_CTRL_CET_MASK			0x0f00
 36#define SPIFMC_CTRL_CET				BIT(8)
 37
 38#define SPIFMC_DMMR				0x0c
 39
 40#define SPIFMC_TRAN_CSR				0x10
 41#define SPIFMC_TRAN_CSR_TRAN_MODE_MASK		GENMASK(1, 0)
 42#define SPIFMC_TRAN_CSR_TRAN_MODE_RX		BIT(0)
 43#define SPIFMC_TRAN_CSR_TRAN_MODE_TX		BIT(1)
 44#define SPIFMC_TRAN_CSR_FAST_MODE		BIT(3)
 45#define SPIFMC_TRAN_CSR_BUS_WIDTH_MASK		GENMASK(5, 4)
 46#define SPIFMC_TRAN_CSR_BUS_WIDTH_1_BIT		(0x00 << 4)
 47#define SPIFMC_TRAN_CSR_BUS_WIDTH_2_BIT		(0x01 << 4)
 48#define SPIFMC_TRAN_CSR_BUS_WIDTH_4_BIT		(0x02 << 4)
 49#define SPIFMC_TRAN_CSR_DMA_EN			BIT(6)
 50#define SPIFMC_TRAN_CSR_MISO_LEVEL		BIT(7)
 51#define SPIFMC_TRAN_CSR_ADDR_BYTES_MASK		GENMASK(10, 8)
 52#define SPIFMC_TRAN_CSR_ADDR_BYTES_SHIFT	8
 53#define SPIFMC_TRAN_CSR_WITH_CMD		BIT(11)
 54#define SPIFMC_TRAN_CSR_FIFO_TRG_LVL_MASK	GENMASK(13, 12)
 55#define SPIFMC_TRAN_CSR_FIFO_TRG_LVL_1_BYTE	(0x00 << 12)
 56#define SPIFMC_TRAN_CSR_FIFO_TRG_LVL_2_BYTE	(0x01 << 12)
 57#define SPIFMC_TRAN_CSR_FIFO_TRG_LVL_4_BYTE	(0x02 << 12)
 58#define SPIFMC_TRAN_CSR_FIFO_TRG_LVL_8_BYTE	(0x03 << 12)
 59#define SPIFMC_TRAN_CSR_GO_BUSY			BIT(15)
 60#define SPIFMC_TRAN_CSR_ADDR4B_SHIFT		20
 61#define SPIFMC_TRAN_CSR_CMD4B_SHIFT		21
 62
 63#define SPIFMC_TRAN_NUM				0x14
 64#define SPIFMC_FIFO_PORT			0x18
 65#define SPIFMC_FIFO_PT				0x20
 66
 67#define SPIFMC_INT_STS				0x28
 68#define SPIFMC_INT_TRAN_DONE			BIT(0)
 69#define SPIFMC_INT_RD_FIFO			BIT(2)
 70#define SPIFMC_INT_WR_FIFO			BIT(3)
 71#define SPIFMC_INT_RX_FRAME			BIT(4)
 72#define SPIFMC_INT_TX_FRAME			BIT(5)
 73
 74#define SPIFMC_INT_EN				0x2c
 75#define SPIFMC_INT_TRAN_DONE_EN			BIT(0)
 76#define SPIFMC_INT_RD_FIFO_EN			BIT(2)
 77#define SPIFMC_INT_WR_FIFO_EN			BIT(3)
 78#define SPIFMC_INT_RX_FRAME_EN			BIT(4)
 79#define SPIFMC_INT_TX_FRAME_EN			BIT(5)
 80
 81#define SPIFMC_OPT				0x030
 82#define SPIFMC_OPT_DISABLE_FIFO_FLUSH		BIT(1)
 83
 84#define SPIFMC_MAX_FIFO_DEPTH			8
 85
 86#define SPIFMC_MAX_READ_SIZE			0x10000
 87
 88struct sg204x_spifmc_chip_info {
 89	bool has_opt_reg;
 90	u32 rd_fifo_int_trigger_level;
 91};
 92
 93struct sg2044_spifmc {
 94	struct spi_controller *ctrl;
 95	void __iomem *io_base;
 96	struct device *dev;
 97	struct mutex lock;
 98	struct clk *clk;
 99	const struct sg204x_spifmc_chip_info *chip_info;
100};
101
102static int sg2044_spifmc_wait_int(struct sg2044_spifmc *spifmc, u8 int_type)
103{
104	u32 stat;
105
106	return readl_poll_timeout(spifmc->io_base + SPIFMC_INT_STS, stat,
107				  (stat & int_type), 0, 1000000);
108}
109
110static int sg2044_spifmc_wait_xfer_size(struct sg2044_spifmc *spifmc,
111					int xfer_size)
112{
113	u8 stat;
114
115	return readl_poll_timeout(spifmc->io_base + SPIFMC_FIFO_PT, stat,
116				  ((stat & 0xf) == xfer_size), 1, 1000000);
117}
118
119static u32 sg2044_spifmc_init_reg(struct sg2044_spifmc *spifmc)
120{
121	u32 reg;
122
123	reg = readl(spifmc->io_base + SPIFMC_TRAN_CSR);
124	reg &= ~(SPIFMC_TRAN_CSR_TRAN_MODE_MASK |
125		 SPIFMC_TRAN_CSR_FAST_MODE |
126		 SPIFMC_TRAN_CSR_BUS_WIDTH_MASK |
127		 SPIFMC_TRAN_CSR_DMA_EN |
128		 SPIFMC_TRAN_CSR_ADDR_BYTES_MASK |
129		 SPIFMC_TRAN_CSR_WITH_CMD |
130		 SPIFMC_TRAN_CSR_FIFO_TRG_LVL_MASK);
131
132	writel(reg, spifmc->io_base + SPIFMC_TRAN_CSR);
133
134	return reg;
135}
136
137static ssize_t sg2044_spifmc_read_64k(struct sg2044_spifmc *spifmc,
138				      const struct spi_mem_op *op, loff_t from,
139				      size_t len, u_char *buf)
140{
141	int xfer_size, offset;
142	u32 reg;
143	int ret;
144	int i;
145
146	reg = sg2044_spifmc_init_reg(spifmc);
147	reg |= (op->addr.nbytes + op->dummy.nbytes) << SPIFMC_TRAN_CSR_ADDR_BYTES_SHIFT;
148	reg |= spifmc->chip_info->rd_fifo_int_trigger_level;
149	reg |= SPIFMC_TRAN_CSR_WITH_CMD;
150	reg |= SPIFMC_TRAN_CSR_TRAN_MODE_RX;
151
152	writel(0, spifmc->io_base + SPIFMC_FIFO_PT);
153	writeb(op->cmd.opcode, spifmc->io_base + SPIFMC_FIFO_PORT);
154
155	for (i = op->addr.nbytes - 1; i >= 0; i--)
156		writeb((from >> i * 8) & 0xff, spifmc->io_base + SPIFMC_FIFO_PORT);
157
158	for (i = 0; i < op->dummy.nbytes; i++)
159		writeb(0xff, spifmc->io_base + SPIFMC_FIFO_PORT);
160
161	writel(len, spifmc->io_base + SPIFMC_TRAN_NUM);
162	writel(0, spifmc->io_base + SPIFMC_INT_STS);
163	reg |= SPIFMC_TRAN_CSR_GO_BUSY;
164	writel(reg, spifmc->io_base + SPIFMC_TRAN_CSR);
165
166	ret = sg2044_spifmc_wait_int(spifmc, SPIFMC_INT_RD_FIFO);
167	if (ret < 0)
168		return ret;
169
170	offset = 0;
171	while (offset < len) {
172		xfer_size = min_t(size_t, SPIFMC_MAX_FIFO_DEPTH, len - offset);
173
174		ret = sg2044_spifmc_wait_xfer_size(spifmc, xfer_size);
175		if (ret < 0)
176			return ret;
177
178		for (i = 0; i < xfer_size; i++)
179			buf[i + offset] = readb(spifmc->io_base + SPIFMC_FIFO_PORT);
180
181		offset += xfer_size;
182	}
183
184	ret = sg2044_spifmc_wait_int(spifmc, SPIFMC_INT_TRAN_DONE);
185	if (ret < 0)
186		return ret;
187
188	writel(0, spifmc->io_base + SPIFMC_FIFO_PT);
189
190	return len;
191}
192
193static ssize_t sg2044_spifmc_read(struct sg2044_spifmc *spifmc,
194				  const struct spi_mem_op *op)
195{
196	size_t xfer_size;
197	size_t offset;
198	loff_t from = op->addr.val;
199	size_t len = op->data.nbytes;
200	int ret;
201	u8 *din = op->data.buf.in;
202
203	offset = 0;
204	while (offset < len) {
205		xfer_size = min_t(size_t, SPIFMC_MAX_READ_SIZE, len - offset);
206
207		ret = sg2044_spifmc_read_64k(spifmc, op, from, xfer_size, din);
208		if (ret < 0)
209			return ret;
210
211		offset += xfer_size;
212		din += xfer_size;
213		from += xfer_size;
214	}
215
216	return 0;
217}
218
219static ssize_t sg2044_spifmc_write(struct sg2044_spifmc *spifmc,
220				   const struct spi_mem_op *op)
221{
222	size_t xfer_size;
223	const u8 *dout = op->data.buf.out;
224	int i, offset;
225	int ret;
226	u32 reg;
227
228	reg = sg2044_spifmc_init_reg(spifmc);
229	reg |= (op->addr.nbytes + op->dummy.nbytes) << SPIFMC_TRAN_CSR_ADDR_BYTES_SHIFT;
230	reg |= SPIFMC_TRAN_CSR_FIFO_TRG_LVL_8_BYTE;
231	reg |= SPIFMC_TRAN_CSR_WITH_CMD;
232	reg |= SPIFMC_TRAN_CSR_TRAN_MODE_TX;
233
234	writel(0, spifmc->io_base + SPIFMC_FIFO_PT);
235	writeb(op->cmd.opcode, spifmc->io_base + SPIFMC_FIFO_PORT);
236
237	for (i = op->addr.nbytes - 1; i >= 0; i--)
238		writeb((op->addr.val >> i * 8) & 0xff, spifmc->io_base + SPIFMC_FIFO_PORT);
239
240	for (i = 0; i < op->dummy.nbytes; i++)
241		writeb(0xff, spifmc->io_base + SPIFMC_FIFO_PORT);
242
243	writel(0, spifmc->io_base + SPIFMC_INT_STS);
244	writel(op->data.nbytes, spifmc->io_base + SPIFMC_TRAN_NUM);
245	reg |= SPIFMC_TRAN_CSR_GO_BUSY;
246	writel(reg, spifmc->io_base + SPIFMC_TRAN_CSR);
247
248	ret = sg2044_spifmc_wait_xfer_size(spifmc, 0);
249	if (ret < 0)
250		return ret;
251
252	writel(0, spifmc->io_base + SPIFMC_FIFO_PT);
253
254	offset = 0;
255	while (offset < op->data.nbytes) {
256		xfer_size = min_t(size_t, SPIFMC_MAX_FIFO_DEPTH, op->data.nbytes - offset);
257
258		ret = sg2044_spifmc_wait_xfer_size(spifmc, 0);
259		if (ret < 0)
260			return ret;
261
262		for (i = 0; i < xfer_size; i++)
263			writeb(dout[i + offset], spifmc->io_base + SPIFMC_FIFO_PORT);
264
265		offset += xfer_size;
266	}
267
268	ret = sg2044_spifmc_wait_int(spifmc, SPIFMC_INT_TRAN_DONE);
269	if (ret < 0)
270		return ret;
271
272	writel(0, spifmc->io_base + SPIFMC_FIFO_PT);
273
274	return 0;
275}
276
277static ssize_t sg2044_spifmc_tran_cmd(struct sg2044_spifmc *spifmc,
278				      const struct spi_mem_op *op)
279{
280	int i, ret;
281	u32 reg;
282
283	reg = sg2044_spifmc_init_reg(spifmc);
284	reg |= (op->addr.nbytes + op->dummy.nbytes) << SPIFMC_TRAN_CSR_ADDR_BYTES_SHIFT;
285	reg |= SPIFMC_TRAN_CSR_FIFO_TRG_LVL_1_BYTE;
286	reg |= SPIFMC_TRAN_CSR_WITH_CMD;
287
288	writel(0, spifmc->io_base + SPIFMC_FIFO_PT);
289	writeb(op->cmd.opcode, spifmc->io_base + SPIFMC_FIFO_PORT);
290
291	for (i = op->addr.nbytes - 1; i >= 0; i--)
292		writeb((op->addr.val >> i * 8) & 0xff, spifmc->io_base + SPIFMC_FIFO_PORT);
293
294	for (i = 0; i < op->dummy.nbytes; i++)
295		writeb(0xff, spifmc->io_base + SPIFMC_FIFO_PORT);
296
297	writel(0, spifmc->io_base + SPIFMC_INT_STS);
298	reg |= SPIFMC_TRAN_CSR_GO_BUSY;
299	writel(reg, spifmc->io_base + SPIFMC_TRAN_CSR);
300
301	ret = sg2044_spifmc_wait_int(spifmc, SPIFMC_INT_TRAN_DONE);
302	if (ret < 0)
303		return ret;
304
305	writel(0, spifmc->io_base + SPIFMC_FIFO_PT);
306
307	return 0;
308}
309
310static void sg2044_spifmc_trans(struct sg2044_spifmc *spifmc,
311				const struct spi_mem_op *op)
312{
313	if (op->data.dir == SPI_MEM_DATA_IN)
314		sg2044_spifmc_read(spifmc, op);
315	else if (op->data.dir == SPI_MEM_DATA_OUT)
316		sg2044_spifmc_write(spifmc, op);
317	else
318		sg2044_spifmc_tran_cmd(spifmc, op);
319}
320
321static ssize_t sg2044_spifmc_trans_reg(struct sg2044_spifmc *spifmc,
322				       const struct spi_mem_op *op)
323{
324	const u8 *dout = NULL;
325	u8 *din = NULL;
326	size_t len = op->data.nbytes;
327	int ret, i;
328	u32 reg;
329
330	if (op->data.dir == SPI_MEM_DATA_IN)
331		din = op->data.buf.in;
332	else
333		dout = op->data.buf.out;
334
335	reg = sg2044_spifmc_init_reg(spifmc);
336	reg |= SPIFMC_TRAN_CSR_FIFO_TRG_LVL_1_BYTE;
337	reg |= SPIFMC_TRAN_CSR_WITH_CMD;
338
339	if (din) {
340		reg |= SPIFMC_TRAN_CSR_BUS_WIDTH_1_BIT;
341		reg |= SPIFMC_TRAN_CSR_TRAN_MODE_RX;
342		reg |= SPIFMC_TRAN_CSR_TRAN_MODE_TX;
343
344		if (spifmc->chip_info->has_opt_reg)
345			writel(SPIFMC_OPT_DISABLE_FIFO_FLUSH, spifmc->io_base + SPIFMC_OPT);
346	} else {
347		/*
348		 * If write values to the Status Register,
349		 * configure TRAN_CSR register as the same as
350		 * sg2044_spifmc_read_reg.
351		 */
352		if (op->cmd.opcode == 0x01) {
353			reg |= SPIFMC_TRAN_CSR_TRAN_MODE_RX;
354			reg |= SPIFMC_TRAN_CSR_TRAN_MODE_TX;
355			writel(len, spifmc->io_base + SPIFMC_TRAN_NUM);
356		}
357	}
358
359	writel(0, spifmc->io_base + SPIFMC_FIFO_PT);
360	writeb(op->cmd.opcode, spifmc->io_base + SPIFMC_FIFO_PORT);
361
362	for (i = 0; i < len; i++) {
363		if (din)
364			writeb(0xff, spifmc->io_base + SPIFMC_FIFO_PORT);
365		else
366			writeb(dout[i], spifmc->io_base + SPIFMC_FIFO_PORT);
367	}
368
369	writel(0, spifmc->io_base + SPIFMC_INT_STS);
370	writel(len, spifmc->io_base + SPIFMC_TRAN_NUM);
371	reg |= SPIFMC_TRAN_CSR_GO_BUSY;
372	writel(reg, spifmc->io_base + SPIFMC_TRAN_CSR);
373
374	ret = sg2044_spifmc_wait_int(spifmc, SPIFMC_INT_TRAN_DONE);
375	if (ret < 0)
376		return ret;
377
378	if (din) {
379		while (len--)
380			*din++ = readb(spifmc->io_base + SPIFMC_FIFO_PORT);
381	}
382
383	writel(0, spifmc->io_base + SPIFMC_FIFO_PT);
384
385	return 0;
386}
387
388static int sg2044_spifmc_exec_op(struct spi_mem *mem,
389				 const struct spi_mem_op *op)
390{
391	struct sg2044_spifmc *spifmc;
392
393	spifmc = spi_controller_get_devdata(mem->spi->controller);
394
395	mutex_lock(&spifmc->lock);
396
397	if (op->addr.nbytes == 0)
398		sg2044_spifmc_trans_reg(spifmc, op);
399	else
400		sg2044_spifmc_trans(spifmc, op);
401
402	mutex_unlock(&spifmc->lock);
403
404	return 0;
405}
406
407static const struct spi_controller_mem_ops sg2044_spifmc_mem_ops = {
408	.exec_op = sg2044_spifmc_exec_op,
409};
410
411static void sg2044_spifmc_init(struct sg2044_spifmc *spifmc)
412{
413	u32 tran_csr;
414	u32 reg;
415
416	writel(0, spifmc->io_base + SPIFMC_DMMR);
417
418	reg = readl(spifmc->io_base + SPIFMC_CTRL);
419	reg |= SPIFMC_CTRL_SRST;
420	reg &= ~(SPIFMC_CTRL_SCK_DIV_MASK);
421	reg |= 1;
422	writel(reg, spifmc->io_base + SPIFMC_CTRL);
423
424	writel(0, spifmc->io_base + SPIFMC_CE_CTRL);
425
426	tran_csr = readl(spifmc->io_base + SPIFMC_TRAN_CSR);
427	tran_csr |= (0 << SPIFMC_TRAN_CSR_ADDR_BYTES_SHIFT);
428	tran_csr |= SPIFMC_TRAN_CSR_FIFO_TRG_LVL_4_BYTE;
429	tran_csr |= SPIFMC_TRAN_CSR_WITH_CMD;
430	writel(tran_csr, spifmc->io_base + SPIFMC_TRAN_CSR);
431}
432
433static int sg2044_spifmc_probe(struct platform_device *pdev)
434{
435	struct device *dev = &pdev->dev;
436	struct spi_controller *ctrl;
437	struct sg2044_spifmc *spifmc;
438	int ret;
439
440	ctrl = devm_spi_alloc_host(&pdev->dev, sizeof(*spifmc));
441	if (!ctrl)
442		return -ENOMEM;
443
444	spifmc = spi_controller_get_devdata(ctrl);
445
446	spifmc->clk = devm_clk_get_enabled(&pdev->dev, NULL);
447	if (IS_ERR(spifmc->clk))
448		return dev_err_probe(dev, PTR_ERR(spifmc->clk), "Cannot get and enable AHB clock\n");
449
450	spifmc->dev = &pdev->dev;
451	spifmc->ctrl = ctrl;
452
453	spifmc->io_base = devm_platform_ioremap_resource(pdev, 0);
454	if (IS_ERR(spifmc->io_base))
455		return PTR_ERR(spifmc->io_base);
456
457	ctrl->num_chipselect = 1;
458	ctrl->dev.of_node = pdev->dev.of_node;
459	ctrl->bits_per_word_mask = SPI_BPW_MASK(8);
460	ctrl->auto_runtime_pm = false;
461	ctrl->mem_ops = &sg2044_spifmc_mem_ops;
462	ctrl->mode_bits = SPI_RX_DUAL | SPI_TX_DUAL | SPI_RX_QUAD | SPI_TX_QUAD;
463
464	ret = devm_mutex_init(dev, &spifmc->lock);
465	if (ret)
466		return ret;
467	spifmc->chip_info = device_get_match_data(&pdev->dev);
468	if (!spifmc->chip_info) {
469		dev_err(&pdev->dev, "Failed to get specific chip info\n");
470		return -EINVAL;
471	}
472
473	sg2044_spifmc_init(spifmc);
474	sg2044_spifmc_init_reg(spifmc);
475
476	ret = devm_spi_register_controller(&pdev->dev, ctrl);
477	if (ret)
478		return dev_err_probe(dev, ret, "spi_register_controller failed\n");
479
480	return 0;
481}
482
483static const struct sg204x_spifmc_chip_info sg2044_chip_info = {
484	.has_opt_reg = true,
485	.rd_fifo_int_trigger_level = SPIFMC_TRAN_CSR_FIFO_TRG_LVL_8_BYTE,
486};
487
488static const struct sg204x_spifmc_chip_info sg2042_chip_info = {
489	.has_opt_reg = false,
490	.rd_fifo_int_trigger_level = SPIFMC_TRAN_CSR_FIFO_TRG_LVL_1_BYTE,
491};
492
493static const struct of_device_id sg2044_spifmc_match[] = {
494	{ .compatible = "sophgo,sg2044-spifmc-nor", .data = &sg2044_chip_info },
495	{ .compatible = "sophgo,sg2042-spifmc-nor", .data = &sg2042_chip_info },
496	{ /* sentinel */ }
497};
498MODULE_DEVICE_TABLE(of, sg2044_spifmc_match);
499
500static struct platform_driver sg2044_nor_driver = {
501	.driver = {
502		.name = "sg2044,spifmc-nor",
503		.of_match_table = sg2044_spifmc_match,
504	},
505	.probe = sg2044_spifmc_probe,
506};
507module_platform_driver(sg2044_nor_driver);
508
509MODULE_DESCRIPTION("SG2044 SPI NOR controller driver");
510MODULE_AUTHOR("Longbin Li <looong.bin@gmail.com>");
511MODULE_LICENSE("GPL");
~/ Read-only file preview.