* [RFC PATCH 4/6] drm/bridge/nwl-dsi: Drop mux handling
From: Guido Günther @ 2020-05-15 13:12 UTC (permalink / raw)
To: Laurent Pinchart, David Airlie, Daniel Vetter, Rob Herring,
Shawn Guo, Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
Andrzej Hajda, Sam Ravnborg, Anson Huang, Leonard Crestez,
Lucas Stach, Peng Fan, Robert Chiras, dri-devel, devicetree,
linux-kernel, linux-arm-kernel
In-Reply-To: <cover.1589548223.git.agx@sigxcpu.org>
This will be handled via the mux-input-bridge.
Signed-off-by: Guido Günther <agx@sigxcpu.org>
---
drivers/gpu/drm/bridge/Kconfig | 1 -
drivers/gpu/drm/bridge/nwl-dsi.c | 61 --------------------------------
2 files changed, 62 deletions(-)
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 3886c0f41bdd..11444f841e35 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -78,7 +78,6 @@ config DRM_NWL_MIPI_DSI
select DRM_PANEL_BRIDGE
select GENERIC_PHY_MIPI_DPHY
select MFD_SYSCON
- select MULTIPLEXER
select REGMAP_MMIO
help
This enables the Northwest Logic MIPI DSI Host controller as
diff --git a/drivers/gpu/drm/bridge/nwl-dsi.c b/drivers/gpu/drm/bridge/nwl-dsi.c
index b14d725bf609..8839f333f39c 100644
--- a/drivers/gpu/drm/bridge/nwl-dsi.c
+++ b/drivers/gpu/drm/bridge/nwl-dsi.c
@@ -12,7 +12,6 @@
#include <linux/math64.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
-#include <linux/mux/consumer.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/phy/phy.h>
@@ -44,9 +43,6 @@ enum transfer_direction {
DSI_PACKET_RECEIVE,
};
-#define NWL_DSI_ENDPOINT_LCDIF 0
-#define NWL_DSI_ENDPOINT_DCSS 1
-
struct nwl_dsi_plat_clk_config {
const char *id;
struct clk *clk;
@@ -94,7 +90,6 @@ struct nwl_dsi {
struct reset_control *rst_esc;
struct reset_control *rst_dpi;
struct reset_control *rst_pclk;
- struct mux_control *mux;
/* DSI clocks */
struct clk *phy_ref_clk;
@@ -1018,14 +1013,6 @@ static int nwl_dsi_parse_dt(struct nwl_dsi *dsi)
}
dsi->tx_esc_clk = clk;
- dsi->mux = devm_mux_control_get(dsi->dev, NULL);
- if (IS_ERR(dsi->mux)) {
- ret = PTR_ERR(dsi->mux);
- if (ret != -EPROBE_DEFER)
- DRM_DEV_ERROR(dsi->dev, "Failed to get mux: %d\n", ret);
- return ret;
- }
-
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
@@ -1073,47 +1060,6 @@ static int nwl_dsi_parse_dt(struct nwl_dsi *dsi)
return 0;
}
-static int nwl_dsi_select_input(struct nwl_dsi *dsi)
-{
- struct device_node *remote;
- u32 use_dcss = 1;
- int ret;
-
- remote = of_graph_get_remote_node(dsi->dev->of_node, 0,
- NWL_DSI_ENDPOINT_LCDIF);
- if (remote) {
- use_dcss = 0;
- } else {
- remote = of_graph_get_remote_node(dsi->dev->of_node, 0,
- NWL_DSI_ENDPOINT_DCSS);
- if (!remote) {
- DRM_DEV_ERROR(dsi->dev,
- "No valid input endpoint found\n");
- return -EINVAL;
- }
- }
-
- DRM_DEV_INFO(dsi->dev, "Using %s as input source\n",
- (use_dcss) ? "DCSS" : "LCDIF");
- ret = mux_control_try_select(dsi->mux, use_dcss);
- if (ret < 0)
- DRM_DEV_ERROR(dsi->dev, "Failed to select input: %d\n", ret);
-
- of_node_put(remote);
- return ret;
-}
-
-static int nwl_dsi_deselect_input(struct nwl_dsi *dsi)
-{
- int ret;
-
- ret = mux_control_deselect(dsi->mux);
- if (ret < 0)
- DRM_DEV_ERROR(dsi->dev, "Failed to deselect input: %d\n", ret);
-
- return ret;
-}
-
static const struct drm_bridge_timings nwl_dsi_timings = {
.input_bus_flags = DRM_BUS_FLAG_DE_LOW,
};
@@ -1175,12 +1121,6 @@ static int nwl_dsi_probe(struct platform_device *pdev)
dev_set_drvdata(dev, dsi);
pm_runtime_enable(dev);
- ret = nwl_dsi_select_input(dsi);
- if (ret < 0) {
- mipi_dsi_host_unregister(&dsi->dsi_host);
- return ret;
- }
-
drm_bridge_add(&dsi->bridge);
return 0;
}
@@ -1189,7 +1129,6 @@ static int nwl_dsi_remove(struct platform_device *pdev)
{
struct nwl_dsi *dsi = platform_get_drvdata(pdev);
- nwl_dsi_deselect_input(dsi);
mipi_dsi_host_unregister(&dsi->dsi_host);
drm_bridge_remove(&dsi->bridge);
pm_runtime_disable(&pdev->dev);
--
2.26.1
^ permalink raw reply related
* [RFC PATCH 0/6] drm/bridge: Add mux input selection bridge
From: Guido Günther @ 2020-05-15 13:12 UTC (permalink / raw)
To: Laurent Pinchart, David Airlie, Daniel Vetter, Rob Herring,
Shawn Guo, Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
Andrzej Hajda, Sam Ravnborg, Anson Huang, Leonard Crestez,
Lucas Stach, Peng Fan, Robert Chiras, dri-devel, devicetree,
linux-kernel, linux-arm-kernel
This bridge driver allows to select the input to a downstream bridge (or panel)
via device tree.
It can be useful to separate the pixel source selection from the actual bridge
processing the pixel data. E.g. NXP's imx8mq has two display controllers. Both
can feed the pixel data to the NWL DSI IP core. The input selection is done via
a separate mux register elsewhere on the chip, so separating this out avoids SoC
specific code in such drivers.
The current implementation allows to select the input source via device tree.
The long term goal is to allow to switch the input source at run time. This
can be useful to e.g. use the less power hungry display controller for normal
operation but switch to a the other display controller when running full screen
games (since it can detile textures more efficiently).
This was initially suggested by Laurent Pinchart¹. It is similar in spirit to
the video-mux in the media subsystem but for DRM bridges.
Besides the actual driver this series includes the necessary bits to demo the
usage for the Librem5 devkit.
The series is based on linux-next as of next-20200512.
¹ https://lore.kernel.org/dri-devel/20200415021908.GH19819@pendragon.ideasonboard.com/
Guido Günther (6):
dt-bindings: display/bridge: Add binding for input mux bridge
drm/bridge: Add mux-input bridge
dt-bindings: display/bridge/nwl-dsi: Drop mux handling
drm/bridge/nwl-dsi: Drop mux handling
arm64: dts: imx8mq: Add NWL dsi controller
arm64: dts: imx8mq-librem5-devkit: Enable MIPI DSI panel
.../display/bridge/mux-input-bridge.yaml | 123 +++++++++
.../bindings/display/bridge/nwl-dsi.yaml | 6 -
.../dts/freescale/imx8mq-librem5-devkit.dts | 81 ++++++
arch/arm64/boot/dts/freescale/imx8mq.dtsi | 31 +++
drivers/gpu/drm/bridge/Kconfig | 10 +-
drivers/gpu/drm/bridge/Makefile | 1 +
drivers/gpu/drm/bridge/mux-input.c | 238 ++++++++++++++++++
drivers/gpu/drm/bridge/nwl-dsi.c | 61 -----
8 files changed, 483 insertions(+), 68 deletions(-)
create mode 100644 Documentation/devicetree/bindings/display/bridge/mux-input-bridge.yaml
create mode 100644 drivers/gpu/drm/bridge/mux-input.c
--
2.26.1
^ permalink raw reply
* [RFC PATCH 2/6] drm/bridge: Add mux-input bridge
From: Guido Günther @ 2020-05-15 13:12 UTC (permalink / raw)
To: Laurent Pinchart, David Airlie, Daniel Vetter, Rob Herring,
Shawn Guo, Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
Andrzej Hajda, Sam Ravnborg, Anson Huang, Leonard Crestez,
Lucas Stach, Peng Fan, Robert Chiras, dri-devel, devicetree,
linux-kernel, linux-arm-kernel
In-Reply-To: <cover.1589548223.git.agx@sigxcpu.org>
This bridge allows to select the input source
via a mux controller. The input source is
determined via DT but it could become rutime
selectable in the future.
Signed-off-by: Guido Günther <agx@sigxcpu.org>
---
drivers/gpu/drm/bridge/Kconfig | 9 ++
drivers/gpu/drm/bridge/Makefile | 1 +
drivers/gpu/drm/bridge/mux-input.c | 238 +++++++++++++++++++++++++++++
3 files changed, 248 insertions(+)
create mode 100644 drivers/gpu/drm/bridge/mux-input.c
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 04f876e985de..3886c0f41bdd 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -206,6 +206,15 @@ config DRM_TI_TPD12S015
Texas Instruments TPD12S015 HDMI level shifter and ESD protection
driver.
+config DRM_MUX_INPUT
+ tristate "Bridge to select a video input source"
+ depends on OF
+ depends on DRM_BRIDGE
+ select MULTIPLEXER
+ help
+ Select this option if you want to select the input source to
+ a DRM bridge or panel via a separate mux chip.
+
source "drivers/gpu/drm/bridge/analogix/Kconfig"
source "drivers/gpu/drm/bridge/adv7511/Kconfig"
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index d63d4b7e4347..9f3370ce7e07 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -4,6 +4,7 @@ obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o
obj-$(CONFIG_DRM_DISPLAY_CONNECTOR) += display-connector.o
obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.o
obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o
+obj-$(CONFIG_DRM_MUX_INPUT) += mux-input.o
obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
obj-$(CONFIG_DRM_PARADE_PS8640) += parade-ps8640.o
diff --git a/drivers/gpu/drm/bridge/mux-input.c b/drivers/gpu/drm/bridge/mux-input.c
new file mode 100644
index 000000000000..24961d41ac30
--- /dev/null
+++ b/drivers/gpu/drm/bridge/mux-input.c
@@ -0,0 +1,238 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 Purism SPC
+ */
+
+#include <linux/module.h>
+#include <linux/mux/consumer.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/pm_runtime.h>
+
+#include <drm/drm_bridge.h>
+#include <drm/drm_of.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_print.h>
+
+#define DRV_NAME "mux-input-bridge"
+
+struct mux_input {
+ struct drm_bridge bridge;
+ struct drm_bridge *out;
+ struct device *dev;
+ struct mux_control *mux;
+ unsigned int n_inputs;
+ unsigned int input;
+ struct drm_bridge_timings timings;
+};
+
+static inline struct mux_input *bridge_to_mux_input(struct drm_bridge *bridge)
+{
+ return container_of(bridge, struct mux_input, bridge);
+}
+
+static void mux_input_bridge_disable(struct drm_bridge *bridge)
+{
+ struct mux_input *mux_input = bridge_to_mux_input(bridge);
+
+ pm_runtime_put(mux_input->dev);
+}
+
+static void mux_input_bridge_pre_enable(struct drm_bridge *bridge)
+{
+ struct mux_input *mux_input = bridge_to_mux_input(bridge);
+
+ pm_runtime_get(mux_input->dev);
+}
+
+static int mux_input_bridge_attach(struct drm_bridge *bridge,
+ enum drm_bridge_attach_flags flags)
+{
+ struct mux_input *mux_input = bridge_to_mux_input(bridge);
+ struct drm_bridge *panel_bridge;
+ struct drm_panel *panel;
+ struct device *dev;
+ struct device_node *remote;
+ int ret;
+
+ /* Only attach to the selected input */
+ remote = of_graph_get_remote_node(mux_input->dev->of_node,
+ mux_input->input,
+ 0);
+ if (!remote)
+ return -EINVAL;
+
+ if (bridge->dev) {
+ dev = bridge->dev->dev;
+ if (dev->of_node != remote) {
+ DRM_DEV_DEBUG(mux_input->dev,
+ "Not attaching to endpoint %s",
+ dev->of_node->name);
+ return -EINVAL;
+ }
+ }
+ of_node_put(remote);
+
+ ret = drm_of_find_panel_or_bridge(mux_input->dev->of_node,
+ mux_input->n_inputs - 1, 0, &panel,
+ &panel_bridge);
+ if (ret)
+ return ret;
+
+ if (panel) {
+ panel_bridge = drm_panel_bridge_add(panel);
+ if (IS_ERR(panel_bridge))
+ return PTR_ERR(panel_bridge);
+ }
+ mux_input->out = panel_bridge;
+
+ if (!mux_input->out)
+ return -EPROBE_DEFER;
+
+ /* Bubble downstream bridge timings upwards */
+ memcpy(&mux_input->timings, mux_input->out->timings,
+ sizeof(mux_input->timings));
+ mux_input->bridge.timings = &mux_input->timings;
+ return drm_bridge_attach(bridge->encoder, mux_input->out, bridge,
+ flags);
+}
+
+static void mux_input_bridge_detach(struct drm_bridge *bridge)
+{ struct mux_input *mux_input = bridge_to_mux_input(bridge);
+
+ drm_of_panel_bridge_remove(mux_input->dev->of_node,
+ mux_input->n_inputs - 1, 0);
+}
+
+static const struct drm_bridge_funcs mux_input_bridge_funcs = {
+ .pre_enable = mux_input_bridge_pre_enable,
+ .disable = mux_input_bridge_disable,
+ .attach = mux_input_bridge_attach,
+ .detach = mux_input_bridge_detach,
+};
+
+static int mux_input_select_input(struct mux_input *mux_input)
+{
+ int ret;
+
+ DRM_DEV_DEBUG(mux_input->dev, "Using input %d as pixel source\n",
+ mux_input->input);
+ ret = mux_control_try_select(mux_input->mux, mux_input->input);
+ if (ret < 0) {
+ DRM_DEV_ERROR(mux_input->dev, "Failed to select input: %d\n",
+ ret);
+ }
+
+ return ret;
+}
+
+static int mux_input_deselect_input(struct mux_input *mux_input)
+{
+ int ret;
+
+ ret = mux_control_deselect(mux_input->mux);
+ if (ret < 0) {
+ DRM_DEV_ERROR(mux_input->dev, "Failed to deselect input: %d\n",
+ ret);
+ }
+
+ return ret;
+}
+
+static const struct of_device_id mux_input_dt_ids[] = {
+ { .compatible = "mux-input-bridge", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mux_input_dt_ids);
+
+static int mux_input_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct device_node *ep;
+ struct mux_input *mux_input;
+ int ret;
+
+ mux_input = devm_kzalloc(dev, sizeof(*mux_input), GFP_KERNEL);
+ if (!mux_input)
+ return -ENOMEM;
+
+ mux_input->dev = dev;
+
+ /*
+ * The largest numbered port is the output port. It determines
+ * total number of ports.
+ */
+ for_each_endpoint_of_node(np, ep) {
+ struct of_endpoint endpoint;
+
+ of_graph_parse_endpoint(ep, &endpoint);
+ mux_input->n_inputs = max(mux_input->n_inputs,
+ endpoint.port + 1);
+ }
+
+ if (mux_input->n_inputs < 2) {
+ DRM_DEV_ERROR(dev, "Not enough ports %d\n",
+ mux_input->n_inputs);
+ return -EINVAL;
+ }
+
+ if (device_property_read_u32(dev, "default-input",
+ &mux_input->input))
+ mux_input->input = 0;
+
+ if (mux_input->input > mux_input->n_inputs - 2) {
+ DRM_DEV_ERROR(dev, "Invalid default port %d\n",
+ mux_input->input);
+ return -EINVAL;
+ }
+
+ mux_input->mux = devm_mux_control_get(dev, NULL);
+ if (IS_ERR(mux_input->mux)) {
+ ret = PTR_ERR(mux_input->mux);
+ if (ret != -EPROBE_DEFER)
+ DRM_DEV_ERROR(dev, "Failed to get mux: %d\n", ret);
+ return ret;
+ }
+
+ mux_input->bridge.driver_private = mux_input;
+ mux_input->bridge.funcs = &mux_input_bridge_funcs;
+ mux_input->bridge.of_node = dev->of_node;
+
+ dev_set_drvdata(dev, mux_input);
+ pm_runtime_enable(dev);
+
+ ret = mux_input_select_input(mux_input);
+ if (ret < 0) {
+ pm_runtime_disable(&pdev->dev);
+ return ret;
+ }
+
+ drm_bridge_add(&mux_input->bridge);
+ return 0;
+}
+
+static int mux_input_remove(struct platform_device *pdev)
+{
+ struct mux_input *mux_input = platform_get_drvdata(pdev);
+
+ mux_input_deselect_input(mux_input);
+ drm_bridge_remove(&mux_input->bridge);
+ pm_runtime_disable(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver mux_input_driver = {
+ .probe = mux_input_probe,
+ .remove = mux_input_remove,
+ .driver = {
+ .of_match_table = mux_input_dt_ids,
+ .name = DRV_NAME,
+ },
+};
+
+module_platform_driver(mux_input_driver);
+
+MODULE_AUTHOR("Purism SPC");
+MODULE_DESCRIPTION("Mux input bridge");
+MODULE_LICENSE("GPL");
--
2.26.1
^ permalink raw reply related
* [RFC PATCH 5/6] arm64: dts: imx8mq: Add NWL dsi controller
From: Guido Günther @ 2020-05-15 13:12 UTC (permalink / raw)
To: Laurent Pinchart, David Airlie, Daniel Vetter, Rob Herring,
Shawn Guo, Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
Andrzej Hajda, Sam Ravnborg, Anson Huang, Leonard Crestez,
Lucas Stach, Peng Fan, Robert Chiras, dri-devel, devicetree,
linux-kernel, linux-arm-kernel
In-Reply-To: <cover.1589548223.git.agx@sigxcpu.org>
Add a node for the Northwestlogic MIPI DSI IP core, "disabled" by
default.
Signed-off-by: Guido Günther <agx@sigxcpu.org>
---
arch/arm64/boot/dts/freescale/imx8mq.dtsi | 31 +++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/imx8mq.dtsi b/arch/arm64/boot/dts/freescale/imx8mq.dtsi
index 0142f06ead12..6bbbf44e6be0 100644
--- a/arch/arm64/boot/dts/freescale/imx8mq.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mq.dtsi
@@ -889,6 +889,37 @@ sec_jr2: jr@3000 {
};
};
+ mipi_dsi: mipi-dsi@30a00000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,imx8mq-nwl-dsi";
+ reg = <0x30a00000 0x300>;
+ clocks = <&clk IMX8MQ_CLK_DSI_CORE>,
+ <&clk IMX8MQ_CLK_DSI_AHB>,
+ <&clk IMX8MQ_CLK_DSI_IPG_DIV>,
+ <&clk IMX8MQ_CLK_DSI_PHY_REF>,
+ <&clk IMX8MQ_CLK_LCDIF_PIXEL>;
+ clock-names = "core", "rx_esc", "tx_esc", "phy_ref", "lcdif";
+ assigned-clocks = <&clk IMX8MQ_CLK_DSI_AHB>,
+ <&clk IMX8MQ_CLK_DSI_CORE>,
+ <&clk IMX8MQ_CLK_DSI_IPG_DIV>;
+ assigned-clock-parents = <&clk IMX8MQ_SYS1_PLL_80M>,
+ <&clk IMX8MQ_SYS1_PLL_266M>;
+ assigned-clock-rates = <80000000>,
+ <266000000>,
+ <20000000>;
+ interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+ resets = <&src IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N>,
+ <&src IMX8MQ_RESET_MIPI_DSI_DPI_RESET_N>,
+ <&src IMX8MQ_RESET_MIPI_DSI_ESC_RESET_N>,
+ <&src IMX8MQ_RESET_MIPI_DSI_PCLK_RESET_N>;
+ reset-names = "byte", "dpi", "esc", "pclk";
+ phys = <&dphy>;
+ phy-names = "dphy";
+ power-domains = <&pgc_mipi>;
+ status = "disabled";
+ };
+
dphy: dphy@30a00300 {
compatible = "fsl,imx8mq-mipi-dphy";
reg = <0x30a00300 0x100>;
--
2.26.1
^ permalink raw reply related
* [RFC PATCH 6/6] arm64: dts: imx8mq-librem5-devkit: Enable MIPI DSI panel
From: Guido Günther @ 2020-05-15 13:12 UTC (permalink / raw)
To: Laurent Pinchart, David Airlie, Daniel Vetter, Rob Herring,
Shawn Guo, Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
Andrzej Hajda, Sam Ravnborg, Anson Huang, Leonard Crestez,
Lucas Stach, Peng Fan, Robert Chiras, dri-devel, devicetree,
linux-kernel, linux-arm-kernel
In-Reply-To: <cover.1589548223.git.agx@sigxcpu.org>
Enable MIPI LCD panel output by adding nodes for the NWL DSI host
controller, the mux-input-bridge, the Rocktech panel and the eLCDIF
display controller.
Signed-off-by: Guido Günther <agx@sigxcpu.org>
---
.../dts/freescale/imx8mq-librem5-devkit.dts | 81 +++++++++++++++++++
1 file changed, 81 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts b/arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts
index 7fc31c71a626..d98f9b8dede8 100644
--- a/arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts
@@ -841,6 +841,87 @@ MX8MQ_IOMUXC_NAND_DATA03_GPIO3_IO9 0x19 /* WWAN_RESET */
};
};
+&lcdif {
+ status = "okay";
+
+ port@0 {
+ lcdif_dpi_out: endpoint {
+ remote-endpoint = <&dpi_mux_from_lcdif>;
+ };
+ };
+};
+
+&iomuxc_gpr {
+ mipi_mux: mipi-mux {
+ compatible = "mux-input-bridge";
+ mux-controls = <&mux 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "okay";
+ default-input = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ dpi_mux_from_lcdif: endpoint {
+ remote-endpoint = <&lcdif_dpi_out>;
+ };
+ };
+
+ port@1 { /* dcss */
+ reg = <1>;
+ };
+
+ port@2 {
+ reg = <2>;
+ dpi_mux_out: endpoint {
+ remote-endpoint = <&nwl_dpi_in>;
+ };
+
+ };
+ };
+ };
+};
+
+&mipi_dsi {
+ status = "okay";
+ panel@0 {
+ compatible = "rocktech,jh057n00900";
+ reg = <0>;
+ backlight = <&backlight_dsi>;
+ reset-gpios = <&gpio3 13 GPIO_ACTIVE_LOW>;
+ vcc-supply = <®_2v8_p>;
+ iovcc-supply = <®_1v8_p>;
+ port@0 {
+ panel_in: endpoint {
+ remote-endpoint = <&nwl_dsi_out>;
+ };
+ };
+ };
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ nwl_dpi_in: endpoint {
+ remote-endpoint = <&dpi_mux_out>;
+ };
+ };
+ port@1 {
+ reg = <1>;
+ nwl_dsi_out: endpoint {
+ remote-endpoint = <&panel_in>;
+ };
+ };
+ };
+};
+
&pgc_gpu {
power-supply = <&buck3_reg>;
};
--
2.26.1
^ permalink raw reply related
* [RFC PATCH 1/6] dt-bindings: display/bridge: Add binding for input mux bridge
From: Guido Günther @ 2020-05-15 13:12 UTC (permalink / raw)
To: Laurent Pinchart, David Airlie, Daniel Vetter, Rob Herring,
Shawn Guo, Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
Andrzej Hajda, Sam Ravnborg, Anson Huang, Leonard Crestez,
Lucas Stach, Peng Fan, Robert Chiras, dri-devel, devicetree,
linux-kernel, linux-arm-kernel
In-Reply-To: <cover.1589548223.git.agx@sigxcpu.org>
The bridge allows to select the input source via a mux controller.
Signed-off-by: Guido Günther <agx@sigxcpu.org>
---
.../display/bridge/mux-input-bridge.yaml | 123 ++++++++++++++++++
1 file changed, 123 insertions(+)
create mode 100644 Documentation/devicetree/bindings/display/bridge/mux-input-bridge.yaml
diff --git a/Documentation/devicetree/bindings/display/bridge/mux-input-bridge.yaml b/Documentation/devicetree/bindings/display/bridge/mux-input-bridge.yaml
new file mode 100644
index 000000000000..4029cf63ee5c
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/bridge/mux-input-bridge.yaml
@@ -0,0 +1,123 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/bridge/mux-input-bridge.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: DRM input source selection via multiplexer
+
+maintainers:
+ - Guido Gúnther <agx@sigxcpu.org>
+
+description: |
+ The input multiplexer bridge allows to select an input source
+ via an associated mux controller.
+
+properties:
+ compatible:
+ const: mux-input-bridge
+
+ '#address-cells':
+ const: 1
+
+ '#size-cells':
+ const: 0
+
+ default-input:
+ description: The default input to use
+
+ mux-controls:
+ description:
+ mux controller node to use for operating the input mux
+
+ ports:
+ type: object
+ properties:
+ '#address-cells':
+ const: 1
+ '#size-cells':
+ const: 0
+
+ patternProperties:
+ "^port@[0-9]+":
+ type: object
+ description:
+ At least three nodes containing endpoints connecting to the
+ pixel data inputs and outputs. The last port is always the
+ output port.
+
+ properties:
+ reg:
+ maxItems: 1
+
+ endpoint:
+ description: sub-node describing the input
+ type: object
+
+ required:
+ - reg
+
+ additionalProperties: false
+
+ required:
+ - port@0
+ - port@1
+ - port@2
+
+ additionalProperties: false
+
+required:
+ - '#address-cells'
+ - '#size-cells'
+ - mux-controls
+ - ports
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ mux: mux-controller {
+ compatible = "gpio-mux";
+ #mux-control-cells = <0>;
+
+ mux-gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>;
+ };
+
+ mipi-mux {
+ compatible = "mux-input-bridge";
+ default-input = <0>;
+ mux-controls = <&mux 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ dpi_mux_from_lcdif: endpoint {
+ remote-endpoint = <&lcdif_dpi_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ dpi_mux_from_dccss: endpoint {
+ remote-endpoint = <&dcss_dpi_out>;
+ };
+ };
+
+ port@2 {
+ reg = <2>;
+
+ dpi_mux_out: endpoint {
+ remote-endpoint = <&nwl_dpi_in>;
+ };
+ };
+ };
+ };
--
2.26.1
^ permalink raw reply related
* [RFC PATCH 3/6] dt-bindings: display/bridge/nwl-dsi: Drop mux handling
From: Guido Günther @ 2020-05-15 13:12 UTC (permalink / raw)
To: Laurent Pinchart, David Airlie, Daniel Vetter, Rob Herring,
Shawn Guo, Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
Andrzej Hajda, Sam Ravnborg, Anson Huang, Leonard Crestez,
Lucas Stach, Peng Fan, Robert Chiras, dri-devel, devicetree,
linux-kernel, linux-arm-kernel
In-Reply-To: <cover.1589548223.git.agx@sigxcpu.org>
No need to encode the SoC specifics in the bridge driver. For the
imx8mq we can use the mux-input-bridge.
Signed-off-by: Guido Günther <agx@sigxcpu.org>
---
.../devicetree/bindings/display/bridge/nwl-dsi.yaml | 6 ------
1 file changed, 6 deletions(-)
diff --git a/Documentation/devicetree/bindings/display/bridge/nwl-dsi.yaml b/Documentation/devicetree/bindings/display/bridge/nwl-dsi.yaml
index 8aff2d68fc33..d2c2d4e19a25 100644
--- a/Documentation/devicetree/bindings/display/bridge/nwl-dsi.yaml
+++ b/Documentation/devicetree/bindings/display/bridge/nwl-dsi.yaml
@@ -46,10 +46,6 @@ properties:
- const: phy_ref
- const: lcdif
- mux-controls:
- description:
- mux controller node to use for operating the input mux
-
phys:
maxItems: 1
description:
@@ -151,7 +147,6 @@ required:
- clocks
- compatible
- interrupts
- - mux-controls
- phy-names
- phys
- ports
@@ -180,7 +175,6 @@ examples:
<&clk IMX8MQ_CLK_LCDIF_PIXEL>;
clock-names = "core", "rx_esc", "tx_esc", "phy_ref", "lcdif";
interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
- mux-controls = <&mux 0>;
power-domains = <&pgc_mipi>;
resets = <&src IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N>,
<&src IMX8MQ_RESET_MIPI_DSI_DPI_RESET_N>,
--
2.26.1
^ permalink raw reply related
* Re: [PATCH v3 10/15] net: ethernet: mtk-eth-mac: new driver
From: Arnd Bergmann @ 2020-05-15 13:11 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Jonathan Corbet, Rob Herring, David S . Miller, Matthias Brugger,
John Crispin, Sean Wang, Mark Lee, Jakub Kicinski, Fabien Parent,
Heiner Kallweit, Edwin Peer, DTML, linux-kernel@vger.kernel.org,
Networking, Linux ARM, moderated list:ARM/Mediatek SoC...,
Stephane Le Provost, Pedro Tsai, Andrew Perepech,
Bartosz Golaszewski
In-Reply-To: <CAMRc=Mf_vYt1J-cc6aZ2-Qv_YDEymVoC7ZiwuG9BrXoGMsXepw@mail.gmail.com>
On Fri, May 15, 2020 at 2:56 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> pt., 15 maj 2020 o 14:04 Arnd Bergmann <arnd@arndb.de> napisał(a):
> > On Fri, May 15, 2020 at 9:11 AM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> > > >
> > > > It looks like most of the stuff inside of the loop can be pulled out
> > > > and only done once here.
> > > >
> > >
> > > I did that in one of the previous submissions but it was pointed out
> > > to me that a parallel TX path may fill up the queue before I wake it.
> >
> > Right, I see you plugged that hole, however the way you hold the
> > spinlock across the expensive DMA management but then give it
> > up in each loop iteration feels like this is not the most efficient
> > way.
> >
>
> Maybe my thinking is wrong here, but I assumed that with a spinlock
> it's better to give other threads the chance to run in between each
> iteration. I didn't benchmark it though.
It depends. You want to avoid lock contention (two threads trying to
get the lock at the same time) but you also want to avoid bouncing
around the spinlock between the caches.
In the contention case, what I think would happen here is that the
cleanup thread gives up the lock and the xmit function gets it, but
then the cleanup thread is spinning again, so you are still blocked
on one of the two CPUs but also pay the overhead of synchronizing
between the two.
Holding the lock the whole time would speed up both the good case
(no contention) and the bad case (bouncing the lock) a little bit
because it saves some overhead. Holding the lock for shorter
times (i.e. not during the cache operations) would reduce the
amount of lock-contention but not help in the good case.
Not needing a lock at all is generally best, but getting it right
is tricky ;-)
Arnd
^ permalink raw reply
* [PATCH] dt-bindings: serial: renesas,scifa: Remove part numbers from comments
From: Geert Uytterhoeven @ 2020-05-15 13:12 UTC (permalink / raw)
To: Rob Herring
Cc: Greg Kroah-Hartman, linux-serial, devicetree, linux-renesas-soc,
Geert Uytterhoeven
The conversion to json-schema accidentally retained some SoC part
numbers in comments for compatible values. Drop them, as they're part
of the compatible values anyway.
Fixes: 384d00fae8e51f8f ("dt-bindings: serial: sh-sci: Convert to json-schema")
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
This depends on:
"[PATCH v2 03/10] dt-bindings: serial: renesas,scifa: Document r8a7742 bindings"
https://lore.kernel.org/dmaengine/1588542414-14826-4-git-send-email-prabhakar.mahadev-lad.rj@bp.renesas.com
Rob: as you have taken:
+ 8908a822663f6958 dt-bindings: serial: renesas,scif: Document r8a7742 bindings
+ 3cf1601ab00ce558 dt-bindings: serial: renesas,scifb: Document r8a7742 bindings
+ 65994c09bc66d724 dt-bindings: serial: renesas,hscif: Document r8a7742 bindings
can you please take this one, and its dependency, too?
Thanks!
.../bindings/serial/renesas,scifa.yaml | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/Documentation/devicetree/bindings/serial/renesas,scifa.yaml b/Documentation/devicetree/bindings/serial/renesas,scifa.yaml
index 97ddd76d700f78ca..78b8e20dd34db322 100644
--- a/Documentation/devicetree/bindings/serial/renesas,scifa.yaml
+++ b/Documentation/devicetree/bindings/serial/renesas,scifa.yaml
@@ -24,14 +24,14 @@ properties:
- items:
- enum:
- - renesas,scifa-r8a7742 # R8A7742 RZ/G1H
- - renesas,scifa-r8a7743 # R8A7743 RZ/G1M
- - renesas,scifa-r8a7744 # R8A7744 RZ/G1N
- - renesas,scifa-r8a7745 # R8A7745 RZ/G1E
- - renesas,scifa-r8a7790 # R8A7790 R-Car H2
- - renesas,scifa-r8a7791 # R8A7791 R-Car M2-W
- - renesas,scifa-r8a7793 # R8A7793 R-Car M2-N
- - renesas,scifa-r8a7794 # R8A7794 R-Car E2
+ - renesas,scifa-r8a7742 # RZ/G1H
+ - renesas,scifa-r8a7743 # RZ/G1M
+ - renesas,scifa-r8a7744 # RZ/G1N
+ - renesas,scifa-r8a7745 # RZ/G1E
+ - renesas,scifa-r8a7790 # R-Car H2
+ - renesas,scifa-r8a7791 # R-Car M2-W
+ - renesas,scifa-r8a7793 # R-Car M2-N
+ - renesas,scifa-r8a7794 # R-Car E2
- const: renesas,rcar-gen2-scifa # R-Car Gen2 and RZ/G1
- const: renesas,scifa # generic SCIFA compatible UART
--
2.17.1
^ permalink raw reply related
* Re: [PATCH v2 08/19] spi: dw: Discard dma_width member of the dw_spi structure
From: Andy Shevchenko @ 2020-05-15 13:03 UTC (permalink / raw)
To: Serge Semin
Cc: Mark Brown, Serge Semin, Georgy Vlasov, Ramil Zaripov,
Alexey Malahov, Thomas Bogendoerfer, Paul Burton, Ralf Baechle,
Allison Randal, Gareth Williams, Arnd Bergmann, Rob Herring,
linux-mips, devicetree, Jarkko Nikula, Wan Ahmad Zainie,
Thomas Gleixner, Clement Leger, Xinwei Kong, wuxu.wu,
Phil Edworthy, Linus Walleij, linux-spi, linux-kernel
In-Reply-To: <20200515104758.6934-9-Sergey.Semin@baikalelectronics.ru>
On Fri, May 15, 2020 at 01:47:47PM +0300, Serge Semin wrote:
> This member has exactly the same value as n_bytes of the DW SPI private
> data object, it's calculated at the same point of the transfer method,
> n_bytes isn't changed during the whole transfer, and they even serve for
> the same purpose - keep number of bytes per transfer word, though the
> dma_width is used only to calculate the DMA source/destination addresses
> width, which n_bytes could be also utilized for. Taking all of these
> into account let's replace the dma_width member usage with n_bytes one
> and remove the former.
I've no strong opinion about this.
So, after addressing one issue below,
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> Cc: Georgy Vlasov <Georgy.Vlasov@baikalelectronics.ru>
> Cc: Ramil Zaripov <Ramil.Zaripov@baikalelectronics.ru>
> Cc: Alexey Malahov <Alexey.Malahov@baikalelectronics.ru>
> Cc: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
> Cc: Paul Burton <paulburton@kernel.org>
> Cc: Ralf Baechle <ralf@linux-mips.org>
> Cc: Allison Randal <allison@lohutok.net>
> Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> Cc: Gareth Williams <gareth.williams.jx@renesas.com>
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: linux-mips@vger.kernel.org
> Cc: devicetree@vger.kernel.org
>
> ---
>
> Changelog v2:
> - It's a new patch created as a result of more thorough driver study.
> ---
> drivers/spi/spi-dw-mid.c | 10 +++++-----
> drivers/spi/spi-dw.c | 1 -
> drivers/spi/spi-dw.h | 1 -
> 3 files changed, 5 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c
> index be886e22a1b1..ca8813a693d8 100644
> --- a/drivers/spi/spi-dw-mid.c
> +++ b/drivers/spi/spi-dw-mid.c
> @@ -132,10 +132,10 @@ static bool mid_spi_can_dma(struct spi_controller *master,
> return xfer->len > dws->fifo_len;
> }
>
> -static enum dma_slave_buswidth convert_dma_width(u32 dma_width) {
> - if (dma_width == 1)
> +static enum dma_slave_buswidth convert_dma_width(u8 n_bytes) {
It seems somebody (maybe even me) at some point messed up between enum
definition and function that returns an enum.
For what said, { should be on the separate line.
> + if (n_bytes == 1)
> return DMA_SLAVE_BUSWIDTH_1_BYTE;
> - else if (dma_width == 2)
> + else if (n_bytes == 2)
> return DMA_SLAVE_BUSWIDTH_2_BYTES;
>
> return DMA_SLAVE_BUSWIDTH_UNDEFINED;
> @@ -195,7 +195,7 @@ static struct dma_async_tx_descriptor *dw_spi_dma_prepare_tx(struct dw_spi *dws,
> txconf.dst_addr = dws->dma_addr;
> txconf.dst_maxburst = 16;
> txconf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
> - txconf.dst_addr_width = convert_dma_width(dws->dma_width);
> + txconf.dst_addr_width = convert_dma_width(dws->n_bytes);
> txconf.device_fc = false;
>
> dmaengine_slave_config(dws->txchan, &txconf);
> @@ -268,7 +268,7 @@ static struct dma_async_tx_descriptor *dw_spi_dma_prepare_rx(struct dw_spi *dws,
> rxconf.src_addr = dws->dma_addr;
> rxconf.src_maxburst = 16;
> rxconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
> - rxconf.src_addr_width = convert_dma_width(dws->dma_width);
> + rxconf.src_addr_width = convert_dma_width(dws->n_bytes);
> rxconf.device_fc = false;
>
> dmaengine_slave_config(dws->rxchan, &rxconf);
> diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c
> index 450c8218caeb..1edb8cdd11ee 100644
> --- a/drivers/spi/spi-dw.c
> +++ b/drivers/spi/spi-dw.c
> @@ -353,7 +353,6 @@ static int dw_spi_transfer_one(struct spi_controller *master,
> }
>
> dws->n_bytes = DIV_ROUND_UP(transfer->bits_per_word, BITS_PER_BYTE);
> - dws->dma_width = DIV_ROUND_UP(transfer->bits_per_word, BITS_PER_BYTE);
>
> cr0 = dws->update_cr0(master, spi, transfer);
> dw_writel(dws, DW_SPI_CTRLR0, cr0);
> diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
> index b6ab81e0c747..4902f937c3d7 100644
> --- a/drivers/spi/spi-dw.h
> +++ b/drivers/spi/spi-dw.h
> @@ -136,7 +136,6 @@ struct dw_spi {
> void *rx_end;
> int dma_mapped;
> u8 n_bytes; /* current is a 1/2 bytes op */
> - u32 dma_width;
> irqreturn_t (*transfer_handler)(struct dw_spi *dws);
> u32 current_freq; /* frequency in hz */
>
> --
> 2.25.1
>
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH v3 10/15] net: ethernet: mtk-eth-mac: new driver
From: Bartosz Golaszewski @ 2020-05-15 12:56 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Jonathan Corbet, Rob Herring, David S . Miller, Matthias Brugger,
John Crispin, Sean Wang, Mark Lee, Jakub Kicinski, Fabien Parent,
Heiner Kallweit, Edwin Peer, DTML, linux-kernel@vger.kernel.org,
Networking, Linux ARM, moderated list:ARM/Mediatek SoC...,
Stephane Le Provost, Pedro Tsai, Andrew Perepech,
Bartosz Golaszewski
In-Reply-To: <CAK8P3a0u53rHSW=72CnnbhrY28Z+9f=Yv2K-bbj5OD+2Ds4unA@mail.gmail.com>
pt., 15 maj 2020 o 14:04 Arnd Bergmann <arnd@arndb.de> napisał(a):
>
> On Fri, May 15, 2020 at 9:11 AM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> >
> > czw., 14 maj 2020 o 18:19 Arnd Bergmann <arnd@arndb.de> napisał(a):
> > >
> > > On Thu, May 14, 2020 at 10:00 AM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> > > > +static unsigned int mtk_mac_intr_read_and_clear(struct mtk_mac_priv *priv)
> > > > +{
> > > > + unsigned int val;
> > > > +
> > > > + regmap_read(priv->regs, MTK_MAC_REG_INT_STS, &val);
> > > > + regmap_write(priv->regs, MTK_MAC_REG_INT_STS, val);
> > > > +
> > > > + return val;
> > > > +}
> > >
> > > Do you actually need to read the register? That is usually a relatively
> > > expensive operation, so if possible try to use clear the bits when
> > > you don't care which bits were set.
> > >
> >
> > I do care, I'm afraid. The returned value is being used in the napi
> > poll callback to see which ring to process.
>
> I suppose the other callers are not performance critical.
>
> For the rx and tx processing, it should be better to just always look at
> the queue directly and ignore the irq status, in particular when you
> are already in polling mode: suppose you receive ten frames at once
> and only process five but clear the irq flag.
>
> When the poll function is called again, you still need to process the
> others, but I would assume that the status tells you that nothing
> new has arrived so you don't process them until the next interrupt.
>
> For the statistics, I assume you do need to look at the irq status,
> but this doesn't have to be done in the poll function. How about
> something like:
>
> - in hardirq context, read the irq status word
> - irq rx or tx irq pending, call napi_schedule
> - if stats irq pending, schedule a work function
> - in napi poll, process both queues until empty or
> budget exhausted
> - if packet processing completed in poll function
> ack the irq and check again, call napi_complete
> - in work function, handle stats irq, then ack it
>
I see your point. I'll try to come up with something and send a new
version on Monday.
> > > > +static void mtk_mac_tx_complete_all(struct mtk_mac_priv *priv)
> > > > +{
> > > > + struct mtk_mac_ring *ring = &priv->tx_ring;
> > > > + struct net_device *ndev = priv->ndev;
> > > > + int ret;
> > > > +
> > > > + for (;;) {
> > > > + mtk_mac_lock(priv);
> > > > +
> > > > + if (!mtk_mac_ring_descs_available(ring)) {
> > > > + mtk_mac_unlock(priv);
> > > > + break;
> > > > + }
> > > > +
> > > > + ret = mtk_mac_tx_complete_one(priv);
> > > > + if (ret) {
> > > > + mtk_mac_unlock(priv);
> > > > + break;
> > > > + }
> > > > +
> > > > + if (netif_queue_stopped(ndev))
> > > > + netif_wake_queue(ndev);
> > > > +
> > > > + mtk_mac_unlock(priv);
> > > > + }
> > > > +}
> > >
> > > It looks like most of the stuff inside of the loop can be pulled out
> > > and only done once here.
> > >
> >
> > I did that in one of the previous submissions but it was pointed out
> > to me that a parallel TX path may fill up the queue before I wake it.
>
> Right, I see you plugged that hole, however the way you hold the
> spinlock across the expensive DMA management but then give it
> up in each loop iteration feels like this is not the most efficient
> way.
>
Maybe my thinking is wrong here, but I assumed that with a spinlock
it's better to give other threads the chance to run in between each
iteration. I didn't benchmark it though.
> The easy way would be to just hold the lock across the entire
> loop and then be sure you do it right. Alternatively you could
> minimize the locking and only do the wakeup after up do the final
> update to the tail pointer, at which point you know the queue is not
> full because you have just freed up at least one entry.
>
Makes sense, I'll see what I can do.
Bartosz
^ permalink raw reply
* Re: [PATCH v2] arm64: dts: qcom: apq8016-sbc-d3: Add Qualcomm APQ8016 SBC + D3Camera mezzanine
From: Robert Foss @ 2020-05-15 12:43 UTC (permalink / raw)
To: Vinod Koul, Bjorn Andersson, linux-arm-msm, devicetree,
linux-kernel
Cc: Rob Herring, Nicolas Dechesne
In-Reply-To: <20200515090820.1744353-1-robert.foss@linaro.org>
On Fri, 15 May 2020 at 11:08, Robert Foss <robert.foss@linaro.org> wrote:
>
> Add device treee support for the Qualcomm APQ8016 SBC, otherwise known as
> the Dragonboard 410c with the D3Camera mezzanine expansion board.
>
> The D3Camera mezzanine ships in a kit with a OmniVision 5640 sensor module,
> which is what this DT targets.
>
> Signed-off-by: Robert Foss <robert.foss@linaro.org>
> ---
>
> Changes since v1:
> - Vinod: Changed license to GPL+BSD
> - Vinod: Changed copyright year to 2020
> - Nico: Changed name of mezzanine to d3camera
>
> arch/arm64/boot/dts/qcom/Makefile | 1 +
> .../boot/dts/qcom/apq8016-sbc-d3camera.dts | 45 +++++++++++++++++++
> 2 files changed, 46 insertions(+)
> create mode 100644 arch/arm64/boot/dts/qcom/apq8016-sbc-d3camera.dts
>
> diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
> index cc103f7020fd..3f95b522694e 100644
> --- a/arch/arm64/boot/dts/qcom/Makefile
> +++ b/arch/arm64/boot/dts/qcom/Makefile
> @@ -1,5 +1,6 @@
> # SPDX-License-Identifier: GPL-2.0
> dtb-$(CONFIG_ARCH_QCOM) += apq8016-sbc.dtb
> +dtb-$(CONFIG_ARCH_QCOM) += apq8016-sbc-d3camera.dtb
> dtb-$(CONFIG_ARCH_QCOM) += apq8096-db820c.dtb
> dtb-$(CONFIG_ARCH_QCOM) += apq8096-ifc6640.dtb
> dtb-$(CONFIG_ARCH_QCOM) += ipq6018-cp01-c1.dtb
> diff --git a/arch/arm64/boot/dts/qcom/apq8016-sbc-d3camera.dts b/arch/arm64/boot/dts/qcom/apq8016-sbc-d3camera.dts
> new file mode 100644
> index 000000000000..752e5ec47499
> --- /dev/null
> +++ b/arch/arm64/boot/dts/qcom/apq8016-sbc-d3camera.dts
> @@ -0,0 +1,45 @@
> +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
> +/*
> + * Copyright (c) 2020, The Linux Foundation. All rights reserved.
This copyright is incorrect, and should instead assigned to Linaro.
I'll spin a new version with this change.
> + */
> +
> +/dts-v1/;
> +
> +#include "apq8016-sbc.dtsi"
> +
> +/ {
> + model = "Qualcomm Technologies, Inc. APQ 8016 SBC w/ D3Camera Mezzanine";
> + compatible = "qcom,apq8016-sbc", "qcom,apq8016", "qcom,sbc";
> +};
> +
> +&cci_i2c0 {
> + /delete-node/ camera_rear@3b;
> +
> + camera_rear@76 {
> + compatible = "ovti,ov5640";
> + reg = <0x76>;
> +
> + enable-gpios = <&msmgpio 34 GPIO_ACTIVE_HIGH>;
> + reset-gpios = <&msmgpio 35 GPIO_ACTIVE_LOW>;
> + pinctrl-names = "default";
> + pinctrl-0 = <&camera_rear_default>;
> +
> + clocks = <&gcc GCC_CAMSS_MCLK0_CLK>;
> + clock-names = "xclk";
> + clock-frequency = <23880000>;
> +
> + vdddo-supply = <&camera_vdddo_1v8>;
> + vdda-supply = <&camera_vdda_2v8>;
> + vddd-supply = <&camera_vddd_1v5>;
> +
> + status = "ok";
> +
> + port {
> + ov5640_ep: endpoint {
> + clock-lanes = <1>;
> + data-lanes = <0 2>;
> + remote-endpoint = <&csiphy0_ep>;
> + };
> + };
> + };
> +};
> --
> 2.25.1
>
^ permalink raw reply
* Re: [PATCH v2 02/19] spi: dw: Add Tx/Rx finish wait methods to the MID DMA
From: Mark Brown @ 2020-05-15 12:41 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Serge Semin, Serge Semin, Georgy Vlasov, Ramil Zaripov,
Alexey Malahov, Thomas Bogendoerfer, Paul Burton, Ralf Baechle,
Arnd Bergmann, Allison Randal, Gareth Williams, Rob Herring,
linux-mips, devicetree, Jarkko Nikula, Wan Ahmad Zainie,
Thomas Gleixner, wuxu.wu, Clement Leger, linux-spi, linux-kernel
In-Reply-To: <20200515123702.GA185537@smile.fi.intel.com>
[-- Attachment #1: Type: text/plain, Size: 493 bytes --]
On Fri, May 15, 2020 at 03:37:02PM +0300, Andy Shevchenko wrote:
> On Fri, May 15, 2020 at 01:18:15PM +0100, Mark Brown wrote:
> > Well, nobody wrote one.
> spi_delay_exec() seems quite good to be used here.
> Can we use it for delays?
I guess we could, though it's really there because for historical
reasons we've got a bunch of different ways of specifying delays from
client drivers rather than for the executing a delay where you've
already got a good idea of the length of the delay.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH v2 07/19] spi: dw: Discard unused void priv pointer
From: Andy Shevchenko @ 2020-05-15 12:38 UTC (permalink / raw)
To: Serge Semin
Cc: Mark Brown, Serge Semin, Georgy Vlasov, Ramil Zaripov,
Alexey Malahov, Thomas Bogendoerfer, Paul Burton, Ralf Baechle,
Allison Randal, Gareth Williams, Arnd Bergmann, Rob Herring,
linux-mips, devicetree, Wan Ahmad Zainie, wuxu.wu, Jarkko Nikula,
Clement Leger, linux-spi, linux-kernel
In-Reply-To: <20200515104758.6934-8-Sergey.Semin@baikalelectronics.ru>
On Fri, May 15, 2020 at 01:47:46PM +0300, Serge Semin wrote:
> Seeing the "void *priv" member of the dw_spi data structure is unused
> let's remove it. The glue-layers can embed the DW APB SSI controller
> descriptor into their private data object. MMIO driver for instance
> already utilizes that design pattern.
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
>
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> Cc: Georgy Vlasov <Georgy.Vlasov@baikalelectronics.ru>
> Cc: Ramil Zaripov <Ramil.Zaripov@baikalelectronics.ru>
> Cc: Alexey Malahov <Alexey.Malahov@baikalelectronics.ru>
> Cc: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
> Cc: Paul Burton <paulburton@kernel.org>
> Cc: Ralf Baechle <ralf@linux-mips.org>
> Cc: Allison Randal <allison@lohutok.net>
> Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> Cc: Gareth Williams <gareth.williams.jx@renesas.com>
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: linux-mips@vger.kernel.org
> Cc: devicetree@vger.kernel.org
>
> ---
>
> Changelog v2:
> - It's a new patch created as a result of more thorough driver study.
> ---
> drivers/spi/spi-dw.h | 2 --
> 1 file changed, 2 deletions(-)
>
> diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
> index 60e9e430ce7b..b6ab81e0c747 100644
> --- a/drivers/spi/spi-dw.h
> +++ b/drivers/spi/spi-dw.h
> @@ -147,8 +147,6 @@ struct dw_spi {
> dma_addr_t dma_addr; /* phy address of the Data register */
> const struct dw_spi_dma_ops *dma_ops;
>
> - /* Bus interface info */
> - void *priv;
> #ifdef CONFIG_DEBUG_FS
> struct dentry *debugfs;
> #endif
> --
> 2.25.1
>
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH v2 02/19] spi: dw: Add Tx/Rx finish wait methods to the MID DMA
From: Andy Shevchenko @ 2020-05-15 12:37 UTC (permalink / raw)
To: Mark Brown
Cc: Serge Semin, Serge Semin, Georgy Vlasov, Ramil Zaripov,
Alexey Malahov, Thomas Bogendoerfer, Paul Burton, Ralf Baechle,
Arnd Bergmann, Allison Randal, Gareth Williams, Rob Herring,
linux-mips, devicetree, Jarkko Nikula, Wan Ahmad Zainie,
Thomas Gleixner, wuxu.wu, Clement Leger, linux-spi, linux-kernel
In-Reply-To: <20200515121815.GB5066@sirena.org.uk>
On Fri, May 15, 2020 at 01:18:15PM +0100, Mark Brown wrote:
> On Fri, May 15, 2020 at 03:01:11PM +0300, Andy Shevchenko wrote:
>
> > General question, doesn't spi core provides us some helpers like
> > spi_delay_exec()?
>
> Well, nobody wrote one.
spi_delay_exec() seems quite good to be used here.
Can we use it for delays?
> It's also a bit tricky to handle given that
> often you're checking some controller specific things while a FIFO in
> the IP drains/fills, though nothing insurmountable.
Yes, input can be gathered by reading controller specific data.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH v2 06/19] spi: dw: Discard static DW DMA slave structures
From: Andy Shevchenko @ 2020-05-15 12:34 UTC (permalink / raw)
To: Serge Semin
Cc: Mark Brown, Serge Semin, Georgy Vlasov, Ramil Zaripov,
Alexey Malahov, Thomas Bogendoerfer, Paul Burton, Ralf Baechle,
Allison Randal, Gareth Williams, Arnd Bergmann, Rob Herring,
linux-mips, devicetree, Wan Ahmad Zainie, Jarkko Nikula,
Thomas Gleixner, wuxu.wu, Clement Leger, linux-spi, linux-kernel
In-Reply-To: <20200515104758.6934-7-Sergey.Semin@baikalelectronics.ru>
On Fri, May 15, 2020 at 01:47:45PM +0300, Serge Semin wrote:
> Having them declared is redundant since each struct dw_dma_chan has
> the same structure embedded and the structure from the passed dma_chan
> private pointer will be copied there as a result of the next calls
> chain:
> dma_request_channel() -> find_candidate() -> dma_chan_get() ->
> device_alloc_chan_resources() = dwc_alloc_chan_resources() ->
> dw_dma_filter().
> So just remove the static dw_dma_chan structures and use a locally
> declared data instance with dst_id/src_id set to the same values as
> the static copies used to have.
...
> -static struct dw_dma_slave mid_dma_tx = { .dst_id = 1 };
> -static struct dw_dma_slave mid_dma_rx = { .src_id = 0 };
> + struct dw_dma_slave slave = {0};
I really would like to leave them separated and as in the original form, i.e.
struct dw_dma_slave tx = { .dst_id = 1 };
struct dw_dma_slave rx = { .src_id = 0 };
those src and dst IDs are put in that form on purpose...
> + /* 1. Init rx channel (.src_id = 0, .dst_id = 0) */
...this comment adds a bit of confusion.
(Needs more time to parse and understand what IDs are in use)
> + slave.dma_dev = &dma_dev->dev;
> + dws->rxchan = dma_request_channel(mask, mid_spi_dma_chan_filter, &slave);
> + /* 2. Init tx channel (.src_id = 0, .dst_id = 1) */
Ditto.
P.S. Just a recommendation for the future: in all your patches try to be less
invasive where it's possible.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH v2 01/19] dt-bindings: spi: dw: Add Tx/Rx DMA properties
From: Mark Brown @ 2020-05-15 12:27 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Serge Semin, Rob Herring, Serge Semin, Georgy Vlasov,
Ramil Zaripov, Alexey Malahov, Thomas Bogendoerfer, Paul Burton,
Ralf Baechle, Arnd Bergmann, Allison Randal, Gareth Williams,
linux-mips, Wan Ahmad Zainie, linux-spi, devicetree, linux-kernel
In-Reply-To: <20200515115151.GU185537@smile.fi.intel.com>
[-- Attachment #1: Type: text/plain, Size: 635 bytes --]
On Fri, May 15, 2020 at 02:51:51PM +0300, Andy Shevchenko wrote:
> On Fri, May 15, 2020 at 01:47:40PM +0300, Serge Semin wrote:
> > Since commit 22d48ad7bfac ("spi: dw: Add Elkhart Lake PSE DMA support")
> > the spi-dw-mid.c module supports a platform DMA engine handling the DW APB
> > SSI controller requests. Lets alter the DW SPI bindings file to accept the
> > Rx and Tx DMA line specifiers.
> I'm wondering if these properties are implied by the SPI generic one?
> (forgive me if I'm not understanding all DT schema relations)
Which SPI generic DMA bindings are you thinking of here? There aren't
any in spi-controller.yaml.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH v2 05/19] spi: dw: Enable interrupts in accordance with DMA xfer mode
From: Andy Shevchenko @ 2020-05-15 12:27 UTC (permalink / raw)
To: Serge Semin
Cc: Mark Brown, Serge Semin, Georgy Vlasov, Ramil Zaripov,
Alexey Malahov, Thomas Bogendoerfer, Paul Burton, Ralf Baechle,
Arnd Bergmann, Allison Randal, Gareth Williams, Rob Herring,
linux-mips, devicetree, Jarkko Nikula, Thomas Gleixner,
Wan Ahmad Zainie, linux-spi, linux-kernel
In-Reply-To: <20200515104758.6934-6-Sergey.Semin@baikalelectronics.ru>
On Fri, May 15, 2020 at 01:47:44PM +0300, Serge Semin wrote:
> It's pointless to track the Tx overrun interrupts if Rx-only SPI
> transfer is issued. Similarly there is no need in handling the Rx
> overrun/underrun interrupts if Tx-only SPI transfer is executed.
> So lets unmask the interrupts only if corresponding SPI
> transactions are implied.
My comments below.
> Co-developed-by: Georgy Vlasov <Georgy.Vlasov@baikalelectronics.ru>
> Signed-off-by: Georgy Vlasov <Georgy.Vlasov@baikalelectronics.ru>
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> Cc: Ramil Zaripov <Ramil.Zaripov@baikalelectronics.ru>
> Cc: Alexey Malahov <Alexey.Malahov@baikalelectronics.ru>
> Cc: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
> Cc: Paul Burton <paulburton@kernel.org>
> Cc: Ralf Baechle <ralf@linux-mips.org>
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: Allison Randal <allison@lohutok.net>
> Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> Cc: Gareth Williams <gareth.williams.jx@renesas.com>
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: linux-mips@vger.kernel.org
> Cc: devicetree@vger.kernel.org
I think you really need to revisit Cc list in all patches (DT people hardly
interested in this one, though ones where properties are being used might be
point of interest).
...
> /* Set the interrupt mask */
> - spi_umask_intr(dws, SPI_INT_TXOI | SPI_INT_RXUI | SPI_INT_RXOI);
> + spi_umask_intr(dws, imr);
Can we rather do like this
/* Set the interrupt mask */
if (xfer->tx_buf)
imr |= SPI_INT_TXOI;
if (xfer->rx_buf)
imr |= SPI_INT_RXUI | SPI_INT_RXOI;
spi_umask_intr(dws, imr);
?
(First block sets DMA, second one IRQ)
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH v2 02/19] spi: dw: Add Tx/Rx finish wait methods to the MID DMA
From: Mark Brown @ 2020-05-15 12:18 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Serge Semin, Serge Semin, Georgy Vlasov, Ramil Zaripov,
Alexey Malahov, Thomas Bogendoerfer, Paul Burton, Ralf Baechle,
Arnd Bergmann, Allison Randal, Gareth Williams, Rob Herring,
linux-mips, devicetree, Jarkko Nikula, Wan Ahmad Zainie,
Thomas Gleixner, wuxu.wu, Clement Leger, linux-spi, linux-kernel
In-Reply-To: <20200515120111.GV185537@smile.fi.intel.com>
[-- Attachment #1: Type: text/plain, Size: 345 bytes --]
On Fri, May 15, 2020 at 03:01:11PM +0300, Andy Shevchenko wrote:
> General question, doesn't spi core provides us some helpers like
> spi_delay_exec()?
Well, nobody wrote one. It's also a bit tricky to handle given that
often you're checking some controller specific things while a FIFO in
the IP drains/fills, though nothing insurmountable.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [Freedreno] [PATCH] drm/msm/dpu: ensure device suspend happens during PM sleep
From: kalyan_t @ 2020-05-15 12:05 UTC (permalink / raw)
To: Doug Anderson
Cc: open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
mkrishn, linux-arm-msm, travitej, LKML, dri-devel, Rob Clark,
nganji, Sean Paul, Kristian H. Kristensen, freedreno,
Jeykumar Sankaran
In-Reply-To: <CAD=FV=UJGivCyp=t0J++1DbSFDVf+5zSCcXgh83VZtssBmavjg@mail.gmail.com>
On 2020-05-14 21:47, Doug Anderson wrote:
> Hi,
>
> On Fri, May 1, 2020 at 6:31 AM Kalyan Thota <kalyan_t@codeaurora.org>
> wrote:
>>
>> "The PM core always increments the runtime usage counter
>> before calling the ->suspend() callback and decrements it
>> after calling the ->resume() callback"
>>
>> DPU and DSI are managed as runtime devices. When
>> suspend is triggered, PM core adds a refcount on all the
>> devices and calls device suspend, since usage count is
>> already incremented, runtime suspend was not getting called
>> and it kept the clocks on which resulted in target not
>> entering into XO shutdown.
>>
>> Add changes to force suspend on runtime devices during pm sleep.
>>
>> Changes in v1:
>> - Remove unnecessary checks in the function
>> _dpu_kms_disable_dpu (Rob Clark).
>>
>> Changes in v2:
>> - Avoid using suspend_late to reset the usagecount
>> as suspend_late might not be called during suspend
>> call failures (Doug).
>>
>> Changes in v3:
>> - Use force suspend instead of managing device usage_count
>> via runtime put and get API's to trigger callbacks (Doug).
>>
>> Changes in v4:
>> - Check the return values of pm_runtime_force_suspend and
>> pm_runtime_force_resume API's and pass appropriately (Doug).
>>
>> Changes in v5:
>
> Can you please put the version number properly in your subject? It's
> really hard to tell one version of your patch from another.
>
>
>> - With v4 patch, test cycle has uncovered issues in device resume.
>>
>> On bubs: cmd tx failures were seen as SW is sending panel off
>> commands when the dsi resources are turned off.
>>
>> Upon suspend, DRM driver will issue a NULL composition to the
>> dpu, followed by turning off all the HW blocks.
>>
>> v5 changes will serialize the NULL commit and resource unwinding
>> by handling them under PM prepare and PM complete phases there by
>> ensuring that clks are on when panel off commands are being
>> processed.
>
> I'm still most definitely not an expert in how all the DRM pieces all
> hook up together, but the solution you have in this patch seems wrong
> to me. As far as I can tell the "prepare" state isn't supposed to be
> actually doing the suspend work and here that's exactly what you're
> doing. I think you should find a different solution to ensure
> ordering is correct.
>
> -Doug
>
Hi,
Prepare and Complete are callbacks defined as part of Sleep and Resume
sequence
Entering PM SUSPEND the phases are : prepare --> suspend -->
suspend_late --> suspend_noirq.
While leaving PM SUSPEND the phases are: resume_noirq --> resume_early
--> resume --> complete.
The reason to push drm suspend handling to PM prepare phase is that
parent here will trigger a modeset to turn off the timing and
subsequently the panel.
the child devices should not turn of their clocks before parent unwinds
the composition. Hence they are serialized as per the sequence mentioned
above.
A similar approach is taken by other driver that use drm framework. In
this driver, the device registers for prepare and complete callbacks to
handle drm_suspend and drm_resume.
https://gitlab.freedesktop.org/drm/msm/-/blob/msm-next/drivers/gpu/drm/exynos/exynos_drm_drv.c#L163
Kalyan
_______________________________________________
> Freedreno mailing list
> Freedreno@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/freedreno
^ permalink raw reply
* Re: [PATCH v2 04/19] spi: dw: Fix native CS being unset
From: Andy Shevchenko @ 2020-05-15 12:05 UTC (permalink / raw)
To: Serge Semin
Cc: Mark Brown, Linus Walleij, Charles Keepax, Serge Semin,
Georgy Vlasov, Ramil Zaripov, Alexey Malahov, Thomas Bogendoerfer,
Paul Burton, Ralf Baechle, Arnd Bergmann, Allison Randal,
Gareth Williams, Rob Herring, linux-mips, devicetree,
Wan Ahmad Zainie, Clement Leger, Phil Edworthy, wuxu.wu,
Thomas Gleixner, linux-spi, linux-kernel
In-Reply-To: <20200515104758.6934-5-Sergey.Semin@baikalelectronics.ru>
On Fri, May 15, 2020 at 01:47:43PM +0300, Serge Semin wrote:
> Commit 6e0a32d6f376 ("spi: dw: Fix default polarity of native
> chipselect") attempted to fix the problem when GPIO active-high
> chip-select is utilized to communicate with some SPI slave. It fixed
> the problem, but broke the normal native CS support. At the same time
> the reversion commit ada9e3fcc175 ("spi: dw: Correct handling of native
> chipselect") didn't solve the problem either, since it just inverted
> the set_cs() polarity perception without taking into account that
> CS-high might be applicable. Here is what is done to finally fix the
> problem.
>
> DW SPI controller demands any native CS being set in order to proceed
> with data transfer. So in order to activate the SPI communications we
> must set any bit in the Slave Select DW SPI controller register no
> matter whether the platform requests the GPIO- or native CS. Preferably
> it should be the bit corresponding to the SPI slave CS number. But
> currently the dw_spi_set_cs() method activates the chip-select
> only if the second argument is false. Since the second argument of the
> set_cs callback is expected to be a boolean with "is-high" semantics
> (actual chip-select pin state value), the bit in the DW SPI Slave
> Select register will be set only if SPI core requests the driver
> to set the CS in the low state. So this will work for active-low
> GPIO-based CS case, and won't work for active-high CS setting
> the bit when SPI core actually needs to deactivate the CS.
>
> This commit fixes the problem for all described cases. So no matter
> whether an SPI slave needs GPIO- or native-based CS with active-high
> or low signal the corresponding bit will be set in SER.
Nice catch!
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> Fixes: ada9e3fcc175 ("spi: dw: Correct handling of native chipselect")
> Fixes: 6e0a32d6f376 ("spi: dw: Fix default polarity of native chipselect")
> Reviewed-by: Charles Keepax <ckeepax@opensource.cirrus.com>
> Acked-by: Linus Walleij <linus.walleij@linaro.org>
> Cc: Georgy Vlasov <Georgy.Vlasov@baikalelectronics.ru>
> Cc: Ramil Zaripov <Ramil.Zaripov@baikalelectronics.ru>
> Cc: Alexey Malahov <Alexey.Malahov@baikalelectronics.ru>
> Cc: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
> Cc: Paul Burton <paulburton@kernel.org>
> Cc: Ralf Baechle <ralf@linux-mips.org>
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: Allison Randal <allison@lohutok.net>
> Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> Cc: Gareth Williams <gareth.williams.jx@renesas.com>
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: linux-mips@vger.kernel.org
> Cc: devicetree@vger.kernel.org
>
> ---
>
> Changelog v2:
> - Add a comment about SER register, that it must be set to activate the
> SPI communications.
> ---
> drivers/spi/spi-dw.c | 10 +++++++++-
> 1 file changed, 9 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c
> index 6de196df9c96..450c8218caeb 100644
> --- a/drivers/spi/spi-dw.c
> +++ b/drivers/spi/spi-dw.c
> @@ -124,8 +124,16 @@ static inline void dw_spi_debugfs_remove(struct dw_spi *dws)
> void dw_spi_set_cs(struct spi_device *spi, bool enable)
> {
> struct dw_spi *dws = spi_controller_get_devdata(spi->controller);
> + bool cs_high = !!(spi->mode & SPI_CS_HIGH);
>
> - if (!enable)
> + /*
> + * DW SPI controller demands any native CS being set in order to
> + * proceed with data transfer. So in order to activate the SPI
> + * communications we must set a corresponding bit in the Slave
> + * Enable register no matter whether the SPI core is configured to
> + * support active-high or active-low CS level.
> + */
> + if (cs_high == enable)
> dw_writel(dws, DW_SPI_SER, BIT(spi->chip_select));
> else if (dws->cs_override)
> dw_writel(dws, DW_SPI_SER, 0);
> --
> 2.25.1
>
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH v3 10/15] net: ethernet: mtk-eth-mac: new driver
From: Arnd Bergmann @ 2020-05-15 12:04 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Jonathan Corbet, Rob Herring, David S . Miller, Matthias Brugger,
John Crispin, Sean Wang, Mark Lee, Jakub Kicinski, Fabien Parent,
Heiner Kallweit, Edwin Peer, DTML, linux-kernel@vger.kernel.org,
Networking, Linux ARM, moderated list:ARM/Mediatek SoC...,
Stephane Le Provost, Pedro Tsai, Andrew Perepech,
Bartosz Golaszewski
In-Reply-To: <CAMRc=MeypzZBHo6dJGKm4JujYyejqHxtdo7Ts95DXuL0VuMYCw@mail.gmail.com>
On Fri, May 15, 2020 at 9:11 AM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
>
> czw., 14 maj 2020 o 18:19 Arnd Bergmann <arnd@arndb.de> napisał(a):
> >
> > On Thu, May 14, 2020 at 10:00 AM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> > > +static unsigned int mtk_mac_intr_read_and_clear(struct mtk_mac_priv *priv)
> > > +{
> > > + unsigned int val;
> > > +
> > > + regmap_read(priv->regs, MTK_MAC_REG_INT_STS, &val);
> > > + regmap_write(priv->regs, MTK_MAC_REG_INT_STS, val);
> > > +
> > > + return val;
> > > +}
> >
> > Do you actually need to read the register? That is usually a relatively
> > expensive operation, so if possible try to use clear the bits when
> > you don't care which bits were set.
> >
>
> I do care, I'm afraid. The returned value is being used in the napi
> poll callback to see which ring to process.
I suppose the other callers are not performance critical.
For the rx and tx processing, it should be better to just always look at
the queue directly and ignore the irq status, in particular when you
are already in polling mode: suppose you receive ten frames at once
and only process five but clear the irq flag.
When the poll function is called again, you still need to process the
others, but I would assume that the status tells you that nothing
new has arrived so you don't process them until the next interrupt.
For the statistics, I assume you do need to look at the irq status,
but this doesn't have to be done in the poll function. How about
something like:
- in hardirq context, read the irq status word
- irq rx or tx irq pending, call napi_schedule
- if stats irq pending, schedule a work function
- in napi poll, process both queues until empty or
budget exhausted
- if packet processing completed in poll function
ack the irq and check again, call napi_complete
- in work function, handle stats irq, then ack it
> > > +static void mtk_mac_tx_complete_all(struct mtk_mac_priv *priv)
> > > +{
> > > + struct mtk_mac_ring *ring = &priv->tx_ring;
> > > + struct net_device *ndev = priv->ndev;
> > > + int ret;
> > > +
> > > + for (;;) {
> > > + mtk_mac_lock(priv);
> > > +
> > > + if (!mtk_mac_ring_descs_available(ring)) {
> > > + mtk_mac_unlock(priv);
> > > + break;
> > > + }
> > > +
> > > + ret = mtk_mac_tx_complete_one(priv);
> > > + if (ret) {
> > > + mtk_mac_unlock(priv);
> > > + break;
> > > + }
> > > +
> > > + if (netif_queue_stopped(ndev))
> > > + netif_wake_queue(ndev);
> > > +
> > > + mtk_mac_unlock(priv);
> > > + }
> > > +}
> >
> > It looks like most of the stuff inside of the loop can be pulled out
> > and only done once here.
> >
>
> I did that in one of the previous submissions but it was pointed out
> to me that a parallel TX path may fill up the queue before I wake it.
Right, I see you plugged that hole, however the way you hold the
spinlock across the expensive DMA management but then give it
up in each loop iteration feels like this is not the most efficient
way.
The easy way would be to just hold the lock across the entire
loop and then be sure you do it right. Alternatively you could
minimize the locking and only do the wakeup after up do the final
update to the tail pointer, at which point you know the queue is not
full because you have just freed up at least one entry.
> > > +static int mtk_mac_poll(struct napi_struct *napi, int budget)
> > > +{
> > > + struct mtk_mac_priv *priv;
> > > + unsigned int status;
> > > + int received = 0;
> > > +
> > > + priv = container_of(napi, struct mtk_mac_priv, napi);
> > > +
> > > + status = mtk_mac_intr_read_and_clear(priv);
> > > +
> > > + /* Clean up TX */
> > > + if (status & MTK_MAC_BIT_INT_STS_TNTC)
> > > + mtk_mac_tx_complete_all(priv);
> > > +
> > > + /* Receive up to $budget packets */
> > > + if (status & MTK_MAC_BIT_INT_STS_FNRC)
> > > + received = mtk_mac_process_rx(priv, budget);
> > > +
> > > + /* One of the counter reached 0x8000000 - update stats and reset all
> > > + * counters.
> > > + */
> > > + if (status & MTK_MAC_REG_INT_STS_MIB_CNT_TH) {
> > > + mtk_mac_update_stats(priv);
> > > + mtk_mac_reset_counters(priv);
> > > + }
> > > +
> > > + if (received < budget)
> > > + napi_complete_done(napi, received);
> > > +
> > > + mtk_mac_intr_unmask_all(priv);
> > > +
> > > + return received;
> > > +}
> >
> > I think you want to leave (at least some of) the interrupts masked
> > if your budget is exhausted, to avoid generating unnecessary
> > irqs.
> >
>
> The networking stack shouldn't queue any new TX packets if the queue
> is stopped - is this really worth complicating the code? Looks like
> premature optimization IMO.
Avoiding IRQs is one of the central aspects of using NAPI -- the idea
is that either you know there is more work to do and you will be called
again in the near future with additional budget, or you enable interrupts
and the irq handler calls napi_schedule, but not both.
This is mostly about RX processing, which is limited by the budget,
for TX you already free all descriptors regardless of the budget.
Arnd
^ permalink raw reply
* Re: [PATCH v2 03/19] spi: dw: Clear DMAC register when done or stopped
From: Andy Shevchenko @ 2020-05-15 12:01 UTC (permalink / raw)
To: Serge Semin
Cc: Mark Brown, Serge Semin, Georgy Vlasov, Ramil Zaripov,
Alexey Malahov, Thomas Bogendoerfer, Paul Burton, Ralf Baechle,
Arnd Bergmann, Allison Randal, Gareth Williams, Rob Herring,
linux-mips, devicetree, Thomas Gleixner, Wan Ahmad Zainie,
Jarkko Nikula, linux-spi, linux-kernel
In-Reply-To: <20200515104758.6934-4-Sergey.Semin@baikalelectronics.ru>
On Fri, May 15, 2020 at 01:47:42PM +0300, Serge Semin wrote:
> If DMAC register is left uncleared any further DMAless transfers
> may cause the DMAC hardware handshaking interface getting activated.
> So the next DMA-based Rx/Tx transaction will be started right
> after the dma_async_issue_pending() method is invoked even if no
> DMATDLR/DMARDLR conditions are met. This at the same time may cause
> the Tx/Rx FIFO buffers underrun/overrun. In order to fix this we
> must clear DMAC register after a current DMA-based transaction is
> finished.
After adding a Fixes tag,
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
>
> Co-developed-by: Georgy Vlasov <Georgy.Vlasov@baikalelectronics.ru>
> Signed-off-by: Georgy Vlasov <Georgy.Vlasov@baikalelectronics.ru>
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> Cc: Ramil Zaripov <Ramil.Zaripov@baikalelectronics.ru>
> Cc: Alexey Malahov <Alexey.Malahov@baikalelectronics.ru>
> Cc: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
> Cc: Paul Burton <paulburton@kernel.org>
> Cc: Ralf Baechle <ralf@linux-mips.org>
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: Allison Randal <allison@lohutok.net>
> Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> Cc: Gareth Williams <gareth.williams.jx@renesas.com>
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: linux-mips@vger.kernel.org
> Cc: devicetree@vger.kernel.org
>
> ---
>
> Changelog v2:
> - Move the patch to the head of the series so one could be picked up to
> the stable kernels as a fix.
> - Clear the DMACR in the DMA exit callback too.
> ---
> drivers/spi/spi-dw-mid.c | 8 ++++++++
> 1 file changed, 8 insertions(+)
>
> diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c
> index 7a5ae1506365..0c597b6bb154 100644
> --- a/drivers/spi/spi-dw-mid.c
> +++ b/drivers/spi/spi-dw-mid.c
> @@ -108,6 +108,8 @@ static void mid_spi_dma_exit(struct dw_spi *dws)
> dmaengine_terminate_sync(dws->rxchan);
> dma_release_channel(dws->rxchan);
> }
> +
> + dw_writel(dws, DW_SPI_DMACR, 0);
> }
>
> static irqreturn_t dma_transfer(struct dw_spi *dws)
> @@ -178,6 +180,8 @@ static void dw_spi_dma_tx_done(void *arg)
> clear_bit(TX_BUSY, &dws->dma_chan_busy);
> if (test_bit(RX_BUSY, &dws->dma_chan_busy))
> return;
> +
> + dw_writel(dws, DW_SPI_DMACR, 0);
> spi_finalize_current_transfer(dws->master);
> }
>
> @@ -249,6 +253,8 @@ static void dw_spi_dma_rx_done(void *arg)
> clear_bit(RX_BUSY, &dws->dma_chan_busy);
> if (test_bit(TX_BUSY, &dws->dma_chan_busy))
> return;
> +
> + dw_writel(dws, DW_SPI_DMACR, 0);
> spi_finalize_current_transfer(dws->master);
> }
>
> @@ -342,6 +348,8 @@ static void mid_spi_dma_stop(struct dw_spi *dws)
> dmaengine_terminate_sync(dws->rxchan);
> clear_bit(RX_BUSY, &dws->dma_chan_busy);
> }
> +
> + dw_writel(dws, DW_SPI_DMACR, 0);
> }
>
> static const struct dw_spi_dma_ops mfld_dma_ops = {
> --
> 2.25.1
>
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH v2 02/19] spi: dw: Add Tx/Rx finish wait methods to the MID DMA
From: Andy Shevchenko @ 2020-05-15 12:01 UTC (permalink / raw)
To: Serge Semin
Cc: Mark Brown, Serge Semin, Georgy Vlasov, Ramil Zaripov,
Alexey Malahov, Thomas Bogendoerfer, Paul Burton, Ralf Baechle,
Arnd Bergmann, Allison Randal, Gareth Williams, Rob Herring,
linux-mips, devicetree, Jarkko Nikula, Wan Ahmad Zainie,
Thomas Gleixner, wuxu.wu, Clement Leger, linux-spi, linux-kernel
In-Reply-To: <20200515104758.6934-3-Sergey.Semin@baikalelectronics.ru>
On Fri, May 15, 2020 at 01:47:41PM +0300, Serge Semin wrote:
> Since DMA transfers are performed asynchronously with actual SPI
> transaction, then even if DMA transfers are finished it doesn't mean
> all data is actually pushed to the SPI bus. Some data might still be
> in the controller FIFO. This is specifically true for Tx-only
> transfers. In this case if the next SPI transfer is recharged while
> a tail of the previous one is still in FIFO, we'll loose that tail
> data. In order to fix this lets add the wait procedure of the Tx/Rx
> SPI transfers completion after the corresponding DMA transactions
> are finished.
General question, doesn't spi core provides us some helpers like
spi_delay_exec()?
> Co-developed-by: Georgy Vlasov <Georgy.Vlasov@baikalelectronics.ru>
> Signed-off-by: Georgy Vlasov <Georgy.Vlasov@baikalelectronics.ru>
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> Cc: Ramil Zaripov <Ramil.Zaripov@baikalelectronics.ru>
> Cc: Alexey Malahov <Alexey.Malahov@baikalelectronics.ru>
> Cc: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
> Cc: Paul Burton <paulburton@kernel.org>
> Cc: Ralf Baechle <ralf@linux-mips.org>
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: Allison Randal <allison@lohutok.net>
> Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> Cc: Gareth Williams <gareth.williams.jx@renesas.com>
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: linux-mips@vger.kernel.org
> Cc: devicetree@vger.kernel.org
>
> ---
>
> Changelog v2:
> - Use conditional statement instead of the ternary operator in the ref
> clock getter.
> - Move the patch to the head of the series so one could be picked up to
> the stable kernels as a fix.
You forgot a Fixes tag.
> ---
> drivers/spi/spi-dw-mid.c | 50 ++++++++++++++++++++++++++++++++++++++++
> drivers/spi/spi-dw.h | 10 ++++++++
> 2 files changed, 60 insertions(+)
>
> diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c
> index 177e1f5ec62b..7a5ae1506365 100644
> --- a/drivers/spi/spi-dw-mid.c
> +++ b/drivers/spi/spi-dw-mid.c
> @@ -16,7 +16,9 @@
> #include <linux/irqreturn.h>
> #include <linux/pci.h>
> #include <linux/platform_data/dma-dw.h>
> +#include <linux/delay.h>
Keep it in order.
>
> +#define WAIT_RETRIES 5
> #define RX_BUSY 0
> #define TX_BUSY 1
>
> @@ -141,6 +143,28 @@ static enum dma_slave_buswidth convert_dma_width(u32 dma_width) {
> return DMA_SLAVE_BUSWIDTH_UNDEFINED;
> }
>
> +static inline bool dw_spi_dma_tx_busy(struct dw_spi *dws)
> +{
> + return !(dw_readl(dws, DW_SPI_SR) & SR_TF_EMPT);
> +}
> +
> +static void dw_spi_dma_wait_tx_done(struct dw_spi *dws)
> +{
> + int retry = WAIT_RETRIES;
> + unsigned long ns;
> +
> + ns = (NSEC_PER_SEC / spi_get_clk(dws)) * dws->n_bytes * BITS_PER_BYTE;
> + ns *= dw_readl(dws, DW_SPI_TXFLR);
> +
> + while (dw_spi_dma_tx_busy(dws) && retry--)
> + ndelay(ns);
This misses power management for CPU and do you really need this to be atomic?
At the end why not to use readx_poll_timeout() ?
> + if (retry < 0) {
Usually we do
unsigned int retries = NNNN;
do {
...
} while (--retries);
if (!retries)
...
But in any case, see above.
> + dev_err(&dws->master->dev, "Tx hanged up\n");
> + dws->master->cur_msg->status = -EIO;
> + }
> +}
Same comments to Rx part.
> +
> /*
> * dws->dma_chan_busy is set before the dma transfer starts, callback for tx
> * channel will clear a corresponding bit.
> @@ -149,6 +173,8 @@ static void dw_spi_dma_tx_done(void *arg)
> {
> struct dw_spi *dws = arg;
>
> + dw_spi_dma_wait_tx_done(dws);
> +
> clear_bit(TX_BUSY, &dws->dma_chan_busy);
> if (test_bit(RX_BUSY, &dws->dma_chan_busy))
> return;
> @@ -188,6 +214,28 @@ static struct dma_async_tx_descriptor *dw_spi_dma_prepare_tx(struct dw_spi *dws,
> return txdesc;
> }
>
> +static inline bool dw_spi_dma_rx_busy(struct dw_spi *dws)
> +{
> + return !!(dw_readl(dws, DW_SPI_SR) & SR_RF_NOT_EMPT);
> +}
> +
> +static void dw_spi_dma_wait_rx_done(struct dw_spi *dws)
> +{
> + int retry = WAIT_RETRIES;
> + unsigned long ns;
> +
> + ns = (NSEC_PER_SEC / spi_get_clk(dws)) * dws->n_bytes * BITS_PER_BYTE;
> + ns *= dw_readl(dws, DW_SPI_RXFLR);
> +
> + while (dw_spi_dma_rx_busy(dws) && retry--)
> + ndelay(ns);
> +
> + if (retry < 0) {
> + dev_err(&dws->master->dev, "Rx hanged up\n");
> + dws->master->cur_msg->status = -EIO;
> + }
> +}
> +
> /*
> * dws->dma_chan_busy is set before the dma transfer starts, callback for rx
> * channel will clear a corresponding bit.
> @@ -196,6 +244,8 @@ static void dw_spi_dma_rx_done(void *arg)
> {
> struct dw_spi *dws = arg;
>
> + dw_spi_dma_wait_rx_done(dws);
> +
> clear_bit(RX_BUSY, &dws->dma_chan_busy);
> if (test_bit(TX_BUSY, &dws->dma_chan_busy))
> return;
> diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
> index e92d43b9a9e6..81364f501b7e 100644
> --- a/drivers/spi/spi-dw.h
> +++ b/drivers/spi/spi-dw.h
> @@ -210,6 +210,16 @@ static inline void spi_set_clk(struct dw_spi *dws, u16 div)
> dw_writel(dws, DW_SPI_BAUDR, div);
> }
>
> +static inline u32 spi_get_clk(struct dw_spi *dws)
> +{
> + u32 div = dw_readl(dws, DW_SPI_BAUDR);
> +
> + if (!div)
> + return 0;
> +
> + return dws->max_freq / div;
> +}
> +
> /* Disable IRQ bits */
> static inline void spi_mask_intr(struct dw_spi *dws, u32 mask)
> {
> --
> 2.25.1
>
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH v2 01/19] dt-bindings: spi: dw: Add Tx/Rx DMA properties
From: Andy Shevchenko @ 2020-05-15 11:51 UTC (permalink / raw)
To: Serge Semin
Cc: Mark Brown, Rob Herring, Serge Semin, Georgy Vlasov,
Ramil Zaripov, Alexey Malahov, Thomas Bogendoerfer, Paul Burton,
Ralf Baechle, Arnd Bergmann, Allison Randal, Gareth Williams,
linux-mips, Wan Ahmad Zainie, linux-spi, devicetree, linux-kernel
In-Reply-To: <20200515104758.6934-2-Sergey.Semin@baikalelectronics.ru>
On Fri, May 15, 2020 at 01:47:40PM +0300, Serge Semin wrote:
> Since commit 22d48ad7bfac ("spi: dw: Add Elkhart Lake PSE DMA support")
> the spi-dw-mid.c module supports a platform DMA engine handling the DW APB
> SSI controller requests. Lets alter the DW SPI bindings file to accept the
> Rx and Tx DMA line specifiers.
I'm wondering if these properties are implied by the SPI generic one?
(forgive me if I'm not understanding all DT schema relations)
Per se looks good.
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> Cc: Georgy Vlasov <Georgy.Vlasov@baikalelectronics.ru>
> Cc: Ramil Zaripov <Ramil.Zaripov@baikalelectronics.ru>
> Cc: Alexey Malahov <Alexey.Malahov@baikalelectronics.ru>
> Cc: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
> Cc: Paul Burton <paulburton@kernel.org>
> Cc: Ralf Baechle <ralf@linux-mips.org>
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: Allison Randal <allison@lohutok.net>
> Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> Cc: Gareth Williams <gareth.williams.jx@renesas.com>
> Cc: linux-mips@vger.kernel.org
>
> ---
>
> Changelog v2:
> - Revert the order of the DT changes: first add the DMA channels support,
> then perform the binding file conversion.
> ---
> Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.txt | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.txt b/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.txt
> index 7a4702edf896..020e3168ee41 100644
> --- a/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.txt
> +++ b/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.txt
> @@ -23,6 +23,8 @@ Optional properties:
> - num-cs : The number of chipselects. If omitted, this will default to 4.
> - reg-io-width : The I/O register width (in bytes) implemented by this
> device. Supported values are 2 or 4 (the default).
> +- dmas : Phandle + identifiers of Tx and Rx DMA channels.
> +- dma-names : Contains the names of the DMA channels. Must be "tx" and "rx".
>
> Child nodes as per the generic SPI binding.
>
> --
> 2.25.1
>
--
With Best Regards,
Andy Shevchenko
^ 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