Sfoglia il codice sorgente

msm: eva: power on off sequence update

update according to HPG
--added utility to asser & de-assert clk individually by name
--added xo clk reset and vote for sleep_clk
--defined more CVP_AON_WRAPPER_XXX regs in IO header
--updated power off controller sequence
--updated power on controller sequence
Debug, to move later
--clk_set_flags for mvs1c cbcr for retain_periph retain_mem

Change-Id: Ia0872270412119e4dc6c3e2b12b59862adeea0c5
Signed-off-by: Yu SI <[email protected]>
Signed-off-by: George Shen <[email protected]>
Yu SI 2 anni fa
parent
commit
d9410c7653
4 ha cambiato i file con 234 aggiunte e 16 eliminazioni
  1. 9 0
      msm/eva/cvp_core_hfi.h
  2. 221 15
      msm/eva/cvp_hfi.c
  3. 3 0
      msm/eva/cvp_hfi_io.h
  4. 1 1
      msm/eva/msm_cvp_platform.c

+ 9 - 0
msm/eva/cvp_core_hfi.h

@@ -175,6 +175,13 @@ struct cvp_iface_q_info {
 	iris_hfi_for_each_thing_reverse_continue(__device, __rinfo, \
 			clock, __from)
 
+/* reset set helpers */
+#define iris_hfi_for_each_reset_clock(__device, __resetinfo) \
+	iris_hfi_for_each_thing(__device, __resetinfo, reset)
+
+#define iris_hfi_for_each_reset_clock_reverse(__device, __resetinfo) \
+	iris_hfi_for_each_thing_reverse(__device, __resetinfo, reset)
+
 /* Bus set helpers */
 #define iris_hfi_for_each_bus(__device, __binfo) \
 	iris_hfi_for_each_thing(__device, __binfo, bus)
@@ -224,6 +231,8 @@ struct iris_hfi_vpu_ops {
 	int (*reset_ahb2axi_bridge)(struct iris_hfi_device *device);
 	void (*power_off)(struct iris_hfi_device *device);
 	void (*noc_error_info)(struct iris_hfi_device *device);
+	int (*reset_control_assert_name)(struct iris_hfi_device *device, const char *name);
+	int (*reset_control_deassert_name)(struct iris_hfi_device *device, const char *name);
 };
 
 struct iris_hfi_device {

+ 221 - 15
msm/eva/cvp_hfi.c

@@ -33,6 +33,9 @@
 #include "vm/cvp_vm.h"
 #include "cvp_dump.h"
 
+// ysi - added for debug
+#include <linux/clk/qcom.h>
+
 #define REG_ADDR_OFFSET_BITMASK	0x000FFFFF
 #define QDSS_IOVA_START 0x80001000
 #define MIN_PAYLOAD_SIZE 3
@@ -103,6 +106,9 @@ static int __power_off_controller(struct iris_hfi_device *device);
 static int __hwfence_regs_map(struct iris_hfi_device *device);
 static int __hwfence_regs_unmap(struct iris_hfi_device *device);
 
+static int __reset_control_assert_name(struct iris_hfi_device *device, const char *name);
+static int __reset_control_deassert_name(struct iris_hfi_device *device, const char *name);
+
 static struct iris_hfi_vpu_ops iris2_ops = {
 	.interrupt_init = interrupt_init_iris2,
 	.setup_dsp_uc_memmap = setup_dsp_uc_memmap_vpu5,
@@ -110,6 +116,8 @@ static struct iris_hfi_vpu_ops iris2_ops = {
 	.reset_ahb2axi_bridge = reset_ahb2axi_bridge,
 	.power_off = power_off_iris2,
 	.noc_error_info = __noc_error_info_iris2,
+	.reset_control_assert_name = __reset_control_assert_name,
+	.reset_control_deassert_name = __reset_control_deassert_name,
 };
 
 /**
@@ -1001,7 +1009,7 @@ static inline void check_tensilica_in_reset(struct iris_hfi_device *device)
 static inline int __boot_firmware(struct iris_hfi_device *device)
 {
 	int rc = 0, loop = 10;
-	u32 ctrl_init_val = 0, ctrl_status = 0, count = 0, max_tries = 1000;
+	u32 ctrl_init_val = 0, ctrl_status = 0, count = 0, max_tries = 500;
 	u32 reg_gdsc;
 
 	/*
@@ -1013,6 +1021,9 @@ static inline int __boot_firmware(struct iris_hfi_device *device)
 	if (__enable_hw_power_collapse(device))
 		dprintk(CVP_ERR, "Failed to enabled inter-frame PC\n");
 
+	if (!msm_cvp_fw_low_power_mode)
+		goto skip_core_power_check;
+
 	while (loop) {
 		reg_gdsc = __read_register(device, CVP_CC_MVS1_GDSCR);
 		if (reg_gdsc & 0x80000000) {
@@ -1026,6 +1037,7 @@ static inline int __boot_firmware(struct iris_hfi_device *device)
 	if (!loop)
 		dprintk(CVP_ERR, "fail to power off CORE during resume\n");
 
+skip_core_power_check:
 	ctrl_init_val = BIT(0);
 	__write_register(device, CVP_CTRL_INIT, ctrl_init_val);
 	while (!ctrl_status && count < max_tries) {
@@ -1037,7 +1049,7 @@ static inline int __boot_firmware(struct iris_hfi_device *device)
 		}
 
 		/* Reduce to 500, 1000 on silicon */
-		usleep_range(50000, 100000);
+		usleep_range(500, 1000);
 		count++;
 	}
 
@@ -3393,6 +3405,69 @@ failed_to_reset:
 	return rc;
 }
 
+
+static int __reset_control_assert_name(struct iris_hfi_device *device,
+	const char *name)
+{
+	struct reset_info *rcinfo = NULL;
+	int rc = 0;
+	bool found = false;
+
+	iris_hfi_for_each_reset_clock(device, rcinfo) {
+		if (strcmp(rcinfo->name, name))
+			continue;
+
+		found = true;
+		rc = reset_control_assert(rcinfo->rst);
+		if (rc)
+			dprintk(CVP_ERR,
+				"%s: failed to assert reset control (%s), rc = %d\n",
+				__func__, rcinfo->name, rc);
+		else
+			dprintk(CVP_PWR, "%s: assert reset control (%s)\n",
+				__func__, rcinfo->name);
+		break;
+	}
+	if (!found) {
+		dprintk(CVP_PWR, "%s: reset control (%s) not found\n",
+			__func__, name);
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+static int __reset_control_deassert_name(struct iris_hfi_device *device,
+	const char *name)
+{
+	struct reset_info *rcinfo = NULL;
+	int rc = 0;
+	bool found = false;
+
+	iris_hfi_for_each_reset_clock(device, rcinfo) {
+		if (strcmp(rcinfo->name, name))
+			continue;
+		found = true;
+		rc = reset_control_deassert(rcinfo->rst);
+		if (rc)
+			dprintk(CVP_ERR, 
+				"%s: deassert reset control for (%s) failed, rc %d\n",
+				__func__, rcinfo->name, rc);
+		else
+			dprintk(CVP_PWR, "%s: deassert reset control (%s)\n",
+				__func__, rcinfo->name);
+		break;
+	}
+	if (!found) {
+		dprintk(CVP_PWR, "%s: reset control (%s) not found\n",
+			__func__, name);
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+
 static void __deinit_bus(struct iris_hfi_device *device)
 {
 	struct bus_info *bus = NULL;
@@ -3947,18 +4022,53 @@ static int __power_on_controller(struct iris_hfi_device *device)
 {
 	int rc = 0;
 
+	struct clock_info *cl = NULL;
+
 	rc = __enable_regulator(device, "cvp");
 	if (rc) {
 		dprintk(CVP_ERR, "Failed to enable ctrler: %d\n", rc);
 		return rc;
 	}
 
-	rc = call_iris_op(device, reset_ahb2axi_bridge, device);
+	rc = msm_cvp_prepare_enable_clk(device, "sleep_clk");
 	if (rc) {
-		dprintk(CVP_ERR, "Failed to reset ahb2axi: %d\n", rc);
+		dprintk(CVP_ERR, "Failed to enable sleep clk: %d\n", rc);
 		goto fail_reset_clks;
 	}
 
+	rc = call_iris_op(device, reset_control_assert_name, device, "cvp_axi_reset");
+	if (rc) {
+		dprintk(CVP_ERR, "%s: assert cvp_axi_reset failed\n", __func__);
+	}
+	else {
+		dprintk(CVP_PWR, "%s: ysi-debug assert cvp_axi_reset succeed\n", __func__);
+	}
+
+	rc = call_iris_op(device, reset_control_assert_name, device, "cvp_core_reset");
+	if (rc) {
+		dprintk(CVP_ERR, "%s: assert cvp_core_reset failed\n", __func__);
+	}
+	else {
+		dprintk(CVP_PWR, "%s: ysi-debug assert cvp_core_reset succeed\n", __func__);
+	}
+	/* wait for deassert */
+	usleep_range(1000, 1050);
+
+	rc = call_iris_op(device, reset_control_deassert_name, device, "cvp_axi_reset");
+	if (rc) {
+		dprintk(CVP_ERR, "%s: de-assert cvp_axi_reset failed\n", __func__);
+	}
+	else {
+		dprintk(CVP_PWR, "%s: ysi-debug de-assert cvp_axi_reset succeed\n", __func__);
+	}
+	rc = call_iris_op(device, reset_control_deassert_name, device, "cvp_core_reset");
+	if (rc) {
+		dprintk(CVP_ERR, "%s: de-assert cvp_core_reset failed\n", __func__);
+	}
+	else {
+		dprintk(CVP_PWR, "%s: ysi-debug de-assert cvp_core_reset succeed\n", __func__);
+	}
+
 	rc = msm_cvp_prepare_enable_clk(device, "gcc_video_axi1");
 	if (rc) {
 		dprintk(CVP_ERR, "Failed to enable axi1 clk: %d\n", rc);
@@ -3971,6 +4081,14 @@ static int __power_on_controller(struct iris_hfi_device *device)
 		goto fail_enable_clk;
 	}
 
+	iris_hfi_for_each_clock(device, cl) {
+		if (strcmp(cl->name, "cvp_clk")) {
+			qcom_clk_set_flags(cl->clk, CLKFLAG_RETAIN_PERIPH);
+			qcom_clk_set_flags(cl->clk, CLKFLAG_RETAIN_MEM);
+			break;
+		}
+	}
+
 	dprintk(CVP_PWR, "EVA controller powered on\n");
 	return 0;
 
@@ -4006,14 +4124,14 @@ static int __power_on_core(struct iris_hfi_device *device)
 		return rc;
 	}
 
-#ifdef CONFIG_EVA_PINEAPPLE
+/*#ifdef CONFIG_EVA_PINEAPPLE
 	__write_register(device, CVP_AON_WRAPPER_CVP_NOC_ARCG_CONTROL, 0);
 	__write_register(device, CVP_NOC_RCGCONTROLLER_HYSTERESIS_LOW, 0x2f);
 	__write_register(device, CVP_NOC_RCG_VNOC_NOC_CLK_FORCECLOCKON_LOW, 1);
 	__write_register(device, CVP_NOC_RCGCONTROLLER_MAINCTL_LOW, 1);
 	usleep_range(50, 100);
 	__write_register(device, CVP_NOC_RCG_VNOC_NOC_CLK_FORCECLOCKON_LOW, 0);
-#endif
+#endif*/
 	dprintk(CVP_PWR, "EVA core powered on\n");
 	return 0;
 }
@@ -4163,6 +4281,8 @@ static int __power_off_controller(struct iris_hfi_device *device)
 	u32 sbm_ln0_low;
 	int rc;
 
+	u32 spare_val, spare_status;
+
 	/* HPG 6.2.2 Step 1  */
 	__write_register(device, CVP_CPU_CS_X2RPMh, 0x3);
 
@@ -4247,27 +4367,111 @@ static int __power_off_controller(struct iris_hfi_device *device)
 			"DBLP Release: lpi_status %x\n", lpi_status);
 	}
 
-	/* PDXFIFO reset: addition for Kailua */
-#ifdef CONFIG_EVA_KALAMA
+	/* PDXFIFO reset: addition for Kailua / Lanai */
+
 	__write_register(device, CVP_WRAPPER_AXI_CLOCK_CONFIG, 0x3);
 	__write_register(device, CVP_WRAPPER_QNS4PDXFIFO_RESET, 0x1);
 	__write_register(device, CVP_WRAPPER_QNS4PDXFIFO_RESET, 0x0);
 	__write_register(device, CVP_WRAPPER_AXI_CLOCK_CONFIG, 0x0);
-#endif
+
 	/* HPG 6.2.2 Step 5 */
 	msm_cvp_disable_unprepare_clk(device, "cvp_clk");
 
-	/* HPG 6.2.2 Step 7 */
-	msm_cvp_disable_unprepare_clk(device, "gcc_video_axi1");
+	rc = call_iris_op(device, reset_control_assert_name, device, "cvp_axi_reset");
+	if (rc) {
+		dprintk(CVP_ERR, "%s: assert cvp_axi_reset failed\n", __func__);
+	}
+	else {
+		dprintk(CVP_PWR, "%s: ysi-debug assert cvp_axi_reset succeed\n", __func__);
+	}
 
-	/* Added to avoid pending transaction after power off */
-	rc = call_iris_op(device, reset_ahb2axi_bridge, device);
-	if (rc)
-		dprintk(CVP_ERR, "Off: Failed to reset ahb2axi: %d\n", rc);
+	rc = call_iris_op(device, reset_control_assert_name, device, "cvp_core_reset");
+	if (rc) {
+		dprintk(CVP_ERR, "%s: assert cvp_core_reset failed\n", __func__);
+	}
+	else {
+		dprintk(CVP_PWR, "%s: ysi-debug assert cvp_core_reset succeed\n", __func__);
+	}
+	/* wait for deassert */
+	usleep_range(1000, 1050);
+
+	rc = call_iris_op(device, reset_control_deassert_name, device, "cvp_axi_reset");
+	if (rc) {
+		dprintk(CVP_ERR, "%s: de-assert cvp_axi_reset failed\n", __func__);
+	}
+	else {
+		dprintk(CVP_PWR, "%s: ysi-debug de-assert cvp_axi_reset succeed\n", __func__);
+	}
+	rc = call_iris_op(device, reset_control_deassert_name, device, "cvp_core_reset");
+	if (rc) {
+		dprintk(CVP_ERR, "%s: de-assert cvp_core_reset failed\n", __func__);
+	}
+	else {
+		dprintk(CVP_PWR, "%s: ysi-debug de-assert cvp_core_reset succeed\n", __func__);
+	}
+
+	/* disable EVA NoC clock */
+	__write_register(device, CVP_AON_WRAPPER_CVP_NOC_CORE_CLK_CONTROL, 0x1);
+
+	/* enable EVA NoC reset */
+	__write_register(device, CVP_AON_WRAPPER_CVP_NOC_CORE_SW_RESET, 0x1);
+
+
+	spare_status = 0x1;
+	while (spare_status != 0x0) {
+		spare_val = __read_register(device, CVP_AON_WRAPPER_SPARE);
+		dprintk(CVP_PWR, "%s: ysi-debug spare_val %x\n", __func__, spare_val);
+		spare_status = spare_val & 0x2;
+		dprintk(CVP_PWR, "%s: ysi-debug spare_status & 0x2 %x\n", __func__, spare_status);
+		usleep_range(50, 100);
+	}
+	__write_register(device, CVP_AON_WRAPPER_SPARE, 0x1);
+	rc = call_iris_op(device, reset_control_assert_name, device, "cvp_xo_reset");
+	if (rc) {
+		dprintk(CVP_ERR, "%s: assert cvp_xo_reset failed\n", __func__);
+	}
+	else {
+		dprintk(CVP_PWR, "%s: ysi-debug assert cvp_xo_reset succeed\n", __func__);
+	}
+
+	/* de-assert EVA_NoC reset */
+	__write_register(device, CVP_AON_WRAPPER_CVP_NOC_CORE_SW_RESET, 0x0);
+
+	/* de-assert EVA video_cc XO reset and enable video_cc XO clock after 80us */
+	usleep_range(80, 100);
+	rc = call_iris_op(device, reset_control_deassert_name, device, "cvp_xo_reset");
+	if (rc) {
+		dprintk(CVP_ERR, "%s: de-assert cvp_xo_reset failed\n", __func__);
+	}
+	else {
+		dprintk(CVP_PWR, "%s: ysi-debug de-assert cvp_xo_reset succeed\n", __func__);
+	}
+
+	/* clear XO mask bit - this step was missing in previous sequence */
+	__write_register(device, CVP_AON_WRAPPER_SPARE, 0x0);
+
+
+	/* enable EVA NoC clock */
+	__write_register(device, CVP_AON_WRAPPER_CVP_NOC_CORE_CLK_CONTROL, 0x0);
+
+	/* De-assert EVA_CTL Force Sleep Retention */
+
+	usleep_range(400, 500);
 
 	/* HPG 6.2.2 Step 6 */
 	__disable_regulator(device, "cvp");
 
+	/* HPG 6.2.2 Step 7 */
+	rc = msm_cvp_disable_unprepare_clk(device, "gcc_video_axi1");
+	if (rc) {
+		dprintk(CVP_ERR, "Failed to enable axi1 clk: %d\n", rc);
+	}
+
+	rc = msm_cvp_disable_unprepare_clk(device, "sleep_clk");
+	if (rc) {
+		dprintk(CVP_ERR, "Failed to disable sleep clk: %d\n", rc);
+	}
+
 	return 0;
 }
 
@@ -4389,6 +4593,8 @@ static int __power_off_core(struct iris_hfi_device *device)
 
 		__print_sidebandmanager_regs(device);
 	}
+
+	__write_register(device, CVP_AON_WRAPPER_CVP_NOC_LPI_CONTROL, 0x0);
 #endif
 
 	if (warn_flag)

+ 3 - 0
msm/eva/cvp_hfi_io.h

@@ -253,6 +253,9 @@
 #define CVP_AON_WRAPPER_CVP_NOC_LPI_CONTROL	(CVP_AON_BASE_OFFS + 0x8)
 #define CVP_AON_WRAPPER_CVP_NOC_LPI_STATUS	(CVP_AON_BASE_OFFS + 0xC)
 #define CVP_AON_WRAPPER_CVP_NOC_ARCG_CONTROL	(CVP_AON_BASE_OFFS + 0x14)
+#define CVP_AON_WRAPPER_CVP_NOC_CORE_CLK_CONTROL	(CVP_AON_BASE_OFFS + 0x24)
+#define CVP_AON_WRAPPER_CVP_NOC_CORE_SW_RESET	(CVP_AON_BASE_OFFS + 0x1C)
+#define CVP_AON_WRAPPER_SPARE		(CVP_AON_BASE_OFFS + 0x28)
 
 #define CVP_CC_BASE_OFFS			0x000F8000
 #define CVP_CC_MVS1C_GDSCR			(CVP_CC_BASE_OFFS + 0x78)

+ 1 - 1
msm/eva/msm_cvp_platform.c

@@ -206,7 +206,7 @@ static struct msm_cvp_common_data sm8650_common_data[] = {
 	},
 	{
 		.key = "qcom,sw-power-collapse",
-		.value = 0,	/* Disable during initial stage for Rumi 48 bringup */
+		.value = 0,
 	},
 	{
 		.key = "qcom,domain-attr-non-fatal-faults",