AM625: Delay between two SPI words and CS to first data

Part Number: AM625
Other Parts Discussed in Thread: SK-AM62, TCA6424

Tool/software:

Hi,

We have a application where continuous SPI read is needed and we are using default SPI driver given in SDK(TI-RTOS). We have configured 10MHZ clock and we need register level detail to optimize following delays.

1. CS to First data assertion delay

2. Inter packet delay

3. Last SPI packet to CS high delay.

I have attached signal capture from scope for reference. 

Thanks,

siva. SCOPE CAPTURE

h     14    
w   1192    

14

1192

 

 

 

 

 

 

 

 

 

 

 

 

 

 

12

 

 

 

  • Hello,

    The thread is assigned to the subject matter expert. Please expect reply soon.

    Regards,
    Aparna

  • Hi Aparna,

    Thanks for the update.

    thanks,

    siva.

  • Hello Sivakumar,

    Thank you for your question.

    Can you help me by confirming you are using MCU PLUS SDK?

    Please also mention the version of the same.

    Looking forward to your response.

    Regards,

    Vaibhav

  • Hi Vaibhav,

    I am using  TI RT Linux package 8.6 version "ti-processor-sdk-linux-rt-am62xx-evm-08.06.00.42-Linux-x86" .

    thanks,

    siva.

  • Hi Sivakumar,

    Thank you for mentioning the exact SDK you are using along with the version.

    I am going to route this query to the correct expert, as I take care of the MCSPI queries on MCU PLUS SDK.

    You can expect responses in sometime.

    I will keep an eye on this thread to make sure you are getting timely responses.

    Thanks for your patience.

    Regards,

    Vaibhav

  • 1. CS to First data assertion delay
    3. Last SPI packet to CS high delay.

    In the McSPI Linux driver the CS signal is controlled by SW. There's not much you can do to shorten those specific delays.

    2. Inter packet delay

    To optimize inter-byte delays, you can enable the use of DMA for the McSPI peripheral. Doing so will also enable/leverage the module's built-in FIFO, and will make sure transfers are as optimized as much as possible. Here's a relevant E2E post for your review: https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1291527/sk-am62-cannot-enable-dma-for-mcspi0-on-linux/4972717#4972717

    Note that enabling DMA will not completely eliminate the inter-byte gap. If you need higher overall throughput also consider increasing the SPI clock frequency.

    Regards, Andreas

  • Hi Andreas,

    Thanks for the response. I will increase the clock and minimize the delay. Also pls let me know how to increase the MAXIMUM SPI Bytes transferred in single transfer? This aspect also poses challenge for reading the realtime data.

    thnaks,

    siva.

  • Thanks for the response. I will increase the clock and minimize the delay. Also pls let me know how to increase the MAXIMUM SPI Bytes transferred in single transfer? This aspect also poses challenge for reading the realtime data.

    How much data are you transferring? And what do you currently see/experience as "maximum limit"?

    Also this reminds me of, there's a cut-off threshold in the driver of I think 160 bytes, and DMA will only be used for transfers larger than that. So when you want to make transfers that are smaller and want to minimize the inter-byte gaps you need to reduce this limit by editing the driver file. This E2E FAQ here has more info on this: https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1356551/faq-am6x-optimizing-spi-transfer-inter-byte-gaps-using-the-dma-in-linux

    Regards, Andreas

  • Hi Andreas, 

    Apologize for the delay. Got strucked in other issue. Basically we dont want DMA transfer since we have only 140 bytes to be transferred. Default kernel driver supports only 15 bytes maximum. How do we change the maximum length to be 140 bytes?

    thanks,

    siva.

  • Apologize for the delay. Got strucked in other issue. Basically we dont want DMA transfer since we have only 140 bytes to be transferred

    Using the DMA is the only way to minimize inter-byte gap for those transfers. Why not use/enable it (will need minor driver modification, as per E2E FAQ I pointed to).

    Regards, Andreas

  • Hi Andreas,

    Let me try it and update you regarding DMA transfer. Also, I need to attach this SPI function call triggered on GPIO interrupt. I am using TI RT Linux package 8.6 version.

    thanks,

    siva.

  • Hi Andreas,

    I tried DMA transfer in spi0 and it is not working. I added the diagnostics procedure as you suggested in spi-omap2-mcspi.c. When I did dmesg | grep omap2_mcspi , I dont see any message related to DMA. Basically DMA is not enabled. I have attached both device tree and spi-omap2-mcspi.c for your reference. Please let me if there is any issue with the code. 

    thanks,

    siva.

    6740.k3-am625-sk.txt
    // SPDX-License-Identifier: GPL-2.0
    /*
     * AM625 SK: https://www.ti.com/lit/zip/sprr448
     *
     * Copyright (C) 2021-2022 Texas Instruments Incorporated - https://www.ti.com/
     */
    
    /dts-v1/;
    
    #include <dt-bindings/leds/common.h>
    #include <dt-bindings/gpio/gpio.h>
    #include <dt-bindings/net/ti-dp83867.h>
    #include "k3-am625.dtsi"
    #include "k3-am62x-sk-common.dtsi"
    
    / {
    	compatible =  "ti,am625-sk", "ti,am625";
    	model = "Texas Instruments AM625 SK";
    
    	wlan_lten: regulator-5 {
    		compatible = "regulator-fixed";
    		regulator-name = "wlan_lten";
    		regulator-min-microvolt = <3300000>;
    		regulator-max-microvolt = <3300000>;
    		regulator-always-on;
    		vin-supply = <&vcc_3v3_sys>;
    		gpios = <&exp1 11 GPIO_ACTIVE_LOW>;
    	};
    
    	wlan_en: regulator-6 {
    		/* OUTPUT of SN74AVC2T244DQMR */
    		compatible = "regulator-fixed";
    		regulator-name = "wlan_en";
    		regulator-min-microvolt = <1800000>;
    		regulator-max-microvolt = <1800000>;
    		enable-active-high;
    		vin-supply = <&wlan_lten>;
    		gpios = <&main_gpio0 71 GPIO_ACTIVE_HIGH>;
    		pinctrl-names = "default";
    		pinctrl-0 = <&wlan_en_pins_default>;
    	};
    
    	opp-table {
    		/* Add 1.4GHz OPP for am625-sk board. Requires VDD_CORE to be at 0.85V */
    		opp-1400000000 {
    			opp-hz = /bits/ 64 <1400000000>;
    			opp-supported-hw = <0x01 0x0004>;
    			clock-latency-ns = <6000000>;
    		};
    	};
    };
    
    &main_pmx0 {
    	wlan_en_pins_default: wlan-en-pins-default {
    		pinctrl-single,pins = <
    			AM62X_IOPAD(0x124, PIN_OUTPUT, 7) /* (A23) MMC2_SDCD.GPIO0_71 */
    		>;
    	};
    
    	main_mmc2_pins_default: main-mmc2-pins-default {
    		pinctrl-single,pins = <
    			AM62X_IOPAD(0x120, PIN_INPUT, 0) /* (C24) MMC2_CMD */
    			AM62X_IOPAD(0x118, PIN_INPUT, 0) /* (D25) MMC2_CLK */
    			AM62X_IOPAD(0x114, PIN_INPUT, 0) /* (B24) MMC2_DAT0 */
    			AM62X_IOPAD(0x110, PIN_INPUT, 0) /* (C25) MMC2_DAT1 */
    			AM62X_IOPAD(0x10c, PIN_INPUT, 0) /* (E23) MMC2_DAT2 */
    			AM62X_IOPAD(0x108, PIN_INPUT, 0) /* (D24) MMC2_DAT3 */
    			AM62X_IOPAD(0x11c, PIN_INPUT, 0) /* (#N/A) MMC2_CLKB */
    		>;
    	};
    
    	main_wlirq_pins_default: main-wlirq-pins-default {
    		pinctrl-single,pins = <
    			AM62X_IOPAD(0x128, PIN_INPUT, 7) /* (B23) MMC2_SDWP.GPIO0_72 */
    		>;
    	};
    
    	main_spi0_pins_default: main-spi0-pins-default {
    		pinctrl-single,pins = <
    			AM62X_IOPAD(0x01C0, PIN_OUTPUT, 0) /* (B13) SPI0_D0 */
    			AM62X_IOPAD(0x01C4, PIN_INPUT, 0) /* (B14) SPI0_D1 */
    			AM62X_IOPAD(0x01B4, PIN_OUTPUT, 0) /* (A13) SPI0_CS0 */
    			AM62X_IOPAD(0x01BC, PIN_INPUT, 0) /* (A14) SPI0_CLK */	
    			AM62X_IOPAD(0x01b8, PIN_OUTPUT, 0) /* (C13) SPI0_CS1 */
    		>;
    	};
    
    	main_spi2_pins_default: main-spi2-pins-default {
    		pinctrl-single,pins = <
    			
    			AM62X_IOPAD(0x01b0, PIN_INPUT, 1) /* (A20) MCASP0_ACLKR.SPI2_CLK */
    			AM62X_IOPAD(0x0194, PIN_OUTPUT, 1) /* (B19) MCASP0_AXR3.SPI2_D0 */
    			AM62X_IOPAD(0x0198, PIN_INPUT, 1) /* (A19) MCASP0_AXR2.SPI2_D1 */
    			AM62X_IOPAD(0x01ac, PIN_OUTPUT, 1) /* (E19) MCASP0_AFSR.SPI2_CS0 */
    			AM62X_IOPAD(0x01a4, PIN_OUTPUT, 1) /* (B20) MCASP0_ACLKX.SPI2_CS1 */
    			AM62X_IOPAD(0x019c, PIN_OUTPUT, 1) /* (B18) MCASP0_AXR1.SPI2_CS2 */
    		>;
    	};
    
    };
    &main_i2c1 {
    	exp1: gpio@74 {
    		compatible = "ti,tca9539";
    		reg = <0x74>;
    		gpio-controller;
    		#gpio-cells = <2>;
    		gpio-line-names = "GPIO_CPSW2_RST", "GPIO_CPSW1_RST",
    				   "PRU_DETECT", "MMC1_SD_EN",
    				   "VPP_LDO_EN", "EXP_PS_3V3_En",
    				   "EXP_PS_5V0_En", "EXP_HAT_DETECT",
    				   "GPIO_AUD_RSTn", "GPIO_eMMC_RSTn",
    				   "UART1_FET_BUF_EN", "WL_LT_EN",
    				   "GPIO_HDMI_RSTn", "CSI_GPIO1",
    				   "CSI_GPIO2", "PRU_3V3_EN",
    				   "HDMI_INTn", "TEST_GPIO2",
    				   "MCASP1_FET_EN", "MCASP1_BUF_BT_EN",
    				   "MCASP1_FET_SEL", "UART1_FET_SEL",
    				   "TSINT#", "IO_EXP_TEST_LED";
    
    		interrupt-parent = <&main_gpio1>;
    		interrupts = <23 IRQ_TYPE_EDGE_FALLING>;
    		interrupt-controller;
    		#interrupt-cells = <2>;
    
    		pinctrl-names = "default";
    	};
    
    };
    
    
    
    &main_spi0 {
    	status = "okay";
    	#address-cells = <1>;
    	#size-cells = <0>;
    	pinctrl-0 = <&main_spi0_pins_default>;
    	pinctrl-names = "default";
    	dmas = <&main_pktdma 0xc300 0>, <&main_pktdma 0x4300 0>;
    	dma-names = "tx0", "rx0";
    	spidev@0 {
    		/*
    		 * Using spidev compatible is warned loudly,
    		 * thus use another equivalent compatible id
    		 * from spidev.
    		 */
    		compatible = "rohm,dh2228fv";
    		spi-max-frequency = <24000000>;
    		reg = <0>;
    	};
    };
    
    
    
    &main_spi2 {
    	    status = "disabled";
            
    		status = "okay";
            pinctrl-names = "default";
            pinctrl-0 = <&main_spi2_pins_default>;
    		ti,spi-num-chipselects = <3>;  
    		cs-gpios = <0>, <0>, <0>;
    		
    		ti,pindir-d0-out-d1-in = <0>;
             
    		spidev2:spidev@0 {
                    spi-max-frequency = <10000000>;
                    reg = <0>;
                    compatible = "rohm,dh2228fv";
            };
    
    		spidev3:spidev@1 {
                    spi-max-frequency = <10000000>;
                    reg = <1>;
                    compatible = "rohm,dh2228fv";
            };
    
    		spidev4:spidev@2 {
                    spi-max-frequency = <10000000>;
                    reg = <2>;
                    compatible = "rohm,dh2228fv";
            };
    		
    
    };
    
    
    &sdhci2 {
    	vmmc-supply = <&wlan_en>;
    	pinctrl-names = "default";
    	pinctrl-0 = <&main_mmc2_pins_default>;
    	bus-width = <4>;
    	non-removable;
    	ti,fails-without-test-cd;
    	cap-power-off-card;
    	keep-power-in-suspend;
    	ti,driver-strength-ohm = <50>;
    	assigned-clocks = <&k3_clks 157 158>;
    	assigned-clock-parents = <&k3_clks 157 160>;
    
    	#address-cells = <1>;
    	#size-cells = <0>;
    	wlcore: wlcore@2 {
    		compatible = "ti,wl1837";
    		reg = <2>;
    		pinctrl-names = "default";
    		pinctrl-0 = <&main_wlirq_pins_default>;
    		interrupt-parent = <&main_gpio0>;
    		interrupts = <72 IRQ_TYPE_EDGE_FALLING>;
    	};
    };
    
    &ospi0 {
    	spi_nor_flash: flash@0 {
    		compatible = "jedec,spi-nor";
    		reg = <0x0>;
    		spi-tx-bus-width = <8>;
    		spi-rx-bus-width = <8>;
    		spi-max-frequency = <25000000>;
    		cdns,tshsl-ns = <60>;
    		cdns,tsd2d-ns = <60>;
    		cdns,tchsh-ns = <60>;
    		cdns,tslch-ns = <60>;
    		cdns,read-delay = <4>;
    		cdns,phy-mode;
    
    		partitions {
    			compatible = "fixed-partitions";
    			#address-cells = <1>;
    			#size-cells = <1>;
    
    			partition@0 {
    				label = "ospi.tiboot3";
    				reg = <0x0 0x80000>;
    			};
    
    			partition@80000 {
    				label = "ospi.tispl";
    				reg = <0x80000 0x200000>;
    			};
    
    			partition@280000 {
    				label = "ospi.u-boot";
    				reg = <0x280000 0x400000>;
    			};
    
    			partition@680000 {
    				label = "ospi.env";
    				reg = <0x680000 0x40000>;
    			};
    
    			partition@6c0000 {
    				label = "ospi.env.backup";
    				reg = <0x6c0000 0x40000>;
    			};
    
    			partition@800000 {
    				label = "ospi.rootfs";
    				reg = <0x800000 0x37c0000>;
    			};
    
    			partition@3fc0000 {
    				label = "ospi.phypattern";
    				reg = <0x3fc0000 0x40000>;
    			};
    		};
    	};
    };
     
    spi-omap2-mcspi.txt
    // SPDX-License-Identifier: GPL-2.0-or-later
    /*
     * OMAP2 McSPI controller driver
     *
     * Copyright (C) 2005, 2006 Nokia Corporation
     * Author:	Samuel Ortiz <samuel.ortiz@nokia.com> and
     *		Juha Yrj�l� <juha.yrjola@nokia.com>
     */
    
    #include <linux/kernel.h>
    #include <linux/interrupt.h>
    #include <linux/module.h>
    #include <linux/device.h>
    #include <linux/delay.h>
    #include <linux/dma-mapping.h>
    #include <linux/dmaengine.h>
    #include <linux/pinctrl/consumer.h>
    #include <linux/platform_device.h>
    #include <linux/err.h>
    #include <linux/clk.h>
    #include <linux/io.h>
    #include <linux/slab.h>
    #include <linux/pm_runtime.h>
    #include <linux/of.h>
    #include <linux/of_device.h>
    #include <linux/gcd.h>
    
    #include <linux/spi/spi.h>
    
    #include <linux/platform_data/spi-omap2-mcspi.h>
    
    #define OMAP2_MCSPI_MAX_FREQ		48000000
    #define OMAP2_MCSPI_MAX_DIVIDER		4096
    #define OMAP2_MCSPI_MAX_FIFODEPTH	64
    #define OMAP2_MCSPI_MAX_FIFOWCNT	0xFFFF
    #define SPI_AUTOSUSPEND_TIMEOUT		2000
    
    #define OMAP2_MCSPI_REVISION		0x00
    #define OMAP2_MCSPI_SYSSTATUS		0x14
    #define OMAP2_MCSPI_IRQSTATUS		0x18
    #define OMAP2_MCSPI_IRQENABLE		0x1c
    #define OMAP2_MCSPI_WAKEUPENABLE	0x20
    #define OMAP2_MCSPI_SYST		0x24
    #define OMAP2_MCSPI_MODULCTRL		0x28
    #define OMAP2_MCSPI_XFERLEVEL		0x7c
    
    /* per-channel banks, 0x14 bytes each, first is: */
    #define OMAP2_MCSPI_CHCONF0		0x2c
    #define OMAP2_MCSPI_CHSTAT0		0x30
    #define OMAP2_MCSPI_CHCTRL0		0x34
    #define OMAP2_MCSPI_TX0			0x38
    #define OMAP2_MCSPI_RX0			0x3c
    
    /* per-register bitmasks: */
    #define OMAP2_MCSPI_IRQSTATUS_EOW	BIT(17)
    
    #define OMAP2_MCSPI_MODULCTRL_SINGLE	BIT(0)
    #define OMAP2_MCSPI_MODULCTRL_MS	BIT(2)
    #define OMAP2_MCSPI_MODULCTRL_STEST	BIT(3)
    
    #define OMAP2_MCSPI_CHCONF_PHA		BIT(0)
    #define OMAP2_MCSPI_CHCONF_POL		BIT(1)
    #define OMAP2_MCSPI_CHCONF_CLKD_MASK	(0x0f << 2)
    #define OMAP2_MCSPI_CHCONF_EPOL		BIT(6)
    #define OMAP2_MCSPI_CHCONF_WL_MASK	(0x1f << 7)
    #define OMAP2_MCSPI_CHCONF_TRM_RX_ONLY	BIT(12)
    #define OMAP2_MCSPI_CHCONF_TRM_TX_ONLY	BIT(13)
    #define OMAP2_MCSPI_CHCONF_TRM_MASK	(0x03 << 12)
    #define OMAP2_MCSPI_CHCONF_DMAW		BIT(14)
    #define OMAP2_MCSPI_CHCONF_DMAR		BIT(15)
    #define OMAP2_MCSPI_CHCONF_DPE0		BIT(16)
    #define OMAP2_MCSPI_CHCONF_DPE1		BIT(17)
    #define OMAP2_MCSPI_CHCONF_IS		BIT(18)
    #define OMAP2_MCSPI_CHCONF_TURBO	BIT(19)
    #define OMAP2_MCSPI_CHCONF_FORCE	BIT(20)
    #define OMAP2_MCSPI_CHCONF_FFET		BIT(27)
    #define OMAP2_MCSPI_CHCONF_FFER		BIT(28)
    #define OMAP2_MCSPI_CHCONF_CLKG		BIT(29)
    
    #define OMAP2_MCSPI_CHSTAT_RXS		BIT(0)
    #define OMAP2_MCSPI_CHSTAT_TXS		BIT(1)
    #define OMAP2_MCSPI_CHSTAT_EOT		BIT(2)
    #define OMAP2_MCSPI_CHSTAT_TXFFE	BIT(3)
    
    #define OMAP2_MCSPI_CHCTRL_EN		BIT(0)
    #define OMAP2_MCSPI_CHCTRL_EXTCLK_MASK	(0xff << 8)
    
    #define OMAP2_MCSPI_WAKEUPENABLE_WKEN	BIT(0)
    
    /* We have 2 DMA channels per CS, one for RX and one for TX */
    struct omap2_mcspi_dma {
    	struct dma_chan *dma_tx;
    	struct dma_chan *dma_rx;
    	char dma_rx_ch_name[14];
    	char dma_tx_ch_name[14];
    };
    
    /* use PIO for small transfers, avoiding DMA setup/teardown overhead and
     * cache operations; better heuristics consider wordsize and bitrate.
     */
    #define DMA_MIN_BYTES			10
    
    
    /*
     * Used for context save and restore, structure members to be updated whenever
     * corresponding registers are modified.
     */
    struct omap2_mcspi_regs {
    	u32 modulctrl;
    	u32 wakeupenable;
    	struct list_head cs;
    };
    
    struct omap2_mcspi {
    	struct completion	txrxdone;
    	struct spi_master	*master;
    	/* Virtual base address of the controller */
    	void __iomem		*base;
    	unsigned long		phys;
    	/* SPI1 has 4 channels, while SPI2 has 2 */
    	struct omap2_mcspi_dma	*dma_channels;
    	struct device		*dev;
    	struct omap2_mcspi_regs ctx;
    	int			fifo_depth;
    	bool			slave_aborted;
    	unsigned int		pin_dir:1;
    	size_t			max_xfer_len;
    };
    
    struct omap2_mcspi_cs {
    	void __iomem		*base;
    	unsigned long		phys;
    	int			word_len;
    	u16			mode;
    	struct list_head	node;
    	/* Context save and restore shadow register */
    	u32			chconf0, chctrl0;
    };
    
    static inline void mcspi_write_reg(struct spi_master *master,
    		int idx, u32 val)
    {
    	struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
    
    	writel_relaxed(val, mcspi->base + idx);
    }
    
    static inline u32 mcspi_read_reg(struct spi_master *master, int idx)
    {
    	struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
    
    	return readl_relaxed(mcspi->base + idx);
    }
    
    static inline void mcspi_write_cs_reg(const struct spi_device *spi,
    		int idx, u32 val)
    {
    	struct omap2_mcspi_cs	*cs = spi->controller_state;
    
    	writel_relaxed(val, cs->base +  idx);
    }
    
    static inline u32 mcspi_read_cs_reg(const struct spi_device *spi, int idx)
    {
    	struct omap2_mcspi_cs	*cs = spi->controller_state;
    
    	return readl_relaxed(cs->base + idx);
    }
    
    static inline u32 mcspi_cached_chconf0(const struct spi_device *spi)
    {
    	struct omap2_mcspi_cs *cs = spi->controller_state;
    
    	return cs->chconf0;
    }
    
    static inline void mcspi_write_chconf0(const struct spi_device *spi, u32 val)
    {
    	struct omap2_mcspi_cs *cs = spi->controller_state;
    
    	cs->chconf0 = val;
    	mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCONF0, val);
    	mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0);
    }
    
    static inline int mcspi_bytes_per_word(int word_len)
    {
    	if (word_len <= 8)
    		return 1;
    	else if (word_len <= 16)
    		return 2;
    	else /* word_len <= 32 */
    		return 4;
    }
    
    static void omap2_mcspi_set_dma_req(const struct spi_device *spi,
    		int is_read, int enable)
    {
    	u32 l, rw;
    
    	l = mcspi_cached_chconf0(spi);
    
    	if (is_read) /* 1 is read, 0 write */
    		rw = OMAP2_MCSPI_CHCONF_DMAR;
    	else
    		rw = OMAP2_MCSPI_CHCONF_DMAW;
    
    	if (enable)
    		l |= rw;
    	else
    		l &= ~rw;
    
    	mcspi_write_chconf0(spi, l);
    }
    
    static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable)
    {
    	struct omap2_mcspi_cs *cs = spi->controller_state;
    	u32 l;
    
    	l = cs->chctrl0;
    	if (enable)
    		l |= OMAP2_MCSPI_CHCTRL_EN;
    	else
    		l &= ~OMAP2_MCSPI_CHCTRL_EN;
    	cs->chctrl0 = l;
    	mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, cs->chctrl0);
    	/* Flash post-writes */
    	mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCTRL0);
    }
    
    static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable)
    {
    	struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
    	u32 l;
    
    	/* The controller handles the inverted chip selects
    	 * using the OMAP2_MCSPI_CHCONF_EPOL bit so revert
    	 * the inversion from the core spi_set_cs function.
    	 */
    	if (spi->mode & SPI_CS_HIGH)
    		enable = !enable;
    
    	if (spi->controller_state) {
    		int err = pm_runtime_get_sync(mcspi->dev);
    		if (err < 0) {
    			pm_runtime_put_noidle(mcspi->dev);
    			dev_err(mcspi->dev, "failed to get sync: %d\n", err);
    			return;
    		}
    
    		l = mcspi_cached_chconf0(spi);
    
    		if (enable)
    			l &= ~OMAP2_MCSPI_CHCONF_FORCE;
    		else
    			l |= OMAP2_MCSPI_CHCONF_FORCE;
    
    		mcspi_write_chconf0(spi, l);
    
    		pm_runtime_mark_last_busy(mcspi->dev);
    		pm_runtime_put_autosuspend(mcspi->dev);
    	}
    }
    
    static void omap2_mcspi_set_mode(struct spi_master *master)
    {
    	struct omap2_mcspi	*mcspi = spi_master_get_devdata(master);
    	struct omap2_mcspi_regs	*ctx = &mcspi->ctx;
    	u32 l;
    
    	/*
    	 * Choose master or slave mode
    	 */
    	l = mcspi_read_reg(master, OMAP2_MCSPI_MODULCTRL);
    	l &= ~(OMAP2_MCSPI_MODULCTRL_STEST);
    	if (spi_controller_is_slave(master)) {
    		l |= (OMAP2_MCSPI_MODULCTRL_MS);
    	} else {
    		l &= ~(OMAP2_MCSPI_MODULCTRL_MS);
    		l |= OMAP2_MCSPI_MODULCTRL_SINGLE;
    	}
    	mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, l);
    
    	ctx->modulctrl = l;
    }
    
    static void omap2_mcspi_set_fifo(const struct spi_device *spi,
    				struct spi_transfer *t, int enable)
    {
    	struct spi_master *master = spi->master;
    	struct omap2_mcspi_cs *cs = spi->controller_state;
    	struct omap2_mcspi *mcspi;
    	unsigned int wcnt;
    	int max_fifo_depth, bytes_per_word;
    	u32 chconf, xferlevel;
    
    	mcspi = spi_master_get_devdata(master);
    
    	chconf = mcspi_cached_chconf0(spi);
    	if (enable) {
    		bytes_per_word = mcspi_bytes_per_word(cs->word_len);
    		if (t->len % bytes_per_word != 0)
    			goto disable_fifo;
    
    		if (t->rx_buf != NULL && t->tx_buf != NULL)
    			max_fifo_depth = OMAP2_MCSPI_MAX_FIFODEPTH / 2;
    		else
    			max_fifo_depth = OMAP2_MCSPI_MAX_FIFODEPTH;
    
    		wcnt = t->len / bytes_per_word;
    		if (wcnt > OMAP2_MCSPI_MAX_FIFOWCNT)
    			goto disable_fifo;
    
    		xferlevel = wcnt << 16;
    		if (t->rx_buf != NULL) {
    			chconf |= OMAP2_MCSPI_CHCONF_FFER;
    			xferlevel |= (bytes_per_word - 1) << 8;
    		}
    
    		if (t->tx_buf != NULL) {
    			chconf |= OMAP2_MCSPI_CHCONF_FFET;
    			xferlevel |= bytes_per_word - 1;
    		}
    
    		mcspi_write_reg(master, OMAP2_MCSPI_XFERLEVEL, xferlevel);
    		mcspi_write_chconf0(spi, chconf);
    		mcspi->fifo_depth = max_fifo_depth;
    
    		return;
    	}
    
    disable_fifo:
    	if (t->rx_buf != NULL)
    		chconf &= ~OMAP2_MCSPI_CHCONF_FFER;
    
    	if (t->tx_buf != NULL)
    		chconf &= ~OMAP2_MCSPI_CHCONF_FFET;
    
    	mcspi_write_chconf0(spi, chconf);
    	mcspi->fifo_depth = 0;
    }
    
    static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit)
    {
    	unsigned long timeout;
    
    	timeout = jiffies + msecs_to_jiffies(1000);
    	while (!(readl_relaxed(reg) & bit)) {
    		if (time_after(jiffies, timeout)) {
    			if (!(readl_relaxed(reg) & bit))
    				return -ETIMEDOUT;
    			else
    				return 0;
    		}
    		cpu_relax();
    	}
    	return 0;
    }
    
    static int mcspi_wait_for_completion(struct  omap2_mcspi *mcspi,
    				     struct completion *x)
    {
    	if (spi_controller_is_slave(mcspi->master)) {
    		if (wait_for_completion_interruptible(x) ||
    		    mcspi->slave_aborted)
    			return -EINTR;
    	} else {
    		wait_for_completion(x);
    	}
    
    	return 0;
    }
    
    static void omap2_mcspi_tx_dma(struct spi_device *spi,
    				struct spi_transfer *xfer,
    				struct dma_slave_config cfg)
    {
    	struct omap2_mcspi	*mcspi;
    	struct omap2_mcspi_dma  *mcspi_dma;
    	struct dma_async_tx_descriptor *tx;
    
    	mcspi = spi_master_get_devdata(spi->master);
    	mcspi_dma = &mcspi->dma_channels[spi->chip_select];
    
    	dev_info_once(mcspi->dev, "%s:\n", _func_);
    	dmaengine_slave_config(mcspi_dma->dma_tx, &cfg);
    
    	tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, xfer->tx_sg.sgl,
    					xfer->tx_sg.nents, DMA_MEM_TO_DEV, DMA_CTRL_ACK);
    
    	if (tx) {
    		dmaengine_submit(tx);
    	} else {
    		/* FIXME: fall back to PIO? */
    	}
    	dma_async_issue_pending(mcspi_dma->dma_tx);
    	omap2_mcspi_set_dma_req(spi, 0, 1);
    }
    
    static unsigned
    omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
    				struct dma_slave_config cfg,
    				unsigned es)
    {
    	struct omap2_mcspi	*mcspi;
    	struct omap2_mcspi_dma  *mcspi_dma;
    	unsigned int		count, transfer_reduction = 0;
    	struct scatterlist	*sg_out[2];
    	int			nb_sizes = 0, out_mapped_nents[2], ret, x;
    	size_t			sizes[2];
    	u32			l;
    	int			elements = 0;
    	int			word_len, element_count;
    	struct omap2_mcspi_cs	*cs = spi->controller_state;
    	void __iomem		*chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
    	struct dma_async_tx_descriptor *tx;
    	dma_cookie_t dma_rx_cookie = 0;
    	struct dma_tx_state mcspi_dma_rxstate;
    	enum dma_status dma_status;
    
    	mcspi = spi_master_get_devdata(spi->master);
    	mcspi_dma = &mcspi->dma_channels[spi->chip_select];
    	count = xfer->len;
    	dev_info_once(mcspi->dev, "%s:\n", _func_);
    
    	/*
    	 *  In the "End-of-Transfer Procedure" section for DMA RX in OMAP35x TRM
    	 *  it mentions reducing DMA transfer length by one element in master
    	 *  normal mode.
    	 */
    	if (mcspi->fifo_depth == 0)
    		transfer_reduction = es;
    
    	word_len = cs->word_len;
    	l = mcspi_cached_chconf0(spi);
    
    	if (word_len <= 8)
    		element_count = count;
    	else if (word_len <= 16)
    		element_count = count >> 1;
    	else /* word_len <= 32 */
    		element_count = count >> 2;
    
    
    	dmaengine_slave_config(mcspi_dma->dma_rx, &cfg);
    
    	/*
    	 *  Reduce DMA transfer length by one more if McSPI is
    	 *  configured in turbo mode.
    	 */
    	if ((l & OMAP2_MCSPI_CHCONF_TURBO) && mcspi->fifo_depth == 0)
    		transfer_reduction += es;
    
    	if (transfer_reduction) {
    		/* Split sgl into two. The second sgl won't be used. */
    		sizes[0] = count - transfer_reduction;
    		sizes[1] = transfer_reduction;
    		nb_sizes = 2;
    	} else {
    		/*
    		 * Don't bother splitting the sgl. This essentially
    		 * clones the original sgl.
    		 */
    		sizes[0] = count;
    		nb_sizes = 1;
    	}
    
    	ret = sg_split(xfer->rx_sg.sgl, xfer->rx_sg.nents, 0, nb_sizes,
    		       sizes, sg_out, out_mapped_nents, GFP_KERNEL);
    
    	if (ret < 0) {
    		dev_err(&spi->dev, "sg_split failed\n");
    		return 0;
    	}
    
    	tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, sg_out[0],
    				     out_mapped_nents[0], DMA_DEV_TO_MEM, DMA_CTRL_ACK);
    
    	if (tx) {
    		dma_rx_cookie = dmaengine_submit(tx);
    	} else {
    		/* FIXME: fall back to PIO? */
    	}
    
    	dma_async_issue_pending(mcspi_dma->dma_rx);
    	omap2_mcspi_set_dma_req(spi, 1, 1);
    
    	ret = mcspi_wait_for_completion(mcspi, &mcspi->txrxdone);
    
    	/*
    	 * Before disabling RX DMA we need to confirm whether DMA RX is complete.
    	 * This polling completes on the first attempt itself in most cases.
    	 */
    	do {
    		dma_status = dmaengine_tx_status(mcspi_dma->dma_rx, dma_rx_cookie,
    						 &mcspi_dma_rxstate);
    	} while (dma_status != DMA_COMPLETE);
    
    	omap2_mcspi_set_dma_req(spi, 1, 0);
    	if (ret || mcspi->slave_aborted) {
    		dmaengine_terminate_sync(mcspi_dma->dma_rx);
    		return 0;
    	}
    
    	for (x = 0; x < nb_sizes; x++)
    		kfree(sg_out[x]);
    
    	if (mcspi->fifo_depth > 0)
    		return count;
    
    	/*
    	 *  Due to the DMA transfer length reduction the missing bytes must
    	 *  be read manually to receive all of the expected data.
    	 */
    	omap2_mcspi_set_enable(spi, 0);
    
    	elements = element_count - 1;
    
    	if (l & OMAP2_MCSPI_CHCONF_TURBO) {
    		elements--;
    
    		if (!mcspi_wait_for_reg_bit(chstat_reg,
    					    OMAP2_MCSPI_CHSTAT_RXS)) {
    			u32 w;
    
    			w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
    			if (word_len <= 8)
    				((u8 *)xfer->rx_buf)[elements++] = w;
    			else if (word_len <= 16)
    				((u16 *)xfer->rx_buf)[elements++] = w;
    			else /* word_len <= 32 */
    				((u32 *)xfer->rx_buf)[elements++] = w;
    		} else {
    			int bytes_per_word = mcspi_bytes_per_word(word_len);
    			dev_err(&spi->dev, "DMA RX penultimate word empty\n");
    			count -= (bytes_per_word << 1);
    			omap2_mcspi_set_enable(spi, 1);
    			return count;
    		}
    	}
    	if (!mcspi_wait_for_reg_bit(chstat_reg, OMAP2_MCSPI_CHSTAT_RXS)) {
    		u32 w;
    
    		w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
    		if (word_len <= 8)
    			((u8 *)xfer->rx_buf)[elements] = w;
    		else if (word_len <= 16)
    			((u16 *)xfer->rx_buf)[elements] = w;
    		else /* word_len <= 32 */
    			((u32 *)xfer->rx_buf)[elements] = w;
    	} else {
    		dev_err(&spi->dev, "DMA RX last word empty\n");
    		count -= mcspi_bytes_per_word(word_len);
    	}
    	omap2_mcspi_set_enable(spi, 1);
    	return count;
    }
    
    static unsigned
    omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
    {
    	struct omap2_mcspi	*mcspi;
    	struct omap2_mcspi_cs	*cs = spi->controller_state;
    	struct omap2_mcspi_dma  *mcspi_dma;
    	unsigned int		count;
    	u8			*rx;
    	const u8		*tx;
    	struct dma_slave_config	cfg;
    	enum dma_slave_buswidth width;
    	unsigned es;
    	void __iomem		*chstat_reg;
    	int			wait_res;
    	int ret;
    
    	mcspi = spi_master_get_devdata(spi->master);
    	dev_info_once(mcspi->dev, "%s:\n", _func_);
    	mcspi_dma = &mcspi->dma_channels[spi->chip_select];
    
    	if (cs->word_len <= 8) {
    		width = DMA_SLAVE_BUSWIDTH_1_BYTE;
    		es = 1;
    	} else if (cs->word_len <= 16) {
    		width = DMA_SLAVE_BUSWIDTH_2_BYTES;
    		es = 2;
    	} else {
    		width = DMA_SLAVE_BUSWIDTH_4_BYTES;
    		es = 4;
    	}
    
    	count = xfer->len;
    
    	memset(&cfg, 0, sizeof(cfg));
    	cfg.src_addr = cs->phys + OMAP2_MCSPI_RX0;
    	cfg.dst_addr = cs->phys + OMAP2_MCSPI_TX0;
    	cfg.src_addr_width = width;
    	cfg.dst_addr_width = width;
    	cfg.src_maxburst = 1;
    	cfg.dst_maxburst = 1;
    
    	rx = xfer->rx_buf;
    	tx = xfer->tx_buf;
    
    	mcspi->slave_aborted = false;
    	reinit_completion(&mcspi->txrxdone);
    	mcspi_write_reg(spi->master, OMAP2_MCSPI_IRQENABLE,	OMAP2_MCSPI_IRQSTATUS_EOW);
    	if (tx)
    		omap2_mcspi_tx_dma(spi, xfer, cfg);
    
    	if (rx)
    		count = omap2_mcspi_rx_dma(spi, xfer, cfg, es);
    
    	ret = mcspi_wait_for_completion(mcspi, &mcspi->txrxdone);
    	omap2_mcspi_set_dma_req(spi, 0, 0);
    	if (ret || mcspi->slave_aborted)
    		return 0;
    
    	/* for TX_ONLY mode, be sure all words have shifted out */
    	if (tx && !rx) {
    		chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
    		if (mcspi->fifo_depth > 0) {
    			wait_res = mcspi_wait_for_reg_bit(chstat_reg, OMAP2_MCSPI_CHSTAT_TXFFE);
    			if (wait_res < 0)
    				dev_err(&spi->dev, "TXFFE timed out\n");
    		} else {
    			wait_res = mcspi_wait_for_reg_bit(chstat_reg, OMAP2_MCSPI_CHSTAT_TXS);
    			if (wait_res < 0)
    				dev_err(&spi->dev, "TXS timed out\n");
    		}
    		if (wait_res >= 0 && (mcspi_wait_for_reg_bit(chstat_reg,
    							     OMAP2_MCSPI_CHSTAT_EOT) < 0))
    			dev_err(&spi->dev, "EOT timed out\n");
    	}
    
    	return count;
    }
    
    static unsigned
    omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
    {
    	struct omap2_mcspi_cs	*cs = spi->controller_state;
    	unsigned int		count, c;
    	u32			l;
    	void __iomem		*base = cs->base;
    	void __iomem		*tx_reg;
    	void __iomem		*rx_reg;
    	void __iomem		*chstat_reg;
    	int			word_len;
    
    	count = xfer->len;
    	c = count;
    	word_len = cs->word_len;
    
    	l = mcspi_cached_chconf0(spi);
    
    	/* We store the pre-calculated register addresses on stack to speed
    	 * up the transfer loop. */
    	tx_reg		= base + OMAP2_MCSPI_TX0;
    	rx_reg		= base + OMAP2_MCSPI_RX0;
    	chstat_reg	= base + OMAP2_MCSPI_CHSTAT0;
    
    	if (c < (word_len>>3))
    		return 0;
    
    	if (word_len <= 8) {
    		u8		*rx;
    		const u8	*tx;
    
    		rx = xfer->rx_buf;
    		tx = xfer->tx_buf;
    
    		do {
    			c -= 1;
    			if (tx != NULL) {
    				if (mcspi_wait_for_reg_bit(chstat_reg,
    						OMAP2_MCSPI_CHSTAT_TXS) < 0) {
    					dev_err(&spi->dev, "TXS timed out\n");
    					goto out;
    				}
    				dev_vdbg(&spi->dev, "write-%d %02x\n",
    						word_len, *tx);
    				writel_relaxed(*tx++, tx_reg);
    			}
    			if (rx != NULL) {
    				if (mcspi_wait_for_reg_bit(chstat_reg,
    						OMAP2_MCSPI_CHSTAT_RXS) < 0) {
    					dev_err(&spi->dev, "RXS timed out\n");
    					goto out;
    				}
    
    				if (c == 1 && tx == NULL &&
    				    (l & OMAP2_MCSPI_CHCONF_TURBO)) {
    					omap2_mcspi_set_enable(spi, 0);
    					*rx++ = readl_relaxed(rx_reg);
    					dev_vdbg(&spi->dev, "read-%d %02x\n",
    						    word_len, *(rx - 1));
    					if (mcspi_wait_for_reg_bit(chstat_reg,
    						OMAP2_MCSPI_CHSTAT_RXS) < 0) {
    						dev_err(&spi->dev,
    							"RXS timed out\n");
    						goto out;
    					}
    					c = 0;
    				} else if (c == 0 && tx == NULL) {
    					omap2_mcspi_set_enable(spi, 0);
    				}
    
    				*rx++ = readl_relaxed(rx_reg);
    				dev_vdbg(&spi->dev, "read-%d %02x\n",
    						word_len, *(rx - 1));
    			}
    		} while (c);
    	} else if (word_len <= 16) {
    		u16		*rx;
    		const u16	*tx;
    
    		rx = xfer->rx_buf;
    		tx = xfer->tx_buf;
    		do {
    			c -= 2;
    			if (tx != NULL) {
    				if (mcspi_wait_for_reg_bit(chstat_reg,
    						OMAP2_MCSPI_CHSTAT_TXS) < 0) {
    					dev_err(&spi->dev, "TXS timed out\n");
    					goto out;
    				}
    				dev_vdbg(&spi->dev, "write-%d %04x\n",
    						word_len, *tx);
    				writel_relaxed(*tx++, tx_reg);
    			}
    			if (rx != NULL) {
    				if (mcspi_wait_for_reg_bit(chstat_reg,
    						OMAP2_MCSPI_CHSTAT_RXS) < 0) {
    					dev_err(&spi->dev, "RXS timed out\n");
    					goto out;
    				}
    
    				if (c == 2 && tx == NULL &&
    				    (l & OMAP2_MCSPI_CHCONF_TURBO)) {
    					omap2_mcspi_set_enable(spi, 0);
    					*rx++ = readl_relaxed(rx_reg);
    					dev_vdbg(&spi->dev, "read-%d %04x\n",
    						    word_len, *(rx - 1));
    					if (mcspi_wait_for_reg_bit(chstat_reg,
    						OMAP2_MCSPI_CHSTAT_RXS) < 0) {
    						dev_err(&spi->dev,
    							"RXS timed out\n");
    						goto out;
    					}
    					c = 0;
    				} else if (c == 0 && tx == NULL) {
    					omap2_mcspi_set_enable(spi, 0);
    				}
    
    				*rx++ = readl_relaxed(rx_reg);
    				dev_vdbg(&spi->dev, "read-%d %04x\n",
    						word_len, *(rx - 1));
    			}
    		} while (c >= 2);
    	} else if (word_len <= 32) {
    		u32		*rx;
    		const u32	*tx;
    
    		rx = xfer->rx_buf;
    		tx = xfer->tx_buf;
    		do {
    			c -= 4;
    			if (tx != NULL) {
    				if (mcspi_wait_for_reg_bit(chstat_reg,
    						OMAP2_MCSPI_CHSTAT_TXS) < 0) {
    					dev_err(&spi->dev, "TXS timed out\n");
    					goto out;
    				}
    				dev_vdbg(&spi->dev, "write-%d %08x\n",
    						word_len, *tx);
    				writel_relaxed(*tx++, tx_reg);
    			}
    			if (rx != NULL) {
    				if (mcspi_wait_for_reg_bit(chstat_reg,
    						OMAP2_MCSPI_CHSTAT_RXS) < 0) {
    					dev_err(&spi->dev, "RXS timed out\n");
    					goto out;
    				}
    
    				if (c == 4 && tx == NULL &&
    				    (l & OMAP2_MCSPI_CHCONF_TURBO)) {
    					omap2_mcspi_set_enable(spi, 0);
    					*rx++ = readl_relaxed(rx_reg);
    					dev_vdbg(&spi->dev, "read-%d %08x\n",
    						    word_len, *(rx - 1));
    					if (mcspi_wait_for_reg_bit(chstat_reg,
    						OMAP2_MCSPI_CHSTAT_RXS) < 0) {
    						dev_err(&spi->dev,
    							"RXS timed out\n");
    						goto out;
    					}
    					c = 0;
    				} else if (c == 0 && tx == NULL) {
    					omap2_mcspi_set_enable(spi, 0);
    				}
    
    				*rx++ = readl_relaxed(rx_reg);
    				dev_vdbg(&spi->dev, "read-%d %08x\n",
    						word_len, *(rx - 1));
    			}
    		} while (c >= 4);
    	}
    
    	/* for TX_ONLY mode, be sure all words have shifted out */
    	if (xfer->rx_buf == NULL) {
    		if (mcspi_wait_for_reg_bit(chstat_reg,
    				OMAP2_MCSPI_CHSTAT_TXS) < 0) {
    			dev_err(&spi->dev, "TXS timed out\n");
    		} else if (mcspi_wait_for_reg_bit(chstat_reg,
    				OMAP2_MCSPI_CHSTAT_EOT) < 0)
    			dev_err(&spi->dev, "EOT timed out\n");
    
    		/* disable chan to purge rx datas received in TX_ONLY transfer,
    		 * otherwise these rx datas will affect the direct following
    		 * RX_ONLY transfer.
    		 */
    		omap2_mcspi_set_enable(spi, 0);
    	}
    out:
    	omap2_mcspi_set_enable(spi, 1);
    	return count - c;
    }
    
    static u32 omap2_mcspi_calc_divisor(u32 speed_hz)
    {
    	u32 div;
    
    	for (div = 0; div < 15; div++)
    		if (speed_hz >= (OMAP2_MCSPI_MAX_FREQ >> div))
    			return div;
    
    	return 15;
    }
    
    /* called only when no transfer is active to this device */
    static int omap2_mcspi_setup_transfer(struct spi_device *spi,
    		struct spi_transfer *t)
    {
    	struct omap2_mcspi_cs *cs = spi->controller_state;
    	struct omap2_mcspi *mcspi;
    	u32 l = 0, clkd = 0, div, extclk = 0, clkg = 0;
    	u8 word_len = spi->bits_per_word;
    	u32 speed_hz = spi->max_speed_hz;
    
    	mcspi = spi_master_get_devdata(spi->master);
    
    	if (t != NULL && t->bits_per_word)
    		word_len = t->bits_per_word;
    
    	cs->word_len = word_len;
    
    	if (t && t->speed_hz)
    		speed_hz = t->speed_hz;
    
    	speed_hz = min_t(u32, speed_hz, OMAP2_MCSPI_MAX_FREQ);
    	if (speed_hz < (OMAP2_MCSPI_MAX_FREQ / OMAP2_MCSPI_MAX_DIVIDER)) {
    		clkd = omap2_mcspi_calc_divisor(speed_hz);
    		speed_hz = OMAP2_MCSPI_MAX_FREQ >> clkd;
    		clkg = 0;
    	} else {
    		div = (OMAP2_MCSPI_MAX_FREQ + speed_hz - 1) / speed_hz;
    		speed_hz = OMAP2_MCSPI_MAX_FREQ / div;
    		clkd = (div - 1) & 0xf;
    		extclk = (div - 1) >> 4;
    		clkg = OMAP2_MCSPI_CHCONF_CLKG;
    	}
    
    	l = mcspi_cached_chconf0(spi);
    
    	/* standard 4-wire master mode:  SCK, MOSI/out, MISO/in, nCS
    	 * REVISIT: this controller could support SPI_3WIRE mode.
    	 */
    	if (mcspi->pin_dir == MCSPI_PINDIR_D0_IN_D1_OUT) {
    		l &= ~OMAP2_MCSPI_CHCONF_IS;
    		l &= ~OMAP2_MCSPI_CHCONF_DPE1;
    		l |= OMAP2_MCSPI_CHCONF_DPE0;
    	} else {
    		l |= OMAP2_MCSPI_CHCONF_IS;
    		l |= OMAP2_MCSPI_CHCONF_DPE1;
    		l &= ~OMAP2_MCSPI_CHCONF_DPE0;
    	}
    
    	/* wordlength */
    	l &= ~OMAP2_MCSPI_CHCONF_WL_MASK;
    	l |= (word_len - 1) << 7;
    
    	/* set chipselect polarity; manage with FORCE */
    	if (!(spi->mode & SPI_CS_HIGH))
    		l |= OMAP2_MCSPI_CHCONF_EPOL;	/* active-low; normal */
    	else
    		l &= ~OMAP2_MCSPI_CHCONF_EPOL;
    
    	/* set clock divisor */
    	l &= ~OMAP2_MCSPI_CHCONF_CLKD_MASK;
    	l |= clkd << 2;
    
    	/* set clock granularity */
    	l &= ~OMAP2_MCSPI_CHCONF_CLKG;
    	l |= clkg;
    	if (clkg) {
    		cs->chctrl0 &= ~OMAP2_MCSPI_CHCTRL_EXTCLK_MASK;
    		cs->chctrl0 |= extclk << 8;
    		mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, cs->chctrl0);
    	}
    
    	/* set SPI mode 0..3 */
    	if (spi->mode & SPI_CPOL)
    		l |= OMAP2_MCSPI_CHCONF_POL;
    	else
    		l &= ~OMAP2_MCSPI_CHCONF_POL;
    	if (spi->mode & SPI_CPHA)
    		l |= OMAP2_MCSPI_CHCONF_PHA;
    	else
    		l &= ~OMAP2_MCSPI_CHCONF_PHA;
    
    	mcspi_write_chconf0(spi, l);
    
    	cs->mode = spi->mode;
    
    	dev_dbg(&spi->dev, "setup: speed %d, sample %s edge, clk %s\n",
    			speed_hz,
    			(spi->mode & SPI_CPHA) ? "trailing" : "leading",
    			(spi->mode & SPI_CPOL) ? "inverted" : "normal");
    
    	return 0;
    }
    
    /*
     * Note that we currently allow DMA only if we get a channel
     * for both rx and tx. Otherwise we'll do PIO for both rx and tx.
     */
    static int omap2_mcspi_request_dma(struct omap2_mcspi *mcspi,
    				   struct omap2_mcspi_dma *mcspi_dma)
    {
    	int ret = 0;
    
    	mcspi_dma->dma_rx = dma_request_chan(mcspi->dev,
    					     mcspi_dma->dma_rx_ch_name);
    	if (IS_ERR(mcspi_dma->dma_rx)) {
    		ret = PTR_ERR(mcspi_dma->dma_rx);
    		mcspi_dma->dma_rx = NULL;
    		goto no_dma;
    	}
    
    	mcspi_dma->dma_tx = dma_request_chan(mcspi->dev,
    					     mcspi_dma->dma_tx_ch_name);
    	if (IS_ERR(mcspi_dma->dma_tx)) {
    		ret = PTR_ERR(mcspi_dma->dma_tx);
    		mcspi_dma->dma_tx = NULL;
    		dma_release_channel(mcspi_dma->dma_rx);
    		mcspi_dma->dma_rx = NULL;
    	}
    	
    	if (mcspi_dma->dma_rx)
    		dev_info(mcspi->dev, "RX DMA enabled\n");
    
    	if (mcspi_dma->dma_tx)
    		dev_info(mcspi->dev, "TX DMA enabled\n");
    
    no_dma:
    	return ret;
    }
    
    static void omap2_mcspi_release_dma(struct spi_master *master)
    {
    	struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
    	struct omap2_mcspi_dma	*mcspi_dma;
    	int i;
    
    	for (i = 0; i < master->num_chipselect; i++) {
    		mcspi_dma = &mcspi->dma_channels[i];
    
    		if (mcspi_dma->dma_rx) {
    			dma_release_channel(mcspi_dma->dma_rx);
    			mcspi_dma->dma_rx = NULL;
    		}
    		if (mcspi_dma->dma_tx) {
    			dma_release_channel(mcspi_dma->dma_tx);
    			mcspi_dma->dma_tx = NULL;
    		}
    	}
    }
    
    static void omap2_mcspi_cleanup(struct spi_device *spi)
    {
    	struct omap2_mcspi_cs	*cs;
    
    	if (spi->controller_state) {
    		/* Unlink controller state from context save list */
    		cs = spi->controller_state;
    		list_del(&cs->node);
    
    		kfree(cs);
    	}
    }
    
    static int omap2_mcspi_setup(struct spi_device *spi)
    {
    	bool			initial_setup = false;
    	int			ret;
    	struct omap2_mcspi	*mcspi = spi_master_get_devdata(spi->master);
    	struct omap2_mcspi_regs	*ctx = &mcspi->ctx;
    	struct omap2_mcspi_cs	*cs = spi->controller_state;
    
    	if (!cs) {
    		cs = kzalloc(sizeof *cs, GFP_KERNEL);
    		if (!cs)
    			return -ENOMEM;
    		cs->base = mcspi->base + spi->chip_select * 0x14;
    		cs->phys = mcspi->phys + spi->chip_select * 0x14;
    		cs->mode = 0;
    		cs->chconf0 = 0;
    		cs->chctrl0 = 0;
    		spi->controller_state = cs;
    		/* Link this to context save list */
    		list_add_tail(&cs->node, &ctx->cs);
    		initial_setup = true;
    	}
    
    	ret = pm_runtime_get_sync(mcspi->dev);
    	if (ret < 0) {
    		pm_runtime_put_noidle(mcspi->dev);
    		if (initial_setup)
    			omap2_mcspi_cleanup(spi);
    
    		return ret;
    	}
    
    	ret = omap2_mcspi_setup_transfer(spi, NULL);
    	if (ret && initial_setup)
    		omap2_mcspi_cleanup(spi);
    
    	pm_runtime_mark_last_busy(mcspi->dev);
    	pm_runtime_put_autosuspend(mcspi->dev);
    
    	return ret;
    }
    
    static irqreturn_t omap2_mcspi_irq_handler(int irq, void *data)
    {
    	struct omap2_mcspi *mcspi = data;
    	u32 irqstat;
    
    	irqstat	= mcspi_read_reg(mcspi->master, OMAP2_MCSPI_IRQSTATUS);
    	if (!irqstat)
    		return IRQ_NONE;
    
    	/* Disable IRQ and wakeup slave xfer task */
    	mcspi_write_reg(mcspi->master, OMAP2_MCSPI_IRQENABLE, 0);
    	if (irqstat & OMAP2_MCSPI_IRQSTATUS_EOW) {
    		complete_all(&mcspi->txrxdone);
    		mcspi_write_reg(mcspi->master, OMAP2_MCSPI_IRQSTATUS, OMAP2_MCSPI_IRQSTATUS_EOW);
    	}
    
    	return IRQ_HANDLED;
    }
    
    static int omap2_mcspi_slave_abort(struct spi_master *master)
    {
    	struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
    
    	mcspi->slave_aborted = true;
    	complete_all(&mcspi->txrxdone);
    
    	return 0;
    }
    
    static int omap2_mcspi_transfer_one(struct spi_master *master,
    				    struct spi_device *spi,
    				    struct spi_transfer *t)
    {
    
    	/* We only enable one channel at a time -- the one whose message is
    	 * -- although this controller would gladly
    	 * arbitrate among multiple channels.  This corresponds to "single
    	 * channel" master mode.  As a side effect, we need to manage the
    	 * chipselect with the FORCE bit ... CS != channel enable.
    	 */
    
    	struct omap2_mcspi		*mcspi;
    	struct omap2_mcspi_dma		*mcspi_dma;
    	struct omap2_mcspi_cs		*cs;
    	struct omap2_mcspi_device_config *cd;
    	int				par_override = 0;
    	int				status = 0;
    	u32				chconf;
    
    	mcspi = spi_master_get_devdata(master);
    	mcspi_dma = mcspi->dma_channels + spi->chip_select;
    	cs = spi->controller_state;
    	cd = spi->controller_data;
    
    	/*
    	 * The slave driver could have changed spi->mode in which case
    	 * it will be different from cs->mode (the current hardware setup).
    	 * If so, set par_override (even though its not a parity issue) so
    	 * omap2_mcspi_setup_transfer will be called to configure the hardware
    	 * with the correct mode on the first iteration of the loop below.
    	 */
    	if (spi->mode != cs->mode)
    		par_override = 1;
    
    	omap2_mcspi_set_enable(spi, 0);
    
    	if (spi->cs_gpiod)
    		omap2_mcspi_set_cs(spi, spi->mode & SPI_CS_HIGH);
    
    	if (par_override ||
    	    (t->speed_hz != spi->max_speed_hz) ||
    	    (t->bits_per_word != spi->bits_per_word)) {
    		par_override = 1;
    		status = omap2_mcspi_setup_transfer(spi, t);
    		if (status < 0)
    			goto out;
    		if (t->speed_hz == spi->max_speed_hz &&
    		    t->bits_per_word == spi->bits_per_word)
    			par_override = 0;
    	}
    	if (cd && cd->cs_per_word) {
    		chconf = mcspi->ctx.modulctrl;
    		chconf &= ~OMAP2_MCSPI_MODULCTRL_SINGLE;
    		mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, chconf);
    		mcspi->ctx.modulctrl =
    			mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL);
    	}
    
    	chconf = mcspi_cached_chconf0(spi);
    	chconf &= ~OMAP2_MCSPI_CHCONF_TRM_MASK;
    	chconf &= ~OMAP2_MCSPI_CHCONF_TURBO;
    
    	if (t->tx_buf == NULL)
    		chconf |= OMAP2_MCSPI_CHCONF_TRM_RX_ONLY;
    	else if (t->rx_buf == NULL)
    		chconf |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY;
    
    	if (cd && cd->turbo_mode && t->tx_buf == NULL) {
    		/* Turbo mode is for more than one word */
    		if (t->len > ((cs->word_len + 7) >> 3))
    			chconf |= OMAP2_MCSPI_CHCONF_TURBO;
    	}
    
    	mcspi_write_chconf0(spi, chconf);
    
    	if (t->len) {
    		unsigned	count;
    
    		if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
    		    master->cur_msg_mapped &&
    		    master->can_dma(master, spi, t))
    			omap2_mcspi_set_fifo(spi, t, 1);
    
    		omap2_mcspi_set_enable(spi, 1);
    
    		/* RX_ONLY mode needs dummy data in TX reg */
    		if (t->tx_buf == NULL)
    			writel_relaxed(0, cs->base
    					+ OMAP2_MCSPI_TX0);
    
    		if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
    		    master->cur_msg_mapped &&
    		    master->can_dma(master, spi, t))
    			count = omap2_mcspi_txrx_dma(spi, t);
    		else
    			count = omap2_mcspi_txrx_pio(spi, t);
    
    		if (count != t->len) {
    			status = -EIO;
    			goto out;
    		}
    	}
    
    	omap2_mcspi_set_enable(spi, 0);
    
    	if (mcspi->fifo_depth > 0)
    		omap2_mcspi_set_fifo(spi, t, 0);
    
    out:
    	/* Restore defaults if they were overriden */
    	if (par_override) {
    		par_override = 0;
    		status = omap2_mcspi_setup_transfer(spi, NULL);
    	}
    
    	if (cd && cd->cs_per_word) {
    		chconf = mcspi->ctx.modulctrl;
    		chconf |= OMAP2_MCSPI_MODULCTRL_SINGLE;
    		mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, chconf);
    		mcspi->ctx.modulctrl =
    			mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL);
    	}
    
    	omap2_mcspi_set_enable(spi, 0);
    
    	if (spi->cs_gpiod)
    		omap2_mcspi_set_cs(spi, !(spi->mode & SPI_CS_HIGH));
    
    	if (mcspi->fifo_depth > 0 && t)
    		omap2_mcspi_set_fifo(spi, t, 0);
    
    	return status;
    }
    
    static int omap2_mcspi_prepare_message(struct spi_master *master,
    				       struct spi_message *msg)
    {
    	struct omap2_mcspi	*mcspi = spi_master_get_devdata(master);
    	struct omap2_mcspi_regs	*ctx = &mcspi->ctx;
    	struct omap2_mcspi_cs	*cs;
    
    	/* Only a single channel can have the FORCE bit enabled
    	 * in its chconf0 register.
    	 * Scan all channels and disable them except the current one.
    	 * A FORCE can remain from a last transfer having cs_change enabled
    	 */
    	list_for_each_entry(cs, &ctx->cs, node) {
    		if (msg->spi->controller_state == cs)
    			continue;
    
    		if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE)) {
    			cs->chconf0 &= ~OMAP2_MCSPI_CHCONF_FORCE;
    			writel_relaxed(cs->chconf0,
    					cs->base + OMAP2_MCSPI_CHCONF0);
    			readl_relaxed(cs->base + OMAP2_MCSPI_CHCONF0);
    		}
    	}
    
    	return 0;
    }
    
    static bool omap2_mcspi_can_dma(struct spi_master *master,
    				struct spi_device *spi,
    				struct spi_transfer *xfer)
    {
    	struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
    	struct omap2_mcspi_dma *mcspi_dma =
    		&mcspi->dma_channels[spi->chip_select];
    
    	if (!mcspi_dma->dma_rx || !mcspi_dma->dma_tx)
    		return false;
    
    	if (spi_controller_is_slave(master))
    		return true;
    
    	master->dma_rx = mcspi_dma->dma_rx;
    	master->dma_tx = mcspi_dma->dma_tx;
    
    	return (xfer->len >= DMA_MIN_BYTES);
    }
    
    static size_t omap2_mcspi_max_xfer_size(struct spi_device *spi)
    {
    	struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
    	struct omap2_mcspi_dma *mcspi_dma =
    		&mcspi->dma_channels[spi->chip_select];
    
    	if (mcspi->max_xfer_len && mcspi_dma->dma_rx)
    		return mcspi->max_xfer_len;
    
    	return SIZE_MAX;
    }
    
    static int omap2_mcspi_controller_setup(struct omap2_mcspi *mcspi)
    {
    	struct spi_master	*master = mcspi->master;
    	struct omap2_mcspi_regs	*ctx = &mcspi->ctx;
    	int			ret = 0;
    
    	ret = pm_runtime_get_sync(mcspi->dev);
    	if (ret < 0) {
    		pm_runtime_put_noidle(mcspi->dev);
    
    		return ret;
    	}
    
    	mcspi_write_reg(master, OMAP2_MCSPI_WAKEUPENABLE,
    			OMAP2_MCSPI_WAKEUPENABLE_WKEN);
    	ctx->wakeupenable = OMAP2_MCSPI_WAKEUPENABLE_WKEN;
    
    	omap2_mcspi_set_mode(master);
    	pm_runtime_mark_last_busy(mcspi->dev);
    	pm_runtime_put_autosuspend(mcspi->dev);
    	return 0;
    }
    
    /*
     * When SPI wake up from off-mode, CS is in activate state. If it was in
     * inactive state when driver was suspend, then force it to inactive state at
     * wake up.
     */
    static int omap_mcspi_runtime_resume(struct device *dev)
    {
    	struct spi_master *master = dev_get_drvdata(dev);
    	struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
    	struct omap2_mcspi_regs *ctx = &mcspi->ctx;
    	struct omap2_mcspi_cs *cs;
    
    	/* McSPI: context restore */
    	mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, ctx->modulctrl);
    	mcspi_write_reg(master, OMAP2_MCSPI_WAKEUPENABLE, ctx->wakeupenable);
    
    	list_for_each_entry(cs, &ctx->cs, node) {
    		/*
    		 * We need to toggle CS state for OMAP take this
    		 * change in account.
    		 */
    		if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE) == 0) {
    			cs->chconf0 |= OMAP2_MCSPI_CHCONF_FORCE;
    			writel_relaxed(cs->chconf0,
    				       cs->base + OMAP2_MCSPI_CHCONF0);
    			cs->chconf0 &= ~OMAP2_MCSPI_CHCONF_FORCE;
    			writel_relaxed(cs->chconf0,
    				       cs->base + OMAP2_MCSPI_CHCONF0);
    		} else {
    			writel_relaxed(cs->chconf0,
    				       cs->base + OMAP2_MCSPI_CHCONF0);
    		}
    	}
    
    	return 0;
    }
    
    static struct omap2_mcspi_platform_config omap2_pdata = {
    	.regs_offset = 0,
    };
    
    static struct omap2_mcspi_platform_config omap4_pdata = {
    	.regs_offset = OMAP4_MCSPI_REG_OFFSET,
    };
    
    static struct omap2_mcspi_platform_config am654_pdata = {
    	.regs_offset = OMAP4_MCSPI_REG_OFFSET,
    	.max_xfer_len = SZ_4K - 1,
    };
    
    static const struct of_device_id omap_mcspi_of_match[] = {
    	{
    		.compatible = "ti,omap2-mcspi",
    		.data = &omap2_pdata,
    	},
    	{
    		.compatible = "ti,omap4-mcspi",
    		.data = &omap4_pdata,
    	},
    	{
    		.compatible = "ti,am654-mcspi",
    		.data = &am654_pdata,
    	},
    	{ },
    };
    MODULE_DEVICE_TABLE(of, omap_mcspi_of_match);
    
    static int omap2_mcspi_probe(struct platform_device *pdev)
    {
    	struct spi_master	*master;
    	const struct omap2_mcspi_platform_config *pdata;
    	struct omap2_mcspi	*mcspi;
    	struct resource		*r;
    	int			status = 0, i;
    	u32			regs_offset = 0;
    	struct device_node	*node = pdev->dev.of_node;
    	const struct of_device_id *match;
    
    	if (of_property_read_bool(node, "spi-slave"))
    		master = spi_alloc_slave(&pdev->dev, sizeof(*mcspi));
    	else
    		master = spi_alloc_master(&pdev->dev, sizeof(*mcspi));
    	if (!master)
    		return -ENOMEM;
    
    	/* the spi->mode bits understood by this driver: */
    	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
    	master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
    	master->setup = omap2_mcspi_setup;
    	master->auto_runtime_pm = true;
    	master->prepare_message = omap2_mcspi_prepare_message;
    	master->can_dma = omap2_mcspi_can_dma;
    	master->transfer_one = omap2_mcspi_transfer_one;
    	master->set_cs = omap2_mcspi_set_cs;
    	master->cleanup = omap2_mcspi_cleanup;
    	master->slave_abort = omap2_mcspi_slave_abort;
    	master->dev.of_node = node;
    	master->max_speed_hz = OMAP2_MCSPI_MAX_FREQ;
    	master->min_speed_hz = OMAP2_MCSPI_MAX_FREQ >> 15;
    	master->use_gpio_descriptors = true;
    
    	platform_set_drvdata(pdev, master);
    
    	mcspi = spi_master_get_devdata(master);
    	mcspi->master = master;
    
    	match = of_match_device(omap_mcspi_of_match, &pdev->dev);
    	if (match) {
    		u32 num_cs = 1; /* default number of chipselect */
    		pdata = match->data;
    
    		of_property_read_u32(node, "ti,spi-num-cs", &num_cs);
    		master->num_chipselect = num_cs;
    		if (of_get_property(node, "ti,pindir-d0-out-d1-in", NULL))
    			mcspi->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN;
    	} else {
    		pdata = dev_get_platdata(&pdev->dev);
    		master->num_chipselect = pdata->num_cs;
    		mcspi->pin_dir = pdata->pin_dir;
    	}
    	regs_offset = pdata->regs_offset;
    	if (pdata->max_xfer_len) {
    		mcspi->max_xfer_len = pdata->max_xfer_len;
    		master->max_transfer_size = omap2_mcspi_max_xfer_size;
    	}
    
    	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    	mcspi->base = devm_ioremap_resource(&pdev->dev, r);
    	if (IS_ERR(mcspi->base)) {
    		status = PTR_ERR(mcspi->base);
    		goto free_master;
    	}
    	mcspi->phys = r->start + regs_offset;
    	mcspi->base += regs_offset;
    
    	mcspi->dev = &pdev->dev;
    
    	INIT_LIST_HEAD(&mcspi->ctx.cs);
    
    	mcspi->dma_channels = devm_kcalloc(&pdev->dev, master->num_chipselect,
    					   sizeof(struct omap2_mcspi_dma),
    					   GFP_KERNEL);
    	if (mcspi->dma_channels == NULL) {
    		status = -ENOMEM;
    		goto free_master;
    	}
    
    	for (i = 0; i < master->num_chipselect; i++) {
    		sprintf(mcspi->dma_channels[i].dma_rx_ch_name, "rx%d", i);
    		sprintf(mcspi->dma_channels[i].dma_tx_ch_name, "tx%d", i);
    
    		status = omap2_mcspi_request_dma(mcspi,
    						 &mcspi->dma_channels[i]);
    		if (status == -EPROBE_DEFER)
    			goto free_master;
    	}
    
    	status = platform_get_irq(pdev, 0);
    	if (status == -EPROBE_DEFER)
    		goto free_master;
    	if (status < 0) {
    		dev_err(&pdev->dev, "no irq resource found\n");
    		goto free_master;
    	}
    	init_completion(&mcspi->txrxdone);
    	status = devm_request_irq(&pdev->dev, status,
    				  omap2_mcspi_irq_handler, 0, pdev->name,
    				  mcspi);
    	if (status) {
    		dev_err(&pdev->dev, "Cannot request IRQ");
    		goto free_master;
    	}
    
    	pm_runtime_use_autosuspend(&pdev->dev);
    	pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);
    	pm_runtime_enable(&pdev->dev);
    
    	status = omap2_mcspi_controller_setup(mcspi);
    	if (status < 0)
    		goto disable_pm;
    
    	status = devm_spi_register_controller(&pdev->dev, master);
    	if (status < 0)
    		goto disable_pm;
    
    	return status;
    
    disable_pm:
    	pm_runtime_dont_use_autosuspend(&pdev->dev);
    	pm_runtime_put_sync(&pdev->dev);
    	pm_runtime_disable(&pdev->dev);
    free_master:
    	omap2_mcspi_release_dma(master);
    	spi_master_put(master);
    	return status;
    }
    
    static int omap2_mcspi_remove(struct platform_device *pdev)
    {
    	struct spi_master *master = platform_get_drvdata(pdev);
    	struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
    
    	omap2_mcspi_release_dma(master);
    
    	pm_runtime_dont_use_autosuspend(mcspi->dev);
    	pm_runtime_put_sync(mcspi->dev);
    	pm_runtime_disable(&pdev->dev);
    
    	return 0;
    }
    
    /* work with hotplug and coldplug */
    MODULE_ALIAS("platform:omap2_mcspi");
    
    static int __maybe_unused omap2_mcspi_suspend(struct device *dev)
    {
    	struct spi_master *master = dev_get_drvdata(dev);
    	struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
    	int error;
    
    	error = pinctrl_pm_select_sleep_state(dev);
    	if (error)
    		dev_warn(mcspi->dev, "%s: failed to set pins: %i\n",
    			 _func_, error);
    
    	error = spi_master_suspend(master);
    	if (error)
    		dev_warn(mcspi->dev, "%s: master suspend failed: %i\n",
    			 _func_, error);
    
    	return pm_runtime_force_suspend(dev);
    }
    
    static int __maybe_unused omap2_mcspi_resume(struct device *dev)
    {
    	struct spi_master *master = dev_get_drvdata(dev);
    	struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
    	int error;
    
    	error = pinctrl_pm_select_default_state(dev);
    	if (error)
    		dev_warn(mcspi->dev, "%s: failed to set pins: %i\n",
    			 _func_, error);
    
    	error = spi_master_resume(master);
    	if (error)
    		dev_warn(mcspi->dev, "%s: master resume failed: %i\n",
    			 _func_, error);
    
    	return pm_runtime_force_resume(dev);
    }
    
    static const struct dev_pm_ops omap2_mcspi_pm_ops = {
    	SET_SYSTEM_SLEEP_PM_OPS(omap2_mcspi_suspend,
    				omap2_mcspi_resume)
    	.runtime_resume	= omap_mcspi_runtime_resume,
    };
    
    static struct platform_driver omap2_mcspi_driver = {
    	.driver = {
    		.name =		"omap2_mcspi",
    		.pm =		&omap2_mcspi_pm_ops,
    		.of_match_table = omap_mcspi_of_match,
    	},
    	.probe =	omap2_mcspi_probe,
    	.remove =	omap2_mcspi_remove,
    };
    
    module_platform_driver(omap2_mcspi_driver);
    MODULE_LICENSE("GPL");

  • Hi Siva,

    did you trigger/run any DMA transfers from userspace before checking the log? Like using `spidev_test` as suggested in the E2E FAQ? What was your command line? Did you add the needed DMA properties to the `main_spi0` device tree node, and confirmed those were added?

    Regards, Andreas

  • Hi Andreas,

    Yes I tried spedev_test and checked the waveform in scope. Here is the part of the main_spi0 code.

    &main_spi0 {
    status = "okay";
    #address-cells = <1>;
    #size-cells = <0>;
    pinctrl-0 = <&main_spi0_pins_default>;
    pinctrl-names = "default";
    dmas = <&main_pktdma 0xc300 0>, <&main_pktdma 0x4300 0>;
    dma-names = "tx0", "rx0";
    spidev@0 {
    /*
    * Using spidev compatible is warned loudly,
    * thus use another equivalent compatible id
    * from spidev.
    */
    compatible = "rohm,dh2228fv";
    spi-max-frequency = <24000000>;
    reg = <0>;
    };
    };

    thanks,

    siva.

  • Hi Siva,

    what SDK version are you using? If I recall correctly you need at least SDK v9.1 for DMA to work together with main_spi0 correctly. Please confirm your SDK version.

    If this isn't the issue, can you post your entire boot/kernel log?

    Regards, Andreas

  • Hi Andreas,I am using 8.6 version. I tried to download 9.01 and in end of the download,it stops. I will update you once I install 9.01 .

    thanks,

    siva.

  • Hi Andreas,

    Is there any site maintenance going on? We couldnt download the sdk. I tried wget in linux pc also. No luck. Changed different wifi too. No use. Please let me know. 

    thanks,

    siva.

  • Hi Siva,

    yes indeed it looks like we had some (rare) web issues in the last 24hrs or so but the SDK seems to be accessible again now. Please make sure to download the latest one (v9.2) as of now (as a good practice) https://www.ti.com/tool/download/PROCESSOR-SDK-LINUX-AM62X/09.02.01.10

    Regards, Andreas

  • Hi Andreas,

    Finally I downloaded 9.02 version and DMA works fine. Thanks for your detailed reply. But I couldnt rampup frequency beyond 25MHZ. But I need 40MHZ speed to achieve the required latency. Any inputs on this issue? 

    thanks,

    siva.

  • Hi Siva,

    Finally I downloaded 9.02 version and DMA works fine. Thanks for your detailed reply

    Glad to hear this piece is working now, thanks for confirming.

    ut I couldnt rampup frequency beyond 25MHZ. But I need 40MHZ speed to achieve the required latency

    Well you are limited by what the clock divider inside the McSPI peripheral module can provide. With the module being clocked by a 50MHz clock internally as per TRM you get the following...

    Can you see if 50MHz works for you? Perhaps you can use that instead to meet your latency requirements.

    Regards, Andreas

  • Hi Andreas,

    There is problem with 50MHZ. My slave device max limit is 40MHZ. Is there any other workaround?

    thanks,

    siva.

  • Hi Siva,

    There is problem with 50MHZ. My slave device max limit is 40MHZ. Is there any other workaround?

    I don't see another easy / quick workaround. I tried lowering the input frequency going into the SPI module from 50MHz to 40MHz through Device Manager clock requests but the firmware does not support a frequency other than 50MHz, so we are bound to this (and the derived frequencies via integer dividers from above table).

    What is your slave device? Perhaps we can figure out another way to find a solution on a system level to get you the throughout you need.

    Regards, Andreas

  • Hi Andreas,

    We use HI-3220 as a slave and maximum SPI clocking is 40mhz. When I look at the TRM page.139, MCSPI clock source as MAINSYSCLK0/10. Is it not possible to crank it up to higher frequencies?

    thanks,

    siva. 

  • Hi Siva,

    We use HI-3220 as a slave and maximum SPI clocking is 40mhz. When I look at the TRM page.139, MCSPI clock source as MAINSYSCLK0/10. Is it not possible to crank it up to higher frequencies?

    I was researching this today some more, so this /10 clock divider feeding into the McSPI peripheral is fixed. Then if you think oh ok then let's just increase the clock frequency going into this divider, the issue then is that this particular clock source is probably sourcing ~20 different peripheral modules, so you can't simply modify it without some larger system-wide impact (you can use the "AM62X Clock Tree" tool available at https://dev.ti.com/sysconfig to inspect the clock tree & dependencies and possible settings),.

    From thereon I see two possible methods to still get 40MHz SPI communication that you want, but both are not straightforward and may or may not easily work, and will require some amount of custom SW development.

    1. Implement a custom SPI peripheral using the on-chip "PRU-ICSS" accelerator, or

    2. Use the OSPI peripheral module, which has a lot more flexibility from a clocking POV

    Both (1) and (2) will require driver development work. For option (2) this may or may not be possible as the OSPI module is targeted for memory-type SPI devices, and that's what the current Linux driver supports. Still, let me go and check with the team if it is theoretically possible to use it as a "SPI controller", w/ some software enhancements (adding the needed transfer routines).

    Regards, Andreas

  • Hi Andreas,

    We have a problem with RT Linux kernel  09.02.01.09 kernel build. After changing the device tree for SPI-0 inclusion, we built the kernel and loaded into eval board (SK-AM62). We also changed the DMA_MIN_LENGTH to 8. Now the spi devices are not listed in /dev. Please find the kernel log for your reference. I suspect some issue with kernel building process. When you look at last 10 line, when we try to manually insert the ko moduel, there is some mismatch in version. 

    KERN_BOOT_LOG_DIRTY.txt
    BOOT LOG � AM 62 � EVM � V09.02.01.09 � After Kernel ReBuild
    
    U-Boot SPL 2023.04-ti-gf9b966c67473 (Mar 19 2024 - 20:31:40 +0000)
    SYSFW ABI: 3.1 (firmware rev 0x0009 '9.2.7--v09.02.07 (Kool Koala)')
    SPL initial stack usage: 13408 bytes
    Trying to boot from MMC2
    Warning: Detected image signing certificate on GP device. Skipping certificate to prevent boot failure. This will fail if the image was also encrypted
    Warning: Detected image signing certificate on GP device. Skipping certificate to prevent boot failure. This will fail if the image was also encrypted
    Warning: Detected image signing certificate on GP device. Skipping certificate to prevent boot failure. This will fail if the image was also encrypted
    Warning: Detected image signing certificate on GP device. Skipping certificate to prevent boot failure. This will fail if the image was also encrypted
    Warning: Detected image signing certificate on GP device. Skipping certificate to prevent boot failure. This will fail if the image was also encrypted
    Starting ATF on ARM64 core...
    
    NOTICE:  BL31: v2.10.0(release):v2.10.0-367-g00f1ec6b87-dirty
    NOTICE:  BL31: Built : 16:09:05, Feb  9 2024
    
    U-Boot SPL 2023.04-ti-gf9b966c67473 (Mar 19 2024 - 20:31:40 +0000)
    SYSFW ABI: 3.1 (firmware rev 0x0009 '9.2.7--v09.02.07 (Kool Koala)')
    SPL initial stack usage: 1856 bytes
    Error (-2): cannot determine file size
    Trying to boot from MMC2
    Warning: Detected image signing certificate on GP device. Skipping certificate to prevent boot failure. This will fail if the image was also encrypted
    Warning: Detected image signing certificate on GP device. Skipping certificate to prevent boot failure. This will fail if the image was also encrypted
    
    
    U-Boot 2023.04-ti-gf9b966c67473 (Mar 19 2024 - 20:31:40 +0000)
    
    SoC:   AM62X SR1.0 GP
    Model: Texas Instruments AM625 SK
    EEPROM not available at 80, trying to read at 81
    Board: AM62-SKEVM rev E3
    DRAM:  no bloblist found!2 GiB
    Core:  72 devices, 32 uclasses, devicetree: separate
    MMC:   mmc@fa10000: 0, mmc@fa00000: 1
    Loading Environment from nowhere... OK
    In:    serial
    Out:   serial
    Err:   serial
    Net:   eth0: ethernet@8000000port@1
    Hit any key to stop autoboot:  0
    switch to partitions #0, OK
    mmc1 is current device
    SD/MMC found on device 1
    Failed to load 'boot.scr'
    Failed to load 'uEnv.txt'
    ## Error: "main_cpsw0_qsgmii_phyinit" not defined
    33329664 bytes read in 369 ms (86.1 MiB/s)
    63195 bytes read in 17 ms (3.5 MiB/s)
    Working FDT set to 88000000
    ## Flattened Device Tree blob at 88000000
       Booting using the fdt blob at 0x88000000
    Working FDT set to 88000000
       Loading Device Tree to 000000008feed000, end 000000008fffffff ... OK
    Working FDT set to 8feed000
    
    Starting kernel ...
    
    [    0.000000] Booting Linux on physical CPU 0x0000000000 [0x410fd034]
    [    0.000000] Linux version 6.1.80-rt26-dirty (aswin_ubunutu@aswin-ubuntu-hp-elitebook-840-g5) (aarch64-oe-linux-gcc (GCC) 11.4.0, GNU ld (GNU Binutils) 2.38.20220708) #1 SMP PREEMPT_RT Wed Jul 24 16:04:43 IST 2024
    [    0.000000] Machine model: Texas Instruments AM625 SK
    [    0.000000] earlycon: ns16550a0 at MMIO32 0x0000000002800000 (options '')
    [    0.000000] printk: bootconsole [ns16550a0] enabled
    [    0.000000] efi: UEFI not found.
    [    0.000000] Reserved memory: created CMA memory pool at 0x00000000f8000000, size 128 MiB
    [    0.000000] OF: reserved mem: initialized node linux,cma, compatible id shared-dma-pool
    [    0.000000] Reserved memory: created DMA memory pool at 0x000000009c800000, size 3 MiB
    [    0.000000] OF: reserved mem: initialized node ipc-memories@9c800000, compatible id shared-dma-pool
    [    0.000000] Reserved memory: created DMA memory pool at 0x000000009cb00000, size 1 MiB
    [    0.000000] OF: reserved mem: initialized node m4f-dma-memory@9cb00000, compatible id shared-dma-pool
    [    0.000000] Reserved memory: created DMA memory pool at 0x000000009cc00000, size 14 MiB
    [    0.000000] OF: reserved mem: initialized node m4f-memory@9cc00000, compatible id shared-dma-pool
    [    0.000000] Reserved memory: created DMA memory pool at 0x000000009da00000, size 1 MiB
    [    0.000000] OF: reserved mem: initialized node r5f-dma-memory@9da00000, compatible id shared-dma-pool
    [    0.000000] Reserved memory: created DMA memory pool at 0x000000009db00000, size 12 MiB
    [    0.000000] OF: reserved mem: initialized node r5f-memory@9db00000, compatible id shared-dma-pool
    [    0.000000] NUMA: No NUMA configuration found
    [    0.000000] NUMA: Faking a node at [mem 0x0000000080000000-0x00000000ffffffff]
    [    0.000000] NUMA: NODE_DATA [mem 0xf7faa980-0xf7facfff]
    [    0.000000] Zone ranges:
    [    0.000000]   DMA      [mem 0x0000000080000000-0x00000000ffffffff]
    [    0.000000]   DMA32    empty
    [    0.000000]   Normal   empty
    [    0.000000] Movable zone start for each node
    [    0.000000] Early memory node ranges
    [    0.000000]   node   0: [mem 0x0000000080000000-0x000000009c7fffff]
    [    0.000000]   node   0: [mem 0x000000009c800000-0x000000009e6fffff]
    [    0.000000]   node   0: [mem 0x000000009e700000-0x000000009e77ffff]
    [    0.000000]   node   0: [mem 0x000000009e780000-0x000000009fffffff]
    [    0.000000]   node   0: [mem 0x00000000a0000000-0x00000000ffffffff]
    [    0.000000] Initmem setup node 0 [mem 0x0000000080000000-0x00000000ffffffff]
    [    0.000000] psci: probing for conduit method from DT.
    [    0.000000] psci: PSCIv1.1 detected in firmware.
    [    0.000000] psci: Using standard PSCI v0.2 function IDs
    [    0.000000] psci: Trusted OS migration not required
    [    0.000000] psci: SMC Calling Convention v1.4
    [    0.000000] percpu: Embedded 23 pages/cpu s53568 r8192 d32448 u94208
    [    0.000000] Detected VIPT I-cache on CPU0
    [    0.000000] CPU features: detected: GIC system register CPU interface
    [    0.000000] CPU features: kernel page table isolation disabled by kernel configuration
    [    0.000000] CPU features: detected: ARM erratum 845719
    [    0.000000] alternatives: applying boot alternatives
    [    0.000000] Fallback order for Node 0: 0
    [    0.000000] Built 1 zonelists, mobility grouping on.  Total pages: 516096
    [    0.000000] Policy zone: DMA
    [    0.000000] Kernel command line: console=ttyS2,115200n8 earlycon=ns16550a,mmio32,0x02800000 mtdparts=spi-nand0:512k(ospi.tiboot3),2m(ospi.tispl),4m(ospi.u-boot),256k(ospi.env),256k(ospi.env.backup),98048k@32m(ospi.rootfs),256k@130816k(ospi.phypattern);omap2-nand.0:2m(NAND.tiboot3),2m(NAND.tispl),2m(NAND.tiboot3.backup),4m(NAND.u-boot),256k(NAND.u-boot-env),256k(NAND.u-boot-env.backup),-(NAND.file-system) root=PARTUUID=d2c3753a-02 rw rootfstype=ext4 rootwait
    [    0.000000] Dentry cache hash table entries: 262144 (order: 9, 2097152 bytes, linear)
    [    0.000000] Inode-cache hash table entries: 131072 (order: 8, 1048576 bytes, linear)
    [    0.000000] mem auto-init: stack:off, heap alloc:off, heap free:off
    [    0.000000] Memory: 1838388K/2097152K available (14784K kernel code, 3748K rwdata, 6604K rodata, 7296K init, 614K bss, 127692K reserved, 131072K cma-reserved)
    [    0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=4, Nodes=1
    [    0.000000] rcu: Preemptible hierarchical RCU implementation.
    [    0.000000] rcu:     RCU restricting CPUs from NR_CPUS=256 to nr_cpu_ids=4.
    [    0.000000] rcu:     RCU_SOFTIRQ processing moved to rcuc kthreads.
    [    0.000000]  No expedited grace period (rcu_normal_after_boot).
    [    0.000000] rcu: RCU calculated value of scheduler-enlistment delay is 100 jiffies.
    [    0.000000] rcu: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=4
    [    0.000000] NR_IRQS: 64, nr_irqs: 64, preallocated irqs: 0
    [    0.000000] GICv3: GIC: Using split EOI/Deactivate mode
    [    0.000000] GICv3: 256 SPIs implemented
    [    0.000000] GICv3: 0 Extended SPIs implemented
    [    0.000000] Root IRQ handler: 0xffff80000847b0a0
    [    0.000000] GICv3: GICv3 features: 16 PPIs
    [    0.000000] GICv3: CPU0: found redistributor 0 region 0:0x0000000001880000
    [    0.000000] ITS [mem 0x01820000-0x0182ffff]
    [    0.000000] GIC: enabling workaround for ITS: Socionext Synquacer pre-ITS
    [    0.000000] ITS@0x0000000001820000: Devices Table too large, reduce ids 20->19
    [    0.000000] ITS@0x0000000001820000: allocated 524288 Devices @80800000 (flat, esz 8, psz 64K, shr 0)
    [    0.000000] ITS: using cache flushing for cmd queue
    [    0.000000] GICv3: using LPI property table @0x0000000080020000
    [    0.000000] GIC: using cache flushing for LPI property table
    [    0.000000] GICv3: CPU0: using allocated LPI pending table @0x0000000080030000
    [    0.000000] rcu: srcu_init: Setting srcu_struct sizes based on contention.
    [    0.000000] arch_timer: cp15 timer(s) running at 200.00MHz (phys).
    [    0.000000] clocksource: arch_sys_counter: mask: 0x3ffffffffffffff max_cycles: 0x2e2049d3e8, max_idle_ns: 440795210634 ns
    [    0.000000] sched_clock: 58 bits at 200MHz, resolution 5ns, wraps every 4398046511102ns
    [    0.001588] Console: colour dummy device 80x25
    [    0.515414] Calibrating delay loop (skipped), value calculated using timer frequency.. 400.00 BogoMIPS (lpj=200000)
    [    0.515425] pid_max: default: 32768 minimum: 301
    [    0.515492] LSM: Security Framework initializing
    [    0.515626] Mount-cache hash table entries: 4096 (order: 3, 32768 bytes, linear)
    [    0.515649] Mountpoint-cache hash table entries: 4096 (order: 3, 32768 bytes, linear)
    [    0.517341] rcu: Hierarchical SRCU implementation.
    [    0.517349] rcu:     Max phase no-delay instances is 400.
    [    0.517394] printk: bootconsole [ns16550a0] printing thread started
    [    0.569884] Platform MSI: msi-controller@1820000 domain created
    [    0.570150] PCI/MSI: /bus@f0000/interrupt-controller@1800000/msi-controller@1820000 domain created
    [    0.570267] fsl-mc MSI: msi-controller@1820000 domain created
    [    0.572496] EFI services will not be available.
    [    0.572770] smp: Bringing up secondary CPUs ...
    [    0.573527] Detected VIPT I-cache on CPU1
    [    0.573641] GICv3: CPU1: found redistributor 1 region 0:0x00000000018a0000
    [    0.573658] GICv3: CPU1: using allocated LPI pending table @0x0000000080040000
    [    0.573713] CPU1: Booted secondary processor 0x0000000001 [0x410fd034]
    [    0.629694] Detected VIPT I-cache on CPU2
    [    0.629791] GICv3: CPU2: found redistributor 2 region 0:0x00000000018c0000
    [    0.629807] GICv3: CPU2: using allocated LPI pending table @0x0000000080050000
    [    0.629841] CPU2: Booted secondary processor 0x0000000002 [0x410fd034]
    [    0.655743] Detected VIPT I-cache on CPU3
    [    0.655835] GICv3: CPU3: found redistributor 3 region 0:0x00000000018e0000
    [    0.655848] GICv3: CPU3: using allocated LPI pending table @0x0000000080060000
    [    0.655881] CPU3: Booted secondary processor 0x0000000003 [0x410fd034]
    [    0.655946] smp: Brought up 1 node, 4 CPUs
    [    0.685352] SMP: Total of 4 processors activated.
    [    0.685358] CPU features: detected: 32-bit EL0 Support
    [    0.685360] CPU features: detected: 32-bit EL1 Support
    [    0.685364] CPU features: detected: CRC32 instructions
    [    0.685418] CPU: All CPU(s) started at EL2
    [    0.685435] alternatives: applying system-wide alternatives
    [    0.687379] devtmpfs: initialized
    [    0.699159] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 1911260446275000 ns
    [    0.699184] futex hash table entries: 1024 (order: 4, 65536 bytes, linear)
    [    0.704502] pinctrl core: initialized pinctrl subsystem
    [    0.707106] DMI not present or invalid.
    [    0.707718] NET: Registered PF_NETLINK/PF_ROUTE protocol family
    [    0.721180] DMA: preallocated 256 KiB GFP_KERNEL pool for atomic allocations
    [    0.721418] DMA: preallocated 256 KiB GFP_KERNEL|GFP_DMA pool for atomic allocations
    [    0.721572] DMA: preallocated 256 KiB GFP_KERNEL|GFP_DMA32 pool for atomic allocations
    [    0.721677] audit: initializing netlink subsys (disabled)
    [    0.721820] audit: type=2000 audit(0.718:1): state=initialized audit_enabled=0 res=1
    [    0.723496] thermal_sys: Registered thermal governor 'step_wise'
    [    0.723591] cpuidle: using governor ladder
    [    0.723613] cpuidle: using governor menu
    [    0.723900] ASID allocator initialised with 65536 entries
    [    0.725999] Serial: AMBA PL011 UART driver
    [    0.745505] platform a40000.pinctrl: Fixed dependency cycle(s) with /bus@f0000/pinctrl@a40000/cpsw-cpts
    [    0.764121] HugeTLB: registered 1.00 GiB page size, pre-allocated 0 pages
    [    0.764132] HugeTLB: 0 KiB vmemmap can be freed for a 1.00 GiB page
    [    0.764137] HugeTLB: registered 32.0 MiB page size, pre-allocated 0 pages
    [    0.764140] HugeTLB: 0 KiB vmemmap can be freed for a 32.0 MiB page
    [    0.764143] HugeTLB: registered 2.00 MiB page size, pre-allocated 0 pages
    [    0.764146] HugeTLB: 0 KiB vmemmap can be freed for a 2.00 MiB page
    [    0.764150] HugeTLB: registered 64.0 KiB page size, pre-allocated 0 pages
    [    0.764152] HugeTLB: 0 KiB vmemmap can be freed for a 64.0 KiB page
    [    0.768387] ACPI: Interpreter disabled.
    [    0.770875] k3-chipinfo 43000014.chipid: Family:AM62X rev:SR1.0 JTAGID[0x0bb7e02f] Detected
    [    0.773300] iommu: Default domain type: Translated
    [    0.773310] iommu: DMA domain TLB invalidation policy: strict mode
    [    0.773680] SCSI subsystem initialized
    [    0.774111] usbcore: registered new interface driver usbfs
    [    0.774150] usbcore: registered new interface driver hub
    [    0.774178] usbcore: registered new device driver usb
    [    0.775716] pps_core: LinuxPPS API ver. 1 registered
    [    0.775720] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
    [    0.775739] PTP clock support registered
    [    0.775893] EDAC MC: Ver: 3.0.0
    [    0.777882] omap-mailbox 29000000.mailbox: omap mailbox rev 0x66fc9100
    [    0.778730] FPGA manager framework
    [    0.778841] Advanced Linux Sound Architecture Driver Initialized.
    [    0.779835] vgaarb: loaded
    [    0.780227] clocksource: Switched to clocksource arch_sys_counter
    [    0.780502] VFS: Disk quotas dquot_6.6.0
    [    0.780546] VFS: Dquot-cache hash table entries: 512 (order 0, 4096 bytes)
    [    0.780771] pnp: PnP ACPI: disabled
    [    0.787387] NET: Registered PF_INET protocol family
    [    0.787754] IP idents hash table entries: 32768 (order: 6, 262144 bytes, linear)
    [    0.789565] tcp_listen_portaddr_hash hash table entries: 1024 (order: 3, 40960 bytes, linear)
    [    0.789616] Table-perturb hash table entries: 65536 (order: 6, 262144 bytes, linear)
    [    0.789636] TCP established hash table entries: 16384 (order: 5, 131072 bytes, linear)
    [    0.789861] TCP bind hash table entries: 16384 (order: 8, 1310720 bytes, linear)
    [    0.791300] TCP: Hash tables configured (established 16384 bind 16384)
    [    0.791522] UDP hash table entries: 1024 (order: 4, 98304 bytes, linear)
    [    0.791677] UDP-Lite hash table entries: 1024 (order: 4, 98304 bytes, linear)
    [    0.792051] NET: Registered PF_UNIX/PF_LOCAL protocol family
    [    0.792594] RPC: Registered named UNIX socket transport module.
    [    0.792601] RPC: Registered udp transport module.
    [    0.792603] RPC: Registered tcp transport module.
    [    0.792606] RPC: Registered tcp NFSv4.1 backchannel transport module.
    [    0.792617] PCI: CLS 0 bytes, default 64
    [    0.807333] kvm [1]: IPA Size Limit: 40 bits
    [    0.808497] kvm [1]: vgic-v2@100010000
    [    0.808524] kvm [1]: GIC system register CPU interface enabled
    [    0.823289] kvm [1]: vgic interrupt IRQ9
    [    0.851252] kvm [1]: Hyp mode initialized successfully
    [    0.852815] Initialise system trusted keyrings
    [    0.853032] workingset: timestamp_bits=58 max_order=19 bucket_order=0
    [    0.859966] squashfs: version 4.0 (2009/01/31) Phillip Lougher
    [    0.860581] NFS: Registering the id_resolver key type
    [    0.860621] Key type id_resolver registered
    [    0.860624] Key type id_legacy registered
    [    0.860714] nfs4filelayout_init: NFSv4 File Layout Driver Registering...
    [    0.860719] nfs4flexfilelayout_init: NFSv4 Flexfile Layout Driver Registering...
    [    0.860933] 9p: Installing v9fs 9p2000 file system support
    [    0.896232] Key type asymmetric registered
    [    0.896239] Asymmetric key parser 'x509' registered
    [    0.896308] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 244)
    [    0.896314] io scheduler mq-deadline registered
    [    0.896319] io scheduler kyber registered
    [    0.908059] pinctrl-single 4084000.pinctrl: 34 pins, size 136
    [    0.908776] pinctrl-single f4000.pinctrl: 171 pins, size 684
    [    0.911012] pinctrl-single a40000.pinctrl: 512 pins, size 2048
    [    0.921390] EINJ: ACPI disabled.
    [    0.952073] Serial: 8250/16550 driver, 12 ports, IRQ sharing enabled
    [    0.958128] SuperH (H)SCI(F) driver initialized
    [    0.958956] msm_serial: driver initialized
    [i0.995566] loop: module loaded
    [   [ 1.219969] printk: console [ttyS2] printing thread started
        0.997745] megasas: 07.719.03.00-rc1
    [    1.219988] printk: console [ttyS2] enabled
    [    1.219993] printk: bootconsole [ns16550a0] disabled
    [    1.229298] printk: bootconsole [ns16550a0] printing thread stopped
    [    1.232118] am65-cpsw-nuss 8000000.ethernet: initializing am65 cpsw nuss version 0x6BA01103, cpsw version 0x6BA81103 Ports: 3 quirks:00000006
    [    1.232386] am65-cpsw-nuss 8000000.ethernet: initialized cpsw ale version 1.5
    [    1.232392] am65-cpsw-nuss 8000000.ethernet: ALE Table size 512
    [    1.232957] pps pps0: new PPS source ptp0
    [    1.233227] am65-cpsw-nuss 8000000.ethernet: CPTS ver 0x4e8a010c, freq:500000000, add_val:1 pps:1
    [    1.245774] am65-cpsw-nuss 8000000.ethernet: set new flow-id-base 19
    [    1.254902] mmc0: CQHCI version 5.10
    [    1.269248] pca953x 1-0022: supply vcc not found, using dummy regulator
    [    1.269401] pca953x 1-0022: using AI
    [    1.289367] spi-nor spi0.0: s28hs512t (65536 Kbytes)
    [    1.289491] 7 fixed-partitions partitions found on MTD device fc40000.spi.0
    [    1.289501] Creating 7 MTD partitions on "fc40000.spi.0":
    [    1.289508] 0x000000000000-0x000000080000 : "ospi.tiboot3"
    [    1.291007] 0x000000080000-0x000000280000 : "ospi.tispl"
    [    1.292182] 0x000000280000-0x000000680000 : "ospi.u-boot"
    [    1.293376] 0x000000680000-0x0000006c0000 : "ospi.env"
    [    1.294580] 0x0000006c0000-0x000000700000 : "ospi.env.backup"
    [    1.295777] 0x000000800000-0x000003fc0000 : "ospi.rootfs"
    [    1.296993] 0x000003fc0000-0x000004000000 : "ospi.phypattern"
    [    1.298419] mmc0: SDHCI controller on fa10000.mmc [fa10000.mmc] using ADMA 64-bit
    [    1.324462] mmc1: CQHCI version 5.10
    [    1.328064] mmc2: CQHCI version 5.10
    [    1.332738] debugfs: Directory 'pd:182' with parent 'pm_genpd' already present!
    [    1.335513] debugfs: Directory 'pd:186' with parent 'pm_genpd' already present!
    [    1.341298] ti-sci-clk 44043000.system-controller:clock-controller: is_prepared failed for dev=81, clk=20, ret=-19
    [    1.346970] ALSA device list:
    [    1.346976]   No soundcards found.
    [    1.365193] mmc1: SDHCI controller on fa00000.mmc [fa00000.mmc] using ADMA 64-bit
    [    1.369950] mmc2: SDHCI controller on fa20000.mmc [fa20000.mmc] using ADMA 64-bit
    [    1.370606] Waiting for root device PARTUUID=d2c3753a-02...
    [    1.375549] sdhci-am654 fa20000.mmc: card claims to support voltages below defined range
    [    1.389044] mmc2: new high speed SDIO card at address 0001
    [    1.389801] mmc0: Command Queue Engine enabled
    [    1.389812] mmc0: new HS200 MMC card at address 0001
    [    1.390497] mmcblk0: mmc0:0001 S0J56X 14.8 GiB
    [    1.392180]  mmcblk0: p1
    [    1.392791] mmcblk0boot0: mmc0:0001 S0J56X 31.5 MiB
    [    1.394083] mmcblk0boot1: mmc0:0001 S0J56X 31.5 MiB
    [    1.395243] mmcblk0rpmb: mmc0:0001 S0J56X 4.00 MiB, chardev (511:0)
    [    1.414528] mmc1: new ultra high speed SDR104 SDXC card at address 0001
    [    1.415425] mmcblk1: mmc1:0001 BC2QT 59.6 GiB
    [    1.417516]  mmcblk1: p1 p2
    [    1.434310] EXT4-fs (mmcblk1p2): mounted filesystem with ordered data mode. Quota mode: none.
    [    1.434400] VFS: Mounted root (ext4 filesystem) on device 179:98.
    [    1.435060] devtmpfs: mounted
    [    1.440386] Freeing unused kernel memory: 7296K
    [    1.440527] Run /sbin/init as init process
    [    1.618051] systemd[1]: System time before build time, advancing clock.
    [    1.645834] systemd[1]: systemd 250.5+ running in system mode (+PAM -AUDIT -SELINUX -APPARMOR +IMA -SMACK +SECCOMP -GCRYPT -GNUTLS -OPENSSL +ACL +BLKID -CURL -ELFUTILS -FIDO2 -IDN2 -IDN -IPTC +KMOD -LIBCRYPTSETUP +LIBFDISK -PCRE2 -PWQUALITY -P11KIT -QRENCODE -BZIP2 -LZ4 -XZ -ZLIB +ZSTD -BPF_FRAMEWORK -XKBCOMMON +UTMP +SYSVINIT default-hierarchy=hybrid)
    [    1.646660] systemd[1]: Detected architecture arm64.
    
    Welcome to Arago 2023.10!
    
    [    1.689569] systemd[1]: Hostname set to <am62xx-evm>.
    [    1.796367] systemd-sysv-generator[173]: SysV service '/etc/init.d/thermal-zone-init' lacks a native systemd unit file. Automatically generating a unit file for compatibility. Please update package to include a native systemd unit file, in order to make it more safe and robust.
    [    1.949953] systemd[1]: Configuration file /lib/systemd/system/ti-apps-launcher.service is marked executable. Please remove executable permission bits. Proceeding anyway.
    [    1.966310] systemd[1]: Configuration file /lib/systemd/system/seva-launcher.service is marked executable. Please remove executable permission bits. Proceeding anyway.
    [    2.004402] systemd[1]: Binding to IPv6 address not available since kernel does not support IPv6.
    [    2.004442] systemd[1]: Binding to IPv6 address not available since kernel does not support IPv6.
    [    2.038304] systemd[1]: /lib/systemd/system/bt-enable.service:9: Standard output type syslog is obsolete, automatically updating to journal. Please update your unit file, and consider removing the setting altogether.
    [    2.087826] systemd[1]: /etc/systemd/system/sync-clocks.service:11: Standard output type syslog is obsolete, automatically updating to journal. Please update your unit file, and consider removing the setting altogether.
    [    2.149419] systemd[1]: Queued start job for default target Graphical Interface.
    [  OK  ] Created slice Slice /system/getty    2.184212] systemd[1]: Created slice Slice /system/getty.
    0m.
    [    2.200104] systemd[1]: Created slice Slice /system/modprobe.
    [  OK  ] Created slice Slice /system/modprobe.
    [    2.216064] systemd[1]: Created slice Slice /system/serial-getty.
    [  OK  ] Created slice Slice /system/serial-getty.
    [  OK  ] Created slice User and Session Slic[    2.231542] systemd[1]: Created slice User and Session Slice.
    e.
    [  OK  ] Started Dispatch Password �ts to [    2.245766] systemd[1]: Started Dispatch Password Requests to Console Directory Watch.
    Console Directory Watch.
    [  OK  ] Started Forward Password R�uests [    2.263635] systemd[1]: Started Forward Password Requests to Wall Directory Watch.
    to Wall Directory Watch.
    [  OK  ] Reached target Path Units.
    [    2.282746] systemd[1]: Reached target Path Units.
    [    2.293190] systemd[1]: Reached target Remote File Systems.
    [  OK  ] Reached target Remote File Systems.
    [  OK  ] Reached target Slice Units.
    [    2.307397] systemd[1]: Reached target Slice Units.
    [  OK  ] Reached target Swaps.
    [    2.317957] systemd[1]: Reached target Swaps.
    [  OK  ] Listening on RPCbind Server Activat[    2.332600] systemd[1]: Listening on RPCbind Server Activation Socket.
    ion Socket.
    [  OK  ] Reached target RPC Port Mapper.[    2.347467] systemd[1]: Reached target RPC Port Mapper.
    
    [  OK  ] Listening on Process Core Dump Sock[    2.367810] systemd[1]: Listening on Process Core Dump Socket.
    et.
    [  OK  ] Listening on initctl Compatibility [    2.382827] systemd[1]: Listening on initctl Compatibility Named Pipe.
    Named Pipe.
    [  OK  ] Listening on Journal Audit Socket    2.398327] systemd[1]: Listening on Journal Audit Socket.
    0m.
    [  OK  ] Listening on Journal Socket (/dev/l[    2.413020] systemd[1]: Listening on Journal Socket (/dev/log).
    og).
    [    2.428089] systemd[1]: Listening on Journal Socket.
    [  OK  ] Listening on Journal Socket.
    [  OK  ] Listening on Network Service Netlin[    2.442382] systemd[1]: Listening on Network Service Netlink Socket.
    k Socket.
    [  OK  ] Listening on udev Control Socket    2.458790] systemd[1]: Listening on udev Control Socket.
    m.
    [  OK  ] Listening on udev Kernel Socket[    2.472907] systemd[1]: Listening on udev Kernel Socket.
    .
    [  OK  ] Listening on User Database Manager [    2.487004] systemd[1]: Listening on User Database Manager Socket.
    Socket.
             Mounting Huge Pages File System...
    [    2.512793] systemd[1]: Mounting Huge Pages File System...
             Mounting POSIX Message Queue File System..[    2.527614] systemd[1]: Mounting POSIX Message Queue File System...
    .
             Mounting Kernel Debug File System...
    [    2.547205] systemd[1]: Mounting Kernel Debug File System...
    [    2.559193] systemd[1]: Kernel Trace File System was skipped because of a failed condition check (ConditionPathExists=/sys/kernel/tracing).
             Mounting Temporary Directory /tmp...
    [    2.564302] systemd[1]: Mounting Temporary Directory /tmp...
    [    2.583693] systemd[1]: Create List of Static Device Nodes was skipped because of a failed condition check (ConditionFileNotEmpty=/lib/modules/6.1.80-rt26-dirty/modules.devname).
    [    2.588006] systemd[1]: Starting Load Kernel Module configfs...
             Starting Load Kernel Module configfs...
    [    2.634106] systemd[1]: Starting Load Kernel Module drm...
             Starting Load Kernel Module drm...
             Starting Load Kernel Module fuse...
    [    2.649647] systemd[1]: Starting Load Kernel Module fuse...
             Starting Start psplash boot splash screen.[    2.670532] systemd[1]: Starting Start psplash boot splash screen...
    ..
    [    2.704116] systemd[1]: Starting RPC Bind...
             Starting RPC Bind...
    [    2.714812] systemd[1]: File System Check on Root Device was skipped because of a failed condition check (ConditionPathIsReadWrite=!/).
    [    2.716139] systemd[1]: systemd-journald.service: unit configures an IP firewall, but the local system does not support BPF/cgroup firewalling.
    [    2.716159] systemd[1]: (This warning is only shown for the first unit using IP firewalling.)
    [    2.721879] systemd[1]: Starting Journal Service...
             Starting Journal Service...
    [    2.776123] systemd[1]: Starting Load Kernel Modules...
             Starting Load Kernel Modules...
    [    2.795103] systemd[1]: Starting Generate network units from Kernel command line...
             Starting Generate network �ts from Kernel command line...
             Starting Remount Root and Kernel File Systems systemd[1]: Starting Remount Root and Kernel File Systems...
    [0m...
    [    2.846732] EXT4-fs (mmcblk1p2): re-mounted. Quota mode: none.
             Starting Coldplug All udev Devices...
    [    2.856298] systemd[1]: Starting Coldplug All udev Devices...
    [  OK  ] Started RPC Bind.
    [    2.877934] systemd[1]: Started RPC Bind.
    [  OK  ] Started Journal Service.
    [    2.887646] systemd[1]: Started Journal Service.
    [  OK  ] Mounted Huge Pages File System.
    [  OK  ] Mounted POSIX Message Queue File System.
    [  OK  ] Mounted Kernel Debug File System.
    [  OK  ] Mounted Temporary Directory /tmp.
    [  OK  ] Finished Load Kernel Module configfs.
    [  OK  ] Finished Load Kernel Module drm.
    [  OK  ] Finished Load Kernel Module fuse.
    [FAILED] Failed to start Start psplash boot splash screen.
    See 'systemctl status psplash-start.service' for details.
    [DEPEND] Dependency failed for Star�progress communication helper.
    [FAILED] Failed to start Load Kernel Modules.
    See 'systemctl status systemd-modules-load.service' for details.
    [  OK  ] Finished Generate network units from Kernel command line.
    [  OK  ] Finished Remount Root and Kernel File Systems.
             Mounting Kernel Configuration File System...
             Starting Flush Journal to Persistent Storage...
             Starting Apply Kernel Variables...
    [    3.104063] systemd-journald[184]: Received client request to flush runtime journal.
             Starting Create Static Device Nodes in /dev...
    [  OK  ] Mounted Kernel Configuration File System.
    [  OK  ] Finished Flush Journal to Persistent Storage.
    [  OK  ] Finished Apply Kernel Variables.
    [  OK  ] Finished Create Static Device Nodes in /dev.
    [  OK  ] Reached target Preparation for Local File Systems.
             Mounting /media/ram...
             Mounting /var/volatile...
             Starting Rule-based Manage�for Device Events and Files...
    [  OK  ] Mounted /media/ram.
    [  OK  ] Mounted /var/volatile.
             Starting Load/Save Random Seed...
    [  OK  ] Reached target Local File Systems.
             Starting Create Volatile Files and Directories...
    [  OK  ] Finished Create Volatile Files and Directories.
    [  OK  ] Started Rule-based Manager for Device Events and Files.
             Starting Network Time Synchronization...
             Starting Record System Boot/Shutdown in UTMP...
    [  OK  ] Finished Record System Boot/Shutdown in UTMP.
    [    3.612275] random: crng init done
    [  OK  ] Finished Load/Save Random Seed.
    [  OK  ] Finished Coldplug All udev Devices.
    [  OK  ] Started Network Time Synchronization.
    [  OK  ] Reached target System Initialization.
    [  OK  ] Started Daily Cleanup of Temporary Directories.
    [  OK  ] Reached target System Time Set.
    [  OK  ] Started Daily rotation of log files.
    [  OK  ] Reached target Timer Units.
    [  OK  ] Listening on Avahi mDNS/DNS-SD Stack Activation Socket.
    [  OK  ] Listening on D-Bus System Message Bus Socket.
             Starting Docker Socket for the API...
    [  OK  ] Listening on dropbear.socket.
    [  OK  ] Listening on PC/SC Smart Card Daemon Activation Socket.
             Starting Weston socket...
             Starting D-Bus System Message Bus...
             Starting Reboot and dump vmcore via kexec...
    [  OK  ] Listening on Docker Socket for the API.
    [  OK  ] Listening on Weston socket.
    [  OK  ] Reached target Socket Units.
    [  OK  ] Finished Reboot and dump vmcore via kexec.
    [  OK  ] Found device /dev/ttyS2.
    [  OK  ] Started D-Bus System Message Bus.
    [  OK  ] Reached target Basic System.
    [  OK  ] Started Job spooling tools.
    [  OK  ] Started Periodic Command Scheduler.
             Starting DEMO...
             Starting Print notice about GPLv3 packages...
             Starting IPv6 Packet Filtering Framework...
             Starting IPv4 Packet Filtering Framework...
    [  OK  ] Started irqbalance daemon.
             Starting Telephony service...
             Starting PulseAudio Sound System...
             Starting Expand the rootfs�ll size of the boot device....
    [  OK  ] Started Seva Launcher Service.
    [  OK  ] Started strongSwan IPsec I�IKEv2 daemon using ipsec.conf.
             Starting User Login Management...
    [  OK  ] Started TEE Supplicant.
             Starting Telnet Server...
    [  OK  ] Started ti-apps-launcher service.
    [  OK  ] Finished IPv6 Packet Filtering Framework.
    [  OK  ] Finished IPv4 Packet Filtering Framework.
    [  OK  ] Finished Telnet Server.
    [  OK  ] Started Telephony service.
    [  OK  ] Reached target Preparation for Network.
             Starting Network Configuration...
    [  OK  ] Started DEMO.
    [  OK  ] Started User Login Management.
    [  OK  ] Started PulseAudio Sound System.
    [  OK  ] Finished Expand the rootfs�full size of the boot device..
    [  OK  ] Started Network Configuration.
             Starting Network Name Resolution...
    [  OK  ] Started Network Name Resolution.
    [  OK  ] Reached target Network.
    [  OK  ] Reached target Host and Network Name Lookups.
             Starting Avahi mDNS/DNS-SD Stack...
             Starting Enable and configure wl18xx bluetooth stack...
             Starting containerd container runtime...
    [  OK  ] Started Netperf Benchmark Server.
    [  OK  ] Started NFS status monitor for NFSv2/3 locking..
             Starting Simple Network Ma�ent Protocol (SNMP) Daemon....
             Starting Permit User Sessions...
    [  OK  ] Finished Enable and configure wl18xx bluetooth stack.
    [  OK  ] Finished Permit User Sessions.
    [  OK  ] Started Avahi mDNS/DNS-SD Stack.
    [  OK  ] Started Getty on tty1.
    [  OK  ] Started Serial Getty on ttyS2.
    [  OK  ] Reached target Login Prompts.
             Starting Synchronize System and HW clocks...
             Starting Weston, a Wayland�ositor, as a system service...
    [FAILED] Failed to start Synchronize System and HW clocks.
    See 'systemctl status sync-clocks.service' for details.
    [  OK  ] Created slice Slice /system/systemd-fsck.
             Starting User Database Manager...
    [  OK  ] Found device /dev/mmcblk0p1.
             Starting File System Check on /dev/mmcblk0p1...
    [  OK  ] Started User Database Manager.
    [  OK  ] Finished File System Check on /dev/mmcblk0p1.
    [  OK  ] Created slice User Slice of UID 1000.
             Mounting /run/media/mmcblk0p1...
             Starting User Runtime Directory /run/user/1000...
    [    7.177684] audit: type=1701 audit(1651167750.560:2): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=743 comm="kmsprint" exe="/usr/bin/kmsprint" sig=6 res=1
    [    7.178392] EXT4-fs (mmcblk0p1): mounted filesystem with ordered data mode. Quota mode: none.
    [  OK  ] Finished User Runtime Directory /run/user/1000.
    [  OK  ] Mounted /run/media/mmcblk0p1.
             Starting User Manager for UID 1000...
    [  OK  ] Created slice Slice /system/systemd[    7.258791] audit: type=1006 audit(1651167750.641:3): pid=769 uid=0 old-auid=4294967295 auid=1000 tty=(none) old-ses=4294967295 ses=1 res=1
    -coredump.
    [    7.259040] audit: type=1300 audit(1651167750.641:3): arch=c00000b7 syscall=64 success=yes exit=4 a0=8 a1=ffffd60abde8 a2=4 a3=ffffb3ab0020 items=0 ppid=1 pid=769 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=1 comm="(systemd)" exe="/lib/systemd/systemd" key=(null)
    [    7.260279] audit: type=1327 audit(1651167750.641:3): proctitle="(systemd)"
    [  OK  ] Started Process Core Dump (PID 760/UID 0).
    [  OK  ] Found device /dev/mmcblk1p1.
             Starting File System Check on /dev/mmcblk1p1...
    [  OK  ] Finished File System Check on /dev/mmcblk1p1.
             Mounting /run/media/boot-mmcblk1p1...
    [  OK  ] Started Simple Network Man�ement Protocol (SNMP) Daemon..
    [  OK  ] Mounted /run/media/boot-mmcblk1p1.
    [  OK  ] Started User Manager for UID 1000.
    [  OK  ] Started Session c1 of User weston.
    [    8.011278] audit: type=1006 audit(1651167751.393:4): pid=709 uid=0 old-auid=4294967295 auid=1000 tty=tty7 old-ses=4294967295 ses=2 res=1
    [    8.011308] audit: type=1300 audit(1651167751.393:4): arch=c00000b7 syscall=64 success=yes exit=4 a0=8 a1=ffffd60abde8 a2=4 a3=ffffb3ab0020 items=0 ppid=1 pid=709 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=tty7 ses=2 comm="(weston)" exe="/lib/systemd/systemd" key=(null)
    [    8.011321] audit: type=1327 audit(1651167751.393:4): proctitle="(weston)"
    [FAILED] Failed to start Weston, a �mpositor, as a system service.
    See 'systemctl status weston.service' for details.
             Starting Weston, a Wayland�ositor, as a system service...
    [  OK  ] Started Session c2 of User weston.
    [    8.474142] audit: type=1006 audit(1651167751.856:5): pid=804 uid=0 old-auid=4294967295 auid=1000 tty=tty7 old-ses=4294967295 ses=3 res=1
    [    8.475157] audit: type=1300 audit(1651167751.856:5): arch=c00000b7 syscall=64 success=yes exit=4 a0=8 a1=ffffd60abde8 a2=4 a3=0 items=0 ppid=1 pid=804 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=tty7 ses=3 comm="(weston)" exe="/lib/systemd/systemd" key=(null)
    [    8.475180] audit: type=1327 audit(1651167751.856:5): proctitle="(weston)"
    [FAILED] Failed to start Weston, a �mpositor, as a system service.
    See 'systemctl status weston.service' for details.
             Starting Weston, a Wayland�ositor, as a system service...
    [  OK  ] Started Session c3 of User weston.
    [FAILED] Failed to start Weston, a �mpositor, as a system service.
    See 'systemctl status weston.service' for details.
             Starting Weston, a Wayland�ositor, as a system service...
    [  OK  ] Started Session c4 of User weston.
    [  OK  ] Started containerd container runtime.
    [FAILED] Failed to start Weston, a �mpositor, as a system service.
    See 'systemctl status weston.service' for details.
             Starting Weston, a Wayland�ositor, as a system service...
    [  OK  ] Started Session c5 of User weston.
    [FAILED] Failed to start Weston, a �mpositor, as a system service.
    See 'systemctl status weston.service' for details.
    [FAILED] Failed to start Weston, a �mpositor, as a system service.
    See 'systemctl status weston.service' for details.
    ***************************************************************
    ***************************************************************
    NOTICE: This file system contains the following GPL-3.0 packages:
            adwaita-icon-theme-symbolic
            autoconf
            bash-dev
            bash
            bc
            binutils
            cifs-utils
            coreutils-stdbuf
            coreutils
            cpio
            cpp-symlinks
            cpp
            dosfstools
            elfutils
            g++-symlinks
            g++
            gawk
            gcc-symlinks
            gcc
            gdb
            gdbserver
            gettext
            glmark2
            gnu-config
            grep
            grub-common
            grub-editenv
            grub-efi
            gzip
            hidapi
            less
            libasm1
            libatomic-dev
            libatomic1
            libbfd
            libdebuginfod1
            libdw1
            libeigen-dev
            libelf1
            libgcc-s-dev
            libgcc1
            libgdbm-compat4
            libgdbm-dev
            libgdbm6
            libgettextlib
            libgettextsrc
            libgmp10
            libidn2-0
            libmpc3
            libmpfr6
            libopcodes
            libqt5charts-examples
            libqt5charts-plugins
            libqt5charts-qmlplugins
            libqt5charts5
            libqt5sensors-plugins
            libqt5sensors-qmlplugins
            libqt5sensors5
            libqt5serialport-examples
            libqt5serialport-plugins
            libqt5serialport-qmlplugins
            libqt5serialport5
            libqt5svg-examples
            libqt5svg-plugins
            libqt5svg-qmlplugins
            libqt5svg5
            libqt5virtualkeyboard-plugins
            libqt5virtualkeyboard-qmlplugins
            libqt5virtualkeyboard5
            libqt5webchannel-plugins
            libqt5webchannel-qmlplugins
            libqt5webchannel5
            libreadline-dev
            libreadline8
            libstdc++-dev
            libstdc++6
            libunistring2
            m4-dev
            m4
            make
            nettle
            parted
            piglit
            qt3d-plugins
            qt3d-qmlplugins
            qt3d
            qtbase-examples
            qtbase-plugins
            qtbase-qmlplugins
            qtbase
            qtconnectivity-plugins
            qtconnectivity-qmlplugins
            qtconnectivity
            qtdeclarative-plugins
            qtdeclarative-qmlplugins
            qtdeclarative-tools
            qtdeclarative
            qtgraphicaleffects-qmlplugins
            qtlocation-examples
            qtlocation-plugins
            qtlocation-qmlplugins
            qtlocation
            qtmultimedia-examples
            qtmultimedia-plugins
            qtmultimedia-qmlplugins
            qtmultimedia
            qtquick3d-plugins
            qtquick3d-qmlplugins
            qtquick3d
            qtquics-qmlplugins.control
            qtquics2-plugins.control
            qtquics2-qmlplugins.control
            qtquics2.control
            qtscript-examples
            qtscript-plugins
            qtscript-qmlplugins
            qtscript
            qtwayland-examples
            qtwayland-plugins
            qtwayland-qmlplugins
            qtwayland
            tar
            which
    
    If you do not wish to distribute GPL-3.0 components please remove
    the above packages prior to distribution.  This can be done using
    the opkg remove command.  i.e.:
        opkg remove <package>
    Where <package> is the name printed in the list above
    
    NOTE: If the package is a dependency of another package you
          will be notified of the dependent packages.  You should
          use the --force-removal-of-dependent-packages option to
          also remove the dependent packages as well
    ***************************************************************
    ***************************************************************
    [  OK  ] Finished Print notice about GPLv3 packages.
    [  OK  ] Reached target Multi-User System.
    [  OK  ] Reached target Graphical Interface.
             Starting Record Runlevel Change in UTMP...
    [  OK  ] Finished Record Runlevel Change in UTMP.
    
     _____                    _____           _         _
    |  _  |___ ___ ___ ___   |  _  |___ ___  |_|___ ___| |_
    |     |  _| .'| . | . |  |   __|  _| . | | | -_|  _|  _|
    |__|__|_| |__,|_  |___|  |__|  |_| |___|_| |___|___|_|
                  |___|                    |___|
    
    Arago Project am62xx-evm -
    
    Arago 2023.10 am62xx-evm -
    
    am62xx-evm login: [   11.753872] platform leds: deferred probe pending
    [   11.753889] platform 2b300050.target-module: deferred probe pending
    
    am62xx-evm login: root
    [   41.132027] kauditd_printk_skb: 10 callbacks suppressed
    [   41.132043] audit: type=1006 audit(1651167784.514:10): pid=1207 uid=0 old-auid=4294967295 auid=0 tty=(none) old-ses=4294967295 ses=7 res=1
    [   41.132059] audit: type=1300 audit(1651167784.514:10): arch=c00000b7 syscall=64 success=yes exit=1 a0=8 a1=ffffd60abde8 a2=1 a3=0 items=0 ppid=1 pid=1207 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=7 comm="(systemd)" exe="/lib/systemd/systemd" key=(null)
    [   41.132071] audit: type=1327 audit(1651167784.514:10): proctitle="(systemd)"
    
    root@am62xx-evm:~# ls /dev/
    autofs           i2c-0         loop6         mtd0ro  mtdblock0  pts    ptypc     tty    tty2   tty31  tty43  tty55  ttyS0   ttyp1  ttype               vcsa   vcsu5
    
    block            i2c-1         loop7         mtd1    mtdblock1  ptyp0  ptypd     tty0   tty20  tty32  tty44  tty56  ttyS1   ttyp2  ttypf               vcsa1  vcsu6
    
    char             initctl       mem           mtd1ro  mtdblock2  ptyp1  ptype     tty1   tty21  tty33  tty45  tty57  ttyS10  ttyp3  ubi_ctrl            vcsa2  vcsu7
    
    console          kmsg          mmcblk0       mtd2    mtdblock3  ptyp2  ptypf     tty10  tty22  tty34  tty46  tty58  ttyS11  ttyp4  udev_network_queue  vcsa3  vfio
    
    cpu_dma_latency  kvm           mmcblk0boot0  mtd2ro  mtdblock4  ptyp3  random    tty11  tty23  tty35  tty47  tty59  ttyS2   ttyp5  urandom             vcsa4  vga_arbiter
    
    disk             log           mmcblk0boot1  mtd3    mtdblock5  ptyp4  shm       tty12  tty24  tty36  tty48  tty6   ttyS3   ttyp6  vcs                 vcsa5  zero
    dma_heap         loop-control  mmcblk0p1     mtd3ro  mtdblock6  ptyp5  snapshot  tty13  tty25  tty37  tty49  tty60  ttyS4   ttyp7  vcs1                vcsa6
    
    fd               loop0         mmcblk0rpmb   mtd4    net        ptyp6  snd       tty14  tty26  tty38  tty5   tty61  ttyS5   ttyp8  vcs2                vcsa7
    
    full             loop1         mmcblk1       mtd4ro  null       ptyp7  stderr    tty15  tty27  tty39  tty50  tty62  ttyS6   ttyp9  vcs3                vcsu
    
    gpiochip0        loop2         mmcblk1p1     mtd5    port       ptyp8  stdin     tty16  tty28  tty4   tty51  tty63  ttyS7   ttypa  vcs4                vcsu1
    
    gpiochip1        loop3         mmcblk1p2     mtd5ro  pps0       ptyp9  stdout    tty17  tty29  tty40  tty52  tty7   ttyS8   ttypb  vcs5                vcsu2
    
    gpiochip2        loop4         mqueue        mtd6    ptmx       ptypa  tee0      tty18  tty3   tty41  tty53  tty8   ttyS9   ttypc  vcs6                vcsu3
    
    hugepages        loop5         mtd0          mtd6ro  ptp0       ptypb  teepriv0  tty19  tty30  tty42  tty54  tty9   ttyp0   ttypd  vcs7                vcsu4
    
    root@am62xx-evm:~# uname -r
    6.1.80-rt26-dirty
    
    root@am62xx-evm:~# dmesg | grep spi
    [    0.000000] Kernel command line: console=ttyS2,115200n8 earlycon=ns16550a,mmio32,0x02800000 mtdparts=spi-nand0:512k(ospi.tiboot3),2m(ospi.tispl),4m(ospi.u-boot),256k(ospi.env),256k(ospi.env.backup),98048k@32m(ospi.rootfs),256k@130816k(ospi.phypattern);omap2-nand.0:2m(NAND.tiboot3),2m(NAND.tispl),2m(NAND.tiboot3.backup),4m(NAND.u-boot),256k(NAND.u-boot-env),256k(NAND.u-boot-env.backup),-(NAND.file-system) root=PARTUUID=d2c3753a-02 rw rootfstype=ext4 rootwait
    [    1.289367] spi-nor spi0.0: s28hs512t (65536 Kbytes)
    [    1.289491] 7 fixed-partitions partitions found on MTD device fc40000.spi.0
    [    1.289501] Creating 7 MTD partitions on "fc40000.spi.0":
    [    1.289508] 0x000000000000-0x000000080000 : "ospi.tiboot3"
    [    1.291007] 0x000000080000-0x000000280000 : "ospi.tispl"
    [    1.292182] 0x000000280000-0x000000680000 : "ospi.u-boot"
    [    1.293376] 0x000000680000-0x0000006c0000 : "ospi.env"
    [    1.294580] 0x0000006c0000-0x000000700000 : "ospi.env.backup"
    [    1.295777] 0x000000800000-0x000003fc0000 : "ospi.rootfs"
    [    1.296993] 0x000003fc0000-0x000004000000 : "ospi.phypattern"
    
    root@am62xx-evm:~# cd /lib/modules/6.1.80-rt26-ti-rt-g3c08dbfd7bfd/kernel/drivers/spi/
    
    root@am62xx-evm:/lib/modules/6.1.80-rt26-ti-rt-g3c08dbfd7bfd/kernel/drivers/spi# ls
    spi-omap2-mcspi.ko  spidev.ko
    
    root@am62xx-evm:/lib/modules/6.1.80-rt26-ti-rt-g3c08dbfd7bfd/kernel/drivers/spi# insmod spi-omap2-mcspi.ko
    insmod: ERROR: could not insert module spi-omap2-mcspi.ko: Inval[  181.685577] spi_omap2_mcspi: version magic '6.1.80-rt26-ti-rt-g3c08dbfd7bfd SMP preempt_rt mod_unload aarch64' should be '6.1.80-rt26-dirty SMP preempt_rt mod_unload aarch64'
    id module format
    
    root@am62xx-evm:/lib/modules/6.1.80-rt26-ti-rt-g3c08dbfd7bfd/kernel/drivers/spi# insmod spidev.ko
    insmod: ERROR: could not insert module spidev.ko: Invalid module[  234.200037] spidev: version magic '6.1.80-rt26-ti-rt-g3c08dbfd7bfd SMP preempt_rt mod_unload aarch64' should be '6.1.80-rt26-dirty SMP preempt_rt mod_unload aarch64'
     format
    
    root@am62xx-evm:/lib/modules/6.1.80-rt26-ti-rt-g3c08dbfd7bfd/kernel/drivers/spi# uname -r
    6.1.80-rt26-dirty
    
    root@am62xx-evm:/lib/modules/6.1.80-rt26-ti-rt-g3c08dbfd7bfd/kernel/drivers/spi#
    

    thanks,

    siva. 

  • Hi Siva,

    when you re-build the Linux kernel you normally also need to re-build and re-deploy the kernel modules, as they are tied together. On a rootfs level that is managed by Kernel-specific subdirectories within /lib/modules, as you have already kind of discovered.

    Look into make modules_install INSTALL_MOD_PATH=<...>, but make sure you specify the correct INSTALL_MOD_PATH parameter!! It should point to the root of the mounted MMC/SD card. If you do this wrong there is a risk that command will corrupt your Linux host system/PC!

    Regards, Andreas

  • Hi Andreas,

    It work like a charm by adding modules in lib folder. Thanks.

    I had another problem. For SPI2, there is a IO exapnder (TCA6424) which is not enabling the SPI2 signal to expansion_header thru a mux. Please see the corresponding device tree section. How do I change the I2C IO expander output for UART1_FET_SEL signal to enable SPI2 to be muxed to expansion header?

    &main_i2c1 {
    exp1: gpio@22 {
    compatible = "ti,tca6424";
    reg = <0x22>;
    gpio-controller;
    #gpio-cells = <2>;

    gpio-line-names = "GPIO_CPSW2_RST", "GPIO_CPSW1_RST",
    "PRU_DETECT", "MMC1_SD_EN",
    "VPP_LDO_EN", "EXP_PS_3V3_En",
    "EXP_PS_5V0_En", "EXP_HAT_DETECT",
    "GPIO_AUD_RSTn", "GPIO_eMMC_RSTn",
    "UART1_FET_BUF_EN", "WL_LT_EN",
    "GPIO_HDMI_RSTn", "CSI_GPIO1",
    "CSI_GPIO2", "PRU_3V3_EN",
    "HDMI_INTn", "PD_I2C_IRQ",
    "MCASP1_FET_EN", "MCASP1_BUF_BT_EN",
    "MCASP1_FET_SEL", "UART1_FET_SEL",
    "TSINT#", "IO_EXP_TEST_LED";

    interrupt-parent = <&main_gpio1>;
    interrupts = <23 IRQ_TYPE_EDGE_FALLING>;
    interrupt-controller;
    #interrupt-cells = <2>;

    pinctrl-names = "default";
    //pinctrl-0 = <&main_gpio1_ioexp_intr_pins_default>;
    };
    };

    thanks,

    siva.

  • Hi Andreas, 

    Its been tough for us the get 9.2 version of SDK working. Now we have another problem. We use custom kernel object code for triggering the spi RW based on GPIO interrupt. But we couldnt directly use the code from 8.6. A function called spi_busnum_to_master  is not supported in 9.2 and we got struck again. Any idea related to this issue? Also , do you have any memory mapped SPI RX/TX based on baremetal code?

    thanks,

    siva

  • e use custom kernel object code for triggering the spi RW based on GPIO interrupt. But we couldnt directly use the code from 8.6. A function called spi_busnum_to_master  is not supported in 9.2 and we got struck again

    You'll need to use a different scheme to implement your kernel module; if you model using the existing ./drivers/spi/spidev.c driver you should have everything you need no? Also see https://forums.raspberrypi.com/viewtopic.php?t=352916  There's probably more resources available if you do a bit of internet search, that was just the first link that I came across.

    Also , do you have any memory mapped SPI RX/TX based on baremetal code?

    If you like to see baremetal SPI code you can look at the MCU+ SDK, it has a complete driver:

    SDK Download Page: https://www.ti.com/tool/PROCESSOR-SDK-AM62X

    SPI Driver API Description: https://software-dl.ti.com/mcu-plus-sdk/esd/AM62X/09_02_01_06/exports/docs/api_guide_am62x/DRIVERS_MCSPI_PAGE.html

    The SPI driver source code will be part of the AM62x MCU+ SDK after you installed it.

    Regards, Andreas

  • Hi Andreas,

    I already tried the link already. No, spidev.c is different from our kernel module file. It worked perfectly on 8.6 . If I use the spi-omap2-mcspi.c of 9.2 in 8.6 sdk, will it work ? Especially DMA portion? Is there any version depedency ?

    thanks,

    siva,

  • Hi Siva,

    does your custom kernel module build on/use the SPI peripheral driver drivers/spi/spi-omap2-mcspi.c?  The use of DMA is abstracted within this driver, so anything building on it shouldn't need any DMA-related changes. If you are not using this driver you should probably modify/rework your own kernel driver to use the standard driver for low-level peripheral and DMA access. If you don't want to do that you can look at that driver file itself to see if there are any DMA related changes you may need to port to your own code.

    This being said I don't see any effective changes really related to DMA usage by the SPI driver between the kernels of SDK v8.6 and v9.2 other than a different scheme being used for determining the end-of-transfers when DMA is used, which is commit ea7d91885686 ("spi: spi-omap2-mcspi: Use EOW interrupt for completion when DMA enabled").

    $ git log --oneline 09.02.00.010 ^08.06.00.007 ./drivers/spi/spi-omap2-mcspi.c
    87dc10a76206 Revert "spi: omap2-mcspi: Add FIFO support without DMA"
    a78c61d33ac4 spi: omap2-mcspi: Add FIFO support without DMA
    b07a95cd1bf1 spi: omap2-mcspi: Fix hardcoded reference clock
    ea7d91885686 spi: spi-omap2-mcspi: Use EOW interrupt for completion when DMA enabled
    e04375120812 spi: omap2-mcspi: Fix probe so driver works again
    f4ca8c88c2c7 spi: omap2-mcspi: Switch to use dev_err_probe() helper
    2cd757e6292e spi: omap2-mcspi: add support for interword delay
    40b6a137717b spi: spi-omap2-mcspi: using pm_runtime_resume_and_get instead of pm_runtime_get_sync
    1a435466b0d4 Merge branch 'for-5.13' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi into spi-5.14
    2ec6f20b33eb spi: Cleanup on failure of initial setup
    b8b0da8312f5 Merge series "drivers: spi - add parenthesis for sizeof" from Zhiqi Song <songzhiqi1@huawei.com>:
    8267dc6d6889 spi: omap2-mcspi: add parenthesis for sizeof
    6328caf04320 spi: fix some invalid char occurrences
    abdc5db39d72 spi: omap2-mcspi: Activate pinctrl idle state during runtime suspend
    1cd260a7905e Merge tag 'drm-misc-next-2020-10-27' of git://anongit.freedesktop.org/drm/drm-misc into drm-next

    Regards, Andreas

  • Hi Andreas,

    Please see the device tree and custom kernel module which send spi packet on GPIO intterrupt. Only issue is DMA is not working for this code. But when I use the /tools/spi/spi_test.c code and send spi packets, DMA is working.

    When I write the custom spi kernel module, it is still using the function from  omap2-mcspi.c, right?

    thanks,

    6366.device_tree.txt
    &main_spi0 {
            status = "okay";
            pinctrl-names = "default";
            pinctrl-0 = <&main_spi0_pins_default>;
    		ti,spi-num-chipselects = <2>; 
    		cs-gpios = <0>, <0>;
    		ti,pindir-d0-out-d1-in = <0>;
             
    		spidev0:spidev@0 {
    		status = "okay";
    		
                    spi-max-frequency = <10000000>;
                    reg = <0>;
                    compatible = "my,spi-device";
            };
    
    		spidev1:spidev@1 {
                    spi-max-frequency = <10000000>;
                    reg = <1>;
                    compatible = "rohm,dh2228fv";
            };
    
    };
    new.c
    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/spi/spi.h>
    #include <linux/gpio.h>
    #include <linux/interrupt.h>
    #include <linux/delay.h>
    
    #define GPIO_IRQ 1992          // Replace with your GPIO number
    #define SPI_BUS_SPEED 500000   // SPI speed in Hz
    #define SPI_BITS_PER_WORD 8    // SPI bits per word
    #define SPI_MODE SPI_MODE_0    // SPI mode
    
    static struct spi_device *spi_dev;
    static int gpio_irq;
    static unsigned char tx_buffer[] = "Hello";
    static unsigned char rx_buffer[sizeof(tx_buffer)];
    
    static int perform_spi_transfer(void)
    {
        struct spi_transfer transfer = {
            .tx_buf = tx_buffer,
            .rx_buf = rx_buffer,
            .len = sizeof(tx_buffer),
            .speed_hz = SPI_BUS_SPEED,
            .bits_per_word = SPI_BITS_PER_WORD,
        };
        struct spi_message msg;
        int ret;
    
        spi_message_init(&msg);
        spi_message_add_tail(&transfer, &msg);
    
        printk(KERN_INFO "Performing SPI transfer\n");
        ret = spi_sync(spi_dev, &msg);
        if (ret < 0) {
            printk(KERN_ERR "SPI transfer failed: %d\n", ret);
            return ret;
        }
    
        printk(KERN_INFO "SPI transfer successful. Received data: %s\n", rx_buffer);
        return 0;
    }
    
    static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
    {
        printk(KERN_INFO "GPIO interrupt triggered\n");
    
        // Perform SPI transfer
        perform_spi_transfer();
    
        return IRQ_HANDLED;
    }
    
    static int my_spi_probe(struct spi_device *spi)
    {
        spi_dev = spi;
    
        // Configure SPI settings
        spi->mode = SPI_MODE;
        spi->max_speed_hz = SPI_BUS_SPEED;
        spi->bits_per_word = SPI_BITS_PER_WORD;
        if (spi_setup(spi)) {
            printk(KERN_ERR "Failed to setup SPI device\n");
            return -ENODEV;
        }
    
        printk(KERN_INFO "SPI device probed: %s\n", dev_name(&spi->dev));
        return 0;
    }
    
    static void my_spi_remove(struct spi_device *spi)
    {
        spi_dev = NULL;
        printk(KERN_INFO "SPI device removed\n");
    }
    
    static const struct of_device_id my_spi_of_match[] = {
        { .compatible = "my,spi-device", },
        { /* sentinel */ }
    };
    MODULE_DEVICE_TABLE(of, my_spi_of_match);
    
    static const struct spi_device_id my_spi_id[] = {
        { "my,spi-device", 0 },
        { /* sentinel */ }
    };
    MODULE_DEVICE_TABLE(spi, my_spi_id);
    
    static struct spi_driver my_spi_driver = {
        .driver = {
            .name = "my_spi_driver",
            .of_match_table = my_spi_of_match,
            .owner = THIS_MODULE,
        },
        .probe = my_spi_probe,
        .remove = my_spi_remove,
        .id_table = my_spi_id,
    };
    
    static int __init my_spi_gpio_init(void)
    {
        int ret;
    
        printk(KERN_INFO "Initializing SPI GPIO module\n");
    
        // Register SPI driver
        ret = spi_register_driver(&my_spi_driver);
        if (ret < 0) {
            printk(KERN_ERR "Failed to register SPI driver: %d\n", ret);
            return ret;
        }
    
        // Request GPIO
        if (!gpio_is_valid(GPIO_IRQ)) {
            printk(KERN_ERR "Invalid GPIO\n");
            spi_unregister_driver(&my_spi_driver);
            return -ENODEV;
        }
    
        ret = gpio_request(GPIO_IRQ, "my_gpio");
        if (ret) {
            printk(KERN_ERR "Failed to request GPIO: %d\n", ret);
            spi_unregister_driver(&my_spi_driver);
            return ret;
        }
    
        // Configure GPIO as input
        ret = gpio_direction_input(GPIO_IRQ);
        if (ret) {
            printk(KERN_ERR "Failed to set GPIO direction: %d\n", ret);
            gpio_free(GPIO_IRQ);
            spi_unregister_driver(&my_spi_driver);
            return ret;
        }
    
        // Request interrupt
        gpio_irq = gpio_to_irq(GPIO_IRQ);
        ret = request_irq(gpio_irq, gpio_irq_handler, IRQF_TRIGGER_RISING, "my_gpio_irq", NULL);
        if (ret) {
            printk(KERN_ERR "Failed to request IRQ: %d\n", ret);
            gpio_free(GPIO_IRQ);
            spi_unregister_driver(&my_spi_driver);
            return ret;
        }
    
        printk(KERN_INFO "SPI GPIO module initialized\n");
        return 0;
    }
    
    static void __exit my_spi_gpio_exit(void)
    {
        printk(KERN_INFO "Exiting SPI GPIO module\n");
    
        free_irq(gpio_irq, NULL);
        gpio_free(GPIO_IRQ);
        spi_unregister_driver(&my_spi_driver);
    
        printk(KERN_INFO "SPI GPIO module exited\n");
    }
    
    module_init(my_spi_gpio_init);
    module_exit(my_spi_gpio_exit);
    
    MODULE_LICENSE("GPL");
    MODULE_DESCRIPTION("SPI GPIO Interrupt Example");
    MODULE_AUTHOR("Your Name");
    

    siva. 

  • Hi Siva,

    Please see the device tree and custom kernel module which send spi packet on GPIO intterrupt. Only issue is DMA is not working for this code. But when I use the /tools/spi/spi_test.c code and send spi packets, DMA is working.

    It looks like your custom code is only transferring a very small amount of data (5 bytes?) which is below the "cut-off" in the SPI peripheral driver for using the DMA (160 bytes). Try the following...

    1. Transfer more than 160 bytes, or
    2. Reduce the DMA-usage cut-off threshold, see  https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1356551/faq-am6x-optimizing-spi-transfer-inter-byte-gaps-using-the-dma-in-linux
    When I write the custom spi kernel module, it is still using the function from  omap2-mcspi.c, right?

    Yes it does.

    Regards, Andreas

  • Hi Andreas,

    I changed DMA_MIN_LENGTH from 160 to 8 bytes. Even then, custom spi kernel code is not enabling DMA for longer bytes also. With the same setup, if I use /dev/spidev1.0 from user space programs, I am able to see the DMA transfer. '

    Maybe any sort of debugging would be helpful.

    thanks,

    siva.

  • Hi Siva,

    , I am able to see the DMA transfer. '

    How do you determine if DMA is used or not? Did you instrument one of the DMA transfer functions?

    Also I'll be out of the office for the next two days, will try to spend some additional time looking into this once I'm back.

    Regards, Andreas

  • Hi Andreas,

    We use R&S scope to check the inter-byte gap. 

    thanks,

    siva.

  • Hi Siva,

    ok understood, that should do the trick. Will look at it once I'm back.

    Regards, Andreas

  • Hi Andreas,

    I added some debugging message inside "spi-omap2-mcspi.c" and noticed that code reaches /drivers/spi.c function and throws error at line 4126 of SPI.C. the error is "spi_master spi1: noqueue transfer failed".

    Interesting part is, this happens after adding the two lines(shown below) in device tree for enabling dma transfer. 

    dmas = <&main_pktdma 0xc300 0>, <&main_pktdma 0x4300 0>;
    dma-names = "tx0", "rx0";

    If I dont add these two lines in device tree "k3-am625-sk.dts", spi works fine. But DMA is not enabled. 

    thanks,

    siva.