@Vengineerの戯言 : Twitter
SystemVerilogの世界へようこそ、すべては、SystemC v0.9公開から始まった
Apple M1 Mac mini の PCIe 関連
dts ファイル では、次の部分が PCIe 部分になります。
デバイスドライバは、apple,pcie-m1 で、ここ にあります。
pcie: pcie@690000000 {
compatible = "apple,pcie-m1";
reg = <0x6 0x90000000 0x0 0x1000000 /* config */
0x6 0x80000000 0x0 0x100000 0x6 0x8c000000 0x0 0x100000 /* core and AXI bridge */
0x6 0x81000000 0x0 0x20000 0x6 0x82000000 0x0 0x20000 0x6 0x83000000 0x0 0x20000>; /* ports */
interrupt-parent = <&aic>;
interrupts = <0 695 4 0 698 4 0 701 4 /* state */
0 704 1 0 705 1 0 706 1 0 707 1 0 708 1 0 709 1 0 710 1 0 711 1 /* MSI */
0 712 1 0 713 1 0 714 1 0 715 1 0 716 1 0 717 1 0 718 1 0 719 1
0 720 1 0 721 1 0 722 1 0 723 1 0 724 1 0 725 1 0 726 1 0 727 1
0 728 1 0 729 1 0 730 1 0 731 1 0 732 1 0 733 1 0 734 1 0 735 1>;
clocks = <&pcie_gp_clk &pcie_clk &pcie_refclk>;
clock-names = "core", "aux", "ref";
pinctrl-0 = <&pcie_clkreq_pins>;
pinctrl-names = "default";
perst-gpios = <&gpio 152 0 &gpio 153 0 &gpio 33 0>;
clkreq-gpios = <&gpio 150 0 &gpio 151 0 &gpio 32 0>;
devpwr-gpios = <&smc 13 0>;
devpwr-on-0 = <0 1>;
devpwr-on-1 = <>;
devpwr-on-2 = <>;
#address-cells = <3>;
#size-cells = <2>;
#interrupt-cells = <1>;
device_type = "pci";
msi-controller;
msi-parent = <&pcie>;
msi-doorbell = <0x0 0xfffff000>;
ranges = <0x43000000 0x6 0xa0000000 0x6 0xa0000000 0x0 0x20000000
0x02000000 0x0 0xc0000000 0x6 0xc0000000 0x0 0x40000000>;
bus-range = <0x00 0x0f>;
iommu-map = <0x0000 &pcie_dart0 0x8000 0x0100>, /* fake, and should never be used as RC bridges don't DMA */
<0x0100 &pcie_dart0 0x0000 0x0100>,
<0x0200 &pcie_dart1 0x0000 0x0100>,
<0x0300 &pcie_dart2 0x0000 0x0100>;
refclk-always-on-2;
max-speed-2 = <1>; /* 2.5 GT/s */
};アドレス空間は、この部分で、全部で6個です。最初の 0x6_9000_0000 からの 16MB は PCI Configuration 空間です。2番目の 0x6_8000_0000 からの 1MB と 0x6_8c00_0000 からの1MBが PCIe RootComplexのコアと AXI bridge 回路用です(もしこれが本当なら 内部バスは、AXI なんですね)。最後の3つはポートで、0x6_8100_0000, 0x6_8200_0000, 0x6_8300_0000 でそれぞれ128KBの空間です。
reg = <0x6 0x90000000 0x0 0x1000000 /* config */
0x6 0x80000000 0x0 0x100000 0x6 0x8c000000 0x0 0x100000 /* core and AXI bridge */
0x6 0x81000000 0x0 0x20000 0x6 0x82000000 0x0 0x20000 0x6 0x83000000 0x0 0x20000>; /* ports */次の2つは、割り込み関連です。interrupt-parent は、PCIe から出る割り込み線がどこに繋がっているかを示しています。aic に繋がっています。
割り込み線は、全部で35本出ています。最初の3個(0 695 4 0 698 4 0 701 4)は、この回路の割り込み用です。残りの32個は、MSI用の割り込み線です。
interrupt-parent = <&aic>;
interrupts = <0 695 4 0 698 4 0 701 4 /* state */
0 704 1 0 705 1 0 706 1 0 707 1 0 708 1 0 709 1 0 710 1 0 711 1 /* MSI */
0 712 1 0 713 1 0 714 1 0 715 1 0 716 1 0 717 1 0 718 1 0 719 1
0 720 1 0 721 1 0 722 1 0 723 1 0 724 1 0 725 1 0 726 1 0 727 1
0 728 1 0 729 1 0 730 1 0 731 1 0 732 1 0 733 1 0 734 1 0 735 1>;aic は、apple,aic で アドレス空間 (0x2_3b10_0000 から32KB)で、fast-ipi オプションが設定されています。
aic: interrupt-controller@23b100000 {
compatible = "apple,aic";
#interrupt-cells = <3>;
interrupt-controller;
reg = <0x2 0x3b100000 0x0 0x8000>;
fast-ipi;
};MSIは、下記の部分です。msi-doorbel は、ドアベル用の64ビットアドレスでここでは、0x_ffff_f000 を設定しています。
msi-controller;
msi-parent = <&pcie>;
msi-doorbell = <0x0 0xfffff000>;下記の ranges の部分は、アドレス変換です。
- 1番目のエントリは、non-prefetchable 32-bit アドレス(0x4300_0000)、64-bitアドレス(0x6_0xa000_0000)は、0x6_a000_0000 から512MBに
- 2番目のエントリは、non-prefetchable 32-bit アドレス(0x0200_0000)、64-bitアドレス(0x0_0xc000_0000)は、0x6_c000_0000 から1GBに
マッピングされます。
ranges = <0x43000000 0x6 0xa0000000 0x6 0xa0000000 0x0 0x20000000
0x02000000 0x0 0xc0000000 0x6 0xc0000000 0x0 0x40000000>;次は、クロック部分です。3つのクロックが接続していて、core, aux, ref という名前が付いています。
clocks = <&pcie_gp_clk &pcie_clk &pcie_refclk>;
clock-names = "core", "aux", "ref";3つのクロック、pcie_gp_clk, pcie_clk, pcie_refclk は、次のような接続になっています。refclk100mhz (100MHzのクロックから)、pcie_refclk と imx_clk に接続しています。この pcie_reflk と imx_clk は、apple,pmgr-clk-gate が示すように、Gated Clock です。ここでクロックを止めることができます。pcie_refclk は、pcie に接続されています。imx_clk は、pcie_clk に繋がっています。ここでも apple,pmgr-clk-gate なので Gated Clock になります。この pcie_clk も pcie に接続しています。そして、pcie_gp_clk を経由して、pcie と pcie_dart0, 1, 2 に接続しています。pcie_gp_clk も Gated Clockになります。Gated Clockにすることで使っていない場合は、この部分を Off にすればいいだけです。Apple M1 Mac mini は PCIe を使っていますが、Apple M1 Macbook Air と Apple M1 Macbook Pro では PCIe を使っていないのでこの大本となる pcie_refclk と pcie_clk を Off にしていると思います。
- refclk100mhz
次の perst-gpios は、PCIe の PERST の制御に使うものだと思います。3つありますので、ポートはやっぱり、3ポートなんでしょうね。
perst-gpios = <&gpio 152 0 &gpio 153 0 &gpio 33 0>;
次の clkreq-gpios は、クロックに関係する何かなんではないでしょうか?
clkreq-gpios = <&gpio 150 0 &gpio 151 0 &gpio 32 0>;
gpio の 150, 151, 32 は、gpio:pinctrl にも、pcie_clkreq_pins: pcie_clkreq_pins とあります。
gpio: pinctrl@23c100000 {
compatible = "apple,gpio-v0";
reg = <0x2 0x3c100000 0x0 0x100000>;
pin-count = <212>;
interrupts = <0 190 4 0 191 4 0 192 4 0 193 4 0 194 4 0 195 4 0 196 4>;
clocks = <&gpio_clk>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
i2c0_pins: i2c0_pins {
pins = "gpio192", "gpio188";
function = "periph";
};
pcie_clkreq_pins: pcie_clkreq_pins {
pins = "gpio150", "gpio151", "gpio32";
function = "periph";
};
};次の devpwr-gpios と devpwr-on-X は電源関連だと思います。
devpwr-gpios = <&smc 13 0>;
devpwr-on-0 = <0 1>;
devpwr-on-1 = <>;
devpwr-on-2 = <>;下記のコードにあるように、ポート番号(0, 1, 2) の内、0のみ、<0 1> を設定しています。ポート番号0のみ電源をONにするのでしょうか?
sprintf(name, "devpwr-on-%d", i); ret = of_property_count_elems_of_size(node, name, 8); pcie->devpwron[i].num = ret; if(ret <= 0) continue; pcie->devpwron[i].seq = devm_kzalloc(dev, ret * 8, GFP_KERNEL); if(!pcie->devpwron[i].seq) return -ENOMEM; ret = of_property_read_variable_u32_array(node, name, pcie->devpwron[i].seq, ret * 2, ret * 2); if(ret < 0) return ret;
bus-range は、PCIe の バス番号は 0x00から0x0f、iommu-map は、pcie_dart0,1,2 に繋がっています。
bus-range = <0x00 0x0f>;
iommu-map = <0x0000 &pcie_dart0 0x8000 0x0100>, /* fake, and should never be used as RC bridges don't DMA */
<0x0100 &pcie_dart0 0x0000 0x0100>,
<0x0200 &pcie_dart1 0x0000 0x0100>,
<0x0300 &pcie_dart2 0x0000 0x0100>;
refclk-always-on-2;
max-speed-2 = <1>; /* 2.5 GT/s */refclk-always-on-2 と max-speed-2 は、PCIe のデバイスドライバ のこの部分でパースしています。refclk-always-on-2 は、2の部分をパースしています。
sprintf(name, "refclk-always-on-%d", i); pcie->refclk_always_on[i] = of_property_read_bool(node, name);
パースした値がポート番号なので、2番目のポートの REFCLK を設定しています。
if(!pcie->refclk_always_on[idx]) rmwl(PORT_REFCLK_CGDIS, 0, pcie->base_port[idx] + PORT_REFCLK); rmwl(PORT_APPCLK_CGDIS, 0, pcie->base_port[idx] + PORT_APPCLK);
また、max-speed-2 も 2 の部分をパースしています。この部分はポート番号はポート2に 1 (2.5GT/s、Gen1)を設定しています。設定していない場合はデフォルト値の 2 (5.0GT/s、Gen2)のようです。
sprintf(name, "max-speed-%d", i); if(of_property_read_u32(node, name, &pcie->max_speed[i]) < 0) pcie->max_speed[i] = 2;
結果的に、ポート0には電源を供給し、ポート0はGen2、ポート1はGen2、ポート2はGen1に設定しているようです。ポート2をGen1にしているのは接続しているデバイスがGen1対応のみだからでしょうか?