1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

MPFS-DISCO-KIT 向け Ubuntu22.04 のメモリマップ

Posted at

はじめに

筆者は MPFS-DISCO-KIT(Microchip PolarFire SoC FPGA Discovery Kit) で動作する Ubuntu 22.04 を独自に構築しています。この記事では、この MPFS-DISCO-KIT 向け Ubuntu 22.04 でのメモリマップを解説します。

MPFS-DISCO-KIT とは

MPFS-DISCO-KIT(Microchip PolarFire SoC FPGA Discovery Kit) は、Microchip Technology 社の PolarFire SoC FPGA(MPFS095T_1FCSG325E) を搭載した開発用のキットです。

  • PolarFire SoC FPGA with 95k LEs
  • 1GByte main memory
  • 1x Gigabit Ethernet
  • 3x UART
  • 1x micro-SD interface
  • form factor 4.1" x3.3"

詳細は次の URL を参照してください。

MPFS-DISCO-KIT 向け Ubuntu 22.04 とは

筆者は MPFS-DISCO-KIT で動作する Ubuntu 22.04 を独自に構築しています。以下の URL で公開しています。

なお、これらはオフィシャルなものではなく、筆者の魔改造がはいっています。ご利用の際はこの点にご留意してください。

PolarFire SoC の特徴

メモリマップを解説するにあたり、あらかじめ知っておいたほうが良い事項を説明します。

MSS(Micro Processor Sub System)

ブロック図

MSS(Micro Processor Sub System) は PolarFire SoC FPGA のうち、CPU Core Complex(U54 Core、U51 Core、L2 Cache、割り込み、TileLink)、 DDR Memory Controller、ENET、USB、各種ペリフェラル、AXI Switch をひとくくりにまとめたものです。だいたい次の図のような構成になっています。

Fig.1 PolarFire SoC MSS Blcok Diagram

Fig.1 PolarFire SoC MSS Blcok Diagram


MSS の各ブロックの詳細は『 PolarFire SoC MSS Technical Reference Manual』を参照してください。

PolarFire SoC のメモリマップ

CPU キャッシュが有効か否かは物理アドレスによって決まる

CPU Core Complex がメモリにアクセスする場合には次の3つのモードがあります。

  • Cached: CPU キャッシュが有効
  • Non-Cached: CPU キャッシュが無効かつ WCB(Write Combining Buffer) も無効
  • Non-Cached WCB: CPU キャッシュが無効だがWCB(Write Combining Buffer) は有効

これらのモードの切り替えは、物理アドレスによって決め打ちされています。

物理アドレスの下位と上位の二つのセグメントを持っている

CPU Core Complex がアクセスする領域は次の二つに分類しています。

  • Low: 物理アドレス 0x00_FFFF_FFFF 以下の領域
  • High: 物理アドレス0x01_0000_0000以上の領域

6つのメモリ領域の物理アドレスとサイズは固定

CPU Core Complex からみた DDR Memory へのアクセスは、Cached、Non-Cached、Non-Cached WCBの3通り × LowとHigh の2通りの合計6領域あり、PolarFire SoC では各々の物理アドレスとサイズは次のように決まっています。

Table.1 PolarFire SoC の DDR Memory Address Space

Name Memory Address Space
Start Address End Address Size
DDR-Cached Low 0x00_8000_0000 0x00_BFFF_FFFF 1GiB
DDR-Cached High 0x10_0000_0000 0x13_FFFF_FFFF 16GiB
DDR-Non-Cached Low 0x00_C000_0000 0x00_CFFF_FFFF 256MiB
DDR-Non-Cached High 0x14_0000_0000 0x17_FFFF_FFFF 16GiB
DDR-Non-Cached WCB Low 0x00_D000_0000 0x00_DFFF_FFFF 256MiB
DDR-Non-Cached WCB High 0x18_0000_0000 0x1B_FFFF_FFFF 16GiB

MPFS-DISCO-KIT の場合

MPFS-DISCO-KIT は 1GB の DDR-SDRAM が搭載されています。MPFS-DISCO-KIT 向け Ubuntu22.04 では、polarfire-soc-discovery-kit-reference-design を元にしており、このリファレンスデザインでは、上記6つの領域の DDR-SDRAM へのマッピングは次のように、すべて同じ開始アドレスが割り振られています。

