diff mbox series

[05/13] clk/qcom: add gdsc_enable helper

Message ID 20240131-b4-qcom-livetree-v1-5-4071c0787db0@linaro.org
State New
Headers show
Series Qualcomm platform USB support | expand

Commit Message

Caleb Connolly Jan. 31, 2024, 3:16 p.m. UTC
Global Distributed Switch Controllers are per-domain switches which are
used to toggle power and clocks to an entire subsystem. They live under
the GCC block and might need to be enabled before certain clocks, so
handle them as part of the clock driver.

Linux models these as power domains, however this additional complexity
doesn't offer much benefit to us in U-Boot. For now they can be turned
on as-needed when a relevant clock is enabled.

In the future, we can add a power-domain driver to model these properly.

Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
---
 drivers/clk/qcom/clock-qcom.c | 18 ++++++++++++++++++
 drivers/clk/qcom/clock-qcom.h |  4 ++++
 2 files changed, 22 insertions(+)
diff mbox series

Patch

diff --git a/drivers/clk/qcom/clock-qcom.c b/drivers/clk/qcom/clock-qcom.c
index d912b673d0d8..0e89e7fe429e 100644
--- a/drivers/clk/qcom/clock-qcom.c
+++ b/drivers/clk/qcom/clock-qcom.c
@@ -39,6 +39,24 @@  void clk_enable_cbc(phys_addr_t cbcr)
 		;
 }
 
+/* Global Distributed Switch Controller - these are
+ * breaker switches for entire peripherals like USB,
+ * they control power and clocks and must be turned on
+ * before configuring clocks or accessing the peripheral.
+ */
+void gdsc_enable(phys_addr_t gdscr)
+{
+	u32 count;
+
+	clrbits_le32(gdscr, GDSC_SW_COLLAPSE);
+	for (count = 0; count < 1500; count++) {
+		if (readl(gdscr) & GDSC_PWR_ON)
+			break;
+		udelay(1);
+	}
+	WARN(count == 1500, "WARNING: GDSC @ %#llx stuck at off\n", gdscr);
+}
+
 void clk_enable_gpll0(phys_addr_t base, const struct pll_vote_clk *gpll0)
 {
 	if (readl(base + gpll0->status) & gpll0->status_bit)
diff --git a/drivers/clk/qcom/clock-qcom.h b/drivers/clk/qcom/clock-qcom.h
index 7eb26369cd8f..2e074d0401c4 100644
--- a/drivers/clk/qcom/clock-qcom.h
+++ b/drivers/clk/qcom/clock-qcom.h
@@ -12,6 +12,9 @@ 
 #define CFG_CLK_SRC_GPLL0_EVEN (6 << 8)
 #define CFG_CLK_SRC_MASK  (7 << 8)
 
+#define GDSC_PWR_ON		BIT(31)
+#define GDSC_SW_COLLAPSE	BIT(0)
+
 #define RCG_CFG_REG		0x4
 #define RCG_M_REG		0x8
 #define RCG_N_REG		0xc
@@ -78,6 +81,7 @@  int qcom_cc_bind(struct udevice *parent);
 void clk_enable_gpll0(phys_addr_t base, const struct pll_vote_clk *gpll0);
 void clk_bcr_update(phys_addr_t apps_cmd_rgcr);
 void clk_enable_cbc(phys_addr_t cbcr);
+void gdsc_enable(phys_addr_t gdscr);
 void clk_enable_vote_clk(phys_addr_t base, const struct vote_clk *vclk);
 const struct freq_tbl *qcom_find_freq(const struct freq_tbl *f, uint rate);
 void clk_rcg_set_rate_mnd(phys_addr_t base, uint32_t cmd_rcgr,