xref: /rk3399_rockchip-uboot/drivers/rkflash/sfc.c (revision 827e2ae92e2103f82dab5b54228ad24e40db6263)
1 /*
2  * Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier:	GPL-2.0
5  */
6 
7 #include <common.h>
8 #include <linux/delay.h>
9 #include <bouncebuf.h>
10 #include <asm/io.h>
11 
12 #include "sfc.h"
13 
14 #define SFC_MAX_IOSIZE_VER3		(1024 * 8)
15 #define SFC_MAX_IOSIZE_VER4		(0xFFFFFFFF)
16 
17 static void __iomem *g_sfc_reg;
18 
19 static void sfc_reset(void)
20 {
21 	int timeout = 10000;
22 
23 	writel(SFC_RESET, g_sfc_reg + SFC_RCVR);
24 	while ((readl(g_sfc_reg + SFC_RCVR) == SFC_RESET) && (timeout > 0)) {
25 		sfc_delay(1);
26 		timeout--;
27 	}
28 	writel(0xFFFFFFFF, g_sfc_reg + SFC_ICLR);
29 }
30 
31 u16 sfc_get_version(void)
32 {
33 	return  (u32)(readl(g_sfc_reg + SFC_VER) & 0xffff);
34 }
35 
36 u32 sfc_get_max_iosize(void)
37 {
38 	if (sfc_get_version() >= SFC_VER_4)
39 		return SFC_MAX_IOSIZE_VER4;
40 	else
41 		return SFC_MAX_IOSIZE_VER3;
42 }
43 
44 int sfc_init(void __iomem *reg_addr)
45 {
46 	g_sfc_reg = reg_addr;
47 	sfc_reset();
48 	writel(0, g_sfc_reg + SFC_CTRL);
49 	if (sfc_get_version() >= SFC_VER_4)
50 		writel(1, g_sfc_reg + SFC_LEN_CTRL);
51 
52 	return SFC_OK;
53 }
54 
55 void sfc_clean_irq(void)
56 {
57 	writel(0xFFFFFFFF, g_sfc_reg + SFC_ICLR);
58 	writel(0xFFFFFFFF, g_sfc_reg + SFC_IMR);
59 }
60 
61 int sfc_request(struct rk_sfc_op *op, u32 addr, void *data, u32 size)
62 {
63 	int ret = SFC_OK;
64 	union SFCCMD_DATA cmd;
65 	int reg;
66 	int timeout = 0;
67 
68 	reg = readl(g_sfc_reg + SFC_FSR);
69 	if (!(reg & SFC_TXEMPTY) || !(reg & SFC_RXEMPTY) ||
70 	    (readl(g_sfc_reg + SFC_SR) & SFC_BUSY))
71 		sfc_reset();
72 
73 	cmd.d32 = op->sfcmd.d32;
74 	if (cmd.b.addrbits == SFC_ADDR_XBITS) {
75 		union SFCCTRL_DATA ctrl;
76 
77 		ctrl.d32 = op->sfctrl.d32;
78 		if (!ctrl.b.addrbits)
79 			return SFC_PARAM_ERR;
80 		/* Controller plus 1 automatically */
81 		writel(ctrl.b.addrbits - 1, g_sfc_reg + SFC_ABIT);
82 	}
83 	/* shift in the data at negedge sclk_out */
84 	op->sfctrl.d32 |= 0x2;
85 	cmd.b.datasize = size;
86 	if (sfc_get_version() >= SFC_VER_4)
87 		writel(size, g_sfc_reg + SFC_LEN_EXT);
88 	else
89 		cmd.b.datasize = size;
90 
91 	writel(op->sfctrl.d32, g_sfc_reg + SFC_CTRL);
92 	writel(cmd.d32, g_sfc_reg + SFC_CMD);
93 	if (cmd.b.addrbits)
94 		writel(addr, g_sfc_reg + SFC_ADDR);
95 	if (!size)
96 		goto exit_wait;
97 	if (op->sfctrl.b.enbledma) {
98 		struct bounce_buffer bb;
99 		unsigned int bb_flags;
100 
101 		if (cmd.b.rw == SFC_WRITE)
102 			bb_flags = GEN_BB_READ;
103 		else
104 			bb_flags = GEN_BB_WRITE;
105 
106 		ret = bounce_buffer_start(&bb, data, size, bb_flags);
107 		if (ret)
108 			return ret;
109 
110 		writel(0xFFFFFFFF, g_sfc_reg + SFC_ICLR);
111 		writel(~((u32)DMA_INT), g_sfc_reg + SFC_IMR);
112 		writel((unsigned long)bb.bounce_buffer, g_sfc_reg + SFC_DMA_ADDR);
113 		writel(SFC_DMA_START, g_sfc_reg + SFC_DMA_TRIGGER);
114 
115 		timeout = size * 10;
116 		while ((readl(g_sfc_reg + SFC_SR) & SFC_BUSY) &&
117 		       (timeout-- > 0))
118 			sfc_delay(1);
119 		writel(0xFFFFFFFF, g_sfc_reg + SFC_ICLR);
120 		if (timeout <= 0)
121 			ret = SFC_WAIT_TIMEOUT;
122 		bounce_buffer_stop(&bb);
123 	} else {
124 		u32 i, words, count, bytes;
125 		union SFCFSR_DATA    fifostat;
126 		u32 *p_data = (u32 *)data;
127 
128 		if (cmd.b.rw == SFC_WRITE) {
129 			words  = (size + 3) >> 2;
130 			while (words) {
131 				fifostat.d32 = readl(g_sfc_reg + SFC_FSR);
132 				if (fifostat.b.txlevel > 0) {
133 					count = words < fifostat.b.txlevel ?
134 						words : fifostat.b.txlevel;
135 					for (i = 0; i < count; i++) {
136 						writel(*p_data++,
137 						       g_sfc_reg + SFC_DATA);
138 						words--;
139 					}
140 					if (words == 0)
141 						break;
142 					timeout = 0;
143 				} else {
144 					sfc_delay(1);
145 					if (timeout++ > 10000) {
146 						ret = SFC_TX_TIMEOUT;
147 						break;
148 					}
149 				}
150 			}
151 		} else {
152 			/* SFC_READ == cmd.b.rw */
153 			bytes = size & 0x3;
154 			words = size >> 2;
155 			while (words) {
156 				fifostat.d32 = readl(g_sfc_reg + SFC_FSR);
157 				if (fifostat.b.rxlevel > 0) {
158 					u32 count;
159 
160 					count = words < fifostat.b.rxlevel ?
161 						words : fifostat.b.rxlevel;
162 
163 					for (i = 0; i < count; i++) {
164 						*p_data++ = readl(g_sfc_reg +
165 								  SFC_DATA);
166 						words--;
167 					}
168 					if (words == 0)
169 						break;
170 					timeout = 0;
171 				} else {
172 					sfc_delay(1);
173 					if (timeout++ > 10000) {
174 						ret = SFC_RX_TIMEOUT;
175 						break;
176 					}
177 				}
178 			}
179 
180 			timeout = 0;
181 			while (bytes) {
182 				fifostat.d32 = readl(g_sfc_reg + SFC_FSR);
183 				if (fifostat.b.rxlevel > 0) {
184 					u8 *p_data1 = (u8 *)p_data;
185 
186 					words = readl(g_sfc_reg + SFC_DATA);
187 					for (i = 0; i < bytes; i++)
188 						p_data1[i] =
189 						(u8)((words >> (i * 8)) & 0xFF);
190 					break;
191 				}
192 
193 				sfc_delay(1);
194 				if (timeout++ > 10000) {
195 					ret = SFC_RX_TIMEOUT;
196 					break;
197 				}
198 			}
199 		}
200 	}
201 
202 exit_wait:
203 	timeout = 0;    /* wait cmd or data send complete */
204 	while (readl(g_sfc_reg + SFC_SR) & SFC_BUSY) {
205 		sfc_delay(1);
206 		if (timeout++ > 100000) {         /* wait 100ms */
207 			ret = SFC_TX_TIMEOUT;
208 			break;
209 		}
210 	}
211 	sfc_delay(1); /* CS# High Time (read/write) >100ns */
212 	return ret;
213 }
214