linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/3] Allwinner D1 power domain support
@ 2023-01-26  6:34 Samuel Holland
  2023-01-26  6:34 ` [PATCH v2 1/3] dt-bindings: power: Add Allwinner D1 PPU Samuel Holland
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Samuel Holland @ 2023-01-26  6:34 UTC (permalink / raw)
  To: Chen-Yu Tsai, Jernej Skrabec
  Cc: Rob Herring, Krzysztof Kozlowski, Samuel Holland, Andre Przywara,
	Conor Dooley, Heiko Stuebner, Palmer Dabbelt, Philipp Zabel,
	devicetree, linux-arm-kernel, linux-kernel, linux-riscv,
	linux-sunxi

This series adds support for the power controller found in D1 and other
recent Allwinner SoCs. There is no first-party documentation, but there
are a couple of vendor drivers for different hardware revisions[1][2],
and the register definitions were easy to verify empirically.

I have tested this driver on D1 with the video engine.

[1]: https://github.com/mangopi-sbc/tina-linux-5.4/blob/main/drivers/soc/sunxi/gpu_domain.c
[2]: https://github.com/mangopi-sbc/tina-linux-5.4/blob/main/drivers/soc/sunxi/pm_domains.c

Changes in v2:
 - Removed quotes from "PPU"
 - Fixed indentation in binding example
 - Removed possibly misleading comment from the Kconfig description
 - Include a patch adding the device tree node

Samuel Holland (3):
  dt-bindings: power: Add Allwinner D1 PPU
  soc: sunxi: Add Allwinner D1 PPU driver
  riscv: dts: allwinner: d1: Add power controller node

 .../power/allwinner,sun20i-d1-ppu.yaml        |  54 +++++
 .../boot/dts/allwinner/sunxi-d1s-t113.dtsi    |   8 +
 drivers/soc/sunxi/Kconfig                     |   8 +
 drivers/soc/sunxi/Makefile                    |   1 +
 drivers/soc/sunxi/sun20i-ppu.c                | 207 ++++++++++++++++++
 .../power/allwinner,sun20i-d1-ppu.h           |  10 +
 6 files changed, 288 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/allwinner,sun20i-d1-ppu.yaml
 create mode 100644 drivers/soc/sunxi/sun20i-ppu.c
 create mode 100644 include/dt-bindings/power/allwinner,sun20i-d1-ppu.h

-- 
2.37.4


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

* [PATCH v2 1/3] dt-bindings: power: Add Allwinner D1 PPU
  2023-01-26  6:34 [PATCH v2 0/3] Allwinner D1 power domain support Samuel Holland
@ 2023-01-26  6:34 ` Samuel Holland
  2023-01-26  6:34 ` [PATCH v2 2/3] soc: sunxi: Add Allwinner D1 PPU driver Samuel Holland
  2023-01-26  6:34 ` [PATCH v2 3/3] riscv: dts: allwinner: d1: Add power controller node Samuel Holland
  2 siblings, 0 replies; 5+ messages in thread
From: Samuel Holland @ 2023-01-26  6:34 UTC (permalink / raw)
  To: Chen-Yu Tsai, Jernej Skrabec
  Cc: Rob Herring, Krzysztof Kozlowski, Samuel Holland, Andre Przywara,
	Conor Dooley, Heiko Stuebner, Palmer Dabbelt, Philipp Zabel,
	devicetree, linux-arm-kernel, linux-kernel, linux-riscv,
	linux-sunxi, Krzysztof Kozlowski

The Allwinner D1 family of SoCs contain a PPU power domain controller
separate from the PRCM. It can power down the video engine and DSP, and
it contains special logic for hardware-assisted CPU idle. Other recent
Allwinner SoCs (e.g. TV303) have a PPU with a different set of domains.

Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
---

Changes in v2:
 - Removed quotes from "PPU"
 - Fixed indentation in binding example

 .../power/allwinner,sun20i-d1-ppu.yaml        | 54 +++++++++++++++++++
 .../power/allwinner,sun20i-d1-ppu.h           | 10 ++++
 2 files changed, 64 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/allwinner,sun20i-d1-ppu.yaml
 create mode 100644 include/dt-bindings/power/allwinner,sun20i-d1-ppu.h

