Commit c90675a0 authored by Steve Wilkins's avatar Steve Wilkins Committed by ZhangPeng
Browse files

spi: microchip-core: only disable SPI controller when register value change requires it

stable inclusion
from stable-v6.6.44
commit c41d2178d61b96b08f4b3b6541690f9ecbd04726
bugzilla: https://gitee.com/openeuler/kernel/issues/IAHMJO

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=c41d2178d61b96b08f4b3b6541690f9ecbd04726



--------------------------------

[ Upstream commit de9850b5c606b754dd7861678d6e2874b96b04f8 ]

Setting up many of the registers for a new SPI transfer involves
unconditionally disabling the SPI controller, writing the register
value and re-enabling the controller. This is being done for registers
even when the value is unchanged and is also done for registers that
don't require the controller to be disabled for the change to take
effect. Make an effort to detect changes to the register values, and
only disables the controller if the new register value is different
and disabling the controller is required. This stops the controller
being repeated disabled and the bus going tristate before every
transfer.

Fixes: 9ac8d176 ("spi: add support for microchip fpga spi controllers")
Signed-off-by: default avatarSteve Wilkins <steve.wilkins@raymarine.com>
Co-developed-by: default avatarConor Dooley <conor.dooley@microchip.com>
Signed-off-by: default avatarConor Dooley <conor.dooley@microchip.com>
Link: https://patch.msgid.link/20240715-depict-twirl-7e592eeabaad@wendy


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
Signed-off-by: default avatarZhangPeng <zhangpeng362@huawei.com>
parent e09d0d22
Loading
Loading
Loading
Loading
+41 −38
Original line number Diff line number Diff line
@@ -75,6 +75,7 @@

#define REG_CONTROL		(0x00)
#define REG_FRAME_SIZE		(0x04)
#define  FRAME_SIZE_MASK	GENMASK(5, 0)
#define REG_STATUS		(0x08)
#define REG_INT_CLEAR		(0x0c)
#define REG_RX_DATA		(0x10)
@@ -89,6 +90,7 @@
#define REG_RIS			(0x24)
#define REG_CONTROL2		(0x28)
#define REG_COMMAND		(0x2c)
#define  COMMAND_CLRFRAMECNT	BIT(4)
#define REG_PKTSIZE		(0x30)
#define REG_CMD_SIZE		(0x34)
#define REG_HWSTATUS		(0x38)
@@ -149,62 +151,59 @@ static inline void mchp_corespi_read_fifo(struct mchp_corespi *spi)

static void mchp_corespi_enable_ints(struct mchp_corespi *spi)
{
	u32 control, mask = INT_ENABLE_MASK;

	mchp_corespi_disable(spi);

	control = mchp_corespi_read(spi, REG_CONTROL);

	control |= mask;
	mchp_corespi_write(spi, REG_CONTROL, control);
	u32 control = mchp_corespi_read(spi, REG_CONTROL);

	control |= CONTROL_ENABLE;
	control |= INT_ENABLE_MASK;
	mchp_corespi_write(spi, REG_CONTROL, control);
}

static void mchp_corespi_disable_ints(struct mchp_corespi *spi)
{
	u32 control, mask = INT_ENABLE_MASK;

	mchp_corespi_disable(spi);

	control = mchp_corespi_read(spi, REG_CONTROL);
	control &= ~mask;
	mchp_corespi_write(spi, REG_CONTROL, control);
	u32 control = mchp_corespi_read(spi, REG_CONTROL);

	control |= CONTROL_ENABLE;
	control &= ~INT_ENABLE_MASK;
	mchp_corespi_write(spi, REG_CONTROL, control);
}

