PebbleOS v4.44.0-46-gef116268a
Loading...
Searching...
No Matches
SPI memory

SPI memory controller class. More...

Modules

 nRF5 QSPI
 SPI memory controller driver for the nRF5 QSPI peripheral.
 
 SF32LB52 MPI
 SPI memory controller driver for the SF32LB52 MPI in NOR mode.
 

Data Structures

struct  pbl_spi_mem_op
 An operation. More...
 
struct  pbl_spi_mem_dirmap
 A memory-mapped read window, see pbl_spi_mem_dirmap_create(). More...
 
struct  pbl_spi_mem_pm
 Memory commands that put it in and out of its lowest power state. More...
 
struct  pbl_spi_mem_suspend
 Memory commands that suspend and resume a long operation, see pbl_spi_mem_poll_status(). More...
 
struct  pbl_spi_mem_ops
 Controller driver operations. More...
 
struct  pbl_spi_mem
 A SPI memory controller. More...
 
struct  pbl_spi_mem_op.cmd
 Command phase. More...
 
struct  pbl_spi_mem_op.addr
 Address phase. More...
 
struct  pbl_spi_mem_op.dummy
 Dummy phase. More...
 
struct  pbl_spi_mem_op.data
 Data phase. More...
 
union  pbl_spi_mem_op.data.buf
 Buffer. More...
 

Macros

#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.
 

Typedefs

typedef void(* pbl_spi_mem_pm_fn_t) (void *arg)
 Function run while the memory is powered down, see pbl_spi_mem_power_down().
 

Enumerations

enum  pbl_spi_mem_data_dir { PBL_SPI_MEM_NO_DATA , PBL_SPI_MEM_DATA_IN , PBL_SPI_MEM_DATA_OUT }
 Data direction of an operation. More...
 

Functions

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.
 

Detailed Description

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;
ret = pbl_spi_mem_exec_op(bus, &op);
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.


Data Structure Documentation

◆ pbl_spi_mem_op

struct pbl_spi_mem_op

An operation.

Data Fields
struct pbl_spi_mem_op.addr addr Address phase.
struct pbl_spi_mem_op.cmd cmd Command phase.
struct pbl_spi_mem_op.data data Data phase.
struct pbl_spi_mem_op.dummy dummy Dummy phase.

◆ 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

struct 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

struct pbl_spi_mem

A SPI memory controller.

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

Command phase.

Data Fields
uint8_t buswidth Bus width.
uint8_t opcode Opcode.

◆ pbl_spi_mem_op.addr

struct pbl_spi_mem_op.addr

Address phase.

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

Dummy phase.

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

Data phase.

Data Fields
union pbl_spi_mem_op.data.buf buf Buffer.
uint8_t buswidth Bus width.
enum pbl_spi_mem_data_dir dir Direction.
size_t nbytes Number of bytes.

◆ pbl_spi_mem_op.data.buf

union pbl_spi_mem_op.data.buf

Buffer.

Data Fields
void * in Buffer to read into.
const void * out Data to write.

Macro Definition Documentation

◆ PBL_SPI_MEM_INIT

#define PBL_SPI_MEM_INIT (   sym,
  _name,
  _deps,
  _ops,
  _flags 
)
Value:
{ \
.dev = PBL_DEVICE_INIT_CLASS(sym, _name, pbl_spi_mem_dev_init, nullptr, _deps, \
&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
symSymbol of the controller instance, with its state defined by PBL_SPI_MEM_STATE_DEFINE().
_nameName.
_depsDependencies from PBL_DEVICE_DEPS(), or NULL.
_opsDriver operations.
_flagsFlags, PBL_SPI_MEM_*.

◆ PBL_SPI_MEM_OP

#define PBL_SPI_MEM_OP (   _cmd,
  _addr,
  _dummy,
  _data 
)
Value:
(struct pbl_spi_mem_op) { \
.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)}

Command phase, for PBL_SPI_MEM_OP().

◆ 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)}

Data phase reading from the memory, for PBL_SPI_MEM_OP().

◆ 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)}

Data phase writing to the memory, for PBL_SPI_MEM_OP().

◆ PBL_SPI_MEM_OP_DUMMY

#define PBL_SPI_MEM_OP_DUMMY (   _nbytes,
  _buswidth 
)    {.nbytes = (_nbytes), .buswidth = (_buswidth)}

Dummy phase, for PBL_SPI_MEM_OP().

◆ PBL_SPI_MEM_OP_NO_ADDR

#define PBL_SPI_MEM_OP_NO_ADDR
Value:
{ \
}

No address phase.

◆ PBL_SPI_MEM_OP_NO_DATA

#define PBL_SPI_MEM_OP_NO_DATA
Value:
{ \
}

No data phase.

◆ PBL_SPI_MEM_OP_NO_DUMMY

#define PBL_SPI_MEM_OP_NO_DUMMY
Value:
{ \
}

No dummy phase.

◆ 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
symSymbol of the controller instance.

◆ PBL_SPI_MEM_XIP

#define PBL_SPI_MEM_XIP   PBL_BIT(0)

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().

Typedef Documentation

◆ pbl_spi_mem_pm_fn_t

typedef void(* pbl_spi_mem_pm_fn_t) (void *arg)

Function run while the memory is powered down, see pbl_spi_mem_power_down().

Enumeration Type Documentation

◆ 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.

Function Documentation

◆ 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 
)

Referenced by pbl_spi_mem_dirmap_read().

◆ pbl_spi_mem_adjust_op_size()

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.

Parameters
memController.
opOperation, whose data.nbytes may be reduced.
Returns
0 or a negative errno.

◆ pbl_spi_mem_dirmap_create()

int pbl_spi_mem_dirmap_create ( const struct pbl_spi_mem *  mem,
struct pbl_spi_mem_dirmap *  desc 
)

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
memController.
[in,out]descWindow: 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()

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.

Parameters
memController.
descWindow, from pbl_spi_mem_dirmap_create().
offsMemory address.
lenNumber of bytes.

◆ 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

Read through a memory-mapped read window.

Parameters
memController.
descWindow, from pbl_spi_mem_dirmap_create().
offsMemory address.
[out]bufBuffer.
lenNumber of bytes.
Returns
0, -EINVAL for a range outside the window, or another negative errno.

References pbl_spi_mem_ops::dirmap_read, pbl_spi_mem_dirmap::length, pbl_spi_mem_dirmap::mapped, pbl_spi_mem_dirmap::offset, pbl_spi_mem::ops, and pbl_spi_mem__dirmap_read_ops().

◆ pbl_spi_mem_exec_op()

int pbl_spi_mem_exec_op ( const struct pbl_spi_mem *  mem,
const struct pbl_spi_mem_op *  op 
)

Run an operation.

Parameters
memController.
opOperation.
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
memController.
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

Check whether the CPU executes from the memory on a controller.

Parameters
memController.
Returns
True with PBL_SPI_MEM_XIP.

References pbl_spi_mem::flags, and PBL_SPI_MEM_XIP.

◆ pbl_spi_mem_poll_status()

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.

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
memController.
opOperation.
statusOperation reading the status into its first data byte.
maskStatus bits to check.
matchValue of the masked status bits to wait for.
suspCommands 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()

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.

Parameters
memController.
pmMemory low power commands, or NULL to leave the memory as is. Must be in RAM with PBL_SPI_MEM_XIP.
fnFunction to run, from RAM with PBL_SPI_MEM_XIP.
argArgument 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
memController.
pollingTrue to poll.

◆ pbl_spi_mem_supports_op()

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.

Parameters
memController.
opOperation.
Returns
True if pbl_spi_mem_exec_op() accepts it.