Forum Discussion

dpeng's avatar
dpeng
Icon for New Contributor rankNew Contributor
4 months ago
Solved

enable bridge crashes Linux

Hi,

We selected a Cyclone V SoC FPGA for our project. I started on Terasic demo boards (DE0 and ADC-SoC). On these boards, that both bear a Cyclone V (P/N 5CSEMA4U23C6N), I could, with a devicetree overlay, program the FPGA from Linux and enable the lwh2f and h2f bridges.

Now that we are developing a custom board, we bought an Enclustra SA2 SoM, with a Cyclone V (P/N 5CSTFD6D5F31I7N).

I am trying to apply the DT overlay on socfpga.dtsi.

/dts-v1/;
/plugin/;

/ {
	fragment@0 {
		target = <&base_fpga_region>;

		// #address-cells = <0x1>;
		// #size-cells = <0x1>;

		__overlay__ {
			#address-cells = <0x1>;
			#size-cells = <0x1>;
			ranges = <

			// The .rbf file must be placed in /lib/firmware
			firmware-name = "soc_firwmare.rbf";
			fpga-bridges = <&fpga_bridge0 &fpga_bridge1>;
		};
	};

	/* Enable the lightweight FPGA to HPS bridge (lwhps2fpga) */
	fragment@1 {
		target = <&fpga_bridge0>;

		__overlay__ {
			status = "okay";
			bridge-enable = <1>;
		};
	};

	/* Enable the HPS to FPGA bridge (hps2fpga) */
	fragment@2 {
		target = <&fpga_bridge1>;

		__overlay__ {
			status = "okay";
			bridge-enable = <1>;
		};
	};
};

But since I switched to the SA2 module, the board freezes when `fragment@1` or `fragment@2` is not commented in the overlay.

If I comment out the `status = "okay"` lines, the board does boot and the FPGA is programmed. By dumping the live tree, I can see that the `bridge-enable` property appears under the expected node.

dtc gives no warning nor errors.

I added some debug messages ("DEBUG >>") in the kernel code, and I could see that the crash happens in some function called by regmap_write(), in regmap.c.

[    2.632673] altera_hps2fpga_bridge ff400000.fpga_bridge: enabling bridge
[    2.639397] altera_hps2fpga_bridge ff400000.fpga_bridge: DEBUG >> Before _alt_hps2fpga_enable_set()
[    2.648424] _alt_hps2fpga_enable_set() DEBUG >> bridge brought out of reset
[    2.655377] _alt_hps2fpga_enable_set() DEBUG >> make bridge visible to L3 masters
[    2.662832] _alt_hps2fpga_enable_set() DEBUG >> spinlock acquired
[    2.668902] _alt_hps2fpga_enable_set() DEBUG >> before regmap_write()
[    2.675315] regmap_write() DEBUG >> start of regmap_write()
[    2.680865] regmap_write() DEBUG >> lock acquired
[    2.685550] _regmap_write() DEBUG >> start
[    2.689632] _regmap_write() DEBUG >> writable
[    2.693971] _regmap_write() DEBUG >> before reg_write()
[    2.699173] _regmap_write() context=0xc18d2e00, reg=0, val=0x00000011
[    2.705598] _regmap_bus_reg_write() DEBUG >> start
[    2.710371] _regmap_bus_reg_write() after _regmap_range_lookup()
[    2.716352] _regmap_bus_reg_write() DEBUG >> after regmap_reg_addr()
[    2.722679] _regmap_bus_reg_write() DEBUG >> map->bus_context=0xc1b31980, reg=0, val=0x00000011

