Samsung S5PV210/S5PC110 SoC 集成多個 DMA 控制器(MDMA、PDMA0、PDMA1),內核啟動階段需將其註冊為平台設備,供 dmaengine 子系統探測綁定。本文解析 arch/arm/mach-s5pv210/dma.c 的初始化邏輯、條件編譯選項與設備資源定義。
#ifdef CONFIG_OLD_DMA_PL330
// 舊版 PL330 驅動邏輯(已廢棄)
.....
#else
// 新版 dmaengine 架構
#include
#include
static struct platform_device *s5pc110_dmacs[] __initdata = {
&s5pc11x_device_mdma, // Memory-to-Memory DMAC
&s5pc11x_device_pdma0, // Peripheral DMAC 0
&s5pc11x_device_pdma1, // Peripheral DMAC 1
};
#endif
配置選項:
CONFIG_OLD_DMA_PL330:舊版字符設備接口驅動。CONFIG_NEW_DMA_PL330(默認 y):基於 dmaengine 的新架構。plat/devs.h設備結構體定義於 arch/arm/plat-s5p/dev-dma.c,包含資源(寄存器基址、中斷號)、平台數據(通道數、外設映射):
struct platform_device s5pc11x_device_mdma = {
.name = "dma-pl330",
.id = 0,
.num_resources = ARRAY_SIZE(mdma_resources),
.resource = mdma_resources,
.dev = {
.platform_data = &mdma_pdata,
},
};
// 資源示例
static struct resource mdma_resources[] = {
[0] = { .start = S5P_MDMA_BASE, .end = S5P_MDMA_BASE + SZ_4K - 1, .flags = IORESOURCE_MEM },
[1] = { .start = IRQ_MDMA, .end = IRQ_MDMA, .flags = IORESOURCE_IRQ },
};
static int __init s5pv210_dma_init(void) {
platform_add_devices(s5pc110_dmacs, ARRAY_SIZE(s5pc110_dmacs));
return 0;
}
arch_initcall(s5pv210_dma_init);
arch_initcall:內核啟動階段「架構初始化」級別調用(早於 subsys_initcall、device_initcall)。platform_add_devices():遍歷數組,對每個設備調用 platform_device_register(),觸發總線匹配、驅動 probe()。drivers/dma/pl330.c 中 pl330_probe() 執行:
devm_ioremap_resource() 映射寄存器區。platform_get_irq() 獲取中斷號,devm_request_irq() 註冊中斷處理函數 pl330_irq_handler。platform_data(通道數、外設請求線映射)。pl330_init() 初始化硬件、創建 dma_device、註冊到 dmaengine(dma_async_device_register())。pl330_chan、初始化任務隊列、綁定中斷親和性。現代內核(3.10+)棄用 mach/dma.c 靜態註冊,改用設備樹描述:
/dts-v1/;
/ {
dma@12130000 { // MDMA
compatible = "arm,pl330";
reg = <0x12130000 0x1000>;
interrupts = <0 45 4>;
#dma-cells = <1>;
dma-channels = <8>;
dma-requests = <16>;
};
dma@12140000 { ... }; // PDMA0
dma@12150000 { ... }; // PDMA1
};
驅動通過 of_dma_controller_register() 自動綁定,無需平台數據硬編碼。