Fig.2 MPFS-DISCO-KIT DDR-Memory Address Mapping

Fig.2 MPFS-DISCO-KIT DDR-Memory Address Mapping


つまり、MSS からみた物理アドレス上は異なる領域からのアクセスであっても、DDR-Memory 上は同一のアドレスの可能性があります。この点に注意して DDR-Memory を割り当てる必要があります。

デバイスツリーによるメモリマッピング

MPFS-DISCO-KIT 向け Ubuntu22.04 では DDR Memory の割り振りを Device Tree で行っています。この章ではこの Device Tree を詳細に説明します。

メモリ領域

MPFS-DISCO-KIT は1GB の DDR Memory を搭載しています。MPFS-DISCO-KIT 向け Ubuntu22.04 では、この1GB を次の5つのメモリ領域に分けて管理しています。

  • kernel: memory@80000000
  • ddr_cached_low: memory@8a000000
  • ddr_non_cached_low: memory@c4000000
  • ddr_cached_high: memory@1022000000
  • ddr_non_cached_high: memory@1412000000

これらの設定は Device Tree (mpfs-disco-kit.dts) で行っています。mpfs-disco-kit.dts のメモリ領域に関する記述を取り出すと次の通りです。

mpfs-disco-kit.dts
	kernel: memory@80000000 {
		device_type = "memory";
		reg = <0x0 0x80000000 0x0 0x4000000>;
	};
	ddr_cached_low: memory@8a000000 {
		device_type = "memory";
		reg = <0x0 0x8a000000 0x0 0x8000000>;
	};
	ddr_non_cached_low: memory@c4000000 {
		device_type = "memory";
		reg = <0x0 0xc4000000 0x0 0x6000000>;
	};
	ddr_cached_high: memory@1022000000 {
		device_type = "memory";
		reg = <0x10 0x22000000 0x0 0x1e000000>;
	};
	ddr_non_cached_high: memory@1412000000 {
		device_type = "memory";
		reg = <0x14 0x12000000 0x0 0x10000000>;
	};

この節ではこれらのメモリ領域について解説します。

kernel: memory@80000000

Kernel は MSS アドレス空間のDDR-Cached Low 領域に配置されます。

kernel のMSS からみた開始アドレスは 0x00_8000_0000 で、領域の大きさは 0x0400_0000 です。DDR Memory からみた開始アドレスは0x0000_0000 になります。

この領域は U-Boot などブート時に Linux Kernel が配置されます。ブート後は、Linux Kernel の実行バイナリおよび各種ヒープに使用されます。

mpfs-disco-kit.dts
	kernel: memory@80000000 {
		device_type = "memory";
		reg = <0x0 0x80000000 0x0 0x4000000>;
	};

Fig.3 kernel: memory@80000000

Fig.3 kernel: memory@80000000


ddr_cached_low: memory@8a000000

ddr_cached_low は MSS アドレス空間のDDR-Cached Low 領域に配置されます。

ddr_cached_low の開始アドレスは 0x00_8a00_0000 で、領域の大きさは 0x0800_0000 です。DDR Memory からみた開始アドレスは0x0a00_0000 になります。

この領域はブート時には Device Tree Blob が一時的にロードされます。また、Linux 起動後はユーザープログラムの実行などに使用されます。

mpfs-disco-kit.dts
	ddr_cached_low: memory@8a000000 {
		device_type = "memory";
		reg = <0x0 0x8a000000 0x0 0x8000000>;
	};

Fig.4 ddr_cached_low: memory@8a000000

Fig.4 ddr_cached_low: memory@8a000000


ddr_non_cached_low: memory@c4000000

ddr_non_cached_low は MSS アドレス空間のDDR-Non-Cached Low 領域に配置されます。

ddr_non_cached_low の開始アドレスは 0x00_c400_0000 で、領域の大きさは 0x0600_0000 です。DDR Memory からみた開始アドレスは0x0a00_0000 になります。

mpfs-disco-kit.dts
	ddr_non_cached_low: memory@c4000000 {
		device_type = "memory";
		reg = <0x0 0xc4000000 0x0 0x6000000>;
	};

