はじめに
Raspberry Pi 5 の40pinのGPIOは直接SoCに繋がっておらず、RP1というチップに集約され、PCIe経由で接続している構成であることがわかった。このRP1に直接レジスタアクセスできないか?を試してみた。
Raspberry Pi RP1 Peripherals のドキュメント
下記PDFがドキュメント。メモリマップを見ると下記となっていた。
| Block | Address |
|---|---|
| uart0 | 0x40030000 |
| spi0 | 0x40050000 |
| spi1 | 0x40054000 |
| i2c0 | 0x40070000 |
| i2c1 | 0x40074000 |
| pwm0 | 0x40070000 |
| pwm1 | 0x4009C000 |
| io_bank0 | 0x400d0000 |
これがラズパイ上、どのように物理アドレスにマッピングされているのかcat /proc/iomemで確認すると 0x1f_0000_0000にマッピングされていそうで、例えばGPIOのピン制御をするio_bank0は0x1f000d0000のよう。
$ cat /proc/iomem
00000000-00000000 : reserved
00000000-00000000 : System RAM
・・・
00000000-00000000 : pcie@1000120000
00000000-00000000 : pcie@1000120000
00000000-00000000 : PCI Bus 0002:01
00000000-00000000 : 0002:01:00.0
00000000-00000000 : 1f00008000.mailbox mailbox@8000
00000000-00000000 : 1f00018000.clocks clocks@18000
00000000-00000000 : 1f00030000.serial serial@30000
00000000-00000000 : 1f00050000.spi spi@50000
00000000-00000000 : 1f00074000.i2c i2c@74000
00000000-00000000 : 1f00098000.pwm pwm@98000
00000000-00000000 : 1f0009c000.pwm pwm@9c000
00000000-00000000 : 1f000c8000.adc adc@c8000
00000000-00000000 : 1f000d0000.gpio gpio@d0000
00000000-00000000 : 1f000d0000.gpio gpio@d0000
00000000-00000000 : 1f000d0000.gpio gpio@d0000
00000000-00000000 : 1f00100000.ethernet ethernet@100000
00000000-00000000 : 1f00178000.pio pio@178000
00000000-00000000 : 1f00188000.dma dma@188000
00000000-00000000 : usb@200000
00000000-00000000 : xhci-hcd.0 usb@200000
00000000-00000000 : 1f00200000.usb usb@200000
00000000-00000000 : usb@300000
00000000-00000000 : xhci-hcd.1 usb@300000
00000000-00000000 : 1f00300000.usb usb@300000
00000000-00000000 : 0002:01:00.0
00000000-00000000 : 1f00400000.sram sram@400000
00000000-00000000 : 0002:01:00.0
mmap()でアクセスしてみる
/dev/memだとアクセス制限でmmap()ができなかったので、他の方法がないか確認してみる。/dev 配下に /dev/gpiomem0,1,2,3,4というのがあったので、素性を知るためdmesgで確認。gpiomem0がio_bank0に一致。サイズが0x30000なのでアドレス配置的に io_bank0(0x1f_000d0000)〜pads_bank2(0x1f_000fc000)までアクセスできそう。
$ dmesg | grep gpiomem
[ 7.118194] rpi-gpiomem 107d508500.gpiomem: window base 0x107d508500 size 0x00000040
[ 7.118371] rpi-gpiomem 107d508500.gpiomem: initialised 1 regions as /dev/gpiomem1
[ 7.118414] rpi-gpiomem 107d517c00.gpiomem: window base 0x107d517c00 size 0x00000040
[ 7.118445] rpi-gpiomem 107d517c00.gpiomem: initialised 1 regions as /dev/gpiomem2
[ 7.118465] rpi-gpiomem 107d504100.gpiomem: window base 0x107d504100 size 0x00000020
[ 7.118628] rpi-gpiomem 107d504100.gpiomem: initialised 1 regions as /dev/gpiomem3
[ 7.118654] rpi-gpiomem 107d510700.gpiomem: window base 0x107d510700 size 0x00000020
[ 7.118680] rpi-gpiomem 107d510700.gpiomem: initialised 1 regions as /dev/gpiomem4
[ 7.118762] rpi-gpiomem 1f000d0000.gpiomem: window base 0x1f000d0000 size 0x00030000
[ 7.118930] rpi-gpiomem 1f000d0000.gpiomem: initialised 1 regions as /dev/gpiomem0
Cでコードを書くと
gpiomem0.c
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
int main() {
const size_t SIZE = 0x30000;
// mmapでOpen (/dev/gpiomem0 size=0x30000)
int fd = open("/dev/gpiomem0", O_RDWR | O_SYNC);
if (fd < 0) {
perror("open");
exit(1);}
void *map = mmap(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (map == MAP_FAILED) {
perror("mmap");
close(fd);
exit(1);}
close(fd);
// 出力ファイル
FILE *outfile = fopen("gpiomem0_dump.txt", "w");
if (!outfile) {
perror("fopen");
munmap(map, SIZE);
exit(1);}
// 32bitずつ出力
for (size_t i = 0; i < (SIZE/4); i++) {
uint32_t val = ((volatile uint32_t *)map)[i];
fprintf(outfile, "%08zx : %08x\n", i * 4, val);
}
munmap(map, SIZE);
return 0;
}
$ gcc gpiomem0.c -o gpiomem0
$ ./gpiomem0
結果は下記の通り。
00000000 : 0abe0000
00000004 : 00000085
00000008 : 0abe0000
0000000c : 00000085
00000010 : 06700000
00000014 : 00000083
00000018 : 0abe0000
0000001c : 00000083
00000020 : 04400000
00000024 : 0000009f
00000028 : 04400000
0000002c : 0000009f
00000030 : 088e0000
00000034 : 00300085
00000038 : 0aae3300
0000003c : 00000085
00000040 : 0abe3300
00000044 : 00000085
00000048 : 06700000
0000004c : 00000080
00000050 : 06700300
00000054 : 00000080
00000058 : 06703000
0000005c : 00000080
00000060 : 04403000
00000064 : 00000080
00000068 : 06703000
0000006c : 00000080
00000070 : 0aae3300
00000074 : 00000084
00000078 : 0aae0000
0000007c : 00000084
00000080 : 04400000
00000084 : 0000009f
00000088 : 04400000
0000008c : 0000009f
00000090 : 04400000
00000094 : 0000009f
00000098 : 04400000
0000009c : 0000009f
000000a0 : 04400000
000000a4 : 0000009f
000000a8 : 04400000
000000ac : 0000009f
000000b0 : 0abe3300
000000b4 : 00000085
000000b8 : 04400000
000000bc : 0000009f
000000c0 : 04400000
000000c4 : 0000009f
000000c8 : 04400000
000000cc : 0000009f
000000d0 : 0abe3300
000000d4 : 00000085
000000d8 : 0abe3300
000000dc : 00000085
・・・・・
参考
以上