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