How to use HW-supported SPI on BeagleY-AI

Hi all,
I know there have been several SPI posts in this forum. I’d like to use the hardware MCU_SPI0 unit to offload the CPU instead of using the SPI-GPIO. In my understanding all BeagleY-AI examples show use of GPIO-SPI which is sort of bit-banging SPI by the CPU, right?.

In the BeagleY-AI schematic listed at Design and Specifications — BeagleBoard Documentation we see the the MCU_SPI0 pins are connected to the correct default RPI4 SPI pins of the expansion port.

Therefore I hope it must be possible to utilize the MCU_SPI0 hardware unit for SPI. I have a kernel driver working with RPI4, but for BeagleY-AI I don’t know how to configure the pinmux so that these MCU_SPI0_D0/D1/CLK/CS0 get activated. At least with a logic analyzer there is always total silence on the expansion port SPI pins.

My current non-working attempt for a DTS overlay looks like this:

/dts-v1/;
/plugin/;
/ {
        compatible = "beagle,am67a-beagley-ai", "ti,j722s";
        fragment@1 {
                target = <&mcu_spi0>; // MCU_SPI0 HW unit
                __overlay__ {
                        status = "okay";
                        #address-cells = <1>;
                        #size-cells = <0>;
                        pinctrl-0 = <&spi_gpio_default_pins>; // this is probably wrong, isn't it?

                        sck-gpios = <&mcu_gpio0 0x00000002 0x00000000>; // do I need these?
                        miso-gpios = <&mcu_gpio0 0x00000004 0x00000000>; // do I need these?
                        mosi-gpios = <&mcu_gpio0 0x00000003 0x00000000>; // do I need these?
                        num-chipselects = <0x00000002>;
                        cs-gpios = <&mcu_gpio0 0x00000000 0x00000000 &mcu_gpio0 0x00000009 0x00000000>; // what to specify here?

                        paa5100je: paa51100je@0 {
                                compatible = "pimoroni,paa5100je";
                                reg = <0x0>;
                                spi-max-frequency = <1000000>;
                                spi-bits-per-word = <8>;
                                swap-xy;
                                status = "okay";
                        };
                };
        };
};

Ha! After some hours of reverse engineering I figured out that the default BeagleY-AI mcu pinmux, i.e. the “spi_gpio_default_pins” sets the alternate functions of the pad which are the GPIO functions.

Using the SYSCONFIG IDE, configuration, compiler or debugger | TI.com I could generate a dtsi which is using the MCU_SPI functions for the pad. It turned out that the last J722S_MCU_IOPAD() parameter is “0” instead of “7” as in the default spi pin setup of the BeagleY-AI kernel. Generated sysconfig code:
[2025-04-01 edited]

&mcu_pmx0 {
	mymcu_spi0_pins_default: mymcu_spi0-default-pins {
		pinctrl-single,pins = <
			J722S_MCU_IOPAD(0x0008, PIN_OUTPUT, 0) /* (A9) MCU_SPI0_CLK */
			J722S_MCU_IOPAD(0x0000, PIN_OUTPUT, 0) /* (C12) MCU_SPI0_CS0 */
			J722S_MCU_IOPAD(0x0024, PIN_OUTPUT, 2) /* (B3) WKUP_UART0_RXD.MCU_SPI0_CS2 */
			J722S_MCU_IOPAD(0x000c, PIN_OUTPUT, 0) /* (B12) MCU_SPI0_D0 */
			J722S_MCU_IOPAD(0x0010, PIN_INPUT, 0) /* (C11) MCU_SPI0_D1 */
		>;
	};
};

Therefore I created my own spi pinmux setting with the values of the existing “spi_gpio_default_pins”, just exchanged the “7” into “0”. Then the bits fired up in the logic analyzer
:sunglasses:
[2025-04-01 Added required “ti,pindir-d0-out-d1-in” as D0 is MOSI and D1 is MISO, see also https://www.kernel.org/doc/Documentation/devicetree/bindings/spi/omap-spi.txt]

/dts-v1/;
/plugin/;
/ {
        compatible = "beagle,am67a-beagley-ai", "ti,j722s";
        fragment@0 {
                target = <&mcu_pmx0>;
                __overlay__ {
                        mymcu_spi0_pins_default: mymcu_spi0-default-pins {
                                pinctrl-single,pins = <
                                        0x00000000 0x00010000 
                                        0x00000024 0x00010002 
                                        0x00000008 0x00010000 
                                        0x00000010 0x00050000 
                                        0x0000000c 0x00010000
                                >;
                        };
                };
        };
        fragment@1 {
                target = <&mcu_spi0>;
                __overlay__ {
                        status = "okay";
                        #address-cells = <1>;
                        #size-cells = <0>;
                        pinctrl-names = "default";
                        pinctrl-0 = <&mymcu_spi0_pins_default>;

                        ti,hwmods = "mcu_mcspi0";
                        ti,spi-num-cs = <2>;
                        ti,pindir-d0-out-d1-in;


                        paa5100je: paa51100je@0 {
                                compatible = "pimoroni,paa5100je";
                                reg = <0x0>;
                                spi-max-frequency = <1000000>;
                                spi-bits-per-word = <8>;
                                swap-xy;
                                status = "okay";
                        };
                };
        };
};