Lines Matching +full:zynq +full:- +full:can +full:- +full:1

1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
10 * 1. Redistributions of source code must retain the above copyright
31 * This is a driver for the Quad-SPI Flash Controller in the Xilinx
32 * Zynq-7000 SoC.
63 {"xlnx,zy7_qspi", 1},
64 {"xlnx,zynq-qspi-1.0", 1},
98 #define QSPI_SC_LOCK(sc) mtx_lock(&(sc)->sc_mtx)
99 #define QSPI_SC_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx)
101 mtx_init(&(sc)->sc_mtx, device_get_nameunit((sc)->dev), NULL, MTX_DEF)
102 #define QSPI_SC_LOCK_DESTROY(sc) mtx_destroy(&(sc)->sc_mtx)
103 #define QSPI_SC_ASSERT_LOCKED(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED)
105 #define RD4(sc, off) (bus_read_4((sc)->mem_res, (off)))
106 #define WR4(sc, off, val) (bus_write_4((sc)->mem_res, (off), (val)))
110 * Reference: Zynq-7000 All Programmable SoC Technical Reference Manual.
111 * (v1.12.2) July 1, 2018. Xilinx doc UG585.
114 #define ZY7_QSPI_CONFIG_IFMODE (1U << 31)
115 #define ZY7_QSPI_CONFIG_ENDIAN (1 << 26)
116 #define ZY7_QSPI_CONFIG_HOLDB_DR (1 << 19)
117 #define ZY7_QSPI_CONFIG_RSVD1 (1 << 17) /* must be 1 */
118 #define ZY7_QSPI_CONFIG_MANSTRT (1 << 16)
119 #define ZY7_QSPI_CONFIG_MANSTRTEN (1 << 15)
120 #define ZY7_QSPI_CONFIG_SSFORCE (1 << 14)
121 #define ZY7_QSPI_CONFIG_PCS (1 << 10)
122 #define ZY7_QSPI_CONFIG_REF_CLK (1 << 8)
128 #define ZY7_QSPI_CONFIG_CLK_PH (1 << 2) /* clock phase */
129 #define ZY7_QSPI_CONFIG_CLK_POL (1 << 1) /* clock polarity */
130 #define ZY7_QSPI_CONFIG_MODE_SEL (1 << 0) /* master enable */
136 #define ZY7_QSPI_INTR_TX_FIFO_UNDERFLOW (1 << 6)
137 #define ZY7_QSPI_INTR_RX_FIFO_FULL (1 << 5)
138 #define ZY7_QSPI_INTR_RX_FIFO_NOT_EMPTY (1 << 4)
139 #define ZY7_QSPI_INTR_TX_FIFO_FULL (1 << 3)
140 #define ZY7_QSPI_INTR_TX_FIFO_NOT_FULL (1 << 2)
141 #define ZY7_QSPI_INTR_RX_OVERFLOW (1 << 0)
144 #define ZY7_SPI_ENABLE 1
170 #define ZY7_QSPI_GPIO_WP_N 1
173 #define ZY7_QSPI_LPBK_DLY_ADJ_LPBK_SEL (1 << 8)
174 #define ZY7_QSPI_LPBK_DLY_ADJ_LPBK_PH (1 << 7)
175 #define ZY7_QSPI_LPBK_DLY_ADJ_USE_LPBK (1 << 5)
188 #define ZY7_QSPI_LQSPI_CFG_LINEAR (1U << 31)
189 #define ZY7_QSPI_LQSPI_CFG_TWO_MEM (1 << 30)
190 #define ZY7_QSPI_LQSPI_CFG_SEP_BUS (1 << 29)
191 #define ZY7_QSPI_LQSPI_CFG_U_PAGE (1 << 28)
192 #define ZY7_QSPI_LQSPI_CFG_MODE_EN (1 << 25)
193 #define ZY7_QSPI_LQSPI_CFG_MODE_ON (1 << 24)
205 #define ZY7_QSPI_LQSPI_STS_D_FSM_ERR (1 << 2)
206 #define ZY7_QSPI_LQSPI_STS_WR_RECVD (1 << 1)
232 if (sc->tx_bytes_sent < sc->cmd->tx_cmd_sz) { in zy7_qspi_write_fifo()
234 n = MIN(nvalid, sc->cmd->tx_cmd_sz - in zy7_qspi_write_fifo()
235 sc->tx_bytes_sent); in zy7_qspi_write_fifo()
236 memcpy(&data, (uint8_t *)sc->cmd->tx_cmd + in zy7_qspi_write_fifo()
237 sc->tx_bytes_sent, n); in zy7_qspi_write_fifo()
242 sc->cmd->tx_data, nvalid - n); in zy7_qspi_write_fifo()
246 memcpy(&data, (uint8_t *)sc->cmd->tx_data + in zy7_qspi_write_fifo()
247 (sc->tx_bytes_sent - sc->cmd->tx_cmd_sz), nvalid); in zy7_qspi_write_fifo()
250 case 1: in zy7_qspi_write_fifo()
264 sc->tx_bytes_sent += nvalid; in zy7_qspi_write_fifo()
265 nbytes -= nvalid; in zy7_qspi_write_fifo()
278 nbytes = MIN(4, sc->rx_bytes - sc->rx_bytes_rcvd); in zy7_qspi_read_fifo()
281 * Last word in non-word-multiple transfer is packed in zy7_qspi_read_fifo()
282 * non-intuitively. in zy7_qspi_read_fifo()
285 data >>= 8 * (4 - nbytes); in zy7_qspi_read_fifo()
287 if (sc->rx_bytes_rcvd < sc->cmd->rx_cmd_sz) { in zy7_qspi_read_fifo()
289 n = MIN(nbytes, sc->cmd->rx_cmd_sz - in zy7_qspi_read_fifo()
290 sc->rx_bytes_rcvd); in zy7_qspi_read_fifo()
291 memcpy((uint8_t *)sc->cmd->rx_cmd + sc->rx_bytes_rcvd, in zy7_qspi_read_fifo()
293 sc->rx_bytes_rcvd += n; in zy7_qspi_read_fifo()
294 nbytes -= n; in zy7_qspi_read_fifo()
300 memcpy((uint8_t *)sc->cmd->rx_data + in zy7_qspi_read_fifo()
301 (sc->rx_bytes_rcvd - sc->cmd->rx_cmd_sz), in zy7_qspi_read_fifo()
303 sc->rx_bytes_rcvd += nbytes; in zy7_qspi_read_fifo()
306 } while (sc->rx_bytes_rcvd < sc->rx_bytes && in zy7_qspi_read_fifo()
335 sc->interrupts++; in zy7_qspi_intr()
339 /* Stray interrupts can happen if a transfer gets interrupted. */ in zy7_qspi_intr()
340 if (!sc->busy) { in zy7_qspi_intr()
341 sc->stray_ints++; in zy7_qspi_intr()
347 device_printf(sc->dev, "rx fifo overflow!\n"); in zy7_qspi_intr()
348 sc->rx_overflows++; in zy7_qspi_intr()
356 if (sc->rx_bytes_rcvd < sc->rx_bytes && in zy7_qspi_intr()
359 if (sc->rx_bytes_rcvd == sc->rx_bytes) in zy7_qspi_intr()
372 sc->tx_underflows++; in zy7_qspi_intr()
380 if (sc->tx_bytes_sent < sc->tx_bytes && in zy7_qspi_intr()
382 zy7_qspi_write_fifo(sc, MIN(240, sc->tx_bytes - in zy7_qspi_intr()
383 sc->tx_bytes_sent)); in zy7_qspi_intr()
385 if (sc->tx_bytes_sent == sc->tx_bytes) { in zy7_qspi_intr()
398 if (sc->tx_bytes_sent == sc->tx_bytes && in zy7_qspi_intr()
399 sc->rx_bytes_rcvd == sc->rx_bytes) { in zy7_qspi_intr()
400 /* De-assert CS. */ in zy7_qspi_intr()
401 sc->cfg_reg_shadow |= ZY7_QSPI_CONFIG_PCS; in zy7_qspi_intr()
402 WR4(sc, ZY7_QSPI_CONFIG_REG, sc->cfg_reg_shadow); in zy7_qspi_intr()
404 wakeup(sc->dev); in zy7_qspi_intr()
417 sc->lqspi_cfg_shadow = RD4(sc, ZY7_QSPI_LQSPI_CFG_REG); in zy7_qspi_init_hw()
418 sc->lqspi_cfg_shadow &= ~(ZY7_QSPI_LQSPI_CFG_LINEAR | in zy7_qspi_init_hw()
421 if (sc->is_dual) { in zy7_qspi_init_hw()
422 sc->lqspi_cfg_shadow |= ZY7_QSPI_LQSPI_CFG_TWO_MEM; in zy7_qspi_init_hw()
423 if (sc->is_stacked) { in zy7_qspi_init_hw()
424 sc->lqspi_cfg_shadow &= in zy7_qspi_init_hw()
426 sc->lqspi_cfg_shadow |= in zy7_qspi_init_hw()
427 ZY7_QSPI_LQSPI_CFG_INST_CODE(sc->is_dio ? in zy7_qspi_init_hw()
430 sc->lqspi_cfg_shadow |= ZY7_QSPI_LQSPI_CFG_SEP_BUS; in zy7_qspi_init_hw()
432 WR4(sc, ZY7_QSPI_LQSPI_CFG_REG, sc->lqspi_cfg_shadow); in zy7_qspi_init_hw()
436 while ((sc->ref_clock >> (baud_div + 1)) > sc->spi_clock && in zy7_qspi_init_hw()
440 device_printf(sc->dev, "cannot configure clock divider: ref=%d" in zy7_qspi_init_hw()
441 " spi=%d.\n", sc->ref_clock, sc->spi_clock); in zy7_qspi_init_hw()
444 sc->spi_clk_real_freq = sc->ref_clock >> (baud_div + 1); in zy7_qspi_init_hw()
448 * clock for read data. (See section 12.3.1 in ref man.) in zy7_qspi_init_hw()
459 sc->cfg_reg_shadow = in zy7_qspi_init_hw()
468 WR4(sc, ZY7_QSPI_CONFIG_REG, sc->cfg_reg_shadow); in zy7_qspi_init_hw()
471 * Set thresholds. We must use 1 for tx threshold because there in zy7_qspi_init_hw()
475 WR4(sc, ZY7_QSPI_TX_THRESH_REG, 1); in zy7_qspi_init_hw()
476 WR4(sc, ZY7_QSPI_RX_THRESH_REG, 1); in zy7_qspi_init_hw()
499 &sc->spi_clk_real_freq, 0, "SPI clock real frequency"); in zy7_qspi_add_sysctls()
502 &sc->rx_overflows, 0, "RX FIFO overflow events"); in zy7_qspi_add_sysctls()
505 &sc->tx_underflows, 0, "TX FIFO underflow events"); in zy7_qspi_add_sysctls()
508 &sc->interrupts, 0, "interrupt calls"); in zy7_qspi_add_sysctls()
511 &sc->stray_ints, 0, "stray interrupts"); in zy7_qspi_add_sysctls()
521 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) in zy7_qspi_probe()
524 device_set_desc(dev, "Zynq Quad-SPI Flash Controller"); in zy7_qspi_probe()
538 sc->dev = dev; in zy7_qspi_attach()
542 /* Get ref-clock, spi-clock, and other properties. */ in zy7_qspi_attach()
544 if (OF_getprop(node, "ref-clock", &cell, sizeof(cell)) > 0) in zy7_qspi_attach()
545 sc->ref_clock = fdt32_to_cpu(cell); in zy7_qspi_attach()
547 device_printf(dev, "must have ref-clock property\n"); in zy7_qspi_attach()
550 if (OF_getprop(node, "spi-clock", &cell, sizeof(cell)) > 0) in zy7_qspi_attach()
551 sc->spi_clock = fdt32_to_cpu(cell); in zy7_qspi_attach()
553 sc->spi_clock = ZY7_QSPI_DEFAULT_SPI_CLOCK; in zy7_qspi_attach()
554 if (OF_getprop(node, "is-stacked", &cell, sizeof(cell)) > 0 && in zy7_qspi_attach()
556 sc->is_dual = 1; in zy7_qspi_attach()
557 sc->is_stacked = 1; in zy7_qspi_attach()
558 } else if (OF_getprop(node, "is-dual", &cell, sizeof(cell)) > 0 && in zy7_qspi_attach()
560 sc->is_dual = 1; in zy7_qspi_attach()
561 if (OF_getprop(node, "is-dio", &cell, sizeof(cell)) > 0 && in zy7_qspi_attach()
563 sc->is_dio = 1; in zy7_qspi_attach()
567 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, in zy7_qspi_attach()
569 if (sc->mem_res == NULL) { in zy7_qspi_attach()
577 sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, in zy7_qspi_attach()
579 if (sc->irq_res == NULL) { in zy7_qspi_attach()
586 err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, in zy7_qspi_attach()
587 NULL, zy7_qspi_intr, sc, &sc->intrhandle); in zy7_qspi_attach()
601 sc->child = device_add_child(dev, "spibus", DEVICE_UNIT_ANY); in zy7_qspi_attach()
620 if (sc->child) in zy7_qspi_detach()
621 device_delete_child(dev, sc->child); in zy7_qspi_detach()
624 if (sc->mem_res != NULL) { in zy7_qspi_detach()
634 if (sc->irq_res != NULL) { in zy7_qspi_detach()
635 if (sc->intrhandle) in zy7_qspi_detach()
636 bus_teardown_intr(dev, sc->irq_res, sc->intrhandle); in zy7_qspi_detach()
638 rman_get_rid(sc->irq_res), sc->irq_res); in zy7_qspi_detach()
642 if (sc->mem_res != NULL) in zy7_qspi_detach()
644 rman_get_rid(sc->mem_res), sc->mem_res); in zy7_qspi_detach()
664 KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz, in zy7_qspi_transfer()
666 KASSERT(cmd->tx_data_sz == cmd->rx_data_sz, in zy7_qspi_transfer()
669 if (sc->is_dual && cmd->tx_data_sz % 2 != 0) { in zy7_qspi_transfer()
671 "transfers in dual mode. (sz=%d)\n", cmd->tx_data_sz); in zy7_qspi_transfer()
678 while (sc->busy != 0) { in zy7_qspi_transfer()
679 err = mtx_sleep(dev, &sc->sc_mtx, 0, "zqspi0", 0); in zy7_qspi_transfer()
687 sc->busy = 1; in zy7_qspi_transfer()
688 sc->cmd = cmd; in zy7_qspi_transfer()
689 sc->tx_bytes = sc->cmd->tx_cmd_sz + sc->cmd->tx_data_sz; in zy7_qspi_transfer()
690 sc->tx_bytes_sent = 0; in zy7_qspi_transfer()
691 sc->rx_bytes = sc->cmd->rx_cmd_sz + sc->cmd->rx_data_sz; in zy7_qspi_transfer()
692 sc->rx_bytes_rcvd = 0; in zy7_qspi_transfer()
700 if (sc->is_stacked) { in zy7_qspi_transfer()
701 if ((cmd->flags & SPI_XFER_U_PAGE) != 0) in zy7_qspi_transfer()
702 sc->lqspi_cfg_shadow |= ZY7_QSPI_LQSPI_CFG_U_PAGE; in zy7_qspi_transfer()
704 sc->lqspi_cfg_shadow &= ~ZY7_QSPI_LQSPI_CFG_U_PAGE; in zy7_qspi_transfer()
705 WR4(sc, ZY7_QSPI_LQSPI_CFG_REG, sc->lqspi_cfg_shadow); in zy7_qspi_transfer()
710 sc->cfg_reg_shadow &= ~ZY7_QSPI_CONFIG_PCS; in zy7_qspi_transfer()
711 WR4(sc, ZY7_QSPI_CONFIG_REG, sc->cfg_reg_shadow); in zy7_qspi_transfer()
714 err = mtx_sleep(dev, &sc->sc_mtx, 0, "zqspi1", hz * 2); in zy7_qspi_transfer()
719 sc->busy = 0; in zy7_qspi_transfer()
751 MODULE_DEPEND(zy7_qspi, ofw_spibus, 1, 1, 1);