00 Linux FPGA Manager subsystem'e genel bakış
Linux FPGA Manager subsystem (v4.7+, drivers/fpga/), FPGA yeniden yapılandırmasını standart bir kernel API'si üzerinden soyutlar. Her FPGA türü için özel bir driver yazmak yerine, tek bir sysfs/device tree overlay arayüzü kullanılır.
Subsystem bileşenleri
Desteklenen FPGA platformları
| Sürücü | Platform | Dosya |
|---|---|---|
| zynq-fpga | Xilinx Zynq-7000 | drivers/fpga/zynq-fpga.c |
| zynqmp-fpga | Zynq UltraScale+ MPSoC | drivers/fpga/zynqmp-fpga.c |
| socfpga | Intel Cyclone V SoC | drivers/fpga/socfpga.c |
| altera-ps-spi | Altera (PS-SPI) | drivers/fpga/altera-ps-spi.c |
| ice40-spi | Lattice iCE40 (SPI) | drivers/fpga/ice40-spi.c |
| xilinx-spi | Xilinx (SPI slave serial) | drivers/fpga/xilinx-spi.c |
Sysfs arayüzü
# FPGA manager listeleme
ls /sys/class/fpga_manager/
# → fpga0
# Mevcut durum
cat /sys/class/fpga_manager/fpga0/state
# → operating (yapılandırılmış ve çalışıyor)
# → unknown (henüz yapılandırılmamış)
# → writing (bitstream yazılıyor)
# İsim ve status flags
cat /sys/class/fpga_manager/fpga0/name
cat /sys/class/fpga_manager/fpga0/status
Bu bölümde
- FPGA Manager: kernel API ile FPGA yapılandırmasını soyutlar (v4.7+)
- fpga_manager + fpga_region + fpga_bridge: üç temel kavram
- zynq-fpga, zynqmp-fpga, socfpga: platform özel sürücüler
- /sys/class/fpga_manager/fpga0/state: çalışma durumu izleme
01 fpga_region ve fpga_bridge kavramları
fpga_region, belirli bir FPGA alanını temsil eder ve o alanı yönetmek için gerekli manager ve bridge referanslarını içerir. fpga_bridge, yapılandırma sırasında PS-PL arasındaki veri yolunu kontrol eder.
fpga_region yapısı (kernel)
struct fpga_region {
struct device dev;
struct fpga_manager *mgr; /* hangi manager kullanılacak */
struct list_head bridge_list; /* hangi bridge'ler kontrol edilecek */
struct fpga_image_info *info; /* bitstream bilgisi */
int (*get_bridges)(struct fpga_region *);
int priv;
};
Bridge durumları
Zynq-7000 bridge listesi
| Bridge | DT compatible | Açıklama |
|---|---|---|
| HP0–HP3 slave AXI | xlnx,zynq-axi-fpga-port-hp | PL→DDR yüksek performans portları |
| GP0/GP1 master AXI | xlnx,zynq-axi-fpga-port-gp | PS→PL genel amaç portları |
| ACP | xlnx,zynq-axi-fpga-port-acp | Önbellek tutarlı PL erişimi |
Bridge'in neden kapatılması gerekir?
Bitstream yazımı sırasında PL'deki lojik tanımsız durumdadır: register'lar rastgele değerler üretebilir, DMA motorları hatalı veri yazabilir, kesme hatları çok sayıda sahte kesme üretebilir. Bridge kapatılarak PS DDR'ı ve sistem bus'ı bu durumdan korunur.
Bu bölümde
- fpga_region: FPGA alanı + manager + bridge listesi — tek yapılandırma birimi
- fpga_bridge: bitstream yazımı öncesi kapatılır, sonra açılır
- Zynq bridge'leri: HP0–HP3, GP0/GP1, ACP portları
- Bridge kapatma zorunluluğu: PL tanımsız durumdayken DDR koruması
02 Device Tree overlay ile FPGA overlay
Device Tree overlay (DTBO), yeni bir bitstream yüklendiğinde PL'deki yeni periferalleri tanımlamak için dinamik olarak kernel'a eklenir. Bu sayede yeniden önyükleme gerekmez.
FPGA overlay DTS şablonu
/dts-v1/;
/plugin/; /* Overlay olduğunu belirtir */
/ {
fragment@0 {
target = <&fpga_full>;
__overlay__ {
/* Bitstream dosya adı (firmware/fpga/ dizininde) */
firmware-name = "design_1_wrapper.bit.bin";
};
};
fragment@1 {
target = <&amba>;
__overlay__ {
/* PL'deki yeni AXI-Lite periferali */
my_periph: my-periph@40000000 {
compatible = "myco,my-periph-1.0";
reg = <0x40000000 0x10000>;
clocks = <&clkc 15>;
clock-names = "s00_axi_aclk";
interrupts = <0 29 4>;
interrupt-parent = <&gic>;
status = "okay";
};
};
};
};
Bitstream formatı: .bit → .bit.bin
# dd ile Xilinx .bit başlığını kaldır (ilk 96 byte genellikle başlıktır)
# Kesin offset: xxd design.bit | head -4 ile byte swap noktasını bul
# Yöntem 1: bootgen (Vitis/Petalinux araçları)
bootgen -arch zynq -process_bitstream bin -image design.bit
# Yöntem 2: Python ile byte swap + başlık kaldırma
python3 - <<'EOF'
import struct
with open('design.bit', 'rb') as fin:
data = fin.read()
# Başlık boyutunu bul (0xFF 0xFF... dizisini ara)
i = data.index(b'\xff\xff\xff\xff')
raw = data[i:]
# Her 4 byte'ı byte-swap yap (Xilinx bit-endian → byte-swap)
out = bytearray()
for k in range(0, len(raw), 4):
chunk = raw[k:k+4]
if len(chunk) == 4:
out.extend(bytes(reversed(chunk)))
with open('design.bit.bin', 'wb') as fout:
fout.write(out)
print(f'Yazıldı: {len(out)} byte')
EOF
DTBO derleme
# DTS → DTBO derleme
dtc -@ -I dts -O dtb -o fpga-overlay.dtbo fpga-overlay.dts
# Bitstream'i firmware dizinine kopyala
cp design.bit.bin /lib/firmware/
# DTBO yükleme (configfs overlay interface)
mkdir /sys/kernel/config/device-tree/overlays/fpga0
cp fpga-overlay.dtbo /sys/kernel/config/device-tree/overlays/fpga0/dtbo
# Durum kontrolü
cat /sys/kernel/config/device-tree/overlays/fpga0/status
# → applied
Bu bölümde
- DTBO: /plugin/ direktifiyle overlay; fragment@0 bitstream, fragment@1 periferaller
- .bit → .bit.bin: başlık kaldırma + byte swap (bootgen veya Python)
- dtc -@: overlay desteğiyle derleme (phandle referansları korunur)
- configfs: /sys/kernel/config/device-tree/overlays/ — runtime DTBO yükleme
03 Tam yeniden yapılandırma (full reconfiguration)
Tam yeniden yapılandırma, tüm PL dokusunu yeni bir bitstream ile programlar. Tüm mevcut PL tasarımı silinir ve yenisi yüklenir.
Yeniden yapılandırma akışı
1. Sürücü: fpga_region_program_fpga() çağrısı
2. Bridge'leri devre dışı bırak (fpga_bridges_disable)
3. fpga_mgr_load(): bitstream → FPGA yapılandırma mantığı
a. state = FPGA_MGR_STATE_WRITE_INIT
b. state = FPGA_MGR_STATE_WRITE (chunk'lar halinde)
c. state = FPGA_MGR_STATE_WRITE_COMPLETE
4. Bridge'leri etkinleştir (fpga_bridges_enable)
5. fpga_region'a DT overlay'i uygula (yeni periferaller)
6. state = FPGA_MGR_STATE_OPERATING
fpga_image_info yapısı
#include <linux/fpga/fpga-mgr.h>
#include <linux/fpga/fpga-region.h>
static int load_full_bitstream(struct fpga_region *region,
const char *firmware_name)
{
struct fpga_image_info *info;
int ret;
info = fpga_image_info_alloc(®ion->dev);
if (!info)
return -ENOMEM;
info->firmware_name = devm_kstrdup(®ion->dev,
firmware_name, GFP_KERNEL);
info->flags = 0; /* FPGA_MGR_PARTIAL_RECONFIG değil */
region->info = info;
ret = fpga_region_program_fpga(region);
fpga_image_info_free(info);
return ret;
}
Tam yeniden yapılandırma sırasında PL üzerinde çalışan tüm DMA işlemleri, aktif kesme kaynakları ve PL bağlantılı sürücüler önceden durdurulmalıdır. Aksi hâlde sistem kilitlenmesi veya bellek bozulması yaşanabilir.
Bu bölümde
- Tam yapılandırma: WRITE_INIT → WRITE → WRITE_COMPLETE → OPERATING
- Bridge'ler yazım öncesi kapatılır, sonra açılır
- fpga_image_info: firmware_name + flags; flags=0 → tam yapılandırma
- Önceki DMA/IRQ'ları durdur: sistem kilitlenmesinden kaçın
04 Kısmi yeniden yapılandırma (partial reconfiguration)
Kısmi Yeniden Yapılandırma (Partial Reconfiguration — PR), PL'nin yalnızca belirli bir bölümünü yeniden programlarken geri kalanın çalışmaya devam etmesini sağlar. Vivado'da özel PR akışı gerektirir.
Vivado PR tasarım gereksinimleri
Linux'ta PR yükleme
/* Kısmi bitstream için flags */
info->flags = FPGA_MGR_PARTIAL_RECONFIG;
info->firmware_name = "partial_rm1.bin";
/* PR region için ayrı fpga_region tanımlanmış olmalı */
ret = fpga_region_program_fpga(pr_region);
/* Sysfs'ten PR yükleme (configfs overlay) */
# mkdir /sys/kernel/config/device-tree/overlays/pr_rm1
# cp pr-overlay.dtbo /sys/kernel/config/device-tree/overlays/pr_rm1/dtbo
Bu bölümde
- PR: statik bölge çalışırken RP yeniden programlanır — kesinti yok
- Vivado PR flow: RP tanımla → RM implementasyonları → .pbin üret
- FPGA_MGR_PARTIAL_RECONFIG: Linux'ta kısmi yükleme için flag
- PR Decoupler: RP izolasyonu — tanımsız sinyal yayılması önlenir
05 FPGA bridge etkinleştirme/devre dışı bırakma
Linux FPGA Manager, bridge'leri otomatik yönetir. Ancak bazı durumlarda manuel bridge kontrolü gerekebilir: hata kurtarma, özel yeniden yapılandırma sekansları veya tanılama.
Kernel API
#include <linux/fpga/fpga-bridge.h>
/* Tek bridge kontrolü */
struct fpga_bridge *bridge;
bridge = of_fpga_bridge_get(dev->of_node, NULL);
if (IS_ERR(bridge)) { /* ... */ }
fpga_bridge_disable(bridge); /* Veri yolunu kapat */
/* ... bitstream yükleme ... */
fpga_bridge_enable(bridge); /* Veri yolunu aç */
fpga_bridge_put(bridge);
/* Birden fazla bridge'i senkron kontrolü */
LIST_HEAD(bridge_list);
fpga_bridge_get_to_list(dev->of_node, NULL, &bridge_list);
fpga_bridges_disable(&bridge_list);
/* ... */
fpga_bridges_enable(&bridge_list);
fpga_bridges_put(&bridge_list);
Sysfs bridge kontrolü
# Bridge'leri listele
ls /sys/class/fpga_bridge/
# → br0 br1 br2 br3
# Bridge durumu
cat /sys/class/fpga_bridge/br0/state
# → enabled veya disabled
# Manuel devre dışı bırakma
echo 0 > /sys/class/fpga_bridge/br0/enable
echo 1 > /sys/class/fpga_bridge/br0/enable
Bu bölümde
- fpga_bridge_disable/enable: tekil bridge kontrolü
- fpga_bridges_disable/enable: listedeki tüm bridge'leri atomik kontrol
- /sys/class/fpga_bridge/br0/enable: sysfs üzerinden manuel kontrol
- Tanımlama: of_fpga_bridge_get() — DT node'undan bridge al
06 xilinx-pr-decoupler
PR Decoupler, Reconfigurable Partition ile statik bölge arasındaki sinyalleri yapılandırma sırasında izole eden bir IP bloğudur. Linux'ta xlnx,pr-decoupler sürücüsü ile yönetilir.
PR Decoupler çalışma prensibi
Statik Bölge → [PR Decoupler] → Reconfigurable Partition
Yapılandırma başlamadan önce:
Decoupler: sinyalleri kes (tüm girişler sabit değer)
Bridge: devre dışı bırak
Bitstream yazımı:
RP tanımsız durumda
Decoupler sinyalleri izole eder → statik bölge etkilenmez
Yapılandırma tamamlandıktan sonra:
Bridge: etkinleştir
Decoupler: sinyalleri geçir (normal çalışma)
Device Tree tanımı
pr_decoupler_0: pr-decoupler@40010000 {
compatible = "xlnx,pr-decoupler-1.00", "xlnx,pr-decoupler";
reg = <0x40010000 0x10>;
clocks = <&clkc 15>;
clock-names = "aclk";
#fpga-bridge-cells = <0>;
};
/* fpga_region bu bridge'i kullanır */
fpga-region0 {
compatible = "fpga-region";
fpga-mgr = <&devcfg>;
fpga-bridges = <&pr_decoupler_0>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
};
Decoupler sysfs kontrolü
# Decoupler'ı etkinleştir (izolasyon başlat)
echo 0 > /sys/class/fpga_bridge/pr_decoupler_0/enable
# PR bitstream yükle...
# Decoupler'ı devre dışı bırak (normal çalışma)
echo 1 > /sys/class/fpga_bridge/pr_decoupler_0/enable
Bu bölümde
- PR Decoupler: statik←→RP sinyal izolasyonu; yapılandırma sırasında zorunlu
- xlnx,pr-decoupler: Linux sürücüsü — fpga_bridge API ile entegre
- DTS: #fpga-bridge-cells = <0>; fpga_region'a bağlanır
- Sıra: decoupler kapat → bridge kapat → bitstream → bridge aç → decoupler aç
07 sysfs arayüzü ile yapılandırma
Linux FPGA Manager subsystem, sysfs üzerinden kullanıcı alanından doğrudan bitstream yüklemeye olanak tanır. Bu yöntem basit senaryolar ve hata ayıklama için uygundur.
Sysfs üzerinden bitstream yükleme
# 1. Bitstream'i firmware dizinine kopyala
cp design.bit.bin /lib/firmware/design.bit.bin
# 2. FPGA manager'ı bul
ls /sys/class/fpga_manager/
# → fpga0
# 3. Mevcut durum
cat /sys/class/fpga_manager/fpga0/state
# → operating
# 4. Bitstream dosya adını yaz (yükleme başlar)
echo "design.bit.bin" > /sys/class/fpga_manager/fpga0/firmware
# 5. Yükleme durumunu izle
cat /sys/class/fpga_manager/fpga0/state
# → writing ... → operating (başarı)
# → write_err (hata)
Hata durumları ve çözümleri
| Durum | Anlamı | Çözüm |
|---|---|---|
| write_err | Bitstream yazımı başarısız | dmesg'i kontrol et; .bit.bin formatını doğrula |
| write_init_err | FPGA başlatma hatası | PS reset; saat frekansı kontrolü |
| write_complete_err | DONE sinyali gelmedi | Hedef cihaz eşleşmesi; bit-endian kontrolü |
| unknown | Henüz yapılandırılmamış | Normal; boot sonrası ilk yükleme öncesi |
flags sysfs attribute
# PR için flags yaz (FPGA_MGR_PARTIAL_RECONFIG = 1)
echo 1 > /sys/class/fpga_manager/fpga0/flags
echo "partial_rm.bin" > /sys/class/fpga_manager/fpga0/firmware
# Tam yapılandırma için flags sıfırla
echo 0 > /sys/class/fpga_manager/fpga0/flags
Bu bölümde
- firmware attribute: dosya adı yazınca yükleme başlar (/lib/firmware/ aranır)
- state attribute: operating/writing/write_err — durum izleme
- flags attribute: 0=tam yapılandırma, 1=kısmi yapılandırma (PR)
- write_err: dmesg + .bit.bin format doğrulama ile tanı
08 Pratik: Zynq runtime DT overlay ile bitstream yükleme
Bu bölümde Zynq-7000 tabanlı bir sistemde (veya Zynq'e bağlı Raspberry Pi senaryosunda) runtime DT overlay kullanılarak yeni bir bitstream yüklenecek ve PL'deki yeni periferale erişilecektir.
Senaryo
Zynq-7000 (ZedBoard / PYNQ-Z2) üzerinde Linux çalışıyor. Başlangıçta PL boş (veya başka bir tasarım yüklü). Çalışma sırasında yeni bir AXI-Lite LED denetleyici bitstream'i yüklenecek ve DT overlay ile periferale erişilecek.
Adım 1: Kernel yapılandırması
# menuconfig'de etkinleştir
CONFIG_FPGA=y
CONFIG_FPGA_MGR_ZYNQ_FPGA=y
CONFIG_FPGA_REGION=y
CONFIG_FPGA_BRIDGE=y
CONFIG_OF_OVERLAY=y
CONFIG_OF_CONFIGFS=y # configfs DT overlay için
Adım 2: Bitstream hazırlama
# Vivado'dan alınan design_1_wrapper.bit → .bit.bin
bootgen -arch zynq -process_bitstream bin \
-image design_1_wrapper.bit
# Zynq Linux'a SCP ile kopyala
scp design_1_wrapper.bit.bin root@192.168.1.1:/lib/firmware/
# Zynq'te doğrula
ls -la /lib/firmware/design_1_wrapper.bit.bin
Adım 3: DT overlay oluşturma
/dts-v1/;
/plugin/;
/ {
fragment@0 {
target = <&fpga_full>;
__overlay__ {
firmware-name = "design_1_wrapper.bit.bin";
};
};
fragment@1 {
target = <&amba>;
__overlay__ {
led_ctrl: led-ctrl@40000000 {
compatible = "xlnx,led-ctrl-1.0";
reg = <0x40000000 0x10000>;
clocks = <&clkc 15>;
clock-names = "s00_axi_aclk";
status = "okay";
};
};
};
};
Adım 4: Overlay derleme ve uygulama
# DTBO derleme (çapraz derleme veya hedef üzerinde)
dtc -@ -I dts -O dtb -o led-fpga-overlay.dtbo led-fpga-overlay.dts
# configfs mount (genellikle zaten mount edilmiş)
mount -t configfs configfs /sys/kernel/config
# Overlay uygula
mkdir /sys/kernel/config/device-tree/overlays/led_fpga
cp led-fpga-overlay.dtbo \
/sys/kernel/config/device-tree/overlays/led_fpga/dtbo
# Durum kontrol
cat /sys/kernel/config/device-tree/overlays/led_fpga/status
# → applied
# FPGA manager durumu
cat /sys/class/fpga_manager/fpga0/state
# → operating
# Yeni periferali doğrula
ls /sys/bus/platform/devices/ | grep led
# → 40000000.led-ctrl
Adım 5: LED periferalini test et
# devmem2 aracıyla (genellikle Zynq Linux'ta mevcut)
devmem2 0x40000000 w 0xFF # Tüm LED'leri yak
devmem2 0x40000000 w 0x00 # Söndür
devmem2 0x40000000 w 0xAA # Alternatif desen
# dmesg çıktısında overlay ve sürücü logları
dmesg | tail -20
# [ 42.123] fpga_manager fpga0: writing design_1_wrapper.bit.bin to Xilinx Zynq FPGA Manager
# [ 43.456] fpga_manager fpga0: state transition: operating
# Overlay'i kaldır (PL sıfırlanmaz, sadece DT kaldırılır)
rmdir /sys/kernel/config/device-tree/overlays/led_fpga
PYNQ framework (Jupyter üzerinden Python), aynı FPGA Manager subsystem'i kullanır ancak Python API'siyle sarmalar. from pynq import Overlay; ol = Overlay("design.bit") komutu aynı DT overlay mekanizmasını tetikler. Düşük seviye anlamak için kernel akışını öğrenmek önemlidir.
Bu bölümde
- Kernel config: FPGA_MGR_ZYNQ_FPGA + FPGA_REGION + OF_OVERLAY + OF_CONFIGFS
- bootgen -process_bitstream bin: .bit → .bit.bin dönüşümü
- configfs overlay: mkdir + cp dtbo → state: applied
- Temizlik: rmdir overlay dizini — DT kaldırılır; PL yeniden yapılandırılmaz