RZ-G/RZG kernel: Difference between revisions

From Renesas.info
(Created page with "{{DISPLAYTITLE:RZ/G kernel Information}} ← RZ-G = CPU Hotplug = You can enable and disable CPU cores by writing to a sysfs value. <br> This is helpful for when you want...")
 
(→‎Building mainline / LTS Linux kernel for RZ/G2E-N-M-H: Update to reflect the current (2023) VLP kernel version.)
 
(24 intermediate revisions by 3 users not shown)
Line 47: Line 47:
* Check current frequency:
* Check current frequency:
: <code> cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq</code>
: <code> cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq</code>
* Change the current frequency:
: <code> echo 15000 > /sys/devices/system/cpu/cpu*/cpufreq/scaling_max_freq</code>


= PMIC Access from Linux =
= PMIC Access from Linux =
Line 111: Line 113:
=> bootm 0x88000000 - 0x48000000
=> bootm 0x88000000 - 0x48000000
</pre>
</pre>
= Building mainline / LTS Linux kernel for RZ/G2E-N-M-H =
The Verified Linux Package (VLP64 v1.x.y) includes the CIP kernel (v4.19.x) and until 2022 it is was the only official kernel to have all the features in. Since 2023 VLP3 includes CIP kernel 5.10. However it is possible to build a working kernel directly from mainline. The kernel built in this way does not provide most of the multimedia functionalities (e.g. GPU, codec, etc).
A recent [https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-a/downloads Linaro toolchain] is needed to build the kernel. The instructions below are for v5.10.x, newer kernel versions can be built as well in a similar way.
git clone <nowiki>https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/</nowiki>
git checkout tags/v5.10.42
or anyway the latest minor revision including bug fixes.
Copy Renesas default kernel build into .out/.config:
cp arch/arm64/configs/renesas_defconfig .out/.config
or, if not present, get from the repository:
wget -O .out/.config <nowiki>https://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers.git/plain/arch/arm64/configs/renesas_defconfig</nowiki>
If you want to be able to build modules:
echo CONFIG_MODULES=y >> .out/.config
echo CONFIG_MODULE_UNLOAD=y >> .out/.config
Run kernel configuration:
make O=.out menuconfig
Exit and save. Then launch the build:
make O=.out all -j$(nproc)
= Renesas RZ/G2 PCIe Endpoint Driver =
* [[RZ-G/RZG2_pcie_ep | Click Here]]
= GPIO Pin Usage =
Since linux-4.8 the GPIO sysfs interface is [https://www.kernel.org/doc/Documentation/gpio/sysfs.txt deprecated]. User space should use the character device instead. The libgpiod library encapsulates the ioctl calls and data structures behind a straightforward API.
Also, the kernel source code contains a GPIO utility for user space. Please see directory tools/gpio/ in the kernel source code.
== Character Device (/dev) Interface ==
* Access to GPIO pins can be made using the /dev driver interfaces.
* Official kernel documentation on this interface can be found here: https://docs.kernel.org/driver-api/gpio/using-gpio.html
* The Linux kernel is distributed with three basic user-mode tools written for testing the GPIO interface. The source can be found in linux/tools/gpio/.
* The three tools are:
: 1) lsgpio – example on how to list the GPIO lines on a system
: 2) gpio-event-mon – monitor GPIO line events from userspace
: 3) gpio-hammer - example to shake GPIO lines on a system
* Note: These are useful for debugging GPIO lines, but none of these tools will allow the user to configure, set and clear GPIO lines.
* However, you can use the user API (chip info, line info, line request for values, reading values, setting values, line request for events, polling for events and reading events) from linux/gpio.h to program GPIO.
'''RZ/G2M/H/N/E Numbering'''
* GPIO pin number for '''RZ/G2M/H/N/E''' is determined by using the command line tool '''lsgpio''':
* The RZ/G2M/H/N/E have multiple gpiochip interfaces.
<pre>
GPIO chip: gpiochip6, "e6055400.gpio", 18 GPIO lines
        line  0: unnamed unused
        ....
....
        line 17: unnamed unused
GPIO chip: gpiochip5, "e6055000.gpio", 20 GPIO lines
        line  0: unnamed unused
        ....
....
        line 19: unnamed unused [output]
GPIO chip: gpiochip4, "e6054000.gpio", 11 GPIO lines
        line  0: unnamed unused
        ....
....
        line 10: unnamed unused
GPIO chip: gpiochip3, "e6053000.gpio", 16 GPIO lines
        line  0: unnamed unused
        ....
....
        line 15: unnamed unused
GPIO chip: gpiochip2, "e6052000.gpio", 26 GPIO lines
        line  0: unnamed unused
        ....
....
        line 25: unnamed "wlan-en-regulator" [kernel output]
GPIO chip: gpiochip1, "e6051000.gpio", 23 GPIO lines
        line  0: unnamed "interrupt" [kernel]
        ....
....
        line 22: unnamed unused
GPIO chip: gpiochip0, "e6050000.gpio", 18 GPIO lines
        line  0: unnamed unused
        ....
....
        line 17: unnamed unused
