mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 00/21] PCIe support for i.MX7
@ 2019-01-09  7:11 Andrey Smirnov
  2019-01-09  7:11 ` [PATCH 01/21] regulator: Convert drivers to use struct regulator_desc Andrey Smirnov
                   ` (20 more replies)
  0 siblings, 21 replies; 27+ messages in thread
From: Andrey Smirnov @ 2019-01-09  7:11 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Everyone:

This seires is a build-up on previously submitted PCI sync set [1] and
contains the patches I created while working on adding support for
PCIe on i.MX7. The series consists of following:

 - Patches adding necessary regulator pluming to support porint ANATOP
   driver

 - ANATOP driver port

 - Port of basic power domain infrastructure from Linux kernel needed
   for controlling GPCv2 (useful for both i.MX7 and, especially, for
   i.MX8MQ)

 - Port of GPCv2 driver from Linux as well as of some bug fixes for it

 - Port of i.MX7 reset controller driver

 - Patches adding support for i.MX7 to existing i.MX6 PCIe host
   controller driver

 - Misc fixes

This series has been tested on i.MX7D SabreSD board against Toshiba
NVMe device.

Feedback is welcome!

Thanks,
Andrey Smirnov

[1] http://lists.infradead.org/pipermail/barebox/2018-December/036005.html

Andrey Smirnov (21):
  regulator: Convert drivers to use struct regulator_desc
  regulator: Port basic regmap regulator functions
  regulator: Add support for setting regulator's voltage
  base: driver: Drop redundant list_empty() check
  base: Port driver_deferred_probe_check_state() from Linux
  regulator: Add primitive support for deferred probe
  regulator: Port ANATOP driver from Linux
  drivers: base: Port power management code from Linux
  soc: imx: Add GPCv2 power gating driver
  soc: imx: gpcv2: fix regulator deferred probe
  soc: imx: gpcv2: correct PGC offset
  reset: Add i.MX7 SRC reset driver
  reset: imx7: Fix always writing bits as 0
  reset: Mark local functions as static
  PCI: imx6: Add code to support i.MX7D
  PCI: imx6: Allow probe deferral by reset GPIO
  PCI: imx6: Do not wait for speed change on i.MX7
  PCI: imx6: Do not switch speed if Gen2 is disabled
  PCI: imx6: Fix spelling mistake: "contol" -> "control"
  PCI: imx6: Drop unnecessary root_bus_nr setting
  PCI: imx6: Port imx6_pcie_ltssm_enable()

 arch/arm/mach-imx/Kconfig            |   1 +
 drivers/Kconfig                      |   2 +
 drivers/Makefile                     |   1 +
 drivers/base/Kconfig                 |   3 +
 drivers/base/Makefile                |   4 +-
 drivers/base/driver.c                |  68 ++++--
 drivers/base/platform.c              |   7 +
 drivers/base/power.c                 | 245 +++++++++++++++++++++
 drivers/pci/Kconfig                  |   4 +-
 drivers/pci/pci-imx6.c               | 245 +++++++++++++++------
 drivers/regulator/Kconfig            |   8 +
 drivers/regulator/Makefile           |   5 +-
 drivers/regulator/anatop-regulator.c | 161 ++++++++++++++
 drivers/regulator/bcm2835.c          |   6 +-
 drivers/regulator/core.c             |  60 ++++-
 drivers/regulator/fixed.c            |   6 +-
 drivers/regulator/helpers.c          | 186 ++++++++++++++++
 drivers/reset/Kconfig                |  11 +
 drivers/reset/Makefile               |   1 +
 drivers/reset/core.c                 |   8 +-
 drivers/reset/reset-imx7.c           | 151 +++++++++++++
 drivers/soc/imx/Kconfig              |   9 +
 drivers/soc/imx/Makefile             |   1 +
 drivers/soc/imx/gpcv2.c              | 315 +++++++++++++++++++++++++++
 include/driver.h                     |   2 +
 include/pm_domain.h                  |  82 +++++++
 include/regulator.h                  |  41 +++-
 27 files changed, 1524 insertions(+), 109 deletions(-)
 create mode 100644 drivers/base/Kconfig
 create mode 100644 drivers/base/power.c
 create mode 100644 drivers/regulator/anatop-regulator.c
 create mode 100644 drivers/regulator/helpers.c
 create mode 100644 drivers/reset/reset-imx7.c
 create mode 100644 drivers/soc/imx/Kconfig
 create mode 100644 drivers/soc/imx/Makefile
 create mode 100644 drivers/soc/imx/gpcv2.c
 create mode 100644 include/pm_domain.h

-- 
2.20.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 01/21] regulator: Convert drivers to use struct regulator_desc
  2019-01-09  7:11 [PATCH 00/21] PCIe support for i.MX7 Andrey Smirnov
@ 2019-01-09  7:11 ` Andrey Smirnov
  2019-01-09  7:11 ` [PATCH 02/21] regulator: Port basic regmap regulator functions Andrey Smirnov
                   ` (19 subsequent siblings)
  20 siblings, 0 replies; 27+ messages in thread
From: Andrey Smirnov @ 2019-01-09  7:11 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

To simplify porting kernel code, port a very basic struct
regulator_desc and convert all of the code to use it.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/regulator/bcm2835.c | 6 ++++--
 drivers/regulator/core.c    | 8 ++++----
 drivers/regulator/fixed.c   | 6 ++++--
 include/regulator.h         | 6 +++++-
 4 files changed, 17 insertions(+), 9 deletions(-)

diff --git a/drivers/regulator/bcm2835.c b/drivers/regulator/bcm2835.c
index 0ada05db1..ea7cf7fe1 100644
--- a/drivers/regulator/bcm2835.c
+++ b/drivers/regulator/bcm2835.c
@@ -24,6 +24,7 @@ static struct regulator_bcm2835 {
 
 	struct device_d *dev;
 	struct regulator_dev rdev;
+	struct regulator_desc rdesc;
 } regs[] = {
 	REG_DEV(BCM2835_MBOX_POWER_DEVID_SDHCI, "bcm2835_mci0"),
 	REG_DEV(BCM2835_MBOX_POWER_DEVID_UART0, "uart0-pl0110"),
@@ -108,7 +109,7 @@ static int regulator_bcm2835_is_enabled(struct regulator_dev *rdev)
 	return msg_pwr->get_power_state.body.resp.state;
 }
 
-static struct regulator_ops bcm2835_ops = {
+const static struct regulator_ops bcm2835_ops = {
 	.enable = regulator_bcm2835_enable,
 	.disable = regulator_bcm2835_disable,
 	.is_enabled = regulator_bcm2835_is_enabled,
@@ -122,7 +123,8 @@ static int regulator_bcm2835_probe(struct device_d *dev)
 	for (i = 0; i < ARRAY_SIZE(regs); i++) {
 		rb = &regs[i];
 
-		rb->rdev.ops = &bcm2835_ops;
+		rb->rdesc.ops = &bcm2835_ops;
+		rb->rdev.desc = &rb->rdesc;
 		rb->dev = dev;
 
 		ret = dev_regulator_register(&rb->rdev, rb->devname, NULL);
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 39df980dc..bcfbda62e 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -52,10 +52,10 @@ static int regulator_enable_internal(struct regulator_internal *ri)
 		return 0;
 	}
 
-	if (!ri->rdev->ops->enable)
+	if (!ri->rdev->desc->ops->enable)
 		return -ENOSYS;
 
-	ret = ri->rdev->ops->enable(ri->rdev);
+	ret = ri->rdev->desc->ops->enable(ri->rdev);
 	if (ret)
 		return ret;
 
@@ -74,10 +74,10 @@ static int regulator_disable_internal(struct regulator_internal *ri)
 	if (!ri->enable_count)
 		return -EINVAL;
 
-	if (!ri->rdev->ops->disable)
+	if (!ri->rdev->desc->ops->disable)
 		return -ENOSYS;
 
-	ret = ri->rdev->ops->disable(ri->rdev);
+	ret = ri->rdev->desc->ops->disable(ri->rdev);
 	if (ret)
 		return ret;
 
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
index 87554d22e..cb5d78581 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -29,6 +29,7 @@ struct regulator_fixed {
 	int active_low;
 	int always_on;
 	struct regulator_dev rdev;
+	struct regulator_desc rdesc;
 };
 
 static int regulator_fixed_enable(struct regulator_dev *rdev)
@@ -54,7 +55,7 @@ static int regulator_fixed_disable(struct regulator_dev *rdev)
 	return gpio_direction_output(fix->gpio, fix->active_low);
 }
 
-static struct regulator_ops fixed_ops = {
+const static struct regulator_ops fixed_ops = {
 	.enable = regulator_fixed_enable,
 	.disable = regulator_fixed_disable,
 };
@@ -82,7 +83,8 @@ static int regulator_fixed_probe(struct device_d *dev)
 			fix->active_low = 1;
 	}
 
-	fix->rdev.ops = &fixed_ops;
+	fix->rdesc.ops = &fixed_ops;
+	fix->rdev.desc = &fix->rdesc;
 
 	if (of_find_property(dev->device_node, "regulator-always-on", NULL)) {
 		fix->always_on = 1;
diff --git a/include/regulator.h b/include/regulator.h
index 367e13f05..907073607 100644
--- a/include/regulator.h
+++ b/include/regulator.h
@@ -4,8 +4,12 @@
 /* struct regulator is an opaque object for consumers */
 struct regulator;
 
+struct regulator_desc {
+	const struct regulator_ops *ops;
+};
+
 struct regulator_dev {
-	struct regulator_ops *ops;
+	const struct regulator_desc *desc;
 	int boot_on;
 };
 
-- 
2.20.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 02/21] regulator: Port basic regmap regulator functions
  2019-01-09  7:11 [PATCH 00/21] PCIe support for i.MX7 Andrey Smirnov
  2019-01-09  7:11 ` [PATCH 01/21] regulator: Convert drivers to use struct regulator_desc Andrey Smirnov
@ 2019-01-09  7:11 ` Andrey Smirnov
  2019-01-09  7:11 ` [PATCH 03/21] regulator: Add support for setting regulator's voltage Andrey Smirnov
                   ` (18 subsequent siblings)
  20 siblings, 0 replies; 27+ messages in thread
From: Andrey Smirnov @ 2019-01-09  7:11 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

In order to be able to port Linux driver relying on this API, port
various regmap related regulator function to Barebox.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/regulator/Makefile  |  2 +-
 drivers/regulator/helpers.c | 87 +++++++++++++++++++++++++++++++++++++
 include/regulator.h         | 11 ++++-
 3 files changed, 98 insertions(+), 2 deletions(-)
 create mode 100644 drivers/regulator/helpers.c

diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index ff5daf9a7..36ce3e87f 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -1,4 +1,4 @@
-obj-$(CONFIG_REGULATOR) += core.o
+obj-$(CONFIG_REGULATOR) += core.o helpers.o
 obj-$(CONFIG_REGULATOR_FIXED) += fixed.o
 obj-$(CONFIG_REGULATOR_BCM283X) += bcm2835.o
 obj-$(CONFIG_REGULATOR_PFUZE) += pfuze.o
\ No newline at end of file
diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c
new file mode 100644
index 000000000..4495b4403
--- /dev/null
+++ b/drivers/regulator/helpers.c
@@ -0,0 +1,87 @@
+#include <common.h>
+#include <regmap.h>
+#include <regulator.h>
+
+/**
+ * regulator_is_enabled_regmap - standard is_enabled() for regmap users
+ *
+ * @rdev: regulator to operate on
+ *
+ * Regulators that use regmap for their register I/O can set the
+ * enable_reg and enable_mask fields in their descriptor and then use
+ * this as their is_enabled operation, saving some code.
+ */
+int regulator_is_enabled_regmap(struct regulator_dev *rdev)
+{
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, &val);
+	if (ret != 0)
+		return ret;
+
+	val &= rdev->desc->enable_mask;
+
+	if (rdev->desc->enable_is_inverted) {
+		if (rdev->desc->enable_val)
+			return val != rdev->desc->enable_val;
+		return val == 0;
+	} else {
+		if (rdev->desc->enable_val)
+			return val == rdev->desc->enable_val;
+		return val != 0;
+	}
+}
+EXPORT_SYMBOL_GPL(regulator_is_enabled_regmap);
+
+/**
+ * regulator_enable_regmap - standard enable() for regmap users
+ *
+ * @rdev: regulator to operate on
+ *
+ * Regulators that use regmap for their register I/O can set the
+ * enable_reg and enable_mask fields in their descriptor and then use
+ * this as their enable() operation, saving some code.
+ */
+int regulator_enable_regmap(struct regulator_dev *rdev)
+{
+	unsigned int val;
+
+	if (rdev->desc->enable_is_inverted) {
+		val = rdev->desc->disable_val;
+	} else {
+		val = rdev->desc->enable_val;
+		if (!val)
+			val = rdev->desc->enable_mask;
+	}
+
+	return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+				  rdev->desc->enable_mask, val);
+}
+EXPORT_SYMBOL_GPL(regulator_enable_regmap);
+
+/**
+ * regulator_disable_regmap - standard disable() for regmap users
+ *
+ * @rdev: regulator to operate on
+ *
+ * Regulators that use regmap for their register I/O can set the
+ * enable_reg and enable_mask fields in their descriptor and then use
+ * this as their disable() operation, saving some code.
+ */
+int regulator_disable_regmap(struct regulator_dev *rdev)
+{
+	unsigned int val;
+
+	if (rdev->desc->enable_is_inverted) {
+		val = rdev->desc->enable_val;
+		if (!val)
+			val = rdev->desc->enable_mask;
+	} else {
+		val = rdev->desc->disable_val;
+	}
+
+	return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+				  rdev->desc->enable_mask, val);
+}
+EXPORT_SYMBOL_GPL(regulator_disable_regmap);
diff --git a/include/regulator.h b/include/regulator.h
index 907073607..1824e6ea1 100644
--- a/include/regulator.h
+++ b/include/regulator.h
@@ -6,10 +6,17 @@ struct regulator;
 
 struct regulator_desc {
 	const struct regulator_ops *ops;
+
+	unsigned int enable_reg;
+	unsigned int enable_mask;
+	unsigned int enable_val;
+	unsigned int disable_val;
+	bool enable_is_inverted;
 };
 
 struct regulator_dev {
 	const struct regulator_desc *desc;
+	struct regmap *regmap;
 	int boot_on;
 };
 
@@ -39,7 +46,9 @@ void regulators_print(void);
 struct regulator *regulator_get(struct device_d *, const char *);
 int regulator_enable(struct regulator *);
 int regulator_disable(struct regulator *);
-
+int regulator_is_enabled_regmap(struct regulator_dev *);
+int regulator_enable_regmap(struct regulator_dev *);
+int regulator_disable_regmap(struct regulator_dev *);
 #else
 
 static inline struct regulator *regulator_get(struct device_d *dev, const char *id)
-- 
2.20.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 03/21] regulator: Add support for setting regulator's voltage
  2019-01-09  7:11 [PATCH 00/21] PCIe support for i.MX7 Andrey Smirnov
  2019-01-09  7:11 ` [PATCH 01/21] regulator: Convert drivers to use struct regulator_desc Andrey Smirnov
  2019-01-09  7:11 ` [PATCH 02/21] regulator: Port basic regmap regulator functions Andrey Smirnov
@ 2019-01-09  7:11 ` Andrey Smirnov
  2019-01-09  7:11 ` [PATCH 04/21] base: driver: Drop redundant list_empty() check Andrey Smirnov
                   ` (17 subsequent siblings)
  20 siblings, 0 replies; 27+ messages in thread
From: Andrey Smirnov @ 2019-01-09  7:11 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Add code needed to implement regulator_set_voltage(). Currently only
bare minmum needed for ANATOP driver (added in follow up commit) is
supported.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/regulator/core.c    | 44 +++++++++++++++++
 drivers/regulator/helpers.c | 99 +++++++++++++++++++++++++++++++++++++
 include/regulator.h         | 24 +++++++++
 3 files changed, 167 insertions(+)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index bcfbda62e..795dcdb8c 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -43,6 +43,15 @@ struct regulator {
 	struct device_d *dev;
 };
 
+static int regulator_map_voltage(struct regulator_dev *rdev, int min_uV,
+				 int max_uV)
+{
+	if (rdev->desc->ops->list_voltage == regulator_list_voltage_linear)
+		return regulator_map_voltage_linear(rdev, min_uV, max_uV);
+
+	return -ENOSYS;
+}
+
 static int regulator_enable_internal(struct regulator_internal *ri)
 {
 	int ret;
@@ -86,6 +95,33 @@ static int regulator_disable_internal(struct regulator_internal *ri)
 	return 0;
 }
 
