All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1] clk: qcom: gdsc: Add support to poll CFG register to check GDSC state
@ 2018-05-01  5:03 Taniya Das
  2018-05-02  6:57   ` Stephen Boyd
  0 siblings, 1 reply; 8+ messages in thread
From: Taniya Das @ 2018-05-01  5:03 UTC (permalink / raw)
  To: Stephen Boyd, Michael Turquette
  Cc: Andy Gross, David Brown, Rajendra Nayak, Odelu Kukatla,
	Amit Nischal, linux-arm-msm, linux-soc, linux-clk, linux-kernel,
	Taniya Das

From: Amit Nischal <anischal@codeaurora.org>

The default behavior of the GDSC enable/disable sequence is to
poll the status bits of either the actual GDSCR or the
corresponding HW_CTRL registers.

On targets which have support for a CFG_GDSCR register, the
status bits might not show the correct state of the GDSC,
especially in the disable sequence, where the status bit
will be cleared even before the core is completely power
collapsed. On targets with this issue, poll the power on/off
bits in the CFG_GDSCR register instead to correctly determine
the GDSC state.

Signed-off-by: Amit Nischal <anischal@codeaurora.org>
Signed-off-by: Taniya Das <tdas@codeaurora.org>
---
 drivers/clk/qcom/gdsc.c | 42 ++++++++++++++++++++++++++----------------
 drivers/clk/qcom/gdsc.h |  1 +
 2 files changed, 27 insertions(+), 16 deletions(-)

diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c
index cb61c15..2a6b0ff 100644
--- a/drivers/clk/qcom/gdsc.c
+++ b/drivers/clk/qcom/gdsc.c
@@ -33,6 +33,11 @@
 #define GMEM_CLAMP_IO_MASK	BIT(0)
 #define GMEM_RESET_MASK		BIT(4)

+/* CFG_GDSCR */
+#define GDSC_POWER_UP_COMPLETE		BIT(16)
+#define GDSC_POWER_DOWN_COMPLETE	BIT(15)
+#define CFG_GDSCR_OFFSET		0x4
+
 /* Wait 2^n CXO cycles between all states. Here, n=2 (4 cycles). */
 #define EN_REST_WAIT_VAL	(0x2 << 20)
 #define EN_FEW_WAIT_VAL		(0x8 << 16)
@@ -45,15 +50,28 @@

 #define domain_to_gdsc(domain) container_of(domain, struct gdsc, pd)

-static int gdsc_is_enabled(struct gdsc *sc, unsigned int reg)
+static int gdsc_is_enabled(struct gdsc *sc, bool en)
 {
+	unsigned int reg;
 	u32 val;
 	int ret;

+	if (sc->flags & POLL_CFG_GDSCR)
+		reg = sc->gdscr + CFG_GDSCR_OFFSET;
+	else
+		reg = sc->gds_hw_ctrl ? sc->gds_hw_ctrl : sc->gdscr;
+
 	ret = regmap_read(sc->regmap, reg, &val);
 	if (ret)
 		return ret;

+	if (sc->flags & POLL_CFG_GDSCR) {
+		if (en)
+			return !!(val & GDSC_POWER_UP_COMPLETE);
+		else
+			return !(val & GDSC_POWER_DOWN_COMPLETE);
+	}
+
 	return !!(val & PWR_ON_MASK);
 }

@@ -64,17 +82,17 @@ static int gdsc_hwctrl(struct gdsc *sc, bool en)
 	return regmap_update_bits(sc->regmap, sc->gdscr, HW_CONTROL_MASK, val);
 }

-static int gdsc_poll_status(struct gdsc *sc, unsigned int reg, bool en)
+static int gdsc_poll_status(struct gdsc *sc, bool en)
 {
 	ktime_t start;

 	start = ktime_get();
 	do {
-		if (gdsc_is_enabled(sc, reg) == en)
+		if (gdsc_is_enabled(sc, en) == en)
 			return 0;
 	} while (ktime_us_delta(ktime_get(), start) < TIMEOUT_US);

-	if (gdsc_is_enabled(sc, reg) == en)
+	if (gdsc_is_enabled(sc, en) == en)
 		return 0;

 	return -ETIMEDOUT;
@@ -84,7 +102,6 @@ static int gdsc_toggle_logic(struct gdsc *sc, bool en)
 {
 	int ret;
 	u32 val = en ? 0 : SW_COLLAPSE_MASK;
-	unsigned int status_reg = sc->gdscr;

 	ret = regmap_update_bits(sc->regmap, sc->gdscr, SW_COLLAPSE_MASK, val);
 	if (ret)
@@ -101,8 +118,7 @@ static int gdsc_toggle_logic(struct gdsc *sc, bool en)
 		return 0;
 	}

-	if (sc->gds_hw_ctrl) {
-		status_reg = sc->gds_hw_ctrl;
+	if (sc->gds_hw_ctrl)
 		/*
 		 * The gds hw controller asserts/de-asserts the status bit soon
 		 * after it receives a power on/off request from a master.
@@ -114,9 +130,8 @@ static int gdsc_toggle_logic(struct gdsc *sc, bool en)
 		 * and polling the status bit.
 		 */
 		udelay(1);
-	}

-	return gdsc_poll_status(sc, status_reg, en);
+	return gdsc_poll_status(sc, en);
 }

 static inline int gdsc_deassert_reset(struct gdsc *sc)
@@ -240,8 +255,6 @@ static int gdsc_disable(struct generic_pm_domain *domain)

 	/* Turn off HW trigger mode if supported */
 	if (sc->flags & HW_CTRL) {
-		unsigned int reg;
-
 		ret = gdsc_hwctrl(sc, false);
 		if (ret < 0)
 			return ret;
@@ -253,8 +266,7 @@ static int gdsc_disable(struct generic_pm_domain *domain)
 		 */
 		udelay(1);

-		reg = sc->gds_hw_ctrl ? sc->gds_hw_ctrl : sc->gdscr;
-		ret = gdsc_poll_status(sc, reg, true);
+		ret = gdsc_poll_status(sc, true);
 		if (ret)
 			return ret;
 	}
@@ -276,7 +288,6 @@ static int gdsc_init(struct gdsc *sc)
 {
 	u32 mask, val;
 	int on, ret;
-	unsigned int reg;

 	/*
 	 * Disable HW trigger: collapse/restore occur based on registers writes.
@@ -297,8 +308,7 @@ static int gdsc_init(struct gdsc *sc)
 			return ret;
 	}

-	reg = sc->gds_hw_ctrl ? sc->gds_hw_ctrl : sc->gdscr;
-	on = gdsc_is_enabled(sc, reg);
+	on = gdsc_is_enabled(sc, true);
 	if (on < 0)
 		return on;

diff --git a/drivers/clk/qcom/gdsc.h b/drivers/clk/qcom/gdsc.h
index 9279278..b0cbb87 100644
--- a/drivers/clk/qcom/gdsc.h
+++ b/drivers/clk/qcom/gdsc.h
@@ -55,6 +55,7 @@ struct gdsc {
 #define HW_CTRL		BIT(2)
 #define SW_RESET	BIT(3)
 #define AON_RESET	BIT(4)
+#define POLL_CFG_GDSCR	BIT(5)
 	struct reset_controller_dev	*rcdev;
 	unsigned int			*resets;
 	unsigned int			reset_count;
--
Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member
of the Code Aurora Forum, hosted by the  Linux Foundation.

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v1] clk: qcom: gdsc: Add support to poll CFG register to check GDSC state
  2018-05-01  5:03 [PATCH v1] clk: qcom: gdsc: Add support to poll CFG register to check GDSC state Taniya Das
  2018-05-02  6:57   ` Stephen Boyd