diff --git a/Documentation/devicetree/bindings/power/allwinner,sun20i-d1-ppu.yaml b/Documentation/devicetree/bindings/power/allwinner,sun20i-d1-ppu.yaml
new file mode 100644
index 000000000000..46e2647a5d72
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/allwinner,sun20i-d1-ppu.yaml
@@ -0,0 +1,54 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/power/allwinner,sun20i-d1-ppu.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner SoCs PPU power domain controller
+
+maintainers:
+  - Samuel Holland <samuel@sholland.org>
+
+description:
+  D1 and related SoCs contain a power domain controller for the CPUs, GPU, and
+  video-related hardware.
+
+properties:
+  compatible:
+    enum:
+      - allwinner,sun20i-d1-ppu
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    description: Bus Clock
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  '#power-domain-cells':
+    const: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - resets
+  - '#power-domain-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/sun20i-d1-r-ccu.h>
+    #include <dt-bindings/reset/sun20i-d1-r-ccu.h>
+
+    ppu: power-controller@7001000 {
+        compatible = "allwinner,sun20i-d1-ppu";
+        reg = <0x7001000 0x1000>;
+        clocks = <&r_ccu CLK_BUS_R_PPU>;
+        resets = <&r_ccu RST_BUS_R_PPU>;
+        #power-domain-cells = <1>;
+    };
diff --git a/include/dt-bindings/power/allwinner,sun20i-d1-ppu.h b/include/dt-bindings/power/allwinner,sun20i-d1-ppu.h
new file mode 100644
index 000000000000..23cfb57256d6
--- /dev/null
+++ b/include/dt-bindings/power/allwinner,sun20i-d1-ppu.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+
+#ifndef _DT_BINDINGS_POWER_SUN20I_D1_PPU_H_
+#define _DT_BINDINGS_POWER_SUN20I_D1_PPU_H_
+
+#define PD_CPU			0
+#define PD_VE			1
+#define PD_DSP			2
+
+#endif /* _DT_BINDINGS_POWER_SUN20I_D1_PPU_H_ */
-- 
2.37.4


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