Now, I'm really stuck.

  • So, I think I made some progress.

    1. I enable the bridges in Barebox by setting the status and bridge-enable properties.
    2. In the Linux devicetree overlay, I only set the status property, not the bridge-enable property.

    The Barebox DT (the "0x1" syntax matters, it seems):

    &fpga_bridge0 {
    	status = "okay";
    	bridge-enable = <0x1>;
    };

    The Linux DT overlay:

    /dts-v1/;
    /plugin/;
    
    / {
    	fragment@0 {
    		target = <&base_fpga_region>;
    
    		__overlay__ {
    			#address-cells = <0x1>;
    			#size-cells = <0x1>;
    
    			// The .rbf file must be placed in /lib/firmware
    			firmware-name = "soc_firwmare.rbf";
    			fpga-bridges = <&fpga_bridge0 &fpga_bridge1>;
    		};
    	};
    
    	/* Enable the lightweight FPGA to HPS bridge (lwhps2fpga) */
    	fragment@1 {
    		target = <&fpga_bridge0>;
    
    		__overlay__ {
    			status = "okay";
    			// Don't set bridge-enable!
    			// bridge-enable = <1>;
    		};
    	};
    
    	/* Enable the HPS to FPGA bridge (hps2fpga) */
    	fragment@2 {
    		target = <&fpga_bridge1>;
    
    		__overlay__ {
    			status = "okay";
    			// Don't set bridge-enable!
    			// bridge-enable = <1>;
    		};
    	};
    };

    Then, I when I check the status of the bridges, I get what I expect:

    # for f in /proc/device-tree/soc/fpga?bridge*; do echo $(basename $f)":" $(cat $f/status); done
    fpga-bridge@ff600000: disabled
    fpga-bridge@ffc25080: disabled
    fpga_bridge@ff400000: okay
    fpga_bridge@ff500000: okay
    #

    I didn't try to communicate between the HPS and the FPGA yet, but it looks promising.