@ 2018-05-02  6:57   ` Stephen Boyd
  0 siblings, 0 replies; 8+ messages in thread
From: Stephen Boyd @ 2018-05-02  6:57 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd
  Cc: Andy Gross, David Brown, Rajendra Nayak, Odelu Kukatla,
	Amit Nischal, linux-arm-msm, linux-soc, linux-clk, linux-kernel,
	Taniya Das

Quoting Taniya Das (2018-04-30 22:03:33)
> @@ -45,15 +50,28 @@
> 
>  #define domain_to_gdsc(domain) container_of(domain, struct gdsc, pd)
> 
> -static int gdsc_is_enabled(struct gdsc *sc, unsigned int reg)
> +static int gdsc_is_enabled(struct gdsc *sc, bool en)
>  {
> +       unsigned int reg;
>         u32 val;
>         int ret;
> 
> +       if (sc->flags & POLL_CFG_GDSCR)
> +               reg = sc->gdscr + CFG_GDSCR_OFFSET;
> +       else
> +               reg = sc->gds_hw_ctrl ? sc->gds_hw_ctrl : sc->gdscr;
> +
>         ret = regmap_read(sc->regmap, reg, &val);
>         if (ret)
>                 return ret;
> 
> +       if (sc->flags & POLL_CFG_GDSCR) {
> +               if (en)
> +                       return !!(val & GDSC_POWER_UP_COMPLETE);
> +               else
> +                       return !(val & GDSC_POWER_DOWN_COMPLETE);

This is confusing, but also is correct, because this function is
returning if the gdsc is enabled or not, and that also happens to be
false when the gdsc is not enabled and this bit is set.

> +       }
> +
>         return !!(val & PWR_ON_MASK);
>  }
> 
> @@ -64,17 +82,17 @@ static int gdsc_hwctrl(struct gdsc *sc, bool en)
>         return regmap_update_bits(sc->regmap, sc->gdscr, HW_CONTROL_MASK, val);
>  }
> 
> -static int gdsc_poll_status(struct gdsc *sc, unsigned int reg, bool en)
> +static int gdsc_poll_status(struct gdsc *sc, bool en)
>  {
>         ktime_t start;
> 
>         start = ktime_get();
>         do {
> -               if (gdsc_is_enabled(sc, reg) == en)
> +               if (gdsc_is_enabled(sc, en) == en)

I still don't like this == en logic. How about this patch on top? If you
can test it out, I'll merge your patch and then my patch to make this
all easier to read. Note that I changed the off case for
POWER_DOWN_COMPLETE to be a double negation.

---8<---
diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c
index 2a6b0ff7d451..4696e241db89 100644
--- a/drivers/clk/qcom/gdsc.c
+++ b/drivers/clk/qcom/gdsc.c
@@ -50,7 +50,13 @@
 
 #define domain_to_gdsc(domain) container_of(domain, struct gdsc, pd)
 
-static int gdsc_is_enabled(struct gdsc *sc, bool en)
+enum gdsc_status {
+	GDSC_OFF,
+	GDSC_ON
+};
+
+/* Returns 1 if GDSC status is status, 0 if not, and < 0 on error */
+static int gdsc_check_status(struct gdsc *sc, enum gdsc_status status)
 {
 	unsigned int reg;
 	u32 val;
@@ -58,21 +64,32 @@ static int gdsc_is_enabled(struct gdsc *sc, bool en)
 
 	if (sc->flags & POLL_CFG_GDSCR)
 		reg = sc->gdscr + CFG_GDSCR_OFFSET;
+	else if (sc->gds_hw_ctrl)
+		reg = sc->gds_hw_ctrl;
 	else
-		reg = sc->gds_hw_ctrl ? sc->gds_hw_ctrl : sc->gdscr;
+		reg = sc->gdscr;
 
 	ret = regmap_read(sc->regmap, reg, &val);
 	if (ret)
 		return ret;
 
 	if (sc->flags & POLL_CFG_GDSCR) {
-		if (en)
+		switch (status) {
+		case GDSC_ON:
 			return !!(val & GDSC_POWER_UP_COMPLETE);
-		else
-			return !(val & GDSC_POWER_DOWN_COMPLETE);
+		case GDSC_OFF:
+			return !!(val & GDSC_POWER_DOWN_COMPLETE);
+		}
+	}
+
+	switch (status) {
+	case GDSC_ON:
+		return !!(val & PWR_ON_MASK);
+	case GDSC_OFF:
+		return !(val & PWR_ON_MASK);
 	}
 
-	return !!(val & PWR_ON_MASK);
+	return -EINVAL;
 }
 
 static int gdsc_hwctrl(struct gdsc *sc, bool en)
@@ -82,33 +99,33 @@ static int gdsc_hwctrl(struct gdsc *sc, bool en)
 	return regmap_update_bits(sc->regmap, sc->gdscr, HW_CONTROL_MASK, val);
 }
 
-static int gdsc_poll_status(struct gdsc *sc, bool en)
+static int gdsc_poll_status(struct gdsc *sc, enum gdsc_status status)
 {
 	ktime_t start;
 
 	start = ktime_get();
 	do {
-		if (gdsc_is_enabled(sc, en) == en)
+		if (gdsc_check_status(sc, status))
 			return 0;
 	} while (ktime_us_delta(ktime_get(), start) < TIMEOUT_US);
 
-	if (gdsc_is_enabled(sc, en) == en)
+	if (gdsc_check_status(sc, status))
 		return 0;
 
 	return -ETIMEDOUT;
 }
 
-static int gdsc_toggle_logic(struct gdsc *sc, bool en)
+static int gdsc_toggle_logic(struct gdsc *sc, enum gdsc_status status)
 {
 	int ret;
-	u32 val = en ? 0 : SW_COLLAPSE_MASK;
+	u32 val = (status == GDSC_ON) ? 0 : SW_COLLAPSE_MASK;
 
 	ret = regmap_update_bits(sc->regmap, sc->gdscr, SW_COLLAPSE_MASK, val);
 	if (ret)
 		return ret;
 
 	/* If disabling votable gdscs, don't poll on status */
-	if ((sc->flags & VOTABLE) && !en) {
+	if ((sc->flags & VOTABLE) && status == GDSC_OFF) {
 		/*
 		 * Add a short delay here to ensure that an enable
 		 * right after it was disabled does not put it in an
@@ -118,7 +135,7 @@ static int gdsc_toggle_logic(struct gdsc *sc, bool en)
 		return 0;
 	}
 
-	if (sc->gds_hw_ctrl)
+	if (sc->gds_hw_ctrl) {
 		/*
 		 * The gds hw controller asserts/de-asserts the status bit soon
 		 * after it receives a power on/off request from a master.
@@ -130,8 +147,9 @@ static int gdsc_toggle_logic(struct gdsc *sc, bool en)
 		 * and polling the status bit.
 		 */
 		udelay(1);
+	}
 
-	return gdsc_poll_status(sc, en);
+	return gdsc_poll_status(sc, status);
 }
 
 static inline int gdsc_deassert_reset(struct gdsc *sc)
@@ -210,7 +228,7 @@ static int gdsc_enable(struct generic_pm_domain *domain)
 		gdsc_deassert_clamp_io(sc);
 	}
 
-	ret = gdsc_toggle_logic(sc, true);
+	ret = gdsc_toggle_logic(sc, GDSC_ON);
 	if (ret)
 		return ret;
 
@@ -266,7 +284,7 @@ static int gdsc_disable(struct generic_pm_domain *domain)
 		 */
 		udelay(1);
 
-		ret = gdsc_poll_status(sc, true);
+		ret = gdsc_poll_status(sc, GDSC_ON);
 		if (ret)
 			return ret;
 	}
@@ -274,7 +292,7 @@ static int gdsc_disable(struct generic_pm_domain *domain)
 	if (sc->pwrsts & PWRSTS_OFF)
 		gdsc_clear_mem_on(sc);
 
-	ret = gdsc_toggle_logic(sc, false);
+	ret = gdsc_toggle_logic(sc, GDSC_OFF);
 	if (ret)
 		return ret;
 
@@ -303,12 +321,12 @@ static int gdsc_init(struct gdsc *sc)
 
 	/* Force gdsc ON if only ON state is supported */
 	if (sc->pwrsts == PWRSTS_ON) {
-		ret = gdsc_toggle_logic(sc, true);
+		ret = gdsc_toggle_logic(sc, GDSC_ON);
 		if (ret)
 			return ret;
 	}
 
-	on = gdsc_is_enabled(sc, true);
+	on = gdsc_check_status(sc, GDSC_ON);
 	if (on < 0)
 		return on;
 

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v1] clk: qcom: gdsc: Add support to poll CFG register to check GDSC state
@ 2018-05-02  6:57   ` Stephen Boyd
  0 siblings, 0 replies; 8+ messages in thread
