| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404 | 
							- /*
 
-  * Copyright (C) 2017 Atmel Corporation
 
-  *
 
-  * SPDX-License-Identifier:	GPL-2.0+
 
-  */
 
- #include <common.h>
 
- #include <clk.h>
 
- #include <dm.h>
 
- #include <fdtdec.h>
 
- #include <errno.h>
 
- #include <spi.h>
 
- #include <asm/io.h>
 
- #include <mach/clk.h>
 
- #include "atmel_qspi.h"
 
- DECLARE_GLOBAL_DATA_PTR;
 
- static void atmel_qspi_memcpy_fromio(void *dst, unsigned long src, size_t len)
 
- {
 
- 	u8 *d = (u8 *)dst;
 
- 	while (len--) {
 
- 		*d++ = readb(src);
 
- 		src++;
 
- 	}
 
- }
 
- static void atmel_qspi_memcpy_toio(unsigned long dst, const void *src,
 
- 				   size_t len)
 
- {
 
- 	const u8 *s = (const u8 *)src;
 
- 	while (len--) {
 
- 		writeb(*s, dst);
 
- 		dst++;
 
- 		s++;
 
- 	}
 
- }
 
- static int atmel_qspi_set_ifr_tfrtype(u8 flags, u32 *ifr)
 
- {
 
- 	u32 ifr_tfrtype;
 
- 	switch (flags & SPI_FCMD_TYPE) {
 
- 	case SPI_FCMD_READ:
 
- 		ifr_tfrtype = QSPI_IFR_TFRTYPE_READ_MEMORY;
 
- 		break;
 
- 	case SPI_FCMD_WRITE:
 
- 		ifr_tfrtype = QSPI_IFR_TFRTYPE_WRITE_MEMORY;
 
- 		break;
 
- 	case SPI_FCMD_ERASE:
 
- 	case SPI_FCMD_WRITE_REG:
 
- 		ifr_tfrtype = QSPI_IFR_TFRTYPE_WRITE;
 
- 		break;
 
- 	case SPI_FCMD_READ_REG:
 
- 		ifr_tfrtype = QSPI_IFR_TFRTYPE_READ;
 
- 		break;
 
- 	default:
 
- 		return -EINVAL;
 
- 	}
 
- 	*ifr = (*ifr & ~QSPI_IFR_TFRTYPE) | ifr_tfrtype;
 
- 	return 0;
 
- }
 
- static int atmel_qpsi_set_ifr_width(enum spi_flash_protocol proto, u32 *ifr)
 
- {
 
- 	u32 ifr_width;
 
- 	switch (proto) {
 
- 	case SPI_FPROTO_1_1_1:
 
- 		ifr_width = QSPI_IFR_WIDTH_SINGLE_BIT_SPI;
 
- 		break;
 
- 	case SPI_FPROTO_1_1_2:
 
- 		ifr_width = QSPI_IFR_WIDTH_DUAL_OUTPUT;
 
- 		break;
 
- 	case SPI_FPROTO_1_2_2:
 
- 		ifr_width = QSPI_IFR_WIDTH_DUAL_IO;
 
- 		break;
 
- 	case SPI_FPROTO_2_2_2:
 
- 		ifr_width = QSPI_IFR_WIDTH_DUAL_CMD;
 
- 		break;
 
- 	case SPI_FPROTO_1_1_4:
 
- 		ifr_width = QSPI_IFR_WIDTH_QUAD_OUTPUT;
 
- 		break;
 
- 	case SPI_FPROTO_1_4_4:
 
- 		ifr_width = QSPI_IFR_WIDTH_QUAD_IO;
 
- 		break;
 
- 	case SPI_FPROTO_4_4_4:
 
- 		ifr_width = QSPI_IFR_WIDTH_QUAD_CMD;
 
- 		break;
 
- 	default:
 
- 		return -EINVAL;
 
- 	}
 
- 	*ifr = (*ifr & ~QSPI_IFR_WIDTH) | ifr_width;
 
- 	return 0;
 
- }
 