Fig.5 ddr_non_cached_low: memory@c4000000

Fig.5 ddr_non_cached_low: memory@c4000000


ddr_cached_high: memory@1022000000

ddr_cached_high は MSS アドレス空間のDDR-Cached High 領域に配置されます。

ddr_cached_high の開始アドレスは 0x10_2200_0000 で、領域の大きさは 0x1e00_0000 です。DDR Memory からみた開始アドレスは0x2200_0000 になります。

この領域はユーザープログラムの実行などに使用されます。

mpfs-disco-kit.dts
	ddr_cached_high: memory@1022000000 {
		device_type = "memory";
		reg = <0x10 0x22000000 0x0 0x1e000000>;
	};

Fig.6 ddr_cached_high: memory@1022000000

Fig.6 ddr_cached_high: memory@1022000000


ddr_non_cached_high: memory@1412000000

ddr_non_cached_high は MSS アドレス空間のDDR-Non-Cached High 領域に配置されます。

ddr_non_cached_high の開始アドレスは 0x14_1200_0000 で、領域の大きさは 0x1000_0000 です。DDR Memory からみた開始アドレスは0x1200_0000 になります。

この領域は DMA Buffer として使用されます。

mpfs-disco-kit.dts
	ddr_non_cached_high: memory@1412000000 {
		device_type = "memory";
		reg = <0x14 0x12000000 0x0 0x10000000>;
	};

Fig.7 ddr_non_cached_high: memory@1412000000

Fig.7 ddr_non_cached_high: memory@1412000000


予約されたメモリ領域

MPFS-DISCO-KIT 向け Ubuntu22.04 では 前節で割り振ったメモリ領域のうち、DMA Buffer などの特殊な用途専用にメモリ空間を予約しています。これらは Device Tree の reserved-memory ノードに記述されています。この節では、この予約されたメモリ領域の説明をします。

hss: hss-buffer@103fc00000

hss は メモリ領域 ddr_cached_high に予約されます。

hss の開始アドレスは 0x10_3fc0_0000 で、領域の大きさは 0x0020_0000 です。DDR Memory からみた開始アドレスは0x3fc0_0000 になります。

この領域は HSS と Linux Kernel との通信用バッファとして使用されます。

mpfs-disco-kit.dts
	reserved-memory {
		hss: hss-buffer@103fc00000 {
			compatible = "shared-dma-pool";
			reg = <0x10 0x3fc00000 0x0 0x200000>;
			no-map;
		};
	};

Fig.8 hss: hss-buffer@103fc00000

Fig.8 hss: hss-buffer@103fc00000


dma_non_cached_low: non-cached-low-buffer

dma_non_cached_low は メモリ領域 ddr_non_cached_low に予約されます。

dma_non_cached_low の開始アドレスは 0x00_c400_0000 で、領域の大きさは 0x0400_0000 です。DDR Memory からみた開始アドレスは0x0400_0000 になります。

この領域は DMA Buffer として使用されます。

mpfs-disco-kit.dts
	reserved-memory {
		dma_non_cached_low: non-cached-low-buffer {
			compatible = "shared-dma-pool";
			size = <0x0 0x4000000>;
			no-map;
			alloc-ranges = <0x0 0xc4000000 0x0 0x4000000>;
		};
	};

Fig.9 dma_non_cached_low: non-cached-low-buffer

Fig.9 dma_non_cached_low: non-cached-low-buffer


dma_non_cached_high: non-cached-high-buffer

dma_non_cached_high は メモリ領域 ddr_non_cached_high に予約されます。

dma_non_cached_high の開始アドレスは 0x14_1200_0000 で、領域の大きさは 0x1000_0000 です。DDR Memory からみた開始アドレスは0x1200_0000 になります。

この領域は DMA Buffer に使われます。特に linux,dma-default プロパティが設定されているため、各種デバイスドライバが DMA Buffer を確保する際は優先的にこの領域が使われます。

mpfs-disco-kit.dts
	reserved-memory {
		dma_non_cached_high: non-cached-high-buffer {
			compatible = "shared-dma-pool";
			size = <0x0 0x10000000>;
			no-map;
			linux,dma-default;
			alloc-ranges = <0x14 0x12000000 0x0 0x10000000>;
		};
	};