+static int regulator_set_voltage_internal(struct regulator_internal *ri,
+					  int min_uV, int max_uV)
+{
+	struct regulator_dev *rdev = ri->rdev;
+	const struct regulator_ops *ops = rdev->desc->ops;
+	unsigned int selector;
+	int best_val = 0;
+	int ret;
+
+	if (ops->set_voltage_sel) {
+		ret = regulator_map_voltage(rdev, min_uV, max_uV);
+		if (ret >= 0) {
+			best_val = ops->list_voltage(rdev, ret);
+			if (min_uV <= best_val && max_uV >= best_val) {
+				selector = ret;
+				ret = ops->set_voltage_sel(rdev, selector);
+			} else {
+				ret = -EINVAL;
+			}
+		}
+
+		return ret;
+	}
+
+	return -ENOSYS;
+}
+
 static struct regulator_internal * __regulator_register(struct regulator_dev *rd, const char *name)
 {
 	struct regulator_internal *ri;
@@ -320,6 +356,14 @@ int regulator_disable(struct regulator *r)
 	return regulator_disable_internal(r->ri);
 }
 
+int regulator_set_voltage(struct regulator *r, int min_uV, int max_uV)
+{
+	if (!r)
+		return 0;
+
+	return regulator_set_voltage_internal(r->ri, min_uV, max_uV);
+}
+
 static void regulator_print_one(struct regulator_internal *ri)
 {
 	struct regulator *r;
diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c
index 4495b4403..f22d21b35 100644
--- a/drivers/regulator/helpers.c
+++ b/drivers/regulator/helpers.c
@@ -85,3 +85,102 @@ int regulator_disable_regmap(struct regulator_dev *rdev)
 				  rdev->desc->enable_mask, val);
 }
 EXPORT_SYMBOL_GPL(regulator_disable_regmap);
+
+/**
+ * regulator_set_voltage_sel_regmap - standard set_voltage_sel for regmap users
+ *
+ * @rdev: regulator to operate on
+ * @sel: Selector to set
+ *
+ * Regulators that use regmap for their register I/O can set the
+ * vsel_reg and vsel_mask fields in their descriptor and then use this
+ * as their set_voltage_vsel operation, saving some code.
+ */
+int regulator_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned sel)
+{
+	int ret;
+
+	sel <<= ffs(rdev->desc->vsel_mask) - 1;
+
+	ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg,
+				  rdev->desc->vsel_mask, sel);
+	if (ret)
+		return ret;
+
+	if (rdev->desc->apply_bit)
+		ret = regmap_update_bits(rdev->regmap, rdev->desc->apply_reg,
+					 rdev->desc->apply_bit,
+					 rdev->desc->apply_bit);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_set_voltage_sel_regmap);
+
+/**
+ * regulator_map_voltage_linear - map_voltage() for simple linear mappings
+ *
+ * @rdev: Regulator to operate on
+ * @min_uV: Lower bound for voltage
+ * @max_uV: Upper bound for voltage
+ *
+ * Drivers providing min_uV and uV_step in their regulator_desc can
+ * use this as their map_voltage() operation.
+ */
+int regulator_map_voltage_linear(struct regulator_dev *rdev,
+				 int min_uV, int max_uV)
+{
+	int ret, voltage;
+
+	/* Allow uV_step to be 0 for fixed voltage */
+	if (rdev->desc->n_voltages == 1 && rdev->desc->uV_step == 0) {
+		if (min_uV <= rdev->desc->min_uV && rdev->desc->min_uV <= max_uV)
+			return 0;
+		else
+			return -EINVAL;
+	}
+
+	if (!rdev->desc->uV_step) {
+		BUG_ON(!rdev->desc->uV_step);
+		return -EINVAL;
+	}
+
+	if (min_uV < rdev->desc->min_uV)
+		min_uV = rdev->desc->min_uV;
+
+	ret = DIV_ROUND_UP(min_uV - rdev->desc->min_uV, rdev->desc->uV_step);
+	if (ret < 0)
+		return ret;
+
+	ret += rdev->desc->linear_min_sel;
+
+	/* Map back into a voltage to verify we're still in bounds */
+	voltage = rdev->desc->ops->list_voltage(rdev, ret);
+	if (voltage < min_uV || voltage > max_uV)
+		return -EINVAL;
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_map_voltage_linear);
+
+/**
+ * regulator_list_voltage_linear - List voltages with simple calculation
+ *
+ * @rdev: Regulator device
+ * @selector: Selector to convert into a voltage
+ *
+ * Regulators with a simple linear mapping between voltages and
+ * selectors can set min_uV and uV_step in the regulator descriptor
+ * and then use this function as their list_voltage() operation,
+ */
+int regulator_list_voltage_linear(struct regulator_dev *rdev,
+				  unsigned int selector)
+{
+	if (selector >= rdev->desc->n_voltages)
+		return -EINVAL;
+	if (selector < rdev->desc->linear_min_sel)
+		return 0;
+
+	selector -= rdev->desc->linear_min_sel;
+
+	return rdev->desc->min_uV + (rdev->desc->uV_step * selector);
+}
+EXPORT_SYMBOL_GPL(regulator_list_voltage_linear);
diff --git a/include/regulator.h b/include/regulator.h
index 1824e6ea1..cd1d3ccf5 100644
--- a/include/regulator.h
+++ b/include/regulator.h
@@ -5,8 +5,17 @@
 struct regulator;
 
 struct regulator_desc {
+	unsigned n_voltages;
 	const struct regulator_ops *ops;
 
+	unsigned int min_uV;
+	unsigned int uV_step;
+	unsigned int linear_min_sel;
+
+	unsigned int vsel_reg;
+	unsigned int vsel_mask;
+	unsigned int apply_reg;
+	unsigned int apply_bit;
 	unsigned int enable_reg;
 	unsigned int enable_mask;
 	unsigned int enable_val;
@@ -25,6 +34,9 @@ struct regulator_ops {
 	int (*enable) (struct regulator_dev *);
 	int (*disable) (struct regulator_dev *);
 	int (*is_enabled) (struct regulator_dev *);
+
+	int (*list_voltage) (struct regulator_dev *, unsigned int);
+	int (*set_voltage_sel) (struct regulator_dev *, unsigned int);
 };
 
 #ifdef CONFIG_OFDEVICE
@@ -49,6 +61,12 @@ int regulator_disable(struct regulator *);
 int regulator_is_enabled_regmap(struct regulator_dev *);
 int regulator_enable_regmap(struct regulator_dev *);
 int regulator_disable_regmap(struct regulator_dev *);
+int regulator_set_voltage_sel_regmap(struct regulator_dev *, unsigned);
+int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV);
+int regulator_map_voltage_linear(struct regulator_dev *rdev,
+				 int min_uV, int max_uV);
+int regulator_list_voltage_linear(struct regulator_dev *rdev,
+				  unsigned int selector);
 #else
 
 static inline struct regulator *regulator_get(struct device_d *dev, const char *id)
@@ -66,6 +84,12 @@ static inline int regulator_disable(struct regulator *r)
 	return 0;
 }
 
+static inline int regulator_set_voltage(struct regulator *regulator,
+					int min_uV, int max_uV)
+{
+	return 0;
+}
+
 #endif
 
 #endif /* __REGULATOR_H */
-- 
2.20.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 04/21] base: driver: Drop redundant list_empty() check
  2019-01-09  7:11 [PATCH 00/21] PCIe support for i.MX7 Andrey Smirnov
                   ` (2 preceding siblings ...)
  2019-01-09  7:11 ` [PATCH 03/21] regulator: Add support for setting regulator's voltage Andrey Smirnov
@ 2019-01-09  7:11 ` Andrey Smirnov
  2019-01-09  7:11 ` [PATCH 05/21] base: Port driver_deferred_probe_check_state() from Linux Andrey Smirnov
                   ` (16 subsequent siblings)
  20 siblings, 0 replies; 27+ messages in thread
From: Andrey Smirnov @ 2019-01-09  7:11 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/base/driver.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 1fd890542..1fd6bbc01 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -269,7 +269,7 @@ static int device_probe_deferred(void)
 		success = false;
 
 		if (list_empty(&deferred))
-			break;
+			return 0;
 
 		list_for_each_entry_safe(dev, tmp, &deferred, active) {
 			list_del(&dev->active);
@@ -285,9 +285,6 @@ static int device_probe_deferred(void)
 		}
 	} while (success);
 
-	if (list_empty(&deferred))
-		return 0;
-
 	list_for_each_entry(dev, &deferred, active)
 		dev_err(dev, "probe permanently deferred\n");
 
-- 
2.20.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 05/21] base: Port driver_deferred_probe_check_state() from Linux
  2019-01-09  7:11 [PATCH 00/21] PCIe support for i.MX7 Andrey Smirnov
                   ` (3 preceding siblings ...)
  2019-01-09  7:11 ` [PATCH 04/21] base: driver: Drop redundant list_empty() check Andrey Smirnov
@ 2019-01-09  7:11 ` Andrey Smirnov
  2019-01-09  7:11 ` [PATCH 06/21] regulator: Add primitive support for deferred probe Andrey Smirnov
                   ` (15 subsequent siblings)
  20 siblings, 0 replies; 27+ messages in thread
From: Andrey Smirnov @ 2019-01-09  7:11 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Port driver_deferred_probe_check_state() from Linux by adding on last
pass going through all of the deferred drivers that allows us to
declare all unresolved dependencies as missing.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/base/driver.c | 73 ++++++++++++++++++++++++++++++++-----------
 include/driver.h      |  2 ++
 2 files changed, 57 insertions(+), 18 deletions(-)

diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 1fd6bbc01..be735189a 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -46,6 +46,8 @@ EXPORT_SYMBOL(driver_list);
 static LIST_HEAD(active);
 static LIST_HEAD(deferred);
 
+static bool initcalls_done;
+
 struct device_d *get_device_by_name(const char *name)
 {
 	struct device_d *dev;
@@ -259,31 +261,66 @@ EXPORT_SYMBOL(unregister_device);
  * For devices finally left in deferred list -EPROBE_DEFER
  * becomes a fatal error.
  */
-static int device_probe_deferred(void)
+
+/**
+ * driver_deferred_probe_check_state() - Check deferred probe state
+ * @dev: device to check
+ *
+ * Returns -ENODEV if init is done and all built-in drivers have had a chance
+ * to probe (i.e. initcalls are done), -ETIMEDOUT if deferred probe debug
+ * timeout has expired, or -EPROBE_DEFER if none of those conditions are met.
+ *
+ * Drivers or subsystems can opt-in to calling this function instead of directly
+ * returning -EPROBE_DEFER.
+ */
+int driver_deferred_probe_check_state(struct device_d *dev)
+{
+	if (initcalls_done) {
+		dev_warn(dev, "ignoring dependency for device, assuming no driver");
+		return -ENODEV;
+	}
+	return -EPROBE_DEFER;
+}
+
+static bool device_probe_deferred_match_all(void)
 {
 	struct device_d *dev, *tmp;
 	struct driver_d *drv;
-	bool success;
+	bool success = false;
 
-	do {
-		success = false;
+	list_for_each_entry_safe(dev, tmp, &deferred, active) {
+		list_del(&dev->active);
+		INIT_LIST_HEAD(&dev->active);
 
-		if (list_empty(&deferred))
-			return 0;
+		dev_dbg(dev, "re-probe device\n");
+		bus_for_each_driver(dev->bus, drv) {
+			if (match(drv, dev))
+				continue;
+			success = true;
+			break;
+		}
+	}
 
-		list_for_each_entry_safe(dev, tmp, &deferred, active) {
-			list_del(&dev->active);
-			INIT_LIST_HEAD(&dev->active);
+	return success;
+}
 
-			dev_dbg(dev, "re-probe device\n");
-			bus_for_each_driver(dev->bus, drv) {
-				if (match(drv, dev))
-					continue;
-				success = true;
-				break;
-			}
-		}
-	} while (success);
+static int device_probe_deferred(void)
+{
+	struct device_d *dev;
+
+	while (device_probe_deferred_match_all())
+		;
+
+	initcalls_done = true;
+
+	if (list_empty(&deferred))
+		return 0;
+	/*
+	 * Loop over all deferred devices to give various functions
+	 * that call driver_deferred_probe_check_state() a chance to
+	 * finally return -ENODEV as opposed to -EPROBE_DEFER
+	 */
+	device_probe_deferred_match_all();
 
 	list_for_each_entry(dev, &deferred, active)
 		dev_err(dev, "probe permanently deferred\n");
diff --git a/include/driver.h b/include/driver.h
index 3d9970df5..385e410dd 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -151,6 +151,8 @@ void device_detect_all(void);
  */
 int unregister_device(struct device_d *);
 
+int driver_deferred_probe_check_state(struct device_d *dev);
+
 /* Iterate over a devices children
  */
 #define device_for_each_child(dev, child) \
-- 
2.20.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 06/21] regulator: Add primitive support for deferred probe
  2019-01-09  7:11 [PATCH 00/21] PCIe support for i.MX7 Andrey Smirnov
                   ` (4 preceding siblings ...)
  2019-01-09  7:11 ` [PATCH 05/21] base: Port driver_deferred_probe_check_state() from Linux Andrey Smirnov
@ 2019-01-09  7:11 ` Andrey Smirnov
  2019-01-09  7:11 ` [PATCH 07/21] regulator: Port ANATOP driver from Linux Andrey Smirnov
                   ` (14 subsequent siblings)
  20 siblings, 0 replies; 27+ messages in thread
From: Andrey Smirnov @ 2019-01-09  7:11 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Don't report requested regulator (via of_regulator_get()) as
non-existent if said regulator is missing from regulator list. Instead
rely on driver_deferred_probe_check_state() to properly declare
regulator as such after all of the initcalls were done and no further
missing dependencies could be resolved.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/regulator/core.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 795dcdb8c..a5ac8f3c9 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -227,7 +227,13 @@ static struct regulator_internal *of_regulator_get(struct device_d *dev, const c
 		}
 	}
 
-	ri = ERR_PTR(-ENODEV);
+	/*
+	 * It is possible that regulator we are looking for will be
+	 * added in future initcalls, so, instead of reporting a
+	 * complete failure we see if probe deferral is more
+	 * appropriate
+	 */
+	ri = ERR_PTR(driver_deferred_probe_check_state(dev));
 out:
 	free(propname);
 
-- 
2.20.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 07/21] regulator: Port ANATOP driver from Linux
  2019-01-09  7:11 [PATCH 00/21] PCIe support for i.MX7 Andrey Smirnov
                   ` (5 preceding siblings ...)
  2019-01-09  7:11 ` [PATCH 06/21] regulator: Add primitive support for deferred probe Andrey Smirnov
@ 2019-01-09  7:11 ` Andrey Smirnov
  2019-01-09  7:11 ` [PATCH 08/21] drivers: base: Port power management code " Andrey Smirnov
                   ` (13 subsequent siblings)
  20 siblings, 0 replies; 27+ messages in thread
From: Andrey Smirnov @ 2019-01-09  7:11 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Port a subset of Linux driver sufficient enough to support feature
needed for PCIe on i.MX7.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/regulator/Kconfig            |   8 ++
 drivers/regulator/Makefile           |   3 +-
 drivers/regulator/anatop-regulator.c | 161 +++++++++++++++++++++++++++
 3 files changed, 171 insertions(+), 1 deletion(-)
 create mode 100644 drivers/regulator/anatop-regulator.c

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 92db8dc0e..c734ef5ef 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -21,4 +21,12 @@ config REGULATOR_PFUZE
 	depends on I2C
 	depends on ARCH_IMX6
 
+config REGULATOR_ANATOP
+	tristate "Freescale i.MX on-chip ANATOP LDO regulators"
+	depends on MFD_SYSCON
+	help
+	  Say y here to support Freescale i.MX on-chip ANATOP LDOs
+	  regulators. It is recommended that this option be
+	  enabled on i.MX6 platform.
+
 endif
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 36ce3e87f..b2fc5b79b 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -1,4 +1,5 @@
 obj-$(CONFIG_REGULATOR) += core.o helpers.o
 obj-$(CONFIG_REGULATOR_FIXED) += fixed.o
 obj-$(CONFIG_REGULATOR_BCM283X) += bcm2835.o
-obj-$(CONFIG_REGULATOR_PFUZE) += pfuze.o
\ No newline at end of file
+obj-$(CONFIG_REGULATOR_PFUZE) += pfuze.o
+obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o
\ No newline at end of file
diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c
new file mode 100644
index 000000000..3944fd592
--- /dev/null
+++ b/drivers/regulator/anatop-regulator.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <common.h>
+#include <init.h>
+#include <mfd/syscon.h>
+#include <regmap.h>
+#include <regulator.h>
+
+struct anatop_regulator {
+	u32 control_reg;
+	struct regmap *anatop;
+	int vol_bit_shift;
+	int vol_bit_width;
+	u32 delay_reg;
+	int delay_bit_shift;
+	int delay_bit_width;
+	int min_bit_val;
+	int min_voltage;
+	int max_voltage;
+
+	struct regulator_dev  rdev;
+	struct regulator_desc rdesc;
+
+	bool bypass;
+	int sel;
+};
+
+static struct regulator_ops anatop_rops = {
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.list_voltage = regulator_list_voltage_linear,
+};
+
+static int anatop_regulator_probe(struct device_d *dev)
+{
+	struct device_node *np = dev->device_node;
+	struct device_node *anatop_np;
+	struct regulator_desc *rdesc;
+	struct regulator_dev *rdev;
+	struct anatop_regulator *sreg;
+	int ret = 0;
+
+	sreg  = xzalloc(sizeof(*sreg));
+	rdesc = &sreg->rdesc;
+	rdev  = &sreg->rdev;
+
+	anatop_np = of_get_parent(np);
+	if (!anatop_np)
+		return -ENODEV;
+
+	rdev->desc = rdesc;
+	rdev->regmap = syscon_node_to_regmap(anatop_np);
+	if (IS_ERR(rdev->regmap))
+		return PTR_ERR(rdev->regmap);
+
+	ret = of_property_read_u32(np, "anatop-reg-offset",
+				   &sreg->control_reg);
+	if (ret) {
+		dev_err(dev, "no anatop-reg-offset property set\n");
+		return ret;
+	}
+	ret = of_property_read_u32(np, "anatop-vol-bit-width",
+				   &sreg->vol_bit_width);
+	if (ret) {
+		dev_err(dev, "no anatop-vol-bit-width property set\n");
+		return ret;
+	}
+	ret = of_property_read_u32(np, "anatop-vol-bit-shift",
+				   &sreg->vol_bit_shift);
+	if (ret) {
+		dev_err(dev, "no anatop-vol-bit-shift property set\n");
+		return ret;
+	}
+	ret = of_property_read_u32(np, "anatop-min-bit-val",
+				   &sreg->min_bit_val);
+	if (ret) {
+		dev_err(dev, "no anatop-min-bit-val property set\n");
+		return ret;
+	}
+	ret = of_property_read_u32(np, "anatop-min-voltage",
+				   &sreg->min_voltage);
+	if (ret) {
+		dev_err(dev, "no anatop-min-voltage property set\n");
+		return ret;
+	}
+	ret = of_property_read_u32(np, "anatop-max-voltage",
+				   &sreg->max_voltage);
+	if (ret) {
+		dev_err(dev, "no anatop-max-voltage property set\n");
+		return ret;
+	}
+
+	/* read LDO ramp up setting, only for core reg */
+	of_property_read_u32(np, "anatop-delay-reg-offset",
+			     &sreg->delay_reg);
+	of_property_read_u32(np, "anatop-delay-bit-width",
+			     &sreg->delay_bit_width);
+	of_property_read_u32(np, "anatop-delay-bit-shift",
+			     &sreg->delay_bit_shift);
+
+	rdesc->n_voltages = (sreg->max_voltage - sreg->min_voltage) / 25000 + 1
+			    + sreg->min_bit_val;
+	rdesc->min_uV = sreg->min_voltage;
+	rdesc->uV_step = 25000;
+	rdesc->linear_min_sel = sreg->min_bit_val;
+	rdesc->vsel_reg  = sreg->control_reg;
+	rdesc->vsel_mask = GENMASK(sreg->vol_bit_width + sreg->vol_bit_shift,
+				   sreg->vol_bit_shift);
+
+	/* Only core regulators have the ramp up delay configuration. */
+	if (sreg->control_reg && sreg->delay_bit_width) {
+		free(sreg);
+		return -ENODEV;
+	} else {
+		u32 enable_bit;
+
+		rdesc->ops = &anatop_rops;
+
+		if (!of_property_read_u32(np, "anatop-enable-bit",
+					  &enable_bit)) {
+			anatop_rops.enable  = regulator_enable_regmap;
+			anatop_rops.disable = regulator_disable_regmap;
+			anatop_rops.is_enabled = regulator_is_enabled_regmap;
+
+			rdesc->enable_reg = sreg->control_reg;
+			rdesc->enable_mask = BIT(enable_bit);
+		}
+	}
+
+	return of_regulator_register(rdev, dev->device_node);
+}
+
+static const struct of_device_id of_anatop_regulator_match_tbl[] = {
+	{ .compatible = "fsl,anatop-regulator", },
+	{ /* end */ }
+};
+
+static struct driver_d anatop_regulator_driver = {
+	.name = "anatop_regulator",
+	.probe = anatop_regulator_probe,
+	.of_compatible = DRV_OF_COMPAT(of_anatop_regulator_match_tbl),
+};
+device_platform_driver(anatop_regulator_driver);
+
-- 
2.20.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 08/21] drivers: base: Port power management code from Linux
  2019-01-09  7:11 [PATCH 00/21] PCIe support for i.MX7 Andrey Smirnov
                   ` (6 preceding siblings ...)
  2019-01-09  7:11 ` [PATCH 07/21] regulator: Port ANATOP driver from Linux Andrey Smirnov
