Guide de portage et de débogage du chargeur de démarrage U-Boot pour une plateforme RV1126B

Introduction au processus de démarrage

Le chargeur de démarrage U-Boot (Universal Boot Loader) est un composant fondamental dans le flux de démarrage d'un système Linux embarqué. Sa position dans la séquence d'amorçage est la suivante :

Alimentation → MiniLoader (TPL/SPL) → U-Boot → Noyau Linux → Système de fichiers racine
               ↑                      ↑
          Initialisation DDR     Initialisation du matériel, chargement du noyau

Le processus de démarrage détaillé se décompose comme suit :

Étape Nom Lieu d'exécution Fonction principale
1 TPL (Tiny Program Loader) SRAM Initialise la mémoire DDR
2 SPL (Secondary Program Loader) DDR Charge U-Boot
3 U-Boot DDR Initialise le matériel, charge le noyau
4 Noyau Linux DDR Noyau du système d'exploitation
5 RootFS DDR Système de fichiers racine

Responsabilités fondamentales d'U-Boot

Initialisation du matériel

U-Boot initialise l'ensemble du matériel nécessaire au démarrage du système. Cette initialisation couvre plusieurs catégories de périphériques :

// Modules matériels initialisés par U-Boot
├── CPU et système d'horloge
│   ├── Configuration de la fréquence CPU
│   ├── Arbre d'horloge système
│   └── Unité de gestion d'alimentation (PMU)
│
├── Contrôleur mémoire
│   ├── Paramètres DDR
│   ├── Ajustement des timings mémoire
│   └── Tests mémoire
│
├── Port série (UART)
│   ├── Configuration du débit en bauds
│   ├── Sortie de débogage
│   └── Interface en ligne de commande
│
├── Périphériques de stockage
│   ├── Contrôleur eMMC
│   ├── Contrôleur SPI Flash
│   └── Contrôleur carte SD
│
├── Interfaces réseau
│   ├── MAC Ethernet
│   ├── Puce PHY
│   └── Support du démarrage TFTP
│
└── Autres périphériques
    ├── GPIO
    ├── I2C
    ├── SPI
    └── USB

Chargement du noyau

La tâche principale d'U-Boot est de charger et de démarrer le noyau Linux. Le flux de chargement se déroule en plusieurs phases :

1. Lecture de la partition boot
   ├─ Lecture de boot.img depuis eMMC/SPI Flash
   └─ boot.img est une image au format FIT

2. Analyse de l'image FIT
   ├─ Extraction de l'image noyau (Image)
   ├─ Extraction de l'arbre des périphériques (DTB)
   └─ Extraction de l'image des ressources (resource.img)

3. Chargement en mémoire
   ├─ Noyau chargé à l'adresse 0x40000000
   ├─ DTB chargé à l'adresse 0x41000000
   └─ Ramdisk chargé à l'adresse 0x42000000 (si présent)

4. Configuration des paramètres de démarrage
   ├─ Variable d'environnement bootargs
   ├─ Paramètres de la ligne de commande du noyau
   └─ Adresse de l'arbre des périphériques

5. Saut vers le noyau
   └─ Exécution de la commande bootm pour démarrer le noyau

Les variables d'environnement critiques incluent :

# Visualisation des variables d'environnement U-Boot
=> printenv

# Variables importantes
bootargs=console=ttyFIQ0,1500000n8 root=/dev/mmcblk0p7 rootwait rw
bootcmd=mmc dev 0; mmc read 0x40000000 0x8000 0x10000; bootm 0x40000000
bootdelay=3

Interface interactive

U-Boot fournit une interface en ligne de commande pour le débogage, les tests et la configuration manuelle. Les commandes sont catégorisées comme suit :

