26. IOP8051
26.1 Introduction
There is an IOP (IO Processor) embedded inside SP7021 which is used as Processor for I/O control, IR decoding / IR wake-up and cooperation with CPU & PMC in power management purpose. The IOP core is DQ8051, so also named IOP8051, it supports dedicated JTAG debug pins which share with SP7021. In standby mode operation, the power spec reach 400uA.
.
26.2 Function Diagram
A generalized function diagram of IOP is shown in Figure 26-1.
Figure 26-1 IOP Functional Blocks
Memory management: Mainly deal with DQ8051 memory read/write access, according to its interface and address, map these operations to GPIO, registers or system memory; when access system memory can improve the performance of IOP access system memory via cache.
RegFile: Control registers for mapping to RBUS and IOP IDM, such as mailbox registers, addressing base control registers, etc.
SFR: SFR (Special Function registers) registers are used for power and GPIO controls.
IR: Infrared Radiation (infrared), usually used as a remote control.
RBUS: Main system can use this interface to control, communicate and debug IOP.
Power Control: System standby / resume control.
IDM: Internal data memory which the address is set between 0x30 ~ 0x6F (64B total)
XDM: External data Memory which the address is set between 0x0000 ~ 0xFFFF. This is part of the mapped to system bus, which enables the cache to speed up execution and reduce the need for main memory access
26.3 Function Descriptions
26.3.1 Timer1 and 2
Two 16-bit timers are embedded, timer period = IOP clock cycle time. The control flow are as below.
Set the timer in IDM: 0x3E~0x41 registers; the counter is cleared to 0x0
Enable the timer in IDM: 0x42 register,up-counting starts
When the timer counts to the time set, an interrupt to IOP is issued
If the interrupt is not masked, IOP enters ISR
IOP may clear the interrupt flag by writing "1" to the corresponding register
26.3.2 Mailbox
Mailbox is a register that can be read and written by IOP and System to exchange information with the system, faster than shared memory. The System side can be read and written by the RGST Bus. The IOP side can be accessed via the IOP_memory_management controller or via IDD memory-mapped registers - this path is still available when power down.
Note! mailbox can be read and written by System and IOP. If there is a case of writing mailbox at the same time, the write of RGST Bus is valid, and the write of IOP is ignored. Therefore, it is recommended that the use of mailbox should be one-way:
For example:
IOP Write -> System Read and Clear
System Write -> IOP Read and Clear
26.3.3 GPIO
IOP supports 128bit GPIO, which specifically supports read access to GPIO output and output enable.
26.3.4 IR
Infrared Radiation (infrared), usually used as a remote control. IR decoding is implemented by software, No hardware IR decoder is embedded
26.3.5 Reset
System may reset IOP to restart the program from the boot address. This action can be performed via RGST bus write iop_control[0]. System write 1 to iop_control[0], which asserts an IOP reset signal. This reset signal resets the IOP core, and it returns to the initial state. Caches, Timers, and other circuits are also reset.
26.3.6 Debug
CPU can stop IOP core with an instruction breakpoint
CPU writes an address to the breakpoint register iop_bp
CPU writes 1 to iop_control register[2], which enables the breakpoint function
When IOP core accesses the address that matches iop_bp, the iop_control[3] will be set to 1
CPU also can stop IOP core with a stall control
CPU writes 1 to iop_control register[1], which enables the stall function
IOP core halts when this stall control bit is set to 1
CPU uses iop_regsel to select IOP core registers for monitoring
CPU reads iop_regout to get the values of IOP core registers for debugging
26.3.7 Interrupts to IOP
Listed below is the interrupt control register (IDM 0x39), where bit 3, 4, 5 is for software monitoring. If some restrictions are violated, the corresponding interrupt will be pulled to notify.
Bit | Description |
[0] | Timer B INT |
[1] | Timer A INT |
[2] | IR INT, this bit equals (IR_IN ^ IR_IN_POLARITY) |
[3] | Access CBUS in Power Down Mode (cache-miss occurs in power down mode) the hardware will pull the INT to notify the software that a cache miss has occurred. |
[4] | Access upper 32K IOP address region(r/w iop_addr>16'h7fff) during cache flushing if the IOP accesses the address region greater than 0x7fff, the INT will pull up. |
IRQ for IOP core are low-level-triggered INTs
The IRQ flags are cleared by writing "1" to them, except the IR INT
26.3.8 Interrupts from IOP
At present, the hardware directly pulls the value of this bit into SYS_INT, that is, the software fills in 1, the SYS_INT is 1, the software fills in 0, and the SYS_INT is 0. If the IOP needs to make an INT to the RISC at some point, fill in the register 1. If it is to be cleared, fill in 0.
Note: For SYS_INT registers, RISC can only perform Read and Clear operations through RGST Bus. That is, RISCx cannot set RISC_INTx to 1 by itself. Only Write 0 is valid.
26.4 System Operation
26.4.1 Initialization flow
IOP is dedicated to the processing of IO-related processors in the system, and its work needs to be controlled and coordinated by the main controllers in the system, such as RISC CPUs. The recommended software developer refers to the following IOP Core Initialization flow:
Figure 26-2 Initialization flow
26.4.2 IOP MODULE EXECUTES 8051 CODE
Source code should reserve SDRAM memory area for IOP module code. 8051 bin file normal code and standby code can be placed in this area. The location area can be select by user.
Normal code: Monitor CPU commands.
Standby code: For RTC wake up, cooperation with CPU&PMC in power management
When the system enters standby mode, 8051 bin file should be moved to I_Cache.
I_Cache has 16K only. Standby code cannot exceed 16K.
When the IOP module is mounted, CPU load 8051 codes (IopNormalCode[]) into memory.
Iop_base_addr_l and iop_base_addr_h specify address.
During system boot up, when the IOP is mounted, it will load 8051 normal code and start execute 8051 code.
26.4.3 Program loader
In the system, IOP can continue to work when other modules in the system enter standby / power down modes to monitor whether the system wakes up through IR. In such a situation, the IOP will not be able to access the system memory. Therefore, the program that the IOP core needs to execute at this time, or the data segment of the operation must be stored in the cache (in the always-on power domain). The program loader is used to complete the cache fill. The implementation method is to capture the required program and data segment through memory read.
26.4.4 Power control flow
IOP supports independent operation when the system is standby / power down. When the user wakes up the system through IR, the IOP will use the power control signals to inform the system to start the relevant power management or system reset.
26.5 How To Create 8051 bin file
Please follow below steps:
Step1: Install Keil C.
Step2: Install DQ8051. (Please contact vendor(https://www.dcd.pl/product-category/cpus/) for the package)
Step3: Open project with IOP 8051 source code and edit. (Refer to figure 26-3)
Figure 26-3 Keil C with IOP 8051 source code
Please get source code at:
Step4: Generated normal bin file and put it in IopNormalCode[] which under linux/kernel/drivers/misc/iop/iopnormal.c. (Refer to figure 26-4)
When system booting, it will download this code as default setting.
Figure 26-4 Content of iopnormal.c
Step4: Generated standby bin file and put it in IopStandbyCode[] which under linux/kernel/drivers/misc/iop/iopstandby.c.
When system enter shutdown, IOP device will call standby code to save power.
26.6 IOP8051 Module Execution
Please follow below steps:
Step1: Reserved memory for IOP module. (Refer to figure 26-5/26-6)
Figure 26-5 reserve memory code
Figure 26-6 memory map
Step2: Load normal code. When the IOP module is mounted, system will load 8051 codes(IopNormalCode[]) into memory.
Below is the example code which include in the linux/kernel/drivers/misc/iop/hal_iop.c .
void hal_iop_init(void __iomem *iopbase) { regs_iop_t *pIopReg = (regs_iop_t *)iopbase; volatile unsigned int* IOP_base =(volatile unsigned int*)SP_IOP_RESERVE_BASE; unsigned char * IOP_kernel_base;
IOP_kernel_base = (unsigned char *)ioremap((unsigned long)IOP_base, IOP_CODE_SIZE); memset((unsigned char *)IOP_kernel_base,0, IOP_CODE_SIZE); memcpy((unsigned char *)IOP_kernel_base, IopNormalCode, IOP_CODE_SIZE);
writel(0x00100010, (void __iomem *)(B_SYSTEM_BASE + 32*4*0+ 4*1));
pIopReg->iop_control|=0x01; pIopReg->iop_control&=~(0x8000); pIopReg->iop_control|=0x0200;//disable watchdog event reset IOP pIopReg->iop_base_adr_l = (unsigned int) ((u32)(IOP_base) & 0xFFFF); pIopReg->iop_base_adr_h =(unsigned int) ((u32)(IOP_base) >> 16); pIopReg->iop_control &=~(0x01); } EXPORT_SYMBOL(hal_iop_init); |
Step3: Load standby code. When system enters standby mode, system will load 8051 codes(IopStandbyCode[]) into memory.
Below is the example code which include in the linux/kernel/drivers/misc/iop/hal_iop.c .
void hal_iop_load_standby_code(void __iomem *iopbase)
{
regs_iop_t *pIopReg = (regs_iop_t *)iopbase;
volatile unsigned int* IOP_base =(volatile unsigned int*)(SP_IOP_RESERVE_BASE+0x10000);
unsigned char * IOP_kernel_base;
IOP_kernel_base = (unsigned char *)ioremap((unsigned long)IOP_base, IOP_CODE_SIZE);
memset((unsigned char *)IOP_kernel_base,0, IOP_CODE_SIZE);
memcpy((unsigned char *)IOP_kernel_base, SourceCode, IOP_CODE_SIZE);
writel(0x00100010, (void __iomem *)(B_SYSTEM_BASE + 32*4*0+ 4*1));
pIopReg->iop_control|=0x01;
pIopReg->iop_control&=~(0x8000);
pIopReg->iop_control|=0x0200;//disable watchdog event reset IOP
pIopReg->iop_base_adr_l = (unsigned int) ((u32)(IOP_base) & 0xFFFF);
pIopReg->iop_base_adr_h =(unsigned int) ((u32)(IOP_base) >> 16);
pIopReg->iop_control &=~(0x01);
}
EXPORT_SYMBOL(hal_iop_load_standby_code);
26.7 8051 Register Tables
26.7.1 IDM memory-mapped registers (in IOP power domain)
IDM addresses listed below are used as special function registers. The registers in 0x30~0x7F not specifically described are reserved. The other registers in 0x00~0x2F and 0x80~0xFF are for general purposes.
0x30 - 0x37 (Bank Addressing Base) | ||||
|---|---|---|---|---|
Address | Signal Name | Attribute | Reset Value | Description |
0x30 | IOP_IM_Base[7:0] | RO | 0x0 | IOP IM base address; always set to 0x0 for UVM test |
0x31 | IOP_IM_Base[15:8] | RO | 0x0 | IOP IM base address; always set to 0x0 for UVM test |
0x32 | IOP_IM_Base[23:16] | RO | 0x0 | IOP IM base address |
0x33 | IOP_IM_Base[31:24] | RO | 0x0 | IOP IM base address |
0x34 | reserved |
|
|
|
0x35 | IOP_DM_Base[23:16] | RW | 0x0 | IOP DM base address; XDM bank address when D-cache is enabled |
0x36 | IOP_DM_Base[31:24] | RW | 0x0 | IOP DM base address; XDM bank address when D-cache is enabled |
0x37 | reserved |
|
|
|
0x38 - 0x3A (Interrupt) | ||||
Address | Signal Name | Attribute | Reset Value | Description |
0x38[5:0] | IOP_INT_MASK_B | RW | 0x0 | refer to Interrupts_to_IOP |
0x39[5:0] | IOP_INT_FLAG | R/W1C | 0x0 | refer to Interrupts_to_IOP |
0x3A[0] | IOP_INT0 | RW | 0x0 | refer to Interrupts_from_IOP |
0x3A[1] | IOP_INT1 | RW | 0x0 | refer to Interrupts_from_IOP |
0x3B - 0x3C (XDM Cache Control) | ||||
Address | Signal Name | Attribute | Reset Value | Description |
0x3B[6:0] | XDM Cache_Flush_LINE_NO | RW | 0x7F | number of cache lines(32B) to be checked and then be flushed if dirty 0x0: none0x1: 2 lines are checked 0x7F(default): all lines of 4KB are checkedthis number has to be set before starting flush and not be modified until the end of flush |
0x3C[0] | XDM Cache Disable | RW | 0x0 | 0: cache is enabled (default) 1: cache is disabled |
0x3C[1] | XDM Cache Flush | RW | 0x0 | 0: normal mode write 1: flush read 1: flushing in progress (this bit is functionless when XDM cache is disabled) |
0x3C[2] | XDM Cache_DIS_CLR_V_EN | RW | 0x1 | 0: valid bits are not cleared 1: all valid bits are cleared when cache is disabled (0x3C[0]=1) (default) |
0x3C[3] | XDM Cache_DIS_CLR_D_EN | RW | 0x1 | 0: dirty bits are not cleared 1: all dirty bits are cleared when cache is disabled (0x3C[0]=1) (default) |
0x3C[4] | XDM Cache_Flush_CLR_V_EN | RW | 0x1 | 0: valid bits are not cleared 1: all valid bits are cleared when cache is flushed (0x3C[1]=1) (default) |
0x3C[5] | XDM Cache_Flush_CLR_D_EN | RW | 0x1 | 0: dirty bits are not cleared 1: all dirty bits are cleared when cache is flushed (0x3C[1]=1) (default) |
0x3C[6] | XDM Cache_all_V_set | RW | 0x0 | 0: normal function (default) 1: all valid bits are set |
0x3C[7] | XDM Cache_all_D_set | RW | 0x0 | 0: normal function (default) 1: all dirty bits are set |
0x3D (IR / RTC) | ||||
Address | Signal Name | Attribute | Reset Value | Description |
0x3D[0] | IR_O | RO | 0x0 | this bit equals IR_IN ^ IR_IN_polarity |
0x3D[1] | IR_IN_polarity | RW | 0x0 | 0: IR_O = IR_IN 1: IR_O = polarity-inverted IR_IN |
0x3D[2] | PMC_IR_LATCH | RO | 0x0 | IR_LATCH flag from PMC 1: IR wakeup |
0x3D[3] | PMC_SYS_RTC_LATCH | RO | 0x0 | SYS_RTC_LATCH flag from PMC 1: RTC wakeup |
0x3D[4] | reserved |
|
|
|
0x3D[5] | reserved |
|
|
|
0x3D[6] | CLR_PMC_IR_LATCH | W1C | 0x0 | Clear PMC_IR_LATCH in PMC |
0x3D[7] | CLR_PMC_SYS_RTC_LATCH | W1C | 0x0 | Clear PMC_SYS_RTC_LATCH in PMC |
0x3E - 0x42 (Embedded Timer) | ||||
Address | Signal Name | Attribute | Reset Value | Description |
0x3E | TIMER1[7:0] | RW | 0xFF | timer1 low byte |
0x3F | TIMER1[15:8] | RW | 0xFF | timer1 high byte |
0x40 | ||||