diff mbox series

[v4,3/6] PCI: brcmstb: Add control of slot0 device voltage regulators

Message ID 20210401212148.47033-4-jim2101024@gmail.com (mailing list archive)
State New, archived
Headers show
Series PCI: brcmstb: add slot0 device regulators and panic handler | expand

Commit Message

Jim Quinlan April 1, 2021, 9:21 p.m. UTC
This Broadcom STB has one port and connects directly to one device, be it a
switch or an endpoint.  We want to be able to turn on/off any regulators
for that device.  Control of regulators is needed because of the
chicken-and-egg situation: although the regulator is "owned" by the device
and would be best handled by its driver, the device cannot be discovered
and probed unless its regulator is already turned on.

Signed-off-by: Jim Quinlan <jim2101024@gmail.com>
---
 drivers/pci/controller/pcie-brcmstb.c | 83 +++++++++++++++++++++++++--
 1 file changed, 78 insertions(+), 5 deletions(-)

Comments

Mark Brown April 6, 2021, 4:34 p.m. UTC | #1
On Thu, Apr 01, 2021 at 05:21:43PM -0400, Jim Quinlan wrote:

> +	/* Look for specific pcie regulators in the RC DT node. */
> +	for_each_property_of_node(np, pp) {
> +		for (i = 0; i < ns; i++)
> +			if (strcmp(supplies[i], pp->name) == 0)

This is broken, the driver knows which supplies are expected, the device
can't function without these supplies so the driver should just
unconditionally request them like any other supply.
Jim Quinlan April 6, 2021, 4:59 p.m. UTC | #2
On Tue, Apr 6, 2021 at 12:34 PM Mark Brown <broonie@kernel.org> wrote:
>
> On Thu, Apr 01, 2021 at 05:21:43PM -0400, Jim Quinlan wrote:
>
> > +     /* Look for specific pcie regulators in the RC DT node. */
> > +     for_each_property_of_node(np, pp) {
> > +             for (i = 0; i < ns; i++)
> > +                     if (strcmp(supplies[i], pp->name) == 0)
>
> This is broken, the driver knows which supplies are expected, the device
> can't function without these supplies so the driver should just
> unconditionally request them like any other supply.

Hi  Mark,
Some boards require the regulators, some do not.  So the driver is
only  sure what the names may be if they are present.  If  I put these
names in my struct regulator_bulk_data array and do a
devm_regulator_bulk_get(), I will get the following for the boards
that do not need the regulators (e.g. the RPi SOC):

[    6.823820] brcm-pcie xxx.pcie: supply vpcie12v-supply not found,
using dummy regulator
[    6.832265] brcm-pcie xxx.pcie: supply vpcie3v3-supply not found,
using dummy regulator

IIRC you consider this a debug feature?  Be that as it may, these
lines will confuse our customers and I'd like that they not be printed
if possible.

So I ask you to allow the code as is.  If you still insist, I will
change and resubmit.

Regards,
Jim Quinlan
Broadcom STB
Mark Brown April 6, 2021, 5:23 p.m. UTC | #3
On Tue, Apr 06, 2021 at 12:59:16PM -0400, Jim Quinlan wrote:
> On Tue, Apr 6, 2021 at 12:34 PM Mark Brown <broonie@kernel.org> wrote:
> > On Thu, Apr 01, 2021 at 05:21:43PM -0400, Jim Quinlan wrote:

> > This is broken, the driver knows which supplies are expected, the device
> > can't function without these supplies so the driver should just
> > unconditionally request them like any other supply.

> Some boards require the regulators, some do not.  So the driver is

No, some boards have the supplies described in firmware and some do not.

> only  sure what the names may be if they are present.  If  I put these
> names in my struct regulator_bulk_data array and do a
> devm_regulator_bulk_get(), I will get the following for the boards
> that do not need the regulators (e.g. the RPi SOC):
> 
> [    6.823820] brcm-pcie xxx.pcie: supply vpcie12v-supply not found,
> using dummy regulator
> [    6.832265] brcm-pcie xxx.pcie: supply vpcie3v3-supply not found,
> using dummy regulator

Sure, those are just warnings.

> IIRC you consider this a debug feature?  Be that as it may, these
> lines will confuse our customers and I'd like that they not be printed
> if possible.

You can stop the warnings by updating your firmware to more completely
describe the system - ideally all the supplies in the system would be
described for future proofing.  Or if this is a custom software stack
just delete whatever error checking and warnings you like.  The warnings
are there in case we've not got something mapped properly (eg, if there
were a typo in a property name) and things stop working, it's not great
to just ignore errors.

> So I ask you to allow the code as is.  If you still insist, I will
> change and resubmit.

Remove it, conditional code like this is just as bad in this driver as
it is in every other one.
Jim Quinlan April 6, 2021, 5:29 p.m. UTC | #4
On Tue, Apr 6, 2021 at 1:23 PM Mark Brown <broonie@kernel.org> wrote:
>
> On Tue, Apr 06, 2021 at 12:59:16PM -0400, Jim Quinlan wrote:
> > On Tue, Apr 6, 2021 at 12:34 PM Mark Brown <broonie@kernel.org> wrote:
> > > On Thu, Apr 01, 2021 at 05:21:43PM -0400, Jim Quinlan wrote:
>
> > > This is broken, the driver knows which supplies are expected, the device
> > > can't function without these supplies so the driver should just
> > > unconditionally request them like any other supply.
>
> > Some boards require the regulators, some do not.  So the driver is
>
> No, some boards have the supplies described in firmware and some do not.
True.
>
> > only  sure what the names may be if they are present.  If  I put these
> > names in my struct regulator_bulk_data array and do a
> > devm_regulator_bulk_get(), I will get the following for the boards
> > that do not need the regulators (e.g. the RPi SOC):
> >
> > [    6.823820] brcm-pcie xxx.pcie: supply vpcie12v-supply not found,
> > using dummy regulator
> > [    6.832265] brcm-pcie xxx.pcie: supply vpcie3v3-supply not found,
> > using dummy regulator
>
> Sure, those are just warnings.
>
> > IIRC you consider this a debug feature?  Be that as it may, these
> > lines will confuse our customers and I'd like that they not be printed
> > if possible.
>
> You can stop the warnings by updating your firmware to more completely
> describe the system - ideally all the supplies in the system would be
> described for future proofing.  Or if this is a custom software stack
> just delete whatever error checking and warnings you like.  The warnings
> are there in case we've not got something mapped properly (eg, if there
> were a typo in a property name) and things stop working, it's not great
> to just ignore errors.
A lot of this is really not under our control.
>
> > So I ask you to allow the code as is.  If you still insist, I will
> > change and resubmit.
>
> Remove it, conditional code like this is just as bad in this driver as
> it is in every other one.
I will remove this and resubmit.
Thanks,
Jim Quinlan
Broadcom STB
diff mbox series