@ 2019-01-09  7:11 ` Andrey Smirnov
  2019-01-09  7:11 ` [PATCH 09/21] soc: imx: Add GPCv2 power gating driver Andrey Smirnov
                   ` (12 subsequent siblings)
  20 siblings, 0 replies; 27+ messages in thread
From: Andrey Smirnov @ 2019-01-09  7:11 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Port an extremely abridged version of power management/power domain
code from Linux as a dependency of i.MX7D PCIe work. Currenlty only
bare minimum of functionality is implemented.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/Kconfig         |   1 +
 drivers/base/Kconfig    |   3 +
 drivers/base/Makefile   |   4 +-
 drivers/base/platform.c |   7 ++
 drivers/base/power.c    | 245 ++++++++++++++++++++++++++++++++++++++++
 include/pm_domain.h     |  82 ++++++++++++++
 6 files changed, 341 insertions(+), 1 deletion(-)
 create mode 100644 drivers/base/Kconfig
 create mode 100644 drivers/base/power.c
 create mode 100644 include/pm_domain.h

diff --git a/drivers/Kconfig b/drivers/Kconfig
index 1e0246da6..c3bf9dfe1 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -1,5 +1,6 @@
 menu "Drivers"
 
+source "drivers/base/Kconfig"
 source "drivers/efi/Kconfig"
 source "drivers/of/Kconfig"
 source "drivers/aiodev/Kconfig"
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
new file mode 100644
index 000000000..1e13e5ed9
--- /dev/null
+++ b/drivers/base/Kconfig
@@ -0,0 +1,3 @@
+
+config PM_GENERIC_DOMAINS
+	bool
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 4bd421774..6d2cef8e1 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -2,4 +2,6 @@ obj-y	+= bus.o
 obj-y	+= driver.o
 obj-y	+= platform.o
 obj-y	+= resource.o
-obj-y	+= regmap/
\ No newline at end of file
+obj-y	+= regmap/
+
+obj-$(CONFIG_PM_GENERIC_DOMAINS) += power.o
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 85bdfb014..1d3fa2eb4 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -21,9 +21,16 @@
 #include <errno.h>
 #include <init.h>
 #include <of.h>
+#include <pm_domain.h>
 
 static int platform_probe(struct device_d *dev)
 {
+	int ret;
+
+	ret = genpd_dev_pm_attach(dev);
+	if (ret < 0)
+		return ret;
+
 	return dev->driver->probe(dev);
 }
 
diff --git a/drivers/base/power.c b/drivers/base/power.c
new file mode 100644
index 000000000..fd9c4e2ba
--- /dev/null
+++ b/drivers/base/power.c
@@ -0,0 +1,245 @@
+#include <common.h>
+#include <driver.h>
+#include <errno.h>
+#include <of.h>
+
+#include <pm_domain.h>
+
+#define genpd_status_on(genpd)		(genpd->status == GPD_STATE_ACTIVE)
+
+static LIST_HEAD(gpd_list);
+
+/**
+ * pm_genpd_init - Initialize a generic I/O PM domain object.
+ * @genpd: PM domain object to initialize.
+ * @gov: PM domain governor to associate with the domain (may be NULL).
+ * @is_off: Initial value of the domain's power_is_off field.
+ *
+ * Returns 0 on successful initialization, else a negative error code.
+ */
+int pm_genpd_init(struct generic_pm_domain *genpd, void *gov, bool is_off)
+{
+	if (IS_ERR_OR_NULL(genpd))
+		return -EINVAL;
+
+	genpd->status = is_off ? GPD_STATE_POWER_OFF : GPD_STATE_ACTIVE;
+
+	list_add(&genpd->gpd_list_node, &gpd_list);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pm_genpd_init);
+
+/**
+ * struct of_genpd_provider - PM domain provider registration structure
+ * @link: Entry in global list of PM domain providers
+ * @node: Pointer to device tree node of PM domain provider
+ * @xlate: Provider-specific xlate callback mapping a set of specifier cells
+ *         into a PM domain.
+ * @data: context pointer to be passed into @xlate callback
+ */
+struct of_genpd_provider {
+	struct list_head link;
+	struct device_node *node;
+	genpd_xlate_t xlate;
+	void *data;
+};
+
+/* List of registered PM domain providers. */
+static LIST_HEAD(of_genpd_providers);
+
+static bool genpd_present(const struct generic_pm_domain *genpd)
+{
+	const struct generic_pm_domain *gpd;
+
+	if (IS_ERR_OR_NULL(genpd))
+		return false;
+
+	list_for_each_entry(gpd, &gpd_list, gpd_list_node)
+		if (gpd == genpd)
+			return true;
+
+	return false;
+}
+
+/**
+ * genpd_xlate_simple() - Xlate function for direct node-domain mapping
+ * @genpdspec: OF phandle args to map into a PM domain
+ * @data: xlate function private data - pointer to struct generic_pm_domain
+ *
+ * This is a generic xlate function that can be used to model PM domains that
+ * have their own device tree nodes. The private data of xlate function needs
+ * to be a valid pointer to struct generic_pm_domain.
+ */
+static struct generic_pm_domain *genpd_xlate_simple(
+					struct of_phandle_args *genpdspec,
+					void *data)
+{
+	return data;
+}
+
+/**
+ * genpd_add_provider() - Register a PM domain provider for a node
+ * @np: Device node pointer associated with the PM domain provider.
+ * @xlate: Callback for decoding PM domain from phandle arguments.
+ * @data: Context pointer for @xlate callback.
+ */
+static int genpd_add_provider(struct device_node *np, genpd_xlate_t xlate,
+			      void *data)
+{
+	struct of_genpd_provider *cp;
+
+	cp = kzalloc(sizeof(*cp), GFP_KERNEL);
+	if (!cp)
+		return -ENOMEM;
+
+	cp->node  = np;
+	cp->data  = data;
+	cp->xlate = xlate;
+
+	list_add(&cp->link, &of_genpd_providers);
+	pr_debug("Added domain provider from %pOF\n", np);
+
+	return 0;
+}
+
+/**
+ * of_genpd_add_provider_simple() - Register a simple PM domain provider
+ * @np: Device node pointer associated with the PM domain provider.
+ * @genpd: Pointer to PM domain associated with the PM domain provider.
+ */
+int of_genpd_add_provider_simple(struct device_node *np,
+				 struct generic_pm_domain *genpd)
+{
+	int ret = -EINVAL;
+
+	if (!np || !genpd)
+		return -EINVAL;
+
+	if (genpd_present(genpd))
+		ret = genpd_add_provider(np, genpd_xlate_simple, genpd);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(of_genpd_add_provider_simple);
+
+/**
+ * genpd_get_from_provider() - Look-up PM domain
+ * @genpdspec: OF phandle args to use for look-up
+ *
+ * Looks for a PM domain provider under the node specified by @genpdspec and if
+ * found, uses xlate function of the provider to map phandle args to a PM
+ * domain.
+ *
+ * Returns a valid pointer to struct generic_pm_domain on success or ERR_PTR()
+ * on failure.
+ */
+static struct generic_pm_domain *genpd_get_from_provider(
+					struct of_phandle_args *genpdspec)
+{
+	struct generic_pm_domain *genpd = ERR_PTR(-ENOENT);
+	struct of_genpd_provider *provider;
+
+	if (!genpdspec)
+		return ERR_PTR(-EINVAL);
+
+	/* Check if we have such a provider in our array */
+	list_for_each_entry(provider, &of_genpd_providers, link) {
+		if (provider->node == genpdspec->np)
+			genpd = provider->xlate(genpdspec, provider->data);
+		if (!IS_ERR(genpd))
+			break;
+	}
+
+	return genpd;
+}
+
+static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
+{
+	if (!genpd->power_on)
+		return 0;
+
+	return genpd->power_on(genpd);
+}
+
+/**
+ * genpd_power_on - Restore power to a given PM domain and its masters.
+ * @genpd: PM domain to power up.
+ * @depth: nesting count for lockdep.
+ *
+ * Restore power to @genpd and all of its masters so that it is possible to
+ * resume a device belonging to it.
+ */
+static int genpd_power_on(struct generic_pm_domain *genpd, unsigned int depth)
+{
+	int ret;
+
+	if (genpd_status_on(genpd))
+		return 0;
+
+	ret = _genpd_power_on(genpd, true);
+	if (ret)
+		return ret;
+
+	genpd->status = GPD_STATE_ACTIVE;
+
+	return 0;
+}
+
+static int __genpd_dev_pm_attach(struct device_d *dev, struct device_node *np,
+				 unsigned int index, bool power_on)
+{
+	struct of_phandle_args pd_args;
+	struct generic_pm_domain *pd;
+	int ret;
+
+	ret = of_parse_phandle_with_args(np, "power-domains",
+				"#power-domain-cells", index, &pd_args);
+	if (ret < 0)
+		return ret;
+
+	pd = genpd_get_from_provider(&pd_args);
+	if (IS_ERR(pd)) {
+		ret = PTR_ERR(pd);
+		dev_dbg(dev, "%s() failed to find PM domain: %d\n",
+			__func__, ret);
+		return driver_deferred_probe_check_state(dev);
+	}
+
+	dev_dbg(dev, "adding to PM domain %s\n", pd->name);
+
+	if (power_on)
+		ret = genpd_power_on(pd, 0);
+
+	return ret ?: 1;
+}
+
+/**
+ * genpd_dev_pm_attach - Attach a device to its PM domain using DT.
+ * @dev: Device to attach.
+ *
+ * Parse device's OF node to find a PM domain specifier. If such is found,
+ * attaches the device to retrieved pm_domain ops.
+ *
+ * Returns 1 on successfully attached PM domain, 0 when the device don't need a
+ * PM domain or when multiple power-domains exists for it, else a negative error
+ * code. Note that if a power-domain exists for the device, but it cannot be
+ * found or turned on, then return -EPROBE_DEFER to ensure that the device is
+ * not probed and to re-try again later.
+ */
+int genpd_dev_pm_attach(struct device_d *dev)
+{
+	if (!dev->device_node)
+		return 0;
+
+	/*
+	 * Devices with multiple PM domains must be attached separately, as we
+	 * can only attach one PM domain per device.
+	 */
+	if (of_count_phandle_with_args(dev->device_node, "power-domains",
+				       "#power-domain-cells") != 1)
+		return 0;
+
+	return __genpd_dev_pm_attach(dev, dev->device_node, 0, true);
+}
+EXPORT_SYMBOL_GPL(genpd_dev_pm_attach);
diff --git a/include/pm_domain.h b/include/pm_domain.h
new file mode 100644
index 000000000..6d59587ec
--- /dev/null
+++ b/include/pm_domain.h
@@ -0,0 +1,82 @@
+#ifndef _PM_DOMAIN_H
+#define _PM_DOMAIN_H
+
+enum gpd_status {
+	GPD_STATE_ACTIVE = 0,	/* PM domain is active */
+	GPD_STATE_POWER_OFF,	/* PM domain is off */
+};
+
+struct generic_pm_domain {
+	const char *name;
+	struct list_head gpd_list_node;	/* Node in the global PM domains list */
+
+	enum gpd_status status;	/* Current state of the domain */
+
+	int (*power_off)(struct generic_pm_domain *domain);
+	int (*power_on)(struct generic_pm_domain *domain);
+};
+
+typedef struct generic_pm_domain *(*genpd_xlate_t)(struct of_phandle_args *args,
+						   void *data);
+
+#ifdef CONFIG_PM_GENERIC_DOMAINS
+
+int genpd_dev_pm_attach(struct device_d *dev);
+
+/**
+ * dev_pm_domain_attach - Attach a device to its PM domain.
+ * @dev: Device to attach.
+ * @power_on: Used to indicate whether we should power on the device.
+ *
+ * The @dev may only be attached to a single PM domain. By iterating through
+ * the available alternatives we try to find a valid PM domain for the device.
+ * As attachment succeeds, the ->detach() callback in the struct dev_pm_domain
+ * should be assigned by the corresponding attach function.
+ *
+ * This function should typically be invoked from subsystem level code during
+ * the probe phase. Especially for those that holds devices which requires
+ * power management through PM domains.
+ *
+ * Callers must ensure proper synchronization of this function with power
+ * management callbacks.
+ *
+ * Returns 0 on successfully attached PM domain or negative error code.
+ */
+static inline int dev_pm_domain_attach(struct device_d *dev, bool power_on)
+{
+	return genpd_dev_pm_attach(dev);
+}
+
+int pm_genpd_init(struct generic_pm_domain *genpd, void *gov, bool is_off);
+
+int of_genpd_add_provider_simple(struct device_node *np,
+				 struct generic_pm_domain *genpd);
+
+#else
+
+static inline int pm_genpd_init(struct generic_pm_domain *genpd,
+				void *gov, bool is_off)
+{
+	return -ENOSYS;
+}
+
+static inline int genpd_dev_pm_attach(struct device_d *dev)
+{
+	return 0;
+}
+
+static inline int dev_pm_domain_attach(struct device_d *dev, bool power_on)
+{
+	return 0;
+}
+
+static inline int
+of_genpd_add_provider_simple(struct device_node *np,
+			     struct generic_pm_domain *genpd)
+{
+	return -ENOTSUPP;
+}
+
+#endif
+
+#endif
\ No newline at end of file
-- 
2.20.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 09/21] soc: imx: Add GPCv2 power gating driver
  2019-01-09  7:11 [PATCH 00/21] PCIe support for i.MX7 Andrey Smirnov
                   ` (7 preceding siblings ...)
  2019-01-09  7:11 ` [PATCH 08/21] drivers: base: Port power management code " Andrey Smirnov
@ 2019-01-09  7:11 ` Andrey Smirnov
  2019-01-09  7:11 ` [PATCH 10/21] soc: imx: gpcv2: fix regulator deferred probe Andrey Smirnov
                   ` (11 subsequent siblings)
  20 siblings, 0 replies; 27+ messages in thread
