Exemple #1
0
/* Opcode + Address (3/4 bytes) */
int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat,
	unsigned int cmdlen, const u8 *cmdbuf)
{
	unsigned int reg;
	unsigned int addr_bytes = cmdlen > 4 ? 4 : 3;

	if (cmdlen < 4 || cmdbuf == NULL) {
		printf("QSPI: iInvalid input argument, len %d cmdbuf 0x%08x\n",
		       cmdlen, (unsigned int)cmdbuf);
		return -EINVAL;
	}
	/* Setup the indirect trigger address */
	writel((u32)plat->ahbbase,
	       plat->regbase + CQSPI_REG_INDIRECTTRIGGER);

	/* Configure the opcode */
	reg = cmdbuf[0] << CQSPI_REG_WR_INSTR_OPCODE_LSB;
	writel(reg, plat->regbase + CQSPI_REG_WR_INSTR);

	/* Setup write address. */
	reg = cadence_qspi_apb_cmd2addr(&cmdbuf[1], addr_bytes);
	writel(reg, plat->regbase + CQSPI_REG_INDIRECTWRSTARTADDR);

	reg = readl(plat->regbase + CQSPI_REG_SIZE);
	reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
	reg |= (addr_bytes - 1);
	writel(reg, plat->regbase + CQSPI_REG_SIZE);
	return 0;
}
static int cadence_qspi_apb_indirect_write_setup(void *reg_base,
	unsigned int ahb_phy_addr, unsigned txlen, const unsigned char *txbuf)
{
	unsigned int reg;
	unsigned int addr_bytes = (txlen >= 5) ? 4: 3;

	pr_debug("%s txlen %d txbuf %p addr_bytes %d\n",
		__func__, txlen, txbuf, addr_bytes);
	hex_dump((unsigned int)txbuf, txbuf, txlen);

	if (txlen < 4 || txbuf == NULL) {
		pr_err("QSPI: Invalid input argument, txlen %d txbuf 0x%08x\n",
			txlen, (unsigned int)txbuf);
		return -EINVAL;
	}

	CQSPI_WRITEL((ahb_phy_addr & CQSPI_INDIRECTTRIGGER_ADDR_MASK),
		reg_base + CQSPI_REG_INDIRECTTRIGGER);

	/* Set opcode. */
	reg = txbuf[0] << CQSPI_REG_WR_INSTR_OPCODE_LSB;
	CQSPI_WRITEL(reg, reg_base + CQSPI_REG_WR_INSTR);

	/* Setup write address. */
	reg = cadence_qspi_apb_cmd2addr(&txbuf[1], addr_bytes);
	CQSPI_WRITEL(reg, reg_base + CQSPI_REG_INDIRECTWRSTARTADDR);

	reg = CQSPI_READL(reg_base + CQSPI_REG_SIZE);
	reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
	reg |= (addr_bytes - 1);
	CQSPI_WRITEL(reg, reg_base +  CQSPI_REG_SIZE);
	return 0;
}
Exemple #3
0
/* 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 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);
}
Exemple #5
0
/* Opcode + Address (3/4 bytes) + dummy bytes (0-4 bytes) */
int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat,
	unsigned int cmdlen, unsigned int rx_width, const u8 *cmdbuf)
{
	unsigned int reg;
	unsigned int rd_reg;
	unsigned int addr_value;
	unsigned int dummy_clk;
	unsigned int dummy_bytes;
	unsigned int addr_bytes;

	/*
	 * Identify addr_byte. All NOR flash device drivers are using fast read
	 * which always expecting 1 dummy byte, 1 cmd byte and 3/4 addr byte.
	 * With that, the length is in value of 5 or 6. Only FRAM chip from
	 * ramtron using normal read (which won't need dummy byte).
	 * Unlikely NOR flash using normal read due to performance issue.
	 */
	if (cmdlen >= 5)
		/* to cater fast read where cmd + addr + dummy */
		addr_bytes = cmdlen - 2;
	else
		/* for normal read (only ramtron as of now) */
		addr_bytes = cmdlen - 1;

	/* Setup the indirect trigger address */
	writel((u32)plat->ahbbase,
	       plat->regbase + CQSPI_REG_INDIRECTTRIGGER);

	/* Configure the opcode */
	rd_reg = cmdbuf[0] << CQSPI_REG_RD_INSTR_OPCODE_LSB;

	if (rx_width & SPI_RX_QUAD)
		/* Instruction and address at DQ0, data at DQ0-3. */
		rd_reg |= CQSPI_INST_TYPE_QUAD << CQSPI_REG_RD_INSTR_TYPE_DATA_LSB;

	/* Get address */
	addr_value = cadence_qspi_apb_cmd2addr(&cmdbuf[1], addr_bytes);
	writel(addr_value, plat->regbase + CQSPI_REG_INDIRECTRDSTARTADDR);

	/* The remaining lenght is dummy bytes. */
	dummy_bytes = cmdlen - addr_bytes - 1;
	if (dummy_bytes) {
		if (dummy_bytes > CQSPI_DUMMY_BYTES_MAX)
			dummy_bytes = CQSPI_DUMMY_BYTES_MAX;

		rd_reg |= (1 << CQSPI_REG_RD_INSTR_MODE_EN_LSB);
#if defined(CONFIG_SPL_SPI_XIP) && defined(CONFIG_SPL_BUILD)
		writel(0x0, plat->regbase + CQSPI_REG_MODE_BIT);
#else
		writel(0xFF, plat->regbase + CQSPI_REG_MODE_BIT);
#endif

		/* Convert to clock cycles. */
		dummy_clk = dummy_bytes * CQSPI_DUMMY_CLKS_PER_BYTE;
		/* Need to minus the mode byte (8 clocks). */
		dummy_clk -= CQSPI_DUMMY_CLKS_PER_BYTE;

		if (dummy_clk)
			rd_reg |= (dummy_clk & CQSPI_REG_RD_INSTR_DUMMY_MASK)
				<< CQSPI_REG_RD_INSTR_DUMMY_LSB;
	}

	writel(rd_reg, plat->regbase + CQSPI_REG_RD_INSTR);

	/* set device size */
	reg = readl(plat->regbase + CQSPI_REG_SIZE);
	reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
	reg |= (addr_bytes - 1);
	writel(reg, plat->regbase + CQSPI_REG_SIZE);
	return 0;
}
static int cadence_qspi_apb_indirect_read_setup(void *reg_base,
	unsigned int ahb_phy_addr, unsigned txlen, const unsigned char *txbuf,
	unsigned int addr_bytes)
{
	unsigned int reg;
	unsigned int addr_value;
	unsigned int dummy_clk;
	unsigned int dummy_bytes;

	pr_debug("%s txlen %d txbuf %p addr_bytes %d\n",
		__func__, txlen, txbuf, addr_bytes);
	hex_dump((unsigned int)txbuf, txbuf, txlen);

	if ((addr_bytes == 3 && txlen < 4) || (addr_bytes == 4 && txlen < 5)) {
		pr_err("QSPI: Invalid txbuf length, length %d\n", txlen);
		return -EINVAL;
	}

	CQSPI_WRITEL((ahb_phy_addr & CQSPI_INDIRECTTRIGGER_ADDR_MASK),
		reg_base + CQSPI_REG_INDIRECTTRIGGER);

	reg = txbuf[0] << CQSPI_REG_RD_INSTR_OPCODE_LSB;

#ifdef CONFIG_M25PXX_USE_FAST_READ_QUAD_OUTPUT
#error WTFO
	reg |= (CQSPI_INST_TYPE_QUAD << CQSPI_REG_RD_INSTR_TYPE_DATA_LSB);
#endif /* CONFIG_M25PXX_USE_FAST_READ_QUAD_OUTPUT */

	/* Get address */
	addr_value = cadence_qspi_apb_cmd2addr(&txbuf[1], addr_bytes);
	CQSPI_WRITEL(addr_value, reg_base + CQSPI_REG_INDIRECTRDSTARTADDR);

	/* The remaining lenght is dummy bytes. */
	dummy_bytes = txlen - addr_bytes - 1;

	/* Setup dummy clock cycles */
	if (dummy_bytes) {

		if (dummy_bytes > CQSPI_DUMMY_BYTES_MAX)
			dummy_bytes = CQSPI_DUMMY_BYTES_MAX;

		reg |= (1 << CQSPI_REG_RD_INSTR_MODE_EN_LSB);
		/* Set all high to ensure chip doesn't enter XIP */
		CQSPI_WRITEL(0xFF, reg_base + CQSPI_REG_MODE_BIT);

		/* Convert to clock cycles. */
		dummy_clk = dummy_bytes * CQSPI_DUMMY_CLKS_PER_BYTE;
		/* Need to minus the mode byte (8 clocks). */
		dummy_clk -= CQSPI_DUMMY_CLKS_PER_BYTE;

		if (dummy_clk)
			reg |= (dummy_clk & CQSPI_REG_RD_INSTR_DUMMY_MASK)
				<< CQSPI_REG_RD_INSTR_DUMMY_LSB;
	}

	CQSPI_WRITEL(reg, reg_base + CQSPI_REG_RD_INSTR);

	/* Set device size */
	reg = CQSPI_READL(reg_base + CQSPI_REG_SIZE);
	reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
	reg |= (addr_bytes - 1);
	CQSPI_WRITEL(reg, reg_base + CQSPI_REG_SIZE);
	return 0;
}