coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
flash_controller.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <assert.h>
4 #include <console/console.h>
5 #include <device/mmio.h>
7 #include <soc/symbols.h>
8 #include <spi_flash.h>
9 #include <spi-generic.h>
10 #include <string.h>
11 #include <symbols.h>
12 #include <timer.h>
13 #include <types.h>
14 
15 static struct mtk_nor_regs *const mtk_nor = (void *)SFLASH_REG_BASE;
16 
17 #define GET_NTH_BYTE(d, n) ((d >> (8 * n)) & 0xff)
18 
19 static int polling_cmd(u32 val)
20 {
21  struct stopwatch sw;
22 
24 
25  while ((read32(&mtk_nor->cmd) & val) != 0) {
26  if (stopwatch_expired(&sw))
27  return -1;
28  }
29 
30  return 0;
31 }
32 
33 static int mtk_nor_execute_cmd(u8 cmdval)
34 {
35  u8 val = cmdval & ~SFLASH_AUTOINC;
36 
37  write8(&mtk_nor->cmd, cmdval);
38  return polling_cmd(val);
39 }
40 
42 {
44  return -1;
45 
46  *value = read8(&mtk_nor->rdsr);
47  return 0;
48 }
49 
50 static int wait_for_write_done(void)
51 {
52  struct stopwatch sw;
53  u8 reg;
54 
56 
57  while (sflashhw_read_flash_status(&reg) == 0) {
58  if (!(reg & SFLASH_WRITE_IN_PROGRESS))
59  return 0;
60  if (stopwatch_expired(&sw))
61  return -1;
62  }
63 
64  return -1;
65 }
66 
67 /* set serial flash program address */
68 static void set_sfpaddr(u32 addr)
69 {
70  write8(&mtk_nor->radr[2], GET_NTH_BYTE(addr, 2));
71  write8(&mtk_nor->radr[1], GET_NTH_BYTE(addr, 1));
72  write8(&mtk_nor->radr[0], GET_NTH_BYTE(addr, 0));
73 }
74 
75 static int sector_erase(int offset)
76 {
77  if (wait_for_write_done())
78  return -1;
79 
81  write8(&mtk_nor->cnt, 8);
83 
88  write8(&mtk_nor->cnt, 32);
90 
91  if (wait_for_write_done())
92  return -1;
93 
94  return 0;
95 }
96 
97 static int dma_read(u32 addr, uintptr_t dma_buf, u32 len)
98 {
99  struct stopwatch sw;
100 
103 
104  /* do dma reset */
107  /* flash source address and dram dest address */
109  write32(&mtk_nor->fdma_dadr, dma_buf);
110  write32(&mtk_nor->fdma_end_dadr, (dma_buf + len));
111  /* start dma */
113 
115  while ((read32(&mtk_nor->fdma_ctl) & SFLASH_DMA_TRIGGER) != 0) {
116  if (stopwatch_expired(&sw)) {
117  printk(BIOS_WARNING, "dma read timeout!\n");
118  return -1;
119  }
120  }
121 
122  return 0;
123 }
124 
125 static int nor_read(const struct spi_flash *flash, u32 addr, size_t len,
126  void *buf)
127 {
128  uintptr_t dma_buf = (uintptr_t)_dma_coherent;
129  size_t dma_buf_len = REGION_SIZE(dma_coherent);
131  u32 skip = addr - start;
132  u32 total = ALIGN_UP(skip + len, SFLASH_DMA_ALIGN);
133  u32 drop = total - skip - len;
134  u32 done, read_len, copy_len;
135  uint8_t *dest = (uint8_t *)buf;
136 
137  /* Refer to CB:13989 for the hardware limitation on mt8173. */
138  if (CONFIG(SOC_MEDIATEK_MT8173)) {
140  dma_buf = (uintptr_t)_dram_dma;
141  dma_buf_len = REGION_SIZE(dram_dma);
142  }
143  }
144 
145  if (CONFIG(FLASH_DUAL_READ)) {
148  }
149 
150  /* DMA: start [ skip | len | drop ] = total end */
151  for (done = 0; done < total; dest += copy_len) {
152  read_len = MIN(dma_buf_len, total - done);
153  if (dma_read(start + done, dma_buf, read_len))
154  return -1;
155 
156  done += read_len;
157  /* decide the range to copy into buffer */
158  if (done == total)
159  read_len -= drop; /* Only drop in last iteration */
160 
161  copy_len = read_len - skip;
162  memcpy(dest, (uint8_t *)dma_buf + skip, copy_len);
163  if (skip)
164  skip = 0; /* Only apply skip in first iteration. */
165  }
166  return 0;
167 }
168 
169 static int nor_write(const struct spi_flash *flash, u32 addr, size_t len,
170  const void *buf)
171 {
172  const u8 *buffer = (const u8 *)buf;
173 
174  set_sfpaddr(addr);
175  while (len) {
176  write8(&mtk_nor->wdata, *buffer);
178  return -1;
179 
180  if (wait_for_write_done())
181  return -1;
182  buffer++;
183  len--;
184  }
185  return 0;
186 }
187 
188 static int nor_erase(const struct spi_flash *flash, u32 offset, size_t len)
189 {
190  int sector_start = offset;
191  int sector_num = (u32)len / flash->sector_size;
192 
193  while (sector_num) {
194  if (!sector_erase(sector_start)) {
195  sector_start += flash->sector_size;
196  sector_num--;
197  } else {
198  printk(BIOS_WARNING, "Erase failed at %#x!\n",
199  sector_start);
200  return -1;
201  }
202  }
203  return 0;
204 }
205 
206 const struct spi_flash_ops spi_flash_ops = {
207  .read = nor_read,
208  .write = nor_write,
209  .erase = nor_erase,
210 };
211 
212 int mtk_spi_flash_probe(const struct spi_slave *spi,
213  struct spi_flash *flash)
214 {
216  memcpy(&flash->spi, spi, sizeof(*spi));
217 
218  flash->sector_size = 0x1000;
219  flash->erase_cmd = SECTOR_ERASE_CMD;
220  flash->size = CONFIG_ROM_SIZE;
221 
222  flash->ops = &spi_flash_ops;
223 
224  return 0;
225 }
pte_t value
Definition: mmu.c:91
static void write8(void *addr, uint8_t val)
Definition: mmio.h:30
static void write32(void *addr, uint32_t val)
Definition: mmio.h:40
static uint32_t read32(const void *addr)
Definition: mmio.h:22
static uint8_t read8(const void *addr)
Definition: mmio.h:12
void * memcpy(void *dest, const void *src, size_t n)
Definition: memcpy.c:7
#define assert(statement)
Definition: assert.h:74
#define IS_ALIGNED(x, a)
Definition: helpers.h:19
#define MIN(a, b)
Definition: helpers.h:37
#define ALIGN_DOWN(x, a)
Definition: helpers.h:18
#define ALIGN_UP(x, a)
Definition: helpers.h:17
static u32 addr
Definition: cirrus.c:14
#define printk(level,...)
Definition: stdlib.h:16
int dma_coherent(void *ptr)
@ CONFIG
Definition: dsi_common.h:201
const struct spi_flash_ops spi_flash_ops
static int nor_write(const struct spi_flash *flash, u32 addr, size_t len, const void *buf)
static struct mtk_nor_regs *const mtk_nor
static int sector_erase(int offset)
static int nor_erase(const struct spi_flash *flash, u32 offset, size_t len)
static int sflashhw_read_flash_status(u8 *value)
static int mtk_nor_execute_cmd(u8 cmdval)
static int wait_for_write_done(void)
static int nor_read(const struct spi_flash *flash, u32 addr, size_t len, void *buf)
static void set_sfpaddr(u32 addr)
int mtk_spi_flash_probe(const struct spi_slave *spi, struct spi_flash *flash)
static int dma_read(u32 addr, uintptr_t dma_buf, u32 len)
static int polling_cmd(u32 val)
#define GET_NTH_BYTE(d, n)
@ SFLASH_READSTATUS
@ SFLASH_AUTOINC
@ SFLASH_OP_WREN
@ SFLASH_DMA_ALIGN
@ SFLASH_COMMAND_ENABLE
@ SFLASH_PRG_CMD
@ SFLASH_DMA_TRIGGER
@ SECTOR_ERASE_CMD
@ SFLASH_READ_DUAL_EN
@ SFLASH_DMA_SW_RESET
@ SFLASH_1_1_2_READ
@ SFLASH_DMA_WDLE_EN
@ SFLASH_POLLINGREG_US
@ SFLASH_WR_TRIGGER
@ SFLASH_WRITE_IN_PROGRESS
static size_t offset
Definition: flashconsole.c:16
#define setbits8(addr, set)
Definition: mmio.h:19
#define REGION_SIZE(name)
Definition: symbols.h:10
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_WARNING
BIOS_WARNING - Bad configuration.
Definition: loglevel.h:86
static uint8_t * buf
Definition: uart.c:7
u8 buffer[C2P_BUFFER_MAXSIZE]
Definition: psp_smm.c:18
#define ENV_BOOTBLOCK
Definition: rules.h:148
#define ENV_SEPARATE_VERSTAGE
Definition: rules.h:152
@ SFLASH_REG_BASE
Definition: addressmap.h:40
uint32_t u32
Definition: stdint.h:51
unsigned long uintptr_t
Definition: stdint.h:21
uint8_t u8
Definition: stdint.h:45
unsigned char uint8_t
Definition: stdint.h:8
int(* read)(const struct spi_flash *flash, u32 offset, size_t len, void *buf)
Definition: spi_flash.h:44
u32 sector_size
Definition: spi_flash.h:96
const struct spi_flash_ops * ops
Definition: spi_flash.h:102
u8 erase_cmd
Definition: spi_flash.h:98
u32 size
Definition: spi_flash.h:95
struct spi_slave spi
Definition: spi_flash.h:84
struct mono_time start
Definition: timer.h:112
u8 val
Definition: sys.c:300