Lors de l'exécution d'un FPGA avec un processeur ARM sous Linux, il est devenu nécessaire de modifier quelque chose appelé une arborescence de périphériques. Par conséquent, j'aimerais écrire sur ce que j'ai étudié (j'ai compris) afin de pouvoir comprendre approximativement le contenu de la source de l'arborescence des périphériques (.dts) incluse dans la source du noyau. J'espère que le contenu donnera aux gens qui regardent le fichier .dts dans la source du noyau et pensent «ce qui ne va pas» qu'ils peuvent le comprendre et apporter des corrections supplémentaires.
L'arborescence des périphériques peut être considérée comme une structure de données (format de fichier) qui décrit les composants matériels accessibles depuis le système d'exploitation (CPU) du point de vue du logiciel (pilote de périphérique). Ce format a été développé par un groupe appelé Open Firmware (un groupe distinct du groupe de développement Linux).
Ce format est également utilisé sous Linux, et le code du noyau et les informations pour chaque carte (c'est-à-dire l'arborescence des périphériques) sont séparés et exploités. En conséquence, si une arborescence de périphériques est préparée pour la carte, il est possible d'opérer sur différentes cartes tout en gardant le binaire du noyau commun.
La source du noyau a un fichier source de l'arborescence des périphériques (.dts) pour les principales cartes prises en charge, et le binaire de l'arborescence des périphériques se trouve sur le système Makefile ainsi que la construction du binaire du noyau (par exemple make zImage
). Il peut être généré (par exemple «make dt bs»). À propos, au moment de la rédaction de cet article (mai 2020), l'arborescence des sources du noyau Linux de Kernel.org d'origine enregistrait plus de 1200 fichiers .dts uniquement pour les processeurs ARM 32 bits.
Le code du noyau (chaque pilote de périphérique) recherche dans l'arborescence des périphériques les informations dont vous avez besoin au moment de l'initialisation, et termine l'enregistrement et l'initialisation du périphérique en fonction de ces informations.
Par conséquent, il peut y avoir des situations où le noyau ne démarrera pas à moins que les informations requises par le code du noyau ne soient décrites dans l'arborescence des périphériques, donc en principe, le binaire du noyau et l'arborescence des périphériques doivent être créés à partir de la même version de la source du noyau. Je vais.
Écrit dans un format de texte lisible par l'homme est appelé une source d'arborescence de périphériques et a une extension .dts. Le fichier converti au format binaire est appelé un objet blob d'arborescence de périphériques et a une extension .dtb. Le noyau lit un objet blob d'arborescence de périphériques (.dtb) au format binaire. Le compilateur d'arborescence de périphériques (commande dtc) est utilisé pour convertir la source de l'arborescence de périphériques en blob de l'arborescence de périphériques. Le compilateur de l'arborescence des périphériques a la possibilité de faire la conversion inverse .dtb-> .dts ainsi que .dts-> .dtb, que vous pouvez utiliser si vous voulez voir le contenu du binaire .dtb.
Comprendre l'arborescence des périphériques sous Linux (bien que l'introduction ait été allongée) --Format de l'arborescence des périphériques (comment écrire)
Je pense qu'il est bon de le comprendre en le divisant en deux parties. Ici, nous allons nous concentrer sur «l'écriture (format) de l'arborescence des périphériques». Les informations à écrire dans l'arborescence des périphériques dépendent des informations dont le pilote de périphérique Linux a besoin. À la fin de cet article, je vais vous donner une brève introduction.
** À propos du fichier dts, **
est. Pour plus de détails, veuillez consulter le lien ci-dessous. https://elinux.org/Device_Tree_Usage
3.2 Node
format de nœud
[label:] node-name[@unit-address] {
[properties definitions]
[child nodes]
}
--device est représenté comme un nœud --node a une propriété et un nœud (nœud enfant)
--node name Définit le nom au format @ unit-address, et définit le contenu du nœud dans le crochet central suivant {} --La partie adresse-unité décrit l'adresse spécifiée par la propriété reg en hexadécimal. Même s'il existe plusieurs périphériques avec le même nom de nœud, ils peuvent être distingués par des adresses d'unité. L'adresse d'unité n'est pas requise pour les nœuds qui n'ont pas de propriété reg. Linux dtc peut être compilé sans adresse d'unité (bien qu'un avertissement apparaisse)
/ {...};
--La structure de l'arborescence des nœuds (nœud parent - relation des nœuds enfants) est décrite de manière à indiquer l'état de connexion du périphérique tel que vu de la CPU (par exemple, le pont de bus est le parent et SlaveDevice connecté au pont de bus est défini comme son nœud enfant. Faire)
--Si vous ajoutez une étiquette (étiquette :), vous pouvez spécifier le phandle de ce nœud en écrivant & label
. S'il est compilé avec l'option "- @", il peut être référencé à partir d'un autre fichier (fichier de superposition). (Voir aussi la description de la propriété phandle ci-dessous)3.3 Property --property est une combinaison de property-name = value --Il n'y a peut-être aucune valeur
[label:] property-name = value;
[label:] property-name ;
--Text String: Entourer entre guillemets compatibles = " arm, cortex-a9 ";
--Array / Cell-list: Un ensemble d'entiers non signés 32 bits séparés par des crochets angulaires <>
reg = <0xffd04000 0x1000>;
--Données binaires: séparées par des crochets [] mac-address = [12 34 56 ab cd ef];
--Données multiples: peuvent être concaténées en utilisant la virgule reg = <0xff900000 0x100000>, <0xffb80000 0x10000>;
mixed-property ="a string", [0x01 0x23 0x45 0x67], <0x12345678>;
compatible
La propriété la plus importante utilisée pour se connecter avec le pilote de périphérique.
Les périphériques qui nécessitent un pilote de périphérique ont besoin de cette propriété
La routine d'initialisation du pilote de périphérique avec une chaîne compatible qui correspond à la chaîne de caractères spécifiée par cette valeur est appelée et l'enregistrement du périphérique est effectué.
Une liste de chaînes de texte au format "fabricant, modèle".
Exemple: compatible =" altr, socfpga-stmmac "," snps, dwmac-3.70a "," snps, dwmac ";
status
Que ce soit pour activer ou non l'appareil.
La valeur est "ok" ou "désactivé"
phandle
Définir le numéro d'identification indiquant le nœud comme liste de cellules
Habituellement omis (en .dts écrit par l'homme)
Pour les nœuds où phandle est omis, le compilateur dtc génère automatiquement un identifiant unique, ajoute phandle et génère .dtb.
Vous pouvez spécifier le phandle d'un nœud avec l'étiquette «XXX» au format «<& XXX>». Souvent utilisé dans la description de la propriété d'interruption.
reg
Informations d'adresse de l'appareil. Spécifié par une paire de (cellules-adresse, cellules-taille). --Spécifiez l'adresse de base avec des cellules d'adresse et la taille de la mémoire (taille d'octet) avec des cellules de taille
Le nombre de cellules d'adresse et de cellules de taille est déterminé par les valeurs de # cellules d'adresse et de # cellules de taille sur le nœud parent.
#address-cells, #size-cells --Défini par le nœud avec le nœud enfant. Définit la manière dont le nœud enfant est attaché. Cela détermine comment spécifier l'adresse dans les plages de la hiérarchie et la propriété reg de la hiérarchie enfant.
Le nombre de cellules addres dans la propriété reg du nœud enfant, généralement 1. 2 si vous avez plusieurs maîtres de bus (spécifiés par numéro de bus et adresse). L'adresse 64 bits est 2.
ranges --Définissez le nœud représentant le bus et spécifiez la méthode de conversion d'adresse entre vous et le nœud enfant.
<Valeur des cellules d'adresse enfant, valeur des cellules d'adresse parent, valeur des cellules taille enfant> --S'il n'a pas de valeur, cela signifie que le nœud parent et le nœud enfant sont dans le même espace d'adressage.
#address-cells,Exemple d'utilisation de renges
/{
....
sopc0: sopc@0 {
ranges;
/*
sopc@0 (Parent) et bridge@Relation de 0xc0000000 (enfant)
sopc@0 et pont@0xc0000000 a le même espace mémoire (pas de traduction d'adresse).
*/
#address-cells = <1>;
#size-cells = <1>;
....
hps_0_bridges: bridge@0xc0000000 {
reg = <0xc0000000 0x20000000>,
<0xff200000 0x00200000>;
/*
bridge@0xc0000000 est un espace mémoire de 0xc0000000 à la taille 0x20000000,
Dispose de deux zones de mémoire avec un espace mémoire de 0xff200000 à 0x00200000
*/
#address-cells = <2>;
#size-cells = <1>;
/*
bridge@Le nœud enfant de 0xc0000000 est l'adresse-les cellules sont deux nombres de 32 bits, taille-la cellule est représentée par une valeur numérique de 32 bits.
*/
ranges = < 0x00000000 0x00000000 0xc0000000 0x00010000 >,
< 0x00000001 0x00020000 0xff220000 0x00000008 >,
< 0x00000001 0x00010040 0xff210040 0x00000020 >;
/*
La zone de mémoire de 0xc0000000 à la taille 0x00010000 est l'adresse du nœud enfant.<0x00000000 0x00000000>Attribué à la taille 0x00010000 à partir de
La zone de mémoire de 0xff220000 à la taille 0x00000008 est l'adresse du nœud enfant.<0x00000001 0x00020000>Attribué à la taille 0x00000008 à partir de
La zone de mémoire de 0xff210040 à la taille 0x00000020 est l'adresse du nœud enfant.<0x00000001 0x00010040>Attribuer à la taille 0x00000020 à partir de
(Les autres zones ne sont pas allouées aux nœuds enfants).
*/
....
led_pio: gpio@0x100010040 {
compatible = "altr,pio-16.0", "altr,pio-1.0";
reg = <0x00000001 0x00010040 0x00000020>;
/*
gpio@0x10001004 est<0x00000001 0x00010040>À partir de la taille 0x00000020
A une zone de mémoire, mais c'est le parent(Upper) Taille de 0xff210040 du nœud
Correspond à la zone de mémoire 0x00000020(0xff210040 du CPU-Accessible dans une gamme de 60).
*/
....
}; //end gpio@0x100010040 (led_pio)
....
}; //end bridge@0xc0000000 (hps_0_bridges)
};
};
À cet égard, il est préférable de lire la documentation Kernel Source. À titre d'exemple, jetons un coup d'œil à la description d'un nœud qui a les interruptions suivantes.
intc: intc@fffed000 {
compatible = "arm,cortex-a9-gic";
#interrupt-cells = <3>;
interrupt-controller;
....
};
soc {
interrupt-parent = <&intc>;
....
i2c0: i2c@ffc04000 {
....
interrupts = <0 158 0x4>;
....
};
};
Dans le code ci-dessus, la propriété interruptions de i2c @ ffc04000 se compose de 3 cellules, mais comment savoir quoi écrire dans ces 3 nombres. Recherchez "arm, cortex-a9-gic", qui est une chaîne compatible d'interruption-controller, dans le fichier sous le répertoire Documentation / devicetree / bindings de Kernel Source (exemple: find Documentation / devicetree / bindings -name" *. txt "| xargs grep" arm, cortex-a9-gic "
, git grep" arm, cortex-a9-gic "--Documentation / devicetree / bindings
si vous avez apporté la source du noyau avec git). Cela va frapper Documentation / devicetree / bindings / interrupt-controller / arm, gic.txt. En regardant le contenu de ce fichier, # interrupt-cells est défini sur 3 et le contenu de chacun est
Il est déclaré être. <0 158 4> dans le code ci-dessus est
Aussi, si vous voulez en savoir plus sur la façon d'écrire .dts en général, vous pouvez lire Documentation / devicetree / booting-without-of.txt dans le dossier Documentation de Linux Source.
En tant que nœud obligatoire
- root node
- /cpus node
- /cpus/* nodes
- /memory node(s)
- /chosen node
- /soc
C'est tout.
https://elinux.org/Device_Tree_Usage https://elinux.org/Device_Tree_presentations_papers_articles https://devicetree-specification.readthedocs.io/ https://git.kernel.org/?p=/linux/kernel/git/torvalds/linux.git;a=blob_plain;f=Documentation/devicetree https://www.nds-osk.co.jp/forum/freedownload/08/casestudy2/DeviceTree2.pdf
Recommended Posts