All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/4]
@ 2024-03-11 21:33 Volodymyr Babchuk
  2024-03-11 21:33 ` [PATCH v3 3/4] clk: qcom: add support for power domains uclass Volodymyr Babchuk
                   ` (4 more replies)
  0 siblings, 5 replies; 13+ messages in thread
From: Volodymyr Babchuk @ 2024-03-11 21:33 UTC (permalink / raw)
  To: u-boot@lists.denx.de
  Cc: Volodymyr Babchuk, Caleb Connolly, Konrad Dybcio, Lukasz Majewski,
	Neil Armstrong, Sean Anderson, Sumit Garg, Tom Rini

Set of pre-req patches for Qualcomm SA8155P-ADP board support.

This path series consist of generic qcom changes that may benefit
different boards. It is the part of the bigger series that adds
SA8155P-ADP support, but I am posting this limited set because there
are other developers who depend on those changes and I am not ready to
post other patches of the bigger series.


Changes in v3:
 - Replaced fdt_valid() with fdt_check_header()
 - Added "depends POWER_DOMAIN" to Kconfig (see note)
 - Use readl_poll_timeout() instead of open coded wait loop
 - Print warning if power domain can't be enabled/disabled

Changes in v2:
 - New patch in v2
 - Reworked qcom_cc_bind() function
 - Added timeout to qcom_power_set()
 - Minor fixes in register names and formatting

Volodymyr Babchuk (4):
  qcom: board: validate fdt before trying to use it
  clk: qcom: clear div mask before assigning a new divider
  clk: qcom: add support for power domains uclass
  pinctrl: qcom: pass pin number to get_function_mux callback

 arch/arm/mach-snapdragon/board.c       |   5 +-
 drivers/clk/qcom/Kconfig               |   2 +-
 drivers/clk/qcom/clock-qcom.c          | 135 ++++++++++++++++++++++---
 drivers/clk/qcom/clock-qcom.h          |   6 ++
 drivers/pinctrl/qcom/pinctrl-apq8016.c |   3 +-
 drivers/pinctrl/qcom/pinctrl-apq8096.c |   3 +-
 drivers/pinctrl/qcom/pinctrl-ipq4019.c |   3 +-
 drivers/pinctrl/qcom/pinctrl-qcom.c    |   4 +-
 drivers/pinctrl/qcom/pinctrl-qcom.h    |   3 +-
 drivers/pinctrl/qcom/pinctrl-qcs404.c  |   3 +-
 drivers/pinctrl/qcom/pinctrl-sdm845.c  |   3 +-
 11 files changed, 146 insertions(+), 24 deletions(-)

-- 
2.43.0

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

* [PATCH v3 1/4] qcom: board: validate fdt before trying to use it
  2024-03-11 21:33 [PATCH v3 0/4] Volodymyr Babchuk
  2024-03-11 21:33 ` [PATCH v3 3/4] clk: qcom: add support for power domains uclass Volodymyr Babchuk
@ 2024-03-11 21:33 ` Volodymyr Babchuk
  2024-03-12 18:02   ` Caleb Connolly
  2024-03-11 21:33 ` [PATCH v3 2/4] clk: qcom: clear div mask before assigning a new divider Volodymyr Babchuk
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 13+ messages in thread
From: Volodymyr Babchuk @ 2024-03-11 21:33 UTC (permalink / raw)
  To: u-boot@lists.denx.de
  Cc: Volodymyr Babchuk, Sumit Garg, Caleb Connolly, Neil Armstrong,
	Tom Rini

There are cases when previous bootloader stage leaves some seemingly
valid value in r0, which in fact does not point to valid FDT
blob. This behavior was encountered when trying to boot U-Boot as
"hyp" loader on SA8155P-ADP.

To be sure that we really got the pointer to a device tree we need to
validate it with fdt_check_header() function.

Note: This approach is not 100% fool-proof, as get_prev_bl_fdt_addr()
theoretically can return a pointer to a region that is not physically
mapped and we will get data abort exception when fdt_check_header()
will try to access it. But at this early boot stage we don't know
where RAM is anyways so there is little we can do.

Signed-off-by: Volodymyr Babchuk <volodymyr_babchuk@epam.com>
Reviewed-by: Sumit Garg <sumit.garg@linaro.org>

---

Changes in v3:
 - Replaced fdt_valid() with fdt_check_header()
 - Added Sumit's R-B tag

Changes in v2:
 - New patch in v2

 arch/arm/mach-snapdragon/board.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-snapdragon/board.c b/arch/arm/mach-snapdragon/board.c
index f12f5791a1..6f762fc948 100644
--- a/arch/arm/mach-snapdragon/board.c
+++ b/arch/arm/mach-snapdragon/board.c
@@ -24,6 +24,7 @@
 #include <linux/sizes.h>
 #include <lmb.h>
 #include <malloc.h>
+#include <fdt_support.h>
 #include <usb.h>
 #include <sort.h>
 
@@ -93,7 +94,9 @@ void *board_fdt_blob_setup(int *err)
 	 * try and use the FDT built into U-Boot if there is one...
 	 * This avoids having a hard dependency on the previous stage bootloader
 	 */
