| 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 boolatmel_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,};
 |