- static int atmel_qspi_xfer(struct udevice *dev, unsigned int bitlen,
 
- 			   const void *dout, void *din, unsigned long flags)
 
- {
 
- 	/* This controller can only be used with SPI NOR flashes. */
 
- 	return -EINVAL;
 
- }
 
- static int atmel_qspi_set_speed(struct udevice *bus, uint hz)
 
- {
 
- 	struct atmel_qspi_priv *aq = dev_get_priv(bus);
 
- 	u32 scr, scbr, mask, new_value;
 
- 	/* Compute the QSPI baudrate */
 
- 	scbr = DIV_ROUND_UP(aq->bus_clk_rate, hz);
 
- 	if (scbr > 0)
 
- 		scbr--;
 
- 	new_value = QSPI_SCR_SCBR_(scbr);
 
- 	mask = QSPI_SCR_SCBR;
 
- 	scr = qspi_readl(aq, QSPI_SCR);
 
- 	if ((scr & mask) == new_value)
 
- 		return 0;
 
- 	scr = (scr & ~mask) | new_value;
 
- 	qspi_writel(aq, QSPI_SCR, scr);
 
- 	return 0;
 
- }
 
- static int atmel_qspi_set_mode(struct udevice *bus, uint mode)
 
- {
 
- 	struct atmel_qspi_priv *aq = dev_get_priv(bus);
 
- 	u32 scr, mask, new_value;
 
- 	new_value = (QSPI_SCR_CPOL_((mode & SPI_CPOL) != 0) |
 
- 		     QSPI_SCR_CPHA_((mode & SPI_CPHA) != 0));
 
- 	mask = (QSPI_SCR_CPOL | QSPI_SCR_CPHA);
 
- 	scr = qspi_readl(aq, QSPI_SCR);
 
- 	if ((scr & mask) == new_value)
 
- 		return 0;
 
- 	scr = (scr & ~mask) | new_value;
 
- 	qspi_writel(aq, QSPI_SCR, scr);
 
- 	return 0;
 
- }
 
- static bool
 
- atmel_qspi_is_flash_command_supported(struct udevice *dev,
 
- 				      const struct spi_flash_command *cmd)
 
- {
 
- 	return true;
 
- }
 
- static int atmel_qspi_exec_flash_command(struct udevice *dev,
 
- 					 const struct spi_flash_command *cmd)
 
