Lines Matching +full:f +full:- +full:ospi
1 // SPDX-License-Identifier: GPL-2.0-only
16 #include <linux/spi/spi-mem.h>
119 return (op->dummy.nbytes * 8) / op->dummy.buswidth; in f_ospi_get_dummy_cycle()
122 static void f_ospi_clear_irq(struct f_ospi *ospi) in f_ospi_clear_irq() argument
125 ospi->base + OSPI_IRQ); in f_ospi_clear_irq()
128 static void f_ospi_enable_irq_status(struct f_ospi *ospi, u32 irq_bits) in f_ospi_enable_irq_status() argument
132 val = readl(ospi->base + OSPI_IRQ_STAT_EN); in f_ospi_enable_irq_status()
134 writel(val, ospi->base + OSPI_IRQ_STAT_EN); in f_ospi_enable_irq_status()
137 static void f_ospi_disable_irq_status(struct f_ospi *ospi, u32 irq_bits) in f_ospi_disable_irq_status() argument
141 val = readl(ospi->base + OSPI_IRQ_STAT_EN); in f_ospi_disable_irq_status()
143 writel(val, ospi->base + OSPI_IRQ_STAT_EN); in f_ospi_disable_irq_status()
146 static void f_ospi_disable_irq_output(struct f_ospi *ospi, u32 irq_bits) in f_ospi_disable_irq_output() argument
150 val = readl(ospi->base + OSPI_IRQ_SIG_EN); in f_ospi_disable_irq_output()
152 writel(val, ospi->base + OSPI_IRQ_SIG_EN); in f_ospi_disable_irq_output()
155 static int f_ospi_prepare_config(struct f_ospi *ospi) in f_ospi_prepare_config() argument
160 val = readl(ospi->base + OSPI_CLK_CTL); in f_ospi_prepare_config()
162 writel(val, ospi->base + OSPI_CLK_CTL); in f_ospi_prepare_config()
168 return readl_poll_timeout(ospi->base + OSPI_STAT, in f_ospi_prepare_config()
173 static int f_ospi_unprepare_config(struct f_ospi *ospi) in f_ospi_unprepare_config() argument
178 val = readl(ospi->base + OSPI_CLK_CTL); in f_ospi_unprepare_config()
180 writel(val, ospi->base + OSPI_CLK_CTL); in f_ospi_unprepare_config()
183 return readl_poll_timeout(ospi->base + OSPI_STAT, in f_ospi_unprepare_config()
188 static void f_ospi_config_clk(struct f_ospi *ospi, u32 device_hz) in f_ospi_config_clk() argument
190 long rate_hz = clk_get_rate(ospi->clk); in f_ospi_config_clk()
196 dev_warn(ospi->dev, "Device frequency too large: %d\n", in f_ospi_config_clk()
209 dev_warn(ospi->dev, "Device frequency too small: %d\n", in f_ospi_config_clk()
220 val = readl(ospi->base + OSPI_CLK_CTL); in f_ospi_config_clk()
226 writel(val, ospi->base + OSPI_CLK_CTL); in f_ospi_config_clk()
229 static void f_ospi_config_dll(struct f_ospi *ospi) in f_ospi_config_dll() argument
234 static u8 f_ospi_get_mode(struct f_ospi *ospi, int width, int data_size) in f_ospi_get_mode() argument
253 dev_err(ospi->dev, "Invalid buswidth: %d\n", width); in f_ospi_get_mode()
260 static void f_ospi_config_indir_protocol(struct f_ospi *ospi, in f_ospi_config_indir_protocol() argument
264 struct spi_device *spi = mem->spi; in f_ospi_config_indir_protocol()
270 writel(BIT(spi_get_chipselect(spi, 0)), ospi->base + OSPI_SSEL); in f_ospi_config_indir_protocol()
272 mode = f_ospi_get_mode(ospi, op->cmd.buswidth, 1); in f_ospi_config_indir_protocol()
275 mode = f_ospi_get_mode(ospi, op->addr.buswidth, op->addr.nbytes); in f_ospi_config_indir_protocol()
278 mode = f_ospi_get_mode(ospi, op->data.buswidth, op->data.nbytes); in f_ospi_config_indir_protocol()
286 if (spi->mode & SPI_LSB_FIRST) in f_ospi_config_indir_protocol()
290 if (spi->mode & SPI_CPHA) in f_ospi_config_indir_protocol()
294 switch (op->data.nbytes & 0x3) { in f_ospi_config_indir_protocol()
301 val = OSPI_DAT_SIZE_EN | (op->data.nbytes - 1); in f_ospi_config_indir_protocol()
305 val = OSPI_DAT_SIZE_EN | (op->data.nbytes - 1); in f_ospi_config_indir_protocol()
310 switch (op->data.dir) { in f_ospi_config_indir_protocol()
324 dev_warn(ospi->dev, "Unsupported direction"); in f_ospi_config_indir_protocol()
328 prot |= FIELD_PREP(OSPI_PROT_ADDR_SIZE_MASK, op->addr.nbytes); in f_ospi_config_indir_protocol()
331 writel(prot, ospi->base + OSPI_PROT_CTL_INDIR); in f_ospi_config_indir_protocol()
332 writel(val, ospi->base + OSPI_DAT_SIZE_INDIR); in f_ospi_config_indir_protocol()
335 static int f_ospi_indir_prepare_op(struct f_ospi *ospi, struct spi_mem *mem, in f_ospi_indir_prepare_op() argument
338 struct spi_device *spi = mem->spi; in f_ospi_indir_prepare_op()
342 ret = f_ospi_prepare_config(ospi); in f_ospi_indir_prepare_op()
346 f_ospi_config_clk(ospi, spi->max_speed_hz); in f_ospi_indir_prepare_op()
348 f_ospi_config_indir_protocol(ospi, mem, op); in f_ospi_indir_prepare_op()
350 writel(f_ospi_get_dummy_cycle(op), ospi->base + OSPI_DMY_INDIR); in f_ospi_indir_prepare_op()
351 writel(op->addr.val, ospi->base + OSPI_ADDR); in f_ospi_indir_prepare_op()
352 writel(op->cmd.opcode, ospi->base + OSPI_CMD_IDX_INDIR); in f_ospi_indir_prepare_op()
354 f_ospi_clear_irq(ospi); in f_ospi_indir_prepare_op()
356 switch (op->data.dir) { in f_ospi_indir_prepare_op()
370 dev_warn(ospi->dev, "Unsupported direction"); in f_ospi_indir_prepare_op()
374 f_ospi_disable_irq_status(ospi, ~irq_stat_en); in f_ospi_indir_prepare_op()
375 f_ospi_enable_irq_status(ospi, irq_stat_en); in f_ospi_indir_prepare_op()
377 return f_ospi_unprepare_config(ospi); in f_ospi_indir_prepare_op()
380 static void f_ospi_indir_start_xfer(struct f_ospi *ospi) in f_ospi_indir_start_xfer() argument
383 writel(OSPI_TRANS_CTL_START_REQ, ospi->base + OSPI_TRANS_CTL); in f_ospi_indir_start_xfer()
386 static void f_ospi_indir_stop_xfer(struct f_ospi *ospi) in f_ospi_indir_stop_xfer() argument
389 writel(OSPI_TRANS_CTL_STOP_REQ, ospi->base + OSPI_TRANS_CTL); in f_ospi_indir_stop_xfer()
392 static int f_ospi_indir_wait_xfer_complete(struct f_ospi *ospi) in f_ospi_indir_wait_xfer_complete() argument
396 return readl_poll_timeout(ospi->base + OSPI_IRQ, val, in f_ospi_indir_wait_xfer_complete()
401 static int f_ospi_indir_read(struct f_ospi *ospi, struct spi_mem *mem, in f_ospi_indir_read() argument
404 u8 *buf = op->data.buf.in; in f_ospi_indir_read()
408 mutex_lock(&ospi->mlock); in f_ospi_indir_read()
410 /* E1-2: Prepare transfer operation */ in f_ospi_indir_read()
411 ret = f_ospi_indir_prepare_op(ospi, mem, op); in f_ospi_indir_read()
415 f_ospi_indir_start_xfer(ospi); in f_ospi_indir_read()
417 /* E3-4: Wait for ready and read data */ in f_ospi_indir_read()
418 for (i = 0; i < op->data.nbytes; i++) { in f_ospi_indir_read()
419 ret = readl_poll_timeout(ospi->base + OSPI_IRQ, val, in f_ospi_indir_read()
425 buf[i] = readl(ospi->base + OSPI_DAT) & 0xFF; in f_ospi_indir_read()
428 /* E5-6: Stop transfer if data size is nothing */ in f_ospi_indir_read()
429 if (!(readl(ospi->base + OSPI_DAT_SIZE_INDIR) & OSPI_DAT_SIZE_EN)) in f_ospi_indir_read()
430 f_ospi_indir_stop_xfer(ospi); in f_ospi_indir_read()
432 /* E7-8: Wait for completion and clear */ in f_ospi_indir_read()
433 ret = f_ospi_indir_wait_xfer_complete(ospi); in f_ospi_indir_read()
437 writel(OSPI_IRQ_CS_TRANS_COMP, ospi->base + OSPI_IRQ); in f_ospi_indir_read()
440 if (readl(ospi->base + OSPI_DAT_SIZE_INDIR) & OSPI_DAT_SIZE_EN) in f_ospi_indir_read()
443 /* E10-11: Reset and check read fifo */ in f_ospi_indir_read()
444 writel(OSPI_SWRST_INDIR_READ_FIFO, ospi->base + OSPI_SWRST); in f_ospi_indir_read()
446 ret = readl_poll_timeout(ospi->base + OSPI_SWRST, val, in f_ospi_indir_read()
450 mutex_unlock(&ospi->mlock); in f_ospi_indir_read()
455 static int f_ospi_indir_write(struct f_ospi *ospi, struct spi_mem *mem, in f_ospi_indir_write() argument
458 u8 *buf = (u8 *)op->data.buf.out; in f_ospi_indir_write()
462 mutex_lock(&ospi->mlock); in f_ospi_indir_write()
464 /* F1-3: Prepare transfer operation */ in f_ospi_indir_write()
465 ret = f_ospi_indir_prepare_op(ospi, mem, op); in f_ospi_indir_write()
469 f_ospi_indir_start_xfer(ospi); in f_ospi_indir_write()
471 if (!(readl(ospi->base + OSPI_PROT_CTL_INDIR) & OSPI_PROT_DATA_EN)) in f_ospi_indir_write()
474 /* F4-5: Wait for buffer ready and write data */ in f_ospi_indir_write()
475 for (i = 0; i < op->data.nbytes; i++) { in f_ospi_indir_write()
476 ret = readl_poll_timeout(ospi->base + OSPI_IRQ, val, in f_ospi_indir_write()
482 writel(buf[i], ospi->base + OSPI_DAT); in f_ospi_indir_write()
485 /* F6-7: Stop transfer if data size is nothing */ in f_ospi_indir_write()
486 if (!(readl(ospi->base + OSPI_DAT_SIZE_INDIR) & OSPI_DAT_SIZE_EN)) in f_ospi_indir_write()
487 f_ospi_indir_stop_xfer(ospi); in f_ospi_indir_write()
490 /* F8-9: Wait for completion and clear */ in f_ospi_indir_write()
491 ret = f_ospi_indir_wait_xfer_complete(ospi); in f_ospi_indir_write()
495 writel(OSPI_IRQ_CS_TRANS_COMP, ospi->base + OSPI_IRQ); in f_ospi_indir_write()
497 mutex_unlock(&ospi->mlock); in f_ospi_indir_write()
504 struct f_ospi *ospi = spi_controller_get_devdata(mem->spi->controller); in f_ospi_exec_op() local
507 switch (op->data.dir) { in f_ospi_exec_op()
509 err = f_ospi_indir_read(ospi, mem, op); in f_ospi_exec_op()
515 err = f_ospi_indir_write(ospi, mem, op); in f_ospi_exec_op()
519 dev_warn(ospi->dev, "Unsupported direction"); in f_ospi_exec_op()
520 err = -EOPNOTSUPP; in f_ospi_exec_op()
530 u8 width_op[] = { op->cmd.buswidth, op->addr.buswidth, in f_ospi_supports_op_width()
531 op->dummy.buswidth, op->data.buswidth }; in f_ospi_supports_op_width()
558 if (op->addr.nbytes > 4) in f_ospi_supports_op()
569 op->data.nbytes = min_t(int, op->data.nbytes, OSPI_DAT_SIZE_MAX); in f_ospi_adjust_op_size()
580 static int f_ospi_init(struct f_ospi *ospi) in f_ospi_init() argument
584 ret = f_ospi_prepare_config(ospi); in f_ospi_init()
589 writel(OSPI_ACC_MODE_BOOT_DISABLE, ospi->base + OSPI_ACC_MODE); in f_ospi_init()
591 f_ospi_config_dll(ospi); in f_ospi_init()
594 f_ospi_clear_irq(ospi); in f_ospi_init()
595 f_ospi_disable_irq_status(ospi, OSPI_IRQ_ALL); in f_ospi_init()
596 f_ospi_disable_irq_output(ospi, OSPI_IRQ_ALL); in f_ospi_init()
598 return f_ospi_unprepare_config(ospi); in f_ospi_init()
604 struct device *dev = &pdev->dev; in f_ospi_probe()
605 struct f_ospi *ospi; in f_ospi_probe() local
609 ctlr = spi_alloc_host(dev, sizeof(*ospi)); in f_ospi_probe()
611 return -ENOMEM; in f_ospi_probe()
613 ctlr->mode_bits = SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL in f_ospi_probe()
616 ctlr->mem_ops = &f_ospi_mem_ops; in f_ospi_probe()
617 ctlr->bus_num = -1; in f_ospi_probe()
618 of_property_read_u32(dev->of_node, "num-cs", &num_cs); in f_ospi_probe()
620 dev_err(dev, "num-cs too large: %d\n", num_cs); in f_ospi_probe()
621 return -ENOMEM; in f_ospi_probe()
623 ctlr->num_chipselect = num_cs; in f_ospi_probe()
624 ctlr->dev.of_node = dev->of_node; in f_ospi_probe()
626 ospi = spi_controller_get_devdata(ctlr); in f_ospi_probe()
627 ospi->dev = dev; in f_ospi_probe()
629 platform_set_drvdata(pdev, ospi); in f_ospi_probe()
631 ospi->base = devm_platform_ioremap_resource(pdev, 0); in f_ospi_probe()
632 if (IS_ERR(ospi->base)) { in f_ospi_probe()
633 ret = PTR_ERR(ospi->base); in f_ospi_probe()
637 ospi->clk = devm_clk_get_enabled(dev, NULL); in f_ospi_probe()
638 if (IS_ERR(ospi->clk)) { in f_ospi_probe()
639 ret = PTR_ERR(ospi->clk); in f_ospi_probe()
643 mutex_init(&ospi->mlock); in f_ospi_probe()
645 ret = f_ospi_init(ospi); in f_ospi_probe()
656 mutex_destroy(&ospi->mlock); in f_ospi_probe()
666 struct f_ospi *ospi = platform_get_drvdata(pdev); in f_ospi_remove() local
668 mutex_destroy(&ospi->mlock); in f_ospi_remove()
672 { .compatible = "socionext,f-ospi" },
679 .name = "socionext,f-ospi",