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 <boot_device.h>
6 #include <cbfs.h>
7 #include <commonlib/region.h>
8 #include <console/console.h>
9 #include <soc/clk.h>
10 #include <soc/gpio.h>
11 #include <soc/spi.h>
12 #include <stddef.h>
13 #include <stdint.h>
14 #include <symbols.h>
15 
16 #if defined(CONFIG_DEBUG_SPI) && CONFIG_DEBUG_SPI
17 # define DEBUG_SPI(x,...) printk(BIOS_DEBUG, "EXYNOS_SPI: " x)
18 #else
19 # define DEBUG_SPI(x,...)
20 #endif
21 
22 static void exynos_spi_rx_tx(struct exynos_spi *regs, int todo,
23  void *dinp, void const *doutp, int i)
24 {
25  int rx_lvl, tx_lvl;
26  unsigned int *rxp = (unsigned int *)(dinp + (i * (32 * 1024)));
27  unsigned int out_bytes, in_bytes;
28 
29  // TODO In current implementation, every read/write must be aligned to
30  // 4 bytes, otherwise you may get timeout or other unexpected results.
31  ASSERT(todo % 4 == 0);
32 
33  out_bytes = in_bytes = todo;
34  setbits32(&regs->ch_cfg, SPI_CH_RST);
35  clrbits32(&regs->ch_cfg, SPI_CH_RST);
36  write32(&regs->pkt_cnt, ((todo * 8) / 32) | SPI_PACKET_CNT_EN);
37 
38  while (in_bytes) {
39  uint32_t spi_sts;
40  int temp;
41 
42  spi_sts = read32(&regs->spi_sts);
43  rx_lvl = ((spi_sts >> 15) & 0x7f);
44  tx_lvl = ((spi_sts >> 6) & 0x7f);
45  while (tx_lvl < 32 && out_bytes) {
46  // TODO The "writing" (tx) is not supported now; that's
47  // why we write garbage to keep driving FIFO clock.
48  temp = 0xffffffff;
49  write32(&regs->tx_data, temp);
50  out_bytes -= 4;
51  tx_lvl += 4;
52  }
53  while (rx_lvl >= 4 && in_bytes) {
54  temp = read32(&regs->rx_data);
55  if (rxp)
56  *rxp++ = temp;
57  in_bytes -= 4;
58  rx_lvl -= 4;
59  }
60  }
61 }
62 
63 /* set up SPI channel */
65 {
66  /* set the spi1 GPIO */
67 
68  /* set pktcnt and enable it */
69  write32(&regs->pkt_cnt, 4 | SPI_PACKET_CNT_EN);
70  /* set FB_CLK_SEL */
71  write32(&regs->fb_clk, SPI_FB_DELAY_180);
72  /* set CH_WIDTH and BUS_WIDTH as word */
73  setbits32(&regs->mode_cfg,
75  clrbits32(&regs->ch_cfg, SPI_CH_CPOL_L); /* CPOL: active high */
76 
77  /* clear rx and tx channel if set previously */
79 
80  setbits32(&regs->swap_cfg,
82 
83  /* do a soft reset */
84  setbits32(&regs->ch_cfg, SPI_CH_RST);
85  clrbits32(&regs->ch_cfg, SPI_CH_RST);
86 
87  /* now set rx and tx channel ON */
89  return 0;
90 }
91 
92 int exynos_spi_read(struct exynos_spi *regs, void *dest, u32 len, u32 off)
93 {
94  int upto, todo;
95  int i;
96  clrbits32(&regs->cs_reg, SPI_SLAVE_SIG_INACT); /* CS low */
97 
98  /* Send read instruction (0x3h) followed by a 24 bit addr */
99  write32(&regs->tx_data, (SF_READ_DATA_CMD << 24) | off);
100 
101  /* waiting for TX done */
102  while (!(read32(&regs->spi_sts) & SPI_ST_TX_DONE));
103 
104  for (upto = 0, i = 0; upto < len; upto += todo, i++) {
105  todo = MIN(len - upto, (1 << 15));
106  exynos_spi_rx_tx(regs, todo, dest, (void *)(off), i);
107  }
108 
109  setbits32(&regs->cs_reg, SPI_SLAVE_SIG_INACT);/* make the CS high */
110 
111  return len;
112 }
113 
115 {
116  /*
117  * Let put controller mode to BYTE as
118  * SPI driver does not support WORD mode yet
119  */
120  clrbits32(&regs->mode_cfg,
122  write32(&regs->swap_cfg, 0);
123 
124  /*
125  * Flush spi tx, rx fifos and reset the SPI controller
126  * and clear rx/tx channel
127  */
129  clrbits32(&regs->ch_cfg, SPI_CH_RST);
131  return 0;
132 }
133 
135 
136 static ssize_t exynos_spi_readat(const struct region_device *rdev, void *dest,
137  size_t offset, size_t count)
138 {
139  int bytes;
140  DEBUG_SPI("exynos_spi_cbfs_read(%u)\n", count);
142  bytes = exynos_spi_read(boot_slave_regs, dest, count, offset);
144  return bytes;
145 }
146 
147 static void *exynos_spi_map(const struct region_device *rdev,
148  size_t offset, size_t count)
149 {
150  DEBUG_SPI("exynos_spi_cbfs_map\n");
151  // exynos: spi_rx_tx may work in 4 byte-width-transmission mode and
152  // requires buffer memory address to be aligned.
153  if (count % 4)
154  count += 4 - (count % 4);
156 }
157 
158 static const struct region_device_ops exynos_spi_ops = {
159  .mmap = exynos_spi_map,
160  .munmap = mmap_helper_rdev_munmap,
161  .readat = exynos_spi_readat,
162 };
163 
164 static struct mmap_helper_region_device mdev =
165  MMAP_HELPER_DEV_INIT(&exynos_spi_ops, 0, CONFIG_ROM_SIZE, &cbfs_cache);
166 
168 {
170 }
171 
173 {
174  return &mdev.rdev;
175 }
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(x)
Definition: assert.h:44
#define MIN(a, b)
Definition: helpers.h:37
struct mem_pool cbfs_cache
Definition: cbfs.c:26
static struct region_device rdev
Definition: flashconsole.c:14
static size_t offset
Definition: flashconsole.c:16
#define setbits32(addr, set)
Definition: mmio.h:21
#define clrsetbits32(addr, clear, set)
Definition: mmio.h:16
#define clrbits32(addr, clear)
Definition: mmio.h:26
void * mmap_helper_rdev_mmap(const struct region_device *, size_t, size_t)
Definition: region.c:303
int mmap_helper_rdev_munmap(const struct region_device *, void *)
Definition: region.c:324
#define MMAP_HELPER_DEV_INIT(ops_, offset_, size_, mpool_)
Definition: region.h:219
#define SF_READ_DATA_CMD
Definition: spi.h:35
#define EXYNOS5_SPI1_BASE
Definition: cpu.h:40
#define SPI_RX_SWAP_EN
Definition: spi.h:68
#define SPI_SLAVE_SIG_INACT
Definition: spi.h:46
#define SPI_CH_HS_EN
Definition: spi.h:33
#define SPI_FB_DELAY_180
Definition: spi.h:57
#define SPI_RX_CH_ON
Definition: spi.h:38
#define SPI_MODE_CH_WIDTH_WORD
Definition: spi.h:42
#define SPI_RX_BYTE_SWAP
Definition: spi.h:69
#define SPI_CH_CPOL_L
Definition: spi.h:36
#define SPI_ST_TX_DONE
Definition: spi.h:49
#define SPI_RX_HWORD_SWAP
Definition: spi.h:70
#define SPI_MODE_BUS_WIDTH_WORD
Definition: spi.h:43
#define SPI_CH_RST
Definition: spi.h:34
#define SPI_TX_CH_ON
Definition: spi.h:39
#define SPI_PACKET_CNT_EN
Definition: spi.h:61
#define DEBUG_SPI(x,...)
Definition: spi.c:19
void exynos_init_spi_boot_device(void)
Definition: spi.c:167
static struct mmap_helper_region_device mdev
Definition: spi.c:164
static ssize_t exynos_spi_readat(const struct region_device *rdev, void *dest, size_t offset, size_t count)
Definition: spi.c:136
const struct region_device * exynos_spi_boot_device(void)
Definition: spi.c:172
int exynos_spi_close(struct exynos_spi *regs)
Definition: spi.c:114
static struct exynos_spi * boot_slave_regs
Definition: spi.c:134
int exynos_spi_open(struct exynos_spi *regs)
Definition: spi.c:64
static void * exynos_spi_map(const struct region_device *rdev, size_t offset, size_t count)
Definition: spi.c:147
static const struct region_device_ops exynos_spi_ops
Definition: spi.c:158
int exynos_spi_read(struct exynos_spi *regs, void *dest, u32 len, u32 off)
Definition: spi.c:92
static void exynos_spi_rx_tx(struct exynos_spi *regs, int todo, void *dinp, void const *doutp, int i)
Definition: spi.c:22
__SIZE_TYPE__ ssize_t
Definition: stddef.h:13
unsigned int uint32_t
Definition: stdint.h:14
uint32_t u32
Definition: stdint.h:51
Definition: spi.h:9
struct region_device rdev
Definition: region.h:216
void *(* mmap)(const struct region_device *, size_t, size_t)
Definition: region.h:68
#define count