/* For commands: WRSR, WREN, WRDI, CHIP_ERASE, BE, etc. */ int cadence_qspi_apb_command_write(void *reg_base, unsigned int cmdlen, const u8 *cmdbuf, unsigned int txlen, const u8 *txbuf) { unsigned int reg = 0; unsigned int addr_value; unsigned int wr_data; unsigned int wr_len; if (!cmdlen || cmdlen > 5 || txlen > 8 || cmdbuf == NULL) { printf("QSPI: Invalid input arguments cmdlen %d txlen %d\n", cmdlen, txlen); return -EINVAL; } reg |= cmdbuf[0] << CQSPI_REG_CMDCTRL_OPCODE_LSB; if (cmdlen == 4 || cmdlen == 5) { /* Command with address */ reg |= (0x1 << CQSPI_REG_CMDCTRL_ADDR_EN_LSB); /* Number of bytes to write. */ reg |= ((cmdlen - 2) & CQSPI_REG_CMDCTRL_ADD_BYTES_MASK) << CQSPI_REG_CMDCTRL_ADD_BYTES_LSB; /* Get address */ addr_value = cadence_qspi_apb_cmd2addr(&cmdbuf[1], cmdlen >= 5 ? 4 : 3); writel(addr_value, reg_base + CQSPI_REG_CMDADDRESS); } if (txlen) { /* writing data = yes */ reg |= (0x1 << CQSPI_REG_CMDCTRL_WR_EN_LSB); reg |= ((txlen - 1) & CQSPI_REG_CMDCTRL_WR_BYTES_MASK) << CQSPI_REG_CMDCTRL_WR_BYTES_LSB; wr_len = txlen > 4 ? 4 : txlen; memcpy(&wr_data, txbuf, wr_len); writel(wr_data, reg_base + CQSPI_REG_CMDWRITEDATALOWER); if (txlen > 4) { txbuf += wr_len; wr_len = txlen - wr_len; memcpy(&wr_data, txbuf, wr_len); writel(wr_data, reg_base + CQSPI_REG_CMDWRITEDATAUPPER); } } /* Execute the command */ return cadence_qspi_apb_exec_flash_cmd(reg_base, reg); }
/* For command RDID, RDSR. */ static int cadence_qspi_apb_command_read(void *reg_base, unsigned int txlen, const unsigned char *txbuf, unsigned rxlen, unsigned char *rxbuf) { unsigned int reg; unsigned int read_len; int status; pr_debug("%s txlen %d txbuf %p rxlen %d rxbuf %p\n", __func__, txlen, txbuf, rxlen, rxbuf); hex_dump((unsigned int)txbuf, txbuf, txlen); if (!rxlen || rxlen > CQSPI_STIG_DATA_LEN_MAX || rxbuf == NULL) { pr_err("QSPI: Invalid input argument, len %d rxbuf 0x%08x\n", rxlen, (unsigned int)rxbuf); return -EINVAL; } reg = txbuf[0] << CQSPI_REG_CMDCTRL_OPCODE_LSB; reg |= (0x1 << CQSPI_REG_CMDCTRL_RD_EN_LSB); /* 0 means 1 byte. */ reg |= (((rxlen - 1) & CQSPI_REG_CMDCTRL_RD_BYTES_MASK) << CQSPI_REG_CMDCTRL_RD_BYTES_LSB); status = cadence_qspi_apb_exec_flash_cmd(reg_base, reg); if (status != 0) return status; reg = CQSPI_READL(reg_base + CQSPI_REG_CMDREADDATALOWER); /* Put the read value into rx_buf */ read_len = (rxlen > 4) ? 4 : rxlen; memcpy(rxbuf, ®, read_len); hex_dump((unsigned int)rxbuf, rxbuf, read_len); rxbuf += read_len; if (rxlen > 4) { reg = CQSPI_READL(reg_base + CQSPI_REG_CMDREADDATAUPPER); read_len = rxlen - read_len; memcpy(rxbuf, ®, read_len); hex_dump((unsigned int)rxbuf, rxbuf, read_len); } return 0; }
/* For commands: WRSR, WREN, WRDI, CHIP_ERASE, BE, etc. */ static int cadence_qspi_apb_command_write(void *reg_base, unsigned txlen, const unsigned char *txbuf) { unsigned int reg; unsigned int addr_value; unsigned int data; pr_debug("%s txlen %d txbuf %p\n", __func__, txlen, txbuf); hex_dump((unsigned int)txbuf, txbuf, txlen); if (!txlen || txlen > 5 || txbuf == NULL) { pr_err("QSPI: Invalid input argument, cmdlen %d txbuf 0x%08x\n", txlen, (unsigned int)txbuf); return -EINVAL; } reg = txbuf[0] << CQSPI_REG_CMDCTRL_OPCODE_LSB; if (txlen == 2 || txlen == 3) { /* Command with data only. */ reg |= (0x1 << CQSPI_REG_CMDCTRL_WR_EN_LSB); reg |= ((txlen - 2) & CQSPI_REG_CMDCTRL_WR_BYTES_MASK) << CQSPI_REG_CMDCTRL_WR_BYTES_LSB; memcpy(&data, &txbuf[1], txlen - 1); /* Write the data */ CQSPI_WRITEL(data, reg_base + CQSPI_REG_CMDWRITEDATALOWER); } else if (txlen == 4 || txlen == 5) { /* Command with address */ reg |= (0x1 << CQSPI_REG_CMDCTRL_ADDR_EN_LSB); /* Number of bytes to write. */ reg |= ((txlen - 2) & CQSPI_REG_CMDCTRL_ADD_BYTES_MASK) << CQSPI_REG_CMDCTRL_ADD_BYTES_LSB; /* Get address */ addr_value = cadence_qspi_apb_cmd2addr(&txbuf[1], txlen >=5 ? 4 : 3); CQSPI_WRITEL(addr_value, reg_base + CQSPI_REG_CMDADDRESS); } return cadence_qspi_apb_exec_flash_cmd(reg_base, reg); }
/* For command RDID, RDSR. */ int cadence_qspi_apb_command_read(void *reg_base, unsigned int cmdlen, const u8 *cmdbuf, unsigned int rxlen, u8 *rxbuf) { unsigned int reg; unsigned int read_len; int status; if (!cmdlen || rxlen > CQSPI_STIG_DATA_LEN_MAX || rxbuf == NULL) { printf("QSPI: Invalid input arguments cmdlen %d rxlen %d\n", cmdlen, rxlen); return -EINVAL; } reg = cmdbuf[0] << CQSPI_REG_CMDCTRL_OPCODE_LSB; reg |= (0x1 << CQSPI_REG_CMDCTRL_RD_EN_LSB); /* 0 means 1 byte. */ reg |= (((rxlen - 1) & CQSPI_REG_CMDCTRL_RD_BYTES_MASK) << CQSPI_REG_CMDCTRL_RD_BYTES_LSB); status = cadence_qspi_apb_exec_flash_cmd(reg_base, reg); if (status != 0) return status; reg = readl(reg_base + CQSPI_REG_CMDREADDATALOWER); /* Put the read value into rx_buf */ read_len = (rxlen > 4) ? 4 : rxlen; memcpy(rxbuf, ®, read_len); rxbuf += read_len; if (rxlen > 4) { reg = readl(reg_base + CQSPI_REG_CMDREADDATAUPPER); read_len = rxlen - read_len; memcpy(rxbuf, ®, read_len); } return 0; }