From: Stephen Boyd @ 2018-05-02  6:57 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Taniya Das
  Cc: Andy Gross, David Brown, Rajendra Nayak, Odelu Kukatla,
	Amit Nischal, linux-arm-msm, linux-soc, linux-clk, linux-kernel,
	Taniya Das

Quoting Taniya Das (2018-04-30 22:03:33)
> @@ -45,15 +50,28 @@
> 
>  #define domain_to_gdsc(domain) container_of(domain, struct gdsc, pd)
> 
> -static int gdsc_is_enabled(struct gdsc *sc, unsigned int reg)
> +static int gdsc_is_enabled(struct gdsc *sc, bool en)
>  {
> +       unsigned int reg;
>         u32 val;
>         int ret;
> 
> +       if (sc->flags & POLL_CFG_GDSCR)
> +               reg = sc->gdscr + CFG_GDSCR_OFFSET;
> +       else
> +               reg = sc->gds_hw_ctrl ? sc->gds_hw_ctrl : sc->gdscr;
> +
>         ret = regmap_read(sc->regmap, reg, &val);
>         if (ret)
>                 return ret;
> 
> +       if (sc->flags & POLL_CFG_GDSCR) {
> +               if (en)
> +                       return !!(val & GDSC_POWER_UP_COMPLETE);
> +               else
> +                       return !(val & GDSC_POWER_DOWN_COMPLETE);

This is confusing, but also is correct, because this function is
returning if the gdsc is enabled or not, and that also happens to be
false when the gdsc is not enabled and this bit is set.

> +       }
> +
>         return !!(val & PWR_ON_MASK);
>  }
> 
> @@ -64,17 +82,17 @@ static int gdsc_hwctrl(struct gdsc *sc, bool en)
>         return regmap_update_bits(sc->regmap, sc->gdscr, HW_CONTROL_MASK, val);
>  }
> 
> -static int gdsc_poll_status(struct gdsc *sc, unsigned int reg, bool en)
> +static int gdsc_poll_status(struct gdsc *sc, bool en)
>  {
>         ktime_t start;
> 
>         start = ktime_get();
>         do {
> -               if (gdsc_is_enabled(sc, reg) == en)
> +               if (gdsc_is_enabled(sc, en) == en)

I still don't like this == en logic. How about this patch on top? If you
can test it out, I'll merge your patch and then my patch to make this
all easier to read. Note that I changed the off case for
POWER_DOWN_COMPLETE to be a double negation.

---8<---
diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c
index 2a6b0ff7d451..4696e241db89 100644
--- a/drivers/clk/qcom/gdsc.c
+++ b/drivers/clk/qcom/gdsc.c
@@ -50,7 +50,13 @@
 
 #define domain_to_gdsc(domain) container_of(domain, struct gdsc, pd)
 
-static int gdsc_is_enabled(struct gdsc *sc, bool en)
+enum gdsc_status {
+	GDSC_OFF,
+	GDSC_ON
+};
+
+/* Returns 1 if GDSC status is status, 0 if not, and < 0 on error */
+static int gdsc_check_status(struct gdsc *sc, enum gdsc_status status)
 {
 	unsigned int reg;
 	u32 val;
@@ -58,21 +64,32 @@ static int gdsc_is_enabled(struct gdsc *sc, bool en)
 
 	if (sc->flags & POLL_CFG_GDSCR)
 		reg = sc->gdscr + CFG_GDSCR_OFFSET;
+	else if (sc->gds_hw_ctrl)
+		reg = sc->gds_hw_ctrl;
 	else
-		reg = sc->gds_hw_ctrl ? sc->gds_hw_ctrl : sc->gdscr;
+		reg = sc->gdscr;
 
 	ret = regmap_read(sc->regmap, reg, &val);
 	if (ret)
 		return ret;
 
 	if (sc->flags & POLL_CFG_GDSCR) {
-		if (en)
+		switch (status) {
+		case GDSC_ON:
 			return !!(val & GDSC_POWER_UP_COMPLETE);
-		else
-			return !(val & GDSC_POWER_DOWN_COMPLETE);
+		case GDSC_OFF:
+			return !!(val & GDSC_POWER_DOWN_COMPLETE);
+		}
+	}
+
+	switch (status) {
+	case GDSC_ON:
+		return !!(val & PWR_ON_MASK);
+	case GDSC_OFF:
+		return !(val & PWR_ON_MASK);
 	}
 
-	return !!(val & PWR_ON_MASK);
+	return -EINVAL;
 }
 
 static int gdsc_hwctrl(struct gdsc *sc, bool en)
@@ -82,33 +99,33 @@ static int gdsc_hwctrl(struct gdsc *sc, bool en)
 	return regmap_update_bits(sc->regmap, sc->gdscr, HW_CONTROL_MASK, val);
 }
 
-static int gdsc_poll_status(struct gdsc *sc, bool en)
+static int gdsc_poll_status(struct gdsc *sc, enum gdsc_status status)
 {
 	ktime_t start;
 
 	start = ktime_get();
 	do {
-		if (gdsc_is_enabled(sc, en) == en)
+		if (gdsc_check_status(sc, status))
 			return 0;
 	} while (ktime_us_delta(ktime_get(), start) < TIMEOUT_US);
 
-	if (gdsc_is_enabled(sc, en) == en)
+	if (gdsc_check_status(sc, status))
 		return 0;
 
 	return -ETIMEDOUT;
 }
 
-static int gdsc_toggle_logic(struct gdsc *sc, bool en)
+static int gdsc_toggle_logic(struct gdsc *sc, enum gdsc_status status)
 {
 	int ret;
-	u32 val = en ? 0 : SW_COLLAPSE_MASK;
+	u32 val = (status == GDSC_ON) ? 0 : SW_COLLAPSE_MASK;
 
 	ret = regmap_update_bits(sc->regmap, sc->gdscr, SW_COLLAPSE_MASK, val);
 	if (ret)
 		return ret;
 
 	/* If disabling votable gdscs, don't poll on status */
-	if ((sc->flags & VOTABLE) && !en) {
+	if ((sc->flags & VOTABLE) && status == GDSC_OFF) {
 		/*
 		 * Add a short delay here to ensure that an enable
 		 * right after it was disabled does not put it in an
@@ -118,7 +135,7 @@ static int gdsc_toggle_logic(struct gdsc *sc, bool en)
 		return 0;
 	}
 
-	if (sc->gds_hw_ctrl)
+	if (sc->gds_hw_ctrl) {
 		/*
 		 * The gds hw controller asserts/de-asserts the status bit soon
 		 * after it receives a power on/off request from a master.
@@ -130,8 +147,9 @@ static int gdsc_toggle_logic(struct gdsc *sc, bool en)
 		 * and polling the status bit.
 		 */
 		udelay(1);
+	}
 
-	return gdsc_poll_status(sc, en);
+	return gdsc_poll_status(sc, status);
 }
 
 static inline int gdsc_deassert_reset(struct gdsc *sc)
@@ -210,7 +228,7 @@ static int gdsc_enable(struct generic_pm_domain *domain)
 		gdsc_deassert_clamp_io(sc);
 	}
 
-	ret = gdsc_toggle_logic(sc, true);
+	ret = gdsc_toggle_logic(sc, GDSC_ON);
 	if (ret)
 		return ret;
 
@@ -266,7 +284,7 @@ static int gdsc_disable(struct generic_pm_domain *domain)
 		 */
 		udelay(1);
 
-		ret = gdsc_poll_status(sc, true);
+		ret = gdsc_poll_status(sc, GDSC_ON);
 		if (ret)
 			return ret;
 	}
