* [PATCH v3 00/17] PCIe support for i.MX7
@ 2019-01-15 20:25 Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 01/17] regulator: Convert drivers to use struct regulator_desc Andrey Smirnov
` (16 more replies)
0 siblings, 17 replies; 19+ messages in thread
From: Andrey Smirnov @ 2019-01-15 20:25 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!
Changes since [v2]:
- Dropped "base: Port driver_deferred_probe_check_state() from
Linux" and adjusted the rest of the series accordingly
Changes since [v1]:
- Patches containing bugfixes for GPCv2 were squashed into the patch
introducing the driver
- Patches containing bugfixes for i.MX7 reset controller were
squashed into the patch introducing the driver
- Deffered probe by GPIO support in i.MX6 PCI driver fixed by having
GPIO request preceed the call to dev_request_mem_resource()
Thanks,
Andrey Smirnov
[1] http://lists.infradead.org/pipermail/barebox/2018-December/036005.html
[v1] http://lists.infradead.org/pipermail/barebox/2019-January/036318.html
[v2] http://lists.infradead.org/pipermail/barebox/2019-January/036406.html
Andrey Smirnov (17):
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
regulator: Assume probe deferral instead of missing regulator
regulator: Port ANATOP driver from Linux
drivers: base: Port power management code from Linux
soc: imx: Add GPCv2 power gating driver
reset: Add i.MX7 SRC reset driver
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 | 5 +-
drivers/base/platform.c | 7 +
drivers/base/power.c | 249 +++++++++++++++++++++
drivers/pci/Kconfig | 4 +-
drivers/pci/pci-imx6.c | 255 +++++++++++++++-------
drivers/regulator/Kconfig | 8 +
drivers/regulator/Makefile | 5 +-
drivers/regulator/anatop-regulator.c | 161 ++++++++++++++
drivers/regulator/bcm2835.c | 6 +-
drivers/regulator/core.c | 59 ++++-
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/pm_domain.h | 82 +++++++
include/regulator.h | 41 +++-
26 files changed, 1480 insertions(+), 101 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] 19+ messages in thread
* [PATCH v3 01/17] regulator: Convert drivers to use struct regulator_desc
2019-01-15 20:25 [PATCH v3 00/17] PCIe support for i.MX7 Andrey Smirnov
@ 2019-01-15 20:25 ` Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 02/17] regulator: Port basic regmap regulator functions Andrey Smirnov
` (15 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Andrey Smirnov @ 2019-01-15 20:25 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 0ada05db16..ea7cf7fe1e 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 = ®s[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 39df980dcb..bcfbda62e3 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 87554d22e3..cb5d785817 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 367e13f05b..907073607f 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] 19+ messages in thread
* [PATCH v3 02/17] regulator: Port basic regmap regulator functions
2019-01-15 20:25 [PATCH v3 00/17] PCIe support for i.MX7 Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 01/17] regulator: Convert drivers to use struct regulator_desc Andrey Smirnov
@ 2019-01-15 20:25 ` Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 03/17] regulator: Add support for setting regulator's voltage Andrey Smirnov
` (14 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Andrey Smirnov @ 2019-01-15 20:25 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 ff5daf9a7d..36ce3e87f7 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 0000000000..4495b4403f
--- /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 907073607f..1824e6ea14 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] 19+ messages in thread
* [PATCH v3 03/17] regulator: Add support for setting regulator's voltage
2019-01-15 20:25 [PATCH v3 00/17] PCIe support for i.MX7 Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 01/17] regulator: Convert drivers to use struct regulator_desc Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 02/17] regulator: Port basic regmap regulator functions Andrey Smirnov
@ 2019-01-15 20:25 ` Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 04/17] base: driver: Drop redundant list_empty() check Andrey Smirnov
` (13 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Andrey Smirnov @ 2019-01-15 20:25 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 bcfbda62e3..795dcdb8c1 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 4495b4403f..f22d21b35d 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 1824e6ea14..cd1d3ccf55 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] 19+ messages in thread
* [PATCH v3 04/17] base: driver: Drop redundant list_empty() check
2019-01-15 20:25 [PATCH v3 00/17] PCIe support for i.MX7 Andrey Smirnov
` (2 preceding siblings ...)
2019-01-15 20:25 ` [PATCH v3 03/17] regulator: Add support for setting regulator's voltage Andrey Smirnov
@ 2019-01-15 20:25 ` Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 05/17] regulator: Assume probe deferral instead of missing regulator Andrey Smirnov
` (12 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Andrey Smirnov @ 2019-01-15 20:25 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 1fd890542e..1fd6bbc014 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] 19+ messages in thread
* [PATCH v3 05/17] regulator: Assume probe deferral instead of missing regulator
2019-01-15 20:25 [PATCH v3 00/17] PCIe support for i.MX7 Andrey Smirnov
` (3 preceding siblings ...)
2019-01-15 20:25 ` [PATCH v3 04/17] base: driver: Drop redundant list_empty() check Andrey Smirnov
@ 2019-01-15 20:25 ` Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 06/17] regulator: Port ANATOP driver from Linux Andrey Smirnov
` (11 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Andrey Smirnov @ 2019-01-15 20:25 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
report it as probe deferral to give other, unprobed, drivers a chance
to resolve this.
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
drivers/regulator/core.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 795dcdb8c1..4ca035ae94 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -227,7 +227,12 @@ 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 report probe deferral
+ */
+ ri = ERR_PTR(-EPROBE_DEFER);
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] 19+ messages in thread
* [PATCH v3 06/17] regulator: Port ANATOP driver from Linux
2019-01-15 20:25 [PATCH v3 00/17] PCIe support for i.MX7 Andrey Smirnov
` (4 preceding siblings ...)
2019-01-15 20:25 ` [PATCH v3 05/17] regulator: Assume probe deferral instead of missing regulator Andrey Smirnov
@ 2019-01-15 20:25 ` Andrey Smirnov
2019-01-16 2:10 ` Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 07/17] drivers: base: Port power management code " Andrey Smirnov
` (10 subsequent siblings)
16 siblings, 1 reply; 19+ messages in thread
From: Andrey Smirnov @ 2019-01-15 20:25 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 92db8dc0e0..c734ef5ef9 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 36ce3e87f7..b2fc5b79b6 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 0000000000..3944fd592c
--- /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] 19+ messages in thread
* [PATCH v3 07/17] drivers: base: Port power management code from Linux
2019-01-15 20:25 [PATCH v3 00/17] PCIe support for i.MX7 Andrey Smirnov
` (5 preceding siblings ...)
2019-01-15 20:25 ` [PATCH v3 06/17] regulator: Port ANATOP driver from Linux Andrey Smirnov
@ 2019-01-15 20:25 ` Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 08/17] soc: imx: Add GPCv2 power gating driver Andrey Smirnov
` (9 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Andrey Smirnov @ 2019-01-15 20:25 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 | 249 ++++++++++++++++++++++++++++++++++++++++
include/pm_domain.h | 82 +++++++++++++
6 files changed, 345 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 1e0246da6d..c3bf9dfe18 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 0000000000..1e13e5ed9d
--- /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 4bd4217745..6d2cef8e1a 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 85bdfb0149..1d3fa2eb44 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 0000000000..12674ca7d9
--- /dev/null
+++ b/drivers/base/power.c
@@ -0,0 +1,249 @@
+#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);
+ /*
+ * Assume that missing genpds are unresolved
+ * dependency are report them as deferred
+ */
+ return (ret == -ENOENT) ? -EPROBE_DEFER : ret;
+ }
+
+ 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 0000000000..6d59587ece
--- /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] 19+ messages in thread
* [PATCH v3 08/17] soc: imx: Add GPCv2 power gating driver
2019-01-15 20:25 [PATCH v3 00/17] PCIe support for i.MX7 Andrey Smirnov
` (6 preceding siblings ...)
2019-01-15 20:25 ` [PATCH v3 07/17] drivers: base: Port power management code " Andrey Smirnov
@ 2019-01-15 20:25 ` Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 09/17] reset: Add i.MX7 SRC reset driver Andrey Smirnov
` (8 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Andrey Smirnov @ 2019-01-15 20:25 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>
Linux commit 9e01e2d56db23485a75864b6aeee8e443f024ddb was squashed
here as well:
soc: imx: gpcv2: fix regulator deferred probe
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>
Linux commit 3637f12faf507b0a4b8ac1e7115fc99583ab1db3 was squashed
here as well
soc: imx: gpcv2: correct PGC offset
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/Kconfig | 1 +
drivers/Makefile | 1 +
drivers/soc/imx/Kconfig | 9 ++
drivers/soc/imx/Makefile | 1 +
drivers/soc/imx/gpcv2.c | 315 +++++++++++++++++++++++++++++++++++++++
5 files changed, 327 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 c3bf9dfe18..c6c2eb14db 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 767789d541..752fd66242 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 0000000000..a78a9e3967
--- /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 0000000000..b039f77dc1
--- /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 0000000000..158bfc02de
--- /dev/null
+++ b/drivers/soc/imx/gpcv2.c
@@ -0,0 +1,315 @@
+/*
+ * 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
+
+/*
+ * 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)
+
+#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;
+
+ domain->regulator = regulator_get(domain->dev, "power");
+ if (IS_ERR(domain->regulator)) {
+ if (PTR_ERR(domain->regulator) != -ENODEV) {
+ if (PTR_ERR(domain->regulator) != -EPROBE_DEFER)
+ 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 = 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) {
+ 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] 19+ messages in thread
* [PATCH v3 09/17] reset: Add i.MX7 SRC reset driver
2019-01-15 20:25 [PATCH v3 00/17] PCIe support for i.MX7 Andrey Smirnov
` (7 preceding siblings ...)
2019-01-15 20:25 ` [PATCH v3 08/17] soc: imx: Add GPCv2 power gating driver Andrey Smirnov
@ 2019-01-15 20:25 ` Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 10/17] reset: Mark local functions as static Andrey Smirnov
` (7 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Andrey Smirnov @ 2019-01-15 20:25 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>
Linux commit 26fce0557fa639fb7bbc33e31a57cff7df25c3a0 was squashed
here as well:
reset: imx7: Fix always writing bits as 0
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/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 c9d04f7978..caf1dc9acb 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 52b10cd480..0b55caa204 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 0000000000..6dc5de16a7
--- /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 = assert ? signal->bit : 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] 19+ messages in thread
* [PATCH v3 10/17] reset: Mark local functions as static
2019-01-15 20:25 [PATCH v3 00/17] PCIe support for i.MX7 Andrey Smirnov
` (8 preceding siblings ...)
2019-01-15 20:25 ` [PATCH v3 09/17] reset: Add i.MX7 SRC reset driver Andrey Smirnov
@ 2019-01-15 20:25 ` Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 11/17] PCI: imx6: Add code to support i.MX7D Andrey Smirnov
` (6 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Andrey Smirnov @ 2019-01-15 20:25 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 59f75ca475..99b9c80655 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] 19+ messages in thread
* [PATCH v3 11/17] PCI: imx6: Add code to support i.MX7D
2019-01-15 20:25 [PATCH v3 00/17] PCIe support for i.MX7 Andrey Smirnov
` (9 preceding siblings ...)
2019-01-15 20:25 ` [PATCH v3 10/17] reset: Mark local functions as static Andrey Smirnov
@ 2019-01-15 20:25 ` Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 12/17] PCI: imx6: Allow probe deferral by reset GPIO Andrey Smirnov
` (5 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Andrey Smirnov @ 2019-01-15 20:25 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 72fbc2f482..44c0feb2b8 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 1c45a1c225..d81afb3d29 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 38e002a1c6..6471f95b62 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] 19+ messages in thread
* [PATCH v3 12/17] PCI: imx6: Allow probe deferral by reset GPIO
2019-01-15 20:25 [PATCH v3 00/17] PCIe support for i.MX7 Andrey Smirnov
` (10 preceding siblings ...)
2019-01-15 20:25 ` [PATCH v3 11/17] PCI: imx6: Add code to support i.MX7D Andrey Smirnov
@ 2019-01-15 20:25 ` Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 13/17] PCI: imx6: Do not wait for speed change on i.MX7 Andrey Smirnov
` (4 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Andrey Smirnov @ 2019-01-15 20:25 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 | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/drivers/pci/pci-imx6.c b/drivers/pci/pci-imx6.c
index 6471f95b62..ce68b007ab 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;
@@ -599,13 +599,11 @@ static int __init imx6_pcie_probe(struct device_d *dev)
imx6_pcie->variant =
(enum imx6_pcie_variants)of_device_get_match_data(dev);
- iores = dev_request_mem_resource(dev, 0);
- if (IS_ERR(iores))
- return PTR_ERR(iores);
- pci->dbi_base = IOMEM(iores->start);
-
/* 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");
@@ -615,6 +613,11 @@ static int __init imx6_pcie_probe(struct device_d *dev)
}
}
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+ pci->dbi_base = IOMEM(iores->start);
+
/* Fetch clocks */
imx6_pcie->pcie_phy = clk_get(dev, "pcie_phy");
if (IS_ERR(imx6_pcie->pcie_phy)) {
--
2.20.1
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 13/17] PCI: imx6: Do not wait for speed change on i.MX7
2019-01-15 20:25 [PATCH v3 00/17] PCIe support for i.MX7 Andrey Smirnov
` (11 preceding siblings ...)
2019-01-15 20:25 ` [PATCH v3 12/17] PCI: imx6: Allow probe deferral by reset GPIO Andrey Smirnov
@ 2019-01-15 20:25 ` Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 14/17] PCI: imx6: Do not switch speed if Gen2 is disabled Andrey Smirnov
` (3 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Andrey Smirnov @ 2019-01-15 20:25 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 ce68b007ab..d121a20ce1 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] 19+ messages in thread
* [PATCH v3 14/17] PCI: imx6: Do not switch speed if Gen2 is disabled
2019-01-15 20:25 [PATCH v3 00/17] PCIe support for i.MX7 Andrey Smirnov
` (12 preceding siblings ...)
2019-01-15 20:25 ` [PATCH v3 13/17] PCI: imx6: Do not wait for speed change on i.MX7 Andrey Smirnov
@ 2019-01-15 20:25 ` Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 15/17] PCI: imx6: Fix spelling mistake: "contol" -> "control" Andrey Smirnov
` (2 subsequent siblings)
16 siblings, 0 replies; 19+ messages in thread
From: Andrey Smirnov @ 2019-01-15 20:25 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 d121a20ce1..6bdc9465db 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] 19+ messages in thread
* [PATCH v3 15/17] PCI: imx6: Fix spelling mistake: "contol" -> "control"
2019-01-15 20:25 [PATCH v3 00/17] PCIe support for i.MX7 Andrey Smirnov
` (13 preceding siblings ...)
2019-01-15 20:25 ` [PATCH v3 14/17] PCI: imx6: Do not switch speed if Gen2 is disabled Andrey Smirnov
@ 2019-01-15 20:25 ` Andrey Smirnov
2019-01-15 20:26 ` [PATCH v3 16/17] PCI: imx6: Drop unnecessary root_bus_nr setting Andrey Smirnov
2019-01-15 20:26 ` [PATCH v3 17/17] PCI: imx6: Port imx6_pcie_ltssm_enable() Andrey Smirnov
16 siblings, 0 replies; 19+ messages in thread
From: Andrey Smirnov @ 2019-01-15 20:25 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 6bdc9465db..9f3c9b69a5 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] 19+ messages in thread
* [PATCH v3 16/17] PCI: imx6: Drop unnecessary root_bus_nr setting
2019-01-15 20:25 [PATCH v3 00/17] PCIe support for i.MX7 Andrey Smirnov
` (14 preceding siblings ...)
2019-01-15 20:25 ` [PATCH v3 15/17] PCI: imx6: Fix spelling mistake: "contol" -> "control" Andrey Smirnov
@ 2019-01-15 20:26 ` Andrey Smirnov
2019-01-15 20:26 ` [PATCH v3 17/17] PCI: imx6: Port imx6_pcie_ltssm_enable() Andrey Smirnov
16 siblings, 0 replies; 19+ messages in thread
From: Andrey Smirnov @ 2019-01-15 20:26 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 9f3c9b69a5..9aa307aabf 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] 19+ messages in thread
* [PATCH v3 17/17] PCI: imx6: Port imx6_pcie_ltssm_enable()
2019-01-15 20:25 [PATCH v3 00/17] PCIe support for i.MX7 Andrey Smirnov
` (15 preceding siblings ...)
2019-01-15 20:26 ` [PATCH v3 16/17] PCI: imx6: Drop unnecessary root_bus_nr setting Andrey Smirnov
@ 2019-01-15 20:26 ` Andrey Smirnov
16 siblings, 0 replies; 19+ messages in thread
From: Andrey Smirnov @ 2019-01-15 20:26 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 9aa307aabf..c1719093be 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] 19+ messages in thread
* Re: [PATCH v3 06/17] regulator: Port ANATOP driver from Linux
2019-01-15 20:25 ` [PATCH v3 06/17] regulator: Port ANATOP driver from Linux Andrey Smirnov
@ 2019-01-16 2:10 ` Andrey Smirnov
0 siblings, 0 replies; 19+ messages in thread
From: Andrey Smirnov @ 2019-01-16 2:10 UTC (permalink / raw)
To: Barebox List
On Tue, Jan 15, 2019 at 12:26 PM Andrey Smirnov
<andrew.smirnov@gmail.com> wrote:
>
> 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 92db8dc0e0..c734ef5ef9 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 36ce3e87f7..b2fc5b79b6 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 0000000000..3944fd592c
> --- /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;
Ugh, missed the fact that I need to return 0 here to avoid bogus boot
error messages. I'll either send a separte fixup or spin a v4 if more
changes are necessary.
Thanks,
Andrey Smirnov
> + } 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] 19+ messages in thread
end of thread, other threads:[~2019-01-16 2:10 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-15 20:25 [PATCH v3 00/17] PCIe support for i.MX7 Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 01/17] regulator: Convert drivers to use struct regulator_desc Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 02/17] regulator: Port basic regmap regulator functions Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 03/17] regulator: Add support for setting regulator's voltage Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 04/17] base: driver: Drop redundant list_empty() check Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 05/17] regulator: Assume probe deferral instead of missing regulator Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 06/17] regulator: Port ANATOP driver from Linux Andrey Smirnov
2019-01-16 2:10 ` Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 07/17] drivers: base: Port power management code " Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 08/17] soc: imx: Add GPCv2 power gating driver Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 09/17] reset: Add i.MX7 SRC reset driver Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 10/17] reset: Mark local functions as static Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 11/17] PCI: imx6: Add code to support i.MX7D Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 12/17] PCI: imx6: Allow probe deferral by reset GPIO Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 13/17] PCI: imx6: Do not wait for speed change on i.MX7 Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 14/17] PCI: imx6: Do not switch speed if Gen2 is disabled Andrey Smirnov
2019-01-15 20:25 ` [PATCH v3 15/17] PCI: imx6: Fix spelling mistake: "contol" -> "control" Andrey Smirnov
2019-01-15 20:26 ` [PATCH v3 16/17] PCI: imx6: Drop unnecessary root_bus_nr setting Andrey Smirnov
2019-01-15 20:26 ` [PATCH v3 17/17] 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