11 Replies

  • @dpeng

    I had tested H2F LWH2F and SDRAM2FPGA.

    No issue on 2024.07 2022.07 but i still cant solve the DMA req singles dead issue.

    Kernel 6.12.11.

    Both from official altera repository no modification.

    For basic register SDRAM burst r/w no issue.

    On UBOOT you can verify via md.l mw.l for fast sanity test.

    I suggest you confirm via apb simple register test on H2F an LWH2F, as far SDRAM2FPGA it is a bit tedious as it uses old AXI3. On HPS it will automatically insert bus translate no need to create HDL.


    ENJOY~

  • JitLoonL_Altera's avatar
    JitLoonL_Altera
    Icon for Occasional Contributor rankOccasional Contributor

    Hi @dpeng

    It looks like the board freeze occurs when the bridge drivers (lwhps2fpga/ hps2fpga) attempt to enable the bridges. Since FPGA programming works but enabling the bridges causes a hang, this is likely due to hardware configuration or base address mismatch between your Terasic boards and the Enclustra SA2 module.

    A few suggestions:

    1. Check bridge base addresses in your device tree against the Enclustra SA2 memory map; the addresses may differ from the DE0/ADC-SoC boards.

    2. Verify preloader / handoff settings – the bridges must be properly configured and clocked before enabling them.

    3. Enable one bridge at a time to isolate which one causes the hang.

    4. Reference Enclustra BSP,compare their provided socfpga.dtsi or device tree overlays for correct bridge configuration.

    Most hangs in regmap_write() indicate access to an unclocked or unmapped peripheral region. Once the bridge base addresses and clocks match your module, the overlay should work as expected.

    If possible, please share the live DT nodes for fpga_bridge0 and fpga_bridge1 after boot but before applying the overlay; that can help pinpoint the issue.

    • dpeng's avatar
      dpeng
      Icon for New Contributor rankNew Contributor

      Hi @JitLoonL_Altera

      About your suggestions:

      1. Aren't the addresses the same for the whole Cyclone V family?
      2. As Enclustra's BSP is really outdated (U-Boot and Linux), I've been working to port the SA2 SoM to Barebox. So, that's definitely something to look at. It copied the handoff files from Enclustra's reference design that matches my hardware. If I get it correctly, you say that Barebox DT must match Platform Designer settings? Can't the bridges be configured in Linux DT only?
      3. Sure. I posted the whole overlay to show what I'm trying to do.
      4. OK, I'll look at it.

      The live tree for nodes fpga_bridge0 and fpga_bridge1:

      // fpga_bridge0:
      		fpga_bridge@ff400000 {
      			compatible = "altr,socfpga-lwhps2fpga-bridge";
      			clocks = <0x05>;
      			resets = <0x06 0x61>;
      			status = "disabled";
      			phandle = <0x49>;
      			reg = <0xff400000 0x100000>;
      		};
      
      // fpga_bridge1:
      		fpga_bridge@ff500000 {
      			compatible = "altr,socfpga-hps2fpga-bridge";
      			clocks = <0x05>;
      			resets = <0x06 0x60>;
      			status = "disabled";
      			phandle = <0x4a>;
      			reg = <0xff500000 0x10000>;
      		};

      and the whole live DT: https://paste.debian.net/1392376/

  • dpeng's avatar
    dpeng
    Icon for New Contributor rankNew Contributor

    I noticed that in Platform Designer, the h2f_lw_axi_clock input signal takes its source from h2f_user2_clock. But the LW H2F bridge clock was &l4_main_clk. So I changed it in the Linux DT (not the overlay), like this:

    &fpga_bridge0 {
    	clocks = <&h2f_user2_clk>;
    };

    I could check the change in the live DT, but it didn't solve the issue.

  • JitLoonL_Altera's avatar
    JitLoonL_Altera
    Icon for Occasional Contributor rankOccasional Contributor

    Hi @dpeng ,

    Looking at your DT, the bridges are currently disabled, which explains why changing the clock in Linux DT alone didn’t help.

    For your setup:

    • fpga_bridge@ff400000 (LW HPS-to-FPGA) is the one you likely need for HPS → FPGA communication. You should enable it in your DT like this:

    &fpga_bridge0 {
    status = "okay";
    clocks = <&h2f_user2_clk>; /* match Platform Designer */
    resets = <0x06 0x61>; /* keep original reset lines */
    };

    • fpga-bridge@ffc25080 (FPGA-to-SDRAM) only needs enabling if your design specifically requires FPGA → SDRAM access.

    Remember, the DT in Barebox should match the Platform Designer settings. Enabling the bridge and assigning the correct clock there is necessary before Linux can use it.

    After this change, check the live DT in Linux - status should now be okay and the bridge should be functional.

    • dpeng's avatar
      dpeng
      Icon for New Contributor rankNew Contributor

      I am not able to dump the live tree after I apply the overlay that enables the bridge, because the system freezes totally at this step. This is precisely what I'm trying to fix.

      In the project, i.e. the Mercury+ SA2 ST1 Reference Design, the Platform Designer setup looks like this:

      I checked that the handoff files in Barebox are up to date with the design. In the Barebox DT, I added these lines, just like in the Linux DT:

      &fpga_bridge0 {
      	clocks = <&h2f_user2_clk>;
      };

      I confirmed that the clock is changed by dumping the live tree and before applying the overlay.

      I'm trying to enable the bridge in a Linux overlay:

      	fragment@1 {
      		target = <&fpga_bridge0>;
      
      		__overlay__ {
      			status = "okay";
      			bridge-enable = <1>;
      		};
      	};

      But applying the overlay keeps freezing the system.

  • dpeng's avatar
    dpeng
    Icon for New Contributor rankNew Contributor

    I noticed that in Barebox, the clock used in the default configuration of "fpga_bridge0" is enabled by default:

    barebox@Enclustra Mercury+ SA2:/ clk_dump l4_main_clk
    osc1 (rate 50000000, enable_count: 4, enabled)
        main_pll@40 (rate 1600000000, enable_count: 3, always enabled)
            mainclk@4c (rate 400000000, enable_count: 1, always enabled)
                l4_main_clk (rate 400000000, enable_count: 1, enabled)

    On the other hand, the one that's used by the lw-h2f bridge in Platform Designer is disabled. I can enable it manually but it doesn't fix the crash.

    barebox@Enclustra Mercury+ SA2:/ clk_dump h2f_user2_clk
    osc1 (rate 50000000, enable_count: 3, enabled)
        sdram_pll@c0 (rate 800000000, enable_count: 0, always enabled)
            h2f_usr2_clk@d4 (rate 50000000, enable_count: 0, always enabled)
                h2f_user2_clk (rate 50000000, enable_count: 0, enabled)
    barebox@Enclustra Mercury+ SA2:/ clk_enable h2f_user2_clk
    barebox@Enclustra Mercury+ SA2:/ clk_dump h2f_user2_clk
    osc1 (rate 50000000, enable_count: 4, enabled)
        sdram_pll@c0 (rate 800000000, enable_count: 1, always enabled)
            h2f_usr2_clk@d4 (rate 50000000, enable_count: 1, always enabled)
                h2f_user2_clk (rate 50000000, enable_count: 1, enabled)

    "h2f_usr2_clk@d4" is the parent of "h2f_user2_clk". I'm not sure which one I should use in the DTs (Barebox and Linux) as the clock of "fpga_bridge0". I tried both. But applying the overlay still crashes the system.

  • dpeng's avatar
    dpeng
    Icon for New Contributor rankNew Contributor

    @JitLoonL_Altera, I enabled the bridge driver in Barebox:

    CONFIG_FPGA=y
    CONFIG_FPGA_BRIDGE=y
    CONFIG_SOCFPGA_FPGA_BRIDGE=y

    And the bridge in Barebox:

    &fpga_bridge0 {
    	status = "okay";
    	bridge-enable = <0x1>;
    };

    Barebox boot log (note the "altera-hps2fpga-bridge" lines):

    barebox 2025.07.0 #2 Thu Aug 28 15:09:04 CEST 2025
    
    
    Board: Enclustra Mercury+ SA2
    netconsole: registered as netconsole-1
    altera-hps2fpga-bridge ff400000.fpga_bridge@ff400000.of: enabling bridge
    altera-hps2fpga-bridge ff400000.fpga_bridge@ff400000.of: fpga bridge [lwhps2fpga] registered
    socfpga_designware_eth ff702000.ethernet@ff702000.of: user ID: 0x10, Synopsys ID: 0x37
    mdio_bus: miibus0: probed
    dw_mmc ff704000.mmc@ff704000.of: registered as mmc0
    cadence_qspi ff705000.spi@ff705000.of: couldn't determine block-size
    cadence_qspi ff705000.spi@ff705000.of: probing for flashchip failed
    cadence_qspi ff705000.spi@ff705000.of: Cadence QSPI NOR probe failed
    malloc space: 0x1ff00000 -> 0x3fdfffff (size 511 MiB)
    mmc0: detected SD card version 2.0
    mmc0: registered mmc0
    eth0: got preset MAC address: 20:b0:f7:0a:6c:08
    
    Hit any to stop autoboot:    1
    barebox@Enclustra Mercury+ SA2:/

    But the system still hangs when I apply the DT overlay.

  • @dpeng

    DMA PL330 handshake also fixed via


    community.intel.com/t5/Intel-SoC-FPGA-Embedded/Cyclone-V-H2F-DMA-is-dead/m-p/1714304#M3338

  • dpeng's avatar
    dpeng
    Icon for New Contributor rankNew Contributor

    So, I think I made some progress.

    1. I enable the bridges in Barebox by setting the status and bridge-enable properties.
    2. In the Linux devicetree overlay, I only set the status property, not the bridge-enable property.

    The Barebox DT (the "0x1" syntax matters, it seems):

    &fpga_bridge0 {
    	status = "okay";
    	bridge-enable = <0x1>;
    };

    The Linux DT overlay:

    /dts-v1/;
    /plugin/;
    
    / {
    	fragment@0 {
    		target = <&base_fpga_region>;
    
    		__overlay__ {
    			#address-cells = <0x1>;
    			#size-cells = <0x1>;
    
    			// The .rbf file must be placed in /lib/firmware
    			firmware-name = "soc_firwmare.rbf";
    			fpga-bridges = <&fpga_bridge0 &fpga_bridge1>;
    		};
    	};
    
    	/* Enable the lightweight FPGA to HPS bridge (lwhps2fpga) */
    	fragment@1 {
    		target = <&fpga_bridge0>;
    
    		__overlay__ {
    			status = "okay";
    			// Don't set bridge-enable!
    			// bridge-enable = <1>;
    		};
    	};
    
    	/* Enable the HPS to FPGA bridge (hps2fpga) */
    	fragment@2 {
    		target = <&fpga_bridge1>;
    
    		__overlay__ {
    			status = "okay";
    			// Don't set bridge-enable!
    			// bridge-enable = <1>;
    		};
    	};
    };

    Then, I when I check the status of the bridges, I get what I expect:

    # for f in /proc/device-tree/soc/fpga?bridge*; do echo $(basename $f)":" $(cat $f/status); done
    fpga-bridge@ff600000: disabled
    fpga-bridge@ffc25080: disabled
    fpga_bridge@ff400000: okay
    fpga_bridge@ff500000: okay
    #

    I didn't try to communicate between the HPS and the FPGA yet, but it looks promising.