@@ -274,7 +292,7 @@ static int gdsc_disable(struct generic_pm_domain *domain)
 	if (sc->pwrsts & PWRSTS_OFF)
 		gdsc_clear_mem_on(sc);
 
-	ret = gdsc_toggle_logic(sc, false);
+	ret = gdsc_toggle_logic(sc, GDSC_OFF);
 	if (ret)
 		return ret;
 
@@ -303,12 +321,12 @@ static int gdsc_init(struct gdsc *sc)
 
 	/* Force gdsc ON if only ON state is supported */
 	if (sc->pwrsts == PWRSTS_ON) {
-		ret = gdsc_toggle_logic(sc, true);
+		ret = gdsc_toggle_logic(sc, GDSC_ON);
 		if (ret)
 			return ret;
 	}
 
-	on = gdsc_is_enabled(sc, true);
+	on = gdsc_check_status(sc, GDSC_ON);
 	if (on < 0)
 		return on;
 

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v1] clk: qcom: gdsc: Add support to poll CFG register to check GDSC state
@ 2018-05-02  6:57   ` Stephen Boyd
  0 siblings, 0 replies; 8+ messages in thread
From: Stephen Boyd @ 2018-05-02  6:57 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Taniya Das
  Cc: Andy Gross, David Brown, Rajendra Nayak, Odelu Kukatla,
	Amit Nischal, linux-arm-msm, linux-soc, linux-clk, linux-kernel,
	Taniya Das

Quoting Taniya Das (2018-04-30 22:03:33)
> @@ -45,15 +50,28 @@
> =

>  #define domain_to_gdsc(domain) container_of(domain, struct gdsc, pd)
> =

> -static int gdsc_is_enabled(struct gdsc *sc, unsigned int reg)
> +static int gdsc_is_enabled(struct gdsc *sc, bool en)
>  {
> +       unsigned int reg;
>         u32 val;
>         int ret;
> =

> +       if (sc->flags & POLL_CFG_GDSCR)
> +               reg =3D sc->gdscr + CFG_GDSCR_OFFSET;
> +       else
> +               reg =3D sc->gds_hw_ctrl ? sc->gds_hw_ctrl : sc->gdscr;
> +
>         ret =3D regmap_read(sc->regmap, reg, &val);
>         if (ret)
>                 return ret;
> =

> +       if (sc->flags & POLL_CFG_GDSCR) {
> +               if (en)
> +                       return !!(val & GDSC_POWER_UP_COMPLETE);
> +               else
> +                       return !(val & GDSC_POWER_DOWN_COMPLETE);

This is confusing, but also is correct, because this function is
returning if the gdsc is enabled or not, and that also happens to be
false when the gdsc is not enabled and this bit is set.

> +       }
> +
>         return !!(val & PWR_ON_MASK);
>  }
> =

> @@ -64,17 +82,17 @@ static int gdsc_hwctrl(struct gdsc *sc, bool en)
>         return regmap_update_bits(sc->regmap, sc->gdscr, HW_CONTROL_MASK,=
 val);
>  }
> =

> -static int gdsc_poll_status(struct gdsc *sc, unsigned int reg, bool en)
> +static int gdsc_poll_status(struct gdsc *sc, bool en)
>  {
>         ktime_t start;
> =

>         start =3D ktime_get();
>         do {
> -               if (gdsc_is_enabled(sc, reg) =3D=3D en)
> +               if (gdsc_is_enabled(sc, en) =3D=3D en)

I still don't like this =3D=3D en logic. How about this patch on top? If you
can test it out, I'll merge your patch and then my patch to make this
all easier to read. Note that I changed the off case for
POWER_DOWN_COMPLETE to be a double negation.

---8<---
diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c
index 2a6b0ff7d451..4696e241db89 100644
--- a/drivers/clk/qcom/gdsc.c
+++ b/drivers/clk/qcom/gdsc.c
@@ -50,7 +50,13 @@
 =

 #define domain_to_gdsc(domain) container_of(domain, struct gdsc, pd)
 =

-static int gdsc_is_enabled(struct gdsc *sc, bool en)
+enum gdsc_status {
+	GDSC_OFF,
+	GDSC_ON
+};
+
+/* Returns 1 if GDSC status is status, 0 if not, and < 0 on error */
+static int gdsc_check_status(struct gdsc *sc, enum gdsc_status status)
 {
 	unsigned int reg;
 	u32 val;
@@ -58,21 +64,32 @@ static int gdsc_is_enabled(struct gdsc *sc, bool en)
 =

 	if (sc->flags & POLL_CFG_GDSCR)
 		reg =3D sc->gdscr + CFG_GDSCR_OFFSET;
+	else if (sc->gds_hw_ctrl)
+		reg =3D sc->gds_hw_ctrl;
 	else
-		reg =3D sc->gds_hw_ctrl ? sc->gds_hw_ctrl : sc->gdscr;
+		reg =3D sc->gdscr;
 =

 	ret =3D regmap_read(sc->regmap, reg, &val);
 	if (ret)
 		return ret;
 =

 	if (sc->flags & POLL_CFG_GDSCR) {
-		if (en)
+		switch (status) {
+		case GDSC_ON:
 			return !!(val & GDSC_POWER_UP_COMPLETE);
-		else
-			return !(val & GDSC_POWER_DOWN_COMPLETE);
+		case GDSC_OFF:
+			return !!(val & GDSC_POWER_DOWN_COMPLETE);
+		}
+	}
+
+	switch (status) {
+	case GDSC_ON:
+		return !!(val & PWR_ON_MASK);
+	case GDSC_OFF:
+		return !(val & PWR_ON_MASK);
 	}
 =

-	return !!(val & PWR_ON_MASK);
+	return -EINVAL;
 }
 =

 static int gdsc_hwctrl(struct gdsc *sc, bool en)
@@ -82,33 +99,33 @@ static int gdsc_hwctrl(struct gdsc *sc, bool en)
 	return regmap_update_bits(sc->regmap, sc->gdscr, HW_CONTROL_MASK, val);
 }
 =

-static int gdsc_poll_status(struct gdsc *sc, bool en)
+static int gdsc_poll_status(struct gdsc *sc, enum gdsc_status status)
 {
 	ktime_t start;
 =

 	start =3D ktime_get();
 	do {
-		if (gdsc_is_enabled(sc, en) =3D=3D en)
+		if (gdsc_check_status(sc, status))
 			return 0;
 	} while (ktime_us_delta(ktime_get(), start) < TIMEOUT_US);
 =

-	if (gdsc_is_enabled(sc, en) =3D=3D en)
+	if (gdsc_check_status(sc, status))
 		return 0;
 =

 	return -ETIMEDOUT;
 }
 =

-static int gdsc_toggle_logic(struct gdsc *sc, bool en)
+static int gdsc_toggle_logic(struct gdsc *sc, enum gdsc_status status)
 {
 	int ret;
-	u32 val =3D en ? 0 : SW_COLLAPSE_MASK;
+	u32 val =3D (status =3D=3D GDSC_ON) ? 0 : SW_COLLAPSE_MASK;
 =

 	ret =3D regmap_update_bits(sc->regmap, sc->gdscr, SW_COLLAPSE_MASK, val);
 	if (ret)
 		return ret;
 =

 	/* If disabling votable gdscs, don't poll on status */
-	if ((sc->flags & VOTABLE) && !en) {
+	if ((sc->flags & VOTABLE) && status =3D=3D GDSC_OFF) {
 		/*
 		 * Add a short delay here to ensure that an enable
 		 * right after it was disabled does not put it in an
@@ -118,7 +135,7 @@ static int gdsc_toggle_logic(struct gdsc *sc, bool en)
 		return 0;
 	}
 =

-	if (sc->gds_hw_ctrl)
+	if (sc->gds_hw_ctrl) {
 		/*
 		 * The gds hw controller asserts/de-asserts the status bit soon
 		 * after it receives a power on/off request from a master.
@@ -130,8 +147,9 @@ static int gdsc_toggle_logic(struct gdsc *sc, bool en)
 		 * and polling the status bit.
 		 */
 		udelay(1);
+	}
 =

-	return gdsc_poll_status(sc, en);
+	return gdsc_poll_status(sc, status);
 }
 =

 static inline int gdsc_deassert_reset(struct gdsc *sc)
@@ -210,7 +228,7 @@ static int gdsc_enable(struct generic_pm_domain *domain)
 		gdsc_deassert_clamp_io(sc);
 	}
 =

-	ret =3D gdsc_toggle_logic(sc, true);
+	ret =3D gdsc_toggle_logic(sc, GDSC_ON);
 	if (ret)
 		return ret;
 =

@@ -266,7 +284,7 @@ static int gdsc_disable(struct generic_pm_domain *domai=
n)
 		 */
 		udelay(1);
 =

-		ret =3D gdsc_poll_status(sc, true);
+		ret =3D gdsc_poll_status(sc, GDSC_ON);
 		if (ret)
 			return ret;
 	}
@@ -274,7 +292,7 @@ static int gdsc_disable(struct generic_pm_domain *domai=
n)
 	if (sc->pwrsts & PWRSTS_OFF)
 		gdsc_clear_mem_on(sc);
 =

-	ret =3D gdsc_toggle_logic(sc, false);
+	ret =3D gdsc_toggle_logic(sc, GDSC_OFF);
 	if (ret)
 		return ret;
 =

@@ -303,12 +321,12 @@ static int gdsc_init(struct gdsc *sc)
 =

 	/* Force gdsc ON if only ON state is supported */
 	if (sc->pwrsts =3D=3D PWRSTS_ON) {
-		ret =3D gdsc_toggle_logic(sc, true);
+		ret =3D gdsc_toggle_logic(sc, GDSC_ON);
 		if (ret)
 			return ret;
 	}
 =

-	on =3D gdsc_is_enabled(sc, true);
+	on =3D gdsc_check_status(sc, GDSC_ON);
 	if (on < 0)
 		return on;
=20

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v1] clk: qcom: gdsc: Add support to poll CFG register to check GDSC state
  2018-05-02  6:57   ` Stephen Boyd
  (?)
  (?)
