soc: Remove copyright notices
[coreboot.git] / src / soc / mediatek / common / spi.c
bloba7f952972c53c502b90cf1df81e3f5483be0acf0
1 /*
2 * This file is part of the coreboot project.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; version 2 of the License.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
15 #include <device/mmio.h>
16 #include <assert.h>
17 #include <console/console.h>
18 #include <endian.h>
19 #include <gpio.h>
20 #include <soc/pll.h>
21 #include <soc/spi.h>
22 #include <timer.h>
23 #include <types.h>
25 #define MTK_SPI_DEBUG 0
27 enum {
28 MTK_FIFO_DEPTH = 32,
29 MTK_TXRX_TIMEOUT_US = 1000 * 1000,
30 MTK_ARBITRARY_VALUE = 0xdeaddead
33 enum {
34 MTK_SPI_IDLE = 0,
35 MTK_SPI_PAUSE_IDLE = 1
38 enum {
39 MTK_SPI_BUSY_STATUS = 1,
40 MTK_SPI_PAUSE_FINISH_INT_STATUS = 3
43 static inline struct mtk_spi_bus *to_mtk_spi(const struct spi_slave *slave)
45 assert(slave->bus < SPI_BUS_NUMBER);
46 return &spi_bus[slave->bus];
49 static void spi_sw_reset(struct mtk_spi_regs *regs)
51 setbits32(&regs->spi_cmd_reg, SPI_CMD_RST_EN);
52 clrbits32(&regs->spi_cmd_reg, SPI_CMD_RST_EN);
55 void mtk_spi_init(unsigned int bus, enum spi_pad_mask pad_select,
56 unsigned int speed_hz, unsigned int tick_dly)
58 u32 div, sck_ticks, cs_ticks;
60 assert(bus < SPI_BUS_NUMBER);
62 struct mtk_spi_bus *slave = &spi_bus[bus];
63 struct mtk_spi_regs *regs = slave->regs;
65 if (speed_hz < SPI_HZ / 2)
66 div = DIV_ROUND_UP(SPI_HZ, speed_hz);
67 else
68 div = 1;
70 sck_ticks = DIV_ROUND_UP(div, 2);
71 cs_ticks = sck_ticks * 2;
73 printk(BIOS_DEBUG, "SPI%u(PAD%u) initialized at %u Hz\n",
74 bus, pad_select, SPI_HZ / (sck_ticks * 2));
76 mtk_spi_set_timing(regs, sck_ticks, cs_ticks, tick_dly);
78 clrsetbits32(&regs->spi_cmd_reg,
79 (SPI_CMD_CPHA_EN | SPI_CMD_CPOL_EN |
80 SPI_CMD_TX_ENDIAN_EN | SPI_CMD_RX_ENDIAN_EN |
81 SPI_CMD_TX_DMA_EN | SPI_CMD_RX_DMA_EN |
82 SPI_CMD_PAUSE_EN | SPI_CMD_DEASSERT_EN),
83 (SPI_CMD_TXMSBF_EN | SPI_CMD_RXMSBF_EN |
84 SPI_CMD_FINISH_IE_EN | SPI_CMD_PAUSE_IE_EN));
86 mtk_spi_set_gpio_pinmux(bus, pad_select);
88 clrsetbits32(&regs->spi_pad_macro_sel_reg, SPI_PAD_SEL_MASK,
89 pad_select);
91 gpio_output(slave->cs_gpio, 1);
94 static void mtk_spi_dump_data(const char *name, const uint8_t *data, int size)
96 if (MTK_SPI_DEBUG) {
97 int i;
99 printk(BIOS_DEBUG, "%s: 0x ", name);
100 for (i = 0; i < size; i++)
101 printk(BIOS_INFO, "%#x ", data[i]);
102 printk(BIOS_DEBUG, "\n");
106 static int spi_ctrlr_claim_bus(const struct spi_slave *slave)
108 struct mtk_spi_bus *mtk_slave = to_mtk_spi(slave);
109 struct mtk_spi_regs *regs = mtk_slave->regs;
111 setbits32(&regs->spi_cmd_reg, 1 << SPI_CMD_PAUSE_EN_SHIFT);
112 mtk_slave->state = MTK_SPI_IDLE;
114 gpio_output(mtk_slave->cs_gpio, 0);
116 return 0;
119 static int do_transfer(const struct spi_slave *slave, void *in, const void *out,
120 size_t *bytes_in, size_t *bytes_out)
122 struct mtk_spi_bus *mtk_slave = to_mtk_spi(slave);
123 struct mtk_spi_regs *regs = mtk_slave->regs;
124 uint32_t reg_val = 0;
125 uint32_t i;
126 struct stopwatch sw;
127 size_t size;
129 if (*bytes_out == 0)
130 size = *bytes_in;
131 else if (*bytes_in == 0)
132 size = *bytes_out;
133 else
134 size = MIN(*bytes_in, *bytes_out);
136 clrsetbits32(&regs->spi_cfg1_reg,
137 SPI_CFG1_PACKET_LENGTH_MASK | SPI_CFG1_PACKET_LOOP_MASK,
138 ((size - 1) << SPI_CFG1_PACKET_LENGTH_SHIFT) |
139 (0 << SPI_CFG1_PACKET_LOOP_SHIFT));
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,