</pre>
* For example, to access LED0, which is defined as GPIO5-19, you will use gpiochip5 chip and line 19.
'''RZ/G2L Numbering'''
* For RZ/G2L, the port numbering in the hardware manual and schematics are P0_0, P43_0, etc...
* This shows you the port number and the pin number as '''Px_y''' (x: port number, y: pin number)
* The equation to find the corresponding global port number is: '''(8*x + y)'''
* For examples, P0_0 is 0 (8*0+0), P5_1 is 41 (8*5+1).
* The RZ/G2L has only 1 gpiochip interface.
<pre>
GPIO chip: gpiochip0, "11030000.pin-controller", 392 GPIO lines
        line  0: unnamed unused
        ....
        ....
        line 390: unnamed unused
        line 391: unnamed unused
</pre>
* Example: To access, P43_1, you need to use, gpiochip0 and line 345 (43*8 + 1)<br>
* [[Media:gpio led linux.zip| Sample Code]] to blink LED0(GPIO5-19) RZG2E RevC using linux/gpio.h API
* Note: To run, download the source code. You also need to install the yocto SDK for RZG2E Rev C<br>
<pre>
$ source /opt/poky/2.4.3/environment-setup-aarch64-poky-linux
$ make
</pre>
== libgpiod – C library & tools ==
* libgpiod is a C library and tools for interacting the Linux GPIO character device.
* To use libgpiod with RZ-G, in yocto, add the recipe to image. This can be done  in local.conf with
<pre>
IMAGE_INSTALL_append = “ libgpiod libgpiod-tools”
</pre>
'''Command Line Tools:'''
1) '''gpiodetect''': To find out which GPIO banks and how many GPIO lines are available on the hardware<br>
*Ex: for RZG2E:
<pre>
root@ek874:~# gpiodetect
gpiochip6 [e6055400.gpio] (18 lines)
gpiochip5 [e6055000.gpio] (20 lines)
gpiochip4 [e6054000.gpio] (11 lines)
gpiochip3 [e6053000.gpio] (16 lines)
gpiochip2 [e6052000.gpio] (26 lines)
gpiochip1 [e6051000.gpio] (23 lines)
gpiochip0 [e6050000.gpio] (18 lines)
</pre>
* In case of RZG2E, you have 7 char devices, seven GPIO banks
2) '''gpioinfo''': List all lines of specified gpiochips, their names, direction, active state and additional flags<br>
<pre>
gpiochip1 - 23 lines:
        line  0:      unnamed  "interrupt"  input  active-high [kernel]
        line  1:      unnamed  "interrupt"  input  active-high [kernel]
        ....
        .... 
        line  22:      unnamed      unused  input  active-high
gpiochip0 - 18 lines:
        line  0:      unnamed      unused  input  active-high
        line  1:      unnamed      unused  input  active-high
        ....
        ....
        line  17:      unnamed      unused  input  active-high
</pre>
3) '''gpiofind''': Find the gpiochip name and line offset given the line name. For RZ/G, we do not have pin name export in driver, so we can not use pin name to find the pin line.
<br> <br>
4) '''gpioset''': Set the values of specified GPIO lines. gpioset expects the bank, gpiochip, GPIO line and the value to be set, 1 for HIGH and 0 for LOW active-high standard<br>
* ⚠ Note: gpioset (and all libgpiod apps) will '''revert the state''' of a GPIO line back to its '''original value when it exits'''. For this reason if you want the state to persist you need to instruct gpioset to wait for a signal and optionally detach and run in the background.<br>
Examples:
<pre>
gpioset  gpiochip5 3=1                              ### To set the line 3 of gpiochip5 to 1 (but it will also immediately go back to 0)
gpioset --mode=signal --background gpiochip5 19=1  ### Set the pin to 1, but continue to running in the background so the pin will stay 1
gpioset --mode=time –-sec=1 gpiochip0 328=0        ### toggle the pin for 1 sec
gpioset --mode=wait gpiochip0 328=0                ### toggle the pin and wait the user to press ENTER
</pre>
5) '''gpioget''': Read values of specified GPIO lines<br>
*Ex: read line 10 of gpiochip6
<pre>root@ek874:~# gpioget gpiochip6 10</pre>
* [[Media:gpio led libgpiod rzg2l.zip| Sample Code]] using PMOD Module(https://store.digilentinc.com/pmod-led-four-high-brightness-leds/) and RZG2L
* Note: To run, download the source code. You also need to install the yocto SDK for RZG2L <br>
* [[Media:gpio led libgpiod.zip| Sample Code]] to blink LED0(GPIO5-19) RZG2E RevC using libgpiod API
* Note: To run, download the source code. You also need to install the yocto SDK for RZG2E Rev C<br>
<pre>
$ source /opt/poky/2.4.3/environment-setup-aarch64-poky-linux
$ make
</pre>
== Using sysfs interface ==
* GPIO pins can be configured, monitored and controller on the command line using the system (/sys) interface
<br>
'''RZ/G2M/H/N/E Numbering for sysfs'''
* GPIO pin number for RZ/G2M/H/N/E is determined by: '''GPIO_ID = GPIO Bank Address + Pin Number'''
<pre>
      RZ/G2E              RZ/G2M/N/H
GPIO Bank  Address    GPIO Bank  Address
GPIO 0      494      GPIO 0      496             
GPIO 1      471      GPIO 1      467
GPIO 2      445      GPIO 2      452
GPIO 3      429      GPIO 3      436
GPIO 4      418      GPIO 4      418
GPIO 5      398      GPIO 5      392
GPIO 6      380      GPIO 6      360
                      GPIO 7      356
</pre>
* For example, on RZ/G2E, GPIO number of GP5_19 is 398 + 19 = 417
* On the RZ/G2E (Rev C) board, to turn on/off LED0 GP5_19 => gpio417
* NOTE: GP5_19 is defined as a GPIO LED0 in Device Tree. So you need to either remove that from the Device Tree and reprogram the board, or you can remove it from device tree in uboot using fdt command. Below is the example using fdt.
<pre>
=> setenv gpioLED_1=fatload mmc 0:1 0x48080000 Image-ek874.bin; fatload mmc 0:1 0x48000000 Image-r8a774c0-ek874-revc-mipi-2.1.dtb
=> setenv gpioLED_2=fdt addr 0x48000000 ; fdt rm /leds
=> setenv gpioLED_3=booti 0x48080000 - 0x48000000
=> setenv gpioLED_boot=run gpioLED_1 gpioLED_2 gpioLED_3
=> setenv
** Then run the command to boot
=> run gpioLED_boot
</pre>
* Now, lets turn on/off switch using sysfs:
<pre>
root@ek874:~# echo 417 > /sys/class/gpio/export # request gpio417
root@ek874:~# echo out > /sys/class/gpio/gpio417/direction # set gpio417 (GP5_19) output
root@ek874:~# echo 1 > /sys/class/gpio/gpio417/value # turn ON LED0
root@ek874:~# cat /sys/class/gpio/gpio417/value
1
root@ek874:~# echo 0 > /sys/class/gpio/gpio417/value # turn OFF LED0
root@ek874:~# cat /sys/class/gpio/gpio417/value
0
</pre>
'''RZ/G2L Pin Numbering for sysfs'''
* GPIO pin number is determined by formula: '''GPIO_ID = GPIO_port * 8 + GPIO_pin + 120'''
* Note that there is a 120 value offset when using the sysfs interface that is not there when using the /dev or libgpio interface
* Example: '''P42_4''' has its id '''460''' with above formula ('''42 * 8 + 4 + 120''')
* For example, on the RZ/G2L EVK, using a GPIO as input by using PMOD slide switch https://digilent.com/shop/pmod-swt-4-user-slide-switches/
<pre>
root@smarc-rzg2l:~# echo 460 > /sys/class/gpio/export
root@smarc-rzg2l:~# echo in > /sys/class/gpio/gpio460/direction
root@smarc-rzg2l:~# cat /sys/class/gpio/gpio460/value
1
root@smarc-rzg2l:~# cat /sys/class/gpio/gpio460/value # after switch off
0
</pre>
== GPIO Interrupt in Linux userspace  ==
One way to work with GPIO interrupts from user space is by polling the GPIO to detect when its value changes.
Depending on the mechanism you use to work with GPIOS in user space, there may be dedicated wait() or poll() method for that. For example, the libgpiod has a method called gpiod_line_event_wait() to wait for any event change in GPIO line. Another option is using character device interface, using line evets structures and functions.
===Supported Triggers===
Note that for the GPIO pins not all trigger methods are supported. Below are the only trigger methods support by GPIO pins.
* Rising-edge
* Falling-edge
* High-level
* Low-level
For example, if you need a Both-edge interrupt, you will need to use a IRQ0-IRQ7 pin instead.
=== Using libgpiod line events ===
libgpiod line events handling has the structures and functions to poll lines for events
<pre>
Data Structures:
struct  gpiod_line_event
Structure holding event info
Enumerations
enum  { GPIOD_LINE_EVENT_RISING_EDGE = 1, GPIOD_LINE_EVENT_FALLING_EDGE }
Event types
Functions
int gpiod_line_event_wait (struct gpiod_line *line, const struct timespec *timeout)
Wait for an event on a single line.
int gpiod_line_event_wait_bulk (struct gpiod_line_bulk *bulk, const struct timespec *timeout, struct gpiod_line_bulk *event_bulk)
Wait for events on a set of lines.
int gpiod_line_event_read (struct gpiod_line *line, struct gpiod_line_event *event)
Read the last event from the GPIO line.
</pre>
* Example source code can be found here https://github.com/renesas-rz/rzg2l_smarc_sample_code/tree/master/gpio-examples/libgpiod-examples/libgpiod-event
== IRQ Interrupt ==
* IRQ Interrupt is referring to the interrupts from IRQ0-7 input pins.
* Using IRQ pins as an interrupts requires re-mapping the pins from a GPIO pins onto IRQ pins.
* There are different options that IRQ pin can be used in Linux:
** Write your own custom kernel driver
** Create an UIO (userspace IO) driver
** Use an existing kernel driver like gpio-keys
* Here we are using 3rd method, configuring the IRQ pin as gpio-keys device.
=== Configure IRQ pin ===
* For the RZ/G2L board, there is a switch connected to a IRQ pin. You can register that pin in the device tree and wait on it in user space to use in your application.
* 'gpio-keys' is a device driver included in the Linux kernel and acts as an input device that can be used as a virtual keyboard key which can be triggered by a gpio interrupt. gpio-keys is much easier to use since it offers.
* The entire gpio-keys node will be read as a single device with multiple key codes (keyboard keys), allowing multiple interrupt pins to be used, each reporting as a different keyboard key.
=== Device Tree bindings ===
<pre>
user_key {
    compatible = "gpio-keys";
pinctrl-names = "default";
#address-cells = <1>;
        #size-cells = <0>;
pinctrl-0 = <&user_key_pin>;
button@1{
interrupt-parent = <&intc_ex>;
interrupts = <7 IRQ_TYPE_EDGE_BOTH>;
linux,code = <KEY_3>;
label = "SW1";
debounce-interval = <50>;
};
};
</pre>
Mapping to GPIO pin:
<pre>
&pinctrl{
user_key_pin: user_key {
pinmux = <RZG2L_PORT_PINMUX(3, 1, 1)>; /* IRQ7 */
};
};
</pre>
Enable the IRQ in device tree if it is not enabled by default
<pre>
&intc_ex {
status = "okay";
};
</pre>
=== Testing Interrupts in Userspace ===
* Connect PMOD button module to PMOD1 7-12. The IRQ7 is connected to Pmod1_pin7.
* You can check the interrupt value by pushing the button.
* Since the interrupt is configured for edge type both so you should get interrupt for both falling and rising event.
* Below you can see for each button press, you will get 2 interrupts (1 x falling, 1 x rising)
<pre>
root@smarc-rzg2l:~# cat /proc/interrupts | grep SW1
226:          0          0  110a0000.intc_ex  7 Edge      SW1
root@smarc-rzg2l:~# cat /proc/interrupts | grep SW1
226:          2          0  110a0000.intc_ex  7 Edge      SW1
root@smarc-rzg2l:~# cat /proc/interrupts | grep SW1
226:          4          0  110a0000.intc_ex  7 Edge      SW1
</pre>
* You can check the the input device for your user key and also check which event handler it is binding to.
<pre>
root@smarc-rzg2l:~# cat /proc/bus/input/devices
I: Bus=0019 Vendor=0001 Product=0001 Version=0100
N: Name="user_key"
P: Phys=gpio-keys/input0
S: Sysfs=/devices/platform/user_key/input/input0
U: Uniq=
H: Handlers=kbd event0
B: PROP=0
B: EV=3
B: KEY=10
</pre>
* From the output, you can see user_key is binding with handler event0.
* You can check and wait for a button press (IRQ interrupt) by simply waiting/blocking on standard input events.
<pre>
root@smarc-rzg2l:~# cat /dev/input/event0
�d�
�d�
�d��
�d��
�dr
�dr
�d)B
�d)�d��d��d%Z�d%Z�d/0�d/0�d�    �d�
</pre>
* There is also tool called '''evtest''' to test the event. To use this tool, you need to add evtest in your yocto build.
<pre>
IMAGE_INSTALL_append = " evtest lib32-evtest"
</pre>
<pre>
root@smarc-rzg2l:~# evtest /dev/input/event0
Input driver version is 1.0.1
Input device ID: bus 0x19 vendor 0x1 product 0x1 version 0x100
Input device name: "user_key"
Supported events:
  Event type 0 (EV_SYN)
  Event type 1 (EV_KEY)
    Event code 4 (KEY_3)
Properties:
Testing ... (interrupt to exit)
Event: time 1678155326.1678155326, type 1 (EV_KEY), code 4 (KEY_3), value 1
Event: time 1678155326.1678155326, -------------- SYN_REPORT ------------
Event: time 1678155326.1678155326, type 1 (EV_KEY), code 4 (KEY_3), value 0
Event: time 1678155326.1678155326, -------------- SYN_REPORT ------------
Event: time 1678155326.1678155326, type 1 (EV_KEY), code 4 (KEY_3), value 1
Event: time 1678155326.1678155326, -------------- SYN_REPORT ------------
Event: time 1678155326.1678155326, type 1 (EV_KEY), code 4 (KEY_3), value 0
Event: time 1678155326.1678155326, -------------- SYN_REPORT ------------
</pre>
* Example source code using above irq configured as gpio-keys where the application wait for event and blink the led on/off for both rising and falling edge.
* The source code can be found here https://github.com/renesas-rz/rzg2l_smarc_sample_code/tree/master/gpio-examples/irq-interrupt

Latest revision as of 09:29, 21 August 2023

RZ-G

CPU Hotplug

You can enable and disable CPU cores by writing to a sysfs value.
This is helpful for when you want to experiment with the performance of your application if you were to use a processor with less CPU cores.

For example, this command will disable the 2nd core.

$ echo 0 > /sys/devices/system/cpu/cpu1/online

More detailed information can be found here: https://www.cyberciti.biz/faq/debian-rhel-centos-redhat-suse-hotplug-cpu


Power Saving

  • In Linux, this is a mechanism that is generally supported by all kernels.(it may depend on the version)
  • The Renesas kernel has support them.

About power consumption in RZ/G2 series, we have some supported features to save power cost in default environment:

  • CPUHotplug: Turn on/off CPU in runtime.
  • CPUIdle: Support 2 modes to turn off clock or power domain of CPU when CPU is idle (nothing to do).
    • Sleep mode: put in sleep state.
    • Core standby mode: put in shutdown state. It is described in devicetree of each SoC => It has deeper state than sleep mode so that save more power.
  • CPUFreq: there are 6 governors to support "Dynamic Frequency Scaling":
    • Performance: The frequency is always set maximum => It is using as default in our current environment.
    • Powersave: The frequency is always set minimum.
    • Ondemand: If CPU load is bigger than 95%, the frequency is set max. If CPU load is equal to or less than 95%, the frequency is set based on CPU load.
    • Conservative: If CPU load is bigger than 80%, the frequency is set one level higher than current frequency. If CPU load is equal to or less than 20%, the frequency is set one level lower than current frequency.
    • Userspace: It sets frequency which is defined by user in runtime.
    • Schedutil: Schedutil governor is driven by scheduler. It uses scheduler-provided CPU utilization information as input for making its decisions by formula: freq_next= 1.25 * freq_max* util_of_CPU.
  • Power Domain: it is supported as default by Linux Power Management Framework. If a module is not use, system will disable its clock and power domain automatically.

Therefore, select proper method will be based on user's purpose. Here are my examples:

  • Want to use with best performance: disable CPUIdle + use performance frequency governor.
  • Want to use less power: enable CPUIdle + use powersave frequency governor.
  • Want to balance performance and power: we can use schedutil.
  • Want to modify frequency as user's purpose: use userspance frequency governor.
  • If user is running realtime environment, I suggest using performance governor to ensure the minimum latency.

Here are some commands to check frequency value and frequency governor in linux:

  • Check available CPU frequency:
cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_available_frequencies
  • Check available CPU frequency governor:
cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_available_governors
  • Change to other governor:
echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor (performance/userspace/schedutil/...)
  • Check current frequency:
cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq
  • Change the current frequency:
echo 15000 > /sys/devices/system/cpu/cpu*/cpufreq/scaling_max_freq

PMIC Access from Linux

The easiest way to access the PMIC registers from command line would would be to use i2ctools. Add the following line to your local.conf.

IMAGE_INSTALL_append = " i2c-tools"

However the PMICs are connected to a I2C (IIC for PMIC or I2C_DVFS) that is not enabled in the default kernel device tree. For the HiHope boards, you can edit the file arch/arm64/boot/dts/renesas/hihope-common.dtsi and add the following lines at the very bottom of the file.

&i2c_dvfs {
	status = "okay";
};

Once booted in Linux, the corresponding device should be /dev/i2c-7

You can query the connected slaves by giving the following command:

i2cdetect -y -r 7 

that on the RZ/G2E board produces the output:

0 1 2 3 4 5 6 7 8 9 a b c d e f 
00: -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- 1e 1f 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --  

So two slaves, at address 0x1e and 0x1f. Finally you can read registers by simply using the i2cget command, for example:

i2cget -y 7 0x1e 0x1 
0x02 
i2cget -y 7 0x1e 0x16 
0x00 
i2cget -y 7 0x1e 0x17 
0xc4 

If you don't want (or can't) update the device tree blob, you could use u-boot to do it temporarily. The procedure below is valid for RZ/G2M but it works also with RZ/G2E-N-H by simply modifying the device tree blob and/or kernel image names.

1) Interrupt the normal kernel boot

2) Once in u-boot, enter the follow commands (after each RESET)

=> fatload mmc 0:1 0x48080000 Image; fatload mmc 0:1 0x48000000 Image-r8a774a1-hihope-rzg2m-ex.dtb;  
=> fdt addr 0x48000000 
=> fdt set /soc/i2c@e60b0000 status "okay"

and finally boot the kernel:

=> booti 0x48080000 - 0x48000000 

Create a uImage

In the kernel, there is no make target to make a uImage for the 64-bit ARM architecture like there is for 32-bit ARM. However, you can manually make one from the file Image.gz that is created by the kernel build system by using the following command on your host machine.

$ cd arch/arm64/boot
$ mkimage -A arm64 -O linux -T kernel -C gzip -a 0x48080000 -e 0x48080000 -n "Linux Kernel Image" -d Image.gz uImage

Below is an example of booting this image on a RZ/G2 HiHiope board from u-boot.

=> fatload mmc 0:1 0x88000000 uImage
=> fatload mmc 0:1 0x48000000 Image-r8a774e1-hihope-rzg2h-ex.dtb
=> bootm 0x88000000 - 0x48000000

Building mainline / LTS Linux kernel for RZ/G2E-N-M-H

The Verified Linux Package (VLP64 v1.x.y) includes the CIP kernel (v4.19.x) and until 2022 it is was the only official kernel to have all the features in. Since 2023 VLP3 includes CIP kernel 5.10. However it is possible to build a working kernel directly from mainline. The kernel built in this way does not provide most of the multimedia functionalities (e.g. GPU, codec, etc).

A recent Linaro toolchain is needed to build the kernel. The instructions below are for v5.10.x, newer kernel versions can be built as well in a similar way.

git clone https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/
git checkout tags/v5.10.42

or anyway the latest minor revision including bug fixes.

Copy Renesas default kernel build into .out/.config:

cp arch/arm64/configs/renesas_defconfig .out/.config

or, if not present, get from the repository:

wget -O .out/.config https://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers.git/plain/arch/arm64/configs/renesas_defconfig

If you want to be able to build modules:

echo CONFIG_MODULES=y >> .out/.config
echo CONFIG_MODULE_UNLOAD=y >> .out/.config

Run kernel configuration:

make O=.out menuconfig

Exit and save. Then launch the build:

make O=.out all -j$(nproc)

Renesas RZ/G2 PCIe Endpoint Driver