From: Andrey Smirnov @ 2019-01-09  7:11 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Port of a Linux commit 03aa12629fc4f73acf28e519c9ee9cb1f5dd3706

  Add code allowing for control of various power domains managed by GPCv2
  IP block found in i.MX7 series of SoCs. Power domains covered by this
  patch are:

      - PCIE PHY
      - MIPI PHY
      - USB HSIC PHY
      - USB OTG1/2 PHY

  Support for any other power domain controlled by GPC is not present, and
  can be added at some later point.

  Testing of this code was done against a PCIe driver.

  Cc: yurovsky@gmail.com
  Cc: Lucas Stach <l.stach@pengutronix.de>
  Cc: Fabio Estevam <fabio.estevam@nxp.com>
  Cc: Dong Aisheng <dongas86@gmail.com>
  Cc: linux-arm-kernel@lists.infradead.org
  Cc: linux-kernel@vger.kernel.org
  Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
  Signed-off-by: Shawn Guo <shawnguo@kernel.org>

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/Kconfig          |   1 +
 drivers/Makefile         |   1 +
 drivers/soc/imx/Kconfig  |   9 ++
 drivers/soc/imx/Makefile |   1 +
 drivers/soc/imx/gpcv2.c  | 309 +++++++++++++++++++++++++++++++++++++++
 5 files changed, 321 insertions(+)
 create mode 100644 drivers/soc/imx/Kconfig
 create mode 100644 drivers/soc/imx/Makefile
 create mode 100644 drivers/soc/imx/gpcv2.c

diff --git a/drivers/Kconfig b/drivers/Kconfig
index c3bf9dfe1..c6c2eb14d 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -38,5 +38,6 @@ source "drivers/firmware/Kconfig"
 source "drivers/phy/Kconfig"
 source "drivers/crypto/Kconfig"
 source "drivers/memory/Kconfig"
+source "drivers/soc/imx/Kconfig"
 
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 767789d54..752fd6624 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -38,3 +38,4 @@ obj-$(CONFIG_HAB) += hab/
 obj-$(CONFIG_CRYPTO_HW) += crypto/
 obj-$(CONFIG_AIODEV) += aiodev/
 obj-y	+= memory/
+obj-y	+= soc/imx/
diff --git a/drivers/soc/imx/Kconfig b/drivers/soc/imx/Kconfig
new file mode 100644
index 000000000..a78a9e396
--- /dev/null
+++ b/drivers/soc/imx/Kconfig
@@ -0,0 +1,9 @@
+menu "i.MX SoC drivers"
+
+config IMX7_PM_DOMAINS
+	bool "i.MX7 PM domains"
+	depends on ARCH_IMX7
+	select PM_GENERIC_DOMAINS
+	default y if ARCH_IMX7
+
+endmenu
diff --git a/drivers/soc/imx/Makefile b/drivers/soc/imx/Makefile
new file mode 100644
index 000000000..b039f77dc
--- /dev/null
+++ b/drivers/soc/imx/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_IMX7_PM_DOMAINS) += gpcv2.o
diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c
new file mode 100644
index 000000000..918a35462
--- /dev/null
+++ b/drivers/soc/imx/gpcv2.c
@@ -0,0 +1,309 @@
+/*
+ * Copyright 2017 Impinj, Inc
+ * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
+ *
+ * Based on the code of analogus driver:
+ *
+ * Copyright 2015-2017 Pengutronix, Lucas Stach <kernel@pengutronix.de>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <common.h>
+#include <clock.h>
+#include <abort.h>
+#include <malloc.h>
+#include <io.h>
+#include <init.h>
+#include <linux/iopoll.h>
+
+#include <pm_domain.h>
+#include <regulator.h>
+#include <dt-bindings/power/imx7-power.h>
+
+#define GPC_LPCR_A7_BSC			0x000
+
+#define GPC_PGC_CPU_MAPPING		0x0ec
+#define USB_HSIC_PHY_A7_DOMAIN		BIT(6)
+#define USB_OTG2_PHY_A7_DOMAIN		BIT(5)
+#define USB_OTG1_PHY_A7_DOMAIN		BIT(4)
+#define PCIE_PHY_A7_DOMAIN		BIT(3)
+#define MIPI_PHY_A7_DOMAIN		BIT(2)
+
+#define GPC_PU_PGC_SW_PUP_REQ		0x0f8
+#define GPC_PU_PGC_SW_PDN_REQ		0x104
+#define USB_HSIC_PHY_SW_Pxx_REQ		BIT(4)
+#define USB_OTG2_PHY_SW_Pxx_REQ		BIT(3)
+#define USB_OTG1_PHY_SW_Pxx_REQ		BIT(2)
+#define PCIE_PHY_SW_Pxx_REQ		BIT(1)
+#define MIPI_PHY_SW_Pxx_REQ		BIT(0)
+
+#define GPC_M4_PU_PDN_FLG		0x1bc
+
+
+#define PGC_MIPI			4
+#define PGC_PCIE			5
+#define PGC_USB_HSIC			8
+#define GPC_PGC_CTRL(n)			(0x800 + (n) * 0x40)
+#define GPC_PGC_SR(n)			(GPC_PGC_CTRL(n) + 0xc)
+
+#define GPC_PGC_CTRL_PCR		BIT(0)
+
+struct imx7_pgc_domain {
+	struct generic_pm_domain genpd;
+	void __iomem *base;
+	struct regulator *regulator;
+
+	unsigned int pgc;
+
+	const struct {
+		u32 pxx;
+		u32 map;
+	} bits;
+
+	const int voltage;
+	struct device_d *dev;
+};
+
+static int imx7_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd,
+				      bool on)
+{
+	struct imx7_pgc_domain *domain = container_of(genpd,
+						      struct imx7_pgc_domain,
+						      genpd);
+	unsigned int offset = on ?
+		GPC_PU_PGC_SW_PUP_REQ : GPC_PU_PGC_SW_PDN_REQ;
+	const bool enable_power_control = !on;
+	const bool has_regulator = !IS_ERR(domain->regulator);
+	int ret = 0;
+	unsigned int mapping, ctrl = 0, pxx;
+
+	mapping = readl(domain->base + GPC_PGC_CPU_MAPPING);
+	mapping |= domain->bits.map;
+	writel(mapping, domain->base + GPC_PGC_CPU_MAPPING);
+
+	if (has_regulator && on) {
+		ret = regulator_enable(domain->regulator);
+		if (ret) {
+			dev_err(domain->dev, "failed to enable regulator\n");
+			goto unmap;
+		}
+	}
+
+	if (enable_power_control) {
+		ctrl = readl(domain->base + GPC_PGC_CTRL(domain->pgc));
+		ctrl |= GPC_PGC_CTRL_PCR;
+		writel(ctrl, domain->base + GPC_PGC_CTRL(domain->pgc));
+	}
+
+	pxx = readl(domain->base + offset);
+	pxx |= domain->bits.pxx;
+	writel(pxx, domain->base + offset);
+
+	/*
+	 * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait
+	 * for PUP_REQ/PDN_REQ bit to be cleared
+	 */
+	ret = readl_poll_timeout(domain->base + offset, pxx,
+				 !(pxx & domain->bits.pxx), MSECOND);
+	if (ret < 0) {
+		dev_err(domain->dev, "falied to command PGC\n");
+		/*
+		 * If we were in a process of enabling a
+		 * domain and failed we might as well disable
+		 * the regulator we just enabled. And if it
+		 * was the opposite situation and we failed to
+		 * power down -- keep the regulator on
+		 */
+		on = !on;
+	}
+
+	if (enable_power_control) {
+		ctrl &= ~GPC_PGC_CTRL_PCR;
+		writel(ctrl, domain->base + GPC_PGC_CTRL(domain->pgc));
+	}
+
+	if (has_regulator && !on) {
+		int err;
+
+		err = regulator_disable(domain->regulator);
+		if (err)
+			dev_err(domain->dev,
+				"failed to disable regulator: %d\n", ret);
+		/* Preserve earlier error code */
+		ret = ret ?: err;
+	}
+unmap:
+	mapping &= ~domain->bits.map;
+	writel(mapping, domain->base + GPC_PGC_CPU_MAPPING);
+
+	return ret;
+}
+
+static int imx7_gpc_pu_pgc_sw_pup_req(struct generic_pm_domain *genpd)
+{
+	return imx7_gpc_pu_pgc_sw_pxx_req(genpd, true);
+}
+
+static int imx7_gpc_pu_pgc_sw_pdn_req(struct generic_pm_domain *genpd)
+{
+	return imx7_gpc_pu_pgc_sw_pxx_req(genpd, false);
+}
+
+static const struct imx7_pgc_domain imx7_pgc_domains[] = {
+	[IMX7_POWER_DOMAIN_MIPI_PHY] = {
+		.genpd = {
+			.name      = "mipi-phy",
+		},
+		.bits  = {
+			.pxx = MIPI_PHY_SW_Pxx_REQ,
+			.map = MIPI_PHY_A7_DOMAIN,
+		},
+		.voltage   = 1000000,
+		.pgc	   = PGC_MIPI,
+	},
+
+	[IMX7_POWER_DOMAIN_PCIE_PHY] = {
+		.genpd = {
+			.name      = "pcie-phy",
+		},
+		.bits  = {
+			.pxx = PCIE_PHY_SW_Pxx_REQ,
+			.map = PCIE_PHY_A7_DOMAIN,
+		},
+		.voltage   = 1000000,
+		.pgc	   = PGC_PCIE,
+	},
+
+	[IMX7_POWER_DOMAIN_USB_HSIC_PHY] = {
+		.genpd = {
+			.name      = "usb-hsic-phy",
+		},
+		.bits  = {
+			.pxx = USB_HSIC_PHY_SW_Pxx_REQ,
+			.map = USB_HSIC_PHY_A7_DOMAIN,
+	},
+		.voltage   = 1200000,
+		.pgc	   = PGC_USB_HSIC,
+	},
+};
+
+static int imx7_pgc_domain_probe(struct device_d *dev)
+{
+	struct imx7_pgc_domain *domain = dev->priv;
+	int ret;
+
+	domain->dev = dev;
+
+	ret = pm_genpd_init(&domain->genpd, NULL, true);
+	if (ret) {
+		dev_err(domain->dev, "Failed to init power domain\n");
+		return ret;
+	}
+
+	domain->regulator = regulator_get(domain->dev, "power");
+	if (IS_ERR(domain->regulator)) {
+		if (PTR_ERR(domain->regulator) != -ENODEV) {
+			dev_err(domain->dev, "Failed to get domain's regulator\n");
+			return PTR_ERR(domain->regulator);
+		}
+	} else {
+		regulator_set_voltage(domain->regulator,
+				      domain->voltage, domain->voltage);
+	}
+
+	ret = of_genpd_add_provider_simple(domain->dev->device_node,
+					   &domain->genpd);
+	if (ret) {
+		dev_err(domain->dev, "Failed to add genpd provider\n");
+	}
+
+	return ret;
+}
+
+static const struct platform_device_id imx7_pgc_domain_id[] = {
+	{ "imx7-pgc-domain", },
+	{ },
+};
+
+static struct driver_d imx7_pgc_domain_driver = {
+	.name = "imx-pgc",
+	.probe = imx7_pgc_domain_probe,
+	.id_table = imx7_pgc_domain_id,
+};
+coredevice_platform_driver(imx7_pgc_domain_driver);
+
+static int imx_gpcv2_probe(struct device_d *dev)
+{
+	struct device_node *pgc_np, *np;
+	struct resource *res;
+	void __iomem *base;
+	int ret;
+
+	pgc_np = of_get_child_by_name(dev->device_node, "pgc");
+	if (!pgc_np) {
+		dev_err(dev, "No power domains specified in DT\n");
+		return -EINVAL;
+	}
+
+	res = dev_request_mem_resource(dev, 0);
+	if (IS_ERR(res))
+		return PTR_ERR(res);
+
+	base = IOMEM(res->start);
+
+	for_each_child_of_node(pgc_np, np) {
+		struct device_d *pd_dev;
+		struct imx7_pgc_domain *domain;
+		u32 domain_index;
+		ret = of_property_read_u32(np, "reg", &domain_index);
+		if (ret) {
+			dev_err(dev, "Failed to read 'reg' property\n");
+			return ret;
+		}
+
+		if (domain_index >= ARRAY_SIZE(imx7_pgc_domains)) {
+			dev_warn(dev,
+				 "Domain index %d is out of bounds\n",
+				 domain_index);
+			continue;
+		}
+
+		domain = xmemdup(&imx7_pgc_domains[domain_index],
+				 sizeof(imx7_pgc_domains[domain_index]));
+		domain->base = base;
+		domain->genpd.power_on = imx7_gpc_pu_pgc_sw_pup_req;
+		domain->genpd.power_off = imx7_gpc_pu_pgc_sw_pdn_req;
+
+		pd_dev = xzalloc(sizeof(*pd_dev));
+		pd_dev->device_node = np;
+		pd_dev->id = domain_index;
+		pd_dev->parent = dev;
+		pd_dev->priv = domain;
+		pd_dev->device_node = np;
+		dev_set_name(pd_dev, imx7_pgc_domain_id[0].name);
+
+		ret = platform_device_register(pd_dev);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id imx_gpcv2_dt_ids[] = {
+	{ .compatible = "fsl,imx7d-gpc" },
+	{ }
+};
+
+static struct driver_d imx_gpcv2_driver = {
+	.name = "imx7d-gpc",
+	.probe = imx_gpcv2_probe,
+	.of_compatible = DRV_OF_COMPAT(imx_gpcv2_dt_ids),
+};
+coredevice_platform_driver(imx_gpcv2_driver);
-- 
2.20.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 10/21] soc: imx: gpcv2: fix regulator deferred probe
  2019-01-09  7:11 [PATCH 00/21] PCIe support for i.MX7 Andrey Smirnov
                   ` (8 preceding siblings ...)
  2019-01-09  7:11 ` [PATCH 09/21] soc: imx: Add GPCv2 power gating driver Andrey Smirnov
@ 2019-01-09  7:11 ` Andrey Smirnov
  2019-01-10  7:37   ` Sascha Hauer
  2019-01-09  7:12 ` [PATCH 11/21] soc: imx: gpcv2: correct PGC offset Andrey Smirnov
                   ` (10 subsequent siblings)
  20 siblings, 1 reply; 27+ messages in thread
From: Andrey Smirnov @ 2019-01-09  7:11 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Port of a Linux commit 9e01e2d56db23485a75864b6aeee8e443f024ddb

  If a regulator requests a deferred probe, the power domain gets
  initialized twice. This leads to a list double add (without
  list debugging the kernel hangs due to the double add later):

    WARNING: CPU: 0 PID: 19 at lib/list_debug.c:31 __list_add_valid+0xbc/0xc4
    list_add double add: new=c1229754, prev=c12383b4, next=c1229754.

  Initialize the power domain after we get the regulator. Also do
  not print an error in case the regulator defers probing.

  Cc: Fabio Estevam <fabio.estevam@nxp.com>
  Cc: Andrey Smirnov <andrew.smirnov@gmail.com>
  Cc: linux-arm-kernel@lists.infradead.org
  Cc: linux-kernel@vger.kernel.org
  Fixes: 03aa12629fc4 ("soc: imx: Add GPCv2 power gating driver")
  Signed-off-by: Stefan Agner <stefan@agner.ch>
  Acked-by: Andrey Smirnov <andrew.smirnov@gmail.com>
  Tested-by: Andrey Smirnov <andrew.smirnov@gmail.com>
  Signed-off-by: Shawn Guo <shawnguo@kernel.org>

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/soc/imx/gpcv2.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c
index 918a35462..f16598e97 100644
--- a/drivers/soc/imx/gpcv2.c
+++ b/drivers/soc/imx/gpcv2.c
@@ -200,16 +200,11 @@ static int imx7_pgc_domain_probe(struct device_d *dev)
 
 	domain->dev = dev;
 
-	ret = pm_genpd_init(&domain->genpd, NULL, true);
-	if (ret) {
-		dev_err(domain->dev, "Failed to init power domain\n");
-		return ret;
-	}
-
 	domain->regulator = regulator_get(domain->dev, "power");
 	if (IS_ERR(domain->regulator)) {
 		if (PTR_ERR(domain->regulator) != -ENODEV) {
-			dev_err(domain->dev, "Failed to get domain's regulator\n");
+			if (PTR_ERR(domain->regulator) != -EPROBE_DEFER)
+				dev_err(domain->dev, "Failed to get domain's regulator\n");
 			return PTR_ERR(domain->regulator);
 		}
 	} else {
@@ -217,6 +212,12 @@ static int imx7_pgc_domain_probe(struct device_d *dev)
 				      domain->voltage, domain->voltage);
 	}
 
