三星 S5P 系列處理器中的 FIMC(Frame Image Memory Controller)是影像擷取與處理的核心子系統,負責攝影頭資料的搬移、格式轉換、縮放等操作。本文深入剖析 Linux 核心中 FIMC 驅動的平台裝置註冊流程,以 FIMC0、FIMC1、FIMC2 三個通道為例,說明資源定義、平台資料設定與 GPIO 配置的關鍵細節。
FIMC0 作為主要攝影頭介面,其平台裝置定義包含記憶體資源與中斷資源:
static struct resource s3c_fimc0_resource[] = {
[0] = {
.start = S5P_PA_FIMC0,
.end = S5P_PA_FIMC0 + S5P_SZ_FIMC0 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_FIMC0,
.end = IRQ_FIMC0,
.flags = IORESOURCE_IRQ,
},
};
struct platform_device s3c_device_fimc0 = {
.name = "s3c-fimc",
.id = 0,
.num_resources = ARRAY_SIZE(s3c_fimc0_resource),
.resource = s3c_fimc0_resource,
};
平台資料結構 s3c_platform_fimc 記錄預設攝影頭類型與硬體版本,並提供 s3c_fimc0_set_platdata() 函數供開機時覆寫:
static struct s3c_platform_fimc default_fimc0_data __initdata = {
.default_cam = CAMERA_PAR_A,
#if defined(CONFIG_CPU_S5PV210_EVT1)
.hw_ver = 0x45,
#else
.hw_ver = 0x43,
#endif
};
void __init s3c_fimc0_set_platdata(struct s3c_platform_fimc *pd) {
struct s3c_platform_fimc *npd;
if (!pd) pd = &default_fimc0_data;
npd = kmemdup(pd, sizeof(struct s3c_platform_fimc), GFP_KERNEL);
if (!npd)
printk(KERN_ERR "%s: no memory for platform data\n", __func__);
else {
if (!npd->cfg_gpio) npd->cfg_gpio = s3c_fimc0_cfg_gpio; // 對應 CAM 介面
if (!npd->clk_on) npd->clk_on = s3c_fimc_clk_on;
if (!npd->clk_off) npd->clk_off = s3c_fimc_clk_off;
#if defined(CONFIG_CPU_S5PV210_EVT1)
npd->hw_ver = 0x45;
#else
npd->hw_ver = 0x43;
#endif
s3c_device_fimc0.dev.platform_data = npd;
}
}
FIMC1 與 FIMC2 結構類似,但 GPIO 配置函數標註為「未實作」:
// FIMC1
if (!npd->cfg_gpio) npd->cfg_gpio = s3c_fimc1_cfg_gpio; // 此 IO 口未實作
// FIMC2
if (!npd->cfg_gpio) npd->cfg_gpio = s3c_fimc2_cfg_gpio; // 此 IO 口未實作
硬體版本號亦有差異:FIMC1 在 EVT1 版本為 0x50,其餘為 0x43;FIMC2 則與 FIMC0 相同。
struct resource 定義暫存器基址與中斷號,核心自動處理映射與申請。kmemdup 複製資料,避免多裝置共用同一記憶體導致競態。cfg_gpio 函數指標允許各板級專案自訂腳位多工設定,FIMC0 已實作,FIMC1/2 需依硬體補全。s3c_fimc_clk_on/off,簡化驅動層邏輯。理解此註冊機制,有助於移植新 SoC 或除錯攝影頭啟動失敗問題。實際開發中,請配合原廠資料表確認各通道支援的解析度、像素格式與 DMA 搬移模式。