커널 포팅 (3. 커널 포팅 기본 실습 / 3.2 새로운 SoC 지원을 위한 포팅)

2025. 3. 6. 19:41프로그래밍/시스템

3.2 새로운 SoC 지원을 위한 포팅

리눅스 커널은 다양한 SoC(System on Chip)를 지원하도록 설계되어 있습니다. 하지만 새로운 SoC를 지원하려면 SoC에 맞는 코드 추가 및 설정 변경이 필요합니다.
이 과정에서는 SoC의 초기화 코드, 디바이스 트리(DTS), Kconfig 및 Makefile 수정 방법을 다룹니다.


🔹 arch/arm/mach-* 디렉토리 분석 (SoC 지원 구조 이해)

리눅스 커널에서 ARM 기반 SoC를 지원하는 코드는 arch/arm/mach-* 디렉토리에 위치합니다.

SoC 관련 디렉토리 구조 (arch/arm/mach-*)

linux/arch/arm/
├── boot/
│   ├── dts/        # 디바이스 트리 (Device Tree)
│   ├── compressed/ # 커널 압축 관련 코드
├── mach-at91/      # Atmel AT91 SoC 지원 코드
├── mach-exynos/    # 삼성 Exynos SoC 지원 코드
├── mach-omap2/     # TI OMAP2+ SoC 지원 코드
├── mach-rockchip/  # Rockchip SoC 지원 코드
├── mach-imx/       # NXP i.MX SoC 지원 코드
├── mach-sunxi/     # Allwinner SoC 지원 코드
└── mach-새로운 SoC/  # 새로운 SoC 추가

SoC 지원을 위한 주요 파일

파일  역할
mach-*/Makefile SoC 관련 코드 빌드 설정
mach-*/Kconfig SoC 관련 커널 옵션 설정
mach-*/board-*.c 특정 보드의 초기화 코드
mach-*/devices.c SoC 내장 디바이스 등록
mach-*/system.c SoC의 클럭 및 전원 관리 코드

🔹 특정 SoC 지원 코드 추가 (arch/arm/boot/dts/)

리눅스 커널에서 새로운 SoC를 지원하려면 디바이스 트리(Device Tree, DT) 를 추가해야 합니다.

1️⃣ 새로운 SoC용 디바이스 트리 파일 생성

cd arch/arm/boot/dts/
touch my_soc.dts

2️⃣ 새로운 SoC의 기본 구조 작성 (my_soc.dts)

/dts-v1/;
#include "my_soc.dtsi"

 / {
    compatible = "mycompany,my_soc";
    model = "My Custom SoC Board";

    memory {
        reg = <0x80000000 0x40000000>;  /* 1GB RAM */
    };

    chosen {
        bootargs = "console=ttyS0,115200 root=/dev/mmcblk0p2";
    };

    uart0: serial@10000000 {
        compatible = "mycompany,my_soc-uart";
        reg = <0x10000000 0x100>;
        clock-frequency = <50000000>;
    };

    gpio: gpio@20000000 {
        compatible = "mycompany,my_soc-gpio";
        reg = <0x20000000 0x1000>;
    };
};
  • compatible → SoC와 보드 이름 정의
  • memory → RAM 주소 및 크기 설정
  • chosen → 부팅 시 커널 명령어 설정 (bootargs)
  • uart0 → UART 시리얼 포트 설정
  • gpio → GPIO 컨트롤러 설정

3️⃣ 공통 SoC 정보(my_soc.dtsi)

/dts-v1/;

 / {
    cpus {
        cpu@0 {
            compatible = "arm,cortex-a53";
            reg = <0>;
        };
    };

    timer {
        compatible = "arm,armv7-timer";
    };

    gic: interrupt-controller@1f000000 {
        compatible = "arm,gic-400";
        reg = <0x1f000000 0x1000>;
    };
};
  • cpus → CPU 코어 정의
  • timer → ARM 타이머 설정
  • gic → 인터럽트 컨트롤러 설정

4️⃣ 새로운 SoC를 Kconfig 및 Makefile에 추가 새로운 SoC를 커널에서 인식하도록 설정해야 합니다.


🔹 Kconfig 및 Makefile 수정하여 SoC 지원 추가

1️⃣ arch/arm/Kconfig 수정

vim arch/arm/Kconfig
config ARCH_MY_SOC
    bool "Support for My Custom SoC"
    select ARCH_GENERIC
    help
        This enables support for My Custom SoC.
  • config ARCH_MY_SOC → 새로운 SoC 설정 추가
  • select ARCH_GENERIC → 일반적인 ARM 커널 기능 사용

2️⃣ arch/arm/Makefile 수정

vim arch/arm/Makefile
ifeq ($(CONFIG_ARCH_MY_SOC),y)
    machine-$(CONFIG_ARCH_MY_SOC) += my_soc
endif
  • CONFIG_ARCH_MY_SOC 옵션이 활성화되면 my_soc 디렉토리 포함

3️⃣ arch/arm/mach-my_soc/Makefile 생성

cd arch/arm/
mkdir mach-my_soc
touch mach-my_soc/Makefile
obj-y += devices.o
obj-y += board.o
obj-y += system.o
  • SoC 초기화 파일을 빌드하도록 설정

4️⃣ arch/arm/mach-my_soc/Kconfig 생성

vim arch/arm/mach-my_soc/Kconfig
menuconfig ARCH_MY_SOC
    bool "Support for My Custom SoC"
    select ARCH_GENERIC

5️⃣ arch/arm/mach-my_soc/board.c 생성

vim arch/arm/mach-my_soc/board.c
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/of.h>

static void __init my_soc_board_init(void)
{
    pr_info("Initializing My Custom SoC\n");
}

arch_initcall(my_soc_board_init);
  • arch_initcall()을 사용하여 SoC 초기화 코드 실행

6️⃣ arch/arm/mach-my_soc/devices.c 생성

vim arch/arm/mach-my_soc/devices.c
#include <linux/init.h>
#include <linux/platform_device.h>

static struct platform_device my_uart_device = {
    .name = "my_soc-uart",
    .id = -1,
};

static int __init my_soc_init_devices(void)
{
    platform_device_register(&my_uart_device);
    return 0;
}

arch_initcall(my_soc_init_devices);
  • UART 디바이스를 등록하는 코드

7️⃣ 디바이스 트리 빌드

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- dtbs

8️⃣ 새로운 SoC 커널 빌드

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- zImage -j$(nproc)

9️⃣ 부트로더에서 커널 실행

tftpboot 0x80000000 zImage
tftpboot 0x82000000 my_soc.dtb
bootz 0x80000000 - 0x82000000

✅ 정리

  1. SoC 지원을 위한 코드 분석
    • arch/arm/mach-*에서 SoC별 초기화 코드 확인
    • 디바이스 트리(arch/arm/boot/dts/) 추가
  2. SoC 지원 코드 추가
    • my_soc.dts 및 my_soc.dtsi 파일 생성
    • Kconfig 및 Makefile 수정하여 SoC 등록
    • mach-my_soc/ 디렉토리에서 초기화 코드 작성
  3. 빌드 및 실행
    • make dtbs로 디바이스 트리 빌드
    • make zImage로 커널 빌드
    • bootz 명령어로 SoC 기반 커널 실행