GPIO Pin Usage

Since linux-4.8 the GPIO sysfs interface is deprecated. User space should use the character device instead. The libgpiod library encapsulates the ioctl calls and data structures behind a straightforward API.

Also, the kernel source code contains a GPIO utility for user space. Please see directory tools/gpio/ in the kernel source code.

Character Device (/dev) Interface

  • Access to GPIO pins can be made using the /dev driver interfaces.
  • Official kernel documentation on this interface can be found here: https://docs.kernel.org/driver-api/gpio/using-gpio.html
  • The Linux kernel is distributed with three basic user-mode tools written for testing the GPIO interface. The source can be found in linux/tools/gpio/.
  • The three tools are:
1) lsgpio – example on how to list the GPIO lines on a system
2) gpio-event-mon – monitor GPIO line events from userspace
3) gpio-hammer - example to shake GPIO lines on a system
  • Note: These are useful for debugging GPIO lines, but none of these tools will allow the user to configure, set and clear GPIO lines.
  • However, you can use the user API (chip info, line info, line request for values, reading values, setting values, line request for events, polling for events and reading events) from linux/gpio.h to program GPIO.

RZ/G2M/H/N/E Numbering

  • GPIO pin number for RZ/G2M/H/N/E is determined by using the command line tool lsgpio:
  • The RZ/G2M/H/N/E have multiple gpiochip interfaces.
GPIO chip: gpiochip6, "e6055400.gpio", 18 GPIO lines
        line  0: unnamed unused
        ....
	....
        line 17: unnamed unused
GPIO chip: gpiochip5, "e6055000.gpio", 20 GPIO lines
        line  0: unnamed unused
        ....
	....
        line 19: unnamed unused [output]
GPIO chip: gpiochip4, "e6054000.gpio", 11 GPIO lines
        line  0: unnamed unused
        ....
	....
        line 10: unnamed unused
GPIO chip: gpiochip3, "e6053000.gpio", 16 GPIO lines
        line  0: unnamed unused
        ....
	....
        line 15: unnamed unused
GPIO chip: gpiochip2, "e6052000.gpio", 26 GPIO lines
        line  0: unnamed unused
        ....
	....
        line 25: unnamed "wlan-en-regulator" [kernel output]
GPIO chip: gpiochip1, "e6051000.gpio", 23 GPIO lines
        line  0: unnamed "interrupt" [kernel]
        ....
	....
        line 22: unnamed unused
GPIO chip: gpiochip0, "e6050000.gpio", 18 GPIO lines
        line  0: unnamed unused
        ....
	....
        line 17: unnamed unused
  • For example, to access LED0, which is defined as GPIO5-19, you will use gpiochip5 chip and line 19.

RZ/G2L Numbering

  • For RZ/G2L, the port numbering in the hardware manual and schematics are P0_0, P43_0, etc...
  • This shows you the port number and the pin number as Px_y (x: port number, y: pin number)
  • The equation to find the corresponding global port number is: (8*x + y)
  • For examples, P0_0 is 0 (8*0+0), P5_1 is 41 (8*5+1).
  • The RZ/G2L has only 1 gpiochip interface.
GPIO chip: gpiochip0, "11030000.pin-controller", 392 GPIO lines
        line  0: unnamed unused
        ....
        ....
        line 390: unnamed unused
        line 391: unnamed unused
  • Example: To access, P43_1, you need to use, gpiochip0 and line 345 (43*8 + 1)
  • Sample Code to blink LED0(GPIO5-19) RZG2E RevC using linux/gpio.h API
  • Note: To run, download the source code. You also need to install the yocto SDK for RZG2E Rev C
$ source /opt/poky/2.4.3/environment-setup-aarch64-poky-linux
$ make

libgpiod – C library & tools

  • libgpiod is a C library and tools for interacting the Linux GPIO character device.
  • To use libgpiod with RZ-G, in yocto, add the recipe to image. This can be done in local.conf with
IMAGE_INSTALL_append = “ libgpiod libgpiod-tools”

Command Line Tools:

1) gpiodetect: To find out which GPIO banks and how many GPIO lines are available on the hardware

  • Ex: for RZG2E:
root@ek874:~# gpiodetect
gpiochip6 [e6055400.gpio] (18 lines)
gpiochip5 [e6055000.gpio] (20 lines)
gpiochip4 [e6054000.gpio] (11 lines)
gpiochip3 [e6053000.gpio] (16 lines)
gpiochip2 [e6052000.gpio] (26 lines)
gpiochip1 [e6051000.gpio] (23 lines)
gpiochip0 [e6050000.gpio] (18 lines)
  • In case of RZG2E, you have 7 char devices, seven GPIO banks

2) gpioinfo: List all lines of specified gpiochips, their names, direction, active state and additional flags

gpiochip1 - 23 lines:
        line   0:      unnamed  "interrupt"   input  active-high [kernel]
        line   1:      unnamed  "interrupt"   input  active-high [kernel]
        ....
        ....  
        line  22:      unnamed       unused   input  active-high 
gpiochip0 - 18 lines:
        line   0:      unnamed       unused   input  active-high 
        line   1:      unnamed       unused   input  active-high 
        ....
        ....
        line  17:      unnamed       unused   input  active-high