Fig.10 dma_non_cached_high: non-cached-high-buffer

Fig.10 dma_non_cached_high: non-cached-high-buffer


fabricbuf0ddrc: buffer@88000000

fabricbuf0ddrc は メモリ領域 ddr_non_cached_low に予約されます。

fabricbuf0ddrc の開始アドレスは 0x00_8800_0000 で、領域の大きさは 0x0020_0000 です。DDR Memory からみた開始アドレスは0x0800_0000 になります。

ここで話がややこしくなるのですが、DDR Memory の領域上は ddr_non_cached_low にあるのですが、MSS アドレス空間上のアドレスは DDR-Cached Low にあることです。したがって、ここへのアクセスは、キャッシュが有効になります。また、後述の fabricbuf1ddrnc や fabricbuf2ddrncwcb と DDR-Memory 上のメモリ領域を共有しています。

mpfs-disco-kit.dts
	reserved-memory {
		fabricbuf0ddrc: buffer@88000000 {
			compatible = "shared-dma-pool";
			reg = <0x0 0x88000000 0x0 0x2000000>;
			no-map;
		};
	};

Fig.11 fabricbuf0ddrc: buffer@88000000

Fig.11 fabricbuf0ddrc: buffer@88000000


fabricbuf1ddrnc: buffer@c8000000

fabricbuf1ddrnc は メモリ領域 ddr_non_cached_low に予約されます。

fabricbuf1ddrnc の開始アドレスは 0x00_C800_0000 で、領域の大きさは 0x0020_0000 です。DDR Memory からみた開始アドレスは0x0800_0000 になります。

DDR Memory の領域上は ddr_non_cached_low にあり、MSS アドレス空間上のアドレスは DDR-Non-Cached Low にあります。したがって、ここへのアクセスは、キャッシュが無効になります。

また、前述の fabricbuf0ddrc や後述の fabricbuf2ddrncwcb と DDR-Memory 上のメモリ領域を共有しています。

mpfs-disco-kit.dts
	reserved-memory {
		fabricbuf1ddrnc: buffer@c8000000 {
			compatible = "shared-dma-pool";
			reg = <0x0 0xc8000000 0x0 0x2000000>;
			no-map;
		 };
	};

Fig.12 fabricbuf1ddrnc: buffer@c8000000

Fig.12 fabricbuf1ddrnc: buffer@c8000000


fabricbuf2ddrncwcb: buffer@d8000000

fabricbuf2ddrncwcb は メモリ領域 ddr_non_cached_low に予約されます。

fabricbuf2ddrncwcb の開始アドレスは 0x00_D800_0000 で、領域の大きさは 0x0020_0000 です。DDR Memory からみた開始アドレスは0x0800_0000 になります。

DDR Memory の領域上は ddr_non_cached_low にありますが、MSS アドレス空間上のアドレスは DDR-Non-Cached WCB Low にあります。したがって、ここへのアクセスは、キャッシュが無効になりますが WCB(Write Combining Buffer) は有効になります。

また、前述の fabricbuf0ddrc や fabricbuf1ddrnc と DDR-Memory 上のメモリ領域を共有しています。

mpfs-disco-kit.dts
	reserved-memory {
		fabricbuf2ddrncwcb: buffer@d8000000 {
			compatible = "shared-dma-pool";
			reg = <0x0 0xd8000000 0x0 0x2000000>;
			no-map;
		};
	};

Fig.13 fabricbuf2ddrncwcb: buffer@d8000000

Fig.13 fabricbuf2ddrncwcb: buffer@d8000000


ペリフェラル各種からみたメモリマップ

デバイスツリー

PolarFire SoC の MSS には、CPU Core Complex 以外にも ENET や USB などの各種ペリフェラルがあります。これらのペリフェラルは mpfs.dtsi という Device Tree で soc ノードの配下として定義されています。一部を抜粋すると次のようになっています。実際には mac0 の他にも gpio や spi 等の各種ペリフェラルが定義されています。

