xref: /openbmc/u-boot/drivers/misc/aspeed-fsi.c (revision e87eb2705bcb5850b6af8ca79d3ba1d6a51f0a26)
1*460fdfe6Sryan_chen // SPDX-License-Identifier: GPL-2.0+
2*460fdfe6Sryan_chen // Copyright (C) IBM Corporation 2018
3*460fdfe6Sryan_chen // FSI master driver for AST2600
4*460fdfe6Sryan_chen 
5*460fdfe6Sryan_chen #include <linux/delay.h>
6*460fdfe6Sryan_chen #include <linux/io.h>
7*460fdfe6Sryan_chen #include <linux/iopoll.h>
8*460fdfe6Sryan_chen #include <linux/bug.h>
9*460fdfe6Sryan_chen #include <linux/bitops.h>
10*460fdfe6Sryan_chen 
11*460fdfe6Sryan_chen #include <common.h>
12*460fdfe6Sryan_chen #include <clk.h>
13*460fdfe6Sryan_chen 
14*460fdfe6Sryan_chen #include <dm/device.h>
15*460fdfe6Sryan_chen #include <dm/fdtaddr.h>
16*460fdfe6Sryan_chen 
17*460fdfe6Sryan_chen /* Control Registers */
18*460fdfe6Sryan_chen #define FSI_MMODE		0x0		/* R/W: mode */
19*460fdfe6Sryan_chen #define FSI_MDLYR		0x4		/* R/W: delay */
20*460fdfe6Sryan_chen #define FSI_MCRSP		0x8		/* R/W: clock rate */
21*460fdfe6Sryan_chen #define FSI_MENP0		0x10		/* R/W: enable */
22*460fdfe6Sryan_chen #define FSI_MLEVP0		0x18		/* R: plug detect */
23*460fdfe6Sryan_chen #define FSI_MSENP0		0x18		/* S: Set enable */
24*460fdfe6Sryan_chen #define FSI_MCENP0		0x20		/* C: Clear enable */
25*460fdfe6Sryan_chen #define FSI_MAEB		0x70		/* R: Error address */
26*460fdfe6Sryan_chen #define FSI_MVER		0x74		/* R: master version/type */
27*460fdfe6Sryan_chen #define FSI_MSTAP0		0xd0		/* R: Port status */
28*460fdfe6Sryan_chen #define FSI_MRESP0		0xd0		/* W: Port reset */
29*460fdfe6Sryan_chen #define FSI_MESRB0		0x1d0		/* R: Master error status */
30*460fdfe6Sryan_chen #define FSI_MRESB0		0x1d0		/* W: Reset bridge */
31*460fdfe6Sryan_chen #define FSI_MSCSB0	 	0x1d4		/* R: Master sub command stack */
32*460fdfe6Sryan_chen #define FSI_MATRB0	 	0x1d8		/* R: Master address trace */
33*460fdfe6Sryan_chen #define FSI_MDTRB0	 	0x1dc		/* R: Master data trace */
34*460fdfe6Sryan_chen #define FSI_MECTRL		0x2e0		/* W: Error control */
35*460fdfe6Sryan_chen 
36*460fdfe6Sryan_chen /* MMODE: Mode control */
37*460fdfe6Sryan_chen #define FSI_MMODE_EIP		0x80000000	/* Enable interrupt polling */
38*460fdfe6Sryan_chen #define FSI_MMODE_ECRC		0x40000000	/* Enable error recovery */
39*460fdfe6Sryan_chen #define FSI_MMODE_RELA		0x20000000	/* Enable relative address commands */
40*460fdfe6Sryan_chen #define FSI_MMODE_EPC		0x10000000	/* Enable parity checking */
41*460fdfe6Sryan_chen #define FSI_MMODE_P8_TO_LSB	0x00000010	/* Timeout value LSB */
42*460fdfe6Sryan_chen 						/*   MSB=1, LSB=0 is 0.8 ms */
43*460fdfe6Sryan_chen 						/*   MSB=0, LSB=1 is 0.9 ms */
44*460fdfe6Sryan_chen #define FSI_MMODE_CRS0SHFT	18		/* Clk rate selection 0 shift */
45*460fdfe6Sryan_chen #define FSI_MMODE_CRS0MASK	0x3ff		/* Clk rate selection 0 mask */
46*460fdfe6Sryan_chen #define FSI_MMODE_CRS1SHFT	8		/* Clk rate selection 1 shift */
47*460fdfe6Sryan_chen #define FSI_MMODE_CRS1MASK	0x3ff		/* Clk rate selection 1 mask */
48*460fdfe6Sryan_chen 
49*460fdfe6Sryan_chen /* MRESB: Reset brindge */
50*460fdfe6Sryan_chen #define FSI_MRESB_RST_GEN	0x80000000	/* General reset */
51*460fdfe6Sryan_chen #define FSI_MRESB_RST_ERR	0x40000000	/* Error Reset */
52*460fdfe6Sryan_chen 
53*460fdfe6Sryan_chen /* MRESB: Reset port */
54*460fdfe6Sryan_chen #define FSI_MRESP_RST_ALL_MASTER 0x20000000	/* Reset all FSI masters */
55*460fdfe6Sryan_chen #define FSI_MRESP_RST_ALL_LINK	0x10000000	/* Reset all FSI port contr. */
56*460fdfe6Sryan_chen #define FSI_MRESP_RST_MCR	0x08000000	/* Reset FSI master reg. */
57*460fdfe6Sryan_chen #define FSI_MRESP_RST_PYE	0x04000000	/* Reset FSI parity error */
58*460fdfe6Sryan_chen #define FSI_MRESP_RST_ALL	0xfc000000	/* Reset any error */
59*460fdfe6Sryan_chen 
60*460fdfe6Sryan_chen /* MECTRL: Error control */
61*460fdfe6Sryan_chen #define FSI_MECTRL_EOAE		0x8000		/* Enable machine check when */
62*460fdfe6Sryan_chen 						/* master 0 in error */
63*460fdfe6Sryan_chen #define FSI_MECTRL_P8_AUTO_TERM	0x4000		/* Auto terminate */
64*460fdfe6Sryan_chen 
65*460fdfe6Sryan_chen #define FSI_ENGID_HUB_MASTER		0x1c
66*460fdfe6Sryan_chen #define FSI_HUB_LINK_OFFSET		0x80000
67*460fdfe6Sryan_chen #define FSI_HUB_LINK_SIZE		0x80000
68*460fdfe6Sryan_chen #define FSI_HUB_MASTER_MAX_LINKS	8
69*460fdfe6Sryan_chen 
70*460fdfe6Sryan_chen #define FSI_LINK_ENABLE_SETUP_TIME	10	/* in mS */
71*460fdfe6Sryan_chen 
72*460fdfe6Sryan_chen #define FSI_NUM_DEBUGFS_ENTRIES		17
73*460fdfe6Sryan_chen 
74*460fdfe6Sryan_chen #define DEFAULT_DIVISOR			14
75*460fdfe6Sryan_chen 
76*460fdfe6Sryan_chen struct fsi_master_aspeed;
77*460fdfe6Sryan_chen 
78*460fdfe6Sryan_chen struct fsi_master_aspeed {
79*460fdfe6Sryan_chen 	struct udevice		*dev;
80*460fdfe6Sryan_chen 	void __iomem		*base;
81*460fdfe6Sryan_chen 	struct clk		clk;
82*460fdfe6Sryan_chen };
83*460fdfe6Sryan_chen 
84*460fdfe6Sryan_chen #define to_fsi_master_aspeed(m) \
85*460fdfe6Sryan_chen 	container_of(m, struct fsi_master_aspeed, master)
86*460fdfe6Sryan_chen 
87*460fdfe6Sryan_chen /* Control register (size 0x400) */
88*460fdfe6Sryan_chen static const u32 ctrl_base = 0x80000000;
89*460fdfe6Sryan_chen 
90*460fdfe6Sryan_chen static const u32 fsi_base = 0xa0000000;
91*460fdfe6Sryan_chen 
92*460fdfe6Sryan_chen #define OPB_FSI_VER	0x00
93*460fdfe6Sryan_chen #define OPB_TRIGGER	0x04
94*460fdfe6Sryan_chen #define OPB_CTRL_BASE	0x08
95*460fdfe6Sryan_chen #define OPB_FSI_BASE	0x0c
96*460fdfe6Sryan_chen #define OPB_CLK_SYNC	0x3c
97*460fdfe6Sryan_chen #define OPB_IRQ_CLEAR	0x40
98*460fdfe6Sryan_chen #define OPB_IRQ_MASK	0x44
99*460fdfe6Sryan_chen #define OPB_IRQ_STATUS	0x48
100*460fdfe6Sryan_chen 
101*460fdfe6Sryan_chen #define OPB0_SELECT	0x10
102*460fdfe6Sryan_chen #define OPB0_RW		0x14
103*460fdfe6Sryan_chen #define OPB0_XFER_SIZE	0x18
104*460fdfe6Sryan_chen #define OPB0_FSI_ADDR	0x1c
105*460fdfe6Sryan_chen #define OPB0_FSI_DATA_W	0x20
106*460fdfe6Sryan_chen #define OPB0_STATUS	0x80
107*460fdfe6Sryan_chen /* half world */
108*460fdfe6Sryan_chen #define  STATUS_HW_ACK	BIT(0)
109*460fdfe6Sryan_chen /* full word */
110*460fdfe6Sryan_chen #define  STATUS_FW_ACK	BIT(1)
111*460fdfe6Sryan_chen #define  STATUS_ERR_ACK	BIT(2)
112*460fdfe6Sryan_chen #define OPB0_FSI_DATA_R	0x84
113*460fdfe6Sryan_chen 
114*460fdfe6Sryan_chen #define OPB0_W_ENDIAN	0x4c
115*460fdfe6Sryan_chen #define OPB0_R_ENDIAN	0x5c
116*460fdfe6Sryan_chen 
117*460fdfe6Sryan_chen /* OPB_IRQ_MASK */
118*460fdfe6Sryan_chen #define OPB1_XFER_ACK_EN BIT(17)
119*460fdfe6Sryan_chen #define OPB0_XFER_ACK_EN BIT(16)
120*460fdfe6Sryan_chen 
121*460fdfe6Sryan_chen #define OPB_IRQ_CH0_DMA_EOT		BIT(0)
122*460fdfe6Sryan_chen #define OPB_IRQ_CH1_DMA_EOT		BIT(1)
123*460fdfe6Sryan_chen #define OPB_IRQ_CH2_DMA_EOT		BIT(2)
124*460fdfe6Sryan_chen #define OPB_IRQ_CH3_DMA_EOT		BIT(3)
125*460fdfe6Sryan_chen #define OPB_IRQ_CH0_DMA_FIFO_FULL	BIT(4)
126*460fdfe6Sryan_chen #define OPB_IRQ_CH1_DMA_FIFO_FULL	BIT(5)
127*460fdfe6Sryan_chen #define OPB_IRQ_CH2_DMA_FIFO_FULL	BIT(6)
128*460fdfe6Sryan_chen #define OPB_IRQ_CH3_DMA_FIFO_FULL	BIT(7)
129*460fdfe6Sryan_chen #define OPB_IRQ_CH0_DMA_FIFO_EMPTY	BIT(8)
130*460fdfe6Sryan_chen #define OPB_IRQ_CH1_DMA_FIFO_EMPTY	BIT(9)
131*460fdfe6Sryan_chen #define OPB_IRQ_CH2_DMA_FIFO_EMPTY	BIT(10)
132*460fdfe6Sryan_chen #define OPB_IRQ_CH3_DMA_FIFO_EMPTY	BIT(11)
133*460fdfe6Sryan_chen #define OPB_IRQ_CH0_DMA_TCONT_DONE	BIT(12)
134*460fdfe6Sryan_chen #define OPB_IRQ_CH1_DMA_TCONT_DONE	BIT(13)
135*460fdfe6Sryan_chen #define OPB_IRQ_CH2_DMA_TCONT_DONE	BIT(14)
136*460fdfe6Sryan_chen #define OPB_IRQ_CH3_DMA_TCONT_DONE	BIT(15)
137*460fdfe6Sryan_chen #define OPB_IRQ_OPB1_XFER_ACK		BIT(16)
138*460fdfe6Sryan_chen #define OPB_IRQ_OPB0_XFER_ACK		BIT(17)
139*460fdfe6Sryan_chen #define OPB_IRQ_SLAVE0			BIT(18)
140*460fdfe6Sryan_chen #define OPB_IRQ_SLAVE1			BIT(19)
141*460fdfe6Sryan_chen #define OPB_IRQ_SLAVE2			BIT(20)
142*460fdfe6Sryan_chen #define OPB_IRQ_SLAVE3			BIT(21)
143*460fdfe6Sryan_chen #define OPB_IRQ_SLAVE4			BIT(22)
144*460fdfe6Sryan_chen #define OPB_IRQ_SLAVE5			BIT(23)
145*460fdfe6Sryan_chen #define OPB_IRQ_SLAVE6			BIT(24)
146*460fdfe6Sryan_chen #define OPB_IRQ_SLAVE7			BIT(25)
147*460fdfe6Sryan_chen #define OPB_IRQ_ANY_HOTPLUG		BIT(26)
148*460fdfe6Sryan_chen #define OPB_IRQ_ANY_PORT_ERROR		BIT(27)
149*460fdfe6Sryan_chen #define OPB_IRQ_ANY_MST_ERROR		BIT(28)
150*460fdfe6Sryan_chen 
151*460fdfe6Sryan_chen /* OPB_RW */
152*460fdfe6Sryan_chen #define CMD_READ	BIT(0)
153*460fdfe6Sryan_chen #define CMD_WRITE	0
154*460fdfe6Sryan_chen 
155*460fdfe6Sryan_chen /* OPBx_XFER_SIZE */
156*460fdfe6Sryan_chen #define XFER_WORD	(BIT(1) | BIT(0))
157*460fdfe6Sryan_chen #define XFER_NIBBLE	(BIT(0))
158*460fdfe6Sryan_chen #define XFER_BYTE	(0)
159*460fdfe6Sryan_chen 
160*460fdfe6Sryan_chen #define trace_aspeed_fsi_opb_write(addr, val, size, status, reg) \
161*460fdfe6Sryan_chen 	debug("aspeed_opb_write: addr %08x val %08x size %d status %08x reg %08x\n", \
162*460fdfe6Sryan_chen 			addr, val, size, status, reg)
163*460fdfe6Sryan_chen 
164*460fdfe6Sryan_chen #define trace_aspeed_fsi_opb_read(addr, size, result, status, reg) \
165*460fdfe6Sryan_chen 	debug("aspeed_opb_read: addr %08x size %d result %08x status %08x reg %08x\n", \
166*460fdfe6Sryan_chen 			addr, size, result, status, reg)
167*460fdfe6Sryan_chen 
168*460fdfe6Sryan_chen #define trace_aspeed_fsi_opb_error(mresp0, mstap0, mesrb0) \
169*460fdfe6Sryan_chen 	debug("aspeed_opb_error: mresp %08x mstap %08x mesrb %08x\n", \
170*460fdfe6Sryan_chen 			mresp0, mstap0, mesrb0)
171*460fdfe6Sryan_chen 
172*460fdfe6Sryan_chen #define trace_aspeed_fsi_opb_error_enabled() (_DEBUG)
173*460fdfe6Sryan_chen 
opb_write(struct fsi_master_aspeed * aspeed,uint32_t addr,uint32_t val,size_t size)174*460fdfe6Sryan_chen static u32 opb_write(struct fsi_master_aspeed *aspeed, uint32_t addr,
175*460fdfe6Sryan_chen 		     uint32_t val, size_t size)
176*460fdfe6Sryan_chen {
177*460fdfe6Sryan_chen 	void __iomem *base = aspeed->base;
178*460fdfe6Sryan_chen 	u32 reg, ret, status;
179*460fdfe6Sryan_chen 
180*460fdfe6Sryan_chen 	/* TODO: implement other sizes, see 0x18 */
181*460fdfe6Sryan_chen 	WARN_ON(size != 4);
182*460fdfe6Sryan_chen 
183*460fdfe6Sryan_chen 	writel(CMD_WRITE, base + OPB0_RW);
184*460fdfe6Sryan_chen 	writel(XFER_WORD, base + OPB0_XFER_SIZE);
185*460fdfe6Sryan_chen 	writel(addr, base + OPB0_FSI_ADDR);
186*460fdfe6Sryan_chen 	writel(val, base + OPB0_FSI_DATA_W);
187*460fdfe6Sryan_chen 	writel(0x1, base + OPB_IRQ_CLEAR);
188*460fdfe6Sryan_chen 	writel(0x1, base + OPB_TRIGGER);
189*460fdfe6Sryan_chen 
190*460fdfe6Sryan_chen 	ret = readl_poll_timeout(base + OPB_IRQ_STATUS, reg,
191*460fdfe6Sryan_chen 				(reg & OPB0_XFER_ACK_EN) != 0,
192*460fdfe6Sryan_chen 				10000);
193*460fdfe6Sryan_chen 
194*460fdfe6Sryan_chen 	status = readl(base + OPB0_STATUS);
195*460fdfe6Sryan_chen 
196*460fdfe6Sryan_chen 	trace_aspeed_fsi_opb_write(addr, val, size, status, reg);
197*460fdfe6Sryan_chen 
198*460fdfe6Sryan_chen 	/* Return error when poll timed out */
199*460fdfe6Sryan_chen 	if (ret)
200*460fdfe6Sryan_chen 		return ret;
201*460fdfe6Sryan_chen 
202*460fdfe6Sryan_chen 	/* Command failed, master will reset */
203*460fdfe6Sryan_chen 	if (status & STATUS_ERR_ACK)
204*460fdfe6Sryan_chen 		return -EIO;
205*460fdfe6Sryan_chen 
206*460fdfe6Sryan_chen 	return 0;
207*460fdfe6Sryan_chen }
208*460fdfe6Sryan_chen 
opb_read(struct fsi_master_aspeed * aspeed,uint32_t addr,size_t size,u32 * out)209*460fdfe6Sryan_chen static int opb_read(struct fsi_master_aspeed *aspeed, uint32_t addr,
210*460fdfe6Sryan_chen 		    size_t size, u32 *out)
211*460fdfe6Sryan_chen {
212*460fdfe6Sryan_chen 	void __iomem *base = aspeed->base;
213*460fdfe6Sryan_chen 	u32 result, reg;
214*460fdfe6Sryan_chen 	int status, ret;
215*460fdfe6Sryan_chen 
216*460fdfe6Sryan_chen 	/* TODO: implement other sizes, see 0x18 */
217*460fdfe6Sryan_chen 	WARN_ON(size != 4);
218*460fdfe6Sryan_chen 
219*460fdfe6Sryan_chen 	writel(CMD_READ, base + OPB0_RW);
220*460fdfe6Sryan_chen 	writel(XFER_WORD, base + OPB0_XFER_SIZE);
221*460fdfe6Sryan_chen 	writel(addr, base + OPB0_FSI_ADDR);
222*460fdfe6Sryan_chen 	writel(0x1, base + OPB_IRQ_CLEAR);
223*460fdfe6Sryan_chen 	writel(0x1, base + OPB_TRIGGER);
224*460fdfe6Sryan_chen 
225*460fdfe6Sryan_chen 	ret = readl_poll_timeout(base + OPB_IRQ_STATUS, reg,
226*460fdfe6Sryan_chen 			   (reg & OPB0_XFER_ACK_EN) != 0,
227*460fdfe6Sryan_chen 			   10000);
228*460fdfe6Sryan_chen 
229*460fdfe6Sryan_chen 	status = readl(base + OPB0_STATUS);
230*460fdfe6Sryan_chen 
231*460fdfe6Sryan_chen 	result = readl(base + OPB0_FSI_DATA_R);
232*460fdfe6Sryan_chen 
233*460fdfe6Sryan_chen 	trace_aspeed_fsi_opb_read(addr, size, result,
234*460fdfe6Sryan_chen 			readl(base + OPB0_STATUS),
235*460fdfe6Sryan_chen 			reg);
236*460fdfe6Sryan_chen 
237*460fdfe6Sryan_chen 	/* Return error when poll timed out */
238*460fdfe6Sryan_chen 	if (ret)
239*460fdfe6Sryan_chen 		return ret;
240*460fdfe6Sryan_chen 
241*460fdfe6Sryan_chen 	/* Command failed, master will reset */
242*460fdfe6Sryan_chen 	if (status & STATUS_ERR_ACK)
243*460fdfe6Sryan_chen 		return -EIO;
244*460fdfe6Sryan_chen 
245*460fdfe6Sryan_chen 	if (out)
246*460fdfe6Sryan_chen 		*out = result;
247*460fdfe6Sryan_chen 
248*460fdfe6Sryan_chen 	return 0;
249*460fdfe6Sryan_chen }
250*460fdfe6Sryan_chen 
check_errors(struct fsi_master_aspeed * aspeed,int err)251*460fdfe6Sryan_chen static int check_errors(struct fsi_master_aspeed *aspeed, int err)
252*460fdfe6Sryan_chen {
253*460fdfe6Sryan_chen 	int ret;
254*460fdfe6Sryan_chen 
255*460fdfe6Sryan_chen 	 if (trace_aspeed_fsi_opb_error_enabled()) {
256*460fdfe6Sryan_chen 		 __be32 mresp0, mstap0, mesrb0;
257*460fdfe6Sryan_chen 
258*460fdfe6Sryan_chen 		 opb_read(aspeed, ctrl_base + FSI_MRESP0, 4, &mresp0);
259*460fdfe6Sryan_chen 		 opb_read(aspeed, ctrl_base + FSI_MSTAP0, 4, &mstap0);
260*460fdfe6Sryan_chen 		 opb_read(aspeed, ctrl_base + FSI_MESRB0, 4, &mesrb0);
261*460fdfe6Sryan_chen 
262*460fdfe6Sryan_chen 		 trace_aspeed_fsi_opb_error(
263*460fdfe6Sryan_chen 				 be32_to_cpu(mresp0),
264*460fdfe6Sryan_chen 				 be32_to_cpu(mstap0),
265*460fdfe6Sryan_chen 				 be32_to_cpu(mesrb0));
266*460fdfe6Sryan_chen 	 };
267*460fdfe6Sryan_chen 
268*460fdfe6Sryan_chen 	if (err == -EIO) {
269*460fdfe6Sryan_chen 		/* Check MAEB (0x70) ? */
270*460fdfe6Sryan_chen 
271*460fdfe6Sryan_chen 		/* Then clear errors in master */
272*460fdfe6Sryan_chen 		ret = opb_write(aspeed, ctrl_base + 0xd0,
273*460fdfe6Sryan_chen 				cpu_to_be32(0x20000000), 4);
274*460fdfe6Sryan_chen 		if (ret) {
275*460fdfe6Sryan_chen 			/* TODO: log? return different code? */
276*460fdfe6Sryan_chen 			return ret;
277*460fdfe6Sryan_chen 		}
278*460fdfe6Sryan_chen 		/* TODO: confirm that 0x70 was okay */
279*460fdfe6Sryan_chen 	}
280*460fdfe6Sryan_chen 
281*460fdfe6Sryan_chen 	/* This will pass through timeout errors */
282*460fdfe6Sryan_chen 	return err;
283*460fdfe6Sryan_chen }
284*460fdfe6Sryan_chen 
aspeed_fsi_read(struct fsi_master_aspeed * aspeed,int link,uint32_t addr,void * val,size_t size)285*460fdfe6Sryan_chen int aspeed_fsi_read(struct fsi_master_aspeed *aspeed, int link,
286*460fdfe6Sryan_chen 		    uint32_t addr, void *val, size_t size)
287*460fdfe6Sryan_chen {
288*460fdfe6Sryan_chen 	int ret;
289*460fdfe6Sryan_chen 
290*460fdfe6Sryan_chen 	addr += link * FSI_HUB_LINK_SIZE;
291*460fdfe6Sryan_chen 	ret = opb_read(aspeed, fsi_base + addr, size, val);
292*460fdfe6Sryan_chen 
293*460fdfe6Sryan_chen 	ret = check_errors(aspeed, ret);
294*460fdfe6Sryan_chen 	if (ret)
295*460fdfe6Sryan_chen 		return ret;
296*460fdfe6Sryan_chen 
297*460fdfe6Sryan_chen 	return 0;
298*460fdfe6Sryan_chen }
299*460fdfe6Sryan_chen 
aspeed_fsi_write(struct fsi_master_aspeed * aspeed,int link,uint8_t id,uint32_t addr,const void * val,size_t size)300*460fdfe6Sryan_chen int aspeed_fsi_write(struct fsi_master_aspeed *aspeed, int link,
301*460fdfe6Sryan_chen 			uint8_t id, uint32_t addr, const void *val, size_t size)
302*460fdfe6Sryan_chen {
303*460fdfe6Sryan_chen 	int ret;
304*460fdfe6Sryan_chen 
305*460fdfe6Sryan_chen 	if (id != 0)
306*460fdfe6Sryan_chen 		return -EINVAL;
307*460fdfe6Sryan_chen 
308*460fdfe6Sryan_chen 	addr += link * FSI_HUB_LINK_SIZE;
309*460fdfe6Sryan_chen 	ret = opb_write(aspeed, fsi_base + addr, *(uint32_t *)val, size);
310*460fdfe6Sryan_chen 
311*460fdfe6Sryan_chen 	ret = check_errors(aspeed, ret);
312*460fdfe6Sryan_chen 	if (ret)
313*460fdfe6Sryan_chen 		return ret;
314*460fdfe6Sryan_chen 
315*460fdfe6Sryan_chen 	return 0;
316*460fdfe6Sryan_chen }
317*460fdfe6Sryan_chen 
aspeed_fsi_link_enable(struct fsi_master_aspeed * aspeed,int link)318*460fdfe6Sryan_chen int aspeed_fsi_link_enable(struct fsi_master_aspeed *aspeed, int link)
319*460fdfe6Sryan_chen {
320*460fdfe6Sryan_chen 	int idx, bit, ret;
321*460fdfe6Sryan_chen 	__be32 reg, result;
322*460fdfe6Sryan_chen 
323*460fdfe6Sryan_chen 	idx = link / 32;
324*460fdfe6Sryan_chen 	bit = link % 32;
325*460fdfe6Sryan_chen 
326*460fdfe6Sryan_chen 	reg = cpu_to_be32(0x80000000 >> bit);
327*460fdfe6Sryan_chen 
328*460fdfe6Sryan_chen 	result = opb_write(aspeed, ctrl_base + FSI_MSENP0 + (4 * idx),
329*460fdfe6Sryan_chen 			reg, 4);
330*460fdfe6Sryan_chen 
331*460fdfe6Sryan_chen 	mdelay(FSI_LINK_ENABLE_SETUP_TIME);
332*460fdfe6Sryan_chen 
333*460fdfe6Sryan_chen 	ret = opb_read(aspeed, ctrl_base + FSI_MENP0 + (4 * idx),
334*460fdfe6Sryan_chen 			4, &result);
335*460fdfe6Sryan_chen 	if (ret)
336*460fdfe6Sryan_chen 		return ret;
337*460fdfe6Sryan_chen 
338*460fdfe6Sryan_chen 	if (result != reg) {
339*460fdfe6Sryan_chen 		dev_err(aspeed->dev, "%s failed: %08x\n", __func__, result);
340*460fdfe6Sryan_chen 		return -EIO;
341*460fdfe6Sryan_chen 	}
342*460fdfe6Sryan_chen 
343*460fdfe6Sryan_chen 	return 0;
344*460fdfe6Sryan_chen }
345*460fdfe6Sryan_chen 
aspeed_fsi_break(struct fsi_master_aspeed * aspeed,int link)346*460fdfe6Sryan_chen int aspeed_fsi_break(struct fsi_master_aspeed *aspeed, int link)
347*460fdfe6Sryan_chen {
348*460fdfe6Sryan_chen 	uint32_t addr;
349*460fdfe6Sryan_chen 	__be32 cmd;
350*460fdfe6Sryan_chen 	int rc;
351*460fdfe6Sryan_chen 
352*460fdfe6Sryan_chen 	addr = 0x0;
353*460fdfe6Sryan_chen 	cmd = cpu_to_be32(0xc0de0000);
354*460fdfe6Sryan_chen 
355*460fdfe6Sryan_chen 	dev_dbg(aspeed->dev, "sending break to link %d\n", link);
356*460fdfe6Sryan_chen 
357*460fdfe6Sryan_chen 	rc = aspeed_fsi_write(aspeed, link, 0, addr, &cmd, 4);
358*460fdfe6Sryan_chen 
359*460fdfe6Sryan_chen 	dev_dbg(aspeed->dev, "break done (%d)\n", rc);
360*460fdfe6Sryan_chen 
361*460fdfe6Sryan_chen 	return rc;
362*460fdfe6Sryan_chen }
363*460fdfe6Sryan_chen 
aspeed_fsi_status(struct fsi_master_aspeed * aspeed)364*460fdfe6Sryan_chen void aspeed_fsi_status(struct fsi_master_aspeed *aspeed)
365*460fdfe6Sryan_chen {
366*460fdfe6Sryan_chen 	__be32 mmode, mresp0, mstap0, mesrb0;
367*460fdfe6Sryan_chen 
368*460fdfe6Sryan_chen 	printf("%s\n", aspeed->dev->name);
369*460fdfe6Sryan_chen 
370*460fdfe6Sryan_chen 	opb_read(aspeed, ctrl_base + FSI_MMODE, 4, &mmode);
371*460fdfe6Sryan_chen 	opb_read(aspeed, ctrl_base + FSI_MRESP0, 4, &mresp0);
372*460fdfe6Sryan_chen 	opb_read(aspeed, ctrl_base + FSI_MSTAP0, 4, &mstap0);
373*460fdfe6Sryan_chen 	opb_read(aspeed, ctrl_base + FSI_MESRB0, 4, &mesrb0);
374*460fdfe6Sryan_chen 
375*460fdfe6Sryan_chen 	printf("mmode %08x\n", be32_to_cpu(mmode));
376*460fdfe6Sryan_chen 	printf("mresp %08x\n", be32_to_cpu(mresp0));
377*460fdfe6Sryan_chen 	printf("mstap %08x\n", be32_to_cpu(mstap0));
378*460fdfe6Sryan_chen 	printf("mesrb %08x\n", be32_to_cpu(mesrb0));
379*460fdfe6Sryan_chen }
380*460fdfe6Sryan_chen 
aspeed_fsi_divisor(struct fsi_master_aspeed * aspeed,uint16_t divisor)381*460fdfe6Sryan_chen int aspeed_fsi_divisor(struct fsi_master_aspeed *aspeed, uint16_t divisor)
382*460fdfe6Sryan_chen {
383*460fdfe6Sryan_chen 	__be32 reg;
384*460fdfe6Sryan_chen 	u32 mmode;
385*460fdfe6Sryan_chen 	int rc;
386*460fdfe6Sryan_chen 
387*460fdfe6Sryan_chen 	rc = opb_read(aspeed, ctrl_base + FSI_MMODE, 4, &reg);
388*460fdfe6Sryan_chen 	if (rc)
389*460fdfe6Sryan_chen 		return rc;
390*460fdfe6Sryan_chen 
391*460fdfe6Sryan_chen 	mmode = be32_to_cpu(reg);
392*460fdfe6Sryan_chen 
393*460fdfe6Sryan_chen 	if (!divisor)
394*460fdfe6Sryan_chen 		return (mmode >> 18) & 0x3ff;
395*460fdfe6Sryan_chen 
396*460fdfe6Sryan_chen 	if (divisor > 0x3ff)
397*460fdfe6Sryan_chen 		return -EINVAL;
398*460fdfe6Sryan_chen 
399*460fdfe6Sryan_chen 	mmode &= ~(0x3ff << 18);
400*460fdfe6Sryan_chen 	mmode |= (divisor & 0x3ff) << 18;
401*460fdfe6Sryan_chen 
402*460fdfe6Sryan_chen 	return opb_write(aspeed, ctrl_base + FSI_MMODE, cpu_to_be32(mmode), 4);
403*460fdfe6Sryan_chen }
404*460fdfe6Sryan_chen 
405*460fdfe6Sryan_chen /* mmode encoders */
fsi_mmode_crs0(u32 x)406*460fdfe6Sryan_chen static inline u32 fsi_mmode_crs0(u32 x)
407*460fdfe6Sryan_chen {
408*460fdfe6Sryan_chen 	return (x & FSI_MMODE_CRS0MASK) << FSI_MMODE_CRS0SHFT;
409*460fdfe6Sryan_chen }
410*460fdfe6Sryan_chen 
fsi_mmode_crs1(u32 x)411*460fdfe6Sryan_chen static inline u32 fsi_mmode_crs1(u32 x)
412*460fdfe6Sryan_chen {
413*460fdfe6Sryan_chen 	return (x & FSI_MMODE_CRS1MASK) << FSI_MMODE_CRS1SHFT;
414*460fdfe6Sryan_chen }
415*460fdfe6Sryan_chen 
aspeed_fsi_init(struct fsi_master_aspeed * aspeed)416*460fdfe6Sryan_chen static int aspeed_fsi_init(struct fsi_master_aspeed *aspeed)
417*460fdfe6Sryan_chen {
418*460fdfe6Sryan_chen 	__be32 reg;
419*460fdfe6Sryan_chen 
420*460fdfe6Sryan_chen 	reg = cpu_to_be32(FSI_MRESP_RST_ALL_MASTER | FSI_MRESP_RST_ALL_LINK
421*460fdfe6Sryan_chen 			| FSI_MRESP_RST_MCR | FSI_MRESP_RST_PYE);
422*460fdfe6Sryan_chen 	opb_write(aspeed, ctrl_base + FSI_MRESP0, reg, 4);
423*460fdfe6Sryan_chen 
424*460fdfe6Sryan_chen 	/* Initialize the MFSI (hub master) engine */
425*460fdfe6Sryan_chen 	reg = cpu_to_be32(FSI_MRESP_RST_ALL_MASTER | FSI_MRESP_RST_ALL_LINK
426*460fdfe6Sryan_chen 			| FSI_MRESP_RST_MCR | FSI_MRESP_RST_PYE);
427*460fdfe6Sryan_chen 	opb_write(aspeed, ctrl_base + FSI_MRESP0, reg, 4);
428*460fdfe6Sryan_chen 
429*460fdfe6Sryan_chen 	reg = cpu_to_be32(FSI_MECTRL_EOAE | FSI_MECTRL_P8_AUTO_TERM);
430*460fdfe6Sryan_chen 	opb_write(aspeed, ctrl_base + FSI_MECTRL, reg, 4);
431*460fdfe6Sryan_chen 
432*460fdfe6Sryan_chen 	reg = cpu_to_be32(FSI_MMODE_ECRC | FSI_MMODE_EPC | FSI_MMODE_RELA
433*460fdfe6Sryan_chen 			| fsi_mmode_crs0(DEFAULT_DIVISOR)
434*460fdfe6Sryan_chen 			| fsi_mmode_crs1(DEFAULT_DIVISOR)
435*460fdfe6Sryan_chen 			| FSI_MMODE_P8_TO_LSB);
436*460fdfe6Sryan_chen 	opb_write(aspeed, ctrl_base + FSI_MMODE, reg, 4);
437*460fdfe6Sryan_chen 
438*460fdfe6Sryan_chen 	reg = cpu_to_be32(0xffff0000);
439*460fdfe6Sryan_chen 	opb_write(aspeed, ctrl_base + FSI_MDLYR, reg, 4);
440*460fdfe6Sryan_chen 
441*460fdfe6Sryan_chen 	reg = cpu_to_be32(~0);
442*460fdfe6Sryan_chen 	opb_write(aspeed, ctrl_base + FSI_MSENP0, reg, 4);
443*460fdfe6Sryan_chen 
444*460fdfe6Sryan_chen 	/* Leave enabled long enough for master logic to set up */
445*460fdfe6Sryan_chen 	mdelay(FSI_LINK_ENABLE_SETUP_TIME);
446*460fdfe6Sryan_chen 
447*460fdfe6Sryan_chen 	opb_write(aspeed, ctrl_base + FSI_MCENP0, reg, 4);
448*460fdfe6Sryan_chen 
449*460fdfe6Sryan_chen 	opb_read(aspeed, ctrl_base + FSI_MAEB, 4, NULL);
450*460fdfe6Sryan_chen 
451*460fdfe6Sryan_chen 	reg = cpu_to_be32(FSI_MRESP_RST_ALL_MASTER | FSI_MRESP_RST_ALL_LINK);
452*460fdfe6Sryan_chen 	opb_write(aspeed, ctrl_base + FSI_MRESP0, reg, 4);
453*460fdfe6Sryan_chen 
454*460fdfe6Sryan_chen 	opb_read(aspeed, ctrl_base + FSI_MLEVP0, 4, NULL);
455*460fdfe6Sryan_chen 
456*460fdfe6Sryan_chen 	/* Reset the master bridge */
457*460fdfe6Sryan_chen 	reg = cpu_to_be32(FSI_MRESB_RST_GEN);
458*460fdfe6Sryan_chen 	opb_write(aspeed, ctrl_base + FSI_MRESB0, reg, 4);
459*460fdfe6Sryan_chen 
460*460fdfe6Sryan_chen 	reg = cpu_to_be32(FSI_MRESB_RST_ERR);
461*460fdfe6Sryan_chen 	opb_write(aspeed, ctrl_base + FSI_MRESB0, reg, 4);
462*460fdfe6Sryan_chen 
463*460fdfe6Sryan_chen 	return 0;
464*460fdfe6Sryan_chen }
465*460fdfe6Sryan_chen 
aspeed_fsi_probe(struct udevice * dev)466*460fdfe6Sryan_chen static int aspeed_fsi_probe(struct udevice *dev)
467*460fdfe6Sryan_chen {
468*460fdfe6Sryan_chen 	struct fsi_master_aspeed *aspeed = dev_get_priv(dev);
469*460fdfe6Sryan_chen 	int ret, links, reg;
470*460fdfe6Sryan_chen 	__be32 raw;
471*460fdfe6Sryan_chen 
472*460fdfe6Sryan_chen 	aspeed->dev = dev;
473*460fdfe6Sryan_chen 
474*460fdfe6Sryan_chen 	aspeed->base = (void *)devfdt_get_addr(dev);
475*460fdfe6Sryan_chen 
476*460fdfe6Sryan_chen 	ret = clk_get_by_index(dev, 0, &aspeed->clk);
477*460fdfe6Sryan_chen         if (ret < 0) {
478*460fdfe6Sryan_chen 		dev_err(dev, "Can't get clock for %s: %d\n", dev->name, ret);
479*460fdfe6Sryan_chen 		return ret;
480*460fdfe6Sryan_chen         }
481*460fdfe6Sryan_chen 
482*460fdfe6Sryan_chen 	ret = clk_enable(&aspeed->clk);
483*460fdfe6Sryan_chen         if (ret) {
484*460fdfe6Sryan_chen                 dev_err(dev, "failed to enable fsi clock (%d)\n", ret);
485*460fdfe6Sryan_chen                 return ret;
486*460fdfe6Sryan_chen         }
487*460fdfe6Sryan_chen 
488*460fdfe6Sryan_chen 	writel(0x1, aspeed->base + OPB_CLK_SYNC);
489*460fdfe6Sryan_chen 	writel(OPB1_XFER_ACK_EN | OPB0_XFER_ACK_EN,
490*460fdfe6Sryan_chen 			aspeed->base + OPB_IRQ_MASK);
491*460fdfe6Sryan_chen 
492*460fdfe6Sryan_chen 	writel(ctrl_base, aspeed->base + OPB_CTRL_BASE);
493*460fdfe6Sryan_chen 	writel(fsi_base, aspeed->base + OPB_FSI_BASE);
494*460fdfe6Sryan_chen 
495*460fdfe6Sryan_chen 	/* Set read data order */
496*460fdfe6Sryan_chen 	writel(0x00030b1b, aspeed->base + OPB0_R_ENDIAN);
497*460fdfe6Sryan_chen 
498*460fdfe6Sryan_chen 	/* Set write data order */
499*460fdfe6Sryan_chen 	writel(0x0011bb1b, aspeed->base + OPB0_W_ENDIAN);
500*460fdfe6Sryan_chen 	writel(0xffaa5500, aspeed->base + 0x50);
501*460fdfe6Sryan_chen 
502*460fdfe6Sryan_chen 	/*
503*460fdfe6Sryan_chen 	 * Select OPB0 for all operations.
504*460fdfe6Sryan_chen 	 * Will need to be reworked when enabling DMA or anything that uses
505*460fdfe6Sryan_chen 	 * OPB1.
506*460fdfe6Sryan_chen 	 */
507*460fdfe6Sryan_chen 	writel(0x1, aspeed->base + OPB0_SELECT);
508*460fdfe6Sryan_chen 
509*460fdfe6Sryan_chen 	ret = opb_read(aspeed, ctrl_base + FSI_MVER, 4, &raw);
510*460fdfe6Sryan_chen 	if (ret) {
511*460fdfe6Sryan_chen 		dev_err(&pdev->dev, "failed to read hub version\n");
512*460fdfe6Sryan_chen 		goto err;
513*460fdfe6Sryan_chen 	}
514*460fdfe6Sryan_chen 
515*460fdfe6Sryan_chen 	reg = be32_to_cpu(raw);
516*460fdfe6Sryan_chen 	links = (reg >> 8) & 0xff;
517*460fdfe6Sryan_chen 	dev_info(&pdev->dev, "hub version %08x (%d links)\n", reg, links);
518*460fdfe6Sryan_chen 
519*460fdfe6Sryan_chen 	aspeed_fsi_init(aspeed);
520*460fdfe6Sryan_chen 
521*460fdfe6Sryan_chen 	printf("FSI: probed %p\n", aspeed->base);
522*460fdfe6Sryan_chen 
523*460fdfe6Sryan_chen 	return 0;
524*460fdfe6Sryan_chen 
525*460fdfe6Sryan_chen err:
526*460fdfe6Sryan_chen 	clk_disable(&aspeed->clk);
527*460fdfe6Sryan_chen 	return ret;
528*460fdfe6Sryan_chen }
529*460fdfe6Sryan_chen 
aspeed_fsi_remove(struct udevice * dev)530*460fdfe6Sryan_chen static int aspeed_fsi_remove(struct udevice *dev)
531*460fdfe6Sryan_chen {
532*460fdfe6Sryan_chen 	struct fsi_master_aspeed *aspeed = dev_get_priv(dev);
533*460fdfe6Sryan_chen 
534*460fdfe6Sryan_chen 	clk_disable(&aspeed->clk);
535*460fdfe6Sryan_chen 
536*460fdfe6Sryan_chen 	return 0;
537*460fdfe6Sryan_chen }
538*460fdfe6Sryan_chen 
539*460fdfe6Sryan_chen static const struct udevice_id aspeed_fsi_ids[] = {
540*460fdfe6Sryan_chen 	{ .compatible = "aspeed,ast2600-fsi-master" },
541*460fdfe6Sryan_chen 	{ }
542*460fdfe6Sryan_chen };
543*460fdfe6Sryan_chen 
544*460fdfe6Sryan_chen U_BOOT_DRIVER(aspeed_fsi) = {
545*460fdfe6Sryan_chen 	.name		= "aspeed_fsi",
546*460fdfe6Sryan_chen 	.id		= UCLASS_MISC,
547*460fdfe6Sryan_chen 	.of_match	= aspeed_fsi_ids,
548*460fdfe6Sryan_chen 	.probe		= aspeed_fsi_probe,
549*460fdfe6Sryan_chen 	.remove 	= aspeed_fsi_remove,
550*460fdfe6Sryan_chen 	.priv_auto_alloc_size = sizeof(struct fsi_master_aspeed),
551*460fdfe6Sryan_chen };
552