Patch

diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c
index 4ce1f3a60574..1b0de0c7da60 100644
--- a/drivers/pci/controller/pcie-brcmstb.c
+++ b/drivers/pci/controller/pcie-brcmstb.c
@@ -24,6 +24,7 @@ 
 #include <linux/pci.h>
 #include <linux/pci-ecam.h>
 #include <linux/printk.h>
+#include <linux/regulator/consumer.h>
 #include <linux/reset.h>
 #include <linux/sizes.h>
 #include <linux/slab.h>
@@ -169,6 +170,7 @@ 
 #define SSC_STATUS_SSC_MASK		0x400
 #define SSC_STATUS_PLL_LOCK_MASK	0x800
 #define PCIE_BRCM_MAX_MEMC		3
+#define PCIE_BRCM_MAX_EP_REGULATORS	4
 
 #define IDX_ADDR(pcie)			(pcie->reg_offsets[EXT_CFG_INDEX])
 #define DATA_ADDR(pcie)			(pcie->reg_offsets[EXT_CFG_DATA])
@@ -192,6 +194,11 @@  static inline void brcm_pcie_perst_set_4908(struct brcm_pcie *pcie, u32 val);
 static inline void brcm_pcie_perst_set_7278(struct brcm_pcie *pcie, u32 val);
 static inline void brcm_pcie_perst_set_generic(struct brcm_pcie *pcie, u32 val);
 