3) gpiofind: Find the gpiochip name and line offset given the line name. For RZ/G, we do not have pin name export in driver, so we can not use pin name to find the pin line.

4) gpioset: Set the values of specified GPIO lines. gpioset expects the bank, gpiochip, GPIO line and the value to be set, 1 for HIGH and 0 for LOW active-high standard

  • ⚠ Note: gpioset (and all libgpiod apps) will revert the state of a GPIO line back to its original value when it exits. For this reason if you want the state to persist you need to instruct gpioset to wait for a signal and optionally detach and run in the background.

Examples:

gpioset  gpiochip5 3=1                              ### To set the line 3 of gpiochip5 to 1 (but it will also immediately go back to 0)
gpioset --mode=signal --background gpiochip5 19=1   ### Set the pin to 1, but continue to running in the background so the pin will stay 1
gpioset --mode=time –-sec=1 gpiochip0 328=0         ### toggle the pin for 1 sec
gpioset --mode=wait gpiochip0 328=0                 ### toggle the pin and wait the user to press ENTER

5) gpioget: Read values of specified GPIO lines

  • Ex: read line 10 of gpiochip6
root@ek874:~# gpioget gpiochip6 10
$ source /opt/poky/2.4.3/environment-setup-aarch64-poky-linux
$ make

Using sysfs interface

  • GPIO pins can be configured, monitored and controller on the command line using the system (/sys) interface


RZ/G2M/H/N/E Numbering for sysfs

  • GPIO pin number for RZ/G2M/H/N/E is determined by: GPIO_ID = GPIO Bank Address + Pin Number
       RZ/G2E              RZ/G2M/N/H
GPIO Bank   Address    GPIO Bank   Address
GPIO 0       494       GPIO 0       496              
GPIO 1       471       GPIO 1       467
GPIO 2       445       GPIO 2       452 
GPIO 3       429       GPIO 3       436
GPIO 4       418       GPIO 4       418
GPIO 5       398       GPIO 5       392
GPIO 6       380       GPIO 6       360
                       GPIO 7       356
  • For example, on RZ/G2E, GPIO number of GP5_19 is 398 + 19 = 417
  • On the RZ/G2E (Rev C) board, to turn on/off LED0 GP5_19 => gpio417
  • NOTE: GP5_19 is defined as a GPIO LED0 in Device Tree. So you need to either remove that from the Device Tree and reprogram the board, or you can remove it from device tree in uboot using fdt command. Below is the example using fdt.
=> setenv gpioLED_1=fatload mmc 0:1 0x48080000 Image-ek874.bin; fatload mmc 0:1 0x48000000 Image-r8a774c0-ek874-revc-mipi-2.1.dtb
=> setenv gpioLED_2=fdt addr 0x48000000 ; fdt rm /leds
=> setenv gpioLED_3=booti 0x48080000 - 0x48000000
=> setenv gpioLED_boot=run gpioLED_1 gpioLED_2 gpioLED_3
=> setenv
** Then run the command to boot
=> run gpioLED_boot
  • Now, lets turn on/off switch using sysfs:
root@ek874:~# echo 417 > /sys/class/gpio/export # request gpio417
root@ek874:~# echo out > /sys/class/gpio/gpio417/direction # set gpio417 (GP5_19) output
root@ek874:~# echo 1 > /sys/class/gpio/gpio417/value # turn ON LED0
root@ek874:~# cat /sys/class/gpio/gpio417/value 
1
root@ek874:~# echo 0 > /sys/class/gpio/gpio417/value # turn OFF LED0
root@ek874:~# cat /sys/class/gpio/gpio417/value 
0

RZ/G2L Pin Numbering for sysfs

  • GPIO pin number is determined by formula: GPIO_ID = GPIO_port * 8 + GPIO_pin + 120
  • Note that there is a 120 value offset when using the sysfs interface that is not there when using the /dev or libgpio interface
  • Example: P42_4 has its id 460 with above formula (42 * 8 + 4 + 120)
  • For example, on the RZ/G2L EVK, using a GPIO as input by using PMOD slide switch https://digilent.com/shop/pmod-swt-4-user-slide-switches/
root@smarc-rzg2l:~# echo 460 > /sys/class/gpio/export
root@smarc-rzg2l:~# echo in > /sys/class/gpio/gpio460/direction 
root@smarc-rzg2l:~# cat /sys/class/gpio/gpio460/value 
1
root@smarc-rzg2l:~# cat /sys/class/gpio/gpio460/value # after switch off
0

GPIO Interrupt in Linux userspace

One way to work with GPIO interrupts from user space is by polling the GPIO to detect when its value changes. Depending on the mechanism you use to work with GPIOS in user space, there may be dedicated wait() or poll() method for that. For example, the libgpiod has a method called gpiod_line_event_wait() to wait for any event change in GPIO line. Another option is using character device interface, using line evets structures and functions.

Supported Triggers

Note that for the GPIO pins not all trigger methods are supported. Below are the only trigger methods support by GPIO pins.

  • Rising-edge
  • Falling-edge
  • High-level
  • Low-level

For example, if you need a Both-edge interrupt, you will need to use a IRQ0-IRQ7 pin instead.


Using libgpiod line events

libgpiod line events handling has the structures and functions to poll lines for events

Data Structures:
struct  	gpiod_line_event
 	Structure holding event info