@ 2018-05-03  9:09   ` Taniya Das
  2018-05-05  2:51       ` Stephen Boyd
  -1 siblings, 1 reply; 8+ messages in thread
From: Taniya Das @ 2018-05-03  9:09 UTC (permalink / raw)
  To: Stephen Boyd, Michael Turquette, Stephen Boyd
  Cc: Andy Gross, David Brown, Rajendra Nayak, Odelu Kukatla,
	Amit Nischal, linux-arm-msm, linux-soc, linux-clk, linux-kernel

Hello Stephen,

I have tested the below patch & didn't see any issues.

On 5/2/2018 12:27 PM, Stephen Boyd wrote:
> Quoting Taniya Das (2018-04-30 22:03:33)
>> @@ -45,15 +50,28 @@
>>
>>   #define domain_to_gdsc(domain) container_of(domain, struct gdsc, pd)
>>
>> -static int gdsc_is_enabled(struct gdsc *sc, unsigned int reg)
>> +static int gdsc_is_enabled(struct gdsc *sc, bool en)
>>   {
>> +       unsigned int reg;
>>          u32 val;
>>          int ret;
>>
>> +       if (sc->flags & POLL_CFG_GDSCR)
>> +               reg = sc->gdscr + CFG_GDSCR_OFFSET;
>> +       else
>> +               reg = sc->gds_hw_ctrl ? sc->gds_hw_ctrl : sc->gdscr;
>> +
>>          ret = regmap_read(sc->regmap, reg, &val);
>>          if (ret)
>>                  return ret;
>>
>> +       if (sc->flags & POLL_CFG_GDSCR) {
>> +               if (en)
>> +                       return !!(val & GDSC_POWER_UP_COMPLETE);
>> +               else
>> +                       return !(val & GDSC_POWER_DOWN_COMPLETE);
> 
> This is confusing, but also is correct, because this function is
> returning if the gdsc is enabled or not, and that also happens to be
> false when the gdsc is not enabled and this bit is set.
> 
>> +       }
>> +
>>          return !!(val & PWR_ON_MASK);
>>   }
>>
>> @@ -64,17 +82,17 @@ static int gdsc_hwctrl(struct gdsc *sc, bool en)
>>          return regmap_update_bits(sc->regmap, sc->gdscr, HW_CONTROL_MASK, val);
>>   }
>>
>> -static int gdsc_poll_status(struct gdsc *sc, unsigned int reg, bool en)
>> +static int gdsc_poll_status(struct gdsc *sc, bool en)
>>   {
>>          ktime_t start;
>>
>>          start = ktime_get();
>>          do {
>> -               if (gdsc_is_enabled(sc, reg) == en)
>> +               if (gdsc_is_enabled(sc, en) == en)
> 
> I still don't like this == en logic. How about this patch on top? If you
> can test it out, I'll merge your patch and then my patch to make this
> all easier to read. Note that I changed the off case for
> POWER_DOWN_COMPLETE to be a double negation.
> 
> ---8<---
> diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c
> index 2a6b0ff7d451..4696e241db89 100644
> --- a/drivers/clk/qcom/gdsc.c
> +++ b/drivers/clk/qcom/gdsc.c
> @@ -50,7 +50,13 @@
>   
>   #define domain_to_gdsc(domain) container_of(domain, struct gdsc, pd)
>   
> -static int gdsc_is_enabled(struct gdsc *sc, bool en)
> +enum gdsc_status {
> +	GDSC_OFF,
> +	GDSC_ON
> +};
> +
> +/* Returns 1 if GDSC status is status, 0 if not, and < 0 on error */
> +static int gdsc_check_status(struct gdsc *sc, enum gdsc_status status)
>   {
>   	unsigned int reg;
>   	u32 val;
> @@ -58,21 +64,32 @@ static int gdsc_is_enabled(struct gdsc *sc, bool en)
>   
>   	if (sc->flags & POLL_CFG_GDSCR)
>   		reg = sc->gdscr + CFG_GDSCR_OFFSET;
> +	else if (sc->gds_hw_ctrl)
> +		reg = sc->gds_hw_ctrl;
>   	else
> -		reg = sc->gds_hw_ctrl ? sc->gds_hw_ctrl : sc->gdscr;
> +		reg = sc->gdscr;
>   
>   	ret = regmap_read(sc->regmap, reg, &val);
>   	if (ret)
>   		return ret;
>   
>   	if (sc->flags & POLL_CFG_GDSCR) {
> -		if (en)
> +		switch (status) {
> +		case GDSC_ON:
>   			return !!(val & GDSC_POWER_UP_COMPLETE);
> -		else
> -			return !(val & GDSC_POWER_DOWN_COMPLETE);
> +		case GDSC_OFF:
> +			return !!(val & GDSC_POWER_DOWN_COMPLETE);
> +		}
> +	}
> +
> +	switch (status) {
> +	case GDSC_ON:
> +		return !!(val & PWR_ON_MASK);
> +	case GDSC_OFF:
> +		return !(val & PWR_ON_MASK);
>   	}
>   
> -	return !!(val & PWR_ON_MASK);
> +	return -EINVAL;
>   }
>   
>   static int gdsc_hwctrl(struct gdsc *sc, bool en)
> @@ -82,33 +99,33 @@ static int gdsc_hwctrl(struct gdsc *sc, bool en)
>   	return regmap_update_bits(sc->regmap, sc->gdscr, HW_CONTROL_MASK, val);
>   }
>   
> -static int gdsc_poll_status(struct gdsc *sc, bool en)
> +static int gdsc_poll_status(struct gdsc *sc, enum gdsc_status status)
>   {
>   	ktime_t start;
>   
>   	start = ktime_get();
>   	do {
> -		if (gdsc_is_enabled(sc, en) == en)
> +		if (gdsc_check_status(sc, status))
>   			return 0;
>   	} while (ktime_us_delta(ktime_get(), start) < TIMEOUT_US);
>   
> -	if (gdsc_is_enabled(sc, en) == en)
> +	if (gdsc_check_status(sc, status))
>   		return 0;
>   
>   	return -ETIMEDOUT;
>   }
>   
> -static int gdsc_toggle_logic(struct gdsc *sc, bool en)
> +static int gdsc_toggle_logic(struct gdsc *sc, enum gdsc_status status)
>   {
>   	int ret;
> -	u32 val = en ? 0 : SW_COLLAPSE_MASK;
> +	u32 val = (status == GDSC_ON) ? 0 : SW_COLLAPSE_MASK;
>   
>   	ret = regmap_update_bits(sc->regmap, sc->gdscr, SW_COLLAPSE_MASK, val);
>   	if (ret)
>   		return ret;
>   
>   	/* If disabling votable gdscs, don't poll on status */
> -	if ((sc->flags & VOTABLE) && !en) {
> +	if ((sc->flags & VOTABLE) && status == GDSC_OFF) {
>   		/*
>   		 * Add a short delay here to ensure that an enable
>   		 * right after it was disabled does not put it in an
> @@ -118,7 +135,7 @@ static int gdsc_toggle_logic(struct gdsc *sc, bool en)
>   		return 0;
>   	}
>   
> -	if (sc->gds_hw_ctrl)
> +	if (sc->gds_hw_ctrl) {
>   		/*
>   		 * The gds hw controller asserts/de-asserts the status bit soon
>   		 * after it receives a power on/off request from a master.
> @@ -130,8 +147,9 @@ static int gdsc_toggle_logic(struct gdsc *sc, bool en)
>   		 * and polling the status bit.
>   		 */
>   		udelay(1);
> +	}
>   
> -	return gdsc_poll_status(sc, en);
> +	return gdsc_poll_status(sc, status);
>   }
>   
>   static inline int gdsc_deassert_reset(struct gdsc *sc)
> @@ -210,7 +228,7 @@ static int gdsc_enable(struct generic_pm_domain *domain)
>   		gdsc_deassert_clamp_io(sc);
>   	}
>   
> -	ret = gdsc_toggle_logic(sc, true);
> +	ret = gdsc_toggle_logic(sc, GDSC_ON);
>   	if (ret)
>   		return ret;
>   
> @@ -266,7 +284,7 @@ static int gdsc_disable(struct generic_pm_domain *domain)
>   		 */
>   		udelay(1);
>   
> -		ret = gdsc_poll_status(sc, true);
> +		ret = gdsc_poll_status(sc, GDSC_ON);
>   		if (ret)
>   			return ret;
>   	}
> @@ -274,7 +292,7 @@ static int gdsc_disable(struct generic_pm_domain *domain)
>   	if (sc->pwrsts & PWRSTS_OFF)
>   		gdsc_clear_mem_on(sc);
>   
> -	ret = gdsc_toggle_logic(sc, false);
> +	ret = gdsc_toggle_logic(sc, GDSC_OFF);
>   	if (ret)
>   		return ret;
>   
> @@ -303,12 +321,12 @@ static int gdsc_init(struct gdsc *sc)
>   
>   	/* Force gdsc ON if only ON state is supported */
>   	if (sc->pwrsts == PWRSTS_ON) {
> -		ret = gdsc_toggle_logic(sc, true);
> +		ret = gdsc_toggle_logic(sc, GDSC_ON);
>   		if (ret)
>   			return ret;
>   	}
>   
> -	on = gdsc_is_enabled(sc, true);
> +	on = gdsc_check_status(sc, GDSC_ON);
>   	if (on < 0)
>   		return on;
>   
> 

