xref: /rk3399_rockchip-uboot/drivers/rkflash/sfc.c (revision 58463f4dec02d3dcdfaa8c647010490edd3b4092)
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(struct rk_sfc_op *op, u32 addr, void *data, u32 size)
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 = op->sfcmd.d32;
61 	if (cmd.b.addrbits == SFC_ADDR_XBITS) {
62 		union SFCCTRL_DATA ctrl;
63 
64 		ctrl.d32 = op->sfctrl.d32;
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 	op->sfctrl.d32 |= 0x2;
72 	cmd.b.datasize = size;
73 
74 	writel(op->sfctrl.d32, g_sfc_reg + SFC_CTRL);
75 	writel(cmd.d32, g_sfc_reg + SFC_CMD);
76 	if (cmd.b.addrbits)
77 		writel(addr, g_sfc_reg + SFC_ADDR);
78 	if (!size)
79 		goto exit_wait;
80 	if (op->sfctrl.b.enbledma) {
81 		struct bounce_buffer bb;
82 		unsigned int bb_flags;
83 
84 		if (cmd.b.rw == SFC_WRITE)
85 			bb_flags = GEN_BB_READ;
86 		else
87 			bb_flags = GEN_BB_WRITE;
88 
89 		ret = bounce_buffer_start(&bb, data, size, bb_flags);
90 		if (ret)
91 			return ret;
92 
93 		writel(0xFFFFFFFF, g_sfc_reg + SFC_ICLR);
94 		writel(~((u32)DMA_INT), g_sfc_reg + SFC_IMR);
95 		writel((unsigned long)bb.bounce_buffer, g_sfc_reg + SFC_DMA_ADDR);
96 		writel(SFC_DMA_START, g_sfc_reg + SFC_DMA_TRIGGER);
97 
98 		timeout = size * 10;
99 		while (!((readl(g_sfc_reg + SFC_RAWISR) & DMA_INT)) &&
100 		       (timeout-- > 0))
101 			sfc_delay(1);
102 		writel(0xFFFFFFFF, g_sfc_reg + SFC_ICLR);
103 		if (timeout <= 0)
104 			ret = SFC_WAIT_TIMEOUT;
105 		bounce_buffer_stop(&bb);
106 	} else {
107 		u32 i, words, count, bytes;
108 		union SFCFSR_DATA    fifostat;
109 		u32 *p_data = (u32 *)data;
110 
111 		if (cmd.b.rw == SFC_WRITE) {
112 			words  = (size + 3) >> 2;
113 			while (words) {
114 				fifostat.d32 = readl(g_sfc_reg + SFC_FSR);
115 				if (fifostat.b.txlevel > 0) {
116 					count = words < fifostat.b.txlevel ?
117 						words : fifostat.b.txlevel;
118 					for (i = 0; i < count; i++) {
119 						writel(*p_data++,
120 						       g_sfc_reg + SFC_DATA);
121 						words--;
122 					}
123 					if (words == 0)
124 						break;
125 					timeout = 0;
126 				} else {
127 					sfc_delay(1);
128 					if (timeout++ > 10000) {
129 						ret = SFC_TX_TIMEOUT;
130 						break;
131 					}
132 				}
133 			}
134 		} else {
135 			/* SFC_READ == cmd.b.rw */
136 			bytes = size & 0x3;
137 			words = size >> 2;
138 			while (words) {
139 				fifostat.d32 = readl(g_sfc_reg + SFC_FSR);
140 				if (fifostat.b.rxlevel > 0) {
141 					u32 count;
142 
143 					count = words < fifostat.b.rxlevel ?
144 						words : fifostat.b.rxlevel;
145 
146 					for (i = 0; i < count; i++) {
147 						*p_data++ = readl(g_sfc_reg +
148 								  SFC_DATA);
149 						words--;
150 					}
151 					if (words == 0)
152 						break;
153 					timeout = 0;
154 				} else {
155 					sfc_delay(1);
156 					if (timeout++ > 10000) {
157 						ret = SFC_RX_TIMEOUT;
158 						break;
159 					}
160 				}
161 			}
162 
163 			timeout = 0;
164 			while (bytes) {
165 				fifostat.d32 = readl(g_sfc_reg + SFC_FSR);
166 				if (fifostat.b.rxlevel > 0) {
167 					u8 *p_data1 = (u8 *)p_data;
168 
169 					words = readl(g_sfc_reg + SFC_DATA);
170 					for (i = 0; i < bytes; i++)
171 						p_data1[i] =
172 						(u8)((words >> (i * 8)) & 0xFF);
173 					break;
174 				}
175 
176 				sfc_delay(1);
177 				if (timeout++ > 10000) {
178 					ret = SFC_RX_TIMEOUT;
179 					break;
180 				}
181 			}
182 		}
183 	}
184 
185 exit_wait:
186 	timeout = 0;    /* wait cmd or data send complete */
187 	while (readl(g_sfc_reg + SFC_SR) & SFC_BUSY) {
188 		sfc_delay(1);
189 		if (timeout++ > 100000) {         /* wait 100ms */
190 			ret = SFC_TX_TIMEOUT;
191 			break;
192 		}
193 	}
194 	sfc_delay(1); /* CS# High Time (read/write) >100ns */
195 	return ret;
196 }
197