mirror of
				https://source.denx.de/u-boot/u-boot.git
				synced 2025-10-31 16:31:25 +01:00 
			
		
		
		
	Like clk_get_by_index, there is requirement for
clk_get_by_index_nodev. In this case to make common
code functionalities for dev and nodev, clk_get_by_index
is trying to get the index of clock by passing ofnode
instead of actual dev like current gpio uclass does.
In these scenarios with current order of include files
the atcspi200_spi driver is unable to find CONFIG_ENV_SIZE.
In file included from arch/nds32/include/asm/u-boot.h:24,
                 from include/dm/of.h:10,
                 from include/dm/ofnode.h:12,
                 from include/clk.h:11,
                 from drivers/spi/atcspi200_spi.c:9:
include/environment.h:145:19: error: 'CONFIG_ENV_SIZE'
undeclared here (not in a function); did you mean 'CONFIG_CMD_XIMG'?
 #define ENV_SIZE (CONFIG_ENV_SIZE - ENV_HEADER_SIZE)
So, fix consists of changing the order of include files
in atcspi200_spi.c to include first common.h file.
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
		
	
			
		
			
				
	
	
		
			414 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			414 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0+
 | |
| /*
 | |
|  * Andestech ATCSPI200 SPI controller driver.
 | |
|  *
 | |
|  * Copyright 2017 Andes Technology, Inc.
 | |
|  * Author: Rick Chen (rick@andestech.com)
 | |
|  */
 | |
| 
 | |
| #include <common.h>
 | |
| #include <clk.h>
 | |
| #include <malloc.h>
 | |
| #include <spi.h>
 | |
| #include <asm/io.h>
 | |
| #include <dm.h>
 | |
| 
 | |
| DECLARE_GLOBAL_DATA_PTR;
 | |
| 
 | |
| #define MAX_TRANSFER_LEN	512
 | |
| #define CHUNK_SIZE		1
 | |
| #define SPI_TIMEOUT		0x100000
 | |
| #define SPI0_BUS		0
 | |
| #define SPI1_BUS		1
 | |
| #define SPI0_BASE		0xf0b00000
 | |
| #define SPI1_BASE		0xf0f00000
 | |
| #define NSPI_MAX_CS_NUM		1
 | |
| 
 | |
| struct atcspi200_spi_regs {
 | |
| 	u32	rev;
 | |
| 	u32	reserve1[3];
 | |
| 	u32	format;		/* 0x10 */
 | |
| #define DATA_LENGTH(x)	((x-1)<<8)
 | |
| 	u32	pio;
 | |
| 	u32	reserve2[2];
 | |
| 	u32	tctrl;		/* 0x20 */
 | |
| #define TRAMODE_OFFSET	24
 | |
| #define TRAMODE_MASK	(0x0F<<TRAMODE_OFFSET)
 | |
| #define TRAMODE_WR_SYNC	(0<<TRAMODE_OFFSET)
 | |
| #define TRAMODE_WO	(1<<TRAMODE_OFFSET)
 | |
| #define TRAMODE_RO	(2<<TRAMODE_OFFSET)
 | |
| #define TRAMODE_WR	(3<<TRAMODE_OFFSET)
 | |
| #define TRAMODE_RW	(4<<TRAMODE_OFFSET)
 | |
| #define TRAMODE_WDR	(5<<TRAMODE_OFFSET)
 | |
| #define TRAMODE_RDW	(6<<TRAMODE_OFFSET)
 | |
| #define TRAMODE_NONE	(7<<TRAMODE_OFFSET)
 | |
| #define TRAMODE_DW	(8<<TRAMODE_OFFSET)
 | |
| #define TRAMODE_DR	(9<<TRAMODE_OFFSET)
 | |
| #define WCNT_OFFSET	12
 | |
| #define WCNT_MASK	(0x1FF<<WCNT_OFFSET)
 | |
| #define RCNT_OFFSET	0
 | |
| #define RCNT_MASK	(0x1FF<<RCNT_OFFSET)
 | |
| 	u32	cmd;
 | |
| 	u32	addr;
 | |
| 	u32	data;
 | |
| 	u32	ctrl;		/* 0x30 */
 | |
| #define TXFTH_OFFSET	16
 | |
| #define RXFTH_OFFSET	8
 | |
| #define TXDMAEN		(1<<4)
 | |
| #define RXDMAEN		(1<<3)
 | |
| #define TXFRST		(1<<2)
 | |
| #define RXFRST		(1<<1)
 | |
| #define SPIRST		(1<<0)
 | |
| 	u32	status;
 | |
| #define TXFFL		(1<<23)
 | |
| #define TXEPTY		(1<<22)
 | |
| #define TXFVE_MASK	(0x1F<<16)
 | |
| #define RXFEM		(1<<14)
 | |
| #define RXFVE_OFFSET	(8)
 | |
| #define RXFVE_MASK	(0x1F<<RXFVE_OFFSET)
 | |
| #define SPIBSY		(1<<0)
 | |
| 	u32	inten;
 | |
| 	u32	intsta;
 | |
| 	u32	timing;		/* 0x40 */
 | |
| #define SCLK_DIV_MASK	0xFF
 | |
| };
 | |
