xref: /openbmc/u-boot/drivers/spi/aspeed_spi.c (revision eba3f26a)
1499853d6Sryan_chen // SPDX-License-Identifier: GPL-2.0+
2499853d6Sryan_chen /*
3499853d6Sryan_chen  * ASPEED AST2500 FMC/SPI Controller driver
4499853d6Sryan_chen  *
5499853d6Sryan_chen  * Copyright (c) 2015-2018, IBM Corporation.
6499853d6Sryan_chen  */
7499853d6Sryan_chen 
8499853d6Sryan_chen #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9499853d6Sryan_chen 
10499853d6Sryan_chen #include <common.h>
11499853d6Sryan_chen #include <clk.h>
12499853d6Sryan_chen #include <dm.h>
13499853d6Sryan_chen #include <spi.h>
14499853d6Sryan_chen #include <spi_flash.h>
15499853d6Sryan_chen #include <asm/io.h>
16499853d6Sryan_chen #include <linux/ioport.h>
17edaef9d2SChin-Ting Kuo #include <malloc.h>
18499853d6Sryan_chen 
19499853d6Sryan_chen #define ASPEED_SPI_MAX_CS		3
20beec505fSChin-Ting Kuo #define FLASH_CALIBRATION_LEN   0x400
21499853d6Sryan_chen 
22499853d6Sryan_chen struct aspeed_spi_regs {
23499853d6Sryan_chen 	u32 conf;			/* 0x00 CE Type Setting */
24499853d6Sryan_chen 	u32 ctrl;			/* 0x04 Control */
25499853d6Sryan_chen 	u32 intr_ctrl;			/* 0x08 Interrupt Control and Status */
26499853d6Sryan_chen 	u32 cmd_ctrl;			/* 0x0c Command Control */
27499853d6Sryan_chen 	u32 ce_ctrl[ASPEED_SPI_MAX_CS];	/* 0x10 .. 0x18 CEx Control */
28499853d6Sryan_chen 	u32 _reserved0[5];		/* .. */
29499853d6Sryan_chen 	u32 segment_addr[ASPEED_SPI_MAX_CS];
30499853d6Sryan_chen 					/* 0x30 .. 0x38 Segment Address */
310a73b911SChin-Ting Kuo 	u32 _reserved1[5];		/* .. */
320a73b911SChin-Ting Kuo 	u32 soft_rst_cmd_ctrl;	/* 0x50 Auto Soft-Reset Command Control */
330a73b911SChin-Ting Kuo 	u32 _reserved2[11];		/* .. */
34499853d6Sryan_chen 	u32 dma_ctrl;			/* 0x80 DMA Control/Status */
35499853d6Sryan_chen 	u32 dma_flash_addr;		/* 0x84 DMA Flash Side Address */
36499853d6Sryan_chen 	u32 dma_dram_addr;		/* 0x88 DMA DRAM Side Address */
37499853d6Sryan_chen 	u32 dma_len;			/* 0x8c DMA Length Register */
38499853d6Sryan_chen 	u32 dma_checksum;		/* 0x90 Checksum Calculation Result */
39499853d6Sryan_chen 	u32 timings;			/* 0x94 Read Timing Compensation */
404c8f336cSChin-Ting Kuo 	u32 _reserved3[1];
41499853d6Sryan_chen 	/* not used */
42499853d6Sryan_chen 	u32 soft_strap_status;		/* 0x9c Software Strap Status */
43499853d6Sryan_chen 	u32 write_cmd_filter_ctrl;	/* 0xa0 Write Command Filter Control */
44499853d6Sryan_chen 	u32 write_addr_filter_ctrl;	/* 0xa4 Write Address Filter Control */
45499853d6Sryan_chen 	u32 lock_ctrl_reset;		/* 0xa8 Lock Control (SRST#) */
46499853d6Sryan_chen 	u32 lock_ctrl_wdt;		/* 0xac Lock Control (Watchdog) */
474c8f336cSChin-Ting Kuo 	u32 write_addr_filter[8];	/* 0xb0 Write Address Filter */
484c8f336cSChin-Ting Kuo 	u32 _reserved4[12];
494c8f336cSChin-Ting Kuo 	u32 fully_qualified_cmd[20];	/* 0x100 Fully Qualified Command */
504c8f336cSChin-Ting Kuo 	u32 addr_qualified_cmd[12];	/* 0x150 Address Qualified Command */
51499853d6Sryan_chen };
52499853d6Sryan_chen 
53499853d6Sryan_chen /* CE Type Setting Register */
54499853d6Sryan_chen #define CONF_ENABLE_W2			BIT(18)
55499853d6Sryan_chen #define CONF_ENABLE_W1			BIT(17)
56499853d6Sryan_chen #define CONF_ENABLE_W0			BIT(16)
57499853d6Sryan_chen #define CONF_FLASH_TYPE2		4
58499853d6Sryan_chen #define CONF_FLASH_TYPE1		2	/* Hardwired to SPI */
59499853d6Sryan_chen #define CONF_FLASH_TYPE0		0	/* Hardwired to SPI */
60499853d6Sryan_chen #define	  CONF_FLASH_TYPE_NOR		0x0
61499853d6Sryan_chen #define	  CONF_FLASH_TYPE_SPI		0x2
62499853d6Sryan_chen 
63499853d6Sryan_chen /* CE Control Register */
64499853d6Sryan_chen #define CTRL_EXTENDED2			BIT(2)	/* 32 bit addressing for SPI */
65499853d6Sryan_chen #define CTRL_EXTENDED1			BIT(1)	/* 32 bit addressing for SPI */
66499853d6Sryan_chen #define CTRL_EXTENDED0			BIT(0)	/* 32 bit addressing for SPI */
67499853d6Sryan_chen 
68499853d6Sryan_chen /* Interrupt Control and Status Register */
69499853d6Sryan_chen #define INTR_CTRL_DMA_STATUS		BIT(11)
70499853d6Sryan_chen #define INTR_CTRL_CMD_ABORT_STATUS	BIT(10)
71499853d6Sryan_chen #define INTR_CTRL_WRITE_PROTECT_STATUS	BIT(9)
72499853d6Sryan_chen #define INTR_CTRL_DMA_EN		BIT(3)
73499853d6Sryan_chen #define INTR_CTRL_CMD_ABORT_EN		BIT(2)
74499853d6Sryan_chen #define INTR_CTRL_WRITE_PROTECT_EN	BIT(1)
75499853d6Sryan_chen 
76499853d6Sryan_chen /* CEx Control Register */
77499853d6Sryan_chen #define CE_CTRL_IO_MODE_MASK		GENMASK(31, 28)
7876e3c7a9Sryan_chen #define CE_CTRL_IO_QPI_DATA			BIT(31)
79499853d6Sryan_chen #define CE_CTRL_IO_DUAL_DATA		BIT(29)
80cd800046SChin-Ting Kuo #define CE_CTRL_IO_SINGLE			0
81499853d6Sryan_chen #define CE_CTRL_IO_DUAL_ADDR_DATA	(BIT(29) | BIT(28))
82499853d6Sryan_chen #define CE_CTRL_IO_QUAD_DATA		BIT(30)
83499853d6Sryan_chen #define CE_CTRL_IO_QUAD_ADDR_DATA	(BIT(30) | BIT(28))
84499853d6Sryan_chen #define CE_CTRL_CMD_SHIFT		16
85499853d6Sryan_chen #define CE_CTRL_CMD_MASK		0xff
86499853d6Sryan_chen #define CE_CTRL_CMD(cmd)					\
87499853d6Sryan_chen 	(((cmd) & CE_CTRL_CMD_MASK) << CE_CTRL_CMD_SHIFT)
88499853d6Sryan_chen #define CE_CTRL_DUMMY_HIGH_SHIFT	14
89499853d6Sryan_chen #define CE_CTRL_DUMMY_HIGH_MASK		0x1
90499853d6Sryan_chen #define CE_CTRL_CLOCK_FREQ_SHIFT	8
91499853d6Sryan_chen #define CE_CTRL_CLOCK_FREQ_MASK		0xf
92499853d6Sryan_chen #define CE_CTRL_CLOCK_FREQ(div)						\
93499853d6Sryan_chen 	(((div) & CE_CTRL_CLOCK_FREQ_MASK) << CE_CTRL_CLOCK_FREQ_SHIFT)
947d182336Sryan_chen #define CE_G6_CTRL_CLOCK_FREQ(div)						\
9541629eddSChin-Ting Kuo 	((((div) & CE_CTRL_CLOCK_FREQ_MASK) << CE_CTRL_CLOCK_FREQ_SHIFT) | (((div) & 0xf0) << 20))
96499853d6Sryan_chen #define CE_CTRL_DUMMY_LOW_SHIFT		6 /* 2 bits [7:6] */
97499853d6Sryan_chen #define CE_CTRL_DUMMY_LOW_MASK		0x3
98499853d6Sryan_chen #define CE_CTRL_DUMMY(dummy)						\
99499853d6Sryan_chen 	(((((dummy) >> 2) & CE_CTRL_DUMMY_HIGH_MASK)			\
100499853d6Sryan_chen 	  << CE_CTRL_DUMMY_HIGH_SHIFT) |				\
101499853d6Sryan_chen 	 (((dummy) & CE_CTRL_DUMMY_LOW_MASK) << CE_CTRL_DUMMY_LOW_SHIFT))
102499853d6Sryan_chen #define CE_CTRL_STOP_ACTIVE		BIT(2)
103499853d6Sryan_chen #define CE_CTRL_MODE_MASK		0x3
104499853d6Sryan_chen #define	CE_CTRL_READMODE		0x0
105499853d6Sryan_chen #define	CE_CTRL_FREADMODE		0x1
106499853d6Sryan_chen #define	CE_CTRL_WRITEMODE		0x2
107499853d6Sryan_chen #define	CE_CTRL_USERMODE		0x3
108edaef9d2SChin-Ting Kuo #define CE_CTRL_FREQ_MASK		0xf0fff0ff
109499853d6Sryan_chen 
110cd800046SChin-Ting Kuo #define SPI_READ_FROM_FLASH		0x00000001
111cd800046SChin-Ting Kuo #define SPI_WRITE_TO_FLASH		0x00000002
112cd800046SChin-Ting Kuo 
1130a73b911SChin-Ting Kuo /* Auto Soft-Reset Command Control */
1140a73b911SChin-Ting Kuo #define SOFT_RST_CMD_EN     GENMASK(1, 0)
1150a73b911SChin-Ting Kuo 
116499853d6Sryan_chen /*
117499853d6Sryan_chen  * The Segment Register uses a 8MB unit to encode the start address
118499853d6Sryan_chen  * and the end address of the AHB window of a SPI flash device.
119499853d6Sryan_chen  * Default segment addresses are :
120499853d6Sryan_chen  *
121499853d6Sryan_chen  *   CE0  0x20000000 - 0x2fffffff  128MB
122499853d6Sryan_chen  *   CE1  0x28000000 - 0x29ffffff   32MB
123499853d6Sryan_chen  *   CE2  0x2a000000 - 0x2bffffff   32MB
124499853d6Sryan_chen  *
125499853d6Sryan_chen  * The full address space of the AHB window of the controller is
126499853d6Sryan_chen  * covered and CE0 start address and CE2 end addresses are read-only.
127499853d6Sryan_chen  */
128499853d6Sryan_chen #define SEGMENT_ADDR_START(reg)		((((reg) >> 16) & 0xff) << 23)
129499853d6Sryan_chen #define SEGMENT_ADDR_END(reg)		((((reg) >> 24) & 0xff) << 23)
130499853d6Sryan_chen #define SEGMENT_ADDR_VALUE(start, end)					\
131499853d6Sryan_chen 	(((((start) >> 23) & 0xff) << 16) | ((((end) >> 23) & 0xff) << 24))
132499853d6Sryan_chen 
1338fbbfa7dSChin-Ting Kuo #define G6_SEGMENT_ADDR_START(reg)		(((reg) << 16) & 0x0ff00000)
1348fbbfa7dSChin-Ting Kuo #define G6_SEGMENT_ADDR_END(reg)		(((reg) & 0x0ff00000) + 0x100000)
135da83dd7eSryan_chen #define G6_SEGMENT_ADDR_VALUE(start, end)					\
1368fbbfa7dSChin-Ting Kuo 	((((start) & 0x0ff00000) >> 16) | (((end) - 0x100000) & 0xffff0000))
137da83dd7eSryan_chen 
138499853d6Sryan_chen /* DMA Control/Status Register */
139499853d6Sryan_chen #define DMA_CTRL_DELAY_SHIFT		8
140499853d6Sryan_chen #define DMA_CTRL_DELAY_MASK		0xf
141beec505fSChin-Ting Kuo #define G6_DMA_CTRL_DELAY_MASK		0xff
142499853d6Sryan_chen #define DMA_CTRL_FREQ_SHIFT		4
143f87fadc3Sryan_chen #define G6_DMA_CTRL_FREQ_SHIFT		16
144f87fadc3Sryan_chen 
145499853d6Sryan_chen #define DMA_CTRL_FREQ_MASK		0xf
146499853d6Sryan_chen #define TIMING_MASK(div, delay)					   \
147499853d6Sryan_chen 	(((delay & DMA_CTRL_DELAY_MASK) << DMA_CTRL_DELAY_SHIFT) | \
148499853d6Sryan_chen 	 ((div & DMA_CTRL_FREQ_MASK) << DMA_CTRL_FREQ_SHIFT))
149f87fadc3Sryan_chen #define G6_TIMING_MASK(div, delay)					   \
150beec505fSChin-Ting Kuo 	(((delay & G6_DMA_CTRL_DELAY_MASK) << DMA_CTRL_DELAY_SHIFT) | \
151f87fadc3Sryan_chen 	 ((div & DMA_CTRL_FREQ_MASK) << G6_DMA_CTRL_FREQ_SHIFT))
152edaef9d2SChin-Ting Kuo #define DAM_CTRL_REQUEST		BIT(31)
153edaef9d2SChin-Ting Kuo #define DAM_CTRL_GRANT			BIT(30)
154499853d6Sryan_chen #define DMA_CTRL_CALIB			BIT(3)
155499853d6Sryan_chen #define DMA_CTRL_CKSUM			BIT(2)
156499853d6Sryan_chen #define DMA_CTRL_WRITE			BIT(1)
157499853d6Sryan_chen #define DMA_CTRL_ENABLE			BIT(0)
158499853d6Sryan_chen 
159edaef9d2SChin-Ting Kuo #define DMA_GET_REQ_MAGIC		0xaeed0000
160edaef9d2SChin-Ting Kuo #define DMA_DISCARD_REQ_MAGIC	0xdeea0000
161edaef9d2SChin-Ting Kuo 
1620a73b911SChin-Ting Kuo /* for ast2600 setting */
1630a73b911SChin-Ting Kuo #define SPI_3B_AUTO_CLR_REG   0x1e6e2510
1640a73b911SChin-Ting Kuo #define SPI_3B_AUTO_CLR       BIT(9)
1650a73b911SChin-Ting Kuo 
1660a73b911SChin-Ting Kuo 
167499853d6Sryan_chen /*
1680a73b911SChin-Ting Kuo  * flash related info
169499853d6Sryan_chen  */
170499853d6Sryan_chen struct aspeed_spi_flash {
171499853d6Sryan_chen 	u8 cs;
172edaef9d2SChin-Ting Kuo 	/* Initialized when the SPI bus is
173499853d6Sryan_chen 	 * first claimed
174499853d6Sryan_chen 	 */
175edaef9d2SChin-Ting Kuo 	bool init;
176499853d6Sryan_chen 	void __iomem *ahb_base; /* AHB Window for this device */
177499853d6Sryan_chen 	u32 ahb_size; /* AHB Window segment size */
178499853d6Sryan_chen 	u32 ce_ctrl_user; /* CE Control Register for USER mode */
179499853d6Sryan_chen 	u32 ce_ctrl_fread; /* CE Control Register for FREAD mode */
180cd800046SChin-Ting Kuo 	u32 read_iomode;
181cd800046SChin-Ting Kuo 	u32 write_iomode;
182edaef9d2SChin-Ting Kuo 	u32 max_freq;
183499853d6Sryan_chen 	struct spi_flash *spi; /* Associated SPI Flash device */
184499853d6Sryan_chen };
185499853d6Sryan_chen 
186bbe907dbSChin-Ting Kuo enum aspeed_spi_dir {
187bbe907dbSChin-Ting Kuo 	ASPEED_SPI_DIR_IN,
188bbe907dbSChin-Ting Kuo 	ASPEED_SPI_DIR_OUT,
189bbe907dbSChin-Ting Kuo };
190bbe907dbSChin-Ting Kuo 
191bbe907dbSChin-Ting Kuo #define ASPEED_SPI_OP_CMD(__opcode)				\
192bbe907dbSChin-Ting Kuo 	{							\
193bbe907dbSChin-Ting Kuo 		.opcode = __opcode,				\
194bbe907dbSChin-Ting Kuo 	}
195bbe907dbSChin-Ting Kuo 
196bbe907dbSChin-Ting Kuo #define ASPEED_SPI_OP_ADDR(__nbytes, __val)			\
197bbe907dbSChin-Ting Kuo 	{							\
198bbe907dbSChin-Ting Kuo 		.nbytes = __nbytes,				\
199bbe907dbSChin-Ting Kuo 		.val = __val,					\
200bbe907dbSChin-Ting Kuo 	}
201bbe907dbSChin-Ting Kuo 
202bbe907dbSChin-Ting Kuo #define ASPEED_SPI_OP_NO_ADDR	{ }
203bbe907dbSChin-Ting Kuo 
204bbe907dbSChin-Ting Kuo #define ASPEED_SPI_OP_DUMMY(__nbytes)				\
205bbe907dbSChin-Ting Kuo 	{							\
206bbe907dbSChin-Ting Kuo 		.nbytes = __nbytes,				\
207bbe907dbSChin-Ting Kuo 	}
208bbe907dbSChin-Ting Kuo 
209bbe907dbSChin-Ting Kuo #define ASPEED_SPI_OP_NO_DUMMY	{ }
210bbe907dbSChin-Ting Kuo 
211bbe907dbSChin-Ting Kuo #define ASPEED_SPI_OP_DATA_IN(__nbytes, __buf)			\
212bbe907dbSChin-Ting Kuo 	{							\
213bbe907dbSChin-Ting Kuo 		.dir = ASPEED_SPI_DIR_IN,				\
214bbe907dbSChin-Ting Kuo 		.nbytes = __nbytes,				\
215bbe907dbSChin-Ting Kuo 		.buf.in = __buf,				\
216bbe907dbSChin-Ting Kuo 	}
217bbe907dbSChin-Ting Kuo 
218bbe907dbSChin-Ting Kuo #define ASPEED_SPI_OP_DATA_OUT(__nbytes, __buf)			\
219bbe907dbSChin-Ting Kuo 	{							\
220bbe907dbSChin-Ting Kuo 		.dir = ASPEED_SPI_DIR_OUT,				\
221bbe907dbSChin-Ting Kuo 		.nbytes = __nbytes,				\
222bbe907dbSChin-Ting Kuo 		.buf.out = __buf,				\
223bbe907dbSChin-Ting Kuo 	}
224bbe907dbSChin-Ting Kuo 
225bbe907dbSChin-Ting Kuo #define ASPEED_SPI_OP_NO_DATA	{ }
226bbe907dbSChin-Ting Kuo 
227bbe907dbSChin-Ting Kuo #define ASPEED_SPI_OP(__io_mode, __cmd, __addr, __dummy, __data)	\
228bbe907dbSChin-Ting Kuo 	{							\
229bbe907dbSChin-Ting Kuo 		.io_mode = __io_mode,				\
230bbe907dbSChin-Ting Kuo 		.cmd = __cmd,					\
231bbe907dbSChin-Ting Kuo 		.addr = __addr,					\
232bbe907dbSChin-Ting Kuo 		.dummy = __dummy,				\
233bbe907dbSChin-Ting Kuo 		.data = __data,					\
234bbe907dbSChin-Ting Kuo 	}
235bbe907dbSChin-Ting Kuo 
236bbe907dbSChin-Ting Kuo struct aspeed_spi_op {
237bbe907dbSChin-Ting Kuo 	u32 io_mode;
238bbe907dbSChin-Ting Kuo 
239bbe907dbSChin-Ting Kuo 	struct {
240bbe907dbSChin-Ting Kuo 		u16 opcode;
241bbe907dbSChin-Ting Kuo 	} cmd;
242bbe907dbSChin-Ting Kuo 
243bbe907dbSChin-Ting Kuo 	struct {
244bbe907dbSChin-Ting Kuo 		u8 nbytes;
245bbe907dbSChin-Ting Kuo 		u32 val;
246bbe907dbSChin-Ting Kuo 	} addr;
247bbe907dbSChin-Ting Kuo 
248bbe907dbSChin-Ting Kuo 	struct {
249bbe907dbSChin-Ting Kuo 		u8 nbytes;
250bbe907dbSChin-Ting Kuo 	} dummy;
251bbe907dbSChin-Ting Kuo 
252bbe907dbSChin-Ting Kuo 	struct {
253bbe907dbSChin-Ting Kuo 		enum aspeed_spi_dir dir;
254bbe907dbSChin-Ting Kuo 		unsigned int nbytes;
255bbe907dbSChin-Ting Kuo 		union {
256bbe907dbSChin-Ting Kuo 			void *in;
257bbe907dbSChin-Ting Kuo 			const void *out;
258bbe907dbSChin-Ting Kuo 		} buf;
259bbe907dbSChin-Ting Kuo 	} data;
260bbe907dbSChin-Ting Kuo };
261bbe907dbSChin-Ting Kuo 
262499853d6Sryan_chen struct aspeed_spi_priv {
263499853d6Sryan_chen 	struct aspeed_spi_regs *regs;
264499853d6Sryan_chen 	void __iomem *ahb_base; /* AHB Window for all flash devices */
265499853d6Sryan_chen 	int new_ver;
266499853d6Sryan_chen 	u32 ahb_size; /* AHB Window segments size */
267499853d6Sryan_chen 	ulong hclk_rate; /* AHB clock rate */
268499853d6Sryan_chen 	u8 num_cs;
269499853d6Sryan_chen 	bool is_fmc;
270499853d6Sryan_chen 
271499853d6Sryan_chen 	struct aspeed_spi_flash flashes[ASPEED_SPI_MAX_CS];
272499853d6Sryan_chen 	u32 flash_count;
273499853d6Sryan_chen 
274499853d6Sryan_chen 	u8 cmd_buf[16]; /* SPI command in progress */
275499853d6Sryan_chen 	size_t cmd_len;
276bbe907dbSChin-Ting Kuo 	u8 *tmp_buf;
277bbe907dbSChin-Ting Kuo 	int (*spi_exec_op_cmd)(struct aspeed_spi_priv *priv,
278bbe907dbSChin-Ting Kuo 			       struct aspeed_spi_flash *flash,
279bbe907dbSChin-Ting Kuo 			       struct aspeed_spi_op *op);
280499853d6Sryan_chen };
281499853d6Sryan_chen 
282bbe907dbSChin-Ting Kuo static u32 aspeed_spi_flash_to_addr(struct aspeed_spi_flash *flash,
283bbe907dbSChin-Ting Kuo 				    const u8 *cmdbuf, unsigned int cmdlen);
284bbe907dbSChin-Ting Kuo 
aspeed_spi_get_flash(struct udevice * dev)285499853d6Sryan_chen static struct aspeed_spi_flash *aspeed_spi_get_flash(struct udevice *dev)
286499853d6Sryan_chen {
287499853d6Sryan_chen 	struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
288499853d6Sryan_chen 	struct aspeed_spi_priv *priv = dev_get_priv(dev->parent);
289499853d6Sryan_chen 	u8 cs = slave_plat->cs;
290499853d6Sryan_chen 
291499853d6Sryan_chen 	if (cs >= priv->flash_count) {
292499853d6Sryan_chen 		pr_err("invalid CS %u\n", cs);
293499853d6Sryan_chen 		return NULL;
294499853d6Sryan_chen 	}
295499853d6Sryan_chen 
296499853d6Sryan_chen 	return &priv->flashes[cs];
297499853d6Sryan_chen }
298499853d6Sryan_chen 
aspeed_g6_spi_hclk_divisor(struct aspeed_spi_priv * priv,u32 max_hz)299ac86fa8bSryan_chen static u32 aspeed_g6_spi_hclk_divisor(struct aspeed_spi_priv *priv, u32 max_hz)
300499853d6Sryan_chen {
3017d182336Sryan_chen 	u32 hclk_rate = priv->hclk_rate;
302499853d6Sryan_chen 	/* HCLK/1 ..	HCLK/16 */
303499853d6Sryan_chen 	const u8 hclk_masks[] = {
304499853d6Sryan_chen 		15, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 0
305499853d6Sryan_chen 	};
306edaef9d2SChin-Ting Kuo 	u8 hclk_div = 0x4; /* default value */
307edaef9d2SChin-Ting Kuo 	bool found = false;
308f87fadc3Sryan_chen 	u32 i, j = 0;
309499853d6Sryan_chen 
310edaef9d2SChin-Ting Kuo 	/* FMC/SPIR10[27:24] */
31141629eddSChin-Ting Kuo 	for (j = 0; j < 0xf; j++) {
3127d182336Sryan_chen 		for (i = 0; i < ARRAY_SIZE(hclk_masks); i++) {
313edaef9d2SChin-Ting Kuo 			if (i == 0 && j == 0)
314edaef9d2SChin-Ting Kuo 				continue;
315f87fadc3Sryan_chen 
316edaef9d2SChin-Ting Kuo 			if ((hclk_rate / ((i + 1) + j * 16)) <= max_hz) {
317edaef9d2SChin-Ting Kuo 				found = 1;
3187d182336Sryan_chen 				break;
3197d182336Sryan_chen 			}
3207d182336Sryan_chen 		}
321edaef9d2SChin-Ting Kuo 
322edaef9d2SChin-Ting Kuo 		if (found)
323f87fadc3Sryan_chen 			break;
3247d182336Sryan_chen 	}
325499853d6Sryan_chen 
326f87fadc3Sryan_chen 	debug("hclk=%d required=%d h_div %d, divisor is %d (mask %x) speed=%d\n",
327edaef9d2SChin-Ting Kuo 		  hclk_rate, max_hz, j, i + 1, hclk_masks[i], hclk_rate / (i + 1 + j * 16));
3287d182336Sryan_chen 
329edaef9d2SChin-Ting Kuo 	hclk_div = ((j << 4) | hclk_masks[i]);
3307d182336Sryan_chen 
331edaef9d2SChin-Ting Kuo 	return hclk_div;
332ac86fa8bSryan_chen }
333ac86fa8bSryan_chen 
aspeed_spi_hclk_divisor(struct aspeed_spi_priv * priv,u32 max_hz)334ac86fa8bSryan_chen static u32 aspeed_spi_hclk_divisor(struct aspeed_spi_priv *priv, u32 max_hz)
335ac86fa8bSryan_chen {
336ac86fa8bSryan_chen 	u32 hclk_rate = priv->hclk_rate;
337ac86fa8bSryan_chen 	/* HCLK/1 ..	HCLK/16 */
338ac86fa8bSryan_chen 	const u8 hclk_masks[] = {
339ac86fa8bSryan_chen 		15, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 0
340ac86fa8bSryan_chen 	};
341d32338fdSryan_chen 	u32 i;
342ac86fa8bSryan_chen 	u32 hclk_div_setting = 0;
343ac86fa8bSryan_chen 
344499853d6Sryan_chen 	for (i = 0; i < ARRAY_SIZE(hclk_masks); i++) {
345499853d6Sryan_chen 		if (max_hz >= (hclk_rate / (i + 1)))
346499853d6Sryan_chen 			break;
347499853d6Sryan_chen 	}
348499853d6Sryan_chen 	debug("hclk=%d required=%d divisor is %d (mask %x) speed=%d\n",
349499853d6Sryan_chen 	      hclk_rate, max_hz, i + 1, hclk_masks[i], hclk_rate / (i + 1));
350499853d6Sryan_chen 
3517d182336Sryan_chen 	hclk_div_setting = hclk_masks[i];
3527d182336Sryan_chen 
3537d182336Sryan_chen 	return hclk_div_setting;
354499853d6Sryan_chen }
355499853d6Sryan_chen 
356499853d6Sryan_chen /*
357499853d6Sryan_chen  * Use some address/size under the first flash device CE0
358499853d6Sryan_chen  */
aspeed_spi_fmc_checksum(struct aspeed_spi_priv * priv,struct aspeed_spi_flash * flash,u8 div,u8 delay)359edaef9d2SChin-Ting Kuo static u32 aspeed_spi_fmc_checksum(struct aspeed_spi_priv *priv,
360edaef9d2SChin-Ting Kuo 				   struct aspeed_spi_flash *flash,
361edaef9d2SChin-Ting Kuo 				   u8 div, u8 delay)
362499853d6Sryan_chen {
363edaef9d2SChin-Ting Kuo 	u32 flash_addr = (u32)flash->ahb_base + 0x10000;
364499853d6Sryan_chen 	u32 dma_ctrl;
365499853d6Sryan_chen 	u32 checksum;
366499853d6Sryan_chen 
367499853d6Sryan_chen 	writel(flash_addr, &priv->regs->dma_flash_addr);
368edaef9d2SChin-Ting Kuo 	writel(FLASH_CALIBRATION_LEN,  &priv->regs->dma_len);
369499853d6Sryan_chen 
370499853d6Sryan_chen 	/*
371499853d6Sryan_chen 	 * When doing calibration, the SPI clock rate in the CE0
372499853d6Sryan_chen 	 * Control Register and the data input delay cycles in the
373499853d6Sryan_chen 	 * Read Timing Compensation Register are replaced by bit[11:4].
374499853d6Sryan_chen 	 */
375499853d6Sryan_chen 	dma_ctrl = DMA_CTRL_ENABLE | DMA_CTRL_CKSUM | DMA_CTRL_CALIB |
376499853d6Sryan_chen 		TIMING_MASK(div, delay);
377edaef9d2SChin-Ting Kuo 
378499853d6Sryan_chen 	writel(dma_ctrl, &priv->regs->dma_ctrl);
379499853d6Sryan_chen 	while (!(readl(&priv->regs->intr_ctrl) & INTR_CTRL_DMA_STATUS))
380499853d6Sryan_chen 		;
381499853d6Sryan_chen 
382499853d6Sryan_chen 	writel(0x0, &priv->regs->intr_ctrl);
383499853d6Sryan_chen 
384499853d6Sryan_chen 	checksum = readl(&priv->regs->dma_checksum);
385499853d6Sryan_chen 
386499853d6Sryan_chen 	writel(0x0, &priv->regs->dma_ctrl);
387499853d6Sryan_chen 	return checksum;
388499853d6Sryan_chen }
389499853d6Sryan_chen 
390edaef9d2SChin-Ting Kuo /*
391edaef9d2SChin-Ting Kuo  * Use some address/size under the first flash device CE0
392499853d6Sryan_chen  */
aspeed_g6_spi_fmc_checksum(struct aspeed_spi_priv * priv,struct aspeed_spi_flash * flash,u8 div,u8 delay)393edaef9d2SChin-Ting Kuo static u32 aspeed_g6_spi_fmc_checksum(struct aspeed_spi_priv *priv,
394edaef9d2SChin-Ting Kuo 				      struct aspeed_spi_flash *flash,
395edaef9d2SChin-Ting Kuo 				      u8 div, u8 delay)
396edaef9d2SChin-Ting Kuo {
397edaef9d2SChin-Ting Kuo 	u32 flash_addr = (u32)flash->ahb_base;
398edaef9d2SChin-Ting Kuo 	u32 dma_ctrl;
399edaef9d2SChin-Ting Kuo 	u32 checksum;
400edaef9d2SChin-Ting Kuo 
401edaef9d2SChin-Ting Kuo 	writel(DMA_GET_REQ_MAGIC, &priv->regs->dma_ctrl);
402edaef9d2SChin-Ting Kuo 	if (readl(&priv->regs->dma_ctrl) & DAM_CTRL_REQUEST) {
403edaef9d2SChin-Ting Kuo 		while (!(readl(&priv->regs->dma_ctrl) & DAM_CTRL_GRANT))
404edaef9d2SChin-Ting Kuo 			;
405edaef9d2SChin-Ting Kuo 	}
406edaef9d2SChin-Ting Kuo 
407edaef9d2SChin-Ting Kuo 	writel(flash_addr, &priv->regs->dma_flash_addr);
408edaef9d2SChin-Ting Kuo 	writel(FLASH_CALIBRATION_LEN,  &priv->regs->dma_len);
409edaef9d2SChin-Ting Kuo 
410edaef9d2SChin-Ting Kuo 	/*
411edaef9d2SChin-Ting Kuo 	 * When doing calibration, the SPI clock rate in the control
412edaef9d2SChin-Ting Kuo 	 * register and the data input delay cycles in the
413edaef9d2SChin-Ting Kuo 	 * read timing compensation register are replaced by bit[11:4].
414edaef9d2SChin-Ting Kuo 	 */
415edaef9d2SChin-Ting Kuo 	dma_ctrl = DMA_CTRL_ENABLE | DMA_CTRL_CKSUM | DMA_CTRL_CALIB |
416edaef9d2SChin-Ting Kuo 		G6_TIMING_MASK(div, delay);
417edaef9d2SChin-Ting Kuo 
418edaef9d2SChin-Ting Kuo 	writel(dma_ctrl, &priv->regs->dma_ctrl);
419edaef9d2SChin-Ting Kuo 	while (!(readl(&priv->regs->intr_ctrl) & INTR_CTRL_DMA_STATUS))
420edaef9d2SChin-Ting Kuo 		;
421edaef9d2SChin-Ting Kuo 
422edaef9d2SChin-Ting Kuo 	checksum = readl(&priv->regs->dma_checksum);
423edaef9d2SChin-Ting Kuo 
424edaef9d2SChin-Ting Kuo 	writel(0x0, &priv->regs->intr_ctrl);
425edaef9d2SChin-Ting Kuo 	writel(0x0, &priv->regs->dma_ctrl);
426edaef9d2SChin-Ting Kuo 	writel(DMA_DISCARD_REQ_MAGIC, &priv->regs->dma_ctrl);
427edaef9d2SChin-Ting Kuo 
428edaef9d2SChin-Ting Kuo 	return checksum;
429edaef9d2SChin-Ting Kuo }
430edaef9d2SChin-Ting Kuo 
aspeed_spi_read_checksum(struct aspeed_spi_priv * priv,struct aspeed_spi_flash * flash,u8 div,u8 delay)431edaef9d2SChin-Ting Kuo static u32 aspeed_spi_read_checksum(struct aspeed_spi_priv *priv,
432edaef9d2SChin-Ting Kuo 				    struct aspeed_spi_flash *flash,
433edaef9d2SChin-Ting Kuo 				    u8 div, u8 delay)
434edaef9d2SChin-Ting Kuo {
435edaef9d2SChin-Ting Kuo 	if (priv->new_ver)
436edaef9d2SChin-Ting Kuo 		return aspeed_g6_spi_fmc_checksum(priv, flash, div, delay);
437edaef9d2SChin-Ting Kuo 
438edaef9d2SChin-Ting Kuo 	/* for AST2500, */
439499853d6Sryan_chen 	if (!priv->is_fmc) {
440499853d6Sryan_chen 		pr_warn("No timing calibration support for SPI controllers");
441499853d6Sryan_chen 		return 0xbadc0de;
442499853d6Sryan_chen 	}
443499853d6Sryan_chen 
444edaef9d2SChin-Ting Kuo 	return aspeed_spi_fmc_checksum(priv, flash, div, delay);
445499853d6Sryan_chen }
446499853d6Sryan_chen 
447499853d6Sryan_chen #define TIMING_DELAY_DI_4NS         BIT(3)
448499853d6Sryan_chen #define TIMING_DELAY_HCYCLE_MAX     5
449499853d6Sryan_chen 
450edaef9d2SChin-Ting Kuo /*
451edaef9d2SChin-Ting Kuo  * Check whether the data is not all 0 or 1 in order to
452edaef9d2SChin-Ting Kuo  * avoid calibriate umount spi-flash.
453edaef9d2SChin-Ting Kuo  */
aspeed_spi_calibriation_enable(const u8 * buf,u32 sz)454edaef9d2SChin-Ting Kuo static bool aspeed_spi_calibriation_enable(const u8 *buf, u32 sz)
455499853d6Sryan_chen {
456edaef9d2SChin-Ting Kuo 	const u32 *buf_32 = (const u32 *)buf;
457edaef9d2SChin-Ting Kuo 	u32 i;
458edaef9d2SChin-Ting Kuo 	u32 valid_count = 0;
459edaef9d2SChin-Ting Kuo 
460edaef9d2SChin-Ting Kuo 	for (i = 0; i < (sz / 4); i++) {
461edaef9d2SChin-Ting Kuo 		if (buf_32[i] != 0 && buf_32[i] != 0xffffffff)
462edaef9d2SChin-Ting Kuo 			valid_count++;
463edaef9d2SChin-Ting Kuo 		if (valid_count > 100)
464edaef9d2SChin-Ting Kuo 			return true;
465edaef9d2SChin-Ting Kuo 	}
466edaef9d2SChin-Ting Kuo 
467edaef9d2SChin-Ting Kuo 	return false;
468edaef9d2SChin-Ting Kuo }
469edaef9d2SChin-Ting Kuo 
get_mid_point_of_longest_one(u8 * buf,u32 len)470edaef9d2SChin-Ting Kuo static int get_mid_point_of_longest_one(u8 *buf, u32 len)
471edaef9d2SChin-Ting Kuo {
472edaef9d2SChin-Ting Kuo 	int i;
473edaef9d2SChin-Ting Kuo 	int start = 0, mid_point = 0;
474edaef9d2SChin-Ting Kuo 	int max_cnt = 0, cnt = 0;
475edaef9d2SChin-Ting Kuo 
476edaef9d2SChin-Ting Kuo 	for (i = 0; i < len; i++) {
477edaef9d2SChin-Ting Kuo 		if (buf[i] == 1) {
478edaef9d2SChin-Ting Kuo 			cnt++;
479edaef9d2SChin-Ting Kuo 		} else {
480edaef9d2SChin-Ting Kuo 			cnt = 0;
481edaef9d2SChin-Ting Kuo 			start = i;
482edaef9d2SChin-Ting Kuo 		}
483edaef9d2SChin-Ting Kuo 
484edaef9d2SChin-Ting Kuo 		if (max_cnt < cnt) {
485edaef9d2SChin-Ting Kuo 			max_cnt = cnt;
486edaef9d2SChin-Ting Kuo 			mid_point = start + (cnt / 2);
487edaef9d2SChin-Ting Kuo 		}
488edaef9d2SChin-Ting Kuo 	}
489edaef9d2SChin-Ting Kuo 
490edaef9d2SChin-Ting Kuo 	/*
491edaef9d2SChin-Ting Kuo 	 * In order to get a stable SPI read timing,
492edaef9d2SChin-Ting Kuo 	 * abandon the result if the length of longest
493edaef9d2SChin-Ting Kuo 	 * consecutive good points is too short.
494edaef9d2SChin-Ting Kuo 	 */
495edaef9d2SChin-Ting Kuo 	if (max_cnt < 4)
496edaef9d2SChin-Ting Kuo 		return -1;
497edaef9d2SChin-Ting Kuo 
498edaef9d2SChin-Ting Kuo 	return mid_point;
499edaef9d2SChin-Ting Kuo }
500edaef9d2SChin-Ting Kuo 
aspeed_spi_timing_calibration(struct aspeed_spi_priv * priv,struct aspeed_spi_flash * flash)501edaef9d2SChin-Ting Kuo static int aspeed_spi_timing_calibration(struct aspeed_spi_priv *priv,
502edaef9d2SChin-Ting Kuo 					 struct aspeed_spi_flash *flash)
503edaef9d2SChin-Ting Kuo {
504edaef9d2SChin-Ting Kuo 	u32 cs = flash->cs;
505499853d6Sryan_chen 	/* HCLK/5 .. HCLK/1 */
506499853d6Sryan_chen 	const u8 hclk_masks[] = {13, 6, 14, 7, 15};
507beec505fSChin-Ting Kuo 	u32 timing_reg;
508499853d6Sryan_chen 	u32 checksum, gold_checksum;
509edaef9d2SChin-Ting Kuo 	int i;
510edaef9d2SChin-Ting Kuo 	u32 hcycle, delay_ns;
511edaef9d2SChin-Ting Kuo 	u32 final_delay = 0;
512edaef9d2SChin-Ting Kuo 	u32 hclk_div = 0;
513edaef9d2SChin-Ting Kuo 	u32 max_freq = flash->max_freq;
514edaef9d2SChin-Ting Kuo 	u32 reg_val;
515edaef9d2SChin-Ting Kuo 	u8 *tmp_buf = NULL;
516edaef9d2SChin-Ting Kuo 	u8 *calib_res = NULL;
517edaef9d2SChin-Ting Kuo 	int calib_point;
518edaef9d2SChin-Ting Kuo 	bool pass;
519beec505fSChin-Ting Kuo 
520edaef9d2SChin-Ting Kuo 	if (priv->new_ver) {
521edaef9d2SChin-Ting Kuo 		timing_reg = readl(&priv->regs->timings + cs);
522edaef9d2SChin-Ting Kuo 		if (timing_reg != 0)
523edaef9d2SChin-Ting Kuo 			return 0;
524edaef9d2SChin-Ting Kuo 
525edaef9d2SChin-Ting Kuo 		/*
526edaef9d2SChin-Ting Kuo 		 * use the related low frequency to get check calibration data
527edaef9d2SChin-Ting Kuo 		 * and get golden data.
528edaef9d2SChin-Ting Kuo 		 */
529edaef9d2SChin-Ting Kuo 		reg_val = flash->ce_ctrl_fread & CE_CTRL_FREQ_MASK;
530edaef9d2SChin-Ting Kuo 		writel(reg_val, &priv->regs->ce_ctrl[cs]);
531edaef9d2SChin-Ting Kuo 		tmp_buf = (u8 *)malloc(FLASH_CALIBRATION_LEN);
532edaef9d2SChin-Ting Kuo 		if (!tmp_buf)
533edaef9d2SChin-Ting Kuo 			return -ENOMEM;
534edaef9d2SChin-Ting Kuo 
535edaef9d2SChin-Ting Kuo 		memcpy_fromio(tmp_buf, flash->ahb_base, FLASH_CALIBRATION_LEN);
536edaef9d2SChin-Ting Kuo 		if (!aspeed_spi_calibriation_enable(tmp_buf, FLASH_CALIBRATION_LEN)) {
537edaef9d2SChin-Ting Kuo 			debug("flash data is monotonous, skip calibration.\n");
538edaef9d2SChin-Ting Kuo 			goto no_calib;
539edaef9d2SChin-Ting Kuo 		}
540edaef9d2SChin-Ting Kuo 
541edaef9d2SChin-Ting Kuo 		/* Compute reference checksum at lowest freq HCLK/16 */
542edaef9d2SChin-Ting Kuo 		gold_checksum = aspeed_spi_read_checksum(priv, flash, 0, 0);
543edaef9d2SChin-Ting Kuo 
544edaef9d2SChin-Ting Kuo 		/*
545edaef9d2SChin-Ting Kuo 		 * allocate a space to record calibration result for
546edaef9d2SChin-Ting Kuo 		 * different timing compensation with fixed
547edaef9d2SChin-Ting Kuo 		 * HCLK division.
548edaef9d2SChin-Ting Kuo 		 */
549edaef9d2SChin-Ting Kuo 		calib_res = (u8 *)malloc(6 * 17);
550edaef9d2SChin-Ting Kuo 		if (!calib_res) {
551edaef9d2SChin-Ting Kuo 			free(tmp_buf);
552edaef9d2SChin-Ting Kuo 			return -ENOMEM;
553edaef9d2SChin-Ting Kuo 		}
554edaef9d2SChin-Ting Kuo 
555edaef9d2SChin-Ting Kuo 		/* from HCLK/2 to HCLK/5 */
556edaef9d2SChin-Ting Kuo 		for (i = 0; i < ARRAY_SIZE(hclk_masks) - 1; i++) {
557edaef9d2SChin-Ting Kuo 			if (priv->hclk_rate / (i + 2) > max_freq) {
558edaef9d2SChin-Ting Kuo 				debug("skipping freq %ld\n", priv->hclk_rate / (i + 2));
559edaef9d2SChin-Ting Kuo 				continue;
560edaef9d2SChin-Ting Kuo 			}
561edaef9d2SChin-Ting Kuo 
562edaef9d2SChin-Ting Kuo 			max_freq = (u32)priv->hclk_rate / (i + 2);
563edaef9d2SChin-Ting Kuo 
564edaef9d2SChin-Ting Kuo 			memset(calib_res, 0x0, 6 * 17);
565edaef9d2SChin-Ting Kuo 			for (hcycle = 0; hcycle <= 5; hcycle++) {
566edaef9d2SChin-Ting Kuo 				/* increase DI delay by the step of 0.5ns */
567edaef9d2SChin-Ting Kuo 				debug("Delay Enable : hcycle %x\n", hcycle);
568edaef9d2SChin-Ting Kuo 				for (delay_ns = 0; delay_ns <= 0xf; delay_ns++) {
569edaef9d2SChin-Ting Kuo 					checksum = aspeed_g6_spi_fmc_checksum(priv, flash,
570edaef9d2SChin-Ting Kuo 									      hclk_masks[3 - i],
571edaef9d2SChin-Ting Kuo 						TIMING_DELAY_DI_4NS | hcycle | (delay_ns << 4));
572edaef9d2SChin-Ting Kuo 					pass = (checksum == gold_checksum);
573edaef9d2SChin-Ting Kuo 					calib_res[hcycle * 17 + delay_ns] = pass;
574edaef9d2SChin-Ting Kuo 					debug("HCLK/%d, %d HCLK cycle, %d delay_ns : %s\n",
575edaef9d2SChin-Ting Kuo 					      i + 2, hcycle, delay_ns, pass ? "PASS" : "FAIL");
576edaef9d2SChin-Ting Kuo 				}
577edaef9d2SChin-Ting Kuo 			}
578edaef9d2SChin-Ting Kuo 
579edaef9d2SChin-Ting Kuo 			calib_point = get_mid_point_of_longest_one(calib_res, 6 * 17);
580edaef9d2SChin-Ting Kuo 			if (calib_point < 0) {
581edaef9d2SChin-Ting Kuo 				debug("cannot get good calibration point.\n");
582edaef9d2SChin-Ting Kuo 				continue;
583edaef9d2SChin-Ting Kuo 			}
584edaef9d2SChin-Ting Kuo 
585edaef9d2SChin-Ting Kuo 			hcycle = calib_point / 17;
586edaef9d2SChin-Ting Kuo 			delay_ns = calib_point % 17;
587edaef9d2SChin-Ting Kuo 			debug("final hcycle: %d, delay_ns: %d\n", hcycle, delay_ns);
588edaef9d2SChin-Ting Kuo 
589edaef9d2SChin-Ting Kuo 			final_delay = (TIMING_DELAY_DI_4NS | hcycle | (delay_ns << 4)) << (i * 8);
590edaef9d2SChin-Ting Kuo 			writel(final_delay, &priv->regs->timings + cs);
591edaef9d2SChin-Ting Kuo 			break;
592edaef9d2SChin-Ting Kuo 		}
593edaef9d2SChin-Ting Kuo 
594edaef9d2SChin-Ting Kuo no_calib:
595edaef9d2SChin-Ting Kuo 		hclk_div = aspeed_g6_spi_hclk_divisor(priv, max_freq);
596edaef9d2SChin-Ting Kuo 		/* configure SPI clock frequency */
597edaef9d2SChin-Ting Kuo 		reg_val = readl(&priv->regs->ce_ctrl[cs]);
598edaef9d2SChin-Ting Kuo 		reg_val = (reg_val & CE_CTRL_FREQ_MASK) | CE_G6_CTRL_CLOCK_FREQ(hclk_div);
599edaef9d2SChin-Ting Kuo 		writel(reg_val, &priv->regs->ce_ctrl[cs]);
600edaef9d2SChin-Ting Kuo 
601edaef9d2SChin-Ting Kuo 		/* add clock setting info for CE ctrl setting */
602edaef9d2SChin-Ting Kuo 		flash->ce_ctrl_user =
603edaef9d2SChin-Ting Kuo 			(flash->ce_ctrl_user & CE_CTRL_FREQ_MASK) | CE_G6_CTRL_CLOCK_FREQ(hclk_div);
604edaef9d2SChin-Ting Kuo 		flash->ce_ctrl_fread =
605edaef9d2SChin-Ting Kuo 			(flash->ce_ctrl_fread & CE_CTRL_FREQ_MASK) | CE_G6_CTRL_CLOCK_FREQ(hclk_div);
606edaef9d2SChin-Ting Kuo 
607edaef9d2SChin-Ting Kuo 		debug("cs: %d, freq: %dMHz\n", cs, max_freq / 1000000);
608edaef9d2SChin-Ting Kuo 
609edaef9d2SChin-Ting Kuo 		if (tmp_buf)
610edaef9d2SChin-Ting Kuo 			free(tmp_buf);
611edaef9d2SChin-Ting Kuo 		if (calib_res)
612edaef9d2SChin-Ting Kuo 			free(calib_res);
613edaef9d2SChin-Ting Kuo 	} else {
614beec505fSChin-Ting Kuo 		/* Use the ctrl setting in aspeed_spi_flash_init() to
615beec505fSChin-Ting Kuo 		 * implement calibration process.
616beec505fSChin-Ting Kuo 		 */
617beec505fSChin-Ting Kuo 		timing_reg = readl(&priv->regs->timings);
618beec505fSChin-Ting Kuo 		if (timing_reg != 0)
619beec505fSChin-Ting Kuo 			return 0;
620499853d6Sryan_chen 
621499853d6Sryan_chen 		/* Compute reference checksum at lowest freq HCLK/16 */
622edaef9d2SChin-Ting Kuo 		gold_checksum = aspeed_spi_read_checksum(priv, flash, 0, 0);
623499853d6Sryan_chen 
624499853d6Sryan_chen 		for (i = 0; i < ARRAY_SIZE(hclk_masks); i++) {
625499853d6Sryan_chen 			u32 hdiv = 5 - i;
626499853d6Sryan_chen 			u32 hshift = (hdiv - 1) << 2;
627499853d6Sryan_chen 			bool pass = false;
628499853d6Sryan_chen 			u8 delay;
629499853d6Sryan_chen 
630edaef9d2SChin-Ting Kuo 			if (priv->hclk_rate / hdiv > flash->max_freq) {
631499853d6Sryan_chen 				debug("skipping freq %ld\n", priv->hclk_rate / hdiv);
632499853d6Sryan_chen 				continue;
633499853d6Sryan_chen 			}
634499853d6Sryan_chen 
635499853d6Sryan_chen 			/* Increase HCLK cycles until read succeeds */
636499853d6Sryan_chen 			for (hcycle = 0; hcycle <= TIMING_DELAY_HCYCLE_MAX; hcycle++) {
637499853d6Sryan_chen 				/* Try first with a 4ns DI delay */
638499853d6Sryan_chen 				delay = TIMING_DELAY_DI_4NS | hcycle;
639edaef9d2SChin-Ting Kuo 				checksum = aspeed_spi_read_checksum(priv, flash, hclk_masks[i],
640499853d6Sryan_chen 								    delay);
641499853d6Sryan_chen 				pass = (checksum == gold_checksum);
642499853d6Sryan_chen 				debug(" HCLK/%d, 4ns DI delay, %d HCLK cycle : %s\n",
643499853d6Sryan_chen 				      hdiv, hcycle, pass ? "PASS" : "FAIL");
644499853d6Sryan_chen 
645499853d6Sryan_chen 				/* Try again with more HCLK cycles */
646499853d6Sryan_chen 				if (!pass)
647499853d6Sryan_chen 					continue;
648499853d6Sryan_chen 
649499853d6Sryan_chen 				/* Try without the 4ns DI delay */
650499853d6Sryan_chen 				delay = hcycle;
651edaef9d2SChin-Ting Kuo 				checksum = aspeed_spi_read_checksum(priv, flash, hclk_masks[i],
652499853d6Sryan_chen 								    delay);
653499853d6Sryan_chen 				pass = (checksum == gold_checksum);
654499853d6Sryan_chen 				debug(" HCLK/%d,  no DI delay, %d HCLK cycle : %s\n",
655499853d6Sryan_chen 				      hdiv, hcycle, pass ? "PASS" : "FAIL");
656499853d6Sryan_chen 
657499853d6Sryan_chen 				/* All good for this freq  */
658499853d6Sryan_chen 				if (pass)
659499853d6Sryan_chen 					break;
660499853d6Sryan_chen 			}
661499853d6Sryan_chen 
662499853d6Sryan_chen 			if (pass) {
663499853d6Sryan_chen 				timing_reg &= ~(0xfu << hshift);
664499853d6Sryan_chen 				timing_reg |= delay << hshift;
665499853d6Sryan_chen 			}
666499853d6Sryan_chen 		}
667beec505fSChin-Ting Kuo 
668499853d6Sryan_chen 		debug("Read Timing Compensation set to 0x%08x\n", timing_reg);
669499853d6Sryan_chen 		writel(timing_reg, &priv->regs->timings);
670edaef9d2SChin-Ting Kuo 	}
671499853d6Sryan_chen 
672499853d6Sryan_chen 	return 0;
673499853d6Sryan_chen }
674499853d6Sryan_chen 
aspeed_spi_controller_init(struct aspeed_spi_priv * priv)675499853d6Sryan_chen static int aspeed_spi_controller_init(struct aspeed_spi_priv *priv)
676499853d6Sryan_chen {
677beec505fSChin-Ting Kuo 	int cs;
678499853d6Sryan_chen 
679499853d6Sryan_chen 	/*
680499853d6Sryan_chen 	 * Enable write on all flash devices as USER command mode
681499853d6Sryan_chen 	 * requires it.
682499853d6Sryan_chen 	 */
683499853d6Sryan_chen 	setbits_le32(&priv->regs->conf,
684499853d6Sryan_chen 		     CONF_ENABLE_W2 | CONF_ENABLE_W1 | CONF_ENABLE_W0);
685499853d6Sryan_chen 
686499853d6Sryan_chen 	/*
687499853d6Sryan_chen 	 * Set safe default settings for each device. These will be
688499853d6Sryan_chen 	 * tuned after the SPI flash devices are probed.
689499853d6Sryan_chen 	 */
690da83dd7eSryan_chen 	if (priv->new_ver) {
691499853d6Sryan_chen 		for (cs = 0; cs < priv->flash_count; cs++) {
692499853d6Sryan_chen 			struct aspeed_spi_flash *flash = &priv->flashes[cs];
693d32338fdSryan_chen 			u32 addr_config = 0;
694499853d6Sryan_chen 			switch(cs) {
695da83dd7eSryan_chen 			case 0:
6968fbbfa7dSChin-Ting Kuo 				flash->ahb_base = priv->ahb_base;
697d32338fdSryan_chen 				debug("cs0 mem-map : %x\n", (u32)flash->ahb_base);
698da83dd7eSryan_chen 				break;
699499853d6Sryan_chen 			case 1:
7008fbbfa7dSChin-Ting Kuo 				flash->ahb_base = priv->flashes[0].ahb_base + 0x4000000; /* cs0 + 64MB */
7018fbbfa7dSChin-Ting Kuo 				debug("cs1 mem-map : %x end %x\n",
7028fbbfa7dSChin-Ting Kuo 				      (u32)flash->ahb_base, (u32)flash->ahb_base + 0x4000000);
703499853d6Sryan_chen 				break;
704499853d6Sryan_chen 			case 2:
7058fbbfa7dSChin-Ting Kuo 				flash->ahb_base = priv->flashes[0].ahb_base + 0x4000000 * 2; /* cs0 + 128MB : use 64MB */
7068fbbfa7dSChin-Ting Kuo 				debug("cs2 mem-map : %x end %x\n",
7078fbbfa7dSChin-Ting Kuo 				      (u32)flash->ahb_base, (u32)flash->ahb_base + 0x4000000);
708499853d6Sryan_chen 				break;
709499853d6Sryan_chen 			}
7108fbbfa7dSChin-Ting Kuo 			addr_config =
7118fbbfa7dSChin-Ting Kuo 				G6_SEGMENT_ADDR_VALUE((u32)flash->ahb_base, (u32)flash->ahb_base + 0x4000000);
7128fbbfa7dSChin-Ting Kuo 			writel(addr_config, &priv->regs->segment_addr[cs]);
713da83dd7eSryan_chen 			flash->cs = cs;
714da83dd7eSryan_chen 			flash->ce_ctrl_user = CE_CTRL_USERMODE;
715da83dd7eSryan_chen 			flash->ce_ctrl_fread = CE_CTRL_READMODE;
716499853d6Sryan_chen 		}
717da83dd7eSryan_chen 	} else {
718da83dd7eSryan_chen 		for (cs = 0; cs < priv->flash_count; cs++) {
719da83dd7eSryan_chen 			struct aspeed_spi_flash *flash = &priv->flashes[cs];
720da83dd7eSryan_chen 			u32 seg_addr = readl(&priv->regs->segment_addr[cs]);
721499853d6Sryan_chen 			/*
722499853d6Sryan_chen 			 * The start address of the AHB window of CE0 is
723499853d6Sryan_chen 			 * read-only and is the same as the address of the
724499853d6Sryan_chen 			 * overall AHB window of the controller for all flash
725499853d6Sryan_chen 			 * devices.
726499853d6Sryan_chen 			 */
727499853d6Sryan_chen 			flash->ahb_base = cs ? (void *)SEGMENT_ADDR_START(seg_addr) :
728499853d6Sryan_chen 				priv->ahb_base;
729499853d6Sryan_chen 
730499853d6Sryan_chen 			flash->cs = cs;
731499853d6Sryan_chen 			flash->ce_ctrl_user = CE_CTRL_USERMODE;
732499853d6Sryan_chen 			flash->ce_ctrl_fread = CE_CTRL_READMODE;
733499853d6Sryan_chen 		}
734da83dd7eSryan_chen 	}
735499853d6Sryan_chen 	return 0;
736499853d6Sryan_chen }
737499853d6Sryan_chen 
aspeed_spi_read_from_ahb(void __iomem * ahb_base,void * buf,size_t len)738499853d6Sryan_chen static int aspeed_spi_read_from_ahb(void __iomem *ahb_base, void *buf,
739499853d6Sryan_chen 				    size_t len)
740499853d6Sryan_chen {
741499853d6Sryan_chen 	size_t offset = 0;
742499853d6Sryan_chen 
743499853d6Sryan_chen 	if (!((uintptr_t)buf % 4)) {
744499853d6Sryan_chen 		readsl(ahb_base, buf, len >> 2);
745499853d6Sryan_chen 		offset = len & ~0x3;
746499853d6Sryan_chen 		len -= offset;
747499853d6Sryan_chen 	}
748499853d6Sryan_chen 	readsb(ahb_base, (u8 *)buf + offset, len);
749499853d6Sryan_chen 
750499853d6Sryan_chen 	return 0;
751499853d6Sryan_chen }
752499853d6Sryan_chen 
aspeed_spi_write_to_ahb(void __iomem * ahb_base,const void * buf,size_t len)753499853d6Sryan_chen static int aspeed_spi_write_to_ahb(void __iomem *ahb_base, const void *buf,
754499853d6Sryan_chen 				   size_t len)
755499853d6Sryan_chen {
756499853d6Sryan_chen 	size_t offset = 0;
757499853d6Sryan_chen 
758499853d6Sryan_chen 	if (!((uintptr_t)buf % 4)) {
759499853d6Sryan_chen 		writesl(ahb_base, buf, len >> 2);
760499853d6Sryan_chen 		offset = len & ~0x3;
761499853d6Sryan_chen 		len -= offset;
762499853d6Sryan_chen 	}
763499853d6Sryan_chen 	writesb(ahb_base, (u8 *)buf + offset, len);
764499853d6Sryan_chen 
765499853d6Sryan_chen 	return 0;
766499853d6Sryan_chen }
767499853d6Sryan_chen 
aspeed_spi_start_user(struct aspeed_spi_priv * priv,struct aspeed_spi_flash * flash)768499853d6Sryan_chen static void aspeed_spi_start_user(struct aspeed_spi_priv *priv,
769499853d6Sryan_chen 				  struct aspeed_spi_flash *flash)
770499853d6Sryan_chen {
771499853d6Sryan_chen 	u32 ctrl_reg = flash->ce_ctrl_user | CE_CTRL_STOP_ACTIVE;
772499853d6Sryan_chen 
773499853d6Sryan_chen 	/* Deselect CS and set USER command mode */
774499853d6Sryan_chen 	writel(ctrl_reg, &priv->regs->ce_ctrl[flash->cs]);
775499853d6Sryan_chen 
776499853d6Sryan_chen 	/* Select CS */
777499853d6Sryan_chen 	clrbits_le32(&priv->regs->ce_ctrl[flash->cs], CE_CTRL_STOP_ACTIVE);
778499853d6Sryan_chen }
779499853d6Sryan_chen 
aspeed_spi_stop_user(struct aspeed_spi_priv * priv,struct aspeed_spi_flash * flash)780499853d6Sryan_chen static void aspeed_spi_stop_user(struct aspeed_spi_priv *priv,
781499853d6Sryan_chen 				 struct aspeed_spi_flash *flash)
782499853d6Sryan_chen {
783499853d6Sryan_chen 	/* Deselect CS first */
784499853d6Sryan_chen 	setbits_le32(&priv->regs->ce_ctrl[flash->cs], CE_CTRL_STOP_ACTIVE);
785499853d6Sryan_chen 
786499853d6Sryan_chen 	/* Restore default command mode */
787499853d6Sryan_chen 	writel(flash->ce_ctrl_fread, &priv->regs->ce_ctrl[flash->cs]);
788499853d6Sryan_chen }
789499853d6Sryan_chen 
aspeed_spi_read_reg(struct aspeed_spi_priv * priv,struct aspeed_spi_flash * flash,u8 opcode,u8 * read_buf,int len)790499853d6Sryan_chen static int aspeed_spi_read_reg(struct aspeed_spi_priv *priv,
791499853d6Sryan_chen 			       struct aspeed_spi_flash *flash,
792499853d6Sryan_chen 			       u8 opcode, u8 *read_buf, int len)
793499853d6Sryan_chen {
794bbe907dbSChin-Ting Kuo 	struct aspeed_spi_op op =
795bbe907dbSChin-Ting Kuo 		ASPEED_SPI_OP(0,
796bbe907dbSChin-Ting Kuo 			      ASPEED_SPI_OP_CMD(opcode),
797bbe907dbSChin-Ting Kuo 			      ASPEED_SPI_OP_ADDR(0, 0),
798bbe907dbSChin-Ting Kuo 			      ASPEED_SPI_OP_DUMMY(0),
799bbe907dbSChin-Ting Kuo 			      ASPEED_SPI_OP_DATA_IN(len, read_buf));
800bbe907dbSChin-Ting Kuo 
801bbe907dbSChin-Ting Kuo 	if (priv->spi_exec_op_cmd) {
802bbe907dbSChin-Ting Kuo 		priv->spi_exec_op_cmd(priv, flash, &op);
803bbe907dbSChin-Ting Kuo 		return 0;
804bbe907dbSChin-Ting Kuo 	}
805bbe907dbSChin-Ting Kuo 
806499853d6Sryan_chen 	aspeed_spi_start_user(priv, flash);
807499853d6Sryan_chen 	aspeed_spi_write_to_ahb(flash->ahb_base, &opcode, 1);
808499853d6Sryan_chen 	aspeed_spi_read_from_ahb(flash->ahb_base, read_buf, len);
809499853d6Sryan_chen 	aspeed_spi_stop_user(priv, flash);
810499853d6Sryan_chen 
811499853d6Sryan_chen 	return 0;
812499853d6Sryan_chen }
813499853d6Sryan_chen 
aspeed_spi_write_reg(struct aspeed_spi_priv * priv,struct aspeed_spi_flash * flash,u8 opcode,const u8 * write_buf,int len)814499853d6Sryan_chen static int aspeed_spi_write_reg(struct aspeed_spi_priv *priv,
815499853d6Sryan_chen 				struct aspeed_spi_flash *flash,
816499853d6Sryan_chen 				u8 opcode, const u8 *write_buf, int len)
817499853d6Sryan_chen {
818d6164108SChin-Ting Kuo 	int i;
819bbe907dbSChin-Ting Kuo 	struct aspeed_spi_op op =
820bbe907dbSChin-Ting Kuo 		ASPEED_SPI_OP(0,
821bbe907dbSChin-Ting Kuo 			      ASPEED_SPI_OP_CMD(opcode),
822bbe907dbSChin-Ting Kuo 			      ASPEED_SPI_OP_ADDR(0, 0),
823bbe907dbSChin-Ting Kuo 			      ASPEED_SPI_OP_DUMMY(0),
824bbe907dbSChin-Ting Kuo 			      ASPEED_SPI_OP_DATA_OUT(len, write_buf));
825bbe907dbSChin-Ting Kuo 
826bbe907dbSChin-Ting Kuo 	if (priv->spi_exec_op_cmd) {
827d6164108SChin-Ting Kuo 		if (opcode == SPINOR_OP_BE_4K || opcode == SPINOR_OP_BE_4K_4B ||
828d6164108SChin-Ting Kuo 		    opcode == SPINOR_OP_BE_32K || opcode == SPINOR_OP_BE_32K_4B ||
829d6164108SChin-Ting Kuo 		    opcode == SPINOR_OP_SE || opcode == SPINOR_OP_SE_4B) {
830d6164108SChin-Ting Kuo 			op.addr.nbytes = len;
831d6164108SChin-Ting Kuo 			for (i = 0; i < len; i++) {
832d6164108SChin-Ting Kuo 				op.addr.val <<= 8;
833d6164108SChin-Ting Kuo 				op.addr.val |= (u32)write_buf[i];
834d6164108SChin-Ting Kuo 			}
835d6164108SChin-Ting Kuo 			op.data.nbytes = 0;
836d6164108SChin-Ting Kuo 		}
837d6164108SChin-Ting Kuo 
838bbe907dbSChin-Ting Kuo 		priv->spi_exec_op_cmd(priv, flash, &op);
839bbe907dbSChin-Ting Kuo 		return 0;
840bbe907dbSChin-Ting Kuo 	}
841bbe907dbSChin-Ting Kuo 
842499853d6Sryan_chen 	aspeed_spi_start_user(priv, flash);
843499853d6Sryan_chen 	aspeed_spi_write_to_ahb(flash->ahb_base, &opcode, 1);
844499853d6Sryan_chen 	aspeed_spi_write_to_ahb(flash->ahb_base, write_buf, len);
845499853d6Sryan_chen 	aspeed_spi_stop_user(priv, flash);
846499853d6Sryan_chen 
847528cd552Sryan_chen 	debug("=== write opcode [%x] ==== \n", opcode);
848499853d6Sryan_chen 	switch(opcode) {
849499853d6Sryan_chen 		case SPINOR_OP_EN4B:
8500a73b911SChin-Ting Kuo 			/* For ast2600, if 2 chips ABR mode is enabled,
8510a73b911SChin-Ting Kuo 			 * turn on 3B mode auto clear in order to avoid
8520a73b911SChin-Ting Kuo 			 * the scenario where spi controller is at 4B mode
8530a73b911SChin-Ting Kuo 			 * and flash site is at 3B mode after 3rd switch.
8540a73b911SChin-Ting Kuo 			 */
8550a73b911SChin-Ting Kuo 			if (priv->new_ver == 1 && (readl(SPI_3B_AUTO_CLR_REG) & SPI_3B_AUTO_CLR))
8560a73b911SChin-Ting Kuo 				writel(readl(&priv->regs->soft_rst_cmd_ctrl) | SOFT_RST_CMD_EN,
8570a73b911SChin-Ting Kuo 						&priv->regs->soft_rst_cmd_ctrl);
8580a73b911SChin-Ting Kuo 
859edbd932bSChin-Ting Kuo 			writel(readl(&priv->regs->ctrl) | (0x11 << flash->cs), &priv->regs->ctrl);
860499853d6Sryan_chen 			break;
861499853d6Sryan_chen 		case SPINOR_OP_EX4B:
862edbd932bSChin-Ting Kuo 			writel(readl(&priv->regs->ctrl) & ~(0x11 << flash->cs), &priv->regs->ctrl);
863499853d6Sryan_chen 			break;
864499853d6Sryan_chen 	}
865499853d6Sryan_chen 	return 0;
866499853d6Sryan_chen }
867499853d6Sryan_chen 
aspeed_spi_send_cmd_addr(struct aspeed_spi_priv * priv,struct aspeed_spi_flash * flash,const u8 * cmdbuf,unsigned int cmdlen,uint32_t flag)868499853d6Sryan_chen static void aspeed_spi_send_cmd_addr(struct aspeed_spi_priv *priv,
869499853d6Sryan_chen 				     struct aspeed_spi_flash *flash,
870cd800046SChin-Ting Kuo 				     const u8 *cmdbuf, unsigned int cmdlen, uint32_t flag)
871499853d6Sryan_chen {
872499853d6Sryan_chen 	int i;
873499853d6Sryan_chen 
874499853d6Sryan_chen 	/* First, send the opcode */
875499853d6Sryan_chen 	aspeed_spi_write_to_ahb(flash->ahb_base, &cmdbuf[0], 1);
876499853d6Sryan_chen 
877cd800046SChin-Ting Kuo 	if(flash->write_iomode == CE_CTRL_IO_QUAD_ADDR_DATA && (flag & SPI_WRITE_TO_FLASH))
878cd800046SChin-Ting Kuo 		writel(flash->ce_ctrl_user | flash->write_iomode, &priv->regs->ce_ctrl[flash->cs]);
879cd800046SChin-Ting Kuo 	else if(flash->read_iomode == CE_CTRL_IO_QUAD_ADDR_DATA && (flag & SPI_READ_FROM_FLASH))
880cd800046SChin-Ting Kuo 		writel(flash->ce_ctrl_user | flash->read_iomode, &priv->regs->ce_ctrl[flash->cs]);
881528cd552Sryan_chen 
882499853d6Sryan_chen 	/* Then the address */
883499853d6Sryan_chen 	for (i = 1 ; i < cmdlen; i++)
884499853d6Sryan_chen 		aspeed_spi_write_to_ahb(flash->ahb_base, &cmdbuf[i], 1);
885499853d6Sryan_chen }
886499853d6Sryan_chen 
aspeed_spi_read_user(struct aspeed_spi_priv * priv,struct aspeed_spi_flash * flash,unsigned int cmdlen,const u8 * cmdbuf,unsigned int len,u8 * read_buf)887499853d6Sryan_chen static ssize_t aspeed_spi_read_user(struct aspeed_spi_priv *priv,
888499853d6Sryan_chen 				    struct aspeed_spi_flash *flash,
889499853d6Sryan_chen 				    unsigned int cmdlen, const u8 *cmdbuf,
890499853d6Sryan_chen 				    unsigned int len, u8 *read_buf)
891499853d6Sryan_chen {
8928fbbfa7dSChin-Ting Kuo 	u8 dummy = 0x00;
893499853d6Sryan_chen 	int i;
894bbe907dbSChin-Ting Kuo 	struct aspeed_spi_op op =
895bbe907dbSChin-Ting Kuo 		ASPEED_SPI_OP(flash->read_iomode,
896bbe907dbSChin-Ting Kuo 			      ASPEED_SPI_OP_CMD(cmdbuf[0]),
897bbe907dbSChin-Ting Kuo 			      ASPEED_SPI_OP_ADDR(0, 0),
898bbe907dbSChin-Ting Kuo 			      ASPEED_SPI_OP_DUMMY(flash->spi->read_dummy / 8),
899bbe907dbSChin-Ting Kuo 			      ASPEED_SPI_OP_DATA_IN(len, read_buf));
900bbe907dbSChin-Ting Kuo 
901bbe907dbSChin-Ting Kuo 	if (priv->spi_exec_op_cmd) {
902bbe907dbSChin-Ting Kuo 		op.addr.nbytes = cmdlen - 1 - op.dummy.nbytes;
903bbe907dbSChin-Ting Kuo 		op.addr.val = aspeed_spi_flash_to_addr(flash, cmdbuf, op.addr.nbytes + 1);
904bbe907dbSChin-Ting Kuo 		priv->spi_exec_op_cmd(priv, flash, &op);
905bbe907dbSChin-Ting Kuo 		return 0;
906bbe907dbSChin-Ting Kuo 	}
907499853d6Sryan_chen 
908499853d6Sryan_chen 	aspeed_spi_start_user(priv, flash);
909499853d6Sryan_chen 
910499853d6Sryan_chen 	/* cmd buffer = cmd + addr + dummies */
911499853d6Sryan_chen 	aspeed_spi_send_cmd_addr(priv, flash, cmdbuf,
912cd800046SChin-Ting Kuo 				 cmdlen - (flash->spi->read_dummy / 8), SPI_READ_FROM_FLASH);
913499853d6Sryan_chen 
914499853d6Sryan_chen 	for (i = 0; i < (flash->spi->read_dummy / 8); i++)
915499853d6Sryan_chen 		aspeed_spi_write_to_ahb(flash->ahb_base, &dummy, 1);
916499853d6Sryan_chen 
917cd800046SChin-Ting Kuo 	if (flash->read_iomode) {
918499853d6Sryan_chen 		clrbits_le32(&priv->regs->ce_ctrl[flash->cs],
919499853d6Sryan_chen 			     CE_CTRL_IO_MODE_MASK);
920cd800046SChin-Ting Kuo 		setbits_le32(&priv->regs->ce_ctrl[flash->cs], flash->read_iomode);
921499853d6Sryan_chen 	}
922499853d6Sryan_chen 
923499853d6Sryan_chen 	aspeed_spi_read_from_ahb(flash->ahb_base, read_buf, len);
924499853d6Sryan_chen 	aspeed_spi_stop_user(priv, flash);
925499853d6Sryan_chen 
926499853d6Sryan_chen 	return 0;
927499853d6Sryan_chen }
928499853d6Sryan_chen 
aspeed_spi_read_sfdp(struct aspeed_spi_priv * priv,struct aspeed_spi_flash * flash,unsigned int cmdlen,const u8 * cmdbuf,unsigned int len,u8 * read_buf)9298fbbfa7dSChin-Ting Kuo static ssize_t aspeed_spi_read_sfdp(struct aspeed_spi_priv *priv,
9308fbbfa7dSChin-Ting Kuo 				    struct aspeed_spi_flash *flash,
9318fbbfa7dSChin-Ting Kuo 				    unsigned int cmdlen, const u8 *cmdbuf,
9328fbbfa7dSChin-Ting Kuo 				    unsigned int len, u8 *read_buf)
9338fbbfa7dSChin-Ting Kuo {
9348fbbfa7dSChin-Ting Kuo 	u8 dummy = 0x00;
9358fbbfa7dSChin-Ting Kuo 	int i;
936bbe907dbSChin-Ting Kuo 	struct aspeed_spi_op op =
937bbe907dbSChin-Ting Kuo 		ASPEED_SPI_OP(flash->read_iomode,
938bbe907dbSChin-Ting Kuo 			      ASPEED_SPI_OP_CMD(cmdbuf[0]),
939bbe907dbSChin-Ting Kuo 			      ASPEED_SPI_OP_ADDR(0, 3),
940bbe907dbSChin-Ting Kuo 			      ASPEED_SPI_OP_DUMMY(flash->spi->read_dummy / 8),
941bbe907dbSChin-Ting Kuo 			      ASPEED_SPI_OP_DATA_IN(len, read_buf));
942bbe907dbSChin-Ting Kuo 
943bbe907dbSChin-Ting Kuo 	if (priv->spi_exec_op_cmd) {
944bbe907dbSChin-Ting Kuo 		op.addr.val = aspeed_spi_flash_to_addr(flash, cmdbuf, op.addr.nbytes + 1);
945bbe907dbSChin-Ting Kuo 		priv->spi_exec_op_cmd(priv, flash, &op);
946bbe907dbSChin-Ting Kuo 		return 0;
947bbe907dbSChin-Ting Kuo 	}
9488fbbfa7dSChin-Ting Kuo 
9498fbbfa7dSChin-Ting Kuo 	/* only 1-1-1 mode is used to read SFDP */
9508fbbfa7dSChin-Ting Kuo 	aspeed_spi_start_user(priv, flash);
9518fbbfa7dSChin-Ting Kuo 
9528fbbfa7dSChin-Ting Kuo 	/* cmd buffer = cmd + addr + dummies */
9538fbbfa7dSChin-Ting Kuo 	aspeed_spi_send_cmd_addr(priv, flash, cmdbuf,
9548fbbfa7dSChin-Ting Kuo 				 cmdlen - (flash->spi->read_dummy / 8), 0);
9558fbbfa7dSChin-Ting Kuo 
9568fbbfa7dSChin-Ting Kuo 	for (i = 0; i < (flash->spi->read_dummy / 8); i++)
9578fbbfa7dSChin-Ting Kuo 		aspeed_spi_write_to_ahb(flash->ahb_base, &dummy, 1);
9588fbbfa7dSChin-Ting Kuo 
9598fbbfa7dSChin-Ting Kuo 	aspeed_spi_read_from_ahb(flash->ahb_base, read_buf, len);
9608fbbfa7dSChin-Ting Kuo 	aspeed_spi_stop_user(priv, flash);
9618fbbfa7dSChin-Ting Kuo 
9628fbbfa7dSChin-Ting Kuo 	return 0;
9638fbbfa7dSChin-Ting Kuo }
9648fbbfa7dSChin-Ting Kuo 
aspeed_spi_write_user(struct aspeed_spi_priv * priv,struct aspeed_spi_flash * flash,unsigned int cmdlen,const u8 * cmdbuf,unsigned int len,const u8 * write_buf)965499853d6Sryan_chen static ssize_t aspeed_spi_write_user(struct aspeed_spi_priv *priv,
966499853d6Sryan_chen 				     struct aspeed_spi_flash *flash,
967499853d6Sryan_chen 				     unsigned int cmdlen, const u8 *cmdbuf,
968499853d6Sryan_chen 				     unsigned int len,	const u8 *write_buf)
969499853d6Sryan_chen {
970bbe907dbSChin-Ting Kuo 	struct aspeed_spi_op op =
971bbe907dbSChin-Ting Kuo 		ASPEED_SPI_OP(flash->write_iomode,
972bbe907dbSChin-Ting Kuo 			      ASPEED_SPI_OP_CMD(cmdbuf[0]),
973bbe907dbSChin-Ting Kuo 			      ASPEED_SPI_OP_ADDR(0, 0),
974bbe907dbSChin-Ting Kuo 			      ASPEED_SPI_OP_DUMMY(0),
975bbe907dbSChin-Ting Kuo 			      ASPEED_SPI_OP_DATA_OUT(len, write_buf));
976bbe907dbSChin-Ting Kuo 
977bbe907dbSChin-Ting Kuo 	if (priv->spi_exec_op_cmd) {
978bbe907dbSChin-Ting Kuo 		op.addr.nbytes = cmdlen - 1;
979bbe907dbSChin-Ting Kuo 		op.addr.val = aspeed_spi_flash_to_addr(flash, cmdbuf, op.addr.nbytes + 1);
980bbe907dbSChin-Ting Kuo 		priv->spi_exec_op_cmd(priv, flash, &op);
981bbe907dbSChin-Ting Kuo 		return 0;
982bbe907dbSChin-Ting Kuo 	}
983bbe907dbSChin-Ting Kuo 
984499853d6Sryan_chen 	aspeed_spi_start_user(priv, flash);
985499853d6Sryan_chen 
98676e3c7a9Sryan_chen 	/* cmd buffer = cmd + addr : normally cmd is use signle mode*/
987cd800046SChin-Ting Kuo 	aspeed_spi_send_cmd_addr(priv, flash, cmdbuf, cmdlen, SPI_WRITE_TO_FLASH);
98876e3c7a9Sryan_chen 
98976e3c7a9Sryan_chen 	/* data will use io mode */
990cd800046SChin-Ting Kuo 	if(flash->write_iomode == CE_CTRL_IO_QUAD_DATA)
991cd800046SChin-Ting Kuo 		writel(flash->ce_ctrl_user | flash->write_iomode, &priv->regs->ce_ctrl[flash->cs]);
99276e3c7a9Sryan_chen 
993499853d6Sryan_chen 	aspeed_spi_write_to_ahb(flash->ahb_base, write_buf, len);
994499853d6Sryan_chen 
995499853d6Sryan_chen 	aspeed_spi_stop_user(priv, flash);
996499853d6Sryan_chen 
997499853d6Sryan_chen 	return 0;
998499853d6Sryan_chen }
999499853d6Sryan_chen 
aspeed_spi_flash_to_addr(struct aspeed_spi_flash * flash,const u8 * cmdbuf,unsigned int cmdlen)1000499853d6Sryan_chen static u32 aspeed_spi_flash_to_addr(struct aspeed_spi_flash *flash,
1001499853d6Sryan_chen 				    const u8 *cmdbuf, unsigned int cmdlen)
1002499853d6Sryan_chen {
1003499853d6Sryan_chen 	u8 addrlen = cmdlen - 1;
1004499853d6Sryan_chen 	u32 addr = (cmdbuf[1] << 16) | (cmdbuf[2] << 8) | cmdbuf[3];
1005499853d6Sryan_chen 
1006499853d6Sryan_chen 	/*
1007499853d6Sryan_chen 	 * U-Boot SPI Flash layer uses 3 bytes addresses, but it might
1008499853d6Sryan_chen 	 * change one day
1009499853d6Sryan_chen 	 */
1010499853d6Sryan_chen 	if (addrlen == 4)
1011499853d6Sryan_chen 		addr = (addr << 8) | cmdbuf[4];
1012499853d6Sryan_chen 
1013499853d6Sryan_chen 	return addr;
1014499853d6Sryan_chen }
1015499853d6Sryan_chen 
1016499853d6Sryan_chen /* TODO(clg@kaod.org): add support for XFER_MMAP instead ? */
aspeed_spi_read(struct aspeed_spi_priv * priv,struct aspeed_spi_flash * flash,unsigned int cmdlen,const u8 * cmdbuf,unsigned int len,u8 * read_buf)1017499853d6Sryan_chen static ssize_t aspeed_spi_read(struct aspeed_spi_priv *priv,
1018499853d6Sryan_chen 			       struct aspeed_spi_flash *flash,
1019499853d6Sryan_chen 			       unsigned int cmdlen, const u8 *cmdbuf,
1020499853d6Sryan_chen 			       unsigned int len, u8 *read_buf)
1021499853d6Sryan_chen {
1022499853d6Sryan_chen 	/* cmd buffer = cmd + addr + dummies */
1023499853d6Sryan_chen 	u32 offset = aspeed_spi_flash_to_addr(flash, cmdbuf,
1024499853d6Sryan_chen 					      cmdlen - (flash->spi->read_dummy/8));
1025bbe907dbSChin-Ting Kuo 	struct aspeed_spi_op op =
1026bbe907dbSChin-Ting Kuo 		ASPEED_SPI_OP(flash->read_iomode,
1027bbe907dbSChin-Ting Kuo 			      ASPEED_SPI_OP_CMD(cmdbuf[0]),
1028bbe907dbSChin-Ting Kuo 			      ASPEED_SPI_OP_ADDR(0, 0),
1029bbe907dbSChin-Ting Kuo 			      ASPEED_SPI_OP_DUMMY(flash->spi->read_dummy / 8),
1030bbe907dbSChin-Ting Kuo 			      ASPEED_SPI_OP_DATA_IN(len, read_buf));
1031bbe907dbSChin-Ting Kuo 
1032bbe907dbSChin-Ting Kuo 	if (priv->spi_exec_op_cmd) {
1033bbe907dbSChin-Ting Kuo 		op.addr.nbytes = cmdlen - 1 - op.dummy.nbytes;
1034bbe907dbSChin-Ting Kuo 		op.addr.val = aspeed_spi_flash_to_addr(flash, cmdbuf, op.addr.nbytes + 1);
1035bbe907dbSChin-Ting Kuo 		priv->spi_exec_op_cmd(priv, flash, &op);
1036bbe907dbSChin-Ting Kuo 		return 0;
1037bbe907dbSChin-Ting Kuo 	}
1038499853d6Sryan_chen 
1039499853d6Sryan_chen 	/*
10406424f9abSChin-Ting Kuo 	 * Switch to USER command mode:
10418fbbfa7dSChin-Ting Kuo 	 * - if read SFDP content.
10426424f9abSChin-Ting Kuo 	 * - if the AHB window configured for the device is
10436424f9abSChin-Ting Kuo 	 *   too small for the read operation
10446424f9abSChin-Ting Kuo 	 * - if read offset is smaller than the decoded start address
10458fbbfa7dSChin-Ting Kuo 	 *   and the decoded range is not multiple of flash size.
1046499853d6Sryan_chen 	 */
10476424f9abSChin-Ting Kuo 	if ((offset + len >= flash->ahb_size) || \
10486424f9abSChin-Ting Kuo 		(offset < ((int)flash->ahb_base & 0x0FFFFFFF) && \
10496424f9abSChin-Ting Kuo 		(((int)flash->ahb_base & 0x0FFFFFFF) % flash->spi->size) != 0)) {
1050499853d6Sryan_chen 		return aspeed_spi_read_user(priv, flash, cmdlen, cmdbuf,
1051499853d6Sryan_chen 					    len, read_buf);
1052499853d6Sryan_chen 	}
1053499853d6Sryan_chen 
1054499853d6Sryan_chen 	memcpy_fromio(read_buf, flash->ahb_base + offset, len);
1055499853d6Sryan_chen 
1056499853d6Sryan_chen 	return 0;
1057499853d6Sryan_chen }
1058499853d6Sryan_chen 
aspeed_spi_exec_op_cmd_mode(struct aspeed_spi_priv * priv,struct aspeed_spi_flash * flash,struct aspeed_spi_op * op)1059bbe907dbSChin-Ting Kuo int aspeed_spi_exec_op_cmd_mode(struct aspeed_spi_priv *priv,
1060bbe907dbSChin-Ting Kuo 				struct aspeed_spi_flash *flash,
1061bbe907dbSChin-Ting Kuo 				struct aspeed_spi_op *op)
1062bbe907dbSChin-Ting Kuo {
1063bbe907dbSChin-Ting Kuo 	uint32_t cs = flash->cs;
1064bbe907dbSChin-Ting Kuo 	uint32_t ctrl_val;
1065bbe907dbSChin-Ting Kuo 	uint32_t addr_mode_reg, addr_mode_reg_backup;
1066bbe907dbSChin-Ting Kuo 	uint32_t addr_data_mask = 0;
1067bbe907dbSChin-Ting Kuo 	void __iomem *op_addr;
1068bbe907dbSChin-Ting Kuo 	const void *data_buf;
1069bbe907dbSChin-Ting Kuo 	uint32_t data_byte = 0;
1070bbe907dbSChin-Ting Kuo 	uint32_t dummy_data = 0;
1071bbe907dbSChin-Ting Kuo 
1072bbe907dbSChin-Ting Kuo 	debug("iomode: %08x, cmd:%02x, addr:%08x, dummy:%d, data_len:%x, dir: %s\n",
1073bbe907dbSChin-Ting Kuo 	      op->io_mode, op->cmd.opcode, op->addr.val, op->dummy.nbytes,
1074bbe907dbSChin-Ting Kuo 	      op->data.nbytes, op->data.dir == ASPEED_SPI_DIR_IN ? "in" : "out");
1075bbe907dbSChin-Ting Kuo 
1076bbe907dbSChin-Ting Kuo 	addr_mode_reg = readl(&priv->regs->ctrl);
1077bbe907dbSChin-Ting Kuo 	addr_mode_reg_backup = addr_mode_reg;
1078bbe907dbSChin-Ting Kuo 	addr_data_mask = readl(&priv->regs->cmd_ctrl);
1079bbe907dbSChin-Ting Kuo 
1080bbe907dbSChin-Ting Kuo 	ctrl_val = flash->ce_ctrl_fread & (~0xf0ff40c7);
1081bbe907dbSChin-Ting Kuo 	ctrl_val |= op->io_mode;
1082bbe907dbSChin-Ting Kuo 	/* configure opcode */
1083bbe907dbSChin-Ting Kuo 	ctrl_val |= op->cmd.opcode << 16;
1084bbe907dbSChin-Ting Kuo 
1085bbe907dbSChin-Ting Kuo 	/* configure operation address, address length and address mask */
1086bbe907dbSChin-Ting Kuo 	if (op->addr.nbytes != 0) {
1087bbe907dbSChin-Ting Kuo 		if (op->addr.nbytes == 3)
1088bbe907dbSChin-Ting Kuo 			addr_mode_reg &= ~(0x11 << cs);
1089bbe907dbSChin-Ting Kuo 		else
1090bbe907dbSChin-Ting Kuo 			addr_mode_reg |= (0x11 << cs);
1091bbe907dbSChin-Ting Kuo 
1092bbe907dbSChin-Ting Kuo 		addr_data_mask &= 0x0f;
1093bbe907dbSChin-Ting Kuo 		op_addr = flash->ahb_base + op->addr.val;
1094bbe907dbSChin-Ting Kuo 	} else {
1095bbe907dbSChin-Ting Kuo 		addr_data_mask |= 0xf0;
1096bbe907dbSChin-Ting Kuo 		op_addr = flash->ahb_base;
1097bbe907dbSChin-Ting Kuo 	}
1098bbe907dbSChin-Ting Kuo 
1099bbe907dbSChin-Ting Kuo 	if (op->dummy.nbytes != 0) {
1100bbe907dbSChin-Ting Kuo 		ctrl_val |= ((op->dummy.nbytes & 0x3) << 6 |
1101bbe907dbSChin-Ting Kuo 			     ((op->dummy.nbytes & 0x4) >> 2) << 14);
1102bbe907dbSChin-Ting Kuo 	}
1103bbe907dbSChin-Ting Kuo 
1104bbe907dbSChin-Ting Kuo 	/* configure data io mode and data mask */
1105bbe907dbSChin-Ting Kuo 	if (op->data.nbytes != 0) {
1106bbe907dbSChin-Ting Kuo 		addr_data_mask &= 0xF0;
1107bbe907dbSChin-Ting Kuo 		if (op->data.nbytes < 4)
1108bbe907dbSChin-Ting Kuo 			addr_data_mask |= ~((1 << op->data.nbytes) - 1);
1109bbe907dbSChin-Ting Kuo 
1110bbe907dbSChin-Ting Kuo 		data_byte = op->data.nbytes;
1111bbe907dbSChin-Ting Kuo 		if (op->data.dir == ASPEED_SPI_DIR_OUT) {
1112bbe907dbSChin-Ting Kuo 			if (data_byte % 4 != 0) {
1113bbe907dbSChin-Ting Kuo 				memset(priv->tmp_buf, 0xff, ((data_byte / 4) + 1) * 4);
1114bbe907dbSChin-Ting Kuo 				memcpy(priv->tmp_buf, op->data.buf.out, data_byte);
1115bbe907dbSChin-Ting Kuo 				data_buf = priv->tmp_buf;
1116bbe907dbSChin-Ting Kuo 				data_byte = ((data_byte / 4) + 1) * 4;
1117bbe907dbSChin-Ting Kuo 			} else {
1118bbe907dbSChin-Ting Kuo 				data_buf = op->data.buf.out;
1119bbe907dbSChin-Ting Kuo 			}
1120bbe907dbSChin-Ting Kuo 		} else {
1121bbe907dbSChin-Ting Kuo 			data_buf = op->data.buf.in;
1122bbe907dbSChin-Ting Kuo 		}
1123bbe907dbSChin-Ting Kuo 	} else {
1124bbe907dbSChin-Ting Kuo 		addr_data_mask |= 0x0f;
1125bbe907dbSChin-Ting Kuo 		data_byte = 1;
1126bbe907dbSChin-Ting Kuo 		data_buf = &dummy_data;
1127bbe907dbSChin-Ting Kuo 	}
1128bbe907dbSChin-Ting Kuo 
1129bbe907dbSChin-Ting Kuo 	/* configure command mode */
1130bbe907dbSChin-Ting Kuo 	if (op->data.dir == ASPEED_SPI_DIR_OUT)
1131bbe907dbSChin-Ting Kuo 		ctrl_val |= CE_CTRL_WRITEMODE;
1132bbe907dbSChin-Ting Kuo 	else
1133bbe907dbSChin-Ting Kuo 		ctrl_val |= CE_CTRL_FREADMODE;
1134bbe907dbSChin-Ting Kuo 
1135bbe907dbSChin-Ting Kuo 	/* set controller registers */
1136bbe907dbSChin-Ting Kuo 	writel(ctrl_val, &priv->regs->ce_ctrl[cs]);
1137bbe907dbSChin-Ting Kuo 	writel(addr_mode_reg, &priv->regs->ctrl);
1138bbe907dbSChin-Ting Kuo 	writel(addr_data_mask, &priv->regs->cmd_ctrl);
1139bbe907dbSChin-Ting Kuo 
1140bbe907dbSChin-Ting Kuo 	debug("ctrl: 0x%08x, addr_mode: 0x%x, mask: 0x%x, addr:0x%08x\n",
1141bbe907dbSChin-Ting Kuo 	      ctrl_val, addr_mode_reg, addr_data_mask, (uint32_t)op_addr);
1142bbe907dbSChin-Ting Kuo 
1143bbe907dbSChin-Ting Kuo 	/* trigger spi transmission or reception sequence */
1144bbe907dbSChin-Ting Kuo 	if (op->data.dir == ASPEED_SPI_DIR_OUT)
1145bbe907dbSChin-Ting Kuo 		memcpy_toio(op_addr, data_buf, data_byte);
1146bbe907dbSChin-Ting Kuo 	else
1147bbe907dbSChin-Ting Kuo 		memcpy_fromio((void *)data_buf, op_addr, data_byte);
1148bbe907dbSChin-Ting Kuo 
1149bbe907dbSChin-Ting Kuo 	/* restore controller setting */
1150bbe907dbSChin-Ting Kuo 	writel(flash->ce_ctrl_fread, &priv->regs->ce_ctrl[cs]);
1151bbe907dbSChin-Ting Kuo 	writel(addr_mode_reg_backup, &priv->regs->ctrl);
1152bbe907dbSChin-Ting Kuo 	writel(0x0, &priv->regs->cmd_ctrl);
1153bbe907dbSChin-Ting Kuo 
1154bbe907dbSChin-Ting Kuo 	return 0;
1155bbe907dbSChin-Ting Kuo }
1156bbe907dbSChin-Ting Kuo 
aspeed_spi_xfer(struct udevice * dev,unsigned int bitlen,const void * dout,void * din,unsigned long flags)1157499853d6Sryan_chen static int aspeed_spi_xfer(struct udevice *dev, unsigned int bitlen,
1158499853d6Sryan_chen 			   const void *dout, void *din, unsigned long flags)
1159499853d6Sryan_chen {
1160499853d6Sryan_chen 	struct udevice *bus = dev->parent;
1161499853d6Sryan_chen 	struct aspeed_spi_priv *priv = dev_get_priv(bus);
1162499853d6Sryan_chen 	struct aspeed_spi_flash *flash;
1163499853d6Sryan_chen 	u8 *cmd_buf = priv->cmd_buf;
1164499853d6Sryan_chen 	size_t data_bytes;
1165499853d6Sryan_chen 	int err = 0;
1166eaad4c09SChin-Ting Kuo 	u32 iomode;
1167499853d6Sryan_chen 
1168499853d6Sryan_chen 	flash = aspeed_spi_get_flash(dev);
1169499853d6Sryan_chen 	if (!flash)
1170499853d6Sryan_chen 		return -ENXIO;
1171499853d6Sryan_chen 
1172499853d6Sryan_chen 	if (flags & SPI_XFER_BEGIN) {
1173499853d6Sryan_chen 		/* save command in progress */
1174499853d6Sryan_chen 		priv->cmd_len = bitlen / 8;
1175499853d6Sryan_chen 		memcpy(cmd_buf, dout, priv->cmd_len);
1176499853d6Sryan_chen 	}
1177499853d6Sryan_chen 
1178499853d6Sryan_chen 	if (flags == (SPI_XFER_BEGIN | SPI_XFER_END)) {
1179499853d6Sryan_chen 		/* if start and end bit are set, the data bytes is 0. */
1180499853d6Sryan_chen 		data_bytes = 0;
1181499853d6Sryan_chen 	} else {
1182499853d6Sryan_chen 		data_bytes = bitlen / 8;
1183499853d6Sryan_chen 	}
1184499853d6Sryan_chen 
1185499853d6Sryan_chen 	debug("CS%u: %s cmd %zu bytes data %zu bytes\n", flash->cs,
1186499853d6Sryan_chen 	      din ? "read" : "write", priv->cmd_len, data_bytes);
1187499853d6Sryan_chen 
1188499853d6Sryan_chen 	if ((flags & SPI_XFER_END) || flags == 0) {
1189499853d6Sryan_chen 		if (priv->cmd_len == 0) {
1190499853d6Sryan_chen 			pr_err("No command is progress !\n");
1191499853d6Sryan_chen 			return -1;
1192499853d6Sryan_chen 		}
1193499853d6Sryan_chen 
1194499853d6Sryan_chen 		if (din && data_bytes) {
11958fbbfa7dSChin-Ting Kuo 			if (priv->cmd_len == 1) {
1196499853d6Sryan_chen 				err = aspeed_spi_read_reg(priv, flash,
1197499853d6Sryan_chen 							  cmd_buf[0],
1198499853d6Sryan_chen 							  din, data_bytes);
11998fbbfa7dSChin-Ting Kuo 			} else if (cmd_buf[0] == SPINOR_OP_RDSFDP) {
12008fbbfa7dSChin-Ting Kuo 				err = aspeed_spi_read_sfdp(priv, flash,
12018fbbfa7dSChin-Ting Kuo 							   priv->cmd_len,
12028fbbfa7dSChin-Ting Kuo 							   cmd_buf, data_bytes,
12038fbbfa7dSChin-Ting Kuo 							   din);
1204eaad4c09SChin-Ting Kuo 			} else if (cmd_buf[0] == SPINOR_OP_RDAR) {
1205eaad4c09SChin-Ting Kuo 				/* only for Cypress flash */
1206eaad4c09SChin-Ting Kuo 				iomode = flash->read_iomode;
1207eaad4c09SChin-Ting Kuo 				flash->read_iomode = 0;
1208eaad4c09SChin-Ting Kuo 				err = aspeed_spi_read_user(priv, flash,
1209eaad4c09SChin-Ting Kuo 							   priv->cmd_len,
1210eaad4c09SChin-Ting Kuo 							   cmd_buf, data_bytes,
1211eaad4c09SChin-Ting Kuo 							   din);
1212eaad4c09SChin-Ting Kuo 				flash->read_iomode = iomode;
12138fbbfa7dSChin-Ting Kuo 			} else {
1214499853d6Sryan_chen 				err = aspeed_spi_read(priv, flash,
1215499853d6Sryan_chen 						      priv->cmd_len,
1216499853d6Sryan_chen 						      cmd_buf, data_bytes,
1217499853d6Sryan_chen 						      din);
12188fbbfa7dSChin-Ting Kuo 			}
1219499853d6Sryan_chen 		} else if (dout) {
12208fbbfa7dSChin-Ting Kuo 			if (priv->cmd_len == 1) {
1221499853d6Sryan_chen 				err = aspeed_spi_write_reg(priv, flash,
1222499853d6Sryan_chen 							   cmd_buf[0],
1223499853d6Sryan_chen 							   dout, data_bytes);
12248fbbfa7dSChin-Ting Kuo 			} else {
1225499853d6Sryan_chen 				err = aspeed_spi_write_user(priv, flash,
1226499853d6Sryan_chen 							    priv->cmd_len,
1227499853d6Sryan_chen 							    cmd_buf, data_bytes,
1228499853d6Sryan_chen 							    dout);
1229499853d6Sryan_chen 			}
12308fbbfa7dSChin-Ting Kuo 		}
1231499853d6Sryan_chen 
1232499853d6Sryan_chen 		if (flags & SPI_XFER_END) {
1233499853d6Sryan_chen 			/* clear command */
1234499853d6Sryan_chen 			memset(cmd_buf, 0, sizeof(priv->cmd_buf));
1235499853d6Sryan_chen 			priv->cmd_len = 0;
1236499853d6Sryan_chen 		}
1237499853d6Sryan_chen 	}
1238499853d6Sryan_chen 
1239499853d6Sryan_chen 	return err;
1240499853d6Sryan_chen }
1241499853d6Sryan_chen 
12424c8f336cSChin-Ting Kuo #ifdef CONFIG_ASPEED_SPI_FLASH_WRITE_PROTECTION
aspeed_spi_fill_FQCD(struct aspeed_spi_priv * priv,u8 cmd)12434c8f336cSChin-Ting Kuo static void aspeed_spi_fill_FQCD(struct aspeed_spi_priv *priv, u8 cmd)
12444c8f336cSChin-Ting Kuo {
12454c8f336cSChin-Ting Kuo 	u32 reg_val;
12464c8f336cSChin-Ting Kuo 	u32 i;
12474c8f336cSChin-Ting Kuo 
12484c8f336cSChin-Ting Kuo 	for (i = 0; i < 20; i++) {
12494c8f336cSChin-Ting Kuo 		reg_val = readl(&priv->regs->fully_qualified_cmd[i]);
12504c8f336cSChin-Ting Kuo 		if ((u8)(reg_val & 0xff) == cmd ||
12514c8f336cSChin-Ting Kuo 		    (u8)((reg_val & 0xff00) >> 8) == cmd) {
12524c8f336cSChin-Ting Kuo 			if ((reg_val & 0x80000000) == 0x80000000) {
12534c8f336cSChin-Ting Kuo 				debug("cmd: %02x already exists in FQCD.\n", cmd);
12544c8f336cSChin-Ting Kuo 				return;
12554c8f336cSChin-Ting Kuo 			}
12564c8f336cSChin-Ting Kuo 		}
12574c8f336cSChin-Ting Kuo 	}
12584c8f336cSChin-Ting Kuo 
12594c8f336cSChin-Ting Kuo 	for (i = 0; i < 20; i++) {
12604c8f336cSChin-Ting Kuo 		reg_val = readl(&priv->regs->fully_qualified_cmd[i]);
12614c8f336cSChin-Ting Kuo 		if ((reg_val & 0x80000000) == 0x80000000) {
12624c8f336cSChin-Ting Kuo 			if ((u8)(reg_val & 0xff) == 0x0) {
12634c8f336cSChin-Ting Kuo 				reg_val |= (u32)cmd;
12644c8f336cSChin-Ting Kuo 				debug("[%d]fill %02x cmd in FQCD%02d.\n", __LINE__, cmd, i);
12654c8f336cSChin-Ting Kuo 				writel(reg_val, &priv->regs->fully_qualified_cmd[i]);
12664c8f336cSChin-Ting Kuo 				return;
12674c8f336cSChin-Ting Kuo 			} else if ((u8)((reg_val & 0xff00) >> 8) == 0x0) {
12684c8f336cSChin-Ting Kuo 				reg_val |= ((u32)cmd) << 8;
12694c8f336cSChin-Ting Kuo 				debug("[%d]fill %02x cmd in FQCD%02d.\n", __LINE__, cmd, i);
12704c8f336cSChin-Ting Kuo 				writel(reg_val, &priv->regs->fully_qualified_cmd[i]);
12714c8f336cSChin-Ting Kuo 				return;
12724c8f336cSChin-Ting Kuo 			}
12734c8f336cSChin-Ting Kuo 		}
12744c8f336cSChin-Ting Kuo 	}
12754c8f336cSChin-Ting Kuo 
12764c8f336cSChin-Ting Kuo 	for (i = 0; i < 20; i++) {
12774c8f336cSChin-Ting Kuo 		reg_val = readl(&priv->regs->fully_qualified_cmd[i]);
12784c8f336cSChin-Ting Kuo 		if (reg_val == 0) {
12794c8f336cSChin-Ting Kuo 			reg_val = 0x80000000 | (u32)cmd;
12804c8f336cSChin-Ting Kuo 			debug("[%d]fill %02x cmd in FQCD%02d.\n", __LINE__, cmd, i);
12814c8f336cSChin-Ting Kuo 			writel(reg_val, &priv->regs->fully_qualified_cmd[i]);
12824c8f336cSChin-Ting Kuo 			return;
12834c8f336cSChin-Ting Kuo 		}
12844c8f336cSChin-Ting Kuo 	}
12854c8f336cSChin-Ting Kuo }
12864c8f336cSChin-Ting Kuo 
aspeed_spi_fill_AQCD(struct aspeed_spi_priv * priv,u8 cmd,u8 addr_width)12874c8f336cSChin-Ting Kuo static void aspeed_spi_fill_AQCD(struct aspeed_spi_priv *priv, u8 cmd, u8 addr_width)
12884c8f336cSChin-Ting Kuo {
12894c8f336cSChin-Ting Kuo 	u32 reg_val;
12904c8f336cSChin-Ting Kuo 	u32 i;
12914c8f336cSChin-Ting Kuo 	u32 bit_offset;
12924c8f336cSChin-Ting Kuo 
12934c8f336cSChin-Ting Kuo 	if (addr_width != 3 && addr_width != 4) {
12944c8f336cSChin-Ting Kuo 		printf("wrong address width: %d.\n", addr_width);
12954c8f336cSChin-Ting Kuo 		return;
12964c8f336cSChin-Ting Kuo 	}
12974c8f336cSChin-Ting Kuo 
12984c8f336cSChin-Ting Kuo 	bit_offset = (addr_width - 3) * 8;
12994c8f336cSChin-Ting Kuo 
13004c8f336cSChin-Ting Kuo 	for (i = 0; i < 12; i++) {
13014c8f336cSChin-Ting Kuo 		reg_val = readl(&priv->regs->addr_qualified_cmd[i]);
13024c8f336cSChin-Ting Kuo 		if ((reg_val & 0x80000000) == 0x80000000) {
13034c8f336cSChin-Ting Kuo 			if ((u8)((reg_val & (0xff << bit_offset)) >> bit_offset) == cmd) {
13044c8f336cSChin-Ting Kuo 				debug("cmd: %02x already exists in AQCD.\n", cmd);
13054c8f336cSChin-Ting Kuo 				return;
13064c8f336cSChin-Ting Kuo 			}
13074c8f336cSChin-Ting Kuo 		}
13084c8f336cSChin-Ting Kuo 	}
13094c8f336cSChin-Ting Kuo 
13104c8f336cSChin-Ting Kuo 	for (i = 0; i < 12; i++) {
13114c8f336cSChin-Ting Kuo 		reg_val = readl(&priv->regs->addr_qualified_cmd[i]);
13124c8f336cSChin-Ting Kuo 		if ((reg_val & 0x80000000) == 0x80000000) {
13134c8f336cSChin-Ting Kuo 			if ((u8)((reg_val & (0xff << bit_offset)) >> bit_offset) == 0x0) {
13144c8f336cSChin-Ting Kuo 				reg_val |= ((u32)cmd << bit_offset);
13154c8f336cSChin-Ting Kuo 				debug("fill %02x cmd in AQCD%02d.\n", cmd, i);
13164c8f336cSChin-Ting Kuo 				writel(reg_val, &priv->regs->addr_qualified_cmd[i]);
13174c8f336cSChin-Ting Kuo 				return;
13184c8f336cSChin-Ting Kuo 			}
13194c8f336cSChin-Ting Kuo 		}
13204c8f336cSChin-Ting Kuo 
13214c8f336cSChin-Ting Kuo 		if (reg_val == 0) {
13224c8f336cSChin-Ting Kuo 			reg_val = 0x80000000 | ((u32)cmd << bit_offset);
13234c8f336cSChin-Ting Kuo 			debug("fill %02x cmd in AQCD%02d.\n", cmd, i);
13244c8f336cSChin-Ting Kuo 			writel(reg_val, &priv->regs->addr_qualified_cmd[i]);
13254c8f336cSChin-Ting Kuo 			return;
13264c8f336cSChin-Ting Kuo 		}
13274c8f336cSChin-Ting Kuo 	}
13284c8f336cSChin-Ting Kuo }
13294c8f336cSChin-Ting Kuo 
aspeed_spi_cmd_filter_config(struct aspeed_spi_priv * priv,u32 cs,bool enable)13304c8f336cSChin-Ting Kuo static void aspeed_spi_cmd_filter_config(struct aspeed_spi_priv *priv,
13314c8f336cSChin-Ting Kuo 					 u32 cs, bool enable)
13324c8f336cSChin-Ting Kuo {
13334c8f336cSChin-Ting Kuo 	u32 reg_val;
13344c8f336cSChin-Ting Kuo 
13354c8f336cSChin-Ting Kuo 	reg_val = readl(&priv->regs->write_cmd_filter_ctrl);
13364c8f336cSChin-Ting Kuo 
13374c8f336cSChin-Ting Kuo 	if (enable)
13384c8f336cSChin-Ting Kuo 		reg_val |= BIT(cs);
13394c8f336cSChin-Ting Kuo 	else
13404c8f336cSChin-Ting Kuo 		reg_val &= ~BIT(cs);
13414c8f336cSChin-Ting Kuo 
13424c8f336cSChin-Ting Kuo 	writel(reg_val, &priv->regs->write_cmd_filter_ctrl);
13434c8f336cSChin-Ting Kuo }
13444c8f336cSChin-Ting Kuo 
aspeed_spi_write_addr_ftr_sanity(struct aspeed_spi_priv * priv,u32 offset,size_t len)13454c8f336cSChin-Ting Kuo static int aspeed_spi_write_addr_ftr_sanity(struct aspeed_spi_priv *priv,
13464c8f336cSChin-Ting Kuo 					    u32 offset, size_t len)
13474c8f336cSChin-Ting Kuo {
13484c8f336cSChin-Ting Kuo 	u32 addr_ftr_ctrl;
13494c8f336cSChin-Ting Kuo 	u32 reg_val;
13504c8f336cSChin-Ting Kuo 	u32 start;
13514c8f336cSChin-Ting Kuo 	u32 end;
13524c8f336cSChin-Ting Kuo 	u32 i;
13534c8f336cSChin-Ting Kuo 
13544c8f336cSChin-Ting Kuo 	addr_ftr_ctrl = readl(&priv->regs->write_addr_filter_ctrl);
13554c8f336cSChin-Ting Kuo 	for (i = 0; i < 8; i++) {
13564c8f336cSChin-Ting Kuo 		if ((addr_ftr_ctrl & (0x3 << (i * 2))) == 0)
13574c8f336cSChin-Ting Kuo 			continue;
13584c8f336cSChin-Ting Kuo 		reg_val = readl(&priv->regs->write_addr_filter[i]);
13594c8f336cSChin-Ting Kuo 		start = (reg_val & 0xffff) << 12;
13604c8f336cSChin-Ting Kuo 		end = (((reg_val & 0xffff0000) >> 16) << 12) | 0xFFF;
13614c8f336cSChin-Ting Kuo 
13624c8f336cSChin-Ting Kuo 		if (offset >= start && offset < end)
13634c8f336cSChin-Ting Kuo 			return -1;
13644c8f336cSChin-Ting Kuo 		else if ((offset + len) > start && (offset + len) < end)
13654c8f336cSChin-Ting Kuo 			return -1;
13664c8f336cSChin-Ting Kuo 	}
13674c8f336cSChin-Ting Kuo 
13684c8f336cSChin-Ting Kuo 	return 0;
13694c8f336cSChin-Ting Kuo }
13704c8f336cSChin-Ting Kuo 
aspeed_add_write_addr_ftr(struct aspeed_spi_priv * priv,u32 offset,size_t len)13714c8f336cSChin-Ting Kuo static int aspeed_add_write_addr_ftr(struct aspeed_spi_priv *priv,
13724c8f336cSChin-Ting Kuo 				     u32 offset, size_t len)
13734c8f336cSChin-Ting Kuo {
13744c8f336cSChin-Ting Kuo 	u32 addr_ftr_ctrl;
13754c8f336cSChin-Ting Kuo 	u32 reg_val;
13764c8f336cSChin-Ting Kuo 	u32 start;
13774c8f336cSChin-Ting Kuo 	u32 end;
13784c8f336cSChin-Ting Kuo 	u32 i;
13794c8f336cSChin-Ting Kuo 
13804c8f336cSChin-Ting Kuo 	if ((offset & 0xfff) != 0) {
13814c8f336cSChin-Ting Kuo 		offset &= 0xfffff000;
13824c8f336cSChin-Ting Kuo 		printf("protected start address will be entend to 0x%08x.\n",
13834c8f336cSChin-Ting Kuo 		       offset);
13844c8f336cSChin-Ting Kuo 	}
13854c8f336cSChin-Ting Kuo 
13864c8f336cSChin-Ting Kuo 	if ((len & 0xfff) != 0) {
13874c8f336cSChin-Ting Kuo 		len &= 0xfff;
13884c8f336cSChin-Ting Kuo 		printf("protected len will be trimed to 0x%x.\n", len);
13894c8f336cSChin-Ting Kuo 	}
13904c8f336cSChin-Ting Kuo 
13914c8f336cSChin-Ting Kuo 	if (len == 0) {
13924c8f336cSChin-Ting Kuo 		printf("invalid protect len: 0x%x.\n", len);
13934c8f336cSChin-Ting Kuo 		return -1;
13944c8f336cSChin-Ting Kuo 	}
13954c8f336cSChin-Ting Kuo 
13964c8f336cSChin-Ting Kuo 	addr_ftr_ctrl = readl(&priv->regs->write_addr_filter_ctrl);
13974c8f336cSChin-Ting Kuo 	for (i = 0; i < 8; i++) {
13984c8f336cSChin-Ting Kuo 		if ((addr_ftr_ctrl & (0x3 << (i * 2))) == 0) {
13994c8f336cSChin-Ting Kuo 			start = offset;
14004c8f336cSChin-Ting Kuo 			end = offset + len - 1;
14014c8f336cSChin-Ting Kuo 
14024c8f336cSChin-Ting Kuo 			reg_val = (start >> 12) | ((end >> 12) << 16);
14034c8f336cSChin-Ting Kuo 
14044c8f336cSChin-Ting Kuo 			debug("start: 0x%08x, end: 0x%08x, val: 0x%08x.\n",
14054c8f336cSChin-Ting Kuo 			      start, end, reg_val);
14064c8f336cSChin-Ting Kuo 
14074c8f336cSChin-Ting Kuo 			writel(reg_val, &priv->regs->write_addr_filter[i]);
14084c8f336cSChin-Ting Kuo 			addr_ftr_ctrl |= 0x3 << (i * 2);
14094c8f336cSChin-Ting Kuo 			writel(addr_ftr_ctrl, &priv->regs->write_addr_filter_ctrl);
14104c8f336cSChin-Ting Kuo 
14114c8f336cSChin-Ting Kuo 			printf("apply write lock from offset, 0x%08x, with len, 0x%08x.\n",
14124c8f336cSChin-Ting Kuo 			       offset, (u32)len);
14134c8f336cSChin-Ting Kuo 
14144c8f336cSChin-Ting Kuo 			break;
14154c8f336cSChin-Ting Kuo 		}
14164c8f336cSChin-Ting Kuo 	}
14174c8f336cSChin-Ting Kuo 
14184c8f336cSChin-Ting Kuo 	if (i == 8) {
14194c8f336cSChin-Ting Kuo 		printf("insufficient write address filter register.\n");
14204c8f336cSChin-Ting Kuo 		return -1;
14214c8f336cSChin-Ting Kuo 	}
14224c8f336cSChin-Ting Kuo 
14234c8f336cSChin-Ting Kuo 	return 0;
14244c8f336cSChin-Ting Kuo }
14254c8f336cSChin-Ting Kuo 
aspeed_remove_write_addr_ftr(struct aspeed_spi_priv * priv,u32 offset,size_t len)14264c8f336cSChin-Ting Kuo static int aspeed_remove_write_addr_ftr(struct aspeed_spi_priv *priv,
14274c8f336cSChin-Ting Kuo 					u32 offset, size_t len)
14284c8f336cSChin-Ting Kuo {
14294c8f336cSChin-Ting Kuo 	u32 addr_ftr_ctrl;
14304c8f336cSChin-Ting Kuo 	u32 reg_val;
14314c8f336cSChin-Ting Kuo 	u32 bit_mask;
14324c8f336cSChin-Ting Kuo 	u32 start;
14334c8f336cSChin-Ting Kuo 	u32 end;
14344c8f336cSChin-Ting Kuo 	u32 i;
14354c8f336cSChin-Ting Kuo 
14364c8f336cSChin-Ting Kuo 	if ((offset & 0xfff) != 0) {
14374c8f336cSChin-Ting Kuo 		printf("start address should be aligned to 0x1000.\n");
14384c8f336cSChin-Ting Kuo 		return -1;
14394c8f336cSChin-Ting Kuo 	}
14404c8f336cSChin-Ting Kuo 
14414c8f336cSChin-Ting Kuo 	if ((len & 0xfff) != 0) {
14424c8f336cSChin-Ting Kuo 		printf("removed length should be aligned to 0x1000.\n");
14434c8f336cSChin-Ting Kuo 		return -1;
14444c8f336cSChin-Ting Kuo 	}
14454c8f336cSChin-Ting Kuo 
14464c8f336cSChin-Ting Kuo 	if (len == 0) {
14474c8f336cSChin-Ting Kuo 		printf("invalid removed length!\n");
14484c8f336cSChin-Ting Kuo 		return -1;
14494c8f336cSChin-Ting Kuo 	}
14504c8f336cSChin-Ting Kuo 
14514c8f336cSChin-Ting Kuo 	addr_ftr_ctrl = readl(&priv->regs->write_addr_filter_ctrl);
14524c8f336cSChin-Ting Kuo 	for (i = 0; i < 8; i++) {
14534c8f336cSChin-Ting Kuo 		bit_mask = 0x3 << (i * 2);
14544c8f336cSChin-Ting Kuo 		if ((addr_ftr_ctrl & bit_mask) != bit_mask)
14554c8f336cSChin-Ting Kuo 			continue;
14564c8f336cSChin-Ting Kuo 
14574c8f336cSChin-Ting Kuo 		reg_val = readl(&priv->regs->write_addr_filter[i]);
14584c8f336cSChin-Ting Kuo 		start = (reg_val & 0xffff) << 12;
14594c8f336cSChin-Ting Kuo 		end = (((reg_val & 0xffff0000) >> 16) << 12) + 0x1000;
14604c8f336cSChin-Ting Kuo 
14614c8f336cSChin-Ting Kuo 		if (offset != start || offset + len != end)
14624c8f336cSChin-Ting Kuo 			continue;
14634c8f336cSChin-Ting Kuo 
14644c8f336cSChin-Ting Kuo 		addr_ftr_ctrl &= ~(0x3 << (i * 2));
14654c8f336cSChin-Ting Kuo 		writel(addr_ftr_ctrl, &priv->regs->write_addr_filter_ctrl);
14664c8f336cSChin-Ting Kuo 		writel(0x0, &priv->regs->write_addr_filter[i]);
14674c8f336cSChin-Ting Kuo 		printf("remove write lock from offset, 0x%08x, with len, 0x%08x.\n",
14684c8f336cSChin-Ting Kuo 		       offset, (u32)len);
14694c8f336cSChin-Ting Kuo 		break;
14704c8f336cSChin-Ting Kuo 	}
14714c8f336cSChin-Ting Kuo 
14724c8f336cSChin-Ting Kuo 	if (i == 8) {
14734c8f336cSChin-Ting Kuo 		printf("cannot find expected removed region.\n");
14744c8f336cSChin-Ting Kuo 		return -1;
14754c8f336cSChin-Ting Kuo 	}
14764c8f336cSChin-Ting Kuo 
14774c8f336cSChin-Ting Kuo 	return 0;
14784c8f336cSChin-Ting Kuo }
14794c8f336cSChin-Ting Kuo 
aspeed_spi_mem_wlock(struct udevice * dev,u32 offset,size_t len)14804c8f336cSChin-Ting Kuo static int aspeed_spi_mem_wlock(struct udevice *dev, u32 offset, size_t len)
14814c8f336cSChin-Ting Kuo {
14824c8f336cSChin-Ting Kuo 	struct udevice *bus = dev->parent;
14834c8f336cSChin-Ting Kuo 	struct aspeed_spi_priv *priv = dev_get_priv(bus);
14844c8f336cSChin-Ting Kuo 	struct aspeed_spi_flash *flash;
14854c8f336cSChin-Ting Kuo 	struct spi_nor *nor;
14864c8f336cSChin-Ting Kuo 	int ret;
14874c8f336cSChin-Ting Kuo 
14884c8f336cSChin-Ting Kuo 	debug("%s offset: 0x%08x, len: 0x%08x.\n", __func__, offset, (u32)len);
14894c8f336cSChin-Ting Kuo 
14904c8f336cSChin-Ting Kuo 	flash = aspeed_spi_get_flash(dev);
14914c8f336cSChin-Ting Kuo 	if (!flash)
14924c8f336cSChin-Ting Kuo 		return -ENXIO;
14934c8f336cSChin-Ting Kuo 
14944c8f336cSChin-Ting Kuo 	nor = flash->spi;
14954c8f336cSChin-Ting Kuo 
14964c8f336cSChin-Ting Kuo 	debug("name: %s, read cmd: %02x, erase cmd: %02x, write cmd: %02x.\n",
14974c8f336cSChin-Ting Kuo 	      nor->name, nor->read_opcode, nor->erase_opcode, nor->program_opcode);
14984c8f336cSChin-Ting Kuo 
14994c8f336cSChin-Ting Kuo 	/* enable address filter */
15004c8f336cSChin-Ting Kuo 	aspeed_spi_fill_FQCD(priv, nor->read_opcode);
15014c8f336cSChin-Ting Kuo 	aspeed_spi_fill_AQCD(priv, nor->erase_opcode, nor->addr_width);
15024c8f336cSChin-Ting Kuo 	aspeed_spi_fill_AQCD(priv, nor->program_opcode, nor->addr_width);
15034c8f336cSChin-Ting Kuo 	aspeed_spi_cmd_filter_config(priv, flash->cs, true);
15044c8f336cSChin-Ting Kuo 
15054c8f336cSChin-Ting Kuo 	ret = aspeed_spi_write_addr_ftr_sanity(priv, offset, len);
15064c8f336cSChin-Ting Kuo 	if (ret < 0) {
15074c8f336cSChin-Ting Kuo 		printf("The expected protect region overlays with the existed regions!\n");
15084c8f336cSChin-Ting Kuo 		return ret;
15094c8f336cSChin-Ting Kuo 	}
15104c8f336cSChin-Ting Kuo 
15114c8f336cSChin-Ting Kuo 	ret = aspeed_add_write_addr_ftr(priv, offset, len);
15124c8f336cSChin-Ting Kuo 	if (ret < 0)
15134c8f336cSChin-Ting Kuo 		return -1;
15144c8f336cSChin-Ting Kuo 
15154c8f336cSChin-Ting Kuo 	return 0;
15164c8f336cSChin-Ting Kuo }
15174c8f336cSChin-Ting Kuo 
aspeed_spi_mem_wunlock(struct udevice * dev,u32 offset,size_t len)15184c8f336cSChin-Ting Kuo static int aspeed_spi_mem_wunlock(struct udevice *dev, u32 offset, size_t len)
15194c8f336cSChin-Ting Kuo {
15204c8f336cSChin-Ting Kuo 	struct udevice *bus = dev->parent;
15214c8f336cSChin-Ting Kuo 	struct aspeed_spi_priv *priv = dev_get_priv(bus);
15224c8f336cSChin-Ting Kuo 	int ret;
15234c8f336cSChin-Ting Kuo 
15244c8f336cSChin-Ting Kuo 	ret = aspeed_remove_write_addr_ftr(priv, offset, len);
15254c8f336cSChin-Ting Kuo 	if (ret < 0)
15264c8f336cSChin-Ting Kuo 		return -1;
15274c8f336cSChin-Ting Kuo 
15284c8f336cSChin-Ting Kuo 	return 0;
15294c8f336cSChin-Ting Kuo }
15304c8f336cSChin-Ting Kuo #endif
15314c8f336cSChin-Ting Kuo 
aspeed_spi_child_pre_probe(struct udevice * dev)1532499853d6Sryan_chen static int aspeed_spi_child_pre_probe(struct udevice *dev)
1533499853d6Sryan_chen {
1534499853d6Sryan_chen 	struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
1535499853d6Sryan_chen 
1536499853d6Sryan_chen 	debug("pre_probe slave device on CS%u, max_hz %u, mode 0x%x.\n",
1537499853d6Sryan_chen 	      slave_plat->cs, slave_plat->max_hz, slave_plat->mode);
1538499853d6Sryan_chen 
1539499853d6Sryan_chen 	if (!aspeed_spi_get_flash(dev))
1540499853d6Sryan_chen 		return -ENXIO;
1541499853d6Sryan_chen 
1542499853d6Sryan_chen 	return 0;
1543499853d6Sryan_chen }
1544499853d6Sryan_chen 
1545499853d6Sryan_chen /*
15468fbbfa7dSChin-Ting Kuo  * AST2600 SPI memory controllers support multiple chip selects.
15478fbbfa7dSChin-Ting Kuo  * The start address of a decode range should be multiple
15488fbbfa7dSChin-Ting Kuo  * of its related flash size. Namely, the total decoded size
15498fbbfa7dSChin-Ting Kuo  * from flash 0 to flash N should be multiple of (N + 1) flash size.
15508fbbfa7dSChin-Ting Kuo  */
aspeed_g6_adjust_decode_sz(u32 decode_sz_arr[],int len)15518fbbfa7dSChin-Ting Kuo void aspeed_g6_adjust_decode_sz(u32 decode_sz_arr[], int len)
15528fbbfa7dSChin-Ting Kuo {
15538fbbfa7dSChin-Ting Kuo 	int cs, j;
15548fbbfa7dSChin-Ting Kuo 	u32 sz;
15558fbbfa7dSChin-Ting Kuo 
15568fbbfa7dSChin-Ting Kuo 	for (cs = len - 1; cs >= 0; cs--) {
15578fbbfa7dSChin-Ting Kuo 		sz = 0;
15588fbbfa7dSChin-Ting Kuo 		for (j = 0; j < cs; j++)
15598fbbfa7dSChin-Ting Kuo 			sz += decode_sz_arr[j];
15608fbbfa7dSChin-Ting Kuo 
15618fbbfa7dSChin-Ting Kuo 		if (sz % decode_sz_arr[cs] != 0)
15628fbbfa7dSChin-Ting Kuo 			decode_sz_arr[0] += (sz % decode_sz_arr[cs]);
15638fbbfa7dSChin-Ting Kuo 	}
15648fbbfa7dSChin-Ting Kuo }
15658fbbfa7dSChin-Ting Kuo 
15668fbbfa7dSChin-Ting Kuo /*
1567499853d6Sryan_chen  * It is possible to automatically define a contiguous address space
1568499853d6Sryan_chen  * on top of all CEs in the AHB window of the controller but it would
1569499853d6Sryan_chen  * require much more work. Let's start with a simple mapping scheme
1570499853d6Sryan_chen  * which should work fine for a single flash device.
1571499853d6Sryan_chen  *
1572499853d6Sryan_chen  * More complex schemes should probably be defined with the device
1573499853d6Sryan_chen  * tree.
1574499853d6Sryan_chen  */
aspeed_spi_flash_set_segment(struct aspeed_spi_priv * priv,struct aspeed_spi_flash * flash)1575499853d6Sryan_chen static int aspeed_spi_flash_set_segment(struct aspeed_spi_priv *priv,
1576499853d6Sryan_chen 					struct aspeed_spi_flash *flash)
1577499853d6Sryan_chen {
1578499853d6Sryan_chen 	u32 seg_addr;
15798fbbfa7dSChin-Ting Kuo 	u32 decode_sz_arr[ASPEED_SPI_MAX_CS];
15808fbbfa7dSChin-Ting Kuo 	u32 reg_val;
15818fbbfa7dSChin-Ting Kuo 	u32 cs;
15828fbbfa7dSChin-Ting Kuo 	u32 total_decode_sz = 0;
15838fbbfa7dSChin-Ting Kuo 	u32 cur_offset = 0;
1584499853d6Sryan_chen 
1585499853d6Sryan_chen 	/* could be configured through the device tree */
1586499853d6Sryan_chen 	flash->ahb_size = flash->spi->size;
1587499853d6Sryan_chen 
1588da83dd7eSryan_chen 	if (priv->new_ver) {
15898fbbfa7dSChin-Ting Kuo 		for (cs = 0; cs < ASPEED_SPI_MAX_CS; cs++) {
15908fbbfa7dSChin-Ting Kuo 			reg_val = readl(&priv->regs->segment_addr[cs]);
159171df69c6SChin-Ting Kuo 			if (reg_val != 0 &&
159271df69c6SChin-Ting Kuo 			    G6_SEGMENT_ADDR_END(reg_val) > G6_SEGMENT_ADDR_START(reg_val)) {
15938fbbfa7dSChin-Ting Kuo 				decode_sz_arr[cs] =
15948fbbfa7dSChin-Ting Kuo 					G6_SEGMENT_ADDR_END(reg_val) - G6_SEGMENT_ADDR_START(reg_val);
15958fbbfa7dSChin-Ting Kuo 			} else {
15968fbbfa7dSChin-Ting Kuo 				decode_sz_arr[cs] = 0;
15978fbbfa7dSChin-Ting Kuo 			}
15988fbbfa7dSChin-Ting Kuo 		}
15998fbbfa7dSChin-Ting Kuo 
16008fbbfa7dSChin-Ting Kuo 		decode_sz_arr[flash->cs] = flash->ahb_size;
16018fbbfa7dSChin-Ting Kuo 		aspeed_g6_adjust_decode_sz(decode_sz_arr, flash->cs + 1);
16028fbbfa7dSChin-Ting Kuo 
16038fbbfa7dSChin-Ting Kuo 		for (cs = 0; cs < ASPEED_SPI_MAX_CS; cs++)
16048fbbfa7dSChin-Ting Kuo 			total_decode_sz += decode_sz_arr[cs];
16058fbbfa7dSChin-Ting Kuo 
16068fbbfa7dSChin-Ting Kuo 		if (total_decode_sz > priv->ahb_size) {
1607edaef9d2SChin-Ting Kuo 			printf("err: Total decoded size, 0x%x, is too large.\n", total_decode_sz);
16088fbbfa7dSChin-Ting Kuo 			return -ENOMEM;
16098fbbfa7dSChin-Ting Kuo 		}
16108fbbfa7dSChin-Ting Kuo 
16118fbbfa7dSChin-Ting Kuo 		for (cs = 0; cs < ASPEED_SPI_MAX_CS; cs++) {
16128fbbfa7dSChin-Ting Kuo 			struct aspeed_spi_flash *flash = &priv->flashes[cs];
16138fbbfa7dSChin-Ting Kuo 
16148fbbfa7dSChin-Ting Kuo 			flash->ahb_base = (void __iomem *)((u32)priv->ahb_base + cur_offset);
16158fbbfa7dSChin-Ting Kuo 
16168fbbfa7dSChin-Ting Kuo 			if (decode_sz_arr[cs] != 0) {
1617da83dd7eSryan_chen 				seg_addr = G6_SEGMENT_ADDR_VALUE((u32)flash->ahb_base,
16188fbbfa7dSChin-Ting Kuo 								 (u32)flash->ahb_base + decode_sz_arr[cs]);
16198fbbfa7dSChin-Ting Kuo 			} else {
16208fbbfa7dSChin-Ting Kuo 				seg_addr = 0;
16218fbbfa7dSChin-Ting Kuo 			}
16228fbbfa7dSChin-Ting Kuo 
16238fbbfa7dSChin-Ting Kuo 			writel(seg_addr, &priv->regs->segment_addr[cs]);
16248fbbfa7dSChin-Ting Kuo 			flash->ahb_size = decode_sz_arr[cs];
16258fbbfa7dSChin-Ting Kuo 			cur_offset += decode_sz_arr[cs];
16268fbbfa7dSChin-Ting Kuo 		}
1627da83dd7eSryan_chen 	} else {
1628499853d6Sryan_chen 		seg_addr = SEGMENT_ADDR_VALUE((u32)flash->ahb_base,
1629499853d6Sryan_chen 						  (u32)flash->ahb_base + flash->ahb_size);
1630499853d6Sryan_chen 		writel(seg_addr, &priv->regs->segment_addr[flash->cs]);
16318fbbfa7dSChin-Ting Kuo 	}
1632499853d6Sryan_chen 
1633499853d6Sryan_chen 	return 0;
1634499853d6Sryan_chen }
1635499853d6Sryan_chen 
aspeed_spi_flash_init(struct aspeed_spi_priv * priv,struct aspeed_spi_flash * flash,struct udevice * dev)1636499853d6Sryan_chen static int aspeed_spi_flash_init(struct aspeed_spi_priv *priv,
1637499853d6Sryan_chen 				 struct aspeed_spi_flash *flash,
1638499853d6Sryan_chen 				 struct udevice *dev)
1639499853d6Sryan_chen {
1640beec505fSChin-Ting Kuo 	int ret;
1641499853d6Sryan_chen 	struct spi_flash *spi_flash = dev_get_uclass_priv(dev);
1642499853d6Sryan_chen 	struct spi_slave *slave = dev_get_parent_priv(dev);
164351b227c8SChin-Ting Kuo 	struct udevice *bus = dev->parent;
1644499853d6Sryan_chen 	u32 read_hclk;
1645499853d6Sryan_chen 
1646a4e44632SChin-Ting Kuo 	flash->spi = spi_flash;
1647a4e44632SChin-Ting Kuo 
1648499853d6Sryan_chen 	/*
1649499853d6Sryan_chen 	 * The flash device has not been probed yet. Initial transfers
1650499853d6Sryan_chen 	 * to read the JEDEC of the device will use the initial
1651499853d6Sryan_chen 	 * default settings of the registers.
1652499853d6Sryan_chen 	 */
1653499853d6Sryan_chen 	if (!spi_flash->name)
1654499853d6Sryan_chen 		return 0;
1655499853d6Sryan_chen 
1656543bff32SChin-Ting Kuo 	/*
1657543bff32SChin-Ting Kuo 	 * The SPI flash device slave should not change, so initialize
1658543bff32SChin-Ting Kuo 	 * it only once.
1659543bff32SChin-Ting Kuo 	 */
1660543bff32SChin-Ting Kuo 	if (flash->init)
1661543bff32SChin-Ting Kuo 		return 0;
1662543bff32SChin-Ting Kuo 
1663edaef9d2SChin-Ting Kuo 	debug("CS%u: init %s flags:%x size:%d page:%d sector:%d erase:%d",
1664499853d6Sryan_chen 	      flash->cs,
1665499853d6Sryan_chen 	      spi_flash->name, spi_flash->flags, spi_flash->size,
1666499853d6Sryan_chen 	      spi_flash->page_size, spi_flash->sector_size,
1667edaef9d2SChin-Ting Kuo 	      spi_flash->erase_size);
1668edaef9d2SChin-Ting Kuo 	debug(" cmds [ erase:%x read=%x write:%x ] dummy:%d, speed:%d\n",
1669edaef9d2SChin-Ting Kuo 	      spi_flash->erase_opcode,
1670499853d6Sryan_chen 	      spi_flash->read_opcode, spi_flash->program_opcode,
1671edaef9d2SChin-Ting Kuo 	      spi_flash->read_dummy, slave->speed);
1672499853d6Sryan_chen 
16737d182336Sryan_chen 	flash->ce_ctrl_user = CE_CTRL_USERMODE;
1674edaef9d2SChin-Ting Kuo 	flash->max_freq = slave->speed;
1675499853d6Sryan_chen 
1676ac86fa8bSryan_chen 	if(priv->new_ver)
1677ac86fa8bSryan_chen 		read_hclk = aspeed_g6_spi_hclk_divisor(priv, slave->speed);
1678ac86fa8bSryan_chen 	else
16797d182336Sryan_chen 		read_hclk = aspeed_spi_hclk_divisor(priv, slave->speed);
1680499853d6Sryan_chen 
1681528cd552Sryan_chen 	switch(flash->spi->read_opcode) {
1682bbe907dbSChin-Ting Kuo 	case SPINOR_OP_READ:
1683bbe907dbSChin-Ting Kuo 	case SPINOR_OP_READ_4B:
1684bbe907dbSChin-Ting Kuo 		flash->read_iomode = CE_CTRL_IO_SINGLE;
1685bbe907dbSChin-Ting Kuo 		break;
1686528cd552Sryan_chen 	case SPINOR_OP_READ_1_1_2:
1687528cd552Sryan_chen 	case SPINOR_OP_READ_1_1_2_4B:
1688cd800046SChin-Ting Kuo 		flash->read_iomode = CE_CTRL_IO_DUAL_DATA;
1689528cd552Sryan_chen 		break;
1690528cd552Sryan_chen 	case SPINOR_OP_READ_1_1_4:
1691528cd552Sryan_chen 	case SPINOR_OP_READ_1_1_4_4B:
1692cd800046SChin-Ting Kuo 		flash->read_iomode = CE_CTRL_IO_QUAD_DATA;
1693528cd552Sryan_chen 		break;
1694528cd552Sryan_chen 	case SPINOR_OP_READ_1_4_4:
1695528cd552Sryan_chen 	case SPINOR_OP_READ_1_4_4_4B:
1696cd800046SChin-Ting Kuo 		flash->read_iomode = CE_CTRL_IO_QUAD_ADDR_DATA;
1697734f8860SChin-Ting Kuo 		printf("need modify dummy for 3 bytes\n");
1698528cd552Sryan_chen 		break;
1699499853d6Sryan_chen 	}
1700499853d6Sryan_chen 
1701cd800046SChin-Ting Kuo 	switch(flash->spi->program_opcode) {
1702cd800046SChin-Ting Kuo 	case SPINOR_OP_PP:
1703cd800046SChin-Ting Kuo 	case SPINOR_OP_PP_4B:
1704cd800046SChin-Ting Kuo 		flash->write_iomode = CE_CTRL_IO_SINGLE;
1705cd800046SChin-Ting Kuo 		break;
1706cd800046SChin-Ting Kuo 	case SPINOR_OP_PP_1_1_4:
1707cd800046SChin-Ting Kuo 	case SPINOR_OP_PP_1_1_4_4B:
1708cd800046SChin-Ting Kuo 		flash->write_iomode = CE_CTRL_IO_QUAD_DATA;
1709cd800046SChin-Ting Kuo 		break;
1710cd800046SChin-Ting Kuo 	case SPINOR_OP_PP_1_4_4:
1711cd800046SChin-Ting Kuo 	case SPINOR_OP_PP_1_4_4_4B:
1712cd800046SChin-Ting Kuo 		flash->write_iomode = CE_CTRL_IO_QUAD_ADDR_DATA;
1713cd800046SChin-Ting Kuo 		printf("need modify dummy for 3 bytes");
1714cd800046SChin-Ting Kuo 		break;
1715cd800046SChin-Ting Kuo 	}
1716cd800046SChin-Ting Kuo 
1717d32338fdSryan_chen 	if(priv->new_ver) {
17187d182336Sryan_chen 		flash->ce_ctrl_fread = CE_G6_CTRL_CLOCK_FREQ(read_hclk) |
1719cd800046SChin-Ting Kuo 			flash->read_iomode |
17207d182336Sryan_chen 			CE_CTRL_CMD(flash->spi->read_opcode) |
17217d182336Sryan_chen 			CE_CTRL_DUMMY((flash->spi->read_dummy/8)) |
17227d182336Sryan_chen 			CE_CTRL_FREADMODE;
1723b679b8adSChin-Ting Kuo 		flash->ce_ctrl_user |= CE_G6_CTRL_CLOCK_FREQ(read_hclk);
1724d32338fdSryan_chen 	} else {
1725499853d6Sryan_chen 		flash->ce_ctrl_fread = CE_CTRL_CLOCK_FREQ(read_hclk) |
1726cd800046SChin-Ting Kuo 			flash->read_iomode |
1727499853d6Sryan_chen 			CE_CTRL_CMD(flash->spi->read_opcode) |
1728499853d6Sryan_chen 			CE_CTRL_DUMMY((flash->spi->read_dummy/8)) |
1729499853d6Sryan_chen 			CE_CTRL_FREADMODE;
1730d32338fdSryan_chen 	}
1731499853d6Sryan_chen 
17329405f2a1SChin-Ting Kuo 	if (flash->spi->addr_width == 4)
17339405f2a1SChin-Ting Kuo 		writel(readl(&priv->regs->ctrl) | 0x11 << flash->cs, &priv->regs->ctrl);
17349405f2a1SChin-Ting Kuo 
1735499853d6Sryan_chen 	debug("CS%u: USER mode 0x%08x FREAD mode 0x%08x\n", flash->cs,
1736499853d6Sryan_chen 	      flash->ce_ctrl_user, flash->ce_ctrl_fread);
1737499853d6Sryan_chen 
1738499853d6Sryan_chen 	/* Set the CE Control Register default (FAST READ) */
1739499853d6Sryan_chen 	writel(flash->ce_ctrl_fread, &priv->regs->ce_ctrl[flash->cs]);
1740499853d6Sryan_chen 
1741499853d6Sryan_chen 	/* Set Address Segment Register for direct AHB accesses */
17428fbbfa7dSChin-Ting Kuo 	ret = aspeed_spi_flash_set_segment(priv, flash);
17438fbbfa7dSChin-Ting Kuo 	if (ret != 0)
17448fbbfa7dSChin-Ting Kuo 		return ret;
1745499853d6Sryan_chen 
1746beec505fSChin-Ting Kuo 	/*
1747beec505fSChin-Ting Kuo 	 * Set the Read Timing Compensation Register. This setting
1748beec505fSChin-Ting Kuo 	 * applies to all devices.
1749beec505fSChin-Ting Kuo 	 */
175051b227c8SChin-Ting Kuo 	if (!dev_read_bool(bus, "timing-calibration-disabled")) {
1751edaef9d2SChin-Ting Kuo 		ret = aspeed_spi_timing_calibration(priv, flash);
1752beec505fSChin-Ting Kuo 		if (ret != 0)
1753beec505fSChin-Ting Kuo 			return ret;
175451b227c8SChin-Ting Kuo 	}
1755beec505fSChin-Ting Kuo 
1756499853d6Sryan_chen 	/* All done */
1757499853d6Sryan_chen 	flash->init = true;
1758499853d6Sryan_chen 
1759499853d6Sryan_chen 	return 0;
1760499853d6Sryan_chen }
1761499853d6Sryan_chen 
aspeed_spi_claim_bus(struct udevice * dev)1762499853d6Sryan_chen static int aspeed_spi_claim_bus(struct udevice *dev)
1763499853d6Sryan_chen {
1764499853d6Sryan_chen 	struct udevice *bus = dev->parent;
1765499853d6Sryan_chen 	struct aspeed_spi_priv *priv = dev_get_priv(bus);
1766499853d6Sryan_chen 	struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
1767499853d6Sryan_chen 	struct aspeed_spi_flash *flash;
1768*eba3f26aSChin-Ting Kuo 	struct spi_slave *slave = dev_get_parent_priv(dev);
1769*eba3f26aSChin-Ting Kuo 	u32 read_hclk;
1770499853d6Sryan_chen 
1771499853d6Sryan_chen 	debug("%s: claim bus CS%u\n", bus->name, slave_plat->cs);
1772499853d6Sryan_chen 
1773499853d6Sryan_chen 	flash = aspeed_spi_get_flash(dev);
1774499853d6Sryan_chen 	if (!flash)
1775499853d6Sryan_chen 		return -ENODEV;
1776499853d6Sryan_chen 
1777*eba3f26aSChin-Ting Kuo 	if (priv->new_ver) {
1778*eba3f26aSChin-Ting Kuo 		if (dev_read_bool(bus, "timing-calibration-disabled")) {
1779*eba3f26aSChin-Ting Kuo 			read_hclk = aspeed_g6_spi_hclk_divisor(priv, slave->speed);
1780*eba3f26aSChin-Ting Kuo 			flash->ce_ctrl_user &= CE_CTRL_FREQ_MASK;
1781*eba3f26aSChin-Ting Kuo 			flash->ce_ctrl_user |= CE_G6_CTRL_CLOCK_FREQ(read_hclk);
1782*eba3f26aSChin-Ting Kuo 			flash->ce_ctrl_fread &= CE_CTRL_FREQ_MASK;
1783*eba3f26aSChin-Ting Kuo 			flash->ce_ctrl_fread |= CE_G6_CTRL_CLOCK_FREQ(read_hclk);
1784*eba3f26aSChin-Ting Kuo 		}
1785*eba3f26aSChin-Ting Kuo 	}
1786*eba3f26aSChin-Ting Kuo 
1787499853d6Sryan_chen 	return aspeed_spi_flash_init(priv, flash, dev);
1788499853d6Sryan_chen }
1789499853d6Sryan_chen 
aspeed_spi_release_bus(struct udevice * dev)1790499853d6Sryan_chen static int aspeed_spi_release_bus(struct udevice *dev)
1791499853d6Sryan_chen {
1792499853d6Sryan_chen 	struct udevice *bus = dev->parent;
1793499853d6Sryan_chen 	struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
1794499853d6Sryan_chen 
1795499853d6Sryan_chen 	debug("%s: release bus CS%u\n", bus->name, slave_plat->cs);
1796499853d6Sryan_chen 
1797499853d6Sryan_chen 	if (!aspeed_spi_get_flash(dev))
1798499853d6Sryan_chen 		return -ENODEV;
1799499853d6Sryan_chen 
1800499853d6Sryan_chen 	return 0;
1801499853d6Sryan_chen }
1802499853d6Sryan_chen 
aspeed_spi_set_mode(struct udevice * bus,uint mode)1803499853d6Sryan_chen static int aspeed_spi_set_mode(struct udevice *bus, uint mode)
1804499853d6Sryan_chen {
1805499853d6Sryan_chen 	debug("%s: setting mode to %x\n", bus->name, mode);
1806499853d6Sryan_chen 
1807499853d6Sryan_chen 	if (mode & (SPI_RX_QUAD | SPI_TX_QUAD)) {
180876e3c7a9Sryan_chen #ifndef CONFIG_ASPEED_AST2600
1809499853d6Sryan_chen 		pr_err("%s invalid QUAD IO mode\n", bus->name);
1810499853d6Sryan_chen 		return -EINVAL;
181176e3c7a9Sryan_chen #endif
1812499853d6Sryan_chen 	}
1813499853d6Sryan_chen 
1814499853d6Sryan_chen 	/* The CE Control Register is set in claim_bus() */
1815499853d6Sryan_chen 	return 0;
1816499853d6Sryan_chen }
1817499853d6Sryan_chen 
aspeed_spi_set_speed(struct udevice * bus,uint hz)1818499853d6Sryan_chen static int aspeed_spi_set_speed(struct udevice *bus, uint hz)
1819499853d6Sryan_chen {
1820499853d6Sryan_chen 	debug("%s: setting speed to %u\n", bus->name, hz);
1821499853d6Sryan_chen 
1822499853d6Sryan_chen 	/* The CE Control Register is set in claim_bus() */
1823499853d6Sryan_chen 	return 0;
1824499853d6Sryan_chen }
1825499853d6Sryan_chen 
aspeed_spi_count_flash_devices(struct udevice * bus)1826499853d6Sryan_chen static int aspeed_spi_count_flash_devices(struct udevice *bus)
1827499853d6Sryan_chen {
1828499853d6Sryan_chen 	ofnode node;
1829499853d6Sryan_chen 	int count = 0;
1830499853d6Sryan_chen 
1831499853d6Sryan_chen 	dev_for_each_subnode(node, bus) {
1832499853d6Sryan_chen 		if (ofnode_is_available(node) &&
18339544b743SCédric Le Goater 		    (ofnode_device_is_compatible(node, "spi-flash") ||
18349544b743SCédric Le Goater 		     ofnode_device_is_compatible(node, "jedec,spi-nor")))
1835499853d6Sryan_chen 			count++;
1836499853d6Sryan_chen 	}
1837499853d6Sryan_chen 
1838499853d6Sryan_chen 	return count;
1839499853d6Sryan_chen }
1840499853d6Sryan_chen 
aspeed_spi_bind(struct udevice * bus)1841499853d6Sryan_chen static int aspeed_spi_bind(struct udevice *bus)
1842499853d6Sryan_chen {
1843499853d6Sryan_chen 	debug("%s assigned req_seq=%d seq=%d\n", bus->name, bus->req_seq,
1844499853d6Sryan_chen 	      bus->seq);
1845499853d6Sryan_chen 
1846499853d6Sryan_chen 	return 0;
1847499853d6Sryan_chen }
1848499853d6Sryan_chen 
aspeed_spi_probe(struct udevice * bus)1849499853d6Sryan_chen static int aspeed_spi_probe(struct udevice *bus)
1850499853d6Sryan_chen {
1851499853d6Sryan_chen 	struct resource res_regs, res_ahb;
1852499853d6Sryan_chen 	struct aspeed_spi_priv *priv = dev_get_priv(bus);
1853499853d6Sryan_chen 	struct clk hclk;
1854499853d6Sryan_chen 	int ret;
1855499853d6Sryan_chen 
1856499853d6Sryan_chen 	ret = dev_read_resource(bus, 0, &res_regs);
1857499853d6Sryan_chen 	if (ret < 0)
1858499853d6Sryan_chen 		return ret;
1859499853d6Sryan_chen 
1860499853d6Sryan_chen 	priv->regs = (void __iomem *)res_regs.start;
1861499853d6Sryan_chen 
1862499853d6Sryan_chen 	ret = dev_read_resource(bus, 1, &res_ahb);
1863499853d6Sryan_chen 	if (ret < 0)
1864499853d6Sryan_chen 		return ret;
1865499853d6Sryan_chen 
1866499853d6Sryan_chen 	priv->ahb_base = (void __iomem *)res_ahb.start;
1867742f43eeSChin-Ting Kuo 	priv->ahb_size = res_ahb.end - res_ahb.start + 1;
1868499853d6Sryan_chen 
1869499853d6Sryan_chen 	ret = clk_get_by_index(bus, 0, &hclk);
1870499853d6Sryan_chen 	if (ret < 0) {
1871499853d6Sryan_chen 		pr_err("%s could not get clock: %d\n", bus->name, ret);
1872499853d6Sryan_chen 		return ret;
1873499853d6Sryan_chen 	}
1874499853d6Sryan_chen 
1875499853d6Sryan_chen 	priv->hclk_rate = clk_get_rate(&hclk);
1876499853d6Sryan_chen 	clk_free(&hclk);
1877499853d6Sryan_chen 
1878499853d6Sryan_chen 	priv->num_cs = dev_read_u32_default(bus, "num-cs", ASPEED_SPI_MAX_CS);
1879499853d6Sryan_chen 
1880499853d6Sryan_chen 	priv->flash_count = aspeed_spi_count_flash_devices(bus);
1881499853d6Sryan_chen 	if (priv->flash_count > priv->num_cs) {
1882499853d6Sryan_chen 		pr_err("%s has too many flash devices: %d\n", bus->name,
1883499853d6Sryan_chen 		       priv->flash_count);
1884499853d6Sryan_chen 		return -EINVAL;
1885499853d6Sryan_chen 	}
1886499853d6Sryan_chen 
1887499853d6Sryan_chen 	if (!priv->flash_count) {
1888499853d6Sryan_chen 		pr_err("%s has no flash devices ?!\n", bus->name);
1889499853d6Sryan_chen 		return -ENODEV;
1890499853d6Sryan_chen 	}
1891499853d6Sryan_chen 
18927d182336Sryan_chen 	if (device_is_compatible(bus, "aspeed,ast2600-fmc") ||
1893f87fadc3Sryan_chen 			device_is_compatible(bus, "aspeed,ast2600-spi")) {
1894499853d6Sryan_chen 		priv->new_ver = 1;
1895499853d6Sryan_chen 	}
1896499853d6Sryan_chen 
1897bbe907dbSChin-Ting Kuo 	if (dev_read_bool(bus, "aspeed-spi-command-mode")) {
1898bbe907dbSChin-Ting Kuo 		debug("adopt command mode\n");
1899bbe907dbSChin-Ting Kuo 		priv->tmp_buf = memalign(4, 512);
1900bbe907dbSChin-Ting Kuo 		priv->spi_exec_op_cmd = aspeed_spi_exec_op_cmd_mode;
1901bbe907dbSChin-Ting Kuo 	} else {
1902bbe907dbSChin-Ting Kuo 		priv->spi_exec_op_cmd = NULL;
1903bbe907dbSChin-Ting Kuo 	}
1904bbe907dbSChin-Ting Kuo 
1905499853d6Sryan_chen 	/*
1906499853d6Sryan_chen 	 * There are some slight differences between the FMC and the
1907499853d6Sryan_chen 	 * SPI controllers
1908499853d6Sryan_chen 	 */
1909499853d6Sryan_chen 	priv->is_fmc = dev_get_driver_data(bus);
1910499853d6Sryan_chen 
1911499853d6Sryan_chen 	ret = aspeed_spi_controller_init(priv);
1912499853d6Sryan_chen 	if (ret)
1913499853d6Sryan_chen 		return ret;
1914499853d6Sryan_chen 
1915edaef9d2SChin-Ting Kuo 	debug("%s probed regs=%p ahb_base=%p cs_num=%d seq=%d\n",
1916edaef9d2SChin-Ting Kuo 	      bus->name, priv->regs, priv->ahb_base, priv->flash_count, bus->seq);
1917499853d6Sryan_chen 
1918499853d6Sryan_chen 	return 0;
1919499853d6Sryan_chen }
1920499853d6Sryan_chen 
1921499853d6Sryan_chen static const struct dm_spi_ops aspeed_spi_ops = {
1922499853d6Sryan_chen 	.claim_bus	= aspeed_spi_claim_bus,
1923499853d6Sryan_chen 	.release_bus	= aspeed_spi_release_bus,
1924499853d6Sryan_chen 	.set_mode	= aspeed_spi_set_mode,
1925499853d6Sryan_chen 	.set_speed	= aspeed_spi_set_speed,
1926499853d6Sryan_chen 	.xfer		= aspeed_spi_xfer,
1927591e1cf0SChin-Ting Kuo #ifdef CONFIG_ASPEED_SPI_FLASH_WRITE_PROTECTION
1928591e1cf0SChin-Ting Kuo 	.mem_ctrl_wlock = aspeed_spi_mem_wlock,
1929591e1cf0SChin-Ting Kuo 	.mem_ctrl_wunlock = aspeed_spi_mem_wunlock,
1930591e1cf0SChin-Ting Kuo #endif
1931499853d6Sryan_chen };
1932499853d6Sryan_chen 
1933499853d6Sryan_chen static const struct udevice_id aspeed_spi_ids[] = {
1934499853d6Sryan_chen 	{ .compatible = "aspeed,ast2600-fmc", .data = 1 },
1935499853d6Sryan_chen 	{ .compatible = "aspeed,ast2600-spi", .data = 0 },
1936499853d6Sryan_chen 	{ .compatible = "aspeed,ast2500-fmc", .data = 1 },
1937499853d6Sryan_chen 	{ .compatible = "aspeed,ast2500-spi", .data = 0 },
1938c4475966Sryan_chen 	{ .compatible = "aspeed,ast2400-fmc", .data = 1 },
1939499853d6Sryan_chen 	{ }
1940499853d6Sryan_chen };
1941499853d6Sryan_chen 
1942499853d6Sryan_chen U_BOOT_DRIVER(aspeed_spi) = {
1943499853d6Sryan_chen 	.name = "aspeed_spi",
1944499853d6Sryan_chen 	.id = UCLASS_SPI,
1945499853d6Sryan_chen 	.of_match = aspeed_spi_ids,
1946499853d6Sryan_chen 	.ops = &aspeed_spi_ops,
1947499853d6Sryan_chen 	.priv_auto_alloc_size = sizeof(struct aspeed_spi_priv),
1948499853d6Sryan_chen 	.child_pre_probe = aspeed_spi_child_pre_probe,
1949499853d6Sryan_chen 	.bind  = aspeed_spi_bind,
1950499853d6Sryan_chen 	.probe = aspeed_spi_probe,
1951499853d6Sryan_chen };
1952