mpfs.dtsi
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/* Copyright (c) 2020-2021 Microchip Technology Inc */
/dts-v1/;
#include "dt-bindings/clock/microchip,mpfs-clock.h"
/ {
	#address-cells = <2>;
	#size-cells = <2>;
	model = "Microchip PolarFire SoC";
	compatible = "microchip,mpfs";
	:
	(中略)
	:
	soc {
		#address-cells = <2>;
		#size-cells = <2>;
		compatible = "simple-bus";
		ranges;
		:	
		(中略)
		:
		mac0: ethernet@20110000 {
			compatible = "microchip,mpfs-macb", "cdns,macb";
			reg = <0x0 0x20110000 0x0 0x2000>;
			#address-cells = <1>;
			#size-cells = <0>;
			interrupt-parent = <&plic>;
			interrupts = <64>, <65>, <66>, <67>, <68>, <69>;
			local-mac-address = [00 00 00 00 00 00];
			clocks = <&clkcfg CLK_MAC0>, <&clkcfg CLK_AHB>;
			clock-names = "pclk", "hclk";
			resets = <&mss_top_sysreg CLK_MAC0>;
			status = "disabled";
		};
		:	
		(中略)
		:
	};
};

mpfs.dtsi は MPFS(Microchip PolarFire SoC) 共通のデバイスツリーです。各種ボード固有のデバイスツリーは、この mpfs.dtsi をインクルードして、個別の定義を追加します。例えば、MPFS-DISCO-KIT のデバイスツリーは次のようになっています。

mpfs-disco-kit.dts
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/* Copyright (c) 2020-2021 Microchip Technology Inc */
/dts-v1/;
#include "mpfs.dtsi"
#include "mpfs-disco-kit-fabric.dtsi"
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/leds/common.h>
/* Clock frequency (in Hz) of the rtcclk */
#define RTCCLK_FREQ		   1000000
/ {
	#address-cells = <2>;
	#size-cells = <2>;
	model = "Microchip PolarFire-SoC Discovery Kit";
	compatible = "microchip,mpfs-disco-kit", "microchip,mpfs";
	soc {
		dma-ranges = <0x14 0x0 0x0 0x80000000 0x0 0x4000000>,
			     <0x14 0x4000000 0x0 0xc4000000 0x0 0x6000000>,
			     <0x14 0xa000000 0x0 0x8a000000 0x0 0x8000000>,
			     <0x14 0x12000000 0x14 0x12000000 0x0 0x10000000>,
			     <0x14 0x22000000 0x10 0x22000000 0x0 0x1e000000>;
	};
	:
	(中略)
	:
};
:
(中略)
:
&mac0 {
	dma-noncoherent;
	status = "okay";
	phy-mode = "sgmii";
	phy-handle = <&phy0>;
	phy0: ethernet-phy@b {
		reg = <0xb>;
	};
};
:
(後略)
:

mpfs-disco-kit.dts では mac0 のノードに次のような変更を加えています。

  • status プロパティに "okay" を上書きして mac0 ノードを有効化
  • phy0 ノードを追加して PHY デバイスドライバと接続
  • dma-noncoherent プロパティを追加(詳細は次々節)

これらの変更により MPFS-DISCO-KIT でmac0 を使えるようにしています。

CPUからみたメモリマップとの違い

もうひとつの留意点は soc ノードの dma-ranges プロパティです。dma-ranges は2セルの dma-address、2セルの cpu-address、2セルの size を一組とした dma-range を複数記述したものです。mpfs-disco-kit.dts では次のようになっています。

Table.2 MPFS-DISCO-KIT の soc の dma-ranges

dma address cpu address Size
0x14_0000_0000 0x00_8000_0000 64MiB
0x14_0400_0000 0x00_c400_0000 96MiB
0x14_0a00_0000 0x00_8a00_0000 128MiB
0x14_1200_0000 0x14_1200_0000 256MiB
0x14_2200_0000 0x10_2200_0000 480MiB

dma-ranges は CPU からみたアドレスと DMA デバイスからみたアドレスが異なる場合に指定されるプロパティです。上記の dma-ranges が何を意味するかというと、CPU からみたアドレスとサイズは、それぞれメモリ領域で説明した kernel、ddr_non_cached_low、ddr_cached_low、ddr_non_cached_high、ddr_cached_high に相当しますが、DMA デバイスからみたアドレスは全て DDR-Non-Cached High に対応しています。これらを表で示すと次のようになります。

