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