How to use I/O processor (8051) of SP7021

An I/O processor (8051) is designed for processing I/O events, like receiving IR signal from remote controller, taking care of power on or off requests from RTC, or other hardware events of external peripherals even when power of main system is off. The goal of the document is to illustrate how to enable, program and use I/O processor (8051). Please follow the following steps to setup and use I/O processor in SP7021.

1. Enable Sunplus I/O processor (IOP) driver

Run make kconfig in project top directory. After Linux Kernel Configuration menu pops up, please use arrow keys to move cursor to go to sub menu “Device Drivers”, then go to its sub menu “Misc devices”, and then go to next sub menu “IOP support”. Enable “Sunplus IOP support”. Refer to screenshot of sub menu “IOP support” below:

where “Sunplus IOP support” is enabled to support I/O processor of Sunplus SP7021.

2. Modify device-tree source file to reserve memory for I/O processor.

Add subnode iop_device in node reserved-memory in device-tree source file, linux/kernel/arch/arm/boot/dts/sp7021-common.dtsi, to reserve memory for I/O processor as shown below:

reserved-memory { #address-cells = <1>; #size-cells = <1>; ranges; iop_reserve: iop_device { no-map; reg = <0x00100000 0x100000>; }; };

where property reg defines base-address and size of memory of I/O processor. It starts from 0x00100000 and its size is 0x000100000 (1 MiB).

3. Modify device-tree source file to add a node for of I/O processor driver.

Add subnode iop@9c000400 in node soc@B in device-tree source, linux/kernel/arch/arm/boot/dts/sp7021-common.dtsi, as shown below:

iop: iop@9c000400 { compatible = "sunplus,sp7021-iop"; reg = <0x9c000400 0x80>, <0x9c000000 0x80>, <0x9c000F00 0x80>, <0x9c003100 0x80>, <0x9c012B80 0x80>; reg-names = "iop", "iop_moon0", "iop_qctl", "iop_pmc", "axi_mon"; interrupt-parent = <&intc>; interrupts = <41 IRQ_TYPE_LEVEL_HIGH>, <42 IRQ_TYPE_LEVEL_HIGH>; memory-region = <&iop_reserve>; pinctrl-names = "default"; pinctrl-0 = <&pins_iop>; };

The compatible string should be “sunplus,sp7021-iop”. Two high-level trigger interrupts, number 41 and 42, are defined here. IOP can send interrupt request to main CPU either by using number 41 or number 42 interrupt. Property memory-region should be a handle to memory area defined in node reserved-memory.

Add subnode pinmux_iop-pins in device-tree source, linux/kernel/arch/arm/boot/dts/sp7021-common.dtsi, as shown below:

pctl: pinctl@9c000100 { compatible = "sunplus,sp7021-pctl"; : : pins_iop: pinmux_iop-pins { sunplus,pins = < SPPCTL_IOPAD(17, SPPCTL_PCTL_G_IOPP, 0, 0) SPPCTL_IOPAD(18, SPPCTL_PCTL_G_IOPP, 0, 0) >; } : : }

where pinmux_iop-pins is sub node of node pinctl@9c000100. Two pins G_MX17 (GPIO_P2_1) and G_MX18 (GPIO_P2_2) are set as pins of I/O processor. Note that the two pins can only be access in normal operation mode because that power of normal GPIO pins (G_MX0/P0_0 ~ G_MX87/P10_7) is turned off during standby mode. In standby mode, only IV_MX0 ~ IV_MX6 can be accessed. No need to set pins in device-tree for standby mode operation.

Please note that to comply with Linux rules, after version 5.10.59, 4 property-names of pin node of SP7021 are changed as shown in table below:

5.4.35

5.10.59

5.4.35

5.10.59

sppctl,function

function

sppctl,groups

groups

sppctl,pins

sunplus,pins

sppctl,zero_func

sunplus,zerofunc

4. Install C compiler or assembler for I/O processor

I/O processor of SP7021 is a low power, turbo mode 8051. Please install 8051 C compiler or assembler. Recommend to use Keil C51 C compiler or SDCC (released under a GPL license).

5. Write C or assembly source files for IOP

Use a text editor to write your C or assembly source files. There are two types of code of IOP you need to write. One is for normal mode and the other is for standby mode. Either type of code will be loaded into the DRAM defined in reserved memory area in device-tree source file according to operating mode of IOP. After finish writing source codes, please use C compiler or assembler to compile your source files into binary image code. Refer to attached source files for normal and standby operation of IOP, respectively:

 

Note that in standby mode, power of DRAM is off. So, before switching IOP to standby mode, standby mode code of IOP is ‘copied’ into 16k I-cache. IOP fetches code from I-cache in standby mode. This means that code-size of standby mode code is limited to no more than size of I-cache (which is 16 KiB). The code size of normal mode code has no limit. It can be as large as 8051 program addressing space, 64 KiB.

6. Convert binary image files to “C” const char array

After compiling sources and linking objectives to binary, you need further to convert them to C char array. And then copy them to char array “const unsigned char IopNormalCode” and “const unsigned char IopStandbyCode“ in C file: “drivers/misc/iop/iopnormal.c” and “drivers/misc/iop/iopstandby.c”, respectively. Refer to screenshot of file iopnormal.c:

During Sunplus IOP driver mounting, the codes in char array IopNormalCode and IopStandbyCode will be loaded into DRAM reserved area for IOP. After driver finishes loading code, it will start IOP on normal mode.

7. Build Linux image

Go to top folder. Run make all to build Linux image.

8. Boot Linux

Boot Linux with the built image.

9. Use system-file (sysfs) to communicate with IOP driver

Sunplus IOP driver supports to update code (firmware) of IOP using Linux system-file (sysfs). For example, you can update 'normal' code of IOP by writing a binary file of IOP to sysfs, normalcode. Refer to screenshot below:

64 KiB firmware, test.bin, is written to IOP for normal mode operation.

Update ‘standby’ code of IOP by writing new binary file of IOP to sysfs, standbycode. Refer to screenshot below:

16 KiB firmware, test2.bin, is written to IOP for standby mode operation.

Code (firmware) of IOP can be read back also. Refer to screenshot below:

Operation mode of IOP can be switched by writing sysfs, mode. Refer to screenshot below:

Operation mode of IOP is switched to standby mode by writing “1” to sysfs, mode.

Operation mode of IOP is switched to normal mode by writing “0” to sysfs, mode.

Current operation mode of IOP can be read out by reading sysfs, mode. Refer to screenshot below:

or

WAKE_IN pin can be enabled by writing 1 to sysfs, wakein. Refer to screenshot below:

Since WAKE_IN pin is enabled, pulling WAKE_IN pin to LOW will wake up system when it is in standby mode.

Normally, when you run poweroff command in Linux shell, system will enter S3. If you want to enter S1 instead, you can read sysfs, S1mode. Refer to screenshot below:

System entered S1 mode.

10. Supplementary

Refer to diagram below, SP7021 has three power states: S0, S1 and S3. After power-on reset, SP7021 will enter S0 in which all modules of SP7021 are powered. This is a state of full power and function. All GPIO pins (GPIO0 ~ GPIO98) of IOP can be set up and mapped to G_MX0 ~ G_MX91 and IV_MX0 ~ IV_MX6 pins of SP7021.

 

In S1 (low power mode), IOP, SRAM (for storing program code of IOP), IV_MX0~IV_MX6 pins are powered. IOP runs ‘standby mode’ code stored in SRAM. Only IV_MX0 ~ IV_MX6 pins can be accessed by IOP via GPIO0 ~ GPIO6. Standby mode code is designed to detected some wake-up events, like power-on key signal from remote controller, special pattern of UART signal and etc. Once wake-up event is detected, IOP sets register to power on whole system (switch back to S0). The power consumption is about 3 mW in this mode.

Refer to mapping table of GPIO to IV_MX pins:

AO domain pins

S0 mode

S1 mode

AO domain pins

S0 mode

S1 mode

IV_MX[0]

GPIO[92]

GPIO[0]

IV_MX[1]

GPIO[93]

GPIO[1]

IV_MX[3]

GPIO[94]

GPIO[3]

IV_MX[4]

GPIO[95]

GPIO[4]

IV_MX[5]

GPIO[96]

GPIO[5]

IV_MX[6]

GPIO[97]

GPIO[6]

IV_MX[2]

GPIO[98]

GPIO[2]

In S3 (ultra low power mode), only SRAM and Wake-up circuitry are powered. This is the minimum power-consumption state. In this state, IOP is powered off, but ‘standby mode’ code of IOP is preserved in SRAM. Wake-up circuitry will detect the state of WAKE_IN (IV_MX1) pin continuously. A LOW state in WAKE_IN pin will switch power state of SP7021 to S0. The power consumption is about 1.8 mW in this mode.

 

Refer to https://sunplus.atlassian.net/wiki/spaces/doc/pages/466190338 for register descriptions.