SPI memory controller class.
More...
|
| #define | PBL_SPI_MEM_OP_CMD(_opcode, _buswidth) {.opcode = (_opcode), .buswidth = (_buswidth)} |
| | Command phase, for PBL_SPI_MEM_OP().
|
| |
| #define | PBL_SPI_MEM_OP_ADDR(_nbytes, _val, _buswidth) {.nbytes = (_nbytes), .buswidth = (_buswidth), .val = (_val)} |
| | Address phase, for PBL_SPI_MEM_OP().
|
| |
| #define | PBL_SPI_MEM_OP_NO_ADDR |
| | No address phase.
|
| |
| #define | PBL_SPI_MEM_OP_DUMMY(_nbytes, _buswidth) {.nbytes = (_nbytes), .buswidth = (_buswidth)} |
| | Dummy phase, for PBL_SPI_MEM_OP().
|
| |
| #define | PBL_SPI_MEM_OP_NO_DUMMY |
| | No dummy phase.
|
| |
| #define | PBL_SPI_MEM_OP_DATA_IN(_nbytes, _buf, _buswidth) {.dir = PBL_SPI_MEM_DATA_IN, .buswidth = (_buswidth), .nbytes = (_nbytes), .buf.in = (_buf)} |
| | Data phase reading from the memory, for PBL_SPI_MEM_OP().
|
| |
| #define | PBL_SPI_MEM_OP_DATA_OUT(_nbytes, _buf, _buswidth) {.dir = PBL_SPI_MEM_DATA_OUT, .buswidth = (_buswidth), .nbytes = (_nbytes), .buf.out = (_buf)} |
| | Data phase writing to the memory, for PBL_SPI_MEM_OP().
|
| |
| #define | PBL_SPI_MEM_OP_NO_DATA |
| | No data phase.
|
| |
| #define | PBL_SPI_MEM_OP(_cmd, _addr, _dummy, _data) |
| | Build an operation from its phases.
|
| |
| #define | PBL_SPI_MEM_XIP PBL_BIT(0) |
| | The CPU executes from the memory on this controller.
|
| |
| #define | PBL_SPI_MEM_STATE_DEFINE(sym) |
| | Define the class state of controller sym, for the PBL_SPI_MEM_*_DEFINE() macro of a driver.
|
| |
| #define | PBL_SPI_MEM_INIT(sym, _name, _deps, _ops, _flags) |
| | Initializer for the struct pbl_spi_mem of controller sym.
|
| |
|
| static bool | pbl_spi_mem_is_xip (const struct pbl_spi_mem *mem) |
| | Check whether the CPU executes from the memory on a controller.
|
| |
| bool | pbl_spi_mem_supports_op (const struct pbl_spi_mem *mem, const struct pbl_spi_mem_op *op) |
| | Check whether the controller can run an operation.
|
| |
| int | pbl_spi_mem_adjust_op_size (const struct pbl_spi_mem *mem, struct pbl_spi_mem_op *op) |
| | Reduce the data of an operation to what one run carries.
|
| |
| int | pbl_spi_mem_exec_op (const struct pbl_spi_mem *mem, const struct pbl_spi_mem_op *op) |
| | Run an operation.
|
| |
| int | pbl_spi_mem_poll_status (const struct pbl_spi_mem *mem, const struct pbl_spi_mem_op *op, const struct pbl_spi_mem_op *status, uint8_t mask, uint8_t match, const struct pbl_spi_mem_suspend *susp) |
| | Run an operation, then poll a status register until it matches.
|
| |
| int | pbl_spi_mem_dirmap_create (const struct pbl_spi_mem *mem, struct pbl_spi_mem_dirmap *desc) |
| | Create a memory-mapped read window.
|
| |
| int | pbl_spi_mem__dirmap_read_ops (const struct pbl_spi_mem *mem, const struct pbl_spi_mem_dirmap *desc, uint32_t offs, void *buf, size_t len) |
| |
| static int | pbl_spi_mem_dirmap_read (const struct pbl_spi_mem *mem, const struct pbl_spi_mem_dirmap *desc, uint32_t offs, void *buf, size_t len) |
| | Read through a memory-mapped read window.
|
| |
| void | pbl_spi_mem_dirmap_invalidate (const struct pbl_spi_mem *mem, const struct pbl_spi_mem_dirmap *desc, uint32_t offs, size_t len) |
| | Drop cached copies of a range of a window, after programming or erasing it.
|
| |
| void | pbl_spi_mem_power_down (const struct pbl_spi_mem *mem, const struct pbl_spi_mem_pm *pm, pbl_spi_mem_pm_fn_t fn, void *arg) |
| | Power the memory and the controller down while a function runs, with interrupts disabled.
|
| |
| void | pbl_spi_mem_set_polling (const struct pbl_spi_mem *mem, bool polling) |
| | Poll for completion instead of sleeping, e.g.
|
| |
| static bool | pbl_spi_mem_is_polling (const struct pbl_spi_mem *mem) |
| | Check whether the controller polls for completion, for drivers.
|
| |
SPI memory controller class.
A SPI memory controller runs operations made of a command, an address, dummy cycles and data against a memory (NOR flash, PSRAM, ...) without knowing its protocol, which belongs to the memory's driver. Each phase has its own bus width. A controller may not support every operation, or may only carry part of the data in one go: drivers check with pbl_spi_mem_supports_op() and split with pbl_spi_mem_adjust_op_size().
uint8_t sr;
An operation.
Definition spi_mem.h:57
#define PBL_SPI_MEM_OP_DATA_IN(_nbytes, _buf, _buswidth)
Data phase reading from the memory, for PBL_SPI_MEM_OP().
Definition spi_mem.h:115
int pbl_spi_mem_exec_op(const struct pbl_spi_mem *mem, const struct pbl_spi_mem_op *op)
Run an operation.
#define PBL_SPI_MEM_OP_NO_DUMMY
No dummy phase.
Definition spi_mem.h:111
#define PBL_SPI_MEM_OP_CMD(_opcode, _buswidth)
Command phase, for PBL_SPI_MEM_OP().
Definition spi_mem.h:100
#define PBL_SPI_MEM_OP(_cmd, _addr, _dummy, _data)
Build an operation from its phases.
Definition spi_mem.h:126
#define PBL_SPI_MEM_OP_NO_ADDR
No address phase.
Definition spi_mem.h:105
Reads may also go through a memory-mapped window the controller sets up for a read operation the memory driver picks, see pbl_spi_mem_dirmap_create(). A controller the CPU executes from is flagged with PBL_SPI_MEM_XIP, and its memory driver then adopts the state the boot code left and runs every operation that leaves the memory busy through pbl_spi_mem_poll_status(), which only returns once the memory is readable again.
Operations are issued by the single memory on the controller, which serializes them; they block until done, polling instead of sleeping once pbl_spi_mem_set_polling() is set.
◆ pbl_spi_mem_op
◆ pbl_spi_mem_dirmap
| struct pbl_spi_mem_dirmap |
A memory-mapped read window, see pbl_spi_mem_dirmap_create().
| Data Fields |
|
uint32_t |
length |
Size of the window, which the controller may reduce. |
|
bool |
mapped |
Set when the controller maps the window, cleared when reads fall back to operations. |
|
uint32_t |
offset |
First memory address of the window. |
|
struct pbl_spi_mem_op |
op |
Read operation; its address value and data length are ignored. |
|
const void * |
ptr |
CPU address of the window when the controller maps it into memory, else NULL. |
◆ pbl_spi_mem_pm
Memory commands that put it in and out of its lowest power state.
| Data Fields |
|
struct pbl_spi_mem_op |
enter |
Command entering the low power state. |
|
uint16_t |
enter_us |
Time the memory takes to enter it, in microseconds. |
|
struct pbl_spi_mem_op |
exit |
Command leaving the low power state. |
|
uint16_t |
exit_us |
Time the memory takes to leave it, in microseconds. |
◆ pbl_spi_mem_suspend
| struct pbl_spi_mem_suspend |
Memory commands that suspend and resume a long operation, see pbl_spi_mem_poll_status().
| Data Fields |
|
struct pbl_spi_mem_op |
resume |
Command resuming it. |
|
uint16_t |
resume_us |
Shortest time between a resume and the next suspend, in microseconds. |
|
struct pbl_spi_mem_op |
suspend |
Command suspending the operation. |
|
uint16_t |
suspend_us |
Longest time the memory takes to suspend, in microseconds. |
◆ pbl_spi_mem
| Data Fields |
|
struct pbl_device |
dev |
Device. |
|
uint8_t |
flags |
Flags, PBL_SPI_MEM_*. |
|
const struct pbl_spi_mem_ops * |
ops |
Driver operations. |
|
struct pbl_spi_mem_state * |
state |
Runtime state. |
◆ pbl_spi_mem_op.cmd
| struct pbl_spi_mem_op.cmd |
| Data Fields |
|
uint8_t |
buswidth |
Bus width. |
|
uint8_t |
opcode |
Opcode. |
◆ pbl_spi_mem_op.addr
| struct pbl_spi_mem_op.addr |
| Data Fields |
|
uint8_t |
buswidth |
Bus width. |
|
uint8_t |
nbytes |
Number of address bytes, 0 for none. |
|
uint32_t |
val |
Address. |
◆ pbl_spi_mem_op.dummy
| struct pbl_spi_mem_op.dummy |
| Data Fields |
|
uint8_t |
buswidth |
Bus width. |
|
uint8_t |
nbytes |
Number of dummy bytes, 0 for none. |
◆ pbl_spi_mem_op.data
| struct pbl_spi_mem_op.data |
◆ pbl_spi_mem_op.data.buf
| union pbl_spi_mem_op.data.buf |
| Data Fields |
|
void * |
in |
Buffer to read into. |
|
const void * |
out |
Data to write. |
◆ PBL_SPI_MEM_INIT
| #define PBL_SPI_MEM_INIT |
( |
|
sym, |
|
|
|
_name, |
|
|
|
_deps, |
|
|
|
_ops, |
|
|
|
_flags |
|
) |
| |
Value: { \
&pbl_spi_mem_class), \
.ops = (_ops), \
.state = &sym##_spi_mem_state, \
.flags = (_flags), \
}
#define PBL_DEVICE_INIT_CLASS(sym, _name, _init, _parent, _deps, _cls)
Initializer for the struct pbl_device of device instance sym, in class _cls.
Definition device.h:123
Initializer for the struct pbl_spi_mem of controller sym.
- Parameters
-
◆ PBL_SPI_MEM_OP
| #define PBL_SPI_MEM_OP |
( |
|
_cmd, |
|
|
|
_addr, |
|
|
|
_dummy, |
|
|
|
_data |
|
) |
| |
Value:
.cmd = _cmd, .addr = _addr, .dummy = _dummy, .data = _data, \
}
Build an operation from its phases.
◆ PBL_SPI_MEM_OP_ADDR
| #define PBL_SPI_MEM_OP_ADDR |
( |
|
_nbytes, |
|
|
|
_val, |
|
|
|
_buswidth |
|
) |
| {.nbytes = (_nbytes), .buswidth = (_buswidth), .val = (_val)} |
◆ PBL_SPI_MEM_OP_CMD
| #define PBL_SPI_MEM_OP_CMD |
( |
|
_opcode, |
|
|
|
_buswidth |
|
) |
| {.opcode = (_opcode), .buswidth = (_buswidth)} |
◆ PBL_SPI_MEM_OP_DATA_IN
| #define PBL_SPI_MEM_OP_DATA_IN |
( |
|
_nbytes, |
|
|
|
_buf, |
|
|
|
_buswidth |
|
) |
| {.dir = PBL_SPI_MEM_DATA_IN, .buswidth = (_buswidth), .nbytes = (_nbytes), .buf.in = (_buf)} |
◆ PBL_SPI_MEM_OP_DATA_OUT
| #define PBL_SPI_MEM_OP_DATA_OUT |
( |
|
_nbytes, |
|
|
|
_buf, |
|
|
|
_buswidth |
|
) |
| {.dir = PBL_SPI_MEM_DATA_OUT, .buswidth = (_buswidth), .nbytes = (_nbytes), .buf.out = (_buf)} |
◆ PBL_SPI_MEM_OP_DUMMY
| #define PBL_SPI_MEM_OP_DUMMY |
( |
|
_nbytes, |
|
|
|
_buswidth |
|
) |
| {.nbytes = (_nbytes), .buswidth = (_buswidth)} |
◆ PBL_SPI_MEM_OP_NO_ADDR
| #define PBL_SPI_MEM_OP_NO_ADDR |
◆ PBL_SPI_MEM_OP_NO_DATA
| #define PBL_SPI_MEM_OP_NO_DATA |
◆ PBL_SPI_MEM_OP_NO_DUMMY
| #define PBL_SPI_MEM_OP_NO_DUMMY |
◆ PBL_SPI_MEM_STATE_DEFINE
| #define PBL_SPI_MEM_STATE_DEFINE |
( |
|
sym | ) |
|
Value:
static struct pbl_spi_mem_state sym##_spi_mem_state
#define PBL_DEVICE_STATE_DEFINE(sym)
Define the runtime state of device instance sym.
Definition device.h:109
Define the class state of controller sym, for the PBL_SPI_MEM_*_DEFINE() macro of a driver.
- Parameters
-
| sym | Symbol of the controller instance. |
◆ PBL_SPI_MEM_XIP
The CPU executes from the memory on this controller.
Its memory driver adopts the state the boot code left instead of resetting the memory, and runs the operations that leave the memory busy through pbl_spi_mem_poll_status().
◆ pbl_spi_mem_pm_fn_t
| typedef void(* pbl_spi_mem_pm_fn_t) (void *arg) |
◆ pbl_spi_mem_data_dir
Data direction of an operation.
| Enumerator |
|---|
| PBL_SPI_MEM_NO_DATA | No data phase.
|
| PBL_SPI_MEM_DATA_IN | Data read from the memory.
|
| PBL_SPI_MEM_DATA_OUT | Data written to the memory.
|
◆ pbl_spi_mem__dirmap_read_ops()
| int pbl_spi_mem__dirmap_read_ops |
( |
const struct pbl_spi_mem * |
mem, |
|
|
const struct pbl_spi_mem_dirmap * |
desc, |
|
|
uint32_t |
offs, |
|
|
void * |
buf, |
|
|
size_t |
len |
|
) |
| |
◆ pbl_spi_mem_adjust_op_size()
Reduce the data of an operation to what one run carries.
- Parameters
-
| mem | Controller. |
| op | Operation, whose data.nbytes may be reduced. |
- Returns
- 0 or a negative errno.
◆ pbl_spi_mem_dirmap_create()
Create a memory-mapped read window.
The controller may map less than asked: reads beyond desc->length after the call are up to the caller. Controllers without a window carry the reads out as operations, through the whole requested range.
- Parameters
-
| mem | Controller. |
| [in,out] | desc | Window: read operation and requested range in, mapped range out. |
- Returns
- 0,
-ENOTSUP if the controller cannot run the read operation, or another negative errno.
◆ pbl_spi_mem_dirmap_invalidate()
Drop cached copies of a range of a window, after programming or erasing it.
- Parameters
-
◆ pbl_spi_mem_dirmap_read()
| static int pbl_spi_mem_dirmap_read |
( |
const struct pbl_spi_mem * |
mem, |
|
|
const struct pbl_spi_mem_dirmap * |
desc, |
|
|
uint32_t |
offs, |
|
|
void * |
buf, |
|
|
size_t |
len |
|
) |
| |
|
inlinestatic |
◆ pbl_spi_mem_exec_op()
Run an operation.
- Parameters
-
| mem | Controller. |
| op | Operation. |
- Returns
- 0,
-ENOTSUP if the controller cannot run it, or another negative errno.
◆ pbl_spi_mem_is_polling()
| static bool pbl_spi_mem_is_polling |
( |
const struct pbl_spi_mem * |
mem | ) |
|
|
inlinestatic |
Check whether the controller polls for completion, for drivers.
- Parameters
-
- Returns
- True if polling.
References pbl_spi_mem::state.
◆ pbl_spi_mem_is_xip()
| static bool pbl_spi_mem_is_xip |
( |
const struct pbl_spi_mem * |
mem | ) |
|
|
inlinestatic |
◆ pbl_spi_mem_poll_status()
Run an operation, then poll a status register until it matches.
Nothing else reaches the memory until the status matches, so this is how operations that leave the memory busy (programs, erases, register writes) are run on a PBL_SPI_MEM_XIP controller.
- Parameters
-
| mem | Controller. |
| op | Operation. |
| status | Operation reading the status into its first data byte. |
| mask | Status bits to check. |
| match | Value of the masked status bits to wait for. |
| susp | Commands suspending and resuming op, or NULL. A controller that would otherwise hold off interrupts until the status matches suspends op with them to let interrupts run. |
- Returns
- 0,
-ENOTSUP if the controller cannot do it, leaving the polling to the caller, or another negative errno.
◆ pbl_spi_mem_power_down()
Power the memory and the controller down while a function runs, with interrupts disabled.
- Parameters
-
| mem | Controller. |
| pm | Memory low power commands, or NULL to leave the memory as is. Must be in RAM with PBL_SPI_MEM_XIP. |
| fn | Function to run, from RAM with PBL_SPI_MEM_XIP. |
| arg | Argument of fn. |
◆ pbl_spi_mem_set_polling()
| void pbl_spi_mem_set_polling |
( |
const struct pbl_spi_mem * |
mem, |
|
|
bool |
polling |
|
) |
| |
Poll for completion instead of sleeping, e.g.
from a fault handler.
- Parameters
-
| mem | Controller. |
| polling | True to poll. |
◆ pbl_spi_mem_supports_op()
Check whether the controller can run an operation.
- Parameters
-
| mem | Controller. |
| op | Operation. |
- Returns
- True if pbl_spi_mem_exec_op() accepts it.