Enumerations
enum  	{ GPIOD_LINE_EVENT_RISING_EDGE = 1, GPIOD_LINE_EVENT_FALLING_EDGE }
 	Event types
Functions
int	gpiod_line_event_wait (struct gpiod_line *line, const struct timespec *timeout)
 	Wait for an event on a single line. 
 
int gpiod_line_event_wait_bulk (struct gpiod_line_bulk *bulk, const struct timespec *timeout, struct gpiod_line_bulk *event_bulk)
 	Wait for events on a set of lines.
 
int gpiod_line_event_read (struct gpiod_line *line, struct gpiod_line_event *event)
 	Read the last event from the GPIO line.

IRQ Interrupt

  • IRQ Interrupt is referring to the interrupts from IRQ0-7 input pins.
  • Using IRQ pins as an interrupts requires re-mapping the pins from a GPIO pins onto IRQ pins.
  • There are different options that IRQ pin can be used in Linux:
    • Write your own custom kernel driver
    • Create an UIO (userspace IO) driver
    • Use an existing kernel driver like gpio-keys
  • Here we are using 3rd method, configuring the IRQ pin as gpio-keys device.

Configure IRQ pin

  • For the RZ/G2L board, there is a switch connected to a IRQ pin. You can register that pin in the device tree and wait on it in user space to use in your application.
  • 'gpio-keys' is a device driver included in the Linux kernel and acts as an input device that can be used as a virtual keyboard key which can be triggered by a gpio interrupt. gpio-keys is much easier to use since it offers.
  • The entire gpio-keys node will be read as a single device with multiple key codes (keyboard keys), allowing multiple interrupt pins to be used, each reporting as a different keyboard key.

Device Tree bindings

user_key {
	    compatible = "gpio-keys";
		pinctrl-names = "default";
		#address-cells = <1>;
        #size-cells = <0>;
		pinctrl-0 = <&user_key_pin>;
		button@1{
			interrupt-parent = <&intc_ex>;
			interrupts = <7 IRQ_TYPE_EDGE_BOTH>;
			linux,code = <KEY_3>;
			label = "SW1";
			debounce-interval = <50>;
		};
};

Mapping to GPIO pin:

&pinctrl{
	user_key_pin: user_key {
		pinmux = <RZG2L_PORT_PINMUX(3, 1, 1)>;	/* IRQ7 */
	};
}; 

Enable the IRQ in device tree if it is not enabled by default

&intc_ex {
	status = "okay";
};

Testing Interrupts in Userspace

  • Connect PMOD button module to PMOD1 7-12. The IRQ7 is connected to Pmod1_pin7.
  • You can check the interrupt value by pushing the button.
  • Since the interrupt is configured for edge type both so you should get interrupt for both falling and rising event.
  • Below you can see for each button press, you will get 2 interrupts (1 x falling, 1 x rising)
root@smarc-rzg2l:~# cat /proc/interrupts | grep SW1
226:          0          0  110a0000.intc_ex   7 Edge      SW1
root@smarc-rzg2l:~# cat /proc/interrupts | grep SW1
226:          2          0  110a0000.intc_ex   7 Edge      SW1
root@smarc-rzg2l:~# cat /proc/interrupts | grep SW1
226:          4          0  110a0000.intc_ex   7 Edge      SW1
  • You can check the the input device for your user key and also check which event handler it is binding to.
root@smarc-rzg2l:~# cat /proc/bus/input/devices
I: Bus=0019 Vendor=0001 Product=0001 Version=0100
N: Name="user_key"
P: Phys=gpio-keys/input0
S: Sysfs=/devices/platform/user_key/input/input0
U: Uniq=
H: Handlers=kbd event0 
B: PROP=0
B: EV=3
B: KEY=10
  • From the output, you can see user_key is binding with handler event0.
  • You can check and wait for a button press (IRQ interrupt) by simply waiting/blocking on standard input events.
root@smarc-rzg2l:~# cat /dev/input/event0
�d�
�d�
�d��
�d��
�dr
�dr
�d)B
�d)�d��d��d%Z�d%Z�d/0�d/0�d�    �d�
  • There is also tool called evtest to test the event. To use this tool, you need to add evtest in your yocto build.
IMAGE_INSTALL_append = " evtest lib32-evtest"
root@smarc-rzg2l:~# evtest /dev/input/event0 
Input driver version is 1.0.1
Input device ID: bus 0x19 vendor 0x1 product 0x1 version 0x100
Input device name: "user_key"
Supported events:
  Event type 0 (EV_SYN)
  Event type 1 (EV_KEY)
    Event code 4 (KEY_3)
Properties:
Testing ... (interrupt to exit)
Event: time 1678155326.1678155326, type 1 (EV_KEY), code 4 (KEY_3), value 1
Event: time 1678155326.1678155326, -------------- SYN_REPORT ------------
Event: time 1678155326.1678155326, type 1 (EV_KEY), code 4 (KEY_3), value 0
Event: time 1678155326.1678155326, -------------- SYN_REPORT ------------

Event: time 1678155326.1678155326, type 1 (EV_KEY), code 4 (KEY_3), value 1
Event: time 1678155326.1678155326, -------------- SYN_REPORT ------------
Event: time 1678155326.1678155326, type 1 (EV_KEY), code 4 (KEY_3), value 0
Event: time 1678155326.1678155326, -------------- SYN_REPORT ------------