+	ret = pm_genpd_init(&domain->genpd, NULL, true);
+	if (ret) {
+		dev_err(domain->dev, "Failed to init power domain\n");
+		return ret;
+	}
+
 	ret = of_genpd_add_provider_simple(domain->dev->device_node,
 					   &domain->genpd);
 	if (ret) {
-- 
2.20.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 11/21] soc: imx: gpcv2: correct PGC offset
  2019-01-09  7:11 [PATCH 00/21] PCIe support for i.MX7 Andrey Smirnov
                   ` (9 preceding siblings ...)
  2019-01-09  7:11 ` [PATCH 10/21] soc: imx: gpcv2: fix regulator deferred probe Andrey Smirnov
@ 2019-01-09  7:12 ` Andrey Smirnov
  2019-01-09  7:12 ` [PATCH 12/21] reset: Add i.MX7 SRC reset driver Andrey Smirnov
                   ` (9 subsequent siblings)
  20 siblings, 0 replies; 27+ messages in thread
From: Andrey Smirnov @ 2019-01-09  7:12 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Port of a Linux commit 3637f12faf507b0a4b8ac1e7115fc99583ab1db3

  Correct MIPI/PCIe/USB_HSIC's PGC offset based on
  design RTL, the values in the Reference Manual
  (Rev. 1, 01/2018 and the older ones) are incorrect.

  The correct offset values should be as below:

  0x800 ~ 0x83F: PGC for core0 of A7 platform;
  0x840 ~ 0x87F: PGC for core1 of A7 platform;
  0x880 ~ 0x8BF: PGC for SCU of A7 platform;
  0xA00 ~ 0xA3F: PGC for fastmix/megamix;
  0xC00 ~ 0xC3F: PGC for MIPI PHY;
  0xC40 ~ 0xC7F: PGC for PCIe_PHY;
  0xC80 ~ 0xCBF: PGC for USB OTG1 PHY;
  0xCC0 ~ 0xCFF: PGC for USB OTG2 PHY;
  0xD00 ~ 0xD3F: PGC for USB HSIC PHY;

  Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
  Fixes: 03aa12629fc4 ("soc: imx: Add GPCv2 power gating driver")
  Acked-by: Andrey Smirnov <andrew.smirnov@gmail.com>
  Reviewed-by: Fabio Estevam <fabio.estevam@nxp.com>
  Signed-off-by: Shawn Guo <shawnguo@kernel.org>

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/soc/imx/gpcv2.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c
index f16598e97..158bfc02d 100644
--- a/drivers/soc/imx/gpcv2.c
+++ b/drivers/soc/imx/gpcv2.c
@@ -45,10 +45,15 @@
 
 #define GPC_M4_PU_PDN_FLG		0x1bc
 
-
-#define PGC_MIPI			4
-#define PGC_PCIE			5
-#define PGC_USB_HSIC			8
+/*
+ * The PGC offset values in Reference Manual
+ * (Rev. 1, 01/2018 and the older ones) GPC chapter's
+ * GPC_PGC memory map are incorrect, below offset
+ * values are from design RTL.
+ */
+#define PGC_MIPI                       16
+#define PGC_PCIE                       17
+#define PGC_USB_HSIC                   20
 #define GPC_PGC_CTRL(n)			(0x800 + (n) * 0x40)
 #define GPC_PGC_SR(n)			(GPC_PGC_CTRL(n) + 0xc)
 
-- 
2.20.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 12/21] reset: Add i.MX7 SRC reset driver
  2019-01-09  7:11 [PATCH 00/21] PCIe support for i.MX7 Andrey Smirnov
                   ` (10 preceding siblings ...)
  2019-01-09  7:12 ` [PATCH 11/21] soc: imx: gpcv2: correct PGC offset Andrey Smirnov
@ 2019-01-09  7:12 ` Andrey Smirnov
  2019-01-09  7:12 ` [PATCH 13/21] reset: imx7: Fix always writing bits as 0 Andrey Smirnov
                   ` (8 subsequent siblings)
  20 siblings, 0 replies; 27+ messages in thread
From: Andrey Smirnov @ 2019-01-09  7:12 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Port of a Linux commit abf97755ae31aaaf35156438dd3036e96f66da83

  Add reset controller driver exposing various reset faculties,
  implemented by System Reset Controller IP block.

  Cc: Lucas Stach <l.stach@pengutronix.de>
  Cc: Mark Rutland <mark.rutland@arm.com>
  Cc: devicetree@vger.kernel.org
  Cc: linux-kernel@vger.kernel.org
  Cc: linux-arm-kernel@lists.infradead.org
  Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
  Acked-by: Rob Herring <robh@kernel.org>
  Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/reset/Kconfig      |  11 +++
 drivers/reset/Makefile     |   1 +
 drivers/reset/reset-imx7.c | 151 +++++++++++++++++++++++++++++++++++++
 3 files changed, 163 insertions(+)
 create mode 100644 drivers/reset/reset-imx7.c

diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index c9d04f797..caf1dc9ac 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -11,3 +11,14 @@ menuconfig RESET_CONTROLLER
 	  via GPIOs or SoC-internal reset controller modules.
 
 	  If unsure, say no.
+
+if RESET_CONTROLLER
+
+config RESET_IMX7
+	bool "i.MX7 Reset Driver"
+	default SOC_IMX7D
+	select MFD_SYSCON
+	help
+	  This enables the reset controller driver for i.MX7 SoCs.
+
+endif
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 52b10cd48..0b55caa20 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_RESET_CONTROLLER) += core.o
 obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o
+obj-$(CONFIG_RESET_IMX7) += reset-imx7.o
diff --git a/drivers/reset/reset-imx7.c b/drivers/reset/reset-imx7.c
new file mode 100644
index 000000000..c8b7f86d4
--- /dev/null
+++ b/drivers/reset/reset-imx7.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2017, Impinj, Inc.
+ *
+ * i.MX7 System Reset Controller (SRC) driver
+ *
+ * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <common.h>
+#include <dt-bindings/reset/imx7-reset.h>
+#include <init.h>
+#include <linux/err.h>
+#include <linux/reset-controller.h>
+#include <mfd/syscon.h>
+#include <regmap.h>
+
+struct imx7_src {
+	struct reset_controller_dev rcdev;
+	struct regmap *regmap;
+};
+
+enum imx7_src_registers {
+	SRC_A7RCR0		= 0x0004,
+	SRC_M4RCR		= 0x000c,
+	SRC_ERCR		= 0x0014,
+	SRC_HSICPHY_RCR		= 0x001c,
+	SRC_USBOPHY1_RCR	= 0x0020,
+	SRC_USBOPHY2_RCR	= 0x0024,
+	SRC_MIPIPHY_RCR		= 0x0028,
+	SRC_PCIEPHY_RCR		= 0x002c,
+	SRC_DDRC_RCR		= 0x1000,
+};
+
+struct imx7_src_signal {
+	unsigned int offset, bit;
+};
+
+static const struct imx7_src_signal imx7_src_signals[IMX7_RESET_NUM] = {
+	[IMX7_RESET_A7_CORE_POR_RESET0] = { SRC_A7RCR0, BIT(0) },
+	[IMX7_RESET_A7_CORE_POR_RESET1] = { SRC_A7RCR0, BIT(1) },
+	[IMX7_RESET_A7_CORE_RESET0]     = { SRC_A7RCR0, BIT(4) },
+	[IMX7_RESET_A7_CORE_RESET1]	= { SRC_A7RCR0, BIT(5) },
+	[IMX7_RESET_A7_DBG_RESET0]	= { SRC_A7RCR0, BIT(8) },
+	[IMX7_RESET_A7_DBG_RESET1]	= { SRC_A7RCR0, BIT(9) },
+	[IMX7_RESET_A7_ETM_RESET0]	= { SRC_A7RCR0, BIT(12) },
+	[IMX7_RESET_A7_ETM_RESET1]	= { SRC_A7RCR0, BIT(13) },
+	[IMX7_RESET_A7_SOC_DBG_RESET]	= { SRC_A7RCR0, BIT(20) },
+	[IMX7_RESET_A7_L2RESET]		= { SRC_A7RCR0, BIT(21) },
+	[IMX7_RESET_SW_M4C_RST]		= { SRC_M4RCR, BIT(1) },
+	[IMX7_RESET_SW_M4P_RST]		= { SRC_M4RCR, BIT(2) },
+	[IMX7_RESET_EIM_RST]		= { SRC_ERCR, BIT(0) },
+	[IMX7_RESET_HSICPHY_PORT_RST]	= { SRC_HSICPHY_RCR, BIT(1) },
+	[IMX7_RESET_USBPHY1_POR]	= { SRC_USBOPHY1_RCR, BIT(0) },
+	[IMX7_RESET_USBPHY1_PORT_RST]	= { SRC_USBOPHY1_RCR, BIT(1) },
+	[IMX7_RESET_USBPHY2_POR]	= { SRC_USBOPHY2_RCR, BIT(0) },
+	[IMX7_RESET_USBPHY2_PORT_RST]	= { SRC_USBOPHY2_RCR, BIT(1) },
+	[IMX7_RESET_MIPI_PHY_MRST]	= { SRC_MIPIPHY_RCR, BIT(1) },
+	[IMX7_RESET_MIPI_PHY_SRST]	= { SRC_MIPIPHY_RCR, BIT(2) },
+	[IMX7_RESET_PCIEPHY]		= { SRC_PCIEPHY_RCR, BIT(2) | BIT(1) },
+	[IMX7_RESET_PCIEPHY_PERST]	= { SRC_PCIEPHY_RCR, BIT(3) },
+	[IMX7_RESET_PCIE_CTRL_APPS_EN]	= { SRC_PCIEPHY_RCR, BIT(6) },
+	[IMX7_RESET_DDRC_PRST]		= { SRC_DDRC_RCR, BIT(0) },
+	[IMX7_RESET_DDRC_CORE_RST]	= { SRC_DDRC_RCR, BIT(1) },
+};
+
+static struct imx7_src *to_imx7_src(struct reset_controller_dev *rcdev)
+{
+	return container_of(rcdev, struct imx7_src, rcdev);
+}
+
+static int imx7_reset_set(struct reset_controller_dev *rcdev,
+			  unsigned long id, bool assert)
+{
+	struct imx7_src *imx7src = to_imx7_src(rcdev);
+	const struct imx7_src_signal *signal = &imx7_src_signals[id];
+	unsigned int value = 0;
+
+	switch (id) {
+	case IMX7_RESET_PCIEPHY:
+		/*
+		 * wait for more than 10us to release phy g_rst and
+		 * btnrst
+		 */
+		if (!assert)
+			udelay(10);
+		break;
+
+	case IMX7_RESET_PCIE_CTRL_APPS_EN:
+		value = (assert) ? 0 : signal->bit;
+		break;
+	}
+
+	return regmap_update_bits(imx7src->regmap,
+				  signal->offset, signal->bit, value);
+}
+
+static int imx7_reset_assert(struct reset_controller_dev *rcdev,
+			     unsigned long id)
+{
+	return imx7_reset_set(rcdev, id, true);
+}
+
+static int imx7_reset_deassert(struct reset_controller_dev *rcdev,
+			       unsigned long id)
+{
+	return imx7_reset_set(rcdev, id, false);
+}
+
+static struct reset_control_ops imx7_reset_ops = {
+	.assert		= imx7_reset_assert,
+	.deassert	= imx7_reset_deassert,
+};
+
+static int imx7_reset_probe(struct device_d *dev)
+{
+	struct imx7_src *imx7src;
+
+	imx7src = xzalloc(sizeof(*imx7src));
+	imx7src->regmap = syscon_node_to_regmap(dev->device_node);
+	if (IS_ERR(imx7src->regmap)) {
+		dev_err(dev, "Unable to get imx7-src regmap");
+		return PTR_ERR(imx7src->regmap);
+	}
+
+	imx7src->rcdev.nr_resets = IMX7_RESET_NUM;
+	imx7src->rcdev.ops       = &imx7_reset_ops;
+	imx7src->rcdev.of_node   = dev->device_node;
+
+	return reset_controller_register(&imx7src->rcdev);
+}
+
+static const struct of_device_id imx7_reset_dt_ids[] = {
+	{ .compatible = "fsl,imx7d-src", },
+	{ /* sentinel */ },
+};
+
+static struct driver_d imx7_reset_driver = {
+	.name = "imx7d-src",
+	.probe = imx7_reset_probe,
+	.of_compatible = DRV_OF_COMPAT(imx7_reset_dt_ids),
+};
+device_platform_driver(imx7_reset_driver);
-- 
2.20.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 13/21] reset: imx7: Fix always writing bits as 0
  2019-01-09  7:11 [PATCH 00/21] PCIe support for i.MX7 Andrey Smirnov
                   ` (11 preceding siblings ...)
  2019-01-09  7:12 ` [PATCH 12/21] reset: Add i.MX7 SRC reset driver Andrey Smirnov
@ 2019-01-09  7:12 ` Andrey Smirnov
  2019-01-10  7:38   ` Sascha Hauer
  2019-01-09  7:12 ` [PATCH 14/21] reset: Mark local functions as static Andrey Smirnov
                   ` (7 subsequent siblings)
  20 siblings, 1 reply; 27+ messages in thread
From: Andrey Smirnov @ 2019-01-09  7:12 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Port of a Linux commit 26fce0557fa639fb7bbc33e31a57cff7df25c3a0

  Right now the only user of reset-imx7 is pci-imx6 and the
  reset_control_assert and deassert calls on pciephy_reset don't toggle
  the PCIEPHY_BTN and PCIEPHY_G_RST bits as expected. Fix this by writing
  1 or 0 respectively.

  The reference manual is not very clear regarding SRC_PCIEPHY_RCR but for
  other registers like MIPIPHY and HSICPHY the bits are explicitly
  documented as "1 means assert, 0 means deassert".

  The values are still reversed for IMX7_RESET_PCIE_CTRL_APPS_EN.

  Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
  Reviewed-by: Lucas Stach <l.stach@pengutronix.de>
  Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/reset/reset-imx7.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/reset/reset-imx7.c b/drivers/reset/reset-imx7.c