* [PATCH v2 2/3] soc: sunxi: Add Allwinner D1 PPU driver
  2023-01-26  6:34 [PATCH v2 0/3] Allwinner D1 power domain support Samuel Holland
  2023-01-26  6:34 ` [PATCH v2 1/3] dt-bindings: power: Add Allwinner D1 PPU Samuel Holland
@ 2023-01-26  6:34 ` Samuel Holland
  2023-01-26  6:34 ` [PATCH v2 3/3] riscv: dts: allwinner: d1: Add power controller node Samuel Holland
  2 siblings, 0 replies; 5+ messages in thread
From: Samuel Holland @ 2023-01-26  6:34 UTC (permalink / raw)
  To: Chen-Yu Tsai, Jernej Skrabec
  Cc: Rob Herring, Krzysztof Kozlowski, Samuel Holland, Andre Przywara,
	Conor Dooley, Heiko Stuebner, Palmer Dabbelt, Philipp Zabel,
	devicetree, linux-arm-kernel, linux-kernel, linux-riscv,
	linux-sunxi

The PPU contains a series of identical MMIO register ranges, one for
each power domain. Each range contains control/status bits for a clock
gate, reset line, output gates, and a power switch. (The clock and reset
are separate from, and in addition to, the bits in the CCU.) It also
contains a hardware power sequence engine to control the other bits.

Acked-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Signed-off-by: Samuel Holland <samuel@sholland.org>
---

Changes in v2:
 - Removed possibly misleading comment from the Kconfig description

 drivers/soc/sunxi/Kconfig      |   8 ++
 drivers/soc/sunxi/Makefile     |   1 +
 drivers/soc/sunxi/sun20i-ppu.c | 207 +++++++++++++++++++++++++++++++++
 3 files changed, 216 insertions(+)
 create mode 100644 drivers/soc/sunxi/sun20i-ppu.c

diff --git a/drivers/soc/sunxi/Kconfig b/drivers/soc/sunxi/Kconfig
index 8aecbc9b1976..29e9ba2d520d 100644
--- a/drivers/soc/sunxi/Kconfig
+++ b/drivers/soc/sunxi/Kconfig
@@ -19,3 +19,11 @@ config SUNXI_SRAM
 	  Say y here to enable the SRAM controller support. This
 	  device is responsible on mapping the SRAM in the sunXi SoCs
 	  whether to the CPU/DMA, or to the devices.
+
+config SUN20I_PPU
+	bool "Allwinner D1 PPU power domain driver"
+	depends on ARCH_SUNXI || COMPILE_TEST
+	select PM_GENERIC_DOMAINS
+	help
+	  Say y to enable the PPU power domain driver. This saves power
+	  when certain peripherals, such as the video engine, are idle.
diff --git a/drivers/soc/sunxi/Makefile b/drivers/soc/sunxi/Makefile
index 549159571d4f..90ff2ebe7655 100644
--- a/drivers/soc/sunxi/Makefile
+++ b/drivers/soc/sunxi/Makefile
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_SUNXI_MBUS) +=	sunxi_mbus.o
 obj-$(CONFIG_SUNXI_SRAM) +=	sunxi_sram.o
+obj-$(CONFIG_SUN20I_PPU) +=	sun20i-ppu.o
diff --git a/drivers/soc/sunxi/sun20i-ppu.c b/drivers/soc/sunxi/sun20i-ppu.c
new file mode 100644
index 000000000000..98cb41d36560
--- /dev/null
+++ b/drivers/soc/sunxi/sun20i-ppu.c
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/reset.h>
+
+#define PD_STATE_ON			1
+#define PD_STATE_OFF			2
+
+#define PD_RSTN_REG			0x00
+#define PD_CLK_GATE_REG			0x04
+#define PD_PWROFF_GATE_REG		0x08
+#define PD_PSW_ON_REG			0x0c
+#define PD_PSW_OFF_REG			0x10
+#define PD_PSW_DELAY_REG		0x14
+#define PD_OFF_DELAY_REG		0x18
+#define PD_ON_DELAY_REG			0x1c
+#define PD_COMMAND_REG			0x20
+#define PD_STATUS_REG			0x24
+#define PD_STATUS_COMPLETE			BIT(1)
+#define PD_STATUS_BUSY				BIT(3)
+#define PD_STATUS_STATE				GENMASK(17, 16)
+#define PD_ACTIVE_CTRL_REG		0x2c
+#define PD_GATE_STATUS_REG		0x30
+#define PD_RSTN_STATUS				BIT(0)
+#define PD_CLK_GATE_STATUS			BIT(1)
+#define PD_PWROFF_GATE_STATUS			BIT(2)
+#define PD_PSW_STATUS_REG		0x34
+
+#define PD_REGS_SIZE			0x80
+
+struct sun20i_ppu_desc {
+	const char *const		*names;
+	unsigned int			num_domains;
+};
+
+struct sun20i_ppu_pd {
+	struct generic_pm_domain	genpd;
+	void __iomem			*base;
+};
+
+#define to_sun20i_ppu_pd(_genpd) \
+	container_of(_genpd, struct sun20i_ppu_pd, genpd)
+
+static bool sun20i_ppu_pd_is_on(const struct sun20i_ppu_pd *pd)
+{
+	u32 status = readl(pd->base + PD_STATUS_REG);
+
+	return FIELD_GET(PD_STATUS_STATE, status) == PD_STATE_ON;
+}
+
+static int sun20i_ppu_pd_set_power(const struct sun20i_ppu_pd *pd, bool power_on)
+{
+	u32 state, status;
+	int ret;
+
+	if (sun20i_ppu_pd_is_on(pd) == power_on)
+		return 0;
+
+	/* Wait for the power controller to be idle. */
+	ret = readl_poll_timeout(pd->base + PD_STATUS_REG, status,
+				 !(status & PD_STATUS_BUSY), 100, 1000);
+	if (ret)
+		return ret;
+
+	state = power_on ? PD_STATE_ON : PD_STATE_OFF;
+	writel(state, pd->base + PD_COMMAND_REG);
+
+	/* Wait for the state transition to complete. */
+	ret = readl_poll_timeout(pd->base + PD_STATUS_REG, status,
+				 FIELD_GET(PD_STATUS_STATE, status) == state &&
+				 (status & PD_STATUS_COMPLETE), 100, 1000);
+	if (ret)
+		return ret;
+
+	/* Clear the completion flag. */
+	writel(status, pd->base + PD_STATUS_REG);
+
+	return 0;
+}
+
+static int sun20i_ppu_pd_power_on(struct generic_pm_domain *genpd)
+{
+	const struct sun20i_ppu_pd *pd = to_sun20i_ppu_pd(genpd);
+
+	return sun20i_ppu_pd_set_power(pd, true);
+}
+
+static int sun20i_ppu_pd_power_off(struct generic_pm_domain *genpd)
+{
+	const struct sun20i_ppu_pd *pd = to_sun20i_ppu_pd(genpd);
+
+	return sun20i_ppu_pd_set_power(pd, false);
+}
+
+static int sun20i_ppu_probe(struct platform_device *pdev)
+{
+	const struct sun20i_ppu_desc *desc;
+	struct device *dev = &pdev->dev;
+	struct genpd_onecell_data *ppu;
+	struct sun20i_ppu_pd *pds;
+	struct reset_control *rst;
+	void __iomem *base;
+	struct clk *clk;
+	int ret;
+
+	desc = of_device_get_match_data(dev);
+	if (!desc)
+		return -EINVAL;
+
+	pds = devm_kcalloc(dev, desc->num_domains, sizeof(*pds), GFP_KERNEL);
+	if (!pds)
+		return -ENOMEM;
+
+	ppu = devm_kzalloc(dev, sizeof(*ppu), GFP_KERNEL);
+	if (!ppu)
+		return -ENOMEM;
+
+	ppu->domains = devm_kcalloc(dev, desc->num_domains,
+				    sizeof(*ppu->domains), GFP_KERNEL);
+	if (!ppu->domains)
+		return -ENOMEM;
+
+	ppu->num_domains = desc->num_domains;
+	platform_set_drvdata(pdev, ppu);
+
+	base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	clk = devm_clk_get_enabled(dev, NULL);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	rst = devm_reset_control_get_exclusive(dev, NULL);
+	if (IS_ERR(rst))
+		return PTR_ERR(rst);
+
+	ret = reset_control_deassert(rst);
+	if (ret)
+		return ret;
+
+	for (unsigned int i = 0; i < ppu->num_domains; ++i) {
+		struct sun20i_ppu_pd *pd = &pds[i];
+
+		pd->genpd.name		= desc->names[i];
+		pd->genpd.power_off	= sun20i_ppu_pd_power_off;
+		pd->genpd.power_on	= sun20i_ppu_pd_power_on;
+		pd->base		= base + PD_REGS_SIZE * i;
+
+		ret = pm_genpd_init(&pd->genpd, NULL, sun20i_ppu_pd_is_on(pd));
+		if (ret) {
+			dev_warn(dev, "Failed to add '%s' domain: %d\n",
+				 pd->genpd.name, ret);
+			continue;
+		}
+
+		ppu->domains[i] = &pd->genpd;
+	}
+
+	ret = of_genpd_add_provider_onecell(dev->of_node, ppu);
+	if (ret)
+		dev_warn(dev, "Failed to add provider: %d\n", ret);
+
+	return 0;
+}
+
+static const char *const sun20i_d1_ppu_pd_names[] = {
+	"CPU",
+	"VE",
+	"DSP",
+};
+
+static const struct sun20i_ppu_desc sun20i_d1_ppu_desc = {
+	.names		= sun20i_d1_ppu_pd_names,
+	.num_domains	= ARRAY_SIZE(sun20i_d1_ppu_pd_names),
+};
+
+static const struct of_device_id sun20i_ppu_of_match[] = {
+	{
+		.compatible	= "allwinner,sun20i-d1-ppu",
+		.data		= &sun20i_d1_ppu_desc,
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, sun20i_ppu_of_match);
+
+static struct platform_driver sun20i_ppu_driver = {
+	.probe	= sun20i_ppu_probe,
+	.driver	= {
+		.name			= "sun20i-ppu",
+		.of_match_table		= sun20i_ppu_of_match,
+		/* Power domains cannot be removed while they are in use. */
+		.suppress_bind_attrs	= true,
+	},
+};
+module_platform_driver(sun20i_ppu_driver);
+
+MODULE_AUTHOR("Samuel Holland <samuel@sholland.org>");
+MODULE_DESCRIPTION("Allwinner D1 PPU power domain driver");
+MODULE_LICENSE("GPL");
-- 
2.37.4


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

* [PATCH v2 3/3] riscv: dts: allwinner: d1: Add power controller node
  2023-01-26  6:34 [PATCH v2 0/3] Allwinner D1 power domain support Samuel Holland
  2023-01-26  6:34 ` [PATCH v2 1/3] dt-bindings: power: Add Allwinner D1 PPU Samuel Holland
  2023-01-26  6:34 ` [PATCH v2 2/3] soc: sunxi: Add Allwinner D1 PPU driver Samuel Holland
@ 2023-01-26  6:34 ` Samuel Holland
  2023-01-27 22:17   ` Jernej Škrabec
  2 siblings, 1 reply; 5+ messages in thread
From: Samuel Holland @ 2023-01-26  6:34 UTC (permalink / raw)
  To: Chen-Yu Tsai, Jernej Skrabec
  Cc: Rob Herring, Krzysztof Kozlowski, Samuel Holland, Andre Przywara,
	Conor Dooley, Heiko Stuebner, Palmer Dabbelt, Philipp Zabel,
	devicetree, linux-arm-kernel, linux-kernel, linux-riscv,
	linux-sunxi

The Allwinner D1 family of SoCs contain a PPU power domain controller
separate from the PRCM. It can power down the video engine and DSP, and
it contains special logic for hardware-assisted CPU idle.

Signed-off-by: Samuel Holland <samuel@sholland.org>
---

Changes in v2:
 - Include a patch adding the device tree node

 arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi b/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi
index 3723612b1fd8..6fadcee7800f 100644
--- a/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi
+++ b/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi
@@ -799,6 +799,14 @@ tcon_tv0_out_tcon_top_hdmi: endpoint {
 			};
 		};
 
+		ppu: power-controller@7001000 {
+			compatible = "allwinner,sun20i-d1-ppu";
+			reg = <0x7001000 0x1000>;
+			clocks = <&r_ccu CLK_BUS_R_PPU>;
+			resets = <&r_ccu RST_BUS_R_PPU>;
+			#power-domain-cells = <1>;
+		};
+
 		r_ccu: clock-controller@7010000 {
 			compatible = "allwinner,sun20i-d1-r-ccu";
 			reg = <0x7010000 0x400>;
-- 
2.37.4


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

* Re: [PATCH v2 3/3] riscv: dts: allwinner: d1: Add power controller node
  2023-01-26  6:34 ` [PATCH v2 3/3] riscv: dts: allwinner: d1: Add power controller node Samuel Holland
