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 writel(0, g_sfc_reg + SFC_CTRL); 48 if (sfc_get_version() >= SFC_VER_4) 49 writel(1, g_sfc_reg + SFC_LEN_CTRL); 50 51 return SFC_OK; 52 } 53 54 void sfc_clean_irq(void) 55 { 56 writel(0xFFFFFFFF, g_sfc_reg + SFC_ICLR); 57 writel(0xFFFFFFFF, g_sfc_reg + SFC_IMR); 58 } 59 60 int sfc_request(struct rk_sfc_op *op, u32 addr, void *data, u32 size) 61 { 62 int ret = SFC_OK; 63 union SFCCMD_DATA cmd; 64 int reg; 65 int timeout = 0; 66 67 reg = readl(g_sfc_reg + SFC_FSR); 68 if (!(reg & SFC_TXEMPTY) || !(reg & SFC_RXEMPTY) || 69 (readl(g_sfc_reg + SFC_SR) & SFC_BUSY)) 70 sfc_reset(); 71 72 cmd.d32 = op->sfcmd.d32; 73 if (cmd.b.addrbits == SFC_ADDR_XBITS) { 74 union SFCCTRL_DATA ctrl; 75 76 ctrl.d32 = op->sfctrl.d32; 77 if (!ctrl.b.addrbits) 78 return SFC_PARAM_ERR; 79 /* Controller plus 1 automatically */ 80 writel(ctrl.b.addrbits - 1, g_sfc_reg + SFC_ABIT); 81 } 82 /* shift in the data at negedge sclk_out */ 83 op->sfctrl.d32 |= 0x2; 84 cmd.b.datasize = size; 85 if (sfc_get_version() >= SFC_VER_4) 86 writel(size, g_sfc_reg + SFC_LEN_EXT); 87 else 88 cmd.b.datasize = size; 89 90 writel(op->sfctrl.d32, g_sfc_reg + SFC_CTRL); 91 writel(cmd.d32, g_sfc_reg + SFC_CMD); 92 if (cmd.b.addrbits) 93 writel(addr, g_sfc_reg + SFC_ADDR); 94 if (!size) 95 goto exit_wait; 96 if (op->sfctrl.b.enbledma) { 97 struct bounce_buffer bb; 98 unsigned int bb_flags; 99 100 if (cmd.b.rw == SFC_WRITE) 101 bb_flags = GEN_BB_READ; 102 else 103 bb_flags = GEN_BB_WRITE; 104 105 ret = bounce_buffer_start(&bb, data, size, bb_flags); 106 if (ret) 107 return ret; 108 109 writel(0xFFFFFFFF, g_sfc_reg + SFC_ICLR); 110 writel(~((u32)DMA_INT), g_sfc_reg + SFC_IMR); 111 writel((unsigned long)bb.bounce_buffer, g_sfc_reg + SFC_DMA_ADDR); 112 writel(SFC_DMA_START, g_sfc_reg + SFC_DMA_TRIGGER); 113 114 timeout = size * 10; 115 while ((readl(g_sfc_reg + SFC_SR) & SFC_BUSY) && 116 (timeout-- > 0)) 117 sfc_delay(1); 118 writel(0xFFFFFFFF, g_sfc_reg + SFC_ICLR); 119 if (timeout <= 0) 120 ret = SFC_WAIT_TIMEOUT; 121 bounce_buffer_stop(&bb); 122 } else { 123 u32 i, words, count, bytes; 124 union SFCFSR_DATA fifostat; 125 u32 *p_data = (u32 *)data; 126 127 if (cmd.b.rw == SFC_WRITE) { 128 words = (size + 3) >> 2; 129 while (words) { 130 fifostat.d32 = readl(g_sfc_reg + SFC_FSR); 131 if (fifostat.b.txlevel > 0) { 132 count = words < fifostat.b.txlevel ? 133 words : fifostat.b.txlevel; 134 for (i = 0; i < count; i++) { 135 writel(*p_data++, 136 g_sfc_reg + SFC_DATA); 137 words--; 138 } 139 if (words == 0) 140 break; 141 timeout = 0; 142 } else { 143 sfc_delay(1); 144 if (timeout++ > 10000) { 145 ret = SFC_TX_TIMEOUT; 146 break; 147 } 148 } 149 } 150 } else { 151 /* SFC_READ == cmd.b.rw */ 152 bytes = size & 0x3; 153 words = size >> 2; 154 while (words) { 155 fifostat.d32 = readl(g_sfc_reg + SFC_FSR); 156 if (fifostat.b.rxlevel > 0) { 157 u32 count; 158 159 count = words < fifostat.b.rxlevel ? 160 words : fifostat.b.rxlevel; 161 162 for (i = 0; i < count; i++) { 163 *p_data++ = readl(g_sfc_reg + 164 SFC_DATA); 165 words--; 166 } 167 if (words == 0) 168 break; 169 timeout = 0; 170 } else { 171 sfc_delay(1); 172 if (timeout++ > 10000) { 173 ret = SFC_RX_TIMEOUT; 174 break; 175 } 176 } 177 } 178 179 timeout = 0; 180 while (bytes) { 181 fifostat.d32 = readl(g_sfc_reg + SFC_FSR); 182 if (fifostat.b.rxlevel > 0) { 183 u8 *p_data1 = (u8 *)p_data; 184 185 words = readl(g_sfc_reg + SFC_DATA); 186 for (i = 0; i < bytes; i++) 187 p_data1[i] = 188 (u8)((words >> (i * 8)) & 0xFF); 189 break; 190 } 191 192 sfc_delay(1); 193 if (timeout++ > 10000) { 194 ret = SFC_RX_TIMEOUT; 195 break; 196 } 197 } 198 } 199 } 200 201 exit_wait: 202 timeout = 0; /* wait cmd or data send complete */ 203 while (readl(g_sfc_reg + SFC_SR) & SFC_BUSY) { 204 sfc_delay(1); 205 if (timeout++ > 100000) { /* wait 100ms */ 206 ret = SFC_TX_TIMEOUT; 207 break; 208 } 209 } 210 sfc_delay(1); /* CS# High Time (read/write) >100ns */ 211 return ret; 212 } 213