index c8b7f86d4..6dc5de16a 100644
--- a/drivers/reset/reset-imx7.c
+++ b/drivers/reset/reset-imx7.c
@@ -82,7 +82,7 @@ static int imx7_reset_set(struct reset_controller_dev *rcdev,
 {
 	struct imx7_src *imx7src = to_imx7_src(rcdev);
 	const struct imx7_src_signal *signal = &imx7_src_signals[id];
-	unsigned int value = 0;
+	unsigned int value = assert ? signal->bit : 0;;
 
 	switch (id) {
 	case IMX7_RESET_PCIEPHY:
-- 
2.20.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 14/21] reset: Mark local functions as static
  2019-01-09  7:11 [PATCH 00/21] PCIe support for i.MX7 Andrey Smirnov
                   ` (12 preceding siblings ...)
  2019-01-09  7:12 ` [PATCH 13/21] reset: imx7: Fix always writing bits as 0 Andrey Smirnov
@ 2019-01-09  7:12 ` Andrey Smirnov
  2019-01-09  7:12 ` [PATCH 15/21] PCI: imx6: Add code to support i.MX7D Andrey Smirnov
                   ` (6 subsequent siblings)
  20 siblings, 0 replies; 27+ messages in thread
From: Andrey Smirnov @ 2019-01-09  7:12 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

There are no outside users of of_reset_control_get() or
gpio_reset_control_get(), so mark them as static. This allows us to
avoid "no previous prototype" warning as well.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/reset/core.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 59f75ca47..99b9c8065 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -147,8 +147,8 @@ EXPORT_SYMBOL_GPL(reset_control_deassert);
  *
  * Use of id names is optional.
  */
-struct reset_control *of_reset_control_get(struct device_node *node,
-					   const char *id)
+static struct reset_control *of_reset_control_get(struct device_node *node,
+						  const char *id)
 {
 	struct reset_control *rstc = ERR_PTR(-ENODEV);
 	struct reset_controller_dev *r, *rcdev;
@@ -194,9 +194,9 @@ struct reset_control *of_reset_control_get(struct device_node *node,
 
 	return rstc;
 }
-EXPORT_SYMBOL_GPL(of_reset_control_get);
 
-struct reset_control *gpio_reset_control_get(struct device_d *dev, const char *id)
+static struct reset_control *
+gpio_reset_control_get(struct device_d *dev, const char *id)
 {
 	struct reset_control *rc;
 	int gpio;
-- 
2.20.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 15/21] PCI: imx6: Add code to support i.MX7D
  2019-01-09  7:11 [PATCH 00/21] PCIe support for i.MX7 Andrey Smirnov
                   ` (13 preceding siblings ...)
  2019-01-09  7:12 ` [PATCH 14/21] reset: Mark local functions as static Andrey Smirnov
@ 2019-01-09  7:12 ` Andrey Smirnov
  2019-01-09  7:12 ` [PATCH 16/21] PCI: imx6: Allow probe deferral by reset GPIO Andrey Smirnov
                   ` (5 subsequent siblings)
  20 siblings, 0 replies; 27+ messages in thread
From: Andrey Smirnov @ 2019-01-09  7:12 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Port of a Linux commit 9b3fe6796d7c0e0c2b87243ce0c7f4744c54efad

  Add various bits of code needed to support i.MX7D variant of the IP.

  Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
  Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
  Reviewed-by: Lucas Stach <l.stach@pengutronix.de>
  Acked-by: Lee Jones <lee.jones@linaro.org>
  Acked-by: Rob Herring <robh@kernel.org>
  Cc: yurovsky@gmail.com
  Cc: Mark Rutland <mark.rutland@arm.com>
  Cc: Fabio Estevam <fabio.estevam@nxp.com>
  Cc: Dong Aisheng <dongas86@gmail.com>
  Cc: linux-arm-kernel@lists.infradead.org
  Cc: devicetree@vger.kernel.org

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 arch/arm/mach-imx/Kconfig |   1 +
 drivers/pci/Kconfig       |   4 +-
 drivers/pci/pci-imx6.c    | 166 ++++++++++++++++++++++++++++----------
 3 files changed, 125 insertions(+), 46 deletions(-)

diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index f14c9c3ed..3ad922c50 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -173,6 +173,7 @@ config ARCH_IMX7
 	select COMMON_CLK_OF_PROVIDER
 	select ARCH_HAS_FEC_IMX
 	select ARCH_HAS_IMX_GPT
+	select HW_HAS_PCI
 
 config ARCH_IMX8MQ
 	bool
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 1c45a1c22..d81afb3d2 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -41,8 +41,8 @@ config PCI_TEGRA
 	select PCI
 
 config PCI_IMX6
-	bool "Freescale i.MX6 PCIe controller"
-	depends on ARCH_IMX6
+	bool "Freescale i.MX6/7 PCIe controller"
+	depends on ARCH_IMX6 || ARCH_IMX7
 	select PCIE_DW
 	select OF_PCI
 	select PCI
diff --git a/drivers/pci/pci-imx6.c b/drivers/pci/pci-imx6.c
index 38e002a1c..6471f95b6 100644
--- a/drivers/pci/pci-imx6.c
+++ b/drivers/pci/pci-imx6.c
@@ -27,8 +27,10 @@
 #include <linux/reset.h>
 #include <linux/sizes.h>
 #include <mfd/imx6q-iomuxc-gpr.h>
+#include <mfd/imx7-iomuxc-gpr.h>
 
 #include <mach/imx6-regs.h>
+#include <mach/imx7-regs.h>
 
 #include "pcie-designware.h"
 
@@ -37,6 +39,7 @@
 enum imx6_pcie_variants {
 	IMX6Q,
 	IMX6QP,
+	IMX7D,
 };
 
 struct imx6_pcie {
@@ -46,6 +49,8 @@ struct imx6_pcie {
 	struct clk		*pcie_phy;
 	struct clk		*pcie;
 	void __iomem		*iomuxc_gpr;
+	struct reset_control	*pciephy_reset;
+	struct reset_control	*apps_reset;
 	enum imx6_pcie_variants variant;
 	u32                     tx_deemph_gen1;
 	u32                     tx_deemph_gen2_3p5db;
@@ -55,6 +60,11 @@ struct imx6_pcie {
 	int			link_gen;
 };
 
+/* Parameters for the waiting for PCIe PHY PLL to lock on i.MX7 */
+#define PHY_PLL_LOCK_WAIT_MAX_RETRIES  2000
+#define PHY_PLL_LOCK_WAIT_USLEEP_MIN   50
+#define PHY_PLL_LOCK_WAIT_USLEEP_MAX   200
+
 /* PCIe Root Complex registers (memory-mapped) */
 #define PCIE_RC_LCR				0x7c
 #define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1	0x1
@@ -239,6 +249,10 @@ static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie)
 	u32 gpr1;
 
 	switch (imx6_pcie->variant) {
+	case IMX7D:
+		reset_control_assert(imx6_pcie->pciephy_reset);
+		reset_control_assert(imx6_pcie->apps_reset);
+		break;
 	case IMX6QP:
 		gpr1 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR1);
 		gpr1 |= IMX6Q_GPR1_PCIE_SW_RST;
@@ -259,24 +273,49 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie)
 {
 	u32 gpr1;
 
-	/* power up core phy and enable ref clock */
-	gpr1 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR1);
-	gpr1 &= ~IMX6Q_GPR1_PCIE_TEST_PD;
-	writel(gpr1, imx6_pcie->iomuxc_gpr + IOMUXC_GPR1);
-	/*
-	 * the async reset input need ref clock to sync internally,
-	 * when the ref clock comes after reset, internal synced
-	 * reset time is too short, cannot meet the requirement.
-	 * add one ~10us delay here.
-	 */
-	udelay(10);
-	gpr1 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR1);
-	gpr1 |= IMX6Q_GPR1_PCIE_REF_CLK_EN;
-	writel(gpr1, imx6_pcie->iomuxc_gpr + IOMUXC_GPR1);
+	switch (imx6_pcie->variant) {
+	case IMX6QP:
+	case IMX6Q:		/* FALLTHROUGH */
+		/* power up core phy and enable ref clock */
+		gpr1 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR1);
+		gpr1 &= ~IMX6Q_GPR1_PCIE_TEST_PD;
+		writel(gpr1, imx6_pcie->iomuxc_gpr + IOMUXC_GPR1);
+		/*
+		 * the async reset input need ref clock to sync
+		 * internally, when the ref clock comes after reset,
+		 * internal synced reset time is too short, cannot
+		 * meet the requirement.  add one ~10us delay here.
+		 */
+		udelay(10);
+		gpr1 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR1);
+		gpr1 |= IMX6Q_GPR1_PCIE_REF_CLK_EN;
+		writel(gpr1, imx6_pcie->iomuxc_gpr + IOMUXC_GPR1);
+		break;
+	case IMX7D:
+		break;
+	}
 
 	return 0;
 }
 
+static void imx7d_pcie_wait_for_phy_pll_lock(struct imx6_pcie *imx6_pcie)
+{
+	u32 val;
+	unsigned int retries;
+	struct device_d *dev = imx6_pcie->pci->dev;
+
+	for (retries = 0; retries < PHY_PLL_LOCK_WAIT_MAX_RETRIES; retries++) {
+		val = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR22);
+
+		if (val & IMX7D_GPR22_PCIE_PHY_PLL_LOCKED)
+			return;
+
+		udelay(PHY_PLL_LOCK_WAIT_USLEEP_MAX);
+	}
+
+	dev_err(dev, "PCIe PLL lock timeout\n");
+}
+
 static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie)
 {
 	struct device_d *dev = imx6_pcie->pci->dev;
@@ -321,6 +360,10 @@ static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie)
 	 * Release the PCIe PHY reset here
 	 */
 	switch (imx6_pcie->variant) {
+	case IMX7D:
+		reset_control_deassert(imx6_pcie->pciephy_reset);
+		imx7d_pcie_wait_for_phy_pll_lock(imx6_pcie);
+		break;
 	case IMX6QP:
 		gpr1 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR1);
 		gpr1 &= ~IMX6Q_GPR1_PCIE_SW_RST;
@@ -347,38 +390,48 @@ static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie)
 	u32 gpr12, gpr8;
 
 	gpr12 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