-	if (IS_ENABLED(CONFIG_OF_SEPARATE) && (!fdt || fdt != ALIGN(fdt, SZ_4K))) {
+
+	if (IS_ENABLED(CONFIG_OF_SEPARATE) && (!fdt || fdt != ALIGN(fdt, SZ_4K) ||
+					       fdt_check_header((void *)fdt))) {
 		debug("%s: Using built in FDT, bootloader gave us %#llx\n", __func__, fdt);
 		return (void *)gd->fdt_blob;
 	}
-- 
2.43.0

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

* [PATCH v3 2/4] clk: qcom: clear div mask before assigning a new divider
  2024-03-11 21:33 [PATCH v3 0/4] Volodymyr Babchuk
  2024-03-11 21:33 ` [PATCH v3 3/4] clk: qcom: add support for power domains uclass Volodymyr Babchuk
  2024-03-11 21:33 ` [PATCH v3 1/4] qcom: board: validate fdt before trying to use it Volodymyr Babchuk
@ 2024-03-11 21:33 ` Volodymyr Babchuk
  2024-03-12  8:29   ` Sumit Garg
  2024-03-11 21:33 ` [PATCH v3 4/4] pinctrl: qcom: pass pin number to get_function_mux callback Volodymyr Babchuk
  2024-03-19 12:39 ` [PATCH v3 0/4] Caleb Connolly
  4 siblings, 1 reply; 13+ messages in thread
From: Volodymyr Babchuk @ 2024-03-11 21:33 UTC (permalink / raw)
  To: u-boot@lists.denx.de
  Cc: Volodymyr Babchuk, Caleb Connolly, Konrad Dybcio, Lukasz Majewski,
	Neil Armstrong, Sean Anderson, Sumit Garg, Tom Rini

The current behaviour does a bitwise OR of the previous and new
divider values, this is wrong as some bits maybe be set already. We
need to clear all the divider bits before applying new ones.

This fixes potential issue with 1Gbit ethernet on SA8155P-ADP boards.

Signed-off-by: Volodymyr Babchuk <volodymyr_babchuk@epam.com>
Reviewed-by: Caleb Connolly <caleb.connolly@linaro.org>

---

(no changes since v2)

Changes in v2:
 - Reworded the commit message
 - Added Caleb's R-b tag

 drivers/clk/qcom/clock-qcom.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/qcom/clock-qcom.c b/drivers/clk/qcom/clock-qcom.c
index 7c683e5192..729d190c54 100644
--- a/drivers/clk/qcom/clock-qcom.c
+++ b/drivers/clk/qcom/clock-qcom.c
@@ -117,7 +117,8 @@ void clk_rcg_set_rate_mnd(phys_addr_t base, const struct bcr_regs *regs,
 
 	/* setup src select and divider */
 	cfg  = readl(base + regs->cfg_rcgr);
-	cfg &= ~(CFG_SRC_SEL_MASK | CFG_MODE_MASK | CFG_HW_CLK_CTRL_MASK);
+	cfg &= ~(CFG_SRC_SEL_MASK | CFG_MODE_MASK | CFG_HW_CLK_CTRL_MASK |
+		 CFG_SRC_DIV_MASK);
 	cfg |= source & CFG_SRC_SEL_MASK; /* Select clock source */
 
 	if (div)
-- 
2.43.0

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

* [PATCH v3 3/4] clk: qcom: add support for power domains uclass
  2024-03-11 21:33 [PATCH v3 0/4] Volodymyr Babchuk
@ 2024-03-11 21:33 ` Volodymyr Babchuk
  2024-03-12  8:31   ` Sumit Garg
                     ` (3 more replies)
  2024-03-11 21:33 ` [PATCH v3 1/4] qcom: board: validate fdt before trying to use it Volodymyr Babchuk
                   ` (3 subsequent siblings)
  4 siblings, 4 replies; 13+ messages in thread
From: Volodymyr Babchuk @ 2024-03-11 21:33 UTC (permalink / raw)
  To: u-boot@lists.denx.de
  Cc: Volodymyr Babchuk, Caleb Connolly, Konrad Dybcio, Lukasz Majewski,
	Neil Armstrong, Sean Anderson, Sumit Garg, Tom Rini

Now sub-drivers for particular SoCs can register them as power domain
drivers. This is needed for upcoming SM8150 support, because it needs
to power up the Ethernet module.

Signed-off-by: Volodymyr Babchuk <volodymyr_babchuk@epam.com>

---
Caleb suggested to use "imply POWER_DOMAIN", not "depends
POWER_DOMAIN" in the Kconfig, but this does not work:
$ make CROSS_COMPILE=aarch64-linux-gnu- ARCH=arm
scripts/kconfig/conf  --syncconfig Kconfig
drivers/clk/Kconfig:3:error: recursive dependency detected!
drivers/clk/Kconfig:3:  symbol CLK is selected by IMX8M_POWER_DOMAIN
drivers/power/domain/Kconfig:35:        symbol IMX8M_POWER_DOMAIN depends on POWER_DOMAIN
drivers/power/domain/Kconfig:3: symbol POWER_DOMAIN is implied by CLK_QCOM
drivers/clk/qcom/Kconfig:3:     symbol CLK_QCOM depends on CLK
For a resolution refer to Documentation/kbuild/kconfig-language.txt
subsection "Kconfig recursive dependency limitations"


Changes in v3:
 - Added "depends POWER_DOMAIN" to Kconfig (see note)
 - Use readl_poll_timeout() instead of open coded wait loop
 - Print warning if power domain can't be enabled/disabled

Changes in v2:
 - Reworked qcom_cc_bind() function
 - Added timeout to qcom_power_set()
 - Minor fixes in register names and formatting

 drivers/clk/qcom/Kconfig      |   2 +-
 drivers/clk/qcom/clock-qcom.c | 132 ++++++++++++++++++++++++++++++----
 drivers/clk/qcom/clock-qcom.h |   6 ++
 3 files changed, 126 insertions(+), 14 deletions(-)

diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 0df0d1881a..8dae635ac2 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -2,7 +2,7 @@ if ARCH_SNAPDRAGON || ARCH_IPQ40XX
 
 config CLK_QCOM
 	bool
-	depends on CLK && DM_RESET
+	depends on CLK && DM_RESET && POWER_DOMAIN
 	def_bool n
 
 menu "Qualcomm clock drivers"
diff --git a/drivers/clk/qcom/clock-qcom.c b/drivers/clk/qcom/clock-qcom.c
index 729d190c54..7a5938a06a 100644
--- a/drivers/clk/qcom/clock-qcom.c
+++ b/drivers/clk/qcom/clock-qcom.c
@@ -22,7 +22,9 @@
 #include <linux/bug.h>
 #include <linux/delay.h>
 #include <linux/bitops.h>
+#include <linux/iopoll.h>
 #include <reset-uclass.h>
+#include <power-domain-uclass.h>
 
 #include "clock-qcom.h"
 
@@ -30,6 +32,13 @@
 #define CBCR_BRANCH_ENABLE_BIT  BIT(0)
 #define CBCR_BRANCH_OFF_BIT     BIT(31)
 
+#define GDSC_SW_COLLAPSE_MASK		BIT(0)
+#define GDSC_POWER_DOWN_COMPLETE	BIT(15)
+#define GDSC_POWER_UP_COMPLETE		BIT(16)
+#define GDSC_PWR_ON_MASK		BIT(31)
+#define CFG_GDSCR_OFFSET		0x4
+#define GDSC_STATUS_POLL_TIMEOUT_US	1500
+
 /* Enable clock controlled by CBC soft macro */
 void clk_enable_cbc(phys_addr_t cbcr)
 {
@@ -223,7 +232,7 @@ U_BOOT_DRIVER(qcom_clk) = {
 int qcom_cc_bind(struct udevice *parent)
 {
 	struct msm_clk_data *data = (struct msm_clk_data *)dev_get_driver_data(parent);
-	struct udevice *clkdev, *rstdev;
+	struct udevice *clkdev = NULL, *rstdev = NULL, *pwrdev;
 	struct driver *drv;
 	int ret;
 
@@ -238,20 +247,41 @@ int qcom_cc_bind(struct udevice *parent)
 	if (ret)
 		return ret;
 
-	/* Bail out early if resets are not specified for this platform */
-	if (!data->resets)
-		return ret;
+	if (data->resets) {
+		/* Get a handle to the common reset handler */
+		drv = lists_driver_lookup_name("qcom_reset");
+		if (!drv) {
+			ret = -ENOENT;
+			goto unbind_clkdev;
+		}
+
+		/* Register the reset controller */
+		ret = device_bind_with_driver_data(parent, drv, "qcom_reset", (ulong)data,
+						   dev_ofnode(parent), &rstdev);
+		if (ret)
+			goto unbind_clkdev;
+	}
 
-	/* Get a handle to the common reset handler */
-	drv = lists_driver_lookup_name("qcom_reset");
-	if (!drv)
-		return -ENOENT;
+	if (data->power_domains) {
+		/* Get a handle to the common power domain handler */
+		drv = lists_driver_lookup_name("qcom_power");
+		if (!drv) {
+			ret = -ENOENT;
+			goto unbind_rstdev;
+		}
+		/* Register the power domain controller */
+		ret = device_bind_with_driver_data(parent, drv, "qcom_power", (ulong)data,
+						   dev_ofnode(parent), &pwrdev);
+		if (ret)
+			goto unbind_rstdev;
+	}
 
-	/* Register the reset controller */
-	ret = device_bind_with_driver_data(parent, drv, "qcom_reset", (ulong)data,
-					   dev_ofnode(parent), &rstdev);
-	if (ret)
-		device_unbind(clkdev);
+	return 0;
+
+unbind_rstdev:
+	device_unbind(rstdev);
+unbind_clkdev:
+	device_unbind(clkdev);
 
 	return ret;
 }
@@ -306,3 +336,79 @@ U_BOOT_DRIVER(qcom_reset) = {
 	.ops = &qcom_reset_ops,
 	.probe = qcom_reset_probe,
 };
+
+static int qcom_power_set(struct power_domain *pwr, bool on)
+{
+	struct msm_clk_data *data = (struct msm_clk_data *)dev_get_driver_data(pwr->dev);
+	void __iomem *base = dev_get_priv(pwr->dev);
+	const struct qcom_power_map *map;
+	u32 value;
+	int ret;
+
+	if (pwr->id >= data->num_power_domains)
+		return -ENODEV;
+
+	map = &data->power_domains[pwr->id];
+
+	if (!map->reg)
+		return -ENODEV;
+
+	value = readl(base + map->reg);
+
+	if (on)
+		value &= ~GDSC_SW_COLLAPSE_MASK;
+	else
+		value |= GDSC_SW_COLLAPSE_MASK;
+
+	writel(value, base + map->reg);
+
+	if (on)
+		ret = readl_poll_timeout(base + map->reg + CFG_GDSCR_OFFSET,
+					 value,
+					 (value & GDSC_POWER_UP_COMPLETE) ||
+					 (value & GDSC_PWR_ON_MASK),
+					 GDSC_STATUS_POLL_TIMEOUT_US);
+
+	else
+		ret = readl_poll_timeout(base + map->reg + CFG_GDSCR_OFFSET,
+					 value,
+					 (value & GDSC_POWER_DOWN_COMPLETE) ||
+					 !(value & GDSC_PWR_ON_MASK),
+					 GDSC_STATUS_POLL_TIMEOUT_US);
+
+
+	if (ret == -ETIMEDOUT)
+		printf("WARNING: GDSC %lu is stuck during power on/off\n",
+		       pwr->id);
+	return ret;
+}
+
+static int qcom_power_on(struct power_domain *pwr)
+{
+	return qcom_power_set(pwr, true);
+}
+
+static int qcom_power_off(struct power_domain *pwr)
+{
+	return qcom_power_set(pwr, false);
+}
+
+static const struct power_domain_ops qcom_power_ops = {
+	.on = qcom_power_on,
+	.off = qcom_power_off,
+};
+
+static int qcom_power_probe(struct udevice *dev)
+{
+	/* Set our priv pointer to the base address */
+	dev_set_priv(dev, (void *)dev_read_addr(dev));
+
+	return 0;
+}
+
+U_BOOT_DRIVER(qcom_power) = {
+	.name = "qcom_power",
+	.id = UCLASS_POWER_DOMAIN,
+	.ops = &qcom_power_ops,
+	.probe = qcom_power_probe,
+};
diff --git a/drivers/clk/qcom/clock-qcom.h b/drivers/clk/qcom/clock-qcom.h
index 01088c1901..12a1eaec2b 100644
--- a/drivers/clk/qcom/clock-qcom.h
+++ b/drivers/clk/qcom/clock-qcom.h
@@ -59,9 +59,15 @@ struct qcom_reset_map {
 	u8 bit;
 };
 
+struct qcom_power_map {
+	unsigned int reg;
+};
+
 struct clk;
 
 struct msm_clk_data {
+	const struct qcom_power_map	*power_domains;
+	unsigned long			num_power_domains;
 	const struct qcom_reset_map	*resets;
 	unsigned long			num_resets;
 	const struct gate_clk		*clks;
-- 
2.43.0

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

* [PATCH v3 4/4] pinctrl: qcom: pass pin number to get_function_mux callback
  2024-03-11 21:33 [PATCH v3 0/4] Volodymyr Babchuk
                   ` (2 preceding siblings ...)
  2024-03-11 21:33 ` [PATCH v3 2/4] clk: qcom: clear div mask before assigning a new divider Volodymyr Babchuk
@ 2024-03-11 21:33 ` Volodymyr Babchuk
  2024-03-19 12:39 ` [PATCH v3 0/4] Caleb Connolly
  4 siblings, 0 replies; 13+ messages in thread
From: Volodymyr Babchuk @ 2024-03-11 21:33 UTC (permalink / raw)
  To: u-boot@lists.denx.de
  Cc: Volodymyr Babchuk, Caleb Connolly, Sumit Garg, Neil Armstrong,
	Tom Rini

This patch is the preparation for SM8150 support. This new SoC
depending on the particular pin can have different numbers for the
same function. For example "rgmii" function for GPIO4 has id=2 while
for GPIO59 it has id=1. So, to support this type of SoCs,
get_function_mux() callback needs to know for which pin the function
is requested.

Signed-off-by: Volodymyr Babchuk <volodymyr_babchuk@epam.com>
Reviewed-by: Caleb Connolly <caleb.connolly@linaro.org>
Reviewed-by: Sumit Garg <sumit.garg@linaro.org>

---

Changes in v3:
 - Added Sumit's R-b tag

Changes in v2:
 - Added Caleb's R-b tag

 drivers/pinctrl/qcom/pinctrl-apq8016.c | 3 ++-
 drivers/pinctrl/qcom/pinctrl-apq8096.c | 3 ++-
 drivers/pinctrl/qcom/pinctrl-ipq4019.c | 3 ++-
 drivers/pinctrl/qcom/pinctrl-qcom.c    | 4 ++--
 drivers/pinctrl/qcom/pinctrl-qcom.h    | 3 ++-
 drivers/pinctrl/qcom/pinctrl-qcs404.c  | 3 ++-
 drivers/pinctrl/qcom/pinctrl-sdm845.c  | 3 ++-
 7 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/drivers/pinctrl/qcom/pinctrl-apq8016.c b/drivers/pinctrl/qcom/pinctrl-apq8016.c
index db0e212468..a9a00f4b08 100644
--- a/drivers/pinctrl/qcom/pinctrl-apq8016.c
+++ b/drivers/pinctrl/qcom/pinctrl-apq8016.c
@@ -49,7 +49,8 @@ static const char *apq8016_get_pin_name(struct udevice *dev,
 	}
 }
 
-static unsigned int apq8016_get_function_mux(unsigned int selector)
+static unsigned int apq8016_get_function_mux(__maybe_unused unsigned int pin,
+					     unsigned int selector)
 {
 	return msm_pinctrl_functions[selector].val;
 }
diff --git a/drivers/pinctrl/qcom/pinctrl-apq8096.c b/drivers/pinctrl/qcom/pinctrl-apq8096.c
index 880df8fe3c..9697cb5beb 100644
--- a/drivers/pinctrl/qcom/pinctrl-apq8096.c
+++ b/drivers/pinctrl/qcom/pinctrl-apq8096.c
@@ -44,7 +44,8 @@ static const char *apq8096_get_pin_name(struct udevice *dev,
 	}
 }
 
-static unsigned int apq8096_get_function_mux(unsigned int selector)
+static unsigned int apq8096_get_function_mux(__maybe_unused unsigned int pin,
+					     unsigned int selector)
 {
 	return msm_pinctrl_functions[selector].val;
 }
diff --git a/drivers/pinctrl/qcom/pinctrl-ipq4019.c b/drivers/pinctrl/qcom/pinctrl-ipq4019.c
index 74c04ab87c..4479230313 100644
--- a/drivers/pinctrl/qcom/pinctrl-ipq4019.c
+++ b/drivers/pinctrl/qcom/pinctrl-ipq4019.c
@@ -40,7 +40,8 @@ static const char *ipq4019_get_pin_name(struct udevice *dev,
 	return pin_name;
 }
 
-static unsigned int ipq4019_get_function_mux(unsigned int selector)
+static unsigned int ipq4019_get_function_mux(__maybe_unused unsigned int pin,
+					     unsigned int selector)
 {
 	return msm_pinctrl_functions[selector].val;
 }
diff --git a/drivers/pinctrl/qcom/pinctrl-qcom.c b/drivers/pinctrl/qcom/pinctrl-qcom.c
index ee0624df29..909e566acf 100644
--- a/drivers/pinctrl/qcom/pinctrl-qcom.c
+++ b/drivers/pinctrl/qcom/pinctrl-qcom.c
@@ -83,14 +83,14 @@ static int msm_pinmux_set(struct udevice *dev, unsigned int pin_selector,
 			  unsigned int func_selector)
 {
 	struct msm_pinctrl_priv *priv = dev_get_priv(dev);
+	u32 func = priv->data->get_function_mux(pin_selector, func_selector);
 
 	/* Always NOP for special pins, assume they're in the correct state */
 	if (qcom_is_special_pin(&priv->data->pin_data, pin_selector))
 		return 0;
 
 	clrsetbits_le32(priv->base + GPIO_CONFIG_REG(priv, pin_selector),
-			TLMM_FUNC_SEL_MASK | TLMM_GPIO_DISABLE,
-			priv->data->get_function_mux(func_selector) << 2);
+			TLMM_FUNC_SEL_MASK | TLMM_GPIO_DISABLE, func << 2);
 	return 0;
 }
 
diff --git a/drivers/pinctrl/qcom/pinctrl-qcom.h b/drivers/pinctrl/qcom/pinctrl-qcom.h
index 07f2eae9ba..49b7bfbc00 100644
--- a/drivers/pinctrl/qcom/pinctrl-qcom.h
+++ b/drivers/pinctrl/qcom/pinctrl-qcom.h
@@ -18,7 +18,8 @@ struct msm_pinctrl_data {
 	int functions_count;
 	const char *(*get_function_name)(struct udevice *dev,
 					 unsigned int selector);
-	unsigned int (*get_function_mux)(unsigned int selector);
+	unsigned int (*get_function_mux)(unsigned int pin,
+					 unsigned int selector);
 	const char *(*get_pin_name)(struct udevice *dev,
 				    unsigned int selector);
 };
diff --git a/drivers/pinctrl/qcom/pinctrl-qcs404.c b/drivers/pinctrl/qcom/pinctrl-qcs404.c
index 3a2d468599..4b7c670c90 100644
--- a/drivers/pinctrl/qcom/pinctrl-qcs404.c
+++ b/drivers/pinctrl/qcom/pinctrl-qcs404.c
@@ -94,7 +94,8 @@ static const char *qcs404_get_pin_name(struct udevice *dev,
 	}
 }
 
-static unsigned int qcs404_get_function_mux(unsigned int selector)
+static unsigned int qcs404_get_function_mux(__maybe_unused unsigned int pin,
+					    unsigned int selector)
 {
 	return msm_pinctrl_functions[selector].val;
 }
diff --git a/drivers/pinctrl/qcom/pinctrl-sdm845.c b/drivers/pinctrl/qcom/pinctrl-sdm845.c
index 76bd8c4ef4..459a4329ec 100644
--- a/drivers/pinctrl/qcom/pinctrl-sdm845.c
+++ b/drivers/pinctrl/qcom/pinctrl-sdm845.c
@@ -70,7 +70,8 @@ static const char *sdm845_get_pin_name(struct udevice *dev,
 	return pin_name;
 }
 
-static unsigned int sdm845_get_function_mux(unsigned int selector)
+static unsigned int sdm845_get_function_mux(__maybe_unused unsigned int pin,
+					    unsigned int selector)
 {
 	return msm_pinctrl_functions[selector].val;
 }
-- 
2.43.0

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

* Re: [PATCH v3 2/4] clk: qcom: clear div mask before assigning a new divider
  2024-03-11 21:33 ` [PATCH v3 2/4] clk: qcom: clear div mask before assigning a new divider Volodymyr Babchuk
@ 2024-03-12  8:29   ` Sumit Garg
  2024-03-12 20:00     ` Volodymyr Babchuk
  0 siblings, 1 reply; 13+ messages in thread
From: Sumit Garg @ 2024-03-12  8:29 UTC (permalink / raw)
  To: Volodymyr Babchuk
  Cc: u-boot@lists.denx.de, Caleb Connolly, Konrad Dybcio,
	Lukasz Majewski, Neil Armstrong, Sean Anderson, Tom Rini

On Tue, 12 Mar 2024 at 03:03, Volodymyr Babchuk
<Volodymyr_Babchuk@epam.com> wrote:
>
> The current behaviour does a bitwise OR of the previous and new
> divider values, this is wrong as some bits maybe be set already. We

nit: s/maybe be/maybe/

> need to clear all the divider bits before applying new ones.
>
> This fixes potential issue with 1Gbit ethernet on SA8155P-ADP boards.
>
> Signed-off-by: Volodymyr Babchuk <volodymyr_babchuk@epam.com>
> Reviewed-by: Caleb Connolly <caleb.connolly@linaro.org>
>

Reviewed-by: Sumit Garg <sumit.garg@linaro.org>

-Sumit

> ---
>
> (no changes since v2)
>
> Changes in v2:
>  - Reworded the commit message
>  - Added Caleb's R-b tag
>
>  drivers/clk/qcom/clock-qcom.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/clk/qcom/clock-qcom.c b/drivers/clk/qcom/clock-qcom.c
> index 7c683e5192..729d190c54 100644
> --- a/drivers/clk/qcom/clock-qcom.c
> +++ b/drivers/clk/qcom/clock-qcom.c
> @@ -117,7 +117,8 @@ void clk_rcg_set_rate_mnd(phys_addr_t base, const struct bcr_regs *regs,
>
>         /* setup src select and divider */
>         cfg  = readl(base + regs->cfg_rcgr);
> -       cfg &= ~(CFG_SRC_SEL_MASK | CFG_MODE_MASK | CFG_HW_CLK_CTRL_MASK);
> +       cfg &= ~(CFG_SRC_SEL_MASK | CFG_MODE_MASK | CFG_HW_CLK_CTRL_MASK |
> +                CFG_SRC_DIV_MASK);
>         cfg |= source & CFG_SRC_SEL_MASK; /* Select clock source */
>
>         if (div)
> --
> 2.43.0

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

* Re: [PATCH v3 3/4] clk: qcom: add support for power domains uclass
  2024-03-11 21:33 ` [PATCH v3 3/4] clk: qcom: add support for power domains uclass Volodymyr Babchuk
@ 2024-03-12  8:31   ` Sumit Garg
  2024-03-12 18:01   ` Caleb Connolly
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 13+ messages in thread
From: Sumit Garg @ 2024-03-12  8:31 UTC (permalink / raw)
  To: Volodymyr Babchuk
  Cc: u-boot@lists.denx.de, Caleb Connolly, Konrad Dybcio,
	Lukasz Majewski, Neil Armstrong, Sean Anderson, Tom Rini

On Tue, 12 Mar 2024 at 03:03, Volodymyr Babchuk
<Volodymyr_Babchuk@epam.com> wrote:
>
> Now sub-drivers for particular SoCs can register them as power domain
> drivers. This is needed for upcoming SM8150 support, because it needs
> to power up the Ethernet module.
>
> Signed-off-by: Volodymyr Babchuk <volodymyr_babchuk@epam.com>
>
> ---
> Caleb suggested to use "imply POWER_DOMAIN", not "depends
> POWER_DOMAIN" in the Kconfig, but this does not work:
> $ make CROSS_COMPILE=aarch64-linux-gnu- ARCH=arm
> scripts/kconfig/conf  --syncconfig Kconfig
> drivers/clk/Kconfig:3:error: recursive dependency detected!
> drivers/clk/Kconfig:3:  symbol CLK is selected by IMX8M_POWER_DOMAIN
> drivers/power/domain/Kconfig:35:        symbol IMX8M_POWER_DOMAIN depends on POWER_DOMAIN
> drivers/power/domain/Kconfig:3: symbol POWER_DOMAIN is implied by CLK_QCOM
> drivers/clk/qcom/Kconfig:3:     symbol CLK_QCOM depends on CLK
> For a resolution refer to Documentation/kbuild/kconfig-language.txt
> subsection "Kconfig recursive dependency limitations"
>
>
> Changes in v3:
>  - Added "depends POWER_DOMAIN" to Kconfig (see note)
>  - Use readl_poll_timeout() instead of open coded wait loop
>  - Print warning if power domain can't be enabled/disabled
>

Reviewed-by: Sumit Garg <sumit.garg@linaro.org>

-Sumit

> Changes in v2:
>  - Reworked qcom_cc_bind() function
>  - Added timeout to qcom_power_set()
>  - Minor fixes in register names and formatting
>
>  drivers/clk/qcom/Kconfig      |   2 +-
>  drivers/clk/qcom/clock-qcom.c | 132 ++++++++++++++++++++++++++++++----
>  drivers/clk/qcom/clock-qcom.h |   6 ++
>  3 files changed, 126 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
> index 0df0d1881a..8dae635ac2 100644
> --- a/drivers/clk/qcom/Kconfig
> +++ b/drivers/clk/qcom/Kconfig
> @@ -2,7 +2,7 @@ if ARCH_SNAPDRAGON || ARCH_IPQ40XX
>
>  config CLK_QCOM
>         bool
> -       depends on CLK && DM_RESET
> +       depends on CLK && DM_RESET && POWER_DOMAIN
>         def_bool n
>
>  menu "Qualcomm clock drivers"
> diff --git a/drivers/clk/qcom/clock-qcom.c b/drivers/clk/qcom/clock-qcom.c
> index 729d190c54..7a5938a06a 100644
> --- a/drivers/clk/qcom/clock-qcom.c
> +++ b/drivers/clk/qcom/clock-qcom.c
> @@ -22,7 +22,9 @@
>  #include <linux/bug.h>
>  #include <linux/delay.h>
>  #include <linux/bitops.h>
> +#include <linux/iopoll.h>
>  #include <reset-uclass.h>
> +#include <power-domain-uclass.h>
>
>  #include "clock-qcom.h"
>
> @@ -30,6 +32,13 @@
>  #define CBCR_BRANCH_ENABLE_BIT  BIT(0)
>  #define CBCR_BRANCH_OFF_BIT     BIT(31)
>
> +#define GDSC_SW_COLLAPSE_MASK          BIT(0)
> +#define GDSC_POWER_DOWN_COMPLETE       BIT(15)
> +#define GDSC_POWER_UP_COMPLETE         BIT(16)
> +#define GDSC_PWR_ON_MASK               BIT(31)
> +#define CFG_GDSCR_OFFSET               0x4
> +#define GDSC_STATUS_POLL_TIMEOUT_US    1500
> +
>  /* Enable clock controlled by CBC soft macro */
>  void clk_enable_cbc(phys_addr_t cbcr)
>  {
> @@ -223,7 +232,7 @@ U_BOOT_DRIVER(qcom_clk) = {
>  int qcom_cc_bind(struct udevice *parent)
>  {
>         struct msm_clk_data *data = (struct msm_clk_data *)dev_get_driver_data(parent);
> -       struct udevice *clkdev, *rstdev;
> +       struct udevice *clkdev = NULL, *rstdev = NULL, *pwrdev;
>         struct driver *drv;
>         int ret;
>
> @@ -238,20 +247,41 @@ int qcom_cc_bind(struct udevice *parent)
>         if (ret)
>                 return ret;
>
> -       /* Bail out early if resets are not specified for this platform */
> -       if (!data->resets)
> -               return ret;
> +       if (data->resets) {
> +               /* Get a handle to the common reset handler */
> +               drv = lists_driver_lookup_name("qcom_reset");
> +               if (!drv) {
> +                       ret = -ENOENT;
> +                       goto unbind_clkdev;
> +               }
> +
> +               /* Register the reset controller */
> +               ret = device_bind_with_driver_data(parent, drv, "qcom_reset", (ulong)data,
> +                                                  dev_ofnode(parent), &rstdev);
> +               if (ret)
> +                       goto unbind_clkdev;
> +       }
>
> -       /* Get a handle to the common reset handler */
> -       drv = lists_driver_lookup_name("qcom_reset");
> -       if (!drv)
> -               return -ENOENT;
> +       if (data->power_domains) {
> +               /* Get a handle to the common power domain handler */
> +               drv = lists_driver_lookup_name("qcom_power");
> +               if (!drv) {
> +                       ret = -ENOENT;
> +                       goto unbind_rstdev;
> +               }
> +               /* Register the power domain controller */
> +               ret = device_bind_with_driver_data(parent, drv, "qcom_power", (ulong)data,
> +                                                  dev_ofnode(parent), &pwrdev);
> +               if (ret)
> +                       goto unbind_rstdev;
> +       }
>
> -       /* Register the reset controller */
> -       ret = device_bind_with_driver_data(parent, drv, "qcom_reset", (ulong)data,
> -                                          dev_ofnode(parent), &rstdev);
> -       if (ret)
> -               device_unbind(clkdev);
> +       return 0;
> +
> +unbind_rstdev:
> +       device_unbind(rstdev);
> +unbind_clkdev:
> +       device_unbind(clkdev);
>
>         return ret;
>  }
> @@ -306,3 +336,79 @@ U_BOOT_DRIVER(qcom_reset) = {
>         .ops = &qcom_reset_ops,
>         .probe = qcom_reset_probe,
>  };
> +
> +static int qcom_power_set(struct power_domain *pwr, bool on)
> +{
> +       struct msm_clk_data *data = (struct msm_clk_data *)dev_get_driver_data(pwr->dev);
> +       void __iomem *base = dev_get_priv(pwr->dev);
> +       const struct qcom_power_map *map;
> +       u32 value;
> +       int ret;
> +
> +       if (pwr->id >= data->num_power_domains)
> +               return -ENODEV;
> +
> +       map = &data->power_domains[pwr->id];
> +
> +       if (!map->reg)
> +               return -ENODEV;
> +
> +       value = readl(base + map->reg);
> +
> +       if (on)
> +               value &= ~GDSC_SW_COLLAPSE_MASK;
> +       else
> +               value |= GDSC_SW_COLLAPSE_MASK;
> +
> +       writel(value, base + map->reg);
> +
> +       if (on)
> +               ret = readl_poll_timeout(base + map->reg + CFG_GDSCR_OFFSET,
> +                                        value,
> +                                        (value & GDSC_POWER_UP_COMPLETE) ||
> +                                        (value & GDSC_PWR_ON_MASK),
> +                                        GDSC_STATUS_POLL_TIMEOUT_US);
> +
> +       else
> +               ret = readl_poll_timeout(base + map->reg + CFG_GDSCR_OFFSET,
> +                                        value,
> +                                        (value & GDSC_POWER_DOWN_COMPLETE) ||
> +                                        !(value & GDSC_PWR_ON_MASK),
> +                                        GDSC_STATUS_POLL_TIMEOUT_US);
> +
> +
> +       if (ret == -ETIMEDOUT)
> +               printf("WARNING: GDSC %lu is stuck during power on/off\n",
> +                      pwr->id);
> +       return ret;
> +}
> +
> +static int qcom_power_on(struct power_domain *pwr)
> +{
> +       return qcom_power_set(pwr, true);
> +}
> +
> +static int qcom_power_off(struct power_domain *pwr)
> +{
> +       return qcom_power_set(pwr, false);
> +}
> +
> +static const struct power_domain_ops qcom_power_ops = {
> +       .on = qcom_power_on,
> +       .off = qcom_power_off,
> +};
> +
> +static int qcom_power_probe(struct udevice *dev)
> +{
> +       /* Set our priv pointer to the base address */
> +       dev_set_priv(dev, (void *)dev_read_addr(dev));
> +
> +       return 0;
> +}
> +
> +U_BOOT_DRIVER(qcom_power) = {
> +       .name = "qcom_power",
> +       .id = UCLASS_POWER_DOMAIN,
> +       .ops = &qcom_power_ops,
> +       .probe = qcom_power_probe,
> +};
> diff --git a/drivers/clk/qcom/clock-qcom.h b/drivers/clk/qcom/clock-qcom.h
> index 01088c1901..12a1eaec2b 100644
> --- a/drivers/clk/qcom/clock-qcom.h
> +++ b/drivers/clk/qcom/clock-qcom.h
> @@ -59,9 +59,15 @@ struct qcom_reset_map {
>         u8 bit;
>  };
>
> +struct qcom_power_map {
> +       unsigned int reg;
> +};
> +
>  struct clk;
>
>  struct msm_clk_data {
> +       const struct qcom_power_map     *power_domains;
> +       unsigned long                   num_power_domains;
>         const struct qcom_reset_map     *resets;
>         unsigned long                   num_resets;
>         const struct gate_clk           *clks;
> --
> 2.43.0

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

* Re: [PATCH v3 3/4] clk: qcom: add support for power domains uclass
  2024-03-11 21:33 ` [PATCH v3 3/4] clk: qcom: add support for power domains uclass Volodymyr Babchuk
  2024-03-12  8:31   ` Sumit Garg
@ 2024-03-12 18:01   ` Caleb Connolly
  2024-03-13 17:12   ` Caleb Connolly
  2024-03-13 17:15   ` Caleb Connolly
  3 siblings, 0 replies; 13+ messages in thread
From: Caleb Connolly @ 2024-03-12 18:01 UTC (permalink / raw)
  To: Volodymyr Babchuk, u-boot@lists.denx.de
  Cc: Konrad Dybcio, Lukasz Majewski, Neil Armstrong, Sean Anderson,
	Sumit Garg, Tom Rini



On 11/03/2024 21:33, Volodymyr Babchuk wrote:
> Now sub-drivers for particular SoCs can register them as power domain
> drivers. This is needed for upcoming SM8150 support, because it needs
> to power up the Ethernet module.
> 
> Signed-off-by: Volodymyr Babchuk <volodymyr_babchuk@epam.com>

Reviewed-by: Caleb Connolly <caleb.connolly@linaro.org>
> 
> ---
> Caleb suggested to use "imply POWER_DOMAIN", not "depends
> POWER_DOMAIN" in the Kconfig, but this does not work:
> $ make CROSS_COMPILE=aarch64-linux-gnu- ARCH=arm
> scripts/kconfig/conf  --syncconfig Kconfig
> drivers/clk/Kconfig:3:error: recursive dependency detected!
> drivers/clk/Kconfig:3:  symbol CLK is selected by IMX8M_POWER_DOMAIN
> drivers/power/domain/Kconfig:35:        symbol IMX8M_POWER_DOMAIN depends on POWER_DOMAIN
> drivers/power/domain/Kconfig:3: symbol POWER_DOMAIN is implied by CLK_QCOM
> drivers/clk/qcom/Kconfig:3:     symbol CLK_QCOM depends on CLK
> For a resolution refer to Documentation/kbuild/kconfig-language.txt
> subsection "Kconfig recursive dependency limitations"
> 
> 
> Changes in v3:
>  - Added "depends POWER_DOMAIN" to Kconfig (see note)
>  - Use readl_poll_timeout() instead of open coded wait loop
>  - Print warning if power domain can't be enabled/disabled
> 
> Changes in v2:
>  - Reworked qcom_cc_bind() function
>  - Added timeout to qcom_power_set()
>  - Minor fixes in register names and formatting
> 
>  drivers/clk/qcom/Kconfig      |   2 +-
>  drivers/clk/qcom/clock-qcom.c | 132 ++++++++++++++++++++++++++++++----
>  drivers/clk/qcom/clock-qcom.h |   6 ++
>  3 files changed, 126 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
> index 0df0d1881a..8dae635ac2 100644
> --- a/drivers/clk/qcom/Kconfig
> +++ b/drivers/clk/qcom/Kconfig
> @@ -2,7 +2,7 @@ if ARCH_SNAPDRAGON || ARCH_IPQ40XX
>  
>  config CLK_QCOM
>  	bool
> -	depends on CLK && DM_RESET
> +	depends on CLK && DM_RESET && POWER_DOMAIN
>  	def_bool n
>  
>  menu "Qualcomm clock drivers"
> diff --git a/drivers/clk/qcom/clock-qcom.c b/drivers/clk/qcom/clock-qcom.c
> index 729d190c54..7a5938a06a 100644
> --- a/drivers/clk/qcom/clock-qcom.c
> +++ b/drivers/clk/qcom/clock-qcom.c
> @@ -22,7 +22,9 @@
>  #include <linux/bug.h>
>  #include <linux/delay.h>
>  #include <linux/bitops.h>
> +#include <linux/iopoll.h>
>  #include <reset-uclass.h>
> +#include <power-domain-uclass.h>
>  
>  #include "clock-qcom.h"
>  
> @@ -30,6 +32,13 @@
>  #define CBCR_BRANCH_ENABLE_BIT  BIT(0)
>  #define CBCR_BRANCH_OFF_BIT     BIT(31)
>  
> +#define GDSC_SW_COLLAPSE_MASK		BIT(0)
> +#define GDSC_POWER_DOWN_COMPLETE	BIT(15)
> +#define GDSC_POWER_UP_COMPLETE		BIT(16)
> +#define GDSC_PWR_ON_MASK		BIT(31)
> +#define CFG_GDSCR_OFFSET		0x4
> +#define GDSC_STATUS_POLL_TIMEOUT_US	1500
> +
>  /* Enable clock controlled by CBC soft macro */
>  void clk_enable_cbc(phys_addr_t cbcr)
>  {
> @@ -223,7 +232,7 @@ U_BOOT_DRIVER(qcom_clk) = {
>  int qcom_cc_bind(struct udevice *parent)
>  {
>  	struct msm_clk_data *data = (struct msm_clk_data *)dev_get_driver_data(parent);
> -	struct udevice *clkdev, *rstdev;
> +	struct udevice *clkdev = NULL, *rstdev = NULL, *pwrdev;
>  	struct driver *drv;
>  	int ret;
>  
> @@ -238,20 +247,41 @@ int qcom_cc_bind(struct udevice *parent)
>  	if (ret)
>  		return ret;
>  
> -	/* Bail out early if resets are not specified for this platform */
> -	if (!data->resets)
> -		return ret;
> +	if (data->resets) {
> +		/* Get a handle to the common reset handler */
> +		drv = lists_driver_lookup_name("qcom_reset");
> +		if (!drv) {
> +			ret = -ENOENT;
> +			goto unbind_clkdev;
> +		}
> +
> +		/* Register the reset controller */
> +		ret = device_bind_with_driver_data(parent, drv, "qcom_reset", (ulong)data,
> +						   dev_ofnode(parent), &rstdev);
> +		if (ret)
> +			goto unbind_clkdev;
> +	}
>  
> -	/* Get a handle to the common reset handler */
> -	drv = lists_driver_lookup_name("qcom_reset");
> -	if (!drv)
> -		return -ENOENT;
> +	if (data->power_domains) {
> +		/* Get a handle to the common power domain handler */
> +		drv = lists_driver_lookup_name("qcom_power");
> +		if (!drv) {
> +			ret = -ENOENT;
> +			goto unbind_rstdev;
> +		}
> +		/* Register the power domain controller */
> +		ret = device_bind_with_driver_data(parent, drv, "qcom_power", (ulong)data,
> +						   dev_ofnode(parent), &pwrdev);
> +		if (ret)
> +			goto unbind_rstdev;
> +	}
>  
> -	/* Register the reset controller */
> -	ret = device_bind_with_driver_data(parent, drv, "qcom_reset", (ulong)data,
> -					   dev_ofnode(parent), &rstdev);
> -	if (ret)
> -		device_unbind(clkdev);
> +	return 0;
> +
> +unbind_rstdev:
> +	device_unbind(rstdev);
> +unbind_clkdev:
> +	device_unbind(clkdev);
>  
>  	return ret;
>  }
> @@ -306,3 +336,79 @@ U_BOOT_DRIVER(qcom_reset) = {
>  	.ops = &qcom_reset_ops,
>  	.probe = qcom_reset_probe,
>  };
> +
> +static int qcom_power_set(struct power_domain *pwr, bool on)
> +{
> +	struct msm_clk_data *data = (struct msm_clk_data *)dev_get_driver_data(pwr->dev);
> +	void __iomem *base = dev_get_priv(pwr->dev);
> +	const struct qcom_power_map *map;
> +	u32 value;
> +	int ret;
> +
> +	if (pwr->id >= data->num_power_domains)
> +		return -ENODEV;
> +
> +	map = &data->power_domains[pwr->id];
> +
> +	if (!map->reg)
> +		return -ENODEV;
> +
> +	value = readl(base + map->reg);
> +
> +	if (on)
> +		value &= ~GDSC_SW_COLLAPSE_MASK;
> +	else
> +		value |= GDSC_SW_COLLAPSE_MASK;
> +
> +	writel(value, base + map->reg);
> +
> +	if (on)
> +		ret = readl_poll_timeout(base + map->reg + CFG_GDSCR_OFFSET,
> +					 value,
> +					 (value & GDSC_POWER_UP_COMPLETE) ||
> +					 (value & GDSC_PWR_ON_MASK),
> +					 GDSC_STATUS_POLL_TIMEOUT_US);
> +
> +	else
> +		ret = readl_poll_timeout(base + map->reg + CFG_GDSCR_OFFSET,
> +					 value,
> +					 (value & GDSC_POWER_DOWN_COMPLETE) ||
> +					 !(value & GDSC_PWR_ON_MASK),
> +					 GDSC_STATUS_POLL_TIMEOUT_US);
> +
> +
> +	if (ret == -ETIMEDOUT)
> +		printf("WARNING: GDSC %lu is stuck during power on/off\n",
> +		       pwr->id);
> +	return ret;
> +}
> +
> +static int qcom_power_on(struct power_domain *pwr)
> +{
> +	return qcom_power_set(pwr, true);
> +}
> +
> +static int qcom_power_off(struct power_domain *pwr)
> +{
> +	return qcom_power_set(pwr, false);
> +}
> +
> +static const struct power_domain_ops qcom_power_ops = {
> +	.on = qcom_power_on,
> +	.off = qcom_power_off,
> +};
> +
> +static int qcom_power_probe(struct udevice *dev)
> +{
> +	/* Set our priv pointer to the base address */
> +	dev_set_priv(dev, (void *)dev_read_addr(dev));
> +
> +	return 0;
> +}
> +
> +U_BOOT_DRIVER(qcom_power) = {
> +	.name = "qcom_power",
> +	.id = UCLASS_POWER_DOMAIN,
> +	.ops = &qcom_power_ops,
> +	.probe = qcom_power_probe,
> +};
> diff --git a/drivers/clk/qcom/clock-qcom.h b/drivers/clk/qcom/clock-qcom.h
> index 01088c1901..12a1eaec2b 100644
> --- a/drivers/clk/qcom/clock-qcom.h
> +++ b/drivers/clk/qcom/clock-qcom.h
> @@ -59,9 +59,15 @@ struct qcom_reset_map {
>  	u8 bit;
>  };
>  
> +struct qcom_power_map {
> +	unsigned int reg;
> +};
> +
>  struct clk;
>  
>  struct msm_clk_data {
> +	const struct qcom_power_map	*power_domains;
> +	unsigned long			num_power_domains;
>  	const struct qcom_reset_map	*resets;
>  	unsigned long			num_resets;
>  	const struct gate_clk		*clks;

-- 
// Caleb (they/them)

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

* Re: [PATCH v3 1/4] qcom: board: validate fdt before trying to use it
  2024-03-11 21:33 ` [PATCH v3 1/4] qcom: board: validate fdt before trying to use it Volodymyr Babchuk
@ 2024-03-12 18:02   ` Caleb Connolly
  0 siblings, 0 replies; 13+ messages in thread
From: Caleb Connolly @ 2024-03-12 18:02 UTC (permalink / raw)
  To: Volodymyr Babchuk, u-boot@lists.denx.de
  Cc: Sumit Garg, Neil Armstrong, Tom Rini



On 11/03/2024 21:33, Volodymyr Babchuk wrote:
> There are cases when previous bootloader stage leaves some seemingly
> valid value in r0, which in fact does not point to valid FDT
> blob. This behavior was encountered when trying to boot U-Boot as
> "hyp" loader on SA8155P-ADP.
> 
> To be sure that we really got the pointer to a device tree we need to
> validate it with fdt_check_header() function.
> 
> Note: This approach is not 100% fool-proof, as get_prev_bl_fdt_addr()
> theoretically can return a pointer to a region that is not physically
> mapped and we will get data abort exception when fdt_check_header()
> will try to access it. But at this early boot stage we don't know
> where RAM is anyways so there is little we can do.
> 
> Signed-off-by: Volodymyr Babchuk <volodymyr_babchuk@epam.com>
> Reviewed-by: Sumit Garg <sumit.garg@linaro.org>
Reviewed-by: Caleb Connolly <caleb.connolly@linaro.org>
> 
> ---
> 
> Changes in v3:
>  - Replaced fdt_valid() with fdt_check_header()
>  - Added Sumit's R-B tag
> 
> Changes in v2:
>  - New patch in v2
> 
>  arch/arm/mach-snapdragon/board.c | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm/mach-snapdragon/board.c b/arch/arm/mach-snapdragon/board.c
> index f12f5791a1..6f762fc948 100644
> --- a/arch/arm/mach-snapdragon/board.c
> +++ b/arch/arm/mach-snapdragon/board.c
> @@ -24,6 +24,7 @@
>  #include <linux/sizes.h>
>  #include <lmb.h>
>  #include <malloc.h>
> +#include <fdt_support.h>
>  #include <usb.h>
>  #include <sort.h>
>  
> @@ -93,7 +94,9 @@ void *board_fdt_blob_setup(int *err)
>  	 * try and use the FDT built into U-Boot if there is one...
>  	 * This avoids having a hard dependency on the previous stage bootloader
>  	 */
> -	if (IS_ENABLED(CONFIG_OF_SEPARATE) && (!fdt || fdt != ALIGN(fdt, SZ_4K))) {
> +
> +	if (IS_ENABLED(CONFIG_OF_SEPARATE) && (!fdt || fdt != ALIGN(fdt, SZ_4K) ||
> +					       fdt_check_header((void *)fdt))) {
>  		debug("%s: Using built in FDT, bootloader gave us %#llx\n", __func__, fdt);
>  		return (void *)gd->fdt_blob;
>  	}

-- 
// Caleb (they/them)

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

* Re: [PATCH v3 2/4] clk: qcom: clear div mask before assigning a new divider
  2024-03-12  8:29   ` Sumit Garg
@ 2024-03-12 20:00     ` Volodymyr Babchuk
  0 siblings, 0 replies; 13+ messages in thread
From: Volodymyr Babchuk @ 2024-03-12 20:00 UTC (permalink / raw)
  To: Sumit Garg
  Cc: u-boot@lists.denx.de, Caleb Connolly, Konrad Dybcio,
	Lukasz Majewski, Neil Armstrong, Sean Anderson, Tom Rini


Hi Sumit,

Thank you for the review.

Sumit Garg <sumit.garg@linaro.org> writes:

> On Tue, 12 Mar 2024 at 03:03, Volodymyr Babchuk
> <Volodymyr_Babchuk@epam.com> wrote:
>>
>> The current behaviour does a bitwise OR of the previous and new
>> divider values, this is wrong as some bits maybe be set already. We
>
> nit: s/maybe be/maybe/
>

Oops, right. Can this be applied by the committer during the merge
process? I know that committers in other open source project do this
sometimes. Or should I post a new version?

[...]

-- 
WBR, Volodymyr

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

* Re: [PATCH v3 3/4] clk: qcom: add support for power domains uclass
  2024-03-11 21:33 ` [PATCH v3 3/4] clk: qcom: add support for power domains uclass Volodymyr Babchuk
  2024-03-12  8:31   ` Sumit Garg
  2024-03-12 18:01   ` Caleb Connolly
@ 2024-03-13 17:12   ` Caleb Connolly
  2024-03-13 17:15   ` Caleb Connolly
  3 siblings, 0 replies; 13+ messages in thread
From: Caleb Connolly @ 2024-03-13 17:12 UTC (permalink / raw)
  To: Volodymyr Babchuk, u-boot@lists.denx.de
  Cc: Konrad Dybcio, Lukasz Majewski, Neil Armstrong, Sean Anderson,
	Sumit Garg, Tom Rini

Hi Volodymyr,

On 11/03/2024 21:33, Volodymyr Babchuk wrote:
> Now sub-drivers for particular SoCs can register them as power domain
> drivers. This is needed for upcoming SM8150 support, because it needs
> to power up the Ethernet module.
> 
Thanks again for working on this.

I've been trying to rework my SDM845 USB support patches based on this,
and I've run into quite a few issues with CONFIG_POWER_DOMAIN.

Basically, it boils down to the RPM(h)PD, with no driver a bunch of
stuff breaks (including UART). I tried writing a no-op PD driver for it
but this didn't seem to work super well, and wouldn't scale (every soc
has it's own rpm(h)pd compatible).

In the end, I think supporting CONFIG_POWER_DOMAIN is the right approach
here. I have been able to get things working by leveraging OF_LIVE and
modifying the livetree during boot, similarly to how I plan to do for
USB. See [1].

Even with this, all the drivers we probe pre-relocation (like UART) need
the DM_FLAG_DEFAULT_PD_CTRL_OFF flag if they reference the RPM(h)PD, as
the of_fixup stuff doesn't happen until after relocation. I have a patch
which fixes that for sdm845 here [2].

I'll test this on the other boards and then re-send my USB patches
(including the two below) rebased on your series.

I'm a little worried this might come back to bite us later, but I think
by then it'll be worth trying to find a way to have U-Boot handle these
"safe to ignore" devices directly.

[1]:
https://source.denx.de/u-boot/custodians/u-boot-snapdragon/-/commit/8af7731445721adab2206839d6df2d0f4f5f32d9
[2]:
https://source.denx.de/u-boot/custodians/u-boot-snapdragon/-/commit/33b094103fb7e856cff6c08345a16ef8231ffaea
> Signed-off-by: Volodymyr Babchuk <volodymyr_babchuk@epam.com>
> 
> ---
> Caleb suggested to use "imply POWER_DOMAIN", not "depends
> POWER_DOMAIN" in the Kconfig, but this does not work:
> $ make CROSS_COMPILE=aarch64-linux-gnu- ARCH=arm
> scripts/kconfig/conf  --syncconfig Kconfig
> drivers/clk/Kconfig:3:error: recursive dependency detected!
> drivers/clk/Kconfig:3:  symbol CLK is selected by IMX8M_POWER_DOMAIN
> drivers/power/domain/Kconfig:35:        symbol IMX8M_POWER_DOMAIN depends on POWER_DOMAIN
> drivers/power/domain/Kconfig:3: symbol POWER_DOMAIN is implied by CLK_QCOM
> drivers/clk/qcom/Kconfig:3:     symbol CLK_QCOM depends on CLK
> For a resolution refer to Documentation/kbuild/kconfig-language.txt
> subsection "Kconfig recursive dependency limitations"
> 
> 
> Changes in v3:
>  - Added "depends POWER_DOMAIN" to Kconfig (see note)
>  - Use readl_poll_timeout() instead of open coded wait loop
>  - Print warning if power domain can't be enabled/disabled
> 
> Changes in v2:
>  - Reworked qcom_cc_bind() function
>  - Added timeout to qcom_power_set()
>  - Minor fixes in register names and formatting
> 
>  drivers/clk/qcom/Kconfig      |   2 +-
>  drivers/clk/qcom/clock-qcom.c | 132 ++++++++++++++++++++++++++++++----
>  drivers/clk/qcom/clock-qcom.h |   6 ++
>  3 files changed, 126 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
> index 0df0d1881a..8dae635ac2 100644
> --- a/drivers/clk/qcom/Kconfig
> +++ b/drivers/clk/qcom/Kconfig
> @@ -2,7 +2,7 @@ if ARCH_SNAPDRAGON || ARCH_IPQ40XX
>  
>  config CLK_QCOM
>  	bool
> -	depends on CLK && DM_RESET
> +	depends on CLK && DM_RESET && POWER_DOMAIN
>  	def_bool n
>  
>  menu "Qualcomm clock drivers"
> diff --git a/drivers/clk/qcom/clock-qcom.c b/drivers/clk/qcom/clock-qcom.c
> index 729d190c54..7a5938a06a 100644
> --- a/drivers/clk/qcom/clock-qcom.c
> +++ b/drivers/clk/qcom/clock-qcom.c
> @@ -22,7 +22,9 @@
>  #include <linux/bug.h>
>  #include <linux/delay.h>
>  #include <linux/bitops.h>
> +#include <linux/iopoll.h>
>  #include <reset-uclass.h>
> +#include <power-domain-uclass.h>
>  
>  #include "clock-qcom.h"
>  
> @@ -30,6 +32,13 @@
>  #define CBCR_BRANCH_ENABLE_BIT  BIT(0)
>  #define CBCR_BRANCH_OFF_BIT     BIT(31)
>  
> +#define GDSC_SW_COLLAPSE_MASK		BIT(0)
> +#define GDSC_POWER_DOWN_COMPLETE	BIT(15)
> +#define GDSC_POWER_UP_COMPLETE		BIT(16)
> +#define GDSC_PWR_ON_MASK		BIT(31)
> +#define CFG_GDSCR_OFFSET		0x4
> +#define GDSC_STATUS_POLL_TIMEOUT_US	1500
> +
>  /* Enable clock controlled by CBC soft macro */
>  void clk_enable_cbc(phys_addr_t cbcr)
>  {
> @@ -223,7 +232,7 @@ U_BOOT_DRIVER(qcom_clk) = {
>  int qcom_cc_bind(struct udevice *parent)
>  {
>  	struct msm_clk_data *data = (struct msm_clk_data *)dev_get_driver_data(parent);
> -	struct udevice *clkdev, *rstdev;
> +	struct udevice *clkdev = NULL, *rstdev = NULL, *pwrdev;
>  	struct driver *drv;
>  	int ret;
>  
> @@ -238,20 +247,41 @@ int qcom_cc_bind(struct udevice *parent)
>  	if (ret)
>  		return ret;
>  
> -	/* Bail out early if resets are not specified for this platform */
> -	if (!data->resets)
> -		return ret;
> +	if (data->resets) {
> +		/* Get a handle to the common reset handler */
> +		drv = lists_driver_lookup_name("qcom_reset");
> +		if (!drv) {
> +			ret = -ENOENT;
> +			goto unbind_clkdev;
> +		}
> +
> +		/* Register the reset controller */
> +		ret = device_bind_with_driver_data(parent, drv, "qcom_reset", (ulong)data,
> +						   dev_ofnode(parent), &rstdev);
> +		if (ret)
> +			goto unbind_clkdev;
> +	}
>  
> -	/* Get a handle to the common reset handler */
> -	drv = lists_driver_lookup_name("qcom_reset");
> -	if (!drv)
> -		return -ENOENT;
> +	if (data->power_domains) {
> +		/* Get a handle to the common power domain handler */
> +		drv = lists_driver_lookup_name("qcom_power");
> +		if (!drv) {
> +			ret = -ENOENT;
> +			goto unbind_rstdev;
> +		}
> +		/* Register the power domain controller */
> +		ret = device_bind_with_driver_data(parent, drv, "qcom_power", (ulong)data,
> +						   dev_ofnode(parent), &pwrdev);
> +		if (ret)
> +			goto unbind_rstdev;
> +	}
>  
> -	/* Register the reset controller */
> -	ret = device_bind_with_driver_data(parent, drv, "qcom_reset", (ulong)data,
> -					   dev_ofnode(parent), &rstdev);
> -	if (ret)
> -		device_unbind(clkdev);
> +	return 0;
> +
> +unbind_rstdev:
> +	device_unbind(rstdev);
> +unbind_clkdev:
> +	device_unbind(clkdev);
>  
>  	return ret;
>  }
> @@ -306,3 +336,79 @@ U_BOOT_DRIVER(qcom_reset) = {
>  	.ops = &qcom_reset_ops,
>  	.probe = qcom_reset_probe,
>  };
> +
> +static int qcom_power_set(struct power_domain *pwr, bool on)
> +{
> +	struct msm_clk_data *data = (struct msm_clk_data *)dev_get_driver_data(pwr->dev);
> +	void __iomem *base = dev_get_priv(pwr->dev);
> +	const struct qcom_power_map *map;
> +	u32 value;
> +	int ret;
> +
> +	if (pwr->id >= data->num_power_domains)
> +		return -ENODEV;
> +
> +	map = &data->power_domains[pwr->id];
> +
> +	if (!map->reg)
> +		return -ENODEV;
> +
> +	value = readl(base + map->reg);
> +
> +	if (on)
> +		value &= ~GDSC_SW_COLLAPSE_MASK;
> +	else
> +		value |= GDSC_SW_COLLAPSE_MASK;
> +
> +	writel(value, base + map->reg);
> +
> +	if (on)
> +		ret = readl_poll_timeout(base + map->reg + CFG_GDSCR_OFFSET,
> +					 value,
> +					 (value & GDSC_POWER_UP_COMPLETE) ||
> +					 (value & GDSC_PWR_ON_MASK),
> +					 GDSC_STATUS_POLL_TIMEOUT_US);
> +
> +	else
> +		ret = readl_poll_timeout(base + map->reg + CFG_GDSCR_OFFSET,
> +					 value,
> +					 (value & GDSC_POWER_DOWN_COMPLETE) ||
> +					 !(value & GDSC_PWR_ON_MASK),
> +					 GDSC_STATUS_POLL_TIMEOUT_US);
> +
> +
> +	if (ret == -ETIMEDOUT)
> +		printf("WARNING: GDSC %lu is stuck during power on/off\n",
> +		       pwr->id);
> +	return ret;
> +}
> +
> +static int qcom_power_on(struct power_domain *pwr)
> +{
> +	return qcom_power_set(pwr, true);
> +}
> +
> +static int qcom_power_off(struct power_domain *pwr)
> +{
> +	return qcom_power_set(pwr, false);
> +}
> +
> +static const struct power_domain_ops qcom_power_ops = {
> +	.on = qcom_power_on,
> +	.off = qcom_power_off,
> +};
> +
> +static int qcom_power_probe(struct udevice *dev)
> +{
> +	/* Set our priv pointer to the base address */
> +	dev_set_priv(dev, (void *)dev_read_addr(dev));
> +
> +	return 0;
> +}
> +
> +U_BOOT_DRIVER(qcom_power) = {
> +	.name = "qcom_power",
> +	.id = UCLASS_POWER_DOMAIN,
> +	.ops = &qcom_power_ops,
> +	.probe = qcom_power_probe,
> +};
> diff --git a/drivers/clk/qcom/clock-qcom.h b/drivers/clk/qcom/clock-qcom.h
> index 01088c1901..12a1eaec2b 100644
> --- a/drivers/clk/qcom/clock-qcom.h
> +++ b/drivers/clk/qcom/clock-qcom.h
> @@ -59,9 +59,15 @@ struct qcom_reset_map {
>  	u8 bit;
>  };
>  
> +struct qcom_power_map {
> +	unsigned int reg;
> +};
> +
>  struct clk;
>  
>  struct msm_clk_data {
> +	const struct qcom_power_map	*power_domains;
> +	unsigned long			num_power_domains;
>  	const struct qcom_reset_map	*resets;
>  	unsigned long			num_resets;
>  	const struct gate_clk		*clks;

-- 
// Caleb (they/them)

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

* Re: [PATCH v3 3/4] clk: qcom: add support for power domains uclass
  2024-03-11 21:33 ` [PATCH v3 3/4] clk: qcom: add support for power domains uclass Volodymyr Babchuk
                     ` (2 preceding siblings ...)
  2024-03-13 17:12   ` Caleb Connolly
@ 2024-03-13 17:15   ` Caleb Connolly
  3 siblings, 0 replies; 13+ messages in thread
From: Caleb Connolly @ 2024-03-13 17:15 UTC (permalink / raw)
  To: Volodymyr Babchuk, u-boot@lists.denx.de
  Cc: Konrad Dybcio, Lukasz Majewski, Neil Armstrong, Sean Anderson,
	Sumit Garg, Tom Rini



On 11/03/2024 21:33, Volodymyr Babchuk wrote:
> Now sub-drivers for particular SoCs can register them as power domain
> drivers. This is needed for upcoming SM8150 support, because it needs
> to power up the Ethernet module.
> 
> Signed-off-by: Volodymyr Babchuk <volodymyr_babchuk@epam.com>
> 
> ---
> Caleb suggested to use "imply POWER_DOMAIN", not "depends
> POWER_DOMAIN" in the Kconfig, but this does not work:
> $ make CROSS_COMPILE=aarch64-linux-gnu- ARCH=arm
> scripts/kconfig/conf  --syncconfig Kconfig
> drivers/clk/Kconfig:3:error: recursive dependency detected!
> drivers/clk/Kconfig:3:  symbol CLK is selected by IMX8M_POWER_DOMAIN
> drivers/power/domain/Kconfig:35:        symbol IMX8M_POWER_DOMAIN depends on POWER_DOMAIN
> drivers/power/domain/Kconfig:3: symbol POWER_DOMAIN is implied by CLK_QCOM
> drivers/clk/qcom/Kconfig:3:     symbol CLK_QCOM depends on CLK
> For a resolution refer to Documentation/kbuild/kconfig-language.txt
> subsection "Kconfig recursive dependency limitations"
> 
> 
> Changes in v3:
>  - Added "depends POWER_DOMAIN" to Kconfig (see note)
>  - Use readl_poll_timeout() instead of open coded wait loop
>  - Print warning if power domain can't be enabled/disabled
> 
> Changes in v2:
>  - Reworked qcom_cc_bind() function
>  - Added timeout to qcom_power_set()
>  - Minor fixes in register names and formatting
> 
>  drivers/clk/qcom/Kconfig      |   2 +-
>  drivers/clk/qcom/clock-qcom.c | 132 ++++++++++++++++++++++++++++++----
>  drivers/clk/qcom/clock-qcom.h |   6 ++
>  3 files changed, 126 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
> index 0df0d1881a..8dae635ac2 100644
> --- a/drivers/clk/qcom/Kconfig
> +++ b/drivers/clk/qcom/Kconfig
> @@ -2,7 +2,7 @@ if ARCH_SNAPDRAGON || ARCH_IPQ40XX
>  
>  config CLK_QCOM
>  	bool
> -	depends on CLK && DM_RESET
> +	depends on CLK && DM_RESET && POWER_DOMAIN

This results in a similar dependency error to the one above unless
CONFIG_POWER_DOMAIN is enabled in the defconfig. I think we'll just add
"select POWER_DOMAIN" to ARCH_SNAPDRAGON, same as we have for DM_RESET.

I'll do then when picking this series up, just a note to self.
>  	def_bool n
>  
>  menu "Qualcomm clock drivers"
> diff --git a/drivers/clk/qcom/clock-qcom.c b/drivers/clk/qcom/clock-qcom.c
> index 729d190c54..7a5938a06a 100644
> --- a/drivers/clk/qcom/clock-qcom.c
> +++ b/drivers/clk/qcom/clock-qcom.c
> @@ -22,7 +22,9 @@
>  #include <linux/bug.h>
>  #include <linux/delay.h>
>  #include <linux/bitops.h>
> +#include <linux/iopoll.h>
>  #include <reset-uclass.h>
> +#include <power-domain-uclass.h>
>  
>  #include "clock-qcom.h"
>  
> @@ -30,6 +32,13 @@
>  #define CBCR_BRANCH_ENABLE_BIT  BIT(0)
>  #define CBCR_BRANCH_OFF_BIT     BIT(31)
>  
> +#define GDSC_SW_COLLAPSE_MASK		BIT(0)
> +#define GDSC_POWER_DOWN_COMPLETE	BIT(15)
> +#define GDSC_POWER_UP_COMPLETE		BIT(16)
> +#define GDSC_PWR_ON_MASK		BIT(31)
> +#define CFG_GDSCR_OFFSET		0x4
> +#define GDSC_STATUS_POLL_TIMEOUT_US	1500
> +
>  /* Enable clock controlled by CBC soft macro */
>  void clk_enable_cbc(phys_addr_t cbcr)
>  {
> @@ -223,7 +232,7 @@ U_BOOT_DRIVER(qcom_clk) = {
>  int qcom_cc_bind(struct udevice *parent)
>  {
>  	struct msm_clk_data *data = (struct msm_clk_data *)dev_get_driver_data(parent);
> -	struct udevice *clkdev, *rstdev;
> +	struct udevice *clkdev = NULL, *rstdev = NULL, *pwrdev;
>  	struct driver *drv;
>  	int ret;
>  
> @@ -238,20 +247,41 @@ int qcom_cc_bind(struct udevice *parent)
>  	if (ret)
>  		return ret;
>  
> -	/* Bail out early if resets are not specified for this platform */
> -	if (!data->resets)
> -		return ret;
> +	if (data->resets) {
> +		/* Get a handle to the common reset handler */
> +		drv = lists_driver_lookup_name("qcom_reset");
> +		if (!drv) {
> +			ret = -ENOENT;
> +			goto unbind_clkdev;
> +		}
> +
> +		/* Register the reset controller */
> +		ret = device_bind_with_driver_data(parent, drv, "qcom_reset", (ulong)data,
> +						   dev_ofnode(parent), &rstdev);
> +		if (ret)
> +			goto unbind_clkdev;
> +	}
>  
> -	/* Get a handle to the common reset handler */
> -	drv = lists_driver_lookup_name("qcom_reset");
> -	if (!drv)
> -		return -ENOENT;
> +	if (data->power_domains) {
> +		/* Get a handle to the common power domain handler */
> +		drv = lists_driver_lookup_name("qcom_power");
> +		if (!drv) {
> +			ret = -ENOENT;
> +			goto unbind_rstdev;
> +		}
> +		/* Register the power domain controller */
> +		ret = device_bind_with_driver_data(parent, drv, "qcom_power", (ulong)data,
> +						   dev_ofnode(parent), &pwrdev);
> +		if (ret)
> +			goto unbind_rstdev;
> +	}
>  
> -	/* Register the reset controller */
> -	ret = device_bind_with_driver_data(parent, drv, "qcom_reset", (ulong)data,
> -					   dev_ofnode(parent), &rstdev);
> -	if (ret)
> -		device_unbind(clkdev);
> +	return 0;
> +
> +unbind_rstdev:
> +	device_unbind(rstdev);
> +unbind_clkdev:
> +	device_unbind(clkdev);
>  
>  	return ret;
>  }
> @@ -306,3 +336,79 @@ U_BOOT_DRIVER(qcom_reset) = {
>  	.ops = &qcom_reset_ops,
>  	.probe = qcom_reset_probe,
>  };
> +
> +static int qcom_power_set(struct power_domain *pwr, bool on)
> +{
> +	struct msm_clk_data *data = (struct msm_clk_data *)dev_get_driver_data(pwr->dev);
> +	void __iomem *base = dev_get_priv(pwr->dev);
> +	const struct qcom_power_map *map;
> +	u32 value;
> +	int ret;
> +
> +	if (pwr->id >= data->num_power_domains)
> +		return -ENODEV;
> +
> +	map = &data->power_domains[pwr->id];
> +
> +	if (!map->reg)
> +		return -ENODEV;
> +
> +	value = readl(base + map->reg);
> +
> +	if (on)
> +		value &= ~GDSC_SW_COLLAPSE_MASK;
> +	else
> +		value |= GDSC_SW_COLLAPSE_MASK;
> +
> +	writel(value, base + map->reg);
> +
> +	if (on)
> +		ret = readl_poll_timeout(base + map->reg + CFG_GDSCR_OFFSET,
> +					 value,
> +					 (value & GDSC_POWER_UP_COMPLETE) ||
> +					 (value & GDSC_PWR_ON_MASK),
> +					 GDSC_STATUS_POLL_TIMEOUT_US);
> +
> +	else
> +		ret = readl_poll_timeout(base + map->reg + CFG_GDSCR_OFFSET,
> +					 value,
> +					 (value & GDSC_POWER_DOWN_COMPLETE) ||
> +					 !(value & GDSC_PWR_ON_MASK),
> +					 GDSC_STATUS_POLL_TIMEOUT_US);
> +
> +
> +	if (ret == -ETIMEDOUT)
> +		printf("WARNING: GDSC %lu is stuck during power on/off\n",
> +		       pwr->id);
> +	return ret;
> +}
> +
> +static int qcom_power_on(struct power_domain *pwr)
> +{
> +	return qcom_power_set(pwr, true);
> +}
> +
> +static int qcom_power_off(struct power_domain *pwr)
> +{
> +	return qcom_power_set(pwr, false);
> +}
> +
> +static const struct power_domain_ops qcom_power_ops = {
> +	.on = qcom_power_on,
> +	.off = qcom_power_off,
> +};
> +
> +static int qcom_power_probe(struct udevice *dev)
> +{
> +	/* Set our priv pointer to the base address */
> +	dev_set_priv(dev, (void *)dev_read_addr(dev));
> +
> +	return 0;
> +}
> +
> +U_BOOT_DRIVER(qcom_power) = {
> +	.name = "qcom_power",
> +	.id = UCLASS_POWER_DOMAIN,
> +	.ops = &qcom_power_ops,
> +	.probe = qcom_power_probe,
> +};
> diff --git a/drivers/clk/qcom/clock-qcom.h b/drivers/clk/qcom/clock-qcom.h
> index 01088c1901..12a1eaec2b 100644
> --- a/drivers/clk/qcom/clock-qcom.h
> +++ b/drivers/clk/qcom/clock-qcom.h
> @@ -59,9 +59,15 @@ struct qcom_reset_map {
>  	u8 bit;
>  };
>  
> +struct qcom_power_map {
> +	unsigned int reg;
> +};
> +
>  struct clk;
>  
>  struct msm_clk_data {
> +	const struct qcom_power_map	*power_domains;
> +	unsigned long			num_power_domains;
>  	const struct qcom_reset_map	*resets;
>  	unsigned long			num_resets;
>  	const struct gate_clk		*clks;

-- 
// Caleb (they/them)

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

* Re: [PATCH v3 0/4]
  2024-03-11 21:33 [PATCH v3 0/4] Volodymyr Babchuk
                   ` (3 preceding siblings ...)
  2024-03-11 21:33 ` [PATCH v3 4/4] pinctrl: qcom: pass pin number to get_function_mux callback Volodymyr Babchuk
@ 2024-03-19 12:39 ` Caleb Connolly
  4 siblings, 0 replies; 13+ messages in thread
From: Caleb Connolly @ 2024-03-19 12:39 UTC (permalink / raw)
  To: u-boot, Volodymyr Babchuk
  Cc: Caleb Connolly, Konrad Dybcio, Lukasz Majewski, Neil Armstrong,
	Sean Anderson, Sumit Garg, Tom Rini


On Mon, 11 Mar 2024 21:33:44 +0000, Volodymyr Babchuk wrote:
> Set of pre-req patches for Qualcomm SA8155P-ADP board support.
> 
> This path series consist of generic qcom changes that may benefit
> different boards. It is the part of the bigger series that adds
> SA8155P-ADP support, but I am posting this limited set because there
> are other developers who depend on those changes and I am not ready to
> post other patches of the bigger series.
> 
> [...]

Applied, thanks!

[1/4] qcom: board: validate fdt before trying to use it
      commit: a1ecfa2371efc68671c66d3e186743f82926a640
[2/4] clk: qcom: clear div mask before assigning a new divider
      commit: 10f402108a9063d5bc4d517e2a1197afcfabc3a4
[3/4] clk: qcom: add support for power domains uclass
      commit: 95d76bf4e9a912ee458726a59b1045ecb2eff0cc
[4/4] pinctrl: qcom: pass pin number to get_function_mux callback
      commit: 018b8ab702ce38f79e7d276186565478513880a6

Best regards,
-- 
// Caleb (they/them)


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

end of thread, other threads:[~2024-03-19 12:39 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-03-11 21:33 [PATCH v3 0/4] Volodymyr Babchuk
2024-03-11 21:33 ` [PATCH v3 3/4] clk: qcom: add support for power domains uclass Volodymyr Babchuk
2024-03-12  8:31   ` Sumit Garg
2024-03-12 18:01   ` Caleb Connolly
2024-03-13 17:12   ` Caleb Connolly
2024-03-13 17:15   ` Caleb Connolly
2024-03-11 21:33 ` [PATCH v3 1/4] qcom: board: validate fdt before trying to use it Volodymyr Babchuk
2024-03-12 18:02   ` Caleb Connolly
2024-03-11 21:33 ` [PATCH v3 2/4] clk: qcom: clear div mask before assigning a new divider Volodymyr Babchuk
2024-03-12  8:29   ` Sumit Garg
2024-03-12 20:00     ` Volodymyr Babchuk
2024-03-11 21:33 ` [PATCH v3 4/4] pinctrl: qcom: pass pin number to get_function_mux callback Volodymyr Babchuk
2024-03-19 12:39 ` [PATCH v3 0/4] Caleb Connolly

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.