Catégorie Commande Description
Informations version Affiche la version d'U-Boot
bdinfo Affiche les informations de la carte
printenv Affiche les variables d'environnement
Mémoire md Affiche le contenu mémoire
mm Modifie la mémoire
mw Écrit dans la mémoire
cp Copie la mémoire
Stockage mmc list Liste les périphériques MMC
mmc dev Sélectionne un périphérique MMC
mmc read Lit depuis MMC
mmc write Écrit sur MMC
Réseau ping Teste la connectivité réseau
dhcp Obtient une adresse IP
tftp Télécharge via TFTP
Démarrage boot Démarre le système
bootm Démarre une image noyau
reset Redémarre le système

Procédure de portage d'U-Boot

Étape 1 : Création d'un fichier de configuration de carte

Pour adapter U-Boot à un matériel spécifique, il est recommandé de créer un fichier de configuration personnalisé. La méthode consiste à copier une configuration existante et à la modifier :

cd /chemin/vers/u-boot

# Copie du fichier de configuration
cp configs/config_existante_defconfig configs/ma_config_defconfig

# Édition du fichier
vim configs/ma_config_defconfig

Un exemple de contenu du fichier defconfig :

# configs/ma_config_defconfig

CONFIG_ARM=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_SPL_LIBCOMMON_SUPPORT=y
CONFIG_SPL_LIBGENERIC_SUPPORT=y
CONFIG_SYS_MALLOC_F_LEN=0x2000
CONFIG_ROCKCHIP_RV1126=y
CONFIG_ROCKCHIP_SPL_RESERVE_IRAM=0x0
CONFIG_TARGET_RV1126_RV1109=y
CONFIG_SPL_STACK_R_ADDR=0x600000
CONFIG_DEFAULT_DEVICE_TREE="rv1126-ma-carte"  # Nom de l'arbre des périphériques
CONFIG_DEBUG_UART=y
CONFIG_FIT=y
CONFIG_FIT_VERBOSE=y
CONFIG_SPL_LOAD_FIT=y
# ... plus de configurations

Étape 2 : Modification de l'arbre des périphériques (DTS)

L'arbre des périphériques décrit la configuration matérielle. Il est situé dans le répertoire :

cd /chemin/vers/u-boot/arch/arm/dts/

# Fichiers principaux pour RV1126
rv1126.dtsi                          # Arbre de niveau puce (base)
rv1126-carte-reference.dts        # Arbre de niveau carte de référence

Pour créer un arbre personnalisé :

# Copie de l'arbre de référence
cp rv1126-carte-reference.dts rv1126-ma-carte.dts

# Édition de l'arbre
vim rv1126-ma-carte.dts

La structure de base d'un arbre des périphériques est la suivante :

/dts-v1/;
#include "rv1126.dtsi"
#include "rv1126-ma-carte-camera.dtsi"
#include "rv1126-ma-carte-affichage.dtsi"

/ {
    model = "Ma Carte RV1126B";
    compatible = "ma-societe,rv1126b", "rockchip,rv1126";

    chosen {
        stdout-path = "serial2:1500000n8";
    };
};

// Configuration des périphériques
&uart2 {
    status = "okay";
};

&i2c0 {
    status = "okay";
    clock-frequency = <400000>;
};

Étape 3 : Ajout de code de niveau carte

Pour ajouter des initialisations matérielles personnalisées, modifiez les fichiers de niveau carte situés dans :

cd /chemin/vers/u-boot/board/rockchip/evb_rv1126b/

# Fichiers principaux
evb_rv1126b.c  - Code d'initialisation de niveau carte

Voici un exemple de code d'initialisation :

// board/rockchip/rv1126_rv1109/rv1126-rv1109.c

#include <common.h>
#include <dm.h>
#include <asm>
#include <asm>
#include <asm>

DECLARE_GLOBAL_DATA_PTR;

int board_early_init_f(void)
{
    return 0;
}

int board_init(void)
{
    printf("Carte : Ma Carte RV1126B\n");
    preparer_module_5g();
    preparer_module_wifi();
    return 0;
}