- {
 
- 	struct udevice *bus = dev_get_parent(dev);
 
- 	struct atmel_qspi_priv *aq = dev_get_priv(bus);
 
- 	unsigned int iar, icr, ifr;
 
- 	unsigned int offset;
 
- 	unsigned int imr, sr;
 
- 	unsigned long memaddr;
 
- 	int err;
 
- 	iar = 0;
 
- 	icr = 0;
 
- 	ifr = 0;
 
- 	err = atmel_qspi_set_ifr_tfrtype(cmd->flags, &ifr);
 
- 	if (err)
 
- 		return err;
 
- 	err = atmel_qpsi_set_ifr_width(cmd->proto, &ifr);
 
- 	if (err)
 
- 		return err;
 
- 	/* Compute instruction parameters */
 
- 	icr |= QSPI_ICR_INST_(cmd->inst);
 
- 	ifr |= QSPI_IFR_INSTEN;
 
- 	/* Compute address parameters. */
 
- 	switch (cmd->addr_len) {
 
- 	case 4:
 
- 		ifr |= QSPI_IFR_ADDRL_32_BIT;
 
- 		/*break;*/ /* fall through the 24bit (3 byte) address case */
 
- 	case 3:
 
- 		iar = cmd->data_len ? 0 : cmd->addr;
 
- 		ifr |= QSPI_IFR_ADDREN;
 
- 		offset = cmd->addr;
 
- 		break;
 
- 	case 0:
 
- 		offset = 0;
 
- 		break;
 
- 	default:
 
- 		return -EINVAL;
 
- 	}
 
- 	/* Compute option parameters. */
 
- 	if (cmd->num_mode_cycles) {
 
- 		unsigned int mode_cycle_bits, mode_bits;
 
- 		icr |= QSPI_ICR_OPT_(cmd->mode);
 
- 		ifr |= QSPI_IFR_OPTEN;
 
- 		switch (ifr & QSPI_IFR_WIDTH) {
 
- 		case QSPI_IFR_WIDTH_SINGLE_BIT_SPI:
 
- 		case QSPI_IFR_WIDTH_DUAL_OUTPUT:
 
- 		case QSPI_IFR_WIDTH_QUAD_OUTPUT:
 
- 			mode_cycle_bits = 1;
 
- 			break;
 
- 		case QSPI_IFR_WIDTH_DUAL_IO:
 
- 		case QSPI_IFR_WIDTH_DUAL_CMD:
 
- 			mode_cycle_bits = 2;
 
- 			break;
 
- 		case QSPI_IFR_WIDTH_QUAD_IO:
 
- 		case QSPI_IFR_WIDTH_QUAD_CMD:
 
- 			mode_cycle_bits = 4;
 
- 			break;
 
- 		default:
 
- 			return -EINVAL;
 
- 		}
 
- 		mode_bits = cmd->num_mode_cycles * mode_cycle_bits;
 
- 		switch (mode_bits) {
 
- 		case 1:
 
- 			ifr |= QSPI_IFR_OPTL_1BIT;
 
- 			break;
 
- 		case 2:
 
- 			ifr |= QSPI_IFR_OPTL_2BIT;
 
- 			break;
 
- 		case 4:
 
- 			ifr |= QSPI_IFR_OPTL_4BIT;
 
- 			break;
 
- 		case 8:
 
- 			ifr |= QSPI_IFR_OPTL_8BIT;
 
- 			break;
 
- 		default:
 
- 			return -EINVAL;
 
- 		}
 
- 	}
 
- 	/* Set the number of dummy cycles. */
 
- 	if (cmd->num_wait_states)
 
- 		ifr |= QSPI_IFR_NBDUM_(cmd->num_wait_states);
 
- 	/* Set data enable. */
 
- 	if (cmd->data_len)
 
- 		ifr |= QSPI_IFR_DATAEN;
 
- 	/* Clear pending interrupts. */
 
- 	(void)qspi_readl(aq, QSPI_SR);
 
- 	/* Set QSPI Instruction Frame registers. */
 
- 	qspi_writel(aq, QSPI_IAR, iar);
 
- 	qspi_writel(aq, QSPI_ICR, icr);
 
- 	qspi_writel(aq, QSPI_IFR, ifr);
 
- 	/* Skip to the final steps if there is no data. */
 
- 	if (!cmd->data_len)
 
- 		goto no_data;
 
- 	/* Dummy read of QSPI_IFR to synchronize APB and AHB accesses. */
 
- 	(void)qspi_readl(aq, QSPI_IFR);
 
- 	/* Stop here for Continuous Read. */
 
- 	memaddr = (unsigned long)(aq->membase + offset);
 
- 	if (cmd->tx_data)
 
- 		/* Write data. */
 
- 		atmel_qspi_memcpy_toio(memaddr, cmd->tx_data, cmd->data_len);
 
- 	else if (cmd->rx_data)
 
- 		/* Read data. */
 
- 		atmel_qspi_memcpy_fromio(cmd->rx_data, memaddr, cmd->data_len);
 
- 	/* Release the chip-select. */
 
- 	qspi_writel(aq, QSPI_CR, QSPI_CR_LASTXFER);
 
- no_data:
 
- 	/* Poll INSTruction End and Chip Select Rise flags. */
 
- 	imr = QSPI_SR_INSTRE | QSPI_SR_CSR;
 
- 	sr = 0;
 
- 	while (sr != (QSPI_SR_INSTRE | QSPI_SR_CSR))
 
- 		sr |= qspi_readl(aq, QSPI_SR) & imr;
 
- 	return 0;
 
- }
 
