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

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

Merge "slim_msm: Add support for external MDM restart"

parents 66162040 76c6b0e1
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -54,7 +54,11 @@ Optional property:
		 are to be used, so that application processor can query
		 logical address of the ported generic device to be used.
		 Other than PC, fields of EA are same across platforms.

 -qcom,slim-mdm: This value indicates presence of slimbus component on
		 external mdm. This property enables the slimbus driver to
		 receive subsytem restart notification from mdm and follow
		 appropriate steps to ensure communication on the bus can be
		 resumed after mdm-restart.
Example:
	slim@fe12f000 {
		cell-index = <1>;
+84 −8
Original line number Diff line number Diff line
@@ -83,6 +83,7 @@ enum ngd_status {
};

static int ngd_slim_runtime_resume(struct device *device);
static int ngd_slim_power_up(struct msm_slim_ctrl *dev);

static irqreturn_t ngd_slim_interrupt(int irq, void *d)
{
@@ -180,6 +181,41 @@ static int ngd_qmi_available(struct notifier_block *n, unsigned long code,
	return 0;
}

static int mdm_ssr_notify_cb(struct notifier_block *n, unsigned long code,
				void *_cmd)
{
	struct msm_slim_mdm *mdm = container_of(n, struct msm_slim_mdm, nb);
	struct msm_slim_ctrl *dev = container_of(mdm, struct msm_slim_ctrl,
						mdm);
	int ret;

	switch (code) {
	case SUBSYS_BEFORE_SHUTDOWN:
		/* make sure runtime-pm doesn't suspend during modem SSR */
		pm_runtime_get_noresume(dev->dev);
		break;
	case SUBSYS_AFTER_POWERUP:
		ret = msm_slim_qmi_check_framer_request(dev);
		dev_err(dev->dev,
			"%s:SLIM %lu external_modem SSR notify cb, ret %d",
			__func__, code, ret);
		/*
		 * Next codec transaction will reinit the HW
		 * if it was suspended
		 */
		if (pm_runtime_suspended(dev->dev) ||
			dev->state >= MSM_CTRL_ASLEEP) {
			break;
		} else {
			ngd_slim_power_up(dev);
			msm_slim_put_ctrl(dev);
		}
	default:
		break;
	}
	return NOTIFY_DONE;
}

static int ngd_get_tid(struct slim_controller *ctrl, struct slim_msg_txn *txn,
				u8 *tid, struct completion *done)
{
@@ -744,6 +780,7 @@ capability_retry:
		ret = ngd_xfer_msg(&dev->ctrl, &txn);
		if (!ret) {
			enum msm_ctrl_state prev_state = dev->state;
			pr_info("SLIM SAT: capability exchange successful");
			dev->state = MSM_CTRL_AWAKE;
			if (prev_state >= MSM_CTRL_ASLEEP)
				complete(&dev->reconf);
@@ -815,7 +852,7 @@ capability_retry:
static int ngd_slim_power_up(struct msm_slim_ctrl *dev)
{
	void __iomem *ngd;
	int timeout, ret;
	int timeout, ret = 0;
	enum msm_ctrl_state cur_state = dev->state;
	u32 laddr;
	u32 ngd_int = (NGD_INT_TX_NACKED_2 |
@@ -830,11 +867,14 @@ static int ngd_slim_power_up(struct msm_slim_ctrl *dev)
			pr_err("slimbus QMI init timed out");
	}

	/* No need to vote if contorller is not in low power mode */
	if (cur_state == MSM_CTRL_DOWN || cur_state == MSM_CTRL_ASLEEP) {
		ret = msm_slim_qmi_power_request(dev, true);
		if (ret) {
			pr_err("SLIM QMI power request failed:%d", ret);
			return ret;
		}
	}
	if (!dev->ver) {
		dev->ver = readl_relaxed(dev->base);
		/* Version info in 16 MSbits */
@@ -843,15 +883,36 @@ static int ngd_slim_power_up(struct msm_slim_ctrl *dev)
	ngd = dev->base + NGD_BASE(dev->ctrl.nr, dev->ver);
	laddr = readl_relaxed(ngd + NGD_STATUS);
	if (laddr & NGD_LADDR) {
		/*
		 * external MDM restart case where ADSP itself was active framer
		 * For example, modem restarted when playback was active
		 */
		if (cur_state == MSM_CTRL_AWAKE) {
			pr_err("SLIM MDM restart: ADSP active framer:NO OP");
			return 0;
		}
		/*
		 * ADSP power collapse case, where HW wasn't reset.
		 * Reconnect BAM pipes if disconnected
		 */
		ngd_slim_setup_msg_path(dev);
		return 0;
	} else if (cur_state != MSM_CTRL_DOWN) {
		pr_info("ADSP P.C. CTRL state:%d NGD not enumerated:0x%x",
	} else if (cur_state == MSM_CTRL_ASLEEP) {
		pr_debug("ADSP P.C. CTRL state:%d NGD not enumerated:0x%x",
					dev->state, laddr);
	} else if (cur_state == MSM_CTRL_IDLE || cur_state == MSM_CTRL_AWAKE) {
		/*
		 * external MDM SSR when only voice call is in progress.
		 * ADSP will reset slimbus HW. disconnect BAM pipes so that
		 * they can be connected after capability message is received.
		 * Set device state to ASLEEP to be synchronous with the HW
		 */
		pr_err("SLIM MDM restart: MDM active framer: reinit HW");
		dev->state = MSM_CTRL_ASLEEP;
		msm_slim_disconnect_endp(dev, &dev->rx_msgq,
					&dev->use_rx_msgqs);
		msm_slim_disconnect_endp(dev, &dev->tx_msgq,
					&dev->use_tx_msgqs);
	}
	/* ADSP SSR scenario, need to disconnect pipe before connecting */
	if (dev->use_rx_msgqs == MSM_MSGQ_DOWN) {
@@ -882,7 +943,7 @@ static int ngd_slim_power_up(struct msm_slim_ctrl *dev)

	timeout = wait_for_completion_timeout(&dev->reconf, HZ);
	if (!timeout) {
		pr_err("failed to received master capability");
		pr_err("Failed to receive master capability");
		return -ETIMEDOUT;
	}
	if (cur_state == MSM_CTRL_DOWN)
@@ -1043,6 +1104,7 @@ static int ngd_slim_probe(struct platform_device *pdev)
	struct resource		*irq, *bam_irq;
	enum apr_subsys_state q6_state;
	bool			rxreg_access = false;
	bool			slim_mdm = false;

	q6_state = apr_get_q6_state();
	if (q6_state == APR_SUBSYS_DOWN) {
@@ -1111,6 +1173,8 @@ static int ngd_slim_probe(struct platform_device *pdev)
					&dev->pdata.apps_pipes);
		of_property_read_u32(pdev->dev.of_node, "qcom,ea-pc",
					&dev->pdata.eapc);
		slim_mdm = of_property_read_bool(pdev->dev.of_node,
					"qcom,slim-mdm");
	} else {
		dev->ctrl.nr = pdev->id;
	}
@@ -1180,6 +1244,16 @@ static int ngd_slim_probe(struct platform_device *pdev)
	pm_runtime_set_suspended(dev->dev);
	pm_runtime_enable(dev->dev);

	if (slim_mdm) {
		dev->mdm.nb.notifier_call = mdm_ssr_notify_cb;
		dev->mdm.ssr = subsys_notif_register_notifier("external_modem",
							&dev->mdm.nb);
		if (IS_ERR_OR_NULL(dev->mdm.ssr))
			dev_err(dev->dev,
				"subsys_notif_register_notifier failed %p",
				dev->mdm.ssr);
	}

	INIT_WORK(&dev->slave_notify, ngd_laddr_lookup);
	INIT_WORK(&dev->qmi.ssr_down, ngd_adsp_down);
	INIT_WORK(&dev->qmi.ssr_up, ngd_adsp_up);
@@ -1237,6 +1311,8 @@ static int ngd_slim_remove(struct platform_device *pdev)
				SLIMBUS_QMI_SVC_V1,
				SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
	pm_runtime_disable(&pdev->dev);
	if (!IS_ERR_OR_NULL(dev->mdm.ssr))
		subsys_notif_unregister_notifier(dev->mdm.ssr, &dev->mdm.nb);
	free_irq(dev->irq, dev);
	slim_del_controller(&dev->ctrl);
	kthread_stop(dev->rx_msgq_thread);
+60 −0
Original line number Diff line number Diff line
@@ -884,11 +884,14 @@ void msm_slim_sps_exit(struct msm_slim_ctrl *dev, bool dereg)
#define SLIMBUS_QMI_SELECT_INSTANCE_RESP_V01 0x0020
#define SLIMBUS_QMI_POWER_REQ_V01 0x0021
#define SLIMBUS_QMI_POWER_RESP_V01 0x0021
#define SLIMBUS_QMI_CHECK_FRAMER_STATUS_REQ 0x0022
#define SLIMBUS_QMI_CHECK_FRAMER_STATUS_RESP 0x0022

#define SLIMBUS_QMI_POWER_REQ_MAX_MSG_LEN 7
#define SLIMBUS_QMI_POWER_RESP_MAX_MSG_LEN 7
#define SLIMBUS_QMI_SELECT_INSTANCE_REQ_MAX_MSG_LEN 14
#define SLIMBUS_QMI_SELECT_INSTANCE_RESP_MAX_MSG_LEN 7
#define SLIMBUS_QMI_CHECK_FRAMER_STAT_RESP_MAX_MSG_LEN 7

enum slimbus_mode_enum_type_v01 {
	/* To force a 32 bit signed enum. Do not change or use*/
@@ -936,6 +939,13 @@ struct slimbus_power_resp_msg_v01 {
	struct qmi_response_type_v01 resp;
};

struct slimbus_chkfrm_resp_msg {
	/* Mandatory */
	/* Result Code */
	struct qmi_response_type_v01 resp;
};


static struct elem_info slimbus_select_inst_req_msg_v01_ei[] = {
	{
		.data_type = QMI_UNSIGNED_4_BYTE,
@@ -1042,6 +1052,27 @@ static struct elem_info slimbus_power_resp_msg_v01_ei[] = {
	},
};

static struct elem_info slimbus_chkfrm_resp_msg_v01_ei[] = {
	{
		.data_type = QMI_STRUCT,
		.elem_len  = 1,
		.elem_size = sizeof(struct qmi_response_type_v01),
		.is_array  = NO_ARRAY,
		.tlv_type  = 0x02,
		.offset    = offsetof(struct slimbus_chkfrm_resp_msg, resp),
		.ei_array  = get_qmi_response_type_v01_ei(),
	},
	{
		.data_type = QMI_EOTI,
		.elem_len  = 0,
		.elem_size = 0,
		.is_array  = NO_ARRAY,
		.tlv_type  = 0x00,
		.offset    = 0,
		.ei_array  = NULL,
	},
};

static void msm_slim_qmi_recv_msg(struct kthread_work *work)
{
	int rc;
@@ -1232,3 +1263,32 @@ int msm_slim_qmi_power_request(struct msm_slim_ctrl *dev, bool active)

	return msm_slim_qmi_send_power_request(dev, &req);
}

int msm_slim_qmi_check_framer_request(struct msm_slim_ctrl *dev)
{
	struct slimbus_chkfrm_resp_msg resp = { { 0, 0 } };
	struct msg_desc req_desc, resp_desc;
	int rc;

	req_desc.msg_id = SLIMBUS_QMI_CHECK_FRAMER_STATUS_REQ;
	req_desc.max_msg_len = 0;
	req_desc.ei_array = NULL;

	resp_desc.msg_id = SLIMBUS_QMI_CHECK_FRAMER_STATUS_RESP;
	resp_desc.max_msg_len = SLIMBUS_QMI_CHECK_FRAMER_STAT_RESP_MAX_MSG_LEN;
	resp_desc.ei_array = slimbus_chkfrm_resp_msg_v01_ei;

	rc = qmi_send_req_wait(dev->qmi.handle, &req_desc, NULL, 0,
					&resp_desc, &resp, sizeof(resp), 5000);
	if (rc < 0) {
		dev_err(dev->dev, "%s: QMI send req failed %d\n", __func__, rc);
		return rc;
	}
	/* Check the response */
	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
		dev_err(dev->dev, "%s: QMI request failed 0x%x (%s)\n",
			__func__, resp.resp.result, get_qmi_error(&resp.resp));
		return -EREMOTEIO;
	}
	return 0;
}
+8 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#include <linux/irq.h>
#include <linux/kthread.h>
#include <mach/msm_qmi_interface.h>
#include <mach/subsystem_notif.h>

/* Per spec.max 40 bytes per received message */
#define SLIM_MSGQ_BUF_LEN	40
@@ -206,6 +207,11 @@ struct msm_slim_qmi {
	struct work_struct		ssr_up;
};

struct msm_slim_mdm {
	struct notifier_block nb;
	void *ssr;
};

struct msm_slim_pdata {
	u32 apps_pipes;
	u32 eapc;
@@ -254,6 +260,7 @@ struct msm_slim_ctrl {
	struct work_struct	slave_notify;
	struct msm_slim_qmi	qmi;
	struct msm_slim_pdata	pdata;
	struct msm_slim_mdm	mdm;
};

struct msm_sat_chan {
@@ -318,4 +325,5 @@ void msm_slim_disconnect_endp(struct msm_slim_ctrl *dev,
void msm_slim_qmi_exit(struct msm_slim_ctrl *dev);
int msm_slim_qmi_init(struct msm_slim_ctrl *dev, bool apps_is_master);
int msm_slim_qmi_power_request(struct msm_slim_ctrl *dev, bool active);
int msm_slim_qmi_check_framer_request(struct msm_slim_ctrl *dev);
#endif