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 25 while ((readl(g_sfc_reg + SFC_RCVR) == SFC_RESET) && (timeout > 0)) { 26 sfc_delay(1); 27 timeout--; 28 } 29 30 writel(0xFFFFFFFF, g_sfc_reg + SFC_ICLR); 31 } 32 33 u16 sfc_get_version(void) 34 { 35 return (u32)(readl(g_sfc_reg + SFC_VER) & 0xffff); 36 } 37 38 u32 sfc_get_max_iosize(void) 39 { 40 if (sfc_get_version() >= SFC_VER_4) 41 return SFC_MAX_IOSIZE_VER4; 42 else 43 return SFC_MAX_IOSIZE_VER3; 44 } 45 46 void sfc_set_delay_lines(u16 cells) 47 { 48 u16 cell_max = SCLK_SMP_SEL_MAX_V4; 49 50 if (sfc_get_version() >= SFC_VER_5) 51 cell_max = SCLK_SMP_SEL_MAX_V5; 52 53 if (cells > cell_max) 54 cells = cell_max; 55 56 writel(SCLK_SMP_SEL_EN | cells, g_sfc_reg + SFC_DLL_CTRL0); 57 } 58 59 void sfc_disable_delay_lines(void) 60 { 61 writel(0, g_sfc_reg + SFC_DLL_CTRL0); 62 } 63 64 int sfc_init(void __iomem *reg_addr) 65 { 66 g_sfc_reg = reg_addr; 67 writel(0, g_sfc_reg + SFC_CTRL); 68 69 if (sfc_get_version() >= SFC_VER_4) 70 writel(1, g_sfc_reg + SFC_LEN_CTRL); 71 72 return SFC_OK; 73 } 74 75 void sfc_clean_irq(void) 76 { 77 writel(0xFFFFFFFF, g_sfc_reg + SFC_ICLR); 78 writel(0xFFFFFFFF, g_sfc_reg + SFC_IMR); 79 } 80 81 int sfc_request(struct rk_sfc_op *op, u32 addr, void *data, u32 size) 82 { 83 int ret = SFC_OK; 84 union SFCCMD_DATA cmd; 85 int reg; 86 int timeout = 0; 87 88 reg = readl(g_sfc_reg + SFC_FSR); 89 90 if (!(reg & SFC_TXEMPTY) || !(reg & SFC_RXEMPTY) || 91 (readl(g_sfc_reg + SFC_SR) & SFC_BUSY)) 92 sfc_reset(); 93 94 cmd.d32 = op->sfcmd.d32; 95 96 if (cmd.b.addrbits == SFC_ADDR_XBITS) { 97 union SFCCTRL_DATA ctrl; 98 99 ctrl.d32 = op->sfctrl.d32; 100 101 if (!ctrl.b.addrbits) 102 return SFC_PARAM_ERR; 103 104 /* Controller plus 1 automatically */ 105 writel(ctrl.b.addrbits - 1, g_sfc_reg + SFC_ABIT); 106 } 107 108 /* shift in the data at negedge sclk_out */ 109 op->sfctrl.d32 |= 0x2; 110 cmd.b.datasize = size; 111 112 if (sfc_get_version() >= SFC_VER_4) 113 writel(size, g_sfc_reg + SFC_LEN_EXT); 114 else 115 cmd.b.datasize = size; 116 117 writel(op->sfctrl.d32, g_sfc_reg + SFC_CTRL); 118 writel(cmd.d32, g_sfc_reg + SFC_CMD); 119 120 if (cmd.b.addrbits) 121 writel(addr, g_sfc_reg + SFC_ADDR); 122 123 if (!size) 124 goto exit_wait; 125 126 if (op->sfctrl.b.enbledma) { 127 struct bounce_buffer bb; 128 unsigned int bb_flags; 129 130 if (cmd.b.rw == SFC_WRITE) 131 bb_flags = GEN_BB_READ; 132 else 133 bb_flags = GEN_BB_WRITE; 134 135 ret = bounce_buffer_start(&bb, data, size, bb_flags); 136 if (ret) 137 return ret; 138 139 writel(0xFFFFFFFF, g_sfc_reg + SFC_ICLR); 140 writel(~((u32)DMA_INT), g_sfc_reg + SFC_IMR); 141 writel((unsigned long)bb.bounce_buffer, g_sfc_reg + SFC_DMA_ADDR); 142 writel(SFC_DMA_START, g_sfc_reg + SFC_DMA_TRIGGER); 143 144 timeout = size * 10; 145 146 while ((readl(g_sfc_reg + SFC_SR) & SFC_BUSY) && 147 (timeout-- > 0)) 148 sfc_delay(1); 149 150 writel(0xFFFFFFFF, g_sfc_reg + SFC_ICLR); 151 152 if (timeout <= 0) 153 ret = SFC_WAIT_TIMEOUT; 154 bounce_buffer_stop(&bb); 155 } else { 156 u32 i, words, count, bytes; 157 union SFCFSR_DATA fifostat; 158 u32 *p_data = (u32 *)data; 159 160 if (cmd.b.rw == SFC_WRITE) { 161 words = (size + 3) >> 2; 162 163 while (words) { 164 fifostat.d32 = readl(g_sfc_reg + SFC_FSR); 165 166 if (fifostat.b.txlevel > 0) { 167 count = words < fifostat.b.txlevel ? 168 words : fifostat.b.txlevel; 169 170 for (i = 0; i < count; i++) { 171 writel(*p_data++, 172 g_sfc_reg + SFC_DATA); 173 words--; 174 } 175 176 if (words == 0) 177 break; 178 179 timeout = 0; 180 } else { 181 sfc_delay(1); 182 183 if (timeout++ > 10000) { 184 ret = SFC_TX_TIMEOUT; 185 break; 186 } 187 } 188 } 189 } else { 190 /* SFC_READ == cmd.b.rw */ 191 bytes = size & 0x3; 192 words = size >> 2; 193 194 while (words) { 195 fifostat.d32 = readl(g_sfc_reg + SFC_FSR); 196 197 if (fifostat.b.rxlevel > 0) { 198 u32 count; 199 200 count = words < fifostat.b.rxlevel ? 201 words : fifostat.b.rxlevel; 202 203 for (i = 0; i < count; i++) { 204 *p_data++ = readl(g_sfc_reg + 205 SFC_DATA); 206 words--; 207 } 208 209 if (words == 0) 210 break; 211 212 timeout = 0; 213 } else { 214 sfc_delay(1); 215 216 if (timeout++ > 10000) { 217 ret = SFC_RX_TIMEOUT; 218 break; 219 } 220 } 221 } 222 223 timeout = 0; 224 225 while (bytes) { 226 fifostat.d32 = readl(g_sfc_reg + SFC_FSR); 227 228 if (fifostat.b.rxlevel > 0) { 229 u8 *p_data1 = (u8 *)p_data; 230 231 words = readl(g_sfc_reg + SFC_DATA); 232 233 for (i = 0; i < bytes; i++) 234 p_data1[i] = 235 (u8)((words >> (i * 8)) & 0xFF); 236 237 break; 238 } 239 240 sfc_delay(1); 241 242 if (timeout++ > 10000) { 243 ret = SFC_RX_TIMEOUT; 244 break; 245 } 246 } 247 } 248 } 249 250 exit_wait: 251 timeout = 0; /* wait cmd or data send complete */ 252 253 while (readl(g_sfc_reg + SFC_SR) & SFC_BUSY) { 254 sfc_delay(1); 255 256 if (timeout++ > 100000) { /* wait 100ms */ 257 ret = SFC_TX_TIMEOUT; 258 break; 259 } 260 } 261 262 sfc_delay(1); /* CS# High Time (read/write) >100ns */ 263 return ret; 264 } 265