Unverified Commit 66c705d0 authored by Yongbo Zhang's avatar Yongbo Zhang Committed by Mark Brown
Browse files

SoC: rsnd: add interrupt support for SSI BUSIF buffer



SSI BUSIF buffer is possible to overflow or underflow, especially in a
hypervisor environment. If there is no interrupt support, it will eventually
lead to errors in pcm data.
This patch adds overflow and underflow interrupt support for SSI BUSIF buffer.

Reported-by: default avatarChen Li <licheng0822@thundersoft.com>
Signed-off-by: default avatarYongbo Zhang <giraffesnn123@gmail.com>
Tested-by: default avatarChen Li <licheng0822@thundersoft.com>
Acked-by: default avatarKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Link: https://lore.kernel.org/r/20200512093003.28332-1-giraffesnn123@gmail.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 7d8785bc
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -224,6 +224,14 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv)
		RSND_GEN_S_REG(SSI_SYS_STATUS5,	0x884),
		RSND_GEN_S_REG(SSI_SYS_STATUS6,	0x888),
		RSND_GEN_S_REG(SSI_SYS_STATUS7,	0x88c),
		RSND_GEN_S_REG(SSI_SYS_INT_ENABLE0, 0x850),
		RSND_GEN_S_REG(SSI_SYS_INT_ENABLE1, 0x854),
		RSND_GEN_S_REG(SSI_SYS_INT_ENABLE2, 0x858),
		RSND_GEN_S_REG(SSI_SYS_INT_ENABLE3, 0x85c),
		RSND_GEN_S_REG(SSI_SYS_INT_ENABLE4, 0x890),
		RSND_GEN_S_REG(SSI_SYS_INT_ENABLE5, 0x894),
		RSND_GEN_S_REG(SSI_SYS_INT_ENABLE6, 0x898),
		RSND_GEN_S_REG(SSI_SYS_INT_ENABLE7, 0x89c),
		RSND_GEN_S_REG(HDMI0_SEL,	0x9e0),
		RSND_GEN_S_REG(HDMI1_SEL,	0x9e4),

+9 −0
Original line number Diff line number Diff line
@@ -189,6 +189,14 @@ enum rsnd_reg {
	SSI_SYS_STATUS5,
	SSI_SYS_STATUS6,
	SSI_SYS_STATUS7,
	SSI_SYS_INT_ENABLE0,
	SSI_SYS_INT_ENABLE1,
	SSI_SYS_INT_ENABLE2,
	SSI_SYS_INT_ENABLE3,
	SSI_SYS_INT_ENABLE4,
	SSI_SYS_INT_ENABLE5,
	SSI_SYS_INT_ENABLE6,
	SSI_SYS_INT_ENABLE7,
	HDMI0_SEL,
	HDMI1_SEL,
	SSI9_BUSIF0_MODE,
@@ -237,6 +245,7 @@ enum rsnd_reg {
#define SSI9_BUSIF_ADINR(i)	(SSI9_BUSIF0_ADINR + (i))
#define SSI9_BUSIF_DALIGN(i)	(SSI9_BUSIF0_DALIGN + (i))
#define SSI_SYS_STATUS(i)	(SSI_SYS_STATUS0 + (i))
#define SSI_SYS_INT_ENABLE(i) (SSI_SYS_INT_ENABLE0 + (i))


struct rsnd_priv;
+145 −0
Original line number Diff line number Diff line
@@ -372,6 +372,9 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
	u32 wsr		= ssi->wsr;
	int width;
	int is_tdm, is_tdm_split;
	int id = rsnd_mod_id(mod);
	int i;
	u32 sys_int_enable = 0;

	is_tdm		= rsnd_runtime_is_tdm(io);
	is_tdm_split	= rsnd_runtime_is_tdm_split(io);
@@ -447,6 +450,38 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
		cr_mode = DIEN;		/* PIO : enable Data interrupt */
	}

	/* enable busif buffer over/under run interrupt. */
	if (is_tdm || is_tdm_split) {
		switch (id) {
		case 0:
		case 1:
		case 2:
		case 3:
		case 4:
			for (i = 0; i < 4; i++) {
				sys_int_enable = rsnd_mod_read(mod,
					SSI_SYS_INT_ENABLE(i * 2));
				sys_int_enable |= 0xf << (id * 4);
				rsnd_mod_write(mod,
					       SSI_SYS_INT_ENABLE(i * 2),
					       sys_int_enable);
			}

			break;
		case 9:
			for (i = 0; i < 4; i++) {
				sys_int_enable = rsnd_mod_read(mod,
					SSI_SYS_INT_ENABLE((i * 2) + 1));
				sys_int_enable |= 0xf << 4;
				rsnd_mod_write(mod,
					       SSI_SYS_INT_ENABLE((i * 2) + 1),
					       sys_int_enable);
			}

			break;
		}
	}

init_end:
	ssi->cr_own	= cr_own;
	ssi->cr_mode	= cr_mode;
@@ -496,6 +531,13 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod,
{
	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
	struct device *dev = rsnd_priv_to_dev(priv);
	int is_tdm, is_tdm_split;
	int id = rsnd_mod_id(mod);
	int i;
	u32 sys_int_enable = 0;

	is_tdm		= rsnd_runtime_is_tdm(io);
	is_tdm_split	= rsnd_runtime_is_tdm_split(io);

	if (!rsnd_ssi_is_run_mods(mod, io))
		return 0;
@@ -517,6 +559,38 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod,
		ssi->wsr	= 0;
	}

	/* disable busif buffer over/under run interrupt. */
	if (is_tdm || is_tdm_split) {
		switch (id) {
		case 0:
		case 1:
		case 2:
		case 3:
		case 4:
			for (i = 0; i < 4; i++) {
				sys_int_enable = rsnd_mod_read(mod,
						SSI_SYS_INT_ENABLE(i * 2));
				sys_int_enable &= ~(0xf << (id * 4));
				rsnd_mod_write(mod,
					       SSI_SYS_INT_ENABLE(i * 2),
					       sys_int_enable);
			}

			break;
		case 9:
			for (i = 0; i < 4; i++) {
				sys_int_enable = rsnd_mod_read(mod,
					SSI_SYS_INT_ENABLE((i * 2) + 1));
				sys_int_enable &= ~(0xf << 4);
				rsnd_mod_write(mod,
					       SSI_SYS_INT_ENABLE((i * 2) + 1),
					       sys_int_enable);
			}

			break;
		}
	}

	return 0;
}

@@ -622,6 +696,11 @@ static int rsnd_ssi_irq(struct rsnd_mod *mod,
			int enable)
{
	u32 val = 0;
	int is_tdm, is_tdm_split;
	int id = rsnd_mod_id(mod);

	is_tdm		= rsnd_runtime_is_tdm(io);
	is_tdm_split	= rsnd_runtime_is_tdm_split(io);

	if (rsnd_is_gen1(priv))
		return 0;
@@ -635,6 +714,19 @@ static int rsnd_ssi_irq(struct rsnd_mod *mod,
	if (enable)
		val = rsnd_ssi_is_dma_mode(mod) ? 0x0e000000 : 0x0f000000;

	if (is_tdm || is_tdm_split) {
		switch (id) {
		case 0:
		case 1:
		case 2:
		case 3:
		case 4:
		case 9:
			val |= 0x0000ff00;
			break;
		}
	}

	rsnd_mod_write(mod, SSI_INT_ENABLE, val);

	return 0;
@@ -651,6 +743,12 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
	u32 status;
	bool elapsed = false;
	bool stop = false;
	int id = rsnd_mod_id(mod);
	int i;
	int is_tdm, is_tdm_split;

	is_tdm		= rsnd_runtime_is_tdm(io);
	is_tdm_split	= rsnd_runtime_is_tdm_split(io);

	spin_lock(&priv->lock);

@@ -672,6 +770,53 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
		stop = true;
	}

	status = 0;

	if (is_tdm || is_tdm_split) {
		switch (id) {
		case 0:
		case 1:
		case 2:
		case 3:
		case 4:
			for (i = 0; i < 4; i++) {
				status = rsnd_mod_read(mod,
						       SSI_SYS_STATUS(i * 2));
				status &= 0xf << (id * 4);

				if (status) {
					rsnd_dbg_irq_status(dev,
						"%s err status : 0x%08x\n",
						rsnd_mod_name(mod), status);
					rsnd_mod_write(mod,
						       SSI_SYS_STATUS(i * 2),
						       0xf << (id * 4));
					stop = true;
					break;
				}
			}
			break;
		case 9:
			for (i = 0; i < 4; i++) {
				status = rsnd_mod_read(mod,
						SSI_SYS_STATUS((i * 2) + 1));
				status &= 0xf << 4;

				if (status) {
					rsnd_dbg_irq_status(dev,
						"%s err status : 0x%08x\n",
						rsnd_mod_name(mod), status);
					rsnd_mod_write(mod,
						SSI_SYS_STATUS((i * 2) + 1),
						0xf << 4);
					stop = true;
					break;
				}
			}
			break;
		}
	}

	rsnd_ssi_status_clear(mod);
rsnd_ssi_interrupt_out:
	spin_unlock(&priv->lock);