-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation.

--

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v1] clk: qcom: gdsc: Add support to poll CFG register to check GDSC state
  2018-05-03  9:09   ` Taniya Das
@ 2018-05-05  2:51       ` Stephen Boyd
  0 siblings, 0 replies; 8+ messages in thread
From: Stephen Boyd @ 2018-05-05  2:51 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Taniya Das
  Cc: Andy Gross, David Brown, Rajendra Nayak, Odelu Kukatla,
	Amit Nischal, linux-arm-msm, linux-soc, linux-clk, linux-kernel

Quoting Taniya Das (2018-05-03 02:09:57)
> Hello Stephen,
> 
> I have tested the below patch & didn't see any issues.

Alright. Thanks! Can I take that as a "Tested-by"?

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v1] clk: qcom: gdsc: Add support to poll CFG register to check GDSC state
@ 2018-05-05  2:51       ` Stephen Boyd
  0 siblings, 0 replies; 8+ messages in thread
From: Stephen Boyd @ 2018-05-05  2:51 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Taniya Das
  Cc: Andy Gross, David Brown, Rajendra Nayak, Odelu Kukatla,
	Amit Nischal, linux-arm-msm, linux-soc, linux-clk, linux-kernel

Quoting Taniya Das (2018-05-03 02:09:57)
> Hello Stephen,
> =

> I have tested the below patch & didn't see any issues.

Alright. Thanks! Can I take that as a "Tested-by"?

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v1] clk: qcom: gdsc: Add support to poll CFG register to check GDSC state
  2018-05-05  2:51       ` Stephen Boyd
  (?)
