blob: bb9d10a2233257ab09305a932456db6661bec322 [file] [log] [blame]
ron minnichb44a3882024-03-03 21:21:55 +00001/* SPDX-License-Identifier: GPL-2.0-only */
2
3/*
4 * This file is basically drivers/spi/cbfs_spi.cb but the boot device is not known at build time
5 */
6
7#include <boot_device.h>
8#include <cbfs.h>
9#include <console/console.h>
10#include <device/mmio.h>
11#include <lib.h>
12#include <soc/addressmap.h>
13#include <soc/clock.h>
14#include <soc/spi.h>
15#include <spi_flash.h>
16#include <spi_sdcard.h>
17#include <stdint.h>
18#include <symbols.h>
ron minnichb44a3882024-03-03 21:21:55 +000019
20// There are two different means of accessing the SPI flash.
21// They are controlled by the fctrl register.
22// 1. memory mapped access
23// 2. FIFO based access
24
25/* follow is the FSBL boot device defined by ZSBL of sifive
26 * FSBL replaced by bootblock of coreboot
27 * MSEL_SPInx1 -> test if boot from memory-mapped on SPIn
28 * MSEL_SPInx4 -> test if boot from memory-mapped on QPIn
29 * MSEL_SPInSD -> test if boot from sdcard mount on SPIn */
30#define MSEL_SPI0x1(m) (((m) == 5) || ((m) == 14))
31#define MSEL_SPI0x4(m) (((m) == 6) || ((m) == 10) || ((m) == 15))
32#define MSEL_SPI1x1(m) ((m) == 12)
33#define MSEL_SPI1x4(m) (((m) == 7) || ((m) == 13))
34#define MSEL_SPI1SD(m) ((m) == 8)
35#define MSEL_SPI2x1(m) ((m) == 9)
36#define MSEL_SPI2SD(m) ((m) == 11)
37
38#define MSEL_ACCESS_METHOD_MMAP(m) ((m == 5) || (m == 6) || (m == 7) || (m == 10) || (m == 13))
39
40// probably something for devicetree
41struct fu740_spi_config fu740_spi_configs[] = {
42 { 0 },
43 {
44 .freq = 10*1000*1000,
45 },
46 { 0 },
47};
48
49static struct spi_sdcard spi2_sdcard; //TODO initialize SPI2
50//static struct spi_flash spi0_flash;
51//static struct spi_flash spi1_flash;
52static struct spi_flash spi_flash;
53static bool spi_flash_init_done;
54
55static ssize_t sd_readat(const struct region_device *rdev, void *dest,
56 size_t offset, size_t count)
57{
58 spi_sdcard_read(&spi2_sdcard, dest, offset, count);
59 return count;
60}
61
62static ssize_t spi_readat(const struct region_device *rd, void *b, size_t offset, size_t size)
63{
64 if (spi_flash_read(&spi_flash, offset, size, b))
65 return -1;
66 return size;
67}
68
69static ssize_t spi_writeat(const struct region_device *rd, const void *b,
70 size_t offset, size_t size)
71{
72 if (spi_flash_write(&spi_flash, offset, size, b))
73 return -1;
74 return size;
75}
76
77static ssize_t spi_eraseat(const struct region_device *rd, size_t offset, size_t size)
78{
79 if (spi_flash_erase(&spi_flash, offset, size))
80 return -1;
81 return size;
82}
83
84static const struct region_device_ops sd_ops = {
85 .mmap = mmap_helper_rdev_mmap,
86 .munmap = mmap_helper_rdev_munmap,
87 .readat = sd_readat,
88};
89
90static const struct region_device_ops spi_ops = {
91 .mmap = mmap_helper_rdev_mmap,
92 .munmap = mmap_helper_rdev_munmap,
93 .readat = spi_readat,
94 .writeat = spi_writeat,
95 .eraseat = spi_eraseat,
96};
97
98//TODO using postram cache means that all spi transitions are transferred to actual memory.
99// Native memory mapping obviously doesnt have that problem. That can however only happen if
100// memory has been initialized before accessing the boot device. So no CBFS access before boot.
101//static struct mem_pool mem_cbfs_cache =
102// MEM_POOL_INIT(_postram_cbfs_cache, REGION_SIZE(postram_cbfs_cache), CONFIG_CBFS_CACHE_ALIGN);
103//static struct mmap_helper_region_device spi_mdev =
104// MMAP_HELPER_DEV_INIT(&spi_ops, 0, CONFIG_ROM_SIZE, &mem_cbfs_cache);
105
106static struct mmap_helper_region_device spi_mdev =
107 MMAP_HELPER_DEV_INIT(&spi_ops, 0, CONFIG_ROM_SIZE, &cbfs_cache);
108
109static struct mmap_helper_region_device sd_mdev =
110 MMAP_HELPER_DEV_INIT(&sd_ops, 0, CONFIG_ROM_SIZE, &cbfs_cache);
111
112void boot_device_init(void)
113{
114 printk(BIOS_DEBUG, "%s 0\n", __func__);
115 if (spi_flash_init_done == true)
116 return;
117
Ronald G Minnichd31b1092024-02-15 22:28:01 -0800118 uint32_t m = read32((uint32_t *)FU740_MSEL) & 0xf;
119 printk(BIOS_DEBUG, "%s MSEL %#x\n", __func__, m);
120
121 // We have not yet found a way to reliably program the
122 // on-board SPI part (sifive neglected to put a diode on vcc ...)
123 // Once we work that out, we can test this code.
124 // It is left here as a hint of what needs to be done.
ron minnichb44a3882024-03-03 21:21:55 +0000125 // Pass the information of the flash read operation to the spi controller
Ronald G Minnichd31b1092024-02-15 22:28:01 -0800126 if (MSEL_SPI0x4(m)) {
127 die("SPI0x4 is not supported yet");
ron minnichb44a3882024-03-03 21:21:55 +0000128 //config.ffmt_config.data_proto = FU740_SPI_PROTO_Q;
129 //config.ffmt_config.cmd_code = 0x6B; // Quad output read
130 //.cmd_code = 0xec,
Ronald G Minnichd31b1092024-02-15 22:28:01 -0800131 //.pad_cnt = 6,
ron minnichb44a3882024-03-03 21:21:55 +0000132 }
Ronald G Minnichd31b1092024-02-15 22:28:01 -0800133 if (MSEL_SPI1x4(m)) {
134 printk(BIOS_DEBUG, "%s SPI1x4 1\n", __func__);
135 fu740_spi_configs[1].ffmt_config.data_proto = FU740_SPI_PROTO_Q;
136 fu740_spi_configs[1].ffmt_config.cmd_code = 0x6b; // quad
137 if (spi_flash_probe(1, 0, &spi_flash)) {
138 printk(BIOS_EMERG, "SPI1x4 failed to init SPI flash\n");
139 return;
140 }
141 if (fu740_spi_setup(&spi_flash.spi) == -1) {
142 printk(BIOS_EMERG, "SPI1x4 failed to configure mmap for SPI flash\n");
143 }
144 printk(BIOS_DEBUG, "%s SPI1x4 2\n", __func__);
145 } else if (MSEL_SPI1x1(m)) {
ron minnichb44a3882024-03-03 21:21:55 +0000146 printk(BIOS_DEBUG, "%s 1\n", __func__);
147 fu740_spi_configs[1].ffmt_config.data_proto = FU740_SPI_PROTO_S;
148 fu740_spi_configs[1].ffmt_config.cmd_code = 0x03; // Normal read
149 //TODO SPI1x1 is always using programmed IO (FIFO)? (memory map did not work...)
150 if (spi_flash_probe(1, 0, &spi_flash)) {
151 printk(BIOS_EMERG, "failed to init SPI flash\n");
152 return;
153 }
ron minnichb44a3882024-03-03 21:21:55 +0000154 printk(BIOS_DEBUG, "%s 2\n", __func__);
155 } else if (MSEL_SPI2SD(m)) {
156 spi_sdcard_init(&spi2_sdcard, 2, 0);
157 } else {
Ronald G Minnichd31b1092024-02-15 22:28:01 -0800158 printk(BIOS_EMERG, "MSEL: %#02x: ", m);
159 die("unsupported configuration of MSEL\n");
ron minnichb44a3882024-03-03 21:21:55 +0000160 }
161
162 spi_flash_init_done = true;
163}
164
165/* Return the CBFS boot device. */
166const struct region_device *boot_device_ro(void)
167{
168 if (spi_flash_init_done != true)
169 return NULL;
170
171 uint32_t m = read32((uint32_t *)FU740_MSEL);
172
173 if (MSEL_SPI2SD(m) || MSEL_SPI1SD(m))
174 return &sd_mdev.rdev;
175 return &spi_mdev.rdev;
176}
177
178//const struct spi_flash *boot_device_spi_flash(void)
179//{
180// boot_device_init();
181//
182// if (spi_flash_init_done != true)
183// return NULL;
184//
185// return &spi_flash;
186//}