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 <soc/spi.h>
5 #include <soc/clock.h>
6 #include <soc/addressmap.h>
7 
8 #include "spi_internal.h"
9 
10 static struct spi_ctrl *spictrls[] = {
11  (struct spi_ctrl *)FU540_QSPI0,
12  (struct spi_ctrl *)FU540_QSPI1,
13  (struct spi_ctrl *)FU540_QSPI2
14 };
15 
16 /**
17  * Wait until SPI is ready for transmission and transmit byte.
18  */
19 static void spi_tx(volatile struct spi_ctrl *spictrl, uint8_t in)
20 {
21 #if __riscv_atomic
22  int32_t r;
23  do {
24  asm volatile (
25  "amoor.w %0, %2, %1\n"
26  : "=r" (r), "+A" (spictrl->txdata.raw_bits)
27  : "r" (in)
28  );
29  } while (r < 0);
30 #else
31  while ((int32_t) spictrl->txdata.raw_bits < 0)
32  ;
33  spictrl->txdata.data = in;
34 #endif
35 }
36 
37 /**
38  * Wait until SPI receive queue has data and read byte.
39  */
40 static uint8_t spi_rx(volatile struct spi_ctrl *spictrl)
41 {
42  int32_t out;
43  while ((out = (int32_t) spictrl->rxdata.raw_bits) < 0)
44  ;
45  return (uint8_t) out;
46 }
47 
48 static int spi_claim_bus_(const struct spi_slave *slave)
49 {
50  struct spi_ctrl *spictrl = spictrls[slave->bus];
52  csmode.raw_bits = 0;
55  return 0;
56 }
57 
58 static void spi_release_bus_(const struct spi_slave *slave)
59 {
60  struct spi_ctrl *spictrl = spictrls[slave->bus];
62  csmode.raw_bits = 0;
65 }
66 
67 static int spi_xfer_(const struct spi_slave *slave,
68  const void *dout, size_t bytesout,
69  void *din, size_t bytesin)
70 {
71  struct spi_ctrl *spictrl = spictrls[slave->bus];
73  fmt.raw_bits = read32(&spictrl->fmt.raw_bits);
74  if (fmt.proto == FU540_SPI_PROTO_S) {
75  /* working in full-duplex mode
76  * receiving data needs to be triggered by sending data */
77  while (bytesout || bytesin) {
78  uint8_t in, out = 0;
79  if (bytesout) {
80  out = *(uint8_t *)dout++;
81  bytesout--;
82  }
83  spi_tx(spictrl, out);
84  in = spi_rx(spictrl);
85  if (bytesin) {
86  *(uint8_t *)din++ = in;
87  bytesin--;
88  }
89  }
90  } else {
91  /* Working in half duplex
92  * send and receive can be done separately */
93  if (dout && din)
94  return -1;
95 
96  if (dout) {
97  while (bytesout) {
98  spi_tx(spictrl, *(uint8_t *)dout++);
99  bytesout--;
100  }
101  }
102 
103  if (din) {
104  while (bytesin) {
105  *(uint8_t *)din++ = spi_rx(spictrl);
106  bytesin--;
107  }
108  }
109  }
110  return 0;
111 }
112 
113 static int spi_setup_(const struct spi_slave *slave)
114 {
118 
119  if ((slave->bus > 2) || (slave->cs != 0))
120  return -1;
121 
122  struct spi_ctrl *spictrl = spictrls[slave->bus];
123 
125  10000));
126 
127  sckmode.raw_bits = 0;
131 
132  write32(&spictrl->csdef, 0xffffffff);
133 
134  csmode.raw_bits = 0;
136  write32(&spictrl->csmode.raw_bits, csmode.raw_bits);
137 
138  fmt.raw_bits = 0;
141  fmt.dir = 0;
142  fmt.len = 8;
143  write32(&spictrl->fmt.raw_bits, fmt.raw_bits);
144 
145  return 0;
146 }
147 
148 struct spi_ctrlr fu540_spi_ctrlr = {
149  .xfer = spi_xfer_,
150  .setup = spi_setup_,
151  .claim_bus = spi_claim_bus_,
152  .release_bus = spi_release_bus_,
153 };
154 
155 const struct spi_ctrlr_buses spi_ctrlr_bus_map[] = {
156  {
157  .bus_start = 0,
158  .bus_end = 2,
159  .ctrlr = &fu540_spi_ctrlr,
160  }
161 };
162 
164 
165 int fu540_spi_setup(unsigned int bus, unsigned int cs,
166  struct spi_slave *slave,
167  struct fu540_spi_config *config)
168 {
169  spi_reg_sckmode sckmode;
170  spi_reg_csmode csmode;
171  spi_reg_fmt fmt;
172 
173  if ((bus > 2) || (cs != 0))
174  return -1;
175 
176  if ((config->pha > 1)
177  || (config->pol > 1)
178  || (config->protocol > 2)
179  || (config->endianness > 1)
180  || (config->bits_per_frame > 8))
181  return -1;
182 
183  slave->bus = bus;
184  slave->cs = cs;
186 
187  struct spi_ctrl *spictrl = spictrls[slave->bus];
188 
190  config->freq / 1000));
191 
192  sckmode.raw_bits = 0;
193  sckmode.pha = config->pha;
194  sckmode.pol = config->pol;
196 
197  write32(&spictrl->csdef, 0xffffffff);
198 
199  csmode.raw_bits = 0;
201  write32(&spictrl->csmode.raw_bits, csmode.raw_bits);
202 
203  fmt.raw_bits = 0;
204  fmt.proto = config->protocol;
205  fmt.endian = config->endianness;
206  fmt.dir = 0;
207  fmt.len = config->bits_per_frame;
208  write32(&spictrl->fmt.raw_bits, fmt.raw_bits);
209 
210  return 0;
211 }
212 
214  const struct spi_slave *slave,
215  const struct fu540_spi_mmap_config *config)
216 {
219 
220  if (slave->bus > 2)
221  return -1;
222 
223  if ((config->cmd_en > 1)
224  || (config->addr_len > 4)
225  || (config->pad_cnt > 15)
226  || (config->cmd_proto > 2)
227  || (config->addr_proto > 2)
228  || (config->data_proto > 2)
229  || (config->cmd_code > 255)
230  || (config->pad_code > 255))
231  return -1;
232 
233  struct spi_ctrl *spictrl = spictrls[slave->bus];
234 
235  /* disable direct memory-mapped spi flash mode */
236  fctrl.raw_bits = 0;
237  fctrl.en = 0;
238  write32(&spictrl->fctrl.raw_bits, fctrl.raw_bits);
239 
240  /* reset spi flash chip */
241  spi_tx(spictrl, 0x66);
242  spi_tx(spictrl, 0x99);
243 
244  /* Pass the information of the flash read operation to the spi
245  * controller */
246  ffmt.raw_bits = 0;
247  ffmt.cmd_en = config->cmd_en;
248  ffmt.addr_len = config->addr_len;
249  ffmt.pad_cnt = config->pad_cnt;
250  ffmt.command_proto = config->cmd_proto;
251  ffmt.addr_proto = config->addr_proto;
252  ffmt.data_proto = config->data_proto;
253  ffmt.command_code = config->cmd_code;
254  ffmt.pad_code = config->pad_code;
255  write32(&spictrl->ffmt.raw_bits, ffmt.raw_bits);
256 
257  /* enable direct memory-mapped spi flash mode */
258  fctrl.raw_bits = 0;
259  fctrl.en = 1;
260  write32(&spictrl->fctrl.raw_bits, fctrl.raw_bits);
261 
262  return 0;
263 }
static void write32(void *addr, uint32_t val)
Definition: mmio.h:40
static uint32_t read32(const void *addr)
Definition: mmio.h:22
#define ARRAY_SIZE(a)
Definition: helpers.h:12
enum board_config config
Definition: memory.c:448
const struct spi_ctrlr_buses spi_ctrlr_bus_map[]
Definition: spi.c:401
const size_t spi_ctrlr_bus_map_count
Definition: spi.c:408
int clock_get_tlclk_khz(void)
Definition: clock.c:274
#define FU540_QSPI2
Definition: addressmap.h:12
#define FU540_QSPI1
Definition: addressmap.h:11
#define FU540_QSPI0
Definition: addressmap.h:10
#define FU540_SPI_PROTO_S
Definition: spi.h:8
#define FU540_SPI_ENDIAN_BIG
Definition: spi.h:15
#define FU540_SPI_POL_LEADING
Definition: spi.h:25
#define FU540_SPI_PHA_LOW
Definition: spi.h:20
static uint8_t spi_rx(volatile struct spi_ctrl *spictrl)
Wait until SPI receive queue has data and read byte.
Definition: spi.c:40
int fu540_spi_mmap(const struct spi_slave *slave, const struct fu540_spi_mmap_config *config)
Definition: spi.c:213
static void spi_release_bus_(const struct spi_slave *slave)
Definition: spi.c:58
static int spi_xfer_(const struct spi_slave *slave, const void *dout, size_t bytesout, void *din, size_t bytesin)
Definition: spi.c:67
static struct spi_ctrl * spictrls[]
Definition: spi.c:10
static void spi_tx(volatile struct spi_ctrl *spictrl, uint8_t in)
Wait until SPI is ready for transmission and transmit byte.
Definition: spi.c:19
struct spi_ctrlr fu540_spi_ctrlr
Definition: spi.c:148
int fu540_spi_setup(unsigned int bus, unsigned int cs, struct spi_slave *slave, struct fu540_spi_config *config)
Definition: spi.c:165
static int spi_setup_(const struct spi_slave *slave)
Definition: spi.c:113
static int spi_claim_bus_(const struct spi_slave *slave)
Definition: spi.c:48
#define FU540_SPI_CSMODE_OFF
Definition: spi_internal.h:13
#define FU540_SPI_CSMODE_AUTO
Definition: spi_internal.h:11
static unsigned int spi_min_clk_divisor(unsigned int input_khz, unsigned int max_target_khz)
Get smallest clock divisor that divides input_khz to a quotient less than or equal to max_target_khz;...
Definition: spi_internal.h:196
#define FU540_SPI_CSMODE_HOLD
Definition: spi_internal.h:12
static struct spi_slave slave
Definition: spiconsole.c:7
signed int int32_t
Definition: stdint.h:13
unsigned char uint8_t
Definition: stdint.h:8
Definition: device.h:76
Definition: jpeg.c:27
SPI control register memory map.
Definition: spi_internal.h:151
uint32_t sckdiv
Definition: spi_internal.h:152
spi_reg_ffmt ffmt
Definition: spi_internal.h:183
spi_reg_rxdata rxdata
Definition: spi_internal.h:175
uint32_t csdef
Definition: spi_internal.h:158
spi_reg_txdata txdata
Definition: spi_internal.h:174
spi_reg_csmode csmode
Definition: spi_internal.h:159
spi_reg_fmt fmt
Definition: spi_internal.h:172
spi_reg_fctrl fctrl
Definition: spi_internal.h:182
spi_reg_sckmode sckmode
Definition: spi_internal.h:153
unsigned int bus_start
Definition: spi-generic.h:176
int(* xfer)(const struct spi_slave *slave, const void *dout, size_t bytesout, void *din, size_t bytesin)
Definition: spi-generic.h:152
unsigned int bus
Definition: spi-generic.h:41
unsigned int cs
Definition: spi-generic.h:42
const struct spi_ctrlr * ctrlr
Definition: spi-generic.h:43
uint32_t mode
Definition: spi_internal.h:27
uint32_t raw_bits
Definition: spi_internal.h:30
uint32_t raw_bits
Definition: spi_internal.h:112
uint32_t cmd_en
Definition: spi_internal.h:118
uint32_t raw_bits
Definition: spi_internal.h:128
uint32_t command_proto
Definition: spi_internal.h:121
uint32_t pad_code
Definition: spi_internal.h:126
uint32_t command_code
Definition: spi_internal.h:125
uint32_t addr_len
Definition: spi_internal.h:119
uint32_t addr_proto
Definition: spi_internal.h:122
uint32_t pad_cnt
Definition: spi_internal.h:120
uint32_t data_proto
Definition: spi_internal.h:123
uint32_t endian
Definition: spi_internal.h:59
uint32_t proto
Definition: spi_internal.h:58
uint32_t len
Definition: spi_internal.h:62
uint32_t dir
Definition: spi_internal.h:60
uint32_t raw_bits
Definition: spi_internal.h:65
uint32_t raw_bits
Definition: spi_internal.h:85
uint32_t raw_bits
Definition: spi_internal.h:21
uint32_t raw_bits
Definition: spi_internal.h:75
uint32_t data
Definition: spi_internal.h:71