Skip to content

Commit d71ad16

Browse files
maass-hamburgcarlescufi
authored andcommitted
drivers: spi: litex: add litespi driver
add litespi driver for flash. Signed-off-by: Fin Maaß <[email protected]>
1 parent 0f3955c commit d71ad16

File tree

5 files changed

+310
-0
lines changed

5 files changed

+310
-0
lines changed

drivers/spi/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ zephyr_library_sources_ifdef(CONFIG_SPI_NRFX_SPIM spi_nrfx_spim.c
2525
spi_nrfx_common.c)
2626
zephyr_library_sources_ifdef(CONFIG_SPI_NRFX_SPIS spi_nrfx_spis.c)
2727
zephyr_library_sources_ifdef(CONFIG_SPI_LITEX spi_litex.c)
28+
zephyr_library_sources_ifdef(CONFIG_SPI_LITEX_LITESPI spi_litex_litespi.c)
2829
zephyr_library_sources_ifdef(CONFIG_SPI_OC_SIMPLE spi_oc_simple.c)
2930
zephyr_library_sources_ifdef(CONFIG_SPI_XEC_QMSPI spi_xec_qmspi.c)
3031
zephyr_library_sources_ifdef(CONFIG_SPI_GECKO spi_gecko.c)

drivers/spi/Kconfig.litex

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,10 @@ config SPI_LITEX
99
depends on DT_HAS_LITEX_SPI_ENABLED
1010
help
1111
Enable the SPI peripherals on LiteX
12+
13+
config SPI_LITEX_LITESPI
14+
bool "LiteX SPI LiteSPI controller driver"
15+
default y
16+
depends on DT_HAS_LITEX_SPI_LITESPI_ENABLED
17+
help
18+
Enable the SPI peripherals on LiteX

