00 Heterojen SoC mimarisi
Modern SoC'lar aynı silikon üzerinde farklı mimarilere sahip işlemcileri bir araya getirir: güçlü Cortex-A uygulama işlemcisi yanında gerçek zamanlı görevler için Cortex-M mikrodenetleyici.
Neden heterojen tasarım
Yaygın heterojen SoC'lar
| SoC | A çekirdeği | M çekirdeği | Bellek | Tipik kullanım |
|---|---|---|---|---|
| STM32MP157 | Cortex-A7 (2 çekirdek, 650 MHz) | Cortex-M4 (209 MHz) | DDR3 + SRAM | Endüstriyel kontrol, tıbbi |
| STM32MP135 | Cortex-A7 (1 çekirdek, 1 GHz) | — | DDR3L | HMI, IoT gateway |
| i.MX8M Plus | Cortex-A53 (4 çekirdek) | Cortex-M7 (800 MHz) | LPDDR4 | ML + gerçek zamanlı kontrol |
| i.MX8M Mini | Cortex-A53 (4 çekirdek) | Cortex-M4 (400 MHz) | LPDDR4 | Ses, enerji yönetimi |
| AM62x (AM6254) | Cortex-A53 (4 çekirdek) | Cortex-M4F (x2) | LPDDR4 | Endüstriyel HMI, otomotiv |
| AM64x | Cortex-A53 (2 çekirdek) | Cortex-M4F + R5F | DDR4 | EtherCAT, CAN, motor kontrol |
İki çekirdek arasındaki iletişim seçenekleri
Cortex-A (Linux) Cortex-M (RTOS / bare-metal)
│ │
│ ┌─────────────────────────┐ │
├──│ Shared Memory (DDR) │─────────┤
│ └─────────────────────────┘ │
│ ┌─────────────────────────┐ │
├──│ Mailbox / IPC HW │─────────┤ ← IRQ tetikler
│ └─────────────────────────┘ │
│ ┌─────────────────────────┐ │
├──│ OpenAMP (RPMsg/virtio) │─────────┤ ← Bu rehberin konusu
│ └─────────────────────────┘ │
│ ┌─────────────────────────┐ │
└──│ RPMSG char / tty │─────────┘ ← Kullanıcı alanı arayüzü
Bu bölümde
- Heterojen SoC: aynı çipte A (Linux) + M (RTOS) — güç, deterministlik, izolasyon
- Popüler SoC'lar: STM32MP1, i.MX8M, AM62x — her birinde Cortex-M yan işlemci
- OpenAMP: shared memory + mailbox üzerine inşa edilen standart iletişim katmanı
01 OpenAMP bileşenleri
OpenAMP (Open Asymmetric Multi-Processing), üç temel katmandan oluşur: remoteproc (yaşam döngüsü), virtio/vring (aktarım), RPMsg (mesajlaşma).
Katman mimarisi
Kullanıcı alanı
┌────────────────────────────────────────────┐
│ /dev/rpmsg0 /dev/ttyRPMSG0 │
│ rpmsg_char driver rpmsg_tty driver │
└────────────────────────────────────────────┘
│
Kernel alanı
┌────────────────────────────────────────────┐
│ RPMsg çerçevesi (mesaj yönlendirme) │
│ ┌──────────────────────────────────────┐ │
│ │ virtio + vring (ring buffer DMA) │ │
│ └──────────────────────────────────────┘ │
│ ┌──────────────────────────────────────┐ │
│ │ remoteproc (firmware lifecycle) │ │
│ └──────────────────────────────────────┘ │
│ ┌──────────────────────────────────────┐ │
│ │ mailbox driver (IPC interrupt) │ │
│ └──────────────────────────────────────┘ │
│ ┌──────────────────────────────────────┐ │
│ │ libmetal (shared memory, I/O) │ │
│ └──────────────────────────────────────┘ │
└────────────────────────────────────────────┘
│ Shared DDR + HW Mailbox
Cortex-M tarafı (bare-metal / FreeRTOS)
┌────────────────────────────────────────────┐
│ OpenAMP lib: remoteproc_virtio + rpmsg │
│ libmetal: bellek/IRQ soyutlama │
│ RTOS: FreeRTOS / Zephyr / ThreadX │
└────────────────────────────────────────────┘
Bileşen görevleri
OpenAMP proje bileşenleri
| Bileşen | Konum | Açıklama |
|---|---|---|
| openamp | github.com/OpenAMP/open-amp | Çekirdek kütüphane: remoteproc, rpmsg, virtio |
| libmetal | github.com/OpenAMP/libmetal | Donanım soyutlama katmanı |
| openamp-system-reference | github.com/OpenAMP/openamp-system-reference | Demo uygulamalar ve BSP örnekleri |
| Kernel remoteproc | drivers/remoteproc/ | Linux kernel remoteproc sürücüleri |
| Kernel rpmsg | drivers/rpmsg/ | Linux kernel RPMsg çerçevesi |
Bu bölümde
- OpenAMP = libmetal + remoteproc + virtio/vring + RPMsg
- libmetal: donanım soyutlama (her iki tarafta)
- remoteproc: M çekirdeği yaşam döngüsü (Linux kernel sürücüsü)
- RPMsg: virtio tabanlı 512B mesajlaşma — endpoint adresleme
02 remoteproc
remoteproc alt sistemi, Linux'un kardeş işlemciyi (remote processor) yönetmesini sağlar: ELF firmware yükleme, başlatma, durdurma ve güvenli yeniden başlatma.
remoteproc sysfs arayüzü
| sysfs düğümü | Okuma | Yazma |
|---|---|---|
| /sys/class/remoteproc/remoteproc0/state | offline / running / suspended / crashed | start / stop |
| /sys/class/remoteproc/remoteproc0/firmware | Firmware adı | Firmware adını değiştir |
| /sys/class/remoteproc/remoteproc0/coredump | crash sonrası dump etkinleştir | disabled / enabled / inline |
| /sys/class/remoteproc/remoteproc0/recovery | Otomatik yeniden başlatma durumu | enabled / disabled |
| /sys/class/remoteproc/remoteproc0/name | Remoteproc adı | — |
Firmware yükleme ve başlatma
# Firmware dosyasının yerini kontrol et (/lib/firmware/ altında olmalı)
ls /lib/firmware/stm32mp157c-rproc.elf
# Hangi firmware yüklenecek?
cat /sys/class/remoteproc/remoteproc0/firmware
# stm32mp157c-rproc.elf
# Firmware adını değiştir (çalışmıyorken)
echo "myfirmware.elf" > /sys/class/remoteproc/remoteproc0/firmware
# Cortex-M çekirdeğini başlat
echo "start" > /sys/class/remoteproc/remoteproc0/state
# Durum kontrolü
cat /sys/class/remoteproc/remoteproc0/state
# running
# Cortex-M çekirdeğini durdur
echo "stop" > /sys/class/remoteproc/remoteproc0/state
# Kernel log'unda remoteproc mesajlarını izle
dmesg | grep remoteproc
remoteproc sürücü zinciri
Platform device tree: &m4_rproc { ... }
│
▼
SoC özgü remoteproc sürücüsü
(stm32_rproc.c / imx_rproc.c / ti_k3_r5_remoteproc.c)
│ firmware yükleme isteği
▼
request_firmware("stm32mp157c-rproc.elf")
│ /lib/firmware/ üzerinden
▼
ELF ayrıştırma + resource table okuma
│
├─ Bellek bölgelerini eşle (carveout)
├─ vdev'leri başlat (virtio)
├─ Mailbox kanallarını aç
│
▼
M çekirdeği PC/SP değerlerini yaz → reset kaldır
│
▼
M çekirdeği çalışıyor → virtio handshake
Kernel konfigürasyonu
CONFIG_REMOTEPROC=y
CONFIG_STM32_RPROC=y # STM32MP için
# CONFIG_IMX_REMOTEPROC=y # i.MX için
# CONFIG_TI_K3_R5_REMOTEPROC=y # AM62x/AM64x için
CONFIG_RPMSG=y
CONFIG_RPMSG_VIRTIO=y
CONFIG_RPMSG_CHAR=y # /dev/rpmsgX karakter aygıtları
CONFIG_RPMSG_TTY=y # /dev/ttyRPMSGX sanal seri port
CONFIG_VIRTIO=y
CONFIG_VIRTIO_MMIO=y # Bellek eşlemeli virtio
CONFIG_MAILBOX=y
# STM32 için:
CONFIG_STM32_IPCC=y # STM32 IPCC mailbox
Bu bölümde
- /sys/class/remoteproc/remoteproc0/: state, firmware, coredump, recovery
- echo start/stop ile M çekirdeği kontrolü
- ELF firmware: /lib/firmware/ altında, resource table içermeli
- SoC özgü sürücü: stm32_rproc, imx_rproc, ti_k3_r5_remoteproc
03 RPMsg
RPMsg (Remote Processor Messaging), virtio vring halka tamponları üzerine inşa edilmiş hafif bir mesajlaşma çerçevesidir. Her endpoint bir adres-port çiftine sahiptir; mesajlar 512 bayta kadardır.
RPMsg mesaj yapısı
/* Kernel kaynak: include/linux/rpmsg.h */
struct rpmsg_hdr {
__u32 src; /* Kaynak endpoint adresi */
__u32 dst; /* Hedef endpoint adresi */
__u32 reserved;
__u16 len; /* Yük uzunluğu (maks 512 byte) */
__u16 flags;
__u8 data[]; /* Mesaj verisi */
} __packed;
Linux tarafında RPMsg sürücüsü yazma
#include <linux/module.h>
#include <linux/rpmsg.h>
/* Mesaj geldiğinde çağrılır */
static int mydrv_cb(struct rpmsg_device *rpdev,
void *data, int len,
void *priv, u32 src)
{
dev_info(&rpdev->dev, "M4'ten mesaj (src=%u, len=%d): %.*s\n",
src, len, len, (char *)data);
/* M4'e yanıt gönder */
rpmsg_send(rpdev->ept, "ACK", 3);
return 0;
}
static int mydrv_probe(struct rpmsg_device *rpdev)
{
dev_info(&rpdev->dev, "RPMsg kanalı açıldı (src=%u dst=%u)\n",
rpdev->src, rpdev->dst);
/* Karşı tarafa tanışma mesajı gönder */
rpmsg_send(rpdev->ept, "HELLO", 5);
return 0;
}
static void mydrv_remove(struct rpmsg_device *rpdev)
{
dev_info(&rpdev->dev, "RPMsg kanalı kapandı\n");
}
/* Bu isim, M4 tarafındaki endpoint adıyla eşleşmeli */
static struct rpmsg_device_id mydrv_id_table[] = {
{ .name = "my-rpmsg-channel" },
{ },
};
MODULE_DEVICE_TABLE(rpmsg, mydrv_id_table);
static struct rpmsg_driver mydrv = {
.drv.name = "my_rpmsg_driver",
.id_table = mydrv_id_table,
.probe = mydrv_probe,
.remove = mydrv_remove,
.callback = mydrv_cb,
};
module_rpmsg_driver(mydrv);
Kullanıcı alanından RPMsg erişimi
# rpmsg_char modülü yüklü olmalı
modprobe rpmsg_char
# RPMsg karakter aygıtları oluştur
ls /dev/rpmsg*
# /dev/rpmsg0 /dev/rpmsg_ctrl0
# rpmsg_ctrl üzerinden yeni endpoint aç
# (rpmsg_create_ept ioctl)
# Doğrudan okuma/yazma:
echo "Merhaba M4" > /dev/rpmsg0
cat /dev/rpmsg0 # M4'ten gelen veriyi oku
# ttyRPMSG sanal seri port ile (rpmsg_tty modülü)
modprobe rpmsg_tty
ls /dev/ttyRPMSG*
# /dev/ttyRPMSG0
minicom -D /dev/ttyRPMSG0 -b 115200
RPMsg endpoint adresleme
Bu bölümde
- RPMsg: src/dst endpoint adresi + maks 512B mesaj
- Kernel sürücüsü: rpmsg_driver + callback — name ile otomatik eşleşme
- Kullanıcı alanı: /dev/rpmsg0 (char) veya /dev/ttyRPMSG0 (tty)
- Name service (0x35): kanal adı üzerinden otomatik keşif ve eşleşme
04 Cortex-M tarafı
M çekirdeği, OpenAMP kütüphanesini doğrudan kullanarak RPMsg endpoint oluşturur, mesaj alır ve gönderir. FreeRTOS ile entegrasyon en yaygın yaklaşımdır.
OpenAMP bare-metal kurulumu
/* M4 tarafı: OpenAMP + FreeRTOS ile RPMsg endpoint */
#include "openamp/open_amp.h"
#include "metal/alloc.h"
#include "metal/sys.h"
/* Virtio cihaz ve vring yapıları (resource table'dan gelir) */
static struct virtio_device vdev;
static struct rpmsg_virtio_device rvdev;
static struct metal_io_region shm_io;
/* RPMsg endpoint */
static struct rpmsg_endpoint my_ept;
/* Mesaj alındığında çağrılır (ISR veya task context'ten) */
static int rpmsg_recv_callback(struct rpmsg_endpoint *ept,
void *data, size_t len,
uint32_t src, void *priv)
{
/* Gelen veriyi işle */
uint8_t *msg = (uint8_t *)data;
/* Yanıt gönder */
rpmsg_send(ept, "ACK", 3);
return 0;
}
/* OpenAMP başlatma */
void openamp_init(void) {
struct metal_init_params metal_params = METAL_INIT_DEFAULTS;
/* libmetal başlat */
metal_init(&metal_params);
/* Shared memory I/O bölgesini kaydet */
metal_io_init(&shm_io,
(void *)SHARED_MEM_BASE, /* Fiziksel adres */
&(uint64_t){SHARED_MEM_BASE},
SHARED_MEM_SIZE,
(unsigned int)-1, /* page_shift: sayfa yok */
0, /* flags */
NULL); /* ops */
/* Resource table'dan virtio cihaz oluştur */
rproc_virtio_init_vdev(&vdev,
&rsc_table->vdev,
VDEV_NOTIFY_ID,
notify_callback, NULL);
/* RPMsg virtio cihaz başlat */
rpmsg_init_vdev(&rvdev, &vdev,
rpmsg_ns_callback, /* name service callback */
&shm_io,
&rpmsg_vring_rx,
&rpmsg_vring_tx,
RPMSG_ROLE_REMOTE); /* M4 = remote, A7 = host */
}
/* Endpoint oluştur ve kaydet */
void create_endpoint(void) {
struct rpmsg_device *rdev = rpmsg_virtio_get_rpmsg_device(&rvdev);
rpmsg_create_ept(&my_ept,
rdev,
"my-rpmsg-channel", /* Kanal adı (Linux sürücüsüyle eşleşmeli) */
RPMSG_ADDR_ANY, /* Yerel adres: dinamik ata */
RPMSG_ADDR_ANY, /* Uzak adres: name service'den öğren */
rpmsg_recv_callback,
NULL);
}
Mailbox (IPC) kesme işleme
/* STM32MP1 IPCC kesme işleyici (M4 tarafı) */
void IPCC_C1_RX_IRQHandler(void)
{
/* A7'den M4'e gelen bildirim */
/* virtio vring'de yeni mesaj var */
rproc_virtio_notified(&vdev, VRING0_ID);
/* Kesme bayrağını temizle */
HAL_IPCC_RxCallback(&hipcc, IPCC_CHANNEL_1, IPCC_CHANNEL_DIR_TX);
}
/* M4'ten A7'ye bildirim gönder */
static void notify_callback(struct virtio_device *vdev,
uint32_t notifyid)
{
/* A7 tarafına IRQ gönder (IPCC üzerinden) */
HAL_IPCC_NotifyCPU2(&hipcc, IPCC_CHANNEL_1, IPCC_CHANNEL_DIR_RX);
}
FreeRTOS task ile RPMsg döngüsü
/* FreeRTOS task: RPMsg mesaj işleme döngüsü */
void rpmsg_task(void *pvParameters)
{
openamp_init();
create_endpoint();
/* Bağlantı kurulana kadar bekle */
while (!rpmsg_endpoint_is_bound(&my_ept)) {
taskYIELD();
}
/* Ana döngü: mesaj gönder ve bekle */
for (;;) {
/* Sensör verisi örneği gönder */
sensor_data_t sensor = read_sensor();
rpmsg_send(&my_ept, &sensor, sizeof(sensor));
/* 100ms bekle */
vTaskDelay(pdMS_TO_TICKS(100));
}
}
/* FreeRTOS task oluşturma (main veya scheduler başlatılmadan önce) */
xTaskCreate(rpmsg_task, "RPMsg", 512, NULL, tskIDLE_PRIORITY + 1, NULL);
Bu bölümde
- M4 tarafı: metal_init + rpmsg_init_vdev + rpmsg_create_ept
- Rol: M4 = RPMSG_ROLE_REMOTE, A7/Linux = host
- Mailbox IRQ: A7'den bildirim geldiğinde rproc_virtio_notified() çağır
- FreeRTOS: ayrı task ile RPMsg döngüsü, endpoint_is_bound() ile bağlantı kontrolü
05 Shared memory ve resource table
Resource table, M4 ELF firmware içinde gömülü bir veri yapısıdır. Linux remoteproc bu tabloyu okuyarak paylaşımlı bellek bölgelerini, vdev'leri ve trace buffer'ı yapılandırır.
Resource table yapısı
/* M4 ELF firmware içindeki resource_table bölümü */
/* Linker script'te: .resource_table bölümü tanımlanmalı */
#include "openamp/remoteproc.h"
/* Resource table yapısı — SoC'a göre değişir */
struct __resource_table {
struct resource_table base;
/* Kaynak sayısı kadar offset */
uint32_t offset[2];
/* 1. Kaynak: Paylaşımlı bellek carveout */
struct fw_rsc_carveout shm_carveout;
/* 2. Kaynak: virtio cihaz (RPMsg için) */
struct fw_rsc_vdev vdev;
struct fw_rsc_vdev_vring vring0; /* TX vring (M4 -> A7) */
struct fw_rsc_vdev_vring vring1; /* RX vring (A7 -> M4) */
uint8_t vdev_features[RSC_VDEV_FEATURE_SIZE];
/* 3. Kaynak: Trace buffer */
struct fw_rsc_trace trace;
} __packed;
/* ELF içinde .resource_table bölümüne yerleştir */
__attribute__((section(".resource_table")))
struct __resource_table rsc_table = {
.base = {
.ver = 1, /* Resource table versiyon */
.num = 2, /* Kaynak sayısı */
},
.offset = { offsetof(struct __resource_table, shm_carveout),
offsetof(struct __resource_table, vdev) },
.shm_carveout = {
.type = RSC_CARVEOUT,
.da = 0x10040000, /* M4 görüş adresi */
.pa = 0x10040000, /* Fiziksel adres */
.len = 0x10000, /* 64 KB */
.flags = 0,
.name = "OPENAMP_SHM",
},
.vdev = {
.type = RSC_VDEV,
.id = VIRTIO_ID_RPMSG, /* 7 */
.notifyid = 0,
.dfeatures = 1, /* VIRTIO_RPMSG_F_NS */
.gfeatures = 0,
.config_len = 0,
.status = 0,
.num_of_vrings = 2,
},
.vring0 = {
.da = FW_RSC_ADDR_ANY, /* Linux tarafından atanır */
.align = 4096,
.num = 16, /* Descriptor sayısı */
.notifyid = 0,
},
.vring1 = {
.da = FW_RSC_ADDR_ANY,
.align = 4096,
.num = 16,
.notifyid = 1,
},
.trace = {
.type = RSC_TRACE,
.da = 0x10050000, /* Trace buffer adresi */
.len = 0x1000, /* 4 KB */
.name = "M4_TRACE",
},
};
Bellek haritası planlaması
DDR Bellek Haritası (STM32MP157 örneği) ┌──────────────────┬──────────────┬─────────────────────────┐ │ Adres │ Boyut │ Kullanım │ ├──────────────────┼──────────────┼─────────────────────────┤ │ 0xC0000000 │ 512 MB │ Linux DDR (DT reserved) │ │ 0xDD000000 │ 1 MB │ M4 DDR firmware │ │ 0xDD100000 │ 64 KB │ Carveout: vring + IPC │ │ 0xDD110000 │ 4 KB │ Trace buffer │ │ 0x10000000 │ 64 KB │ M4 SRAM (yerel) │ └──────────────────┴──────────────┴─────────────────────────┘
Device tree'de carveout bölge tanımlama
/* arch/arm/boot/dts/stm32mp157c-myboard.dts */
/ {
reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
ranges;
/* M4 firmware için ayrılmış DDR bölgesi */
mcuram: mcuram@dd000000 {
compatible = "shared-dma-pool";
reg = <0xdd000000 0x100000>; /* 1 MB */
no-map;
};
/* OpenAMP paylaşımlı bellek */
openamp_shmem: openamp-shmem@dd100000 {
compatible = "shared-dma-pool";
reg = <0xdd100000 0x10000>; /* 64 KB */
no-map;
};
};
/* remoteproc düğümü */
&m4_rproc {
memory-region = <&mcuram>, <&openamp_shmem>;
mboxes = <&ipcc 0>, <&ipcc 1>;
mbox-names = "vq0", "vq1";
status = "okay";
};
};
Bu bölümde
- Resource table: ELF içindeki .resource_table bölümü — carveout + vdev + trace
- vring: iki yönlü halka tampon — TX (M4→A7) ve RX (A7→M4)
- Device tree: reserved-memory ile carveout bölge no-map olarak ayrılır
- FW_RSC_ADDR_ANY: vring adresini Linux dinamik olarak atar
06 STM32MP1 üzerinde OpenAMP
STM32MP157, Cortex-A7 ve Cortex-M4'ü aynı çipte barındırır. ST, Linux tarafı için OpenSTLinux dağıtımını ve M4 tarafı için STM32CubeMP1 HAL + FreeRTOS referans paketini sağlar.
Gerekli yazılım bileşenleri
Yocto ile OpenAMP etkinleştirme
# meta-st-stm32mp layer'ı içeren Yocto projesi
# local.conf veya image recipe:
IMAGE_INSTALL:append = " \
kernel-modules \
rpmsg-utils \
copro-utils \
"
# Firmware dosyasını rootfs'e koy
# meta-mylayer/recipes-firmware/m4-firmware/m4-firmware.bb
# Hedef üzerinde M4 firmware başlatma
# 1. Firmware dosyasını /lib/firmware/ altına koy
cp stm32mp157c-rproc.elf /lib/firmware/
# 2. remoteproc sysfs üzerinden başlat
echo "stm32mp157c-rproc.elf" > /sys/class/remoteproc/remoteproc0/firmware
echo start > /sys/class/remoteproc/remoteproc0/state
# 3. Durum kontrolü
cat /sys/class/remoteproc/remoteproc0/state # running
# 4. RPMsg kanalının açılıp açılmadığını kontrol et
dmesg | grep rpmsg
# rpmsg_virtio0: creating channel my-rpmsg-channel addr 0x400
# 5. Kullanıcı alanından test
ls /dev/rpmsg*
echo "test" > /dev/rpmsg0
cat /dev/rpmsg0
M4 trace buffer okuma
# M4 firmware'in yazdığı trace buffer'ı oku
cat /sys/kernel/debug/remoteproc/remoteproc0/trace0
# Örnek M4 çıktısı:
# [M4] OpenAMP baslatiliyor...
# [M4] RPMsg endpoint olusturuldu: addr=1024
# [M4] A7 baglantisi kuruldu
# [M4] Sensor: temp=25.3C, humidity=65%
Copro (coprocessor) servis birimi
[Unit]
Description=STM32MP1 M4 Coprocessor
After=multi-user.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/copro-utils start stm32mp157c-rproc.elf
ExecStop=/usr/bin/copro-utils stop
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
Bu bölümde
- STM32MP157: A7 Linux + M4 FreeRTOS, IPCC donanım mailbox üzerinden haberleşir
- Firmware: /lib/firmware/ altında ELF; copro-utils veya sysfs ile başlatılır
- Trace buffer: /sys/kernel/debug/remoteproc/remoteproc0/trace0 — M4 log çıktısı
- Yocto: meta-st-stm32mp layer + rpmsg-utils + copro-utils
07 i.MX8M ve AM62x üzerinde OpenAMP
i.MX8M ve AM62x, STM32MP1'den farklı SoC mimarisine sahiptir; remoteproc sürücüleri ve device tree yapısı değişir ancak OpenAMP kullanım modeli aynı kalır.
i.MX8M Plus — Cortex-M7
/* arch/arm64/boot/dts/freescale/imx8mp-myboard.dts */
/ {
reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
ranges;
/* M7 için ayrılmış bellek */
m7_reserved: m7-reserved@55000000 {
no-map;
reg = <0 0x55000000 0 0x1000000>; /* 16 MB */
};
/* vdev ring buffers */
vdev0vring0: vdev0vring0@55000000 {
no-map;
reg = <0 0x55000000 0 0x8000>;
};
vdev0vring1: vdev0vring1@55008000 {
no-map;
reg = <0 0x55008000 0 0x8000>;
};
vdev0buffer: vdev0buffer@55400000 {
compatible = "shared-dma-pool";
no-map;
reg = <0 0x55400000 0 0x100000>;
};
};
&rpmsg {
memory-region = <&vdev0buffer>;
status = "okay";
};
};
/* Kernel: CONFIG_IMX_REMOTEPROC=y */
# i.MX8M M7 firmware başlatma
# NXP MCUXpresso SDK veya Zephyr ile derlenen ELF kullanılır
# Firmware konumu
ls /lib/firmware/imx8mp-cm7-*
# remoteproc0 = M7 çekirdeği
echo "imx8mp-cm7-rpmsg.elf" > /sys/class/remoteproc/remoteproc0/firmware
echo start > /sys/class/remoteproc/remoteproc0/state
# i.MX8M MU (Messaging Unit) — mailbox mekanizması
# IPCC yerine MU kullanılır: drivers/mailbox/imx-mailbox.c
# Kernel: CONFIG_IMX_MBOX=y
AM62x (TI) — Cortex-M4F
| Bileşen | AM62x'te karşılığı |
|---|---|
| remoteproc sürücüsü | ti_k3_r5_remoteproc.c (R5F) / ti_k3_m4_remoteproc.c (M4F) |
| Mailbox | OMAP mailbox: mailbox-j721e.c |
| sysfs | /sys/class/remoteproc/remoteproc0/ (aynı arayüz) |
| Firmware konumu | /lib/firmware/ti-ipc/am62xx/ipc_echo_testb_mcu1_0_release_strip.xer5f |
| IPC çerçevesi | TI IPC (eski) veya OpenAMP (yeni, önerilen) |
| SDK | MCU+ SDK, Processor SDK Linux |
/* arch/arm64/boot/dts/ti/k3-am625-sk.dts */
&mcu_m4fss {
mboxes = <&mailbox0_cluster0 &mbox_m4_0>,
<&mailbox0_cluster0 &mbox_r5_0>;
mbox-names = "txacq", "rxacq";
memory-region = <&mcu_m4fss0_dma_memory_region>,
<&mcu_m4fss0_memory_region>;
status = "okay";
};
# AM62x M4F başlatma (TI Processor SDK Linux)
# remoteproc sayısını kontrol et
ls /sys/class/remoteproc/
# remoteproc0 remoteproc1 (M4F-0 ve M4F-1)
# Firmware adı ve durumu
cat /sys/class/remoteproc/remoteproc0/firmware
# ti-ipc/am62xx/ipc_echo_testb_mcu1_0_release_strip.xer5f
echo start > /sys/class/remoteproc/remoteproc0/state
# TI IPC test aracı
# apt install ti-rpmsg-char (veya Yocto'da rpmsg-utils)
rpmsg_char_simple -d /dev/rpmsg0 -n 10 -m "Merhaba AM62x"
SoC karşılaştırması
| Özellik | STM32MP157 | i.MX8M Plus | AM62x |
|---|---|---|---|
| M çekirdeği | Cortex-M4 @ 209 MHz | Cortex-M7 @ 800 MHz | Cortex-M4F @ 400 MHz |
| Mailbox HW | IPCC | MU (Messaging Unit) | OMAP Mailbox |
| remoteproc sürücüsü | stm32_rproc.c | imx_rproc.c | ti_k3_m4_remoteproc.c |
| Yocto layer | meta-st-stm32mp | meta-imx | meta-ti |
| M tarafı SDK | STM32CubeMP1 | MCUXpresso SDK | MCU+ SDK |
| Trace okuma | /debug/remoteproc/trace0 | /debug/remoteproc/trace0 | /debug/remoteproc/trace0 |
Bu bölümde
- i.MX8M: IMX_REMOTEPROC sürücüsü, MU mailbox, MCUXpresso firmware
- AM62x: ti_k3_m4_remoteproc, OMAP mailbox, MCU+ SDK
- Tüm SoC'larda sysfs arayüzü aynı: state/firmware/coredump
- Device tree: reserved-memory + vring bölgeleri SoC'a özgü adreslenmeli
08 Hata ayıklama
OpenAMP sorunları firmware yükleme hatalarından RPMsg mesaj kayıplarına kadar geniş bir yelpazede görülür. debugfs, dmesg ve donanım izleme araçları temel tanı araçlardır.
remoteproc debugfs arayüzü
# debugfs bağla (genellikle zaten bağlı)
mount -t debugfs debugfs /sys/kernel/debug
# remoteproc debugfs dizini
ls /sys/kernel/debug/remoteproc/remoteproc0/
# carveout_memories name recovery regs trace0 version
# M4/M7 trace buffer çıktısı
cat /sys/kernel/debug/remoteproc/remoteproc0/trace0
# Çıktı yoksa: M4 firmware trace buffer başlatmamış olabilir
# Resource table'da fw_rsc_trace girişi kontrol et
# Carveout bellek bölgelerini listele
cat /sys/kernel/debug/remoteproc/remoteproc0/carveout_memories
# Name: OPENAMP_SHM PA: 0xdd100000 DA: 0xdd100000 Len: 0x10000
# Firmware versiyonunu göster
cat /sys/kernel/debug/remoteproc/remoteproc0/version
virtio-mmio ve vring durumu
# virtio cihaz listesi
ls /sys/bus/virtio/devices/
# virtio0
# virtio cihaz bilgisi
cat /sys/bus/virtio/devices/virtio0/device
# 0x0007 (VIRTIO_ID_RPMSG)
cat /sys/bus/virtio/devices/virtio0/vendor
# 0x0000
# RPMsg kanal listesi
ls /sys/bus/rpmsg/devices/
# virtio0.my-rpmsg-channel.-1.1024
# Biçim: vdevNAME.channel.src.dst
# Virtio mmio aygıt bilgisi (debugfs)
ls /sys/kernel/debug/virtio-mmio/
cat /sys/kernel/debug/virtio-mmio/virtio0
Yaygın hata senaryoları
| Hata | Belirti | Çözüm |
|---|---|---|
| Firmware bulunamadı | dmesg: "failed to load firmware" | /lib/firmware/ altında doğru isimde ELF var mı kontrol et |
| Resource table geçersiz | dmesg: "bad resource table" | resource_table sürümü ve offset'leri kontrol et |
| State offline kalıyor | echo start sonrası hâlâ offline | mailbox sürücüsü yüklü mü (dmesg | grep ipcc/mu/mbox) |
| RPMsg kanalı açılmıyor | dmesg'de rpmsg mesajı yok | M4 firmware endpoint oluşturuyor mu (trace0 oku) |
| Mesaj kaybı | Uygulama veri kaybediyor | vring descriptor sayısını artır (num=32), flow control ekle |
| M4 crash sonrası recovery | state: crashed | coredump okuma + recovery: enabled ile otomatik yeniden başlat |
M4 crash dump okuma
# Coredump etkinleştir
echo "enabled" > /sys/class/remoteproc/remoteproc0/coredump
# M4 crash olursa state "crashed" olur
cat /sys/class/remoteproc/remoteproc0/state
# crashed
# Coredump dosyasını kaydet (inline mode — debugfs üzerinden)
echo "inline" > /sys/class/remoteproc/remoteproc0/coredump
cat /sys/kernel/debug/remoteproc/remoteproc0/core_dump > m4_crash.elf
# GDB ile analiz
arm-none-eabi-gdb firmware.elf -c m4_crash.elf
# (gdb) bt — backtrace
# (gdb) info registers
# Otomatik recovery etkinleştir
echo enabled > /sys/class/remoteproc/remoteproc0/recovery
# Crash sonrası firmware otomatik yeniden yüklenir ve başlatılır
Kernel log filtreleme
# OpenAMP ile ilgili tüm kernel mesajları
dmesg | grep -E "remoteproc|rpmsg|virtio|ipcc|mailbox" | tail -50
# Dinamik debug etkinleştirme (çalışma zamanında)
echo "file drivers/remoteproc/stm32_rproc.c +p" > \
/sys/kernel/debug/dynamic_debug/control
echo "file drivers/rpmsg/*.c +p" > \
/sys/kernel/debug/dynamic_debug/control
# Etkinleştirilmiş dynamic debug kurallarını listele
grep "=p" /sys/kernel/debug/dynamic_debug/control | grep -E "remoteproc|rpmsg"
# ftrace ile remoteproc fonksiyon izleme
echo function > /sys/kernel/debug/tracing/current_tracer
echo "stm32_rproc*" > /sys/kernel/debug/tracing/set_ftrace_filter
echo 1 > /sys/kernel/debug/tracing/tracing_on
echo start > /sys/class/remoteproc/remoteproc0/state
cat /sys/kernel/debug/tracing/trace | head -50
echo 0 > /sys/kernel/debug/tracing/tracing_on
Bu bölümde
- /sys/kernel/debug/remoteproc/remoteproc0/trace0: M4 firmware log çıktısı
- carveout_memories: bellek bölgelerinin düzgün eşlenip eşlenmediğini kontrol et
- coredump=inline: M4 crash ELF dump, GDB ile analiz edilebilir
- dynamic_debug: çalışma zamanında remoteproc/rpmsg sürücü loglarını etkinleştir