aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmit Nischal <anischal@codeaurora.org>2018-05-01 01:03:33 -0400
committerStephen Boyd <sboyd@kernel.org>2018-05-01 19:34:07 -0400
commite892e17d0c0e3d1bb8a56b84d15f9995807b92fa (patch)
tree4fd6eacff0c5ec6ada7f83aad5430daf7cf01817
parent9fb38caee2541009c9e040d9a3962157c7bb4c5f (diff)
clk: qcom: gdsc: Add support to poll CFG register to check GDSC state
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> Signed-off-by: Stephen Boyd <sboyd@kernel.org>
-rw-r--r--drivers/clk/qcom/gdsc.c42
-rw-r--r--drivers/clk/qcom/gdsc.h1
2 files changed, 27 insertions, 16 deletions
diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c
index cb61c1590e9c..2a6b0ff7d451 100644
--- a/drivers/clk/qcom/gdsc.c
+++ b/drivers/clk/qcom/gdsc.c
@@ -33,6 +33,11 @@
33#define GMEM_CLAMP_IO_MASK BIT(0) 33#define GMEM_CLAMP_IO_MASK BIT(0)
34#define GMEM_RESET_MASK BIT(4) 34#define GMEM_RESET_MASK BIT(4)
35 35
36/* CFG_GDSCR */
37#define GDSC_POWER_UP_COMPLETE BIT(16)
38#define GDSC_POWER_DOWN_COMPLETE BIT(15)
39#define CFG_GDSCR_OFFSET 0x4
40
36/* Wait 2^n CXO cycles between all states. Here, n=2 (4 cycles). */ 41/* Wait 2^n CXO cycles between all states. Here, n=2 (4 cycles). */
37#define EN_REST_WAIT_VAL (0x2 << 20) 42#define EN_REST_WAIT_VAL (0x2 << 20)
38#define EN_FEW_WAIT_VAL (0x8 << 16) 43#define EN_FEW_WAIT_VAL (0x8 << 16)
@@ -45,15 +50,28 @@
45 50
46#define domain_to_gdsc(domain) container_of(domain, struct gdsc, pd) 51#define domain_to_gdsc(domain) container_of(domain, struct gdsc, pd)
47 52
48static int gdsc_is_enabled(struct gdsc *sc, unsigned int reg) 53static int gdsc_is_enabled(struct gdsc *sc, bool en)
49{ 54{
55 unsigned int reg;
50 u32 val; 56 u32 val;
51 int ret; 57 int ret;
52 58
59 if (sc->flags & POLL_CFG_GDSCR)
60 reg = sc->gdscr + CFG_GDSCR_OFFSET;
61 else
62 reg = sc->gds_hw_ctrl ? sc->gds_hw_ctrl : sc->gdscr;
63
53 ret = regmap_read(sc->regmap, reg, &val); 64 ret = regmap_read(sc->regmap, reg, &val);
54 if (ret) 65 if (ret)
55 return ret; 66 return ret;
56 67
68 if (sc->flags & POLL_CFG_GDSCR) {
69 if (en)
70 return !!(val & GDSC_POWER_UP_COMPLETE);
71 else
72 return !(val & GDSC_POWER_DOWN_COMPLETE);
73 }
74
57 return !!(val & PWR_ON_MASK); 75 return !!(val & PWR_ON_MASK);
58} 76}
59 77
@@ -64,17 +82,17 @@ static int gdsc_hwctrl(struct gdsc *sc, bool en)
64 return regmap_update_bits(sc->regmap, sc->gdscr, HW_CONTROL_MASK, val); 82 return regmap_update_bits(sc->regmap, sc->gdscr, HW_CONTROL_MASK, val);
65} 83}
66 84
67static int gdsc_poll_status(struct gdsc *sc, unsigned int reg, bool en) 85static int gdsc_poll_status(struct gdsc *sc, bool en)
68{ 86{
69 ktime_t start; 87 ktime_t start;
70 88
71 start = ktime_get(); 89 start = ktime_get();
72 do { 90 do {
73 if (gdsc_is_enabled(sc, reg) == en) 91 if (gdsc_is_enabled(sc, en) == en)
74 return 0; 92 return 0;
75 } while (ktime_us_delta(ktime_get(), start) < TIMEOUT_US); 93 } while (ktime_us_delta(ktime_get(), start) < TIMEOUT_US);
76 94
77 if (gdsc_is_enabled(sc, reg) == en) 95 if (gdsc_is_enabled(sc, en) == en)
78 return 0; 96 return 0;
79 97
80 return -ETIMEDOUT; 98 return -ETIMEDOUT;
@@ -84,7 +102,6 @@ static int gdsc_toggle_logic(struct gdsc *sc, bool en)
84{ 102{
85 int ret; 103 int ret;
86 u32 val = en ? 0 : SW_COLLAPSE_MASK; 104 u32 val = en ? 0 : SW_COLLAPSE_MASK;
87 unsigned int status_reg = sc->gdscr;
88 105
89 ret = regmap_update_bits(sc->regmap, sc->gdscr, SW_COLLAPSE_MASK, val); 106 ret = regmap_update_bits(sc->regmap, sc->gdscr, SW_COLLAPSE_MASK, val);
90 if (ret) 107 if (ret)
@@ -101,8 +118,7 @@ static int gdsc_toggle_logic(struct gdsc *sc, bool en)
101 return 0; 118 return 0;
102 } 119 }
103 120
104 if (sc->gds_hw_ctrl) { 121 if (sc->gds_hw_ctrl)
105 status_reg = sc->gds_hw_ctrl;
106 /* 122 /*
107 * The gds hw controller asserts/de-asserts the status bit soon 123 * The gds hw controller asserts/de-asserts the status bit soon
108 * after it receives a power on/off request from a master. 124 * 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)
114 * and polling the status bit. 130 * and polling the status bit.
115 */ 131 */
116 udelay(1); 132 udelay(1);
117 }
118 133
119 return gdsc_poll_status(sc, status_reg, en); 134 return gdsc_poll_status(sc, en);
120} 135}
121 136
122static inline int gdsc_deassert_reset(struct gdsc *sc) 137static inline int gdsc_deassert_reset(struct gdsc *sc)
@@ -240,8 +255,6 @@ static int gdsc_disable(struct generic_pm_domain *domain)
240 255
241 /* Turn off HW trigger mode if supported */ 256 /* Turn off HW trigger mode if supported */
242 if (sc->flags & HW_CTRL) { 257 if (sc->flags & HW_CTRL) {
243 unsigned int reg;
244
245 ret = gdsc_hwctrl(sc, false); 258 ret = gdsc_hwctrl(sc, false);
246 if (ret < 0) 259 if (ret < 0)
247 return ret; 260 return ret;
@@ -253,8 +266,7 @@ static int gdsc_disable(struct generic_pm_domain *domain)
253 */ 266 */
254 udelay(1); 267 udelay(1);
255 268
256 reg = sc->gds_hw_ctrl ? sc->gds_hw_ctrl : sc->gdscr; 269 ret = gdsc_poll_status(sc, true);
257 ret = gdsc_poll_status(sc, reg, true);
258 if (ret) 270 if (ret)
259 return ret; 271 return ret;
260 } 272 }
@@ -276,7 +288,6 @@ static int gdsc_init(struct gdsc *sc)
276{ 288{
277 u32 mask, val; 289 u32 mask, val;
278 int on, ret; 290 int on, ret;
279 unsigned int reg;
280 291
281 /* 292 /*
282 * Disable HW trigger: collapse/restore occur based on registers writes. 293 * Disable HW trigger: collapse/restore occur based on registers writes.
@@ -297,8 +308,7 @@ static int gdsc_init(struct gdsc *sc)
297 return ret; 308 return ret;
298 } 309 }
299 310
300 reg = sc->gds_hw_ctrl ? sc->gds_hw_ctrl : sc->gdscr; 311 on = gdsc_is_enabled(sc, true);
301 on = gdsc_is_enabled(sc, reg);
302 if (on < 0) 312 if (on < 0)
303 return on; 313 return on;
304 314
diff --git a/drivers/clk/qcom/gdsc.h b/drivers/clk/qcom/gdsc.h
index 9279278535cd..b0cbb87dd02b 100644
--- a/drivers/clk/qcom/gdsc.h
+++ b/drivers/clk/qcom/gdsc.h
@@ -55,6 +55,7 @@ struct gdsc {
55#define HW_CTRL BIT(2) 55#define HW_CTRL BIT(2)
56#define SW_RESET BIT(3) 56#define SW_RESET BIT(3)
57#define AON_RESET BIT(4) 57#define AON_RESET BIT(4)
58#define POLL_CFG_GDSCR BIT(5)
58 struct reset_controller_dev *rcdev; 59 struct reset_controller_dev *rcdev;
59 unsigned int *resets; 60 unsigned int *resets;
60 unsigned int reset_count; 61 unsigned int reset_count;