xref: /openbmc/u-boot/drivers/spi/aspeed_spi.c (revision b679b8ad)
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>
17499853d6Sryan_chen 
18499853d6Sryan_chen #define ASPEED_SPI_MAX_CS		3
19beec505fSChin-Ting Kuo #define FLASH_CALIBRATION_LEN   0x400
20499853d6Sryan_chen 
21499853d6Sryan_chen struct aspeed_spi_regs {
22499853d6Sryan_chen 	u32 conf;			/* 0x00 CE Type Setting */
23499853d6Sryan_chen 	u32 ctrl;			/* 0x04 Control */
24499853d6Sryan_chen 	u32 intr_ctrl;			/* 0x08 Interrupt Control and Status */
25499853d6Sryan_chen 	u32 cmd_ctrl;			/* 0x0c Command Control */
26499853d6Sryan_chen 	u32 ce_ctrl[ASPEED_SPI_MAX_CS];	/* 0x10 .. 0x18 CEx Control */
27499853d6Sryan_chen 	u32 _reserved0[5];		/* .. */
28499853d6Sryan_chen 	u32 segment_addr[ASPEED_SPI_MAX_CS];
29499853d6Sryan_chen 					/* 0x30 .. 0x38 Segment Address */
300a73b911SChin-Ting Kuo 	u32 _reserved1[5];		/* .. */
310a73b911SChin-Ting Kuo 	u32 soft_rst_cmd_ctrl;	/* 0x50 Auto Soft-Reset Command Control */
320a73b911SChin-Ting Kuo 	u32 _reserved2[11];		/* .. */
33499853d6Sryan_chen 	u32 dma_ctrl;			/* 0x80 DMA Control/Status */
34499853d6Sryan_chen 	u32 dma_flash_addr;		/* 0x84 DMA Flash Side Address */
35499853d6Sryan_chen 	u32 dma_dram_addr;		/* 0x88 DMA DRAM Side Address */
36499853d6Sryan_chen 	u32 dma_len;			/* 0x8c DMA Length Register */
37499853d6Sryan_chen 	u32 dma_checksum;		/* 0x90 Checksum Calculation Result */
38499853d6Sryan_chen 	u32 timings;			/* 0x94 Read Timing Compensation */
39499853d6Sryan_chen 
40499853d6Sryan_chen 	/* not used */
41499853d6Sryan_chen 	u32 soft_strap_status;		/* 0x9c Software Strap Status */
42499853d6Sryan_chen 	u32 write_cmd_filter_ctrl;	/* 0xa0 Write Command Filter Control */
43499853d6Sryan_chen 	u32 write_addr_filter_ctrl;	/* 0xa4 Write Address Filter Control */
44499853d6Sryan_chen 	u32 lock_ctrl_reset;		/* 0xa8 Lock Control (SRST#) */
45499853d6Sryan_chen 	u32 lock_ctrl_wdt;		/* 0xac Lock Control (Watchdog) */
46499853d6Sryan_chen 	u32 write_addr_filter[5];	/* 0xb0 Write Address Filter */
47499853d6Sryan_chen };
48499853d6Sryan_chen 
49499853d6Sryan_chen /* CE Type Setting Register */
50499853d6Sryan_chen #define CONF_ENABLE_W2			BIT(18)
51499853d6Sryan_chen #define CONF_ENABLE_W1			BIT(17)
52499853d6Sryan_chen #define CONF_ENABLE_W0			BIT(16)
53499853d6Sryan_chen #define CONF_FLASH_TYPE2		4
54499853d6Sryan_chen #define CONF_FLASH_TYPE1		2	/* Hardwired to SPI */
55499853d6Sryan_chen #define CONF_FLASH_TYPE0		0	/* Hardwired to SPI */
56499853d6Sryan_chen #define	  CONF_FLASH_TYPE_NOR		0x0
57499853d6Sryan_chen #define	  CONF_FLASH_TYPE_SPI		0x2
58499853d6Sryan_chen 
59499853d6Sryan_chen /* CE Control Register */
60499853d6Sryan_chen #define CTRL_EXTENDED2			BIT(2)	/* 32 bit addressing for SPI */
61499853d6Sryan_chen #define CTRL_EXTENDED1			BIT(1)	/* 32 bit addressing for SPI */
62499853d6Sryan_chen #define CTRL_EXTENDED0			BIT(0)	/* 32 bit addressing for SPI */
63499853d6Sryan_chen 
64499853d6Sryan_chen /* Interrupt Control and Status Register */
65499853d6Sryan_chen #define INTR_CTRL_DMA_STATUS		BIT(11)
66499853d6Sryan_chen #define INTR_CTRL_CMD_ABORT_STATUS	BIT(10)
67499853d6Sryan_chen #define INTR_CTRL_WRITE_PROTECT_STATUS	BIT(9)
68499853d6Sryan_chen #define INTR_CTRL_DMA_EN		BIT(3)
69499853d6Sryan_chen #define INTR_CTRL_CMD_ABORT_EN		BIT(2)
70499853d6Sryan_chen #define INTR_CTRL_WRITE_PROTECT_EN	BIT(1)
71499853d6Sryan_chen 
72499853d6Sryan_chen /* CEx Control Register */
73499853d6Sryan_chen #define CE_CTRL_IO_MODE_MASK		GENMASK(31, 28)
7476e3c7a9Sryan_chen #define CE_CTRL_IO_QPI_DATA			BIT(31)
75499853d6Sryan_chen #define CE_CTRL_IO_DUAL_DATA		BIT(29)
76cd800046SChin-Ting Kuo #define CE_CTRL_IO_SINGLE			0
77499853d6Sryan_chen #define CE_CTRL_IO_DUAL_ADDR_DATA	(BIT(29) | BIT(28))
78499853d6Sryan_chen #define CE_CTRL_IO_QUAD_DATA		BIT(30)
79499853d6Sryan_chen #define CE_CTRL_IO_QUAD_ADDR_DATA	(BIT(30) | BIT(28))
80499853d6Sryan_chen #define CE_CTRL_CMD_SHIFT		16
81499853d6Sryan_chen #define CE_CTRL_CMD_MASK		0xff
82499853d6Sryan_chen #define CE_CTRL_CMD(cmd)					\
83499853d6Sryan_chen 	(((cmd) & CE_CTRL_CMD_MASK) << CE_CTRL_CMD_SHIFT)
84499853d6Sryan_chen #define CE_CTRL_DUMMY_HIGH_SHIFT	14
85499853d6Sryan_chen #define CE_CTRL_DUMMY_HIGH_MASK		0x1
86499853d6Sryan_chen #define CE_CTRL_CLOCK_FREQ_SHIFT	8
87499853d6Sryan_chen #define CE_CTRL_CLOCK_FREQ_MASK		0xf
88499853d6Sryan_chen #define CE_CTRL_CLOCK_FREQ(div)						\
89499853d6Sryan_chen 	(((div) & CE_CTRL_CLOCK_FREQ_MASK) << CE_CTRL_CLOCK_FREQ_SHIFT)
907d182336Sryan_chen #define CE_G6_CTRL_CLOCK_FREQ(div)						\
917d182336Sryan_chen 	((((div) & CE_CTRL_CLOCK_FREQ_MASK) << CE_CTRL_CLOCK_FREQ_SHIFT) | (((div) & 0xf0) << 20))
92499853d6Sryan_chen #define CE_CTRL_DUMMY_LOW_SHIFT		6 /* 2 bits [7:6] */
93499853d6Sryan_chen #define CE_CTRL_DUMMY_LOW_MASK		0x3
94499853d6Sryan_chen #define CE_CTRL_DUMMY(dummy)						\
95499853d6Sryan_chen 	(((((dummy) >> 2) & CE_CTRL_DUMMY_HIGH_MASK)			\
96499853d6Sryan_chen 	  << CE_CTRL_DUMMY_HIGH_SHIFT) |				\
97499853d6Sryan_chen 	 (((dummy) & CE_CTRL_DUMMY_LOW_MASK) << CE_CTRL_DUMMY_LOW_SHIFT))
98499853d6Sryan_chen #define CE_CTRL_STOP_ACTIVE		BIT(2)
99499853d6Sryan_chen #define CE_CTRL_MODE_MASK		0x3
100499853d6Sryan_chen #define	  CE_CTRL_READMODE		0x0
101499853d6Sryan_chen #define	  CE_CTRL_FREADMODE		0x1
102499853d6Sryan_chen #define	  CE_CTRL_WRITEMODE		0x2
103499853d6Sryan_chen #define	  CE_CTRL_USERMODE		0x3
104499853d6Sryan_chen 
105cd800046SChin-Ting Kuo #define SPI_READ_FROM_FLASH		0x00000001
106cd800046SChin-Ting Kuo #define SPI_WRITE_TO_FLASH		0x00000002
107cd800046SChin-Ting Kuo 
1080a73b911SChin-Ting Kuo /* Auto Soft-Reset Command Control */
1090a73b911SChin-Ting Kuo #define SOFT_RST_CMD_EN     GENMASK(1, 0)
1100a73b911SChin-Ting Kuo 
111499853d6Sryan_chen /*
112499853d6Sryan_chen  * The Segment Register uses a 8MB unit to encode the start address
113499853d6Sryan_chen  * and the end address of the AHB window of a SPI flash device.
114499853d6Sryan_chen  * Default segment addresses are :
115499853d6Sryan_chen  *
116499853d6Sryan_chen  *   CE0  0x20000000 - 0x2fffffff  128MB
117499853d6Sryan_chen  *   CE1  0x28000000 - 0x29ffffff   32MB
118499853d6Sryan_chen  *   CE2  0x2a000000 - 0x2bffffff   32MB
119499853d6Sryan_chen  *
120499853d6Sryan_chen  * The full address space of the AHB window of the controller is
121499853d6Sryan_chen  * covered and CE0 start address and CE2 end addresses are read-only.
122499853d6Sryan_chen  */
123499853d6Sryan_chen #define SEGMENT_ADDR_START(reg)		((((reg) >> 16) & 0xff) << 23)
124499853d6Sryan_chen #define SEGMENT_ADDR_END(reg)		((((reg) >> 24) & 0xff) << 23)
125499853d6Sryan_chen #define SEGMENT_ADDR_VALUE(start, end)					\
126499853d6Sryan_chen 	(((((start) >> 23) & 0xff) << 16) | ((((end) >> 23) & 0xff) << 24))
127499853d6Sryan_chen 
128da83dd7eSryan_chen #define G6_SEGMENT_ADDR_START(reg)		(reg & 0xffff)
129da83dd7eSryan_chen #define G6_SEGMENT_ADDR_END(reg)		((reg >> 16) & 0xffff)
130da83dd7eSryan_chen #define G6_SEGMENT_ADDR_VALUE(start, end)					\
1316167da3dSryan_chen 	((((start) >> 16) & 0xffff) | (((end) - 0x100000) & 0xffff0000))
132da83dd7eSryan_chen 
133499853d6Sryan_chen /* DMA Control/Status Register */
134499853d6Sryan_chen #define DMA_CTRL_DELAY_SHIFT		8
135499853d6Sryan_chen #define DMA_CTRL_DELAY_MASK		0xf
136beec505fSChin-Ting Kuo #define G6_DMA_CTRL_DELAY_MASK		0xff
137499853d6Sryan_chen #define DMA_CTRL_FREQ_SHIFT		4
138f87fadc3Sryan_chen #define G6_DMA_CTRL_FREQ_SHIFT		16
139f87fadc3Sryan_chen 
140499853d6Sryan_chen #define DMA_CTRL_FREQ_MASK		0xf
141499853d6Sryan_chen #define TIMING_MASK(div, delay)					   \
142499853d6Sryan_chen 	(((delay & DMA_CTRL_DELAY_MASK) << DMA_CTRL_DELAY_SHIFT) | \
143499853d6Sryan_chen 	 ((div & DMA_CTRL_FREQ_MASK) << DMA_CTRL_FREQ_SHIFT))
144f87fadc3Sryan_chen #define G6_TIMING_MASK(div, delay)					   \
145beec505fSChin-Ting Kuo 	(((delay & G6_DMA_CTRL_DELAY_MASK) << DMA_CTRL_DELAY_SHIFT) | \
146f87fadc3Sryan_chen 	 ((div & DMA_CTRL_FREQ_MASK) << G6_DMA_CTRL_FREQ_SHIFT))
147499853d6Sryan_chen #define DMA_CTRL_CALIB			BIT(3)
148499853d6Sryan_chen #define DMA_CTRL_CKSUM			BIT(2)
149499853d6Sryan_chen #define DMA_CTRL_WRITE			BIT(1)
150499853d6Sryan_chen #define DMA_CTRL_ENABLE			BIT(0)
151499853d6Sryan_chen 
1520a73b911SChin-Ting Kuo /* for ast2600 setting */
1530a73b911SChin-Ting Kuo #define SPI_3B_AUTO_CLR_REG   0x1e6e2510
1540a73b911SChin-Ting Kuo #define SPI_3B_AUTO_CLR       BIT(9)
1550a73b911SChin-Ting Kuo 
1560a73b911SChin-Ting Kuo 
157499853d6Sryan_chen /*
1580a73b911SChin-Ting Kuo  * flash related info
159499853d6Sryan_chen  */
160499853d6Sryan_chen struct aspeed_spi_flash {
161499853d6Sryan_chen 	u8		cs;
162499853d6Sryan_chen 	bool		init;		/* Initialized when the SPI bus is
163499853d6Sryan_chen 					 * first claimed
164499853d6Sryan_chen 					 */
165499853d6Sryan_chen 	void __iomem	*ahb_base;	/* AHB Window for this device */
166499853d6Sryan_chen 	u32		ahb_size;	/* AHB Window segment size */
167499853d6Sryan_chen 	u32		ce_ctrl_user;	/* CE Control Register for USER mode */
168499853d6Sryan_chen 	u32		ce_ctrl_fread;	/* CE Control Register for FREAD mode */
169cd800046SChin-Ting Kuo 	u32 	read_iomode;
170cd800046SChin-Ting Kuo 	u32 	write_iomode;
171499853d6Sryan_chen 
172499853d6Sryan_chen 	struct spi_flash *spi;		/* Associated SPI Flash device */
173499853d6Sryan_chen };
174499853d6Sryan_chen 
175499853d6Sryan_chen struct aspeed_spi_priv {
176499853d6Sryan_chen 	struct aspeed_spi_regs	*regs;
177499853d6Sryan_chen 	void __iomem	*ahb_base;	/* AHB Window for all flash devices */
178499853d6Sryan_chen 	int new_ver;
179499853d6Sryan_chen 	u32		ahb_size;	/* AHB Window segments size */
180499853d6Sryan_chen 
181499853d6Sryan_chen 	ulong		hclk_rate;	/* AHB clock rate */
182499853d6Sryan_chen 	u32		max_hz;
183499853d6Sryan_chen 	u8		num_cs;
184499853d6Sryan_chen 	bool		is_fmc;
185499853d6Sryan_chen 
186499853d6Sryan_chen 	struct aspeed_spi_flash flashes[ASPEED_SPI_MAX_CS];
187499853d6Sryan_chen 	u32		flash_count;
188499853d6Sryan_chen 
189499853d6Sryan_chen 	u8		cmd_buf[16];	/* SPI command in progress */
190499853d6Sryan_chen 	size_t		cmd_len;
191499853d6Sryan_chen };
192499853d6Sryan_chen 
193499853d6Sryan_chen static struct aspeed_spi_flash *aspeed_spi_get_flash(struct udevice *dev)
194499853d6Sryan_chen {
195499853d6Sryan_chen 	struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
196499853d6Sryan_chen 	struct aspeed_spi_priv *priv = dev_get_priv(dev->parent);
197499853d6Sryan_chen 	u8 cs = slave_plat->cs;
198499853d6Sryan_chen 
199499853d6Sryan_chen 	if (cs >= priv->flash_count) {
200499853d6Sryan_chen 		pr_err("invalid CS %u\n", cs);
201499853d6Sryan_chen 		return NULL;
202499853d6Sryan_chen 	}
203499853d6Sryan_chen 
204499853d6Sryan_chen 	return &priv->flashes[cs];
205499853d6Sryan_chen }
206499853d6Sryan_chen 
207ac86fa8bSryan_chen static u32 aspeed_g6_spi_hclk_divisor(struct aspeed_spi_priv *priv, u32 max_hz)
208499853d6Sryan_chen {
2097d182336Sryan_chen 	u32 hclk_rate = priv->hclk_rate;
210499853d6Sryan_chen 	/* HCLK/1 ..	HCLK/16 */
211499853d6Sryan_chen 	const u8 hclk_masks[] = {
212499853d6Sryan_chen 		15, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 0
213499853d6Sryan_chen 	};
2147d182336Sryan_chen 	u8 base_div = 0;
215f87fadc3Sryan_chen 	int done = 0;
216f87fadc3Sryan_chen 	u32 i, j = 0;
2177d182336Sryan_chen 	u32 hclk_div_setting = 0;
218499853d6Sryan_chen 
219f87fadc3Sryan_chen 	for (j = 0; j < 0xf; i++) {
2207d182336Sryan_chen 		for (i = 0; i < ARRAY_SIZE(hclk_masks); i++) {
2217d182336Sryan_chen 			base_div = j * 16;
222f87fadc3Sryan_chen 			if (max_hz >= (hclk_rate / ((i + 1) + base_div))) {
223f87fadc3Sryan_chen 
224f87fadc3Sryan_chen 				done = 1;
2257d182336Sryan_chen 				break;
2267d182336Sryan_chen 			}
2277d182336Sryan_chen 		}
228f87fadc3Sryan_chen 			if (done)
229f87fadc3Sryan_chen 				break;
2307d182336Sryan_chen 	}
231499853d6Sryan_chen 
232f87fadc3Sryan_chen 	debug("hclk=%d required=%d h_div %d, divisor is %d (mask %x) speed=%d\n",
233f87fadc3Sryan_chen 		  hclk_rate, max_hz, j, i + 1, hclk_masks[i], hclk_rate / (i + 1 + base_div));
2347d182336Sryan_chen 
2357d182336Sryan_chen 	hclk_div_setting = ((j << 4) | hclk_masks[i]);
2367d182336Sryan_chen 
237ac86fa8bSryan_chen 	return hclk_div_setting;
238ac86fa8bSryan_chen 
239ac86fa8bSryan_chen }
240ac86fa8bSryan_chen 
241ac86fa8bSryan_chen static u32 aspeed_spi_hclk_divisor(struct aspeed_spi_priv *priv, u32 max_hz)
242ac86fa8bSryan_chen {
243ac86fa8bSryan_chen 	u32 hclk_rate = priv->hclk_rate;
244ac86fa8bSryan_chen 	/* HCLK/1 ..	HCLK/16 */
245ac86fa8bSryan_chen 	const u8 hclk_masks[] = {
246ac86fa8bSryan_chen 		15, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 0
247ac86fa8bSryan_chen 	};
248d32338fdSryan_chen 	u32 i;
249ac86fa8bSryan_chen 	u32 hclk_div_setting = 0;
250ac86fa8bSryan_chen 
251499853d6Sryan_chen 	for (i = 0; i < ARRAY_SIZE(hclk_masks); i++) {
252499853d6Sryan_chen 		if (max_hz >= (hclk_rate / (i + 1)))
253499853d6Sryan_chen 			break;
254499853d6Sryan_chen 	}
255499853d6Sryan_chen 	debug("hclk=%d required=%d divisor is %d (mask %x) speed=%d\n",
256499853d6Sryan_chen 	      hclk_rate, max_hz, i + 1, hclk_masks[i], hclk_rate / (i + 1));
257499853d6Sryan_chen 
2587d182336Sryan_chen 	hclk_div_setting = hclk_masks[i];
2597d182336Sryan_chen 
2607d182336Sryan_chen 	return hclk_div_setting;
261499853d6Sryan_chen }
262499853d6Sryan_chen 
263499853d6Sryan_chen /*
264499853d6Sryan_chen  * Use some address/size under the first flash device CE0
265499853d6Sryan_chen  */
266499853d6Sryan_chen static u32 aspeed_spi_fmc_checksum(struct aspeed_spi_priv *priv, u8 div,
267499853d6Sryan_chen 				   u8 delay)
268499853d6Sryan_chen {
269499853d6Sryan_chen 	u32 flash_addr = (u32)priv->ahb_base + 0x10000;
270beec505fSChin-Ting Kuo 	u32 flash_len = FLASH_CALIBRATION_LEN;
271499853d6Sryan_chen 	u32 dma_ctrl;
272499853d6Sryan_chen 	u32 checksum;
273499853d6Sryan_chen 
274499853d6Sryan_chen 	writel(flash_addr, &priv->regs->dma_flash_addr);
275499853d6Sryan_chen 	writel(flash_len,  &priv->regs->dma_len);
276499853d6Sryan_chen 
277499853d6Sryan_chen 	/*
278499853d6Sryan_chen 	 * When doing calibration, the SPI clock rate in the CE0
279499853d6Sryan_chen 	 * Control Register and the data input delay cycles in the
280499853d6Sryan_chen 	 * Read Timing Compensation Register are replaced by bit[11:4].
281499853d6Sryan_chen 	 */
282f87fadc3Sryan_chen 	if(priv->new_ver)
283f87fadc3Sryan_chen 		dma_ctrl = DMA_CTRL_ENABLE | DMA_CTRL_CKSUM | DMA_CTRL_CALIB |
284f87fadc3Sryan_chen 			G6_TIMING_MASK(div, delay);
285f87fadc3Sryan_chen 	else
286499853d6Sryan_chen 		dma_ctrl = DMA_CTRL_ENABLE | DMA_CTRL_CKSUM | DMA_CTRL_CALIB |
287499853d6Sryan_chen 			TIMING_MASK(div, delay);
288499853d6Sryan_chen 	writel(dma_ctrl, &priv->regs->dma_ctrl);
289499853d6Sryan_chen 	while (!(readl(&priv->regs->intr_ctrl) & INTR_CTRL_DMA_STATUS))
290499853d6Sryan_chen 		;
291499853d6Sryan_chen 
292499853d6Sryan_chen 	writel(0x0, &priv->regs->intr_ctrl);
293499853d6Sryan_chen 
294499853d6Sryan_chen 	checksum = readl(&priv->regs->dma_checksum);
295499853d6Sryan_chen 
296499853d6Sryan_chen 	writel(0x0, &priv->regs->dma_ctrl);
297499853d6Sryan_chen 	return checksum;
298499853d6Sryan_chen }
299499853d6Sryan_chen 
300499853d6Sryan_chen static u32 aspeed_spi_read_checksum(struct aspeed_spi_priv *priv, u8 div,
301499853d6Sryan_chen 				    u8 delay)
302499853d6Sryan_chen {
303499853d6Sryan_chen 	/* TODO(clg@kaod.org): the SPI controllers do not have the DMA
304499853d6Sryan_chen 	 * registers. The algorithm is the same.
305499853d6Sryan_chen 	 */
306499853d6Sryan_chen 	if (!priv->is_fmc) {
307499853d6Sryan_chen 		pr_warn("No timing calibration support for SPI controllers");
308499853d6Sryan_chen 		return 0xbadc0de;
309499853d6Sryan_chen 	}
310499853d6Sryan_chen 
311499853d6Sryan_chen 	return aspeed_spi_fmc_checksum(priv, div, delay);
312499853d6Sryan_chen }
313499853d6Sryan_chen 
314499853d6Sryan_chen #define TIMING_DELAY_DI_4NS         BIT(3)
315499853d6Sryan_chen #define TIMING_DELAY_HCYCLE_MAX     5
316499853d6Sryan_chen 
317499853d6Sryan_chen static int aspeed_spi_timing_calibration(struct aspeed_spi_priv *priv)
318499853d6Sryan_chen {
319499853d6Sryan_chen 	/* HCLK/5 .. HCLK/1 */
320499853d6Sryan_chen 	const u8 hclk_masks[] = {13, 6, 14, 7, 15};
321beec505fSChin-Ting Kuo 	u32 timing_reg;
322499853d6Sryan_chen 	u32 checksum, gold_checksum;
323f87fadc3Sryan_chen 	int i, hcycle, delay_ns;
324beec505fSChin-Ting Kuo 
325beec505fSChin-Ting Kuo 	/* Use the ctrl setting in aspeed_spi_flash_init() to
326beec505fSChin-Ting Kuo 	 * implement calibration process.
327beec505fSChin-Ting Kuo 	 */
328beec505fSChin-Ting Kuo 	timing_reg = readl(&priv->regs->timings);
329beec505fSChin-Ting Kuo 	if (timing_reg != 0)
330beec505fSChin-Ting Kuo 		return 0;
331499853d6Sryan_chen 
332499853d6Sryan_chen 	debug("Read timing calibration :\n");
333499853d6Sryan_chen 
334499853d6Sryan_chen 	/* Compute reference checksum at lowest freq HCLK/16 */
335499853d6Sryan_chen 	gold_checksum = aspeed_spi_read_checksum(priv, 0, 0);
336499853d6Sryan_chen 
337499853d6Sryan_chen 	/* Increase HCLK freq */
3387d182336Sryan_chen 	if (priv->new_ver) {
3397d182336Sryan_chen 		for (i = 0; i < ARRAY_SIZE(hclk_masks) - 1; i++) {
3407d182336Sryan_chen 			u32 hdiv = 5 - i;
341f87fadc3Sryan_chen 			u32 hshift = (hdiv - 2) * 8;
3427d182336Sryan_chen 			bool pass = false;
3437d182336Sryan_chen 			u8 delay;
344f87fadc3Sryan_chen 			u16 first_delay = 0;
345f87fadc3Sryan_chen 			u16 end_delay = 0;
346f87fadc3Sryan_chen 			u32 cal_tmp;
347beec505fSChin-Ting Kuo 			u32 max_window_sz = 0;
348beec505fSChin-Ting Kuo 			u32 cur_window_sz = 0;
349beec505fSChin-Ting Kuo 			u32 tmp_delay;
350beec505fSChin-Ting Kuo 
351f87fadc3Sryan_chen 			debug("hdiv %d, hshift %d\n", hdiv, hshift);
3527d182336Sryan_chen 			if (priv->hclk_rate / hdiv > priv->max_hz) {
3537d182336Sryan_chen 				debug("skipping freq %ld\n", priv->hclk_rate / hdiv);
3547d182336Sryan_chen 				continue;
3557d182336Sryan_chen 			}
3567d182336Sryan_chen 
3577d182336Sryan_chen 			/* Try without the 4ns DI delay */
358f87fadc3Sryan_chen 			hcycle = delay = 0;
359f87fadc3Sryan_chen 			debug("** Dealy Disable **\n");
360f87fadc3Sryan_chen 			checksum = aspeed_spi_read_checksum(priv, hclk_masks[i], delay);
3617d182336Sryan_chen 			pass = (checksum == gold_checksum);
362d32338fdSryan_chen 			debug("HCLK/%d, no DI delay, %d HCLK cycle : %s\n",
3637d182336Sryan_chen 				  hdiv, hcycle, pass ? "PASS" : "FAIL");
3647d182336Sryan_chen 
3657d182336Sryan_chen 			/* All good for this freq  */
3667d182336Sryan_chen 			if (pass)
367f87fadc3Sryan_chen 				goto next_div;
368f87fadc3Sryan_chen 
369beec505fSChin-Ting Kuo 			/* Try each hcycle delay */
370f87fadc3Sryan_chen 			for (hcycle = 0; hcycle <= TIMING_DELAY_HCYCLE_MAX; hcycle++) {
371beec505fSChin-Ting Kuo 				/* Increase DI delay by the step of 0.5ns */
372f87fadc3Sryan_chen 				debug("** Delay Enable : hcycle %x ** \n", hcycle);
373f87fadc3Sryan_chen 				for (delay_ns = 0; delay_ns < 0xf; delay_ns++) {
374beec505fSChin-Ting Kuo 					tmp_delay = TIMING_DELAY_DI_4NS | hcycle | (delay_ns << 4);
375f87fadc3Sryan_chen 					checksum = aspeed_spi_read_checksum(priv, hclk_masks[i],
376beec505fSChin-Ting Kuo 									    tmp_delay);
377f87fadc3Sryan_chen 					pass = (checksum == gold_checksum);
378beec505fSChin-Ting Kuo 					debug("HCLK/%d, DI delay, %d HCLK cycle, %d delay_ns : %s\n",
379f87fadc3Sryan_chen 					      hdiv, hcycle, delay_ns, pass ? "PASS" : "FAIL");
380f87fadc3Sryan_chen 
381f87fadc3Sryan_chen 					if (!pass) {
382f87fadc3Sryan_chen 						if (!first_delay)
383f87fadc3Sryan_chen 							continue;
384f87fadc3Sryan_chen 						else {
385f87fadc3Sryan_chen 							end_delay = (hcycle << 4) | (delay_ns);
386f87fadc3Sryan_chen 							end_delay = end_delay - 1;
387beec505fSChin-Ting Kuo 							/* Larger window size is found */
388beec505fSChin-Ting Kuo 							if (cur_window_sz > max_window_sz) {
389beec505fSChin-Ting Kuo 								max_window_sz = cur_window_sz;
390beec505fSChin-Ting Kuo 								cal_tmp = (first_delay + end_delay) / 2;
391beec505fSChin-Ting Kuo 								delay = TIMING_DELAY_DI_4NS |
392beec505fSChin-Ting Kuo 										((cal_tmp & 0xf) << 4) |
393beec505fSChin-Ting Kuo 										(cal_tmp >> 4);
394beec505fSChin-Ting Kuo 							}
395beec505fSChin-Ting Kuo 							debug("find end_delay %x %d %d\n", end_delay,
396beec505fSChin-Ting Kuo 									hcycle, delay_ns);
397beec505fSChin-Ting Kuo 
398beec505fSChin-Ting Kuo 							first_delay = 0;
399beec505fSChin-Ting Kuo 							end_delay = 0;
400beec505fSChin-Ting Kuo 							cur_window_sz = 0;
401beec505fSChin-Ting Kuo 
4027d182336Sryan_chen 							break;
4037d182336Sryan_chen 						}
404f87fadc3Sryan_chen 					} else {
405f87fadc3Sryan_chen 						if (!first_delay) {
406f87fadc3Sryan_chen 							first_delay = (hcycle << 4) | delay_ns;
407f87fadc3Sryan_chen 							debug("find first_delay %x %d %d\n", first_delay, hcycle, delay_ns);
408f87fadc3Sryan_chen 						}
409beec505fSChin-Ting Kuo 						/* Record current pass window size */
410beec505fSChin-Ting Kuo 						cur_window_sz++;
411beec505fSChin-Ting Kuo 					}
412f87fadc3Sryan_chen 				}
413f87fadc3Sryan_chen 			}
4147d182336Sryan_chen 
4157d182336Sryan_chen 			if (pass) {
416beec505fSChin-Ting Kuo 				if (cur_window_sz > max_window_sz) {
417beec505fSChin-Ting Kuo 					max_window_sz = cur_window_sz;
418beec505fSChin-Ting Kuo 					end_delay = ((hcycle - 1) << 4) | (delay_ns - 1);
419f87fadc3Sryan_chen 					cal_tmp = (first_delay + end_delay) / 2;
420beec505fSChin-Ting Kuo 					delay = TIMING_DELAY_DI_4NS |
421beec505fSChin-Ting Kuo 							((cal_tmp & 0xf) << 4) |
422beec505fSChin-Ting Kuo 							(cal_tmp >> 4);
423f87fadc3Sryan_chen 				}
424f87fadc3Sryan_chen 			}
425f87fadc3Sryan_chen next_div:
4267d182336Sryan_chen 			timing_reg &= ~(0xfu << hshift);
4277d182336Sryan_chen 			timing_reg |= delay << hshift;
428f87fadc3Sryan_chen 			debug("timing_reg %x, delay %x, hshift bit %d\n",timing_reg, delay, hshift);
4297d182336Sryan_chen 		}
4307d182336Sryan_chen 	} else {
431499853d6Sryan_chen 		for (i = 0; i < ARRAY_SIZE(hclk_masks); i++) {
432499853d6Sryan_chen 			u32 hdiv = 5 - i;
433499853d6Sryan_chen 			u32 hshift = (hdiv - 1) << 2;
434499853d6Sryan_chen 			bool pass = false;
435499853d6Sryan_chen 			u8 delay;
436499853d6Sryan_chen 
437499853d6Sryan_chen 			if (priv->hclk_rate / hdiv > priv->max_hz) {
438499853d6Sryan_chen 				debug("skipping freq %ld\n", priv->hclk_rate / hdiv);
439499853d6Sryan_chen 				continue;
440499853d6Sryan_chen 			}
441499853d6Sryan_chen 
442499853d6Sryan_chen 			/* Increase HCLK cycles until read succeeds */
443499853d6Sryan_chen 			for (hcycle = 0; hcycle <= TIMING_DELAY_HCYCLE_MAX; hcycle++) {
444499853d6Sryan_chen 				/* Try first with a 4ns DI delay */
445499853d6Sryan_chen 				delay = TIMING_DELAY_DI_4NS | hcycle;
446499853d6Sryan_chen 				checksum = aspeed_spi_read_checksum(priv, hclk_masks[i],
447499853d6Sryan_chen 								    delay);
448499853d6Sryan_chen 				pass = (checksum == gold_checksum);
449499853d6Sryan_chen 				debug(" HCLK/%d, 4ns DI delay, %d HCLK cycle : %s\n",
450499853d6Sryan_chen 				      hdiv, hcycle, pass ? "PASS" : "FAIL");
451499853d6Sryan_chen 
452499853d6Sryan_chen 				/* Try again with more HCLK cycles */
453499853d6Sryan_chen 				if (!pass)
454499853d6Sryan_chen 					continue;
455499853d6Sryan_chen 
456499853d6Sryan_chen 				/* Try without the 4ns DI delay */
457499853d6Sryan_chen 				delay = hcycle;
458499853d6Sryan_chen 				checksum = aspeed_spi_read_checksum(priv, hclk_masks[i],
459499853d6Sryan_chen 								    delay);
460499853d6Sryan_chen 				pass = (checksum == gold_checksum);
461499853d6Sryan_chen 				debug(" HCLK/%d,  no DI delay, %d HCLK cycle : %s\n",
462499853d6Sryan_chen 				      hdiv, hcycle, pass ? "PASS" : "FAIL");
463499853d6Sryan_chen 
464499853d6Sryan_chen 				/* All good for this freq  */
465499853d6Sryan_chen 				if (pass)
466499853d6Sryan_chen 					break;
467499853d6Sryan_chen 			}
468499853d6Sryan_chen 
469499853d6Sryan_chen 			if (pass) {
470499853d6Sryan_chen 				timing_reg &= ~(0xfu << hshift);
471499853d6Sryan_chen 				timing_reg |= delay << hshift;
472499853d6Sryan_chen 			}
473499853d6Sryan_chen 		}
4747d182336Sryan_chen 	}
475beec505fSChin-Ting Kuo 
476499853d6Sryan_chen 	debug("Read Timing Compensation set to 0x%08x\n", timing_reg);
477499853d6Sryan_chen 	writel(timing_reg, &priv->regs->timings);
478499853d6Sryan_chen 
479499853d6Sryan_chen 	return 0;
480499853d6Sryan_chen }
481499853d6Sryan_chen 
482499853d6Sryan_chen static int aspeed_spi_controller_init(struct aspeed_spi_priv *priv)
483499853d6Sryan_chen {
484beec505fSChin-Ting Kuo 	int cs;
485499853d6Sryan_chen 
486499853d6Sryan_chen 	/*
487499853d6Sryan_chen 	 * Enable write on all flash devices as USER command mode
488499853d6Sryan_chen 	 * requires it.
489499853d6Sryan_chen 	 */
490499853d6Sryan_chen 	setbits_le32(&priv->regs->conf,
491499853d6Sryan_chen 		     CONF_ENABLE_W2 | CONF_ENABLE_W1 | CONF_ENABLE_W0);
492499853d6Sryan_chen 
493499853d6Sryan_chen 	/*
494499853d6Sryan_chen 	 * Set safe default settings for each device. These will be
495499853d6Sryan_chen 	 * tuned after the SPI flash devices are probed.
496499853d6Sryan_chen 	 */
497da83dd7eSryan_chen 	if (priv->new_ver) {
498499853d6Sryan_chen 		for (cs = 0; cs < priv->flash_count; cs++) {
499499853d6Sryan_chen 			struct aspeed_spi_flash *flash = &priv->flashes[cs];
500499853d6Sryan_chen 			u32 seg_addr = readl(&priv->regs->segment_addr[cs]);
501d32338fdSryan_chen 			u32 addr_config = 0;
502499853d6Sryan_chen 			switch(cs) {
503da83dd7eSryan_chen 				case 0:
504da83dd7eSryan_chen 					flash->ahb_base = cs ? (void *)G6_SEGMENT_ADDR_START(seg_addr) :
505da83dd7eSryan_chen 						priv->ahb_base;
506d32338fdSryan_chen 					debug("cs0 mem-map : %x \n", (u32)flash->ahb_base);
507da83dd7eSryan_chen 					break;
508499853d6Sryan_chen 				case 1:
509aed21223SChin-Ting Kuo 					flash->ahb_base = priv->flashes[0].ahb_base + 0x8000000;	//cs0 + 128Mb : use 64MB
5106167da3dSryan_chen 					debug("cs1 mem-map : %x end %x \n", (u32)flash->ahb_base, (u32)flash->ahb_base + 0x4000000);
5116424f9abSChin-Ting Kuo 					addr_config = G6_SEGMENT_ADDR_VALUE((u32)flash->ahb_base, (u32)flash->ahb_base + 0x4000000); //add 512Mb
512d32338fdSryan_chen 					writel(addr_config, &priv->regs->segment_addr[cs]);
513499853d6Sryan_chen 					break;
514499853d6Sryan_chen 				case 2:
5156167da3dSryan_chen 					flash->ahb_base = priv->flashes[0].ahb_base + 0xc000000;	//cs0 + 192Mb : use 64MB
5166167da3dSryan_chen 					debug("cs2 mem-map : %x end %x \n", (u32)flash->ahb_base, (u32)flash->ahb_base + 0x4000000);
5176424f9abSChin-Ting Kuo 					addr_config = G6_SEGMENT_ADDR_VALUE((u32)flash->ahb_base, (u32)flash->ahb_base + 0x4000000); //add 512Mb
5186167da3dSryan_chen 					writel(addr_config, &priv->regs->segment_addr[cs]);
519499853d6Sryan_chen 					break;
520499853d6Sryan_chen 			}
521da83dd7eSryan_chen 			flash->cs = cs;
522da83dd7eSryan_chen 			flash->ce_ctrl_user = CE_CTRL_USERMODE;
523da83dd7eSryan_chen 			flash->ce_ctrl_fread = CE_CTRL_READMODE;
524499853d6Sryan_chen 		}
525da83dd7eSryan_chen 	} else {
526da83dd7eSryan_chen 		for (cs = 0; cs < priv->flash_count; cs++) {
527da83dd7eSryan_chen 			struct aspeed_spi_flash *flash = &priv->flashes[cs];
528da83dd7eSryan_chen 			u32 seg_addr = readl(&priv->regs->segment_addr[cs]);
529499853d6Sryan_chen 			/*
530499853d6Sryan_chen 			 * The start address of the AHB window of CE0 is
531499853d6Sryan_chen 			 * read-only and is the same as the address of the
532499853d6Sryan_chen 			 * overall AHB window of the controller for all flash
533499853d6Sryan_chen 			 * devices.
534499853d6Sryan_chen 			 */
535499853d6Sryan_chen 			flash->ahb_base = cs ? (void *)SEGMENT_ADDR_START(seg_addr) :
536499853d6Sryan_chen 				priv->ahb_base;
537499853d6Sryan_chen 
538499853d6Sryan_chen 			flash->cs = cs;
539499853d6Sryan_chen 			flash->ce_ctrl_user = CE_CTRL_USERMODE;
540499853d6Sryan_chen 			flash->ce_ctrl_fread = CE_CTRL_READMODE;
541499853d6Sryan_chen 		}
542da83dd7eSryan_chen 	}
543499853d6Sryan_chen 	return 0;
544499853d6Sryan_chen }
545499853d6Sryan_chen 
546499853d6Sryan_chen static int aspeed_spi_read_from_ahb(void __iomem *ahb_base, void *buf,
547499853d6Sryan_chen 				    size_t len)
548499853d6Sryan_chen {
549499853d6Sryan_chen 	size_t offset = 0;
550499853d6Sryan_chen 
551499853d6Sryan_chen 	if (!((uintptr_t)buf % 4)) {
552499853d6Sryan_chen 		readsl(ahb_base, buf, len >> 2);
553499853d6Sryan_chen 		offset = len & ~0x3;
554499853d6Sryan_chen 		len -= offset;
555499853d6Sryan_chen 	}
556499853d6Sryan_chen 	readsb(ahb_base, (u8 *)buf + offset, len);
557499853d6Sryan_chen 
558499853d6Sryan_chen 	return 0;
559499853d6Sryan_chen }
560499853d6Sryan_chen 
561499853d6Sryan_chen static int aspeed_spi_write_to_ahb(void __iomem *ahb_base, const void *buf,
562499853d6Sryan_chen 				   size_t len)
563499853d6Sryan_chen {
564499853d6Sryan_chen 	size_t offset = 0;
565499853d6Sryan_chen 
566499853d6Sryan_chen 	if (!((uintptr_t)buf % 4)) {
567499853d6Sryan_chen 		writesl(ahb_base, buf, len >> 2);
568499853d6Sryan_chen 		offset = len & ~0x3;
569499853d6Sryan_chen 		len -= offset;
570499853d6Sryan_chen 	}
571499853d6Sryan_chen 	writesb(ahb_base, (u8 *)buf + offset, len);
572499853d6Sryan_chen 
573499853d6Sryan_chen 	return 0;
574499853d6Sryan_chen }
575499853d6Sryan_chen 
576499853d6Sryan_chen static void aspeed_spi_start_user(struct aspeed_spi_priv *priv,
577499853d6Sryan_chen 				  struct aspeed_spi_flash *flash)
578499853d6Sryan_chen {
579499853d6Sryan_chen 	u32 ctrl_reg = flash->ce_ctrl_user | CE_CTRL_STOP_ACTIVE;
580499853d6Sryan_chen 
581499853d6Sryan_chen 	/* Deselect CS and set USER command mode */
582499853d6Sryan_chen 	writel(ctrl_reg, &priv->regs->ce_ctrl[flash->cs]);
583499853d6Sryan_chen 
584499853d6Sryan_chen 	/* Select CS */
585499853d6Sryan_chen 	clrbits_le32(&priv->regs->ce_ctrl[flash->cs], CE_CTRL_STOP_ACTIVE);
586499853d6Sryan_chen }
587499853d6Sryan_chen 
588499853d6Sryan_chen static void aspeed_spi_stop_user(struct aspeed_spi_priv *priv,
589499853d6Sryan_chen 				 struct aspeed_spi_flash *flash)
590499853d6Sryan_chen {
591499853d6Sryan_chen 	/* Deselect CS first */
592499853d6Sryan_chen 	setbits_le32(&priv->regs->ce_ctrl[flash->cs], CE_CTRL_STOP_ACTIVE);
593499853d6Sryan_chen 
594499853d6Sryan_chen 	/* Restore default command mode */
595499853d6Sryan_chen 	writel(flash->ce_ctrl_fread, &priv->regs->ce_ctrl[flash->cs]);
596499853d6Sryan_chen }
597499853d6Sryan_chen 
598499853d6Sryan_chen static int aspeed_spi_read_reg(struct aspeed_spi_priv *priv,
599499853d6Sryan_chen 			       struct aspeed_spi_flash *flash,
600499853d6Sryan_chen 			       u8 opcode, u8 *read_buf, int len)
601499853d6Sryan_chen {
602499853d6Sryan_chen 	aspeed_spi_start_user(priv, flash);
603499853d6Sryan_chen 	aspeed_spi_write_to_ahb(flash->ahb_base, &opcode, 1);
604499853d6Sryan_chen 	aspeed_spi_read_from_ahb(flash->ahb_base, read_buf, len);
605499853d6Sryan_chen 	aspeed_spi_stop_user(priv, flash);
606499853d6Sryan_chen 
607499853d6Sryan_chen 	return 0;
608499853d6Sryan_chen }
609499853d6Sryan_chen 
610499853d6Sryan_chen static int aspeed_spi_write_reg(struct aspeed_spi_priv *priv,
611499853d6Sryan_chen 				struct aspeed_spi_flash *flash,
612499853d6Sryan_chen 				u8 opcode, const u8 *write_buf, int len)
613499853d6Sryan_chen {
614499853d6Sryan_chen 	aspeed_spi_start_user(priv, flash);
615499853d6Sryan_chen 	aspeed_spi_write_to_ahb(flash->ahb_base, &opcode, 1);
616499853d6Sryan_chen 	aspeed_spi_write_to_ahb(flash->ahb_base, write_buf, len);
617499853d6Sryan_chen 	aspeed_spi_stop_user(priv, flash);
618499853d6Sryan_chen 
619528cd552Sryan_chen 	debug("=== write opcode [%x] ==== \n", opcode);
620499853d6Sryan_chen 	switch(opcode) {
621499853d6Sryan_chen 		case SPINOR_OP_EN4B:
6220a73b911SChin-Ting Kuo 			/* For ast2600, if 2 chips ABR mode is enabled,
6230a73b911SChin-Ting Kuo 			 * turn on 3B mode auto clear in order to avoid
6240a73b911SChin-Ting Kuo 			 * the scenario where spi controller is at 4B mode
6250a73b911SChin-Ting Kuo 			 * and flash site is at 3B mode after 3rd switch.
6260a73b911SChin-Ting Kuo 			 */
6270a73b911SChin-Ting Kuo 			if (priv->new_ver == 1 && (readl(SPI_3B_AUTO_CLR_REG) & SPI_3B_AUTO_CLR))
6280a73b911SChin-Ting Kuo 				writel(readl(&priv->regs->soft_rst_cmd_ctrl) | SOFT_RST_CMD_EN,
6290a73b911SChin-Ting Kuo 						&priv->regs->soft_rst_cmd_ctrl);
6300a73b911SChin-Ting Kuo 
631edbd932bSChin-Ting Kuo 			writel(readl(&priv->regs->ctrl) | (0x11 << flash->cs), &priv->regs->ctrl);
632499853d6Sryan_chen 			break;
633499853d6Sryan_chen 		case SPINOR_OP_EX4B:
634edbd932bSChin-Ting Kuo 			writel(readl(&priv->regs->ctrl) & ~(0x11 << flash->cs), &priv->regs->ctrl);
635499853d6Sryan_chen 			break;
636499853d6Sryan_chen 	}
637499853d6Sryan_chen 	return 0;
638499853d6Sryan_chen }
639499853d6Sryan_chen 
640499853d6Sryan_chen static void aspeed_spi_send_cmd_addr(struct aspeed_spi_priv *priv,
641499853d6Sryan_chen 				     struct aspeed_spi_flash *flash,
642cd800046SChin-Ting Kuo 				     const u8 *cmdbuf, unsigned int cmdlen, uint32_t flag)
643499853d6Sryan_chen {
644499853d6Sryan_chen 	int i;
645499853d6Sryan_chen 	u8 byte0 = 0x0;
646499853d6Sryan_chen 	u8 addrlen = cmdlen - 1;
647499853d6Sryan_chen 
648499853d6Sryan_chen 	/* First, send the opcode */
649499853d6Sryan_chen 	aspeed_spi_write_to_ahb(flash->ahb_base, &cmdbuf[0], 1);
650499853d6Sryan_chen 
651cd800046SChin-Ting Kuo 	if(flash->write_iomode == CE_CTRL_IO_QUAD_ADDR_DATA && (flag & SPI_WRITE_TO_FLASH))
652cd800046SChin-Ting Kuo 		writel(flash->ce_ctrl_user | flash->write_iomode, &priv->regs->ce_ctrl[flash->cs]);
653cd800046SChin-Ting Kuo 	else if(flash->read_iomode == CE_CTRL_IO_QUAD_ADDR_DATA && (flag & SPI_READ_FROM_FLASH))
654cd800046SChin-Ting Kuo 		writel(flash->ce_ctrl_user | flash->read_iomode, &priv->regs->ce_ctrl[flash->cs]);
655528cd552Sryan_chen 
656499853d6Sryan_chen 	/*
657499853d6Sryan_chen 	 * The controller is configured for 4BYTE address mode. Fix
658499853d6Sryan_chen 	 * the address width and send an extra byte if the SPI Flash
659499853d6Sryan_chen 	 * layer uses 3 bytes addresses.
660499853d6Sryan_chen 	 */
661499853d6Sryan_chen 	if (addrlen == 3 && readl(&priv->regs->ctrl) & BIT(flash->cs))
662499853d6Sryan_chen 		aspeed_spi_write_to_ahb(flash->ahb_base, &byte0, 1);
663499853d6Sryan_chen 
664499853d6Sryan_chen 	/* Then the address */
665499853d6Sryan_chen 	for (i = 1 ; i < cmdlen; i++)
666499853d6Sryan_chen 		aspeed_spi_write_to_ahb(flash->ahb_base, &cmdbuf[i], 1);
667499853d6Sryan_chen }
668499853d6Sryan_chen 
669499853d6Sryan_chen static ssize_t aspeed_spi_read_user(struct aspeed_spi_priv *priv,
670499853d6Sryan_chen 				    struct aspeed_spi_flash *flash,
671499853d6Sryan_chen 				    unsigned int cmdlen, const u8 *cmdbuf,
672499853d6Sryan_chen 				    unsigned int len, u8 *read_buf)
673499853d6Sryan_chen {
674499853d6Sryan_chen 	u8 dummy = 0xff;
675499853d6Sryan_chen 	int i;
676499853d6Sryan_chen 
677499853d6Sryan_chen 	aspeed_spi_start_user(priv, flash);
678499853d6Sryan_chen 
679499853d6Sryan_chen 	/* cmd buffer = cmd + addr + dummies */
680499853d6Sryan_chen 	aspeed_spi_send_cmd_addr(priv, flash, cmdbuf,
681cd800046SChin-Ting Kuo 				 cmdlen - (flash->spi->read_dummy/8), SPI_READ_FROM_FLASH);
682499853d6Sryan_chen 
683499853d6Sryan_chen 	for (i = 0 ; i < (flash->spi->read_dummy/8); i++)
684499853d6Sryan_chen 		aspeed_spi_write_to_ahb(flash->ahb_base, &dummy, 1);
685499853d6Sryan_chen 
686cd800046SChin-Ting Kuo 	if (flash->read_iomode) {
687499853d6Sryan_chen 		clrbits_le32(&priv->regs->ce_ctrl[flash->cs],
688499853d6Sryan_chen 			     CE_CTRL_IO_MODE_MASK);
689cd800046SChin-Ting Kuo 		setbits_le32(&priv->regs->ce_ctrl[flash->cs], flash->read_iomode);
690499853d6Sryan_chen 	}
691499853d6Sryan_chen 
692499853d6Sryan_chen 	aspeed_spi_read_from_ahb(flash->ahb_base, read_buf, len);
693499853d6Sryan_chen 	aspeed_spi_stop_user(priv, flash);
694499853d6Sryan_chen 
695499853d6Sryan_chen 	return 0;
696499853d6Sryan_chen }
697499853d6Sryan_chen 
698499853d6Sryan_chen static ssize_t aspeed_spi_write_user(struct aspeed_spi_priv *priv,
699499853d6Sryan_chen 				     struct aspeed_spi_flash *flash,
700499853d6Sryan_chen 				     unsigned int cmdlen, const u8 *cmdbuf,
701499853d6Sryan_chen 				     unsigned int len,	const u8 *write_buf)
702499853d6Sryan_chen {
703499853d6Sryan_chen 	aspeed_spi_start_user(priv, flash);
704499853d6Sryan_chen 
70576e3c7a9Sryan_chen 	/* cmd buffer = cmd + addr : normally cmd is use signle mode*/
706cd800046SChin-Ting Kuo 	aspeed_spi_send_cmd_addr(priv, flash, cmdbuf, cmdlen, SPI_WRITE_TO_FLASH);
70776e3c7a9Sryan_chen 
70876e3c7a9Sryan_chen 	/* data will use io mode */
709cd800046SChin-Ting Kuo 	if(flash->write_iomode == CE_CTRL_IO_QUAD_DATA)
710cd800046SChin-Ting Kuo 		writel(flash->ce_ctrl_user | flash->write_iomode, &priv->regs->ce_ctrl[flash->cs]);
71176e3c7a9Sryan_chen 
712499853d6Sryan_chen 	aspeed_spi_write_to_ahb(flash->ahb_base, write_buf, len);
713499853d6Sryan_chen 
714499853d6Sryan_chen 	aspeed_spi_stop_user(priv, flash);
715499853d6Sryan_chen 
716499853d6Sryan_chen 	return 0;
717499853d6Sryan_chen }
718499853d6Sryan_chen 
719499853d6Sryan_chen static u32 aspeed_spi_flash_to_addr(struct aspeed_spi_flash *flash,
720499853d6Sryan_chen 				    const u8 *cmdbuf, unsigned int cmdlen)
721499853d6Sryan_chen {
722499853d6Sryan_chen 	u8 addrlen = cmdlen - 1;
723499853d6Sryan_chen 	u32 addr = (cmdbuf[1] << 16) | (cmdbuf[2] << 8) | cmdbuf[3];
724499853d6Sryan_chen 
725499853d6Sryan_chen 	/*
726499853d6Sryan_chen 	 * U-Boot SPI Flash layer uses 3 bytes addresses, but it might
727499853d6Sryan_chen 	 * change one day
728499853d6Sryan_chen 	 */
729499853d6Sryan_chen 	if (addrlen == 4)
730499853d6Sryan_chen 		addr = (addr << 8) | cmdbuf[4];
731499853d6Sryan_chen 
732499853d6Sryan_chen 	return addr;
733499853d6Sryan_chen }
734499853d6Sryan_chen 
735499853d6Sryan_chen /* TODO(clg@kaod.org): add support for XFER_MMAP instead ? */
736499853d6Sryan_chen static ssize_t aspeed_spi_read(struct aspeed_spi_priv *priv,
737499853d6Sryan_chen 			       struct aspeed_spi_flash *flash,
738499853d6Sryan_chen 			       unsigned int cmdlen, const u8 *cmdbuf,
739499853d6Sryan_chen 			       unsigned int len, u8 *read_buf)
740499853d6Sryan_chen {
741499853d6Sryan_chen 	/* cmd buffer = cmd + addr + dummies */
742499853d6Sryan_chen 	u32 offset = aspeed_spi_flash_to_addr(flash, cmdbuf,
743499853d6Sryan_chen 					      cmdlen - (flash->spi->read_dummy/8));
744499853d6Sryan_chen 
745499853d6Sryan_chen 	/*
7466424f9abSChin-Ting Kuo 	 * Switch to USER command mode:
7476424f9abSChin-Ting Kuo 	 * - if the AHB window configured for the device is
7486424f9abSChin-Ting Kuo 	 *   too small for the read operation
7496424f9abSChin-Ting Kuo 	 * - if read offset is smaller than the decoded start address
7506424f9abSChin-Ting Kuo 	 *   and the decoded range is not multiple of flash size
751499853d6Sryan_chen 	 */
7526424f9abSChin-Ting Kuo 	if ((offset + len >= flash->ahb_size) || \
7536424f9abSChin-Ting Kuo 		(offset < ((int)flash->ahb_base & 0x0FFFFFFF) && \
7546424f9abSChin-Ting Kuo 		(((int)flash->ahb_base & 0x0FFFFFFF) % flash->spi->size) != 0)) {
755499853d6Sryan_chen 		return aspeed_spi_read_user(priv, flash, cmdlen, cmdbuf,
756499853d6Sryan_chen 					    len, read_buf);
757499853d6Sryan_chen 	}
758499853d6Sryan_chen 
759499853d6Sryan_chen 	memcpy_fromio(read_buf, flash->ahb_base + offset, len);
760499853d6Sryan_chen 
761499853d6Sryan_chen 	return 0;
762499853d6Sryan_chen }
763499853d6Sryan_chen 
764499853d6Sryan_chen static int aspeed_spi_xfer(struct udevice *dev, unsigned int bitlen,
765499853d6Sryan_chen 			   const void *dout, void *din, unsigned long flags)
766499853d6Sryan_chen {
767499853d6Sryan_chen 	struct udevice *bus = dev->parent;
768499853d6Sryan_chen 	struct aspeed_spi_priv *priv = dev_get_priv(bus);
769499853d6Sryan_chen 	struct aspeed_spi_flash *flash;
770499853d6Sryan_chen 	u8 *cmd_buf = priv->cmd_buf;
771499853d6Sryan_chen 	size_t data_bytes;
772499853d6Sryan_chen 	int err = 0;
773499853d6Sryan_chen 
774499853d6Sryan_chen 	flash = aspeed_spi_get_flash(dev);
775499853d6Sryan_chen 	if (!flash)
776499853d6Sryan_chen 		return -ENXIO;
777499853d6Sryan_chen 
778499853d6Sryan_chen 	if (flags & SPI_XFER_BEGIN) {
779499853d6Sryan_chen 		/* save command in progress */
780499853d6Sryan_chen 		priv->cmd_len = bitlen / 8;
781499853d6Sryan_chen 		memcpy(cmd_buf, dout, priv->cmd_len);
782499853d6Sryan_chen 	}
783499853d6Sryan_chen 
784499853d6Sryan_chen 	if (flags == (SPI_XFER_BEGIN | SPI_XFER_END)) {
785499853d6Sryan_chen 		/* if start and end bit are set, the data bytes is 0. */
786499853d6Sryan_chen 		data_bytes = 0;
787499853d6Sryan_chen 	} else {
788499853d6Sryan_chen 		data_bytes = bitlen / 8;
789499853d6Sryan_chen 	}
790499853d6Sryan_chen 
791499853d6Sryan_chen 	debug("CS%u: %s cmd %zu bytes data %zu bytes\n", flash->cs,
792499853d6Sryan_chen 	      din ? "read" : "write", priv->cmd_len, data_bytes);
793499853d6Sryan_chen 
794499853d6Sryan_chen 	if ((flags & SPI_XFER_END) || flags == 0) {
795499853d6Sryan_chen 		if (priv->cmd_len == 0) {
796499853d6Sryan_chen 			pr_err("No command is progress !\n");
797499853d6Sryan_chen 			return -1;
798499853d6Sryan_chen 		}
799499853d6Sryan_chen 
800499853d6Sryan_chen 		if (din && data_bytes) {
801499853d6Sryan_chen 			if (priv->cmd_len == 1)
802499853d6Sryan_chen 				err = aspeed_spi_read_reg(priv, flash,
803499853d6Sryan_chen 							  cmd_buf[0],
804499853d6Sryan_chen 							  din, data_bytes);
805499853d6Sryan_chen 			else
806499853d6Sryan_chen 				err = aspeed_spi_read(priv, flash,
807499853d6Sryan_chen 						      priv->cmd_len,
808499853d6Sryan_chen 						      cmd_buf, data_bytes,
809499853d6Sryan_chen 						      din);
810499853d6Sryan_chen 		} else if (dout) {
811499853d6Sryan_chen 			if (priv->cmd_len == 1)
812499853d6Sryan_chen 				err = aspeed_spi_write_reg(priv, flash,
813499853d6Sryan_chen 							   cmd_buf[0],
814499853d6Sryan_chen 							   dout, data_bytes);
815499853d6Sryan_chen 			else
816499853d6Sryan_chen 				err = aspeed_spi_write_user(priv, flash,
817499853d6Sryan_chen 							    priv->cmd_len,
818499853d6Sryan_chen 							    cmd_buf, data_bytes,
819499853d6Sryan_chen 							    dout);
820499853d6Sryan_chen 		}
821499853d6Sryan_chen 
822499853d6Sryan_chen 		if (flags & SPI_XFER_END) {
823499853d6Sryan_chen 			/* clear command */
824499853d6Sryan_chen 			memset(cmd_buf, 0, sizeof(priv->cmd_buf));
825499853d6Sryan_chen 			priv->cmd_len = 0;
826499853d6Sryan_chen 		}
827499853d6Sryan_chen 	}
828499853d6Sryan_chen 
829499853d6Sryan_chen 	return err;
830499853d6Sryan_chen }
831499853d6Sryan_chen 
832499853d6Sryan_chen static int aspeed_spi_child_pre_probe(struct udevice *dev)
833499853d6Sryan_chen {
834499853d6Sryan_chen 	struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
835499853d6Sryan_chen 
836499853d6Sryan_chen 	debug("pre_probe slave device on CS%u, max_hz %u, mode 0x%x.\n",
837499853d6Sryan_chen 	      slave_plat->cs, slave_plat->max_hz, slave_plat->mode);
838499853d6Sryan_chen 
839499853d6Sryan_chen 	if (!aspeed_spi_get_flash(dev))
840499853d6Sryan_chen 		return -ENXIO;
841499853d6Sryan_chen 
842499853d6Sryan_chen 	return 0;
843499853d6Sryan_chen }
844499853d6Sryan_chen 
845499853d6Sryan_chen /*
846499853d6Sryan_chen  * It is possible to automatically define a contiguous address space
847499853d6Sryan_chen  * on top of all CEs in the AHB window of the controller but it would
848499853d6Sryan_chen  * require much more work. Let's start with a simple mapping scheme
849499853d6Sryan_chen  * which should work fine for a single flash device.
850499853d6Sryan_chen  *
851499853d6Sryan_chen  * More complex schemes should probably be defined with the device
852499853d6Sryan_chen  * tree.
853499853d6Sryan_chen  */
854499853d6Sryan_chen static int aspeed_spi_flash_set_segment(struct aspeed_spi_priv *priv,
855499853d6Sryan_chen 					struct aspeed_spi_flash *flash)
856499853d6Sryan_chen {
857499853d6Sryan_chen 	u32 seg_addr;
858499853d6Sryan_chen 
859499853d6Sryan_chen 	/* could be configured through the device tree */
860499853d6Sryan_chen 	flash->ahb_size = flash->spi->size;
861499853d6Sryan_chen 
862da83dd7eSryan_chen 	if (priv->new_ver) {
863da83dd7eSryan_chen 		seg_addr = G6_SEGMENT_ADDR_VALUE((u32)flash->ahb_base,
864da83dd7eSryan_chen 					      (u32)flash->ahb_base + flash->ahb_size);
865da83dd7eSryan_chen 	} else {
866499853d6Sryan_chen 		seg_addr = SEGMENT_ADDR_VALUE((u32)flash->ahb_base,
867499853d6Sryan_chen 						  (u32)flash->ahb_base + flash->ahb_size);
868da83dd7eSryan_chen 	}
869499853d6Sryan_chen 	writel(seg_addr, &priv->regs->segment_addr[flash->cs]);
870499853d6Sryan_chen 
871499853d6Sryan_chen 	return 0;
872499853d6Sryan_chen }
873499853d6Sryan_chen 
874499853d6Sryan_chen static int aspeed_spi_flash_init(struct aspeed_spi_priv *priv,
875499853d6Sryan_chen 				 struct aspeed_spi_flash *flash,
876499853d6Sryan_chen 				 struct udevice *dev)
877499853d6Sryan_chen {
878beec505fSChin-Ting Kuo 	int ret;
879499853d6Sryan_chen 	struct spi_flash *spi_flash = dev_get_uclass_priv(dev);
880499853d6Sryan_chen 	struct spi_slave *slave = dev_get_parent_priv(dev);
881499853d6Sryan_chen 	u32 read_hclk;
882499853d6Sryan_chen 
883a4e44632SChin-Ting Kuo 	flash->spi = spi_flash;
884a4e44632SChin-Ting Kuo 
885499853d6Sryan_chen 	/*
886499853d6Sryan_chen 	 * The flash device has not been probed yet. Initial transfers
887499853d6Sryan_chen 	 * to read the JEDEC of the device will use the initial
888499853d6Sryan_chen 	 * default settings of the registers.
889499853d6Sryan_chen 	 */
890499853d6Sryan_chen 	if (!spi_flash->name)
891499853d6Sryan_chen 		return 0;
892499853d6Sryan_chen 
893543bff32SChin-Ting Kuo 	/*
894543bff32SChin-Ting Kuo 	 * The SPI flash device slave should not change, so initialize
895543bff32SChin-Ting Kuo 	 * it only once.
896543bff32SChin-Ting Kuo 	 */
897543bff32SChin-Ting Kuo 	if (flash->init)
898543bff32SChin-Ting Kuo 		return 0;
899543bff32SChin-Ting Kuo 
900499853d6Sryan_chen 	debug("CS%u: init %s flags:%x size:%d page:%d sector:%d erase:%d "
901499853d6Sryan_chen 	      "cmds [ erase:%x read=%x write:%x ] dummy:%d\n",
902499853d6Sryan_chen 	      flash->cs,
903499853d6Sryan_chen 	      spi_flash->name, spi_flash->flags, spi_flash->size,
904499853d6Sryan_chen 	      spi_flash->page_size, spi_flash->sector_size,
905499853d6Sryan_chen 	      spi_flash->erase_size, spi_flash->erase_opcode,
906499853d6Sryan_chen 	      spi_flash->read_opcode, spi_flash->program_opcode,
907499853d6Sryan_chen 	      spi_flash->read_dummy);
908499853d6Sryan_chen 
9097d182336Sryan_chen 	flash->ce_ctrl_user = CE_CTRL_USERMODE;
910499853d6Sryan_chen 
911ac86fa8bSryan_chen 	if(priv->new_ver)
912ac86fa8bSryan_chen 		read_hclk = aspeed_g6_spi_hclk_divisor(priv, slave->speed);
913ac86fa8bSryan_chen 	else
9147d182336Sryan_chen 		read_hclk = aspeed_spi_hclk_divisor(priv, slave->speed);
915499853d6Sryan_chen 
916528cd552Sryan_chen 	switch(flash->spi->read_opcode) {
917528cd552Sryan_chen 		case SPINOR_OP_READ_1_1_2:
918528cd552Sryan_chen 		case SPINOR_OP_READ_1_1_2_4B:
919cd800046SChin-Ting Kuo 			flash->read_iomode = CE_CTRL_IO_DUAL_DATA;
920528cd552Sryan_chen 			break;
921528cd552Sryan_chen 		case SPINOR_OP_READ_1_1_4:
922528cd552Sryan_chen 		case SPINOR_OP_READ_1_1_4_4B:
923cd800046SChin-Ting Kuo 			flash->read_iomode = CE_CTRL_IO_QUAD_DATA;
924528cd552Sryan_chen 			break;
925528cd552Sryan_chen 		case SPINOR_OP_READ_1_4_4:
926528cd552Sryan_chen 		case SPINOR_OP_READ_1_4_4_4B:
927cd800046SChin-Ting Kuo 			flash->read_iomode = CE_CTRL_IO_QUAD_ADDR_DATA;
928734f8860SChin-Ting Kuo 			printf("need modify dummy for 3 bytes\n");
929528cd552Sryan_chen 			break;
930499853d6Sryan_chen 	}
931499853d6Sryan_chen 
932cd800046SChin-Ting Kuo 	switch(flash->spi->program_opcode) {
933cd800046SChin-Ting Kuo 		case SPINOR_OP_PP:
934cd800046SChin-Ting Kuo 		case SPINOR_OP_PP_4B:
935cd800046SChin-Ting Kuo 			flash->write_iomode = CE_CTRL_IO_SINGLE;
936cd800046SChin-Ting Kuo 			break;
937cd800046SChin-Ting Kuo 		case SPINOR_OP_PP_1_1_4:
938cd800046SChin-Ting Kuo 		case SPINOR_OP_PP_1_1_4_4B:
939cd800046SChin-Ting Kuo 			flash->write_iomode = CE_CTRL_IO_QUAD_DATA;
940cd800046SChin-Ting Kuo 			break;
941cd800046SChin-Ting Kuo 		case SPINOR_OP_PP_1_4_4:
942cd800046SChin-Ting Kuo 		case SPINOR_OP_PP_1_4_4_4B:
943cd800046SChin-Ting Kuo 			flash->write_iomode = CE_CTRL_IO_QUAD_ADDR_DATA;
944cd800046SChin-Ting Kuo 			printf("need modify dummy for 3 bytes");
945cd800046SChin-Ting Kuo 			break;
946cd800046SChin-Ting Kuo 	}
947cd800046SChin-Ting Kuo 
948d32338fdSryan_chen 	if(priv->new_ver) {
9497d182336Sryan_chen 		flash->ce_ctrl_fread = CE_G6_CTRL_CLOCK_FREQ(read_hclk) |
950cd800046SChin-Ting Kuo 			flash->read_iomode |
9517d182336Sryan_chen 			CE_CTRL_CMD(flash->spi->read_opcode) |
9527d182336Sryan_chen 			CE_CTRL_DUMMY((flash->spi->read_dummy/8)) |
9537d182336Sryan_chen 			CE_CTRL_FREADMODE;
954*b679b8adSChin-Ting Kuo 		flash->ce_ctrl_user |= CE_G6_CTRL_CLOCK_FREQ(read_hclk);
955d32338fdSryan_chen 	} else {
956499853d6Sryan_chen 		flash->ce_ctrl_fread = CE_CTRL_CLOCK_FREQ(read_hclk) |
957cd800046SChin-Ting Kuo 			flash->read_iomode |
958499853d6Sryan_chen 			CE_CTRL_CMD(flash->spi->read_opcode) |
959499853d6Sryan_chen 			CE_CTRL_DUMMY((flash->spi->read_dummy/8)) |
960499853d6Sryan_chen 			CE_CTRL_FREADMODE;
961d32338fdSryan_chen 	}
962499853d6Sryan_chen 
9639405f2a1SChin-Ting Kuo 	if (flash->spi->addr_width == 4)
9649405f2a1SChin-Ting Kuo 		writel(readl(&priv->regs->ctrl) | 0x11 << flash->cs, &priv->regs->ctrl);
9659405f2a1SChin-Ting Kuo 
966499853d6Sryan_chen 	debug("CS%u: USER mode 0x%08x FREAD mode 0x%08x\n", flash->cs,
967499853d6Sryan_chen 	      flash->ce_ctrl_user, flash->ce_ctrl_fread);
968499853d6Sryan_chen 
969499853d6Sryan_chen 	/* Set the CE Control Register default (FAST READ) */
970499853d6Sryan_chen 	writel(flash->ce_ctrl_fread, &priv->regs->ce_ctrl[flash->cs]);
971499853d6Sryan_chen 
972499853d6Sryan_chen 	/* Set Address Segment Register for direct AHB accesses */
973499853d6Sryan_chen 	aspeed_spi_flash_set_segment(priv, flash);
974499853d6Sryan_chen 
975beec505fSChin-Ting Kuo 	/*
976beec505fSChin-Ting Kuo 	 * Set the Read Timing Compensation Register. This setting
977beec505fSChin-Ting Kuo 	 * applies to all devices.
978beec505fSChin-Ting Kuo 	 */
979beec505fSChin-Ting Kuo 	ret = aspeed_spi_timing_calibration(priv);
980beec505fSChin-Ting Kuo 	if (ret != 0)
981beec505fSChin-Ting Kuo 		return ret;
982beec505fSChin-Ting Kuo 
983499853d6Sryan_chen 	/* All done */
984499853d6Sryan_chen 	flash->init = true;
985499853d6Sryan_chen 
986499853d6Sryan_chen 	return 0;
987499853d6Sryan_chen }
988499853d6Sryan_chen 
989499853d6Sryan_chen static int aspeed_spi_claim_bus(struct udevice *dev)
990499853d6Sryan_chen {
991499853d6Sryan_chen 	struct udevice *bus = dev->parent;
992499853d6Sryan_chen 	struct aspeed_spi_priv *priv = dev_get_priv(bus);
993499853d6Sryan_chen 	struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
994499853d6Sryan_chen 	struct aspeed_spi_flash *flash;
995499853d6Sryan_chen 
996499853d6Sryan_chen 	debug("%s: claim bus CS%u\n", bus->name, slave_plat->cs);
997499853d6Sryan_chen 
998499853d6Sryan_chen 	flash = aspeed_spi_get_flash(dev);
999499853d6Sryan_chen 	if (!flash)
1000499853d6Sryan_chen 		return -ENODEV;
1001499853d6Sryan_chen 
1002499853d6Sryan_chen 	return aspeed_spi_flash_init(priv, flash, dev);
1003499853d6Sryan_chen }
1004499853d6Sryan_chen 
1005499853d6Sryan_chen static int aspeed_spi_release_bus(struct udevice *dev)
1006499853d6Sryan_chen {
1007499853d6Sryan_chen 	struct udevice *bus = dev->parent;
1008499853d6Sryan_chen 	struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
1009499853d6Sryan_chen 
1010499853d6Sryan_chen 	debug("%s: release bus CS%u\n", bus->name, slave_plat->cs);
1011499853d6Sryan_chen 
1012499853d6Sryan_chen 	if (!aspeed_spi_get_flash(dev))
1013499853d6Sryan_chen 		return -ENODEV;
1014499853d6Sryan_chen 
1015499853d6Sryan_chen 	return 0;
1016499853d6Sryan_chen }
1017499853d6Sryan_chen 
1018499853d6Sryan_chen static int aspeed_spi_set_mode(struct udevice *bus, uint mode)
1019499853d6Sryan_chen {
1020499853d6Sryan_chen 	debug("%s: setting mode to %x\n", bus->name, mode);
1021499853d6Sryan_chen 
1022499853d6Sryan_chen 	if (mode & (SPI_RX_QUAD | SPI_TX_QUAD)) {
102376e3c7a9Sryan_chen #ifndef CONFIG_ASPEED_AST2600
1024499853d6Sryan_chen 		pr_err("%s invalid QUAD IO mode\n", bus->name);
1025499853d6Sryan_chen 		return -EINVAL;
102676e3c7a9Sryan_chen #endif
1027499853d6Sryan_chen 	}
1028499853d6Sryan_chen 
1029499853d6Sryan_chen 	/* The CE Control Register is set in claim_bus() */
1030499853d6Sryan_chen 	return 0;
1031499853d6Sryan_chen }
1032499853d6Sryan_chen 
1033499853d6Sryan_chen static int aspeed_spi_set_speed(struct udevice *bus, uint hz)
1034499853d6Sryan_chen {
1035499853d6Sryan_chen 	debug("%s: setting speed to %u\n", bus->name, hz);
1036499853d6Sryan_chen 
1037499853d6Sryan_chen 	/* The CE Control Register is set in claim_bus() */
1038499853d6Sryan_chen 	return 0;
1039499853d6Sryan_chen }
1040499853d6Sryan_chen 
1041499853d6Sryan_chen static int aspeed_spi_count_flash_devices(struct udevice *bus)
1042499853d6Sryan_chen {
1043499853d6Sryan_chen 	ofnode node;
1044499853d6Sryan_chen 	int count = 0;
1045499853d6Sryan_chen 
1046499853d6Sryan_chen 	dev_for_each_subnode(node, bus) {
1047499853d6Sryan_chen 		if (ofnode_is_available(node) &&
1048499853d6Sryan_chen 		    ofnode_device_is_compatible(node, "spi-flash"))
1049499853d6Sryan_chen 			count++;
1050499853d6Sryan_chen 	}
1051499853d6Sryan_chen 
1052499853d6Sryan_chen 	return count;
1053499853d6Sryan_chen }
1054499853d6Sryan_chen 
1055499853d6Sryan_chen static int aspeed_spi_bind(struct udevice *bus)
1056499853d6Sryan_chen {
1057499853d6Sryan_chen 	debug("%s assigned req_seq=%d seq=%d\n", bus->name, bus->req_seq,
1058499853d6Sryan_chen 	      bus->seq);
1059499853d6Sryan_chen 
1060499853d6Sryan_chen 	return 0;
1061499853d6Sryan_chen }
1062499853d6Sryan_chen 
1063499853d6Sryan_chen static int aspeed_spi_probe(struct udevice *bus)
1064499853d6Sryan_chen {
1065499853d6Sryan_chen 	struct resource res_regs, res_ahb;
1066499853d6Sryan_chen 	struct aspeed_spi_priv *priv = dev_get_priv(bus);
1067499853d6Sryan_chen 	struct clk hclk;
1068499853d6Sryan_chen 	int ret;
1069499853d6Sryan_chen 
1070499853d6Sryan_chen 	ret = dev_read_resource(bus, 0, &res_regs);
1071499853d6Sryan_chen 	if (ret < 0)
1072499853d6Sryan_chen 		return ret;
1073499853d6Sryan_chen 
1074499853d6Sryan_chen 	priv->regs = (void __iomem *)res_regs.start;
1075499853d6Sryan_chen 
1076499853d6Sryan_chen 	ret = dev_read_resource(bus, 1, &res_ahb);
1077499853d6Sryan_chen 	if (ret < 0)
1078499853d6Sryan_chen 		return ret;
1079499853d6Sryan_chen 
1080499853d6Sryan_chen 	priv->ahb_base = (void __iomem *)res_ahb.start;
1081499853d6Sryan_chen 	priv->ahb_size = res_ahb.end - res_ahb.start;
1082499853d6Sryan_chen 
1083499853d6Sryan_chen 	ret = clk_get_by_index(bus, 0, &hclk);
1084499853d6Sryan_chen 	if (ret < 0) {
1085499853d6Sryan_chen 		pr_err("%s could not get clock: %d\n", bus->name, ret);
1086499853d6Sryan_chen 		return ret;
1087499853d6Sryan_chen 	}
1088499853d6Sryan_chen 
1089499853d6Sryan_chen 	priv->hclk_rate = clk_get_rate(&hclk);
1090499853d6Sryan_chen 	clk_free(&hclk);
1091499853d6Sryan_chen 
1092499853d6Sryan_chen 	priv->max_hz = dev_read_u32_default(bus, "spi-max-frequency",
1093499853d6Sryan_chen 					    100000000);
1094499853d6Sryan_chen 
1095499853d6Sryan_chen 	priv->num_cs = dev_read_u32_default(bus, "num-cs", ASPEED_SPI_MAX_CS);
1096499853d6Sryan_chen 
1097499853d6Sryan_chen 	priv->flash_count = aspeed_spi_count_flash_devices(bus);
1098499853d6Sryan_chen 	if (priv->flash_count > priv->num_cs) {
1099499853d6Sryan_chen 		pr_err("%s has too many flash devices: %d\n", bus->name,
1100499853d6Sryan_chen 		       priv->flash_count);
1101499853d6Sryan_chen 		return -EINVAL;
1102499853d6Sryan_chen 	}
1103499853d6Sryan_chen 
1104499853d6Sryan_chen 	if (!priv->flash_count) {
1105499853d6Sryan_chen 		pr_err("%s has no flash devices ?!\n", bus->name);
1106499853d6Sryan_chen 		return -ENODEV;
1107499853d6Sryan_chen 	}
1108499853d6Sryan_chen 
11097d182336Sryan_chen 	if (device_is_compatible(bus, "aspeed,ast2600-fmc") ||
1110f87fadc3Sryan_chen 			device_is_compatible(bus, "aspeed,ast2600-spi")) {
1111499853d6Sryan_chen 		priv->new_ver = 1;
1112499853d6Sryan_chen 	}
1113499853d6Sryan_chen 
1114499853d6Sryan_chen 	/*
1115499853d6Sryan_chen 	 * There are some slight differences between the FMC and the
1116499853d6Sryan_chen 	 * SPI controllers
1117499853d6Sryan_chen 	 */
1118499853d6Sryan_chen 	priv->is_fmc = dev_get_driver_data(bus);
1119499853d6Sryan_chen 
1120499853d6Sryan_chen 	ret = aspeed_spi_controller_init(priv);
1121499853d6Sryan_chen 	if (ret)
1122499853d6Sryan_chen 		return ret;
1123499853d6Sryan_chen 
1124499853d6Sryan_chen 	debug("%s probed regs=%p ahb_base=%p max-hz=%d cs=%d seq=%d\n",
1125499853d6Sryan_chen 	      bus->name, priv->regs, priv->ahb_base, priv->max_hz,
1126499853d6Sryan_chen 	      priv->flash_count, bus->seq);
1127499853d6Sryan_chen 
1128499853d6Sryan_chen 	return 0;
1129499853d6Sryan_chen }
1130499853d6Sryan_chen 
1131499853d6Sryan_chen static const struct dm_spi_ops aspeed_spi_ops = {
1132499853d6Sryan_chen 	.claim_bus	= aspeed_spi_claim_bus,
1133499853d6Sryan_chen 	.release_bus	= aspeed_spi_release_bus,
1134499853d6Sryan_chen 	.set_mode	= aspeed_spi_set_mode,
1135499853d6Sryan_chen 	.set_speed	= aspeed_spi_set_speed,
1136499853d6Sryan_chen 	.xfer		= aspeed_spi_xfer,
1137499853d6Sryan_chen };
1138499853d6Sryan_chen 
1139499853d6Sryan_chen static const struct udevice_id aspeed_spi_ids[] = {
1140499853d6Sryan_chen 	{ .compatible = "aspeed,ast2600-fmc", .data = 1 },
1141499853d6Sryan_chen 	{ .compatible = "aspeed,ast2600-spi", .data = 0 },
1142499853d6Sryan_chen 	{ .compatible = "aspeed,ast2500-fmc", .data = 1 },
1143499853d6Sryan_chen 	{ .compatible = "aspeed,ast2500-spi", .data = 0 },
1144c4475966Sryan_chen 	{ .compatible = "aspeed,ast2400-fmc", .data = 1 },
1145499853d6Sryan_chen 	{ }
1146499853d6Sryan_chen };
1147499853d6Sryan_chen 
1148499853d6Sryan_chen U_BOOT_DRIVER(aspeed_spi) = {
1149499853d6Sryan_chen 	.name = "aspeed_spi",
1150499853d6Sryan_chen 	.id = UCLASS_SPI,
1151499853d6Sryan_chen 	.of_match = aspeed_spi_ids,
1152499853d6Sryan_chen 	.ops = &aspeed_spi_ops,
1153499853d6Sryan_chen 	.priv_auto_alloc_size = sizeof(struct aspeed_spi_priv),
1154499853d6Sryan_chen 	.child_pre_probe = aspeed_spi_child_pre_probe,
1155499853d6Sryan_chen 	.bind  = aspeed_spi_bind,
1156499853d6Sryan_chen 	.probe = aspeed_spi_probe,
1157499853d6Sryan_chen };
1158