drivers/spi/spi_litex_litespi.c

Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
/*
2+
* Copyright (c) 2024 Vogl Electronic GmbH
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT litex_spi_litespi
8+
9+
#define LOG_LEVEL CONFIG_SPI_LOG_LEVEL
10+
#include <zephyr/logging/log.h>
11+
LOG_MODULE_REGISTER(spi_litex_litespi);
12+
13+
#include <zephyr/sys/byteorder.h>
14+
#include "spi_litex_common.h"
15+
16+
#define SPIFLASH_CORE_MASTER_PHYCONFIG_LEN_OFFSET 0x0
17+
#define SPIFLASH_CORE_MASTER_PHYCONFIG_WIDTH_OFFSET 0x1
18+
#define SPIFLASH_CORE_MASTER_PHYCONFIG_MASK_OFFSET 0x2
19+
20+
#define SPIFLASH_CORE_MASTER_STATUS_TX_READY_OFFSET 0x0
21+
#define SPIFLASH_CORE_MASTER_STATUS_RX_READY_OFFSET 0x1
22+
23+
#define SPI_MAX_WORD_SIZE 32
24+
#define SPI_MAX_CS_SIZE 4
25+
26+
struct spi_litex_dev_config {
27+
uint32_t core_mmap_dummy_bits_addr;
28+
uint32_t core_master_cs_addr;
29+
uint32_t core_master_phyconfig_addr;
30+
uint32_t core_master_rxtx_addr;
31+
uint32_t core_master_rxtx_size;
32+
uint32_t core_master_status_addr;
33+
uint32_t phy_clk_divisor_addr;
34+
bool phy_clk_divisor_exists;
35+
};
36+
37+
struct spi_litex_data {
38+
struct spi_context ctx;
39+
uint8_t dfs; /* dfs in bytes: 1,2 or 4 */
40+
};
41+
42+
43+
static int spi_litex_set_frequency(const struct device *dev, const struct spi_config *config)
44+
{
45+
const struct spi_litex_dev_config *dev_config = dev->config;
46+
47+
if (!dev_config->phy_clk_divisor_exists) {
48+
/* In the LiteX Simulator the phy_clk_divisor doesn't exists, thats why we check. */
49+
LOG_WRN("No phy_clk_divisor found, can't change frequency");
50+
return 0;
51+
}
52+
53+
uint32_t divisor = DIV_ROUND_UP(sys_clock_hw_cycles_per_sec(), (2 * config->frequency)) - 1;
54+
55+
litex_write32(divisor, dev_config->phy_clk_divisor_addr);
56+
return 0;
57+
}
58+
59+
/* Helper Functions */
60+
static int spi_config(const struct device *dev, const struct spi_config *config)
61+
{
62+
struct spi_litex_data *dev_data = dev->data;
63+
64+
if (config->slave != 0) {
65+
if (config->slave >= SPI_MAX_CS_SIZE) {
66+
LOG_ERR("More slaves than supported");
67+
return -ENOTSUP;
68+
}
69+
}
70+
71+
if (config->operation & SPI_HALF_DUPLEX) {
72+
LOG_ERR("Half-duplex not supported");
73+
return -ENOTSUP;
74+
}
75+
76+
if (SPI_WORD_SIZE_GET(config->operation) > SPI_MAX_WORD_SIZE) {
77+
LOG_ERR("Word size must be <= %d, is %d", SPI_MAX_WORD_SIZE,
78+
SPI_WORD_SIZE_GET(config->operation));
79+
return -ENOTSUP;
80+
}
81+
82+
if (config->operation & SPI_CS_ACTIVE_HIGH) {
83+
LOG_ERR("CS active high not supported");
84+
return -ENOTSUP;
85+
}
86+
87+
if (config->operation & SPI_LOCK_ON) {
88+
LOG_ERR("Lock On not supported");
89+
return -ENOTSUP;
90+
}
91+
92+
if (IS_ENABLED(CONFIG_SPI_EXTENDED_MODES) &&
93+
(config->operation & SPI_LINES_MASK) != SPI_LINES_SINGLE) {
94+
LOG_ERR("Only supports single mode");
95+
return -ENOTSUP;
96+
}
97+
98+
if (config->operation & SPI_TRANSFER_LSB) {
99+
LOG_ERR("LSB first not supported");
100+
return -ENOTSUP;
101+
}
102+
103+
if (config->operation & (SPI_MODE_CPOL | SPI_MODE_CPHA)) {
104+
LOG_ERR("Only supports CPOL=CPHA=0");
105+
return -ENOTSUP;
106+
}
107+
108+
if (config->operation & SPI_OP_MODE_SLAVE) {
109+
LOG_ERR("Slave mode not supported");
110+
return -ENOTSUP;
111+
}
112+
113+
if (config->operation & SPI_MODE_LOOP) {
114+
LOG_ERR("Loopback mode not supported");
115+
return -ENOTSUP;
116+
}
117+
118+
dev_data->dfs = get_dfs_value(config);
119+
120+
spi_litex_set_frequency(dev, config);
121+
122+
return 0;
123+
}
124+
125+
static void spiflash_len_mask_width_write(uint32_t len, uint32_t width, uint32_t mask,
126+
uint32_t addr)
127+
{
128+
uint32_t tmp = len & BIT_MASK(8);
129+
uint32_t word = tmp << (SPIFLASH_CORE_MASTER_PHYCONFIG_LEN_OFFSET * 8);
130+
131+
tmp = width & BIT_MASK(8);
132+
word |= tmp << (SPIFLASH_CORE_MASTER_PHYCONFIG_WIDTH_OFFSET * 8);
133+
tmp = mask & BIT_MASK(8);
134+
word |= tmp << (SPIFLASH_CORE_MASTER_PHYCONFIG_MASK_OFFSET * 8);
135+
litex_write32(word, addr);
136+
}
137+
138+
static int spi_litex_xfer(const struct device *dev, const struct spi_config *config)
139+
{
140+
const struct spi_litex_dev_config *dev_config = dev->config;
141+
struct spi_litex_data *data = dev->data;
142+
struct spi_context *ctx = &data->ctx;
143+
uint32_t txd, rxd;
144+
int ret = 0;
145+
146+
uint8_t len = data->dfs; /* SPI Xfer length*/
147+
uint8_t old_len = len; /* old SPI Xfer length*/
148+
uint8_t width = BIT(0); /* SPI Xfer width*/
149+
uint8_t mask = BIT(0); /* SPI Xfer mask*/
150+
151+
spiflash_len_mask_width_write(len * 8, width, mask, dev_config->core_master_phyconfig_addr);
152+
153+
litex_write32(BIT(config->slave), dev_config->core_master_cs_addr);
154+
155+
do {
156+
len = MIN(spi_context_max_continuous_chunk(ctx), dev_config->core_master_rxtx_size);
157+
if (len != old_len) {
158+
spiflash_len_mask_width_write(len * 8, width, mask,
159+
dev_config->core_master_phyconfig_addr);
160+
old_len = len;
161+
}
162+
163+
if (spi_context_tx_buf_on(ctx)) {
164+
litex_spi_tx_put(len, &txd, ctx->tx_buf);
165+
} else {
166+
txd = 0U;
167+
}
168+
169+
while (!(litex_read8(dev_config->core_master_status_addr) &
170+
BIT(SPIFLASH_CORE_MASTER_STATUS_TX_READY_OFFSET))) {
171+
;
172+
}
173+
174+
LOG_DBG("txd: 0x%x", txd);
175+
litex_write32(txd, dev_config->core_master_rxtx_addr);
176+
177+
spi_context_update_tx(ctx, data->dfs, len / data->dfs);
178+
179+
while (!(litex_read8(dev_config->core_master_status_addr) &
180+
BIT(SPIFLASH_CORE_MASTER_STATUS_RX_READY_OFFSET))) {
181+
;
182+
}
183+
184+
rxd = litex_read32(dev_config->core_master_rxtx_addr);
185+
LOG_DBG("rxd: 0x%x", rxd);
186+
187+
if (spi_context_rx_buf_on(ctx)) {
188+
litex_spi_rx_put(len, &rxd, ctx->rx_buf);
189+
}
190+
191+
spi_context_update_rx(ctx, data->dfs, len / data->dfs);
192+
193+
} while (spi_context_tx_on(ctx) || spi_context_rx_on(ctx));
194+
195+
litex_write32(0, dev_config->core_master_cs_addr);
196+
197+
spi_context_complete(ctx, dev, 0);
198+
199+
return ret;
200+
}
201+
202+
static int spi_litex_transceive(const struct device *dev, const struct spi_config *config,
203+
const struct spi_buf_set *tx_bufs,
204+
const struct spi_buf_set *rx_bufs)
205+
{
206+
struct spi_litex_data *data = dev->data;
207+
208+
int ret = spi_config(dev, config);
209+
210+
if (ret) {
211+
return ret;
212+
}
213+
214+
if (!tx_bufs && !rx_bufs) {
215+
return 0;
216+
}
217+
218+
spi_context_buffers_setup(&data->ctx, tx_bufs, rx_bufs, data->dfs);
219+
220+
ret = spi_litex_xfer(dev, config);
221+
222+
return ret;
223+
}
224+
225+
#ifdef CONFIG_SPI_ASYNC
226+
static int spi_litex_transceive_async(const struct device *dev, const struct spi_config *config,
227+
const struct spi_buf_set *tx_bufs,
228+
const struct spi_buf_set *rx_bufs,
229+
struct k_poll_signal *async)
230+
{
231+
return -ENOTSUP;
232+
}
233+
#endif /* CONFIG_SPI_ASYNC */
234+
235+
static int spi_litex_release(const struct device *dev, const struct spi_config *config)
236+
{
237+
238+
return 0;
239+
}
240+
241+
/* Device Instantiation */
242+
static const struct spi_driver_api spi_litex_api = {
243+
.transceive = spi_litex_transceive,
244+
#ifdef CONFIG_SPI_ASYNC
245+
.transceive_async = spi_litex_transceive_async,
246+
#endif /* CONFIG_SPI_ASYNC */
247+
.release = spi_litex_release,
248+
};
249+
250+
#define SPI_INIT(n) \
251+
static struct spi_litex_data spi_litex_data_##n = { \
252+
SPI_CONTEXT_INIT_LOCK(spi_litex_data_##n, ctx), \
253+
SPI_CONTEXT_INIT_SYNC(spi_litex_data_##n, ctx), \
254+
}; \
255+
static struct spi_litex_dev_config spi_litex_cfg_##n = { \
256+
.core_mmap_dummy_bits_addr = DT_INST_REG_ADDR_BY_NAME(n, core_mmap_dummy_bits), \
257+
.core_master_cs_addr = DT_INST_REG_ADDR_BY_NAME(n, core_master_cs), \
258+
.core_master_phyconfig_addr = DT_INST_REG_ADDR_BY_NAME(n, core_master_phyconfig), \
259+
.core_master_rxtx_addr = DT_INST_REG_ADDR_BY_NAME(n, core_master_rxtx), \
260+
.core_master_rxtx_size = DT_INST_REG_SIZE_BY_NAME(n, core_master_rxtx), \
261+
.core_master_status_addr = DT_INST_REG_ADDR_BY_NAME(n, core_master_status), \
262+
.phy_clk_divisor_exists = DT_INST_REG_HAS_NAME(n, phy_clk_divisor), \
263+
.phy_clk_divisor_addr = DT_INST_REG_ADDR_BY_NAME_OR(n, phy_clk_divisor, 0) \
264+
\
265+
}; \
266+
DEVICE_DT_INST_DEFINE(n, NULL, NULL, &spi_litex_data_##n, &spi_litex_cfg_##n, POST_KERNEL, \
267+
CONFIG_SPI_INIT_PRIORITY, &spi_litex_api);
268+
269+
DT_INST_FOREACH_STATUS_OKAY(SPI_INIT)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
description: LiteX SPI LiteSPI Controller
2+
3+
compatible: "litex,spi-litespi"
4+
5+
include: spi-controller.yaml
6+
7+
properties:
8+
reg:
9+
required: true

dts/riscv/riscv32-litex-vexriscv.dtsi

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,30 @@
9393
#address-cells = <1>;
9494
#size-cells = <0>;
9595
};
96+
spi1: spi@e000c000 {
97+
compatible = "litex,spi-litespi";
98+
reg = <0xe000c000 0x4>,
99+
<0xe000c004 0x4>,
100+
<0xe000c008 0x4>,
101+
<0xe000c00c 0x4>,
102+
<0xe000c010 0x4>,
103+
<0xe000c800 0x4>,
104+
<0x60000000 0x1000000>;
105+
reg-names = "core_mmap_dummy_bits",
106+
"core_master_cs",
107+
"core_master_phyconfig",
108+
"core_master_rxtx",
109+
"core_master_status",
110+
"phy_clk_divisor",
111+
"flash_mmap";
112+
#address-cells = <1>;
113+
#size-cells = <0>;
114+
spiflash0: flash@0 {
115+
compatible = "jedec,spi-nor";
116+
reg = <0>;
117+
spi-max-frequency = <10000000>;
118+
};
119+
};
96120
timer0: timer@e0002800 {
97121
compatible = "litex,timer0";
98122
interrupt-parent = <&intc0>;

0 commit comments

Comments
 (0)