• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <device/mmio.h>
4 #include <assert.h>
5 #include <console/console.h>
6 #include <endian.h>
7 #include <gpio.h>
8 #include <soc/pll.h>
9 #include <soc/spi.h>
10 #include <timer.h>
11 #include <types.h>
12 
13 #define MTK_SPI_DEBUG 0
14 
15 enum {
16 	MTK_FIFO_DEPTH = 32,
17 	MTK_TXRX_TIMEOUT_US = 1000 * 1000,
18 	MTK_ARBITRARY_VALUE = 0xdeaddead
19 };
20 
21 enum {
22 	MTK_SPI_IDLE = 0,
23 	MTK_SPI_PAUSE_IDLE = 1
24 };
25 
26 enum {
27 	MTK_SPI_BUSY_STATUS = 1,
28 	MTK_SPI_PAUSE_FINISH_INT_STATUS = 3
29 };
30 
to_mtk_spi(const struct spi_slave * slave)31 static inline struct mtk_spi_bus *to_mtk_spi(const struct spi_slave *slave)
32 {
33 	assert(slave->bus < SPI_BUS_NUMBER);
34 	return &spi_bus[slave->bus];
35 }
36 
mtk_spi_set_timing(struct mtk_spi_regs * regs,u32 sck_ticks,u32 cs_ticks,unsigned int tick_dly)37 void mtk_spi_set_timing(struct mtk_spi_regs *regs, u32 sck_ticks,
38 			u32 cs_ticks, unsigned int tick_dly)
39 {
40 	SET32_BITFIELDS(&regs->spi_cfg0_reg, SPI_CFG_CS_HOLD, cs_ticks - 1,
41 			SPI_CFG_CS_SETUP, cs_ticks - 1);
42 
43 	SET32_BITFIELDS(&GET_SCK_REG(regs), SPI_CFG_SCK_LOW, sck_ticks - 1,
44 			SPI_CFG_SCK_HIGH, sck_ticks - 1);
45 
46 	SET32_BITFIELDS(&regs->spi_cfg1_reg, SPI_CFG1_CS_IDLE, cs_ticks - 1);
47 
48 	SET32_BITFIELDS(&GET_TICK_DLY_REG(regs), SPI_TICK_DLY, tick_dly);
49 }
50 
spi_sw_reset(struct mtk_spi_regs * regs)51 static void spi_sw_reset(struct mtk_spi_regs *regs)
52 {
53 	setbits32(&regs->spi_cmd_reg, SPI_CMD_RST_EN);
54 	clrbits32(&regs->spi_cmd_reg, SPI_CMD_RST_EN);
55 }
56 
mtk_spi_init(unsigned int bus,enum spi_pad_mask pad_select,unsigned int speed_hz,unsigned int tick_dly)57 void mtk_spi_init(unsigned int bus, enum spi_pad_mask pad_select,
58 		  unsigned int speed_hz, unsigned int tick_dly)
59 {
60 	u32 div, sck_ticks, cs_ticks;
61 
62 	assert(bus < SPI_BUS_NUMBER);
63 
64 	struct mtk_spi_bus *slave = &spi_bus[bus];
65 	struct mtk_spi_regs *regs = slave->regs;
66 
67 	if (speed_hz < SPI_HZ / 2)
68 		div = DIV_ROUND_UP(SPI_HZ, speed_hz);
69 	else
70 		div = 1;
71 
72 	sck_ticks = DIV_ROUND_UP(div, 2);
73 	cs_ticks = sck_ticks * 2;
74 
75 	printk(BIOS_DEBUG, "SPI%u(PAD%u) initialized at %u Hz\n",
76 	       bus, pad_select, SPI_HZ / (sck_ticks * 2));
77 
78 	mtk_spi_set_timing(regs, sck_ticks, cs_ticks, tick_dly);
79 
80 	clrsetbits32(&regs->spi_cmd_reg,
81 		     (SPI_CMD_CPHA_EN | SPI_CMD_CPOL_EN |
82 		      SPI_CMD_TX_ENDIAN_EN | SPI_CMD_RX_ENDIAN_EN |
83 		      SPI_CMD_TX_DMA_EN | SPI_CMD_RX_DMA_EN |
84 		      SPI_CMD_PAUSE_EN | SPI_CMD_DEASSERT_EN),
85 		     (SPI_CMD_TXMSBF_EN | SPI_CMD_RXMSBF_EN |
86 		      SPI_CMD_FINISH_IE_EN | SPI_CMD_PAUSE_IE_EN));
87 
88 	mtk_spi_set_gpio_pinmux(bus, pad_select);
89 
90 	clrsetbits32(&regs->spi_pad_macro_sel_reg, SPI_PAD_SEL_MASK,
91 			pad_select);
92 
93 	gpio_output(slave->cs_gpio, 1);
94 }
95 
mtk_spi_dump_data(const char * name,const uint8_t * data,int size)96 static void mtk_spi_dump_data(const char *name, const uint8_t *data, int size)
97 {
98 	if (MTK_SPI_DEBUG) {
99 		int i;
100 
101 		printk(BIOS_DEBUG, "%s: 0x ", name);
102 		for (i = 0; i < size; i++)
103 			printk(BIOS_INFO, "%#x ", data[i]);
104 		printk(BIOS_DEBUG, "\n");
105 	}
106 }
107 
spi_ctrlr_claim_bus(const struct spi_slave * slave)108 static int spi_ctrlr_claim_bus(const struct spi_slave *slave)
109 {
110 	struct mtk_spi_bus *mtk_slave = to_mtk_spi(slave);
111 	struct mtk_spi_regs *regs = mtk_slave->regs;
112 
113 	setbits32(&regs->spi_cmd_reg, 1 << SPI_CMD_PAUSE_EN_SHIFT);
114 	mtk_slave->state = MTK_SPI_IDLE;
115 
116 	gpio_output(mtk_slave->cs_gpio, 0);
117 
118 	return 0;
119 }
120 
do_transfer(const struct spi_slave * slave,void * in,const void * out,size_t * bytes_in,size_t * bytes_out)121 static int do_transfer(const struct spi_slave *slave, void *in, const void *out,
122 		       size_t *bytes_in, size_t *bytes_out)
123 {
124 	struct mtk_spi_bus *mtk_slave = to_mtk_spi(slave);
125 	struct mtk_spi_regs *regs = mtk_slave->regs;
126 	uint32_t reg_val = 0;
127 	uint32_t i;
128 	struct stopwatch sw;
129 	size_t size;
130 
131 	if (*bytes_out == 0)
132 		size = *bytes_in;
133 	else if (*bytes_in == 0)
134 		size = *bytes_out;
135 	else
136 		size = MIN(*bytes_in, *bytes_out);
137 
138 	SET32_BITFIELDS(&regs->spi_cfg1_reg, SPI_CFG1_PACKET_LENGTH, size - 1,
139 			SPI_CFG1_PACKET_LOOP, 0);
140 
141 	if (*bytes_out) {
142 		const uint8_t *outb = (const uint8_t *)out;
143 		for (i = 0; i < size; i++) {
144 			reg_val |= outb[i] << ((i % 4) * 8);
145 			if (i % 4 == 3) {
146 				write32(&regs->spi_tx_data_reg, reg_val);
147 				reg_val = 0;
148 			}
149 		}
150 
151 		if (i % 4 != 0)
152 			write32(&regs->spi_tx_data_reg, reg_val);
153 
154 		mtk_spi_dump_data("the outb data is",
155 				  (const uint8_t *)outb, size);
156 	} else {
157 		/* The SPI controller will transmit in full-duplex for RX,
158 		 * therefore we need arbitrary data on MOSI which the slave
159 		 * must ignore.
160 		 */
161 		uint32_t word_count = DIV_ROUND_UP(size, sizeof(u32));
162 		for (i = 0; i < word_count; i++)
163 			write32(&regs->spi_tx_data_reg, MTK_ARBITRARY_VALUE);
164 	}
165 
166 	if (mtk_slave->state == MTK_SPI_IDLE) {
167 		setbits32(&regs->spi_cmd_reg, SPI_CMD_ACT_EN);
168 		mtk_slave->state = MTK_SPI_PAUSE_IDLE;
169 	} else if (mtk_slave->state == MTK_SPI_PAUSE_IDLE) {
170 		setbits32(&regs->spi_cmd_reg, SPI_CMD_RESUME_EN);
171 	}
172 
173 	stopwatch_init_usecs_expire(&sw, MTK_TXRX_TIMEOUT_US);
174 	while ((read32(&regs->spi_status1_reg) & MTK_SPI_BUSY_STATUS) == 0) {
175 		if (stopwatch_expired(&sw)) {
176 			printk(BIOS_ERR,
177 			       "Timeout waiting for status1 status.\n");
178 			goto error;
179 		}
180 	}
181 	stopwatch_init_usecs_expire(&sw, MTK_TXRX_TIMEOUT_US);
182 	while ((read32(&regs->spi_status0_reg) &
183 	       MTK_SPI_PAUSE_FINISH_INT_STATUS) == 0) {
184 		if (stopwatch_expired(&sw)) {
185 			printk(BIOS_ERR,
186 			       "Timeout waiting for status0 status.\n");
187 			goto error;
188 		}
189 	}
190 
191 	if (*bytes_in) {
192 		uint8_t *inb = (uint8_t *)in;
193 		for (i = 0; i < size; i++) {
194 			if (i % 4 == 0)
195 				reg_val = read32(&regs->spi_rx_data_reg);
196 			inb[i] = (reg_val >> ((i % 4) * 8)) & 0xff;
197 		}
198 		mtk_spi_dump_data("the inb data is", inb, size);
199 
200 		*bytes_in -= size;
201 	}
202 
203 	if (*bytes_out)
204 		*bytes_out -= size;
205 
206 	return 0;
207 error:
208 	spi_sw_reset(regs);
209 	mtk_slave->state = MTK_SPI_IDLE;
210 	return -1;
211 }
212 
spi_ctrlr_xfer(const struct spi_slave * slave,const void * dout,size_t bytes_out,void * din,size_t bytes_in)213 static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout,
214 			  size_t bytes_out, void *din, size_t bytes_in)
215 {
216 	while (bytes_out || bytes_in) {
217 		size_t in_now = MIN(bytes_in, MTK_FIFO_DEPTH);
218 		size_t out_now = MIN(bytes_out, MTK_FIFO_DEPTH);
219 		size_t in_rem = in_now;
220 		size_t out_rem = out_now;
221 
222 		int ret = do_transfer(slave, din, dout, &in_rem, &out_rem);
223 		if (ret != 0)
224 			return ret;
225 
226 		if (bytes_out) {
227 			size_t sent = out_now - out_rem;
228 			bytes_out -= sent;
229 			dout += sent;
230 		}
231 
232 		if (bytes_in) {
233 			size_t received = in_now - in_rem;
234 			bytes_in -= received;
235 			din += received;
236 		}
237 	}
238 
239 	return 0;
240 }
241 
spi_ctrlr_release_bus(const struct spi_slave * slave)242 static void spi_ctrlr_release_bus(const struct spi_slave *slave)
243 {
244 	struct mtk_spi_bus *mtk_slave = to_mtk_spi(slave);
245 	struct mtk_spi_regs *regs = mtk_slave->regs;
246 
247 	clrbits32(&regs->spi_cmd_reg, SPI_CMD_PAUSE_EN);
248 	spi_sw_reset(regs);
249 	mtk_slave->state = MTK_SPI_IDLE;
250 
251 	gpio_output(mtk_slave->cs_gpio, 1);
252 }
253 
spi_ctrlr_setup(const struct spi_slave * slave)254 static int spi_ctrlr_setup(const struct spi_slave *slave)
255 {
256 	struct mtk_spi_bus *eslave = to_mtk_spi(slave);
257 	assert(read32(&eslave->regs->spi_cfg0_reg) != 0);
258 	spi_sw_reset(eslave->regs);
259 	return 0;
260 }
261 
262 const struct spi_ctrlr spi_ctrlr = {
263 	.setup = spi_ctrlr_setup,
264 	.claim_bus = spi_ctrlr_claim_bus,
265 	.release_bus = spi_ctrlr_release_bus,
266 	.xfer = spi_ctrlr_xfer,
267 	.max_xfer_size = 65535,
268 };
269