drivers/mipi: Add support for KD_KD110N11_51IE panel
[coreboot2.git] / src / soc / mediatek / common / flash_controller.c
blob4f0d4b0dfac4abd0c1e82fd142bc6fbe4dd04e7e
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <assert.h>
4 #include <console/console.h>
5 #include <device/mmio.h>
6 #include <soc/flash_controller_common.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>
15 static struct mtk_nor_regs *const mtk_nor = (void *)SFLASH_REG_BASE;
17 #define GET_NTH_BYTE(d, n) ((d >> (8 * n)) & 0xff)
19 static int polling_cmd(u32 val)
21 struct stopwatch sw;
23 stopwatch_init_usecs_expire(&sw, SFLASH_POLLINGREG_US);
25 while ((read32(&mtk_nor->cmd) & val) != 0) {
26 if (stopwatch_expired(&sw))
27 return -1;
30 return 0;
33 static int mtk_nor_execute_cmd(u8 cmdval)
35 u8 val = cmdval & ~SFLASH_AUTOINC;
37 write8(&mtk_nor->cmd, cmdval);
38 return polling_cmd(val);
41 static int sflashhw_read_flash_status(u8 *value)
43 if (mtk_nor_execute_cmd(SFLASH_READSTATUS))
44 return -1;
46 *value = read8(&mtk_nor->rdsr);
47 return 0;
50 static int wait_for_write_done(void)
52 struct stopwatch sw;
53 u8 reg;
55 stopwatch_init_usecs_expire(&sw, SFLASH_POLLINGREG_US);
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;
64 return -1;
67 /* set serial flash program address */
68 static void set_sfpaddr(u32 addr)
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));
75 static int sector_erase(int offset)
77 if (wait_for_write_done())
78 return -1;
80 write8(&mtk_nor->prgdata[5], SFLASH_OP_WREN);
81 write8(&mtk_nor->cnt, 8);
82 mtk_nor_execute_cmd(SFLASH_PRG_CMD);
84 write8(&mtk_nor->prgdata[5], SECTOR_ERASE_CMD);
85 write8(&mtk_nor->prgdata[4], GET_NTH_BYTE(offset, 2));
86 write8(&mtk_nor->prgdata[3], GET_NTH_BYTE(offset, 1));
87 write8(&mtk_nor->prgdata[2], GET_NTH_BYTE(offset, 0));
88 write8(&mtk_nor->cnt, 32);
89 mtk_nor_execute_cmd(SFLASH_PRG_CMD);
91 if (wait_for_write_done())
92 return -1;
94 return 0;
97 static int dma_read(u32 addr, uintptr_t dma_buf, u32 len)
99 struct stopwatch sw;
101 assert(IS_ALIGNED((uintptr_t)addr, SFLASH_DMA_ALIGN) &&
102 IS_ALIGNED(len, SFLASH_DMA_ALIGN));
104 /* do dma reset */
105 write32(&mtk_nor->fdma_ctl, SFLASH_DMA_SW_RESET);
106 write32(&mtk_nor->fdma_ctl, SFLASH_DMA_WDLE_EN);
107 /* flash source address and dram dest address */
108 write32(&mtk_nor->fdma_fadr, addr);
109 write32(&mtk_nor->fdma_dadr, dma_buf);
110 write32(&mtk_nor->fdma_end_dadr, (dma_buf + len));
111 /* start dma */
112 write32(&mtk_nor->fdma_ctl, SFLASH_DMA_TRIGGER | SFLASH_DMA_WDLE_EN);
114 stopwatch_init_usecs_expire(&sw, SFLASH_POLLINGREG_US);
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;
122 return 0;
125 static int nor_read(const struct spi_flash *flash, u32 addr, size_t len,
126 void *buf)
128 uintptr_t dma_buf = (uintptr_t)_dma_coherent;
129 size_t dma_buf_len = REGION_SIZE(dma_coherent);
130 u32 start = ALIGN_DOWN(addr, SFLASH_DMA_ALIGN);
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;
137 /* Refer to CB:13989 for the hardware limitation on mt8173. */
138 if (CONFIG(SOC_MEDIATEK_MT8173)) {
139 if (!ENV_BOOTBLOCK && !ENV_SEPARATE_VERSTAGE) {
140 dma_buf = (uintptr_t)_dram_dma;
141 dma_buf_len = REGION_SIZE(dram_dma);
145 if (CONFIG(FLASH_DUAL_IO_READ)) {
146 setbits8(&mtk_nor->read_dual, SFLASH_READ_DUAL_EN);
147 write8(&mtk_nor->prgdata[3], SFLASH_1_1_2_READ);
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;
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 */
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. */
166 return 0;
169 static int nor_write(const struct spi_flash *flash, u32 addr, size_t len,
170 const void *buf)
172 const u8 *buffer = (const u8 *)buf;
174 set_sfpaddr(addr);
175 while (len) {
176 write8(&mtk_nor->wdata, *buffer);
177 if (mtk_nor_execute_cmd(SFLASH_WR_TRIGGER | SFLASH_AUTOINC))
178 return -1;
180 if (wait_for_write_done())
181 return -1;
182 buffer++;
183 len--;
185 return 0;
188 static int nor_erase(const struct spi_flash *flash, u32 offset, size_t len)
190 int sector_start = offset;
191 int sector_num = (u32)len / flash->sector_size;
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;
203 return 0;
206 const struct spi_flash_ops spi_flash_ops = {
207 .read = nor_read,
208 .write = nor_write,
209 .erase = nor_erase,
212 int mtk_spi_flash_probe(const struct spi_slave *spi,
213 struct spi_flash *flash)
215 write32(&mtk_nor->wrprot, SFLASH_COMMAND_ENABLE);
216 memcpy(&flash->spi, spi, sizeof(*spi));
218 flash->sector_size = 0x1000;
219 flash->erase_cmd = SECTOR_ERASE_CMD;
220 flash->size = CONFIG_ROM_SIZE;
222 flash->ops = &spi_flash_ops;
224 return 0;
227 int mtk_snfc_init_pad_func(const struct pad_func *pad, enum gpio_drv strength)
229 gpio_set_pull(pad->gpio, GPIO_PULL_ENABLE, pad->select);
230 gpio_set_mode(pad->gpio, pad->func);
232 if (gpio_set_driving(pad->gpio, strength) < 0) {
233 printk(BIOS_ERR,
234 "%s: failed to set pin drive to %d for %d\n",
235 __func__, strength, pad->gpio.id);
236 return -1;
239 printk(BIOS_DEBUG, "%s: got pin drive: %#x\n", __func__,
240 gpio_get_driving(pad->gpio));
242 return 0;