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