| 
 | |
| struct nds_spi_slave {
 | |
| 	volatile struct atcspi200_spi_regs *regs;
 | |
| 	int		to;
 | |
| 	unsigned int	freq;
 | |
| 	ulong		clock;
 | |
| 	unsigned int	mode;
 | |
| 	u8 		num_cs;
 | |
| 	unsigned int	mtiming;
 | |
| 	size_t		cmd_len;
 | |
| 	u8		cmd_buf[16];
 | |
| 	size_t		data_len;
 | |
| 	size_t		tran_len;
 | |
| 	u8		*din;
 | |
| 	u8		*dout;
 | |
| 	unsigned int    max_transfer_length;
 | |
| };
 | |
| 
 | |
| static int __atcspi200_spi_set_speed(struct nds_spi_slave *ns)
 | |
| {
 | |
| 	u32 tm;
 | |
| 	u8 div;
 | |
| 	tm = ns->regs->timing;
 | |
| 	tm &= ~SCLK_DIV_MASK;
 | |
| 
 | |
| 	if(ns->freq >= ns->clock)
 | |
| 		div =0xff;
 | |
| 	else{
 | |
| 		for (div = 0; div < 0xff; div++) {
 | |
| 			if (ns->freq >= ns->clock / (2 * (div + 1)))
 | |
| 				break;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	tm |= div;
 | |
| 	ns->regs->timing = tm;
 | |
| 
 | |
| 	return 0;
 | |
| 
 | |
| }
 | |
| 
 | |
| static int __atcspi200_spi_claim_bus(struct nds_spi_slave *ns)
 | |
| {
 | |
| 		unsigned int format=0;
 | |
| 		ns->regs->ctrl |= (TXFRST|RXFRST|SPIRST);
 | |
| 		while((ns->regs->ctrl &(TXFRST|RXFRST|SPIRST))&&(ns->to--))
 | |
| 			if(!ns->to)
 | |
| 				return -EINVAL;
 | |
| 
 | |
| 		ns->cmd_len = 0;
 | |
| 		format = ns->mode|DATA_LENGTH(8);
 | |
| 		ns->regs->format = format;
 | |
| 		__atcspi200_spi_set_speed(ns);
 | |
| 
 | |
| 		return 0;
 | |
| }
 | |
| 
 | |
| static int __atcspi200_spi_release_bus(struct nds_spi_slave *ns)
 | |
| {
 | |
| 	/* do nothing */
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int __atcspi200_spi_start(struct nds_spi_slave *ns)
 | |
| {
 | |
| 	int i,olen=0;
 | |
| 	int tc = ns->regs->tctrl;
 | |
| 
 | |
| 	tc &= ~(WCNT_MASK|RCNT_MASK|TRAMODE_MASK);
 | |
| 	if ((ns->din)&&(ns->cmd_len))
 | |
| 		tc |= TRAMODE_WR;
 | |
| 	else if (ns->din)
 | |
| 		tc |= TRAMODE_RO;
 | |
| 	else
 | |
| 		tc |= TRAMODE_WO;
 | |
| 
 | |
| 	if(ns->dout)
 | |
| 		olen = ns->tran_len;
 | |
| 	tc |= (ns->cmd_len+olen-1) << WCNT_OFFSET;
 | |
| 
 | |
| 	if(ns->din)
 | |
| 		tc |= (ns->tran_len-1) << RCNT_OFFSET;
 | |
| 
 | |
| 	ns->regs->tctrl = tc;
 | |
| 	ns->regs->cmd = 1;
 | |
| 
 | |
| 	for (i=0;i<ns->cmd_len;i++)
 | |
| 		ns->regs->data = ns->cmd_buf[i];
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int __atcspi200_spi_stop(struct nds_spi_slave *ns)
 | |
| {
 | |
| 	ns->regs->timing = ns->mtiming;
 | |
| 	while ((ns->regs->status & SPIBSY)&&(ns->to--))
 | |
| 		if (!ns->to)
 | |
| 			return -EINVAL;
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static void __nspi_espi_tx(struct nds_spi_slave *ns, const void *dout)
 | |
| {
 | |
| 	ns->regs->data = *(u8 *)dout;
 | |
| }
 | |
| 
 | |
| static int __nspi_espi_rx(struct nds_spi_slave *ns, void *din, unsigned int bytes)
 | |
| {
 | |
| 	*(u8 *)din = ns->regs->data;
 | |
| 	return bytes;
 | |
| }
 | |
| 
 | |
| 
 | |
| static int __atcspi200_spi_xfer(struct nds_spi_slave *ns,
 | |
| 		unsigned int bitlen,  const void *data_out, void *data_in,
 | |
| 		unsigned long flags)
 | |
| {
 | |
| 		unsigned int event, rx_bytes;
 | |
| 		const void *dout = NULL;
 | |
| 		void *din = NULL;
 | |
| 		int num_blks, num_chunks, max_tran_len, tran_len;
 | |
| 		int num_bytes;
 | |
| 		u8 *cmd_buf = ns->cmd_buf;
 | |
| 		size_t cmd_len = ns->cmd_len;
 | |
| 		unsigned long data_len = bitlen / 8;
 | |
| 		int rf_cnt;
 | |
| 		int ret = 0;
 | |
| 
 | |
| 		max_tran_len = ns->max_transfer_length;
 | |
| 		switch (flags) {
 | |
| 		case SPI_XFER_BEGIN:
 | |
| 			cmd_len = ns->cmd_len = data_len;
 | |
| 			memcpy(cmd_buf, data_out, cmd_len);
 | |
| 			return 0;
 | |
| 
 | |
| 		case 0:
 | |
| 		case SPI_XFER_END:
 | |
| 			if (bitlen == 0) {
 | |
| 				return 0;
 | |
| 			}
 | |
| 			ns->data_len = data_len;
 | |
| 			ns->din = (u8 *)data_in;
 | |
| 			ns->dout = (u8 *)data_out;
 | |
| 			break;
 | |
| 
 | |
| 		case SPI_XFER_BEGIN | SPI_XFER_END:
 | |
| 			ns->data_len = 0;
 | |
| 			ns->din = 0;
 | |
| 			ns->dout = 0;
 | |
| 			cmd_len = ns->cmd_len = data_len;
 | |
| 			memcpy(cmd_buf, data_out, cmd_len);
 | |
| 			data_out = 0;
 | |
| 			data_len = 0;
 | |
| 			__atcspi200_spi_start(ns);
 | |
| 			break;
 | |
| 		}
 | |
| 		if (data_out)
 | |
| 			debug("spi_xfer: data_out %08X(%p) data_in %08X(%p) data_len %lu\n",
 | |
| 			      *(uint *)data_out, data_out, *(uint *)data_in,
 | |
| 			      data_in, data_len);
 | |
| 		num_chunks = DIV_ROUND_UP(data_len, max_tran_len);
 | |
| 		din = data_in;
 | |
| 		dout = data_out;
 | |
| 		while (num_chunks--) {
 | |
| 			tran_len = min((size_t)data_len, (size_t)max_tran_len);
 | |
| 			ns->tran_len = tran_len;
 | |
| 			num_blks = DIV_ROUND_UP(tran_len , CHUNK_SIZE);
 | |
| 			num_bytes = (tran_len) % CHUNK_SIZE;
 | |
| 			if(num_bytes == 0)
 | |
| 				num_bytes = CHUNK_SIZE;
 | |
| 			__atcspi200_spi_start(ns);
 | |
| 
 | |
| 			while (num_blks) {
 | |
| 				event = in_le32(&ns->regs->status);
 | |
| 				if ((event & TXEPTY) && (data_out)) {
 | |
| 					__nspi_espi_tx(ns, dout);
 | |
| 					num_blks -= CHUNK_SIZE;
 | |
| 					dout += CHUNK_SIZE;
 | |
| 				}
 | |
| 
 | |
| 				if ((event & RXFVE_MASK) && (data_in)) {
 | |
| 					rf_cnt = ((event & RXFVE_MASK)>> RXFVE_OFFSET);
 | |
| 					if (rf_cnt >= CHUNK_SIZE)
 | |
| 						rx_bytes = CHUNK_SIZE;
 | |
| 					else if (num_blks == 1 && rf_cnt == num_bytes)
 | |
| 						rx_bytes = num_bytes;
 | |
| 					else
 | |
| 						continue;
 | |
| 
 | |
| 					if (__nspi_espi_rx(ns, din, rx_bytes) == rx_bytes) {
 | |
| 						num_blks -= CHUNK_SIZE;
 | |
| 						din = (unsigned char *)din + rx_bytes;
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			data_len -= tran_len;
 | |
| 			if(data_len)
 | |
| 			{
 | |
| 				ns->cmd_buf[1] += ((tran_len>>16)&0xff);
 | |
| 				ns->cmd_buf[2] += ((tran_len>>8)&0xff);
 | |
| 				ns->cmd_buf[3] += ((tran_len)&0xff);
 | |
| 				ns->data_len = data_len;
 | |
| 			}
 | |
| 			ret = __atcspi200_spi_stop(ns);
 | |
| 		}
 | |
| 		ret = __atcspi200_spi_stop(ns);
 | |
| 
 | |
| 		return ret;
 | |
| }
 | |
| 
 | |
| static int atcspi200_spi_set_speed(struct udevice *bus, uint max_hz)
 | |
| {
 | |
| 	struct nds_spi_slave *ns = dev_get_priv(bus);
 | |
| 
 | |
| 	debug("%s speed %u\n", __func__, max_hz);
 | |
| 
 | |
| 	ns->freq = max_hz;
 | |
| 	__atcspi200_spi_set_speed(ns);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int atcspi200_spi_set_mode(struct udevice *bus, uint mode)
 | |
| {
 | |
| 	struct nds_spi_slave *ns = dev_get_priv(bus);
 | |
| 
 | |
| 	debug("%s mode %u\n", __func__, mode);
 | |
| 	ns->mode = mode;
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int atcspi200_spi_claim_bus(struct udevice *dev)
 | |
| {
 | |
| 	struct dm_spi_slave_platdata *slave_plat =
 | |
| 		dev_get_parent_platdata(dev);
 | |
| 	struct udevice *bus = dev->parent;
 | |
| 	struct nds_spi_slave *ns = dev_get_priv(bus);
 | |
| 
 | |
| 	if (slave_plat->cs >= ns->num_cs) {
 | |
| 		printf("Invalid SPI chipselect\n");
 | |
| 		return -EINVAL;
 | |
| 	}
 | |
| 
 | |
| 	return __atcspi200_spi_claim_bus(ns);
 | |
| }
 | |
| 
 | |
| static int atcspi200_spi_release_bus(struct udevice *dev)
 | |
| {
 | |
| 	struct nds_spi_slave *ns = dev_get_priv(dev->parent);
 | |
| 
 | |
| 	return __atcspi200_spi_release_bus(ns);
 | |
| }
 | |
| 
 | |
| static int atcspi200_spi_xfer(struct udevice *dev, unsigned int bitlen,
 | |
| 			    const void *dout, void *din,
 | |
| 			    unsigned long flags)
 | |
| {
 | |
| 	struct udevice *bus = dev->parent;
 | |
| 	struct nds_spi_slave *ns = dev_get_priv(bus);
 | |
| 
 | |
| 	return __atcspi200_spi_xfer(ns, bitlen, dout, din, flags);
 | |
| }
 | |
| 
 | |
| static int atcspi200_spi_get_clk(struct udevice *bus)
 | |
| {
 | |
| 	struct nds_spi_slave *ns = dev_get_priv(bus);
 | |
| 	struct clk clk;
 | |
| 	ulong clk_rate;
 | |
| 	int ret;
 | |
| 
 | |
| 	ret = clk_get_by_index(bus, 0, &clk);
 | |
| 	if (ret)
 | |
| 		return -EINVAL;
 | |
| 
 | |
| 	clk_rate = clk_get_rate(&clk);
 | |
| 	if (!clk_rate)
 | |
| 		return -EINVAL;
 | |
| 
 | |
| 	ns->clock = clk_rate;
 | |
| 	clk_free(&clk);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int atcspi200_spi_probe(struct udevice *bus)
 | |
| {
 | |
| 	struct nds_spi_slave *ns = dev_get_priv(bus);
 | |
| 
 | |
| 	ns->to = SPI_TIMEOUT;
 | |
| 	ns->max_transfer_length = MAX_TRANSFER_LEN;
 | |
| 	ns->mtiming = ns->regs->timing;
 | |
| 	atcspi200_spi_get_clk(bus);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int atcspi200_ofdata_to_platadata(struct udevice *bus)
 | |
| {
 | |
| 	struct nds_spi_slave *ns = dev_get_priv(bus);
 | |
| 	const void *blob = gd->fdt_blob;
 | |
| 	int node = dev_of_offset(bus);
 | |
| 
 | |
| 	ns->regs = map_physmem(devfdt_get_addr(bus),
 | |
| 				 sizeof(struct atcspi200_spi_regs),
 | |
| 				 MAP_NOCACHE);
 | |
| 	if (!ns->regs) {
 | |
| 		printf("%s: could not map device address\n", __func__);
 | |
| 		return -EINVAL;
 | |
| 	}
 | |
| 	ns->num_cs = fdtdec_get_int(blob, node, "num-cs", 4);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static const struct dm_spi_ops atcspi200_spi_ops = {
 | |
| 	.claim_bus	= atcspi200_spi_claim_bus,
 | |
| 	.release_bus	= atcspi200_spi_release_bus,
 | |
| 	.xfer		= atcspi200_spi_xfer,
 | |
| 	.set_speed	= atcspi200_spi_set_speed,
 | |
| 	.set_mode	= atcspi200_spi_set_mode,
 | |
| };
 | |
| 
 | |
| static const struct udevice_id atcspi200_spi_ids[] = {
 | |
| 	{ .compatible = "andestech,atcspi200" },
 | |
| 	{ }
 | |
| };
 | |
| 
 | |
| U_BOOT_DRIVER(atcspi200_spi) = {
 | |
| 	.name = "atcspi200_spi",
 | |
| 	.id = UCLASS_SPI,
 | |
| 	.of_match = atcspi200_spi_ids,
 | |
| 	.ops = &atcspi200_spi_ops,
 | |
| 	.ofdata_to_platdata = atcspi200_ofdata_to_platadata,
 | |
| 	.priv_auto_alloc_size = sizeof(struct nds_spi_slave),
 | |
| 	.probe = atcspi200_spi_probe,
 | |
| };
 |