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 /*
4  * Derived from Cavium's BSD-3 Clause OCTEONTX-SDK-6.2.0.
5  */
6 
7 #include <device/mmio.h>
8 #include <assert.h>
9 #include <console/console.h>
10 #include <endian.h>
11 #include <soc/addressmap.h>
12 #include <soc/spi.h>
13 #include <soc/clock.h>
14 #include <spi-generic.h>
15 #include <spi_flash.h>
16 #include <timer.h>
17 
19  u64 u;
20  struct {
21  u64 enable : 1;
22  u64 idlelow : 1;
24  u64 wireor : 1;
26  u64 : 2;
27  u64 cshi : 1;
30  u64 cslate : 1;
31  u64 csena : 4; /* Must be one */
32  u64 clkdiv : 13;
33  u64 : 35;
34  } s;
35 };
36 
38  u64 u;
39  struct {
40  u64 busy : 1;
42  u64 : 6;
43  u64 rxnum : 5;
44  u64 : 51;
45  } s;
46 };
47 
49  u64 u;
50  struct {
51  u64 totnum : 5;
52  u64 : 3;
53  u64 txnum : 5;
54  u64 : 3;
55  u64 leavecs : 1;
56  u64 : 3;
57  u64 csid : 2;
58  u64 : 42;
59  } s;
60 };
61 
62 struct cavium_spi {
63  union cavium_spi_cfg cfg;
64  union cavium_spi_sts sts;
65  union cavium_spi_tx tx;
72  u8 rsvd4[0x38];
73  u64 dat[8];
74 };
75 
79 check_member(cavium_spi, dat[7], 0xb8);
80 
82  struct cavium_spi *regs;
83  int cs;
84 };
85 
86 #define SPI_TIMEOUT_US 5000
87 
88 static struct cavium_spi_slave cavium_spi_slaves[] = {
89  {
90  .regs = (struct cavium_spi *)MPI_PF_BAR0,
91  .cs = 0,
92  },
93 };
94 
95 static struct cavium_spi_slave *to_cavium_spi(const struct spi_slave *slave)
96 {
98  return &cavium_spi_slaves[slave->bus];
99 }
100 
101 /**
102  * Enable the SPI controller. Pins are driven.
103  *
104  * @param bus The SPI bus to operate on
105  */
106 void spi_enable(const size_t bus)
107 {
108  union cavium_spi_cfg cfg;
109 
112  return;
113 
115 
116  cfg.u = read64(&regs->cfg);
117  cfg.s.csena = 0xf;
118  cfg.s.enable = 1;
119  write64(&regs->cfg, cfg.u);
120 }
121 
122 /**
123  * Disable the SPI controller. Pins are tristated.
124  *
125  * @param bus The SPI bus to operate on
126  */
127 void spi_disable(const size_t bus)
128 {
129  union cavium_spi_cfg cfg;
130 
133  return;
134 
136 
137  cfg.u = read64(&regs->cfg);
138  cfg.s.csena = 0xf;
139  cfg.s.enable = 0;
140  write64(&regs->cfg, cfg.u);
141 }
142 
143 /**
144  * Set SPI Chip select line and level if asserted.
145  *
146  * @param bus The SPI bus to operate on
147  * @param chip_select The chip select pin to use (0 - 3)
148  * @param assert_is_low CS pin state is low when asserted
149  */
150 void spi_set_cs(const size_t bus,
151  const size_t chip_select,
152  const size_t assert_is_low)
153 {
154  union cavium_spi_cfg cfg;
155 
158  return;
159 
160  cavium_spi_slaves[bus].cs = chip_select & 0x3;
162 
163  cfg.u = read64(&regs->cfg);
164  cfg.s.csena = 0xf;
165  cfg.s.cshi = !assert_is_low;
166  write64(&regs->cfg, cfg.u);
167 
168  //FIXME: CS2/3: Change pin mux here
169 }
170 
171 /**
172  * Set SPI clock frequency.
173  *
174  * @param bus The SPI bus to operate on
175  * @param speed_hz The SPI frequency in Hz
176  * @param idle_low The SPI clock idles low
177  * @param idle_cycles Number of CLK cycles between two commands (0 - 3)
178 
179  */
180 void spi_set_clock(const size_t bus,
181  const size_t speed_hz,
182  const size_t idle_low,
183  const size_t idle_cycles)
184 {
185  union cavium_spi_cfg cfg;
186 
189  return;
190 
192  const uint64_t sclk = thunderx_get_io_clock();
193 
194  cfg.u = read64(&regs->cfg);
195  cfg.s.csena = 0xf;
196  cfg.s.clk_cont = 0;
197  cfg.s.idlelow = !!idle_low;
198  cfg.s.idleclks = idle_cycles & 0x3;
199  cfg.s.clkdiv = MIN(sclk / (2ULL * speed_hz), 0x1fff);
200  write64(&regs->cfg, cfg.u);
201 
202  printk(BIOS_DEBUG, "SPI: set clock to %lld kHz\n",
203  (sclk / (2ULL * cfg.s.clkdiv)) >> 10);
204 }
205 
206 /**
207  * Get current SPI clock frequency in Hz.
208  *
209  * @param bus The SPI bus to operate on
210  */
212 {
213  union cavium_spi_cfg cfg;
214 
217  return 0;
218 
220  const uint64_t sclk = thunderx_get_io_clock();
221 
222  cfg.u = read64(&regs->cfg);
223 
224  return (sclk / (2ULL * cfg.s.clkdiv));
225 }
226 
227 /**
228  * Set SPI LSB/MSB first.
229  *
230  * @param bus The SPI bus to operate on
231  * @param lsb_first The SPI operates LSB first
232  *
233  */
234 void spi_set_lsbmsb(const size_t bus, const size_t lsb_first)
235 {
236  union cavium_spi_cfg cfg;
237 
240  return;
241 
243 
244  cfg.u = read64(&regs->cfg);
245  cfg.s.csena = 0xf;
246  cfg.s.lsbfirst = !!lsb_first;
247  write64(&regs->cfg, cfg.u);
248 }
249 
250 /**
251  * Init SPI with custom parameters and enable SPI controller.
252  *
253  * @param bus The SPI bus to operate on
254  * @param speed_hz The SPI frequency in Hz
255  * @param idle_low The SPI clock idles low
256  * @param idle_cycles Number of CLK cycles between two commands (0 - 3)
257  * @param lsb_first The SPI operates LSB first
258  * @param chip_select The chip select pin to use (0 - 3)
259  * @param assert_is_low CS pin state is low when asserted
260  */
261 void spi_init_custom(const size_t bus,
262  const size_t speed_hz,
263  const size_t idle_low,
264  const size_t idle_cycles,
265  const size_t lsb_first,
266  const size_t chip_select,
267  const size_t assert_is_low)
268 {
269  spi_disable(bus);
270  spi_set_clock(bus, speed_hz, idle_low, idle_cycles);
271  spi_set_lsbmsb(bus, lsb_first);
272  spi_set_cs(bus, chip_select, assert_is_low);
273  spi_enable(bus);
274 }
275 
276 /**
277  * Init all SPI controllers with default values and enable all SPI controller.
278  *
279  */
280 void spi_init(void)
281 {
282  for (size_t i = 0; i < ARRAY_SIZE(cavium_spi_slaves); i++) {
283  spi_disable(i);
284  spi_set_clock(i, 12500000, 0, 0);
285  spi_set_lsbmsb(i, 0);
286  spi_set_cs(i, 0, 1);
287  spi_enable(i);
288  }
289 }
290 
291 static int cavium_spi_wait(struct cavium_spi *regs)
292 {
293  struct stopwatch sw;
294  union cavium_spi_sts sts;
295 
297  do {
298  sts.u = read64(&regs->sts);
299  if (!sts.s.busy)
300  return 0;
301  } while (!stopwatch_expired(&sw));
302  printk(BIOS_DEBUG, "SPI: Timed out after %uus\n", SPI_TIMEOUT_US);
303  return -1;
304 }
305 
306 static int do_xfer(const struct spi_slave *slave, struct spi_op *vector,
307  int leavecs)
308 {
309  struct cavium_spi *regs = to_cavium_spi(slave)->regs;
310  uint8_t *out_buf = (uint8_t *)vector->dout;
311  size_t bytesout = vector->bytesout;
312  uint8_t *in_buf = (uint8_t *)vector->din;
313  size_t bytesin = vector->bytesin;
314  union cavium_spi_sts sts;
315  union cavium_spi_tx tx;
316 
317  /**
318  * The CN81xx SPI controller is half-duplex and has 8 data registers.
319  * If >8 bytes remain in the transfer then we must set LEAVECS = 1 so
320  * that the /CS remains asserted. Once <=8 bytes remain we must set
321  * LEAVECS = 0 so that /CS is de-asserted, thus completing the transfer.
322  */
323  while (bytesout) {
324  size_t out_now = MIN(bytesout, 8);
325  unsigned int i;
326 
327  for (i = 0; i < out_now; i++)
328  write64(&regs->dat[i], out_buf[i] & 0xff);
329 
330  tx.u = 0;
331  tx.s.csid = to_cavium_spi(slave)->cs;
332  if (leavecs || ((bytesout > 8) || bytesin))
333  tx.s.leavecs = 1;
334  /* number of bytes to transmit goes in both TXNUM and TOTNUM */
335  tx.s.totnum = out_now;
336  tx.s.txnum = out_now;
337  write64(&regs->tx, tx.u);
338 
339  /* check status */
340  if (cavium_spi_wait(regs) < 0)
341  return -1;
342 
343  bytesout -= out_now;
344  out_buf += out_now;
345  }
346 
347  while (bytesin) {
348  size_t in_now = MIN(bytesin, 8);
349  unsigned int i;
350 
351  tx.u = 0;
352  tx.s.csid = to_cavium_spi(slave)->cs;
353  if (leavecs || (bytesin > 8))
354  tx.s.leavecs = 1;
355  tx.s.totnum = in_now;
356  write64(&regs->tx, tx.u);
357 
358  /* check status */
359  if (cavium_spi_wait(regs) < 0)
360  return -1;
361 
362  sts.u = read64(&regs->sts);
363  if (sts.s.rxnum != in_now) {
365  "SPI: Incorrect number of bytes received: %u.\n",
366  sts.s.rxnum);
367  return -1;
368  }
369 
370  for (i = 0; i < in_now; i++) {
371  *in_buf = (uint8_t)((read64(&regs->dat[i]) & 0xff));
372  in_buf++;
373  }
374  bytesin -= in_now;
375  }
376 
377  return 0;
378 }
379 
380 static int spi_ctrlr_xfer_vector(const struct spi_slave *slave,
381  struct spi_op vectors[], size_t count)
382 {
383  int i;
384 
385  for (i = 0; i < count; i++) {
386  if (do_xfer(slave, &vectors[i], count - 1 == i ? 0 : 1)) {
388  "SPI: Failed to transfer %zu vectors.\n", count);
389  return -1;
390  }
391  }
392 
393  return 0;
394 }
395 static const struct spi_ctrlr spi_ctrlr = {
396 
398  .max_xfer_size = SPI_CTRLR_DEFAULT_MAX_XFER_SIZE,
399 };
400 
401 const struct spi_ctrlr_buses spi_ctrlr_bus_map[] = {
402  {
403  .ctrlr = &spi_ctrlr,
404  .bus_start = 0,
405  .bus_end = ARRAY_SIZE(cavium_spi_slaves) - 1,
406  },
407 };
void write64(void *addr, uint64_t val)
uint64_t read64(const void *addr)
#define assert(statement)
Definition: assert.h:74
#define ARRAY_SIZE(a)
Definition: helpers.h:12
#define MIN(a, b)
Definition: helpers.h:37
#define printk(level,...)
Definition: stdlib.h:16
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_DEBUG
BIOS_DEBUG - Verbose output.
Definition: loglevel.h:128
#define BIOS_ERR
BIOS_ERR - System in incomplete state.
Definition: loglevel.h:72
u64 thunderx_get_io_clock(void)
Returns the I/O clock speed in Hz.
Definition: clock.c:45
#define MPI_PF_BAR0
Definition: addressmap.h:116
static int spi_ctrlr_xfer_vector(const struct spi_slave *slave, struct spi_op vectors[], size_t count)
Definition: spi.c:380
void spi_set_cs(const size_t bus, const size_t chip_select, const size_t assert_is_low)
Set SPI Chip select line and level if asserted.
Definition: spi.c:150
void spi_set_clock(const size_t bus, const size_t speed_hz, const size_t idle_low, const size_t idle_cycles)
Set SPI clock frequency.
Definition: spi.c:180
void spi_enable(const size_t bus)
Enable the SPI controller.
Definition: spi.c:106
static struct cavium_spi_slave cavium_spi_slaves[]
Definition: spi.c:88
static const struct spi_ctrlr spi_ctrlr
Definition: spi.c:395
void spi_init_custom(const size_t bus, const size_t speed_hz, const size_t idle_low, const size_t idle_cycles, const size_t lsb_first, const size_t chip_select, const size_t assert_is_low)
Init SPI with custom parameters and enable SPI controller.
Definition: spi.c:261
void spi_disable(const size_t bus)
Disable the SPI controller.
Definition: spi.c:127
static int cavium_spi_wait(struct cavium_spi *regs)
Definition: spi.c:291
const struct spi_ctrlr_buses spi_ctrlr_bus_map[]
Definition: spi.c:401
check_member(cavium_spi, cfg, 0)
#define SPI_TIMEOUT_US
Definition: spi.c:86
void spi_set_lsbmsb(const size_t bus, const size_t lsb_first)
Set SPI LSB/MSB first.
Definition: spi.c:234
static struct cavium_spi_slave * to_cavium_spi(const struct spi_slave *slave)
Definition: spi.c:95
uint64_t spi_get_clock(const size_t bus)
Get current SPI clock frequency in Hz.
Definition: spi.c:211
void spi_init(void)
Init all SPI controllers with default values and enable all SPI controller.
Definition: spi.c:280
static int do_xfer(const struct spi_slave *slave, struct spi_op *vector, int leavecs)
Definition: spi.c:306
const size_t spi_ctrlr_bus_map_count
Definition: spi.c:408
#define SPI_CTRLR_DEFAULT_MAX_XFER_SIZE
Definition: spi-generic.h:102
static struct spi_slave slave
Definition: spiconsole.c:7
uint64_t u64
Definition: stdint.h:54
unsigned long long uint64_t
Definition: stdint.h:17
uint8_t u8
Definition: stdint.h:45
unsigned char uint8_t
Definition: stdint.h:8
Definition: device.h:76
struct cavium_spi * regs
Definition: spi.c:82
Definition: spi.c:62
union cavium_spi_tx tx
Definition: spi.c:65
u64 sts_w1s
Definition: spi.c:67
u64 rsvd1
Definition: spi.c:66
u64 int_ena_w1s
Definition: spi.c:70
u64 int_ena_w1c
Definition: spi.c:69
u64 dat[8]
Definition: spi.c:73
union cavium_spi_sts sts
Definition: spi.c:64
u64 rsvd2
Definition: spi.c:68
union cavium_spi_cfg cfg
Definition: spi.c:63
u64 wide_dat
Definition: spi.c:71
u8 rsvd4[0x38]
Definition: spi.c:72
const struct spi_ctrlr * ctrlr
Definition: spi-generic.h:175
int(* xfer_vector)(const struct spi_slave *slave, struct spi_op vectors[], size_t count)
Definition: spi-generic.h:154
size_t bytesin
Definition: spi-generic.h:65
void * din
Definition: spi-generic.h:64
size_t bytesout
Definition: spi-generic.h:63
const void * dout
Definition: spi-generic.h:62
unsigned int bus
Definition: spi-generic.h:41
u64 lsbfirst
Definition: spi.c:25
u64 clkdiv
Definition: spi.c:32
u64 csena
Definition: spi.c:31
struct cavium_spi_cfg::@434 s
u64 tristate
Definition: spi.c:29
u64 cslate
Definition: spi.c:30
u64 wireor
Definition: spi.c:24
u64 cshi
Definition: spi.c:27
u64 enable
Definition: spi.c:21
u64 idleclks
Definition: spi.c:28
u64 idlelow
Definition: spi.c:22
u64 u
Definition: spi.c:19
u64 clk_cont
Definition: spi.c:23
u64 mpi_intr
Definition: spi.c:41
struct cavium_spi_sts::@435 s
u64 u
Definition: spi.c:38
u64 busy
Definition: spi.c:40
u64 rxnum
Definition: spi.c:43
u64 u
Definition: spi.c:49
u64 txnum
Definition: spi.c:53
u64 leavecs
Definition: spi.c:55
u64 csid
Definition: spi.c:57
u64 totnum
Definition: spi.c:51
struct cavium_spi_tx::@436 s
#define count