drivers/wifi: Remove unnecessary data structure copy
[coreboot2.git] / src / soc / mediatek / common / spi.c
blob8bcc56e0cb7ee4f3fdffff8b6650d6d186b542f7
1 /* SPDX-License-Identifier: GPL-2.0-only */
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>
13 #define MTK_SPI_DEBUG 0
15 enum {
16 MTK_FIFO_DEPTH = 32,
17 MTK_TXRX_TIMEOUT_US = 1000 * 1000,
18 MTK_ARBITRARY_VALUE = 0xdeaddead
21 enum {
22 MTK_SPI_IDLE = 0,
23 MTK_SPI_PAUSE_IDLE = 1
26 enum {
27 MTK_SPI_BUSY_STATUS = 1,
28 MTK_SPI_PAUSE_FINISH_INT_STATUS = 3
31 static inline struct mtk_spi_bus *to_mtk_spi(const struct spi_slave *slave)
33 assert(slave->bus < SPI_BUS_NUMBER);
34 return &spi_bus[slave->bus];
37 void mtk_spi_set_timing(struct mtk_spi_regs *regs, u32 sck_ticks,
38 u32 cs_ticks, unsigned int tick_dly)
40 SET32_BITFIELDS(&regs->spi_cfg0_reg, SPI_CFG_CS_HOLD, cs_ticks - 1,
41 SPI_CFG_CS_SETUP, cs_ticks - 1);
43 SET32_BITFIELDS(&GET_SCK_REG(regs), SPI_CFG_SCK_LOW, sck_ticks - 1,
44 SPI_CFG_SCK_HIGH, sck_ticks - 1);
46 SET32_BITFIELDS(&regs->spi_cfg1_reg, SPI_CFG1_CS_IDLE, cs_ticks - 1);
48 SET32_BITFIELDS(&GET_TICK_DLY_REG(regs), SPI_TICK_DLY, tick_dly);
51 static void spi_sw_reset(struct mtk_spi_regs *regs)
53 setbits32(&regs->spi_cmd_reg, SPI_CMD_RST_EN);
54 clrbits32(&regs->spi_cmd_reg, SPI_CMD_RST_EN);
57 void mtk_spi_init(unsigned int bus, enum spi_pad_mask pad_select,
58 unsigned int speed_hz, unsigned int tick_dly)
60 u32 div, sck_ticks, cs_ticks;
62 assert(bus < SPI_BUS_NUMBER);
64 struct mtk_spi_bus *slave = &spi_bus[bus];
65 struct mtk_spi_regs *regs = slave->regs;
67 if (speed_hz < SPI_HZ / 2)
68 div = DIV_ROUND_UP(SPI_HZ, speed_hz);
69 else
70 div = 1;
72 sck_ticks = DIV_ROUND_UP(div, 2);
73 cs_ticks = sck_ticks * 2;
75 printk(BIOS_DEBUG, "SPI%u(PAD%u) initialized at %u Hz\n",
76 bus, pad_select, SPI_HZ / (sck_ticks * 2));
78 mtk_spi_set_timing(regs, sck_ticks, cs_ticks, tick_dly);
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));
88 mtk_spi_set_gpio_pinmux(bus, pad_select);
90 clrsetbits32(&regs->spi_pad_macro_sel_reg, SPI_PAD_SEL_MASK,
91 pad_select);
93 gpio_output(slave->cs_gpio, 1);
96 static void mtk_spi_dump_data(const char *name, const uint8_t *data, int size)
98 if (MTK_SPI_DEBUG) {
99 int i;
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");
108 static int spi_ctrlr_claim_bus(const struct spi_slave *slave)
110 struct mtk_spi_bus *mtk_slave = to_mtk_spi(slave);
111 struct mtk_spi_regs *regs = mtk_slave->regs;
113 setbits32(&regs->spi_cmd_reg, 1 << SPI_CMD_PAUSE_EN_SHIFT);
114 mtk_slave->state = MTK_SPI_IDLE;
116 gpio_output(mtk_slave->cs_gpio, 0);
118 return 0;
121 static int do_transfer(const struct spi_slave *slave, void *in, const void *out,
122 size_t *bytes_in, size_t *bytes_out)
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;
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);
138 SET32_BITFIELDS(&regs->spi_cfg1_reg, SPI_CFG1_PACKET_LENGTH, size - 1,
139 SPI_CFG1_PACKET_LOOP, 0);
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;
151 if (i % 4 != 0)
152 write32(&regs->spi_tx_data_reg, reg_val);
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.
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);
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);
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;
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;
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;
198 mtk_spi_dump_data("the inb data is", inb, size);
200 *bytes_in -= size;
203 if (*bytes_out)
204 *bytes_out -= size;
206 return 0;
207 error:
208 spi_sw_reset(regs);
209 mtk_slave->state = MTK_SPI_IDLE;
210 return -1;
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)
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;
222 int ret = do_transfer(slave, din, dout, &in_rem, &out_rem);
223 if (ret != 0)
224 return ret;
226 if (bytes_out) {
227 size_t sent = out_now - out_rem;
228 bytes_out -= sent;
229 dout += sent;
232 if (bytes_in) {
233 size_t received = in_now - in_rem;
234 bytes_in -= received;
235 din += received;
239 return 0;
242 static void spi_ctrlr_release_bus(const struct spi_slave *slave)
244 struct mtk_spi_bus *mtk_slave = to_mtk_spi(slave);
245 struct mtk_spi_regs *regs = mtk_slave->regs;
247 clrbits32(&regs->spi_cmd_reg, SPI_CMD_PAUSE_EN);
248 spi_sw_reset(regs);
249 mtk_slave->state = MTK_SPI_IDLE;
251 gpio_output(mtk_slave->cs_gpio, 1);
254 static int spi_ctrlr_setup(const struct spi_slave *slave)
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;
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,