+static const char * const supplies[] = {
+	"vpcie12v-supply",
+	"vpcie3v3-supply",
+};
+
 enum {
 	RGR1_SW_INIT_1,
 	EXT_CFG_INDEX,
@@ -295,8 +302,27 @@  struct brcm_pcie {
 	u32			hw_rev;
 	void			(*perst_set)(struct brcm_pcie *pcie, u32 val);
 	void			(*bridge_sw_init_set)(struct brcm_pcie *pcie, u32 val);
+	struct regulator_bulk_data supplies[PCIE_BRCM_MAX_EP_REGULATORS];
+	unsigned int		num_supplies;
 };
 
+static int brcm_set_regulators(struct brcm_pcie *pcie, bool on)
+{
+	struct device *dev = pcie->dev;
+	int ret;
+
+	if (!pcie->num_supplies)
+		return 0;
+	if (on)
+		ret = regulator_bulk_enable(pcie->num_supplies, pcie->supplies);
+	else
+		ret = regulator_bulk_disable(pcie->num_supplies, pcie->supplies);
+	if (ret)
+		dev_err(dev, "failed to %s EP regulators\n",
+			on ? "enable" : "disable");
+	return ret;
+}
+
 /*
  * This is to convert the size of the inbound "BAR" region to the
  * non-linear values of PCIE_X_MISC_RC_BAR[123]_CONFIG_LO.SIZE
@@ -1112,9 +1138,10 @@  static inline int brcm_phy_start(struct brcm_pcie *pcie)
 	return pcie->rescal ? brcm_phy_cntl(pcie, 1) : 0;
 }
 
-static inline int brcm_phy_stop(struct brcm_pcie *pcie)
+static inline void brcm_phy_stop(struct brcm_pcie *pcie)
 {
-	return pcie->rescal ? brcm_phy_cntl(pcie, 0) : 0;
+	if (pcie->rescal)
+		brcm_phy_cntl(pcie, 0);
 }
 
 static void brcm_pcie_turn_off(struct brcm_pcie *pcie)
@@ -1141,16 +1168,45 @@  static void brcm_pcie_turn_off(struct brcm_pcie *pcie)
 	pcie->bridge_sw_init_set(pcie, 1);
 }
 
+static int brcm_pcie_get_regulators(struct brcm_pcie *pcie)
+{
+	struct device_node *np = pcie->np;
+	struct property *pp;
+	const unsigned int ns = ARRAY_SIZE(supplies);
+	unsigned int i;
+	int ret = 0;
+
+	/* Look for specific pcie regulators in the RC DT node. */
+	for_each_property_of_node(np, pp) {
+		for (i = 0; i < ns; i++)
+			if (strcmp(supplies[i], pp->name) == 0)
+				break;
+		if (i >= ns)
+			continue;
+
+		if (pcie->num_supplies < PCIE_BRCM_MAX_EP_REGULATORS)
+			pcie->supplies[pcie->num_supplies++].supply
+				= supplies[i];
+		else
+			dev_warn(pcie->dev, "No room for supply %s\n",
+				 supplies[i]);
+	}
+
+	if (pcie->num_supplies)
+		ret = devm_regulator_bulk_get(pcie->dev, pcie->num_supplies,
+					      pcie->supplies);
+	return ret;
+}
+
 static int brcm_pcie_suspend(struct device *dev)
 {
 	struct brcm_pcie *pcie = dev_get_drvdata(dev);
-	int ret;
 
 	brcm_pcie_turn_off(pcie);
-	ret = brcm_phy_stop(pcie);
+	brcm_phy_stop(pcie);
 	clk_disable_unprepare(pcie->clk);
 
-	return ret;
+	return brcm_set_regulators(pcie, false);
 }
 
 static int brcm_pcie_resume(struct device *dev)
@@ -1165,6 +1221,10 @@  static int brcm_pcie_resume(struct device *dev)
 	if (ret)
 		return ret;
 
+	ret = brcm_set_regulators(pcie, true);
+	if (ret)
+		return ret;
+
 	ret = brcm_phy_start(pcie);
 	if (ret)
 		goto err;
@@ -1201,6 +1261,7 @@  static void __brcm_pcie_remove(struct brcm_pcie *pcie)
 	brcm_phy_stop(pcie);
 	reset_control_assert(pcie->rescal);
 	clk_disable_unprepare(pcie->clk);
+	brcm_set_regulators(pcie, false);
 }
 
 static int brcm_pcie_remove(struct platform_device *pdev)
@@ -1291,6 +1352,18 @@  static int brcm_pcie_probe(struct platform_device *pdev)
 		return ret;
 	}
 
+	ret = brcm_pcie_get_regulators(pcie);
+	if (ret) {
+		pcie->num_supplies = 0;
+		if (ret != -EPROBE_DEFER)
+			dev_err(pcie->dev, "failed to get regulators (err=%d)\n", ret);
+		goto fail;
+	}
+
+	ret = brcm_set_regulators(pcie, true);
+	if (ret)
+		goto fail;
+
 	ret = brcm_pcie_setup(pcie);
 	if (ret)
 		goto fail;