System Protection Unit (SPU)
The System Protection Unit (SPU) protects peripheral configuration registers from unintended writes. In systems with multiple processors and DMA controllers, the SPU acts like a security guard, controlling who can modify critical peripheral settings.
Note
This guide applies to all ADSP-SC5xx processors. While the SPU functionality is consistent across processor families, the specific details vary:
Number of protected peripherals
Specific register mappings
What Does the SPU Do?
Think of the SPU as a gatekeeper for peripheral registers. It sits between the system bus and peripheral configuration registers, checking every write request. If a write comes from an unauthorized source, the SPU blocks it.
Key Features
Write Protection per Peripheral
Each peripheral has a dedicated protection register SPU_WP[n] that controls
which bus masters can write to its registers. We can:
Allow or block specific processor cores
Allow or block DMA controllers
Configure different permissions for each peripheral
Global Locking
The SPU can issue a system-wide lock signal that all peripherals recognize. When enabled, any peripheral with its lock bit set will reject all write attempts to its control register.
Security Integration
The SPU integrates with ARM TrustZone to enforce security boundaries:
Secure peripherals only accept secure transactions
Non-secure masters cannot access secure peripherals
Each peripheral’s security level is configurable
Self-Protection
The SPU can protect its own configuration registers, preventing unauthorized changes to the protection settings. Once locked, only a system reset can restore access.
How It Works
The SPU examines every write transaction in this order:
Destination Check - Which peripheral is being accessed?
Source Check - Which bus master is requesting the write?
Permission Check - Is this master allowed to write to this peripheral?
Decide - Pass the write through, or return a bus error
Basically, SPU sits between the system crossbar and peripheral registers.
Basic Configuration
Protecting a Peripheral
To protect a peripheral from writes by specific bus masters, we need to configure several registers.
First, we should find the peripheral’s write-protect register number in the Hardware Reference Manual.
Second, we can set the corresponding bits in SPU_WP[n] for bus masters we want to block. It exist of
two types of bits, named CM[n] and SM[n] for Core Requesters and System Requesters. They keep the
information of who is going to be blocked.
Bits [2:0] = - Block writes from processor cores
Bits [18:16] = - Block writes from system masters (DMA, etc.)
The bit positions (CM, SM) are the similar across all families, but the peripheral-to-WP register mappings differ more.
Using Global Lock
Global lock provides a quick way to simultaneously protect control registers across multiple peripherals. This mechanism is controlled by registers both in SPU and others. For example CDU_CTL register has LOCK bit to enable it. When we activate the global lock over SPU_CTL by setting GCLK bit, the registers with lock bit enabled are going to be blocked from write access.
Configuring Security
TrustZone security features apply to all SC5xx processors with ARM Cortex cores.
The SPU security register numbers match the WP numbers. This is controlled over
SSEC and MSEC bits under SPU_SECUREP[n] registers for peripherals. For cores, there is
SPU_SECUREC[n] register with CSEC[n] bits. For peripherals, each SPU_SECUREP
register is assigned to a specific MMR address range associated with one peripheral. Each has
a Slave Secure (SSEC) bit and a Master Secure (MSEC) bit. When the Slave Secure (SSEC) bit is
set, the SPU will only allow Secure Masters generating secure transactions to access the
peripheral’s MMR address space. When the Master Secure (MSEC) bit is set, the associated
peripheral will be secure and will generate secure transactions.
Checking Security Status
Software can check if it’s running in secure or non-secure mode by examining the value of
SPU_SECURECHK register. The SPU_SECURECHK register reads by secure requesters return
0xFFFFFFFF. Reads by non-secure requesters return 0x00000000.
Locking the SPU
To prevent any changes to SPU configuration until the next reset, we can even lock the SPU itself. For this, we can set WPLCK and GLCK and also block all masters to SPUs own write-protect registers. We need to be careful since this lock can only be unclocked with a reset.
Error Handling
Interrupts
The SPU can generate interrupts when a write is blocked.
We can configure the SPU to generate interrupts. This is controlled under SPU_CTL
register as PINTEN bit. After setting this bit, we can examine SPU_STAT register
to see the details of the violation. Detailed instructions on how we can handle interrupts
can be examined in Hardware Reference Manual.
Bus Errors
When a transaction is blocked, the SPU returns a bus error to the requesting master.
The master’s bus fault handler will be called. We can examine SPU_STAT register to see the
details of the violation. Specifically, the LWERR, ADDRERR or VIRQ bits can be used to see
the details of the error. Detailed instructions on how we can handle bus errors can be examined
in Hardware Reference Manual.
Peripherals with Global Lock Support
The following peripherals support the global lock feature (they have a lock enable bit in their control register) for SC59x.
General-Purpose IO
System Event Controller
Trigger Routing Unit
Clock Generation Unit
Clock Distribution Unit
Dynamic Power Management
Reset Control Unit
System Protection Unit
L2 Memory Controller
For SC57x and SC58x, refer to processor’s Hardware Reference Manual for the list of peripherals that support global lock.
Register Summary
Key SPU registers:
Register |
Purpose |
|---|---|
|
Control: Global lock, write-protect lock, interrupt enable |
|
Status: Lock write errors, interrupts |
|
Write-protect register for each peripheral (n = 0-202) |
|
Security control: Lock secure config, interrupt enable |
|
Core security configuration |
|
Peripheral security configuration (n = 0-213) |
|
Check if running in secure or non-secure mode |
Important Notes
Don’t lock peripherals before completing all initialization. You might lock yourself out and need a hard reset.
If you lock the SPU’s control register but forget to protect the SPU’s own WP register (WP121), someone can still modify the protection settings.
Global lock only works if the peripheral has its lock enable bit set in its control register. Don’t forget that step.
After system initialization, lock down clock, power, and boot configuration to prevent accidental changes.
Current Linux Support Status
SPU driver support is currently being tracked in the ADI Linux kernel repository (Implement system partitioning in ADSP SoCs).
The ADI DSP Linux kernel and accompanying examples are designed with the intent that the ARM core owns and allocates most of the system’s peripherals. The accompanying SHARC examples leverage peripherals minimally to prevent contention with the ARM for system resources.
Systems where SHARC cores boot their own applications prior to Linux/ARM will not be supported due to contention with Linux for system resources (peripherals, interrupts, DMA, shared L2 memory, etc.). For these systems, system resources must be carefully managed by the developer to avoid conflicts with the understanding that Linux/ARM will own the SPU configuration and all system resources allocated in the devicetree.
See Also
System Memory Protection Unit (SMPU) for memory protection
System Protection Features for overview of protection features
Hardware Reference Manual for complete SPU documentation and system security overview
Silicon Anomaly 20000003 for known SPU limitations