@ 2023-01-27 22:17   ` Jernej Škrabec
  0 siblings, 0 replies; 5+ messages in thread
From: Jernej Škrabec @ 2023-01-27 22:17 UTC (permalink / raw)
  To: Chen-Yu Tsai, Samuel Holland
  Cc: Rob Herring, Krzysztof Kozlowski, Samuel Holland, Andre Przywara,
	Conor Dooley, Heiko Stuebner, Palmer Dabbelt, Philipp Zabel,
	devicetree, linux-arm-kernel, linux-kernel, linux-riscv,
	linux-sunxi

Dne četrtek, 26. januar 2023 ob 07:34:19 CET je Samuel Holland napisal(a):
> The Allwinner D1 family of SoCs contain a PPU power domain controller
> separate from the PRCM. It can power down the video engine and DSP, and
> it contains special logic for hardware-assisted CPU idle.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

Acked-by: Jernej Skrabec <jernej.skrabec@gmail.com>

Best regards,
Jernej

> ---
> 
> Changes in v2:
>  - Include a patch adding the device tree node
> 
>  arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 
> diff --git a/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi
> b/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi index
> 3723612b1fd8..6fadcee7800f 100644
> --- a/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi
> +++ b/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi
> @@ -799,6 +799,14 @@ tcon_tv0_out_tcon_top_hdmi: endpoint {
>  			};
>  		};
> 
> +		ppu: power-controller@7001000 {
> +			compatible = "allwinner,sun20i-d1-ppu";
> +			reg = <0x7001000 0x1000>;
> +			clocks = <&r_ccu CLK_BUS_R_PPU>;
> +			resets = <&r_ccu RST_BUS_R_PPU>;
> +			#power-domain-cells = <1>;
> +		};
> +
>  		r_ccu: clock-controller@7010000 {
>  			compatible = "allwinner,sun20i-d1-r-ccu";
>  			reg = <0x7010000 0x400>;





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

end of thread, other threads:[~2023-01-27 22:17 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-01-26  6:34 [PATCH v2 0/3] Allwinner D1 power domain support Samuel Holland
2023-01-26  6:34 ` [PATCH v2 1/3] dt-bindings: power: Add Allwinner D1 PPU Samuel Holland
2023-01-26  6:34 ` [PATCH v2 2/3] soc: sunxi: Add Allwinner D1 PPU driver Samuel Holland
2023-01-26  6:34 ` [PATCH v2 3/3] riscv: dts: allwinner: d1: Add power controller node Samuel Holland
2023-01-27 22:17   ` Jernej Škrabec

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).