@ 2018-05-05  3:48       ` Taniya Das
  -1 siblings, 0 replies; 8+ messages in thread
From: Taniya Das @ 2018-05-05  3:48 UTC (permalink / raw)
  To: Stephen Boyd, Michael Turquette, Stephen Boyd
  Cc: Andy Gross, David Brown, Rajendra Nayak, Odelu Kukatla,
	Amit Nischal, linux-arm-msm, linux-soc, linux-clk, linux-kernel

Yeah sure Stephen.

On 5/5/2018 8:21 AM, Stephen Boyd wrote:
> Quoting Taniya Das (2018-05-03 02:09:57)
>> Hello Stephen,
>>
>> I have tested the below patch & didn't see any issues.
> 
> Alright. Thanks! Can I take that as a "Tested-by"?
> 

-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation.

--

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2018-05-05  3:48 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-05-01  5:03 [PATCH v1] clk: qcom: gdsc: Add support to poll CFG register to check GDSC state Taniya Das
2018-05-02  6:57 ` Stephen Boyd
2018-05-02  6:57   ` Stephen Boyd
2018-05-02  6:57   ` Stephen Boyd
2018-05-03  9:09   ` Taniya Das
2018-05-05  2:51     ` Stephen Boyd
2018-05-05  2:51       ` Stephen Boyd
2018-05-05  3:48       ` Taniya Das

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.