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