Table.3 MPFS-DISCO-KIT の CPU メモリマップと SoC メモリマップの対応

Memory Map(CPU) Memory Map(DMA Device)
memory range cpu address memory range dma address
kernel 0x00_8000_0000 DDR-Non-Cached High 0x14_0000_0000
ddr_non_cached_low 0x00_c400_0000 0x14_0400_0000
ddr_cached_low 0x00_8a00_0000 0x14_0a00_0000
ddr_non_cached_high 0x14_1200_0000 0x14_1200_0000
ddr_cached_high 0x10_2200_0000 0x14_2200_0000

CPU が確保した DMA Buffer がどのメモリ領域であっても DMA Device からみたメモリ領域はすべて DDR-NonCached Highに配置されています。このことは、キャッシュのコヒーレンシ—に注意しなければならないことを意味します。

キャッシュのコヒーレンシーに注意

PolarFire SoC の MSS ではキャッシュのコヒーレンシ—は TileLink によって自動的に保証されます。

Fabricや各種ペリフェラルがメモリにアクセスする際は一旦 AXI Switch を通します。AXI Switch は与えられたアドレスによってどのスレーブポートにアクセスするか決まります。『PolarFire SoC MSS Technical Reference Manual』の「Table 3-35. Address Ranges of Slaves」では次のようになっています。

Table.4 Address Range of Slaves (PolarFire SoC MSS Technical Reference Manual)

Slave Port Region 1 Region 2 Region 3
Start End Start End Start End
S1 0x20_0000_0000 0x2F_FFFF_FFFF 0x00_6000_0000 0x00_7FFF_FFFF - -
S2 0x30_0000_0000 0x3F_FFFF_FFFF 0x00_E000_0000 0x00_FFFF_FFFF - -
S3 0x00_4000_0000 0x00_5FFF_FFFF - - - -
S4 0x00_2200_0000 0x00_2201_FFFF - - - -
S5 0x00_2000_0000 0x00_21FF_FFFF - - - -
S6 0x00_2800_0000 0x00_2FFF_FFFF - - - -
S7 0x14_0000_0000 0x1B_FFFF_FFFF 0x00_C000_0000 0x00_DFFF_FFFF - -
S8 0x10_0000_0000 0x13_FFFF_FFFF 0x00_8000_0000 0x00_BFFF_FFFF 0x00_0000_0000 0x00_1FFF_FFFF
S9 0x00_2300_0000 0x00_2303_FFFF - - - -

DDR Memory に対するアクセスはアドレスによってS7(DDR Memory に直接アクセス)か S8(TileLinkを経由して DDR Memory にアクセス) かが選択されます。S8が選択された場合(TileLink を経由する場合)は、キャッシュのコヒーレンシーは TileLink によって自動的に保証されますが、S7 が選択された場合(DDR Memory に直接アクセス)は、キャッシュのコヒーレンシーは自動的に保証されません。

Fig.14 CPU Cached Access and Peripheral Non-Cached Access

Fig.14 CPU Cached Access and Peripheral Non-Cached Access


したがって、S7 が選択された場合はキャッシュのコヒーレンシーはソフトウェアで保証する必要があります。具体的には Peripheral が DMA Buffer にアクセスする前後でCPUが明示的にキャッシュと DDR Memory と同期します。

そのために、デバイスツリーの soc ノード配下の DMA を行うデバイスには dma-noncoherent プロパティを定義して、キャッシュのコヒーレンシをソフトウェアで保証することを明示しなければなりません。

Linux のキャッシュコヒーレンシの詳細は別記事にまとめているので、[参考]の[Linux のキャッシュコヒーレンシーに関する記事]を参照してください。

参考

MPFS(Microchip PolarFire SoC) の資料

MPFS-DISCO-KIT(Microchip PolarFire SoC FPGA Discovery Kit) の資料

MPFS-DISCO-KIT 向け Ubuntu22.04 の記事

Linux のキャッシュコヒーレンシーに関する記事

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?