- static const struct dm_spi_ops atmel_qspi_ops = {
 
- 	.xfer				= atmel_qspi_xfer,
 
- 	.set_speed			= atmel_qspi_set_speed,
 
- 	.set_mode			= atmel_qspi_set_mode,
 
- 	.is_flash_command_supported	= atmel_qspi_is_flash_command_supported,
 
- 	.exec_flash_command		= atmel_qspi_exec_flash_command,
 
- };
 
- static int atmel_qspi_enable_clk(struct udevice *bus)
 
- {
 
- 	struct atmel_qspi_priv *aq = dev_get_priv(bus);
 
- 	struct clk clk;
 
- 	ulong clk_rate;
 
- 	int ret;
 
- 	ret = clk_get_by_index(bus, 0, &clk);
 
- 	if (ret)
 
- 		return -EINVAL;
 
- 	ret = clk_enable(&clk);
 
- 	if (ret)
 
- 		goto free_clock;
 
- 	clk_rate = clk_get_rate(&clk);
 
- 	if (!clk_rate) {
 
- 		ret = -EINVAL;
 
- 		goto free_clock;
 
- 	}
 
- 	aq->bus_clk_rate = clk_rate;
 
- free_clock:
 
- 	clk_free(&clk);
 
- 	return ret;
 
- }
 
- static int atmel_qspi_probe(struct udevice *bus)
 
- {
 
- 	const struct atmel_qspi_platdata *plat = dev_get_platdata(bus);
 
- 	struct atmel_qspi_priv *aq = dev_get_priv(bus);
 
- 	u32 mr;
 
- 	int ret;
 
- 	ret = atmel_qspi_enable_clk(bus);
 
- 	if (ret)
 
- 		return ret;
 
- 	aq->regbase = plat->regbase;
 
- 	aq->membase = plat->membase;
 
- 	/* Reset the QSPI controler */
 
- 	qspi_writel(aq, QSPI_CR, QSPI_CR_SWRST);
 
- 	/* Set the QSPI controller in Serial Memory Mode */
 
- 	mr = (QSPI_MR_NBBITS_8_BIT |
 
- 	      QSPI_MR_SMM_MEMORY |
 
- 	      QSPI_MR_CSMODE_LASTXFER);
 
- 	qspi_writel(aq, QSPI_MR, mr);
 
- 	/* Enable the QSPI controller */
 
- 	qspi_writel(aq, QSPI_CR, QSPI_CR_QSPIEN);
 
- 	return 0;
 
- }
 
- static int atmel_qspi_ofdata_to_platdata(struct udevice *bus)
 
- {
 
- 	struct atmel_qspi_platdata *plat = dev_get_platdata(bus);
 
- 	const void *blob = gd->fdt_blob;
 
- 	int node = dev_of_offset (bus);
 
- 	u32 data[4];
 
- 	int ret;
 
- 	ret = fdtdec_get_int_array(blob, node, "reg", data, ARRAY_SIZE(data));
 
- 	if (ret) {
 
- 		printf("Error: Can't get base addresses (ret=%d)!\n", ret);
 
- 		return -ENODEV;
 
- 	}
 
- 	plat->regbase = (void *)data[0];
 
- 	plat->membase = (void *)data[2];
 
- 	return 0;
 
- }
 
- static const struct udevice_id atmel_qspi_ids[] = {
 
- 	{ .compatible = "atmel,sama5d2-qspi" },
 
- 	{ }
 
- };
 
- U_BOOT_DRIVER(atmel_qspi) = {
 
- 	.name		= "atmel_qspi",
 
- 	.id		= UCLASS_SPI,
 
- 	.of_match	= atmel_qspi_ids,
 
- 	.ops		= &atmel_qspi_ops,
 
- 	.ofdata_to_platdata = atmel_qspi_ofdata_to_platdata,
 
- 	.platdata_auto_alloc_size = sizeof(struct atmel_qspi_platdata),
 
- 	.priv_auto_alloc_size = sizeof(struct atmel_qspi_priv),
 
- 	.probe		= atmel_qspi_probe,
 
- };
 
 
  |