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