// SPDX-License-Identifier: GPL-2.0+ /* * Driver for Cortina SPI-FLASH Controller * * Copyright (C) 2020 Cortina Access Inc. All Rights Reserved. * * Author: PengPeng Chen */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include DECLARE_GLOBAL_DATA_PTR; struct ca_sflash_regs { u32 idr; /* 0x00:Flash word ID Register */ u32 tc; /* 0x04:Flash Timeout Counter Register */ u32 sr; /* 0x08:Flash Status Register */ u32 tr; /* 0x0C:Flash Type Register */ u32 asr; /* 0x10:Flash ACCESS START/BUSY Register */ u32 isr; /* 0x14:Flash Interrupt Status Register */ u32 imr; /* 0x18:Flash Interrupt Mask Register */ u32 fcr; /* 0x1C:NAND Flash FIFO Control Register */ u32 ffsr; /* 0x20:Flash FIFO Status Register */ u32 ffar; /* 0x24:Flash FIFO ADDRESS Register */ u32 ffmar; /* 0x28:Flash FIFO MATCHING ADDRESS Register */ u32 ffdr; /* 0x2C:Flash FIFO Data Register */ u32 ar; /* 0x30:Serial Flash Access Register */ u32 ear; /* 0x34:Serial Flash Extend Access Register */ u32 adr; /* 0x38:Serial Flash ADdress Register */ u32 dr; /* 0x3C:Serial Flash Data Register */ u32 tmr; /* 0x40:Serial Flash Timing Register */ }; /* * FLASH_TYPE */ #define CA_FLASH_TR_PIN BIT(15) #define CA_FLASH_TR_TYPE_MSK GENMASK(14, 12) #define CA_FLASH_TR_TYPE(tp) (((tp) << 12) & CA_FLASH_TR_TYPE_MSK) #define CA_FLASH_TR_WIDTH BIT(11) #define CA_FLASH_TR_SIZE_MSK GENMASK(10, 9) #define CA_FLASH_TR_SIZE(sz) (((sz) << 9) & CA_FLASH_TR_SIZE_MSK) /* * FLASH_FLASH_ACCESS_START */ #define CA_FLASH_ASR_IND_START_EN BIT(1) #define CA_FLASH_ASR_DMA_START_EN BIT(3) #define CA_FLASH_ASR_WR_ACCESS_EN BIT(9) /* * FLASH_FLASH_INTERRUPT */ #define CA_FLASH_ISR_REG_IRQ BIT(1) #define CA_FLASH_ISR_FIFO_IRQ BIT(2) /* * FLASH_SF_ACCESS */ #define CA_SF_AR_OP_MSK GENMASK(7, 0) #define CA_SF_AR_OP(op) ((op) << 0 & CA_SF_AR_OP_MSK) #define CA_SF_AR_ACCODE_MSK GENMASK(11, 8) #define CA_SF_AR_ACCODE(ac) (((ac) << 8) & CA_SF_AR_ACCODE_MSK) #define CA_SF_AR_FORCE_TERM BIT(12) #define CA_SF_AR_FORCE_BURST BIT(13) #define CA_SF_AR_AUTO_MODE_EN BIT(15) #define CA_SF_AR_CHIP_EN_ALT BIT(16) #define CA_SF_AR_HI_SPEED_RD BIT(17) #define CA_SF_AR_MIO_INF_DC BIT(24) #define CA_SF_AR_MIO_INF_AC BIT(25) #define CA_SF_AR_MIO_INF_CC BIT(26) #define CA_SF_AR_DDR_MSK GENMASK(29, 28) #define CA_SF_AR_DDR(ddr) (((ddr) << 28) & CA_SF_AR_DDR_MSK) #define CA_SF_AR_MIO_INF_MSK GENMASK(31, 30) #define CA_SF_AR_MIO_INF(io) (((io) << 30) & CA_SF_AR_MIO_INF_MSK) /* * FLASH_SF_EXT_ACCESS */ #define CA_SF_EAR_OP_MSK GENMASK(7, 0) #define CA_SF_EAR_OP(op) (((op) << 0) & CA_SF_EAR_OP_MSK) #define CA_SF_EAR_DATA_CNT_MSK GENMASK(20, 8) #define CA_SF_EAR_DATA_CNT(cnt) (((cnt) << 8) & CA_SF_EAR_DATA_CNT_MSK) #define CA_SF_EAR_DATA_CNT_MAX (4096) #define CA_SF_EAR_ADDR_CNT_MSK GENMASK(23, 21) #define CA_SF_EAR_ADDR_CNT(cnt) (((cnt) << 21) & CA_SF_EAR_ADDR_CNT_MSK) #define CA_SF_EAR_ADDR_CNT_MAX (5) #define CA_SF_EAR_DUMY_CNT_MSK GENMASK(29, 24) #define CA_SF_EAR_DUMY_CNT(cnt) (((cnt) << 24) & CA_SF_EAR_DUMY_CNT_MSK) #define CA_SF_EAR_DUMY_CNT_MAX (32) #define CA_SF_EAR_DRD_CMD_EN BIT(31) /* * FLASH_SF_ADDRESS */ #define CA_SF_ADR_REG_MSK GENMASK(31, 0) #define CA_SF_ADR_REG(addr) (((addr) << 0) & CA_SF_ADR_REG_MSK) /* * FLASH_SF_DATA */ #define CA_SF_DR_REG_MSK GENMASK(31, 0) #define CA_SF_DR_REG(addr) (((addr) << 0) & CA_SF_DR_REG_MSK) /* * FLASH_SF_TIMING */ #define CA_SF_TMR_IDLE_MSK GENMASK(7, 0) #define CA_SF_TMR_IDLE(idle) (((idle) << 0) & CA_SF_TMR_IDLE_MSK) #define CA_SF_TMR_HOLD_MSK GENMASK(15, 8) #define CA_SF_TMR_HOLD(hold) (((hold) << 8) & CA_SF_TMR_HOLD_MSK) #define CA_SF_TMR_SETUP_MSK GENMASK(23, 16) #define CA_SF_TMR_SETUP(setup) (((setup) << 16) & CA_SF_TMR_SETUP_MSK) #define CA_SF_TMR_CLK_MSK GENMASK(26, 24) #define CA_SF_TMR_CLK(clk) (((clk) << 24) & CA_SF_TMR_CLK_MSK) #define CA_SFLASH_IND_WRITE 0 #define CA_SFLASH_IND_READ 1 #define CA_SFLASH_MEM_MAP 3 #define CA_SFLASH_FIFO_TIMEOUT_US 30000 #define CA_SFLASH_BUSY_TIMEOUT_US 40000 #define CA_SF_AC_OP 0x00 #define CA_SF_AC_OP_1_DATA 0x01 #define CA_SF_AC_OP_2_DATA 0x02 #define CA_SF_AC_OP_3_DATA 0x03 #define CA_SF_AC_OP_4_DATA 0x04 #define CA_SF_AC_OP_3_ADDR 0x05 #define CA_SF_AC_OP_4_ADDR (CA_SF_AC_OP_3_ADDR) #define CA_SF_AC_OP_3_ADDR_1_DATA 0x06 #define CA_SF_AC_OP_4_ADDR_1_DATA (CA_SF_AC_OP_3_ADDR_1_DATA << 2) #define CA_SF_AC_OP_3_ADDR_2_DATA 0x07 #define CA_SF_AC_OP_4_ADDR_2_DATA (CA_SF_AC_OP_3_ADDR_2_DATA << 2) #define CA_SF_AC_OP_3_ADDR_3_DATA 0x08 #define CA_SF_AC_OP_4_ADDR_3_DATA (CA_SF_AC_OP_3_ADDR_3_DATA << 2) #define CA_SF_AC_OP_3_ADDR_4_DATA 0x09 #define CA_SF_AC_OP_4_ADDR_4_DATA (CA_SF_AC_OP_3_ADDR_4_DATA << 2) #define CA_SF_AC_OP_3_ADDR_X_1_DATA 0x0A #define CA_SF_AC_OP_4_ADDR_X_1_DATA (CA_SF_AC_OP_3_ADDR_X_1_DATA << 2) #define CA_SF_AC_OP_3_ADDR_X_2_DATA 0x0B #define CA_SF_AC_OP_4_ADDR_X_2_DATA (CA_SF_AC_OP_3_ADDR_X_2_DATA << 2) #define CA_SF_AC_OP_3_ADDR_X_3_DATA 0x0C #define CA_SF_AC_OP_4_ADDR_X_3_DATA (CA_SF_AC_OP_3_ADDR_X_3_DATA << 2) #define CA_SF_AC_OP_3_ADDR_X_4_DATA 0x0D #define CA_SF_AC_OP_4_ADDR_X_4_DATA (CA_SF_AC_OP_3_ADDR_X_4_DATA << 2) #define CA_SF_AC_OP_3_ADDR_4X_1_DATA 0x0E #define CA_SF_AC_OP_4_ADDR_4X_1_DATA (CA_SF_AC_OP_3_ADDR_4X_1_DATA << 2) #define CA_SF_AC_OP_EXTEND 0x0F #define CA_SF_ACCESS_MIO_SINGLE 0 #define CA_SF_ACCESS_MIO_DUAL 1 #define CA_SF_ACCESS_MIO_QUARD 2 enum access_type { RD_ACCESS, WR_ACCESS, }; struct ca_sflash_priv { struct ca_sflash_regs *regs; u8 rx_width; u8 tx_width; }; /* * This function doesn't do anything except help with debugging */ static int ca_sflash_claim_bus(struct udevice *dev) { debug("%s:\n", __func__); return 0; } static int ca_sflash_release_bus(struct udevice *dev) { debug("%s:\n", __func__); return 0; } static int ca_sflash_set_speed(struct udevice *dev, uint speed) { debug("%s:\n", __func__); return 0; } static int ca_sflash_set_mode(struct udevice *dev, uint mode) { struct ca_sflash_priv *priv = dev_get_priv(dev); if (mode & SPI_RX_QUAD) priv->rx_width = 4; else if (mode & SPI_RX_DUAL) priv->rx_width = 2; else priv->rx_width = 1; if (mode & SPI_TX_QUAD) priv->tx_width = 4; else if (mode & SPI_TX_DUAL) priv->tx_width = 2; else priv->tx_width = 1; debug("%s: mode=%d, rx_width=%d, tx_width=%d\n", __func__, mode, priv->rx_width, priv->tx_width); return 0; } static int _ca_sflash_wait_for_not_busy(struct ca_sflash_priv *priv) { u32 asr; if (readl_poll_timeout(&priv->regs->asr, asr, !(asr & CA_FLASH_ASR_IND_START_EN), CA_SFLASH_BUSY_TIMEOUT_US)) { pr_err("busy timeout (stat:%#x)\n", asr); return -1; } return 0; } static int _ca_sflash_wait_cmd(struct ca_sflash_priv *priv, enum access_type type) { if (type == WR_ACCESS) { /* Enable write access and start the sflash indirect access */ clrsetbits_le32(&priv->regs->asr, GENMASK(31, 0), CA_FLASH_ASR_WR_ACCESS_EN | CA_FLASH_ASR_IND_START_EN); } else if (type == RD_ACCESS) { /* Start the sflash indirect access */ clrsetbits_le32(&priv->regs->asr, GENMASK(31, 0), CA_FLASH_ASR_IND_START_EN); } else { printf("%s: !error access type.\n", __func__); return -1; } /* Wait til the action(rd/wr) completed */ return _ca_sflash_wait_for_not_busy(priv); } static int _ca_sflash_read(struct ca_sflash_priv *priv, u8 *buf, unsigned int data_len) { u32 reg_data; int len; len = data_len; while (len >= 4) { if (_ca_sflash_wait_cmd(priv, RD_ACCESS)) return -1; reg_data = readl(&priv->regs->dr); *buf++ = reg_data & 0xFF; *buf++ = (reg_data >> 8) & 0xFF; *buf++ = (reg_data >> 16) & 0xFF; *buf++ = (reg_data >> 24) & 0xFF; len -= 4; debug("%s: reg_data=%#08x\n", __func__, reg_data); } if (len > 0) { if (_ca_sflash_wait_cmd(priv, RD_ACCESS)) return -1; reg_data = readl(&priv->regs->dr); debug("%s: reg_data=%#08x\n", __func__, reg_data); } switch (len) { case 3: *buf++ = reg_data & 0xFF; *buf++ = (reg_data >> 8) & 0xFF; *buf++ = (reg_data >> 16) & 0xFF; break; case 2: *buf++ = reg_data & 0xFF; *buf++ = (reg_data >> 8) & 0xFF; break; case 1: *buf++ = reg_data & 0xFF; break; case 0: break; default: printf("%s: error data_length %d!\n", __func__, len); } return 0; } static int _ca_sflash_mio_set(struct ca_sflash_priv *priv, u8 width) { if (width == 4) { setbits_le32(&priv->regs->ar, CA_SF_AR_MIO_INF_DC | CA_SF_AR_MIO_INF(CA_SF_ACCESS_MIO_QUARD) | CA_SF_AR_FORCE_BURST); } else if (width == 2) { setbits_le32(&priv->regs->ar, CA_SF_AR_MIO_INF_DC | CA_SF_AR_MIO_INF(CA_SF_ACCESS_MIO_DUAL) | CA_SF_AR_FORCE_BURST); } else if (width == 1) { setbits_le32(&priv->regs->ar, CA_SF_AR_MIO_INF(CA_SF_ACCESS_MIO_SINGLE) | CA_SF_AR_FORCE_BURST); } else { printf("%s: error rx/tx width %d!\n", __func__, width); return -1; } return 0; } static int _ca_sflash_write(struct ca_sflash_priv *priv, u8 *buf, unsigned int data_len) { u32 reg_data; int len; len = data_len; while (len > 0) { reg_data = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); debug("%s: reg_data=%#08x\n", __func__, reg_data); /* Fill data */ clrsetbits_le32(&priv->regs->dr, GENMASK(31, 0), reg_data); if (_ca_sflash_wait_cmd(priv, WR_ACCESS)) return -1; len -= 4; buf += 4; } return 0; } static int _ca_sflash_access_data(struct ca_sflash_priv *priv, struct spi_mem_op *op) { int total_cnt; unsigned int len; unsigned int data_cnt = op->data.nbytes; u64 addr_offset = op->addr.val; u8 addr_cnt = op->addr.nbytes; u8 *data_buf = NULL; u8 *buf = NULL; if (op->data.dir == SPI_MEM_DATA_IN) data_buf = (u8 *)op->data.buf.in; else data_buf = (u8 *)op->data.buf.out; if (data_cnt > CA_SF_EAR_DATA_CNT_MAX) buf = malloc(CA_SF_EAR_DATA_CNT_MAX); else buf = malloc(data_cnt); total_cnt = data_cnt; while (total_cnt > 0) { /* Fill address */ if (addr_cnt > 0) clrsetbits_le32(&priv->regs->adr, GENMASK(31, 0), (u32)addr_offset); if (total_cnt > CA_SF_EAR_DATA_CNT_MAX) { len = CA_SF_EAR_DATA_CNT_MAX; addr_offset += CA_SF_EAR_DATA_CNT_MAX; /* Clear start bit before next bulk read */ clrbits_le32(&priv->regs->asr, GENMASK(31, 0)); } else { len = total_cnt; } memset(buf, 0, len); if (op->data.dir == SPI_MEM_DATA_IN) { if (_ca_sflash_read(priv, buf, len)) break; memcpy(data_buf, buf, len); } else { memcpy(buf, data_buf, len); if (_ca_sflash_write(priv, buf, len)) break; } total_cnt -= len; data_buf += len; } if (buf) free(buf); return total_cnt > 0 ? -1 : 0; } static int _ca_sflash_issue_cmd(struct ca_sflash_priv *priv, struct spi_mem_op *op, u8 opcode) { u8 dummy_cnt = op->dummy.nbytes; u8 addr_cnt = op->addr.nbytes; u8 mio_width; unsigned int data_cnt = op->data.nbytes; u64 addr_offset = op->addr.val; /* Set the access register */ clrsetbits_le32(&priv->regs->ar, GENMASK(31, 0), CA_SF_AR_ACCODE(opcode)); if (opcode == CA_SF_AC_OP_EXTEND) { /* read_data, write_data */ if (data_cnt > 6) { if (op->data.dir == SPI_MEM_DATA_IN) mio_width = priv->rx_width; else mio_width = priv->tx_width; if (_ca_sflash_mio_set(priv, mio_width)) return -1; } debug("%s: FLASH ACCESS reg=%#08x\n", __func__, readl(&priv->regs->ar)); /* Use command in extend_access register */ clrsetbits_le32(&priv->regs->ear, GENMASK(31, 0), CA_SF_EAR_OP(op->cmd.opcode) | CA_SF_EAR_DUMY_CNT(dummy_cnt * 8 - 1) | CA_SF_EAR_ADDR_CNT(addr_cnt - 1) | CA_SF_EAR_DATA_CNT(4 - 1) | CA_SF_EAR_DRD_CMD_EN); debug("%s: FLASH EXT ACCESS reg=%#08x\n", __func__, readl(&priv->regs->ear)); if (_ca_sflash_access_data(priv, op)) return -1; } else { /* reset_op, wr_enable, wr_disable */ setbits_le32(&priv->regs->ar, CA_SF_AR_OP(op->cmd.opcode)); debug("%s: FLASH ACCESS reg=%#08x\n", __func__, readl(&priv->regs->ar)); if (opcode == CA_SF_AC_OP_4_ADDR) { /* erase_op */ /* Configure address length */ if (addr_cnt > 3) /* 4 Bytes address */ setbits_le32(&priv->regs->tr, CA_FLASH_TR_SIZE(2)); else /* 3 Bytes address */ clrbits_le32(&priv->regs->tr, CA_FLASH_TR_SIZE_MSK); /* Fill address */ if (addr_cnt > 0) clrsetbits_le32(&priv->regs->adr, GENMASK(31, 0), (u32)addr_offset); } if (_ca_sflash_wait_cmd(priv, RD_ACCESS)) return -1; } /* elapse 10us before issuing any other command */ udelay(10); return 0; } static int ca_sflash_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) { struct ca_sflash_priv *priv = dev_get_priv(slave->dev->parent); u8 opcode; debug("%s: cmd:%#02x addr.val:%#llx addr.len:%#x data.len:%#x data.dir:%#x\n", __func__, op->cmd.opcode, op->addr.val, op->addr.nbytes, op->data.nbytes, op->data.dir); if (op->data.nbytes == 0 && op->addr.nbytes == 0) { opcode = CA_SF_AC_OP; } else if (op->data.nbytes == 0 && op->addr.nbytes > 0) { opcode = CA_SF_AC_OP_4_ADDR; } else if (op->data.nbytes > 0) { opcode = CA_SF_AC_OP_EXTEND; } else { printf("%s: can't support cmd.opcode:(%#02x) type currently!\n", __func__, op->cmd.opcode); return -1; } return _ca_sflash_issue_cmd(priv, (struct spi_mem_op *)op, opcode); } static void ca_sflash_init(struct ca_sflash_priv *priv) { /* Set FLASH_TYPE as serial flash, value: 0x0400*/ clrsetbits_le32(&priv->regs->tr, GENMASK(31, 0), CA_FLASH_TR_SIZE(2)); debug("%s: FLASH_TYPE reg=%#x\n", __func__, readl(&priv->regs->tr)); /* Minimize flash timing, value: 0x07010101 */ clrsetbits_le32(&priv->regs->tmr, GENMASK(31, 0), CA_SF_TMR_CLK(0x07) | CA_SF_TMR_SETUP(0x01) | CA_SF_TMR_HOLD(0x01) | CA_SF_TMR_IDLE(0x01)); debug("%s: FLASH_TIMING reg=%#x\n", __func__, readl(&priv->regs->tmr)); } static int ca_sflash_probe(struct udevice *dev) { struct ca_sflash_priv *priv = dev_get_priv(dev); struct resource res; int ret; /* Map the registers */ ret = dev_read_resource_byname(dev, "sflash-regs", &res); if (ret) { dev_err(dev, "can't get regs base addresses(ret = %d)!\n", ret); return ret; } priv->regs = devm_ioremap(dev, res.start, resource_size(&res)); if (IS_ERR(priv->regs)) return PTR_ERR(priv->regs); ca_sflash_init(priv); printf("SFLASH: Controller probed ready\n"); return 0; } static const struct spi_controller_mem_ops ca_sflash_mem_ops = { .exec_op = ca_sflash_exec_op, }; static const struct dm_spi_ops ca_sflash_ops = { .claim_bus = ca_sflash_claim_bus, .release_bus = ca_sflash_release_bus, .set_speed = ca_sflash_set_speed, .set_mode = ca_sflash_set_mode, .mem_ops = &ca_sflash_mem_ops, }; static const struct udevice_id ca_sflash_ids[] = { {.compatible = "cortina,ca-sflash"}, {} }; U_BOOT_DRIVER(ca_sflash) = { .name = "ca_sflash", .id = UCLASS_SPI, .of_match = ca_sflash_ids, .ops = &ca_sflash_ops, .priv_auto = sizeof(struct ca_sflash_priv), .probe = ca_sflash_probe, };