static inline void mchp_corespi_set_xfer_size(struct mchp_corespi *spi, int len)
{
	u32 control;
	u16 lenpart;
	u32 lenpart;
	u32 frames = mchp_corespi_read(spi, REG_FRAMESUP);

	/*
	 * Disable the SPI controller. Writes to transfer length have
	 * no effect when the controller is enabled.
	 * Writing to FRAMECNT in REG_CONTROL will reset the frame count, taking
	 * a shortcut requires an explicit clear.
	 */
	mchp_corespi_disable(spi);
	if (frames == len) {
		mchp_corespi_write(spi, REG_COMMAND, COMMAND_CLRFRAMECNT);
		return;
	}

	/*
	 * The lower 16 bits of the frame count are stored in the control reg
	 * for legacy reasons, but the upper 16 written to a different register:
	 * FRAMESUP. While both the upper and lower bits can be *READ* from the
	 * FRAMESUP register, writing to the lower 16 bits is a NOP
	 * FRAMESUP register, writing to the lower 16 bits is (supposedly) a NOP.
	 *
	 * The driver used to disable the controller while modifying the frame
	 * count, and mask off the lower 16 bits of len while writing to
	 * FRAMES_UP. When the driver was changed to disable the controller as
	 * infrequently as possible, it was discovered that the logic of
	 * lenpart = len & 0xffff_0000
	 * write(REG_FRAMESUP, lenpart)
	 * would actually write zeros into the lower 16 bits on an mpfs250t-es,
	 * despite documentation stating these bits were read-only.
	 * Writing len unmasked into FRAMES_UP ensures those bits aren't zeroed
	 * on an mpfs250t-es and will be a NOP for the lower 16 bits on hardware
	 * that matches the documentation.
	 */
	lenpart = len & 0xffff;

	control = mchp_corespi_read(spi, REG_CONTROL);
	control &= ~CONTROL_FRAMECNT_MASK;
	control |= lenpart << CONTROL_FRAMECNT_SHIFT;
	mchp_corespi_write(spi, REG_CONTROL, control);

	lenpart = len & 0xffff0000;
	mchp_corespi_write(spi, REG_FRAMESUP, lenpart);

	control |= CONTROL_ENABLE;
	mchp_corespi_write(spi, REG_CONTROL, control);
	mchp_corespi_write(spi, REG_FRAMESUP, len);
}

static inline void mchp_corespi_write_fifo(struct mchp_corespi *spi)
@@ -227,17 +226,22 @@ static inline void mchp_corespi_write_fifo(struct mchp_corespi *spi)

static inline void mchp_corespi_set_framesize(struct mchp_corespi *spi, int bt)
{
	u32 frame_size = mchp_corespi_read(spi, REG_FRAME_SIZE);
	u32 control;

	if ((frame_size & FRAME_SIZE_MASK) == bt)
		return;

	/*
	 * Disable the SPI controller. Writes to the frame size have
	 * no effect when the controller is enabled.
	 */
	mchp_corespi_disable(spi);
	control = mchp_corespi_read(spi, REG_CONTROL);
	control &= ~CONTROL_ENABLE;
	mchp_corespi_write(spi, REG_CONTROL, control);

	mchp_corespi_write(spi, REG_FRAME_SIZE, bt);

	control = mchp_corespi_read(spi, REG_CONTROL);
	control |= CONTROL_ENABLE;
	mchp_corespi_write(spi, REG_CONTROL, control);
}
@@ -334,8 +338,6 @@ static inline void mchp_corespi_set_clk_gen(struct mchp_corespi *spi)
{
	u32 control;

	mchp_corespi_disable(spi);

	control = mchp_corespi_read(spi, REG_CONTROL);
	if (spi->clk_mode)
		control |= CONTROL_CLKMODE;
@@ -344,12 +346,12 @@ static inline void mchp_corespi_set_clk_gen(struct mchp_corespi *spi)

	mchp_corespi_write(spi, REG_CLK_GEN, spi->clk_gen);
	mchp_corespi_write(spi, REG_CONTROL, control);
	mchp_corespi_write(spi, REG_CONTROL, control | CONTROL_ENABLE);
}

static inline void mchp_corespi_set_mode(struct mchp_corespi *spi, unsigned int mode)
{
	u32 control, mode_val;
	u32 mode_val;
	u32 control = mchp_corespi_read(spi, REG_CONTROL);

	switch (mode & SPI_MODE_X_MASK) {
	case SPI_MODE_0:
@@ -367,12 +369,13 @@ static inline void mchp_corespi_set_mode(struct mchp_corespi *spi, unsigned int
	}

	/*
	 * Disable the SPI controller. Writes to the frame size have
	 * Disable the SPI controller. Writes to the frame protocol have
	 * no effect when the controller is enabled.
	 */
	mchp_corespi_disable(spi);

	control = mchp_corespi_read(spi, REG_CONTROL);
	control &= ~CONTROL_ENABLE;
	mchp_corespi_write(spi, REG_CONTROL, control);

	control &= ~(SPI_MODE_X_MASK << MODE_X_MASK_SHIFT);
	control |= mode_val;