static int preparer_module_5g(void)
{
    int resultat;
    printf("Préparation du module 5G (RM500Q)...\n");

    resultat = gpio_request(GPIO_ALIM_5G, "alim_5g");
    if (resultat) {
        printf("Échec de la demande du GPIO d'alimentation 5G\n");
        return resultat;
    }

    gpio_direction_output(GPIO_ALIM_5G, 1);
    mdelay(100);

    resultat = gpio_request(GPIO_RESET_5G, "reset_5g");
    if (resultat) {
        printf("Échec de la demande du GPIO de reset 5G\n");
        return resultat;
    }

    gpio_direction_output(GPIO_RESET_5G, 0);
    mdelay(10);
    gpio_direction_output(GPIO_RESET_5G, 1);
    mdelay(100);

    printf("Module 5G initialisé\n");
    return 0;
}

static int preparer_module_wifi(void)
{
    // Logique d'initialisation du module WiFi
    return 0;
}

int board_late_init(void)
{
    env_set("nom_carte", "ma_rv1126b");
    env_set("revision_carte", "v1.0");
    verifier_mode_demarrage();
    return 0;
}

static void verifier_mode_demarrage(void)
{
    int etat_touche_recup = gpio_get_value(GPIO_TOUCHE_RECUP);
    if (etat_touche_recup == 0) {
        printf("Touche de récupération enfoncée, entrée en mode récupération\n");
        env_set("bootcmd", "run demarrage_recup");
    }
}</asm></asm></asm></dm.h></common.h>

Étape 4 : Compilation et test

Après configuration, compilez U-Boot avec la commande :

make -j$(nproc)

Le produit de compilation principal est le fichier uboot.img, qui peut être flashé sur le périphérique cible. Pour tester, connectez-vous via un port série avec un débit de 1500000 bauds.

Méthodes de débogage d'U-Boot

Débogage série

Le port série est la méthode de débogage la plus courante. Connexion :

sudo minicom -D /dev/ttyUSB0 -b 1500000

Commandes U-Boot utiles pour le débogage :

# Vérification de la version
=> version

# Inspection des variables d'environnement
=> printenv

# Test des périphériques MMC
=> mmc list
=> mmc info

# Manipulation mémoire
=> md.l 0x40000000 0x10

# Test GPIO
=> gpio status

Ajout de traces de débogage

Insérez des messages de débogage dans le code source :

void ma_fonction_debug(void)
{
    printf("Débogage : Entrée dans ma_fonction_debug\n");
    debug("Ceci s'affiche uniquement si DEBUG est défini\n");
    pr_err("Message d'erreur\n");
}

Pour activer les traces détaillées, définissez la macro DEBUG ou activez les options de journalisation dans la configuration.

Débogage avancé avec JTAG

Pour le débogage au niveau matériel, utilisez un adaptateur JTAG et des outils comme OpenOCD et GDB :

# Démarrage du serveur OpenOCD
openocd -f interface/jlink.cfg -f rv1126.cfg

# Connexion avec GDB
arm-linux-gnueabihf-gdb u-boot
(gdb) target remote localhost:3333
(gdb) break board_init
(gdb) continue

Problèmes courants et solutions

Erreurs de compilation

Problème : Outil de compilation croisé introuvable.
Solution : Ajoutez le chemin de l'outil à la variable PATH.

export PATH=/chemin/vers/toolchain/bin:$PATH

Problèmes de démarrage

Problème : Sortie série absente ou illisible.
Solution : Vérifiez la connexion du port série et le débit en bauds (1500000 pour RV1126B).

Problème : Initialisation DDR échouée.
Solution : Vérifiez les paramètres DDR dans les fichiers de configuration du bootloader.

Problèmes fonctionnels

Problème : Périphérique MMC non détecté.
Solution : Vérifiez la configuration de l'alimentation et les timings dans l'arbre des périphériques.

&emmc {
    status = "okay";
    vmmc-supply = <&vcc_3v3>;
    vqmmc-supply = <&vcc_1v8>;
};

Problème : Interface réseau indisponible.
Solution : Assurez-vous que le pilote réseau est activé dans la configuration et que la puce PHY est correctement initialisée.

Étiquettes: u-boot RV1126B Portage Démarrage Embarqué Débogage Noyau

Publié le 29 juin à 16h53