* Re: [PATCH v2 2/6] dt-bindings: dma: dw: Add max burst transaction length property
From: Vinod Koul @ 2020-05-15 6:09 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Serge Semin, Serge Semin, Viresh Kumar, Rob Herring,
Alexey Malahov, Thomas Bogendoerfer, Paul Burton, Ralf Baechle,
Arnd Bergmann, Dan Williams, linux-mips, dmaengine, devicetree,
linux-kernel
In-Reply-To: <20200512123840.GY185537@smile.fi.intel.com>
On 12-05-20, 15:38, Andy Shevchenko wrote:
> On Tue, May 12, 2020 at 02:49:46PM +0300, Serge Semin wrote:
> > On Tue, May 12, 2020 at 12:08:04PM +0300, Andy Shevchenko wrote:
> > > On Tue, May 12, 2020 at 12:35:31AM +0300, Serge Semin wrote:
> > > > On Tue, May 12, 2020 at 12:01:38AM +0300, Andy Shevchenko wrote:
> > > > > On Mon, May 11, 2020 at 11:05:28PM +0300, Serge Semin wrote:
> > > > > > On Fri, May 08, 2020 at 02:12:42PM +0300, Andy Shevchenko wrote:
> > > > > > > On Fri, May 08, 2020 at 01:53:00PM +0300, Serge Semin wrote:
>
> ...
>
> I leave it to Rob and Vinod.
> It won't break our case, so, feel free with your approach.
I agree the DT is about describing the hardware and looks like value of
1 is not allowed. If allowed it should be added..
> P.S. Perhaps at some point we need to
> 1) convert properties to be u32 (it will simplify things);
> 2) convert legacy ones to proper format ('-' instead of '_', vendor prefix added);
> 3) parse them in core with device property API.
These suggestions are good and should be done.
--
~Vinod
^ permalink raw reply
* Re: [PATCH v7 2/4] usb: dwc3: qcom: Add interconnect support in dwc3 driver
From: Felipe Balbi @ 2020-05-15 5:54 UTC (permalink / raw)
To: Georgi Djakov, Matthias Kaehlcke
Cc: Sandeep Maheswaram, Andy Gross, Bjorn Andersson,
Greg Kroah-Hartman, Rob Herring, Mark Rutland, Stephen Boyd,
Doug Anderson, linux-arm-msm, linux-usb, devicetree, linux-kernel,
Manu Gautam, Chandana Kishori Chiluveru, Viresh Kumar
In-Reply-To: <abbc3f8c-c8c9-c189-735e-f8058dab3e40@linaro.org>
[-- Attachment #1: Type: text/plain, Size: 1851 bytes --]
Hi,
Georgi Djakov <georgi.djakov@linaro.org> writes:
> On 5/14/20 20:13, Matthias Kaehlcke wrote:
>> On Thu, May 14, 2020 at 02:30:28PM +0300, Felipe Balbi wrote:
>>> Felipe Balbi <balbi@kernel.org> writes:
>>>
>>>> Hi,
>>>>
>>>> Sandeep Maheswaram <sanm@codeaurora.org> writes:
>>>>> +static int dwc3_qcom_interconnect_init(struct dwc3_qcom *qcom)
>>>>> +{
>>>>> + struct device *dev = qcom->dev;
>>>>> + int ret;
>>>>> +
>>>>> + if (!device_is_bound(&qcom->dwc3->dev))
>>>>> + return -EPROBE_DEFER;
>>>>
>>>> this breaks allmodconfig. I'm dropping this series from my queue for
>>>> this merge window.
>>>
>>> Sorry, I meant this patch ;-)
>>
>> I guess that's due to INTERCONNECT being a module. There is currently a
>
> I believe it's because of this:
> ERROR: modpost: "device_is_bound" [drivers/usb/dwc3/dwc3-qcom.ko] undefined!
>
>> discussion about this with Viresh and Georgi in response to another
>> automated build failure. Viresh suggests changing CONFIG_INTERCONNECT
>> from tristate to bool, which seems sensible to me given that interconnect
>> is a core subsystem.
>
> The problem you are talking about would arise when INTERCONNECT=m and
> USB_DWC3_QCOM=y and it definitely exists here and could be triggered with
> randconfig build. So i suggest to squash also the diff below.
>
> Thanks,
> Georgi
>
> ---8<---
> diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
> index 206caa0ea1c6..6661788b1a76 100644
> --- a/drivers/usb/dwc3/Kconfig
> +++ b/drivers/usb/dwc3/Kconfig
> @@ -129,6 +129,7 @@ config USB_DWC3_QCOM
> tristate "Qualcomm Platform"
> depends on ARCH_QCOM || COMPILE_TEST
> depends on EXTCON || !EXTCON
> + depends on INTERCONNECT || !INTERCONNECT
I would prefer to see a patch adding EXPORT_SYMBOL_GPL() to device_is_bound()
--
balbi
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]
^ permalink raw reply
* [PATCH v11 1/2] dt-bindings: drm/bridge: anx7625: MIPI to DP transmitter DT schema
From: Xin Ji @ 2020-05-15 5:49 UTC (permalink / raw)
To: devicetree, devel, Laurent Pinchart, Andrzej Hajda,
Nicolas Boichat, Sam Ravnborg, Rob Herring
Cc: Neil Armstrong, Jonas Karlman, Jernej Skrabec, David Airlie,
Daniel Vetter, Dan Carpenter, Nicolas Boichat, linux-kernel,
dri-devel, Pi-Hsun Shih, Sheng Pan
In-Reply-To: <cover.1589511894.git.xji@analogixsemi.com>
anx7625: MIPI to DP transmitter DT schema
Signed-off-by: Xin Ji <xji@analogixsemi.com>
---
.../bindings/display/bridge/analogix,anx7625.yaml | 95 ++++++++++++++++++++++
1 file changed, 95 insertions(+)
create mode 100644 Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml
diff --git a/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml b/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml
new file mode 100644
index 0000000..60585a4
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/bridge/analogix,anx7625.yaml
@@ -0,0 +1,95 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright 2019 Analogix Semiconductor, Inc.
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/display/bridge/analogix,anx7625.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Analogix ANX7625 SlimPort (4K Mobile HD Transmitter)
+
+maintainers:
+ - Xin Ji <xji@analogixsemi.com>
+
+description: |
+ The ANX7625 is an ultra-low power 4K Mobile HD Transmitter
+ designed for portable devices.
+
+properties:
+ compatible:
+ items:
+ - const: analogix,anx7625
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ description: used for interrupt pin B8.
+ maxItems: 1
+
+ enable-gpios:
+ description: used for power on chip control, POWER_EN pin D2.
+ maxItems: 1
+
+ reset-gpios:
+ description: used for reset chip control, RESET_N pin B7.
+ maxItems: 1
+
+ ports:
+ type: object
+
+ properties:
+ port@0:
+ type: object
+ description:
+ Video port for MIPI DSI input.
+
+ port@1:
+ type: object
+ description:
+ Video port for panel or connector.
+
+ required:
+ - port@0
+ - port@1
+
+required:
+ - compatible
+ - reg
+ - ports
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ i2c0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ encoder@58 {
+ compatible = "analogix,anx7625";
+ reg = <0x58>;
+ enable-gpios = <&pio 45 GPIO_ACTIVE_HIGH>;
+ reset-gpios = <&pio 73 GPIO_ACTIVE_HIGH>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mipi2dp_bridge_in: port@0 {
+ reg = <0>;
+ anx7625_in: endpoint {
+ remote-endpoint = <&mipi_dsi>;
+ };
+ };
+
+ mipi2dp_bridge_out: port@1 {
+ reg = <1>;
+ anx7625_out: endpoint {
+ remote-endpoint = <&panel_in>;
+ };
+ };
+ };
+ };
+ };
--
2.7.4
^ permalink raw reply related
* [PATCH v1 2/4] driver core: Look for waiting consumers only for a fwnode's primary device
From: Saravana Kannan @ 2020-05-15 5:34 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Rob Herring, Frank Rowand,
Len Brown
Cc: Saravana Kannan, kernel-team, linux-kernel, devicetree,
linux-acpi, Ji Luo
In-Reply-To: <20200515053500.215929-1-saravanak@google.com>
Commit 4dbe191c046e ("driver core: Add device links from fwnode only for
the primary device") skipped linking a fwnode's secondary device to
the suppliers listed in its fwnode.
However, a fwnode's secondary device can't be found using
get_dev_from_fwnode(). So, there's no point in trying to see if devices
waiting for suppliers might want to link to a fwnode's secondary device.
This commit removes that unnecessary step for devices that aren't a
fwnode's primary device and also moves the code to a more appropriate
part of the file.
Signed-off-by: Saravana Kannan <saravanak@google.com>
---
drivers/base/core.c | 29 ++++++++++++++++++-----------
1 file changed, 18 insertions(+), 11 deletions(-)
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 2b454aae64b5..f585d92e09d0 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -1173,6 +1173,21 @@ static bool fw_devlink_is_permissive(void)
return fw_devlink_flags == DL_FLAG_SYNC_STATE_ONLY;
}
+static void fw_devlink_link_device(struct device *dev)
+{
+ int fw_ret;
+
+ device_link_add_missing_supplier_links();
+
+ if (fw_devlink_flags && fwnode_has_op(dev->fwnode, add_links)) {
+ fw_ret = fwnode_call_int_op(dev->fwnode, add_links, dev);
+ if (fw_ret == -ENODEV && !fw_devlink_is_permissive())
+ device_link_wait_for_mandatory_supplier(dev);
+ else if (fw_ret)
+ device_link_wait_for_optional_supplier(dev);
+ }
+}
+
/* Device links support end. */
int (*platform_notify)(struct device *dev) = NULL;
@@ -2407,7 +2422,7 @@ int device_add(struct device *dev)
struct device *parent;
struct kobject *kobj;
struct class_interface *class_intf;
- int error = -EINVAL, fw_ret;
+ int error = -EINVAL;
struct kobject *glue_dir = NULL;
bool is_fwnode_dev = false;
@@ -2524,16 +2539,8 @@ int device_add(struct device *dev)
* waiting consumers can link to it before the driver is bound to the
* device and the driver sync_state callback is called for this device.
*/
- device_link_add_missing_supplier_links();
-
- if (fw_devlink_flags && is_fwnode_dev &&
- fwnode_has_op(dev->fwnode, add_links)) {
- fw_ret = fwnode_call_int_op(dev->fwnode, add_links, dev);
- if (fw_ret == -ENODEV && !fw_devlink_is_permissive())
- device_link_wait_for_mandatory_supplier(dev);
- else if (fw_ret)
- device_link_wait_for_optional_supplier(dev);
- }
+ if (is_fwnode_dev)
+ fw_devlink_link_device(dev);
bus_probe_device(dev);
if (parent)
--
2.26.2.761.g0e0b3e54be-goog
^ permalink raw reply related
* [PATCH v1 3/4] driver core: fw_devlink: Add support for batching fwnode parsing
From: Saravana Kannan @ 2020-05-15 5:34 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Rob Herring, Frank Rowand,
Len Brown
Cc: Saravana Kannan, kernel-team, linux-kernel, devicetree,
linux-acpi, Ji Luo
In-Reply-To: <20200515053500.215929-1-saravanak@google.com>
The amount of time spent parsing fwnodes of devices can become really
high if the devices are added in an non-ideal order. Worst case can be
O(N^2) when N devices are added. But this can be optimized to O(N) by
adding all the devices and then parsing all their fwnodes in one batch.
This commit adds fw_devlink_pause() and fw_devlink_resume() to allow
doing this.
Signed-off-by: Saravana Kannan <saravanak@google.com>
---
drivers/base/base.h | 1 +
drivers/base/core.c | 116 ++++++++++++++++++++++++++++++++++++++---
drivers/base/dd.c | 8 +++
include/linux/fwnode.h | 2 +
4 files changed, 120 insertions(+), 7 deletions(-)
diff --git a/drivers/base/base.h b/drivers/base/base.h
index 40fb069a8a7e..95c22c0f9036 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -153,6 +153,7 @@ extern char *make_class_name(const char *name, struct kobject *kobj);
extern int devres_release_all(struct device *dev);
extern void device_block_probing(void);
extern void device_unblock_probing(void);
+extern void driver_deferred_probe_force_trigger(void);
/* /sys/devices directory */
extern struct kset *devices_kset;
diff --git a/drivers/base/core.c b/drivers/base/core.c
index f585d92e09d0..84c569726d75 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -49,6 +49,9 @@ static LIST_HEAD(wait_for_suppliers);
static DEFINE_MUTEX(wfs_lock);
static LIST_HEAD(deferred_sync);
static unsigned int defer_sync_state_count = 1;
+static unsigned int defer_fw_devlink_count;
+static DEFINE_MUTEX(defer_fw_devlink_lock);
+static bool fw_devlink_is_permissive(void);
#ifdef CONFIG_SRCU
static DEFINE_MUTEX(device_links_lock);
@@ -527,7 +530,7 @@ static void device_link_add_missing_supplier_links(void)
int ret = fwnode_call_int_op(dev->fwnode, add_links, dev);
if (!ret)
list_del_init(&dev->links.needs_suppliers);
- else if (ret != -ENODEV)
+ else if (ret != -ENODEV || fw_devlink_is_permissive())
dev->links.need_for_probe = false;
}
mutex_unlock(&wfs_lock);
@@ -1177,17 +1180,116 @@ static void fw_devlink_link_device(struct device *dev)
{
int fw_ret;
- device_link_add_missing_supplier_links();
+ if (!fw_devlink_flags)
+ return;
+
+ mutex_lock(&defer_fw_devlink_lock);
+ if (!defer_fw_devlink_count)
+ device_link_add_missing_supplier_links();
+
+ /*
+ * The device's fwnode not having add_links() doesn't affect if other
+ * consumers can find this device as a supplier. So, this check is
+ * intentionally placed after device_link_add_missing_supplier_links().
+ */
+ if (!fwnode_has_op(dev->fwnode, add_links))
+ goto out;
- if (fw_devlink_flags && fwnode_has_op(dev->fwnode, add_links)) {
+ /*
+ * If fw_devlink is being deferred, assume all devices have mandatory
+ * suppliers they need to link to later. Then, when the fw_devlink is
+ * resumed, all these devices will get a chance to try and link to any
+ * suppliers they have.
+ */
+ if (!defer_fw_devlink_count) {
fw_ret = fwnode_call_int_op(dev->fwnode, add_links, dev);
- if (fw_ret == -ENODEV && !fw_devlink_is_permissive())
- device_link_wait_for_mandatory_supplier(dev);
- else if (fw_ret)
- device_link_wait_for_optional_supplier(dev);
+ if (fw_ret == -ENODEV && fw_devlink_is_permissive())
+ fw_ret = -EAGAIN;
+ } else {
+ fw_ret = -ENODEV;
}
+
+ if (fw_ret == -ENODEV)
+ device_link_wait_for_mandatory_supplier(dev);
+ else if (fw_ret)
+ device_link_wait_for_optional_supplier(dev);
+
+out:
+ mutex_unlock(&defer_fw_devlink_lock);
}
+/**
+ * fw_devlink_pause - Pause parsing of fwnode to create device links
+ *
+ * Calling this function defers any fwnode parsing to create device links until
+ * fw_devlink_resume() is called. Both these functions are ref counted and the
+ * caller needs to match the calls.
+ *
+ * While fw_devlink is paused:
+ * - Any device that is added won't have its fwnode parsed to create device
+ * links.
+ * - The probe of the device will also be deferred during this period.
+ * - Any devices that were already added, but waiting for suppliers won't be
+ * able to link to newly added devices.
+ *
+ * Once fw_devlink_resume():
+ * - All the fwnodes that was not parsed will be parsed.
+ * - All the devices that were deferred probing will be reattempted if they
+ * aren't waiting for any more suppliers.
+ *
+ * This pair of functions, is mainly meant to optimize the parsing of fwnodes
+ * when a lot of devices that need to link to each other are added in a short
+ * interval of time. For example, adding all the top level devices in a system.
+ *
+ * For example, if N devices are added and:
+ * - All the consumers are added before their suppliers
+ * - All the suppliers of the N devices are part of the N devices
+ *
+ * Then:
+ *
+ * - With the use of fw_devlink_pause() and fw_devlink_resume(), each device
+ * will only need one parsing of its fwnode because it is guaranteed to find
+ * all the supplier devices already registered and ready to link to. It won't
+ * have to do another pass later to find one or more suppliers it couldn't
+ * find in the first parse of the fwnode. So, we'll only need O(N) fwnode
+ * parses.
+ *
+ * - Without the use of fw_devlink_pause() and fw_devlink_resume(), we would
+ * end up doing O(N^2) parses of fwnodes because every device that's added is
+ * guaranteed to trigger a parse of the fwnode of every device added before
+ * it. This O(N^2) parse is made worse by the fact that when a fwnode of a
+ * device is parsed, all it descendant devices might need to have their
+ * fwnodes parsed too (even if the devices themselves aren't added).
+ */
+void fw_devlink_pause(void)
+{
+ mutex_lock(&defer_fw_devlink_lock);
+ defer_fw_devlink_count++;
+ mutex_unlock(&defer_fw_devlink_lock);
+}
+
+/** fw_devlink_resume - Resume parsing of fwnode to create device links
+ *
+ * This function is used in conjunction with fw_devlink_pause() and is ref
+ * counted. See documentation for fw_devlink_pause() for more details.
+ */
+void fw_devlink_resume(void)
+{
+ mutex_lock(&defer_fw_devlink_lock);
+ if (!defer_fw_devlink_count) {
+ WARN(true, "Unmatched fw_devlink pause/resume!");
+ goto out;
+ }
+
+ defer_fw_devlink_count--;
+ if (defer_fw_devlink_count)
+ goto out;
+
+ device_link_add_missing_supplier_links();
+ driver_deferred_probe_force_trigger();
+out:
+ mutex_unlock(&defer_fw_devlink_lock);
+}
/* Device links support end. */
int (*platform_notify)(struct device *dev) = NULL;
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 48ca81cb8ebc..63991d97adcc 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -160,6 +160,14 @@ static bool driver_deferred_probe_enable = false;
* again.
*/
static void driver_deferred_probe_trigger(void)
+{
+ if (!driver_deferred_probe_enable)
+ return;
+
+ driver_deferred_probe_force_trigger();
+}
+
+void driver_deferred_probe_force_trigger(void)
{
if (!driver_deferred_probe_enable)
return;
diff --git a/include/linux/fwnode.h b/include/linux/fwnode.h
index e0abafbb17f8..9506f8ec0974 100644
--- a/include/linux/fwnode.h
+++ b/include/linux/fwnode.h
@@ -171,5 +171,7 @@ struct fwnode_operations {
#define get_dev_from_fwnode(fwnode) get_device((fwnode)->dev)
extern u32 fw_devlink_get_flags(void);
+void fw_devlink_pause(void);
+void fw_devlink_resume(void);
#endif
--
2.26.2.761.g0e0b3e54be-goog
^ permalink raw reply related
* [PATCH v1 4/4] of: platform: Batch fwnode parsing when adding all top level devices
From: Saravana Kannan @ 2020-05-15 5:35 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Rob Herring, Frank Rowand,
Len Brown
Cc: Saravana Kannan, kernel-team, linux-kernel, devicetree,
linux-acpi, Ji Luo
In-Reply-To: <20200515053500.215929-1-saravanak@google.com>
The fw_devlink_pause() and fw_devlink_resume() APIs allow batching the
parsing of the device tree nodes when a lot of devices are added. This
will significantly cut down parsing time (as much a 1 second on some
systems). So, use them when adding devices for all the top level device
tree nodes in a system.
Signed-off-by: Saravana Kannan <saravanak@google.com>
---
drivers/of/platform.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 3371e4a06248..55d719347810 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -538,7 +538,9 @@ static int __init of_platform_default_populate_init(void)
}
/* Populate everything else. */
+ fw_devlink_pause();
of_platform_default_populate(NULL, NULL, NULL);
+ fw_devlink_resume();
return 0;
}
--
2.26.2.761.g0e0b3e54be-goog
^ permalink raw reply related
* [PATCH v1 1/4] driver core: Move code to the right part of the file
From: Saravana Kannan @ 2020-05-15 5:34 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Rob Herring, Frank Rowand,
Len Brown
Cc: Saravana Kannan, kernel-team, linux-kernel, devicetree,
linux-acpi, Ji Luo
In-Reply-To: <20200515053500.215929-1-saravanak@google.com>
This commit just moves around code to match the general organization of
the file.
Signed-off-by: Saravana Kannan <saravanak@google.com>
---
drivers/base/core.c | 60 ++++++++++++++++++++++-----------------------
1 file changed, 30 insertions(+), 30 deletions(-)
diff --git a/drivers/base/core.c b/drivers/base/core.c
index c9045521596f..2b454aae64b5 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -1143,6 +1143,36 @@ static void device_links_purge(struct device *dev)
device_links_write_unlock();
}
+static u32 fw_devlink_flags = DL_FLAG_SYNC_STATE_ONLY;
+static int __init fw_devlink_setup(char *arg)
+{
+ if (!arg)
+ return -EINVAL;
+
+ if (strcmp(arg, "off") == 0) {
+ fw_devlink_flags = 0;
+ } else if (strcmp(arg, "permissive") == 0) {
+ fw_devlink_flags = DL_FLAG_SYNC_STATE_ONLY;
+ } else if (strcmp(arg, "on") == 0) {
+ fw_devlink_flags = DL_FLAG_AUTOPROBE_CONSUMER;
+ } else if (strcmp(arg, "rpm") == 0) {
+ fw_devlink_flags = DL_FLAG_AUTOPROBE_CONSUMER |
+ DL_FLAG_PM_RUNTIME;
+ }
+ return 0;
+}
+early_param("fw_devlink", fw_devlink_setup);
+
+u32 fw_devlink_get_flags(void)
+{
+ return fw_devlink_flags;
+}
+
+static bool fw_devlink_is_permissive(void)
+{
+ return fw_devlink_flags == DL_FLAG_SYNC_STATE_ONLY;
+}
+
/* Device links support end. */
int (*platform_notify)(struct device *dev) = NULL;
@@ -2345,36 +2375,6 @@ static int device_private_init(struct device *dev)
return 0;
}
-static u32 fw_devlink_flags = DL_FLAG_SYNC_STATE_ONLY;
-static int __init fw_devlink_setup(char *arg)
-{
- if (!arg)
- return -EINVAL;
-
- if (strcmp(arg, "off") == 0) {
- fw_devlink_flags = 0;
- } else if (strcmp(arg, "permissive") == 0) {
- fw_devlink_flags = DL_FLAG_SYNC_STATE_ONLY;
- } else if (strcmp(arg, "on") == 0) {
- fw_devlink_flags = DL_FLAG_AUTOPROBE_CONSUMER;
- } else if (strcmp(arg, "rpm") == 0) {
- fw_devlink_flags = DL_FLAG_AUTOPROBE_CONSUMER |
- DL_FLAG_PM_RUNTIME;
- }
- return 0;
-}
-early_param("fw_devlink", fw_devlink_setup);
-
-u32 fw_devlink_get_flags(void)
-{
- return fw_devlink_flags;
-}
-
-static bool fw_devlink_is_permissive(void)
-{
- return fw_devlink_flags == DL_FLAG_SYNC_STATE_ONLY;
-}
-
/**
* device_add - add device to device hierarchy.
* @dev: device.
--
2.26.2.761.g0e0b3e54be-goog
^ permalink raw reply related
* [PATCH v1 0/4] Optimize fw_devlink parsing
From: Saravana Kannan @ 2020-05-15 5:34 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Rob Herring, Frank Rowand,
Len Brown
Cc: Saravana Kannan, kernel-team, linux-kernel, devicetree,
linux-acpi, Ji Luo
When fw_devlink is enabled on hardware with a large number of device
tree nodes, the initial device addition done in
of_platform_default_populate_init() can be very inefficient. This is
because most devices will fail to find all their suppliers when they are
added and will keep trying to parse their device tree nodes and link to
any newly added devices
This was an item on my TODO list that I'm finally getting around to. On
hardware I'm testing on, this saved 1.216 _seconds_! Another SoC vendor
was also able to test a similar but hacky patch series and confirmed
that it saved them around 1 second.
Thanks,
Saravana
P.S: It took me longer to write the comments than the code!
Saravana Kannan (4):
driver core: Move code to the right part of the file
driver core: Look for waiting consumers only for a fwnode's primary
device
driver core: fw_devlink: Add support for batching fwnode parsing
of: platform: Batch fwnode parsing when adding all top level devices
drivers/base/base.h | 1 +
drivers/base/core.c | 193 ++++++++++++++++++++++++++++++++---------
drivers/base/dd.c | 8 ++
drivers/of/platform.c | 2 +
include/linux/fwnode.h | 2 +
5 files changed, 164 insertions(+), 42 deletions(-)
--
2.26.2.761.g0e0b3e54be-goog
^ permalink raw reply
* [RFC] dt-bindings: mailbox: add doorbell support to ARM MHU
From: Viresh Kumar @ 2020-05-15 5:17 UTC (permalink / raw)
To: Jassi Brar, Arnd Bergmann, Rob Herring, Frank Rowand
Cc: Viresh Kumar, Bjorn Andersson, Vincent Guittot, linux-arm-kernel,
Sudeep Holla, devicetree, linux-kernel
From: Sudeep Holla <sudeep.holla@arm.com>
Hi Rob, Arnd and Jassi,
This stuff has been doing rounds on the mailing list since several years
now with no agreed conclusion by all the parties. And here is another
attempt to get some feedback from everyone involved to close this once
and for ever. Your comments will very much be appreciated.
The ARM MHU is defined here in the TRM [1] for your reference, which
states following:
"The MHU drives the signal using a 32-bit register, with all 32
bits logically ORed together. The MHU provides a set of
registers to enable software to set, clear, and check the status
of each of the bits of this register independently. The use of
32 bits for each interrupt line enables software to provide more
information about the source of the interrupt. For example, each
bit of the register can be associated with a type of event that
can contribute to raising the interrupt."
On few other platforms, like qcom, similar doorbell mechanism is present
with separate interrupt for each of the bits (that's how I understood
it), while in case of ARM MHU, there is a single interrupt line for all
the 32 bits. Also in case of ARM MHU, these registers and interrupts
have 3 copies for different priority levels, i.e. low priority
non-secure, high priority non-secure and secure channels.
For ARM MHU, both the dt bindings and the Linux driver support 3
channels for the different priorities right now and support sending a 32
bit data on every transfer in a locked fashion, i.e. only one transfer
can be done at once and the other have to wait for it to finish first.
Here are the point of view of the parties involved on this subject:
Jassi's viewpoint:
- Virtualization of channels should be discouraged in software based on
specific usecases of the application. This may invite other mailbox
driver authors to ask for doing virtualization in their drivers.
- In mailbox's terminology, every channel is equivalent to a signal,
since there is only one signal generated here by the MHU, there should
be only one channel per priority level.
- The clients should send data (of just setting 1 bit or many in the 32
bit word) using the existing mechanism as the delays due to
serialization shouldn't be significant anyway.
- The driver supports 90% of the users with the current implementation
and it shouldn't be extended to support doorbell and implement two
different modes by changing value of #mbox-cells field in bindings.
Sudeep (ARM) and myself as well to some extent:
- The hardware gives us the capability to write the register in
parallel, i.e. we can write 0x800 and 0x400 together without any
software locks, and so these 32 bits should be considered as separate
channel even if only one interrupt is issued by the hardware finally.
This shouldn't be called as virtualization of the channels, as the
hardware supports this (as clearly mentioned in the TRM) and it takes
care of handling the signal properly.
- With serialization, if we use only one channel as today at every
priority, if there are 5 requests to send signal to the receiver and
the dvfs request is the last one in queue (which may be called from
scheduler's hot path with fast switching), it unnecessarily needs to
wait for the first four transfers to finish due to the software
locking imposed by the mailbox framework. This adds additional delay,
maybe of few ms only, which isn't required by the hardware but just by
the software and few ms can be important in scheduler's hotpath.
- With the current approach it isn't possible to assign different bits
(or doorbell numbers) to clients from DT and the only way of doing
that without adding new bindings is by extending #mbox-cells to accept
a value of 2 as done in this patch.
Jassi and Sudeep, I hope I was able to represent both the view points
properly here. Please correct me if I have made a mistake here.
This is it. It would be nice to get the views of everyone now on this
and how should this be handled.
Thanks.
[1] http://infocenter.arm.com/help/topic/com.arm.doc.ddi0515f/DDI0515F_juno_arm_development_platform_soc_trm.pdf , section 3.4.4, page 3-38.
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
.../devicetree/bindings/mailbox/arm-mhu.txt | 39 ++++++++++++++++++-
1 file changed, 37 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/mailbox/arm-mhu.txt b/Documentation/devicetree/bindings/mailbox/arm-mhu.txt
index 4971f03f0b33..ba659bcc7109 100644
--- a/Documentation/devicetree/bindings/mailbox/arm-mhu.txt
+++ b/Documentation/devicetree/bindings/mailbox/arm-mhu.txt
@@ -10,6 +10,15 @@ STAT register and the remote clears it after having read the data.
The last channel is specified to be a 'Secure' resource, hence can't be
used by Linux running NS.
+The MHU drives the interrupt signal using a 32-bit register, with all
+32-bits logically ORed together. It provides a set of registers to
+enable software to set, clear and check the status of each of the bits
+of this register independently. The use of 32 bits per interrupt line
+enables software to provide more information about the source of the
+interrupt. For example, each bit of the register can be associated with
+a type of event that can contribute to raising the interrupt. Each of
+the 32-bits can be used as "doorbell" to alert the remote processor.
+
Mailbox Device Node:
====================
@@ -18,13 +27,21 @@ used by Linux running NS.
- compatible: Shall be "arm,mhu" & "arm,primecell"
- reg: Contains the mailbox register address range (base
address and length)
-- #mbox-cells Shall be 1 - the index of the channel needed.
+- #mbox-cells Shall be 1 - the index of the channel needed when
+ not used as set of doorbell bits.
+ Shall be 2 - the index of the channel needed, and
+ the index of the doorbell bit within the channel
+ when used in doorbell mode.
- interrupts: Contains the interrupt information corresponding to
- each of the 3 links of MHU.
+ each of the 3 physical channels of MHU namely low
+ priority non-secure, high priority non-secure and
+ secure channels.
Example:
--------
+1. Controller which doesn't support doorbells
+
mhu: mailbox@2b1f0000 {
#mbox-cells = <1>;
compatible = "arm,mhu", "arm,primecell";
@@ -41,3 +58,21 @@ used by Linux running NS.
reg = <0 0x2e000000 0x4000>;
mboxes = <&mhu 1>; /* HP-NonSecure */
};
+
+2. Controller which supports doorbells
+
+ mhu: mailbox@2b1f0000 {
+ #mbox-cells = <2>;
+ compatible = "arm,mhu", "arm,primecell";
+ reg = <0 0x2b1f0000 0x1000>;
+ interrupts = <0 36 4>, /* LP-NonSecure */
+ <0 35 4>; /* HP-NonSecure */
+ clocks = <&clock 0 2 1>;
+ clock-names = "apb_pclk";
+ };
+
+ mhu_client: scb@2e000000 {
+ compatible = "arm,scpi";
+ reg = <0 0x2e000000 0x200>;
+ mboxes = <&mhu 1 4>; /* HP-NonSecure 5th doorbell bit */
+ };
--
2.25.0.rc1.19.g042ed3e048af
^ permalink raw reply related
* RE: [PATCH V2] pwm: tegra: dynamic clk freq configuration by PWM driver
From: Sandipan Patra @ 2020-05-15 5:12 UTC (permalink / raw)
To: Uwe Kleine-König
Cc: Thierry Reding, robh+dt@kernel.org, Jonathan Hunter, Bibek Basu,
Laxman Dewangan, linux-pwm@vger.kernel.org,
devicetree@vger.kernel.org, linux-tegra@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <MN2PR12MB3021278ADEBD123D56B91D1CADA50@MN2PR12MB3021.namprd12.prod.outlook.com>
Hello Uwe,
Gentle reminder to review my replies.
It will help me to push next cleaner patch.
Thanks & Regards,
Sandipan
> -----Original Message-----
> From: Sandipan Patra
> Sent: Thursday, May 7, 2020 1:40 PM
> To: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
> Cc: Thierry Reding <treding@nvidia.com>; robh+dt@kernel.org; Jonathan
> Hunter <jonathanh@nvidia.com>; Bibek Basu <bbasu@nvidia.com>; Laxman
> Dewangan <ldewangan@nvidia.com>; linux-pwm@vger.kernel.org;
> devicetree@vger.kernel.org; linux-tegra@vger.kernel.org; linux-
> kernel@vger.kernel.org
> Subject: RE: [PATCH V2] pwm: tegra: dynamic clk freq configuration by PWM
> driver
>
> Hello,
>
> > -----Original Message-----
> > From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
> > Sent: Tuesday, May 5, 2020 1:42 AM
> > To: Sandipan Patra <spatra@nvidia.com>
> > Cc: Thierry Reding <treding@nvidia.com>; robh+dt@kernel.org; Jonathan
> > Hunter <jonathanh@nvidia.com>; Bibek Basu <bbasu@nvidia.com>; Laxman
> > Dewangan <ldewangan@nvidia.com>; linux-pwm@vger.kernel.org;
> > devicetree@vger.kernel.org; linux-tegra@vger.kernel.org; linux-
> > kernel@vger.kernel.org
> > Subject: Re: [PATCH V2] pwm: tegra: dynamic clk freq configuration by
> > PWM driver
> >
> > External email: Use caution opening links or attachments
> >
> >
> > Hello,
> >
> > On Mon, Apr 20, 2020 at 09:24:03PM +0530, Sandipan Patra wrote:
> > > Added support for dynamic clock freq configuration in pwm kernel driver.
> > > Earlier the pwm driver used to cache boot time clock rate by pwm
> > > clock parent during probe. Hence dynamically changing pwm frequency
> > > was not possible for all the possible ranges. With this change,
> > > dynamic calculation is enabled and it is able to set the requested
> > > period from sysfs knob provided the value is supported by clock source.
> > >
> > > Changes mainly have 2 parts:
> > > - T186 and later chips [1]
> > > - T210 and prior chips [2]
> > >
> > > For [1] - Changes implemented to set pwm period dynamically and
> > > also checks added to allow only if requested period(ns) is
> > > below or equals to higher range.
> > >
> > > For [2] - Only checks if the requested period(ns) is below or equals
> > > to higher range defined by max clock limit. The limitation
> > > in T210 or prior chips are due to the reason of having only
> > > one pwm-controller supporting multiple channels. But later
> > > chips have multiple pwm controller instances each having
> > > single channel support.
> > >
> > > Signed-off-by: Sandipan Patra <spatra@nvidia.com>
> > > ---
> > > V2:
> > > 1. Min period_ns calculation is moved to probe.
> > > 2. Added descriptioins for PWM register bits and regarding behaviour
> > > of the controller when new configuration is applied or pwm is disabled.
> > > 3. Setting period with possible value when supplied period is below limit.
> > > 4. Corrected the earlier code comment:
> > > plus 1 instead of minus 1 during pwm calculation
> > >
> > > drivers/pwm/pwm-tegra.c | 110
> > > +++++++++++++++++++++++++++++++++++++++++-------
> > > 1 file changed, 94 insertions(+), 16 deletions(-)
> > >
> > > diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c index
> > > d26ed8f..7a36325 100644
> > > --- a/drivers/pwm/pwm-tegra.c
> > > +++ b/drivers/pwm/pwm-tegra.c
> > > @@ -4,8 +4,39 @@
> > > *
> > > * Tegra pulse-width-modulation controller driver
> > > *
> > > - * Copyright (c) 2010, NVIDIA Corporation.
> > > - * Based on arch/arm/plat-mxc/pwm.c by Sascha Hauer
> > > <s.hauer@pengutronix.de>
> > > + * Copyright (c) 2010-2020, NVIDIA Corporation.
> > > + *
> > > + * Overview of Tegra Pulse Width Modulator Register:
> > > + * 1. 13-bit: Frequency division (SCALE)
> > > + * 2. 8-bit : Puls division (DUTY)
> > > + * 3. 1-bit : Enable bit
> > > + *
> > > + * The PWM clock frequency is divided by 256 before subdividing it
> > > + based
> > > + * on the programmable frequency division value to generate the
> > > + required
> > > + * frequency for PWM output. The maximum output frequency that can
> > > + be
> > > + * achieved is (max rate of source clock) / 256.
> > > + * i.e. if source clock rate is 408 MHz, maximum output frequency cab be:
> >
> > s/i.e./e.g./, s/cab/can/
>
> Noted, correction in next patch.
>
> >
> > > + * 408 MHz/256 = 1.6 MHz.
> > > + * This 1.6 MHz frequency can further be divided using SCALE value in PWM.
> > > + *
> > > + * PWM pulse width: 8 bits are usable [23:16] for varying pulse width.
> > > + * To achieve 100% duty cycle, program Bit [24] of this register to
> > > + * 1’b1. In which case the other bits [23:16] are set to don't care.
> > > + *
> > > + * Limitations and known facts:
> >
> > Please use "Limitations:" here to make this easier greppable.
>
> Will update in next patch.
>
> >
> > > + * - When PWM is disabled, the output is driven to 0.
> >
> > 0 or inactive?
>
> Yes, Inactive. When it is 0, it is disabled.
> Will update it to "inactive".
>
> >
> > > + * - It does not allow the current PWM period to complete and
> > > + * stops abruptly.
> > > + *
> > > + * - If the register is reconfigured while pwm is running,
> >
> > s/pwm/PWM/
>
> Noted, correction in next patch.
>
> >
> > > + * It does not let the currently running period to complete.
> >
> > s/It/it/; s/let/complete/; s/ to complete//
> >
>
> Noted, correction in next patch
>
> > > + *
> > > + * - Pulse width of the pwm can never be out of bound.
> >
> > I don't understand that one.
>
> As I understand:
> Pulse width is configured on bits [23:16]. So any misconfiguration or overflow
> from Software will be restricted by the hardware and only the respective bits will
> be considered.
> Also the explanation is added above during register bit field descriptions.
> Please advise if that doesn't help.
>
> >
> > > + * It's taken care at HW and SW
> > > + * - If the user input duty is below limit, then driver sets it to
> > > + * minimum possible value.
> >
> > that is 0? Do you mean "input period"? If so, better refuse the request.
>
> This is for pwm duty. If user requested duty is below lower bound, then pwm
> driver configures to the min possible duty.
> Lower bound and upper bound values are derived based on min and max clock
> rates respectively.
>
> >
> > > + * - If anything else goes wrong for setting duty or period,
> > > + * -EINVAL is returned.
> >
> > I wouldn't state this, too trivial. Instead the following are
> > interesting:
> >
> > - The driver doesn't implement the right rounding rules
> > - The driver needs updating to the atomic API
> >
> > > */
> > >
> > > #include <linux/clk.h>
> > > @@ -41,6 +72,7 @@ struct tegra_pwm_chip {
> > > struct reset_control*rst;
> > >
> > > unsigned long clk_rate;
> > > + unsigned long min_period_ns;
> > >
> > > void __iomem *regs;
> > >
> > > @@ -67,8 +99,9 @@ static int tegra_pwm_config(struct pwm_chip *chip,
> > struct pwm_device *pwm,
> > > int duty_ns, int period_ns) {
> > > struct tegra_pwm_chip *pc = to_tegra_pwm_chip(chip);
> > > - unsigned long long c = duty_ns, hz;
> > > - unsigned long rate;
> > > + unsigned long long p_width = duty_ns, period_hz;
> > > + unsigned long rate, required_clk_rate;
> > > + unsigned long pfm; /* Frequency divider */
> > > u32 val = 0;
> > > int err;
> > >
> > > @@ -77,37 +110,77 @@ static int tegra_pwm_config(struct pwm_chip
> > > *chip,
> > struct pwm_device *pwm,
> > > * per (1 << PWM_DUTY_WIDTH) cycles and make sure to round to the
> > > * nearest integer during division.
> > > */
> > > - c *= (1 << PWM_DUTY_WIDTH);
> > > - c = DIV_ROUND_CLOSEST_ULL(c, period_ns);
> > > + p_width *= (1 << PWM_DUTY_WIDTH);
> > > + p_width = DIV_ROUND_CLOSEST_ULL(p_width, period_ns);
> > >
> > > - val = (u32)c << PWM_DUTY_SHIFT;
> > > + val = (u32)p_width << PWM_DUTY_SHIFT;
> > > +
> > > + /*
> > > + * Period in nano second has to be <= highest allowed period
> > > + * based on max clock rate of the pwm controller.
> > > + *
> > > + * higher limit = max clock limit >> PWM_DUTY_WIDTH
> > > + * lower limit = min clock limit >> PWM_DUTY_WIDTH >>
> > PWM_SCALE_WIDTH
> > > + */
> > > + if (period_ns < pc->min_period_ns) {
> > > + period_ns = pc->min_period_ns;
> > > + pr_warn("Period is adjusted to allowed value (%d ns)\n",
> > > + period_ns);
> >
> > That pr_warn is a bad idea as it spams the kernel log when the
> > configuration is changed frequently. Wouldn't it be easier to
> > calculate the frequency that is needed to achieve period_ns and check that
> against max_frequency?
>
> I think you are suggesting which is done just next:
> required_clk_rate = (NSEC_PER_SEC / period_ns) << PWM_DUTY_WIDTH;
> clk_set_rate(pc->clk, required_clk_rate); Please let me know if I missed what
> you meant.
>
> >
> > > + }
> > >
> > > /*
> > > * Compute the prescaler value for which (1 << PWM_DUTY_WIDTH)
> > > * cycles at the PWM clock rate will take period_ns nanoseconds.
> > > */
> > > - rate = pc->clk_rate >> PWM_DUTY_WIDTH;
> > > + if (pc->soc->num_channels == 1) {
> >
> > required_clk_rate could be defined here, which is better as it narrows its
> scope.
> >
>
> Noted, will define here to limit its scope.
>
> > > + /*
> > > + * Rate is multiplied with 2^PWM_DUTY_WIDTH so that it matches
> > > + * with the hieghest applicable rate that the
> > > + controller can
> >
> > s/hieghest/highest/
>
> Noted, correction in next patch
>
> >
> > > + * provide. Any further lower value can be derived by setting
> > > + * PFM bits[0:12].
> > > + * Higher mark is taken since BPMP has round-up mechanism
> > > + * implemented.
> >
> > I don't understand the part with the round-up mechanism.
>
> Understood. This comment is misleading.
> I think it can be updated as below:
> "required_clk_rate" is a reference rate for source clock and it is derived based
> on user requested period.
> By successfully setting the source clock rate to required_clk_rate, pwm
> controller can configure the requested period.
>
> >
> > > + */
> > > + required_clk_rate =
> > > + (NSEC_PER_SEC / period_ns) << PWM_DUTY_WIDTH;
> > > +
> > > + err = clk_set_rate(pc->clk, required_clk_rate);
> > > + if (err < 0)
> > > + return -EINVAL;
> >
> > What happens if clk_set_rate configures a higher rate than requested?
>
> The clock configuration is taken care in a separate R5 called BPMP.
> BPMP-FW does not round up the rate of PWM controller clock.
> It rounds down the clock divider value that generates PWM controller clock.
>
> >
> > > +
> > > + rate = clk_get_rate(pc->clk) >> PWM_DUTY_WIDTH;
> > > + } else {
> > > + /*
> > > + * This is the case for SoCs who support multiple channels:
> >
> > s/who/that/
>
> Noted, correction in next patch.
>
> >
> > > + *
> > > + * clk_set_rate() can not be called again in config because
> > > + * T210 or any prior chip supports one pwm-controller and
> > > + * multiple channels. Hence in this case cached clock rate
> > > + * will be considered which was stored during probe.
> > > + */
> > > + rate = pc->clk_rate >> PWM_DUTY_WIDTH;
> > > + }
> > >
> > > /* Consider precision in PWM_SCALE_WIDTH rate calculation */
> > > - hz = DIV_ROUND_CLOSEST_ULL(100ULL * NSEC_PER_SEC, period_ns);
> > > - rate = DIV_ROUND_CLOSEST_ULL(100ULL * rate, hz);
> > > + period_hz = DIV_ROUND_CLOSEST_ULL(100ULL * NSEC_PER_SEC,
> > period_ns);
> > > + pfm = DIV_ROUND_CLOSEST_ULL(100ULL * rate, period_hz);
> > >
> > > /*
> > > * Since the actual PWM divider is the register's frequency divider
> > > - * field minus 1, we need to decrement to get the correct value to
> > > + * field plus 1, we need to decrement to get the correct value
> > > + to
> > > * write to the register.
> > > */
> > > - if (rate > 0)
> > > - rate--;
> > > + if (pfm > 0)
> > > + pfm--;
> > >
> > > /*
> > > - * Make sure that the rate will fit in the register's frequency
> > > + * Make sure that pfm will fit in the register's frequency
> > > * divider field.
> > > */
> > > - if (rate >> PWM_SCALE_WIDTH)
> > > + if (pfm >> PWM_SCALE_WIDTH)
> > > return -EINVAL;
> > >
> > > - val |= rate << PWM_SCALE_SHIFT;
> > > + val |= pfm << PWM_SCALE_SHIFT;
> > >
> > > /*
> > > * If the PWM channel is disabled, make sure to turn on the
> > > clock @@ -205,6 +278,10 @@ static int tegra_pwm_probe(struct
> > platform_device *pdev)
> > > */
> > > pwm->clk_rate = clk_get_rate(pwm->clk);
> > >
> > > + /* Set minimum limit of PWM period for the IP */
> > > + pwm->min_period_ns =
> > > + (NSEC_PER_SEC / (pwm->soc->max_frequency >>
> > > + PWM_DUTY_WIDTH))
> > > + + 1;
> >
> > With my suggestion above, you can drop the min_period_ns field.
>
> I have added some comments above. Please help me understand if they are not
> aligned with what you meant.
>
> >
> > > +
> > > pwm->rst = devm_reset_control_get_exclusive(&pdev->dev, "pwm");
> > > if (IS_ERR(pwm->rst)) {
> > > ret = PTR_ERR(pwm->rst); @@ -313,4 +390,5 @@
> > > module_platform_driver(tegra_pwm_driver);
> > >
> > > MODULE_LICENSE("GPL");
> > > MODULE_AUTHOR("NVIDIA Corporation");
> > > +MODULE_AUTHOR("Sandipan Patra <spatra@nvidia.com>");
> > > MODULE_ALIAS("platform:tegra-pwm");
> >
> > Best regards
> > Uwe
> >
> > --
> > Pengutronix e.K. | Uwe Kleine-König |
> > Industrial Linux Solutions | https://www.pengutronix.de/ |
^ permalink raw reply
* [PATCH 0/5] PCI: uniphier: Add features for UniPhier PCIe host controller
From: Kunihiko Hayashi @ 2020-05-15 4:48 UTC (permalink / raw)
To: Bjorn Helgaas, Lorenzo Pieralisi, Jingoo Han, Gustavo Pimentel,
Rob Herring, Masahiro Yamada
Cc: linux-pci, devicetree, linux-arm-kernel, linux-kernel,
Masami Hiramatsu, Jassi Brar, Kunihiko Hayashi
This series adds some features for UniPhier PCIe host controller.
- Add support for PME and AER invoked by MSI interrupt
- Add iATU register view support for PCIe version >= 4.80
- Add an error message when failing to get phy driver
This adds a new function called by MSI handler in DesignWare PCIe framework,
that invokes PME and AER funcions to detect the factor from SoC-dependent
registers.
---
Kunihiko Hayashi (5):
PCI: dwc: Add msi_host_isr() callback
PCI: uniphier: Add misc interrupt handler to invoke PME and AER
dt-bindings: PCI: uniphier: Add iATU register description
PCI: uniphier: Add iATU register support
PCI: uniphier: Add error message when failed to get phy
.../devicetree/bindings/pci/uniphier-pcie.txt | 1 +
drivers/pci/controller/dwc/pcie-designware-host.c | 8 +--
drivers/pci/controller/dwc/pcie-designware.h | 1 +
drivers/pci/controller/dwc/pcie-uniphier.c | 62 +++++++++++++++++-----
4 files changed, 56 insertions(+), 16 deletions(-)
--
2.7.4
^ permalink raw reply
* [PATCH 1/5] PCI: dwc: Add msi_host_isr() callback
From: Kunihiko Hayashi @ 2020-05-15 4:48 UTC (permalink / raw)
To: Bjorn Helgaas, Lorenzo Pieralisi, Jingoo Han, Gustavo Pimentel,
Rob Herring, Masahiro Yamada
Cc: linux-pci, devicetree, linux-arm-kernel, linux-kernel,
Masami Hiramatsu, Jassi Brar, Kunihiko Hayashi
In-Reply-To: <1589518105-18368-1-git-send-email-hayashi.kunihiko@socionext.com>
This adds msi_host_isr() callback function support to describe
SoC-dependent service triggered by MSI.
For example, when AER interrupt is triggered by MSI, the callback function
reads SoC-dependent registers and detects that the interrupt is from AER,
and invoke AER interrupts related to MSI.
Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
---
drivers/pci/controller/dwc/pcie-designware-host.c | 8 ++++----
drivers/pci/controller/dwc/pcie-designware.h | 1 +
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index 0f36a92..491b7a8 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -110,13 +110,13 @@ irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
static void dw_chained_msi_isr(struct irq_desc *desc)
{
struct irq_chip *chip = irq_desc_get_chip(desc);
- struct pcie_port *pp;
+ struct pcie_port *pp = irq_desc_get_handler_data(desc);
- chained_irq_enter(chip, desc);
+ if (pp->ops->msi_host_isr)
+ pp->ops->msi_host_isr(pp);
- pp = irq_desc_get_handler_data(desc);
+ chained_irq_enter(chip, desc);
dw_handle_msi_irq(pp);
-
chained_irq_exit(chip, desc);
}
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 5a18e94..27fee10 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -160,6 +160,7 @@ struct dw_pcie_host_ops {
void (*scan_bus)(struct pcie_port *pp);
void (*set_num_vectors)(struct pcie_port *pp);
int (*msi_host_init)(struct pcie_port *pp);
+ void (*msi_host_isr)(struct pcie_port *pp);
};
struct pcie_port {
--
2.7.4
^ permalink raw reply related
* [PATCH 2/5] PCI: uniphier: Add misc interrupt handler to invoke PME and AER
From: Kunihiko Hayashi @ 2020-05-15 4:48 UTC (permalink / raw)
To: Bjorn Helgaas, Lorenzo Pieralisi, Jingoo Han, Gustavo Pimentel,
Rob Herring, Masahiro Yamada
Cc: linux-pci, devicetree, linux-arm-kernel, linux-kernel,
Masami Hiramatsu, Jassi Brar, Kunihiko Hayashi
In-Reply-To: <1589518105-18368-1-git-send-email-hayashi.kunihiko@socionext.com>
The misc interrupts consisting of PME, AER, and Link event, is handled
by INTx handler, however, these interrupts should be also handled by
MSI handler.
This adds the function uniphier_pcie_misc_isr() that handles misc
intterupts, which is called from both INTx and MSI handlers.
This function detects PME and AER interrupts with the status register,
and invoke PME and AER drivers related to INTx or MSI.
And this sets the mask for misc interrupts from INTx if MSI is enabled
and sets the mask for misc interrupts from MSI if MSI is disabled.
Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
---
drivers/pci/controller/dwc/pcie-uniphier.c | 53 +++++++++++++++++++++++-------
1 file changed, 42 insertions(+), 11 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-uniphier.c b/drivers/pci/controller/dwc/pcie-uniphier.c
index 8fd7bad..508fc7b 100644
--- a/drivers/pci/controller/dwc/pcie-uniphier.c
+++ b/drivers/pci/controller/dwc/pcie-uniphier.c
@@ -44,7 +44,9 @@
#define PCL_SYS_AUX_PWR_DET BIT(8)
#define PCL_RCV_INT 0x8108
+#define PCL_RCV_INT_ALL_INT_MASK GENMASK(28, 25)
#define PCL_RCV_INT_ALL_ENABLE GENMASK(20, 17)
+#define PCL_RCV_INT_ALL_MSI_MASK GENMASK(12, 9)
#define PCL_CFG_BW_MGT_STATUS BIT(4)
#define PCL_CFG_LINK_AUTO_BW_STATUS BIT(3)
#define PCL_CFG_AER_RC_ERR_MSI_STATUS BIT(2)
@@ -167,7 +169,15 @@ static void uniphier_pcie_stop_link(struct dw_pcie *pci)
static void uniphier_pcie_irq_enable(struct uniphier_pcie_priv *priv)
{
- writel(PCL_RCV_INT_ALL_ENABLE, priv->base + PCL_RCV_INT);
+ u32 val;
+
+ val = PCL_RCV_INT_ALL_ENABLE;
+ if (pci_msi_enabled())
+ val |= PCL_RCV_INT_ALL_INT_MASK;
+ else
+ val |= PCL_RCV_INT_ALL_MSI_MASK;
+
+ writel(val, priv->base + PCL_RCV_INT);
writel(PCL_RCV_INTX_ALL_ENABLE, priv->base + PCL_RCV_INTX);
}
@@ -237,28 +247,48 @@ static const struct irq_domain_ops uniphier_intx_domain_ops = {
.map = uniphier_pcie_intx_map,
};
-static void uniphier_pcie_irq_handler(struct irq_desc *desc)
+static void uniphier_pcie_misc_isr(struct pcie_port *pp)
{
- struct pcie_port *pp = irq_desc_get_handler_data(desc);
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci);
- struct irq_chip *chip = irq_desc_get_chip(desc);
- unsigned long reg;
- u32 val, bit, virq;
+ u32 val, virq;
- /* INT for debug */
val = readl(priv->base + PCL_RCV_INT);
if (val & PCL_CFG_BW_MGT_STATUS)
dev_dbg(pci->dev, "Link Bandwidth Management Event\n");
+
if (val & PCL_CFG_LINK_AUTO_BW_STATUS)
dev_dbg(pci->dev, "Link Autonomous Bandwidth Event\n");
- if (val & PCL_CFG_AER_RC_ERR_MSI_STATUS)
- dev_dbg(pci->dev, "Root Error\n");
- if (val & PCL_CFG_PME_MSI_STATUS)
- dev_dbg(pci->dev, "PME Interrupt\n");
+
+ if (pci_msi_enabled()) {
+ if (val & PCL_CFG_AER_RC_ERR_MSI_STATUS) {
+ dev_dbg(pci->dev, "Root Error Status\n");
+ virq = irq_linear_revmap(pp->irq_domain, 0);
+ generic_handle_irq(virq);
+ }
+
+ if (val & PCL_CFG_PME_MSI_STATUS) {
+ dev_dbg(pci->dev, "PME Interrupt\n");
+ virq = irq_linear_revmap(pp->irq_domain, 0);
+ generic_handle_irq(virq);
+ }
+ }
writel(val, priv->base + PCL_RCV_INT);
+}
+
+static void uniphier_pcie_irq_handler(struct irq_desc *desc)
+{
+ struct pcie_port *pp = irq_desc_get_handler_data(desc);
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ unsigned long reg;
+ u32 val, bit, virq;
+
+ /* misc interrupt */
+ uniphier_pcie_misc_isr(pp);
/* INTx */
chained_irq_enter(chip, desc);
@@ -336,6 +366,7 @@ static int uniphier_pcie_host_init(struct pcie_port *pp)
static const struct dw_pcie_host_ops uniphier_pcie_host_ops = {
.host_init = uniphier_pcie_host_init,
+ .msi_host_isr = uniphier_pcie_misc_isr,
};
static int uniphier_add_pcie_port(struct uniphier_pcie_priv *priv,
--
2.7.4
^ permalink raw reply related
* [PATCH 3/5] dt-bindings: PCI: uniphier: Add iATU register description
From: Kunihiko Hayashi @ 2020-05-15 4:48 UTC (permalink / raw)
To: Bjorn Helgaas, Lorenzo Pieralisi, Jingoo Han, Gustavo Pimentel,
Rob Herring, Masahiro Yamada
Cc: linux-pci, devicetree, linux-arm-kernel, linux-kernel,
Masami Hiramatsu, Jassi Brar, Kunihiko Hayashi
In-Reply-To: <1589518105-18368-1-git-send-email-hayashi.kunihiko@socionext.com>
In the dt-bindings, "atu" reg-names is required to get the register space
for iATU in Synopsis DWC version 4.80 or later.
Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
---
Documentation/devicetree/bindings/pci/uniphier-pcie.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/pci/uniphier-pcie.txt b/Documentation/devicetree/bindings/pci/uniphier-pcie.txt
index 1fa2c59..c4b7381 100644
--- a/Documentation/devicetree/bindings/pci/uniphier-pcie.txt
+++ b/Documentation/devicetree/bindings/pci/uniphier-pcie.txt
@@ -16,6 +16,7 @@ Required properties:
"dbi" - controller configuration registers
"link" - SoC-specific glue layer registers
"config" - PCIe configuration space
+ "atu" - iATU registers for DWC version 4.80 or later
- clocks: A phandle to the clock gate for PCIe glue layer including
the host controller.
- resets: A phandle to the reset line for PCIe glue layer including
--
2.7.4
^ permalink raw reply related
* [PATCH 5/5] PCI: uniphier: Add error message when failed to get phy
From: Kunihiko Hayashi @ 2020-05-15 4:48 UTC (permalink / raw)
To: Bjorn Helgaas, Lorenzo Pieralisi, Jingoo Han, Gustavo Pimentel,
Rob Herring, Masahiro Yamada
Cc: linux-pci, devicetree, linux-arm-kernel, linux-kernel,
Masami Hiramatsu, Jassi Brar, Kunihiko Hayashi
In-Reply-To: <1589518105-18368-1-git-send-email-hayashi.kunihiko@socionext.com>
Even if phy driver doesn't probe, the error message can't be
distinguished from other errors. This displays error message
caused by the phy driver explicitly.
Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
---
drivers/pci/controller/dwc/pcie-uniphier.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/controller/dwc/pcie-uniphier.c b/drivers/pci/controller/dwc/pcie-uniphier.c
index 6180d50..2bcf394 100644
--- a/drivers/pci/controller/dwc/pcie-uniphier.c
+++ b/drivers/pci/controller/dwc/pcie-uniphier.c
@@ -480,8 +480,10 @@ static int uniphier_pcie_probe(struct platform_device *pdev)
return PTR_ERR(priv->rst);
priv->phy = devm_phy_optional_get(dev, "pcie-phy");
- if (IS_ERR(priv->phy))
+ if (IS_ERR(priv->phy)) {
+ dev_err(dev, "Failed to get phy (%d)\n", PTR_ERR(priv->phy));
return PTR_ERR(priv->phy);
+ }
platform_set_drvdata(pdev, priv);
--
2.7.4
^ permalink raw reply related
* [PATCH 4/5] PCI: uniphier: Add iATU register support
From: Kunihiko Hayashi @ 2020-05-15 4:48 UTC (permalink / raw)
To: Bjorn Helgaas, Lorenzo Pieralisi, Jingoo Han, Gustavo Pimentel,
Rob Herring, Masahiro Yamada
Cc: linux-pci, devicetree, linux-arm-kernel, linux-kernel,
Masami Hiramatsu, Jassi Brar, Kunihiko Hayashi
In-Reply-To: <1589518105-18368-1-git-send-email-hayashi.kunihiko@socionext.com>
This gets iATU register area from reg property. In Synopsis DWC version
4.80 or later, since iATU register area is separated from core register
area, this area is necessary to get from DT independently.
Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
---
drivers/pci/controller/dwc/pcie-uniphier.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/pci/controller/dwc/pcie-uniphier.c b/drivers/pci/controller/dwc/pcie-uniphier.c
index 508fc7b..6180d50 100644
--- a/drivers/pci/controller/dwc/pcie-uniphier.c
+++ b/drivers/pci/controller/dwc/pcie-uniphier.c
@@ -461,6 +461,11 @@ static int uniphier_pcie_probe(struct platform_device *pdev)
if (IS_ERR(priv->pci.dbi_base))
return PTR_ERR(priv->pci.dbi_base);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "atu");
+ priv->pci.atu_base = devm_pci_remap_cfg_resource(dev, res);
+ if (IS_ERR(priv->pci.atu_base))
+ priv->pci.atu_base = NULL;
+
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "link");
priv->base = devm_ioremap_resource(dev, res);
if (IS_ERR(priv->base))
--
2.7.4
^ permalink raw reply related
* [PATCH v8 3/3] phy: intel: Add driver support for ComboPhy
From: Dilip Kota @ 2020-05-15 4:30 UTC (permalink / raw)
To: linux-kernel, kishon, vkoul, devicetree
Cc: robh, andriy.shevchenko, cheol.yong.kim, chuanhua.lei, qi-ming.wu,
yixin.zhu, Dilip Kota
In-Reply-To: <cover.1589516297.git.eswara.kota@linux.intel.com>
ComboPhy subsystem provides PHYs for various
controllers like PCIe, SATA and EMAC.
Signed-off-by: Dilip Kota <eswara.kota@linux.intel.com>
---
Changes on v8:
As per PHY Maintainer's request add description for doing register access
through regmap in comments.
Changes on v7:
Use device_node_to_regmap instead of fwnode_to_regmap
Changes on v6:
No changes
Changes on v5:
Add changes as per inputs from Andy and Rob:
DT node uses phy-mode values as defined in "include/dt-bindings/phy/phy.h",
add changes to handle it.
ComboPhy no longer has children nodes, and children node properties(reset)
moved to parent node, so do the code changes accordingly.
Add _xlate() function to pass the appropriate phy handle.
Fix couple of nitpicks.
Changes on v4:
Address review comments
Remove dependency on OF config
Update copyright to 2019-2020
Define register macro PAD_DIS_CFG instead of const variable inside function.
Improve the error prints, and error returns.
Call put_device(dev), for get_dev_from_fwnode()
Move platform_set_drvdata() at the end of the probe().
Correct alignment in phy_ops intel_cbphy_ops.
Correct commented lines with proper vocabulary and punctuation.
Add/remove commas for the required constant arrays and enums.
Remove in driver:
linux/kernel.h, not required
macros: PCIE_PHY_MPLLA_CTRL, PCIE_PHY_MPLLB_CTRL
temp variable u32 prop;
Change function names:
intel_cbphy_iphy_dt_parse() -> intel_cbphy_iphy_fwnode_parse()
intel_cbphy_dt_sanity_check() -> intel_cbphy_sanity_check()
intel_cbphy_dt_parse() -> intel_cbphy_fwnode_parse()
Changes on v3:
Remove intel_iphy_names
Remove struct phy in struct intel_cbphy_iphy
Imporve if conditions logic
Use fwnode_to_regmap()
Call devm_of_platform_populate() to populate child nodes
Fix reset sequence during phy_init
Add SoC specific compatible "intel,combophy-lgm"
Add description for enums
Remove default case in switch {} intel_cbphy_set_mode() as it
never happens.
Use mutex_lock to synchronise combophy initialization across
two phys.
Change init_cnt to u32 datatype as it is within mutex lock.
Correct error handling of
fwnode_property_read_u32_array(fwnode, "intel,phy-mode", ...)
drivers/phy/intel/Kconfig | 14 +
drivers/phy/intel/Makefile | 1 +
drivers/phy/intel/phy-intel-combo.c | 627 ++++++++++++++++++++++++++++++++++++
3 files changed, 642 insertions(+)
create mode 100644 drivers/phy/intel/phy-intel-combo.c
diff --git a/drivers/phy/intel/Kconfig b/drivers/phy/intel/Kconfig
index 4ea6a8897cd7..3b40eb7b4fb4 100644
--- a/drivers/phy/intel/Kconfig
+++ b/drivers/phy/intel/Kconfig
@@ -2,6 +2,20 @@
#
# Phy drivers for Intel Lightning Mountain(LGM) platform
#
+config PHY_INTEL_COMBO
+ bool "Intel ComboPHY driver"
+ depends on X86 || COMPILE_TEST
+ depends on OF && HAS_IOMEM
+ select MFD_SYSCON
+ select GENERIC_PHY
+ select REGMAP
+ help
+ Enable this to support Intel ComboPhy.
+
+ This driver configures ComboPhy subsystem on Intel gateway
+ chipsets which provides PHYs for various controllers, EMAC,
+ SATA and PCIe.
+
config PHY_INTEL_EMMC
tristate "Intel EMMC PHY driver"
select GENERIC_PHY
diff --git a/drivers/phy/intel/Makefile b/drivers/phy/intel/Makefile
index 6b876a75599d..233d530dadde 100644
--- a/drivers/phy/intel/Makefile
+++ b/drivers/phy/intel/Makefile
@@ -1,2 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_PHY_INTEL_COMBO) += phy-intel-combo.o
obj-$(CONFIG_PHY_INTEL_EMMC) += phy-intel-emmc.o
diff --git a/drivers/phy/intel/phy-intel-combo.c b/drivers/phy/intel/phy-intel-combo.c
new file mode 100644
index 000000000000..04ad595e21e4
--- /dev/null
+++ b/drivers/phy/intel/phy-intel-combo.c
@@ -0,0 +1,627 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel Combo-PHY driver
+ *
+ * Copyright (C) 2019-2020 Intel Corporation.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+#include <dt-bindings/phy/phy.h>
+
+#define PCIE_PHY_GEN_CTRL 0x00
+#define PCIE_PHY_CLK_PAD BIT(17)
+
+#define PAD_DIS_CFG 0x174
+
+#define PCS_XF_ATE_OVRD_IN_2 0x3008
+#define ADAPT_REQ_MSK GENMASK(5, 4)
+
+#define PCS_XF_RX_ADAPT_ACK 0x3010
+#define RX_ADAPT_ACK_BIT BIT(0)
+
+#define CR_ADDR(addr, lane) (((addr) + (lane) * 0x100) << 2)
+#define REG_COMBO_MODE(x) ((x) * 0x200)
+#define REG_CLK_DISABLE(x) ((x) * 0x200 + 0x124)
+
+#define COMBO_PHY_ID(x) ((x)->parent->id)
+#define PHY_ID(x) ((x)->id)
+
+#define CLK_100MHZ 100000000
+#define CLK_156_25MHZ 156250000
+
+static const unsigned long intel_iphy_clk_rates[] = {
+ CLK_100MHZ, CLK_156_25MHZ, CLK_100MHZ,
+};
+
+enum {
+ PHY_0,
+ PHY_1,
+ PHY_MAX_NUM
+};
+
+/*
+ * Clock Register bit fields to enable clocks
+ * for ComboPhy according to the mode.
+ */
+enum intel_phy_mode {
+ PHY_PCIE_MODE = 0,
+ PHY_XPCS_MODE,
+ PHY_SATA_MODE,
+};
+
+/* ComboPhy mode Register values */
+enum intel_combo_mode {
+ PCIE0_PCIE1_MODE = 0,
+ PCIE_DL_MODE,
+ RXAUI_MODE,
+ XPCS0_XPCS1_MODE,
+ SATA0_SATA1_MODE,
+};
+
+enum aggregated_mode {
+ PHY_SL_MODE,
+ PHY_DL_MODE,
+};
+
+struct intel_combo_phy;
+
+struct intel_cbphy_iphy {
+ struct phy *phy;
+ struct intel_combo_phy *parent;
+ struct reset_control *app_rst;
+ u32 id;
+};
+
+struct intel_combo_phy {
+ struct device *dev;
+ struct clk *core_clk;
+ unsigned long clk_rate;
+ void __iomem *app_base;
+ void __iomem *cr_base;
+ struct regmap *syscfg;
+ struct regmap *hsiocfg;
+ u32 id;
+ u32 bid;
+ struct reset_control *phy_rst;
+ struct reset_control *core_rst;
+ struct intel_cbphy_iphy iphy[PHY_MAX_NUM];
+ enum intel_phy_mode phy_mode;
+ enum aggregated_mode aggr_mode;
+ u32 init_cnt;
+ struct mutex lock;
+};
+
+static int intel_cbphy_iphy_enable(struct intel_cbphy_iphy *iphy, bool set)
+{
+ struct intel_combo_phy *cbphy = iphy->parent;
+ u32 mask = BIT(cbphy->phy_mode * 2 + iphy->id);
+ u32 val;
+
+ /* Register: 0 is enable, 1 is disable */
+ val = set ? 0 : mask;
+
+ return regmap_update_bits(cbphy->hsiocfg, REG_CLK_DISABLE(cbphy->bid),
+ mask, val);
+}
+
+static int intel_cbphy_pcie_refclk_cfg(struct intel_cbphy_iphy *iphy, bool set)
+{
+ struct intel_combo_phy *cbphy = iphy->parent;
+ u32 mask = BIT(cbphy->id * 2 + iphy->id);
+ u32 val;
+
+ /* Register: 0 is enable, 1 is disable */
+ val = set ? 0 : mask;
+
+ return regmap_update_bits(cbphy->syscfg, PAD_DIS_CFG, mask, val);
+}
+
+static inline void combo_phy_w32_off_mask(void __iomem *base, unsigned int reg,
+ u32 mask, u32 val)
+{
+ u32 reg_val;
+
+ reg_val = readl(base + reg);
+ reg_val &= ~mask;
+ reg_val |= FIELD_PREP(mask, val);
+ writel(reg_val, base + reg);
+}
+
+static int intel_cbphy_iphy_cfg(struct intel_cbphy_iphy *iphy,
+ int (*phy_cfg)(struct intel_cbphy_iphy *))
+{
+ struct intel_combo_phy *cbphy = iphy->parent;
+ int ret;
+
+ ret = phy_cfg(iphy);
+ if (ret)
+ return ret;
+
+ if (cbphy->aggr_mode != PHY_DL_MODE)
+ return 0;
+
+ return phy_cfg(&cbphy->iphy[PHY_1]);
+}
+
+static int intel_cbphy_pcie_en_pad_refclk(struct intel_cbphy_iphy *iphy)
+{
+ struct intel_combo_phy *cbphy = iphy->parent;
+ int ret;
+
+ ret = intel_cbphy_pcie_refclk_cfg(iphy, true);
+ if (ret) {
+ dev_err(cbphy->dev, "Failed to enable PCIe pad refclk\n");
+ return ret;
+ }
+
+ if (cbphy->init_cnt)
+ return 0;
+
+ combo_phy_w32_off_mask(cbphy->app_base, PCIE_PHY_GEN_CTRL,
+ PCIE_PHY_CLK_PAD, 0);
+
+ /* Delay for stable clock PLL */
+ usleep_range(50, 100);
+
+ return 0;
+}
+
+static int intel_cbphy_pcie_dis_pad_refclk(struct intel_cbphy_iphy *iphy)
+{
+ struct intel_combo_phy *cbphy = iphy->parent;
+ int ret;
+
+ ret = intel_cbphy_pcie_refclk_cfg(iphy, false);
+ if (ret) {
+ dev_err(cbphy->dev, "Failed to disable PCIe pad refclk\n");
+ return ret;
+ }
+
+ if (cbphy->init_cnt)
+ return 0;
+
+ combo_phy_w32_off_mask(cbphy->app_base, PCIE_PHY_GEN_CTRL,
+ PCIE_PHY_CLK_PAD, 1);
+
+ return 0;
+}
+
+static int intel_cbphy_set_mode(struct intel_combo_phy *cbphy)
+{
+ enum aggregated_mode aggr = cbphy->aggr_mode;
+ struct device *dev = cbphy->dev;
+ enum intel_combo_mode cb_mode;
+ enum intel_phy_mode mode;
+ int ret;
+
+ mode = cbphy->phy_mode;
+
+ switch (mode) {
+ case PHY_PCIE_MODE:
+ cb_mode = (aggr == PHY_DL_MODE) ? PCIE_DL_MODE : PCIE0_PCIE1_MODE;
+ break;
+
+ case PHY_XPCS_MODE:
+ cb_mode = (aggr == PHY_DL_MODE) ? RXAUI_MODE : XPCS0_XPCS1_MODE;
+ break;
+
+ case PHY_SATA_MODE:
+ if (aggr == PHY_DL_MODE) {
+ dev_err(dev, "Mode:%u not support dual lane!\n", mode);
+ return -EINVAL;
+ }
+
+ cb_mode = SATA0_SATA1_MODE;
+ break;
+ }
+
+ ret = regmap_write(cbphy->hsiocfg, REG_COMBO_MODE(cbphy->bid), cb_mode);
+ if (ret)
+ dev_err(dev, "Failed to set ComboPhy mode: %d\n", ret);
+
+ return ret;
+}
+
+static void intel_cbphy_rst_assert(struct intel_combo_phy *cbphy)
+{
+ reset_control_assert(cbphy->core_rst);
+ reset_control_assert(cbphy->phy_rst);
+}
+
+static void intel_cbphy_rst_deassert(struct intel_combo_phy *cbphy)
+{
+ reset_control_deassert(cbphy->core_rst);
+ reset_control_deassert(cbphy->phy_rst);
+ /* Delay to ensure reset process is done */
+ usleep_range(10, 20);
+}
+
+static int intel_cbphy_iphy_power_on(struct intel_cbphy_iphy *iphy)
+{
+ struct intel_combo_phy *cbphy = iphy->parent;
+ int ret;
+
+ if (!cbphy->init_cnt) {
+ ret = clk_prepare_enable(cbphy->core_clk);
+ if (ret) {
+ dev_err(cbphy->dev, "Clock enable failed!\n");
+ return ret;
+ }
+
+ ret = clk_set_rate(cbphy->core_clk, cbphy->clk_rate);
+ if (ret) {
+ dev_err(cbphy->dev, "Clock freq set to %lu failed!\n",
+ cbphy->clk_rate);
+ goto clk_err;
+ }
+
+ intel_cbphy_rst_assert(cbphy);
+ intel_cbphy_rst_deassert(cbphy);
+ ret = intel_cbphy_set_mode(cbphy);
+ if (ret)
+ goto clk_err;
+ }
+
+ ret = intel_cbphy_iphy_enable(iphy, true);
+ if (ret) {
+ dev_err(cbphy->dev, "Failed enabling PHY core\n");
+ goto clk_err;
+ }
+
+ ret = reset_control_deassert(iphy->app_rst);
+ if (ret) {
+ dev_err(cbphy->dev, "PHY(%u:%u) reset deassert failed!\n",
+ COMBO_PHY_ID(iphy), PHY_ID(iphy));
+ goto clk_err;
+ }
+
+ /* Delay to ensure reset process is done */
+ udelay(1);
+
+ return 0;
+
+clk_err:
+ clk_disable_unprepare(cbphy->core_clk);
+
+ return ret;
+}
+
+static int intel_cbphy_iphy_power_off(struct intel_cbphy_iphy *iphy)
+{
+ struct intel_combo_phy *cbphy = iphy->parent;
+ int ret;
+
+ ret = reset_control_assert(iphy->app_rst);
+ if (ret) {
+ dev_err(cbphy->dev, "PHY(%u:%u) reset assert failed!\n",
+ COMBO_PHY_ID(iphy), PHY_ID(iphy));
+ return ret;
+ }
+
+ ret = intel_cbphy_iphy_enable(iphy, false);
+ if (ret) {
+ dev_err(cbphy->dev, "Failed disabling PHY core\n");
+ return ret;
+ }
+
+ if (cbphy->init_cnt)
+ return 0;
+
+ clk_disable_unprepare(cbphy->core_clk);
+ intel_cbphy_rst_assert(cbphy);
+
+ return 0;
+}
+
+static int intel_cbphy_init(struct phy *phy)
+{
+ struct intel_cbphy_iphy *iphy = phy_get_drvdata(phy);
+ struct intel_combo_phy *cbphy = iphy->parent;
+ int ret;
+
+ mutex_lock(&cbphy->lock);
+ ret = intel_cbphy_iphy_cfg(iphy, intel_cbphy_iphy_power_on);
+ if (ret)
+ goto err;
+
+ if (cbphy->phy_mode == PHY_PCIE_MODE) {
+ ret = intel_cbphy_iphy_cfg(iphy, intel_cbphy_pcie_en_pad_refclk);
+ if (ret)
+ goto err;
+ }
+
+ cbphy->init_cnt++;
+
+err:
+ mutex_unlock(&cbphy->lock);
+
+ return ret;
+}
+
+static int intel_cbphy_exit(struct phy *phy)
+{
+ struct intel_cbphy_iphy *iphy = phy_get_drvdata(phy);
+ struct intel_combo_phy *cbphy = iphy->parent;
+ int ret;
+
+ mutex_lock(&cbphy->lock);
+ cbphy->init_cnt--;
+ if (cbphy->phy_mode == PHY_PCIE_MODE) {
+ ret = intel_cbphy_iphy_cfg(iphy, intel_cbphy_pcie_dis_pad_refclk);
+ if (ret)
+ goto err;
+ }
+
+ ret = intel_cbphy_iphy_cfg(iphy, intel_cbphy_iphy_power_off);
+
+err:
+ mutex_unlock(&cbphy->lock);
+
+ return ret;
+}
+
+static int intel_cbphy_calibrate(struct phy *phy)
+{
+ struct intel_cbphy_iphy *iphy = phy_get_drvdata(phy);
+ struct intel_combo_phy *cbphy = iphy->parent;
+ void __iomem *cr_base = cbphy->cr_base;
+ int val, ret, id;
+
+ if (cbphy->phy_mode != PHY_XPCS_MODE)
+ return 0;
+
+ id = PHY_ID(iphy);
+
+ /* trigger auto RX adaptation */
+ combo_phy_w32_off_mask(cr_base, CR_ADDR(PCS_XF_ATE_OVRD_IN_2, id),
+ ADAPT_REQ_MSK, 3);
+ /* Wait RX adaptation to finish */
+ ret = readl_poll_timeout(cr_base + CR_ADDR(PCS_XF_RX_ADAPT_ACK, id),
+ val, val & RX_ADAPT_ACK_BIT, 10, 5000);
+ if (ret)
+ dev_err(cbphy->dev, "RX Adaptation failed!\n");
+ else
+ dev_dbg(cbphy->dev, "RX Adaptation success!\n");
+
+ /* Stop RX adaptation */
+ combo_phy_w32_off_mask(cr_base, CR_ADDR(PCS_XF_ATE_OVRD_IN_2, id),
+ ADAPT_REQ_MSK, 0);
+
+ return ret;
+}
+
+static int intel_cbphy_fwnode_parse(struct intel_combo_phy *cbphy)
+{
+ struct device *dev = cbphy->dev;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
+ struct fwnode_reference_args ref;
+ int ret;
+ u32 val;
+
+ cbphy->core_clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(cbphy->core_clk)) {
+ ret = PTR_ERR(cbphy->core_clk);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Get clk failed:%d!\n", ret);
+ return ret;
+ }
+
+ cbphy->core_rst = devm_reset_control_get_optional(dev, "core");
+ if (IS_ERR(cbphy->core_rst)) {
+ ret = PTR_ERR(cbphy->core_rst);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Get core reset control err: %d!\n", ret);
+ return ret;
+ }
+
+ cbphy->phy_rst = devm_reset_control_get_optional(dev, "phy");
+ if (IS_ERR(cbphy->phy_rst)) {
+ ret = PTR_ERR(cbphy->phy_rst);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Get PHY reset control err: %d!\n", ret);
+ return ret;
+ }
+
+ cbphy->iphy[0].app_rst = devm_reset_control_get_optional(dev, "iphy0");
+ if (IS_ERR(cbphy->iphy[0].app_rst)) {
+ ret = PTR_ERR(cbphy->iphy[0].app_rst);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Get phy0 reset control err: %d!\n", ret);
+ return ret;
+ }
+
+ cbphy->iphy[1].app_rst = devm_reset_control_get_optional(dev, "iphy1");
+ if (IS_ERR(cbphy->iphy[1].app_rst)) {
+ ret = PTR_ERR(cbphy->iphy[1].app_rst);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Get phy1 reset control err: %d!\n", ret);
+ return ret;
+ }
+
+ cbphy->app_base = devm_platform_ioremap_resource_byname(pdev, "app");
+ if (IS_ERR(cbphy->app_base))
+ return PTR_ERR(cbphy->app_base);
+
+ cbphy->cr_base = devm_platform_ioremap_resource_byname(pdev, "core");
+ if (IS_ERR(cbphy->cr_base))
+ return PTR_ERR(cbphy->cr_base);
+
+ ret = fwnode_property_get_reference_args(fwnode, "intel,syscfg", NULL,
+ 1, 0, &ref);
+ if (ret < 0)
+ return ret;
+
+ cbphy->id = ref.args[0];
+ cbphy->syscfg = device_node_to_regmap(to_of_node(ref.fwnode));
+ fwnode_handle_put(ref.fwnode);
+
+ ret = fwnode_property_get_reference_args(fwnode, "intel,hsio", NULL, 1,
+ 0, &ref);
+ if (ret < 0)
+ return ret;
+
+ cbphy->bid = ref.args[0];
+ cbphy->hsiocfg = device_node_to_regmap(to_of_node(ref.fwnode));
+ fwnode_handle_put(ref.fwnode);
+
+ ret = fwnode_property_read_u32_array(fwnode, "intel,phy-mode", &val, 1);
+ if (ret)
+ return ret;
+
+ switch (val) {
+ case PHY_TYPE_PCIE:
+ cbphy->phy_mode = PHY_PCIE_MODE;
+ break;
+
+ case PHY_TYPE_SATA:
+ cbphy->phy_mode = PHY_SATA_MODE;
+ break;
+
+ case PHY_TYPE_XPCS:
+ cbphy->phy_mode = PHY_XPCS_MODE;
+ break;
+
+ default:
+ dev_err(dev, "Invalid PHY mode: %u\n", val);
+ return -EINVAL;
+ }
+
+ cbphy->clk_rate = intel_iphy_clk_rates[cbphy->phy_mode];
+
+ if (fwnode_property_present(fwnode, "intel,aggregation"))
+ cbphy->aggr_mode = PHY_DL_MODE;
+ else
+ cbphy->aggr_mode = PHY_SL_MODE;
+
+ return 0;
+}
+
+static const struct phy_ops intel_cbphy_ops = {
+ .init = intel_cbphy_init,
+ .exit = intel_cbphy_exit,
+ .calibrate = intel_cbphy_calibrate,
+ .owner = THIS_MODULE,
+};
+
+static struct phy *intel_cbphy_xlate(struct device *dev,
+ struct of_phandle_args *args)
+{
+ struct intel_combo_phy *cbphy = dev_get_drvdata(dev);
+ u32 iphy_id;
+
+ if (args->args_count < 1) {
+ dev_err(dev, "Invalid number of arguments\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ iphy_id = args->args[0];
+ if (iphy_id >= PHY_MAX_NUM) {
+ dev_err(dev, "Invalid phy instance %d\n", iphy_id);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (cbphy->aggr_mode == PHY_DL_MODE && iphy_id == PHY_1) {
+ dev_err(dev, "Invalid. ComboPhy is in Dual lane mode %d\n", iphy_id);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return cbphy->iphy[iphy_id].phy;
+}
+
+static int intel_cbphy_create(struct intel_combo_phy *cbphy)
+{
+ struct phy_provider *phy_provider;
+ struct device *dev = cbphy->dev;
+ struct intel_cbphy_iphy *iphy;
+ int i;
+
+ for (i = 0; i < PHY_MAX_NUM; i++) {
+ iphy = &cbphy->iphy[i];
+ iphy->parent = cbphy;
+ iphy->id = i;
+
+ /* In dual lane mode skip phy creation for the second phy */
+ if (cbphy->aggr_mode == PHY_DL_MODE && iphy->id == PHY_1)
+ continue;
+
+ iphy->phy = devm_phy_create(dev, NULL, &intel_cbphy_ops);
+ if (IS_ERR(iphy->phy)) {
+ dev_err(dev, "PHY[%u:%u]: create PHY instance failed!\n",
+ COMBO_PHY_ID(iphy), PHY_ID(iphy));
+
+ return PTR_ERR(iphy->phy);
+ }
+
+ phy_set_drvdata(iphy->phy, iphy);
+ }
+
+ dev_set_drvdata(dev, cbphy);
+ phy_provider = devm_of_phy_provider_register(dev, intel_cbphy_xlate);
+ if (IS_ERR(phy_provider))
+ dev_err(dev, "Register PHY provider failed!\n");
+
+ return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static int intel_cbphy_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct intel_combo_phy *cbphy;
+ int ret;
+
+ cbphy = devm_kzalloc(dev, sizeof(*cbphy), GFP_KERNEL);
+ if (!cbphy)
+ return -ENOMEM;
+
+ cbphy->dev = dev;
+ cbphy->init_cnt = 0;
+ mutex_init(&cbphy->lock);
+ ret = intel_cbphy_fwnode_parse(cbphy);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, cbphy);
+
+ return intel_cbphy_create(cbphy);
+}
+
+static int intel_cbphy_remove(struct platform_device *pdev)
+{
+ struct intel_combo_phy *cbphy = platform_get_drvdata(pdev);
+
+ intel_cbphy_rst_assert(cbphy);
+ clk_disable_unprepare(cbphy->core_clk);
+ return 0;
+}
+
+static const struct of_device_id of_intel_cbphy_match[] = {
+ { .compatible = "intel,combo-phy" },
+ { .compatible = "intel,combophy-lgm" },
+ {}
+};
+
+static struct platform_driver intel_cbphy_driver = {
+ .probe = intel_cbphy_probe,
+ .remove = intel_cbphy_remove,
+ .driver = {
+ .name = "intel-combo-phy",
+ .of_match_table = of_intel_cbphy_match,
+ }
+};
+
+module_platform_driver(intel_cbphy_driver);
+
+MODULE_DESCRIPTION("Intel Combo-phy driver");
+MODULE_LICENSE("GPL v2");
--
2.11.0
^ permalink raw reply related
* [PATCH v8 2/3] dt-bindings: phy: Add YAML schemas for Intel ComboPhy
From: Dilip Kota @ 2020-05-15 4:30 UTC (permalink / raw)
To: linux-kernel, kishon, vkoul, devicetree
Cc: robh, andriy.shevchenko, cheol.yong.kim, chuanhua.lei, qi-ming.wu,
yixin.zhu, Dilip Kota
In-Reply-To: <cover.1589516297.git.eswara.kota@linux.intel.com>
ComboPhy subsystem provides PHY support to various
controllers, viz. PCIe, SATA and EMAC.
Adding YAML schemas for the same.
Signed-off-by: Dilip Kota <eswara.kota@linux.intel.com>
Reviewed-by: Rob Herring <robh@kernel.org>
---
Changes on v8:
No Change.
Changes on v7:
No Change.
Changes on v6:
Add Reviewed-by: Rob Herring <robh@kernel.org>
.../devicetree/bindings/phy/intel,combo-phy.yaml | 101 +++++++++++++++++++++
1 file changed, 101 insertions(+)
create mode 100644 Documentation/devicetree/bindings/phy/intel,combo-phy.yaml
diff --git a/Documentation/devicetree/bindings/phy/intel,combo-phy.yaml b/Documentation/devicetree/bindings/phy/intel,combo-phy.yaml
new file mode 100644
index 000000000000..347d0cdfb80d
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/intel,combo-phy.yaml
@@ -0,0 +1,101 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/intel,combo-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Intel ComboPhy Subsystem
+
+maintainers:
+ - Dilip Kota <eswara.kota@linux.intel.com>
+
+description: |
+ Intel Combophy subsystem supports PHYs for PCIe, EMAC and SATA
+ controllers. A single Combophy provides two PHY instances.
+
+properties:
+ $nodename:
+ pattern: "combophy(@.*|-[0-9a-f])*$"
+
+ compatible:
+ items:
+ - const: intel,combophy-lgm
+ - const: intel,combo-phy
+
+ clocks:
+ maxItems: 1
+
+ reg:
+ items:
+ - description: ComboPhy core registers
+ - description: PCIe app core control registers
+
+ reg-names:
+ items:
+ - const: core
+ - const: app
+
+ resets:
+ maxItems: 4
+
+ reset-names:
+ items:
+ - const: phy
+ - const: core
+ - const: iphy0
+ - const: iphy1
+
+ intel,syscfg:
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ description: Chip configuration registers handle and ComboPhy instance id
+
+ intel,hsio:
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ description: HSIO registers handle and ComboPhy instance id on NOC
+
+ intel,aggregation:
+ type: boolean
+ description: |
+ Specify the flag to configure ComboPHY in dual lane mode.
+
+ intel,phy-mode:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: |
+ Mode of the two phys in ComboPhy.
+ See dt-bindings/phy/phy.h for values.
+
+ "#phy-cells":
+ const: 1
+
+required:
+ - compatible
+ - clocks
+ - reg
+ - reg-names
+ - intel,syscfg
+ - intel,hsio
+ - intel,phy-mode
+ - "#phy-cells"
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/phy/phy.h>
+ combophy@d0a00000 {
+ compatible = "intel,combophy-lgm", "intel,combo-phy";
+ clocks = <&cgu0 1>;
+ #phy-cells = <1>;
+ reg = <0xd0a00000 0x40000>,
+ <0xd0a40000 0x1000>;
+ reg-names = "core", "app";
+ resets = <&rcu0 0x50 6>,
+ <&rcu0 0x50 17>,
+ <&rcu0 0x50 23>,
+ <&rcu0 0x50 24>;
+ reset-names = "phy", "core", "iphy0", "iphy1";
+ intel,syscfg = <&sysconf 0>;
+ intel,hsio = <&hsiol 0>;
+ intel,phy-mode = <PHY_TYPE_PCIE>;
+ intel,aggregation;
+ };
--
2.11.0
^ permalink raw reply related
* [PATCH v8 1/3] dt-bindings: phy: Add PHY_TYPE_XPCS definition
From: Dilip Kota @ 2020-05-15 4:30 UTC (permalink / raw)
To: linux-kernel, kishon, vkoul, devicetree
Cc: robh, andriy.shevchenko, cheol.yong.kim, chuanhua.lei, qi-ming.wu,
yixin.zhu, Dilip Kota
In-Reply-To: <cover.1589516297.git.eswara.kota@linux.intel.com>
Add definition for Ethernet PCS phy type.
Signed-off-by: Dilip Kota <eswara.kota@linux.intel.com>
Acked-by: Rob Herring <robh@kernel.org>
---
Changes on v8:
No Change
Changes on v7:
No Change
Changes on v6:
Add Acked-by: Rob Herring <robh@kernel.org>
include/dt-bindings/phy/phy.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/include/dt-bindings/phy/phy.h b/include/dt-bindings/phy/phy.h
index 1f3f866fae7b..3727ef72138b 100644
--- a/include/dt-bindings/phy/phy.h
+++ b/include/dt-bindings/phy/phy.h
@@ -17,5 +17,6 @@
#define PHY_TYPE_USB3 4
#define PHY_TYPE_UFS 5
#define PHY_TYPE_DP 6
+#define PHY_TYPE_XPCS 7
#endif /* _DT_BINDINGS_PHY */
--
2.11.0
^ permalink raw reply related
* [PATCH v8 0/3] Add Intel ComboPhy driver
From: Dilip Kota @ 2020-05-15 4:30 UTC (permalink / raw)
To: linux-kernel, kishon, vkoul, devicetree
Cc: robh, andriy.shevchenko, cheol.yong.kim, chuanhua.lei, qi-ming.wu,
yixin.zhu, Dilip Kota
This patch series adds Intel ComboPhy driver, respective yaml schemas
Changes on v8:
As per PHY Maintainer's request add description in comments for doing
register access through register map framework.
Changes on v7:
As per System control driver maintainer's inputs remove
fwnode_to_regmap() definition and use device_node_get_regmap()
Changes on v6:
Rebase patches on the latest maintainer's branch
https://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux-phy.git/?h=phy-for-5.7
Dilip Kota (3):
dt-bindings: phy: Add PHY_TYPE_XPCS definition
dt-bindings: phy: Add YAML schemas for Intel ComboPhy
phy: intel: Add driver support for ComboPhy
.../devicetree/bindings/phy/intel,combo-phy.yaml | 101 ++++
drivers/phy/intel/Kconfig | 14 +
drivers/phy/intel/Makefile | 1 +
drivers/phy/intel/phy-intel-combo.c | 627 +++++++++++++++++++++
include/dt-bindings/phy/phy.h | 1 +
5 files changed, 744 insertions(+)
create mode 100644 Documentation/devicetree/bindings/phy/intel,combo-phy.yaml
create mode 100644 drivers/phy/intel/phy-intel-combo.c
--
2.11.0
^ permalink raw reply
* Re: [PATCH v7 2/4] usb: dwc3: qcom: Add interconnect support in dwc3 driver
From: Viresh Kumar @ 2020-05-15 4:26 UTC (permalink / raw)
To: Manu Gautam
Cc: Georgi Djakov, Matthias Kaehlcke, Felipe Balbi,
Sandeep Maheswaram, Andy Gross, Bjorn Andersson,
Greg Kroah-Hartman, Rob Herring, Mark Rutland, Stephen Boyd,
Doug Anderson, linux-arm-msm@vger.kernel.org,
open list:ULTRA-WIDEBAND (UWB) SUBSYSTEM:,
devicetree@vger.kernel.org, Linux Kernel Mailing List,
Chandana Kishori Chiluveru
In-Reply-To: <20a2adc5-4153-1447-0542-908b7996c187@codeaurora.org>
On 15-05-20, 09:53, Manu Gautam wrote:
> Hi,
>
> On 5/15/2020 9:27 AM, Viresh Kumar wrote:
> > On Fri, 15 May 2020 at 02:33, Georgi Djakov <georgi.djakov@linaro.org> wrote:
> >
> >> ---8<---
> >> diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
> >> index 206caa0ea1c6..6661788b1a76 100644
> >> --- a/drivers/usb/dwc3/Kconfig
> >> +++ b/drivers/usb/dwc3/Kconfig
> >> @@ -129,6 +129,7 @@ config USB_DWC3_QCOM
> >> tristate "Qualcomm Platform"
> >> depends on ARCH_QCOM || COMPILE_TEST
> >> depends on EXTCON || !EXTCON
> >> + depends on INTERCONNECT || !INTERCONNECT
> > Again, as I said yesterday. This looks incorrect and may not fix the problem..
> >
> > With this we will be able to select USB_DWC3_QCOM even when INTERCONNECT=m.
>
> DWC3_QCOM in that case would be 'm' if INTERCONNECT =m and
> that should be fine?
Ahh, I was speaking in context of PM_OPP where it is a bool. Perhaps
this works just fine with DWC3_QCOM, sorry for the confusion.
--
viresh
^ permalink raw reply
* Re: [PATCH v7 2/4] usb: dwc3: qcom: Add interconnect support in dwc3 driver
From: Manu Gautam @ 2020-05-15 4:23 UTC (permalink / raw)
To: Viresh Kumar, Georgi Djakov
Cc: Matthias Kaehlcke, Felipe Balbi, Sandeep Maheswaram, Andy Gross,
Bjorn Andersson, Greg Kroah-Hartman, Rob Herring, Mark Rutland,
Stephen Boyd, Doug Anderson, linux-arm-msm@vger.kernel.org,
open list:ULTRA-WIDEBAND (UWB) SUBSYSTEM:,
devicetree@vger.kernel.org, Linux Kernel Mailing List,
Chandana Kishori Chiluveru
In-Reply-To: <CAKohpon+JBpV3fC7j=rhc1R4gi_mVG6teBDrE8Yryd4QXfw9bw@mail.gmail.com>
Hi,
On 5/15/2020 9:27 AM, Viresh Kumar wrote:
> On Fri, 15 May 2020 at 02:33, Georgi Djakov <georgi.djakov@linaro.org> wrote:
>
>> ---8<---
>> diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
>> index 206caa0ea1c6..6661788b1a76 100644
>> --- a/drivers/usb/dwc3/Kconfig
>> +++ b/drivers/usb/dwc3/Kconfig
>> @@ -129,6 +129,7 @@ config USB_DWC3_QCOM
>> tristate "Qualcomm Platform"
>> depends on ARCH_QCOM || COMPILE_TEST
>> depends on EXTCON || !EXTCON
>> + depends on INTERCONNECT || !INTERCONNECT
> Again, as I said yesterday. This looks incorrect and may not fix the problem..
>
> With this we will be able to select USB_DWC3_QCOM even when INTERCONNECT=m.
DWC3_QCOM in that case would be 'm' if INTERCONNECT =m and
that should be fine?
> What we perhaps need here is:
> depends on INTERCONNECT != m
>
> --
> viresh
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply
* Re: [PATCH v7 2/4] usb: dwc3: qcom: Add interconnect support in dwc3 driver
From: Viresh Kumar @ 2020-05-15 3:57 UTC (permalink / raw)
To: Georgi Djakov
Cc: Matthias Kaehlcke, Felipe Balbi, Sandeep Maheswaram, Andy Gross,
Bjorn Andersson, Greg Kroah-Hartman, Rob Herring, Mark Rutland,
Stephen Boyd, Doug Anderson, linux-arm-msm@vger.kernel.org,
open list:ULTRA-WIDEBAND (UWB) SUBSYSTEM:,
devicetree@vger.kernel.org, Linux Kernel Mailing List,
Manu Gautam, Chandana Kishori Chiluveru
In-Reply-To: <abbc3f8c-c8c9-c189-735e-f8058dab3e40@linaro.org>
On Fri, 15 May 2020 at 02:33, Georgi Djakov <georgi.djakov@linaro.org> wrote:
> ---8<---
> diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
> index 206caa0ea1c6..6661788b1a76 100644
> --- a/drivers/usb/dwc3/Kconfig
> +++ b/drivers/usb/dwc3/Kconfig
> @@ -129,6 +129,7 @@ config USB_DWC3_QCOM
> tristate "Qualcomm Platform"
> depends on ARCH_QCOM || COMPILE_TEST
> depends on EXTCON || !EXTCON
> + depends on INTERCONNECT || !INTERCONNECT
Again, as I said yesterday. This looks incorrect and may not fix the problem..
With this we will be able to select USB_DWC3_QCOM even when INTERCONNECT=m.
What we perhaps need here is:
depends on INTERCONNECT != m
--
viresh
^ permalink raw reply
* Re: [PATCH v3 20/20] dt-bindings: ehci/ohci: Allow iommus property
From: Rob Herring @ 2020-05-15 3:17 UTC (permalink / raw)
To: Andre Przywara
Cc: devicetree, Liviu Dudau, Mark Rutland, Lorenzo Pieralisi,
Sudeep Holla, linux-arm-kernel, Greg Kroah-Hartman, linux-usb
In-Reply-To: <20200513103016.130417-21-andre.przywara@arm.com>
On Wed, 13 May 2020 11:30:16 +0100, Andre Przywara wrote:
> A OHCI/EHCI controller could be behind an IOMMU, in which case an iommus
> property assigns the stream ID for this device.
>
> Allow that property in the DT bindings to fix a complaint about the Arm Juno
> board's DTS file.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Documentation/devicetree/bindings/usb/generic-ehci.yaml | 3 +++
> Documentation/devicetree/bindings/usb/generic-ohci.yaml | 3 +++
> 2 files changed, 6 insertions(+)
>
Applied, thanks!
^ permalink raw reply
* Re: [PATCH v3 19/20] dt-bindings: mali-midgard: Allow dma-coherent
From: Rob Herring @ 2020-05-15 3:16 UTC (permalink / raw)
To: Andre Przywara
Cc: Sudeep Holla, Liviu Dudau, linux-arm-kernel, Lorenzo Pieralisi,
devicetree, dri-devel, David Airlie, Mark Rutland
In-Reply-To: <20200513103016.130417-20-andre.przywara@arm.com>
On Wed, 13 May 2020 11:30:15 +0100, Andre Przywara wrote:
> Add the boolean dma-coherent property to the list of allowed properties,
> since some boards (Arm Juno) integrate the GPU this way.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> Documentation/devicetree/bindings/gpu/arm,mali-midgard.yaml | 2 ++
> 1 file changed, 2 insertions(+)
>
Applied, thanks!
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox