Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a8916feb authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: ipa3: vote for clocks before enable uC"

parents 6f59d09e 5bb5703c
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -970,7 +970,8 @@ enum ipa3_hw_features {
 * section in 128B shared memory located in offset zero of SW Partition in IPA
 * SRAM.
 * @cmdOp : CPU->HW command opcode. See IPA_CPU_2_HW_COMMANDS
 * @cmdParams : CPU->HW command parameter. The parameter filed can hold 32 bits
 * @cmdParams : CPU->HW command parameter lower 32bit.
 * @cmdParams_hi : CPU->HW command parameter higher 32bit.
 * of parameters (immediate parameters) and point on structure in system memory
 * (in such case the address must be accessible for HW)
 * @responseOp : HW->CPU response opcode. See IPA_HW_2_CPU_RESPONSES
+137 −144
Original line number Diff line number Diff line
@@ -153,8 +153,7 @@ union IpaHwResetPipeCmdData_t {
/**
 * struct IpaHwRegWriteCmdData_t - holds the parameters for
 * IPA_CPU_2_HW_CMD_REG_WRITE command. Parameters are
 * sent as pointer (not direct) thus should be reside
 * in memory address accessible to HW
 * sent as 64b immediate parameters.
 * @RegisterAddress: RG10 register address where the value needs to be written
 * @RegisterValue: 32-Bit value to be written into the register
 */
@@ -521,6 +520,127 @@ static void ipa3_uc_response_hdlr(enum ipa_irq_type interrupt,
	ipa3_dec_client_disable_clks();
}

static int ipa3_uc_send_cmd_64b_param(u32 cmd_lo, u32 cmd_hi, u32 opcode,
	u32 expected_status, bool polling_mode, unsigned long timeout_jiffies)
{
	int index;
	union IpaHwCpuCmdCompletedResponseData_t uc_rsp;
	unsigned long flags;
	int retries = 0;

	IPA3_UC_LOCK(flags);

	if (ipa3_uc_state_check()) {
		IPADBG("uC send command aborted\n");
		IPA3_UC_UNLOCK(flags);
		return -EBADF;
	}

send_cmd:
	if (ipa3_ctx->apply_rg10_wa) {
		if (!polling_mode)
			IPADBG("Overriding mode to polling mode\n");
		polling_mode = true;
	} else {
		init_completion(&ipa3_ctx->uc_ctx.uc_completion);
	}

	ipa3_ctx->uc_ctx.uc_sram_mmio->cmdParams = cmd_lo;
	ipa3_ctx->uc_ctx.uc_sram_mmio->cmdParams_hi = cmd_hi;
	ipa3_ctx->uc_ctx.uc_sram_mmio->cmdOp = opcode;
	ipa3_ctx->uc_ctx.pending_cmd = opcode;
	ipa3_ctx->uc_ctx.uc_sram_mmio->responseOp = 0;
	ipa3_ctx->uc_ctx.uc_sram_mmio->responseParams = 0;

	ipa3_ctx->uc_ctx.uc_status = 0;

	/* ensure write to shared memory is done before triggering uc */
	wmb();

	if (ipa3_ctx->apply_rg10_wa)
		ipa_write_reg(ipa3_ctx->mmio,
			IPA_UC_MAILBOX_m_n_OFFS_v3_0(IPA_CPU_2_HW_CMD_MBOX_m,
			IPA_CPU_2_HW_CMD_MBOX_n), 0x1);
	else
		ipa_write_reg(ipa3_ctx->mmio, IPA_IRQ_EE_UC_n_OFFS(0), 0x1);

	if (polling_mode) {
		for (index = 0; index < IPA_UC_POLL_MAX_RETRY; index++) {
			if (ipa3_ctx->uc_ctx.uc_sram_mmio->responseOp ==
			    IPA_HW_2_CPU_RESPONSE_CMD_COMPLETED) {
				uc_rsp.raw32b = ipa3_ctx->uc_ctx.uc_sram_mmio->
						responseParams;
				if (uc_rsp.params.originalCmdOp ==
					ipa3_ctx->uc_ctx.pending_cmd) {
					ipa3_ctx->uc_ctx.uc_status =
						uc_rsp.params.status;
					break;
				}
			}
			if (ipa3_ctx->apply_rg10_wa)
				udelay(IPA_UC_POLL_SLEEP_USEC);
			else
				usleep_range(IPA_UC_POLL_SLEEP_USEC,
					IPA_UC_POLL_SLEEP_USEC);
		}

		if (index == IPA_UC_POLL_MAX_RETRY) {
			IPAERR("uC max polling retries reached\n");
			if (ipa3_ctx->uc_ctx.uc_failed) {
				IPAERR("uC reported on Error, errorType = %s\n",
					ipa_hw_error_str(ipa3_ctx->
					uc_ctx.uc_error_type));
			}
			IPA3_UC_UNLOCK(flags);
			BUG();
			return -EFAULT;
		}
	} else {
		if (wait_for_completion_timeout(&ipa3_ctx->uc_ctx.uc_completion,
			timeout_jiffies) == 0) {
			IPAERR("uC timed out\n");
			if (ipa3_ctx->uc_ctx.uc_failed) {
				IPAERR("uC reported on Error, errorType = %s\n",
					ipa_hw_error_str(ipa3_ctx->
					uc_ctx.uc_error_type));
			}
			IPA3_UC_UNLOCK(flags);
			BUG();
			return -EFAULT;
		}
	}

	if (ipa3_ctx->uc_ctx.uc_status != expected_status) {
		if (ipa3_ctx->uc_ctx.uc_status ==
			IPA_HW_PROD_DISABLE_CMD_GSI_STOP_FAILURE) {
			retries++;
			if (retries == IPA_GSI_CHANNEL_STOP_MAX_RETRY) {
				IPAERR("Failed after %d tries\n", retries);
				IPA3_UC_UNLOCK(flags);
				BUG();
				return -EFAULT;
			}

			ipa3_inject_dma_task_for_gsi();
			/* sleep for short period to flush IPA */
			usleep_range(IPA_GSI_CHANNEL_STOP_SLEEP_MIN_USEC,
				IPA_GSI_CHANNEL_STOP_SLEEP_MAX_USEC);
			goto send_cmd;
		}

		IPAERR("Recevied status %u, Expected status %u\n",
			ipa3_ctx->uc_ctx.uc_status, expected_status);
		IPA3_UC_UNLOCK(flags);
		return -EFAULT;
	}

	IPA3_UC_UNLOCK(flags);

	IPADBG("uC cmd %u send succeeded\n", opcode);

	return 0;
}

/**
 * ipa3_uc_interface_init() - Initialize the interface with the uC
 *
@@ -592,7 +712,6 @@ remap_fail:
 * interrupts.
 * The function should perform actions that were not done at init due to uC
 * not being loaded then.
 *
 */
void ipa3_uc_load_notify(void)
{
@@ -602,6 +721,7 @@ void ipa3_uc_load_notify(void)
	if (!ipa3_ctx->apply_rg10_wa)
		return;

	ipa3_inc_client_enable_clks();
	ipa3_ctx->uc_ctx.uc_loaded = true;
	IPADBG("IPA uC loaded\n");

@@ -619,13 +739,17 @@ void ipa3_uc_load_notify(void)
		if (ipa3_uc_hdlrs[i].ipa_uc_loaded_hdlr)
			ipa3_uc_hdlrs[i].ipa_uc_loaded_hdlr();
	}
	ipa3_dec_client_disable_clks();
}
EXPORT_SYMBOL(ipa3_uc_load_notify);

/**
 * ipa3_uc_send_cmd() - Send a command to the uC
 *
 * Note: In case the operation times out (No response from the uC) or
 * Note1: This function sends command with 32bit parameter and do not
 *	use the higher 32bit of the command parameter (set to zero).
 *
 * Note2: In case the operation times out (No response from the uC) or
 *       polling maximal amount of retries has reached, the logic
 *       considers it as an invalid state of the uC/IPA, and
 *       issues a kernel panic.
@@ -640,121 +764,8 @@ EXPORT_SYMBOL(ipa3_uc_load_notify);
int ipa3_uc_send_cmd(u32 cmd, u32 opcode, u32 expected_status,
		    bool polling_mode, unsigned long timeout_jiffies)
{
	int index;
	union IpaHwCpuCmdCompletedResponseData_t uc_rsp;
	unsigned long flags;
	int retries = 0;

	IPA3_UC_LOCK(flags);

	if (ipa3_uc_state_check()) {
		IPADBG("uC send command aborted\n");
		IPA3_UC_UNLOCK(flags);
		return -EBADF;
	}

send_cmd:
	if (ipa3_ctx->apply_rg10_wa) {
		if (!polling_mode)
			IPADBG("Overriding mode to polling mode\n");
		polling_mode = true;
	} else {
		init_completion(&ipa3_ctx->uc_ctx.uc_completion);
	}

	ipa3_ctx->uc_ctx.uc_sram_mmio->cmdParams = cmd;
	ipa3_ctx->uc_ctx.uc_sram_mmio->cmdOp = opcode;
	ipa3_ctx->uc_ctx.pending_cmd = opcode;
	ipa3_ctx->uc_ctx.uc_sram_mmio->responseOp = 0;
	ipa3_ctx->uc_ctx.uc_sram_mmio->responseParams = 0;

	ipa3_ctx->uc_ctx.uc_status = 0;

	/* ensure write to shared memory is done before triggering uc */
	wmb();

	if (ipa3_ctx->apply_rg10_wa)
		ipa_write_reg(ipa3_ctx->mmio,
			IPA_UC_MAILBOX_m_n_OFFS_v3_0(IPA_CPU_2_HW_CMD_MBOX_m,
			IPA_CPU_2_HW_CMD_MBOX_n), 0x1);
	else
		ipa_write_reg(ipa3_ctx->mmio, IPA_IRQ_EE_UC_n_OFFS(0), 0x1);

	if (polling_mode) {
		for (index = 0; index < IPA_UC_POLL_MAX_RETRY; index++) {
			if (ipa3_ctx->uc_ctx.uc_sram_mmio->responseOp ==
			    IPA_HW_2_CPU_RESPONSE_CMD_COMPLETED) {
				uc_rsp.raw32b = ipa3_ctx->uc_ctx.uc_sram_mmio->
						responseParams;
				if (uc_rsp.params.originalCmdOp ==
					ipa3_ctx->uc_ctx.pending_cmd) {
					ipa3_ctx->uc_ctx.uc_status =
						uc_rsp.params.status;
					break;
				}
			}
			if (ipa3_ctx->apply_rg10_wa)
				udelay(IPA_UC_POLL_SLEEP_USEC);
			else
				usleep_range(IPA_UC_POLL_SLEEP_USEC,
					IPA_UC_POLL_SLEEP_USEC);
		}

		if (index == IPA_UC_POLL_MAX_RETRY) {
			IPAERR("uC max polling retries reached\n");
			if (ipa3_ctx->uc_ctx.uc_failed) {
				IPAERR("uC reported on Error, errorType = %s\n",
					ipa_hw_error_str(ipa3_ctx->
					uc_ctx.uc_error_type));
			}
			IPA3_UC_UNLOCK(flags);
			BUG();
			return -EFAULT;
		}
	} else {
		if (wait_for_completion_timeout(&ipa3_ctx->uc_ctx.uc_completion,
			timeout_jiffies) == 0) {
			IPAERR("uC timed out\n");
			if (ipa3_ctx->uc_ctx.uc_failed) {
				IPAERR("uC reported on Error, errorType = %s\n",
					ipa_hw_error_str(ipa3_ctx->
					uc_ctx.uc_error_type));
			}
			IPA3_UC_UNLOCK(flags);
			BUG();
			return -EFAULT;
		}
	}

	if (ipa3_ctx->uc_ctx.uc_status != expected_status) {
		if (ipa3_ctx->uc_ctx.uc_status ==
			IPA_HW_PROD_DISABLE_CMD_GSI_STOP_FAILURE) {
			retries++;
			if (retries == IPA_GSI_CHANNEL_STOP_MAX_RETRY) {
				IPAERR("Failed after %d tries\n", retries);
				IPA3_UC_UNLOCK(flags);
				BUG();
				return -EFAULT;
			}

			ipa3_inject_dma_task_for_gsi();
			/* sleep for short period to flush IPA */
			usleep_range(IPA_GSI_CHANNEL_STOP_SLEEP_MIN_USEC,
				IPA_GSI_CHANNEL_STOP_SLEEP_MAX_USEC);
			goto send_cmd;
		}

		IPAERR("Recevied status %u, Expected status %u\n",
			ipa3_ctx->uc_ctx.uc_status, expected_status);
		IPA3_UC_UNLOCK(flags);
		return -EFAULT;
	}

	IPA3_UC_UNLOCK(flags);

	IPADBG("uC cmd %u send succeeded\n", opcode);

	return 0;
	return ipa3_uc_send_cmd_64b_param(cmd, 0, opcode,
		expected_status, polling_mode, timeout_jiffies);
}