-	gpr12 &= ~IMX6Q_GPR12_PCIE_CTL_2;
-	writel(gpr12, imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
 
-	/* configure constant input signal to the pcie ctrl and phy */
-	gpr12 &= ~IMX6Q_GPR12_DEVICE_TYPE;
-	gpr12 |= PCI_EXP_TYPE_ROOT_PORT << 12;
-	writel(gpr12, imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
+	switch (imx6_pcie->variant) {
+	case IMX7D:
+		gpr12 &= ~IMX7D_GPR12_PCIE_PHY_REFCLK_SEL;
+		writel(gpr12, imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
+		break;
+	case IMX6QP:
+	case IMX6Q:	/* FALLTHROUGH */
+		gpr12 &= ~IMX6Q_GPR12_PCIE_CTL_2;
+		writel(gpr12, imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
 
-	gpr12 &= ~IMX6Q_GPR12_LOS_LEVEL;
-	gpr12 |= 9 << 4;
-	writel(gpr12, imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
+		/* configure constant input signal to the pcie ctrl and phy */
+		gpr12 &= ~IMX6Q_GPR12_LOS_LEVEL;
+		gpr12 |= 9 << 4;
+		writel(gpr12, imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
 
-	gpr8 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR8);
-	gpr8 &= ~IMX6Q_GPR8_TX_DEEMPH_GEN1;
-	gpr8 |= imx6_pcie->tx_deemph_gen1 << 0;
-	writel(gpr8, imx6_pcie->iomuxc_gpr + IOMUXC_GPR8);
+		gpr8 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR8);
+		gpr8 &= ~IMX6Q_GPR8_TX_DEEMPH_GEN1;
+		gpr8 |= imx6_pcie->tx_deemph_gen1 << 0;
+		writel(gpr8, imx6_pcie->iomuxc_gpr + IOMUXC_GPR8);
 
-	gpr8 &= ~IMX6Q_GPR8_TX_DEEMPH_GEN2_3P5DB;
-	gpr8 |= imx6_pcie->tx_deemph_gen2_3p5db << 6;
-	writel(gpr8, imx6_pcie->iomuxc_gpr + IOMUXC_GPR8);
+		gpr8 &= ~IMX6Q_GPR8_TX_DEEMPH_GEN2_3P5DB;
+		gpr8 |= imx6_pcie->tx_deemph_gen2_3p5db << 6;
+		writel(gpr8, imx6_pcie->iomuxc_gpr + IOMUXC_GPR8);
 
-	gpr8 &= ~IMX6Q_GPR8_TX_DEEMPH_GEN2_6DB;
-	gpr8 |= imx6_pcie->tx_deemph_gen2_6db << 12;
-	writel(gpr8, imx6_pcie->iomuxc_gpr + IOMUXC_GPR8);
+		gpr8 &= ~IMX6Q_GPR8_TX_DEEMPH_GEN2_6DB;
+		gpr8 |= imx6_pcie->tx_deemph_gen2_6db << 12;
+		writel(gpr8, imx6_pcie->iomuxc_gpr + IOMUXC_GPR8);
 
-	gpr8 &= ~IMX6Q_GPR8_TX_SWING_FULL;
-	gpr8 |= imx6_pcie->tx_swing_full << 18;
-	writel(gpr8, imx6_pcie->iomuxc_gpr + IOMUXC_GPR8);
+		gpr8 &= ~IMX6Q_GPR8_TX_SWING_FULL;
+		gpr8 |= imx6_pcie->tx_swing_full << 18;
+		writel(gpr8, imx6_pcie->iomuxc_gpr + IOMUXC_GPR8);
 
-	gpr8 &= ~IMX6Q_GPR8_TX_SWING_LOW;
-	gpr8 |= imx6_pcie->tx_swing_low << 25;
-	writel(gpr8, imx6_pcie->iomuxc_gpr + IOMUXC_GPR8);
+		gpr8 &= ~IMX6Q_GPR8_TX_SWING_LOW;
+		gpr8 |= imx6_pcie->tx_swing_low << 25;
+		writel(gpr8, imx6_pcie->iomuxc_gpr + IOMUXC_GPR8);
+		break;
+	}
+
+	gpr12 &= ~IMX6Q_GPR12_DEVICE_TYPE;
+	gpr12 |= PCI_EXP_TYPE_ROOT_PORT << 12;
+	writel(gpr12, imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
 }
 
 static int imx6_pcie_wait_for_link(struct imx6_pcie *imx6_pcie)
@@ -424,9 +477,13 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
 	dw_pcie_writel_dbi(pci, PCIE_RC_LCR, tmp);
 
 	/* Start LTSSM. */
-	gpr12 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
-	gpr12 |= IMX6Q_GPR12_PCIE_CTL_2;
-	writel(gpr12, imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
+	if (imx6_pcie->variant == IMX7D) {
+		reset_control_deassert(imx6_pcie->apps_reset);
+	} else {
+		gpr12 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
+		gpr12 |= IMX6Q_GPR12_PCIE_CTL_2;
+		writel(gpr12, imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
+	}
 
 	ret = imx6_pcie_wait_for_link(imx6_pcie);
 	if (ret)
@@ -577,8 +634,28 @@ static int __init imx6_pcie_probe(struct device_d *dev)
 		return PTR_ERR(imx6_pcie->pcie);
 	}
 
-	/* Grab GPR config register range */
-	imx6_pcie->iomuxc_gpr = IOMEM(MX6_IOMUXC_BASE_ADDR);
+	switch (imx6_pcie->variant) {
+	case IMX7D:
+		imx6_pcie->iomuxc_gpr = IOMEM(MX7_IOMUXC_GPR_BASE_ADDR);
+
+		imx6_pcie->pciephy_reset = reset_control_get(dev, "pciephy");
+		if (IS_ERR(imx6_pcie->pciephy_reset)) {
+			dev_err(dev, "Failed to get PCIEPHY reset contol\n");
+			return PTR_ERR(imx6_pcie->pciephy_reset);
+		}
+
+		imx6_pcie->apps_reset = reset_control_get(dev, "apps");
+		if (IS_ERR(imx6_pcie->apps_reset)) {
+			dev_err(dev, "Failed to get PCIE APPS reset contol\n");
+			return PTR_ERR(imx6_pcie->apps_reset);
+		}
+		break;
+	default:
+		/* Grab GPR config register range */
+		imx6_pcie->iomuxc_gpr = IOMEM(MX6_IOMUXC_BASE_ADDR);
+		break;
+	}
+
 
 	/* Grab PCIe PHY Tx Settings */
 	if (of_property_read_u32(np, "fsl,tx-deemph-gen1",
@@ -653,6 +730,7 @@ static void imx6_pcie_remove(struct device_d *dev)
 static struct of_device_id imx6_pcie_of_match[] = {
 	{ .compatible = "fsl,imx6q-pcie",  .data = (void *)IMX6Q,  },
 	{ .compatible = "fsl,imx6qp-pcie", .data = (void *)IMX6QP, },
+	{ .compatible = "fsl,imx7d-pcie",  .data = (void *)IMX7D,  },
 	{},
 };
 
-- 
2.20.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 16/21] PCI: imx6: Allow probe deferral by reset GPIO
  2019-01-09  7:11 [PATCH 00/21] PCIe support for i.MX7 Andrey Smirnov
                   ` (14 preceding siblings ...)
  2019-01-09  7:12 ` [PATCH 15/21] PCI: imx6: Add code to support i.MX7D Andrey Smirnov
@ 2019-01-09  7:12 ` Andrey Smirnov
  2019-01-10  8:05   ` Sascha Hauer
  2019-01-09  7:12 ` [PATCH 17/21] PCI: imx6: Do not wait for speed change on i.MX7 Andrey Smirnov
                   ` (4 subsequent siblings)
  20 siblings, 1 reply; 27+ messages in thread
From: Andrey Smirnov @ 2019-01-09  7:12 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Port of a Linux commit bde4a5a00e761f55be92f62378cf5024ced79ee3

  Some designs implement reset GPIO via a GPIO expander connected to a
  peripheral bus.  One such example would be i.MX7 Sabre board where said
  GPIO is provided by SPI shift register connected to a bitbanged SPI bus.
  To support such designs, allow reset GPIO request to defer probing of the
  driver.

  Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
  Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
  Reviewed-by: Lucas Stach <l.stach@pengutronix.de>
  Cc: yurovsky@gmail.com
  Cc: Fabio Estevam <fabio.estevam@nxp.com>
  Cc: Dong Aisheng <dongas86@gmail.com>
  Cc: linux-arm-kernel@lists.infradead.org

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/pci/pci-imx6.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/pci/pci-imx6.c b/drivers/pci/pci-imx6.c
index 6471f95b6..517c6bef8 100644
--- a/drivers/pci/pci-imx6.c
+++ b/drivers/pci/pci-imx6.c
@@ -562,8 +562,8 @@ static const struct dw_pcie_host_ops imx6_pcie_host_ops = {
 	.host_init = imx6_pcie_host_init,
 };
 
-static int __init imx6_add_pcie_port(struct imx6_pcie *imx6_pcie,
-				     struct device_d *dev)
+static int imx6_add_pcie_port(struct imx6_pcie *imx6_pcie,
+			      struct device_d *dev)
 {
 	struct dw_pcie *pci = imx6_pcie->pci;
 	struct pcie_port *pp = &pci->pp;
@@ -581,7 +581,7 @@ static int __init imx6_add_pcie_port(struct imx6_pcie *imx6_pcie,
 	return 0;
 }
 
-static int __init imx6_pcie_probe(struct device_d *dev)
+static int imx6_pcie_probe(struct device_d *dev)
 {
 	struct resource *iores;
 	struct dw_pcie *pci;
@@ -606,6 +606,9 @@ static int __init imx6_pcie_probe(struct device_d *dev)
 
 	/* Fetch GPIOs */
 	imx6_pcie->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
+	if (imx6_pcie->reset_gpio == -EPROBE_DEFER)
+		return imx6_pcie->reset_gpio;
+
 	if (gpio_is_valid(imx6_pcie->reset_gpio)) {
 		ret = gpio_request_one(imx6_pcie->reset_gpio,
 					    GPIOF_OUT_INIT_LOW, "PCIe reset");
-- 
2.20.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 17/21] PCI: imx6: Do not wait for speed change on i.MX7
  2019-01-09  7:11 [PATCH 00/21] PCIe support for i.MX7 Andrey Smirnov
                   ` (15 preceding siblings ...)
  2019-01-09  7:12 ` [PATCH 16/21] PCI: imx6: Allow probe deferral by reset GPIO Andrey Smirnov
@ 2019-01-09  7:12 ` Andrey Smirnov
  2019-01-09  7:12 ` [PATCH 18/21] PCI: imx6: Do not switch speed if Gen2 is disabled Andrey Smirnov
                   ` (3 subsequent siblings)
  20 siblings, 0 replies; 27+ messages in thread
From: Andrey Smirnov @ 2019-01-09  7:12 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Port of a Linux commit e6dcd87fff69a9d454104b65569074855cf95b1e

  As can be seen from [1]:

    "...the different behavior between iMX6Q PCIe and iMX7D PCIe maybe caused
    by the different controller version.

    Regarding to the DOC description, the DIRECT_SPEED_CHANGE should be
    cleared after the speed change from GEN1 to GEN2. Unfortunately, when
    GEN1 device is used, the behavior is not documented.

    So, IC design guys run the simulation and find out the following
    behaviors:

       1. DIRECT_SPEED_CHANGE will be cleared in 7D after speed change
          from GEN1 to GEN2. This matches doc’s description

       2. set MAX link speed(PCIE_CAP_TARGET_LINK_SPEED=0x01) as GEN1 and
          re-run the simulation, DIRECT_SPEED_CHANGE will not be cleared;
          remain as 1, this matches your result, but function test is
          passed, so this bit should not affect the normal PCIe function."

  imx6_pcie_wait_for_speed_change() will report false failures for Gen1 ->
  Gen1 speed transition, so avoid doing that check and just rely on
  imx6_pcie_wait_for_link() only.

  [1] https://community.nxp.com/message/867943

  Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
  Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
  Reviewed-by: Lucas Stach <l.stach@pengutronix.de>
  Cc: yurovsky@gmail.com
  Cc: Fabio Estevam <fabio.estevam@nxp.com>
  Cc: Dong Aisheng <dongas86@gmail.com>
  Cc: linux-arm-kernel@lists.infradead.org

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/pci/pci-imx6.c | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/drivers/pci/pci-imx6.c b/drivers/pci/pci-imx6.c
index 517c6bef8..db7b10bc9 100644
--- a/drivers/pci/pci-imx6.c
+++ b/drivers/pci/pci-imx6.c
@@ -508,10 +508,21 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
 	tmp |= PORT_LOGIC_SPEED_CHANGE;
 	dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, tmp);
 
-	ret = imx6_pcie_wait_for_speed_change(imx6_pcie);
-	if (ret) {
-		dev_err(dev, "Failed to bring link up!\n");
-		goto err_reset_phy;
+	if (imx6_pcie->variant != IMX7D) {
+		/*
+		 * On i.MX7, DIRECT_SPEED_CHANGE behaves differently
+		 * from i.MX6 family when no link speed transition
+		 * occurs and we go Gen1 -> yep, Gen1. The difference
+		 * is that, in such case, it will not be cleared by HW
+		 * which will cause the following code to report false
+		 * failure.
+		 */
+
+		ret = imx6_pcie_wait_for_speed_change(imx6_pcie);
+		if (ret) {
+			dev_err(dev, "Failed to bring link up!\n");
+			goto err_reset_phy;
+		}
 	}
 
 	/* Make sure link training is finished as well! */
-- 
2.20.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 18/21] PCI: imx6: Do not switch speed if Gen2 is disabled
  2019-01-09  7:11 [PATCH 00/21] PCIe support for i.MX7 Andrey Smirnov
                   ` (16 preceding siblings ...)
  2019-01-09  7:12 ` [PATCH 17/21] PCI: imx6: Do not wait for speed change on i.MX7 Andrey Smirnov
@ 2019-01-09  7:12 ` Andrey Smirnov
  2019-01-09  7:12 ` [PATCH 19/21] PCI: imx6: Fix spelling mistake: "contol" -> "control" Andrey Smirnov
                   ` (2 subsequent siblings)
  20 siblings, 0 replies; 27+ messages in thread
From: Andrey Smirnov @ 2019-01-09  7:12 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Port of a Linux commit 93b226f9c65a951a91617f87ba1f05f14e59f26f

  Save a bit of time and avoid going through link speed change procedure in
  configuration where link max speed is limited to Gen1 in DT.

  Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
  Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
  Reviewed-by: Lucas Stach <l.stach@pengutronix.de>
  Cc: yurovsky@gmail.com
  Cc: Fabio Estevam <fabio.estevam@nxp.com>
  Cc: Dong Aisheng <dongas86@gmail.com>
  Cc: linux-arm-kernel@lists.infradead.org

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/pci/pci-imx6.c | 55 +++++++++++++++++++++---------------------
 1 file changed, 28 insertions(+), 27 deletions(-)

diff --git a/drivers/pci/pci-imx6.c b/drivers/pci/pci-imx6.c
index db7b10bc9..978c5392f 100644
--- a/drivers/pci/pci-imx6.c
+++ b/drivers/pci/pci-imx6.c
@@ -496,41 +496,42 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
 		tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK;
 		tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2;
 		dw_pcie_writel_dbi(pci, PCIE_RC_LCR, tmp);
-	} else {
-		dev_info(dev, "Link: Gen2 disabled\n");
-	}
-
-	/*
-	 * Start Directed Speed Change so the best possible speed both link
-	 * partners support can be negotiated.
-	 */
-	tmp = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
-	tmp |= PORT_LOGIC_SPEED_CHANGE;
-	dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, tmp);
 
-	if (imx6_pcie->variant != IMX7D) {
 		/*
-		 * On i.MX7, DIRECT_SPEED_CHANGE behaves differently
-		 * from i.MX6 family when no link speed transition
-		 * occurs and we go Gen1 -> yep, Gen1. The difference
-		 * is that, in such case, it will not be cleared by HW
-		 * which will cause the following code to report false
-		 * failure.
+		 * Start Directed Speed Change so the best possible
+		 * speed both link partners support can be negotiated.
 		 */
+		tmp = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
+		tmp |= PORT_LOGIC_SPEED_CHANGE;
+		dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, tmp);
+
+		if (imx6_pcie->variant != IMX7D) {
+			/*
+			 * On i.MX7, DIRECT_SPEED_CHANGE behaves
+			 * differently from i.MX6 family when no link
+			 * speed transition occurs and we go Gen1 ->
+			 * yep, Gen1. The difference is that, in such
+			 * case, it will not be cleared by HW which
+			 * will cause the following code to report
+			 * false failure.
+			 */
+
+			ret = imx6_pcie_wait_for_speed_change(imx6_pcie);
+			if (ret) {
+				dev_err(dev, "Failed to bring link up!\n");
+				goto err_reset_phy;
+			}
+		}
 
-		ret = imx6_pcie_wait_for_speed_change(imx6_pcie);
+		/* Make sure link training is finished as well! */
+		ret = imx6_pcie_wait_for_link(imx6_pcie);
 		if (ret) {
 			dev_err(dev, "Failed to bring link up!\n");
 			goto err_reset_phy;
 		}
-	}
-
-	/* Make sure link training is finished as well! */
-	ret = imx6_pcie_wait_for_link(imx6_pcie);
-	if (ret) {
-		dev_err(dev, "Failed to bring link up!\n");
-		goto err_reset_phy;
-	}
+	} else {
+		dev_info(dev, "Link: Gen2 disabled\n");
+        }
 
 	tmp = dw_pcie_readl_dbi(pci, PCIE_RC_LCSR);
 	dev_info(dev, "Link up, Gen%i\n", (tmp >> 16) & 0xf);
-- 
2.20.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 19/21] PCI: imx6: Fix spelling mistake: "contol" -> "control"
  2019-01-09  7:11 [PATCH 00/21] PCIe support for i.MX7 Andrey Smirnov
                   ` (17 preceding siblings ...)
  2019-01-09  7:12 ` [PATCH 18/21] PCI: imx6: Do not switch speed if Gen2 is disabled Andrey Smirnov
@ 2019-01-09  7:12 ` Andrey Smirnov
  2019-01-09  7:12 ` [PATCH 20/21] PCI: imx6: Drop unnecessary root_bus_nr setting Andrey Smirnov
  2019-01-09  7:12 ` [PATCH 21/21] PCI: imx6: Port imx6_pcie_ltssm_enable() Andrey Smirnov
  20 siblings, 0 replies; 27+ messages in thread
From: Andrey Smirnov @ 2019-01-09  7:12 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Port of a Linux commit 7221547e55b7929e4d46983f6f3ca15f36ee4dac

  Trivial fix to spelling mistake in dev_err message

  Signed-off-by: Colin Ian King <colin.king@canonical.com>
  Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
  Acked-by: Richard Zhu <hongxing.Zhu@nxp.com>

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/pci/pci-imx6.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/pci-imx6.c b/drivers/pci/pci-imx6.c
index 978c5392f..b8d54d17a 100644
--- a/drivers/pci/pci-imx6.c
+++ b/drivers/pci/pci-imx6.c
@@ -655,13 +655,13 @@ static int imx6_pcie_probe(struct device_d *dev)
 
 		imx6_pcie->pciephy_reset = reset_control_get(dev, "pciephy");
 		if (IS_ERR(imx6_pcie->pciephy_reset)) {
-			dev_err(dev, "Failed to get PCIEPHY reset contol\n");
+			dev_err(dev, "Failed to get PCIEPHY reset control\n");
 			return PTR_ERR(imx6_pcie->pciephy_reset);
 		}
 
 		imx6_pcie->apps_reset = reset_control_get(dev, "apps");
 		if (IS_ERR(imx6_pcie->apps_reset)) {
-			dev_err(dev, "Failed to get PCIE APPS reset contol\n");
+			dev_err(dev, "Failed to get PCIE APPS reset control\n");
 			return PTR_ERR(imx6_pcie->apps_reset);
 		}
 		break;
-- 
2.20.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 20/21] PCI: imx6: Drop unnecessary root_bus_nr setting
  2019-01-09  7:11 [PATCH 00/21] PCIe support for i.MX7 Andrey Smirnov
                   ` (18 preceding siblings ...)
  2019-01-09  7:12 ` [PATCH 19/21] PCI: imx6: Fix spelling mistake: "contol" -> "control" Andrey Smirnov
@ 2019-01-09  7:12 ` Andrey Smirnov
  2019-01-09  7:12 ` [PATCH 21/21] PCI: imx6: Port imx6_pcie_ltssm_enable() Andrey Smirnov
  20 siblings, 0 replies; 27+ messages in thread
From: Andrey Smirnov @ 2019-01-09  7:12 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Port of a Linux commit 39f712e989c5e591c58b65b62981b85027ba3103

  Function dw_pcie_host_init() already initializes the root_bus_nr field
  of 'struct pcie_port', so the -1 assignment prior to calling
  dw_pcie_host_init() in platform specific driver is not really needed.
  Drop it.

  Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
  Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
  Reviewed-by: Lucas Stach <l.stach@pengutronix.de>
  Cc: Richard Zhu <hongxing.zhu@nxp.com>
  Cc: Lucas Stach <l.stach@pengutronix.de>

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/pci/pci-imx6.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/pci/pci-imx6.c b/drivers/pci/pci-imx6.c
index b8d54d17a..573888a33 100644
--- a/drivers/pci/pci-imx6.c
+++ b/drivers/pci/pci-imx6.c
@@ -581,7 +581,6 @@ static int imx6_add_pcie_port(struct imx6_pcie *imx6_pcie,
 	struct pcie_port *pp = &pci->pp;
 	int ret;
 
-	pp->root_bus_nr = -1;
 	pp->ops = &imx6_pcie_host_ops;
 
 	ret = dw_pcie_host_init(pp);
-- 
2.20.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 21/21] PCI: imx6: Port imx6_pcie_ltssm_enable()
  2019-01-09  7:11 [PATCH 00/21] PCIe support for i.MX7 Andrey Smirnov
                   ` (19 preceding siblings ...)
  2019-01-09  7:12 ` [PATCH 20/21] PCI: imx6: Drop unnecessary root_bus_nr setting Andrey Smirnov
@ 2019-01-09  7:12 ` Andrey Smirnov
  20 siblings, 0 replies; 27+ messages in thread
From: Andrey Smirnov @ 2019-01-09  7:12 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Port imx6_pcie_ltssm_enable() from Linux kernel driver.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/pci/pci-imx6.c | 27 ++++++++++++++++++---------
 1 file changed, 18 insertions(+), 9 deletions(-)

diff --git a/drivers/pci/pci-imx6.c b/drivers/pci/pci-imx6.c
index 573888a33..ab67a552c 100644
--- a/drivers/pci/pci-imx6.c
+++ b/drivers/pci/pci-imx6.c
@@ -457,6 +457,23 @@ static int imx6_pcie_wait_for_speed_change(struct imx6_pcie *imx6_pcie)
 	return -EINVAL;
 }
 
+static void imx6_pcie_ltssm_enable(struct device_d *dev)
+{
+	struct imx6_pcie *imx6_pcie = dev->priv;
+	u32 gpr12;
+
+	switch (imx6_pcie->variant) {
+	case IMX6Q:
+	case IMX6QP:
+		gpr12 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
+		gpr12 |= IMX6Q_GPR12_PCIE_CTL_2;
+		writel(gpr12, imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
+		break;
+	case IMX7D:
+		reset_control_deassert(imx6_pcie->apps_reset);
+		break;
+	}
+}
 
 static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
 {
@@ -464,7 +481,6 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
 	struct device_d *dev = pci->dev;
 	uint32_t tmp;
 	int ret;
-	u32 gpr12;
 
 	/*
 	 * Force Gen1 operation when starting the link.  In case the link is
@@ -476,14 +492,7 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
 	tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1;
 	dw_pcie_writel_dbi(pci, PCIE_RC_LCR, tmp);
 
-	/* Start LTSSM. */
-	if (imx6_pcie->variant == IMX7D) {
-		reset_control_deassert(imx6_pcie->apps_reset);
-	} else {
-		gpr12 = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
-		gpr12 |= IMX6Q_GPR12_PCIE_CTL_2;
-		writel(gpr12, imx6_pcie->iomuxc_gpr + IOMUXC_GPR12);
-	}
+	imx6_pcie_ltssm_enable(dev);
 
 	ret = imx6_pcie_wait_for_link(imx6_pcie);
 	if (ret)
-- 
2.20.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [PATCH 10/21] soc: imx: gpcv2: fix regulator deferred probe
  2019-01-09  7:11 ` [PATCH 10/21] soc: imx: gpcv2: fix regulator deferred probe Andrey Smirnov
@ 2019-01-10  7:37   ` Sascha Hauer
  2019-01-10 19:20     ` Andrey Smirnov
  0 siblings, 1 reply; 27+ messages in thread
From: Sascha Hauer @ 2019-01-10  7:37 UTC (permalink / raw)
  To: Andrey Smirnov; +Cc: barebox

On Tue, Jan 08, 2019 at 11:11:59PM -0800, Andrey Smirnov wrote:
> Port of a Linux commit 9e01e2d56db23485a75864b6aeee8e443f024ddb
> 
>   If a regulator requests a deferred probe, the power domain gets
>   initialized twice. This leads to a list double add (without
>   list debugging the kernel hangs due to the double add later):
> 
>     WARNING: CPU: 0 PID: 19 at lib/list_debug.c:31 __list_add_valid+0xbc/0xc4
>     list_add double add: new=c1229754, prev=c12383b4, next=c1229754.
> 
>   Initialize the power domain after we get the regulator. Also do
>   not print an error in case the regulator defers probing.
> 
>   Cc: Fabio Estevam <fabio.estevam@nxp.com>
>   Cc: Andrey Smirnov <andrew.smirnov@gmail.com>
>   Cc: linux-arm-kernel@lists.infradead.org
>   Cc: linux-kernel@vger.kernel.org
>   Fixes: 03aa12629fc4 ("soc: imx: Add GPCv2 power gating driver")
>   Signed-off-by: Stefan Agner <stefan@agner.ch>
>   Acked-by: Andrey Smirnov <andrew.smirnov@gmail.com>
>   Tested-by: Andrey Smirnov <andrew.smirnov@gmail.com>
>   Signed-off-by: Shawn Guo <shawnguo@kernel.org>
> 
> Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
> ---
>  drivers/soc/imx/gpcv2.c | 15 ++++++++-------
>  1 file changed, 8 insertions(+), 7 deletions(-)

This file has been added in the last patch. Please squash this patch and
the next one into it.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [PATCH 13/21] reset: imx7: Fix always writing bits as 0
  2019-01-09  7:12 ` [PATCH 13/21] reset: imx7: Fix always writing bits as 0 Andrey Smirnov
@ 2019-01-10  7:38   ` Sascha Hauer
  0 siblings, 0 replies; 27+ messages in thread
From: Sascha Hauer @ 2019-01-10  7:38 UTC (permalink / raw)
  To: Andrey Smirnov; +Cc: barebox

On Tue, Jan 08, 2019 at 11:12:02PM -0800, Andrey Smirnov wrote:
> Port of a Linux commit 26fce0557fa639fb7bbc33e31a57cff7df25c3a0
> 
>   Right now the only user of reset-imx7 is pci-imx6 and the
>   reset_control_assert and deassert calls on pciephy_reset don't toggle
>   the PCIEPHY_BTN and PCIEPHY_G_RST bits as expected. Fix this by writing
>   1 or 0 respectively.
> 
>   The reference manual is not very clear regarding SRC_PCIEPHY_RCR but for
>   other registers like MIPIPHY and HSICPHY the bits are explicitly
>   documented as "1 means assert, 0 means deassert".
> 
>   The values are still reversed for IMX7_RESET_PCIE_CTRL_APPS_EN.
> 
>   Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>   Reviewed-by: Lucas Stach <l.stach@pengutronix.de>
>   Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
> 
> Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
> ---
>  drivers/reset/reset-imx7.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)

Should also be part of the last patch.

Sascha


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [PATCH 16/21] PCI: imx6: Allow probe deferral by reset GPIO
  2019-01-09  7:12 ` [PATCH 16/21] PCI: imx6: Allow probe deferral by reset GPIO Andrey Smirnov
@ 2019-01-10  8:05   ` Sascha Hauer
  2019-01-12  4:24     ` Andrey Smirnov
  0 siblings, 1 reply; 27+ messages in thread
From: Sascha Hauer @ 2019-01-10  8:05 UTC (permalink / raw)
  To: Andrey Smirnov; +Cc: barebox

On Tue, Jan 08, 2019 at 11:12:05PM -0800, Andrey Smirnov wrote:
> Port of a Linux commit bde4a5a00e761f55be92f62378cf5024ced79ee3
> 
>   Some designs implement reset GPIO via a GPIO expander connected to a
>   peripheral bus.  One such example would be i.MX7 Sabre board where said
>   GPIO is provided by SPI shift register connected to a bitbanged SPI bus.
>   To support such designs, allow reset GPIO request to defer probing of the
>   driver.
> 
>   Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
>   Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
>   Reviewed-by: Lucas Stach <l.stach@pengutronix.de>
>   Cc: yurovsky@gmail.com
>   Cc: Fabio Estevam <fabio.estevam@nxp.com>
>   Cc: Dong Aisheng <dongas86@gmail.com>
>   Cc: linux-arm-kernel@lists.infradead.org
> 
> Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
> ---
>  drivers/pci/pci-imx6.c | 9 ++++++---
>  1 file changed, 6 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/pci/pci-imx6.c b/drivers/pci/pci-imx6.c
> index 6471f95b6..517c6bef8 100644
> --- a/drivers/pci/pci-imx6.c
> +++ b/drivers/pci/pci-imx6.c
> @@ -562,8 +562,8 @@ static const struct dw_pcie_host_ops imx6_pcie_host_ops = {
>  	.host_init = imx6_pcie_host_init,
>  };
>  
> -static int __init imx6_add_pcie_port(struct imx6_pcie *imx6_pcie,
> -				     struct device_d *dev)
> +static int imx6_add_pcie_port(struct imx6_pcie *imx6_pcie,
> +			      struct device_d *dev)
>  {
>  	struct dw_pcie *pci = imx6_pcie->pci;
>  	struct pcie_port *pp = &pci->pp;
> @@ -581,7 +581,7 @@ static int __init imx6_add_pcie_port(struct imx6_pcie *imx6_pcie,
>  	return 0;
>  }
>  
> -static int __init imx6_pcie_probe(struct device_d *dev)
> +static int imx6_pcie_probe(struct device_d *dev)
>  {
>  	struct resource *iores;
>  	struct dw_pcie *pci;
> @@ -606,6 +606,9 @@ static int __init imx6_pcie_probe(struct device_d *dev)
>  
>  	/* Fetch GPIOs */
>  	imx6_pcie->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
> +	if (imx6_pcie->reset_gpio == -EPROBE_DEFER)
> +		return imx6_pcie->reset_gpio;

Normally probe function run only once in barebox and in that case I do
not care about loosing memory. When doing probe deferral here we loose a
private data struct with each deferred probe here.

Before returning -EPROBE_DEFER Here we already claimed a iomem resource using
dev_request_mem_resource() which will fail during next probe, so I
believe this patch doesn't work.

Probe deferral is something I introduced to barebox out of despair, but
it really doesn't work very well without all this devm_* stuff the
kernel has.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [PATCH 10/21] soc: imx: gpcv2: fix regulator deferred probe
  2019-01-10  7:37   ` Sascha Hauer
@ 2019-01-10 19:20     ` Andrey Smirnov
  0 siblings, 0 replies; 27+ messages in thread
From: Andrey Smirnov @ 2019-01-10 19:20 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: Barebox List

On Wed, Jan 9, 2019 at 11:37 PM Sascha Hauer <s.hauer@pengutronix.de> wrote:
>
> On Tue, Jan 08, 2019 at 11:11:59PM -0800, Andrey Smirnov wrote:
> > Port of a Linux commit 9e01e2d56db23485a75864b6aeee8e443f024ddb
> >
> >   If a regulator requests a deferred probe, the power domain gets
> >   initialized twice. This leads to a list double add (without
> >   list debugging the kernel hangs due to the double add later):
> >
> >     WARNING: CPU: 0 PID: 19 at lib/list_debug.c:31 __list_add_valid+0xbc/0xc4
> >     list_add double add: new=c1229754, prev=c12383b4, next=c1229754.
> >
> >   Initialize the power domain after we get the regulator. Also do
> >   not print an error in case the regulator defers probing.
> >
> >   Cc: Fabio Estevam <fabio.estevam@nxp.com>
> >   Cc: Andrey Smirnov <andrew.smirnov@gmail.com>
> >   Cc: linux-arm-kernel@lists.infradead.org
> >   Cc: linux-kernel@vger.kernel.org
> >   Fixes: 03aa12629fc4 ("soc: imx: Add GPCv2 power gating driver")
> >   Signed-off-by: Stefan Agner <stefan@agner.ch>
> >   Acked-by: Andrey Smirnov <andrew.smirnov@gmail.com>
> >   Tested-by: Andrey Smirnov <andrew.smirnov@gmail.com>
> >   Signed-off-by: Shawn Guo <shawnguo@kernel.org>
> >
> > Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
> > ---
> >  drivers/soc/imx/gpcv2.c | 15 ++++++++-------
> >  1 file changed, 8 insertions(+), 7 deletions(-)
>
> This file has been added in the last patch. Please squash this patch and
> the next one into it.
>

I purposefully kept this patch separate, since the bugs weren't deal
breakers (PCI still worked despite my bugs) and it would be easier to
see that the fixes that came later were back-ported to BB. I guess I
can squash this in v2.

Thanks,
Andrey Smirnov

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [PATCH 16/21] PCI: imx6: Allow probe deferral by reset GPIO
  2019-01-10  8:05   ` Sascha Hauer
@ 2019-01-12  4:24     ` Andrey Smirnov
  0 siblings, 0 replies; 27+ messages in thread
From: Andrey Smirnov @ 2019-01-12  4:24 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: Barebox List

On Thu, Jan 10, 2019 at 12:05 AM Sascha Hauer <s.hauer@pengutronix.de> wrote:
>
> On Tue, Jan 08, 2019 at 11:12:05PM -0800, Andrey Smirnov wrote:
> > Port of a Linux commit bde4a5a00e761f55be92f62378cf5024ced79ee3
> >
> >   Some designs implement reset GPIO via a GPIO expander connected to a
> >   peripheral bus.  One such example would be i.MX7 Sabre board where said
> >   GPIO is provided by SPI shift register connected to a bitbanged SPI bus.
> >   To support such designs, allow reset GPIO request to defer probing of the
> >   driver.
> >
> >   Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
> >   Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
> >   Reviewed-by: Lucas Stach <l.stach@pengutronix.de>
> >   Cc: yurovsky@gmail.com
> >   Cc: Fabio Estevam <fabio.estevam@nxp.com>
> >   Cc: Dong Aisheng <dongas86@gmail.com>
> >   Cc: linux-arm-kernel@lists.infradead.org
> >
> > Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
> > ---
> >  drivers/pci/pci-imx6.c | 9 ++++++---
> >  1 file changed, 6 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/pci/pci-imx6.c b/drivers/pci/pci-imx6.c
> > index 6471f95b6..517c6bef8 100644
> > --- a/drivers/pci/pci-imx6.c
> > +++ b/drivers/pci/pci-imx6.c
> > @@ -562,8 +562,8 @@ static const struct dw_pcie_host_ops imx6_pcie_host_ops = {
> >       .host_init = imx6_pcie_host_init,
> >  };
> >
> > -static int __init imx6_add_pcie_port(struct imx6_pcie *imx6_pcie,
> > -                                  struct device_d *dev)
> > +static int imx6_add_pcie_port(struct imx6_pcie *imx6_pcie,
> > +                           struct device_d *dev)
> >  {
> >       struct dw_pcie *pci = imx6_pcie->pci;
> >       struct pcie_port *pp = &pci->pp;
> > @@ -581,7 +581,7 @@ static int __init imx6_add_pcie_port(struct imx6_pcie *imx6_pcie,
> >       return 0;
> >  }
> >
> > -static int __init imx6_pcie_probe(struct device_d *dev)
> > +static int imx6_pcie_probe(struct device_d *dev)
> >  {
> >       struct resource *iores;
> >       struct dw_pcie *pci;
> > @@ -606,6 +606,9 @@ static int __init imx6_pcie_probe(struct device_d *dev)
> >
> >       /* Fetch GPIOs */
> >       imx6_pcie->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
> > +     if (imx6_pcie->reset_gpio == -EPROBE_DEFER)
> > +             return imx6_pcie->reset_gpio;
>
> Normally probe function run only once in barebox and in that case I do
> not care about loosing memory. When doing probe deferral here we loose a
> private data struct with each deferred probe here.
>
> Before returning -EPROBE_DEFER Here we already claimed a iomem resource using
> dev_request_mem_resource() which will fail during next probe, so I
> believe this patch doesn't work.
>

Yeah, it just happens to be that in Barebox 74164 GPIO driver gets
probed before PCIe, so this patch isn't strictly needed on i.MX7
(unlike on Linux). The simplest solution, I think, would be to move
GPIO request before dev_request_mem_resource(), which is my plan for
v2. If you'd rather this patch be dropped, since, technically things
are working without it, let me know.

Thanks,
Andrey Smirnov

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

end of thread, other threads:[~2019-01-12  4:24 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-09  7:11 [PATCH 00/21] PCIe support for i.MX7 Andrey Smirnov
2019-01-09  7:11 ` [PATCH 01/21] regulator: Convert drivers to use struct regulator_desc Andrey Smirnov
2019-01-09  7:11 ` [PATCH 02/21] regulator: Port basic regmap regulator functions Andrey Smirnov
2019-01-09  7:11 ` [PATCH 03/21] regulator: Add support for setting regulator's voltage Andrey Smirnov
2019-01-09  7:11 ` [PATCH 04/21] base: driver: Drop redundant list_empty() check Andrey Smirnov
2019-01-09  7:11 ` [PATCH 05/21] base: Port driver_deferred_probe_check_state() from Linux Andrey Smirnov
2019-01-09  7:11 ` [PATCH 06/21] regulator: Add primitive support for deferred probe Andrey Smirnov
2019-01-09  7:11 ` [PATCH 07/21] regulator: Port ANATOP driver from Linux Andrey Smirnov
2019-01-09  7:11 ` [PATCH 08/21] drivers: base: Port power management code " Andrey Smirnov
2019-01-09  7:11 ` [PATCH 09/21] soc: imx: Add GPCv2 power gating driver Andrey Smirnov
2019-01-09  7:11 ` [PATCH 10/21] soc: imx: gpcv2: fix regulator deferred probe Andrey Smirnov
2019-01-10  7:37   ` Sascha Hauer
2019-01-10 19:20     ` Andrey Smirnov
2019-01-09  7:12 ` [PATCH 11/21] soc: imx: gpcv2: correct PGC offset Andrey Smirnov
2019-01-09  7:12 ` [PATCH 12/21] reset: Add i.MX7 SRC reset driver Andrey Smirnov
2019-01-09  7:12 ` [PATCH 13/21] reset: imx7: Fix always writing bits as 0 Andrey Smirnov
2019-01-10  7:38   ` Sascha Hauer
2019-01-09  7:12 ` [PATCH 14/21] reset: Mark local functions as static Andrey Smirnov
2019-01-09  7:12 ` [PATCH 15/21] PCI: imx6: Add code to support i.MX7D Andrey Smirnov
2019-01-09  7:12 ` [PATCH 16/21] PCI: imx6: Allow probe deferral by reset GPIO Andrey Smirnov
2019-01-10  8:05   ` Sascha Hauer
2019-01-12  4:24     ` Andrey Smirnov
2019-01-09  7:12 ` [PATCH 17/21] PCI: imx6: Do not wait for speed change on i.MX7 Andrey Smirnov
2019-01-09  7:12 ` [PATCH 18/21] PCI: imx6: Do not switch speed if Gen2 is disabled Andrey Smirnov
2019-01-09  7:12 ` [PATCH 19/21] PCI: imx6: Fix spelling mistake: "contol" -> "control" Andrey Smirnov
2019-01-09  7:12 ` [PATCH 20/21] PCI: imx6: Drop unnecessary root_bus_nr setting Andrey Smirnov
2019-01-09  7:12 ` [PATCH 21/21] PCI: imx6: Port imx6_pcie_ltssm_enable() Andrey Smirnov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox