sunxi-6.14: Add drm patches

This commit is contained in:
The-going 2025-04-30 12:37:10 +03:00 committed by Igor
parent 468871e561
commit fb4b91a169
39 changed files with 4399 additions and 16 deletions

View File

@ -0,0 +1,41 @@
From 86ef31fcb116682d399b9723a7ab66c87e6f2cc5 Mon Sep 17 00:00:00 2001
From: Stephen Graf <stephen.graf@gmail.com>
Date: Tue, 18 Feb 2025 05:12:44 +0000
Subject: add TCON global control reg for pad selection
Signed-off-by: Stephen Graf <stephen.graf@gmail.com>
---
drivers/gpu/drm/sun4i/sun4i_tcon.c | 4 ++++
drivers/gpu/drm/sun4i/sun4i_tcon.h | 1 +
2 files changed, 5 insertions(+)
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index af67bf2e6e09..88984572f5c5 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -1308,6 +1308,10 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
goto err_free_dclk;
}
+ regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
+ SUN4I_TCON_GCTL_PAD_SEL,
+ SUN4I_TCON_GCTL_PAD_SEL);
+
if (tcon->quirks->has_channel_0) {
/*
* If we have an LVDS panel connected to the TCON, we should
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h
index bd4abc90062b..e8d28bad4060 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.h
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h
@@ -19,6 +19,7 @@
#define SUN4I_TCON_GCTL_REG 0x0
#define SUN4I_TCON_GCTL_TCON_ENABLE BIT(31)
+#define SUN4I_TCON_GCTL_PAD_SEL BIT(1)
#define SUN4I_TCON_GCTL_IOMAP_MASK BIT(0)
#define SUN4I_TCON_GCTL_IOMAP_TCON1 (1 << 0)
#define SUN4I_TCON_GCTL_IOMAP_TCON0 (0 << 0)
--
2.35.3

View File

@ -0,0 +1,61 @@
From 02dc976a5f62b393f378c056888f121ba1880fc5 Mon Sep 17 00:00:00 2001
From: Andre Przywara <andre.przywara@arm.com>
Date: Fri, 21 Feb 2025 00:58:01 +0000
Subject: arm64: dts: allwinner: h616: Add Mali GPU node
The Allwinner H616 SoC contains a Mali-G31 MP2 GPU, which is of the Mali
Bifrost family. There is a power domain specifically for that GPU, which
needs to be enabled to make use of the it.
Add the DT nodes for those two devices, and link them together through
the "power-domains" property.
Any board wishing to use the GPU would need to enable the GPU node and
specify the "mali-supply" regulator.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
.../arm64/boot/dts/allwinner/sun50i-h616.dtsi | 21 +++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi
index cdce3dcb8ec0..ceedae9e399b 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi
@@ -150,6 +150,21 @@ soc {
#size-cells = <1>;
ranges = <0x0 0x0 0x0 0x40000000>;
+ gpu: gpu@1800000 {
+ compatible = "allwinner,sun50i-h616-mali",
+ "arm,mali-bifrost";
+ reg = <0x1800000 0x40000>;
+ interrupts = <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "job", "mmu", "gpu";
+ clocks = <&ccu CLK_GPU0>, <&ccu CLK_BUS_GPU>;
+ clock-names = "core", "bus";
+ power-domains = <&prcm_ppu 2>;
+ resets = <&ccu RST_BUS_GPU>;
+ status = "disabled";
+ };
+
crypto: crypto@1904000 {
compatible = "allwinner,sun50i-h616-crypto";
reg = <0x01904000 0x800>;
@@ -874,6 +889,12 @@ r_ccu: clock@7010000 {
#reset-cells = <1>;
};
+ prcm_ppu: power-controller@7010250 {
+ compatible = "allwinner,sun50i-h616-prcm-ppu";
+ reg = <0x07010250 0x10>;
+ #power-domain-cells = <1>;
+ };
+
nmi_intc: interrupt-controller@7010320 {
compatible = "allwinner,sun50i-h616-nmi",
"allwinner,sun9i-a80-nmi";
--
2.35.3

View File

@ -0,0 +1,86 @@
From b41f5a9ec8841c0342f101585c64c292019543d2 Mon Sep 17 00:00:00 2001
From: Ryan Walklin <ryan@testtoast.com>
Date: Sun, 29 Sep 2024 22:04:54 +1300
Subject: clk: sunxi-ng: ccu: add Display Engine 3.3 (DE33) support
The DE33 is a newer version of the Allwinner Display Engine IP block,
found in the H616, H618, H700 and T507 SoCs. DE2 and DE3 are already
supported by the mainline driver.
The DE33 in the H616 has mixer0 and writeback units. The clocks
and resets required are identical to the H3 and H5 respectively, so use
those existing structs for the H616 description.
There are two additional 32-bit registers (at offsets 0x24 and 0x28)
which require clearing and setting respectively to bring up the
hardware. The function of these registers is currently unknown, and the
values are taken from the out-of-tree driver.
Add the required clock description struct and compatible string to the
DE2 driver.
Signed-off-by: Ryan Walklin <ryan@testtoast.com>
---
drivers/clk/sunxi-ng/ccu-sun8i-de2.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
index 7683ea08d8e3..83eab6f132aa 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
@@ -5,6 +5,7 @@
#include <linux/clk.h>
#include <linux/clk-provider.h>
+#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
@@ -239,6 +240,16 @@ static const struct sunxi_ccu_desc sun50i_h5_de2_clk_desc = {
.num_resets = ARRAY_SIZE(sun50i_h5_de2_resets),
};
+static const struct sunxi_ccu_desc sun50i_h616_de33_clk_desc = {
+ .ccu_clks = sun8i_de2_ccu_clks,
+ .num_ccu_clks = ARRAY_SIZE(sun8i_de2_ccu_clks),
+
+ .hw_clks = &sun8i_h3_de2_hw_clks,
+
+ .resets = sun50i_h5_de2_resets,
+ .num_resets = ARRAY_SIZE(sun50i_h5_de2_resets),
+};
+
static int sunxi_de2_clk_probe(struct platform_device *pdev)
{
struct clk *bus_clk, *mod_clk;
@@ -291,6 +302,16 @@ static int sunxi_de2_clk_probe(struct platform_device *pdev)
goto err_disable_mod_clk;
}
+ /*
+ * The DE33 requires these additional (unknown) registers set
+ * during initialisation.
+ */
+ if (of_device_is_compatible(pdev->dev.of_node,
+ "allwinner,sun50i-h616-de33-clk")) {
+ writel(0, reg + 0x24);
+ writel(0x0000a980, reg + 0x28);
+ }
+
ret = devm_sunxi_ccu_probe(&pdev->dev, reg, ccu_desc);
if (ret)
goto err_assert_reset;
@@ -335,6 +356,10 @@ static const struct of_device_id sunxi_de2_clk_ids[] = {
.compatible = "allwinner,sun50i-h6-de3-clk",
.data = &sun50i_h5_de2_clk_desc,
},
+ {
+ .compatible = "allwinner,sun50i-h616-de33-clk",
+ .data = &sun50i_h616_de33_clk_desc,
+ },
{ }
};
MODULE_DEVICE_TABLE(of, sunxi_de2_clk_ids);
--
2.35.3

View File

@ -0,0 +1,111 @@
From ce56f3f385e0830a1e242f9fca9a82c3067ba03f Mon Sep 17 00:00:00 2001
From: Philippe Simons <simons.philippe@gmail.com>
Date: Thu, 13 Mar 2025 00:23:18 +0100
Subject: drm/panfrost: Add PM runtime flags
Allwinner H616 has a dedicated power domain for its Mali G31.
Currently after probe, the GPU is put in runtime suspend which
disable the power domain.
On first usage of GPU, the power domain enable hangs the system.
This series adds the necessary calls to enable the clocks and
deasserting the reset line after the power domain enabling and
asserting the reset line and disabling the clocks prior to the
power domain disabling.
This allows to use the Mali GPU on all Allwinner H616
boards and devices.
When the GPU is the only device attached to a single power domain,
core genpd disable and enable it when gpu enter and leave runtime suspend.
Some power-domain requires a sequence before disabled,
and the reverse when enabled.
Add GPU_PM_RT flag, and implement in
panfrost_device_runtime_suspend/resume.
Signed-off-by: Philippe Simons <simons.philippe@gmail.com>
---
drivers/gpu/drm/panfrost/panfrost_device.c | 33 ++++++++++++++++++++++
drivers/gpu/drm/panfrost/panfrost_device.h | 3 ++
2 files changed, 36 insertions(+)
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c
index a45e4addcc19..93d48e97ce10 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.c
+++ b/drivers/gpu/drm/panfrost/panfrost_device.c
@@ -406,11 +406,36 @@ void panfrost_device_reset(struct panfrost_device *pfdev)
static int panfrost_device_runtime_resume(struct device *dev)
{
struct panfrost_device *pfdev = dev_get_drvdata(dev);
+ int ret;
+
+ if (pfdev->comp->pm_features & BIT(GPU_PM_RT)) {
+ ret = reset_control_deassert(pfdev->rstc);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(pfdev->clock);
+ if (ret)
+ goto err_clk;
+
+ if (pfdev->bus_clock) {
+ ret = clk_enable(pfdev->bus_clock);
+ if (ret)
+ goto err_bus_clk;
+ }
+ }
panfrost_device_reset(pfdev);
panfrost_devfreq_resume(pfdev);
return 0;
+
+err_bus_clk:
+ if (pfdev->comp->pm_features & BIT(GPU_PM_RT))
+ clk_disable(pfdev->clock);
+err_clk:
+ if (pfdev->comp->pm_features & BIT(GPU_PM_RT))
+ reset_control_assert(pfdev->rstc);
+ return ret;
}
static int panfrost_device_runtime_suspend(struct device *dev)
@@ -426,6 +451,14 @@ static int panfrost_device_runtime_suspend(struct device *dev)
panfrost_gpu_suspend_irq(pfdev);
panfrost_gpu_power_off(pfdev);
+ if (pfdev->comp->pm_features & BIT(GPU_PM_RT)) {
+ if (pfdev->bus_clock)
+ clk_disable(pfdev->bus_clock);
+
+ clk_disable(pfdev->clock);
+ reset_control_assert(pfdev->rstc);
+ }
+
return 0;
}
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h
index cffcb0ac7c11..861555ceea65 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.h
+++ b/drivers/gpu/drm/panfrost/panfrost_device.h
@@ -36,10 +36,13 @@ enum panfrost_drv_comp_bits {
* enum panfrost_gpu_pm - Supported kernel power management features
* @GPU_PM_CLK_DIS: Allow disabling clocks during system suspend
* @GPU_PM_VREG_OFF: Allow turning off regulators during system suspend
+ * @GPU_PM_RT: Allow disabling clocks and asserting the reset control during
+ * system runtime suspend
*/
enum panfrost_gpu_pm {
GPU_PM_CLK_DIS,
GPU_PM_VREG_OFF,
+ GPU_PM_RT
};
struct panfrost_features {
--
2.35.3

View File

@ -0,0 +1,43 @@
From 16e3a927918e0c6349c2bfcbe468ee1690eaaaca Mon Sep 17 00:00:00 2001
From: Philippe Simons <simons.philippe@gmail.com>
Date: Thu, 13 Mar 2025 00:23:19 +0100
Subject: drm/panfrost: add h616 compatible string
Tie the Allwinner compatible string to the GPU_PM_RT feature bits that will
toggle the clocks and the reset line whenever the power domain is changing
state.
Signed-off-by: Philippe Simons <simons.philippe@gmail.com>
---
drivers/gpu/drm/panfrost/panfrost_drv.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c
index 0f3935556ac7..9470c04c5487 100644
--- a/drivers/gpu/drm/panfrost/panfrost_drv.c
+++ b/drivers/gpu/drm/panfrost/panfrost_drv.c
@@ -776,6 +776,13 @@ static const struct panfrost_compatible default_data = {
.pm_domain_names = NULL,
};
+static const struct panfrost_compatible allwinner_h616_data = {
+ .num_supplies = ARRAY_SIZE(default_supplies) - 1,
+ .supply_names = default_supplies,
+ .num_pm_domains = 1,
+ .pm_features = BIT(GPU_PM_RT),
+};
+
static const struct panfrost_compatible amlogic_data = {
.num_supplies = ARRAY_SIZE(default_supplies) - 1,
.supply_names = default_supplies,
@@ -859,6 +866,7 @@ static const struct of_device_id dt_match[] = {
{ .compatible = "mediatek,mt8186-mali", .data = &mediatek_mt8186_data },
{ .compatible = "mediatek,mt8188-mali", .data = &mediatek_mt8188_data },
{ .compatible = "mediatek,mt8192-mali", .data = &mediatek_mt8192_data },
+ { .compatible = "allwinner,sun50i-h616-mali", .data = &allwinner_h616_data },
{}
};
MODULE_DEVICE_TABLE(of, dt_match);
--
2.35.3

View File

@ -0,0 +1,106 @@
From 37f8be7eaca786f85cf2a17dfd33227e2ff45780 Mon Sep 17 00:00:00 2001
From: Philippe Simons <simons.philippe@gmail.com>
Date: Thu, 3 Apr 2025 07:52:10 +0200
Subject: drm/panfrost: reorder pd/clk/rst sequence
According to Mali manuals, the powerup sequence should be
enable pd, asserting the reset then enabling the clock and
the reverse for powerdown.
Signed-off-by: Philippe Simons <simons.philippe@gmail.com>
---
drivers/gpu/drm/panfrost/panfrost_device.c | 38 +++++++++++-----------
1 file changed, 19 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c
index 93d48e97ce10..5d35076b2e6d 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.c
+++ b/drivers/gpu/drm/panfrost/panfrost_device.c
@@ -209,10 +209,20 @@ int panfrost_device_init(struct panfrost_device *pfdev)
spin_lock_init(&pfdev->cycle_counter.lock);
+ err = panfrost_pm_domain_init(pfdev);
+ if (err)
+ return err;
+
+ err = panfrost_reset_init(pfdev);
+ if (err) {
+ dev_err(pfdev->dev, "reset init failed %d\n", err);
+ goto out_pm_domain;
+ }
+
err = panfrost_clk_init(pfdev);
if (err) {
dev_err(pfdev->dev, "clk init failed %d\n", err);
- return err;
+ goto out_reset;
}
err = panfrost_devfreq_init(pfdev);
@@ -229,25 +239,15 @@ int panfrost_device_init(struct panfrost_device *pfdev)
goto out_devfreq;
}
- err = panfrost_reset_init(pfdev);
- if (err) {
- dev_err(pfdev->dev, "reset init failed %d\n", err);
- goto out_regulator;
- }
-
- err = panfrost_pm_domain_init(pfdev);
- if (err)
- goto out_reset;
-
pfdev->iomem = devm_platform_ioremap_resource(pfdev->pdev, 0);
if (IS_ERR(pfdev->iomem)) {
err = PTR_ERR(pfdev->iomem);
- goto out_pm_domain;
+ goto out_regulator;
}
err = panfrost_gpu_init(pfdev);
if (err)
- goto out_pm_domain;
+ goto out_regulator;
err = panfrost_mmu_init(pfdev);
if (err)
@@ -268,16 +268,16 @@ int panfrost_device_init(struct panfrost_device *pfdev)
panfrost_mmu_fini(pfdev);
out_gpu:
panfrost_gpu_fini(pfdev);
-out_pm_domain:
- panfrost_pm_domain_fini(pfdev);
-out_reset:
- panfrost_reset_fini(pfdev);
out_regulator:
panfrost_regulator_fini(pfdev);
out_devfreq:
panfrost_devfreq_fini(pfdev);
out_clk:
panfrost_clk_fini(pfdev);
+out_reset:
+ panfrost_reset_fini(pfdev);
+out_pm_domain:
+ panfrost_pm_domain_fini(pfdev);
return err;
}
@@ -287,11 +287,11 @@ void panfrost_device_fini(struct panfrost_device *pfdev)
panfrost_job_fini(pfdev);
panfrost_mmu_fini(pfdev);
panfrost_gpu_fini(pfdev);
- panfrost_pm_domain_fini(pfdev);
- panfrost_reset_fini(pfdev);
panfrost_devfreq_fini(pfdev);
panfrost_regulator_fini(pfdev);
panfrost_clk_fini(pfdev);
+ panfrost_reset_fini(pfdev);
+ panfrost_pm_domain_fini(pfdev);
}
#define PANFROST_EXCEPTION(id) \
--
2.35.3

View File

@ -0,0 +1,108 @@
From 6c8bbaf43b8eaf62d4682ce66a35fc7f341f4a13 Mon Sep 17 00:00:00 2001
From: The-going <48602507+The-going@users.noreply.github.com>
Date: Mon, 10 Feb 2025 15:45:13 +0300
Subject: [PATCH] drm: sun4i: add sun50i-h616-hdmi-phy support
---
drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 71 ++++++++++++++++++++++++++
1 file changed, 71 insertions(+)
diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
index 4fa69c463dc4..8a07052037c3 100644
--- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
+++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
@@ -124,6 +124,66 @@ static const struct dw_hdmi_phy_config sun50i_h6_phy_config[] = {
{ ~0UL, 0x0000, 0x0000, 0x0000}
};
+static const struct dw_hdmi_mpll_config sun50i_h616_mpll_cfg[] = {
+ {
+ 27000000, {
+ {0x00b3, 0x0003},
+ {0x2153, 0x0003},
+ {0x40f3, 0x0003},
+ },
+ }, {
+ 74250000, {
+ {0x0072, 0x0003},
+ {0x2145, 0x0003},
+ {0x4061, 0x0003},
+ },
+ }, {
+ 148500000, {
+ {0x0051, 0x0003},
+ {0x214c, 0x0003},
+ {0x4064, 0x0003},
+ },
+ }, {
+ 297000000, {
+ {0x0040, 0x0003},
+ {0x3b4c, 0x0003},
+ {0x5a64, 0x0003},
+ },
+ }, {
+ 594000000, {
+ {0x1a40, 0x0003},
+ {0x3b4c, 0x0003},
+ {0x5a64, 0x0003},
+ },
+ }, {
+ ~0UL, {
+ {0x0000, 0x0000},
+ {0x0000, 0x0000},
+ {0x0000, 0x0000},
+ },
+ }
+};
+
+static const struct dw_hdmi_curr_ctrl sun50i_h616_cur_ctr[] = {
+ /* pixelclk bpp8 bpp10 bpp12 */
+ { 27000000, { 0x0012, 0x0000, 0x0000 }, },
+ { 74250000, { 0x0013, 0x0013, 0x0013 }, },
+ { 148500000, { 0x0019, 0x0019, 0x0019 }, },
+ { 297000000, { 0x0019, 0x001b, 0x0019 }, },
+ { 594000000, { 0x0010, 0x0010, 0x0010 }, },
+ { ~0UL, { 0x0000, 0x0000, 0x0000 }, }
+};
+
+static const struct dw_hdmi_phy_config sun50i_h616_phy_config[] = {
+ /*pixelclk symbol term vlev*/
+ {27000000, 0x8009, 0x0007, 0x02b0},
+ {74250000, 0x8019, 0x0004, 0x0290},
+ {148500000, 0x8019, 0x0004, 0x0290},
+ {297000000, 0x8039, 0x0004, 0x022b},
+ {594000000, 0x8029, 0x0000, 0x008a},
+ {~0UL, 0x0000, 0x0000, 0x0000}
+};
+
static void sun8i_hdmi_phy_set_polarity(struct sun8i_hdmi_phy *phy,
const struct drm_display_mode *mode)
{
@@ -626,6 +686,13 @@ static const struct sun8i_hdmi_phy_variant sun50i_h6_hdmi_phy = {
.phy_init = &sun50i_hdmi_phy_init_h6,
};
+static const struct sun8i_hdmi_phy_variant sun50i_h616_hdmi_phy = {
+ .cur_ctr = sun50i_h616_cur_ctr,
+ .mpll_cfg = sun50i_h616_mpll_cfg,
+ .phy_cfg = sun50i_h616_phy_config,
+ .phy_init = &sun50i_hdmi_phy_init_h6,
+};
+
static const struct of_device_id sun8i_hdmi_phy_of_table[] = {
{
.compatible = "allwinner,sun8i-a83t-hdmi-phy",
@@ -647,6 +714,10 @@ static const struct of_device_id sun8i_hdmi_phy_of_table[] = {
.compatible = "allwinner,sun50i-h6-hdmi-phy",
.data = &sun50i_h6_hdmi_phy,
},
+ {
+ .compatible = "allwinner,sun50i-h616-hdmi-phy",
+ .data = &sun50i_h616_hdmi_phy,
+ },
{ /* sentinel */ }
};
--
2.35.3

View File

@ -0,0 +1,75 @@
From 5c2859b3cccd1b1b3f1700fd70c06770f418247a Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Date: Sun, 29 Sep 2024 22:04:36 +1300
Subject: drm: sun4i: de2: Initialize layer fields earlier
drm_universal_plane_init() can already call some callbacks, like
format_mod_supported, during initialization. Because of that, fields
should be initialized beforehand.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Co-developed-by: Ryan Walklin <ryan@testtoast.com>
Signed-off-by: Ryan Walklin <ryan@testtoast.com>
Reviewed-by: Chen-Yu Tsai <wens@csie.org>
---
drivers/gpu/drm/sun4i/sun8i_ui_layer.c | 9 +++++----
drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 9 +++++----
2 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
index aa987bca1dbb..cb9b694fef10 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
@@ -295,6 +295,11 @@ struct sun8i_layer *sun8i_ui_layer_init_one(struct drm_device *drm,
if (!layer)
return ERR_PTR(-ENOMEM);
+ layer->mixer = mixer;
+ layer->type = SUN8I_LAYER_TYPE_UI;
+ layer->channel = channel;
+ layer->overlay = 0;
+
if (index == 0)
type = DRM_PLANE_TYPE_PRIMARY;
@@ -325,10 +330,6 @@ struct sun8i_layer *sun8i_ui_layer_init_one(struct drm_device *drm,
}
drm_plane_helper_add(&layer->plane, &sun8i_ui_layer_helper_funcs);
- layer->mixer = mixer;
- layer->type = SUN8I_LAYER_TYPE_UI;
- layer->channel = channel;
- layer->overlay = 0;
return layer;
}
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
index f3a5329351ca..3c657b069d1f 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
@@ -478,6 +478,11 @@ struct sun8i_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
if (!layer)
return ERR_PTR(-ENOMEM);
+ layer->mixer = mixer;
+ layer->type = SUN8I_LAYER_TYPE_VI;
+ layer->channel = index;
+ layer->overlay = 0;
+
if (mixer->cfg->is_de3) {
formats = sun8i_vi_layer_de3_formats;
format_count = ARRAY_SIZE(sun8i_vi_layer_de3_formats);
@@ -536,10 +541,6 @@ struct sun8i_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
}
drm_plane_helper_add(&layer->plane, &sun8i_vi_layer_helper_funcs);
- layer->mixer = mixer;
- layer->type = SUN8I_LAYER_TYPE_VI;
- layer->channel = index;
- layer->overlay = 0;
return layer;
}
--
2.35.3

View File

@ -0,0 +1,178 @@
From 54669ac67e47835b8cc3eea215026385a0050567 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Date: Sun, 29 Sep 2024 22:04:33 +1300
Subject: drm: sun4i: de2/de3: Change CSC argument
Currently, CSC module takes care only for converting YUV to RGB.
However, DE3 is more suited to work in YUV color space. Change CSC mode
argument to format type to be more neutral. New argument only tells
layer format type and doesn't imply output type.
This commit doesn't make any functional change.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Signed-off-by: Ryan Walklin <ryan@testtoast.com>
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
---
drivers/gpu/drm/sun4i/sun8i_csc.c | 22 +++++++++++-----------
drivers/gpu/drm/sun4i/sun8i_csc.h | 10 +++++-----
drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 16 ++++++++--------
3 files changed, 24 insertions(+), 24 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c b/drivers/gpu/drm/sun4i/sun8i_csc.c
index 58480d8e4f70..6ebd1c3aa3ab 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -108,7 +108,7 @@ static const u32 yuv2rgb_de3[2][3][12] = {
};
static void sun8i_csc_set_coefficients(struct regmap *map, u32 base,
- enum sun8i_csc_mode mode,
+ enum format_type fmt_type,
enum drm_color_encoding encoding,
enum drm_color_range range)
{
@@ -118,12 +118,12 @@ static void sun8i_csc_set_coefficients(struct regmap *map, u32 base,
table = yuv2rgb[range][encoding];
- switch (mode) {
- case SUN8I_CSC_MODE_YUV2RGB:
+ switch (fmt_type) {
+ case FORMAT_TYPE_YUV:
base_reg = SUN8I_CSC_COEFF(base, 0);
regmap_bulk_write(map, base_reg, table, 12);
break;
- case SUN8I_CSC_MODE_YVU2RGB:
+ case FORMAT_TYPE_YVU:
for (i = 0; i < 12; i++) {
if ((i & 3) == 1)
base_reg = SUN8I_CSC_COEFF(base, i + 1);
@@ -141,7 +141,7 @@ static void sun8i_csc_set_coefficients(struct regmap *map, u32 base,
}
static void sun8i_de3_ccsc_set_coefficients(struct regmap *map, int layer,
- enum sun8i_csc_mode mode,
+ enum format_type fmt_type,
enum drm_color_encoding encoding,
enum drm_color_range range)
{
@@ -151,12 +151,12 @@ static void sun8i_de3_ccsc_set_coefficients(struct regmap *map, int layer,
table = yuv2rgb_de3[range][encoding];
- switch (mode) {
- case SUN8I_CSC_MODE_YUV2RGB:
+ switch (fmt_type) {
+ case FORMAT_TYPE_YUV:
addr = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE, layer, 0);
regmap_bulk_write(map, addr, table, 12);
break;
- case SUN8I_CSC_MODE_YVU2RGB:
+ case FORMAT_TYPE_YVU:
for (i = 0; i < 12; i++) {
if ((i & 3) == 1)
addr = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE,
@@ -206,7 +206,7 @@ static void sun8i_de3_ccsc_enable(struct regmap *map, int layer, bool enable)
}
void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer *mixer, int layer,
- enum sun8i_csc_mode mode,
+ enum format_type fmt_type,
enum drm_color_encoding encoding,
enum drm_color_range range)
{
@@ -214,14 +214,14 @@ void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer *mixer, int layer,
if (mixer->cfg->is_de3) {
sun8i_de3_ccsc_set_coefficients(mixer->engine.regs, layer,
- mode, encoding, range);
+ fmt_type, encoding, range);
return;
}
base = ccsc_base[mixer->cfg->ccsc][layer];
sun8i_csc_set_coefficients(mixer->engine.regs, base,
- mode, encoding, range);
+ fmt_type, encoding, range);
}
void sun8i_csc_enable_ccsc(struct sun8i_mixer *mixer, int layer, bool enable)
diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.h b/drivers/gpu/drm/sun4i/sun8i_csc.h
index 828b86fd0cab..7322770f39f0 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.h
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.h
@@ -22,14 +22,14 @@ struct sun8i_mixer;
#define SUN8I_CSC_CTRL_EN BIT(0)
-enum sun8i_csc_mode {
- SUN8I_CSC_MODE_OFF,
- SUN8I_CSC_MODE_YUV2RGB,
- SUN8I_CSC_MODE_YVU2RGB,
+enum format_type {
+ FORMAT_TYPE_RGB,
+ FORMAT_TYPE_YUV,
+ FORMAT_TYPE_YVU,
};
void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer *mixer, int layer,
- enum sun8i_csc_mode mode,
+ enum format_type fmt_type,
enum drm_color_encoding encoding,
enum drm_color_range range);
void sun8i_csc_enable_ccsc(struct sun8i_mixer *mixer, int layer, bool enable);
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
index 9c09d9c08496..8a80934e928f 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
@@ -193,19 +193,19 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
return 0;
}
-static u32 sun8i_vi_layer_get_csc_mode(const struct drm_format_info *format)
+static u32 sun8i_vi_layer_get_format_type(const struct drm_format_info *format)
{
if (!format->is_yuv)
- return SUN8I_CSC_MODE_OFF;
+ return FORMAT_TYPE_RGB;
switch (format->format) {
case DRM_FORMAT_YVU411:
case DRM_FORMAT_YVU420:
case DRM_FORMAT_YVU422:
case DRM_FORMAT_YVU444:
- return SUN8I_CSC_MODE_YVU2RGB;
+ return FORMAT_TYPE_YVU;
default:
- return SUN8I_CSC_MODE_YUV2RGB;
+ return FORMAT_TYPE_YUV;
}
}
@@ -213,7 +213,7 @@ static int sun8i_vi_layer_update_formats(struct sun8i_mixer *mixer, int channel,
int overlay, struct drm_plane *plane)
{
struct drm_plane_state *state = plane->state;
- u32 val, ch_base, csc_mode, hw_fmt;
+ u32 val, ch_base, fmt_type, hw_fmt;
const struct drm_format_info *fmt;
int ret;
@@ -231,9 +231,9 @@ static int sun8i_vi_layer_update_formats(struct sun8i_mixer *mixer, int channel,
SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay),
SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_MASK, val);
- csc_mode = sun8i_vi_layer_get_csc_mode(fmt);
- if (csc_mode != SUN8I_CSC_MODE_OFF) {
- sun8i_csc_set_ccsc_coefficients(mixer, channel, csc_mode,
+ fmt_type = sun8i_vi_layer_get_format_type(fmt);
+ if (fmt_type != FORMAT_TYPE_RGB) {
+ sun8i_csc_set_ccsc_coefficients(mixer, channel, fmt_type,
state->color_encoding,
state->color_range);
sun8i_csc_enable_ccsc(mixer, channel, true);
--
2.35.3

View File

@ -0,0 +1,221 @@
From 09744193cdcf400e5a4c54d9309acf5aea3a591c Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Date: Sun, 29 Sep 2024 22:04:34 +1300
Subject: drm: sun4i: de2/de3: Merge CSC functions into one
At the moment the colour space conversion is handled by two functions:
one to setup the conversion parameters, and another one to enable the
conversion. Merging both into one gives more flexibility for upcoming
extensions to support whole YUV pipelines, in the DE33.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Signed-off-by: Ryan Walklin <ryan@testtoast.com>
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
---
drivers/gpu/drm/sun4i/sun8i_csc.c | 89 ++++++++++----------------
drivers/gpu/drm/sun4i/sun8i_csc.h | 9 ++-
drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 11 +---
3 files changed, 40 insertions(+), 69 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c b/drivers/gpu/drm/sun4i/sun8i_csc.c
index 6ebd1c3aa3ab..0dcbc0866ae8 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -107,23 +107,28 @@ static const u32 yuv2rgb_de3[2][3][12] = {
},
};
-static void sun8i_csc_set_coefficients(struct regmap *map, u32 base,
- enum format_type fmt_type,
- enum drm_color_encoding encoding,
- enum drm_color_range range)
+static void sun8i_csc_setup(struct regmap *map, u32 base,
+ enum format_type fmt_type,
+ enum drm_color_encoding encoding,
+ enum drm_color_range range)
{
+ u32 base_reg, val;
const u32 *table;
- u32 base_reg;
int i;
table = yuv2rgb[range][encoding];
switch (fmt_type) {
+ case FORMAT_TYPE_RGB:
+ val = 0;
+ break;
case FORMAT_TYPE_YUV:
+ val = SUN8I_CSC_CTRL_EN;
base_reg = SUN8I_CSC_COEFF(base, 0);
regmap_bulk_write(map, base_reg, table, 12);
break;
case FORMAT_TYPE_YVU:
+ val = SUN8I_CSC_CTRL_EN;
for (i = 0; i < 12; i++) {
if ((i & 3) == 1)
base_reg = SUN8I_CSC_COEFF(base, i + 1);
@@ -135,28 +140,37 @@ static void sun8i_csc_set_coefficients(struct regmap *map, u32 base,
}
break;
default:
+ val = 0;
DRM_WARN("Wrong CSC mode specified.\n");
return;
}
+
+ regmap_write(map, SUN8I_CSC_CTRL(base), val);
}
-static void sun8i_de3_ccsc_set_coefficients(struct regmap *map, int layer,
- enum format_type fmt_type,
- enum drm_color_encoding encoding,
- enum drm_color_range range)
+static void sun8i_de3_ccsc_setup(struct regmap *map, int layer,
+ enum format_type fmt_type,
+ enum drm_color_encoding encoding,
+ enum drm_color_range range)
{
+ u32 addr, val, mask;
const u32 *table;
- u32 addr;
int i;
+ mask = SUN50I_MIXER_BLEND_CSC_CTL_EN(layer);
table = yuv2rgb_de3[range][encoding];
switch (fmt_type) {
+ case FORMAT_TYPE_RGB:
+ val = 0;
+ break;
case FORMAT_TYPE_YUV:
+ val = mask;
addr = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE, layer, 0);
regmap_bulk_write(map, addr, table, 12);
break;
case FORMAT_TYPE_YVU:
+ val = mask;
for (i = 0; i < 12; i++) {
if ((i & 3) == 1)
addr = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE,
@@ -173,67 +187,30 @@ static void sun8i_de3_ccsc_set_coefficients(struct regmap *map, int layer,
}
break;
default:
+ val = 0;
DRM_WARN("Wrong CSC mode specified.\n");
return;
}
-}
-
-static void sun8i_csc_enable(struct regmap *map, u32 base, bool enable)
-{
- u32 val;
-
- if (enable)
- val = SUN8I_CSC_CTRL_EN;
- else
- val = 0;
-
- regmap_update_bits(map, SUN8I_CSC_CTRL(base), SUN8I_CSC_CTRL_EN, val);
-}
-
-static void sun8i_de3_ccsc_enable(struct regmap *map, int layer, bool enable)
-{
- u32 val, mask;
-
- mask = SUN50I_MIXER_BLEND_CSC_CTL_EN(layer);
-
- if (enable)
- val = mask;
- else
- val = 0;
regmap_update_bits(map, SUN50I_MIXER_BLEND_CSC_CTL(DE3_BLD_BASE),
mask, val);
}
-void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer *mixer, int layer,
- enum format_type fmt_type,
- enum drm_color_encoding encoding,
- enum drm_color_range range)
-{
- u32 base;
-
- if (mixer->cfg->is_de3) {
- sun8i_de3_ccsc_set_coefficients(mixer->engine.regs, layer,
- fmt_type, encoding, range);
- return;
- }
-
- base = ccsc_base[mixer->cfg->ccsc][layer];
-
- sun8i_csc_set_coefficients(mixer->engine.regs, base,
- fmt_type, encoding, range);
-}
-
-void sun8i_csc_enable_ccsc(struct sun8i_mixer *mixer, int layer, bool enable)
+void sun8i_csc_set_ccsc(struct sun8i_mixer *mixer, int layer,
+ enum format_type fmt_type,
+ enum drm_color_encoding encoding,
+ enum drm_color_range range)
{
u32 base;
if (mixer->cfg->is_de3) {
- sun8i_de3_ccsc_enable(mixer->engine.regs, layer, enable);
+ sun8i_de3_ccsc_setup(mixer->engine.regs, layer,
+ fmt_type, encoding, range);
return;
}
base = ccsc_base[mixer->cfg->ccsc][layer];
- sun8i_csc_enable(mixer->engine.regs, base, enable);
+ sun8i_csc_setup(mixer->engine.regs, base,
+ fmt_type, encoding, range);
}
diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.h b/drivers/gpu/drm/sun4i/sun8i_csc.h
index 7322770f39f0..b7546e06e315 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.h
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.h
@@ -28,10 +28,9 @@ enum format_type {
FORMAT_TYPE_YVU,
};
-void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer *mixer, int layer,
- enum format_type fmt_type,
- enum drm_color_encoding encoding,
- enum drm_color_range range);
-void sun8i_csc_enable_ccsc(struct sun8i_mixer *mixer, int layer, bool enable);
+void sun8i_csc_set_ccsc(struct sun8i_mixer *mixer, int layer,
+ enum format_type fmt_type,
+ enum drm_color_encoding encoding,
+ enum drm_color_range range);
#endif
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
index 8a80934e928f..f3a5329351ca 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
@@ -232,14 +232,9 @@ static int sun8i_vi_layer_update_formats(struct sun8i_mixer *mixer, int channel,
SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_MASK, val);
fmt_type = sun8i_vi_layer_get_format_type(fmt);
- if (fmt_type != FORMAT_TYPE_RGB) {
- sun8i_csc_set_ccsc_coefficients(mixer, channel, fmt_type,
- state->color_encoding,
- state->color_range);
- sun8i_csc_enable_ccsc(mixer, channel, true);
- } else {
- sun8i_csc_enable_ccsc(mixer, channel, false);
- }
+ sun8i_csc_set_ccsc(mixer, channel, fmt_type,
+ state->color_encoding,
+ state->color_range);
if (!fmt->is_yuv)
val = SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE;
--
2.35.3

View File

@ -0,0 +1,38 @@
From 45d06599927825fe1fa3c374508d6d0c8c9f9f52 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Date: Sun, 29 Sep 2024 22:04:48 +1300
Subject: drm: sun4i: de2/de3: add generic blender register reference function
The DE2 and DE3 engines have a blender register range within the
mixer engine register map, whereas the DE33 separates this out into
a separate display group.
Prepare for this by adding a function to look the blender reference up,
with a subsequent patch to add a conditional based on the DE type.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Signed-off-by: Ryan Walklin <ryan@testtoast.com>
---
drivers/gpu/drm/sun4i/sun8i_mixer.h | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h b/drivers/gpu/drm/sun4i/sun8i_mixer.h
index 82956cb97cfd..75facc7d1fa6 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.h
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
@@ -224,6 +224,12 @@ sun8i_blender_base(struct sun8i_mixer *mixer)
return mixer->cfg->de_type == sun8i_mixer_de3 ? DE3_BLD_BASE : DE2_BLD_BASE;
}
+static inline struct regmap *
+sun8i_blender_regmap(struct sun8i_mixer *mixer)
+{
+ return mixer->engine.regs;
+}
+
static inline u32
sun8i_channel_base(struct sun8i_mixer *mixer, int channel)
{
--
2.35.3

View File

@ -0,0 +1,257 @@
From b49e4fb3439c50eb6effc559366b3e88e2ac2f27 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Date: Sun, 29 Sep 2024 22:04:45 +1300
Subject: drm: sun4i: de2/de3: add mixer version enum
The Allwinner DE2 and DE3 display engine mixers are currently identified
by a simple boolean flag. This will not scale to support additional DE
variants.
Convert the boolean flag to an enum.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Signed-off-by: Ryan Walklin <ryan@testtoast.com>
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
---
drivers/gpu/drm/sun4i/sun8i_csc.c | 2 +-
drivers/gpu/drm/sun4i/sun8i_mixer.c | 14 ++++++++++++--
drivers/gpu/drm/sun4i/sun8i_mixer.h | 11 ++++++++---
drivers/gpu/drm/sun4i/sun8i_ui_scaler.c | 2 +-
drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 8 ++++----
drivers/gpu/drm/sun4i/sun8i_vi_scaler.c | 4 ++--
6 files changed, 28 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c b/drivers/gpu/drm/sun4i/sun8i_csc.c
index e12a81fa9108..2d5a2cf7cba2 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -365,7 +365,7 @@ void sun8i_csc_set_ccsc(struct sun8i_mixer *mixer, int layer,
{
u32 base;
- if (mixer->cfg->is_de3) {
+ if (mixer->cfg->de_type == sun8i_mixer_de3) {
sun8i_de3_ccsc_setup(&mixer->engine, layer,
fmt_type, encoding, range);
return;
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index a50c583852ed..16e018aa4aae 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -584,7 +584,7 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
base = sun8i_blender_base(mixer);
/* Reset registers and disable unused sub-engines */
- if (mixer->cfg->is_de3) {
+ if (mixer->cfg->de_type == sun8i_mixer_de3) {
for (i = 0; i < DE3_MIXER_UNIT_SIZE; i += 4)
regmap_write(mixer->engine.regs, i, 0);
@@ -675,6 +675,7 @@ static void sun8i_mixer_remove(struct platform_device *pdev)
static const struct sun8i_mixer_cfg sun8i_a83t_mixer0_cfg = {
.ccsc = CCSC_MIXER0_LAYOUT,
+ .de_type = sun8i_mixer_de2,
.scaler_mask = 0xf,
.scanline_yuv = 2048,
.ui_num = 3,
@@ -683,6 +684,7 @@ static const struct sun8i_mixer_cfg sun8i_a83t_mixer0_cfg = {
static const struct sun8i_mixer_cfg sun8i_a83t_mixer1_cfg = {
.ccsc = CCSC_MIXER1_LAYOUT,
+ .de_type = sun8i_mixer_de2,
.scaler_mask = 0x3,
.scanline_yuv = 2048,
.ui_num = 1,
@@ -691,6 +693,7 @@ static const struct sun8i_mixer_cfg sun8i_a83t_mixer1_cfg = {
static const struct sun8i_mixer_cfg sun8i_h3_mixer0_cfg = {
.ccsc = CCSC_MIXER0_LAYOUT,
+ .de_type = sun8i_mixer_de2,
.mod_rate = 432000000,
.scaler_mask = 0xf,
.scanline_yuv = 2048,
@@ -700,6 +703,7 @@ static const struct sun8i_mixer_cfg sun8i_h3_mixer0_cfg = {
static const struct sun8i_mixer_cfg sun8i_r40_mixer0_cfg = {
.ccsc = CCSC_MIXER0_LAYOUT,
+ .de_type = sun8i_mixer_de2,
.mod_rate = 297000000,
.scaler_mask = 0xf,
.scanline_yuv = 2048,
@@ -709,6 +713,7 @@ static const struct sun8i_mixer_cfg sun8i_r40_mixer0_cfg = {
static const struct sun8i_mixer_cfg sun8i_r40_mixer1_cfg = {
.ccsc = CCSC_MIXER1_LAYOUT,
+ .de_type = sun8i_mixer_de2,
.mod_rate = 297000000,
.scaler_mask = 0x3,
.scanline_yuv = 2048,
@@ -717,6 +722,7 @@ static const struct sun8i_mixer_cfg sun8i_r40_mixer1_cfg = {
};
static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
+ .de_type = sun8i_mixer_de2,
.vi_num = 2,
.ui_num = 1,
.scaler_mask = 0x3,
@@ -727,6 +733,7 @@ static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
static const struct sun8i_mixer_cfg sun20i_d1_mixer0_cfg = {
.ccsc = CCSC_D1_MIXER0_LAYOUT,
+ .de_type = sun8i_mixer_de2,
.mod_rate = 297000000,
.scaler_mask = 0x3,
.scanline_yuv = 2048,
@@ -736,6 +743,7 @@ static const struct sun8i_mixer_cfg sun20i_d1_mixer0_cfg = {
static const struct sun8i_mixer_cfg sun20i_d1_mixer1_cfg = {
.ccsc = CCSC_MIXER1_LAYOUT,
+ .de_type = sun8i_mixer_de2,
.mod_rate = 297000000,
.scaler_mask = 0x1,
.scanline_yuv = 1024,
@@ -745,6 +753,7 @@ static const struct sun8i_mixer_cfg sun20i_d1_mixer1_cfg = {
static const struct sun8i_mixer_cfg sun50i_a64_mixer0_cfg = {
.ccsc = CCSC_MIXER0_LAYOUT,
+ .de_type = sun8i_mixer_de2,
.mod_rate = 297000000,
.scaler_mask = 0xf,
.scanline_yuv = 4096,
@@ -754,6 +763,7 @@ static const struct sun8i_mixer_cfg sun50i_a64_mixer0_cfg = {
static const struct sun8i_mixer_cfg sun50i_a64_mixer1_cfg = {
.ccsc = CCSC_MIXER1_LAYOUT,
+ .de_type = sun8i_mixer_de2,
.mod_rate = 297000000,
.scaler_mask = 0x3,
.scanline_yuv = 2048,
@@ -763,7 +773,7 @@ static const struct sun8i_mixer_cfg sun50i_a64_mixer1_cfg = {
static const struct sun8i_mixer_cfg sun50i_h6_mixer0_cfg = {
.ccsc = CCSC_MIXER0_LAYOUT,
- .is_de3 = true,
+ .de_type = sun8i_mixer_de3,
.has_formatter = 1,
.mod_rate = 600000000,
.scaler_mask = 0xf,
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h b/drivers/gpu/drm/sun4i/sun8i_mixer.h
index 8417b8fef2e1..82956cb97cfd 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.h
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
@@ -151,6 +151,11 @@ enum {
CCSC_D1_MIXER0_LAYOUT,
};
+enum sun8i_mixer_type {
+ sun8i_mixer_de2,
+ sun8i_mixer_de3,
+};
+
/**
* struct sun8i_mixer_cfg - mixer HW configuration
* @vi_num: number of VI channels
@@ -172,7 +177,7 @@ struct sun8i_mixer_cfg {
int scaler_mask;
int ccsc;
unsigned long mod_rate;
- unsigned int is_de3 : 1;
+ unsigned int de_type;
unsigned int has_formatter : 1;
unsigned int scanline_yuv;
};
@@ -216,13 +221,13 @@ engine_to_sun8i_mixer(struct sunxi_engine *engine)
static inline u32
sun8i_blender_base(struct sun8i_mixer *mixer)
{
- return mixer->cfg->is_de3 ? DE3_BLD_BASE : DE2_BLD_BASE;
+ return mixer->cfg->de_type == sun8i_mixer_de3 ? DE3_BLD_BASE : DE2_BLD_BASE;
}
static inline u32
sun8i_channel_base(struct sun8i_mixer *mixer, int channel)
{
- if (mixer->cfg->is_de3)
+ if (mixer->cfg->de_type == sun8i_mixer_de3)
return DE3_CH_BASE + channel * DE3_CH_SIZE;
else
return DE2_CH_BASE + channel * DE2_CH_SIZE;
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_scaler.c b/drivers/gpu/drm/sun4i/sun8i_ui_scaler.c
index ae0806bccac7..504ffa0971a4 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_scaler.c
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_scaler.c
@@ -93,7 +93,7 @@ static u32 sun8i_ui_scaler_base(struct sun8i_mixer *mixer, int channel)
{
int vi_num = mixer->cfg->vi_num;
- if (mixer->cfg->is_de3)
+ if (mixer->cfg->de_type == sun8i_mixer_de3)
return DE3_VI_SCALER_UNIT_BASE +
DE3_VI_SCALER_UNIT_SIZE * vi_num +
DE3_UI_SCALER_UNIT_SIZE * (channel - vi_num);
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
index 3c657b069d1f..4647e9bcccaa 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
@@ -25,7 +25,7 @@ static void sun8i_vi_layer_update_alpha(struct sun8i_mixer *mixer, int channel,
ch_base = sun8i_channel_base(mixer, channel);
- if (mixer->cfg->is_de3) {
+ if (mixer->cfg->de_type >= sun8i_mixer_de3) {
mask = SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA_MASK |
SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA_MODE_MASK;
val = SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA
@@ -483,7 +483,7 @@ struct sun8i_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
layer->channel = index;
layer->overlay = 0;
- if (mixer->cfg->is_de3) {
+ if (mixer->cfg->de_type >= sun8i_mixer_de3) {
formats = sun8i_vi_layer_de3_formats;
format_count = ARRAY_SIZE(sun8i_vi_layer_de3_formats);
} else {
@@ -507,7 +507,7 @@ struct sun8i_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
plane_cnt = mixer->cfg->ui_num + mixer->cfg->vi_num;
- if (mixer->cfg->vi_num == 1 || mixer->cfg->is_de3) {
+ if (mixer->cfg->vi_num == 1 || mixer->cfg->de_type >= sun8i_mixer_de3) {
ret = drm_plane_create_alpha_property(&layer->plane);
if (ret) {
dev_err(drm->dev, "Couldn't add alpha property\n");
@@ -524,7 +524,7 @@ struct sun8i_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
supported_encodings = BIT(DRM_COLOR_YCBCR_BT601) |
BIT(DRM_COLOR_YCBCR_BT709);
- if (mixer->cfg->is_de3)
+ if (mixer->cfg->de_type >= sun8i_mixer_de3)
supported_encodings |= BIT(DRM_COLOR_YCBCR_BT2020);
supported_ranges = BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
index 2e49a6e5f1f1..aa346c3beb30 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
@@ -835,7 +835,7 @@ static const u32 bicubic4coefftab32[480] = {
static u32 sun8i_vi_scaler_base(struct sun8i_mixer *mixer, int channel)
{
- if (mixer->cfg->is_de3)
+ if (mixer->cfg->de_type == sun8i_mixer_de3)
return DE3_VI_SCALER_UNIT_BASE +
DE3_VI_SCALER_UNIT_SIZE * channel;
else
@@ -982,7 +982,7 @@ void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,
cvphase = vphase;
}
- if (mixer->cfg->is_de3) {
+ if (mixer->cfg->de_type >= sun8i_mixer_de3) {
u32 val;
if (format->hsub == 1 && format->vsub == 1)
--
2.35.3

View File

@ -0,0 +1,64 @@
From 000c586a34ad82e4673e6dfda5457147b0d85606 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Date: Sun, 29 Sep 2024 22:04:35 +1300
Subject: drm: sun4i: de2/de3: call csc setup also for UI layer
Currently, only VI layer calls CSC setup function. This comes from DE2
limitation, which doesn't have CSC unit for UI layers. However, DE3 has
separate CSC units for each layer. This allows display pipeline to make
output signal in different color spaces. To support both use cases, add
a call to CSC setup function also in UI layer code. For DE2, this will
be a no-op, but it will allow DE3 to output signal in multiple formats.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Signed-off-by: Ryan Walklin <ryan@testtoast.com>
---
drivers/gpu/drm/sun4i/sun8i_csc.c | 8 +++++---
drivers/gpu/drm/sun4i/sun8i_ui_layer.c | 6 ++++++
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c b/drivers/gpu/drm/sun4i/sun8i_csc.c
index 0dcbc0866ae8..68d955c63b05 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -209,8 +209,10 @@ void sun8i_csc_set_ccsc(struct sun8i_mixer *mixer, int layer,
return;
}
- base = ccsc_base[mixer->cfg->ccsc][layer];
+ if (layer < mixer->cfg->vi_num) {
+ base = ccsc_base[mixer->cfg->ccsc][layer];
- sun8i_csc_setup(mixer->engine.regs, base,
- fmt_type, encoding, range);
+ sun8i_csc_setup(mixer->engine.regs, base,
+ fmt_type, encoding, range);
+ }
}
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
index b90e5edef4e8..aa987bca1dbb 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
@@ -20,6 +20,7 @@
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_probe_helper.h>
+#include "sun8i_csc.h"
#include "sun8i_mixer.h"
#include "sun8i_ui_layer.h"
#include "sun8i_ui_scaler.h"
@@ -135,6 +136,11 @@ static int sun8i_ui_layer_update_formats(struct sun8i_mixer *mixer, int channel,
SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, overlay),
SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK, val);
+ /* Note: encoding and range arguments are ignored for RGB */
+ sun8i_csc_set_ccsc(mixer, channel, FORMAT_TYPE_RGB,
+ DRM_COLOR_YCBCR_BT601,
+ DRM_COLOR_YCBCR_FULL_RANGE);
+
return 0;
}
--
2.35.3

View File

@ -0,0 +1,121 @@
From 18890b5c9dbf9270b7f0e42875d6b8bd14ee6624 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Date: Sun, 29 Sep 2024 22:04:46 +1300
Subject: drm: sun4i: de2/de3: refactor mixer initialisation
Now that the DE variant can be selected by enum, take the oppportunity
to factor out some common initialisation code to a separate function.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Signed-off-by: Ryan Walklin <ryan@testtoast.com>
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
---
drivers/gpu/drm/sun4i/sun8i_mixer.c | 64 +++++++++++++++--------------
1 file changed, 34 insertions(+), 30 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index 16e018aa4aae..18745af08954 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -468,6 +468,38 @@ static int sun8i_mixer_of_get_id(struct device_node *node)
return of_ep.id;
}
+static void sun8i_mixer_init(struct sun8i_mixer *mixer)
+{
+ unsigned int base = sun8i_blender_base(mixer);
+ int plane_cnt, i;
+
+ /* Enable the mixer */
+ regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_CTL,
+ SUN8I_MIXER_GLOBAL_CTL_RT_EN);
+
+ /* Set background color to black */
+ regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_BKCOLOR(base),
+ SUN8I_MIXER_BLEND_COLOR_BLACK);
+
+ /*
+ * Set fill color of bottom plane to black. Generally not needed
+ * except when VI plane is at bottom (zpos = 0) and enabled.
+ */
+ regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
+ SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
+ regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(base, 0),
+ SUN8I_MIXER_BLEND_COLOR_BLACK);
+
+ plane_cnt = mixer->cfg->vi_num + mixer->cfg->ui_num;
+ for (i = 0; i < plane_cnt; i++)
+ regmap_write(mixer->engine.regs,
+ SUN8I_MIXER_BLEND_MODE(base, i),
+ SUN8I_MIXER_BLEND_MODE_DEF);
+
+ regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
+ SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0);
+}
+
static int sun8i_mixer_bind(struct device *dev, struct device *master,
void *data)
{
@@ -476,8 +508,6 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
struct sun4i_drv *drv = drm->dev_private;
struct sun8i_mixer *mixer;
void __iomem *regs;
- unsigned int base;
- int plane_cnt;
int i, ret;
/*
@@ -581,8 +611,6 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
list_add_tail(&mixer->engine.list, &drv->engine_list);
- base = sun8i_blender_base(mixer);
-
/* Reset registers and disable unused sub-engines */
if (mixer->cfg->de_type == sun8i_mixer_de3) {
for (i = 0; i < DE3_MIXER_UNIT_SIZE; i += 4)
@@ -598,7 +626,7 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
regmap_write(mixer->engine.regs, SUN50I_MIXER_FMT_EN, 0);
regmap_write(mixer->engine.regs, SUN50I_MIXER_CDC0_EN, 0);
regmap_write(mixer->engine.regs, SUN50I_MIXER_CDC1_EN, 0);
- } else {
+ } else if (mixer->cfg->de_type == sun8i_mixer_de2) {
for (i = 0; i < DE2_MIXER_UNIT_SIZE; i += 4)
regmap_write(mixer->engine.regs, i, 0);
@@ -611,31 +639,7 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
regmap_write(mixer->engine.regs, SUN8I_MIXER_DCSC_EN, 0);
}
- /* Enable the mixer */
- regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_CTL,
- SUN8I_MIXER_GLOBAL_CTL_RT_EN);
-
- /* Set background color to black */
- regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_BKCOLOR(base),
- SUN8I_MIXER_BLEND_COLOR_BLACK);
-
- /*
- * Set fill color of bottom plane to black. Generally not needed
- * except when VI plane is at bottom (zpos = 0) and enabled.
- */
- regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
- SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
- regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(base, 0),
- SUN8I_MIXER_BLEND_COLOR_BLACK);
-
- plane_cnt = mixer->cfg->vi_num + mixer->cfg->ui_num;
- for (i = 0; i < plane_cnt; i++)
- regmap_write(mixer->engine.regs,
- SUN8I_MIXER_BLEND_MODE(base, i),
- SUN8I_MIXER_BLEND_MODE_DEF);
-
- regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
- SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0);
+ sun8i_mixer_init(mixer);
return 0;
--
2.35.3

View File

@ -0,0 +1,117 @@
From a756d6b4ac645ac3c18d5758faec068b3c8819a6 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Date: Sun, 29 Sep 2024 22:04:49 +1300
Subject: drm: sun4i: de2/de3: use generic register reference function for
layer configuration
Use the new blender register lookup function where required in the layer
commit and update code.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Signed-off-by: Ryan Walklin <ryan@testtoast.com>
---
drivers/gpu/drm/sun4i/sun8i_mixer.c | 5 +++--
drivers/gpu/drm/sun4i/sun8i_ui_layer.c | 7 +++++--
drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 6 ++++--
3 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index 18745af08954..600084286b39 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -277,6 +277,7 @@ static void sun8i_mixer_commit(struct sunxi_engine *engine,
{
struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
u32 bld_base = sun8i_blender_base(mixer);
+ struct regmap *bld_regs = sun8i_blender_regmap(mixer);
struct drm_plane_state *plane_state;
struct drm_plane *plane;
u32 route = 0, pipe_en = 0;
@@ -316,8 +317,8 @@ static void sun8i_mixer_commit(struct sunxi_engine *engine,
pipe_en |= SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos);
}
- regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ROUTE(bld_base), route);
- regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
+ regmap_write(bld_regs, SUN8I_MIXER_BLEND_ROUTE(bld_base), route);
+ regmap_write(bld_regs, SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
pipe_en | SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF,
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
index cb9b694fef10..7f1231cf0f01 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
@@ -24,6 +24,7 @@
#include "sun8i_mixer.h"
#include "sun8i_ui_layer.h"
#include "sun8i_ui_scaler.h"
+#include "sun8i_vi_scaler.h"
static void sun8i_ui_layer_update_alpha(struct sun8i_mixer *mixer, int channel,
int overlay, struct drm_plane *plane)
@@ -52,6 +53,7 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel,
{
struct drm_plane_state *state = plane->state;
u32 src_w, src_h, dst_w, dst_h;
+ struct regmap *bld_regs;
u32 bld_base, ch_base;
u32 outsize, insize;
u32 hphase, vphase;
@@ -60,6 +62,7 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel,
channel, overlay);
bld_base = sun8i_blender_base(mixer);
+ bld_regs = sun8i_blender_regmap(mixer);
ch_base = sun8i_channel_base(mixer, channel);
src_w = drm_rect_width(&state->src) >> 16;
@@ -104,10 +107,10 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel,
DRM_DEBUG_DRIVER("Layer destination coordinates X: %d Y: %d\n",
state->dst.x1, state->dst.y1);
DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h);
- regmap_write(mixer->engine.regs,
+ regmap_write(bld_regs,
SUN8I_MIXER_BLEND_ATTR_COORD(bld_base, zpos),
SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1));
- regmap_write(mixer->engine.regs,
+ regmap_write(bld_regs,
SUN8I_MIXER_BLEND_ATTR_INSIZE(bld_base, zpos),
outsize);
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
index e348fd0a3d81..d19349eecc9d 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
@@ -55,6 +55,7 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
struct drm_plane_state *state = plane->state;
const struct drm_format_info *format = state->fb->format;
u32 src_w, src_h, dst_w, dst_h;
+ struct regmap *bld_regs;
u32 bld_base, ch_base;
u32 outsize, insize;
u32 hphase, vphase;
@@ -66,6 +67,7 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
channel, overlay);
bld_base = sun8i_blender_base(mixer);
+ bld_regs = sun8i_blender_regmap(mixer);
ch_base = sun8i_channel_base(mixer, channel);
src_w = drm_rect_width(&state->src) >> 16;
@@ -182,10 +184,10 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
DRM_DEBUG_DRIVER("Layer destination coordinates X: %d Y: %d\n",
state->dst.x1, state->dst.y1);
DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h);
- regmap_write(mixer->engine.regs,
+ regmap_write(bld_regs,
SUN8I_MIXER_BLEND_ATTR_COORD(bld_base, zpos),
SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1));
- regmap_write(mixer->engine.regs,
+ regmap_write(bld_regs,
SUN8I_MIXER_BLEND_ATTR_INSIZE(bld_base, zpos),
outsize);
--
2.35.3

View File

@ -0,0 +1,164 @@
From 8bdcc131fedb576a8db65bb6e87ca8742660add0 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Date: Sun, 29 Sep 2024 22:04:37 +1300
Subject: drm: sun4i: de3: Add YUV formatter module
The display engine formatter (FMT) module is present in the DE3 engine
and provides YUV444 to YUV422/YUV420 conversion, format re-mapping and
color depth conversion.
Add support for this module.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Signed-off-by: Ryan Walklin <ryan@testtoast.com>
---
drivers/gpu/drm/sun4i/Makefile | 3 +-
drivers/gpu/drm/sun4i/sun50i_fmt.c | 82 ++++++++++++++++++++++++++++++
drivers/gpu/drm/sun4i/sun50i_fmt.h | 32 ++++++++++++
3 files changed, 116 insertions(+), 1 deletion(-)
create mode 100644 drivers/gpu/drm/sun4i/sun50i_fmt.c
create mode 100644 drivers/gpu/drm/sun4i/sun50i_fmt.h
diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
index bad7497a0d11..3f516329f51e 100644
--- a/drivers/gpu/drm/sun4i/Makefile
+++ b/drivers/gpu/drm/sun4i/Makefile
@@ -16,7 +16,8 @@ sun8i-drm-hdmi-y += sun8i_hdmi_phy_clk.o
sun8i-mixer-y += sun8i_mixer.o sun8i_ui_layer.o \
sun8i_vi_layer.o sun8i_ui_scaler.o \
- sun8i_vi_scaler.o sun8i_csc.o
+ sun8i_vi_scaler.o sun8i_csc.o \
+ sun50i_fmt.o
sun4i-tcon-y += sun4i_crtc.o
sun4i-tcon-y += sun4i_tcon_dclk.o
diff --git a/drivers/gpu/drm/sun4i/sun50i_fmt.c b/drivers/gpu/drm/sun4i/sun50i_fmt.c
new file mode 100644
index 000000000000..050a8716ae86
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun50i_fmt.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) Jernej Skrabec <jernej.skrabec@gmail.com>
+ */
+
+#include <uapi/linux/media-bus-format.h>
+
+#include "sun50i_fmt.h"
+
+static bool sun50i_fmt_is_10bit(u32 format)
+{
+ switch (format) {
+ case MEDIA_BUS_FMT_RGB101010_1X30:
+ case MEDIA_BUS_FMT_YUV10_1X30:
+ case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
+ case MEDIA_BUS_FMT_UYVY10_1X20:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static u32 sun50i_fmt_get_colorspace(u32 format)
+{
+ switch (format) {
+ case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
+ case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
+ return SUN50I_FMT_CS_YUV420;
+ case MEDIA_BUS_FMT_UYVY8_1X16:
+ case MEDIA_BUS_FMT_UYVY10_1X20:
+ return SUN50I_FMT_CS_YUV422;
+ default:
+ return SUN50I_FMT_CS_YUV444RGB;
+ }
+}
+
+static void sun50i_fmt_de3_limits(u32 *limits, u32 colorspace, bool bit10)
+{
+ if (colorspace != SUN50I_FMT_CS_YUV444RGB) {
+ limits[0] = SUN50I_FMT_LIMIT(64, 940);
+ limits[1] = SUN50I_FMT_LIMIT(64, 960);
+ limits[2] = SUN50I_FMT_LIMIT(64, 960);
+ } else if (bit10) {
+ limits[0] = SUN50I_FMT_LIMIT(0, 1023);
+ limits[1] = SUN50I_FMT_LIMIT(0, 1023);
+ limits[2] = SUN50I_FMT_LIMIT(0, 1023);
+ } else {
+ limits[0] = SUN50I_FMT_LIMIT(0, 1021);
+ limits[1] = SUN50I_FMT_LIMIT(0, 1021);
+ limits[2] = SUN50I_FMT_LIMIT(0, 1021);
+ }
+}
+
+void sun50i_fmt_setup(struct sun8i_mixer *mixer, u16 width,
+ u16 height, u32 format)
+{
+ u32 colorspace, limit[3], base;
+ struct regmap *regs;
+ bool bit10;
+
+ colorspace = sun50i_fmt_get_colorspace(format);
+ bit10 = sun50i_fmt_is_10bit(format);
+ base = SUN50I_FMT_DE3;
+ regs = sun8i_blender_regmap(mixer);
+
+ sun50i_fmt_de3_limits(limit, colorspace, bit10);
+
+ regmap_write(regs, SUN50I_FMT_CTRL(base), 0);
+
+ regmap_write(regs, SUN50I_FMT_SIZE(base),
+ SUN8I_MIXER_SIZE(width, height));
+ regmap_write(regs, SUN50I_FMT_SWAP(base), 0);
+ regmap_write(regs, SUN50I_FMT_DEPTH(base), bit10);
+ regmap_write(regs, SUN50I_FMT_FORMAT(base), colorspace);
+ regmap_write(regs, SUN50I_FMT_COEF(base), 0);
+
+ regmap_write(regs, SUN50I_FMT_LMT_Y(base), limit[0]);
+ regmap_write(regs, SUN50I_FMT_LMT_C0(base), limit[1]);
+ regmap_write(regs, SUN50I_FMT_LMT_C1(base), limit[2]);
+
+ regmap_write(regs, SUN50I_FMT_CTRL(base), 1);
+}
diff --git a/drivers/gpu/drm/sun4i/sun50i_fmt.h b/drivers/gpu/drm/sun4i/sun50i_fmt.h
new file mode 100644
index 000000000000..4127f7206aad
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun50i_fmt.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) Jernej Skrabec <jernej.skrabec@gmail.com>
+ */
+
+#ifndef _SUN50I_FMT_H_
+#define _SUN50I_FMT_H_
+
+#include "sun8i_mixer.h"
+
+#define SUN50I_FMT_DE3 0xa8000
+
+#define SUN50I_FMT_CTRL(base) ((base) + 0x00)
+#define SUN50I_FMT_SIZE(base) ((base) + 0x04)
+#define SUN50I_FMT_SWAP(base) ((base) + 0x08)
+#define SUN50I_FMT_DEPTH(base) ((base) + 0x0c)
+#define SUN50I_FMT_FORMAT(base) ((base) + 0x10)
+#define SUN50I_FMT_COEF(base) ((base) + 0x14)
+#define SUN50I_FMT_LMT_Y(base) ((base) + 0x20)
+#define SUN50I_FMT_LMT_C0(base) ((base) + 0x24)
+#define SUN50I_FMT_LMT_C1(base) ((base) + 0x28)
+
+#define SUN50I_FMT_LIMIT(low, high) (((high) << 16) | (low))
+
+#define SUN50I_FMT_CS_YUV444RGB 0
+#define SUN50I_FMT_CS_YUV422 1
+#define SUN50I_FMT_CS_YUV420 2
+
+void sun50i_fmt_setup(struct sun8i_mixer *mixer, u16 width,
+ u16 height, u32 format);
+
+#endif
--
2.35.3

View File

@ -0,0 +1,569 @@
From 0788787d1240dba85ecbbdb559cb46d413975656 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Date: Sun, 29 Sep 2024 22:04:50 +1300
Subject: drm: sun4i: de3: Implement AFBC support
Buffers, compressed with AFBC, are supported by the DE3 and above, and
are generally more efficient for memory transfers. Add support for them.
Currently it's implemented only for VI layers, but vendor code and
documentation suggest UI layers can have them too. However, I haven't
observed any SoC with such feature.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Signed-off-by: Ryan Walklin <ryan@testtoast.com>
---
drivers/gpu/drm/sun4i/Makefile | 2 +-
drivers/gpu/drm/sun4i/sun50i_afbc.c | 250 +++++++++++++++++++++++++
drivers/gpu/drm/sun4i/sun50i_afbc.h | 87 +++++++++
drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 84 +++++++--
4 files changed, 409 insertions(+), 14 deletions(-)
create mode 100644 drivers/gpu/drm/sun4i/sun50i_afbc.c
create mode 100644 drivers/gpu/drm/sun4i/sun50i_afbc.h
diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
index 3f516329f51e..78290f1660fb 100644
--- a/drivers/gpu/drm/sun4i/Makefile
+++ b/drivers/gpu/drm/sun4i/Makefile
@@ -17,7 +17,7 @@ sun8i-drm-hdmi-y += sun8i_hdmi_phy_clk.o
sun8i-mixer-y += sun8i_mixer.o sun8i_ui_layer.o \
sun8i_vi_layer.o sun8i_ui_scaler.o \
sun8i_vi_scaler.o sun8i_csc.o \
- sun50i_fmt.o
+ sun50i_fmt.o sun50i_afbc.o
sun4i-tcon-y += sun4i_crtc.o
sun4i-tcon-y += sun4i_tcon_dclk.o
diff --git a/drivers/gpu/drm/sun4i/sun50i_afbc.c b/drivers/gpu/drm/sun4i/sun50i_afbc.c
new file mode 100644
index 000000000000..b55e1c553371
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun50i_afbc.c
@@ -0,0 +1,250 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) Jernej Skrabec <jernej.skrabec@gmail.com>
+ */
+
+#include <drm/drm_blend.h>
+#include <drm/drm_fb_dma_helper.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_gem_dma_helper.h>
+#include <drm/drm_plane.h>
+#include <uapi/drm/drm_fourcc.h>
+
+#include "sun50i_afbc.h"
+#include "sun8i_mixer.h"
+
+static u32 sun50i_afbc_get_base(struct sun8i_mixer *mixer, unsigned int channel)
+{
+ u32 base = sun8i_channel_base(mixer, channel);
+
+ if (mixer->cfg->de_type == sun8i_mixer_de3)
+ return base + SUN50I_AFBC_CH_OFFSET;
+
+ return base + 0x4000;
+}
+
+bool sun50i_afbc_format_mod_supported(struct sun8i_mixer *mixer,
+ u32 format, u64 modifier)
+{
+ u64 mode;
+
+ if (modifier == DRM_FORMAT_MOD_INVALID)
+ return false;
+
+ if (modifier == DRM_FORMAT_MOD_LINEAR) {
+ if (format == DRM_FORMAT_YUV420_8BIT ||
+ format == DRM_FORMAT_YUV420_10BIT ||
+ format == DRM_FORMAT_Y210)
+ return false;
+ return true;
+ }
+
+ if (mixer->cfg->de_type == sun8i_mixer_de2)
+ return false;
+
+ mode = AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+ AFBC_FORMAT_MOD_SPARSE |
+ AFBC_FORMAT_MOD_SPLIT;
+
+ switch (format) {
+ case DRM_FORMAT_RGBA8888:
+ case DRM_FORMAT_RGB888:
+ case DRM_FORMAT_RGB565:
+ case DRM_FORMAT_RGBA4444:
+ case DRM_FORMAT_RGBA5551:
+ case DRM_FORMAT_RGBA1010102:
+ mode |= AFBC_FORMAT_MOD_YTR;
+ break;
+ case DRM_FORMAT_YUYV:
+ case DRM_FORMAT_Y210:
+ case DRM_FORMAT_YUV420_8BIT:
+ case DRM_FORMAT_YUV420_10BIT:
+ break;
+ default:
+ return false;
+ }
+
+ return modifier == DRM_FORMAT_MOD_ARM_AFBC(mode);
+}
+
+void sun50i_afbc_atomic_update(struct sun8i_mixer *mixer, unsigned int channel,
+ struct drm_plane *plane)
+{
+ struct drm_plane_state *state = plane->state;
+ struct drm_framebuffer *fb = state->fb;
+ const struct drm_format_info *format = fb->format;
+ struct drm_gem_dma_object *gem;
+ u32 base, val, src_w, src_h;
+ u32 def_color0, def_color1;
+ struct regmap *regs;
+ dma_addr_t dma_addr;
+
+ base = sun50i_afbc_get_base(mixer, channel);
+ regs = mixer->engine.regs;
+
+ src_w = drm_rect_width(&state->src) >> 16;
+ src_h = drm_rect_height(&state->src) >> 16;
+
+ val = SUN50I_FBD_SIZE_HEIGHT(src_h);
+ val |= SUN50I_FBD_SIZE_WIDTH(src_w);
+ regmap_write(regs, SUN50I_FBD_SIZE(base), val);
+
+ val = SUN50I_FBD_BLK_SIZE_HEIGHT(DIV_ROUND_UP(src_h, 16));
+ val = SUN50I_FBD_BLK_SIZE_WIDTH(DIV_ROUND_UP(src_w, 16));
+ regmap_write(regs, SUN50I_FBD_BLK_SIZE(base), val);
+
+ val = SUN50I_FBD_SRC_CROP_TOP(0);
+ val |= SUN50I_FBD_SRC_CROP_LEFT(0);
+ regmap_write(regs, SUN50I_FBD_SRC_CROP(base), val);
+
+ val = SUN50I_FBD_LAY_CROP_TOP(state->src.y1 >> 16);
+ val |= SUN50I_FBD_LAY_CROP_LEFT(state->src.x1 >> 16);
+ regmap_write(regs, SUN50I_FBD_LAY_CROP(base), val);
+
+ /*
+ * Default color is always set to white, in colorspace and bitness
+ * that coresponds to used format. If it is actually used or not
+ * depends on AFBC buffer. At least in Cedrus it can be turned on
+ * or off.
+ * NOTE: G and B channels are off by 1 (up). It's unclear if this
+ * is because HW need such value or it is due to good enough code
+ * in vendor driver and HW clips the value anyway.
+ */
+ def_color0 = 0;
+ def_color1 = 0;
+
+ val = 0;
+ switch (format->format) {
+ case DRM_FORMAT_YUYV:
+ case DRM_FORMAT_YUV420_10BIT:
+ val |= SUN50I_FBD_FMT_SBS1(2);
+ val |= SUN50I_FBD_FMT_SBS0(1);
+ break;
+ case DRM_FORMAT_Y210:
+ val |= SUN50I_FBD_FMT_SBS1(3);
+ val |= SUN50I_FBD_FMT_SBS0(2);
+ break;
+ default:
+ val |= SUN50I_FBD_FMT_SBS1(1);
+ val |= SUN50I_FBD_FMT_SBS0(1);
+ break;
+ }
+ switch (format->format) {
+ case DRM_FORMAT_RGBA8888:
+ val |= SUN50I_FBD_FMT_YUV_TRAN;
+ val |= SUN50I_FBD_FMT_IN_FMT(SUN50I_AFBC_RGBA_8888);
+ def_color0 = SUN50I_FBD_DEFAULT_COLOR0_ALPHA(255) |
+ SUN50I_FBD_DEFAULT_COLOR0_YR(255);
+ def_color1 = SUN50I_FBD_DEFAULT_COLOR1_UG(256) |
+ SUN50I_FBD_DEFAULT_COLOR1_VB(256);
+ break;
+ case DRM_FORMAT_RGB888:
+ val |= SUN50I_FBD_FMT_YUV_TRAN;
+ val |= SUN50I_FBD_FMT_IN_FMT(SUN50I_AFBC_RGB_888);
+ def_color0 = SUN50I_FBD_DEFAULT_COLOR0_ALPHA(0) |
+ SUN50I_FBD_DEFAULT_COLOR0_YR(255);
+ def_color1 = SUN50I_FBD_DEFAULT_COLOR1_UG(256) |
+ SUN50I_FBD_DEFAULT_COLOR1_VB(256);
+ break;
+ case DRM_FORMAT_RGB565:
+ val |= SUN50I_FBD_FMT_YUV_TRAN;
+ val |= SUN50I_FBD_FMT_IN_FMT(SUN50I_AFBC_RGB_565);
+ def_color0 = SUN50I_FBD_DEFAULT_COLOR0_ALPHA(0) |
+ SUN50I_FBD_DEFAULT_COLOR0_YR(31);
+ def_color1 = SUN50I_FBD_DEFAULT_COLOR1_UG(64) |
+ SUN50I_FBD_DEFAULT_COLOR1_VB(32);
+ break;
+ case DRM_FORMAT_RGBA4444:
+ val |= SUN50I_FBD_FMT_YUV_TRAN;
+ val |= SUN50I_FBD_FMT_IN_FMT(SUN50I_AFBC_RGBA_4444);
+ def_color0 = SUN50I_FBD_DEFAULT_COLOR0_ALPHA(15) |
+ SUN50I_FBD_DEFAULT_COLOR0_YR(15);
+ def_color1 = SUN50I_FBD_DEFAULT_COLOR1_UG(16) |
+ SUN50I_FBD_DEFAULT_COLOR1_VB(16);
+ break;
+ case DRM_FORMAT_RGBA5551:
+ val |= SUN50I_FBD_FMT_YUV_TRAN;
+ val |= SUN50I_FBD_FMT_IN_FMT(SUN50I_AFBC_RGBA_5551);
+ def_color0 = SUN50I_FBD_DEFAULT_COLOR0_ALPHA(1) |
+ SUN50I_FBD_DEFAULT_COLOR0_YR(31);
+ def_color1 = SUN50I_FBD_DEFAULT_COLOR1_UG(32) |
+ SUN50I_FBD_DEFAULT_COLOR1_VB(32);
+ break;
+ case DRM_FORMAT_RGBA1010102:
+ val |= SUN50I_FBD_FMT_YUV_TRAN;
+ val |= SUN50I_FBD_FMT_IN_FMT(SUN50I_AFBC_RGBA1010102);
+ def_color0 = SUN50I_FBD_DEFAULT_COLOR0_ALPHA(3) |
+ SUN50I_FBD_DEFAULT_COLOR0_YR(1023);
+ def_color1 = SUN50I_FBD_DEFAULT_COLOR1_UG(1024) |
+ SUN50I_FBD_DEFAULT_COLOR1_VB(1024);
+ break;
+ case DRM_FORMAT_YUV420_8BIT:
+ val |= SUN50I_FBD_FMT_IN_FMT(SUN50I_AFBC_YUV420);
+ def_color0 = SUN50I_FBD_DEFAULT_COLOR0_ALPHA(0) |
+ SUN50I_FBD_DEFAULT_COLOR0_YR(255);
+ def_color1 = SUN50I_FBD_DEFAULT_COLOR1_UG(128) |
+ SUN50I_FBD_DEFAULT_COLOR1_VB(128);
+ break;
+ case DRM_FORMAT_YUYV:
+ val |= SUN50I_FBD_FMT_IN_FMT(SUN50I_AFBC_YUV422);
+ def_color0 = SUN50I_FBD_DEFAULT_COLOR0_ALPHA(0) |
+ SUN50I_FBD_DEFAULT_COLOR0_YR(255);
+ def_color1 = SUN50I_FBD_DEFAULT_COLOR1_UG(128) |
+ SUN50I_FBD_DEFAULT_COLOR1_VB(128);
+ break;
+ case DRM_FORMAT_YUV420_10BIT:
+ val |= SUN50I_FBD_FMT_IN_FMT(SUN50I_AFBC_P010);
+ def_color0 = SUN50I_FBD_DEFAULT_COLOR0_ALPHA(0) |
+ SUN50I_FBD_DEFAULT_COLOR0_YR(1023);
+ def_color1 = SUN50I_FBD_DEFAULT_COLOR1_UG(512) |
+ SUN50I_FBD_DEFAULT_COLOR1_VB(512);
+ break;
+ case DRM_FORMAT_Y210:
+ val |= SUN50I_FBD_FMT_IN_FMT(SUN50I_AFBC_P210);
+ def_color0 = SUN50I_FBD_DEFAULT_COLOR0_ALPHA(0) |
+ SUN50I_FBD_DEFAULT_COLOR0_YR(1023);
+ def_color1 = SUN50I_FBD_DEFAULT_COLOR1_UG(512) |
+ SUN50I_FBD_DEFAULT_COLOR1_VB(512);
+ break;
+ }
+ regmap_write(regs, SUN50I_FBD_FMT(base), val);
+
+ /* Get the physical address of the buffer in memory */
+ gem = drm_fb_dma_get_gem_obj(fb, 0);
+
+ DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->dma_addr);
+
+ /* Compute the start of the displayed memory */
+ dma_addr = gem->dma_addr + fb->offsets[0];
+
+ regmap_write(regs, SUN50I_FBD_LADDR(base), lower_32_bits(dma_addr));
+ regmap_write(regs, SUN50I_FBD_HADDR(base), upper_32_bits(dma_addr));
+
+ val = SUN50I_FBD_OVL_SIZE_HEIGHT(src_h);
+ val |= SUN50I_FBD_OVL_SIZE_WIDTH(src_w);
+ regmap_write(regs, SUN50I_FBD_OVL_SIZE(base), val);
+
+ val = SUN50I_FBD_OVL_COOR_Y(0);
+ val |= SUN50I_FBD_OVL_COOR_X(0);
+ regmap_write(regs, SUN50I_FBD_OVL_COOR(base), val);
+
+ regmap_write(regs, SUN50I_FBD_OVL_BG_COLOR(base),
+ SUN8I_MIXER_BLEND_COLOR_BLACK);
+ regmap_write(regs, SUN50I_FBD_DEFAULT_COLOR0(base), def_color0);
+ regmap_write(regs, SUN50I_FBD_DEFAULT_COLOR1(base), def_color1);
+
+ val = SUN50I_FBD_CTL_GLB_ALPHA(state->alpha >> 16);
+ val |= SUN50I_FBD_CTL_CLK_GATE;
+ val |= (state->alpha == DRM_BLEND_ALPHA_OPAQUE) ?
+ SUN50I_FBD_CTL_ALPHA_MODE_PIXEL :
+ SUN50I_FBD_CTL_ALPHA_MODE_COMBINED;
+ val |= SUN50I_FBD_CTL_FBD_EN;
+ regmap_write(regs, SUN50I_FBD_CTL(base), val);
+}
+
+void sun50i_afbc_disable(struct sun8i_mixer *mixer, unsigned int channel)
+{
+ u32 base = sun50i_afbc_get_base(mixer, channel);
+
+ regmap_write(mixer->engine.regs, SUN50I_FBD_CTL(base), 0);
+}
diff --git a/drivers/gpu/drm/sun4i/sun50i_afbc.h b/drivers/gpu/drm/sun4i/sun50i_afbc.h
new file mode 100644
index 000000000000..cea685c86855
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun50i_afbc.h
@@ -0,0 +1,87 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) Jernej Skrabec <jernej.skrabec@gmail.com>
+ */
+
+#ifndef _SUN50I_AFBC_H_
+#define _SUN50I_AFBC_H_
+
+#include <linux/types.h>
+
+#define SUN50I_AFBC_CH_OFFSET 0x300
+
+#define SUN50I_AFBC_RGBA_8888 0x02
+#define SUN50I_AFBC_RGB_888 0x08
+#define SUN50I_AFBC_RGB_565 0x0a
+#define SUN50I_AFBC_RGBA_4444 0x0e
+#define SUN50I_AFBC_RGBA_5551 0x12
+#define SUN50I_AFBC_RGBA1010102 0x16
+#define SUN50I_AFBC_YUV422 0x26
+#define SUN50I_AFBC_YUV420 0x2a
+#define SUN50I_AFBC_P010 0x30
+#define SUN50I_AFBC_P210 0x32
+
+#define SUN50I_FBD_CTL(base) ((base) + 0x00)
+#define SUN50I_FBD_CTL_GLB_ALPHA(v) ((v) << 24)
+#define SUN50I_FBD_CTL_CLK_GATE BIT(4)
+#define SUN50I_FBD_CTL_ALPHA_MODE_PIXEL ((0) << 2)
+#define SUN50I_FBD_CTL_ALPHA_MODE_LAYER ((1) << 2)
+#define SUN50I_FBD_CTL_ALPHA_MODE_COMBINED ((2) << 2)
+#define SUN50I_FBD_CTL_FBD_FCEN BIT(1)
+#define SUN50I_FBD_CTL_FBD_EN BIT(0)
+
+#define SUN50I_FBD_SIZE(base) ((base) + 0x08)
+#define SUN50I_FBD_SIZE_HEIGHT(v) (((v) - 1) << 16)
+#define SUN50I_FBD_SIZE_WIDTH(v) (((v) - 1) << 0)
+
+#define SUN50I_FBD_BLK_SIZE(base) ((base) + 0x0c)
+#define SUN50I_FBD_BLK_SIZE_HEIGHT(v) ((v) << 16)
+#define SUN50I_FBD_BLK_SIZE_WIDTH(v) ((v) << 0)
+
+#define SUN50I_FBD_SRC_CROP(base) ((base) + 0x10)
+#define SUN50I_FBD_SRC_CROP_TOP(v) ((v) << 16)
+#define SUN50I_FBD_SRC_CROP_LEFT(v) ((v) << 0)
+
+#define SUN50I_FBD_LAY_CROP(base) ((base) + 0x14)
+#define SUN50I_FBD_LAY_CROP_TOP(v) ((v) << 16)
+#define SUN50I_FBD_LAY_CROP_LEFT(v) ((v) << 0)
+
+#define SUN50I_FBD_FMT(base) ((base) + 0x18)
+#define SUN50I_FBD_FMT_SBS1(v) ((v) << 18)
+#define SUN50I_FBD_FMT_SBS0(v) ((v) << 16)
+#define SUN50I_FBD_FMT_YUV_TRAN BIT(7)
+#define SUN50I_FBD_FMT_IN_FMT(v) ((v) << 0)
+
+#define SUN50I_FBD_LADDR(base) ((base) + 0x20)
+#define SUN50I_FBD_HADDR(base) ((base) + 0x24)
+
+#define SUN50I_FBD_OVL_SIZE(base) ((base) + 0x30)
+#define SUN50I_FBD_OVL_SIZE_HEIGHT(v) (((v) - 1) << 16)
+#define SUN50I_FBD_OVL_SIZE_WIDTH(v) (((v) - 1) << 0)
+
+#define SUN50I_FBD_OVL_COOR(base) ((base) + 0x34)
+#define SUN50I_FBD_OVL_COOR_Y(v) ((v) << 16)
+#define SUN50I_FBD_OVL_COOR_X(v) ((v) << 0)
+
+#define SUN50I_FBD_OVL_BG_COLOR(base) ((base) + 0x38)
+#define SUN50I_FBD_OVL_FILL_COLOR(base) ((base) + 0x3c)
+
+#define SUN50I_FBD_DEFAULT_COLOR0(base) ((base) + 0x50)
+#define SUN50I_FBD_DEFAULT_COLOR0_ALPHA(v) ((v) << 16)
+#define SUN50I_FBD_DEFAULT_COLOR0_YR(v) ((v) << 0)
+
+#define SUN50I_FBD_DEFAULT_COLOR1(base) ((base) + 0x54)
+#define SUN50I_FBD_DEFAULT_COLOR1_VB(v) ((v) << 16)
+#define SUN50I_FBD_DEFAULT_COLOR1_UG(v) ((v) << 0)
+
+struct sun8i_mixer;
+struct drm_plane;
+
+bool sun50i_afbc_format_mod_supported(struct sun8i_mixer *mixer,
+ u32 format, u64 modifier);
+
+void sun50i_afbc_atomic_update(struct sun8i_mixer *mixer, unsigned int channel,
+ struct drm_plane *plane);
+void sun50i_afbc_disable(struct sun8i_mixer *mixer, unsigned int channel);
+
+#endif
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
index d19349eecc9d..84f8917e2dd8 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
@@ -11,8 +11,10 @@
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_gem_dma_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_probe_helper.h>
+#include "sun50i_afbc.h"
#include "sun8i_csc.h"
#include "sun8i_mixer.h"
#include "sun8i_vi_layer.h"
@@ -50,7 +52,7 @@ static void sun8i_vi_layer_update_alpha(struct sun8i_mixer *mixer, int channel,
static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
int overlay, struct drm_plane *plane,
- unsigned int zpos)
+ unsigned int zpos, bool afbc)
{
struct drm_plane_state *state = plane->state;
const struct drm_format_info *format = state->fb->format;
@@ -135,7 +137,7 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
required = src_h * 100 / dst_h;
- if (ability < required) {
+ if (!afbc && ability < required) {
DRM_DEBUG_DRIVER("Using vertical coarse scaling\n");
vm = src_h;
vn = (u32)ability * dst_h / 100;
@@ -145,7 +147,7 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
/* it seems that every RGB scaler has buffer for 2048 pixels */
scanline = subsampled ? mixer->cfg->scanline_yuv : 2048;
- if (src_w > scanline) {
+ if (!afbc && src_w > scanline) {
DRM_DEBUG_DRIVER("Using horizontal coarse scaling\n");
hm = src_w;
hn = scanline;
@@ -308,6 +310,15 @@ static int sun8i_vi_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
return 0;
}
+static void sun8i_vi_layer_prepare_non_linear(struct sun8i_mixer *mixer,
+ int channel, int overlay)
+{
+ u32 base = sun8i_channel_base(mixer, channel);
+
+ regmap_write(mixer->engine.regs,
+ SUN8I_MIXER_CHAN_VI_LAYER_ATTR(base, overlay), 0);
+}
+
static int sun8i_vi_layer_atomic_check(struct drm_plane *plane,
struct drm_atomic_state *state)
{
@@ -348,18 +359,45 @@ static void sun8i_vi_layer_atomic_update(struct drm_plane *plane,
struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
unsigned int zpos = new_state->normalized_zpos;
struct sun8i_mixer *mixer = layer->mixer;
+ struct drm_framebuffer *fb = plane->state->fb;
+ bool afbc = drm_is_afbc(fb->modifier);
- if (!new_state->crtc || !new_state->visible)
+ if (!new_state->crtc || !new_state->visible) {
+ if (mixer->cfg->de_type >= sun8i_mixer_de3)
+ sun50i_afbc_disable(mixer, layer->channel);
return;
+ }
sun8i_vi_layer_update_coord(mixer, layer->channel,
- layer->overlay, plane, zpos);
- sun8i_vi_layer_update_alpha(mixer, layer->channel,
- layer->overlay, plane);
- sun8i_vi_layer_update_formats(mixer, layer->channel,
- layer->overlay, plane);
- sun8i_vi_layer_update_buffer(mixer, layer->channel,
- layer->overlay, plane);
+ layer->overlay, plane, zpos, afbc);
+
+ if (afbc) {
+ u32 fmt_type;
+
+ sun8i_vi_layer_prepare_non_linear(mixer, layer->channel,
+ layer->overlay);
+ sun50i_afbc_atomic_update(mixer, layer->channel, plane);
+
+ fmt_type = sun8i_vi_layer_get_format_type(fb->format);
+ sun8i_csc_set_ccsc(mixer, layer->channel, fmt_type,
+ plane->state->color_encoding,
+ plane->state->color_range);
+ } else {
+ sun8i_vi_layer_update_alpha(mixer, layer->channel,
+ layer->overlay, plane);
+ sun8i_vi_layer_update_formats(mixer, layer->channel,
+ layer->overlay, plane);
+ sun8i_vi_layer_update_buffer(mixer, layer->channel,
+ layer->overlay, plane);
+ }
+}
+
+static bool sun8i_vi_layer_format_mod_supported(struct drm_plane *plane,
+ u32 format, u64 modifier)
+{
+ struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
+
+ return sun50i_afbc_format_mod_supported(layer->mixer, format, modifier);
}
static const struct drm_plane_helper_funcs sun8i_vi_layer_helper_funcs = {
@@ -374,6 +412,7 @@ static const struct drm_plane_funcs sun8i_vi_layer_funcs = {
.disable_plane = drm_atomic_helper_disable_plane,
.reset = drm_atomic_helper_plane_reset,
.update_plane = drm_atomic_helper_update_plane,
+ .format_mod_supported = sun8i_vi_layer_format_mod_supported,
};
/*
@@ -457,6 +496,11 @@ static const u32 sun8i_vi_layer_de3_formats[] = {
DRM_FORMAT_YVU411,
DRM_FORMAT_YVU420,
DRM_FORMAT_YVU422,
+
+ /* AFBC only formats */
+ DRM_FORMAT_YUV420_8BIT,
+ DRM_FORMAT_YUV420_10BIT,
+ DRM_FORMAT_Y210,
};
static const uint64_t sun8i_layer_modifiers[] = {
@@ -464,6 +508,18 @@ static const uint64_t sun8i_layer_modifiers[] = {
DRM_FORMAT_MOD_INVALID
};
+static const uint64_t sun50i_layer_de3_modifiers[] = {
+ DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+ AFBC_FORMAT_MOD_SPARSE |
+ AFBC_FORMAT_MOD_SPLIT),
+ DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+ AFBC_FORMAT_MOD_YTR |
+ AFBC_FORMAT_MOD_SPARSE |
+ AFBC_FORMAT_MOD_SPLIT),
+ DRM_FORMAT_MOD_LINEAR,
+ DRM_FORMAT_MOD_INVALID
+};
+
struct sun8i_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
struct sun8i_mixer *mixer,
int index)
@@ -472,6 +528,7 @@ struct sun8i_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
u32 supported_encodings, supported_ranges;
unsigned int plane_cnt, format_count;
struct sun8i_layer *layer;
+ const uint64_t *modifiers;
const u32 *formats;
int ret;
@@ -487,9 +544,11 @@ struct sun8i_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
if (mixer->cfg->de_type >= sun8i_mixer_de3) {
formats = sun8i_vi_layer_de3_formats;
format_count = ARRAY_SIZE(sun8i_vi_layer_de3_formats);
+ modifiers = sun50i_layer_de3_modifiers;
} else {
formats = sun8i_vi_layer_formats;
format_count = ARRAY_SIZE(sun8i_vi_layer_formats);
+ modifiers = sun8i_layer_modifiers;
}
if (!mixer->cfg->ui_num && index == 0)
@@ -499,8 +558,7 @@ struct sun8i_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
ret = drm_universal_plane_init(drm, &layer->plane, 0,
&sun8i_vi_layer_funcs,
formats, format_count,
- sun8i_layer_modifiers,
- type, NULL);
+ modifiers, type, NULL);
if (ret) {
dev_err(drm->dev, "Couldn't initialize layer\n");
return ERR_PTR(ret);
--
2.35.3

View File

@ -0,0 +1,126 @@
From 3b6462ebad249f4762acfd8e262442bb0cda95b4 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Date: Sun, 29 Sep 2024 22:04:40 +1300
Subject: drm: sun4i: de3: add YUV support to the DE3 mixer
The mixer in the DE3 display engine supports YUV 8 and 10 bit
formats in addition to 8-bit RGB. Add the required register
configuration and format enumeration callback functions to the mixer,
and store the in-use output format (defaulting to RGB) and color
encoding in engine variables.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Signed-off-by: Ryan Walklin <ryan@testtoast.com>
---
drivers/gpu/drm/sun4i/sun8i_mixer.c | 53 ++++++++++++++++++++++++++--
drivers/gpu/drm/sun4i/sunxi_engine.h | 5 +++
2 files changed, 55 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index 252827715de1..a50c583852ed 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -23,7 +23,10 @@
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_probe_helper.h>
+#include <uapi/linux/media-bus-format.h>
+
#include "sun4i_drv.h"
+#include "sun50i_fmt.h"
#include "sun8i_mixer.h"
#include "sun8i_ui_layer.h"
#include "sun8i_vi_layer.h"
@@ -390,12 +393,52 @@ static void sun8i_mixer_mode_set(struct sunxi_engine *engine,
DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
interlaced ? "on" : "off");
+
+ if (engine->format == MEDIA_BUS_FMT_RGB888_1X24)
+ val = SUN8I_MIXER_BLEND_COLOR_BLACK;
+ else
+ val = 0xff108080;
+
+ regmap_write(mixer->engine.regs,
+ SUN8I_MIXER_BLEND_BKCOLOR(bld_base), val);
+ regmap_write(mixer->engine.regs,
+ SUN8I_MIXER_BLEND_ATTR_FCOLOR(bld_base, 0), val);
+
+ if (mixer->cfg->has_formatter)
+ sun50i_fmt_setup(mixer, mode->hdisplay,
+ mode->vdisplay, mixer->engine.format);
+}
+
+static u32 *sun8i_mixer_get_supported_fmts(struct sunxi_engine *engine, u32 *num)
+{
+ struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
+ u32 *formats, count;
+
+ count = 0;
+
+ formats = kcalloc(5, sizeof(*formats), GFP_KERNEL);
+ if (!formats)
+ return NULL;
+
+ if (mixer->cfg->has_formatter) {
+ formats[count++] = MEDIA_BUS_FMT_UYYVYY10_0_5X30;
+ formats[count++] = MEDIA_BUS_FMT_YUV8_1X24;
+ formats[count++] = MEDIA_BUS_FMT_UYVY8_1X16;
+ formats[count++] = MEDIA_BUS_FMT_UYYVYY8_0_5X24;
+ }
+
+ formats[count++] = MEDIA_BUS_FMT_RGB888_1X24;
+
+ *num = count;
+
+ return formats;
}
static const struct sunxi_engine_ops sun8i_engine_ops = {
- .commit = sun8i_mixer_commit,
- .layers_init = sun8i_layers_init,
- .mode_set = sun8i_mixer_mode_set,
+ .commit = sun8i_mixer_commit,
+ .layers_init = sun8i_layers_init,
+ .mode_set = sun8i_mixer_mode_set,
+ .get_supported_fmts = sun8i_mixer_get_supported_fmts,
};
static const struct regmap_config sun8i_mixer_regmap_config = {
@@ -456,6 +499,10 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
dev_set_drvdata(dev, mixer);
mixer->engine.ops = &sun8i_engine_ops;
mixer->engine.node = dev->of_node;
+ /* default output format, supported by all mixers */
+ mixer->engine.format = MEDIA_BUS_FMT_RGB888_1X24;
+ /* default color encoding, ignored with RGB I/O */
+ mixer->engine.encoding = DRM_COLOR_YCBCR_BT601;
if (of_property_present(dev->of_node, "iommus")) {
/*
diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h b/drivers/gpu/drm/sun4i/sunxi_engine.h
index c48cbc1aceb8..ffafc29b3a0c 100644
--- a/drivers/gpu/drm/sun4i/sunxi_engine.h
+++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
@@ -6,6 +6,8 @@
#ifndef _SUNXI_ENGINE_H_
#define _SUNXI_ENGINE_H_
+#include <drm/drm_color_mgmt.h>
+
struct drm_plane;
struct drm_crtc;
struct drm_device;
@@ -151,6 +153,9 @@ struct sunxi_engine {
int id;
+ u32 format;
+ enum drm_color_encoding encoding;
+
/* Engine list management */
struct list_head list;
};
--
2.35.3

View File

@ -0,0 +1,83 @@
From ff794822d56721795fec59dea66164cc19ba792c Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Date: Sun, 29 Sep 2024 22:04:43 +1300
Subject: drm: sun4i: de3: add YUV support to the TCON
Account for U/V channel subsampling by reducing the dot clock and
resolution with a divider in the DE3 timing controller if a YUV format
is selected.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Signed-off-by: Ryan Walklin <ryan@testtoast.com>
---
drivers/gpu/drm/sun4i/sun4i_tcon.c | 26 +++++++++++++++++++-------
1 file changed, 19 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index 3675c87461e9..af67bf2e6e09 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -649,14 +649,26 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
const struct drm_display_mode *mode)
{
- unsigned int bp, hsync, vsync, vtotal;
+ unsigned int bp, hsync, vsync, vtotal, div;
+ struct sun4i_crtc *scrtc = tcon->crtc;
+ struct sunxi_engine *engine = scrtc->engine;
u8 clk_delay;
u32 val;
WARN_ON(!tcon->quirks->has_channel_1);
+ switch (engine->format) {
+ case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
+ case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
+ div = 2;
+ break;
+ default:
+ div = 1;
+ break;
+ }
+
/* Configure the dot clock */
- clk_set_rate(tcon->sclk1, mode->crtc_clock * 1000);
+ clk_set_rate(tcon->sclk1, mode->crtc_clock * 1000 / div);
/* Adjust clock delay */
clk_delay = sun4i_tcon_get_clk_delay(mode, 1);
@@ -675,17 +687,17 @@ static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
/* Set the input resolution */
regmap_write(tcon->regs, SUN4I_TCON1_BASIC0_REG,
- SUN4I_TCON1_BASIC0_X(mode->crtc_hdisplay) |
+ SUN4I_TCON1_BASIC0_X(mode->crtc_hdisplay / div) |
SUN4I_TCON1_BASIC0_Y(mode->crtc_vdisplay));
/* Set the upscaling resolution */
regmap_write(tcon->regs, SUN4I_TCON1_BASIC1_REG,
- SUN4I_TCON1_BASIC1_X(mode->crtc_hdisplay) |
+ SUN4I_TCON1_BASIC1_X(mode->crtc_hdisplay / div) |
SUN4I_TCON1_BASIC1_Y(mode->crtc_vdisplay));
/* Set the output resolution */
regmap_write(tcon->regs, SUN4I_TCON1_BASIC2_REG,
- SUN4I_TCON1_BASIC2_X(mode->crtc_hdisplay) |
+ SUN4I_TCON1_BASIC2_X(mode->crtc_hdisplay / div) |
SUN4I_TCON1_BASIC2_Y(mode->crtc_vdisplay));
/* Set horizontal display timings */
@@ -693,8 +705,8 @@ static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n",
mode->htotal, bp);
regmap_write(tcon->regs, SUN4I_TCON1_BASIC3_REG,
- SUN4I_TCON1_BASIC3_H_TOTAL(mode->crtc_htotal) |
- SUN4I_TCON1_BASIC3_H_BACKPORCH(bp));
+ SUN4I_TCON1_BASIC3_H_TOTAL(mode->crtc_htotal / div) |
+ SUN4I_TCON1_BASIC3_H_BACKPORCH(bp / div));
bp = mode->crtc_vtotal - mode->crtc_vsync_start;
DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n",
--
2.35.3

View File

@ -0,0 +1,225 @@
From a23ed976ee720c2445791716d975f040ef576c2b Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Date: Sun, 29 Sep 2024 22:04:42 +1300
Subject: drm: sun4i: de3: add YUV support to the color space correction module
Add coefficients and support for YUV formats to the display engine
colorspace and dynamic range correction submodule.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Signed-off-by: Ryan Walklin <ryan@testtoast.com>
---
drivers/gpu/drm/sun4i/sun8i_csc.c | 164 +++++++++++++++++++++++++++++-
1 file changed, 162 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c b/drivers/gpu/drm/sun4i/sun8i_csc.c
index 8a336ccb27d3..e12a81fa9108 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -5,6 +5,8 @@
#include <drm/drm_print.h>
+#include <uapi/linux/media-bus-format.h>
+
#include "sun8i_csc.h"
#include "sun8i_mixer.h"
@@ -107,6 +109,135 @@ static const u32 yuv2rgb_de3[2][3][12] = {
},
};
+/* always convert to limited mode */
+static const u32 rgb2yuv_de3[3][12] = {
+ [DRM_COLOR_YCBCR_BT601] = {
+ 0x0000837A, 0x0001021D, 0x00003221, 0x00000040,
+ 0xFFFFB41C, 0xFFFF6B03, 0x0000E0E1, 0x00000200,
+ 0x0000E0E1, 0xFFFF43B1, 0xFFFFDB6E, 0x00000200,
+ },
+ [DRM_COLOR_YCBCR_BT709] = {
+ 0x00005D7C, 0x00013A7C, 0x00001FBF, 0x00000040,
+ 0xFFFFCC78, 0xFFFF52A7, 0x0000E0E1, 0x00000200,
+ 0x0000E0E1, 0xFFFF33BE, 0xFFFFEB61, 0x00000200,
+ },
+ [DRM_COLOR_YCBCR_BT2020] = {
+ 0x00007384, 0x00012A21, 0x00001A13, 0x00000040,
+ 0xFFFFC133, 0xFFFF5DEC, 0x0000E0E1, 0x00000200,
+ 0x0000E0E1, 0xFFFF3135, 0xFFFFEDEA, 0x00000200,
+ },
+};
+
+/* always convert to limited mode */
+static const u32 yuv2yuv_de3[2][3][3][12] = {
+ [DRM_COLOR_YCBCR_LIMITED_RANGE] = {
+ [DRM_COLOR_YCBCR_BT601] = {
+ [DRM_COLOR_YCBCR_BT601] = {
+ 0x00020000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00020000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00020000, 0x00000000,
+ },
+ [DRM_COLOR_YCBCR_BT709] = {
+ 0x00020000, 0xFFFFC4D7, 0xFFFF9589, 0xFFC00040,
+ 0x00000000, 0x0002098B, 0x00003AAF, 0xFE000200,
+ 0x00000000, 0x0000266D, 0x00020CF8, 0xFE000200,
+ },
+ [DRM_COLOR_YCBCR_BT2020] = {
+ 0x00020000, 0xFFFFBFCE, 0xFFFFC5FF, 0xFFC00040,
+ 0x00000000, 0x00020521, 0x00001F89, 0xFE000200,
+ 0x00000000, 0x00002C87, 0x00020F07, 0xFE000200,
+ },
+ },
+ [DRM_COLOR_YCBCR_BT709] = {
+ [DRM_COLOR_YCBCR_BT601] = {
+ 0x00020000, 0x000032D9, 0x00006226, 0xFFC00040,
+ 0x00000000, 0x0001FACE, 0xFFFFC759, 0xFE000200,
+ 0x00000000, 0xFFFFDAE7, 0x0001F780, 0xFE000200,
+ },
+ [DRM_COLOR_YCBCR_BT709] = {
+ 0x00020000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00020000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00020000, 0x00000000,
+ },
+ [DRM_COLOR_YCBCR_BT2020] = {
+ 0x00020000, 0xFFFFF782, 0x00003036, 0xFFC00040,
+ 0x00000000, 0x0001FD99, 0xFFFFE5CA, 0xFE000200,
+ 0x00000000, 0x000005E4, 0x0002015A, 0xFE000200,
+ },
+ },
+ [DRM_COLOR_YCBCR_BT2020] = {
+ [DRM_COLOR_YCBCR_BT601] = {
+ 0x00020000, 0x00003B03, 0x000034D2, 0xFFC00040,
+ 0x00000000, 0x0001FD8C, 0xFFFFE183, 0xFE000200,
+ 0x00000000, 0xFFFFD4F3, 0x0001F3FA, 0xFE000200,
+ },
+ [DRM_COLOR_YCBCR_BT709] = {
+ 0x00020000, 0x00000916, 0xFFFFD061, 0xFFC00040,
+ 0x00000000, 0x0002021C, 0x00001A40, 0xFE000200,
+ 0x00000000, 0xFFFFFA19, 0x0001FE5A, 0xFE000200,
+ },
+ [DRM_COLOR_YCBCR_BT2020] = {
+ 0x00020000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00020000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00020000, 0x00000000,
+ },
+ },
+ },
+ [DRM_COLOR_YCBCR_FULL_RANGE] = {
+ [DRM_COLOR_YCBCR_BT601] = {
+ [DRM_COLOR_YCBCR_BT601] = {
+ 0x0001B7B8, 0x00000000, 0x00000000, 0x00000040,
+ 0x00000000, 0x0001C1C2, 0x00000000, 0xFE000200,
+ 0x00000000, 0x00000000, 0x0001C1C2, 0xFE000200,
+ },
+ [DRM_COLOR_YCBCR_BT709] = {
+ 0x0001B7B8, 0xFFFFCC08, 0xFFFFA27B, 0x00000040,
+ 0x00000000, 0x0001CA24, 0x0000338D, 0xFE000200,
+ 0x00000000, 0x000021C1, 0x0001CD26, 0xFE000200,
+ },
+ [DRM_COLOR_YCBCR_BT2020] = {
+ 0x0001B7B8, 0xFFFFC79C, 0xFFFFCD0C, 0x00000040,
+ 0x00000000, 0x0001C643, 0x00001BB4, 0xFE000200,
+ 0x00000000, 0x0000271D, 0x0001CEF5, 0xFE000200,
+ },
+ },
+ [DRM_COLOR_YCBCR_BT709] = {
+ [DRM_COLOR_YCBCR_BT601] = {
+ 0x0001B7B8, 0x00002CAB, 0x00005638, 0x00000040,
+ 0x00000000, 0x0001BD32, 0xFFFFCE3C, 0xFE000200,
+ 0x00000000, 0xFFFFDF6A, 0x0001BA4A, 0xFE000200,
+ },
+ [DRM_COLOR_YCBCR_BT709] = {
+ 0x0001B7B8, 0x00000000, 0x00000000, 0x00000040,
+ 0x00000000, 0x0001C1C2, 0x00000000, 0xFE000200,
+ 0x00000000, 0x00000000, 0x0001C1C2, 0xFE000200,
+ },
+ [DRM_COLOR_YCBCR_BT2020] = {
+ 0x0001B7B8, 0xFFFFF88A, 0x00002A5A, 0x00000040,
+ 0x00000000, 0x0001BFA5, 0xFFFFE8FA, 0xFE000200,
+ 0x00000000, 0x0000052D, 0x0001C2F1, 0xFE000200,
+ },
+ },
+ [DRM_COLOR_YCBCR_BT2020] = {
+ [DRM_COLOR_YCBCR_BT601] = {
+ 0x0001B7B8, 0x000033D6, 0x00002E66, 0x00000040,
+ 0x00000000, 0x0001BF9A, 0xFFFFE538, 0xFE000200,
+ 0x00000000, 0xFFFFDA2F, 0x0001B732, 0xFE000200,
+ },
+ [DRM_COLOR_YCBCR_BT709] = {
+ 0x0001B7B8, 0x000007FB, 0xFFFFD62B, 0x00000040,
+ 0x00000000, 0x0001C39D, 0x0000170F, 0xFE000200,
+ 0x00000000, 0xFFFFFAD1, 0x0001C04F, 0xFE000200,
+ },
+ [DRM_COLOR_YCBCR_BT2020] = {
+ 0x0001B7B8, 0x00000000, 0x00000000, 0x00000040,
+ 0x00000000, 0x0001C1C2, 0x00000000, 0xFE000200,
+ 0x00000000, 0x00000000, 0x0001C1C2, 0xFE000200,
+ },
+ },
+ },
+};
+
static void sun8i_csc_setup(struct regmap *map, u32 base,
enum format_type fmt_type,
enum drm_color_encoding encoding,
@@ -148,12 +279,27 @@ static void sun8i_csc_setup(struct regmap *map, u32 base,
regmap_write(map, SUN8I_CSC_CTRL(base), val);
}
+static const u32 *sun8i_csc_get_de3_yuv_table(enum drm_color_encoding in_enc,
+ enum drm_color_range in_range,
+ u32 out_format,
+ enum drm_color_encoding out_enc)
+{
+ if (out_format == MEDIA_BUS_FMT_RGB888_1X24)
+ return yuv2rgb_de3[in_range][in_enc];
+
+ /* check for identity transformation */
+ if (in_range == DRM_COLOR_YCBCR_LIMITED_RANGE && out_enc == in_enc)
+ return NULL;
+
+ return yuv2yuv_de3[in_range][in_enc][out_enc];
+}
+
static void sun8i_de3_ccsc_setup(struct sunxi_engine *engine, int layer,
enum format_type fmt_type,
enum drm_color_encoding encoding,
enum drm_color_range range)
{
- u32 addr, val, mask;
+ u32 addr, val = 0, mask;
struct regmap *map;
const u32 *table;
int i;
@@ -164,14 +310,28 @@ static void sun8i_de3_ccsc_setup(struct sunxi_engine *engine, int layer,
switch (fmt_type) {
case FORMAT_TYPE_RGB:
- val = 0;
+ if (engine->format == MEDIA_BUS_FMT_RGB888_1X24)
+ break;
+ val = mask;
+ addr = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE, layer, 0);
+ regmap_bulk_write(map, addr, rgb2yuv_de3[engine->encoding], 12);
break;
case FORMAT_TYPE_YUV:
+ table = sun8i_csc_get_de3_yuv_table(encoding, range,
+ engine->format,
+ engine->encoding);
+ if (!table)
+ break;
val = mask;
addr = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE, layer, 0);
regmap_bulk_write(map, addr, table, 12);
break;
case FORMAT_TYPE_YVU:
+ table = sun8i_csc_get_de3_yuv_table(encoding, range,
+ engine->format,
+ engine->encoding);
+ if (!table)
+ table = yuv2yuv_de3[range][encoding][encoding];
val = mask;
for (i = 0; i < 12; i++) {
if ((i & 3) == 1)
--
2.35.3

View File

@ -0,0 +1,63 @@
From 99d327853acbc5d6c6d4140f004f82fcd5c40ea1 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Date: Sun, 29 Sep 2024 22:04:38 +1300
Subject: drm: sun4i: de3: add format enumeration function to engine
The DE3 display engine supports YUV formats in addition to RGB.
Add an optional format enumeration function to the engine.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Signed-off-by: Ryan Walklin <ryan@testtoast.com>
---
drivers/gpu/drm/sun4i/sunxi_engine.h | 29 ++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h b/drivers/gpu/drm/sun4i/sunxi_engine.h
index ec0c4932f15c..c48cbc1aceb8 100644
--- a/drivers/gpu/drm/sun4i/sunxi_engine.h
+++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
@@ -123,6 +123,17 @@ struct sunxi_engine_ops {
*/
void (*mode_set)(struct sunxi_engine *engine,
const struct drm_display_mode *mode);
+
+ /**
+ * @get_supported_fmts
+ *
+ * This callback is used to enumerate all supported output
+ * formats by the engine. They are used for bridge format
+ * negotiation.
+ *
+ * This function is optional.
+ */
+ u32 *(*get_supported_fmts)(struct sunxi_engine *engine, u32 *num);
};
/**
@@ -215,4 +226,22 @@ sunxi_engine_mode_set(struct sunxi_engine *engine,
if (engine->ops && engine->ops->mode_set)
engine->ops->mode_set(engine, mode);
}
+
+/**
+ * sunxi_engine_get_supported_formats - Provide array of supported formats
+ * @engine: pointer to the engine
+ * @num: pointer to variable, which will hold number of formats
+ *
+ * This list can be used for format negotiation by bridge.
+ */
+static inline u32 *
+sunxi_engine_get_supported_formats(struct sunxi_engine *engine, u32 *num)
+{
+ if (engine->ops && engine->ops->get_supported_fmts)
+ return engine->ops->get_supported_fmts(engine, num);
+
+ *num = 0;
+
+ return NULL;
+}
#endif /* _SUNXI_ENGINE_H_ */
--
2.35.3

View File

@ -0,0 +1,53 @@
From f9a39553dcf5e87eba968d2aac4f5acf52baa392 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Date: Sun, 29 Sep 2024 22:04:39 +1300
Subject: drm: sun4i: de3: add formatter flag to mixer config
Only the DE3 (and newer) display engines have a formatter module. This
could be inferred from the is_de3 flag alone, however this will not
scale with addition of future DE versions in subsequent patches.
Add a separate flag to signal this in the mixer configuration.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Signed-off-by: Ryan Walklin <ryan@testtoast.com>
---
drivers/gpu/drm/sun4i/sun8i_mixer.c | 1 +
drivers/gpu/drm/sun4i/sun8i_mixer.h | 2 ++
2 files changed, 3 insertions(+)
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index bd0fe2c6624e..252827715de1 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -717,6 +717,7 @@ static const struct sun8i_mixer_cfg sun50i_a64_mixer1_cfg = {
static const struct sun8i_mixer_cfg sun50i_h6_mixer0_cfg = {
.ccsc = CCSC_MIXER0_LAYOUT,
.is_de3 = true,
+ .has_formatter = 1,
.mod_rate = 600000000,
.scaler_mask = 0xf,
.scanline_yuv = 4096,
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h b/drivers/gpu/drm/sun4i/sun8i_mixer.h
index d7898c9c9cc0..8417b8fef2e1 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.h
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
@@ -163,6 +163,7 @@ enum {
* @mod_rate: module clock rate that needs to be set in order to have
* a functional block.
* @is_de3: true, if this is next gen display engine 3.0, false otherwise.
+ * @has_formatter: true, if mixer has formatter core, for 10-bit and YUV handling
* @scaline_yuv: size of a scanline for VI scaler for YUV formats.
*/
struct sun8i_mixer_cfg {
@@ -172,6 +173,7 @@ struct sun8i_mixer_cfg {
int ccsc;
unsigned long mod_rate;
unsigned int is_de3 : 1;
+ unsigned int has_formatter : 1;
unsigned int scanline_yuv;
};
--
2.35.3

View File

@ -0,0 +1,54 @@
From 2d7c88fc2af6d07ccadc99b157753638b4940293 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Date: Sun, 29 Sep 2024 22:04:41 +1300
Subject: drm: sun4i: de3: pass engine reference to ccsc setup function
Configuration of the DE3 colorspace and dynamic range correction module
requires knowledge of the current video format and encoding.
Pass the display engine by reference to the csc setup function, rather
than the register map alone, to allow access to this information.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Signed-off-by: Ryan Walklin <ryan@testtoast.com>
---
drivers/gpu/drm/sun4i/sun8i_csc.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c b/drivers/gpu/drm/sun4i/sun8i_csc.c
index 68d955c63b05..8a336ccb27d3 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -148,17 +148,19 @@ static void sun8i_csc_setup(struct regmap *map, u32 base,
regmap_write(map, SUN8I_CSC_CTRL(base), val);
}
-static void sun8i_de3_ccsc_setup(struct regmap *map, int layer,
+static void sun8i_de3_ccsc_setup(struct sunxi_engine *engine, int layer,
enum format_type fmt_type,
enum drm_color_encoding encoding,
enum drm_color_range range)
{
u32 addr, val, mask;
+ struct regmap *map;
const u32 *table;
int i;
mask = SUN50I_MIXER_BLEND_CSC_CTL_EN(layer);
table = yuv2rgb_de3[range][encoding];
+ map = engine->regs;
switch (fmt_type) {
case FORMAT_TYPE_RGB:
@@ -204,7 +206,7 @@ void sun8i_csc_set_ccsc(struct sun8i_mixer *mixer, int layer,
u32 base;
if (mixer->cfg->is_de3) {
- sun8i_de3_ccsc_setup(mixer->engine.regs, layer,
+ sun8i_de3_ccsc_setup(&mixer->engine, layer,
fmt_type, encoding, range);
return;
}
--
2.35.3

View File

@ -0,0 +1,156 @@
From 0d003a88bcacf5f405f3922b0c56b7eecdb68386 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Date: Sun, 29 Sep 2024 22:04:58 +1300
Subject: drm: sun4i: de33: csc: add Display Engine 3.3 (DE33) support
Like earlier DE versions, the DE33 has a CSC (Color Space Correction)
module. which provides color space conversion between BT2020/BT709, and
dynamic range conversion between SDR/ST2084/HLG.
Add support for the DE33.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Signed-off-by: Ryan Walklin <ryan@testtoast.com>
---
drivers/gpu/drm/sun4i/sun8i_csc.c | 96 +++++++++++++++++++++++++++++++
drivers/gpu/drm/sun4i/sun8i_csc.h | 3 +
2 files changed, 99 insertions(+)
diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c b/drivers/gpu/drm/sun4i/sun8i_csc.c
index 2d5a2cf7cba2..45bd1ca06400 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -238,6 +238,14 @@ static const u32 yuv2yuv_de3[2][3][3][12] = {
},
};
+static u32 sun8i_csc_base(struct sun8i_mixer *mixer, int layer)
+{
+ if (mixer->cfg->de_type == sun8i_mixer_de33)
+ return sun8i_channel_base(mixer, layer) - 0x800;
+ else
+ return ccsc_base[mixer->cfg->ccsc][layer];
+}
+
static void sun8i_csc_setup(struct regmap *map, u32 base,
enum format_type fmt_type,
enum drm_color_encoding encoding,
@@ -358,6 +366,90 @@ static void sun8i_de3_ccsc_setup(struct sunxi_engine *engine, int layer,
mask, val);
}
+/* extract constant from high word and invert sign if necessary */
+static u32 sun8i_de33_ccsc_get_constant(u32 value)
+{
+ value >>= 16;
+
+ if (value & BIT(15))
+ return 0x400 - (value & 0x3ff);
+
+ return value;
+}
+
+static void sun8i_de33_convert_table(const u32 *src, u32 *dst)
+{
+ dst[0] = sun8i_de33_ccsc_get_constant(src[3]);
+ dst[1] = sun8i_de33_ccsc_get_constant(src[7]);
+ dst[2] = sun8i_de33_ccsc_get_constant(src[11]);
+ memcpy(&dst[3], src, sizeof(u32) * 12);
+ dst[6] &= 0xffff;
+ dst[10] &= 0xffff;
+ dst[14] &= 0xffff;
+}
+
+static void sun8i_de33_ccsc_setup(struct sun8i_mixer *mixer, int layer,
+ enum format_type fmt_type,
+ enum drm_color_encoding encoding,
+ enum drm_color_range range)
+{
+ u32 addr, val = 0, base, csc[15];
+ struct sunxi_engine *engine;
+ struct regmap *map;
+ const u32 *table;
+ int i;
+
+ table = yuv2rgb_de3[range][encoding];
+ base = sun8i_csc_base(mixer, layer);
+ engine = &mixer->engine;
+ map = engine->regs;
+
+ switch (fmt_type) {
+ case FORMAT_TYPE_RGB:
+ if (engine->format == MEDIA_BUS_FMT_RGB888_1X24)
+ break;
+ val = SUN8I_CSC_CTRL_EN;
+ sun8i_de33_convert_table(rgb2yuv_de3[engine->encoding], csc);
+ regmap_bulk_write(map, SUN50I_CSC_COEFF(base, 0), csc, 15);
+ break;
+ case FORMAT_TYPE_YUV:
+ table = sun8i_csc_get_de3_yuv_table(encoding, range,
+ engine->format,
+ engine->encoding);
+ if (!table)
+ break;
+ val = SUN8I_CSC_CTRL_EN;
+ sun8i_de33_convert_table(table, csc);
+ regmap_bulk_write(map, SUN50I_CSC_COEFF(base, 0), csc, 15);
+ break;
+ case FORMAT_TYPE_YVU:
+ table = sun8i_csc_get_de3_yuv_table(encoding, range,
+ engine->format,
+ engine->encoding);
+ if (!table)
+ table = yuv2yuv_de3[range][encoding][encoding];
+ val = SUN8I_CSC_CTRL_EN;
+ sun8i_de33_convert_table(table, csc);
+ for (i = 0; i < 15; i++) {
+ addr = SUN50I_CSC_COEFF(base, i);
+ if (i > 3) {
+ if (((i - 3) & 3) == 1)
+ addr = SUN50I_CSC_COEFF(base, i + 1);
+ else if (((i - 3) & 3) == 2)
+ addr = SUN50I_CSC_COEFF(base, i - 1);
+ }
+ regmap_write(map, addr, csc[i]);
+ }
+ break;
+ default:
+ val = 0;
+ DRM_WARN("Wrong CSC mode specified.\n");
+ return;
+ }
+
+ regmap_write(map, SUN8I_CSC_CTRL(base), val);
+}
+
void sun8i_csc_set_ccsc(struct sun8i_mixer *mixer, int layer,
enum format_type fmt_type,
enum drm_color_encoding encoding,
@@ -369,6 +461,10 @@ void sun8i_csc_set_ccsc(struct sun8i_mixer *mixer, int layer,
sun8i_de3_ccsc_setup(&mixer->engine, layer,
fmt_type, encoding, range);
return;
+ } else if (mixer->cfg->de_type == sun8i_mixer_de33) {
+ sun8i_de33_ccsc_setup(mixer, layer, fmt_type,
+ encoding, range);
+ return;
}
if (layer < mixer->cfg->vi_num) {
diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.h b/drivers/gpu/drm/sun4i/sun8i_csc.h
index b7546e06e315..2b762cb79f02 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.h
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.h
@@ -20,6 +20,9 @@ struct sun8i_mixer;
#define SUN8I_CSC_CTRL(base) ((base) + 0x0)
#define SUN8I_CSC_COEFF(base, i) ((base) + 0x10 + 4 * (i))
+#define SUN50I_CSC_COEFF(base, i) ((base) + 0x04 + 4 * (i))
+#define SUN50I_CSC_ALPHA(base) ((base) + 0x40)
+
#define SUN8I_CSC_CTRL_EN BIT(0)
enum format_type {
--
2.35.3

View File

@ -0,0 +1,75 @@
From 792b816c952bcf5dbf7c3ac7d90937bc71f0a7cd Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Date: Sun, 29 Sep 2024 22:04:57 +1300
Subject: drm: sun4i: de33: fmt: add Display Engine 3.3 (DE33) support
Like the DE3, the DE33 has a FMT (formatter) module, which
provides YUV444 to YUV422/YUV420 conversion, format re-mapping and color
depth conversion, although the DE33 module appears significantly more
capable, including up to 4K video support.
Add support for the DE33.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Signed-off-by: Ryan Walklin <ryan@testtoast.com>
---
drivers/gpu/drm/sun4i/sun50i_fmt.c | 21 +++++++++++++++++++--
drivers/gpu/drm/sun4i/sun50i_fmt.h | 1 +
2 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun50i_fmt.c b/drivers/gpu/drm/sun4i/sun50i_fmt.c
index 050a8716ae86..39682d4e6d20 100644
--- a/drivers/gpu/drm/sun4i/sun50i_fmt.c
+++ b/drivers/gpu/drm/sun4i/sun50i_fmt.c
@@ -51,6 +51,19 @@ static void sun50i_fmt_de3_limits(u32 *limits, u32 colorspace, bool bit10)
}
}
+static void sun50i_fmt_de33_limits(u32 *limits, u32 colorspace)
+{
+ if (colorspace == SUN50I_FMT_CS_YUV444RGB) {
+ limits[0] = SUN50I_FMT_LIMIT(0, 4095);
+ limits[1] = SUN50I_FMT_LIMIT(0, 4095);
+ limits[2] = SUN50I_FMT_LIMIT(0, 4095);
+ } else {
+ limits[0] = SUN50I_FMT_LIMIT(256, 3840);
+ limits[1] = SUN50I_FMT_LIMIT(256, 3840);
+ limits[2] = SUN50I_FMT_LIMIT(256, 3840);
+ }
+}
+
void sun50i_fmt_setup(struct sun8i_mixer *mixer, u16 width,
u16 height, u32 format)
{
@@ -60,10 +73,14 @@ void sun50i_fmt_setup(struct sun8i_mixer *mixer, u16 width,
colorspace = sun50i_fmt_get_colorspace(format);
bit10 = sun50i_fmt_is_10bit(format);
- base = SUN50I_FMT_DE3;
+ base = mixer->cfg->de_type == sun8i_mixer_de3 ?
+ SUN50I_FMT_DE3 : SUN50I_FMT_DE33;
regs = sun8i_blender_regmap(mixer);
- sun50i_fmt_de3_limits(limit, colorspace, bit10);
+ if (mixer->cfg->de_type == sun8i_mixer_de3)
+ sun50i_fmt_de3_limits(limit, colorspace, bit10);
+ else
+ sun50i_fmt_de33_limits(limit, colorspace);
regmap_write(regs, SUN50I_FMT_CTRL(base), 0);
diff --git a/drivers/gpu/drm/sun4i/sun50i_fmt.h b/drivers/gpu/drm/sun4i/sun50i_fmt.h
index 4127f7206aad..3e60d5c788b3 100644
--- a/drivers/gpu/drm/sun4i/sun50i_fmt.h
+++ b/drivers/gpu/drm/sun4i/sun50i_fmt.h
@@ -9,6 +9,7 @@
#include "sun8i_mixer.h"
#define SUN50I_FMT_DE3 0xa8000
+#define SUN50I_FMT_DE33 0x5000
#define SUN50I_FMT_CTRL(base) ((base) + 0x00)
#define SUN50I_FMT_SIZE(base) ((base) + 0x04)
--
2.35.3

View File

@ -0,0 +1,302 @@
From 66c111f3315d2c34c2f9bfb39de61bf3ec46a5f6 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Date: Sun, 29 Sep 2024 22:04:55 +1300
Subject: drm: sun4i: de33: mixer: add Display Engine 3.3 (DE33) support
The DE33 is a newer version of the Allwinner Display Engine IP block,
found in the H616, H618, H700 and T507 SoCs. DE2 and DE3 are already
supported by the mainline driver.
Notable features (from the H616 datasheet and implemented):
- 4096 x 2048 (4K) output support
- AFBC ARM Frame Buffer Compression support
- YUV420 input support
The DE2 and DE3 engines have a blender register range within the
mixer engine register map, whereas the DE33 separates this out into
a separate display group, and adds a top register map.
Extend the mixer to support the DE33.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Signed-off-by: Ryan Walklin <ryan@testtoast.com>
---
drivers/gpu/drm/sun4i/sun8i_mixer.c | 109 ++++++++++++++++++++++++----
drivers/gpu/drm/sun4i/sun8i_mixer.h | 16 +++-
2 files changed, 108 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index 600084286b39..204fc8055b32 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -321,8 +321,12 @@ static void sun8i_mixer_commit(struct sunxi_engine *engine,
regmap_write(bld_regs, SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
pipe_en | SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
- regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF,
- SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
+ if (mixer->cfg->de_type == sun8i_mixer_de33)
+ regmap_write(mixer->top_regs, SUN50I_MIXER_GLOBAL_DBUFF,
+ SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
+ else
+ regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF,
+ SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
}
static struct drm_plane **sun8i_layers_init(struct drm_device *drm,
@@ -371,25 +375,33 @@ static void sun8i_mixer_mode_set(struct sunxi_engine *engine,
const struct drm_display_mode *mode)
{
struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
+ struct regmap *bld_regs, *disp_regs;
u32 bld_base, size, val;
bool interlaced;
bld_base = sun8i_blender_base(mixer);
+ bld_regs = sun8i_blender_regmap(mixer);
interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
size = SUN8I_MIXER_SIZE(mode->hdisplay, mode->vdisplay);
DRM_DEBUG_DRIVER("Updating global size W: %u H: %u\n",
mode->hdisplay, mode->vdisplay);
- regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_SIZE, size);
- regmap_write(engine->regs, SUN8I_MIXER_BLEND_OUTSIZE(bld_base), size);
+ if (mixer->cfg->de_type == sun8i_mixer_de33) {
+ disp_regs = mixer->disp_regs;
+ regmap_write(mixer->top_regs, SUN50I_MIXER_GLOBAL_SIZE, size);
+ } else {
+ disp_regs = mixer->engine.regs;
+ regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_SIZE, size);
+ }
+ regmap_write(bld_regs, SUN8I_MIXER_BLEND_OUTSIZE(bld_base), size);
if (interlaced)
val = SUN8I_MIXER_BLEND_OUTCTL_INTERLACED;
else
val = 0;
- regmap_update_bits(engine->regs, SUN8I_MIXER_BLEND_OUTCTL(bld_base),
+ regmap_update_bits(bld_regs, SUN8I_MIXER_BLEND_OUTCTL(bld_base),
SUN8I_MIXER_BLEND_OUTCTL_INTERLACED, val);
DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
@@ -400,10 +412,8 @@ static void sun8i_mixer_mode_set(struct sunxi_engine *engine,
else
val = 0xff108080;
- regmap_write(mixer->engine.regs,
- SUN8I_MIXER_BLEND_BKCOLOR(bld_base), val);
- regmap_write(mixer->engine.regs,
- SUN8I_MIXER_BLEND_ATTR_FCOLOR(bld_base, 0), val);
+ regmap_write(disp_regs, SUN8I_MIXER_BLEND_BKCOLOR(bld_base), val);
+ regmap_write(disp_regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(bld_base, 0), val);
if (mixer->cfg->has_formatter)
sun50i_fmt_setup(mixer, mode->hdisplay,
@@ -443,12 +453,29 @@ static const struct sunxi_engine_ops sun8i_engine_ops = {
};
static const struct regmap_config sun8i_mixer_regmap_config = {
+ .name = "layers",
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.max_register = 0xffffc, /* guessed */
};
+static const struct regmap_config sun8i_top_regmap_config = {
+ .name = "top",
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = 0x3c,
+};
+
+static const struct regmap_config sun8i_disp_regmap_config = {
+ .name = "display",
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = 0x20000,
+};
+
static int sun8i_mixer_of_get_id(struct device_node *node)
{
struct device_node *ep, *remote;
@@ -471,33 +498,45 @@ static int sun8i_mixer_of_get_id(struct device_node *node)
static void sun8i_mixer_init(struct sun8i_mixer *mixer)
{
+ struct regmap *top_regs, *disp_regs;
unsigned int base = sun8i_blender_base(mixer);
int plane_cnt, i;
+ if (mixer->cfg->de_type == sun8i_mixer_de33) {
+ top_regs = mixer->top_regs;
+ disp_regs = mixer->disp_regs;
+ } else {
+ top_regs = mixer->engine.regs;
+ disp_regs = mixer->engine.regs;
+ }
+
/* Enable the mixer */
- regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_CTL,
+ regmap_write(top_regs, SUN8I_MIXER_GLOBAL_CTL,
SUN8I_MIXER_GLOBAL_CTL_RT_EN);
+ if (mixer->cfg->de_type == sun8i_mixer_de33)
+ regmap_write(top_regs, SUN50I_MIXER_GLOBAL_CLK, 1);
+
/* Set background color to black */
- regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_BKCOLOR(base),
+ regmap_write(disp_regs, SUN8I_MIXER_BLEND_BKCOLOR(base),
SUN8I_MIXER_BLEND_COLOR_BLACK);
/*
* Set fill color of bottom plane to black. Generally not needed
* except when VI plane is at bottom (zpos = 0) and enabled.
*/
- regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
+ regmap_write(disp_regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
- regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(base, 0),
+ regmap_write(disp_regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(base, 0),
SUN8I_MIXER_BLEND_COLOR_BLACK);
plane_cnt = mixer->cfg->vi_num + mixer->cfg->ui_num;
for (i = 0; i < plane_cnt; i++)
- regmap_write(mixer->engine.regs,
+ regmap_write(disp_regs,
SUN8I_MIXER_BLEND_MODE(base, i),
SUN8I_MIXER_BLEND_MODE_DEF);
- regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
+ regmap_update_bits(disp_regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0);
}
@@ -573,6 +612,30 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
return PTR_ERR(mixer->engine.regs);
}
+ if (mixer->cfg->de_type == sun8i_mixer_de33) {
+ regs = devm_platform_ioremap_resource(pdev, 1);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ mixer->top_regs = devm_regmap_init_mmio(dev, regs,
+ &sun8i_top_regmap_config);
+ if (IS_ERR(mixer->top_regs)) {
+ dev_err(dev, "Couldn't create the top regmap\n");
+ return PTR_ERR(mixer->top_regs);
+ }
+
+ regs = devm_platform_ioremap_resource(pdev, 2);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ mixer->disp_regs = devm_regmap_init_mmio(dev, regs,
+ &sun8i_disp_regmap_config);
+ if (IS_ERR(mixer->disp_regs)) {
+ dev_err(dev, "Couldn't create the disp regmap\n");
+ return PTR_ERR(mixer->disp_regs);
+ }
+ }
+
mixer->reset = devm_reset_control_get(dev, NULL);
if (IS_ERR(mixer->reset)) {
dev_err(dev, "Couldn't get our reset line\n");
@@ -787,6 +850,18 @@ static const struct sun8i_mixer_cfg sun50i_h6_mixer0_cfg = {
.vi_num = 1,
};
+static const struct sun8i_mixer_cfg sun50i_h616_mixer0_cfg = {
+ .ccsc = CCSC_MIXER0_LAYOUT,
+ .de_type = sun8i_mixer_de33,
+ .has_formatter = 1,
+ .mod_rate = 600000000,
+ .scaler_mask = 0xf,
+ .scanline_yuv = 4096,
+ .ui_num = 3,
+ .vi_num = 1,
+ .map = {0, 6, 7, 8},
+};
+
static const struct of_device_id sun8i_mixer_of_table[] = {
{
.compatible = "allwinner,sun8i-a83t-de2-mixer-0",
@@ -832,6 +907,10 @@ static const struct of_device_id sun8i_mixer_of_table[] = {
.compatible = "allwinner,sun50i-h6-de3-mixer-0",
.data = &sun50i_h6_mixer0_cfg,
},
+ {
+ .compatible = "allwinner,sun50i-h616-de33-mixer-0",
+ .data = &sun50i_h616_mixer0_cfg,
+ },
{ }
};
MODULE_DEVICE_TABLE(of, sun8i_mixer_of_table);
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h b/drivers/gpu/drm/sun4i/sun8i_mixer.h
index 75facc7d1fa6..26b001164647 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.h
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
@@ -21,6 +21,10 @@
#define SUN8I_MIXER_GLOBAL_DBUFF 0x8
#define SUN8I_MIXER_GLOBAL_SIZE 0xc
+#define SUN50I_MIXER_GLOBAL_SIZE 0x8
+#define SUN50I_MIXER_GLOBAL_CLK 0xc
+#define SUN50I_MIXER_GLOBAL_DBUFF 0x10
+
#define SUN8I_MIXER_GLOBAL_CTL_RT_EN BIT(0)
#define SUN8I_MIXER_GLOBAL_DBUFF_ENABLE BIT(0)
@@ -154,6 +158,7 @@ enum {
enum sun8i_mixer_type {
sun8i_mixer_de2,
sun8i_mixer_de3,
+ sun8i_mixer_de33,
};
/**
@@ -180,6 +185,7 @@ struct sun8i_mixer_cfg {
unsigned int de_type;
unsigned int has_formatter : 1;
unsigned int scanline_yuv;
+ unsigned int map[6];
};
struct sun8i_mixer {
@@ -191,6 +197,9 @@ struct sun8i_mixer {
struct clk *bus_clk;
struct clk *mod_clk;
+
+ struct regmap *top_regs;
+ struct regmap *disp_regs;
};
enum {
@@ -227,13 +236,16 @@ sun8i_blender_base(struct sun8i_mixer *mixer)
static inline struct regmap *
sun8i_blender_regmap(struct sun8i_mixer *mixer)
{
- return mixer->engine.regs;
+ return mixer->cfg->de_type == sun8i_mixer_de33 ?
+ mixer->disp_regs : mixer->engine.regs;
}
static inline u32
sun8i_channel_base(struct sun8i_mixer *mixer, int channel)
{
- if (mixer->cfg->de_type == sun8i_mixer_de3)
+ if (mixer->cfg->de_type == sun8i_mixer_de33)
+ return mixer->cfg->map[channel] * 0x20000 + DE2_CH_SIZE;
+ else if (mixer->cfg->de_type == sun8i_mixer_de3)
return DE3_CH_BASE + channel * DE3_CH_SIZE;
else
return DE2_CH_BASE + channel * DE2_CH_SIZE;
--
2.35.3

View File

@ -0,0 +1,77 @@
From 412294545ec91452cc3eccff746a4243879b4cde Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Date: Sun, 29 Sep 2024 22:04:56 +1300
Subject: drm: sun4i: de33: vi_scaler: add Display Engine 3.3 (DE33) support
The vi_scaler appears to be used in preference to the ui_scaler module
for hardware video scaling in the DE33.
Enable support for this scaler.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Signed-off-by: Ryan Walklin <ryan@testtoast.com>
---
drivers/gpu/drm/sun4i/sun8i_ui_layer.c | 19 +++++++++++++++----
drivers/gpu/drm/sun4i/sun8i_vi_scaler.c | 7 ++++++-
2 files changed, 21 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
index 7f1231cf0f01..180be9d67d9c 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
@@ -95,12 +95,23 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel,
hscale = state->src_w / state->crtc_w;
vscale = state->src_h / state->crtc_h;
- sun8i_ui_scaler_setup(mixer, channel, src_w, src_h, dst_w,
- dst_h, hscale, vscale, hphase, vphase);
- sun8i_ui_scaler_enable(mixer, channel, true);
+ if (mixer->cfg->de_type == sun8i_mixer_de33) {
+ sun8i_vi_scaler_setup(mixer, channel, src_w, src_h,
+ dst_w, dst_h, hscale, vscale,
+ hphase, vphase,
+ state->fb->format);
+ } else {
+ sun8i_ui_scaler_setup(mixer, channel, src_w, src_h,
+ dst_w, dst_h, hscale, vscale,
+ hphase, vphase);
+ sun8i_ui_scaler_enable(mixer, channel, true);
+ }
} else {
DRM_DEBUG_DRIVER("HW scaling is not needed\n");
- sun8i_ui_scaler_enable(mixer, channel, false);
+ if (mixer->cfg->de_type == sun8i_mixer_de33)
+ sun8i_vi_scaler_disable(mixer, channel);
+ else
+ sun8i_ui_scaler_enable(mixer, channel, false);
}
/* Set base coordinates */
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
index e7242301b312..9c7f6e7d71d5 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
@@ -835,7 +835,9 @@ static const u32 bicubic4coefftab32[480] = {
static u32 sun8i_vi_scaler_base(struct sun8i_mixer *mixer, int channel)
{
- if (mixer->cfg->de_type == sun8i_mixer_de3)
+ if (mixer->cfg->de_type == sun8i_mixer_de33)
+ return sun8i_channel_base(mixer, channel) + 0x3000;
+ else if (mixer->cfg->de_type == sun8i_mixer_de3)
return DE3_VI_SCALER_UNIT_BASE +
DE3_VI_SCALER_UNIT_SIZE * channel;
else
@@ -845,6 +847,9 @@ static u32 sun8i_vi_scaler_base(struct sun8i_mixer *mixer, int channel)
static bool sun8i_vi_scaler_is_vi_plane(struct sun8i_mixer *mixer, int channel)
{
+ if (mixer->cfg->de_type == sun8i_mixer_de33)
+ return mixer->cfg->map[channel] < mixer->cfg->vi_num;
+
return true;
}
--
2.35.3

View File

@ -0,0 +1,140 @@
From e0de25f60a3535d345b33dcc541c814499151788 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Date: Sun, 29 Sep 2024 22:04:44 +1300
Subject: drm: sun4i: support YUV formats in VI scaler
Now that YUV formats are available, enable support in the VI scaler.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Signed-off-by: Ryan Walklin <ryan@testtoast.com>
Changelog v4..v5:
- Add commit description
---
drivers/gpu/drm/sun4i/sun8i_vi_scaler.c | 85 +++++++++++++++++--------
1 file changed, 58 insertions(+), 27 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
index 7ba75011adf9..2e49a6e5f1f1 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
@@ -843,6 +843,11 @@ static u32 sun8i_vi_scaler_base(struct sun8i_mixer *mixer, int channel)
DE2_VI_SCALER_UNIT_SIZE * channel;
}
+static bool sun8i_vi_scaler_is_vi_plane(struct sun8i_mixer *mixer, int channel)
+{
+ return true;
+}
+
static int sun8i_vi_scaler_coef_index(unsigned int step)
{
unsigned int scale, int_part, float_part;
@@ -867,44 +872,65 @@ static int sun8i_vi_scaler_coef_index(unsigned int step)
}
}
-static void sun8i_vi_scaler_set_coeff(struct regmap *map, u32 base,
- u32 hstep, u32 vstep,
- const struct drm_format_info *format)
+static void sun8i_vi_scaler_set_coeff_vi(struct regmap *map, u32 base,
+ u32 hstep, u32 vstep,
+ const struct drm_format_info *format)
{
const u32 *ch_left, *ch_right, *cy;
- int offset, i;
+ int offset;
- if (format->hsub == 1 && format->vsub == 1) {
- ch_left = lan3coefftab32_left;
- ch_right = lan3coefftab32_right;
- cy = lan2coefftab32;
- } else {
+ if (format->is_yuv) {
ch_left = bicubic8coefftab32_left;
ch_right = bicubic8coefftab32_right;
cy = bicubic4coefftab32;
+ } else {
+ ch_left = lan3coefftab32_left;
+ ch_right = lan3coefftab32_right;
+ cy = lan2coefftab32;
}
offset = sun8i_vi_scaler_coef_index(hstep) *
SUN8I_VI_SCALER_COEFF_COUNT;
- for (i = 0; i < SUN8I_VI_SCALER_COEFF_COUNT; i++) {
- regmap_write(map, SUN8I_SCALER_VSU_YHCOEFF0(base, i),
- lan3coefftab32_left[offset + i]);
- regmap_write(map, SUN8I_SCALER_VSU_YHCOEFF1(base, i),
- lan3coefftab32_right[offset + i]);
- regmap_write(map, SUN8I_SCALER_VSU_CHCOEFF0(base, i),
- ch_left[offset + i]);
- regmap_write(map, SUN8I_SCALER_VSU_CHCOEFF1(base, i),
- ch_right[offset + i]);
- }
+ regmap_bulk_write(map, SUN8I_SCALER_VSU_YHCOEFF0(base, 0),
+ &lan3coefftab32_left[offset],
+ SUN8I_VI_SCALER_COEFF_COUNT);
+ regmap_bulk_write(map, SUN8I_SCALER_VSU_YHCOEFF1(base, 0),
+ &lan3coefftab32_right[offset],
+ SUN8I_VI_SCALER_COEFF_COUNT);
+ regmap_bulk_write(map, SUN8I_SCALER_VSU_CHCOEFF0(base, 0),
+ &ch_left[offset], SUN8I_VI_SCALER_COEFF_COUNT);
+ regmap_bulk_write(map, SUN8I_SCALER_VSU_CHCOEFF1(base, 0),
+ &ch_right[offset], SUN8I_VI_SCALER_COEFF_COUNT);
offset = sun8i_vi_scaler_coef_index(hstep) *
SUN8I_VI_SCALER_COEFF_COUNT;
- for (i = 0; i < SUN8I_VI_SCALER_COEFF_COUNT; i++) {
- regmap_write(map, SUN8I_SCALER_VSU_YVCOEFF(base, i),
- lan2coefftab32[offset + i]);
- regmap_write(map, SUN8I_SCALER_VSU_CVCOEFF(base, i),
- cy[offset + i]);
- }
+ regmap_bulk_write(map, SUN8I_SCALER_VSU_YVCOEFF(base, 0),
+ &lan2coefftab32[offset], SUN8I_VI_SCALER_COEFF_COUNT);
+ regmap_bulk_write(map, SUN8I_SCALER_VSU_CVCOEFF(base, 0),
+ &cy[offset], SUN8I_VI_SCALER_COEFF_COUNT);
+}
+
+static void sun8i_vi_scaler_set_coeff_ui(struct regmap *map, u32 base,
+ u32 hstep, u32 vstep,
+ const struct drm_format_info *format)
+{
+ const u32 *table;
+ int offset;
+
+ offset = sun8i_vi_scaler_coef_index(hstep) *
+ SUN8I_VI_SCALER_COEFF_COUNT;
+ regmap_bulk_write(map, SUN8I_SCALER_VSU_YHCOEFF0(base, 0),
+ &lan2coefftab32[offset], SUN8I_VI_SCALER_COEFF_COUNT);
+ offset = sun8i_vi_scaler_coef_index(vstep) *
+ SUN8I_VI_SCALER_COEFF_COUNT;
+ regmap_bulk_write(map, SUN8I_SCALER_VSU_YVCOEFF(base, 0),
+ &lan2coefftab32[offset], SUN8I_VI_SCALER_COEFF_COUNT);
+
+ table = format->is_yuv ? bicubic4coefftab32 : lan2coefftab32;
+ offset = sun8i_vi_scaler_coef_index(hstep) *
+ SUN8I_VI_SCALER_COEFF_COUNT;
+ regmap_bulk_write(map, SUN8I_SCALER_VSU_CHCOEFF0(base, 0),
+ &table[offset], SUN8I_VI_SCALER_COEFF_COUNT);
}
void sun8i_vi_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable)
@@ -994,6 +1020,11 @@ void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,
SUN8I_SCALER_VSU_CHPHASE(base), chphase);
regmap_write(mixer->engine.regs,
SUN8I_SCALER_VSU_CVPHASE(base), cvphase);
- sun8i_vi_scaler_set_coeff(mixer->engine.regs, base,
- hscale, vscale, format);
+
+ if (sun8i_vi_scaler_is_vi_plane(mixer, layer))
+ sun8i_vi_scaler_set_coeff_vi(mixer->engine.regs, base,
+ hscale, vscale, format);
+ else
+ sun8i_vi_scaler_set_coeff_ui(mixer->engine.regs, base,
+ hscale, vscale, format);
}
--
2.35.3

View File

@ -0,0 +1,100 @@
From 0c10a80b8e37d9a7fc57d8bf968c70419423065a Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Date: Sun, 29 Sep 2024 22:04:47 +1300
Subject: drm: sun4i: vi_scaler refactor vi_scaler enablement
If the video scaler is required, then it is obligatory to set the
relevant register to enable it, so move this to the
sun8i_vi_scaler_setup() function.
This simplifies the alternate case (scaler not required) so replace the
vi_scaler_enable() function with a vi_scaler_disable() function.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Signed-off-by: Ryan Walklin <ryan@testtoast.com>
---
drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 3 +--
drivers/gpu/drm/sun4i/sun8i_vi_scaler.c | 21 +++++++++++----------
drivers/gpu/drm/sun4i/sun8i_vi_scaler.h | 2 +-
3 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
index 4647e9bcccaa..e348fd0a3d81 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
@@ -156,10 +156,9 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
sun8i_vi_scaler_setup(mixer, channel, src_w, src_h, dst_w,
dst_h, hscale, vscale, hphase, vphase,
format);
- sun8i_vi_scaler_enable(mixer, channel, true);
} else {
DRM_DEBUG_DRIVER("HW scaling is not needed\n");
- sun8i_vi_scaler_enable(mixer, channel, false);
+ sun8i_vi_scaler_disable(mixer, channel);
}
regmap_write(mixer->engine.regs,
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
index aa346c3beb30..e7242301b312 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
@@ -933,20 +933,13 @@ static void sun8i_vi_scaler_set_coeff_ui(struct regmap *map, u32 base,
&table[offset], SUN8I_VI_SCALER_COEFF_COUNT);
}
-void sun8i_vi_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable)
+void sun8i_vi_scaler_disable(struct sun8i_mixer *mixer, int layer)
{
- u32 val, base;
+ u32 base;
base = sun8i_vi_scaler_base(mixer, layer);
- if (enable)
- val = SUN8I_SCALER_VSU_CTRL_EN |
- SUN8I_SCALER_VSU_CTRL_COEFF_RDY;
- else
- val = 0;
-
- regmap_write(mixer->engine.regs,
- SUN8I_SCALER_VSU_CTRL(base), val);
+ regmap_write(mixer->engine.regs, SUN8I_SCALER_VSU_CTRL(base), 0);
}
void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,
@@ -982,6 +975,9 @@ void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,
cvphase = vphase;
}
+ regmap_write(mixer->engine.regs, SUN8I_SCALER_VSU_CTRL(base),
+ SUN8I_SCALER_VSU_CTRL_EN);
+
if (mixer->cfg->de_type >= sun8i_mixer_de3) {
u32 val;
@@ -1027,4 +1023,9 @@ void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,
else
sun8i_vi_scaler_set_coeff_ui(mixer->engine.regs, base,
hscale, vscale, format);
+
+ if (mixer->cfg->de_type <= sun8i_mixer_de3)
+ regmap_write(mixer->engine.regs, SUN8I_SCALER_VSU_CTRL(base),
+ SUN8I_SCALER_VSU_CTRL_EN |
+ SUN8I_SCALER_VSU_CTRL_COEFF_RDY);
}
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h
index 68f6593b369a..e801bc7a4189 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h
@@ -69,7 +69,7 @@
#define SUN50I_SCALER_VSU_ANGLE_SHIFT(x) (((x) << 16) & 0xF)
#define SUN50I_SCALER_VSU_ANGLE_OFFSET(x) ((x) & 0xFF)
-void sun8i_vi_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable);
+void sun8i_vi_scaler_disable(struct sun8i_mixer *mixer, int layer);
void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,
u32 src_w, u32 src_h, u32 dst_w, u32 dst_h,
u32 hscale, u32 vscale, u32 hphase, u32 vphase,
--
2.35.3

View File

@ -0,0 +1,35 @@
From b8344d8eb9d000bc2984a5fcafc25b527f361b5b Mon Sep 17 00:00:00 2001
From: Ryan Walklin <ryan@testtoast.com>
Date: Sun, 29 Sep 2024 22:04:51 +1300
Subject: dt-bindings: allwinner: add H616 DE33 bus binding
The Allwinner H616 and variants have a new display engine revision
(DE33).
Add a display engine bus binding for the DE33.
Signed-off-by: Ryan Walklin <ryan@testtoast.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Reviewed-by: Chen-Yu Tsai <wens@csie.org>
---
.../devicetree/bindings/bus/allwinner,sun50i-a64-de2.yaml | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/bus/allwinner,sun50i-a64-de2.yaml b/Documentation/devicetree/bindings/bus/allwinner,sun50i-a64-de2.yaml
index 9845a187bdf6..ea7ee89158c6 100644
--- a/Documentation/devicetree/bindings/bus/allwinner,sun50i-a64-de2.yaml
+++ b/Documentation/devicetree/bindings/bus/allwinner,sun50i-a64-de2.yaml
@@ -24,7 +24,9 @@ properties:
oneOf:
- const: allwinner,sun50i-a64-de2
- items:
- - const: allwinner,sun50i-h6-de3
+ - enum:
+ - allwinner,sun50i-h6-de3
+ - allwinner,sun50i-h616-de33
- const: allwinner,sun50i-a64-de2
reg:
--
2.35.3

View File

@ -0,0 +1,32 @@
From 58a606c8136c57d23b4e35f0f50cb140f1d65d9b Mon Sep 17 00:00:00 2001
From: Ryan Walklin <ryan@testtoast.com>
Date: Sun, 29 Sep 2024 22:04:52 +1300
Subject: dt-bindings: allwinner: add H616 DE33 clock binding
The Allwinner H616 and variants have a new display engine revision
(DE33).
Add a clock binding for the DE33.
Signed-off-by: Ryan Walklin <ryan@testtoast.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Reviewed-by: Chen-Yu Tsai <wens@csie.org>
---
.../devicetree/bindings/clock/allwinner,sun8i-a83t-de2-clk.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/clock/allwinner,sun8i-a83t-de2-clk.yaml b/Documentation/devicetree/bindings/clock/allwinner,sun8i-a83t-de2-clk.yaml
index 70369bd633e4..7fcd55d468d4 100644
--- a/Documentation/devicetree/bindings/clock/allwinner,sun8i-a83t-de2-clk.yaml
+++ b/Documentation/devicetree/bindings/clock/allwinner,sun8i-a83t-de2-clk.yaml
@@ -25,6 +25,7 @@ properties:
- const: allwinner,sun50i-a64-de2-clk
- const: allwinner,sun50i-h5-de2-clk
- const: allwinner,sun50i-h6-de3-clk
+ - const: allwinner,sun50i-h616-de33-clk
- items:
- const: allwinner,sun8i-r40-de2-clk
- const: allwinner,sun8i-h3-de2-clk
--
2.35.3

View File

@ -0,0 +1,36 @@
From 12d7983166ed867dd72c023af036b1397aec66ba Mon Sep 17 00:00:00 2001
From: Ryan Walklin <ryan@testtoast.com>
Date: Sun, 29 Sep 2024 22:04:53 +1300
Subject: dt-bindings: allwinner: add H616 DE33 mixer binding
The Allwinner H616 and variants have a new display engine revision
(DE33).
The mixer configuration registers are significantly different to the DE3
and DE2 revisions, being split into separate top and display blocks,
therefore a fallback for the mixer compatible is not provided.
Add a display engine mixer binding for the DE33.
Signed-off-by: Ryan Walklin <ryan@testtoast.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Reviewed-by: Chen-Yu Tsai <wens@csie.org>
---
.../bindings/display/allwinner,sun8i-a83t-de2-mixer.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/display/allwinner,sun8i-a83t-de2-mixer.yaml b/Documentation/devicetree/bindings/display/allwinner,sun8i-a83t-de2-mixer.yaml
index b75c1ec686ad..c37eb8ae1b8e 100644
--- a/Documentation/devicetree/bindings/display/allwinner,sun8i-a83t-de2-mixer.yaml
+++ b/Documentation/devicetree/bindings/display/allwinner,sun8i-a83t-de2-mixer.yaml
@@ -24,6 +24,7 @@ properties:
- allwinner,sun50i-a64-de2-mixer-0
- allwinner,sun50i-a64-de2-mixer-1
- allwinner,sun50i-h6-de3-mixer-0
+ - allwinner,sun50i-h616-de33-mixer-0
reg:
maxItems: 1
--
2.35.3

View File

@ -0,0 +1,30 @@
From 7f350d05012873c129458241792d005ef1344d9a Mon Sep 17 00:00:00 2001
From: Andre Przywara <andre.przywara@arm.com>
Date: Fri, 21 Feb 2025 00:58:00 +0000
Subject: dt-bindings: gpu: mali-bifrost: Add Allwinner H616 compatible
The Allwinner H616 SoC has a Mali-G31 MP2 GPU, which is of the Mali
Bifrost family.
Add the SoC specific compatible string and pair it with the bifrost
fallback compatible.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
Documentation/devicetree/bindings/gpu/arm,mali-bifrost.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.yaml b/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.yaml
index 735c7f06c24e..439d5c59daa2 100644
--- a/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.yaml
+++ b/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.yaml
@@ -17,6 +17,7 @@ properties:
oneOf:
- items:
- enum:
+ - allwinner,sun50i-h616-mali
- amlogic,meson-g12a-mali
- mediatek,mt8183-mali
- mediatek,mt8183b-mali
--
2.35.3

View File

@ -0,0 +1,67 @@
From af0be61ac5ff0f86567ddbf3924c46eaa211e07f Mon Sep 17 00:00:00 2001
From: Andre Przywara <andre.przywara@arm.com>
Date: Fri, 21 Feb 2025 00:57:58 +0000
Subject: dt-bindings: power: Add Allwinner H6/H616 PRCM PPU
The Allwinner H6 and some later SoCs contain some bits in the PRCM (Power
Reset Clock Management) block that control some power domains.
Those power domains include the one for the GPU, the PLLs and some
analogue circuits.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
.../power/allwinner,sun50i-h6-prcm-ppu.yaml | 42 +++++++++++++++++++
1 file changed, 42 insertions(+)
create mode 100644 Documentation/devicetree/bindings/power/allwinner,sun50i-h6-prcm-ppu.yaml
diff --git a/Documentation/devicetree/bindings/power/allwinner,sun50i-h6-prcm-ppu.yaml b/Documentation/devicetree/bindings/power/allwinner,sun50i-h6-prcm-ppu.yaml
new file mode 100644
index 000000000000..7eaff9baf726
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/allwinner,sun50i-h6-prcm-ppu.yaml
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/power/allwinner,sun50i-h6-prcm-ppu.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner SoCs PRCM power domain controller
+
+maintainers:
+ - Andre Przywara <andre.przywara@arm.com>
+
+description:
+ The Allwinner Power Reset Clock Management (PRCM) unit contains bits to
+ control a few power domains.
+
+properties:
+ compatible:
+ enum:
+ - allwinner,sun50i-h6-prcm-ppu
+ - allwinner,sun50i-h616-prcm-ppu
+ - allwinner,sun55i-a523-prcm-ppu
+
+ reg:
+ maxItems: 1
+
+ '#power-domain-cells':
+ const: 1
+
+required:
+ - compatible
+ - reg
+ - '#power-domain-cells'
+
+additionalProperties: false
+
+examples:
+ - |
+ prcm_ppu: power-controller@7010210 {
+ compatible = "allwinner,sun50i-h616-prcm-ppu";
+ reg = <0x07010250 0x10>;
+ #power-domain-cells = <1>;
+ };
--
2.35.3

View File

@ -0,0 +1,249 @@
From 9fb1314045a676823428efa503b581c2910169d7 Mon Sep 17 00:00:00 2001
From: Andre Przywara <andre.przywara@arm.com>
Date: Fri, 21 Feb 2025 00:57:59 +0000
Subject: pmdomain: sunxi: add H6 PRCM PPU driver
The Allwinner Power Reset Clock Management (RPCM) block contains a few
bits that control some power domains. The most prominent one is the one
for the Mali GPU. On the Allwinner H6 this domain is enabled at reset, so
we didn't care about it so far, but the H616 defaults to it being disabled.
Add a power domain driver for those bits. Some BSP code snippets and
some spare documentation describe three bits, slightly different between
the H6 and H616, so add three power domains for each SoC, connected to
their compatible string.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
drivers/pmdomain/sunxi/Kconfig | 10 +
drivers/pmdomain/sunxi/Makefile | 1 +
drivers/pmdomain/sunxi/sun50i-h6-prcm-ppu.c | 191 ++++++++++++++++++++
3 files changed, 202 insertions(+)
create mode 100644 drivers/pmdomain/sunxi/sun50i-h6-prcm-ppu.c
diff --git a/drivers/pmdomain/sunxi/Kconfig b/drivers/pmdomain/sunxi/Kconfig
index 17781bf8d86d..43eecb3ea981 100644
--- a/drivers/pmdomain/sunxi/Kconfig
+++ b/drivers/pmdomain/sunxi/Kconfig
@@ -8,3 +8,13 @@ config SUN20I_PPU
help
Say y to enable the PPU power domain driver. This saves power
when certain peripherals, such as the video engine, are idle.
+
+config SUN50I_H6_PRCM_PPU
+ tristate "Allwinner H6 PRCM power domain driver"
+ depends on ARCH_SUNXI || COMPILE_TEST
+ depends on PM
+ select PM_GENERIC_DOMAINS
+ help
+ Say y to enable the Allwinner H6/H616 PRCM power domain driver.
+ This is required to enable the Mali GPU in the H616 SoC, it is
+ optional for the H6.
diff --git a/drivers/pmdomain/sunxi/Makefile b/drivers/pmdomain/sunxi/Makefile
index ec1d7a2fb21d..c1343e123759 100644
--- a/drivers/pmdomain/sunxi/Makefile
+++ b/drivers/pmdomain/sunxi/Makefile
@@ -1,2 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_SUN20I_PPU) += sun20i-ppu.o
+obj-$(CONFIG_SUN50I_H6_PRCM_PPU) += sun50i-h6-prcm-ppu.o
diff --git a/drivers/pmdomain/sunxi/sun50i-h6-prcm-ppu.c b/drivers/pmdomain/sunxi/sun50i-h6-prcm-ppu.c
new file mode 100644
index 000000000000..1c6b0c78b222
--- /dev/null
+++ b/drivers/pmdomain/sunxi/sun50i-h6-prcm-ppu.c
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) Arm Ltd. 2024
+ *
+ * Allwinner H6/H616 PRCM power domain driver.
+ * This covers a few registers inside the PRCM (Power Reset Clock Management)
+ * block that control some power rails, most prominently for the Mali GPU.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/reset.h>
+
+/*
+ * The PRCM block covers multiple devices, starting with some clocks,
+ * then followed by the power rails.
+ * The clocks are covered by a different driver, so this driver's MMIO range
+ * starts later in the PRCM MMIO frame, not at the beginning of it.
+ * To keep the register offsets consistent with other PRCM documentation,
+ * express the registers relative to the beginning of the whole PRCM, and
+ * subtract the PPU offset this driver is bound to.
+ */
+#define PD_H6_PPU_OFFSET 0x250
+#define PD_H6_VDD_SYS_REG 0x250
+#define PD_H616_ANA_VDD_GATE BIT(4)
+#define PD_H6_CPUS_VDD_GATE BIT(3)
+#define PD_H6_AVCC_VDD_GATE BIT(2)
+#define PD_H6_GPU_REG 0x254
+#define PD_H6_GPU_GATE BIT(0)
+
+struct sun50i_h6_ppu_pd {
+ struct generic_pm_domain genpd;
+ void __iomem *reg;
+ u32 gate_mask;
+ bool negated;
+};
+
+#define FLAG_PPU_ALWAYS_ON BIT(0)
+#define FLAG_PPU_NEGATED BIT(1)
+
+struct sun50i_h6_ppu_desc {
+ const char *name;
+ u32 offset;
+ u32 mask;
+ unsigned int flags;
+};
+
+struct sun50i_h6_ppu_desc sun50i_h6_ppus[] = {
+ { "AVCC", PD_H6_VDD_SYS_REG, PD_H6_AVCC_VDD_GATE },
+ { "CPUS", PD_H6_VDD_SYS_REG, PD_H6_CPUS_VDD_GATE },
+ { "GPU", PD_H6_GPU_REG, PD_H6_GPU_GATE },
+ {}
+};
+
+struct sun50i_h6_ppu_desc sun50i_h616_ppus[] = {
+ { "PLL", PD_H6_VDD_SYS_REG, PD_H6_AVCC_VDD_GATE,
+ FLAG_PPU_ALWAYS_ON | FLAG_PPU_NEGATED },
+ { "ANA", PD_H6_VDD_SYS_REG, PD_H616_ANA_VDD_GATE, FLAG_PPU_ALWAYS_ON },
+ { "GPU", PD_H6_GPU_REG, PD_H6_GPU_GATE, FLAG_PPU_NEGATED },
+ {}
+};
+#define to_sun50i_h6_ppu_pd(_genpd) \
+ container_of(_genpd, struct sun50i_h6_ppu_pd, genpd)
+
+static bool sun50i_h6_ppu_power_status(const struct sun50i_h6_ppu_pd *pd)
+{
+ bool bit = readl(pd->reg) & pd->gate_mask;
+
+ return bit ^ pd->negated;
+}
+
+static int sun50i_h6_ppu_pd_set_power(const struct sun50i_h6_ppu_pd *pd,
+ bool set_bit)
+{
+ u32 reg = readl(pd->reg);
+
+ if (set_bit)
+ writel(reg | pd->gate_mask, pd->reg);
+ else
+ writel(reg & ~pd->gate_mask, pd->reg);
+
+ return 0;
+}
+
+static int sun50i_h6_ppu_pd_power_on(struct generic_pm_domain *genpd)
+{
+ const struct sun50i_h6_ppu_pd *pd = to_sun50i_h6_ppu_pd(genpd);
+
+ return sun50i_h6_ppu_pd_set_power(pd, !pd->negated);
+}
+
+static int sun50i_h6_ppu_pd_power_off(struct generic_pm_domain *genpd)
+{
+ const struct sun50i_h6_ppu_pd *pd = to_sun50i_h6_ppu_pd(genpd);
+
+ return sun50i_h6_ppu_pd_set_power(pd, pd->negated);
+}
+
+static int sun50i_h6_ppu_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct genpd_onecell_data *ppu;
+ struct sun50i_h6_ppu_pd *pds;
+ const struct sun50i_h6_ppu_desc *desc;
+ void __iomem *base;
+ int ret, i, count;
+
+ desc = of_device_get_match_data(dev);
+ if (!desc)
+ return -EINVAL;
+
+ for (count = 0; desc[count].name; count++)
+ ;
+
+ pds = devm_kcalloc(dev, count, sizeof(*pds), GFP_KERNEL);
+ if (!pds)
+ return -ENOMEM;
+
+ ppu = devm_kzalloc(dev, sizeof(*ppu), GFP_KERNEL);
+ if (!ppu)
+ return -ENOMEM;
+
+ ppu->num_domains = count;
+ ppu->domains = devm_kcalloc(dev, count, sizeof(*ppu->domains),
+ GFP_KERNEL);
+ if (!ppu->domains)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, ppu);
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ for (i = 0; i < count; i++) {
+ struct sun50i_h6_ppu_pd *pd = &pds[i];
+
+ pd->genpd.name = desc[i].name;
+ pd->genpd.power_off = sun50i_h6_ppu_pd_power_off;
+ pd->genpd.power_on = sun50i_h6_ppu_pd_power_on;
+ if (desc[i].flags & FLAG_PPU_ALWAYS_ON)
+ pd->genpd.flags = GENPD_FLAG_ALWAYS_ON;
+ pd->negated = !!(desc[i].flags & FLAG_PPU_NEGATED);
+ pd->reg = base + desc[i].offset - PD_H6_PPU_OFFSET;
+ pd->gate_mask = desc[i].mask;
+
+ ret = pm_genpd_init(&pd->genpd, NULL,
+ !sun50i_h6_ppu_power_status(pd));
+ if (ret) {
+ dev_warn(dev, "Failed to add GPU power domain: %d\n", ret);
+ return ret;
+ }
+ 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 struct of_device_id sun50i_h6_ppu_of_match[] = {
+ { .compatible = "allwinner,sun50i-h6-prcm-ppu",
+ .data = &sun50i_h6_ppus },
+ { .compatible = "allwinner,sun50i-h616-prcm-ppu",
+ .data = &sun50i_h616_ppus },
+ { }
+};
+MODULE_DEVICE_TABLE(of, sun50i_h6_ppu_of_match);
+
+static struct platform_driver sun50i_h6_ppu_driver = {
+ .probe = sun50i_h6_ppu_probe,
+ .driver = {
+ .name = "sun50i-h6-prcm-ppu",
+ .of_match_table = sun50i_h6_ppu_of_match,
+ /* Power domains cannot be removed while they are in use. */
+ .suppress_bind_attrs = true,
+ },
+};
+module_platform_driver(sun50i_h6_ppu_driver);
+
+MODULE_AUTHOR("Andre Przywara <andre.przywara@arm.com>");
+MODULE_DESCRIPTION("Allwinner H6 PRCM power domain driver");
+MODULE_LICENSE("GPL");
--
2.35.3

View File

@ -13,7 +13,7 @@ Signed-off-by: Ondrej Jirman <megi@xff.cz>
1 file changed, 10 insertions(+), 1 deletion(-) 1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
index c8cdb342b1a0..e76a1c10f390 100644 index 4b3068bdfdf2..e76a1c10f390 100644
--- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c --- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
+++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
@@ -962,6 +962,8 @@ static struct ccu_mux_nb sun50i_a64_cpu_nb = { @@ -962,6 +962,8 @@ static struct ccu_mux_nb sun50i_a64_cpu_nb = {
@ -25,24 +25,24 @@ index c8cdb342b1a0..e76a1c10f390 100644
static int sun50i_a64_ccu_probe(struct platform_device *pdev) static int sun50i_a64_ccu_probe(struct platform_device *pdev)
{ {
void __iomem *reg; void __iomem *reg;
@@ -981,9 +983,16 @@ static int sun50i_a64_ccu_probe(struct platform_device *pdev) @@ -980,7 +982,16 @@ static int sun50i_a64_ccu_probe(struct platform_device *pdev)
/* Decrease the PLL AUDIO bias current to reduce noise. */
writel(0x10040000, reg + SUN50I_A64_PLL_AUDIO_BIAS_REG); writel(0x10040000, reg + SUN50I_A64_PLL_AUDIO_BIAS_REG);
ret = of_property_read_u32_index(of_chosen, "p-boot,framebuffer-start", 0, &val); - writel(0x515, reg + SUN50I_A64_PLL_MIPI_REG);
- if (ret) + ret = of_property_read_u32_index(of_chosen, "p-boot,framebuffer-start", 0, &val);
+ if (ret) { + if (ret) {
writel(0x515, reg + SUN50I_A64_PLL_MIPI_REG); + writel(0x515, reg + SUN50I_A64_PLL_MIPI_REG);
+
+ /* Set MIPI-DSI clock parent to periph0(1x), so that video0(1x) is free to change. */ + /* Set MIPI-DSI clock parent to periph0(1x), so that video0(1x) is free to change. */
+ val = readl(reg + CCU_MIPI_DSI_CLK); + val = readl(reg + CCU_MIPI_DSI_CLK);
+ val &= 0x30f; + val &= 0x30f;
+ val |= (2 << 8) | ((4 - 1) << 0); /* M-1 */ + val |= (2 << 8) | ((4 - 1) << 0); /* M-1 */
+ writel(val, reg + CCU_MIPI_DSI_CLK); + writel(val, reg + CCU_MIPI_DSI_CLK);
+ } + }
+
ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun50i_a64_ccu_desc); ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun50i_a64_ccu_desc);
if (ret) if (ret)
return ret;
-- --
2.35.3 2.35.3

View File

@ -25,7 +25,7 @@ Signed-off-by: Ondrej Jirman <megi@xff.cz>
1 file changed, 70 insertions(+), 2 deletions(-) 1 file changed, 70 insertions(+), 2 deletions(-)
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index f7d9d8813d92..8a7a158dc1f6 100644 index 237d3d3f3bb1..9f96bdd82a87 100644
--- a/drivers/video/backlight/pwm_bl.c --- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c
@@ -437,6 +437,61 @@ static int pwm_backlight_initial_power_state(const struct pwm_bl_data *pb) @@ -437,6 +437,61 @@ static int pwm_backlight_initial_power_state(const struct pwm_bl_data *pb)
@ -90,15 +90,29 @@ index f7d9d8813d92..8a7a158dc1f6 100644
static int pwm_backlight_probe(struct platform_device *pdev) static int pwm_backlight_probe(struct platform_device *pdev)
{ {
struct platform_pwm_backlight_data *data = dev_get_platdata(&pdev->dev); struct platform_pwm_backlight_data *data = dev_get_platdata(&pdev->dev);
@@ -445,6 +500,7 @@ static int pwm_backlight_probe(struct platform_device *pdev) @@ -444,7 +499,8 @@ static int pwm_backlight_probe(struct platform_device *pdev)
struct backlight_properties props;
struct backlight_device *bl; struct backlight_device *bl;
struct pwm_bl_data *pb; struct pwm_bl_data *pb;
struct pwm_state state, state_real; - struct pwm_state state;
+ struct pwm_state state, state_real;
+ u32 lth_brightness; + u32 lth_brightness;
unsigned int i; unsigned int i;
int ret; int ret;
@@ -584,8 +640,20 @@ static int pwm_backlight_probe(struct platform_device *pdev) @@ -509,6 +565,11 @@ static int pwm_backlight_probe(struct platform_device *pdev)
/* Sync up PWM state. */
pwm_init_state(pb->pwm, &state);
+ /* Read real state, but only if the PWM is enabled. */
+ pwm_get_state(pb->pwm, &state_real);
+ if (state_real.enabled)
+ state = state_real;
+
/*
* The DT case will set the pwm_period_ns field to 0 and store the
* period, parsed from the DT, in the PWM device. For the non-DT case,
@@ -579,8 +640,20 @@ static int pwm_backlight_probe(struct platform_device *pdev)
pb->scale = data->max_brightness; pb->scale = data->max_brightness;
} }
@ -121,6 +135,31 @@ index f7d9d8813d92..8a7a158dc1f6 100644
props.type = BACKLIGHT_RAW; props.type = BACKLIGHT_RAW;
props.max_brightness = data->max_brightness; props.max_brightness = data->max_brightness;
@@ -601,6 +674,24 @@ static int pwm_backlight_probe(struct platform_device *pdev)
bl->props.brightness = data->dft_brightness;
bl->props.power = pwm_backlight_initial_power_state(pb);
+ if (bl->props.power == FB_BLANK_UNBLANK && pb->levels) {
+ u64 level;
+
+ /* If the backlight is already on, determine the default
+ * brightness from PWM duty cycle instead of forcing
+ * the brightness determined by the driver
+ */
+ pwm_get_state(pb->pwm, &state);
+ level = (u64)state.duty_cycle * pb->scale;
+ do_div(level, (u64)state.period);
+
+ for (i = 0; i <= data->max_brightness; i++) {
+ if (data->levels[i] > level) {
+ bl->props.brightness = i;
+ break;
+ }
+ }
+ }
backlight_update_status(bl);
platform_set_drvdata(pdev, bl);
-- --
2.35.3 2.35.3

View File

@ -180,10 +180,10 @@
patches.megous/arm64-dts-rk3399-Add-dmc_opp_table.patch patches.megous/arm64-dts-rk3399-Add-dmc_opp_table.patch
patches.megous/arm64-dts-rockchip-rk3399-s-Add-DMC-table.patch patches.megous/arm64-dts-rockchip-rk3399-s-Add-DMC-table.patch
patches.megous/bluetooth-h5-Don-t-re-initialize-rtl8723cs-on-resume.patch patches.megous/bluetooth-h5-Don-t-re-initialize-rtl8723cs-on-resume.patch
patches.megous/drm-sun4i-Mark-one-of-the-UI-planes-as-a-cursor-one.patch - patches.megous/drm-sun4i-Mark-one-of-the-UI-planes-as-a-cursor-one.patch
patches.megous/drm-sun4i-Implement-gamma-correction.patch - patches.megous/drm-sun4i-Implement-gamma-correction.patch
patches.megous/drm-panel-st7703-Fix-xbd599-timings-to-make-refresh-rate-exactl.patch patches.megous/drm-panel-st7703-Fix-xbd599-timings-to-make-refresh-rate-exactl.patch
patches.megous/drm-sun4i-Support-taking-over-display-pipeline-state-from-p-boo.patch - patches.megous/drm-sun4i-Support-taking-over-display-pipeline-state-from-p-boo.patch
patches.megous/video-pwm_bl-Allow-to-change-lth_brightness-via-sysfs.patch patches.megous/video-pwm_bl-Allow-to-change-lth_brightness-via-sysfs.patch
patches.megous/clk-sunxi-ng-sun50i-a64-Switch-parent-of-MIPI-DSI-to-periph0-1x.patch patches.megous/clk-sunxi-ng-sun50i-a64-Switch-parent-of-MIPI-DSI-to-periph0-1x.patch
patches.megous/drm-sun4i-tcon-Support-keeping-dclk-rate-upon-ancestor-clock-ch.patch patches.megous/drm-sun4i-tcon-Support-keeping-dclk-rate-upon-ancestor-clock-ch.patch
@ -245,5 +245,46 @@
patches.megous/Add-support-for-my-private-Sapomat-device.patch patches.megous/Add-support-for-my-private-Sapomat-device.patch
patches.megous/ARM-dts-sun8i-h3-orange-pi-one-Enable-all-gpio-header-UARTs.patch patches.megous/ARM-dts-sun8i-h3-orange-pi-one-Enable-all-gpio-header-UARTs.patch
patches.megous/mtd-spi-nor-Add-Alliance-memory-support.patch patches.megous/mtd-spi-nor-Add-Alliance-memory-support.patch
patches.megous/Add-README.md-with-information-and-u-boot-patches.patch - patches.megous/Add-README.md-with-information-and-u-boot-patches.patch
patches.megous/Defconfigs-for-all-my-devices.patch patches.megous/Defconfigs-for-all-my-devices.patch
################################################################################
#
# drivers/gpu/drm/sun4i/
#
################################################################################
patches.drm/drm-sun4i-de2-de3-Change-CSC-argument.patch
patches.drm/drm-sun4i-de2-de3-Merge-CSC-functions-into-one.patch
patches.drm/drm-sun4i-de2-de3-call-csc-setup-also-for-UI-layer.patch
patches.drm/drm-sun4i-de2-Initialize-layer-fields-earlier.patch
patches.drm/drm-sun4i-de3-Add-YUV-formatter-module.patch
patches.drm/drm-sun4i-de3-add-format-enumeration-function-to-engine.patch
patches.drm/drm-sun4i-de3-add-formatter-flag-to-mixer-config.patch
patches.drm/drm-sun4i-de3-add-YUV-support-to-the-DE3-mixer.patch
patches.drm/drm-sun4i-de3-pass-engine-reference-to-ccsc-setup-function.patch
patches.drm/drm-sun4i-de3-add-YUV-support-to-the-color-space-correction-mod.patch
patches.drm/drm-sun4i-de3-add-YUV-support-to-the-TCON.patch
patches.drm/drm-sun4i-support-YUV-formats-in-VI-scaler.patch
patches.drm/drm-sun4i-de2-de3-add-mixer-version-enum.patch
patches.drm/drm-sun4i-de2-de3-refactor-mixer-initialisation.patch
patches.drm/drm-sun4i-vi_scaler-refactor-vi_scaler-enablement.patch
patches.drm/drm-sun4i-de2-de3-add-generic-blender-register-reference-functi.patch
patches.drm/drm-sun4i-de2-de3-use-generic-register-reference-function-for-l.patch
patches.drm/drm-sun4i-de3-Implement-AFBC-support.patch
patches.drm/dt-bindings-allwinner-add-H616-DE33-bus-binding.patch
patches.drm/dt-bindings-allwinner-add-H616-DE33-clock-binding.patch
patches.drm/dt-bindings-allwinner-add-H616-DE33-mixer-binding.patch
patches.drm/clk-sunxi-ng-ccu-add-Display-Engine-3.3-DE33-support.patch
patches.drm/drm-sun4i-de33-mixer-add-Display-Engine-3.3-DE33-support.patch
patches.drm/drm-sun4i-de33-vi_scaler-add-Display-Engine-3.3-DE33-support.patch
patches.drm/drm-sun4i-de33-fmt-add-Display-Engine-3.3-DE33-support.patch
patches.drm/drm-sun4i-de33-csc-add-Display-Engine-3.3-DE33-support.patch
patches.drm/drm-sun4i-add-sun50i-h616-hdmi-phy-support.patch
patches.drm/add-TCON-global-control-reg-for-pad-selection.patch
patches.drm/dt-bindings-power-Add-Allwinner-H6-H616-PRCM-PPU.patch
patches.drm/pmdomain-sunxi-add-H6-PRCM-PPU-driver.patch
patches.drm/dt-bindings-gpu-mali-bifrost-Add-Allwinner-H616-compatible.patch
patches.drm/arm64-dts-allwinner-h616-Add-Mali-GPU-node.patch
patches.drm/drm-panfrost-Add-PM-runtime-flags.patch
patches.drm/drm-panfrost-add-h616-compatible-string.patch
patches.drm/drm-panfrost-reorder-pd-clk-rst-sequence.patch

View File

@ -0,0 +1,40 @@
################################################################################
#
# drivers/gpu/drm/sun4i/
#
################################################################################
patches.drm/drm-sun4i-de2-de3-Change-CSC-argument.patch
patches.drm/drm-sun4i-de2-de3-Merge-CSC-functions-into-one.patch
patches.drm/drm-sun4i-de2-de3-call-csc-setup-also-for-UI-layer.patch
patches.drm/drm-sun4i-de2-Initialize-layer-fields-earlier.patch
patches.drm/drm-sun4i-de3-Add-YUV-formatter-module.patch
patches.drm/drm-sun4i-de3-add-format-enumeration-function-to-engine.patch
patches.drm/drm-sun4i-de3-add-formatter-flag-to-mixer-config.patch
patches.drm/drm-sun4i-de3-add-YUV-support-to-the-DE3-mixer.patch
patches.drm/drm-sun4i-de3-pass-engine-reference-to-ccsc-setup-function.patch
patches.drm/drm-sun4i-de3-add-YUV-support-to-the-color-space-correction-mod.patch
patches.drm/drm-sun4i-de3-add-YUV-support-to-the-TCON.patch
patches.drm/drm-sun4i-support-YUV-formats-in-VI-scaler.patch
patches.drm/drm-sun4i-de2-de3-add-mixer-version-enum.patch
patches.drm/drm-sun4i-de2-de3-refactor-mixer-initialisation.patch
patches.drm/drm-sun4i-vi_scaler-refactor-vi_scaler-enablement.patch
patches.drm/drm-sun4i-de2-de3-add-generic-blender-register-reference-functi.patch
patches.drm/drm-sun4i-de2-de3-use-generic-register-reference-function-for-l.patch
patches.drm/drm-sun4i-de3-Implement-AFBC-support.patch
patches.drm/dt-bindings-allwinner-add-H616-DE33-bus-binding.patch
patches.drm/dt-bindings-allwinner-add-H616-DE33-clock-binding.patch
patches.drm/dt-bindings-allwinner-add-H616-DE33-mixer-binding.patch
patches.drm/clk-sunxi-ng-ccu-add-Display-Engine-3.3-DE33-support.patch
patches.drm/drm-sun4i-de33-mixer-add-Display-Engine-3.3-DE33-support.patch
patches.drm/drm-sun4i-de33-vi_scaler-add-Display-Engine-3.3-DE33-support.patch
patches.drm/drm-sun4i-de33-fmt-add-Display-Engine-3.3-DE33-support.patch
patches.drm/drm-sun4i-de33-csc-add-Display-Engine-3.3-DE33-support.patch
patches.drm/drm-sun4i-add-sun50i-h616-hdmi-phy-support.patch
patches.drm/add-TCON-global-control-reg-for-pad-selection.patch
patches.drm/dt-bindings-power-Add-Allwinner-H6-H616-PRCM-PPU.patch
patches.drm/pmdomain-sunxi-add-H6-PRCM-PPU-driver.patch
patches.drm/dt-bindings-gpu-mali-bifrost-Add-Allwinner-H616-compatible.patch
patches.drm/arm64-dts-allwinner-h616-Add-Mali-GPU-node.patch
patches.drm/drm-panfrost-Add-PM-runtime-flags.patch
patches.drm/drm-panfrost-add-h616-compatible-string.patch
patches.drm/drm-panfrost-reorder-pd-clk-rst-sequence.patch