/**
@@ -894,42 +905,24 @@ int ipa3_uc_update_hw_flags(u32 flags)
 */
void ipa3_uc_rg10_write_reg(void *base, u32 offset, u32 val)
{
	struct ipa3_mem_buffer reg_data_mem = {0};
	struct IpaHwRegWriteCmdData_t *reg_data;
	int ret = 0;
	u32 pbase;
	int ret;
	u32 paddr;

	if (!ipa3_ctx->apply_rg10_wa)
		return ipa_write_reg(base, offset, val);

	reg_data_mem.size = sizeof(struct IpaHwRegWriteCmdData_t);
	reg_data_mem.base = dma_alloc_coherent(ipa3_ctx->uc_pdev,
		reg_data_mem.size, &reg_data_mem.phys_base,
		GFP_ATOMIC | __GFP_REPEAT);
	if (!reg_data_mem.base) {
		IPAERR("fail to alloc DMA buff of size %d\n",
			reg_data_mem.size);
		BUG();
	}

	/* calculate physical base address */
	pbase = ipa3_ctx->ipa_wrapper_base + ipa3_ctx->ctrl->ipa_reg_base_ofst;

	reg_data = reg_data_mem.base;
	reg_data->RegisterAddress = pbase + offset;
	reg_data->RegisterValue = val;
	/* calculate register physical address */
	paddr = ipa3_ctx->ipa_wrapper_base + ipa3_ctx->ctrl->ipa_reg_base_ofst;
	paddr += offset;

	IPADBG("Sending uC cmd to reg write: addr=0x%x val=0x%x\n",
		reg_data->RegisterAddress, val);
	ret = ipa3_uc_send_cmd((u32)reg_data_mem.phys_base,
		paddr, val);
	ret = ipa3_uc_send_cmd_64b_param(paddr, val,
		IPA_CPU_2_HW_CMD_REG_WRITE, 0, true, 0);
	if (ret) {
		IPAERR("failed to send cmd to uC for reg write\n");
		BUG();
	}

	dma_free_coherent(ipa3_ctx->uc_pdev, reg_data_mem.size,
		reg_data_mem.base, reg_data_mem.phys_base);
}

/**